10c874100SMasahiro Yamada // SPDX-License-Identifier: GPL-2.0 21da177e4SLinus Torvalds /* 31da177e4SLinus Torvalds * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org> 41da177e4SLinus Torvalds */ 51da177e4SLinus Torvalds 667424f61SMasahiro Yamada #include <sys/mman.h> 71da177e4SLinus Torvalds #include <sys/stat.h> 878cb0907SBoris Kolpackov #include <sys/types.h> 91da177e4SLinus Torvalds #include <ctype.h> 1094bedecaSArnaud Lacombe #include <errno.h> 112e3646e5SRoman Zippel #include <fcntl.h> 12558e78e3SMasahiro Yamada #include <limits.h> 1310a4b277SArnaud Lacombe #include <stdarg.h> 146ce45a91SMasahiro Yamada #include <stdbool.h> 151da177e4SLinus Torvalds #include <stdio.h> 161da177e4SLinus Torvalds #include <stdlib.h> 171da177e4SLinus Torvalds #include <string.h> 181da177e4SLinus Torvalds #include <time.h> 191da177e4SLinus Torvalds #include <unistd.h> 201da177e4SLinus Torvalds 21a9d83d74SMasahiro Yamada #include <xalloc.h> 2291b69454SMasahiro Yamada #include "internal.h" 231da177e4SLinus Torvalds #include "lkc.h" 241da177e4SLinus Torvalds 25526396b7SMasahiro Yamada struct gstr autoconf_cmd; 26526396b7SMasahiro Yamada 270608182aSMasahiro Yamada /* return true if 'path' exists, false otherwise */ 280608182aSMasahiro Yamada static bool is_present(const char *path) 290608182aSMasahiro Yamada { 300608182aSMasahiro Yamada struct stat st; 310608182aSMasahiro Yamada 320608182aSMasahiro Yamada return !stat(path, &st); 330608182aSMasahiro Yamada } 340608182aSMasahiro Yamada 350608182aSMasahiro Yamada /* return true if 'path' exists and it is a directory, false otherwise */ 360608182aSMasahiro Yamada static bool is_dir(const char *path) 370608182aSMasahiro Yamada { 380608182aSMasahiro Yamada struct stat st; 390608182aSMasahiro Yamada 400608182aSMasahiro Yamada if (stat(path, &st)) 41a69b191fSYang Li return false; 420608182aSMasahiro Yamada 430608182aSMasahiro Yamada return S_ISDIR(st.st_mode); 440608182aSMasahiro Yamada } 450608182aSMasahiro Yamada 4667424f61SMasahiro Yamada /* return true if the given two files are the same, false otherwise */ 4767424f61SMasahiro Yamada static bool is_same(const char *file1, const char *file2) 4867424f61SMasahiro Yamada { 4967424f61SMasahiro Yamada int fd1, fd2; 5067424f61SMasahiro Yamada struct stat st1, st2; 5167424f61SMasahiro Yamada void *map1, *map2; 5267424f61SMasahiro Yamada bool ret = false; 5367424f61SMasahiro Yamada 5467424f61SMasahiro Yamada fd1 = open(file1, O_RDONLY); 5567424f61SMasahiro Yamada if (fd1 < 0) 5667424f61SMasahiro Yamada return ret; 5767424f61SMasahiro Yamada 5867424f61SMasahiro Yamada fd2 = open(file2, O_RDONLY); 5967424f61SMasahiro Yamada if (fd2 < 0) 6067424f61SMasahiro Yamada goto close1; 6167424f61SMasahiro Yamada 6267424f61SMasahiro Yamada ret = fstat(fd1, &st1); 6367424f61SMasahiro Yamada if (ret) 6467424f61SMasahiro Yamada goto close2; 6567424f61SMasahiro Yamada ret = fstat(fd2, &st2); 6667424f61SMasahiro Yamada if (ret) 6767424f61SMasahiro Yamada goto close2; 6867424f61SMasahiro Yamada 6967424f61SMasahiro Yamada if (st1.st_size != st2.st_size) 7067424f61SMasahiro Yamada goto close2; 7167424f61SMasahiro Yamada 7267424f61SMasahiro Yamada map1 = mmap(NULL, st1.st_size, PROT_READ, MAP_PRIVATE, fd1, 0); 7367424f61SMasahiro Yamada if (map1 == MAP_FAILED) 7467424f61SMasahiro Yamada goto close2; 7567424f61SMasahiro Yamada 7667424f61SMasahiro Yamada map2 = mmap(NULL, st2.st_size, PROT_READ, MAP_PRIVATE, fd2, 0); 7767424f61SMasahiro Yamada if (map2 == MAP_FAILED) 7867424f61SMasahiro Yamada goto close2; 7967424f61SMasahiro Yamada 8067424f61SMasahiro Yamada if (bcmp(map1, map2, st1.st_size)) 8167424f61SMasahiro Yamada goto close2; 8267424f61SMasahiro Yamada 8367424f61SMasahiro Yamada ret = true; 8467424f61SMasahiro Yamada close2: 8567424f61SMasahiro Yamada close(fd2); 8667424f61SMasahiro Yamada close1: 8767424f61SMasahiro Yamada close(fd1); 8867424f61SMasahiro Yamada 8967424f61SMasahiro Yamada return ret; 9067424f61SMasahiro Yamada } 9167424f61SMasahiro Yamada 920608182aSMasahiro Yamada /* 930608182aSMasahiro Yamada * Create the parent directory of the given path. 940608182aSMasahiro Yamada * 950608182aSMasahiro Yamada * For example, if 'include/config/auto.conf' is given, create 'include/config'. 960608182aSMasahiro Yamada */ 970608182aSMasahiro Yamada static int make_parent_dir(const char *path) 980608182aSMasahiro Yamada { 990608182aSMasahiro Yamada char tmp[PATH_MAX + 1]; 1000608182aSMasahiro Yamada char *p; 1010608182aSMasahiro Yamada 1020608182aSMasahiro Yamada strncpy(tmp, path, sizeof(tmp)); 1030608182aSMasahiro Yamada tmp[sizeof(tmp) - 1] = 0; 1040608182aSMasahiro Yamada 1050608182aSMasahiro Yamada /* Remove the base name. Just return if nothing is left */ 1060608182aSMasahiro Yamada p = strrchr(tmp, '/'); 1070608182aSMasahiro Yamada if (!p) 1080608182aSMasahiro Yamada return 0; 1090608182aSMasahiro Yamada *(p + 1) = 0; 1100608182aSMasahiro Yamada 1110608182aSMasahiro Yamada /* Just in case it is an absolute path */ 1120608182aSMasahiro Yamada p = tmp; 1130608182aSMasahiro Yamada while (*p == '/') 1140608182aSMasahiro Yamada p++; 1150608182aSMasahiro Yamada 1160608182aSMasahiro Yamada while ((p = strchr(p, '/'))) { 1170608182aSMasahiro Yamada *p = 0; 1180608182aSMasahiro Yamada 1190608182aSMasahiro Yamada /* skip if the directory exists */ 1200608182aSMasahiro Yamada if (!is_dir(tmp) && mkdir(tmp, 0755)) 1210608182aSMasahiro Yamada return -1; 1220608182aSMasahiro Yamada 1230608182aSMasahiro Yamada *p = '/'; 1240608182aSMasahiro Yamada while (*p == '/') 1250608182aSMasahiro Yamada p++; 1260608182aSMasahiro Yamada } 1270608182aSMasahiro Yamada 1280608182aSMasahiro Yamada return 0; 1290608182aSMasahiro Yamada } 1300608182aSMasahiro Yamada 1311508fec8SMasahiro Yamada static char depfile_path[PATH_MAX]; 1321508fec8SMasahiro Yamada static size_t depfile_prefix_len; 1331508fec8SMasahiro Yamada 1341508fec8SMasahiro Yamada /* touch depfile for symbol 'name' */ 1351508fec8SMasahiro Yamada static int conf_touch_dep(const char *name) 1361508fec8SMasahiro Yamada { 137fee762d6SMasahiro Yamada int fd; 1381508fec8SMasahiro Yamada 1390e0345b7SAlexey Dobriyan /* check overflow: prefix + name + '\0' must fit in buffer. */ 1400e0345b7SAlexey Dobriyan if (depfile_prefix_len + strlen(name) + 1 > sizeof(depfile_path)) 1411508fec8SMasahiro Yamada return -1; 1421508fec8SMasahiro Yamada 143fee762d6SMasahiro Yamada strcpy(depfile_path + depfile_prefix_len, name); 1441508fec8SMasahiro Yamada 1451508fec8SMasahiro Yamada fd = open(depfile_path, O_WRONLY | O_CREAT | O_TRUNC, 0644); 1461508fec8SMasahiro Yamada if (fd == -1) 1471508fec8SMasahiro Yamada return -1; 1481508fec8SMasahiro Yamada close(fd); 1491508fec8SMasahiro Yamada 1501508fec8SMasahiro Yamada return 0; 1511508fec8SMasahiro Yamada } 1521508fec8SMasahiro Yamada 153c1a0f5e3SRoman Zippel static void conf_warning(const char *fmt, ...) 154c1a0f5e3SRoman Zippel __attribute__ ((format (printf, 1, 2))); 155c1a0f5e3SRoman Zippel 15642368c37SMichal Marek static void conf_message(const char *fmt, ...) 15742368c37SMichal Marek __attribute__ ((format (printf, 1, 2))); 15842368c37SMichal Marek 159c1a0f5e3SRoman Zippel static const char *conf_filename; 16084dd95d4SMasahiro Yamada static int conf_lineno, conf_warnings; 161c1a0f5e3SRoman Zippel 16215d3f766SSergey Senozhatsky bool conf_errors(void) 16315d3f766SSergey Senozhatsky { 16415d3f766SSergey Senozhatsky if (conf_warnings) 16515d3f766SSergey Senozhatsky return getenv("KCONFIG_WERROR"); 16615d3f766SSergey Senozhatsky return false; 16715d3f766SSergey Senozhatsky } 16815d3f766SSergey Senozhatsky 169c1a0f5e3SRoman Zippel static void conf_warning(const char *fmt, ...) 170c1a0f5e3SRoman Zippel { 171c1a0f5e3SRoman Zippel va_list ap; 172c1a0f5e3SRoman Zippel va_start(ap, fmt); 173c1a0f5e3SRoman Zippel fprintf(stderr, "%s:%d:warning: ", conf_filename, conf_lineno); 174c1a0f5e3SRoman Zippel vfprintf(stderr, fmt, ap); 175c1a0f5e3SRoman Zippel fprintf(stderr, "\n"); 176c1a0f5e3SRoman Zippel va_end(ap); 177c1a0f5e3SRoman Zippel conf_warnings++; 178c1a0f5e3SRoman Zippel } 179c1a0f5e3SRoman Zippel 1805accd7f3SMasahiro Yamada static void conf_default_message_callback(const char *s) 18142368c37SMichal Marek { 18242368c37SMichal Marek printf("#\n# "); 1835accd7f3SMasahiro Yamada printf("%s", s); 18442368c37SMichal Marek printf("\n#\n"); 18542368c37SMichal Marek } 18642368c37SMichal Marek 1875accd7f3SMasahiro Yamada static void (*conf_message_callback)(const char *s) = 18842368c37SMichal Marek conf_default_message_callback; 1895accd7f3SMasahiro Yamada void conf_set_message_callback(void (*fn)(const char *s)) 19042368c37SMichal Marek { 19142368c37SMichal Marek conf_message_callback = fn; 19242368c37SMichal Marek } 19342368c37SMichal Marek 19442368c37SMichal Marek static void conf_message(const char *fmt, ...) 19542368c37SMichal Marek { 19642368c37SMichal Marek va_list ap; 1975accd7f3SMasahiro Yamada char buf[4096]; 1985accd7f3SMasahiro Yamada 1995accd7f3SMasahiro Yamada if (!conf_message_callback) 2005accd7f3SMasahiro Yamada return; 20142368c37SMichal Marek 20242368c37SMichal Marek va_start(ap, fmt); 2035accd7f3SMasahiro Yamada 2045accd7f3SMasahiro Yamada vsnprintf(buf, sizeof(buf), fmt, ap); 2055accd7f3SMasahiro Yamada conf_message_callback(buf); 206b6a2ab2cSColin Ian King va_end(ap); 20742368c37SMichal Marek } 20842368c37SMichal Marek 20914cdd3c4SRoman Zippel const char *conf_get_configname(void) 21014cdd3c4SRoman Zippel { 21114cdd3c4SRoman Zippel char *name = getenv("KCONFIG_CONFIG"); 21214cdd3c4SRoman Zippel 21314cdd3c4SRoman Zippel return name ? name : ".config"; 21414cdd3c4SRoman Zippel } 21514cdd3c4SRoman Zippel 2169b9f5948SMasahiro Yamada static const char *conf_get_autoconfig_name(void) 21712122f62SMarkus Heidelberg { 21812122f62SMarkus Heidelberg char *name = getenv("KCONFIG_AUTOCONFIG"); 21912122f62SMarkus Heidelberg 22012122f62SMarkus Heidelberg return name ? name : "include/config/auto.conf"; 22112122f62SMarkus Heidelberg } 22212122f62SMarkus Heidelberg 2238499f2ddSMasahiro Yamada static const char *conf_get_autoheader_name(void) 2248499f2ddSMasahiro Yamada { 2258499f2ddSMasahiro Yamada char *name = getenv("KCONFIG_AUTOHEADER"); 2268499f2ddSMasahiro Yamada 2278499f2ddSMasahiro Yamada return name ? name : "include/generated/autoconf.h"; 2288499f2ddSMasahiro Yamada } 2298499f2ddSMasahiro Yamada 2302f7ab126SMiguel Ojeda static const char *conf_get_rustccfg_name(void) 2312f7ab126SMiguel Ojeda { 2322f7ab126SMiguel Ojeda char *name = getenv("KCONFIG_RUSTCCFG"); 2332f7ab126SMiguel Ojeda 2342f7ab126SMiguel Ojeda return name ? name : "include/generated/rustc_cfg"; 2352f7ab126SMiguel Ojeda } 2362f7ab126SMiguel Ojeda 2379c900a9cSSam Ravnborg static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p) 2389c900a9cSSam Ravnborg { 2399c900a9cSSam Ravnborg char *p2; 2409c900a9cSSam Ravnborg 2419c900a9cSSam Ravnborg switch (sym->type) { 2429c900a9cSSam Ravnborg case S_TRISTATE: 2439c900a9cSSam Ravnborg if (p[0] == 'm') { 2449c900a9cSSam Ravnborg sym->def[def].tri = mod; 2459c900a9cSSam Ravnborg sym->flags |= def_flags; 2469c900a9cSSam Ravnborg break; 2479c900a9cSSam Ravnborg } 248d8fc3200SArnaud Lacombe /* fall through */ 2499c900a9cSSam Ravnborg case S_BOOLEAN: 2509c900a9cSSam Ravnborg if (p[0] == 'y') { 2519c900a9cSSam Ravnborg sym->def[def].tri = yes; 2529c900a9cSSam Ravnborg sym->flags |= def_flags; 2539c900a9cSSam Ravnborg break; 2549c900a9cSSam Ravnborg } 2559c900a9cSSam Ravnborg if (p[0] == 'n') { 2569c900a9cSSam Ravnborg sym->def[def].tri = no; 2579c900a9cSSam Ravnborg sym->flags |= def_flags; 2589c900a9cSSam Ravnborg break; 2599c900a9cSSam Ravnborg } 26004b19b77SYann E. MORIN if (def != S_DEF_AUTO) 26104b19b77SYann E. MORIN conf_warning("symbol value '%s' invalid for %s", 26204b19b77SYann E. MORIN p, sym->name); 26375f1468bSArnaud Lacombe return 1; 2649c900a9cSSam Ravnborg case S_STRING: 265129ab0d2SMasahiro Yamada /* No escaping for S_DEF_AUTO (include/config/auto.conf) */ 266129ab0d2SMasahiro Yamada if (def != S_DEF_AUTO) { 2679c900a9cSSam Ravnborg if (*p++ != '"') 2689c900a9cSSam Ravnborg break; 2699c900a9cSSam Ravnborg for (p2 = p; (p2 = strpbrk(p2, "\"\\")); p2++) { 2709c900a9cSSam Ravnborg if (*p2 == '"') { 2719c900a9cSSam Ravnborg *p2 = 0; 2729c900a9cSSam Ravnborg break; 2739c900a9cSSam Ravnborg } 2749c900a9cSSam Ravnborg memmove(p2, p2 + 1, strlen(p2)); 2759c900a9cSSam Ravnborg } 2769c900a9cSSam Ravnborg if (!p2) { 2779c900a9cSSam Ravnborg conf_warning("invalid string found"); 2789c900a9cSSam Ravnborg return 1; 2799c900a9cSSam Ravnborg } 280129ab0d2SMasahiro Yamada } 281d8fc3200SArnaud Lacombe /* fall through */ 2829c900a9cSSam Ravnborg case S_INT: 2839c900a9cSSam Ravnborg case S_HEX: 2849c900a9cSSam Ravnborg if (sym_string_valid(sym, p)) { 285cd81fc82SMasahiro Yamada sym->def[def].val = xstrdup(p); 2869c900a9cSSam Ravnborg sym->flags |= def_flags; 2879c900a9cSSam Ravnborg } else { 28804b19b77SYann E. MORIN if (def != S_DEF_AUTO) 28904b19b77SYann E. MORIN conf_warning("symbol value '%s' invalid for %s", 29004b19b77SYann E. MORIN p, sym->name); 2919c900a9cSSam Ravnborg return 1; 2929c900a9cSSam Ravnborg } 2939c900a9cSSam Ravnborg break; 2949c900a9cSSam Ravnborg default: 2959c900a9cSSam Ravnborg ; 2969c900a9cSSam Ravnborg } 2979c900a9cSSam Ravnborg return 0; 2989c900a9cSSam Ravnborg } 2999c900a9cSSam Ravnborg 3009925d6b7SMasahiro Yamada /* like getline(), but the newline character is stripped away */ 3019925d6b7SMasahiro Yamada static ssize_t getline_stripped(char **lineptr, size_t *n, FILE *stream) 3029925d6b7SMasahiro Yamada { 3039925d6b7SMasahiro Yamada ssize_t len; 3049925d6b7SMasahiro Yamada 305aa8427fbSMasahiro Yamada len = getline(lineptr, n, stream); 3069925d6b7SMasahiro Yamada 3079925d6b7SMasahiro Yamada if (len > 0 && (*lineptr)[len - 1] == '\n') { 3089925d6b7SMasahiro Yamada len--; 3099925d6b7SMasahiro Yamada (*lineptr)[len] = '\0'; 3109925d6b7SMasahiro Yamada 3119925d6b7SMasahiro Yamada if (len > 0 && (*lineptr)[len - 1] == '\r') { 3129925d6b7SMasahiro Yamada len--; 3139925d6b7SMasahiro Yamada (*lineptr)[len] = '\0'; 3149925d6b7SMasahiro Yamada } 3159925d6b7SMasahiro Yamada } 3169925d6b7SMasahiro Yamada 3179925d6b7SMasahiro Yamada return len; 3189925d6b7SMasahiro Yamada } 3199925d6b7SMasahiro Yamada 320669bfad9SRoman Zippel int conf_read_simple(const char *name, int def) 3211da177e4SLinus Torvalds { 3221da177e4SLinus Torvalds FILE *in = NULL; 3231a7a8c6fSCody Schafer char *line = NULL; 3241a7a8c6fSCody Schafer size_t line_asize = 0; 3259925d6b7SMasahiro Yamada char *p, *val; 3261da177e4SLinus Torvalds struct symbol *sym; 32791b69454SMasahiro Yamada int def_flags; 32815d3f766SSergey Senozhatsky const char *warn_unknown, *sym_name; 3291da177e4SLinus Torvalds 3307cd34300SSergey Senozhatsky warn_unknown = getenv("KCONFIG_WARN_UNKNOWN_SYMBOLS"); 3311da177e4SLinus Torvalds if (name) { 3321da177e4SLinus Torvalds in = zconf_fopen(name); 3331da177e4SLinus Torvalds } else { 334b75b0a81SMasahiro Yamada char *env; 335face4374SRoman Zippel 33614cdd3c4SRoman Zippel name = conf_get_configname(); 337ddc97cacSRoman Zippel in = zconf_fopen(name); 338ddc97cacSRoman Zippel if (in) 339ddc97cacSRoman Zippel goto load; 3405ee54659SMasahiro Yamada conf_set_changed(true); 341b75b0a81SMasahiro Yamada 342b75b0a81SMasahiro Yamada env = getenv("KCONFIG_DEFCONFIG_LIST"); 343b75b0a81SMasahiro Yamada if (!env) 344face4374SRoman Zippel return 1; 345face4374SRoman Zippel 346b75b0a81SMasahiro Yamada while (1) { 347b75b0a81SMasahiro Yamada bool is_last; 348b75b0a81SMasahiro Yamada 349b75b0a81SMasahiro Yamada while (isspace(*env)) 350b75b0a81SMasahiro Yamada env++; 351b75b0a81SMasahiro Yamada 352b75b0a81SMasahiro Yamada if (!*env) 353b75b0a81SMasahiro Yamada break; 354b75b0a81SMasahiro Yamada 355b75b0a81SMasahiro Yamada p = env; 356b75b0a81SMasahiro Yamada while (*p && !isspace(*p)) 357b75b0a81SMasahiro Yamada p++; 358b75b0a81SMasahiro Yamada 359b75b0a81SMasahiro Yamada is_last = (*p == '\0'); 360b75b0a81SMasahiro Yamada 361b75b0a81SMasahiro Yamada *p = '\0'; 362b75b0a81SMasahiro Yamada 363b75b0a81SMasahiro Yamada in = zconf_fopen(env); 3641da177e4SLinus Torvalds if (in) { 365694c49a7SSam Ravnborg conf_message("using defaults found in %s", 366b75b0a81SMasahiro Yamada env); 367ddc97cacSRoman Zippel goto load; 3681da177e4SLinus Torvalds } 369b75b0a81SMasahiro Yamada 370b75b0a81SMasahiro Yamada if (is_last) 371b75b0a81SMasahiro Yamada break; 372b75b0a81SMasahiro Yamada 373b75b0a81SMasahiro Yamada env = p + 1; 3741da177e4SLinus Torvalds } 3751da177e4SLinus Torvalds } 3761da177e4SLinus Torvalds if (!in) 3771da177e4SLinus Torvalds return 1; 3781da177e4SLinus Torvalds 379ddc97cacSRoman Zippel load: 380c1a0f5e3SRoman Zippel conf_filename = name; 381c1a0f5e3SRoman Zippel conf_lineno = 0; 382c1a0f5e3SRoman Zippel conf_warnings = 0; 383c1a0f5e3SRoman Zippel 384669bfad9SRoman Zippel def_flags = SYMBOL_DEF << def; 38591b69454SMasahiro Yamada for_all_symbols(sym) { 386669bfad9SRoman Zippel sym->flags &= ~(def_flags|SYMBOL_VALID); 3871da177e4SLinus Torvalds switch (sym->type) { 3881da177e4SLinus Torvalds case S_INT: 3891da177e4SLinus Torvalds case S_HEX: 3901da177e4SLinus Torvalds case S_STRING: 391669bfad9SRoman Zippel free(sym->def[def].val); 392d8fc3200SArnaud Lacombe /* fall through */ 3931da177e4SLinus Torvalds default: 394669bfad9SRoman Zippel sym->def[def].val = NULL; 395669bfad9SRoman Zippel sym->def[def].tri = no; 3961da177e4SLinus Torvalds } 3971da177e4SLinus Torvalds } 3981da177e4SLinus Torvalds 399*95573cacSMasahiro Yamada expr_invalidate_all(); 400*95573cacSMasahiro Yamada 4019925d6b7SMasahiro Yamada while (getline_stripped(&line, &line_asize, in) != -1) { 402f79dc03fSMasahiro Yamada struct menu *choice; 403f79dc03fSMasahiro Yamada 404c1a0f5e3SRoman Zippel conf_lineno++; 40548ab6c9cSMasahiro Yamada 40648ab6c9cSMasahiro Yamada if (!line[0]) /* blank line */ 40748ab6c9cSMasahiro Yamada continue; 40848ab6c9cSMasahiro Yamada 4098baefd30SArnaud Lacombe if (line[0] == '#') { 4104d137ab0SMasahiro Yamada if (line[1] != ' ') 4114d137ab0SMasahiro Yamada continue; 412d854b4b2SMasahiro Yamada p = line + 2; 413d854b4b2SMasahiro Yamada if (memcmp(p, CONFIG_, strlen(CONFIG_))) 4141da177e4SLinus Torvalds continue; 415d854b4b2SMasahiro Yamada sym_name = p + strlen(CONFIG_); 416d854b4b2SMasahiro Yamada p = strchr(sym_name, ' '); 4171da177e4SLinus Torvalds if (!p) 4181da177e4SLinus Torvalds continue; 4191da177e4SLinus Torvalds *p++ = 0; 4204aced3ecSMasahiro Yamada if (strcmp(p, "is not set")) 4211da177e4SLinus Torvalds continue; 42292d4fe0aSMasahiro Yamada 423d854b4b2SMasahiro Yamada val = "n"; 4248baefd30SArnaud Lacombe } else { 42548ab6c9cSMasahiro Yamada if (memcmp(line, CONFIG_, strlen(CONFIG_))) { 4269925d6b7SMasahiro Yamada conf_warning("unexpected data: %s", line); 4271da177e4SLinus Torvalds continue; 4281da177e4SLinus Torvalds } 42975889e9bSMasahiro Yamada 43048ab6c9cSMasahiro Yamada sym_name = line + strlen(CONFIG_); 43148ab6c9cSMasahiro Yamada p = strchr(sym_name, '='); 43248ab6c9cSMasahiro Yamada if (!p) { 43348ab6c9cSMasahiro Yamada conf_warning("unexpected data: %s", line); 43448ab6c9cSMasahiro Yamada continue; 43548ab6c9cSMasahiro Yamada } 43648ab6c9cSMasahiro Yamada *p = 0; 43748ab6c9cSMasahiro Yamada val = p + 1; 43848ab6c9cSMasahiro Yamada } 43948ab6c9cSMasahiro Yamada 440d854b4b2SMasahiro Yamada sym = sym_find(sym_name); 441d854b4b2SMasahiro Yamada if (!sym) { 442d854b4b2SMasahiro Yamada if (def == S_DEF_AUTO) { 443d854b4b2SMasahiro Yamada /* 444d854b4b2SMasahiro Yamada * Reading from include/config/auto.conf. 445d854b4b2SMasahiro Yamada * If CONFIG_FOO previously existed in auto.conf 446d854b4b2SMasahiro Yamada * but it is missing now, include/config/FOO 447d854b4b2SMasahiro Yamada * must be touched. 448d854b4b2SMasahiro Yamada */ 449d854b4b2SMasahiro Yamada conf_touch_dep(sym_name); 450d854b4b2SMasahiro Yamada } else { 451d854b4b2SMasahiro Yamada if (warn_unknown) 452d854b4b2SMasahiro Yamada conf_warning("unknown symbol: %s", sym_name); 453d854b4b2SMasahiro Yamada 454d854b4b2SMasahiro Yamada conf_set_changed(true); 455d854b4b2SMasahiro Yamada } 456d854b4b2SMasahiro Yamada continue; 457d854b4b2SMasahiro Yamada } 458d854b4b2SMasahiro Yamada 459d854b4b2SMasahiro Yamada if (sym->flags & def_flags) 460d854b4b2SMasahiro Yamada conf_warning("override: reassigning to symbol %s", sym->name); 461d854b4b2SMasahiro Yamada 462d854b4b2SMasahiro Yamada if (conf_set_sym_val(sym, def, def_flags, val)) 463d854b4b2SMasahiro Yamada continue; 464d854b4b2SMasahiro Yamada 465f79dc03fSMasahiro Yamada /* 466f79dc03fSMasahiro Yamada * If this is a choice member, give it the highest priority. 467f79dc03fSMasahiro Yamada * If conflicting CONFIG options are given from an input file, 468f79dc03fSMasahiro Yamada * the last one wins. 469f79dc03fSMasahiro Yamada */ 470f79dc03fSMasahiro Yamada choice = sym_get_choice_menu(sym); 471f79dc03fSMasahiro Yamada if (choice) 472f79dc03fSMasahiro Yamada list_move(&sym->choice_link, &choice->choice_members); 4731da177e4SLinus Torvalds } 4741a7a8c6fSCody Schafer free(line); 4751da177e4SLinus Torvalds fclose(in); 4767cd34300SSergey Senozhatsky 47790389160SRoman Zippel return 0; 47890389160SRoman Zippel } 47990389160SRoman Zippel 48090389160SRoman Zippel int conf_read(const char *name) 48190389160SRoman Zippel { 4825d09598dSArnaud Lacombe struct symbol *sym; 48390389160SRoman Zippel 4845ee54659SMasahiro Yamada conf_set_changed(false); 485ddc97cacSRoman Zippel 4866b87b70cSAl Viro if (conf_read_simple(name, S_DEF_USER)) { 4876b87b70cSAl Viro sym_calc_value(modules_sym); 48890389160SRoman Zippel return 1; 4896b87b70cSAl Viro } 4906b87b70cSAl Viro 4916b87b70cSAl Viro sym_calc_value(modules_sym); 49290389160SRoman Zippel 49391b69454SMasahiro Yamada for_all_symbols(sym) { 4941da177e4SLinus Torvalds sym_calc_value(sym); 495a7c79cf3SMasahiro Yamada if (sym_is_choice(sym)) 4965d09598dSArnaud Lacombe continue; 497c1a0f5e3SRoman Zippel if (sym_has_value(sym) && (sym->flags & SYMBOL_WRITE)) { 498c1a0f5e3SRoman Zippel /* check that calculated value agrees with saved value */ 499c1a0f5e3SRoman Zippel switch (sym->type) { 500c1a0f5e3SRoman Zippel case S_BOOLEAN: 501c1a0f5e3SRoman Zippel case S_TRISTATE: 502e3cd5136SMasahiro Yamada if (sym->def[S_DEF_USER].tri == sym_get_tristate_value(sym)) 5035d09598dSArnaud Lacombe continue; 504e3cd5136SMasahiro Yamada break; 505c1a0f5e3SRoman Zippel default: 5060c1822e6SRoman Zippel if (!strcmp(sym->curr.val, sym->def[S_DEF_USER].val)) 5075d09598dSArnaud Lacombe continue; 508c1a0f5e3SRoman Zippel break; 509c1a0f5e3SRoman Zippel } 510c1a0f5e3SRoman Zippel } else if (!sym_has_value(sym) && !(sym->flags & SYMBOL_WRITE)) 511c1a0f5e3SRoman Zippel /* no previous value and not saved */ 5125d09598dSArnaud Lacombe continue; 513cca31837SMasahiro Yamada conf_set_changed(true); 514c1a0f5e3SRoman Zippel /* maybe print value in verbose mode... */ 5151da177e4SLinus Torvalds } 5161da177e4SLinus Torvalds 517cca31837SMasahiro Yamada if (conf_warnings) 5185ee54659SMasahiro Yamada conf_set_changed(true); 5191da177e4SLinus Torvalds 5201da177e4SLinus Torvalds return 0; 5211da177e4SLinus Torvalds } 5221da177e4SLinus Torvalds 523ca51b26bSMasahiro Yamada struct comment_style { 524ca51b26bSMasahiro Yamada const char *decoration; 525ca51b26bSMasahiro Yamada const char *prefix; 526ca51b26bSMasahiro Yamada const char *postfix; 527ca51b26bSMasahiro Yamada }; 528ca51b26bSMasahiro Yamada 529ca51b26bSMasahiro Yamada static const struct comment_style comment_style_pound = { 530ca51b26bSMasahiro Yamada .decoration = "#", 531ca51b26bSMasahiro Yamada .prefix = "#", 532ca51b26bSMasahiro Yamada .postfix = "#", 533ca51b26bSMasahiro Yamada }; 534ca51b26bSMasahiro Yamada 535ca51b26bSMasahiro Yamada static const struct comment_style comment_style_c = { 536ca51b26bSMasahiro Yamada .decoration = " *", 537ca51b26bSMasahiro Yamada .prefix = "/*", 538ca51b26bSMasahiro Yamada .postfix = " */", 539ca51b26bSMasahiro Yamada }; 540ca51b26bSMasahiro Yamada 541ca51b26bSMasahiro Yamada static void conf_write_heading(FILE *fp, const struct comment_style *cs) 542ca51b26bSMasahiro Yamada { 5432f7ab126SMiguel Ojeda if (!cs) 5442f7ab126SMiguel Ojeda return; 5452f7ab126SMiguel Ojeda 546ca51b26bSMasahiro Yamada fprintf(fp, "%s\n", cs->prefix); 547ca51b26bSMasahiro Yamada 548ca51b26bSMasahiro Yamada fprintf(fp, "%s Automatically generated file; DO NOT EDIT.\n", 549ca51b26bSMasahiro Yamada cs->decoration); 550ca51b26bSMasahiro Yamada 551ca51b26bSMasahiro Yamada fprintf(fp, "%s %s\n", cs->decoration, rootmenu.prompt->text); 552ca51b26bSMasahiro Yamada 553ca51b26bSMasahiro Yamada fprintf(fp, "%s\n", cs->postfix); 554ca51b26bSMasahiro Yamada } 555ca51b26bSMasahiro Yamada 55680f7bc77SMasahiro Yamada /* The returned pointer must be freed on the caller side */ 55780f7bc77SMasahiro Yamada static char *escape_string_value(const char *in) 55880f7bc77SMasahiro Yamada { 55980f7bc77SMasahiro Yamada const char *p; 56080f7bc77SMasahiro Yamada char *out; 56180f7bc77SMasahiro Yamada size_t len; 56280f7bc77SMasahiro Yamada 56380f7bc77SMasahiro Yamada len = strlen(in) + strlen("\"\"") + 1; 56480f7bc77SMasahiro Yamada 56580f7bc77SMasahiro Yamada p = in; 56680f7bc77SMasahiro Yamada while (1) { 56780f7bc77SMasahiro Yamada p += strcspn(p, "\"\\"); 56880f7bc77SMasahiro Yamada 56980f7bc77SMasahiro Yamada if (p[0] == '\0') 57080f7bc77SMasahiro Yamada break; 57180f7bc77SMasahiro Yamada 57280f7bc77SMasahiro Yamada len++; 57380f7bc77SMasahiro Yamada p++; 57480f7bc77SMasahiro Yamada } 57580f7bc77SMasahiro Yamada 57680f7bc77SMasahiro Yamada out = xmalloc(len); 57780f7bc77SMasahiro Yamada out[0] = '\0'; 57880f7bc77SMasahiro Yamada 57980f7bc77SMasahiro Yamada strcat(out, "\""); 58080f7bc77SMasahiro Yamada 58180f7bc77SMasahiro Yamada p = in; 58280f7bc77SMasahiro Yamada while (1) { 58380f7bc77SMasahiro Yamada len = strcspn(p, "\"\\"); 58480f7bc77SMasahiro Yamada strncat(out, p, len); 58580f7bc77SMasahiro Yamada p += len; 58680f7bc77SMasahiro Yamada 58780f7bc77SMasahiro Yamada if (p[0] == '\0') 58880f7bc77SMasahiro Yamada break; 58980f7bc77SMasahiro Yamada 59080f7bc77SMasahiro Yamada strcat(out, "\\"); 59180f7bc77SMasahiro Yamada strncat(out, p++, 1); 59280f7bc77SMasahiro Yamada } 59380f7bc77SMasahiro Yamada 59480f7bc77SMasahiro Yamada strcat(out, "\""); 59580f7bc77SMasahiro Yamada 59680f7bc77SMasahiro Yamada return out; 59780f7bc77SMasahiro Yamada } 59880f7bc77SMasahiro Yamada 5996ce45a91SMasahiro Yamada enum output_n { OUTPUT_N, OUTPUT_N_AS_UNSET, OUTPUT_N_NONE }; 60049192f26SSam Ravnborg 6016ce45a91SMasahiro Yamada static void __print_symbol(FILE *fp, struct symbol *sym, enum output_n output_n, 6026ce45a91SMasahiro Yamada bool escape_string) 603e54e692bSArnaud Lacombe { 604229d0cfaSMasahiro Yamada const char *val; 605229d0cfaSMasahiro Yamada char *escaped = NULL; 606e54e692bSArnaud Lacombe 607229d0cfaSMasahiro Yamada if (sym->type == S_UNKNOWN) 608229d0cfaSMasahiro Yamada return; 609229d0cfaSMasahiro Yamada 610229d0cfaSMasahiro Yamada val = sym_get_string_value(sym); 611229d0cfaSMasahiro Yamada 6126ce45a91SMasahiro Yamada if ((sym->type == S_BOOLEAN || sym->type == S_TRISTATE) && 6136ce45a91SMasahiro Yamada output_n != OUTPUT_N && *val == 'n') { 6146ce45a91SMasahiro Yamada if (output_n == OUTPUT_N_AS_UNSET) 6156ce45a91SMasahiro Yamada fprintf(fp, "# %s%s is not set\n", CONFIG_, sym->name); 6166ce45a91SMasahiro Yamada return; 6176ce45a91SMasahiro Yamada } 6186ce45a91SMasahiro Yamada 6196ce45a91SMasahiro Yamada if (sym->type == S_STRING && escape_string) { 62080f7bc77SMasahiro Yamada escaped = escape_string_value(val); 621229d0cfaSMasahiro Yamada val = escaped; 62249192f26SSam Ravnborg } 623229d0cfaSMasahiro Yamada 6246ce45a91SMasahiro Yamada fprintf(fp, "%s%s=%s\n", CONFIG_, sym->name, val); 6256ce45a91SMasahiro Yamada 6266ce45a91SMasahiro Yamada free(escaped); 6276ce45a91SMasahiro Yamada } 6286ce45a91SMasahiro Yamada 6296ce45a91SMasahiro Yamada static void print_symbol_for_dotconfig(FILE *fp, struct symbol *sym) 6306ce45a91SMasahiro Yamada { 6316ce45a91SMasahiro Yamada __print_symbol(fp, sym, OUTPUT_N_AS_UNSET, true); 6326ce45a91SMasahiro Yamada } 6336ce45a91SMasahiro Yamada 6346ce45a91SMasahiro Yamada static void print_symbol_for_autoconf(FILE *fp, struct symbol *sym) 6356ce45a91SMasahiro Yamada { 636129ab0d2SMasahiro Yamada __print_symbol(fp, sym, OUTPUT_N_NONE, false); 6376ce45a91SMasahiro Yamada } 6386ce45a91SMasahiro Yamada 63951d792cbSMasahiro Yamada void print_symbol_for_listconfig(struct symbol *sym) 64051d792cbSMasahiro Yamada { 64151d792cbSMasahiro Yamada __print_symbol(stdout, sym, OUTPUT_N, true); 64251d792cbSMasahiro Yamada } 64351d792cbSMasahiro Yamada 6446ce45a91SMasahiro Yamada static void print_symbol_for_c(FILE *fp, struct symbol *sym) 6456ce45a91SMasahiro Yamada { 6466ce45a91SMasahiro Yamada const char *val; 6476ce45a91SMasahiro Yamada const char *sym_suffix = ""; 6486ce45a91SMasahiro Yamada const char *val_prefix = ""; 6496ce45a91SMasahiro Yamada char *escaped = NULL; 6506ce45a91SMasahiro Yamada 6516ce45a91SMasahiro Yamada if (sym->type == S_UNKNOWN) 6526ce45a91SMasahiro Yamada return; 6536ce45a91SMasahiro Yamada 6546ce45a91SMasahiro Yamada val = sym_get_string_value(sym); 6556ce45a91SMasahiro Yamada 6566ce45a91SMasahiro Yamada switch (sym->type) { 6576ce45a91SMasahiro Yamada case S_BOOLEAN: 6586ce45a91SMasahiro Yamada case S_TRISTATE: 6596ce45a91SMasahiro Yamada switch (*val) { 6606ce45a91SMasahiro Yamada case 'n': 6616ce45a91SMasahiro Yamada return; 6626ce45a91SMasahiro Yamada case 'm': 6636ce45a91SMasahiro Yamada sym_suffix = "_MODULE"; 6646ce45a91SMasahiro Yamada /* fall through */ 6656ce45a91SMasahiro Yamada default: 6666ce45a91SMasahiro Yamada val = "1"; 6676ce45a91SMasahiro Yamada } 6686ce45a91SMasahiro Yamada break; 6696ce45a91SMasahiro Yamada case S_HEX: 6706ce45a91SMasahiro Yamada if (val[0] != '0' || (val[1] != 'x' && val[1] != 'X')) 6716ce45a91SMasahiro Yamada val_prefix = "0x"; 6726ce45a91SMasahiro Yamada break; 6736ce45a91SMasahiro Yamada case S_STRING: 67480f7bc77SMasahiro Yamada escaped = escape_string_value(val); 6756ce45a91SMasahiro Yamada val = escaped; 6766ce45a91SMasahiro Yamada default: 6776ce45a91SMasahiro Yamada break; 6786ce45a91SMasahiro Yamada } 6796ce45a91SMasahiro Yamada 6806ce45a91SMasahiro Yamada fprintf(fp, "#define %s%s%s %s%s\n", CONFIG_, sym->name, sym_suffix, 6816ce45a91SMasahiro Yamada val_prefix, val); 682229d0cfaSMasahiro Yamada 683229d0cfaSMasahiro Yamada free(escaped); 68449192f26SSam Ravnborg } 68549192f26SSam Ravnborg 6862f7ab126SMiguel Ojeda static void print_symbol_for_rustccfg(FILE *fp, struct symbol *sym) 6872f7ab126SMiguel Ojeda { 6882f7ab126SMiguel Ojeda const char *val; 6892f7ab126SMiguel Ojeda const char *val_prefix = ""; 6902f7ab126SMiguel Ojeda char *val_prefixed = NULL; 6912f7ab126SMiguel Ojeda size_t val_prefixed_len; 6922f7ab126SMiguel Ojeda char *escaped = NULL; 6932f7ab126SMiguel Ojeda 6942f7ab126SMiguel Ojeda if (sym->type == S_UNKNOWN) 6952f7ab126SMiguel Ojeda return; 6962f7ab126SMiguel Ojeda 6972f7ab126SMiguel Ojeda val = sym_get_string_value(sym); 6982f7ab126SMiguel Ojeda 6992f7ab126SMiguel Ojeda switch (sym->type) { 7002f7ab126SMiguel Ojeda case S_BOOLEAN: 7012f7ab126SMiguel Ojeda case S_TRISTATE: 7022f7ab126SMiguel Ojeda /* 7032f7ab126SMiguel Ojeda * We do not care about disabled ones, i.e. no need for 7042f7ab126SMiguel Ojeda * what otherwise are "comments" in other printers. 7052f7ab126SMiguel Ojeda */ 7062f7ab126SMiguel Ojeda if (*val == 'n') 7072f7ab126SMiguel Ojeda return; 7082f7ab126SMiguel Ojeda 7092f7ab126SMiguel Ojeda /* 7102f7ab126SMiguel Ojeda * To have similar functionality to the C macro `IS_ENABLED()` 7112f7ab126SMiguel Ojeda * we provide an empty `--cfg CONFIG_X` here in both `y` 7122f7ab126SMiguel Ojeda * and `m` cases. 7132f7ab126SMiguel Ojeda * 7142f7ab126SMiguel Ojeda * Then, the common `fprintf()` below will also give us 7152f7ab126SMiguel Ojeda * a `--cfg CONFIG_X="y"` or `--cfg CONFIG_X="m"`, which can 7162f7ab126SMiguel Ojeda * be used as the equivalent of `IS_BUILTIN()`/`IS_MODULE()`. 7172f7ab126SMiguel Ojeda */ 7182f7ab126SMiguel Ojeda fprintf(fp, "--cfg=%s%s\n", CONFIG_, sym->name); 7192f7ab126SMiguel Ojeda break; 7202f7ab126SMiguel Ojeda case S_HEX: 7212f7ab126SMiguel Ojeda if (val[0] != '0' || (val[1] != 'x' && val[1] != 'X')) 7222f7ab126SMiguel Ojeda val_prefix = "0x"; 7232f7ab126SMiguel Ojeda break; 7242f7ab126SMiguel Ojeda default: 7252f7ab126SMiguel Ojeda break; 7262f7ab126SMiguel Ojeda } 7272f7ab126SMiguel Ojeda 7282f7ab126SMiguel Ojeda if (strlen(val_prefix) > 0) { 7292f7ab126SMiguel Ojeda val_prefixed_len = strlen(val) + strlen(val_prefix) + 1; 7302f7ab126SMiguel Ojeda val_prefixed = xmalloc(val_prefixed_len); 7312f7ab126SMiguel Ojeda snprintf(val_prefixed, val_prefixed_len, "%s%s", val_prefix, val); 7322f7ab126SMiguel Ojeda val = val_prefixed; 7332f7ab126SMiguel Ojeda } 7342f7ab126SMiguel Ojeda 7352f7ab126SMiguel Ojeda /* All values get escaped: the `--cfg` option only takes strings */ 7362f7ab126SMiguel Ojeda escaped = escape_string_value(val); 7372f7ab126SMiguel Ojeda val = escaped; 7382f7ab126SMiguel Ojeda 7392f7ab126SMiguel Ojeda fprintf(fp, "--cfg=%s%s=%s\n", CONFIG_, sym->name, val); 7402f7ab126SMiguel Ojeda 7412f7ab126SMiguel Ojeda free(escaped); 7422f7ab126SMiguel Ojeda free(val_prefixed); 7432f7ab126SMiguel Ojeda } 7442f7ab126SMiguel Ojeda 7457cf3d73bSSam Ravnborg /* 7467cf3d73bSSam Ravnborg * Write out a minimal config. 7477cf3d73bSSam Ravnborg * All values that has default values are skipped as this is redundant. 7487cf3d73bSSam Ravnborg */ 7497cf3d73bSSam Ravnborg int conf_write_defconfig(const char *filename) 7507cf3d73bSSam Ravnborg { 7517cf3d73bSSam Ravnborg struct symbol *sym; 7527cf3d73bSSam Ravnborg struct menu *menu; 7537cf3d73bSSam Ravnborg FILE *out; 7547cf3d73bSSam Ravnborg 7557cf3d73bSSam Ravnborg out = fopen(filename, "w"); 7567cf3d73bSSam Ravnborg if (!out) 7577cf3d73bSSam Ravnborg return 1; 7587cf3d73bSSam Ravnborg 7597cf3d73bSSam Ravnborg sym_clear_all_valid(); 7607cf3d73bSSam Ravnborg 76103c4ecaaSMasahiro Yamada menu_for_each_entry(menu) { 762fb8dd482SMasahiro Yamada struct menu *choice; 763fb8dd482SMasahiro Yamada 7647cf3d73bSSam Ravnborg sym = menu->sym; 765995150e4SMasahiro Yamada 766995150e4SMasahiro Yamada if (!sym || sym_is_choice(sym)) 767995150e4SMasahiro Yamada continue; 768995150e4SMasahiro Yamada 7697cf3d73bSSam Ravnborg sym_calc_value(sym); 7707cf3d73bSSam Ravnborg if (!(sym->flags & SYMBOL_WRITE)) 77103c4ecaaSMasahiro Yamada continue; 7727cf3d73bSSam Ravnborg sym->flags &= ~SYMBOL_WRITE; 773995150e4SMasahiro Yamada /* Skip unchangeable symbols */ 774baa23ec8SMarco Ammon if (!sym_is_changeable(sym)) 77503c4ecaaSMasahiro Yamada continue; 776995150e4SMasahiro Yamada /* Skip symbols that are equal to the default */ 777995150e4SMasahiro Yamada if (!strcmp(sym_get_string_value(sym), sym_get_string_default(sym))) 77803c4ecaaSMasahiro Yamada continue; 7797cf3d73bSSam Ravnborg 780995150e4SMasahiro Yamada /* Skip choice values that are equal to the default */ 781fb8dd482SMasahiro Yamada choice = sym_get_choice_menu(sym); 782fb8dd482SMasahiro Yamada if (choice) { 7837cf3d73bSSam Ravnborg struct symbol *ds; 7847cf3d73bSSam Ravnborg 785e8fcd915SMasahiro Yamada ds = sym_choice_default(choice); 786995150e4SMasahiro Yamada if (sym == ds && sym_get_tristate_value(sym) == yes) 78703c4ecaaSMasahiro Yamada continue; 7887cf3d73bSSam Ravnborg } 7896ce45a91SMasahiro Yamada print_symbol_for_dotconfig(out, sym); 7907cf3d73bSSam Ravnborg } 7917cf3d73bSSam Ravnborg fclose(out); 7927cf3d73bSSam Ravnborg return 0; 7937cf3d73bSSam Ravnborg } 7947cf3d73bSSam Ravnborg 7951da177e4SLinus Torvalds int conf_write(const char *name) 7961da177e4SLinus Torvalds { 797c955ccafSRoman Zippel FILE *out; 7981da177e4SLinus Torvalds struct symbol *sym; 7991da177e4SLinus Torvalds struct menu *menu; 8001da177e4SLinus Torvalds const char *str; 801ceb7f329SMasahiro Yamada char tmpname[PATH_MAX + 1], oldname[PATH_MAX + 1]; 8021da177e4SLinus Torvalds char *env; 803aff11cd9SAlexander Popov bool need_newline = false; 8041da177e4SLinus Torvalds 805ceb7f329SMasahiro Yamada if (!name) 806ceb7f329SMasahiro Yamada name = conf_get_configname(); 807ceb7f329SMasahiro Yamada 808ceb7f329SMasahiro Yamada if (!*name) { 809ceb7f329SMasahiro Yamada fprintf(stderr, "config name is empty\n"); 810ceb7f329SMasahiro Yamada return -1; 811ceb7f329SMasahiro Yamada } 8121da177e4SLinus Torvalds 8130608182aSMasahiro Yamada if (is_dir(name)) { 814ceb7f329SMasahiro Yamada fprintf(stderr, "%s: Is a directory\n", name); 815ceb7f329SMasahiro Yamada return -1; 816ceb7f329SMasahiro Yamada } 8171da177e4SLinus Torvalds 818580c5b3eSMasahiro Yamada if (make_parent_dir(name)) 819580c5b3eSMasahiro Yamada return -1; 820580c5b3eSMasahiro Yamada 82114cdd3c4SRoman Zippel env = getenv("KCONFIG_OVERWRITECONFIG"); 822ceb7f329SMasahiro Yamada if (env && *env) { 82314cdd3c4SRoman Zippel *tmpname = 0; 824ceb7f329SMasahiro Yamada out = fopen(name, "w"); 825ceb7f329SMasahiro Yamada } else { 826ceb7f329SMasahiro Yamada snprintf(tmpname, sizeof(tmpname), "%s.%d.tmp", 827ceb7f329SMasahiro Yamada name, (int)getpid()); 828ceb7f329SMasahiro Yamada out = fopen(tmpname, "w"); 82914cdd3c4SRoman Zippel } 8301da177e4SLinus Torvalds if (!out) 8311da177e4SLinus Torvalds return 1; 83214cdd3c4SRoman Zippel 833ca51b26bSMasahiro Yamada conf_write_heading(out, &comment_style_pound); 8341da177e4SLinus Torvalds 835b3214293SKarsten Wiese if (!conf_get_changed()) 8361da177e4SLinus Torvalds sym_clear_all_valid(); 8371da177e4SLinus Torvalds 8381da177e4SLinus Torvalds menu = rootmenu.list; 8391da177e4SLinus Torvalds while (menu) { 8401da177e4SLinus Torvalds sym = menu->sym; 8411da177e4SLinus Torvalds if (!sym) { 8421da177e4SLinus Torvalds if (!menu_is_visible(menu)) 8431da177e4SLinus Torvalds goto next; 8441da177e4SLinus Torvalds str = menu_get_prompt(menu); 8451da177e4SLinus Torvalds fprintf(out, "\n" 8461da177e4SLinus Torvalds "#\n" 8471da177e4SLinus Torvalds "# %s\n" 8481da177e4SLinus Torvalds "#\n", str); 849aff11cd9SAlexander Popov need_newline = false; 8501da251c6SMasahiro Yamada } else if (!sym_is_choice(sym) && 8518e2442a5SMasahiro Yamada !(sym->flags & SYMBOL_WRITTEN)) { 8521da177e4SLinus Torvalds sym_calc_value(sym); 8531da177e4SLinus Torvalds if (!(sym->flags & SYMBOL_WRITE)) 8541da177e4SLinus Torvalds goto next; 855aff11cd9SAlexander Popov if (need_newline) { 856aff11cd9SAlexander Popov fprintf(out, "\n"); 857aff11cd9SAlexander Popov need_newline = false; 858aff11cd9SAlexander Popov } 8598e2442a5SMasahiro Yamada sym->flags |= SYMBOL_WRITTEN; 8606ce45a91SMasahiro Yamada print_symbol_for_dotconfig(out, sym); 8611da177e4SLinus Torvalds } 8621da177e4SLinus Torvalds 8631da177e4SLinus Torvalds next: 8641da177e4SLinus Torvalds if (menu->list) { 8651da177e4SLinus Torvalds menu = menu->list; 8661da177e4SLinus Torvalds continue; 8671da177e4SLinus Torvalds } 868a7d4f58eSMasahiro Yamada 869a7d4f58eSMasahiro Yamada end_check: 870a7d4f58eSMasahiro Yamada if (!menu->sym && menu_is_visible(menu) && menu != &rootmenu && 871a7d4f58eSMasahiro Yamada menu->prompt->type == P_MENU) { 872a7d4f58eSMasahiro Yamada fprintf(out, "# end of %s\n", menu_get_prompt(menu)); 873aff11cd9SAlexander Popov need_newline = true; 874aff11cd9SAlexander Popov } 875a7d4f58eSMasahiro Yamada 8761da177e4SLinus Torvalds if (menu->next) { 8771da177e4SLinus Torvalds menu = menu->next; 878a7d4f58eSMasahiro Yamada } else { 879a7d4f58eSMasahiro Yamada menu = menu->parent; 880a7d4f58eSMasahiro Yamada if (menu) 881a7d4f58eSMasahiro Yamada goto end_check; 8821da177e4SLinus Torvalds } 8831da177e4SLinus Torvalds } 8841da177e4SLinus Torvalds fclose(out); 88514cdd3c4SRoman Zippel 88691b69454SMasahiro Yamada for_all_symbols(sym) 8870c5b6c28SM. Vefa Bicakci sym->flags &= ~SYMBOL_WRITTEN; 8880c5b6c28SM. Vefa Bicakci 88914cdd3c4SRoman Zippel if (*tmpname) { 89067424f61SMasahiro Yamada if (is_same(name, tmpname)) { 89167424f61SMasahiro Yamada conf_message("No change to %s", name); 89267424f61SMasahiro Yamada unlink(tmpname); 8935ee54659SMasahiro Yamada conf_set_changed(false); 89467424f61SMasahiro Yamada return 0; 89567424f61SMasahiro Yamada } 89667424f61SMasahiro Yamada 897ceb7f329SMasahiro Yamada snprintf(oldname, sizeof(oldname), "%s.old", name); 898ceb7f329SMasahiro Yamada rename(name, oldname); 899ceb7f329SMasahiro Yamada if (rename(tmpname, name)) 9001da177e4SLinus Torvalds return 1; 90114cdd3c4SRoman Zippel } 9021da177e4SLinus Torvalds 903ceb7f329SMasahiro Yamada conf_message("configuration written to %s", name); 904ddc97cacSRoman Zippel 9055ee54659SMasahiro Yamada conf_set_changed(false); 9061da177e4SLinus Torvalds 9071da177e4SLinus Torvalds return 0; 9081da177e4SLinus Torvalds } 909c955ccafSRoman Zippel 910a2ff4040SMasahiro Yamada /* write a dependency file as used by kbuild to track dependencies */ 91100d674cbSMasahiro Yamada static int conf_write_autoconf_cmd(const char *autoconf_name) 912a2ff4040SMasahiro Yamada { 91300d674cbSMasahiro Yamada char name[PATH_MAX], tmp[PATH_MAX]; 914a2ff4040SMasahiro Yamada FILE *out; 91500d674cbSMasahiro Yamada int ret; 916a2ff4040SMasahiro Yamada 91700d674cbSMasahiro Yamada ret = snprintf(name, sizeof(name), "%s.cmd", autoconf_name); 91800d674cbSMasahiro Yamada if (ret >= sizeof(name)) /* check truncation */ 91900d674cbSMasahiro Yamada return -1; 92079123b13SMasahiro Yamada 92179123b13SMasahiro Yamada if (make_parent_dir(name)) 92200d674cbSMasahiro Yamada return -1; 92300d674cbSMasahiro Yamada 92400d674cbSMasahiro Yamada ret = snprintf(tmp, sizeof(tmp), "%s.cmd.tmp", autoconf_name); 92500d674cbSMasahiro Yamada if (ret >= sizeof(tmp)) /* check truncation */ 92600d674cbSMasahiro Yamada return -1; 92700d674cbSMasahiro Yamada 92800d674cbSMasahiro Yamada out = fopen(tmp, "w"); 92900d674cbSMasahiro Yamada if (!out) { 93000d674cbSMasahiro Yamada perror("fopen"); 93100d674cbSMasahiro Yamada return -1; 93200d674cbSMasahiro Yamada } 93300d674cbSMasahiro Yamada 93456e634b0SMasahiro Yamada fprintf(out, "autoconfig := %s\n", autoconf_name); 93556e634b0SMasahiro Yamada 936526396b7SMasahiro Yamada fputs(str_get(&autoconf_cmd), out); 93700d674cbSMasahiro Yamada 938868653f4SMasahiro Yamada fflush(out); 939d23a0c37SMasahiro Yamada ret = ferror(out); /* error check for all fprintf() calls */ 94000d674cbSMasahiro Yamada fclose(out); 941d23a0c37SMasahiro Yamada if (ret) 942d23a0c37SMasahiro Yamada return -1; 94300d674cbSMasahiro Yamada 94400d674cbSMasahiro Yamada if (rename(tmp, name)) { 94500d674cbSMasahiro Yamada perror("rename"); 94600d674cbSMasahiro Yamada return -1; 94700d674cbSMasahiro Yamada } 94800d674cbSMasahiro Yamada 949a2ff4040SMasahiro Yamada return 0; 950a2ff4040SMasahiro Yamada } 951a2ff4040SMasahiro Yamada 9520849d212SMasahiro Yamada static int conf_touch_deps(void) 9532e3646e5SRoman Zippel { 9541b9e740aSJing Leng const char *name, *tmp; 9552e3646e5SRoman Zippel struct symbol *sym; 95691b69454SMasahiro Yamada int res; 9571508fec8SMasahiro Yamada 95812122f62SMarkus Heidelberg name = conf_get_autoconfig_name(); 9591b9e740aSJing Leng tmp = strrchr(name, '/'); 9601b9e740aSJing Leng depfile_prefix_len = tmp ? tmp - name + 1 : 0; 9611b9e740aSJing Leng if (depfile_prefix_len + 1 > sizeof(depfile_path)) 9621b9e740aSJing Leng return -1; 9631b9e740aSJing Leng 9641b9e740aSJing Leng strncpy(depfile_path, name, depfile_prefix_len); 9651b9e740aSJing Leng depfile_path[depfile_prefix_len] = 0; 9661b9e740aSJing Leng 9672e3646e5SRoman Zippel conf_read_simple(name, S_DEF_AUTO); 9686b87b70cSAl Viro sym_calc_value(modules_sym); 9692e3646e5SRoman Zippel 97091b69454SMasahiro Yamada for_all_symbols(sym) { 9712e3646e5SRoman Zippel sym_calc_value(sym); 972a7c79cf3SMasahiro Yamada if (sym_is_choice(sym)) 9732e3646e5SRoman Zippel continue; 9742e3646e5SRoman Zippel if (sym->flags & SYMBOL_WRITE) { 9752e3646e5SRoman Zippel if (sym->flags & SYMBOL_DEF_AUTO) { 9762e3646e5SRoman Zippel /* 9772e3646e5SRoman Zippel * symbol has old and new value, 9782e3646e5SRoman Zippel * so compare them... 9792e3646e5SRoman Zippel */ 9802e3646e5SRoman Zippel switch (sym->type) { 9812e3646e5SRoman Zippel case S_BOOLEAN: 9822e3646e5SRoman Zippel case S_TRISTATE: 9832e3646e5SRoman Zippel if (sym_get_tristate_value(sym) == 9842e3646e5SRoman Zippel sym->def[S_DEF_AUTO].tri) 9852e3646e5SRoman Zippel continue; 9862e3646e5SRoman Zippel break; 9872e3646e5SRoman Zippel case S_STRING: 9882e3646e5SRoman Zippel case S_HEX: 9892e3646e5SRoman Zippel case S_INT: 9902e3646e5SRoman Zippel if (!strcmp(sym_get_string_value(sym), 9912e3646e5SRoman Zippel sym->def[S_DEF_AUTO].val)) 9922e3646e5SRoman Zippel continue; 9932e3646e5SRoman Zippel break; 9942e3646e5SRoman Zippel default: 9952e3646e5SRoman Zippel break; 9962e3646e5SRoman Zippel } 9972e3646e5SRoman Zippel } else { 9982e3646e5SRoman Zippel /* 9992e3646e5SRoman Zippel * If there is no old value, only 'no' (unset) 10002e3646e5SRoman Zippel * is allowed as new value. 10012e3646e5SRoman Zippel */ 10022e3646e5SRoman Zippel switch (sym->type) { 10032e3646e5SRoman Zippel case S_BOOLEAN: 10042e3646e5SRoman Zippel case S_TRISTATE: 10052e3646e5SRoman Zippel if (sym_get_tristate_value(sym) == no) 10062e3646e5SRoman Zippel continue; 10072e3646e5SRoman Zippel break; 10082e3646e5SRoman Zippel default: 10092e3646e5SRoman Zippel break; 10102e3646e5SRoman Zippel } 10112e3646e5SRoman Zippel } 10122e3646e5SRoman Zippel } else if (!(sym->flags & SYMBOL_DEF_AUTO)) 10132e3646e5SRoman Zippel /* There is neither an old nor a new value. */ 10142e3646e5SRoman Zippel continue; 10152e3646e5SRoman Zippel /* else 10162e3646e5SRoman Zippel * There is an old value, but no new value ('no' (unset) 10172e3646e5SRoman Zippel * isn't saved in auto.conf, so the old value is always 10182e3646e5SRoman Zippel * different from 'no'). 10192e3646e5SRoman Zippel */ 10202e3646e5SRoman Zippel 10211508fec8SMasahiro Yamada res = conf_touch_dep(sym->name); 10221508fec8SMasahiro Yamada if (res) 10232e3646e5SRoman Zippel return res; 10242e3646e5SRoman Zippel } 10252e3646e5SRoman Zippel 10261508fec8SMasahiro Yamada return 0; 10271508fec8SMasahiro Yamada } 10281508fec8SMasahiro Yamada 102957ddd07cSMasahiro Yamada static int __conf_write_autoconf(const char *filename, 103057ddd07cSMasahiro Yamada void (*print_symbol)(FILE *, struct symbol *), 103157ddd07cSMasahiro Yamada const struct comment_style *comment_style) 103257ddd07cSMasahiro Yamada { 103357ddd07cSMasahiro Yamada char tmp[PATH_MAX]; 103457ddd07cSMasahiro Yamada FILE *file; 103557ddd07cSMasahiro Yamada struct symbol *sym; 103691b69454SMasahiro Yamada int ret; 103757ddd07cSMasahiro Yamada 103857ddd07cSMasahiro Yamada if (make_parent_dir(filename)) 103957ddd07cSMasahiro Yamada return -1; 104057ddd07cSMasahiro Yamada 104157ddd07cSMasahiro Yamada ret = snprintf(tmp, sizeof(tmp), "%s.tmp", filename); 104257ddd07cSMasahiro Yamada if (ret >= sizeof(tmp)) /* check truncation */ 104357ddd07cSMasahiro Yamada return -1; 104457ddd07cSMasahiro Yamada 104557ddd07cSMasahiro Yamada file = fopen(tmp, "w"); 104657ddd07cSMasahiro Yamada if (!file) { 104757ddd07cSMasahiro Yamada perror("fopen"); 104857ddd07cSMasahiro Yamada return -1; 104957ddd07cSMasahiro Yamada } 105057ddd07cSMasahiro Yamada 105157ddd07cSMasahiro Yamada conf_write_heading(file, comment_style); 105257ddd07cSMasahiro Yamada 105391b69454SMasahiro Yamada for_all_symbols(sym) 105457ddd07cSMasahiro Yamada if ((sym->flags & SYMBOL_WRITE) && sym->name) 105557ddd07cSMasahiro Yamada print_symbol(file, sym); 105657ddd07cSMasahiro Yamada 1057868653f4SMasahiro Yamada fflush(file); 105857ddd07cSMasahiro Yamada /* check possible errors in conf_write_heading() and print_symbol() */ 1059d23a0c37SMasahiro Yamada ret = ferror(file); 106057ddd07cSMasahiro Yamada fclose(file); 1061d23a0c37SMasahiro Yamada if (ret) 1062d23a0c37SMasahiro Yamada return -1; 106357ddd07cSMasahiro Yamada 106457ddd07cSMasahiro Yamada if (rename(tmp, filename)) { 106557ddd07cSMasahiro Yamada perror("rename"); 106657ddd07cSMasahiro Yamada return -1; 106757ddd07cSMasahiro Yamada } 106857ddd07cSMasahiro Yamada 106957ddd07cSMasahiro Yamada return 0; 107057ddd07cSMasahiro Yamada } 107157ddd07cSMasahiro Yamada 107200c864f8SMasahiro Yamada int conf_write_autoconf(int overwrite) 1073c955ccafSRoman Zippel { 1074c955ccafSRoman Zippel struct symbol *sym; 107500c864f8SMasahiro Yamada const char *autoconf_name = conf_get_autoconfig_name(); 107691b69454SMasahiro Yamada int ret; 1077c955ccafSRoman Zippel 107800c864f8SMasahiro Yamada if (!overwrite && is_present(autoconf_name)) 107900c864f8SMasahiro Yamada return 0; 108000c864f8SMasahiro Yamada 108100d674cbSMasahiro Yamada ret = conf_write_autoconf_cmd(autoconf_name); 108200d674cbSMasahiro Yamada if (ret) 108300d674cbSMasahiro Yamada return -1; 1084c955ccafSRoman Zippel 10850849d212SMasahiro Yamada if (conf_touch_deps()) 10862e3646e5SRoman Zippel return 1; 10872e3646e5SRoman Zippel 108891b69454SMasahiro Yamada for_all_symbols(sym) 1089953742c8SArnaud Lacombe sym_calc_value(sym); 1090953742c8SArnaud Lacombe 109157ddd07cSMasahiro Yamada ret = __conf_write_autoconf(conf_get_autoheader_name(), 109257ddd07cSMasahiro Yamada print_symbol_for_c, 109357ddd07cSMasahiro Yamada &comment_style_c); 109457ddd07cSMasahiro Yamada if (ret) 109557ddd07cSMasahiro Yamada return ret; 1096c955ccafSRoman Zippel 10972f7ab126SMiguel Ojeda ret = __conf_write_autoconf(conf_get_rustccfg_name(), 10982f7ab126SMiguel Ojeda print_symbol_for_rustccfg, 10992f7ab126SMiguel Ojeda NULL); 11002f7ab126SMiguel Ojeda if (ret) 11012f7ab126SMiguel Ojeda return ret; 11022f7ab126SMiguel Ojeda 1103c955ccafSRoman Zippel /* 110457ddd07cSMasahiro Yamada * Create include/config/auto.conf. This must be the last step because 110557ddd07cSMasahiro Yamada * Kbuild has a dependency on auto.conf and this marks the successful 110657ddd07cSMasahiro Yamada * completion of the previous steps. 1107c955ccafSRoman Zippel */ 110857ddd07cSMasahiro Yamada ret = __conf_write_autoconf(conf_get_autoconfig_name(), 110957ddd07cSMasahiro Yamada print_symbol_for_autoconf, 111057ddd07cSMasahiro Yamada &comment_style_pound); 111157ddd07cSMasahiro Yamada if (ret) 111257ddd07cSMasahiro Yamada return ret; 1113c955ccafSRoman Zippel 1114c955ccafSRoman Zippel return 0; 1115c955ccafSRoman Zippel } 1116b3214293SKarsten Wiese 11175ee54659SMasahiro Yamada static bool conf_changed; 111803638aaaSMasahiro Yamada static void (*conf_changed_callback)(bool); 1119bfc10001SKarsten Wiese 11205ee54659SMasahiro Yamada void conf_set_changed(bool val) 1121bfc10001SKarsten Wiese { 112203638aaaSMasahiro Yamada if (conf_changed_callback && conf_changed != val) 112303638aaaSMasahiro Yamada conf_changed_callback(val); 1124bfc10001SKarsten Wiese 11255ee54659SMasahiro Yamada conf_changed = val; 1126bfc10001SKarsten Wiese } 1127bfc10001SKarsten Wiese 1128b3214293SKarsten Wiese bool conf_get_changed(void) 1129b3214293SKarsten Wiese { 11305ee54659SMasahiro Yamada return conf_changed; 1131b3214293SKarsten Wiese } 11323b354c55SKarsten Wiese 113303638aaaSMasahiro Yamada void conf_set_changed_callback(void (*fn)(bool)) 11343b354c55SKarsten Wiese { 11353b354c55SKarsten Wiese conf_changed_callback = fn; 11363b354c55SKarsten Wiese } 1137