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(*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], tmpname[128], newname[128];
338 	int type, l;
339 	const char *str;
340 	time_t now;
341 	int use_timestamp = 1;
342 	char *env;
343 
344 	dirname[0] = 0;
345 	if (name && name[0]) {
346 		struct stat st;
347 		char *slash;
348 
349 		if (!stat(name, &st) && S_ISDIR(st.st_mode)) {
350 			strcpy(dirname, name);
351 			strcat(dirname, "/");
352 			basename = conf_def_filename;
353 		} else if ((slash = strrchr(name, '/'))) {
354 			int size = slash - name + 1;
355 			memcpy(dirname, name, size);
356 			dirname[size] = 0;
357 			if (slash[1])
358 				basename = slash + 1;
359 			else
360 				basename = conf_def_filename;
361 		} else
362 			basename = name;
363 	} else
364 		basename = conf_def_filename;
365 
366 	sprintf(newname, "%s.tmpconfig.%d", dirname, (int)getpid());
367 	out = fopen(newname, "w");
368 	if (!out)
369 		return 1;
370 	out_h = NULL;
371 	if (!name) {
372 		out_h = fopen(".tmpconfig.h", "w");
373 		if (!out_h)
374 			return 1;
375 		file_write_dep(NULL);
376 	}
377 	sym = sym_lookup("KERNELVERSION", 0);
378 	sym_calc_value(sym);
379 	time(&now);
380 	env = getenv("KCONFIG_NOTIMESTAMP");
381 	if (env && *env)
382 		use_timestamp = 0;
383 
384 	fprintf(out, _("#\n"
385 		       "# Automatically generated make config: don't edit\n"
386 		       "# Busybox version: %s\n"
387 		       "%s%s"
388 		       "#\n"),
389 		     sym_get_string_value(sym),
390 		     use_timestamp ? "# " : "",
391 		     use_timestamp ? ctime(&now) : "");
392 	if (out_h) {
393 		char buf[sizeof("#define AUTOCONF_TIMESTAMP "
394 				"\"YYYY-MM-DD HH:MM:SS some_timezone\"\n")];
395 		buf[0] = '\0';
396 		if (use_timestamp) {
397 			size_t ret = \
398 				strftime(buf, sizeof(buf), "#define AUTOCONF_TIMESTAMP "
399 					"\"%Y-%m-%d %H:%M:%S %Z\"\n", localtime(&now));
400 			/* if user has Factory timezone or some other odd install, the
401 			 * %Z above will overflow the string leaving us with undefined
402 			 * results ... so let's try again without the timezone.
403 			 */
404 			if (ret == 0)
405 				strftime(buf, sizeof(buf), "#define AUTOCONF_TIMESTAMP "
406 					"\"%Y-%m-%d %H:%M:%S\"\n", localtime(&now));
407 		} else { /* bbox */
408 			strcpy(buf, "#define AUTOCONF_TIMESTAMP \"\"\n");
409 		}
410 		fprintf(out_h, "/*\n"
411 			       " * Automatically generated C config: don't edit\n"
412 			       " * Busybox version: %s\n"
413 			       " */\n"
414 			       "%s"
415 			       "\n",
416 			       sym_get_string_value(sym),
417 			       buf);
418 	}
419 	if (!sym_change_count)
420 		sym_clear_all_valid();
421 
422 	menu = rootmenu.list;
423 	while (menu) {
424 		sym = menu->sym;
425 		if (!sym) {
426 			if (!menu_is_visible(menu))
427 				goto next;
428 			str = menu_get_prompt(menu);
429 			fprintf(out, "\n"
430 				     "#\n"
431 				     "# %s\n"
432 				     "#\n", str);
433 			if (out_h)
434 				fprintf(out_h, "\n"
435 					       "/*\n"
436 					       " * %s\n"
437 					       " */\n", str);
438 		} else if (!(sym->flags & SYMBOL_CHOICE)) {
439 			sym_calc_value(sym);
440 /* bbox: we want to see all syms
441 			if (!(sym->flags & SYMBOL_WRITE))
442 				goto next;
443 */
444 			sym->flags &= ~SYMBOL_WRITE;
445 			type = sym->type;
446 			if (type == S_TRISTATE) {
447 				sym_calc_value(modules_sym);
448 				if (modules_sym->curr.tri == no)
449 					type = S_BOOLEAN;
450 			}
451 			switch (type) {
452 			case S_BOOLEAN:
453 			case S_TRISTATE:
454 				switch (sym_get_tristate_value(sym)) {
455 				case no:
456 					fprintf(out, "# CONFIG_%s is not set\n", sym->name);
457 					if (out_h) {
458 						fprintf(out_h, "#undef CONFIG_%s\n", sym->name);
459 						/* bbox */
460 						fprintf(out_h, "#define ENABLE_%s 0\n", sym->name);
461 						fprintf(out_h, "#define IF_%s(...)\n", sym->name);
462 						fprintf(out_h, "#define IF_NOT_%s(...) __VA_ARGS__\n", sym->name);
463 					}
464 					break;
465 				case mod:
466 					fprintf(out, "CONFIG_%s=m\n", sym->name);
467 					if (out_h)
468 						fprintf(out_h, "#define CONFIG_%s_MODULE 1\n", sym->name);
469 					break;
470 				case yes:
471 					fprintf(out, "CONFIG_%s=y\n", sym->name);
472 					if (out_h) {
473 						fprintf(out_h, "#define CONFIG_%s 1\n", sym->name);
474 						/* bbox */
475 						fprintf(out_h, "#define ENABLE_%s 1\n", sym->name);
476 						fprintf(out_h, "#ifdef MAKE_SUID\n");
477 						fprintf(out_h, "# define IF_%s(...) __VA_ARGS__ \"CONFIG_%s\"\n", sym->name, sym->name);
478 						fprintf(out_h, "#else\n");
479 						fprintf(out_h, "# define IF_%s(...) __VA_ARGS__\n", sym->name);
480 						fprintf(out_h, "#endif\n");
481 						fprintf(out_h, "#define IF_NOT_%s(...)\n", sym->name);
482 					}
483 					break;
484 				}
485 				break;
486 			case S_STRING:
487 				// fix me
488 				str = sym_get_string_value(sym);
489 				fprintf(out, "CONFIG_%s=\"", sym->name);
490 				if (out_h)
491 					fprintf(out_h, "#define CONFIG_%s \"", sym->name);
492 				do {
493 					l = strcspn(str, "\"\\");
494 					if (l) {
495 						fwrite(str, l, 1, out);
496 						if (out_h)
497 							fwrite(str, l, 1, out_h);
498 					}
499 					str += l;
500 					while (*str == '\\' || *str == '"') {
501 						fprintf(out, "\\%c", *str);
502 						if (out_h)
503 							fprintf(out_h, "\\%c", *str);
504 						str++;
505 					}
506 				} while (*str);
507 				fputs("\"\n", out);
508 				if (out_h) {
509 					fputs("\"\n", out_h);
510 					/* bbox */
511 					fprintf(out_h, "#define ENABLE_%s 1\n", sym->name);
512 					fprintf(out_h, "#ifdef MAKE_SUID\n");
513 					fprintf(out_h, "# define IF_%s(...) __VA_ARGS__ \"CONFIG_%s\"\n", sym->name, sym->name);
514 					fprintf(out_h, "#else\n");
515 					fprintf(out_h, "# define IF_%s(...) __VA_ARGS__\n", sym->name);
516 					fprintf(out_h, "#endif\n");
517 					fprintf(out_h, "#define IF_NOT_%s(...)\n", sym->name);
518 				}
519 				break;
520 			case S_HEX:
521 				str = sym_get_string_value(sym);
522 				if (str[0] != '0' || (str[1] != 'x' && str[1] != 'X')) {
523 					fprintf(out, "CONFIG_%s=%s\n", sym->name, str);
524 					if (out_h) {
525 						fprintf(out_h, "#define CONFIG_%s 0x%s\n", sym->name, str);
526 						/* bbox */
527 						fprintf(out_h, "#define ENABLE_%s 1\n", sym->name);
528 						fprintf(out_h, "#ifdef MAKE_SUID\n");
529 						fprintf(out_h, "# define IF_%s(...) __VA_ARGS__ \"CONFIG_%s\"\n", sym->name, sym->name);
530 						fprintf(out_h, "#else\n");
531 						fprintf(out_h, "# define IF_%s(...) __VA_ARGS__\n", sym->name);
532 						fprintf(out_h, "#endif\n");
533 						fprintf(out_h, "#define IF_NOT_%s(...)\n", sym->name);
534 					}
535 					break;
536 				}
537 			case S_INT:
538 				str = sym_get_string_value(sym);
539 				if (!str[0])
540 					str = "0";
541 				fprintf(out, "CONFIG_%s=%s\n", sym->name, str);
542 				if (out_h) {
543 					fprintf(out_h, "#define CONFIG_%s %s\n", sym->name, str);
544 					/* bbox */
545 					fprintf(out_h, "#define ENABLE_%s 1\n", sym->name);
546 					fprintf(out_h, "#ifdef MAKE_SUID\n");
547 					fprintf(out_h, "# define IF_%s(...) __VA_ARGS__ \"CONFIG_%s\"\n", sym->name, sym->name);
548 					fprintf(out_h, "#else\n");
549 					fprintf(out_h, "# define IF_%s(...) __VA_ARGS__\n", sym->name);
550 					fprintf(out_h, "#endif\n");
551 					fprintf(out_h, "#define IF_NOT_%s(...)\n", sym->name);
552 				}
553 				break;
554 			}
555 		}
556 
557 	next:
558 		if (menu->list) {
559 			menu = menu->list;
560 			continue;
561 		}
562 		if (menu->next)
563 			menu = menu->next;
564 		else while ((menu = menu->parent)) {
565 			if (menu->next) {
566 				menu = menu->next;
567 				break;
568 			}
569 		}
570 	}
571 	fclose(out);
572 	if (out_h) {
573 		fclose(out_h);
574 		rename(".tmpconfig.h", "include/autoconf.h");
575 	}
576 	if (!name || basename != conf_def_filename) {
577 		if (!name)
578 			name = conf_def_filename;
579 		sprintf(tmpname, "%s.old", name);
580 		rename(name, tmpname);
581 	}
582 	sprintf(tmpname, "%s%s", dirname, basename);
583 	if (rename(newname, tmpname))
584 		return 1;
585 
586 	sym_change_count = 0;
587 
588 	return 0;
589 }
590