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