xref: /linux/scripts/kconfig/confdata.c (revision 68e5c7d4cefb66de3953a874e670ec8f1ce86a24)
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