blob: 2da4a8d775a58d6f5f1269169a7763aa8436ffb6 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
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 <stdio.h>
9#include <stdlib.h>
10#include <string.h>
11#include <time.h>
12#include <unistd.h>
13
14#define LKC_DIRECT_LINK
15#include "lkc.h"
16
Roman Zippelc1a0f5e2005-11-08 21:34:54 -080017static void conf_warning(const char *fmt, ...)
18 __attribute__ ((format (printf, 1, 2)));
19
20static const char *conf_filename;
21static int conf_lineno, conf_warnings, conf_unsaved;
22
Linus Torvalds1da177e2005-04-16 15:20:36 -070023const char conf_def_filename[] = ".config";
24
25const char conf_defname[] = "arch/$ARCH/defconfig";
26
27const char *conf_confnames[] = {
28 ".config",
29 "/lib/modules/$UNAME_RELEASE/.config",
30 "/etc/kernel-config",
31 "/boot/config-$UNAME_RELEASE",
32 conf_defname,
33 NULL,
34};
35
Roman Zippelc1a0f5e2005-11-08 21:34:54 -080036static void conf_warning(const char *fmt, ...)
37{
38 va_list ap;
39 va_start(ap, fmt);
40 fprintf(stderr, "%s:%d:warning: ", conf_filename, conf_lineno);
41 vfprintf(stderr, fmt, ap);
42 fprintf(stderr, "\n");
43 va_end(ap);
44 conf_warnings++;
45}
46
J.A. Magallon48b9d032005-06-25 14:59:22 -070047static char *conf_expand_value(const char *in)
Linus Torvalds1da177e2005-04-16 15:20:36 -070048{
49 struct symbol *sym;
J.A. Magallon48b9d032005-06-25 14:59:22 -070050 const char *src;
Linus Torvalds1da177e2005-04-16 15:20:36 -070051 static char res_value[SYMBOL_MAXLENGTH];
52 char *dst, name[SYMBOL_MAXLENGTH];
53
54 res_value[0] = 0;
55 dst = name;
56 while ((src = strchr(in, '$'))) {
57 strncat(res_value, in, src - in);
58 src++;
59 dst = name;
60 while (isalnum(*src) || *src == '_')
61 *dst++ = *src++;
62 *dst = 0;
63 sym = sym_lookup(name, 0);
64 sym_calc_value(sym);
65 strcat(res_value, sym_get_string_value(sym));
66 in = src;
67 }
68 strcat(res_value, in);
69
70 return res_value;
71}
72
73char *conf_get_default_confname(void)
74{
75 struct stat buf;
76 static char fullname[PATH_MAX+1];
77 char *env, *name;
78
79 name = conf_expand_value(conf_defname);
80 env = getenv(SRCTREE);
81 if (env) {
82 sprintf(fullname, "%s/%s", env, name);
83 if (!stat(fullname, &buf))
84 return fullname;
85 }
86 return name;
87}
88
Roman Zippel90389162005-11-08 21:34:49 -080089int conf_read_simple(const char *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -070090{
91 FILE *in = NULL;
92 char line[1024];
93 char *p, *p2;
Linus Torvalds1da177e2005-04-16 15:20:36 -070094 struct symbol *sym;
Linus Torvalds1da177e2005-04-16 15:20:36 -070095 int i;
96
97 if (name) {
98 in = zconf_fopen(name);
99 } else {
100 const char **names = conf_confnames;
Roman Zippelddc97ca2006-06-08 22:12:38 -0700101 name = *names++;
102 if (!name)
103 return 1;
104 in = zconf_fopen(name);
105 if (in)
106 goto load;
107 sym_change_count++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108 while ((name = *names++)) {
109 name = conf_expand_value(name);
110 in = zconf_fopen(name);
111 if (in) {
Arnaldo Carvalho de Melo3b9fa092005-05-05 15:09:46 -0700112 printf(_("#\n"
Roman Zippelddc97ca2006-06-08 22:12:38 -0700113 "# using defaults found in %s\n"
114 "#\n"), name);
115 goto load;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116 }
117 }
118 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119 if (!in)
120 return 1;
121
Roman Zippelddc97ca2006-06-08 22:12:38 -0700122load:
Roman Zippelc1a0f5e2005-11-08 21:34:54 -0800123 conf_filename = name;
124 conf_lineno = 0;
125 conf_warnings = 0;
126 conf_unsaved = 0;
127
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128 for_all_symbols(i, sym) {
129 sym->flags |= SYMBOL_NEW | SYMBOL_CHANGED;
Roman Zippelc1a0f5e2005-11-08 21:34:54 -0800130 if (sym_is_choice(sym))
131 sym->flags &= ~SYMBOL_NEW;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132 sym->flags &= ~SYMBOL_VALID;
133 switch (sym->type) {
134 case S_INT:
135 case S_HEX:
136 case S_STRING:
137 if (sym->user.val)
138 free(sym->user.val);
139 default:
140 sym->user.val = NULL;
141 sym->user.tri = no;
142 }
143 }
144
145 while (fgets(line, sizeof(line), in)) {
Roman Zippelc1a0f5e2005-11-08 21:34:54 -0800146 conf_lineno++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147 sym = NULL;
148 switch (line[0]) {
149 case '#':
150 if (memcmp(line + 2, "CONFIG_", 7))
151 continue;
152 p = strchr(line + 9, ' ');
153 if (!p)
154 continue;
155 *p++ = 0;
156 if (strncmp(p, "is not set", 10))
157 continue;
158 sym = sym_find(line + 9);
159 if (!sym) {
Roman Zippelc1a0f5e2005-11-08 21:34:54 -0800160 conf_warning("trying to assign nonexistent symbol %s", line + 9);
161 break;
162 } else if (!(sym->flags & SYMBOL_NEW)) {
163 conf_warning("trying to reassign symbol %s", sym->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164 break;
165 }
166 switch (sym->type) {
167 case S_BOOLEAN:
168 case S_TRISTATE:
169 sym->user.tri = no;
170 sym->flags &= ~SYMBOL_NEW;
171 break;
172 default:
173 ;
174 }
175 break;
176 case 'C':
Roman Zippelc1a0f5e2005-11-08 21:34:54 -0800177 if (memcmp(line, "CONFIG_", 7)) {
178 conf_warning("unexpected data");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179 continue;
Roman Zippelc1a0f5e2005-11-08 21:34:54 -0800180 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181 p = strchr(line + 7, '=');
182 if (!p)
183 continue;
184 *p++ = 0;
185 p2 = strchr(p, '\n');
186 if (p2)
187 *p2 = 0;
188 sym = sym_find(line + 7);
189 if (!sym) {
Roman Zippelc1a0f5e2005-11-08 21:34:54 -0800190 conf_warning("trying to assign nonexistent symbol %s", line + 7);
191 break;
192 } else if (!(sym->flags & SYMBOL_NEW)) {
193 conf_warning("trying to reassign symbol %s", sym->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194 break;
195 }
196 switch (sym->type) {
197 case S_TRISTATE:
198 if (p[0] == 'm') {
199 sym->user.tri = mod;
200 sym->flags &= ~SYMBOL_NEW;
201 break;
202 }
203 case S_BOOLEAN:
204 if (p[0] == 'y') {
205 sym->user.tri = yes;
206 sym->flags &= ~SYMBOL_NEW;
207 break;
208 }
209 if (p[0] == 'n') {
210 sym->user.tri = no;
211 sym->flags &= ~SYMBOL_NEW;
212 break;
213 }
Roman Zippelc1a0f5e2005-11-08 21:34:54 -0800214 conf_warning("symbol value '%s' invalid for %s", p, sym->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215 break;
216 case S_STRING:
217 if (*p++ != '"')
218 break;
219 for (p2 = p; (p2 = strpbrk(p2, "\"\\")); p2++) {
220 if (*p2 == '"') {
221 *p2 = 0;
222 break;
223 }
224 memmove(p2, p2 + 1, strlen(p2));
225 }
226 if (!p2) {
Roman Zippelc1a0f5e2005-11-08 21:34:54 -0800227 conf_warning("invalid string found");
228 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229 }
230 case S_INT:
231 case S_HEX:
232 if (sym_string_valid(sym, p)) {
233 sym->user.val = strdup(p);
234 sym->flags &= ~SYMBOL_NEW;
235 } else {
Roman Zippelc1a0f5e2005-11-08 21:34:54 -0800236 conf_warning("symbol value '%s' invalid for %s", p, sym->name);
237 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238 }
239 break;
240 default:
241 ;
242 }
243 break;
244 case '\n':
245 break;
246 default:
Roman Zippelc1a0f5e2005-11-08 21:34:54 -0800247 conf_warning("unexpected data");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248 continue;
249 }
250 if (sym && sym_is_choice_value(sym)) {
251 struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym));
252 switch (sym->user.tri) {
253 case no:
254 break;
255 case mod:
Roman Zippelc1a0f5e2005-11-08 21:34:54 -0800256 if (cs->user.tri == yes) {
257 conf_warning("%s creates inconsistent choice state", sym->name);
258 cs->flags |= SYMBOL_NEW;
259 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260 break;
261 case yes:
Roman Zippelc1a0f5e2005-11-08 21:34:54 -0800262 if (cs->user.tri != no) {
263 conf_warning("%s creates inconsistent choice state", sym->name);
264 cs->flags |= SYMBOL_NEW;
265 } else
266 cs->user.val = sym;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267 break;
268 }
269 cs->user.tri = E_OR(cs->user.tri, sym->user.tri);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270 }
271 }
272 fclose(in);
273
274 if (modules_sym)
275 sym_calc_value(modules_sym);
Roman Zippel90389162005-11-08 21:34:49 -0800276 return 0;
277}
278
279int conf_read(const char *name)
280{
281 struct symbol *sym;
282 struct property *prop;
283 struct expr *e;
284 int i;
285
Roman Zippelddc97ca2006-06-08 22:12:38 -0700286 sym_change_count = 0;
287
Roman Zippel90389162005-11-08 21:34:49 -0800288 if (conf_read_simple(name))
289 return 1;
290
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291 for_all_symbols(i, sym) {
292 sym_calc_value(sym);
Roman Zippelc1a0f5e2005-11-08 21:34:54 -0800293 if (sym_is_choice(sym) || (sym->flags & SYMBOL_AUTO))
294 goto sym_ok;
295 if (sym_has_value(sym) && (sym->flags & SYMBOL_WRITE)) {
296 /* check that calculated value agrees with saved value */
297 switch (sym->type) {
298 case S_BOOLEAN:
299 case S_TRISTATE:
300 if (sym->user.tri != sym_get_tristate_value(sym))
301 break;
302 if (!sym_is_choice(sym))
303 goto sym_ok;
304 default:
305 if (!strcmp(sym->curr.val, sym->user.val))
306 goto sym_ok;
307 break;
308 }
309 } else if (!sym_has_value(sym) && !(sym->flags & SYMBOL_WRITE))
310 /* no previous value and not saved */
311 goto sym_ok;
312 conf_unsaved++;
313 /* maybe print value in verbose mode... */
314 sym_ok:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315 if (sym_has_value(sym) && !sym_is_choice_value(sym)) {
316 if (sym->visible == no)
317 sym->flags |= SYMBOL_NEW;
318 switch (sym->type) {
319 case S_STRING:
320 case S_INT:
321 case S_HEX:
Roman Zippelc1a0f5e2005-11-08 21:34:54 -0800322 if (!sym_string_within_range(sym, sym->user.val)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323 sym->flags |= SYMBOL_NEW;
Roman Zippelc1a0f5e2005-11-08 21:34:54 -0800324 sym->flags &= ~SYMBOL_VALID;
325 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326 default:
327 break;
328 }
329 }
330 if (!sym_is_choice(sym))
331 continue;
332 prop = sym_get_choice_prop(sym);
333 for (e = prop->expr; e; e = e->left.expr)
334 if (e->right.sym->visible != no)
335 sym->flags |= e->right.sym->flags & SYMBOL_NEW;
336 }
337
Roman Zippelddc97ca2006-06-08 22:12:38 -0700338 sym_change_count += conf_warnings || conf_unsaved;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339
340 return 0;
341}
342
343int conf_write(const char *name)
344{
Roman Zippelc955cca2006-06-08 22:12:39 -0700345 FILE *out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346 struct symbol *sym;
347 struct menu *menu;
348 const char *basename;
349 char dirname[128], tmpname[128], newname[128];
350 int type, l;
351 const char *str;
352 time_t now;
353 int use_timestamp = 1;
354 char *env;
355
356 dirname[0] = 0;
357 if (name && name[0]) {
358 struct stat st;
359 char *slash;
360
361 if (!stat(name, &st) && S_ISDIR(st.st_mode)) {
362 strcpy(dirname, name);
363 strcat(dirname, "/");
364 basename = conf_def_filename;
365 } else if ((slash = strrchr(name, '/'))) {
366 int size = slash - name + 1;
367 memcpy(dirname, name, size);
368 dirname[size] = 0;
369 if (slash[1])
370 basename = slash + 1;
371 else
372 basename = conf_def_filename;
373 } else
374 basename = name;
375 } else
376 basename = conf_def_filename;
377
378 sprintf(newname, "%s.tmpconfig.%d", dirname, (int)getpid());
379 out = fopen(newname, "w");
380 if (!out)
381 return 1;
Sam Ravnborg2244cbd2006-01-16 12:12:12 +0100382 sym = sym_lookup("KERNELVERSION", 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383 sym_calc_value(sym);
384 time(&now);
385 env = getenv("KCONFIG_NOTIMESTAMP");
386 if (env && *env)
387 use_timestamp = 0;
388
Arnaldo Carvalho de Melo3b9fa092005-05-05 15:09:46 -0700389 fprintf(out, _("#\n"
390 "# Automatically generated make config: don't edit\n"
391 "# Linux kernel version: %s\n"
392 "%s%s"
393 "#\n"),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394 sym_get_string_value(sym),
395 use_timestamp ? "# " : "",
396 use_timestamp ? ctime(&now) : "");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397
398 if (!sym_change_count)
399 sym_clear_all_valid();
400
401 menu = rootmenu.list;
402 while (menu) {
403 sym = menu->sym;
404 if (!sym) {
405 if (!menu_is_visible(menu))
406 goto next;
407 str = menu_get_prompt(menu);
408 fprintf(out, "\n"
409 "#\n"
410 "# %s\n"
411 "#\n", str);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412 } else if (!(sym->flags & SYMBOL_CHOICE)) {
413 sym_calc_value(sym);
414 if (!(sym->flags & SYMBOL_WRITE))
415 goto next;
416 sym->flags &= ~SYMBOL_WRITE;
417 type = sym->type;
418 if (type == S_TRISTATE) {
419 sym_calc_value(modules_sym);
420 if (modules_sym->curr.tri == no)
421 type = S_BOOLEAN;
422 }
423 switch (type) {
424 case S_BOOLEAN:
425 case S_TRISTATE:
426 switch (sym_get_tristate_value(sym)) {
427 case no:
428 fprintf(out, "# CONFIG_%s is not set\n", sym->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429 break;
430 case mod:
431 fprintf(out, "CONFIG_%s=m\n", sym->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432 break;
433 case yes:
434 fprintf(out, "CONFIG_%s=y\n", sym->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435 break;
436 }
437 break;
438 case S_STRING:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439 str = sym_get_string_value(sym);
440 fprintf(out, "CONFIG_%s=\"", sym->name);
Roman Zippelc955cca2006-06-08 22:12:39 -0700441 while (1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442 l = strcspn(str, "\"\\");
443 if (l) {
444 fwrite(str, l, 1, out);
Roman Zippelc955cca2006-06-08 22:12:39 -0700445 str += l;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446 }
Roman Zippelc955cca2006-06-08 22:12:39 -0700447 if (!*str)
448 break;
449 fprintf(out, "\\%c", *str++);
450 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451 fputs("\"\n", out);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452 break;
453 case S_HEX:
454 str = sym_get_string_value(sym);
455 if (str[0] != '0' || (str[1] != 'x' && str[1] != 'X')) {
456 fprintf(out, "CONFIG_%s=%s\n", sym->name, str);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457 break;
458 }
459 case S_INT:
460 str = sym_get_string_value(sym);
461 fprintf(out, "CONFIG_%s=%s\n", sym->name, str);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462 break;
463 }
464 }
465
466 next:
467 if (menu->list) {
468 menu = menu->list;
469 continue;
470 }
471 if (menu->next)
472 menu = menu->next;
473 else while ((menu = menu->parent)) {
474 if (menu->next) {
475 menu = menu->next;
476 break;
477 }
478 }
479 }
480 fclose(out);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481 if (!name || basename != conf_def_filename) {
482 if (!name)
483 name = conf_def_filename;
484 sprintf(tmpname, "%s.old", name);
485 rename(name, tmpname);
486 }
487 sprintf(tmpname, "%s%s", dirname, basename);
488 if (rename(newname, tmpname))
489 return 1;
490
Roman Zippelddc97ca2006-06-08 22:12:38 -0700491 printf(_("#\n"
492 "# configuration written to %s\n"
493 "#\n"), tmpname);
494
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495 sym_change_count = 0;
496
497 return 0;
498}
Roman Zippelc955cca2006-06-08 22:12:39 -0700499
500int conf_write_autoconf(void)
501{
502 struct symbol *sym;
503 const char *str;
504 char *name;
505 FILE *out, *out_h;
506 time_t now;
507 int i, l;
508
509 file_write_dep("include/config/auto.conf.cmd");
510
511 out = fopen(".tmpconfig", "w");
512 if (!out)
513 return 1;
514
515 out_h = fopen(".tmpconfig.h", "w");
516 if (!out_h) {
517 fclose(out);
518 return 1;
519 }
520
521 sym = sym_lookup("KERNELVERSION", 0);
522 sym_calc_value(sym);
523 time(&now);
524 fprintf(out, "#\n"
525 "# Automatically generated make config: don't edit\n"
526 "# Linux kernel version: %s\n"
527 "# %s"
528 "#\n",
529 sym_get_string_value(sym), ctime(&now));
530 fprintf(out_h, "/*\n"
531 " * Automatically generated C config: don't edit\n"
532 " * Linux kernel version: %s\n"
533 " * %s"
534 " */\n"
535 "#define AUTOCONF_INCLUDED\n",
536 sym_get_string_value(sym), ctime(&now));
537
538 sym_clear_all_valid();
539
540 for_all_symbols(i, sym) {
541 sym_calc_value(sym);
542 if (!(sym->flags & SYMBOL_WRITE) || !sym->name)
543 continue;
544 switch (sym->type) {
545 case S_BOOLEAN:
546 case S_TRISTATE:
547 switch (sym_get_tristate_value(sym)) {
548 case no:
549 break;
550 case mod:
551 fprintf(out, "CONFIG_%s=m\n", sym->name);
552 fprintf(out_h, "#define CONFIG_%s_MODULE 1\n", sym->name);
553 break;
554 case yes:
555 fprintf(out, "CONFIG_%s=y\n", sym->name);
556 fprintf(out_h, "#define CONFIG_%s 1\n", sym->name);
557 break;
558 }
559 break;
560 case S_STRING:
561 str = sym_get_string_value(sym);
562 fprintf(out, "CONFIG_%s=\"", sym->name);
563 fprintf(out_h, "#define CONFIG_%s \"", sym->name);
564 while (1) {
565 l = strcspn(str, "\"\\");
566 if (l) {
567 fwrite(str, l, 1, out);
568 fwrite(str, l, 1, out_h);
569 str += l;
570 }
571 if (!*str)
572 break;
573 fprintf(out, "\\%c", *str);
574 fprintf(out_h, "\\%c", *str);
575 str++;
576 }
577 fputs("\"\n", out);
578 fputs("\"\n", out_h);
579 break;
580 case S_HEX:
581 str = sym_get_string_value(sym);
582 if (str[0] != '0' || (str[1] != 'x' && str[1] != 'X')) {
583 fprintf(out, "CONFIG_%s=%s\n", sym->name, str);
584 fprintf(out_h, "#define CONFIG_%s 0x%s\n", sym->name, str);
585 break;
586 }
587 case S_INT:
588 str = sym_get_string_value(sym);
589 fprintf(out, "CONFIG_%s=%s\n", sym->name, str);
590 fprintf(out_h, "#define CONFIG_%s %s\n", sym->name, str);
591 break;
592 default:
593 break;
594 }
595 }
596 fclose(out);
597 fclose(out_h);
598
599 name = getenv("KCONFIG_AUTOHEADER");
600 if (!name)
601 name = "include/linux/autoconf.h";
602 if (rename(".tmpconfig.h", name))
603 return 1;
604 name = getenv("KCONFIG_AUTOCONFIG");
605 if (!name)
606 name = "include/config/auto.conf";
607 /*
608 * This must be the last step, kbuild has a dependency on auto.conf
609 * and this marks the successful completion of the previous steps.
610 */
611 if (rename(".tmpconfig", name))
612 return 1;
613
614 return 0;
615}