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