xref: /linux/scripts/kconfig/confdata.c (revision d6ee35764f270c699e165b15dc59f4e55546bfda)
1 /*
2  * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
3  * Released under the terms of the GNU GPL v2.0.
4  */
5 
6 #include <sys/stat.h>
7 #include <ctype.h>
8 #include <fcntl.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <time.h>
13 #include <unistd.h>
14 
15 #define LKC_DIRECT_LINK
16 #include "lkc.h"
17 
18 static void conf_warning(const char *fmt, ...)
19 	__attribute__ ((format (printf, 1, 2)));
20 
21 static const char *conf_filename;
22 static int conf_lineno, conf_warnings, conf_unsaved;
23 
24 const char conf_defname[] = "arch/$ARCH/defconfig";
25 
26 static void conf_warning(const char *fmt, ...)
27 {
28 	va_list ap;
29 	va_start(ap, fmt);
30 	fprintf(stderr, "%s:%d:warning: ", conf_filename, conf_lineno);
31 	vfprintf(stderr, fmt, ap);
32 	fprintf(stderr, "\n");
33 	va_end(ap);
34 	conf_warnings++;
35 }
36 
37 const char *conf_get_configname(void)
38 {
39 	char *name = getenv("KCONFIG_CONFIG");
40 
41 	return name ? name : ".config";
42 }
43 
44 static char *conf_expand_value(const char *in)
45 {
46 	struct symbol *sym;
47 	const char *src;
48 	static char res_value[SYMBOL_MAXLENGTH];
49 	char *dst, name[SYMBOL_MAXLENGTH];
50 
51 	res_value[0] = 0;
52 	dst = name;
53 	while ((src = strchr(in, '$'))) {
54 		strncat(res_value, in, src - in);
55 		src++;
56 		dst = name;
57 		while (isalnum(*src) || *src == '_')
58 			*dst++ = *src++;
59 		*dst = 0;
60 		sym = sym_lookup(name, 0);
61 		sym_calc_value(sym);
62 		strcat(res_value, sym_get_string_value(sym));
63 		in = src;
64 	}
65 	strcat(res_value, in);
66 
67 	return res_value;
68 }
69 
70 char *conf_get_default_confname(void)
71 {
72 	struct stat buf;
73 	static char fullname[PATH_MAX+1];
74 	char *env, *name;
75 
76 	name = conf_expand_value(conf_defname);
77 	env = getenv(SRCTREE);
78 	if (env) {
79 		sprintf(fullname, "%s/%s", env, name);
80 		if (!stat(fullname, &buf))
81 			return fullname;
82 	}
83 	return name;
84 }
85 
86 static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p)
87 {
88 	char *p2;
89 
90 	switch (sym->type) {
91 	case S_TRISTATE:
92 		if (p[0] == 'm') {
93 			sym->def[def].tri = mod;
94 			sym->flags |= def_flags;
95 			break;
96 		}
97 	case S_BOOLEAN:
98 		if (p[0] == 'y') {
99 			sym->def[def].tri = yes;
100 			sym->flags |= def_flags;
101 			break;
102 		}
103 		if (p[0] == 'n') {
104 			sym->def[def].tri = no;
105 			sym->flags |= def_flags;
106 			break;
107 		}
108 		conf_warning("symbol value '%s' invalid for %s", p, sym->name);
109 		break;
110 	case S_OTHER:
111 		if (*p != '"') {
112 			for (p2 = p; *p2 && !isspace(*p2); p2++)
113 				;
114 			sym->type = S_STRING;
115 			goto done;
116 		}
117 	case S_STRING:
118 		if (*p++ != '"')
119 			break;
120 		for (p2 = p; (p2 = strpbrk(p2, "\"\\")); p2++) {
121 			if (*p2 == '"') {
122 				*p2 = 0;
123 				break;
124 			}
125 			memmove(p2, p2 + 1, strlen(p2));
126 		}
127 		if (!p2) {
128 			conf_warning("invalid string found");
129 			return 1;
130 		}
131 	case S_INT:
132 	case S_HEX:
133 	done:
134 		if (sym_string_valid(sym, p)) {
135 			sym->def[def].val = strdup(p);
136 			sym->flags |= def_flags;
137 		} else {
138 			conf_warning("symbol value '%s' invalid for %s", p, sym->name);
139 			return 1;
140 		}
141 		break;
142 	default:
143 		;
144 	}
145 	return 0;
146 }
147 
148 int conf_read_simple(const char *name, int def)
149 {
150 	FILE *in = NULL;
151 	char line[1024];
152 	char *p, *p2;
153 	struct symbol *sym;
154 	int i, def_flags;
155 
156 	if (name) {
157 		in = zconf_fopen(name);
158 	} else {
159 		struct property *prop;
160 
161 		name = conf_get_configname();
162 		in = zconf_fopen(name);
163 		if (in)
164 			goto load;
165 		sym_add_change_count(1);
166 		if (!sym_defconfig_list)
167 			return 1;
168 
169 		for_all_defaults(sym_defconfig_list, prop) {
170 			if (expr_calc_value(prop->visible.expr) == no ||
171 			    prop->expr->type != E_SYMBOL)
172 				continue;
173 			name = conf_expand_value(prop->expr->left.sym->name);
174 			in = zconf_fopen(name);
175 			if (in) {
176 				printf(_("#\n"
177 					 "# using defaults found in %s\n"
178 					 "#\n"), name);
179 				goto load;
180 			}
181 		}
182 	}
183 	if (!in)
184 		return 1;
185 
186 load:
187 	conf_filename = name;
188 	conf_lineno = 0;
189 	conf_warnings = 0;
190 	conf_unsaved = 0;
191 
192 	def_flags = SYMBOL_DEF << def;
193 	for_all_symbols(i, sym) {
194 		sym->flags |= SYMBOL_CHANGED;
195 		sym->flags &= ~(def_flags|SYMBOL_VALID);
196 		if (sym_is_choice(sym))
197 			sym->flags |= def_flags;
198 		switch (sym->type) {
199 		case S_INT:
200 		case S_HEX:
201 		case S_STRING:
202 			if (sym->def[def].val)
203 				free(sym->def[def].val);
204 		default:
205 			sym->def[def].val = NULL;
206 			sym->def[def].tri = no;
207 		}
208 	}
209 
210 	while (fgets(line, sizeof(line), in)) {
211 		conf_lineno++;
212 		sym = NULL;
213 		switch (line[0]) {
214 		case '#':
215 			if (memcmp(line + 2, "CONFIG_", 7))
216 				continue;
217 			p = strchr(line + 9, ' ');
218 			if (!p)
219 				continue;
220 			*p++ = 0;
221 			if (strncmp(p, "is not set", 10))
222 				continue;
223 			if (def == S_DEF_USER) {
224 				sym = sym_find(line + 9);
225 				if (!sym) {
226 					conf_warning("trying to assign nonexistent symbol %s", line + 9);
227 					break;
228 				}
229 			} else {
230 				sym = sym_lookup(line + 9, 0);
231 				if (sym->type == S_UNKNOWN)
232 					sym->type = S_BOOLEAN;
233 			}
234 			if (sym->flags & def_flags) {
235 				conf_warning("override: reassigning to symbol %s", sym->name);
236 			}
237 			switch (sym->type) {
238 			case S_BOOLEAN:
239 			case S_TRISTATE:
240 				sym->def[def].tri = no;
241 				sym->flags |= def_flags;
242 				break;
243 			default:
244 				;
245 			}
246 			break;
247 		case 'C':
248 			if (memcmp(line, "CONFIG_", 7)) {
249 				conf_warning("unexpected data");
250 				continue;
251 			}
252 			p = strchr(line + 7, '=');
253 			if (!p)
254 				continue;
255 			*p++ = 0;
256 			p2 = strchr(p, '\n');
257 			if (p2) {
258 				*p2-- = 0;
259 				if (*p2 == '\r')
260 					*p2 = 0;
261 			}
262 			if (def == S_DEF_USER) {
263 				sym = sym_find(line + 7);
264 				if (!sym) {
265 					conf_warning("trying to assign nonexistent symbol %s", line + 7);
266 					break;
267 				}
268 			} else {
269 				sym = sym_lookup(line + 7, 0);
270 				if (sym->type == S_UNKNOWN)
271 					sym->type = S_OTHER;
272 			}
273 			if (sym->flags & def_flags) {
274 				conf_warning("override: reassigning to symbol %s", sym->name);
275 			}
276 			if (conf_set_sym_val(sym, def, def_flags, p))
277 				continue;
278 			break;
279 		case '\r':
280 		case '\n':
281 			break;
282 		default:
283 			conf_warning("unexpected data");
284 			continue;
285 		}
286 		if (sym && sym_is_choice_value(sym)) {
287 			struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym));
288 			switch (sym->def[def].tri) {
289 			case no:
290 				break;
291 			case mod:
292 				if (cs->def[def].tri == yes) {
293 					conf_warning("%s creates inconsistent choice state", sym->name);
294 					cs->flags &= ~def_flags;
295 				}
296 				break;
297 			case yes:
298 				if (cs->def[def].tri != no)
299 					conf_warning("override: %s changes choice state", sym->name);
300 				cs->def[def].val = sym;
301 				break;
302 			}
303 			cs->def[def].tri = EXPR_OR(cs->def[def].tri, sym->def[def].tri);
304 		}
305 	}
306 	fclose(in);
307 
308 	if (modules_sym)
309 		sym_calc_value(modules_sym);
310 	return 0;
311 }
312 
313 int conf_read(const char *name)
314 {
315 	struct symbol *sym;
316 	struct property *prop;
317 	struct expr *e;
318 	int i, flags;
319 
320 	sym_set_change_count(0);
321 
322 	if (conf_read_simple(name, S_DEF_USER))
323 		return 1;
324 
325 	for_all_symbols(i, sym) {
326 		sym_calc_value(sym);
327 		if (sym_is_choice(sym) || (sym->flags & SYMBOL_AUTO))
328 			goto sym_ok;
329 		if (sym_has_value(sym) && (sym->flags & SYMBOL_WRITE)) {
330 			/* check that calculated value agrees with saved value */
331 			switch (sym->type) {
332 			case S_BOOLEAN:
333 			case S_TRISTATE:
334 				if (sym->def[S_DEF_USER].tri != sym_get_tristate_value(sym))
335 					break;
336 				if (!sym_is_choice(sym))
337 					goto sym_ok;
338 			default:
339 				if (!strcmp(sym->curr.val, sym->def[S_DEF_USER].val))
340 					goto sym_ok;
341 				break;
342 			}
343 		} else if (!sym_has_value(sym) && !(sym->flags & SYMBOL_WRITE))
344 			/* no previous value and not saved */
345 			goto sym_ok;
346 		conf_unsaved++;
347 		/* maybe print value in verbose mode... */
348 	sym_ok:
349 		if (!sym_is_choice(sym))
350 			continue;
351 		/* The choice symbol only has a set value (and thus is not new)
352 		 * if all its visible childs have values.
353 		 */
354 		prop = sym_get_choice_prop(sym);
355 		flags = sym->flags;
356 		for (e = prop->expr; e; e = e->left.expr)
357 			if (e->right.sym->visible != no)
358 				flags &= e->right.sym->flags;
359 		sym->flags &= flags | ~SYMBOL_DEF_USER;
360 	}
361 
362 	for_all_symbols(i, sym) {
363 		if (sym_has_value(sym) && !sym_is_choice_value(sym)) {
364 			/* Reset values of generates values, so they'll appear
365 			 * as new, if they should become visible, but that
366 			 * doesn't quite work if the Kconfig and the saved
367 			 * configuration disagree.
368 			 */
369 			if (sym->visible == no && !conf_unsaved)
370 				sym->flags &= ~SYMBOL_DEF_USER;
371 			switch (sym->type) {
372 			case S_STRING:
373 			case S_INT:
374 			case S_HEX:
375 				/* Reset a string value if it's out of range */
376 				if (sym_string_within_range(sym, sym->def[S_DEF_USER].val))
377 					break;
378 				sym->flags &= ~(SYMBOL_VALID|SYMBOL_DEF_USER);
379 				conf_unsaved++;
380 				break;
381 			default:
382 				break;
383 			}
384 		}
385 	}
386 
387 	sym_add_change_count(conf_warnings || conf_unsaved);
388 
389 	return 0;
390 }
391 
392 int conf_write(const char *name)
393 {
394 	FILE *out;
395 	struct symbol *sym;
396 	struct menu *menu;
397 	const char *basename;
398 	char dirname[128], tmpname[128], newname[128];
399 	int type, l;
400 	const char *str;
401 	time_t now;
402 	int use_timestamp = 1;
403 	char *env;
404 
405 	dirname[0] = 0;
406 	if (name && name[0]) {
407 		struct stat st;
408 		char *slash;
409 
410 		if (!stat(name, &st) && S_ISDIR(st.st_mode)) {
411 			strcpy(dirname, name);
412 			strcat(dirname, "/");
413 			basename = conf_get_configname();
414 		} else if ((slash = strrchr(name, '/'))) {
415 			int size = slash - name + 1;
416 			memcpy(dirname, name, size);
417 			dirname[size] = 0;
418 			if (slash[1])
419 				basename = slash + 1;
420 			else
421 				basename = conf_get_configname();
422 		} else
423 			basename = name;
424 	} else
425 		basename = conf_get_configname();
426 
427 	sprintf(newname, "%s%s", dirname, basename);
428 	env = getenv("KCONFIG_OVERWRITECONFIG");
429 	if (!env || !*env) {
430 		sprintf(tmpname, "%s.tmpconfig.%d", dirname, (int)getpid());
431 		out = fopen(tmpname, "w");
432 	} else {
433 		*tmpname = 0;
434 		out = fopen(newname, "w");
435 	}
436 	if (!out)
437 		return 1;
438 
439 	sym = sym_lookup("KERNELVERSION", 0);
440 	sym_calc_value(sym);
441 	time(&now);
442 	env = getenv("KCONFIG_NOTIMESTAMP");
443 	if (env && *env)
444 		use_timestamp = 0;
445 
446 	fprintf(out, _("#\n"
447 		       "# Automatically generated make config: don't edit\n"
448 		       "# Linux kernel version: %s\n"
449 		       "%s%s"
450 		       "#\n"),
451 		     sym_get_string_value(sym),
452 		     use_timestamp ? "# " : "",
453 		     use_timestamp ? ctime(&now) : "");
454 
455 	if (!conf_get_changed())
456 		sym_clear_all_valid();
457 
458 	menu = rootmenu.list;
459 	while (menu) {
460 		sym = menu->sym;
461 		if (!sym) {
462 			if (!menu_is_visible(menu))
463 				goto next;
464 			str = menu_get_prompt(menu);
465 			fprintf(out, "\n"
466 				     "#\n"
467 				     "# %s\n"
468 				     "#\n", str);
469 		} else if (!(sym->flags & SYMBOL_CHOICE)) {
470 			sym_calc_value(sym);
471 			if (!(sym->flags & SYMBOL_WRITE))
472 				goto next;
473 			sym->flags &= ~SYMBOL_WRITE;
474 			type = sym->type;
475 			if (type == S_TRISTATE) {
476 				sym_calc_value(modules_sym);
477 				if (modules_sym->curr.tri == no)
478 					type = S_BOOLEAN;
479 			}
480 			switch (type) {
481 			case S_BOOLEAN:
482 			case S_TRISTATE:
483 				switch (sym_get_tristate_value(sym)) {
484 				case no:
485 					fprintf(out, "# CONFIG_%s is not set\n", sym->name);
486 					break;
487 				case mod:
488 					fprintf(out, "CONFIG_%s=m\n", sym->name);
489 					break;
490 				case yes:
491 					fprintf(out, "CONFIG_%s=y\n", sym->name);
492 					break;
493 				}
494 				break;
495 			case S_STRING:
496 				str = sym_get_string_value(sym);
497 				fprintf(out, "CONFIG_%s=\"", sym->name);
498 				while (1) {
499 					l = strcspn(str, "\"\\");
500 					if (l) {
501 						fwrite(str, l, 1, out);
502 						str += l;
503 					}
504 					if (!*str)
505 						break;
506 					fprintf(out, "\\%c", *str++);
507 				}
508 				fputs("\"\n", out);
509 				break;
510 			case S_HEX:
511 				str = sym_get_string_value(sym);
512 				if (str[0] != '0' || (str[1] != 'x' && str[1] != 'X')) {
513 					fprintf(out, "CONFIG_%s=%s\n", sym->name, str);
514 					break;
515 				}
516 			case S_INT:
517 				str = sym_get_string_value(sym);
518 				fprintf(out, "CONFIG_%s=%s\n", sym->name, str);
519 				break;
520 			}
521 		}
522 
523 	next:
524 		if (menu->list) {
525 			menu = menu->list;
526 			continue;
527 		}
528 		if (menu->next)
529 			menu = menu->next;
530 		else while ((menu = menu->parent)) {
531 			if (menu->next) {
532 				menu = menu->next;
533 				break;
534 			}
535 		}
536 	}
537 	fclose(out);
538 
539 	if (*tmpname) {
540 		strcat(dirname, basename);
541 		strcat(dirname, ".old");
542 		rename(newname, dirname);
543 		if (rename(tmpname, newname))
544 			return 1;
545 	}
546 
547 	printf(_("#\n"
548 		 "# configuration written to %s\n"
549 		 "#\n"), newname);
550 
551 	sym_set_change_count(0);
552 
553 	return 0;
554 }
555 
556 int conf_split_config(void)
557 {
558 	char *name, path[128];
559 	char *s, *d, c;
560 	struct symbol *sym;
561 	struct stat sb;
562 	int res, i, fd;
563 
564 	name = getenv("KCONFIG_AUTOCONFIG");
565 	if (!name)
566 		name = "include/config/auto.conf";
567 	conf_read_simple(name, S_DEF_AUTO);
568 
569 	if (chdir("include/config"))
570 		return 1;
571 
572 	res = 0;
573 	for_all_symbols(i, sym) {
574 		sym_calc_value(sym);
575 		if ((sym->flags & SYMBOL_AUTO) || !sym->name)
576 			continue;
577 		if (sym->flags & SYMBOL_WRITE) {
578 			if (sym->flags & SYMBOL_DEF_AUTO) {
579 				/*
580 				 * symbol has old and new value,
581 				 * so compare them...
582 				 */
583 				switch (sym->type) {
584 				case S_BOOLEAN:
585 				case S_TRISTATE:
586 					if (sym_get_tristate_value(sym) ==
587 					    sym->def[S_DEF_AUTO].tri)
588 						continue;
589 					break;
590 				case S_STRING:
591 				case S_HEX:
592 				case S_INT:
593 					if (!strcmp(sym_get_string_value(sym),
594 						    sym->def[S_DEF_AUTO].val))
595 						continue;
596 					break;
597 				default:
598 					break;
599 				}
600 			} else {
601 				/*
602 				 * If there is no old value, only 'no' (unset)
603 				 * is allowed as new value.
604 				 */
605 				switch (sym->type) {
606 				case S_BOOLEAN:
607 				case S_TRISTATE:
608 					if (sym_get_tristate_value(sym) == no)
609 						continue;
610 					break;
611 				default:
612 					break;
613 				}
614 			}
615 		} else if (!(sym->flags & SYMBOL_DEF_AUTO))
616 			/* There is neither an old nor a new value. */
617 			continue;
618 		/* else
619 		 *	There is an old value, but no new value ('no' (unset)
620 		 *	isn't saved in auto.conf, so the old value is always
621 		 *	different from 'no').
622 		 */
623 
624 		/* Replace all '_' and append ".h" */
625 		s = sym->name;
626 		d = path;
627 		while ((c = *s++)) {
628 			c = tolower(c);
629 			*d++ = (c == '_') ? '/' : c;
630 		}
631 		strcpy(d, ".h");
632 
633 		/* Assume directory path already exists. */
634 		fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
635 		if (fd == -1) {
636 			if (errno != ENOENT) {
637 				res = 1;
638 				break;
639 			}
640 			/*
641 			 * Create directory components,
642 			 * unless they exist already.
643 			 */
644 			d = path;
645 			while ((d = strchr(d, '/'))) {
646 				*d = 0;
647 				if (stat(path, &sb) && mkdir(path, 0755)) {
648 					res = 1;
649 					goto out;
650 				}
651 				*d++ = '/';
652 			}
653 			/* Try it again. */
654 			fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
655 			if (fd == -1) {
656 				res = 1;
657 				break;
658 			}
659 		}
660 		close(fd);
661 	}
662 out:
663 	if (chdir("../.."))
664 		return 1;
665 
666 	return res;
667 }
668 
669 int conf_write_autoconf(void)
670 {
671 	struct symbol *sym;
672 	const char *str;
673 	char *name;
674 	FILE *out, *out_h;
675 	time_t now;
676 	int i, l;
677 
678 	sym_clear_all_valid();
679 
680 	file_write_dep("include/config/auto.conf.cmd");
681 
682 	if (conf_split_config())
683 		return 1;
684 
685 	out = fopen(".tmpconfig", "w");
686 	if (!out)
687 		return 1;
688 
689 	out_h = fopen(".tmpconfig.h", "w");
690 	if (!out_h) {
691 		fclose(out);
692 		return 1;
693 	}
694 
695 	sym = sym_lookup("KERNELVERSION", 0);
696 	sym_calc_value(sym);
697 	time(&now);
698 	fprintf(out, "#\n"
699 		     "# Automatically generated make config: don't edit\n"
700 		     "# Linux kernel version: %s\n"
701 		     "# %s"
702 		     "#\n",
703 		     sym_get_string_value(sym), ctime(&now));
704 	fprintf(out_h, "/*\n"
705 		       " * Automatically generated C config: don't edit\n"
706 		       " * Linux kernel version: %s\n"
707 		       " * %s"
708 		       " */\n"
709 		       "#define AUTOCONF_INCLUDED\n",
710 		       sym_get_string_value(sym), ctime(&now));
711 
712 	for_all_symbols(i, sym) {
713 		sym_calc_value(sym);
714 		if (!(sym->flags & SYMBOL_WRITE) || !sym->name)
715 			continue;
716 		switch (sym->type) {
717 		case S_BOOLEAN:
718 		case S_TRISTATE:
719 			switch (sym_get_tristate_value(sym)) {
720 			case no:
721 				break;
722 			case mod:
723 				fprintf(out, "CONFIG_%s=m\n", sym->name);
724 				fprintf(out_h, "#define CONFIG_%s_MODULE 1\n", sym->name);
725 				break;
726 			case yes:
727 				fprintf(out, "CONFIG_%s=y\n", sym->name);
728 				fprintf(out_h, "#define CONFIG_%s 1\n", sym->name);
729 				break;
730 			}
731 			break;
732 		case S_STRING:
733 			str = sym_get_string_value(sym);
734 			fprintf(out, "CONFIG_%s=\"", sym->name);
735 			fprintf(out_h, "#define CONFIG_%s \"", sym->name);
736 			while (1) {
737 				l = strcspn(str, "\"\\");
738 				if (l) {
739 					fwrite(str, l, 1, out);
740 					fwrite(str, l, 1, out_h);
741 					str += l;
742 				}
743 				if (!*str)
744 					break;
745 				fprintf(out, "\\%c", *str);
746 				fprintf(out_h, "\\%c", *str);
747 				str++;
748 			}
749 			fputs("\"\n", out);
750 			fputs("\"\n", out_h);
751 			break;
752 		case S_HEX:
753 			str = sym_get_string_value(sym);
754 			if (str[0] != '0' || (str[1] != 'x' && str[1] != 'X')) {
755 				fprintf(out, "CONFIG_%s=%s\n", sym->name, str);
756 				fprintf(out_h, "#define CONFIG_%s 0x%s\n", sym->name, str);
757 				break;
758 			}
759 		case S_INT:
760 			str = sym_get_string_value(sym);
761 			fprintf(out, "CONFIG_%s=%s\n", sym->name, str);
762 			fprintf(out_h, "#define CONFIG_%s %s\n", sym->name, str);
763 			break;
764 		default:
765 			break;
766 		}
767 	}
768 	fclose(out);
769 	fclose(out_h);
770 
771 	name = getenv("KCONFIG_AUTOHEADER");
772 	if (!name)
773 		name = "include/linux/autoconf.h";
774 	if (rename(".tmpconfig.h", name))
775 		return 1;
776 	name = getenv("KCONFIG_AUTOCONFIG");
777 	if (!name)
778 		name = "include/config/auto.conf";
779 	/*
780 	 * This must be the last step, kbuild has a dependency on auto.conf
781 	 * and this marks the successful completion of the previous steps.
782 	 */
783 	if (rename(".tmpconfig", name))
784 		return 1;
785 
786 	return 0;
787 }
788 
789 static int sym_change_count;
790 static void (*conf_changed_callback)(void);
791 
792 void sym_set_change_count(int count)
793 {
794 	int _sym_change_count = sym_change_count;
795 	sym_change_count = count;
796 	if (conf_changed_callback &&
797 	    (bool)_sym_change_count != (bool)count)
798 		conf_changed_callback();
799 }
800 
801 void sym_add_change_count(int count)
802 {
803 	sym_set_change_count(count + sym_change_count);
804 }
805 
806 bool conf_get_changed(void)
807 {
808 	return sym_change_count;
809 }
810 
811 void conf_set_changed_callback(void (*fn)(void))
812 {
813 	conf_changed_callback = fn;
814 }
815