diff options
Diffstat (limited to 'scripts/config/confdata.c')
-rw-r--r-- | scripts/config/confdata.c | 533 |
1 files changed, 220 insertions, 313 deletions
diff --git a/scripts/config/confdata.c b/scripts/config/confdata.c index b696dda5e0..3a3a4bff43 100644 --- a/scripts/config/confdata.c +++ b/scripts/config/confdata.c @@ -1,14 +1,12 @@ -// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org> + * Released under the terms of the GNU GPL v2.0. */ -#include <sys/mman.h> #include <sys/stat.h> #include <ctype.h> #include <errno.h> #include <fcntl.h> -#include <limits.h> #include <stdarg.h> #include <stdio.h> #include <stdlib.h> @@ -18,151 +16,6 @@ #include "lkc.h" -/* return true if 'path' exists, false otherwise */ -static bool is_present(const char *path) -{ - struct stat st; - - return !stat(path, &st); -} - -/* return true if 'path' exists and it is a directory, false otherwise */ -static bool is_dir(const char *path) -{ - struct stat st; - - if (stat(path, &st)) - return 0; - - return S_ISDIR(st.st_mode); -} - -/* return true if the given two files are the same, false otherwise */ -static bool is_same(const char *file1, const char *file2) -{ - int fd1, fd2; - struct stat st1, st2; - void *map1, *map2; - bool ret = false; - - fd1 = open(file1, O_RDONLY); - if (fd1 < 0) - return ret; - - fd2 = open(file2, O_RDONLY); - if (fd2 < 0) - goto close1; - - ret = fstat(fd1, &st1); - if (ret) - goto close2; - ret = fstat(fd2, &st2); - if (ret) - goto close2; - - if (st1.st_size != st2.st_size) - goto close2; - - map1 = mmap(NULL, st1.st_size, PROT_READ, MAP_PRIVATE, fd1, 0); - if (map1 == MAP_FAILED) - goto close2; - - map2 = mmap(NULL, st2.st_size, PROT_READ, MAP_PRIVATE, fd2, 0); - if (map2 == MAP_FAILED) - goto close2; - - if (bcmp(map1, map2, st1.st_size)) - goto close2; - - ret = true; -close2: - close(fd2); -close1: - close(fd1); - - return ret; -} - -/* - * Create the parent directory of the given path. - * - * For example, if 'include/config/auto.conf' is given, create 'include/config'. - */ -static int make_parent_dir(const char *path) -{ - char tmp[PATH_MAX + 1]; - char *p; - - strncpy(tmp, path, sizeof(tmp)); - tmp[sizeof(tmp) - 1] = 0; - - /* Remove the base name. Just return if nothing is left */ - p = strrchr(tmp, '/'); - if (!p) - return 0; - *(p + 1) = 0; - - /* Just in case it is an absolute path */ - p = tmp; - while (*p == '/') - p++; - - while ((p = strchr(p, '/'))) { - *p = 0; - - /* skip if the directory exists */ - if (!is_dir(tmp) && mkdir(tmp, 0755)) - return -1; - - *p = '/'; - while (*p == '/') - p++; - } - - return 0; -} - -static char depfile_path[PATH_MAX]; -static size_t depfile_prefix_len; - -/* touch depfile for symbol 'name' */ -static int conf_touch_dep(const char *name) -{ - int fd, ret; - const char *s; - char *d, c; - - /* check overflow: prefix + name + ".h" + '\0' must fit in buffer. */ - if (depfile_prefix_len + strlen(name) + 3 > sizeof(depfile_path)) - return -1; - - d = depfile_path + depfile_prefix_len; - s = name; - - while ((c = *s++)) - *d++ = (c == '_') ? '/' : tolower(c); - strcpy(d, ".h"); - - /* Assume directory path already exists. */ - fd = open(depfile_path, O_WRONLY | O_CREAT | O_TRUNC, 0644); - if (fd == -1) { - if (errno != ENOENT) - return -1; - - ret = make_parent_dir(depfile_path); - if (ret) - return ret; - - /* Try it again. */ - fd = open(depfile_path, O_WRONLY | O_CREAT | O_TRUNC, 0644); - if (fd == -1) - return -1; - } - close(fd); - - return 0; -} - struct conf_printer { void (*print_symbol)(FILE *, struct symbol *, const char *, void *); void (*print_comment)(FILE *, const char *, void *); @@ -175,7 +28,9 @@ static void conf_message(const char *fmt, ...) __attribute__ ((format (printf, 1, 2))); static const char *conf_filename; -static int conf_lineno, conf_warnings; +static int conf_lineno, conf_warnings, conf_unsaved; + +const char conf_defname[] = "arch/$ARCH/defconfig"; static void conf_warning(const char *fmt, ...) { @@ -188,16 +43,16 @@ static void conf_warning(const char *fmt, ...) conf_warnings++; } -static void conf_default_message_callback(const char *s) +static void conf_default_message_callback(const char *fmt, va_list ap) { printf("#\n# "); - printf("%s", s); + vprintf(fmt, ap); printf("\n#\n"); } -static void (*conf_message_callback)(const char *s) = +static void (*conf_message_callback) (const char *fmt, va_list ap) = conf_default_message_callback; -void conf_set_message_callback(void (*fn)(const char *s)) +void conf_set_message_callback(void (*fn) (const char *fmt, va_list ap)) { conf_message_callback = fn; } @@ -205,15 +60,10 @@ void conf_set_message_callback(void (*fn)(const char *s)) static void conf_message(const char *fmt, ...) { va_list ap; - char buf[4096]; - - if (!conf_message_callback) - return; va_start(ap, fmt); - - vsnprintf(buf, sizeof(buf), fmt, ap); - conf_message_callback(buf); + if (conf_message_callback) + conf_message_callback(fmt, ap); va_end(ap); } @@ -224,13 +74,55 @@ const char *conf_get_configname(void) return name ? name : ".config"; } -static const char *conf_get_autoconfig_name(void) +const char *conf_get_autoconfig_name(void) { char *name = getenv("KCONFIG_AUTOCONFIG"); return name ? name : "include/config/auto.conf"; } +static char *conf_expand_value(const char *in) +{ + struct symbol *sym; + const char *src; + static char res_value[SYMBOL_MAXLENGTH]; + char *dst, name[SYMBOL_MAXLENGTH]; + + res_value[0] = 0; + dst = name; + while ((src = strchr(in, '$'))) { + strncat(res_value, in, src - in); + src++; + dst = name; + while (isalnum(*src) || *src == '_') + *dst++ = *src++; + *dst = 0; + sym = sym_lookup(name, 0); + sym_calc_value(sym); + strcat(res_value, sym_get_string_value(sym)); + in = src; + } + strcat(res_value, in); + + return res_value; +} + +char *conf_get_default_confname(void) +{ + struct stat buf; + static char fullname[PATH_MAX+1]; + char *env, *name; + + name = conf_expand_value(conf_defname); + env = getenv(SRCTREE); + if (env) { + sprintf(fullname, "%s/%s", env, name); + if (!stat(fullname, &buf)) + return fullname; + } + return name; +} + static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p) { char *p2; @@ -258,6 +150,14 @@ static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p) conf_warning("symbol value '%s' invalid for %s", p, sym->name); return 1; + case S_OTHER: + if (*p != '"') { + for (p2 = p; *p2 && !isspace(*p2); p2++) + ; + sym->type = S_STRING; + goto done; + } + /* fall through */ case S_STRING: if (*p++ != '"') break; @@ -276,8 +176,9 @@ static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p) /* fall through */ case S_INT: case S_HEX: + done: if (sym_string_valid(sym, p)) { - sym->def[def].val = xstrdup(p); + sym->def[def].val = strdup(p); sym->flags |= def_flags; } else { if (def != S_DEF_AUTO) @@ -300,7 +201,7 @@ static int add_byte(int c, char **lineptr, size_t slen, size_t *n) if (new_size > *n) { new_size += LINE_GROWTH - 1; new_size *= 2; - nline = xrealloc(*lineptr, new_size); + nline = realloc(*lineptr, new_size); if (!nline) return -1; @@ -398,11 +299,10 @@ int conf_read_simple(const char *name, int def) if (expr_calc_value(prop->visible.expr) == no || prop->expr->type != E_SYMBOL) continue; - sym_calc_value(prop->expr->left.sym); - name = sym_get_string_value(prop->expr->left.sym); + name = conf_expand_value(prop->expr->left.sym->name); in = zconf_fopen(name); if (in) { - conf_message("using defaults found in %s", + conf_message(_("using defaults found in %s"), name); goto load; } @@ -415,6 +315,7 @@ load: conf_filename = name; conf_lineno = 0; conf_warnings = 0; + conf_unsaved = 0; def_flags = SYMBOL_DEF << def; conf_reset(def); @@ -435,7 +336,7 @@ load: sym = sym_find(line + 2 + strlen(CONFIG_)); if (!sym) { sym_add_change_count(1); - continue; + goto setsym; } } else { sym = sym_lookup(line + 2 + strlen(CONFIG_), 0); @@ -462,22 +363,17 @@ load: if (*p2 == '\r') *p2 = 0; } - - sym = sym_find(line + strlen(CONFIG_)); - if (!sym) { - if (def == S_DEF_AUTO) - /* - * Reading from include/config/auto.conf - * If CONFIG_FOO previously existed in - * auto.conf but it is missing now, - * include/config/foo.h must be touched. - */ - conf_touch_dep(line + strlen(CONFIG_)); - else + if (def == S_DEF_USER) { + sym = sym_find(line + strlen(CONFIG_)); + if (!sym) { sym_add_change_count(1); - continue; + goto setsym; + } + } else { + sym = sym_lookup(line + strlen(CONFIG_), 0); + if (sym->type == S_UNKNOWN) + sym->type = S_OTHER; } - if (conf_set_sym_val(sym, def, def_flags, p)) continue; } else { @@ -487,7 +383,7 @@ load: continue; } - +setsym: if (sym && sym_is_choice_value(sym)) { struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym)); switch (sym->def[def].tri) { @@ -516,7 +412,6 @@ load: int conf_read(const char *name) { struct symbol *sym; - int conf_unsaved = 0; int i; sym_set_change_count(0); @@ -530,16 +425,18 @@ int conf_read(const char *name) for_all_symbols(i, sym) { sym_calc_value(sym); - if (sym_is_choice(sym) || (sym->flags & SYMBOL_NO_WRITE)) + if (sym_is_choice(sym) || (sym->flags & SYMBOL_AUTO)) continue; if (sym_has_value(sym) && (sym->flags & SYMBOL_WRITE)) { /* check that calculated value agrees with saved value */ switch (sym->type) { case S_BOOLEAN: case S_TRISTATE: - if (sym->def[S_DEF_USER].tri == sym_get_tristate_value(sym)) + if (sym->def[S_DEF_USER].tri != sym_get_tristate_value(sym)) + break; + if (!sym_is_choice(sym)) continue; - break; + /* fall through */ default: if (!strcmp(sym->curr.val, sym->def[S_DEF_USER].val)) continue; @@ -713,12 +610,32 @@ static struct conf_printer header_printer_cb = .print_comment = header_print_comment, }; +/* + * Tristate printer + * + * This printer is used when generating the `include/config/tristate.conf' file. + */ +static void +tristate_print_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg) +{ + + if (sym->type == S_TRISTATE && *value != 'n') + fprintf(fp, "%s%s=%c\n", CONFIG_, sym->name, (char)toupper(*value)); +} + +static struct conf_printer tristate_printer_cb = +{ + .print_symbol = tristate_print_symbol, + .print_comment = kconfig_print_comment, +}; + static void conf_write_symbol(FILE *fp, struct symbol *sym, struct conf_printer *printer, void *printer_arg) { const char *str; switch (sym->type) { + case S_OTHER: case S_UNKNOWN: break; case S_STRING: @@ -778,7 +695,7 @@ int conf_write_defconfig(const char *filename) goto next_menu; sym->flags &= ~SYMBOL_WRITE; /* If we cannot change the symbol - skip */ - if (!sym_is_changeable(sym)) + if (!sym_is_changable(sym)) goto next_menu; /* If symbol equals to default value - skip */ if (strcmp(sym_get_string_value(sym), sym_get_string_default(sym)) == 0) @@ -829,36 +746,41 @@ int conf_write(const char *name) FILE *out; struct symbol *sym; struct menu *menu; + const char *basename; const char *str; - char tmpname[PATH_MAX + 1], oldname[PATH_MAX + 1]; + char dirname[PATH_MAX+1], tmpname[PATH_MAX+1], newname[PATH_MAX+1]; char *env; - int i; - bool need_newline = false; - - if (!name) - name = conf_get_configname(); - - if (!*name) { - fprintf(stderr, "config name is empty\n"); - return -1; - } - - if (is_dir(name)) { - fprintf(stderr, "%s: Is a directory\n", name); - return -1; - } - - if (make_parent_dir(name)) - return -1; + dirname[0] = 0; + if (name && name[0]) { + struct stat st; + char *slash; + + if (!stat(name, &st) && S_ISDIR(st.st_mode)) { + strcpy(dirname, name); + strcat(dirname, "/"); + basename = conf_get_configname(); + } else if ((slash = strrchr(name, '/'))) { + int size = slash - name + 1; + memcpy(dirname, name, size); + dirname[size] = 0; + if (slash[1]) + basename = slash + 1; + else + basename = conf_get_configname(); + } else + basename = name; + } else + basename = conf_get_configname(); + + sprintf(newname, "%s%s", dirname, basename); env = getenv("KCONFIG_OVERWRITECONFIG"); - if (env && *env) { - *tmpname = 0; - out = fopen(name, "w"); - } else { - snprintf(tmpname, sizeof(tmpname), "%s.%d.tmp", - name, (int)getpid()); + if (!env || !*env) { + sprintf(tmpname, "%s.tmpconfig.%d", dirname, (int)getpid()); out = fopen(tmpname, "w"); + } else { + *tmpname = 0; + out = fopen(newname, "w"); } if (!out) return 1; @@ -879,17 +801,12 @@ int conf_write(const char *name) "#\n" "# %s\n" "#\n", str); - need_newline = false; - } else if (!(sym->flags & SYMBOL_CHOICE) && - !(sym->flags & SYMBOL_WRITTEN)) { + } else if (!(sym->flags & SYMBOL_CHOICE)) { sym_calc_value(sym); if (!(sym->flags & SYMBOL_WRITE)) goto next; - if (need_newline) { - fprintf(out, "\n"); - need_newline = false; - } - sym->flags |= SYMBOL_WRITTEN; + sym->flags &= ~SYMBOL_WRITE; + conf_write_symbol(out, sym, &kconfig_printer_cb, NULL); } @@ -901,12 +818,6 @@ next: if (menu->next) menu = menu->next; else while ((menu = menu->parent)) { - if (!menu->sym && menu_is_visible(menu) && - menu != &rootmenu) { - str = menu_get_prompt(menu); - fprintf(out, "# end of %s\n", str); - need_newline = true; - } if (menu->next) { menu = menu->next; break; @@ -915,76 +826,41 @@ next: } fclose(out); - for_all_symbols(i, sym) - sym->flags &= ~SYMBOL_WRITTEN; - if (*tmpname) { - if (is_same(name, tmpname)) { - conf_message("No change to %s", name); - unlink(tmpname); - sym_set_change_count(0); - return 0; - } - - snprintf(oldname, sizeof(oldname), "%s.old", name); - rename(name, oldname); - if (rename(tmpname, name)) + strcat(dirname, basename); + strcat(dirname, ".old"); + rename(newname, dirname); + if (rename(tmpname, newname)) return 1; } - conf_message("configuration written to %s", name); + conf_message(_("configuration written to %s"), newname); sym_set_change_count(0); return 0; } -/* write a dependency file as used by kbuild to track dependencies */ -static int conf_write_dep(const char *name) -{ - struct file *file; - FILE *out; - - out = fopen("..config.tmp", "w"); - if (!out) - return 1; - fprintf(out, "deps_config := \\\n"); - for (file = file_list; file; file = file->next) { - if (file->next) - fprintf(out, "\t%s \\\n", file->name); - else - fprintf(out, "\t%s\n", file->name); - } - fprintf(out, "\n%s: \\\n" - "\t$(deps_config)\n\n", conf_get_autoconfig_name()); - - env_write_dep(out, conf_get_autoconfig_name()); - - fprintf(out, "\n$(deps_config): ;\n"); - fclose(out); - - if (make_parent_dir(name)) - return 1; - rename("..config.tmp", name); - return 0; -} - -static int conf_touch_deps(void) +static int conf_split_config(void) { const char *name; + char path[PATH_MAX+1]; + char *s, *d, c; struct symbol *sym; - int res, i; - - strcpy(depfile_path, "include/config/"); - depfile_prefix_len = strlen(depfile_path); + struct stat sb; + int res, i, fd; name = conf_get_autoconfig_name(); conf_read_simple(name, S_DEF_AUTO); sym_calc_value(modules_sym); + if (chdir("include/config")) + return 1; + + res = 0; for_all_symbols(i, sym) { sym_calc_value(sym); - if ((sym->flags & SYMBOL_NO_WRITE) || !sym->name) + if ((sym->flags & SYMBOL_AUTO) || !sym->name) continue; if (sym->flags & SYMBOL_WRITE) { if (sym->flags & SYMBOL_DEF_AUTO) { @@ -1033,44 +909,86 @@ static int conf_touch_deps(void) * different from 'no'). */ - res = conf_touch_dep(sym->name); - if (res) - return res; + /* Replace all '_' and append ".h" */ + s = sym->name; + d = path; + while ((c = *s++)) { + c = tolower(c); + *d++ = (c == '_') ? '/' : c; + } + strcpy(d, ".h"); + + /* Assume directory path already exists. */ + fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644); + if (fd == -1) { + if (errno != ENOENT) { + res = 1; + break; + } + /* + * Create directory components, + * unless they exist already. + */ + d = path; + while ((d = strchr(d, '/'))) { + *d = 0; + if (stat(path, &sb) && mkdir(path, 0755)) { + res = 1; + goto out; + } + *d++ = '/'; + } + /* Try it again. */ + fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644); + if (fd == -1) { + res = 1; + break; + } + } + close(fd); } +out: + if (chdir("../..")) + return 1; - return 0; + return res; } -int conf_write_autoconf(int overwrite) +int conf_write_autoconf(void) { struct symbol *sym; const char *name; - const char *autoconf_name = conf_get_autoconfig_name(); - FILE *out, *out_h; + FILE *out, *tristate, *out_h; int i; -#ifndef OPENWRT_DOES_NOT_WANT_THIS - return 0; -#endif - if (!overwrite && is_present(autoconf_name)) - return 0; + sym_clear_all_valid(); - conf_write_dep("include/config/auto.conf.cmd"); + file_write_dep("include/config/auto.conf.cmd"); - if (conf_touch_deps()) + if (conf_split_config()) return 1; out = fopen(".tmpconfig", "w"); if (!out) return 1; + tristate = fopen(".tmpconfig_tristate", "w"); + if (!tristate) { + fclose(out); + return 1; + } + out_h = fopen(".tmpconfig.h", "w"); if (!out_h) { fclose(out); + fclose(tristate); return 1; } conf_write_heading(out, &kconfig_printer_cb, NULL); + + conf_write_heading(tristate, &tristate_printer_cb, NULL); + conf_write_heading(out_h, &header_printer_cb, NULL); for_all_symbols(i, sym) { @@ -1078,28 +996,33 @@ int conf_write_autoconf(int overwrite) if (!(sym->flags & SYMBOL_WRITE) || !sym->name) continue; - /* write symbols to auto.conf and autoconf.h */ + /* write symbol to auto.conf, tristate and header files */ conf_write_symbol(out, sym, &kconfig_printer_cb, (void *)1); + + conf_write_symbol(tristate, sym, &tristate_printer_cb, (void *)1); + conf_write_symbol(out_h, sym, &header_printer_cb, NULL); } fclose(out); + fclose(tristate); fclose(out_h); name = getenv("KCONFIG_AUTOHEADER"); if (!name) name = "include/generated/autoconf.h"; - if (make_parent_dir(name)) - return 1; if (rename(".tmpconfig.h", name)) return 1; - - if (make_parent_dir(autoconf_name)) + name = getenv("KCONFIG_TRISTATE"); + if (!name) + name = "include/config/tristate.conf"; + if (rename(".tmpconfig_tristate", name)) return 1; + name = conf_get_autoconfig_name(); /* * This must be the last step, kbuild has a dependency on auto.conf * and this marks the successful completion of the previous steps. */ - if (rename(".tmpconfig", autoconf_name)) + if (rename(".tmpconfig", name)) return 1; return 0; @@ -1203,7 +1126,7 @@ void set_all_choice_values(struct symbol *csym) bool conf_set_all_new_symbols(enum conf_def_mode mode) { struct symbol *sym, *csym; - int i, cnt, pby, pty, ptm; /* pby: probability of bool = y + int i, cnt, pby, pty, ptm; /* pby: probability of boolean = y * pty: probability of tristate = y * ptm: probability of tristate = m */ @@ -1327,19 +1250,3 @@ bool conf_set_all_new_symbols(enum conf_def_mode mode) return has_changed; } - -void conf_rewrite_mod_or_yes(enum conf_def_mode mode) -{ - struct symbol *sym; - int i; - tristate old_val = (mode == def_y2m) ? yes : mod; - tristate new_val = (mode == def_y2m) ? mod : yes; - - for_all_symbols(i, sym) { - if (sym_get_type(sym) == S_TRISTATE && - sym->def[S_DEF_USER].tri == old_val) { - sym->def[S_DEF_USER].tri = new_val; - sym_add_change_count(1); - } - } -} |