Re: kconfig: list unknown symbols in the old .config

From: Sergey Senozhatsky
Date: Wed Aug 16 2023 - 09:07:11 EST


On (23/08/16 21:42), Sergey Senozhatsky wrote:
> Hi,
>
> We recently were hit (unnecessarily hard) when after kernel uprev we
> figured that something wasn't working. The root cause was a rename of
> the CONFIG_FOO option between kernel releases, which make oldconfig
> doesn't warn/notify about.
>
> Would it be possible to add either a new --listunknown mode to conf or
> to somehow make it conf_warning("unknown symbol: %s\n", line) when it
> reads a line from oldconf that it cannot sym_find()?
>
> That would save a ton of time.

So I have this simple (quick-n-dirty) patch, that seem to be doing
the trick. Just to show the idea.

Running `make listunknown` produces the following (on a hand-crafted
.config):

.config:6:warning: unknown symbol: CONFIG_DISABLE_BUGS
.config:7:warning: unknown symbol: CONFIG_COMPILE_GOOD_CODE_ONLY
make[2]: *** [scripts/kconfig/Makefile:77: listunknown] Error 1
...

---

diff --git a/scripts/kconfig/conf.c b/scripts/kconfig/conf.c
index 33d19e419908..37b777a0848c 100644
--- a/scripts/kconfig/conf.c
+++ b/scripts/kconfig/conf.c
@@ -36,6 +36,7 @@ enum input_mode {
yes2modconfig,
mod2yesconfig,
mod2noconfig,
+ listunknown,
};
static enum input_mode input_mode = oldaskconfig;
static int input_mode_opt;
@@ -683,6 +684,7 @@ static const struct option long_opts[] = {
{"yes2modconfig", no_argument, &input_mode_opt, yes2modconfig},
{"mod2yesconfig", no_argument, &input_mode_opt, mod2yesconfig},
{"mod2noconfig", no_argument, &input_mode_opt, mod2noconfig},
+ {"listunknown", no_argument, &input_mode_opt, listunknown},
{NULL, 0, NULL, 0}
};

@@ -712,6 +714,7 @@ static void conf_usage(const char *progname)
printf(" --yes2modconfig Change answers from yes to mod if possible\n");
printf(" --mod2yesconfig Change answers from mod to yes if possible\n");
printf(" --mod2noconfig Change answers from mod to no if possible\n");
+ printf(" --listunknown List symbols that are not recognized anymore\n");
printf(" (If none of the above is given, --oldaskconfig is the default)\n");
}

@@ -823,6 +826,12 @@ int main(int ac, char **av)
exit(1);
}
break;
+ case listunknown:
+ if (conf_read_listunknown())
+ exit(1);
+ else
+ exit(0);
+ break;
default:
break;
}
diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c
index 992575f1e976..d70cd3b034e1 100644
--- a/scripts/kconfig/confdata.c
+++ b/scripts/kconfig/confdata.c
@@ -341,64 +341,113 @@ static ssize_t compat_getline(char **lineptr, size_t *n, FILE *stream)
return -1;
}

-int conf_read_simple(const char *name, int def)
+static FILE *open_conf_file(const char *name)
{
- FILE *in = NULL;
- char *line = NULL;
- size_t line_asize = 0;
- char *p, *p2;
- struct symbol *sym;
- int i, def_flags;
+ char *env, *p;
+ FILE *in;

- if (name) {
- in = zconf_fopen(name);
- } else {
- char *env;
+ if (name)
+ return zconf_fopen(name);

- name = conf_get_configname();
- in = zconf_fopen(name);
- if (in)
- goto load;
- conf_set_changed(true);
+ name = conf_get_configname();
+ in = zconf_fopen(name);
+ if (in)
+ return in;

- env = getenv("KCONFIG_DEFCONFIG_LIST");
- if (!env)
- return 1;
+ conf_set_changed(true);

- while (1) {
- bool is_last;
+ env = getenv("KCONFIG_DEFCONFIG_LIST");
+ if (!env)
+ return NULL;

- while (isspace(*env))
- env++;
+ while (1) {
+ bool is_last;

- if (!*env)
- break;
+ while (isspace(*env))
+ env++;

- p = env;
- while (*p && !isspace(*p))
- p++;
+ if (!*env)
+ break;

- is_last = (*p == '\0');
+ p = env;
+ while (*p && !isspace(*p))
+ p++;

- *p = '\0';
+ is_last = (*p == '\0');

- in = zconf_fopen(env);
- if (in) {
- conf_message("using defaults found in %s",
- env);
- goto load;
- }
+ *p = '\0';

- if (is_last)
- break;
+ in = zconf_fopen(env);
+ if (in) {
+ conf_message("using defaults found in %s",
+ env);
+ return in;
+ }
+
+ if (is_last)
+ break;
+ env = p + 1;
+ }
+
+ return NULL;
+}
+
+int conf_read_listunknown(void)
+{
+ FILE *in = NULL;
+ char *line = NULL;
+ size_t line_asize = 0;
+ char *p, *p2;
+ struct symbol *sym;

- env = p + 1;
+ conf_filename = conf_get_configname();
+ in = open_conf_file(conf_filename);
+ if (!in)
+ return 1;
+
+ conf_warnings = 0;
+ while (compat_getline(&line, &line_asize, in) != -1) {
+ conf_lineno++;
+ sym = NULL;
+ if (line[0] == '#')
+ continue;
+
+ if (memcmp(line, CONFIG_, strlen(CONFIG_)) == 0) {
+ p = strchr(line + strlen(CONFIG_), '=');
+ if (!p)
+ continue;
+ *p++ = 0;
+ p2 = strchr(p, '\n');
+ if (p2) {
+ *p2-- = 0;
+ if (*p2 == '\r')
+ *p2 = 0;
+ }
+
+ sym = sym_find(line + strlen(CONFIG_));
+ if (!sym)
+ conf_warning("unknown symbol: %s", line);
}
}
+
+ free(line);
+ fclose(in);
+ return conf_warnings;
+}
+
+int conf_read_simple(const char *name, int def)
+{
+ FILE *in = NULL;
+ char *line = NULL;
+ size_t line_asize = 0;
+ char *p, *p2;
+ struct symbol *sym;
+ int i, def_flags;
+
+ in = open_conf_file(name);
if (!in)
return 1;

-load:
conf_filename = name;
conf_lineno = 0;
conf_warnings = 0;
diff --git a/scripts/kconfig/lkc_proto.h b/scripts/kconfig/lkc_proto.h
index edd1e617b25c..d76faaec120a 100644
--- a/scripts/kconfig/lkc_proto.h
+++ b/scripts/kconfig/lkc_proto.h
@@ -5,6 +5,7 @@
void conf_parse(const char *name);
int conf_read(const char *name);
int conf_read_simple(const char *name, int);
+int conf_read_listunknown(void);
int conf_write_defconfig(const char *name);
int conf_write(const char *name);
int conf_write_autoconf(int overwrite);