1 /*
2  * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
3  * Released under the terms of the GNU GPL v2.0.
4  */
5 
6 #include <sys/stat.h>
7 #include <ctype.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <time.h>
12 #include <unistd.h>
13 
14 #define LKC_DIRECT_LINK
15 #include "lkc.h"
16 
17 static void conf_warning(const char *fmt, ...)
18 	__attribute__ ((format (printf, 1, 2)));
19 
20 static const char *conf_filename;
21 static int conf_lineno, conf_warnings, conf_unsaved;
22 
23 const char conf_def_filename[] = ".config";
24 
25 const char conf_defname[] = "/dev/null"; //bbox
26 
27 const char *conf_confnames[] = {
28 	conf_def_filename,
29 	conf_defname,
30 	NULL,
31 };
32 
conf_warning(const char * fmt,...)33 static void conf_warning(const char *fmt, ...)
34 {
35 	va_list ap;
36 	va_start(ap, fmt);
37 	fprintf(stderr, "%s:%d:warning: ", conf_filename, conf_lineno);
38 	vfprintf(stderr, fmt, ap);
39 	fprintf(stderr, "\n");
40 	va_end(ap);
41 	conf_warnings++;
42 }
43 
conf_expand_value(const char * in)44 static char *conf_expand_value(const char *in)
45 {
46 	struct symbol *sym;
47 	const char *src;
48 	static char res_value[SYMBOL_MAXLENGTH];
49 	char *dst, name[SYMBOL_MAXLENGTH];
50 
51 	res_value[0] = 0;
52 	dst = name;
53 	while ((src = strchr(in, '$'))) {
54 		strncat(res_value, in, src - in);
55 		src++;
56 		dst = name;
57 		while (isalnum((unsigned char)*src) || *src == '_')
58 			*dst++ = *src++;
59 		*dst = 0;
60 		sym = sym_lookup(name, 0);
61 		sym_calc_value(sym);
62 		strcat(res_value, sym_get_string_value(sym));
63 		in = src;
64 	}
65 	strcat(res_value, in);
66 
67 	return res_value;
68 }
69 
conf_get_default_confname(void)70 char *conf_get_default_confname(void)
71 {
72 	struct stat buf;
73 	static char *fullname = NULL;
74 	char *env, *name;
75 
76 	name = conf_expand_value(conf_defname);
77 	env = getenv(SRCTREE);
78 	if (env) {
79 		fullname = realloc(fullname, strlen(env) + strlen(name) + 2);
80 		sprintf(fullname, "%s/%s", env, name);
81 		if (!stat(fullname, &buf))
82 			return fullname;
83 	}
84 	return name;
85 }
86 
conf_read_simple(const char * name)87 int conf_read_simple(const char *name)
88 {
89 	FILE *in = NULL;
90 	char line[1024];
91 	char *p, *p2;
92 	struct symbol *sym;
93 	int i;
94 
95 	if (name) {
96 		in = zconf_fopen(name);
97 	} else {
98 		const char **names = conf_confnames;
99 		while ((name = *names++)) {
100 			name = conf_expand_value(name);
101 			in = zconf_fopen(name);
102 			if (in) {
103 				printf(_("#\n"
104 				         "# using defaults found in %s\n"
105 				         "#\n"), name);
106 				break;
107 			}
108 		}
109 	}
110 	if (!in)
111 		return 1;
112 
113 	conf_filename = name;
114 	conf_lineno = 0;
115 	conf_warnings = 0;
116 	conf_unsaved = 0;
117 
118 	for_all_symbols(i, sym) {
119 		sym->flags |= SYMBOL_NEW | SYMBOL_CHANGED;
120 		if (sym_is_choice(sym))
121 			sym->flags &= ~SYMBOL_NEW;
122 		sym->flags &= ~SYMBOL_VALID;
123 		switch (sym->type) {
124 		case S_INT:
125 		case S_HEX:
126 		case S_STRING:
127 			free(sym->user.val);
128 		default:
129 			sym->user.val = NULL;
130 			sym->user.tri = no;
131 		}
132 	}
133 
134 	while (fgets(line, sizeof(line), in)) {
135 		conf_lineno++;
136 		sym = NULL;
137 		switch (line[0]) {
138 		case '#':
139 			if (memcmp(line + 2, "CONFIG_", 7))
140 				continue;
141 			p = strchr(line + 9, ' ');
142 			if (!p)
143 				continue;
144 			*p++ = 0;
145 			if (strncmp(p, "is not set", 10))
146 				continue;
147 			sym = sym_find(line + 9);
148 			if (!sym) {
149 				conf_warning("trying to assign nonexistent symbol %s", line + 9);
150 				break;
151 			} else if (!(sym->flags & SYMBOL_NEW)) {
152 				conf_warning("trying to reassign symbol %s", sym->name);
153 				break;
154 			}
155 			switch (sym->type) {
156 			case S_BOOLEAN:
157 			case S_TRISTATE:
158 				sym->user.tri = no;
159 				sym->flags &= ~SYMBOL_NEW;
160 				break;
161 			default:
162 				;
163 			}
164 			break;
165 		case 'C':
166 			if (memcmp(line, "CONFIG_", 7)) {
167 				conf_warning("unexpected data");
168 				continue;
169 			}
170 			p = strchr(line + 7, '=');
171 			if (!p)
172 				continue;
173 			*p++ = 0;
174 			p2 = strchr(p, '\n');
175 			if (p2)
176 				*p2 = 0;
177 			sym = sym_find(line + 7);
178 			if (!sym) {
179 				conf_warning("trying to assign nonexistent symbol %s", line + 7);
180 				break;
181 			} else if (!(sym->flags & SYMBOL_NEW)) {
182 				conf_warning("trying to reassign symbol %s", sym->name);
183 				break;
184 			}
185 			switch (sym->type) {
186 			case S_TRISTATE:
187 				if (p[0] == 'm') {
188 					sym->user.tri = mod;
189 					sym->flags &= ~SYMBOL_NEW;
190 					break;
191 				}
192 			case S_BOOLEAN:
193 				if (p[0] == 'y') {
194 					sym->user.tri = yes;
195 					sym->flags &= ~SYMBOL_NEW;
196 					break;
197 				}
198 				if (p[0] == 'n') {
199 					sym->user.tri = no;
200 					sym->flags &= ~SYMBOL_NEW;
201 					break;
202 				}
203 				conf_warning("symbol value '%s' invalid for %s", p, sym->name);
204 				break;
205 			case S_STRING:
206 				if (*p++ != '"')
207 					break;
208 				for (p2 = p; (p2 = strpbrk(p2, "\"\\")); p2++) {
209 					if (*p2 == '"') {
210 						*p2 = 0;
211 						break;
212 					}
213 					memmove(p2, p2 + 1, strlen(p2));
214 				}
215 				if (!p2) {
216 					conf_warning("invalid string found");
217 					continue;
218 				}
219 			case S_INT:
220 			case S_HEX:
221 				if (sym_string_valid(sym, p)) {
222 					sym->user.val = strdup(p);
223 					sym->flags &= ~SYMBOL_NEW;
224 				} else {
225 					if (p[0]) /* bbox */
226 						conf_warning("symbol value '%s' invalid for %s", p, sym->name);
227 					continue;
228 				}
229 				break;
230 			default:
231 				;
232 			}
233 			break;
234 		case '\n':
235 			break;
236 		default:
237 			conf_warning("unexpected data");
238 			continue;
239 		}
240 		if (sym && sym_is_choice_value(sym)) {
241 			struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym));
242 			switch (sym->user.tri) {
243 			case no:
244 				break;
245 			case mod:
246 				if (cs->user.tri == yes) {
247 					conf_warning("%s creates inconsistent choice state", sym->name);
248 					cs->flags |= SYMBOL_NEW;
249 				}
250 				break;
251 			case yes:
252 				if (cs->user.tri != no) {
253 					conf_warning("%s creates inconsistent choice state", sym->name);
254 					cs->flags |= SYMBOL_NEW;
255 				} else
256 					cs->user.val = sym;
257 				break;
258 			}
259 			cs->user.tri = E_OR(cs->user.tri, sym->user.tri);
260 		}
261 	}
262 	fclose(in);
263 
264 	if (modules_sym)
265 		sym_calc_value(modules_sym);
266 	return 0;
267 }
268 
conf_read(const char * name)269 int conf_read(const char *name)
270 {
271 	struct symbol *sym;
272 	struct property *prop;
273 	struct expr *e;
274 	int i;
275 
276 	if (conf_read_simple(name))
277 		return 1;
278 
279 	for_all_symbols(i, sym) {
280 		sym_calc_value(sym);
281 		if (sym_is_choice(sym) || (sym->flags & SYMBOL_AUTO))
282 			goto sym_ok;
283 		if (sym_has_value(sym) && (sym->flags & SYMBOL_WRITE)) {
284 			/* check that calculated value agrees with saved value */
285 			switch (sym->type) {
286 			case S_BOOLEAN:
287 			case S_TRISTATE:
288 				if (sym->user.tri != sym_get_tristate_value(sym))
289 					break;
290 				if (!sym_is_choice(sym))
291 					goto sym_ok;
292 			default:
293 				if (!strcmp(sym->curr.val, sym->user.val))
294 					goto sym_ok;
295 				break;
296 			}
297 		} else if (!sym_has_value(sym) && !(sym->flags & SYMBOL_WRITE))
298 			/* no previous value and not saved */
299 			goto sym_ok;
300 		conf_unsaved++;
301 		/* maybe print value in verbose mode... */
302 	sym_ok:
303 		if (sym_has_value(sym) && !sym_is_choice_value(sym)) {
304 			if (sym->visible == no)
305 				sym->flags |= SYMBOL_NEW;
306 			switch (sym->type) {
307 			case S_STRING:
308 			case S_INT:
309 			case S_HEX:
310 				if (!sym_string_within_range(sym, sym->user.val)) {
311 					sym->flags |= SYMBOL_NEW;
312 					sym->flags &= ~SYMBOL_VALID;
313 				}
314 			default:
315 				break;
316 			}
317 		}
318 		if (!sym_is_choice(sym))
319 			continue;
320 		prop = sym_get_choice_prop(sym);
321 		for (e = prop->expr; e; e = e->left.expr)
322 			if (e->right.sym->visible != no)
323 				sym->flags |= e->right.sym->flags & SYMBOL_NEW;
324 	}
325 
326 	sym_change_count = conf_warnings || conf_unsaved;
327 
328 	return 0;
329 }
330 
conf_write(const char * name)331 int conf_write(const char *name)
332 {
333 	FILE *out, *out_h;
334 	struct symbol *sym;
335 	struct menu *menu;
336 	const char *basename;
337 	char dirname[128];
338 	char tmpname[256];
339 	char newname[256];
340 	int type, l;
341 	const char *str;
342 	time_t now;
343 	int use_timestamp = 1;
344 	char *env;
345 	char *source_date_epoch;
346 	struct tm *build_time;
347 
348 	dirname[0] = 0;
349 	if (name && name[0]) {
350 		struct stat st;
351 		char *slash;
352 
353 		if (!stat(name, &st) && S_ISDIR(st.st_mode)) {
354 			strcpy(dirname, name);
355 			strcat(dirname, "/");
356 			basename = conf_def_filename;
357 		} else if ((slash = strrchr(name, '/'))) {
358 			int size = slash - name + 1;
359 			memcpy(dirname, name, size);
360 			dirname[size] = 0;
361 			if (slash[1])
362 				basename = slash + 1;
363 			else
364 				basename = conf_def_filename;
365 		} else
366 			basename = name;
367 	} else
368 		basename = conf_def_filename;
369 
370 	sprintf(newname, "%s.tmpconfig.%d", dirname, (int)getpid());
371 	out = fopen(newname, "w");
372 	if (!out)
373 		return 1;
374 	out_h = NULL;
375 	if (!name) {
376 		out_h = fopen(".tmpconfig.h", "w");
377 		if (!out_h)
378 			return 1;
379 		file_write_dep(NULL);
380 	}
381 	sym = sym_lookup("KERNELVERSION", 0);
382 	sym_calc_value(sym);
383 
384 	source_date_epoch = getenv("SOURCE_DATE_EPOCH");
385 	if (source_date_epoch && *source_date_epoch) {
386 		now = strtoull(source_date_epoch, NULL, 10);
387 		build_time = gmtime(&now);
388 	} else {
389 		time(&now);
390 		build_time = localtime(&now);
391 	}
392 
393 	env = getenv("KCONFIG_NOTIMESTAMP");
394 	if (env && *env)
395 		use_timestamp = 0;
396 
397 	fprintf(out, _("#\n"
398 		       "# Automatically generated make config: don't edit\n"
399 		       "# Busybox version: %s\n"
400 		       "%s%s"
401 		       "#\n"),
402 		     sym_get_string_value(sym),
403 		     use_timestamp ? "# " : "",
404 		     use_timestamp ? ctime(&now) : "");
405 	if (out_h) {
406 		char buf[sizeof("#define AUTOCONF_TIMESTAMP "
407 				"\"YYYY-MM-DD HH:MM:SS some_timezone\"\n")];
408 		buf[0] = '\0';
409 		if (use_timestamp) {
410 			size_t ret = \
411 				strftime(buf, sizeof(buf), "#define AUTOCONF_TIMESTAMP "
412 					"\"%Y-%m-%d %H:%M:%S %Z\"\n", build_time);
413 			/* if user has Factory timezone or some other odd install, the
414 			 * %Z above will overflow the string leaving us with undefined
415 			 * results ... so let's try again without the timezone.
416 			 */
417 			if (ret == 0)
418 				strftime(buf, sizeof(buf), "#define AUTOCONF_TIMESTAMP "
419 					"\"%Y-%m-%d %H:%M:%S\"\n", build_time);
420 		} else { /* bbox */
421 			strcpy(buf, "#define AUTOCONF_TIMESTAMP \"\"\n");
422 		}
423 		fprintf(out_h, "/*\n"
424 			       " * Automatically generated C config: don't edit\n"
425 			       " * Busybox version: %s\n"
426 			       " */\n"
427 			       "%s"
428 			       "\n",
429 			       sym_get_string_value(sym),
430 			       buf);
431 	}
432 	if (!sym_change_count)
433 		sym_clear_all_valid();
434 
435 	menu = rootmenu.list;
436 	while (menu) {
437 		sym = menu->sym;
438 		if (!sym) {
439 			if (!menu_is_visible(menu))
440 				goto next;
441 			str = menu_get_prompt(menu);
442 			fprintf(out, "\n"
443 				     "#\n"
444 				     "# %s\n"
445 				     "#\n", str);
446 			if (out_h)
447 				fprintf(out_h, "\n"
448 					       "/*\n"
449 					       " * %s\n"
450 					       " */\n", str);
451 		} else if (!(sym->flags & SYMBOL_CHOICE)) {
452 			sym_calc_value(sym);
453 /* bbox: we want to see all syms
454 			if (!(sym->flags & SYMBOL_WRITE))
455 				goto next;
456 */
457 			sym->flags &= ~SYMBOL_WRITE;
458 			type = sym->type;
459 			if (type == S_TRISTATE) {
460 				sym_calc_value(modules_sym);
461 				if (modules_sym->curr.tri == no)
462 					type = S_BOOLEAN;
463 			}
464 			switch (type) {
465 			case S_BOOLEAN:
466 			case S_TRISTATE:
467 				switch (sym_get_tristate_value(sym)) {
468 				case no:
469 					fprintf(out, "# CONFIG_%s is not set\n", sym->name);
470 					if (out_h) {
471 						fprintf(out_h, "#undef CONFIG_%s\n", sym->name);
472 						/* bbox */
473 						fprintf(out_h, "#define ENABLE_%s 0\n", sym->name);
474 						fprintf(out_h, "#define IF_%s(...)\n", sym->name);
475 						fprintf(out_h, "#define IF_NOT_%s(...) __VA_ARGS__\n", sym->name);
476 					}
477 					break;
478 				case mod:
479 					fprintf(out, "CONFIG_%s=m\n", sym->name);
480 					if (out_h)
481 						fprintf(out_h, "#define CONFIG_%s_MODULE 1\n", sym->name);
482 					break;
483 				case yes:
484 					fprintf(out, "CONFIG_%s=y\n", sym->name);
485 					if (out_h) {
486 						fprintf(out_h, "#define CONFIG_%s 1\n", sym->name);
487 						/* bbox */
488 						fprintf(out_h, "#define ENABLE_%s 1\n", sym->name);
489 						fprintf(out_h, "#ifdef MAKE_SUID\n");
490 						fprintf(out_h, "# define IF_%s(...) __VA_ARGS__ \"CONFIG_%s\"\n", sym->name, sym->name);
491 						fprintf(out_h, "#else\n");
492 						fprintf(out_h, "# define IF_%s(...) __VA_ARGS__\n", sym->name);
493 						fprintf(out_h, "#endif\n");
494 						fprintf(out_h, "#define IF_NOT_%s(...)\n", sym->name);
495 					}
496 					break;
497 				}
498 				break;
499 			case S_STRING:
500 				// fix me
501 				str = sym_get_string_value(sym);
502 				fprintf(out, "CONFIG_%s=\"", sym->name);
503 				if (out_h)
504 					fprintf(out_h, "#define CONFIG_%s \"", sym->name);
505 				do {
506 					l = strcspn(str, "\"\\");
507 					if (l) {
508 						fwrite(str, l, 1, out);
509 						if (out_h)
510 							fwrite(str, l, 1, out_h);
511 					}
512 					str += l;
513 					while (*str == '\\' || *str == '"') {
514 						fprintf(out, "\\%c", *str);
515 						if (out_h)
516 							fprintf(out_h, "\\%c", *str);
517 						str++;
518 					}
519 				} while (*str);
520 				fputs("\"\n", out);
521 				if (out_h) {
522 					fputs("\"\n", out_h);
523 					/* bbox */
524 					fprintf(out_h, "#define ENABLE_%s 1\n", sym->name);
525 					fprintf(out_h, "#ifdef MAKE_SUID\n");
526 					fprintf(out_h, "# define IF_%s(...) __VA_ARGS__ \"CONFIG_%s\"\n", sym->name, sym->name);
527 					fprintf(out_h, "#else\n");
528 					fprintf(out_h, "# define IF_%s(...) __VA_ARGS__\n", sym->name);
529 					fprintf(out_h, "#endif\n");
530 					fprintf(out_h, "#define IF_NOT_%s(...)\n", sym->name);
531 				}
532 				break;
533 			case S_HEX:
534 				str = sym_get_string_value(sym);
535 				if (str[0] != '0' || (str[1] != 'x' && str[1] != 'X')) {
536 					fprintf(out, "CONFIG_%s=%s\n", sym->name, str);
537 					if (out_h) {
538 						fprintf(out_h, "#define CONFIG_%s 0x%s\n", sym->name, str);
539 						/* bbox */
540 						fprintf(out_h, "#define ENABLE_%s 1\n", sym->name);
541 						fprintf(out_h, "#ifdef MAKE_SUID\n");
542 						fprintf(out_h, "# define IF_%s(...) __VA_ARGS__ \"CONFIG_%s\"\n", sym->name, sym->name);
543 						fprintf(out_h, "#else\n");
544 						fprintf(out_h, "# define IF_%s(...) __VA_ARGS__\n", sym->name);
545 						fprintf(out_h, "#endif\n");
546 						fprintf(out_h, "#define IF_NOT_%s(...)\n", sym->name);
547 					}
548 					break;
549 				}
550 			case S_INT:
551 				str = sym_get_string_value(sym);
552 				if (!str[0])
553 					str = "0";
554 				fprintf(out, "CONFIG_%s=%s\n", sym->name, str);
555 				if (out_h) {
556 					fprintf(out_h, "#define CONFIG_%s %s\n", sym->name, str);
557 					/* bbox */
558 					fprintf(out_h, "#define ENABLE_%s 1\n", sym->name);
559 					fprintf(out_h, "#ifdef MAKE_SUID\n");
560 					fprintf(out_h, "# define IF_%s(...) __VA_ARGS__ \"CONFIG_%s\"\n", sym->name, sym->name);
561 					fprintf(out_h, "#else\n");
562 					fprintf(out_h, "# define IF_%s(...) __VA_ARGS__\n", sym->name);
563 					fprintf(out_h, "#endif\n");
564 					fprintf(out_h, "#define IF_NOT_%s(...)\n", sym->name);
565 				}
566 				break;
567 			}
568 		}
569 
570 	next:
571 		if (menu->list) {
572 			menu = menu->list;
573 			continue;
574 		}
575 		if (menu->next)
576 			menu = menu->next;
577 		else while ((menu = menu->parent)) {
578 			if (menu->next) {
579 				menu = menu->next;
580 				break;
581 			}
582 		}
583 	}
584 	fclose(out);
585 	if (out_h) {
586 		fclose(out_h);
587 		rename(".tmpconfig.h", "include/autoconf.h");
588 	}
589 	if (!name || basename != conf_def_filename) {
590 		if (!name)
591 			name = conf_def_filename;
592 		sprintf(tmpname, "%s.old", name);
593 		rename(name, tmpname);
594 	}
595 	sprintf(tmpname, "%s%s", dirname, basename);
596 	if (rename(newname, tmpname))
597 		return 1;
598 
599 	sym_change_count = 0;
600 
601 	return 0;
602 }
603