xref: /openbmc/linux/scripts/kconfig/confdata.c (revision face4374e288372fba67c865eb0c92337f50d5a4)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
31da177e4SLinus Torvalds  * Released under the terms of the GNU GPL v2.0.
41da177e4SLinus Torvalds  */
51da177e4SLinus Torvalds 
61da177e4SLinus Torvalds #include <sys/stat.h>
71da177e4SLinus Torvalds #include <ctype.h>
82e3646e5SRoman Zippel #include <fcntl.h>
91da177e4SLinus Torvalds #include <stdio.h>
101da177e4SLinus Torvalds #include <stdlib.h>
111da177e4SLinus Torvalds #include <string.h>
121da177e4SLinus Torvalds #include <time.h>
131da177e4SLinus Torvalds #include <unistd.h>
141da177e4SLinus Torvalds 
151da177e4SLinus Torvalds #define LKC_DIRECT_LINK
161da177e4SLinus Torvalds #include "lkc.h"
171da177e4SLinus Torvalds 
18c1a0f5e3SRoman Zippel static void conf_warning(const char *fmt, ...)
19c1a0f5e3SRoman Zippel 	__attribute__ ((format (printf, 1, 2)));
20c1a0f5e3SRoman Zippel 
21c1a0f5e3SRoman Zippel static const char *conf_filename;
22c1a0f5e3SRoman Zippel static int conf_lineno, conf_warnings, conf_unsaved;
23c1a0f5e3SRoman Zippel 
241da177e4SLinus Torvalds const char conf_def_filename[] = ".config";
251da177e4SLinus Torvalds 
261da177e4SLinus Torvalds const char conf_defname[] = "arch/$ARCH/defconfig";
271da177e4SLinus Torvalds 
28c1a0f5e3SRoman Zippel static void conf_warning(const char *fmt, ...)
29c1a0f5e3SRoman Zippel {
30c1a0f5e3SRoman Zippel 	va_list ap;
31c1a0f5e3SRoman Zippel 	va_start(ap, fmt);
32c1a0f5e3SRoman Zippel 	fprintf(stderr, "%s:%d:warning: ", conf_filename, conf_lineno);
33c1a0f5e3SRoman Zippel 	vfprintf(stderr, fmt, ap);
34c1a0f5e3SRoman Zippel 	fprintf(stderr, "\n");
35c1a0f5e3SRoman Zippel 	va_end(ap);
36c1a0f5e3SRoman Zippel 	conf_warnings++;
37c1a0f5e3SRoman Zippel }
38c1a0f5e3SRoman Zippel 
3948b9d03cSJ.A. Magallon static char *conf_expand_value(const char *in)
401da177e4SLinus Torvalds {
411da177e4SLinus Torvalds 	struct symbol *sym;
4248b9d03cSJ.A. Magallon 	const char *src;
431da177e4SLinus Torvalds 	static char res_value[SYMBOL_MAXLENGTH];
441da177e4SLinus Torvalds 	char *dst, name[SYMBOL_MAXLENGTH];
451da177e4SLinus Torvalds 
461da177e4SLinus Torvalds 	res_value[0] = 0;
471da177e4SLinus Torvalds 	dst = name;
481da177e4SLinus Torvalds 	while ((src = strchr(in, '$'))) {
491da177e4SLinus Torvalds 		strncat(res_value, in, src - in);
501da177e4SLinus Torvalds 		src++;
511da177e4SLinus Torvalds 		dst = name;
521da177e4SLinus Torvalds 		while (isalnum(*src) || *src == '_')
531da177e4SLinus Torvalds 			*dst++ = *src++;
541da177e4SLinus Torvalds 		*dst = 0;
551da177e4SLinus Torvalds 		sym = sym_lookup(name, 0);
561da177e4SLinus Torvalds 		sym_calc_value(sym);
571da177e4SLinus Torvalds 		strcat(res_value, sym_get_string_value(sym));
581da177e4SLinus Torvalds 		in = src;
591da177e4SLinus Torvalds 	}
601da177e4SLinus Torvalds 	strcat(res_value, in);
611da177e4SLinus Torvalds 
621da177e4SLinus Torvalds 	return res_value;
631da177e4SLinus Torvalds }
641da177e4SLinus Torvalds 
651da177e4SLinus Torvalds char *conf_get_default_confname(void)
661da177e4SLinus Torvalds {
671da177e4SLinus Torvalds 	struct stat buf;
681da177e4SLinus Torvalds 	static char fullname[PATH_MAX+1];
691da177e4SLinus Torvalds 	char *env, *name;
701da177e4SLinus Torvalds 
711da177e4SLinus Torvalds 	name = conf_expand_value(conf_defname);
721da177e4SLinus Torvalds 	env = getenv(SRCTREE);
731da177e4SLinus Torvalds 	if (env) {
741da177e4SLinus Torvalds 		sprintf(fullname, "%s/%s", env, name);
751da177e4SLinus Torvalds 		if (!stat(fullname, &buf))
761da177e4SLinus Torvalds 			return fullname;
771da177e4SLinus Torvalds 	}
781da177e4SLinus Torvalds 	return name;
791da177e4SLinus Torvalds }
801da177e4SLinus Torvalds 
81669bfad9SRoman Zippel int conf_read_simple(const char *name, int def)
821da177e4SLinus Torvalds {
831da177e4SLinus Torvalds 	FILE *in = NULL;
841da177e4SLinus Torvalds 	char line[1024];
851da177e4SLinus Torvalds 	char *p, *p2;
861da177e4SLinus Torvalds 	struct symbol *sym;
87669bfad9SRoman Zippel 	int i, def_flags;
881da177e4SLinus Torvalds 
891da177e4SLinus Torvalds 	if (name) {
901da177e4SLinus Torvalds 		in = zconf_fopen(name);
911da177e4SLinus Torvalds 	} else {
92*face4374SRoman Zippel 		struct property *prop;
93*face4374SRoman Zippel 
94*face4374SRoman Zippel 		name = conf_def_filename;
95ddc97cacSRoman Zippel 		in = zconf_fopen(name);
96ddc97cacSRoman Zippel 		if (in)
97ddc97cacSRoman Zippel 			goto load;
98ddc97cacSRoman Zippel 		sym_change_count++;
99*face4374SRoman Zippel 		if (!sym_defconfig_list)
100*face4374SRoman Zippel 			return 1;
101*face4374SRoman Zippel 
102*face4374SRoman Zippel 		for_all_defaults(sym_defconfig_list, prop) {
103*face4374SRoman Zippel 			if (expr_calc_value(prop->visible.expr) == no ||
104*face4374SRoman Zippel 			    prop->expr->type != E_SYMBOL)
105*face4374SRoman Zippel 				continue;
106*face4374SRoman Zippel 			name = conf_expand_value(prop->expr->left.sym->name);
1071da177e4SLinus Torvalds 			in = zconf_fopen(name);
1081da177e4SLinus Torvalds 			if (in) {
1093b9fa093SArnaldo Carvalho de Melo 				printf(_("#\n"
1101da177e4SLinus Torvalds 					 "# using defaults found in %s\n"
1113b9fa093SArnaldo Carvalho de Melo 					 "#\n"), name);
112ddc97cacSRoman Zippel 				goto load;
1131da177e4SLinus Torvalds 			}
1141da177e4SLinus Torvalds 		}
1151da177e4SLinus Torvalds 	}
1161da177e4SLinus Torvalds 	if (!in)
1171da177e4SLinus Torvalds 		return 1;
1181da177e4SLinus Torvalds 
119ddc97cacSRoman Zippel load:
120c1a0f5e3SRoman Zippel 	conf_filename = name;
121c1a0f5e3SRoman Zippel 	conf_lineno = 0;
122c1a0f5e3SRoman Zippel 	conf_warnings = 0;
123c1a0f5e3SRoman Zippel 	conf_unsaved = 0;
124c1a0f5e3SRoman Zippel 
125669bfad9SRoman Zippel 	def_flags = SYMBOL_DEF << def;
1261da177e4SLinus Torvalds 	for_all_symbols(i, sym) {
127669bfad9SRoman Zippel 		sym->flags |= SYMBOL_CHANGED;
128669bfad9SRoman Zippel 		sym->flags &= ~(def_flags|SYMBOL_VALID);
129c1a0f5e3SRoman Zippel 		if (sym_is_choice(sym))
130669bfad9SRoman Zippel 			sym->flags |= def_flags;
1311da177e4SLinus Torvalds 		switch (sym->type) {
1321da177e4SLinus Torvalds 		case S_INT:
1331da177e4SLinus Torvalds 		case S_HEX:
1341da177e4SLinus Torvalds 		case S_STRING:
135669bfad9SRoman Zippel 			if (sym->def[def].val)
136669bfad9SRoman Zippel 				free(sym->def[def].val);
1371da177e4SLinus Torvalds 		default:
138669bfad9SRoman Zippel 			sym->def[def].val = NULL;
139669bfad9SRoman Zippel 			sym->def[def].tri = no;
1401da177e4SLinus Torvalds 		}
1411da177e4SLinus Torvalds 	}
1421da177e4SLinus Torvalds 
1431da177e4SLinus Torvalds 	while (fgets(line, sizeof(line), in)) {
144c1a0f5e3SRoman Zippel 		conf_lineno++;
1451da177e4SLinus Torvalds 		sym = NULL;
1461da177e4SLinus Torvalds 		switch (line[0]) {
1471da177e4SLinus Torvalds 		case '#':
1481da177e4SLinus Torvalds 			if (memcmp(line + 2, "CONFIG_", 7))
1491da177e4SLinus Torvalds 				continue;
1501da177e4SLinus Torvalds 			p = strchr(line + 9, ' ');
1511da177e4SLinus Torvalds 			if (!p)
1521da177e4SLinus Torvalds 				continue;
1531da177e4SLinus Torvalds 			*p++ = 0;
1541da177e4SLinus Torvalds 			if (strncmp(p, "is not set", 10))
1551da177e4SLinus Torvalds 				continue;
156669bfad9SRoman Zippel 			if (def == S_DEF_USER) {
1571da177e4SLinus Torvalds 				sym = sym_find(line + 9);
1581da177e4SLinus Torvalds 				if (!sym) {
159c1a0f5e3SRoman Zippel 					conf_warning("trying to assign nonexistent symbol %s", line + 9);
160c1a0f5e3SRoman Zippel 					break;
161669bfad9SRoman Zippel 				}
162669bfad9SRoman Zippel 			} else {
163669bfad9SRoman Zippel 				sym = sym_lookup(line + 9, 0);
164669bfad9SRoman Zippel 				if (sym->type == S_UNKNOWN)
165669bfad9SRoman Zippel 					sym->type = S_BOOLEAN;
166669bfad9SRoman Zippel 			}
167669bfad9SRoman Zippel 			if (sym->flags & def_flags) {
168c1a0f5e3SRoman Zippel 				conf_warning("trying to reassign symbol %s", sym->name);
1691da177e4SLinus Torvalds 				break;
1701da177e4SLinus Torvalds 			}
1711da177e4SLinus Torvalds 			switch (sym->type) {
1721da177e4SLinus Torvalds 			case S_BOOLEAN:
1731da177e4SLinus Torvalds 			case S_TRISTATE:
174669bfad9SRoman Zippel 				sym->def[def].tri = no;
175669bfad9SRoman Zippel 				sym->flags |= def_flags;
1761da177e4SLinus Torvalds 				break;
1771da177e4SLinus Torvalds 			default:
1781da177e4SLinus Torvalds 				;
1791da177e4SLinus Torvalds 			}
1801da177e4SLinus Torvalds 			break;
1811da177e4SLinus Torvalds 		case 'C':
182c1a0f5e3SRoman Zippel 			if (memcmp(line, "CONFIG_", 7)) {
183c1a0f5e3SRoman Zippel 				conf_warning("unexpected data");
1841da177e4SLinus Torvalds 				continue;
185c1a0f5e3SRoman Zippel 			}
1861da177e4SLinus Torvalds 			p = strchr(line + 7, '=');
1871da177e4SLinus Torvalds 			if (!p)
1881da177e4SLinus Torvalds 				continue;
1891da177e4SLinus Torvalds 			*p++ = 0;
1901da177e4SLinus Torvalds 			p2 = strchr(p, '\n');
1911da177e4SLinus Torvalds 			if (p2)
1921da177e4SLinus Torvalds 				*p2 = 0;
193669bfad9SRoman Zippel 			if (def == S_DEF_USER) {
1941da177e4SLinus Torvalds 				sym = sym_find(line + 7);
1951da177e4SLinus Torvalds 				if (!sym) {
196c1a0f5e3SRoman Zippel 					conf_warning("trying to assign nonexistent symbol %s", line + 7);
197c1a0f5e3SRoman Zippel 					break;
198669bfad9SRoman Zippel 				}
199669bfad9SRoman Zippel 			} else {
200669bfad9SRoman Zippel 				sym = sym_lookup(line + 7, 0);
201669bfad9SRoman Zippel 				if (sym->type == S_UNKNOWN)
202669bfad9SRoman Zippel 					sym->type = S_OTHER;
203669bfad9SRoman Zippel 			}
204669bfad9SRoman Zippel 			if (sym->flags & def_flags) {
205c1a0f5e3SRoman Zippel 				conf_warning("trying to reassign symbol %s", sym->name);
2061da177e4SLinus Torvalds 				break;
2071da177e4SLinus Torvalds 			}
2081da177e4SLinus Torvalds 			switch (sym->type) {
2091da177e4SLinus Torvalds 			case S_TRISTATE:
2101da177e4SLinus Torvalds 				if (p[0] == 'm') {
211669bfad9SRoman Zippel 					sym->def[def].tri = mod;
212669bfad9SRoman Zippel 					sym->flags |= def_flags;
2131da177e4SLinus Torvalds 					break;
2141da177e4SLinus Torvalds 				}
2151da177e4SLinus Torvalds 			case S_BOOLEAN:
2161da177e4SLinus Torvalds 				if (p[0] == 'y') {
217669bfad9SRoman Zippel 					sym->def[def].tri = yes;
218669bfad9SRoman Zippel 					sym->flags |= def_flags;
2191da177e4SLinus Torvalds 					break;
2201da177e4SLinus Torvalds 				}
2211da177e4SLinus Torvalds 				if (p[0] == 'n') {
222669bfad9SRoman Zippel 					sym->def[def].tri = no;
223669bfad9SRoman Zippel 					sym->flags |= def_flags;
2241da177e4SLinus Torvalds 					break;
2251da177e4SLinus Torvalds 				}
226c1a0f5e3SRoman Zippel 				conf_warning("symbol value '%s' invalid for %s", p, sym->name);
2271da177e4SLinus Torvalds 				break;
228669bfad9SRoman Zippel 			case S_OTHER:
229669bfad9SRoman Zippel 				if (*p != '"') {
230669bfad9SRoman Zippel 					for (p2 = p; *p2 && !isspace(*p2); p2++)
231669bfad9SRoman Zippel 						;
232669bfad9SRoman Zippel 					sym->type = S_STRING;
233669bfad9SRoman Zippel 					goto done;
234669bfad9SRoman Zippel 				}
2351da177e4SLinus Torvalds 			case S_STRING:
2361da177e4SLinus Torvalds 				if (*p++ != '"')
2371da177e4SLinus Torvalds 					break;
2381da177e4SLinus Torvalds 				for (p2 = p; (p2 = strpbrk(p2, "\"\\")); p2++) {
2391da177e4SLinus Torvalds 					if (*p2 == '"') {
2401da177e4SLinus Torvalds 						*p2 = 0;
2411da177e4SLinus Torvalds 						break;
2421da177e4SLinus Torvalds 					}
2431da177e4SLinus Torvalds 					memmove(p2, p2 + 1, strlen(p2));
2441da177e4SLinus Torvalds 				}
2451da177e4SLinus Torvalds 				if (!p2) {
246c1a0f5e3SRoman Zippel 					conf_warning("invalid string found");
247c1a0f5e3SRoman Zippel 					continue;
2481da177e4SLinus Torvalds 				}
2491da177e4SLinus Torvalds 			case S_INT:
2501da177e4SLinus Torvalds 			case S_HEX:
251669bfad9SRoman Zippel 			done:
2521da177e4SLinus Torvalds 				if (sym_string_valid(sym, p)) {
253669bfad9SRoman Zippel 					sym->def[def].val = strdup(p);
254669bfad9SRoman Zippel 					sym->flags |= def_flags;
2551da177e4SLinus Torvalds 				} else {
256c1a0f5e3SRoman Zippel 					conf_warning("symbol value '%s' invalid for %s", p, sym->name);
257c1a0f5e3SRoman Zippel 					continue;
2581da177e4SLinus Torvalds 				}
2591da177e4SLinus Torvalds 				break;
2601da177e4SLinus Torvalds 			default:
2611da177e4SLinus Torvalds 				;
2621da177e4SLinus Torvalds 			}
2631da177e4SLinus Torvalds 			break;
2641da177e4SLinus Torvalds 		case '\n':
2651da177e4SLinus Torvalds 			break;
2661da177e4SLinus Torvalds 		default:
267c1a0f5e3SRoman Zippel 			conf_warning("unexpected data");
2681da177e4SLinus Torvalds 			continue;
2691da177e4SLinus Torvalds 		}
2701da177e4SLinus Torvalds 		if (sym && sym_is_choice_value(sym)) {
2711da177e4SLinus Torvalds 			struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym));
272669bfad9SRoman Zippel 			switch (sym->def[def].tri) {
2731da177e4SLinus Torvalds 			case no:
2741da177e4SLinus Torvalds 				break;
2751da177e4SLinus Torvalds 			case mod:
276669bfad9SRoman Zippel 				if (cs->def[def].tri == yes) {
277c1a0f5e3SRoman Zippel 					conf_warning("%s creates inconsistent choice state", sym->name);
278669bfad9SRoman Zippel 					cs->flags &= ~def_flags;
279c1a0f5e3SRoman Zippel 				}
2801da177e4SLinus Torvalds 				break;
2811da177e4SLinus Torvalds 			case yes:
282669bfad9SRoman Zippel 				if (cs->def[def].tri != no) {
283c1a0f5e3SRoman Zippel 					conf_warning("%s creates inconsistent choice state", sym->name);
284669bfad9SRoman Zippel 					cs->flags &= ~def_flags;
285c1a0f5e3SRoman Zippel 				} else
286669bfad9SRoman Zippel 					cs->def[def].val = sym;
2871da177e4SLinus Torvalds 				break;
2881da177e4SLinus Torvalds 			}
289669bfad9SRoman Zippel 			cs->def[def].tri = E_OR(cs->def[def].tri, sym->def[def].tri);
2901da177e4SLinus Torvalds 		}
2911da177e4SLinus Torvalds 	}
2921da177e4SLinus Torvalds 	fclose(in);
2931da177e4SLinus Torvalds 
2941da177e4SLinus Torvalds 	if (modules_sym)
2951da177e4SLinus Torvalds 		sym_calc_value(modules_sym);
29690389160SRoman Zippel 	return 0;
29790389160SRoman Zippel }
29890389160SRoman Zippel 
29990389160SRoman Zippel int conf_read(const char *name)
30090389160SRoman Zippel {
30190389160SRoman Zippel 	struct symbol *sym;
30290389160SRoman Zippel 	struct property *prop;
30390389160SRoman Zippel 	struct expr *e;
304669bfad9SRoman Zippel 	int i, flags;
30590389160SRoman Zippel 
306ddc97cacSRoman Zippel 	sym_change_count = 0;
307ddc97cacSRoman Zippel 
308669bfad9SRoman Zippel 	if (conf_read_simple(name, S_DEF_USER))
30990389160SRoman Zippel 		return 1;
31090389160SRoman Zippel 
3111da177e4SLinus Torvalds 	for_all_symbols(i, sym) {
3121da177e4SLinus Torvalds 		sym_calc_value(sym);
313c1a0f5e3SRoman Zippel 		if (sym_is_choice(sym) || (sym->flags & SYMBOL_AUTO))
314c1a0f5e3SRoman Zippel 			goto sym_ok;
315c1a0f5e3SRoman Zippel 		if (sym_has_value(sym) && (sym->flags & SYMBOL_WRITE)) {
316c1a0f5e3SRoman Zippel 			/* check that calculated value agrees with saved value */
317c1a0f5e3SRoman Zippel 			switch (sym->type) {
318c1a0f5e3SRoman Zippel 			case S_BOOLEAN:
319c1a0f5e3SRoman Zippel 			case S_TRISTATE:
3200c1822e6SRoman Zippel 				if (sym->def[S_DEF_USER].tri != sym_get_tristate_value(sym))
321c1a0f5e3SRoman Zippel 					break;
322c1a0f5e3SRoman Zippel 				if (!sym_is_choice(sym))
323c1a0f5e3SRoman Zippel 					goto sym_ok;
324c1a0f5e3SRoman Zippel 			default:
3250c1822e6SRoman Zippel 				if (!strcmp(sym->curr.val, sym->def[S_DEF_USER].val))
326c1a0f5e3SRoman Zippel 					goto sym_ok;
327c1a0f5e3SRoman Zippel 				break;
328c1a0f5e3SRoman Zippel 			}
329c1a0f5e3SRoman Zippel 		} else if (!sym_has_value(sym) && !(sym->flags & SYMBOL_WRITE))
330c1a0f5e3SRoman Zippel 			/* no previous value and not saved */
331c1a0f5e3SRoman Zippel 			goto sym_ok;
332c1a0f5e3SRoman Zippel 		conf_unsaved++;
333c1a0f5e3SRoman Zippel 		/* maybe print value in verbose mode... */
334c1a0f5e3SRoman Zippel 	sym_ok:
3351da177e4SLinus Torvalds 		if (sym_has_value(sym) && !sym_is_choice_value(sym)) {
3361da177e4SLinus Torvalds 			if (sym->visible == no)
337669bfad9SRoman Zippel 				sym->flags &= ~SYMBOL_DEF_USER;
3381da177e4SLinus Torvalds 			switch (sym->type) {
3391da177e4SLinus Torvalds 			case S_STRING:
3401da177e4SLinus Torvalds 			case S_INT:
3411da177e4SLinus Torvalds 			case S_HEX:
342669bfad9SRoman Zippel 				if (!sym_string_within_range(sym, sym->def[S_DEF_USER].val))
343669bfad9SRoman Zippel 					sym->flags &= ~(SYMBOL_VALID|SYMBOL_DEF_USER);
3441da177e4SLinus Torvalds 			default:
3451da177e4SLinus Torvalds 				break;
3461da177e4SLinus Torvalds 			}
3471da177e4SLinus Torvalds 		}
3481da177e4SLinus Torvalds 		if (!sym_is_choice(sym))
3491da177e4SLinus Torvalds 			continue;
3501da177e4SLinus Torvalds 		prop = sym_get_choice_prop(sym);
351669bfad9SRoman Zippel 		flags = sym->flags;
3521da177e4SLinus Torvalds 		for (e = prop->expr; e; e = e->left.expr)
3531da177e4SLinus Torvalds 			if (e->right.sym->visible != no)
354669bfad9SRoman Zippel 				flags &= e->right.sym->flags;
355669bfad9SRoman Zippel 		sym->flags |= flags & SYMBOL_DEF_USER;
3561da177e4SLinus Torvalds 	}
3571da177e4SLinus Torvalds 
358ddc97cacSRoman Zippel 	sym_change_count += conf_warnings || conf_unsaved;
3591da177e4SLinus Torvalds 
3601da177e4SLinus Torvalds 	return 0;
3611da177e4SLinus Torvalds }
3621da177e4SLinus Torvalds 
3631da177e4SLinus Torvalds int conf_write(const char *name)
3641da177e4SLinus Torvalds {
365c955ccafSRoman Zippel 	FILE *out;
3661da177e4SLinus Torvalds 	struct symbol *sym;
3671da177e4SLinus Torvalds 	struct menu *menu;
3681da177e4SLinus Torvalds 	const char *basename;
3691da177e4SLinus Torvalds 	char dirname[128], tmpname[128], newname[128];
3701da177e4SLinus Torvalds 	int type, l;
3711da177e4SLinus Torvalds 	const char *str;
3721da177e4SLinus Torvalds 	time_t now;
3731da177e4SLinus Torvalds 	int use_timestamp = 1;
3741da177e4SLinus Torvalds 	char *env;
3751da177e4SLinus Torvalds 
3761da177e4SLinus Torvalds 	dirname[0] = 0;
3771da177e4SLinus Torvalds 	if (name && name[0]) {
3781da177e4SLinus Torvalds 		struct stat st;
3791da177e4SLinus Torvalds 		char *slash;
3801da177e4SLinus Torvalds 
3811da177e4SLinus Torvalds 		if (!stat(name, &st) && S_ISDIR(st.st_mode)) {
3821da177e4SLinus Torvalds 			strcpy(dirname, name);
3831da177e4SLinus Torvalds 			strcat(dirname, "/");
3841da177e4SLinus Torvalds 			basename = conf_def_filename;
3851da177e4SLinus Torvalds 		} else if ((slash = strrchr(name, '/'))) {
3861da177e4SLinus Torvalds 			int size = slash - name + 1;
3871da177e4SLinus Torvalds 			memcpy(dirname, name, size);
3881da177e4SLinus Torvalds 			dirname[size] = 0;
3891da177e4SLinus Torvalds 			if (slash[1])
3901da177e4SLinus Torvalds 				basename = slash + 1;
3911da177e4SLinus Torvalds 			else
3921da177e4SLinus Torvalds 				basename = conf_def_filename;
3931da177e4SLinus Torvalds 		} else
3941da177e4SLinus Torvalds 			basename = name;
3951da177e4SLinus Torvalds 	} else
3961da177e4SLinus Torvalds 		basename = conf_def_filename;
3971da177e4SLinus Torvalds 
3981da177e4SLinus Torvalds 	sprintf(newname, "%s.tmpconfig.%d", dirname, (int)getpid());
3991da177e4SLinus Torvalds 	out = fopen(newname, "w");
4001da177e4SLinus Torvalds 	if (!out)
4011da177e4SLinus Torvalds 		return 1;
4022244cbd8SSam Ravnborg 	sym = sym_lookup("KERNELVERSION", 0);
4031da177e4SLinus Torvalds 	sym_calc_value(sym);
4041da177e4SLinus Torvalds 	time(&now);
4051da177e4SLinus Torvalds 	env = getenv("KCONFIG_NOTIMESTAMP");
4061da177e4SLinus Torvalds 	if (env && *env)
4071da177e4SLinus Torvalds 		use_timestamp = 0;
4081da177e4SLinus Torvalds 
4093b9fa093SArnaldo Carvalho de Melo 	fprintf(out, _("#\n"
4101da177e4SLinus Torvalds 		       "# Automatically generated make config: don't edit\n"
4111da177e4SLinus Torvalds 		       "# Linux kernel version: %s\n"
4121da177e4SLinus Torvalds 		       "%s%s"
4133b9fa093SArnaldo Carvalho de Melo 		       "#\n"),
4141da177e4SLinus Torvalds 		     sym_get_string_value(sym),
4151da177e4SLinus Torvalds 		     use_timestamp ? "# " : "",
4161da177e4SLinus Torvalds 		     use_timestamp ? ctime(&now) : "");
4171da177e4SLinus Torvalds 
4181da177e4SLinus Torvalds 	if (!sym_change_count)
4191da177e4SLinus Torvalds 		sym_clear_all_valid();
4201da177e4SLinus Torvalds 
4211da177e4SLinus Torvalds 	menu = rootmenu.list;
4221da177e4SLinus Torvalds 	while (menu) {
4231da177e4SLinus Torvalds 		sym = menu->sym;
4241da177e4SLinus Torvalds 		if (!sym) {
4251da177e4SLinus Torvalds 			if (!menu_is_visible(menu))
4261da177e4SLinus Torvalds 				goto next;
4271da177e4SLinus Torvalds 			str = menu_get_prompt(menu);
4281da177e4SLinus Torvalds 			fprintf(out, "\n"
4291da177e4SLinus Torvalds 				     "#\n"
4301da177e4SLinus Torvalds 				     "# %s\n"
4311da177e4SLinus Torvalds 				     "#\n", str);
4321da177e4SLinus Torvalds 		} else if (!(sym->flags & SYMBOL_CHOICE)) {
4331da177e4SLinus Torvalds 			sym_calc_value(sym);
4341da177e4SLinus Torvalds 			if (!(sym->flags & SYMBOL_WRITE))
4351da177e4SLinus Torvalds 				goto next;
4361da177e4SLinus Torvalds 			sym->flags &= ~SYMBOL_WRITE;
4371da177e4SLinus Torvalds 			type = sym->type;
4381da177e4SLinus Torvalds 			if (type == S_TRISTATE) {
4391da177e4SLinus Torvalds 				sym_calc_value(modules_sym);
4401da177e4SLinus Torvalds 				if (modules_sym->curr.tri == no)
4411da177e4SLinus Torvalds 					type = S_BOOLEAN;
4421da177e4SLinus Torvalds 			}
4431da177e4SLinus Torvalds 			switch (type) {
4441da177e4SLinus Torvalds 			case S_BOOLEAN:
4451da177e4SLinus Torvalds 			case S_TRISTATE:
4461da177e4SLinus Torvalds 				switch (sym_get_tristate_value(sym)) {
4471da177e4SLinus Torvalds 				case no:
4481da177e4SLinus Torvalds 					fprintf(out, "# CONFIG_%s is not set\n", sym->name);
4491da177e4SLinus Torvalds 					break;
4501da177e4SLinus Torvalds 				case mod:
4511da177e4SLinus Torvalds 					fprintf(out, "CONFIG_%s=m\n", sym->name);
4521da177e4SLinus Torvalds 					break;
4531da177e4SLinus Torvalds 				case yes:
4541da177e4SLinus Torvalds 					fprintf(out, "CONFIG_%s=y\n", sym->name);
4551da177e4SLinus Torvalds 					break;
4561da177e4SLinus Torvalds 				}
4571da177e4SLinus Torvalds 				break;
4581da177e4SLinus Torvalds 			case S_STRING:
4591da177e4SLinus Torvalds 				str = sym_get_string_value(sym);
4601da177e4SLinus Torvalds 				fprintf(out, "CONFIG_%s=\"", sym->name);
461c955ccafSRoman Zippel 				while (1) {
4621da177e4SLinus Torvalds 					l = strcspn(str, "\"\\");
4631da177e4SLinus Torvalds 					if (l) {
4641da177e4SLinus Torvalds 						fwrite(str, l, 1, out);
4651da177e4SLinus Torvalds 						str += l;
4661da177e4SLinus Torvalds 					}
467c955ccafSRoman Zippel 					if (!*str)
468c955ccafSRoman Zippel 						break;
469c955ccafSRoman Zippel 					fprintf(out, "\\%c", *str++);
470c955ccafSRoman Zippel 				}
4711da177e4SLinus Torvalds 				fputs("\"\n", out);
4721da177e4SLinus Torvalds 				break;
4731da177e4SLinus Torvalds 			case S_HEX:
4741da177e4SLinus Torvalds 				str = sym_get_string_value(sym);
4751da177e4SLinus Torvalds 				if (str[0] != '0' || (str[1] != 'x' && str[1] != 'X')) {
4761da177e4SLinus Torvalds 					fprintf(out, "CONFIG_%s=%s\n", sym->name, str);
4771da177e4SLinus Torvalds 					break;
4781da177e4SLinus Torvalds 				}
4791da177e4SLinus Torvalds 			case S_INT:
4801da177e4SLinus Torvalds 				str = sym_get_string_value(sym);
4811da177e4SLinus Torvalds 				fprintf(out, "CONFIG_%s=%s\n", sym->name, str);
4821da177e4SLinus Torvalds 				break;
4831da177e4SLinus Torvalds 			}
4841da177e4SLinus Torvalds 		}
4851da177e4SLinus Torvalds 
4861da177e4SLinus Torvalds 	next:
4871da177e4SLinus Torvalds 		if (menu->list) {
4881da177e4SLinus Torvalds 			menu = menu->list;
4891da177e4SLinus Torvalds 			continue;
4901da177e4SLinus Torvalds 		}
4911da177e4SLinus Torvalds 		if (menu->next)
4921da177e4SLinus Torvalds 			menu = menu->next;
4931da177e4SLinus Torvalds 		else while ((menu = menu->parent)) {
4941da177e4SLinus Torvalds 			if (menu->next) {
4951da177e4SLinus Torvalds 				menu = menu->next;
4961da177e4SLinus Torvalds 				break;
4971da177e4SLinus Torvalds 			}
4981da177e4SLinus Torvalds 		}
4991da177e4SLinus Torvalds 	}
5001da177e4SLinus Torvalds 	fclose(out);
5011da177e4SLinus Torvalds 	if (!name || basename != conf_def_filename) {
5021da177e4SLinus Torvalds 		if (!name)
5031da177e4SLinus Torvalds 			name = conf_def_filename;
5041da177e4SLinus Torvalds 		sprintf(tmpname, "%s.old", name);
5051da177e4SLinus Torvalds 		rename(name, tmpname);
5061da177e4SLinus Torvalds 	}
5071da177e4SLinus Torvalds 	sprintf(tmpname, "%s%s", dirname, basename);
5081da177e4SLinus Torvalds 	if (rename(newname, tmpname))
5091da177e4SLinus Torvalds 		return 1;
5101da177e4SLinus Torvalds 
511ddc97cacSRoman Zippel 	printf(_("#\n"
512ddc97cacSRoman Zippel 		 "# configuration written to %s\n"
513ddc97cacSRoman Zippel 		 "#\n"), tmpname);
514ddc97cacSRoman Zippel 
5151da177e4SLinus Torvalds 	sym_change_count = 0;
5161da177e4SLinus Torvalds 
5171da177e4SLinus Torvalds 	return 0;
5181da177e4SLinus Torvalds }
519c955ccafSRoman Zippel 
5202e3646e5SRoman Zippel int conf_split_config(void)
5212e3646e5SRoman Zippel {
5222e3646e5SRoman Zippel 	char *name, path[128];
5232e3646e5SRoman Zippel 	char *s, *d, c;
5242e3646e5SRoman Zippel 	struct symbol *sym;
5252e3646e5SRoman Zippel 	struct stat sb;
5262e3646e5SRoman Zippel 	int res, i, fd;
5272e3646e5SRoman Zippel 
5282e3646e5SRoman Zippel 	name = getenv("KCONFIG_AUTOCONFIG");
5292e3646e5SRoman Zippel 	if (!name)
5302e3646e5SRoman Zippel 		name = "include/config/auto.conf";
5312e3646e5SRoman Zippel 	conf_read_simple(name, S_DEF_AUTO);
5322e3646e5SRoman Zippel 
5332e3646e5SRoman Zippel 	if (chdir("include/config"))
5342e3646e5SRoman Zippel 		return 1;
5352e3646e5SRoman Zippel 
5362e3646e5SRoman Zippel 	res = 0;
5372e3646e5SRoman Zippel 	for_all_symbols(i, sym) {
5382e3646e5SRoman Zippel 		sym_calc_value(sym);
5392e3646e5SRoman Zippel 		if ((sym->flags & SYMBOL_AUTO) || !sym->name)
5402e3646e5SRoman Zippel 			continue;
5412e3646e5SRoman Zippel 		if (sym->flags & SYMBOL_WRITE) {
5422e3646e5SRoman Zippel 			if (sym->flags & SYMBOL_DEF_AUTO) {
5432e3646e5SRoman Zippel 				/*
5442e3646e5SRoman Zippel 				 * symbol has old and new value,
5452e3646e5SRoman Zippel 				 * so compare them...
5462e3646e5SRoman Zippel 				 */
5472e3646e5SRoman Zippel 				switch (sym->type) {
5482e3646e5SRoman Zippel 				case S_BOOLEAN:
5492e3646e5SRoman Zippel 				case S_TRISTATE:
5502e3646e5SRoman Zippel 					if (sym_get_tristate_value(sym) ==
5512e3646e5SRoman Zippel 					    sym->def[S_DEF_AUTO].tri)
5522e3646e5SRoman Zippel 						continue;
5532e3646e5SRoman Zippel 					break;
5542e3646e5SRoman Zippel 				case S_STRING:
5552e3646e5SRoman Zippel 				case S_HEX:
5562e3646e5SRoman Zippel 				case S_INT:
5572e3646e5SRoman Zippel 					if (!strcmp(sym_get_string_value(sym),
5582e3646e5SRoman Zippel 						    sym->def[S_DEF_AUTO].val))
5592e3646e5SRoman Zippel 						continue;
5602e3646e5SRoman Zippel 					break;
5612e3646e5SRoman Zippel 				default:
5622e3646e5SRoman Zippel 					break;
5632e3646e5SRoman Zippel 				}
5642e3646e5SRoman Zippel 			} else {
5652e3646e5SRoman Zippel 				/*
5662e3646e5SRoman Zippel 				 * If there is no old value, only 'no' (unset)
5672e3646e5SRoman Zippel 				 * is allowed as new value.
5682e3646e5SRoman Zippel 				 */
5692e3646e5SRoman Zippel 				switch (sym->type) {
5702e3646e5SRoman Zippel 				case S_BOOLEAN:
5712e3646e5SRoman Zippel 				case S_TRISTATE:
5722e3646e5SRoman Zippel 					if (sym_get_tristate_value(sym) == no)
5732e3646e5SRoman Zippel 						continue;
5742e3646e5SRoman Zippel 					break;
5752e3646e5SRoman Zippel 				default:
5762e3646e5SRoman Zippel 					break;
5772e3646e5SRoman Zippel 				}
5782e3646e5SRoman Zippel 			}
5792e3646e5SRoman Zippel 		} else if (!(sym->flags & SYMBOL_DEF_AUTO))
5802e3646e5SRoman Zippel 			/* There is neither an old nor a new value. */
5812e3646e5SRoman Zippel 			continue;
5822e3646e5SRoman Zippel 		/* else
5832e3646e5SRoman Zippel 		 *	There is an old value, but no new value ('no' (unset)
5842e3646e5SRoman Zippel 		 *	isn't saved in auto.conf, so the old value is always
5852e3646e5SRoman Zippel 		 *	different from 'no').
5862e3646e5SRoman Zippel 		 */
5872e3646e5SRoman Zippel 
5882e3646e5SRoman Zippel 		/* Replace all '_' and append ".h" */
5892e3646e5SRoman Zippel 		s = sym->name;
5902e3646e5SRoman Zippel 		d = path;
5912e3646e5SRoman Zippel 		while ((c = *s++)) {
5922e3646e5SRoman Zippel 			c = tolower(c);
5932e3646e5SRoman Zippel 			*d++ = (c == '_') ? '/' : c;
5942e3646e5SRoman Zippel 		}
5952e3646e5SRoman Zippel 		strcpy(d, ".h");
5962e3646e5SRoman Zippel 
5972e3646e5SRoman Zippel 		/* Assume directory path already exists. */
5982e3646e5SRoman Zippel 		fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
5992e3646e5SRoman Zippel 		if (fd == -1) {
6002e3646e5SRoman Zippel 			if (errno != ENOENT) {
6012e3646e5SRoman Zippel 				res = 1;
6022e3646e5SRoman Zippel 				break;
6032e3646e5SRoman Zippel 			}
6042e3646e5SRoman Zippel 			/*
6052e3646e5SRoman Zippel 			 * Create directory components,
6062e3646e5SRoman Zippel 			 * unless they exist already.
6072e3646e5SRoman Zippel 			 */
6082e3646e5SRoman Zippel 			d = path;
6092e3646e5SRoman Zippel 			while ((d = strchr(d, '/'))) {
6102e3646e5SRoman Zippel 				*d = 0;
6112e3646e5SRoman Zippel 				if (stat(path, &sb) && mkdir(path, 0755)) {
6122e3646e5SRoman Zippel 					res = 1;
6132e3646e5SRoman Zippel 					goto out;
6142e3646e5SRoman Zippel 				}
6152e3646e5SRoman Zippel 				*d++ = '/';
6162e3646e5SRoman Zippel 			}
6172e3646e5SRoman Zippel 			/* Try it again. */
6182e3646e5SRoman Zippel 			fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
6192e3646e5SRoman Zippel 			if (fd == -1) {
6202e3646e5SRoman Zippel 				res = 1;
6212e3646e5SRoman Zippel 				break;
6222e3646e5SRoman Zippel 			}
6232e3646e5SRoman Zippel 		}
6242e3646e5SRoman Zippel 		close(fd);
6252e3646e5SRoman Zippel 	}
6262e3646e5SRoman Zippel out:
6272e3646e5SRoman Zippel 	if (chdir("../.."))
6282e3646e5SRoman Zippel 		return 1;
6292e3646e5SRoman Zippel 
6302e3646e5SRoman Zippel 	return res;
6312e3646e5SRoman Zippel }
6322e3646e5SRoman Zippel 
633c955ccafSRoman Zippel int conf_write_autoconf(void)
634c955ccafSRoman Zippel {
635c955ccafSRoman Zippel 	struct symbol *sym;
636c955ccafSRoman Zippel 	const char *str;
637c955ccafSRoman Zippel 	char *name;
638c955ccafSRoman Zippel 	FILE *out, *out_h;
639c955ccafSRoman Zippel 	time_t now;
640c955ccafSRoman Zippel 	int i, l;
641c955ccafSRoman Zippel 
6422e3646e5SRoman Zippel 	sym_clear_all_valid();
6432e3646e5SRoman Zippel 
644c955ccafSRoman Zippel 	file_write_dep("include/config/auto.conf.cmd");
645c955ccafSRoman Zippel 
6462e3646e5SRoman Zippel 	if (conf_split_config())
6472e3646e5SRoman Zippel 		return 1;
6482e3646e5SRoman Zippel 
649c955ccafSRoman Zippel 	out = fopen(".tmpconfig", "w");
650c955ccafSRoman Zippel 	if (!out)
651c955ccafSRoman Zippel 		return 1;
652c955ccafSRoman Zippel 
653c955ccafSRoman Zippel 	out_h = fopen(".tmpconfig.h", "w");
654c955ccafSRoman Zippel 	if (!out_h) {
655c955ccafSRoman Zippel 		fclose(out);
656c955ccafSRoman Zippel 		return 1;
657c955ccafSRoman Zippel 	}
658c955ccafSRoman Zippel 
659c955ccafSRoman Zippel 	sym = sym_lookup("KERNELVERSION", 0);
660c955ccafSRoman Zippel 	sym_calc_value(sym);
661c955ccafSRoman Zippel 	time(&now);
662c955ccafSRoman Zippel 	fprintf(out, "#\n"
663c955ccafSRoman Zippel 		     "# Automatically generated make config: don't edit\n"
664c955ccafSRoman Zippel 		     "# Linux kernel version: %s\n"
665c955ccafSRoman Zippel 		     "# %s"
666c955ccafSRoman Zippel 		     "#\n",
667c955ccafSRoman Zippel 		     sym_get_string_value(sym), ctime(&now));
668c955ccafSRoman Zippel 	fprintf(out_h, "/*\n"
669c955ccafSRoman Zippel 		       " * Automatically generated C config: don't edit\n"
670c955ccafSRoman Zippel 		       " * Linux kernel version: %s\n"
671c955ccafSRoman Zippel 		       " * %s"
672c955ccafSRoman Zippel 		       " */\n"
673c955ccafSRoman Zippel 		       "#define AUTOCONF_INCLUDED\n",
674c955ccafSRoman Zippel 		       sym_get_string_value(sym), ctime(&now));
675c955ccafSRoman Zippel 
676c955ccafSRoman Zippel 	for_all_symbols(i, sym) {
677c955ccafSRoman Zippel 		sym_calc_value(sym);
678c955ccafSRoman Zippel 		if (!(sym->flags & SYMBOL_WRITE) || !sym->name)
679c955ccafSRoman Zippel 			continue;
680c955ccafSRoman Zippel 		switch (sym->type) {
681c955ccafSRoman Zippel 		case S_BOOLEAN:
682c955ccafSRoman Zippel 		case S_TRISTATE:
683c955ccafSRoman Zippel 			switch (sym_get_tristate_value(sym)) {
684c955ccafSRoman Zippel 			case no:
685c955ccafSRoman Zippel 				break;
686c955ccafSRoman Zippel 			case mod:
687c955ccafSRoman Zippel 				fprintf(out, "CONFIG_%s=m\n", sym->name);
688c955ccafSRoman Zippel 				fprintf(out_h, "#define CONFIG_%s_MODULE 1\n", sym->name);
689c955ccafSRoman Zippel 				break;
690c955ccafSRoman Zippel 			case yes:
691c955ccafSRoman Zippel 				fprintf(out, "CONFIG_%s=y\n", sym->name);
692c955ccafSRoman Zippel 				fprintf(out_h, "#define CONFIG_%s 1\n", sym->name);
693c955ccafSRoman Zippel 				break;
694c955ccafSRoman Zippel 			}
695c955ccafSRoman Zippel 			break;
696c955ccafSRoman Zippel 		case S_STRING:
697c955ccafSRoman Zippel 			str = sym_get_string_value(sym);
698c955ccafSRoman Zippel 			fprintf(out, "CONFIG_%s=\"", sym->name);
699c955ccafSRoman Zippel 			fprintf(out_h, "#define CONFIG_%s \"", sym->name);
700c955ccafSRoman Zippel 			while (1) {
701c955ccafSRoman Zippel 				l = strcspn(str, "\"\\");
702c955ccafSRoman Zippel 				if (l) {
703c955ccafSRoman Zippel 					fwrite(str, l, 1, out);
704c955ccafSRoman Zippel 					fwrite(str, l, 1, out_h);
705c955ccafSRoman Zippel 					str += l;
706c955ccafSRoman Zippel 				}
707c955ccafSRoman Zippel 				if (!*str)
708c955ccafSRoman Zippel 					break;
709c955ccafSRoman Zippel 				fprintf(out, "\\%c", *str);
710c955ccafSRoman Zippel 				fprintf(out_h, "\\%c", *str);
711c955ccafSRoman Zippel 				str++;
712c955ccafSRoman Zippel 			}
713c955ccafSRoman Zippel 			fputs("\"\n", out);
714c955ccafSRoman Zippel 			fputs("\"\n", out_h);
715c955ccafSRoman Zippel 			break;
716c955ccafSRoman Zippel 		case S_HEX:
717c955ccafSRoman Zippel 			str = sym_get_string_value(sym);
718c955ccafSRoman Zippel 			if (str[0] != '0' || (str[1] != 'x' && str[1] != 'X')) {
719c955ccafSRoman Zippel 				fprintf(out, "CONFIG_%s=%s\n", sym->name, str);
720c955ccafSRoman Zippel 				fprintf(out_h, "#define CONFIG_%s 0x%s\n", sym->name, str);
721c955ccafSRoman Zippel 				break;
722c955ccafSRoman Zippel 			}
723c955ccafSRoman Zippel 		case S_INT:
724c955ccafSRoman Zippel 			str = sym_get_string_value(sym);
725c955ccafSRoman Zippel 			fprintf(out, "CONFIG_%s=%s\n", sym->name, str);
726c955ccafSRoman Zippel 			fprintf(out_h, "#define CONFIG_%s %s\n", sym->name, str);
727c955ccafSRoman Zippel 			break;
728c955ccafSRoman Zippel 		default:
729c955ccafSRoman Zippel 			break;
730c955ccafSRoman Zippel 		}
731c955ccafSRoman Zippel 	}
732c955ccafSRoman Zippel 	fclose(out);
733c955ccafSRoman Zippel 	fclose(out_h);
734c955ccafSRoman Zippel 
735c955ccafSRoman Zippel 	name = getenv("KCONFIG_AUTOHEADER");
736c955ccafSRoman Zippel 	if (!name)
737c955ccafSRoman Zippel 		name = "include/linux/autoconf.h";
738c955ccafSRoman Zippel 	if (rename(".tmpconfig.h", name))
739c955ccafSRoman Zippel 		return 1;
740c955ccafSRoman Zippel 	name = getenv("KCONFIG_AUTOCONFIG");
741c955ccafSRoman Zippel 	if (!name)
742c955ccafSRoman Zippel 		name = "include/config/auto.conf";
743c955ccafSRoman Zippel 	/*
744c955ccafSRoman Zippel 	 * This must be the last step, kbuild has a dependency on auto.conf
745c955ccafSRoman Zippel 	 * and this marks the successful completion of the previous steps.
746c955ccafSRoman Zippel 	 */
747c955ccafSRoman Zippel 	if (rename(".tmpconfig", name))
748c955ccafSRoman Zippel 		return 1;
749c955ccafSRoman Zippel 
750c955ccafSRoman Zippel 	return 0;
751c955ccafSRoman Zippel }
752