xref: /openbmc/linux/scripts/kconfig/conf.c (revision 97da55fc)
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 <locale.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 #include <getopt.h>
14 #include <sys/stat.h>
15 #include <sys/time.h>
16 
17 #include "lkc.h"
18 
19 static void conf(struct menu *menu);
20 static void check_conf(struct menu *menu);
21 static void xfgets(char *str, int size, FILE *in);
22 
23 enum input_mode {
24 	oldaskconfig,
25 	silentoldconfig,
26 	oldconfig,
27 	allnoconfig,
28 	allyesconfig,
29 	allmodconfig,
30 	alldefconfig,
31 	randconfig,
32 	defconfig,
33 	savedefconfig,
34 	listnewconfig,
35 	olddefconfig,
36 } input_mode = oldaskconfig;
37 
38 static int indent = 1;
39 static int tty_stdio;
40 static int valid_stdin = 1;
41 static int sync_kconfig;
42 static int conf_cnt;
43 static char line[128];
44 static struct menu *rootEntry;
45 
46 static void print_help(struct menu *menu)
47 {
48 	struct gstr help = str_new();
49 
50 	menu_get_ext_help(menu, &help);
51 
52 	printf("\n%s\n", str_get(&help));
53 	str_free(&help);
54 }
55 
56 static void strip(char *str)
57 {
58 	char *p = str;
59 	int l;
60 
61 	while ((isspace(*p)))
62 		p++;
63 	l = strlen(p);
64 	if (p != str)
65 		memmove(str, p, l + 1);
66 	if (!l)
67 		return;
68 	p = str + l - 1;
69 	while ((isspace(*p)))
70 		*p-- = 0;
71 }
72 
73 static void check_stdin(void)
74 {
75 	if (!valid_stdin) {
76 		printf(_("aborted!\n\n"));
77 		printf(_("Console input/output is redirected. "));
78 		printf(_("Run 'make oldconfig' to update configuration.\n\n"));
79 		exit(1);
80 	}
81 }
82 
83 static int conf_askvalue(struct symbol *sym, const char *def)
84 {
85 	enum symbol_type type = sym_get_type(sym);
86 
87 	if (!sym_has_value(sym))
88 		printf(_("(NEW) "));
89 
90 	line[0] = '\n';
91 	line[1] = 0;
92 
93 	if (!sym_is_changable(sym)) {
94 		printf("%s\n", def);
95 		line[0] = '\n';
96 		line[1] = 0;
97 		return 0;
98 	}
99 
100 	switch (input_mode) {
101 	case oldconfig:
102 	case silentoldconfig:
103 		if (sym_has_value(sym)) {
104 			printf("%s\n", def);
105 			return 0;
106 		}
107 		check_stdin();
108 		/* fall through */
109 	case oldaskconfig:
110 		fflush(stdout);
111 		xfgets(line, 128, stdin);
112 		if (!tty_stdio)
113 			printf("\n");
114 		return 1;
115 	default:
116 		break;
117 	}
118 
119 	switch (type) {
120 	case S_INT:
121 	case S_HEX:
122 	case S_STRING:
123 		printf("%s\n", def);
124 		return 1;
125 	default:
126 		;
127 	}
128 	printf("%s", line);
129 	return 1;
130 }
131 
132 static int conf_string(struct menu *menu)
133 {
134 	struct symbol *sym = menu->sym;
135 	const char *def;
136 
137 	while (1) {
138 		printf("%*s%s ", indent - 1, "", _(menu->prompt->text));
139 		printf("(%s) ", sym->name);
140 		def = sym_get_string_value(sym);
141 		if (sym_get_string_value(sym))
142 			printf("[%s] ", def);
143 		if (!conf_askvalue(sym, def))
144 			return 0;
145 		switch (line[0]) {
146 		case '\n':
147 			break;
148 		case '?':
149 			/* print help */
150 			if (line[1] == '\n') {
151 				print_help(menu);
152 				def = NULL;
153 				break;
154 			}
155 			/* fall through */
156 		default:
157 			line[strlen(line)-1] = 0;
158 			def = line;
159 		}
160 		if (def && sym_set_string_value(sym, def))
161 			return 0;
162 	}
163 }
164 
165 static int conf_sym(struct menu *menu)
166 {
167 	struct symbol *sym = menu->sym;
168 	tristate oldval, newval;
169 
170 	while (1) {
171 		printf("%*s%s ", indent - 1, "", _(menu->prompt->text));
172 		if (sym->name)
173 			printf("(%s) ", sym->name);
174 		putchar('[');
175 		oldval = sym_get_tristate_value(sym);
176 		switch (oldval) {
177 		case no:
178 			putchar('N');
179 			break;
180 		case mod:
181 			putchar('M');
182 			break;
183 		case yes:
184 			putchar('Y');
185 			break;
186 		}
187 		if (oldval != no && sym_tristate_within_range(sym, no))
188 			printf("/n");
189 		if (oldval != mod && sym_tristate_within_range(sym, mod))
190 			printf("/m");
191 		if (oldval != yes && sym_tristate_within_range(sym, yes))
192 			printf("/y");
193 		if (menu_has_help(menu))
194 			printf("/?");
195 		printf("] ");
196 		if (!conf_askvalue(sym, sym_get_string_value(sym)))
197 			return 0;
198 		strip(line);
199 
200 		switch (line[0]) {
201 		case 'n':
202 		case 'N':
203 			newval = no;
204 			if (!line[1] || !strcmp(&line[1], "o"))
205 				break;
206 			continue;
207 		case 'm':
208 		case 'M':
209 			newval = mod;
210 			if (!line[1])
211 				break;
212 			continue;
213 		case 'y':
214 		case 'Y':
215 			newval = yes;
216 			if (!line[1] || !strcmp(&line[1], "es"))
217 				break;
218 			continue;
219 		case 0:
220 			newval = oldval;
221 			break;
222 		case '?':
223 			goto help;
224 		default:
225 			continue;
226 		}
227 		if (sym_set_tristate_value(sym, newval))
228 			return 0;
229 help:
230 		print_help(menu);
231 	}
232 }
233 
234 static int conf_choice(struct menu *menu)
235 {
236 	struct symbol *sym, *def_sym;
237 	struct menu *child;
238 	bool is_new;
239 
240 	sym = menu->sym;
241 	is_new = !sym_has_value(sym);
242 	if (sym_is_changable(sym)) {
243 		conf_sym(menu);
244 		sym_calc_value(sym);
245 		switch (sym_get_tristate_value(sym)) {
246 		case no:
247 			return 1;
248 		case mod:
249 			return 0;
250 		case yes:
251 			break;
252 		}
253 	} else {
254 		switch (sym_get_tristate_value(sym)) {
255 		case no:
256 			return 1;
257 		case mod:
258 			printf("%*s%s\n", indent - 1, "", _(menu_get_prompt(menu)));
259 			return 0;
260 		case yes:
261 			break;
262 		}
263 	}
264 
265 	while (1) {
266 		int cnt, def;
267 
268 		printf("%*s%s\n", indent - 1, "", _(menu_get_prompt(menu)));
269 		def_sym = sym_get_choice_value(sym);
270 		cnt = def = 0;
271 		line[0] = 0;
272 		for (child = menu->list; child; child = child->next) {
273 			if (!menu_is_visible(child))
274 				continue;
275 			if (!child->sym) {
276 				printf("%*c %s\n", indent, '*', _(menu_get_prompt(child)));
277 				continue;
278 			}
279 			cnt++;
280 			if (child->sym == def_sym) {
281 				def = cnt;
282 				printf("%*c", indent, '>');
283 			} else
284 				printf("%*c", indent, ' ');
285 			printf(" %d. %s", cnt, _(menu_get_prompt(child)));
286 			if (child->sym->name)
287 				printf(" (%s)", child->sym->name);
288 			if (!sym_has_value(child->sym))
289 				printf(_(" (NEW)"));
290 			printf("\n");
291 		}
292 		printf(_("%*schoice"), indent - 1, "");
293 		if (cnt == 1) {
294 			printf("[1]: 1\n");
295 			goto conf_childs;
296 		}
297 		printf("[1-%d", cnt);
298 		if (menu_has_help(menu))
299 			printf("?");
300 		printf("]: ");
301 		switch (input_mode) {
302 		case oldconfig:
303 		case silentoldconfig:
304 			if (!is_new) {
305 				cnt = def;
306 				printf("%d\n", cnt);
307 				break;
308 			}
309 			check_stdin();
310 			/* fall through */
311 		case oldaskconfig:
312 			fflush(stdout);
313 			xfgets(line, 128, stdin);
314 			strip(line);
315 			if (line[0] == '?') {
316 				print_help(menu);
317 				continue;
318 			}
319 			if (!line[0])
320 				cnt = def;
321 			else if (isdigit(line[0]))
322 				cnt = atoi(line);
323 			else
324 				continue;
325 			break;
326 		default:
327 			break;
328 		}
329 
330 	conf_childs:
331 		for (child = menu->list; child; child = child->next) {
332 			if (!child->sym || !menu_is_visible(child))
333 				continue;
334 			if (!--cnt)
335 				break;
336 		}
337 		if (!child)
338 			continue;
339 		if (line[0] && line[strlen(line) - 1] == '?') {
340 			print_help(child);
341 			continue;
342 		}
343 		sym_set_choice_value(sym, child->sym);
344 		for (child = child->list; child; child = child->next) {
345 			indent += 2;
346 			conf(child);
347 			indent -= 2;
348 		}
349 		return 1;
350 	}
351 }
352 
353 static void conf(struct menu *menu)
354 {
355 	struct symbol *sym;
356 	struct property *prop;
357 	struct menu *child;
358 
359 	if (!menu_is_visible(menu))
360 		return;
361 
362 	sym = menu->sym;
363 	prop = menu->prompt;
364 	if (prop) {
365 		const char *prompt;
366 
367 		switch (prop->type) {
368 		case P_MENU:
369 			if ((input_mode == silentoldconfig ||
370 			     input_mode == listnewconfig ||
371 			     input_mode == olddefconfig) &&
372 			    rootEntry != menu) {
373 				check_conf(menu);
374 				return;
375 			}
376 			/* fall through */
377 		case P_COMMENT:
378 			prompt = menu_get_prompt(menu);
379 			if (prompt)
380 				printf("%*c\n%*c %s\n%*c\n",
381 					indent, '*',
382 					indent, '*', _(prompt),
383 					indent, '*');
384 		default:
385 			;
386 		}
387 	}
388 
389 	if (!sym)
390 		goto conf_childs;
391 
392 	if (sym_is_choice(sym)) {
393 		conf_choice(menu);
394 		if (sym->curr.tri != mod)
395 			return;
396 		goto conf_childs;
397 	}
398 
399 	switch (sym->type) {
400 	case S_INT:
401 	case S_HEX:
402 	case S_STRING:
403 		conf_string(menu);
404 		break;
405 	default:
406 		conf_sym(menu);
407 		break;
408 	}
409 
410 conf_childs:
411 	if (sym)
412 		indent += 2;
413 	for (child = menu->list; child; child = child->next)
414 		conf(child);
415 	if (sym)
416 		indent -= 2;
417 }
418 
419 static void check_conf(struct menu *menu)
420 {
421 	struct symbol *sym;
422 	struct menu *child;
423 
424 	if (!menu_is_visible(menu))
425 		return;
426 
427 	sym = menu->sym;
428 	if (sym && !sym_has_value(sym)) {
429 		if (sym_is_changable(sym) ||
430 		    (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)) {
431 			if (input_mode == listnewconfig) {
432 				if (sym->name && !sym_is_choice_value(sym)) {
433 					printf("%s%s\n", CONFIG_, sym->name);
434 				}
435 			} else if (input_mode != olddefconfig) {
436 				if (!conf_cnt++)
437 					printf(_("*\n* Restart config...\n*\n"));
438 				rootEntry = menu_get_parent_menu(menu);
439 				conf(rootEntry);
440 			}
441 		}
442 	}
443 
444 	for (child = menu->list; child; child = child->next)
445 		check_conf(child);
446 }
447 
448 static struct option long_opts[] = {
449 	{"oldaskconfig",    no_argument,       NULL, oldaskconfig},
450 	{"oldconfig",       no_argument,       NULL, oldconfig},
451 	{"silentoldconfig", no_argument,       NULL, silentoldconfig},
452 	{"defconfig",       optional_argument, NULL, defconfig},
453 	{"savedefconfig",   required_argument, NULL, savedefconfig},
454 	{"allnoconfig",     no_argument,       NULL, allnoconfig},
455 	{"allyesconfig",    no_argument,       NULL, allyesconfig},
456 	{"allmodconfig",    no_argument,       NULL, allmodconfig},
457 	{"alldefconfig",    no_argument,       NULL, alldefconfig},
458 	{"randconfig",      no_argument,       NULL, randconfig},
459 	{"listnewconfig",   no_argument,       NULL, listnewconfig},
460 	{"olddefconfig",    no_argument,       NULL, olddefconfig},
461 	/*
462 	 * oldnoconfig is an alias of olddefconfig, because people already
463 	 * are dependent on its behavior(sets new symbols to their default
464 	 * value but not 'n') with the counter-intuitive name.
465 	 */
466 	{"oldnoconfig",     no_argument,       NULL, olddefconfig},
467 	{NULL, 0, NULL, 0}
468 };
469 
470 static void conf_usage(const char *progname)
471 {
472 
473 	printf("Usage: %s [option] <kconfig-file>\n", progname);
474 	printf("[option] is _one_ of the following:\n");
475 	printf("  --listnewconfig         List new options\n");
476 	printf("  --oldaskconfig          Start a new configuration using a line-oriented program\n");
477 	printf("  --oldconfig             Update a configuration using a provided .config as base\n");
478 	printf("  --silentoldconfig       Same as oldconfig, but quietly, additionally update deps\n");
479 	printf("  --olddefconfig          Same as silentoldconfig but sets new symbols to their default value\n");
480 	printf("  --oldnoconfig           An alias of olddefconfig\n");
481 	printf("  --defconfig <file>      New config with default defined in <file>\n");
482 	printf("  --savedefconfig <file>  Save the minimal current configuration to <file>\n");
483 	printf("  --allnoconfig           New config where all options are answered with no\n");
484 	printf("  --allyesconfig          New config where all options are answered with yes\n");
485 	printf("  --allmodconfig          New config where all options are answered with mod\n");
486 	printf("  --alldefconfig          New config with all symbols set to default\n");
487 	printf("  --randconfig            New config with random answer to all options\n");
488 }
489 
490 int main(int ac, char **av)
491 {
492 	const char *progname = av[0];
493 	int opt;
494 	const char *name, *defconfig_file = NULL /* gcc uninit */;
495 	struct stat tmpstat;
496 
497 	setlocale(LC_ALL, "");
498 	bindtextdomain(PACKAGE, LOCALEDIR);
499 	textdomain(PACKAGE);
500 
501 	tty_stdio = isatty(0) && isatty(1) && isatty(2);
502 
503 	while ((opt = getopt_long(ac, av, "", long_opts, NULL)) != -1) {
504 		input_mode = (enum input_mode)opt;
505 		switch (opt) {
506 		case silentoldconfig:
507 			sync_kconfig = 1;
508 			break;
509 		case defconfig:
510 		case savedefconfig:
511 			defconfig_file = optarg;
512 			break;
513 		case randconfig:
514 		{
515 			struct timeval now;
516 			unsigned int seed;
517 
518 			/*
519 			 * Use microseconds derived seed,
520 			 * compensate for systems where it may be zero
521 			 */
522 			gettimeofday(&now, NULL);
523 
524 			seed = (unsigned int)((now.tv_sec + 1) * (now.tv_usec + 1));
525 			srand(seed);
526 			break;
527 		}
528 		case oldaskconfig:
529 		case oldconfig:
530 		case allnoconfig:
531 		case allyesconfig:
532 		case allmodconfig:
533 		case alldefconfig:
534 		case listnewconfig:
535 		case olddefconfig:
536 			break;
537 		case '?':
538 			conf_usage(progname);
539 			exit(1);
540 			break;
541 		}
542 	}
543 	if (ac == optind) {
544 		printf(_("%s: Kconfig file missing\n"), av[0]);
545 		conf_usage(progname);
546 		exit(1);
547 	}
548 	name = av[optind];
549 	conf_parse(name);
550 	//zconfdump(stdout);
551 	if (sync_kconfig) {
552 		name = conf_get_configname();
553 		if (stat(name, &tmpstat)) {
554 			fprintf(stderr, _("***\n"
555 				"*** Configuration file \"%s\" not found!\n"
556 				"***\n"
557 				"*** Please run some configurator (e.g. \"make oldconfig\" or\n"
558 				"*** \"make menuconfig\" or \"make xconfig\").\n"
559 				"***\n"), name);
560 			exit(1);
561 		}
562 	}
563 
564 	switch (input_mode) {
565 	case defconfig:
566 		if (!defconfig_file)
567 			defconfig_file = conf_get_default_confname();
568 		if (conf_read(defconfig_file)) {
569 			printf(_("***\n"
570 				"*** Can't find default configuration \"%s\"!\n"
571 				"***\n"), defconfig_file);
572 			exit(1);
573 		}
574 		break;
575 	case savedefconfig:
576 	case silentoldconfig:
577 	case oldaskconfig:
578 	case oldconfig:
579 	case listnewconfig:
580 	case olddefconfig:
581 		conf_read(NULL);
582 		break;
583 	case allnoconfig:
584 	case allyesconfig:
585 	case allmodconfig:
586 	case alldefconfig:
587 	case randconfig:
588 		name = getenv("KCONFIG_ALLCONFIG");
589 		if (!name)
590 			break;
591 		if ((strcmp(name, "") != 0) && (strcmp(name, "1") != 0)) {
592 			if (conf_read_simple(name, S_DEF_USER)) {
593 				fprintf(stderr,
594 					_("*** Can't read seed configuration \"%s\"!\n"),
595 					name);
596 				exit(1);
597 			}
598 			break;
599 		}
600 		switch (input_mode) {
601 		case allnoconfig:	name = "allno.config"; break;
602 		case allyesconfig:	name = "allyes.config"; break;
603 		case allmodconfig:	name = "allmod.config"; break;
604 		case alldefconfig:	name = "alldef.config"; break;
605 		case randconfig:	name = "allrandom.config"; break;
606 		default: break;
607 		}
608 		if (conf_read_simple(name, S_DEF_USER) &&
609 		    conf_read_simple("all.config", S_DEF_USER)) {
610 			fprintf(stderr,
611 				_("*** KCONFIG_ALLCONFIG set, but no \"%s\" or \"all.config\" file found\n"),
612 				name);
613 			exit(1);
614 		}
615 		break;
616 	default:
617 		break;
618 	}
619 
620 	if (sync_kconfig) {
621 		if (conf_get_changed()) {
622 			name = getenv("KCONFIG_NOSILENTUPDATE");
623 			if (name && *name) {
624 				fprintf(stderr,
625 					_("\n*** The configuration requires explicit update.\n\n"));
626 				return 1;
627 			}
628 		}
629 		valid_stdin = tty_stdio;
630 	}
631 
632 	switch (input_mode) {
633 	case allnoconfig:
634 		conf_set_all_new_symbols(def_no);
635 		break;
636 	case allyesconfig:
637 		conf_set_all_new_symbols(def_yes);
638 		break;
639 	case allmodconfig:
640 		conf_set_all_new_symbols(def_mod);
641 		break;
642 	case alldefconfig:
643 		conf_set_all_new_symbols(def_default);
644 		break;
645 	case randconfig:
646 		conf_set_all_new_symbols(def_random);
647 		break;
648 	case defconfig:
649 		conf_set_all_new_symbols(def_default);
650 		break;
651 	case savedefconfig:
652 		break;
653 	case oldaskconfig:
654 		rootEntry = &rootmenu;
655 		conf(&rootmenu);
656 		input_mode = silentoldconfig;
657 		/* fall through */
658 	case oldconfig:
659 	case listnewconfig:
660 	case olddefconfig:
661 	case silentoldconfig:
662 		/* Update until a loop caused no more changes */
663 		do {
664 			conf_cnt = 0;
665 			check_conf(&rootmenu);
666 		} while (conf_cnt &&
667 			 (input_mode != listnewconfig &&
668 			  input_mode != olddefconfig));
669 		break;
670 	}
671 
672 	if (sync_kconfig) {
673 		/* silentoldconfig is used during the build so we shall update autoconf.
674 		 * All other commands are only used to generate a config.
675 		 */
676 		if (conf_get_changed() && conf_write(NULL)) {
677 			fprintf(stderr, _("\n*** Error during writing of the configuration.\n\n"));
678 			exit(1);
679 		}
680 		if (conf_write_autoconf()) {
681 			fprintf(stderr, _("\n*** Error during update of the configuration.\n\n"));
682 			return 1;
683 		}
684 	} else if (input_mode == savedefconfig) {
685 		if (conf_write_defconfig(defconfig_file)) {
686 			fprintf(stderr, _("n*** Error while saving defconfig to: %s\n\n"),
687 			        defconfig_file);
688 			return 1;
689 		}
690 	} else if (input_mode != listnewconfig) {
691 		if (conf_write(NULL)) {
692 			fprintf(stderr, _("\n*** Error during writing of the configuration.\n\n"));
693 			exit(1);
694 		}
695 	}
696 	return 0;
697 }
698 
699 /*
700  * Helper function to facilitate fgets() by Jean Sacren.
701  */
702 void xfgets(char *str, int size, FILE *in)
703 {
704 	if (fgets(str, size, in) == NULL)
705 		fprintf(stderr, "\nError in reading or end of file.\n");
706 }
707