10c874100SMasahiro Yamada // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds * Copyright (C) 2002 Roman Zippel <[email protected]>
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 */
is_present(const char * path)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 */
is_dir(const char * path)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 */
is_same(const char * file1,const char * file2)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 */
make_parent_dir(const char * path)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' */
conf_touch_dep(const char * 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
conf_errors(void)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
conf_warning(const char * fmt,...)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
conf_default_message_callback(const char * s)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;
conf_set_message_callback(void (* fn)(const char * s))1895accd7f3SMasahiro Yamada void conf_set_message_callback(void (*fn)(const char *s))
19042368c37SMichal Marek {
19142368c37SMichal Marek conf_message_callback = fn;
19242368c37SMichal Marek }
19342368c37SMichal Marek
conf_message(const char * fmt,...)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
conf_get_configname(void)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
conf_get_autoconfig_name(void)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
conf_get_autoheader_name(void)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
conf_get_rustccfg_name(void)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
conf_set_sym_val(struct symbol * sym,int def,int def_flags,char * p)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 */
getline_stripped(char ** lineptr,size_t * n,FILE * stream)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
conf_read_simple(const char * name,int def)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
363a314f52aSMasahiro Yamada name = env;
364a314f52aSMasahiro Yamada
365a314f52aSMasahiro Yamada in = zconf_fopen(name);
3661da177e4SLinus Torvalds if (in) {
367694c49a7SSam Ravnborg conf_message("using defaults found in %s",
368a314f52aSMasahiro Yamada name);
369ddc97cacSRoman Zippel goto load;
3701da177e4SLinus Torvalds }
371b75b0a81SMasahiro Yamada
372b75b0a81SMasahiro Yamada if (is_last)
373b75b0a81SMasahiro Yamada break;
374b75b0a81SMasahiro Yamada
375b75b0a81SMasahiro Yamada env = p + 1;
3761da177e4SLinus Torvalds }
3771da177e4SLinus Torvalds }
3781da177e4SLinus Torvalds if (!in)
3791da177e4SLinus Torvalds return 1;
3801da177e4SLinus Torvalds
381ddc97cacSRoman Zippel load:
382c1a0f5e3SRoman Zippel conf_filename = name;
383c1a0f5e3SRoman Zippel conf_lineno = 0;
384c1a0f5e3SRoman Zippel conf_warnings = 0;
385c1a0f5e3SRoman Zippel
386669bfad9SRoman Zippel def_flags = SYMBOL_DEF << def;
38791b69454SMasahiro Yamada for_all_symbols(sym) {
388*226ac19cSMasahiro Yamada sym->flags &= ~def_flags;
3891da177e4SLinus Torvalds switch (sym->type) {
3901da177e4SLinus Torvalds case S_INT:
3911da177e4SLinus Torvalds case S_HEX:
3921da177e4SLinus Torvalds case S_STRING:
393669bfad9SRoman Zippel free(sym->def[def].val);
394d8fc3200SArnaud Lacombe /* fall through */
3951da177e4SLinus Torvalds default:
396669bfad9SRoman Zippel sym->def[def].val = NULL;
397669bfad9SRoman Zippel sym->def[def].tri = no;
3981da177e4SLinus Torvalds }
3991da177e4SLinus Torvalds }
4001da177e4SLinus Torvalds
401*226ac19cSMasahiro Yamada if (def == S_DEF_USER) {
402*226ac19cSMasahiro Yamada for_all_symbols(sym)
403*226ac19cSMasahiro Yamada sym->flags &= ~SYMBOL_VALID;
40495573cacSMasahiro Yamada expr_invalidate_all();
405*226ac19cSMasahiro Yamada }
40695573cacSMasahiro Yamada
4079925d6b7SMasahiro Yamada while (getline_stripped(&line, &line_asize, in) != -1) {
408f79dc03fSMasahiro Yamada struct menu *choice;
409f79dc03fSMasahiro Yamada
410c1a0f5e3SRoman Zippel conf_lineno++;
41148ab6c9cSMasahiro Yamada
41248ab6c9cSMasahiro Yamada if (!line[0]) /* blank line */
41348ab6c9cSMasahiro Yamada continue;
41448ab6c9cSMasahiro Yamada
4158baefd30SArnaud Lacombe if (line[0] == '#') {
4164d137ab0SMasahiro Yamada if (line[1] != ' ')
4174d137ab0SMasahiro Yamada continue;
418d854b4b2SMasahiro Yamada p = line + 2;
419d854b4b2SMasahiro Yamada if (memcmp(p, CONFIG_, strlen(CONFIG_)))
4201da177e4SLinus Torvalds continue;
421d854b4b2SMasahiro Yamada sym_name = p + strlen(CONFIG_);
422d854b4b2SMasahiro Yamada p = strchr(sym_name, ' ');
4231da177e4SLinus Torvalds if (!p)
4241da177e4SLinus Torvalds continue;
4251da177e4SLinus Torvalds *p++ = 0;
4264aced3ecSMasahiro Yamada if (strcmp(p, "is not set"))
4271da177e4SLinus Torvalds continue;
42892d4fe0aSMasahiro Yamada
429d854b4b2SMasahiro Yamada val = "n";
4308baefd30SArnaud Lacombe } else {
43148ab6c9cSMasahiro Yamada if (memcmp(line, CONFIG_, strlen(CONFIG_))) {
4329925d6b7SMasahiro Yamada conf_warning("unexpected data: %s", line);
4331da177e4SLinus Torvalds continue;
4341da177e4SLinus Torvalds }
43575889e9bSMasahiro Yamada
43648ab6c9cSMasahiro Yamada sym_name = line + strlen(CONFIG_);
43748ab6c9cSMasahiro Yamada p = strchr(sym_name, '=');
43848ab6c9cSMasahiro Yamada if (!p) {
43948ab6c9cSMasahiro Yamada conf_warning("unexpected data: %s", line);
44048ab6c9cSMasahiro Yamada continue;
44148ab6c9cSMasahiro Yamada }
44248ab6c9cSMasahiro Yamada *p = 0;
44348ab6c9cSMasahiro Yamada val = p + 1;
44448ab6c9cSMasahiro Yamada }
44548ab6c9cSMasahiro Yamada
446d854b4b2SMasahiro Yamada sym = sym_find(sym_name);
447d854b4b2SMasahiro Yamada if (!sym) {
448d854b4b2SMasahiro Yamada if (def == S_DEF_AUTO) {
449d854b4b2SMasahiro Yamada /*
450d854b4b2SMasahiro Yamada * Reading from include/config/auto.conf.
451d854b4b2SMasahiro Yamada * If CONFIG_FOO previously existed in auto.conf
452d854b4b2SMasahiro Yamada * but it is missing now, include/config/FOO
453d854b4b2SMasahiro Yamada * must be touched.
454d854b4b2SMasahiro Yamada */
455d854b4b2SMasahiro Yamada conf_touch_dep(sym_name);
456d854b4b2SMasahiro Yamada } else {
457d854b4b2SMasahiro Yamada if (warn_unknown)
458d854b4b2SMasahiro Yamada conf_warning("unknown symbol: %s", sym_name);
459d854b4b2SMasahiro Yamada
460d854b4b2SMasahiro Yamada conf_set_changed(true);
461d854b4b2SMasahiro Yamada }
462d854b4b2SMasahiro Yamada continue;
463d854b4b2SMasahiro Yamada }
464d854b4b2SMasahiro Yamada
465d854b4b2SMasahiro Yamada if (sym->flags & def_flags)
466d854b4b2SMasahiro Yamada conf_warning("override: reassigning to symbol %s", sym->name);
467d854b4b2SMasahiro Yamada
468d854b4b2SMasahiro Yamada if (conf_set_sym_val(sym, def, def_flags, val))
469d854b4b2SMasahiro Yamada continue;
470d854b4b2SMasahiro Yamada
471*226ac19cSMasahiro Yamada if (def != S_DEF_USER)
472*226ac19cSMasahiro Yamada continue;
473*226ac19cSMasahiro Yamada
474f79dc03fSMasahiro Yamada /*
475f79dc03fSMasahiro Yamada * If this is a choice member, give it the highest priority.
476f79dc03fSMasahiro Yamada * If conflicting CONFIG options are given from an input file,
477f79dc03fSMasahiro Yamada * the last one wins.
478f79dc03fSMasahiro Yamada */
479f79dc03fSMasahiro Yamada choice = sym_get_choice_menu(sym);
480f79dc03fSMasahiro Yamada if (choice)
481f79dc03fSMasahiro Yamada list_move(&sym->choice_link, &choice->choice_members);
4821da177e4SLinus Torvalds }
4831a7a8c6fSCody Schafer free(line);
4841da177e4SLinus Torvalds fclose(in);
4857cd34300SSergey Senozhatsky
48690389160SRoman Zippel return 0;
48790389160SRoman Zippel }
48890389160SRoman Zippel
conf_read(const char * name)48990389160SRoman Zippel int conf_read(const char *name)
49090389160SRoman Zippel {
4915d09598dSArnaud Lacombe struct symbol *sym;
49290389160SRoman Zippel
4935ee54659SMasahiro Yamada conf_set_changed(false);
494ddc97cacSRoman Zippel
4956b87b70cSAl Viro if (conf_read_simple(name, S_DEF_USER)) {
4966b87b70cSAl Viro sym_calc_value(modules_sym);
49790389160SRoman Zippel return 1;
4986b87b70cSAl Viro }
4996b87b70cSAl Viro
5006b87b70cSAl Viro sym_calc_value(modules_sym);
50190389160SRoman Zippel
50291b69454SMasahiro Yamada for_all_symbols(sym) {
5031da177e4SLinus Torvalds sym_calc_value(sym);
504a7c79cf3SMasahiro Yamada if (sym_is_choice(sym))
5055d09598dSArnaud Lacombe continue;
506c1a0f5e3SRoman Zippel if (sym_has_value(sym) && (sym->flags & SYMBOL_WRITE)) {
507c1a0f5e3SRoman Zippel /* check that calculated value agrees with saved value */
508c1a0f5e3SRoman Zippel switch (sym->type) {
509c1a0f5e3SRoman Zippel case S_BOOLEAN:
510c1a0f5e3SRoman Zippel case S_TRISTATE:
511e3cd5136SMasahiro Yamada if (sym->def[S_DEF_USER].tri == sym_get_tristate_value(sym))
5125d09598dSArnaud Lacombe continue;
513e3cd5136SMasahiro Yamada break;
514c1a0f5e3SRoman Zippel default:
5150c1822e6SRoman Zippel if (!strcmp(sym->curr.val, sym->def[S_DEF_USER].val))
5165d09598dSArnaud Lacombe continue;
517c1a0f5e3SRoman Zippel break;
518c1a0f5e3SRoman Zippel }
519c1a0f5e3SRoman Zippel } else if (!sym_has_value(sym) && !(sym->flags & SYMBOL_WRITE))
520c1a0f5e3SRoman Zippel /* no previous value and not saved */
5215d09598dSArnaud Lacombe continue;
522cca31837SMasahiro Yamada conf_set_changed(true);
523c1a0f5e3SRoman Zippel /* maybe print value in verbose mode... */
5241da177e4SLinus Torvalds }
5251da177e4SLinus Torvalds
526cca31837SMasahiro Yamada if (conf_warnings)
5275ee54659SMasahiro Yamada conf_set_changed(true);
5281da177e4SLinus Torvalds
5291da177e4SLinus Torvalds return 0;
5301da177e4SLinus Torvalds }
5311da177e4SLinus Torvalds
532ca51b26bSMasahiro Yamada struct comment_style {
533ca51b26bSMasahiro Yamada const char *decoration;
534ca51b26bSMasahiro Yamada const char *prefix;
535ca51b26bSMasahiro Yamada const char *postfix;
536ca51b26bSMasahiro Yamada };
537ca51b26bSMasahiro Yamada
538ca51b26bSMasahiro Yamada static const struct comment_style comment_style_pound = {
539ca51b26bSMasahiro Yamada .decoration = "#",
540ca51b26bSMasahiro Yamada .prefix = "#",
541ca51b26bSMasahiro Yamada .postfix = "#",
542ca51b26bSMasahiro Yamada };
543ca51b26bSMasahiro Yamada
544ca51b26bSMasahiro Yamada static const struct comment_style comment_style_c = {
545ca51b26bSMasahiro Yamada .decoration = " *",
546ca51b26bSMasahiro Yamada .prefix = "/*",
547ca51b26bSMasahiro Yamada .postfix = " */",
548ca51b26bSMasahiro Yamada };
549ca51b26bSMasahiro Yamada
conf_write_heading(FILE * fp,const struct comment_style * cs)550ca51b26bSMasahiro Yamada static void conf_write_heading(FILE *fp, const struct comment_style *cs)
551ca51b26bSMasahiro Yamada {
5522f7ab126SMiguel Ojeda if (!cs)
5532f7ab126SMiguel Ojeda return;
5542f7ab126SMiguel Ojeda
555ca51b26bSMasahiro Yamada fprintf(fp, "%s\n", cs->prefix);
556ca51b26bSMasahiro Yamada
557ca51b26bSMasahiro Yamada fprintf(fp, "%s Automatically generated file; DO NOT EDIT.\n",
558ca51b26bSMasahiro Yamada cs->decoration);
559ca51b26bSMasahiro Yamada
560ca51b26bSMasahiro Yamada fprintf(fp, "%s %s\n", cs->decoration, rootmenu.prompt->text);
561ca51b26bSMasahiro Yamada
562ca51b26bSMasahiro Yamada fprintf(fp, "%s\n", cs->postfix);
563ca51b26bSMasahiro Yamada }
564ca51b26bSMasahiro Yamada
56580f7bc77SMasahiro Yamada /* The returned pointer must be freed on the caller side */
escape_string_value(const char * in)56680f7bc77SMasahiro Yamada static char *escape_string_value(const char *in)
56780f7bc77SMasahiro Yamada {
56880f7bc77SMasahiro Yamada const char *p;
56980f7bc77SMasahiro Yamada char *out;
57080f7bc77SMasahiro Yamada size_t len;
57180f7bc77SMasahiro Yamada
57280f7bc77SMasahiro Yamada len = strlen(in) + strlen("\"\"") + 1;
57380f7bc77SMasahiro Yamada
57480f7bc77SMasahiro Yamada p = in;
57580f7bc77SMasahiro Yamada while (1) {
57680f7bc77SMasahiro Yamada p += strcspn(p, "\"\\");
57780f7bc77SMasahiro Yamada
57880f7bc77SMasahiro Yamada if (p[0] == '\0')
57980f7bc77SMasahiro Yamada break;
58080f7bc77SMasahiro Yamada
58180f7bc77SMasahiro Yamada len++;
58280f7bc77SMasahiro Yamada p++;
58380f7bc77SMasahiro Yamada }
58480f7bc77SMasahiro Yamada
58580f7bc77SMasahiro Yamada out = xmalloc(len);
58680f7bc77SMasahiro Yamada out[0] = '\0';
58780f7bc77SMasahiro Yamada
58880f7bc77SMasahiro Yamada strcat(out, "\"");
58980f7bc77SMasahiro Yamada
59080f7bc77SMasahiro Yamada p = in;
59180f7bc77SMasahiro Yamada while (1) {
59280f7bc77SMasahiro Yamada len = strcspn(p, "\"\\");
59380f7bc77SMasahiro Yamada strncat(out, p, len);
59480f7bc77SMasahiro Yamada p += len;
59580f7bc77SMasahiro Yamada
59680f7bc77SMasahiro Yamada if (p[0] == '\0')
59780f7bc77SMasahiro Yamada break;
59880f7bc77SMasahiro Yamada
59980f7bc77SMasahiro Yamada strcat(out, "\\");
60080f7bc77SMasahiro Yamada strncat(out, p++, 1);
60180f7bc77SMasahiro Yamada }
60280f7bc77SMasahiro Yamada
60380f7bc77SMasahiro Yamada strcat(out, "\"");
60480f7bc77SMasahiro Yamada
60580f7bc77SMasahiro Yamada return out;
60680f7bc77SMasahiro Yamada }
60780f7bc77SMasahiro Yamada
6086ce45a91SMasahiro Yamada enum output_n { OUTPUT_N, OUTPUT_N_AS_UNSET, OUTPUT_N_NONE };
60949192f26SSam Ravnborg
__print_symbol(FILE * fp,struct symbol * sym,enum output_n output_n,bool escape_string)6106ce45a91SMasahiro Yamada static void __print_symbol(FILE *fp, struct symbol *sym, enum output_n output_n,
6116ce45a91SMasahiro Yamada bool escape_string)
612e54e692bSArnaud Lacombe {
613229d0cfaSMasahiro Yamada const char *val;
614229d0cfaSMasahiro Yamada char *escaped = NULL;
615e54e692bSArnaud Lacombe
616229d0cfaSMasahiro Yamada if (sym->type == S_UNKNOWN)
617229d0cfaSMasahiro Yamada return;
618229d0cfaSMasahiro Yamada
619229d0cfaSMasahiro Yamada val = sym_get_string_value(sym);
620229d0cfaSMasahiro Yamada
6216ce45a91SMasahiro Yamada if ((sym->type == S_BOOLEAN || sym->type == S_TRISTATE) &&
6226ce45a91SMasahiro Yamada output_n != OUTPUT_N && *val == 'n') {
6236ce45a91SMasahiro Yamada if (output_n == OUTPUT_N_AS_UNSET)
6246ce45a91SMasahiro Yamada fprintf(fp, "# %s%s is not set\n", CONFIG_, sym->name);
6256ce45a91SMasahiro Yamada return;
6266ce45a91SMasahiro Yamada }
6276ce45a91SMasahiro Yamada
6286ce45a91SMasahiro Yamada if (sym->type == S_STRING && escape_string) {
62980f7bc77SMasahiro Yamada escaped = escape_string_value(val);
630229d0cfaSMasahiro Yamada val = escaped;
63149192f26SSam Ravnborg }
632229d0cfaSMasahiro Yamada
6336ce45a91SMasahiro Yamada fprintf(fp, "%s%s=%s\n", CONFIG_, sym->name, val);
6346ce45a91SMasahiro Yamada
6356ce45a91SMasahiro Yamada free(escaped);
6366ce45a91SMasahiro Yamada }
6376ce45a91SMasahiro Yamada
print_symbol_for_dotconfig(FILE * fp,struct symbol * sym)6386ce45a91SMasahiro Yamada static void print_symbol_for_dotconfig(FILE *fp, struct symbol *sym)
6396ce45a91SMasahiro Yamada {
6406ce45a91SMasahiro Yamada __print_symbol(fp, sym, OUTPUT_N_AS_UNSET, true);
6416ce45a91SMasahiro Yamada }
6426ce45a91SMasahiro Yamada
print_symbol_for_autoconf(FILE * fp,struct symbol * sym)6436ce45a91SMasahiro Yamada static void print_symbol_for_autoconf(FILE *fp, struct symbol *sym)
6446ce45a91SMasahiro Yamada {
645129ab0d2SMasahiro Yamada __print_symbol(fp, sym, OUTPUT_N_NONE, false);
6466ce45a91SMasahiro Yamada }
6476ce45a91SMasahiro Yamada
print_symbol_for_listconfig(struct symbol * sym)64851d792cbSMasahiro Yamada void print_symbol_for_listconfig(struct symbol *sym)
64951d792cbSMasahiro Yamada {
65051d792cbSMasahiro Yamada __print_symbol(stdout, sym, OUTPUT_N, true);
65151d792cbSMasahiro Yamada }
65251d792cbSMasahiro Yamada
print_symbol_for_c(FILE * fp,struct symbol * sym)6536ce45a91SMasahiro Yamada static void print_symbol_for_c(FILE *fp, struct symbol *sym)
6546ce45a91SMasahiro Yamada {
6556ce45a91SMasahiro Yamada const char *val;
6566ce45a91SMasahiro Yamada const char *sym_suffix = "";
6576ce45a91SMasahiro Yamada const char *val_prefix = "";
6586ce45a91SMasahiro Yamada char *escaped = NULL;
6596ce45a91SMasahiro Yamada
6606ce45a91SMasahiro Yamada if (sym->type == S_UNKNOWN)
6616ce45a91SMasahiro Yamada return;
6626ce45a91SMasahiro Yamada
6636ce45a91SMasahiro Yamada val = sym_get_string_value(sym);
6646ce45a91SMasahiro Yamada
6656ce45a91SMasahiro Yamada switch (sym->type) {
6666ce45a91SMasahiro Yamada case S_BOOLEAN:
6676ce45a91SMasahiro Yamada case S_TRISTATE:
6686ce45a91SMasahiro Yamada switch (*val) {
6696ce45a91SMasahiro Yamada case 'n':
6706ce45a91SMasahiro Yamada return;
6716ce45a91SMasahiro Yamada case 'm':
6726ce45a91SMasahiro Yamada sym_suffix = "_MODULE";
6736ce45a91SMasahiro Yamada /* fall through */
6746ce45a91SMasahiro Yamada default:
6756ce45a91SMasahiro Yamada val = "1";
6766ce45a91SMasahiro Yamada }
6776ce45a91SMasahiro Yamada break;
6786ce45a91SMasahiro Yamada case S_HEX:
6796ce45a91SMasahiro Yamada if (val[0] != '0' || (val[1] != 'x' && val[1] != 'X'))
6806ce45a91SMasahiro Yamada val_prefix = "0x";
6816ce45a91SMasahiro Yamada break;
6826ce45a91SMasahiro Yamada case S_STRING:
68380f7bc77SMasahiro Yamada escaped = escape_string_value(val);
6846ce45a91SMasahiro Yamada val = escaped;
6856ce45a91SMasahiro Yamada default:
6866ce45a91SMasahiro Yamada break;
6876ce45a91SMasahiro Yamada }
6886ce45a91SMasahiro Yamada
6896ce45a91SMasahiro Yamada fprintf(fp, "#define %s%s%s %s%s\n", CONFIG_, sym->name, sym_suffix,
6906ce45a91SMasahiro Yamada val_prefix, val);
691229d0cfaSMasahiro Yamada
692229d0cfaSMasahiro Yamada free(escaped);
69349192f26SSam Ravnborg }
69449192f26SSam Ravnborg
print_symbol_for_rustccfg(FILE * fp,struct symbol * sym)6952f7ab126SMiguel Ojeda static void print_symbol_for_rustccfg(FILE *fp, struct symbol *sym)
6962f7ab126SMiguel Ojeda {
6972f7ab126SMiguel Ojeda const char *val;
6982f7ab126SMiguel Ojeda const char *val_prefix = "";
6992f7ab126SMiguel Ojeda char *val_prefixed = NULL;
7002f7ab126SMiguel Ojeda size_t val_prefixed_len;
7012f7ab126SMiguel Ojeda char *escaped = NULL;
7022f7ab126SMiguel Ojeda
7032f7ab126SMiguel Ojeda if (sym->type == S_UNKNOWN)
7042f7ab126SMiguel Ojeda return;
7052f7ab126SMiguel Ojeda
7062f7ab126SMiguel Ojeda val = sym_get_string_value(sym);
7072f7ab126SMiguel Ojeda
7082f7ab126SMiguel Ojeda switch (sym->type) {
7092f7ab126SMiguel Ojeda case S_BOOLEAN:
7102f7ab126SMiguel Ojeda case S_TRISTATE:
7112f7ab126SMiguel Ojeda /*
7122f7ab126SMiguel Ojeda * We do not care about disabled ones, i.e. no need for
7132f7ab126SMiguel Ojeda * what otherwise are "comments" in other printers.
7142f7ab126SMiguel Ojeda */
7152f7ab126SMiguel Ojeda if (*val == 'n')
7162f7ab126SMiguel Ojeda return;
7172f7ab126SMiguel Ojeda
7182f7ab126SMiguel Ojeda /*
7192f7ab126SMiguel Ojeda * To have similar functionality to the C macro `IS_ENABLED()`
7202f7ab126SMiguel Ojeda * we provide an empty `--cfg CONFIG_X` here in both `y`
7212f7ab126SMiguel Ojeda * and `m` cases.
7222f7ab126SMiguel Ojeda *
7232f7ab126SMiguel Ojeda * Then, the common `fprintf()` below will also give us
7242f7ab126SMiguel Ojeda * a `--cfg CONFIG_X="y"` or `--cfg CONFIG_X="m"`, which can
7252f7ab126SMiguel Ojeda * be used as the equivalent of `IS_BUILTIN()`/`IS_MODULE()`.
7262f7ab126SMiguel Ojeda */
7272f7ab126SMiguel Ojeda fprintf(fp, "--cfg=%s%s\n", CONFIG_, sym->name);
7282f7ab126SMiguel Ojeda break;
7292f7ab126SMiguel Ojeda case S_HEX:
7302f7ab126SMiguel Ojeda if (val[0] != '0' || (val[1] != 'x' && val[1] != 'X'))
7312f7ab126SMiguel Ojeda val_prefix = "0x";
7322f7ab126SMiguel Ojeda break;
7332f7ab126SMiguel Ojeda default:
7342f7ab126SMiguel Ojeda break;
7352f7ab126SMiguel Ojeda }
7362f7ab126SMiguel Ojeda
7372f7ab126SMiguel Ojeda if (strlen(val_prefix) > 0) {
7382f7ab126SMiguel Ojeda val_prefixed_len = strlen(val) + strlen(val_prefix) + 1;
7392f7ab126SMiguel Ojeda val_prefixed = xmalloc(val_prefixed_len);
7402f7ab126SMiguel Ojeda snprintf(val_prefixed, val_prefixed_len, "%s%s", val_prefix, val);
7412f7ab126SMiguel Ojeda val = val_prefixed;
7422f7ab126SMiguel Ojeda }
7432f7ab126SMiguel Ojeda
7442f7ab126SMiguel Ojeda /* All values get escaped: the `--cfg` option only takes strings */
7452f7ab126SMiguel Ojeda escaped = escape_string_value(val);
7462f7ab126SMiguel Ojeda val = escaped;
7472f7ab126SMiguel Ojeda
7482f7ab126SMiguel Ojeda fprintf(fp, "--cfg=%s%s=%s\n", CONFIG_, sym->name, val);
7492f7ab126SMiguel Ojeda
7502f7ab126SMiguel Ojeda free(escaped);
7512f7ab126SMiguel Ojeda free(val_prefixed);
7522f7ab126SMiguel Ojeda }
7532f7ab126SMiguel Ojeda
7547cf3d73bSSam Ravnborg /*
7557cf3d73bSSam Ravnborg * Write out a minimal config.
7567cf3d73bSSam Ravnborg * All values that has default values are skipped as this is redundant.
7577cf3d73bSSam Ravnborg */
conf_write_defconfig(const char * filename)7587cf3d73bSSam Ravnborg int conf_write_defconfig(const char *filename)
7597cf3d73bSSam Ravnborg {
7607cf3d73bSSam Ravnborg struct symbol *sym;
7617cf3d73bSSam Ravnborg struct menu *menu;
7627cf3d73bSSam Ravnborg FILE *out;
7637cf3d73bSSam Ravnborg
7647cf3d73bSSam Ravnborg out = fopen(filename, "w");
7657cf3d73bSSam Ravnborg if (!out)
7667cf3d73bSSam Ravnborg return 1;
7677cf3d73bSSam Ravnborg
7687cf3d73bSSam Ravnborg sym_clear_all_valid();
7697cf3d73bSSam Ravnborg
77003c4ecaaSMasahiro Yamada menu_for_each_entry(menu) {
771fb8dd482SMasahiro Yamada struct menu *choice;
772fb8dd482SMasahiro Yamada
7737cf3d73bSSam Ravnborg sym = menu->sym;
774995150e4SMasahiro Yamada
775995150e4SMasahiro Yamada if (!sym || sym_is_choice(sym))
776995150e4SMasahiro Yamada continue;
777995150e4SMasahiro Yamada
7787cf3d73bSSam Ravnborg sym_calc_value(sym);
7797cf3d73bSSam Ravnborg if (!(sym->flags & SYMBOL_WRITE))
78003c4ecaaSMasahiro Yamada continue;
7817cf3d73bSSam Ravnborg sym->flags &= ~SYMBOL_WRITE;
782995150e4SMasahiro Yamada /* Skip unchangeable symbols */
783baa23ec8SMarco Ammon if (!sym_is_changeable(sym))
78403c4ecaaSMasahiro Yamada continue;
785995150e4SMasahiro Yamada /* Skip symbols that are equal to the default */
786995150e4SMasahiro Yamada if (!strcmp(sym_get_string_value(sym), sym_get_string_default(sym)))
78703c4ecaaSMasahiro Yamada continue;
7887cf3d73bSSam Ravnborg
789995150e4SMasahiro Yamada /* Skip choice values that are equal to the default */
790fb8dd482SMasahiro Yamada choice = sym_get_choice_menu(sym);
791fb8dd482SMasahiro Yamada if (choice) {
7927cf3d73bSSam Ravnborg struct symbol *ds;
7937cf3d73bSSam Ravnborg
794e8fcd915SMasahiro Yamada ds = sym_choice_default(choice);
795995150e4SMasahiro Yamada if (sym == ds && sym_get_tristate_value(sym) == yes)
79603c4ecaaSMasahiro Yamada continue;
7977cf3d73bSSam Ravnborg }
7986ce45a91SMasahiro Yamada print_symbol_for_dotconfig(out, sym);
7997cf3d73bSSam Ravnborg }
8007cf3d73bSSam Ravnborg fclose(out);
8017cf3d73bSSam Ravnborg return 0;
8027cf3d73bSSam Ravnborg }
8037cf3d73bSSam Ravnborg
conf_write(const char * name)8041da177e4SLinus Torvalds int conf_write(const char *name)
8051da177e4SLinus Torvalds {
806c955ccafSRoman Zippel FILE *out;
8071da177e4SLinus Torvalds struct symbol *sym;
8081da177e4SLinus Torvalds struct menu *menu;
8091da177e4SLinus Torvalds const char *str;
810ceb7f329SMasahiro Yamada char tmpname[PATH_MAX + 1], oldname[PATH_MAX + 1];
8111da177e4SLinus Torvalds char *env;
812aff11cd9SAlexander Popov bool need_newline = false;
8131da177e4SLinus Torvalds
814ceb7f329SMasahiro Yamada if (!name)
815ceb7f329SMasahiro Yamada name = conf_get_configname();
816ceb7f329SMasahiro Yamada
817ceb7f329SMasahiro Yamada if (!*name) {
818ceb7f329SMasahiro Yamada fprintf(stderr, "config name is empty\n");
819ceb7f329SMasahiro Yamada return -1;
820ceb7f329SMasahiro Yamada }
8211da177e4SLinus Torvalds
8220608182aSMasahiro Yamada if (is_dir(name)) {
823ceb7f329SMasahiro Yamada fprintf(stderr, "%s: Is a directory\n", name);
824ceb7f329SMasahiro Yamada return -1;
825ceb7f329SMasahiro Yamada }
8261da177e4SLinus Torvalds
827580c5b3eSMasahiro Yamada if (make_parent_dir(name))
828580c5b3eSMasahiro Yamada return -1;
829580c5b3eSMasahiro Yamada
83014cdd3c4SRoman Zippel env = getenv("KCONFIG_OVERWRITECONFIG");
831ceb7f329SMasahiro Yamada if (env && *env) {
83214cdd3c4SRoman Zippel *tmpname = 0;
833ceb7f329SMasahiro Yamada out = fopen(name, "w");
834ceb7f329SMasahiro Yamada } else {
835ceb7f329SMasahiro Yamada snprintf(tmpname, sizeof(tmpname), "%s.%d.tmp",
836ceb7f329SMasahiro Yamada name, (int)getpid());
837ceb7f329SMasahiro Yamada out = fopen(tmpname, "w");
83814cdd3c4SRoman Zippel }
8391da177e4SLinus Torvalds if (!out)
8401da177e4SLinus Torvalds return 1;
84114cdd3c4SRoman Zippel
842ca51b26bSMasahiro Yamada conf_write_heading(out, &comment_style_pound);
8431da177e4SLinus Torvalds
844b3214293SKarsten Wiese if (!conf_get_changed())
8451da177e4SLinus Torvalds sym_clear_all_valid();
8461da177e4SLinus Torvalds
8471da177e4SLinus Torvalds menu = rootmenu.list;
8481da177e4SLinus Torvalds while (menu) {
8491da177e4SLinus Torvalds sym = menu->sym;
8501da177e4SLinus Torvalds if (!sym) {
8511da177e4SLinus Torvalds if (!menu_is_visible(menu))
8521da177e4SLinus Torvalds goto next;
8531da177e4SLinus Torvalds str = menu_get_prompt(menu);
8541da177e4SLinus Torvalds fprintf(out, "\n"
8551da177e4SLinus Torvalds "#\n"
8561da177e4SLinus Torvalds "# %s\n"
8571da177e4SLinus Torvalds "#\n", str);
858aff11cd9SAlexander Popov need_newline = false;
8591da251c6SMasahiro Yamada } else if (!sym_is_choice(sym) &&
8608e2442a5SMasahiro Yamada !(sym->flags & SYMBOL_WRITTEN)) {
8611da177e4SLinus Torvalds sym_calc_value(sym);
8621da177e4SLinus Torvalds if (!(sym->flags & SYMBOL_WRITE))
8631da177e4SLinus Torvalds goto next;
864aff11cd9SAlexander Popov if (need_newline) {
865aff11cd9SAlexander Popov fprintf(out, "\n");
866aff11cd9SAlexander Popov need_newline = false;
867aff11cd9SAlexander Popov }
8688e2442a5SMasahiro Yamada sym->flags |= SYMBOL_WRITTEN;
8696ce45a91SMasahiro Yamada print_symbol_for_dotconfig(out, sym);
8701da177e4SLinus Torvalds }
8711da177e4SLinus Torvalds
8721da177e4SLinus Torvalds next:
8731da177e4SLinus Torvalds if (menu->list) {
8741da177e4SLinus Torvalds menu = menu->list;
8751da177e4SLinus Torvalds continue;
8761da177e4SLinus Torvalds }
877a7d4f58eSMasahiro Yamada
878a7d4f58eSMasahiro Yamada end_check:
879a7d4f58eSMasahiro Yamada if (!menu->sym && menu_is_visible(menu) && menu != &rootmenu &&
880a7d4f58eSMasahiro Yamada menu->prompt->type == P_MENU) {
881a7d4f58eSMasahiro Yamada fprintf(out, "# end of %s\n", menu_get_prompt(menu));
882aff11cd9SAlexander Popov need_newline = true;
883aff11cd9SAlexander Popov }
884a7d4f58eSMasahiro Yamada
8851da177e4SLinus Torvalds if (menu->next) {
8861da177e4SLinus Torvalds menu = menu->next;
887a7d4f58eSMasahiro Yamada } else {
888a7d4f58eSMasahiro Yamada menu = menu->parent;
889a7d4f58eSMasahiro Yamada if (menu)
890a7d4f58eSMasahiro Yamada goto end_check;
8911da177e4SLinus Torvalds }
8921da177e4SLinus Torvalds }
8931da177e4SLinus Torvalds fclose(out);
89414cdd3c4SRoman Zippel
89591b69454SMasahiro Yamada for_all_symbols(sym)
8960c5b6c28SM. Vefa Bicakci sym->flags &= ~SYMBOL_WRITTEN;
8970c5b6c28SM. Vefa Bicakci
89814cdd3c4SRoman Zippel if (*tmpname) {
89967424f61SMasahiro Yamada if (is_same(name, tmpname)) {
90067424f61SMasahiro Yamada conf_message("No change to %s", name);
90167424f61SMasahiro Yamada unlink(tmpname);
9025ee54659SMasahiro Yamada conf_set_changed(false);
90367424f61SMasahiro Yamada return 0;
90467424f61SMasahiro Yamada }
90567424f61SMasahiro Yamada
906ceb7f329SMasahiro Yamada snprintf(oldname, sizeof(oldname), "%s.old", name);
907ceb7f329SMasahiro Yamada rename(name, oldname);
908ceb7f329SMasahiro Yamada if (rename(tmpname, name))
9091da177e4SLinus Torvalds return 1;
91014cdd3c4SRoman Zippel }
9111da177e4SLinus Torvalds
912ceb7f329SMasahiro Yamada conf_message("configuration written to %s", name);
913ddc97cacSRoman Zippel
9145ee54659SMasahiro Yamada conf_set_changed(false);
9151da177e4SLinus Torvalds
9161da177e4SLinus Torvalds return 0;
9171da177e4SLinus Torvalds }
918c955ccafSRoman Zippel
919a2ff4040SMasahiro Yamada /* write a dependency file as used by kbuild to track dependencies */
conf_write_autoconf_cmd(const char * autoconf_name)92000d674cbSMasahiro Yamada static int conf_write_autoconf_cmd(const char *autoconf_name)
921a2ff4040SMasahiro Yamada {
92200d674cbSMasahiro Yamada char name[PATH_MAX], tmp[PATH_MAX];
923a2ff4040SMasahiro Yamada FILE *out;
92400d674cbSMasahiro Yamada int ret;
925a2ff4040SMasahiro Yamada
92600d674cbSMasahiro Yamada ret = snprintf(name, sizeof(name), "%s.cmd", autoconf_name);
92700d674cbSMasahiro Yamada if (ret >= sizeof(name)) /* check truncation */
92800d674cbSMasahiro Yamada return -1;
92979123b13SMasahiro Yamada
93079123b13SMasahiro Yamada if (make_parent_dir(name))
93100d674cbSMasahiro Yamada return -1;
93200d674cbSMasahiro Yamada
93300d674cbSMasahiro Yamada ret = snprintf(tmp, sizeof(tmp), "%s.cmd.tmp", autoconf_name);
93400d674cbSMasahiro Yamada if (ret >= sizeof(tmp)) /* check truncation */
93500d674cbSMasahiro Yamada return -1;
93600d674cbSMasahiro Yamada
93700d674cbSMasahiro Yamada out = fopen(tmp, "w");
93800d674cbSMasahiro Yamada if (!out) {
93900d674cbSMasahiro Yamada perror("fopen");
94000d674cbSMasahiro Yamada return -1;
94100d674cbSMasahiro Yamada }
94200d674cbSMasahiro Yamada
94356e634b0SMasahiro Yamada fprintf(out, "autoconfig := %s\n", autoconf_name);
94456e634b0SMasahiro Yamada
945526396b7SMasahiro Yamada fputs(str_get(&autoconf_cmd), out);
94600d674cbSMasahiro Yamada
947868653f4SMasahiro Yamada fflush(out);
948d23a0c37SMasahiro Yamada ret = ferror(out); /* error check for all fprintf() calls */
94900d674cbSMasahiro Yamada fclose(out);
950d23a0c37SMasahiro Yamada if (ret)
951d23a0c37SMasahiro Yamada return -1;
95200d674cbSMasahiro Yamada
95300d674cbSMasahiro Yamada if (rename(tmp, name)) {
95400d674cbSMasahiro Yamada perror("rename");
95500d674cbSMasahiro Yamada return -1;
95600d674cbSMasahiro Yamada }
95700d674cbSMasahiro Yamada
958a2ff4040SMasahiro Yamada return 0;
959a2ff4040SMasahiro Yamada }
960a2ff4040SMasahiro Yamada
conf_touch_deps(void)9610849d212SMasahiro Yamada static int conf_touch_deps(void)
9622e3646e5SRoman Zippel {
9631b9e740aSJing Leng const char *name, *tmp;
9642e3646e5SRoman Zippel struct symbol *sym;
96591b69454SMasahiro Yamada int res;
9661508fec8SMasahiro Yamada
96712122f62SMarkus Heidelberg name = conf_get_autoconfig_name();
9681b9e740aSJing Leng tmp = strrchr(name, '/');
9691b9e740aSJing Leng depfile_prefix_len = tmp ? tmp - name + 1 : 0;
9701b9e740aSJing Leng if (depfile_prefix_len + 1 > sizeof(depfile_path))
9711b9e740aSJing Leng return -1;
9721b9e740aSJing Leng
9731b9e740aSJing Leng strncpy(depfile_path, name, depfile_prefix_len);
9741b9e740aSJing Leng depfile_path[depfile_prefix_len] = 0;
9751b9e740aSJing Leng
9762e3646e5SRoman Zippel conf_read_simple(name, S_DEF_AUTO);
9772e3646e5SRoman Zippel
97891b69454SMasahiro Yamada for_all_symbols(sym) {
979a7c79cf3SMasahiro Yamada if (sym_is_choice(sym))
9802e3646e5SRoman Zippel continue;
9812e3646e5SRoman Zippel if (sym->flags & SYMBOL_WRITE) {
9822e3646e5SRoman Zippel if (sym->flags & SYMBOL_DEF_AUTO) {
9832e3646e5SRoman Zippel /*
9842e3646e5SRoman Zippel * symbol has old and new value,
9852e3646e5SRoman Zippel * so compare them...
9862e3646e5SRoman Zippel */
9872e3646e5SRoman Zippel switch (sym->type) {
9882e3646e5SRoman Zippel case S_BOOLEAN:
9892e3646e5SRoman Zippel case S_TRISTATE:
9902e3646e5SRoman Zippel if (sym_get_tristate_value(sym) ==
9912e3646e5SRoman Zippel sym->def[S_DEF_AUTO].tri)
9922e3646e5SRoman Zippel continue;
9932e3646e5SRoman Zippel break;
9942e3646e5SRoman Zippel case S_STRING:
9952e3646e5SRoman Zippel case S_HEX:
9962e3646e5SRoman Zippel case S_INT:
9972e3646e5SRoman Zippel if (!strcmp(sym_get_string_value(sym),
9982e3646e5SRoman Zippel sym->def[S_DEF_AUTO].val))
9992e3646e5SRoman Zippel continue;
10002e3646e5SRoman Zippel break;
10012e3646e5SRoman Zippel default:
10022e3646e5SRoman Zippel break;
10032e3646e5SRoman Zippel }
10042e3646e5SRoman Zippel } else {
10052e3646e5SRoman Zippel /*
10062e3646e5SRoman Zippel * If there is no old value, only 'no' (unset)
10072e3646e5SRoman Zippel * is allowed as new value.
10082e3646e5SRoman Zippel */
10092e3646e5SRoman Zippel switch (sym->type) {
10102e3646e5SRoman Zippel case S_BOOLEAN:
10112e3646e5SRoman Zippel case S_TRISTATE:
10122e3646e5SRoman Zippel if (sym_get_tristate_value(sym) == no)
10132e3646e5SRoman Zippel continue;
10142e3646e5SRoman Zippel break;
10152e3646e5SRoman Zippel default:
10162e3646e5SRoman Zippel break;
10172e3646e5SRoman Zippel }
10182e3646e5SRoman Zippel }
10192e3646e5SRoman Zippel } else if (!(sym->flags & SYMBOL_DEF_AUTO))
10202e3646e5SRoman Zippel /* There is neither an old nor a new value. */
10212e3646e5SRoman Zippel continue;
10222e3646e5SRoman Zippel /* else
10232e3646e5SRoman Zippel * There is an old value, but no new value ('no' (unset)
10242e3646e5SRoman Zippel * isn't saved in auto.conf, so the old value is always
10252e3646e5SRoman Zippel * different from 'no').
10262e3646e5SRoman Zippel */
10272e3646e5SRoman Zippel
10281508fec8SMasahiro Yamada res = conf_touch_dep(sym->name);
10291508fec8SMasahiro Yamada if (res)
10302e3646e5SRoman Zippel return res;
10312e3646e5SRoman Zippel }
10322e3646e5SRoman Zippel
10331508fec8SMasahiro Yamada return 0;
10341508fec8SMasahiro Yamada }
10351508fec8SMasahiro Yamada
__conf_write_autoconf(const char * filename,void (* print_symbol)(FILE *,struct symbol *),const struct comment_style * comment_style)103657ddd07cSMasahiro Yamada static int __conf_write_autoconf(const char *filename,
103757ddd07cSMasahiro Yamada void (*print_symbol)(FILE *, struct symbol *),
103857ddd07cSMasahiro Yamada const struct comment_style *comment_style)
103957ddd07cSMasahiro Yamada {
104057ddd07cSMasahiro Yamada char tmp[PATH_MAX];
104157ddd07cSMasahiro Yamada FILE *file;
104257ddd07cSMasahiro Yamada struct symbol *sym;
104391b69454SMasahiro Yamada int ret;
104457ddd07cSMasahiro Yamada
104557ddd07cSMasahiro Yamada if (make_parent_dir(filename))
104657ddd07cSMasahiro Yamada return -1;
104757ddd07cSMasahiro Yamada
104857ddd07cSMasahiro Yamada ret = snprintf(tmp, sizeof(tmp), "%s.tmp", filename);
104957ddd07cSMasahiro Yamada if (ret >= sizeof(tmp)) /* check truncation */
105057ddd07cSMasahiro Yamada return -1;
105157ddd07cSMasahiro Yamada
105257ddd07cSMasahiro Yamada file = fopen(tmp, "w");
105357ddd07cSMasahiro Yamada if (!file) {
105457ddd07cSMasahiro Yamada perror("fopen");
105557ddd07cSMasahiro Yamada return -1;
105657ddd07cSMasahiro Yamada }
105757ddd07cSMasahiro Yamada
105857ddd07cSMasahiro Yamada conf_write_heading(file, comment_style);
105957ddd07cSMasahiro Yamada
106091b69454SMasahiro Yamada for_all_symbols(sym)
106157ddd07cSMasahiro Yamada if ((sym->flags & SYMBOL_WRITE) && sym->name)
106257ddd07cSMasahiro Yamada print_symbol(file, sym);
106357ddd07cSMasahiro Yamada
1064868653f4SMasahiro Yamada fflush(file);
106557ddd07cSMasahiro Yamada /* check possible errors in conf_write_heading() and print_symbol() */
1066d23a0c37SMasahiro Yamada ret = ferror(file);
106757ddd07cSMasahiro Yamada fclose(file);
1068d23a0c37SMasahiro Yamada if (ret)
1069d23a0c37SMasahiro Yamada return -1;
107057ddd07cSMasahiro Yamada
107157ddd07cSMasahiro Yamada if (rename(tmp, filename)) {
107257ddd07cSMasahiro Yamada perror("rename");
107357ddd07cSMasahiro Yamada return -1;
107457ddd07cSMasahiro Yamada }
107557ddd07cSMasahiro Yamada
107657ddd07cSMasahiro Yamada return 0;
107757ddd07cSMasahiro Yamada }
107857ddd07cSMasahiro Yamada
conf_write_autoconf(int overwrite)107900c864f8SMasahiro Yamada int conf_write_autoconf(int overwrite)
1080c955ccafSRoman Zippel {
1081c955ccafSRoman Zippel struct symbol *sym;
108200c864f8SMasahiro Yamada const char *autoconf_name = conf_get_autoconfig_name();
108391b69454SMasahiro Yamada int ret;
1084c955ccafSRoman Zippel
108500c864f8SMasahiro Yamada if (!overwrite && is_present(autoconf_name))
108600c864f8SMasahiro Yamada return 0;
108700c864f8SMasahiro Yamada
108800d674cbSMasahiro Yamada ret = conf_write_autoconf_cmd(autoconf_name);
108900d674cbSMasahiro Yamada if (ret)
109000d674cbSMasahiro Yamada return -1;
1091c955ccafSRoman Zippel
109291b69454SMasahiro Yamada for_all_symbols(sym)
1093953742c8SArnaud Lacombe sym_calc_value(sym);
1094953742c8SArnaud Lacombe
1095*226ac19cSMasahiro Yamada if (conf_touch_deps())
1096*226ac19cSMasahiro Yamada return 1;
1097*226ac19cSMasahiro Yamada
109857ddd07cSMasahiro Yamada ret = __conf_write_autoconf(conf_get_autoheader_name(),
109957ddd07cSMasahiro Yamada print_symbol_for_c,
110057ddd07cSMasahiro Yamada &comment_style_c);
110157ddd07cSMasahiro Yamada if (ret)
110257ddd07cSMasahiro Yamada return ret;
1103c955ccafSRoman Zippel
11042f7ab126SMiguel Ojeda ret = __conf_write_autoconf(conf_get_rustccfg_name(),
11052f7ab126SMiguel Ojeda print_symbol_for_rustccfg,
11062f7ab126SMiguel Ojeda NULL);
11072f7ab126SMiguel Ojeda if (ret)
11082f7ab126SMiguel Ojeda return ret;
11092f7ab126SMiguel Ojeda
1110c955ccafSRoman Zippel /*
111157ddd07cSMasahiro Yamada * Create include/config/auto.conf. This must be the last step because
111257ddd07cSMasahiro Yamada * Kbuild has a dependency on auto.conf and this marks the successful
111357ddd07cSMasahiro Yamada * completion of the previous steps.
1114c955ccafSRoman Zippel */
111557ddd07cSMasahiro Yamada ret = __conf_write_autoconf(conf_get_autoconfig_name(),
111657ddd07cSMasahiro Yamada print_symbol_for_autoconf,
111757ddd07cSMasahiro Yamada &comment_style_pound);
111857ddd07cSMasahiro Yamada if (ret)
111957ddd07cSMasahiro Yamada return ret;
1120c955ccafSRoman Zippel
1121c955ccafSRoman Zippel return 0;
1122c955ccafSRoman Zippel }
1123b3214293SKarsten Wiese
11245ee54659SMasahiro Yamada static bool conf_changed;
112503638aaaSMasahiro Yamada static void (*conf_changed_callback)(bool);
1126bfc10001SKarsten Wiese
conf_set_changed(bool val)11275ee54659SMasahiro Yamada void conf_set_changed(bool val)
1128bfc10001SKarsten Wiese {
112903638aaaSMasahiro Yamada if (conf_changed_callback && conf_changed != val)
113003638aaaSMasahiro Yamada conf_changed_callback(val);
1131bfc10001SKarsten Wiese
11325ee54659SMasahiro Yamada conf_changed = val;
1133bfc10001SKarsten Wiese }
1134bfc10001SKarsten Wiese
conf_get_changed(void)1135b3214293SKarsten Wiese bool conf_get_changed(void)
1136b3214293SKarsten Wiese {
11375ee54659SMasahiro Yamada return conf_changed;
1138b3214293SKarsten Wiese }
11393b354c55SKarsten Wiese
conf_set_changed_callback(void (* fn)(bool))114003638aaaSMasahiro Yamada void conf_set_changed_callback(void (*fn)(bool))
11413b354c55SKarsten Wiese {
11423b354c55SKarsten Wiese conf_changed_callback = fn;
11433b354c55SKarsten Wiese }
1144