mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-22 20:23:57 +08:00
cd9140e1e7
Previously when running "make oldconfig" we saw all the propmt lines from kconfig and noone actully read this. With this patch the user will only see output if there is new symbols. This will be seen as "make oldconfig" runs which does not generate any output. A typical run now looks like this: $ make oldconfig scripts/kconfig/conf -o arch/x86/Kconfig $ If a new symbol is found then we restart the config process like this: $ make oldconfig scripts/kconfig/conf -o arch/x86/Kconfig * * Restart config... * * * General setup * Prompt for development and/or incomplete code/drivers (EXPERIMENTAL) [Y/n/?] y Local version - append to kernel release (LOCALVERSION) [] ... The bahaviour is similar to what we know when running the implicit oldconfig target "make silentoldconfig". "make silentoldconfig" are run as part of the kernel build process if the configuration has changed. Signed-off-by: Sam Ravnborg <sam@ravnborg.org> Cc: Roman Zippel <zippel@linux-m68k.org>
617 lines
12 KiB
C
617 lines
12 KiB
C
/*
|
|
* Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
|
|
* Released under the terms of the GNU GPL v2.0.
|
|
*/
|
|
|
|
#include <locale.h>
|
|
#include <ctype.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
#include <unistd.h>
|
|
#include <sys/stat.h>
|
|
|
|
#define LKC_DIRECT_LINK
|
|
#include "lkc.h"
|
|
|
|
static void conf(struct menu *menu);
|
|
static void check_conf(struct menu *menu);
|
|
|
|
enum {
|
|
ask_all,
|
|
ask_new,
|
|
ask_silent,
|
|
set_default,
|
|
set_yes,
|
|
set_mod,
|
|
set_no,
|
|
set_random
|
|
} input_mode = ask_all;
|
|
char *defconfig_file;
|
|
|
|
static int indent = 1;
|
|
static int valid_stdin = 1;
|
|
static int conf_cnt;
|
|
static char line[128];
|
|
static struct menu *rootEntry;
|
|
|
|
static char nohelp_text[] = N_("Sorry, no help available for this option yet.\n");
|
|
|
|
static const char *get_help(struct menu *menu)
|
|
{
|
|
if (menu_has_help(menu))
|
|
return _(menu_get_help(menu));
|
|
else
|
|
return nohelp_text;
|
|
}
|
|
|
|
static void strip(char *str)
|
|
{
|
|
char *p = str;
|
|
int l;
|
|
|
|
while ((isspace(*p)))
|
|
p++;
|
|
l = strlen(p);
|
|
if (p != str)
|
|
memmove(str, p, l + 1);
|
|
if (!l)
|
|
return;
|
|
p = str + l - 1;
|
|
while ((isspace(*p)))
|
|
*p-- = 0;
|
|
}
|
|
|
|
static void check_stdin(void)
|
|
{
|
|
if (!valid_stdin && input_mode == ask_silent) {
|
|
printf(_("aborted!\n\n"));
|
|
printf(_("Console input/output is redirected. "));
|
|
printf(_("Run 'make oldconfig' to update configuration.\n\n"));
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
static int conf_askvalue(struct symbol *sym, const char *def)
|
|
{
|
|
enum symbol_type type = sym_get_type(sym);
|
|
|
|
if (!sym_has_value(sym))
|
|
printf(_("(NEW) "));
|
|
|
|
line[0] = '\n';
|
|
line[1] = 0;
|
|
|
|
if (!sym_is_changable(sym)) {
|
|
printf("%s\n", def);
|
|
line[0] = '\n';
|
|
line[1] = 0;
|
|
return 0;
|
|
}
|
|
|
|
switch (input_mode) {
|
|
case ask_new:
|
|
case ask_silent:
|
|
if (sym_has_value(sym)) {
|
|
printf("%s\n", def);
|
|
return 0;
|
|
}
|
|
check_stdin();
|
|
case ask_all:
|
|
fflush(stdout);
|
|
fgets(line, 128, stdin);
|
|
return 1;
|
|
case set_default:
|
|
printf("%s\n", def);
|
|
return 1;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
switch (type) {
|
|
case S_INT:
|
|
case S_HEX:
|
|
case S_STRING:
|
|
printf("%s\n", def);
|
|
return 1;
|
|
default:
|
|
;
|
|
}
|
|
printf("%s", line);
|
|
return 1;
|
|
}
|
|
|
|
int conf_string(struct menu *menu)
|
|
{
|
|
struct symbol *sym = menu->sym;
|
|
const char *def;
|
|
|
|
while (1) {
|
|
printf("%*s%s ", indent - 1, "", _(menu->prompt->text));
|
|
printf("(%s) ", sym->name);
|
|
def = sym_get_string_value(sym);
|
|
if (sym_get_string_value(sym))
|
|
printf("[%s] ", def);
|
|
if (!conf_askvalue(sym, def))
|
|
return 0;
|
|
switch (line[0]) {
|
|
case '\n':
|
|
break;
|
|
case '?':
|
|
/* print help */
|
|
if (line[1] == '\n') {
|
|
printf("\n%s\n", get_help(menu));
|
|
def = NULL;
|
|
break;
|
|
}
|
|
default:
|
|
line[strlen(line)-1] = 0;
|
|
def = line;
|
|
}
|
|
if (def && sym_set_string_value(sym, def))
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static int conf_sym(struct menu *menu)
|
|
{
|
|
struct symbol *sym = menu->sym;
|
|
int type;
|
|
tristate oldval, newval;
|
|
|
|
while (1) {
|
|
printf("%*s%s ", indent - 1, "", _(menu->prompt->text));
|
|
if (sym->name)
|
|
printf("(%s) ", sym->name);
|
|
type = sym_get_type(sym);
|
|
putchar('[');
|
|
oldval = sym_get_tristate_value(sym);
|
|
switch (oldval) {
|
|
case no:
|
|
putchar('N');
|
|
break;
|
|
case mod:
|
|
putchar('M');
|
|
break;
|
|
case yes:
|
|
putchar('Y');
|
|
break;
|
|
}
|
|
if (oldval != no && sym_tristate_within_range(sym, no))
|
|
printf("/n");
|
|
if (oldval != mod && sym_tristate_within_range(sym, mod))
|
|
printf("/m");
|
|
if (oldval != yes && sym_tristate_within_range(sym, yes))
|
|
printf("/y");
|
|
if (menu_has_help(menu))
|
|
printf("/?");
|
|
printf("] ");
|
|
if (!conf_askvalue(sym, sym_get_string_value(sym)))
|
|
return 0;
|
|
strip(line);
|
|
|
|
switch (line[0]) {
|
|
case 'n':
|
|
case 'N':
|
|
newval = no;
|
|
if (!line[1] || !strcmp(&line[1], "o"))
|
|
break;
|
|
continue;
|
|
case 'm':
|
|
case 'M':
|
|
newval = mod;
|
|
if (!line[1])
|
|
break;
|
|
continue;
|
|
case 'y':
|
|
case 'Y':
|
|
newval = yes;
|
|
if (!line[1] || !strcmp(&line[1], "es"))
|
|
break;
|
|
continue;
|
|
case 0:
|
|
newval = oldval;
|
|
break;
|
|
case '?':
|
|
goto help;
|
|
default:
|
|
continue;
|
|
}
|
|
if (sym_set_tristate_value(sym, newval))
|
|
return 0;
|
|
help:
|
|
printf("\n%s\n", get_help(menu));
|
|
}
|
|
}
|
|
|
|
static int conf_choice(struct menu *menu)
|
|
{
|
|
struct symbol *sym, *def_sym;
|
|
struct menu *child;
|
|
int type;
|
|
bool is_new;
|
|
|
|
sym = menu->sym;
|
|
type = sym_get_type(sym);
|
|
is_new = !sym_has_value(sym);
|
|
if (sym_is_changable(sym)) {
|
|
conf_sym(menu);
|
|
sym_calc_value(sym);
|
|
switch (sym_get_tristate_value(sym)) {
|
|
case no:
|
|
return 1;
|
|
case mod:
|
|
return 0;
|
|
case yes:
|
|
break;
|
|
}
|
|
} else {
|
|
switch (sym_get_tristate_value(sym)) {
|
|
case no:
|
|
return 1;
|
|
case mod:
|
|
printf("%*s%s\n", indent - 1, "", _(menu_get_prompt(menu)));
|
|
return 0;
|
|
case yes:
|
|
break;
|
|
}
|
|
}
|
|
|
|
while (1) {
|
|
int cnt, def;
|
|
|
|
printf("%*s%s\n", indent - 1, "", _(menu_get_prompt(menu)));
|
|
def_sym = sym_get_choice_value(sym);
|
|
cnt = def = 0;
|
|
line[0] = 0;
|
|
for (child = menu->list; child; child = child->next) {
|
|
if (!menu_is_visible(child))
|
|
continue;
|
|
if (!child->sym) {
|
|
printf("%*c %s\n", indent, '*', _(menu_get_prompt(child)));
|
|
continue;
|
|
}
|
|
cnt++;
|
|
if (child->sym == def_sym) {
|
|
def = cnt;
|
|
printf("%*c", indent, '>');
|
|
} else
|
|
printf("%*c", indent, ' ');
|
|
printf(" %d. %s", cnt, _(menu_get_prompt(child)));
|
|
if (child->sym->name)
|
|
printf(" (%s)", child->sym->name);
|
|
if (!sym_has_value(child->sym))
|
|
printf(_(" (NEW)"));
|
|
printf("\n");
|
|
}
|
|
printf(_("%*schoice"), indent - 1, "");
|
|
if (cnt == 1) {
|
|
printf("[1]: 1\n");
|
|
goto conf_childs;
|
|
}
|
|
printf("[1-%d", cnt);
|
|
if (menu_has_help(menu))
|
|
printf("?");
|
|
printf("]: ");
|
|
switch (input_mode) {
|
|
case ask_new:
|
|
case ask_silent:
|
|
if (!is_new) {
|
|
cnt = def;
|
|
printf("%d\n", cnt);
|
|
break;
|
|
}
|
|
check_stdin();
|
|
case ask_all:
|
|
fflush(stdout);
|
|
fgets(line, 128, stdin);
|
|
strip(line);
|
|
if (line[0] == '?') {
|
|
printf("\n%s\n", get_help(menu));
|
|
continue;
|
|
}
|
|
if (!line[0])
|
|
cnt = def;
|
|
else if (isdigit(line[0]))
|
|
cnt = atoi(line);
|
|
else
|
|
continue;
|
|
break;
|
|
case set_default:
|
|
cnt = def;
|
|
printf("%d\n", cnt);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
conf_childs:
|
|
for (child = menu->list; child; child = child->next) {
|
|
if (!child->sym || !menu_is_visible(child))
|
|
continue;
|
|
if (!--cnt)
|
|
break;
|
|
}
|
|
if (!child)
|
|
continue;
|
|
if (line[strlen(line) - 1] == '?') {
|
|
printf("\n%s\n", get_help(child));
|
|
continue;
|
|
}
|
|
sym_set_choice_value(sym, child->sym);
|
|
for (child = child->list; child; child = child->next) {
|
|
indent += 2;
|
|
conf(child);
|
|
indent -= 2;
|
|
}
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
static void conf(struct menu *menu)
|
|
{
|
|
struct symbol *sym;
|
|
struct property *prop;
|
|
struct menu *child;
|
|
|
|
if (!menu_is_visible(menu))
|
|
return;
|
|
|
|
sym = menu->sym;
|
|
prop = menu->prompt;
|
|
if (prop) {
|
|
const char *prompt;
|
|
|
|
switch (prop->type) {
|
|
case P_MENU:
|
|
if (input_mode == ask_silent && rootEntry != menu) {
|
|
check_conf(menu);
|
|
return;
|
|
}
|
|
case P_COMMENT:
|
|
prompt = menu_get_prompt(menu);
|
|
if (prompt)
|
|
printf("%*c\n%*c %s\n%*c\n",
|
|
indent, '*',
|
|
indent, '*', _(prompt),
|
|
indent, '*');
|
|
default:
|
|
;
|
|
}
|
|
}
|
|
|
|
if (!sym)
|
|
goto conf_childs;
|
|
|
|
if (sym_is_choice(sym)) {
|
|
conf_choice(menu);
|
|
if (sym->curr.tri != mod)
|
|
return;
|
|
goto conf_childs;
|
|
}
|
|
|
|
switch (sym->type) {
|
|
case S_INT:
|
|
case S_HEX:
|
|
case S_STRING:
|
|
conf_string(menu);
|
|
break;
|
|
default:
|
|
conf_sym(menu);
|
|
break;
|
|
}
|
|
|
|
conf_childs:
|
|
if (sym)
|
|
indent += 2;
|
|
for (child = menu->list; child; child = child->next)
|
|
conf(child);
|
|
if (sym)
|
|
indent -= 2;
|
|
}
|
|
|
|
static void check_conf(struct menu *menu)
|
|
{
|
|
struct symbol *sym;
|
|
struct menu *child;
|
|
|
|
if (!menu_is_visible(menu))
|
|
return;
|
|
|
|
sym = menu->sym;
|
|
if (sym && !sym_has_value(sym)) {
|
|
if (sym_is_changable(sym) ||
|
|
(sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)) {
|
|
if (!conf_cnt++)
|
|
printf(_("*\n* Restart config...\n*\n"));
|
|
rootEntry = menu_get_parent_menu(menu);
|
|
conf(rootEntry);
|
|
}
|
|
}
|
|
|
|
for (child = menu->list; child; child = child->next)
|
|
check_conf(child);
|
|
}
|
|
|
|
static void conf_do_update(void)
|
|
{
|
|
/* Update until a loop caused no more changes */
|
|
do {
|
|
conf_cnt = 0;
|
|
check_conf(&rootmenu);
|
|
} while (conf_cnt);
|
|
}
|
|
|
|
static int conf_silent_update(void)
|
|
{
|
|
const char *name;
|
|
|
|
if (conf_get_changed()) {
|
|
name = getenv("KCONFIG_NOSILENTUPDATE");
|
|
if (name && *name) {
|
|
fprintf(stderr,
|
|
_("\n*** Kernel configuration requires explicit update.\n\n"));
|
|
return 1;
|
|
}
|
|
conf_do_update();
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int conf_update(void)
|
|
{
|
|
rootEntry = &rootmenu;
|
|
conf(&rootmenu);
|
|
if (input_mode == ask_all) {
|
|
input_mode = ask_silent;
|
|
valid_stdin = 1;
|
|
}
|
|
conf_do_update();
|
|
return 0;
|
|
}
|
|
|
|
int main(int ac, char **av)
|
|
{
|
|
int opt;
|
|
const char *name;
|
|
struct stat tmpstat;
|
|
|
|
setlocale(LC_ALL, "");
|
|
bindtextdomain(PACKAGE, LOCALEDIR);
|
|
textdomain(PACKAGE);
|
|
|
|
while ((opt = getopt(ac, av, "osdD:nmyrh")) != -1) {
|
|
switch (opt) {
|
|
case 'o':
|
|
input_mode = ask_new;
|
|
break;
|
|
case 's':
|
|
input_mode = ask_silent;
|
|
valid_stdin = isatty(0) && isatty(1) && isatty(2);
|
|
break;
|
|
case 'd':
|
|
input_mode = set_default;
|
|
break;
|
|
case 'D':
|
|
input_mode = set_default;
|
|
defconfig_file = optarg;
|
|
break;
|
|
case 'n':
|
|
input_mode = set_no;
|
|
break;
|
|
case 'm':
|
|
input_mode = set_mod;
|
|
break;
|
|
case 'y':
|
|
input_mode = set_yes;
|
|
break;
|
|
case 'r':
|
|
input_mode = set_random;
|
|
srand(time(NULL));
|
|
break;
|
|
case 'h':
|
|
printf(_("See README for usage info\n"));
|
|
exit(0);
|
|
break;
|
|
default:
|
|
fprintf(stderr, _("See README for usage info\n"));
|
|
exit(1);
|
|
}
|
|
}
|
|
if (ac == optind) {
|
|
printf(_("%s: Kconfig file missing\n"), av[0]);
|
|
exit(1);
|
|
}
|
|
name = av[optind];
|
|
conf_parse(name);
|
|
//zconfdump(stdout);
|
|
switch (input_mode) {
|
|
case set_default:
|
|
if (!defconfig_file)
|
|
defconfig_file = conf_get_default_confname();
|
|
if (conf_read(defconfig_file)) {
|
|
printf(_("***\n"
|
|
"*** Can't find default configuration \"%s\"!\n"
|
|
"***\n"), defconfig_file);
|
|
exit(1);
|
|
}
|
|
break;
|
|
case ask_silent:
|
|
if (stat(".config", &tmpstat)) {
|
|
printf(_("***\n"
|
|
"*** You have not yet configured your kernel!\n"
|
|
"*** (missing kernel .config file)\n"
|
|
"***\n"
|
|
"*** Please run some configurator (e.g. \"make oldconfig\" or\n"
|
|
"*** \"make menuconfig\" or \"make xconfig\").\n"
|
|
"***\n"));
|
|
exit(1);
|
|
}
|
|
case ask_all:
|
|
case ask_new:
|
|
conf_read(NULL);
|
|
break;
|
|
case set_no:
|
|
case set_mod:
|
|
case set_yes:
|
|
case set_random:
|
|
name = getenv("KCONFIG_ALLCONFIG");
|
|
if (name && !stat(name, &tmpstat)) {
|
|
conf_read_simple(name, S_DEF_USER);
|
|
break;
|
|
}
|
|
switch (input_mode) {
|
|
case set_no: name = "allno.config"; break;
|
|
case set_mod: name = "allmod.config"; break;
|
|
case set_yes: name = "allyes.config"; break;
|
|
case set_random: name = "allrandom.config"; break;
|
|
default: break;
|
|
}
|
|
if (!stat(name, &tmpstat))
|
|
conf_read_simple(name, S_DEF_USER);
|
|
else if (!stat("all.config", &tmpstat))
|
|
conf_read_simple("all.config", S_DEF_USER);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
switch (input_mode) {
|
|
case set_no:
|
|
conf_set_all_new_symbols(def_no);
|
|
break;
|
|
case set_yes:
|
|
conf_set_all_new_symbols(def_yes);
|
|
break;
|
|
case set_mod:
|
|
conf_set_all_new_symbols(def_mod);
|
|
break;
|
|
case set_random:
|
|
conf_set_all_new_symbols(def_random);
|
|
break;
|
|
case ask_silent:
|
|
case ask_new:
|
|
if (conf_silent_update())
|
|
exit(1);
|
|
break;
|
|
case ask_all:
|
|
case set_default:
|
|
if (conf_update())
|
|
exit(1);
|
|
break;
|
|
}
|
|
|
|
if (conf_get_changed() && conf_write(NULL)) {
|
|
fprintf(stderr, _("\n*** Error during writing of the kernel configuration.\n\n"));
|
|
exit(1);
|
|
}
|
|
/* ask_silent is used during the build so we shall update autoconf.
|
|
* All other commands are only used to generate a config.
|
|
*/
|
|
if (input_mode == ask_silent && conf_write_autoconf()) {
|
|
fprintf(stderr, _("\n*** Error during writing of the kernel configuration.\n\n"));
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|