blob: ccd45130c482cd1d682cd77be590cf023f510f37 [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;
101 while ((name = *names++)) {
102 name = conf_expand_value(name);
103 in = zconf_fopen(name);
104 if (in) {
Arnaldo Carvalho de Melo3b9fa092005-05-05 15:09:46 -0700105 printf(_("#\n"
106 "# using defaults found in %s\n"
107 "#\n"), name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108 break;
109 }
110 }
111 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112 if (!in)
113 return 1;
114
Roman Zippelc1a0f5e2005-11-08 21:34:54 -0800115 conf_filename = name;
116 conf_lineno = 0;
117 conf_warnings = 0;
118 conf_unsaved = 0;
119
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120 for_all_symbols(i, sym) {
121 sym->flags |= SYMBOL_NEW | SYMBOL_CHANGED;
Roman Zippelc1a0f5e2005-11-08 21:34:54 -0800122 if (sym_is_choice(sym))
123 sym->flags &= ~SYMBOL_NEW;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124 sym->flags &= ~SYMBOL_VALID;
125 switch (sym->type) {
126 case S_INT:
127 case S_HEX:
128 case S_STRING:
129 if (sym->user.val)
130 free(sym->user.val);
131 default:
132 sym->user.val = NULL;
133 sym->user.tri = no;
134 }
135 }
136
137 while (fgets(line, sizeof(line), in)) {
Roman Zippelc1a0f5e2005-11-08 21:34:54 -0800138 conf_lineno++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139 sym = NULL;
140 switch (line[0]) {
141 case '#':
142 if (memcmp(line + 2, "CONFIG_", 7))
143 continue;
144 p = strchr(line + 9, ' ');
145 if (!p)
146 continue;
147 *p++ = 0;
148 if (strncmp(p, "is not set", 10))
149 continue;
150 sym = sym_find(line + 9);
151 if (!sym) {
Roman Zippelc1a0f5e2005-11-08 21:34:54 -0800152 conf_warning("trying to assign nonexistent symbol %s", line + 9);
153 break;
154 } else if (!(sym->flags & SYMBOL_NEW)) {
155 conf_warning("trying to reassign symbol %s", sym->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156 break;
157 }
158 switch (sym->type) {
159 case S_BOOLEAN:
160 case S_TRISTATE:
161 sym->user.tri = no;
162 sym->flags &= ~SYMBOL_NEW;
163 break;
164 default:
165 ;
166 }
167 break;
168 case 'C':
Roman Zippelc1a0f5e2005-11-08 21:34:54 -0800169 if (memcmp(line, "CONFIG_", 7)) {
170 conf_warning("unexpected data");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171 continue;
Roman Zippelc1a0f5e2005-11-08 21:34:54 -0800172 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173 p = strchr(line + 7, '=');
174 if (!p)
175 continue;
176 *p++ = 0;
177 p2 = strchr(p, '\n');
178 if (p2)
179 *p2 = 0;
180 sym = sym_find(line + 7);
181 if (!sym) {
Roman Zippelc1a0f5e2005-11-08 21:34:54 -0800182 conf_warning("trying to assign nonexistent symbol %s", line + 7);
183 break;
184 } else if (!(sym->flags & SYMBOL_NEW)) {
185 conf_warning("trying to reassign symbol %s", sym->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186 break;
187 }
188 switch (sym->type) {
189 case S_TRISTATE:
190 if (p[0] == 'm') {
191 sym->user.tri = mod;
192 sym->flags &= ~SYMBOL_NEW;
193 break;
194 }
195 case S_BOOLEAN:
196 if (p[0] == 'y') {
197 sym->user.tri = yes;
198 sym->flags &= ~SYMBOL_NEW;
199 break;
200 }
201 if (p[0] == 'n') {
202 sym->user.tri = no;
203 sym->flags &= ~SYMBOL_NEW;
204 break;
205 }
Roman Zippelc1a0f5e2005-11-08 21:34:54 -0800206 conf_warning("symbol value '%s' invalid for %s", p, sym->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207 break;
208 case S_STRING:
209 if (*p++ != '"')
210 break;
211 for (p2 = p; (p2 = strpbrk(p2, "\"\\")); p2++) {
212 if (*p2 == '"') {
213 *p2 = 0;
214 break;
215 }
216 memmove(p2, p2 + 1, strlen(p2));
217 }
218 if (!p2) {
Roman Zippelc1a0f5e2005-11-08 21:34:54 -0800219 conf_warning("invalid string found");
220 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221 }
222 case S_INT:
223 case S_HEX:
224 if (sym_string_valid(sym, p)) {
225 sym->user.val = strdup(p);
226 sym->flags &= ~SYMBOL_NEW;
227 } else {
Roman Zippelc1a0f5e2005-11-08 21:34:54 -0800228 conf_warning("symbol value '%s' invalid for %s", p, sym->name);
229 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230 }
231 break;
232 default:
233 ;
234 }
235 break;
236 case '\n':
237 break;
238 default:
Roman Zippelc1a0f5e2005-11-08 21:34:54 -0800239 conf_warning("unexpected data");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240 continue;
241 }
242 if (sym && sym_is_choice_value(sym)) {
243 struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym));
244 switch (sym->user.tri) {
245 case no:
246 break;
247 case mod:
Roman Zippelc1a0f5e2005-11-08 21:34:54 -0800248 if (cs->user.tri == yes) {
249 conf_warning("%s creates inconsistent choice state", sym->name);
250 cs->flags |= SYMBOL_NEW;
251 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252 break;
253 case yes:
Roman Zippelc1a0f5e2005-11-08 21:34:54 -0800254 if (cs->user.tri != no) {
255 conf_warning("%s creates inconsistent choice state", sym->name);
256 cs->flags |= SYMBOL_NEW;
257 } else
258 cs->user.val = sym;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259 break;
260 }
261 cs->user.tri = E_OR(cs->user.tri, sym->user.tri);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262 }
263 }
264 fclose(in);
265
266 if (modules_sym)
267 sym_calc_value(modules_sym);
Roman Zippel90389162005-11-08 21:34:49 -0800268 return 0;
269}
270
271int conf_read(const char *name)
272{
273 struct symbol *sym;
274 struct property *prop;
275 struct expr *e;
276 int i;
277
278 if (conf_read_simple(name))
279 return 1;
280
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281 for_all_symbols(i, sym) {
282 sym_calc_value(sym);
Roman Zippelc1a0f5e2005-11-08 21:34:54 -0800283 if (sym_is_choice(sym) || (sym->flags & SYMBOL_AUTO))
284 goto sym_ok;
285 if (sym_has_value(sym) && (sym->flags & SYMBOL_WRITE)) {
286 /* check that calculated value agrees with saved value */
287 switch (sym->type) {
288 case S_BOOLEAN:
289 case S_TRISTATE:
290 if (sym->user.tri != sym_get_tristate_value(sym))
291 break;
292 if (!sym_is_choice(sym))
293 goto sym_ok;
294 default:
295 if (!strcmp(sym->curr.val, sym->user.val))
296 goto sym_ok;
297 break;
298 }
299 } else if (!sym_has_value(sym) && !(sym->flags & SYMBOL_WRITE))
300 /* no previous value and not saved */
301 goto sym_ok;
302 conf_unsaved++;
303 /* maybe print value in verbose mode... */
304 sym_ok:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305 if (sym_has_value(sym) && !sym_is_choice_value(sym)) {
306 if (sym->visible == no)
307 sym->flags |= SYMBOL_NEW;
308 switch (sym->type) {
309 case S_STRING:
310 case S_INT:
311 case S_HEX:
Roman Zippelc1a0f5e2005-11-08 21:34:54 -0800312 if (!sym_string_within_range(sym, sym->user.val)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313 sym->flags |= SYMBOL_NEW;
Roman Zippelc1a0f5e2005-11-08 21:34:54 -0800314 sym->flags &= ~SYMBOL_VALID;
315 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316 default:
317 break;
318 }
319 }
320 if (!sym_is_choice(sym))
321 continue;
322 prop = sym_get_choice_prop(sym);
323 for (e = prop->expr; e; e = e->left.expr)
324 if (e->right.sym->visible != no)
325 sym->flags |= e->right.sym->flags & SYMBOL_NEW;
326 }
327
Roman Zippelc1a0f5e2005-11-08 21:34:54 -0800328 sym_change_count = conf_warnings && conf_unsaved;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329
330 return 0;
331}
332
333int conf_write(const char *name)
334{
335 FILE *out, *out_h;
336 struct symbol *sym;
337 struct menu *menu;
338 const char *basename;
339 char dirname[128], tmpname[128], newname[128];
340 int type, l;
341 const char *str;
342 time_t now;
343 int use_timestamp = 1;
344 char *env;
345
346 dirname[0] = 0;
347 if (name && name[0]) {
348 struct stat st;
349 char *slash;
350
351 if (!stat(name, &st) && S_ISDIR(st.st_mode)) {
352 strcpy(dirname, name);
353 strcat(dirname, "/");
354 basename = conf_def_filename;
355 } else if ((slash = strrchr(name, '/'))) {
356 int size = slash - name + 1;
357 memcpy(dirname, name, size);
358 dirname[size] = 0;
359 if (slash[1])
360 basename = slash + 1;
361 else
362 basename = conf_def_filename;
363 } else
364 basename = name;
365 } else
366 basename = conf_def_filename;
367
368 sprintf(newname, "%s.tmpconfig.%d", dirname, (int)getpid());
369 out = fopen(newname, "w");
370 if (!out)
371 return 1;
372 out_h = NULL;
373 if (!name) {
374 out_h = fopen(".tmpconfig.h", "w");
375 if (!out_h)
376 return 1;
377 }
378 sym = sym_lookup("KERNELRELEASE", 0);
379 sym_calc_value(sym);
380 time(&now);
381 env = getenv("KCONFIG_NOTIMESTAMP");
382 if (env && *env)
383 use_timestamp = 0;
384
Arnaldo Carvalho de Melo3b9fa092005-05-05 15:09:46 -0700385 fprintf(out, _("#\n"
386 "# Automatically generated make config: don't edit\n"
387 "# Linux kernel version: %s\n"
388 "%s%s"
389 "#\n"),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390 sym_get_string_value(sym),
391 use_timestamp ? "# " : "",
392 use_timestamp ? ctime(&now) : "");
393 if (out_h)
394 fprintf(out_h, "/*\n"
395 " * Automatically generated C config: don't edit\n"
396 " * Linux kernel version: %s\n"
397 "%s%s"
398 " */\n"
399 "#define AUTOCONF_INCLUDED\n",
400 sym_get_string_value(sym),
401 use_timestamp ? " * " : "",
402 use_timestamp ? ctime(&now) : "");
403
404 if (!sym_change_count)
405 sym_clear_all_valid();
406
407 menu = rootmenu.list;
408 while (menu) {
409 sym = menu->sym;
410 if (!sym) {
411 if (!menu_is_visible(menu))
412 goto next;
413 str = menu_get_prompt(menu);
414 fprintf(out, "\n"
415 "#\n"
416 "# %s\n"
417 "#\n", str);
418 if (out_h)
419 fprintf(out_h, "\n"
420 "/*\n"
421 " * %s\n"
422 " */\n", str);
423 } else if (!(sym->flags & SYMBOL_CHOICE)) {
424 sym_calc_value(sym);
425 if (!(sym->flags & SYMBOL_WRITE))
426 goto next;
427 sym->flags &= ~SYMBOL_WRITE;
428 type = sym->type;
429 if (type == S_TRISTATE) {
430 sym_calc_value(modules_sym);
431 if (modules_sym->curr.tri == no)
432 type = S_BOOLEAN;
433 }
434 switch (type) {
435 case S_BOOLEAN:
436 case S_TRISTATE:
437 switch (sym_get_tristate_value(sym)) {
438 case no:
439 fprintf(out, "# CONFIG_%s is not set\n", sym->name);
440 if (out_h)
441 fprintf(out_h, "#undef CONFIG_%s\n", sym->name);
442 break;
443 case mod:
444 fprintf(out, "CONFIG_%s=m\n", sym->name);
445 if (out_h)
446 fprintf(out_h, "#define CONFIG_%s_MODULE 1\n", sym->name);
447 break;
448 case yes:
449 fprintf(out, "CONFIG_%s=y\n", sym->name);
450 if (out_h)
451 fprintf(out_h, "#define CONFIG_%s 1\n", sym->name);
452 break;
453 }
454 break;
455 case S_STRING:
456 // fix me
457 str = sym_get_string_value(sym);
458 fprintf(out, "CONFIG_%s=\"", sym->name);
459 if (out_h)
460 fprintf(out_h, "#define CONFIG_%s \"", sym->name);
461 do {
462 l = strcspn(str, "\"\\");
463 if (l) {
464 fwrite(str, l, 1, out);
465 if (out_h)
466 fwrite(str, l, 1, out_h);
467 }
468 str += l;
469 while (*str == '\\' || *str == '"') {
470 fprintf(out, "\\%c", *str);
471 if (out_h)
472 fprintf(out_h, "\\%c", *str);
473 str++;
474 }
475 } while (*str);
476 fputs("\"\n", out);
477 if (out_h)
478 fputs("\"\n", out_h);
479 break;
480 case S_HEX:
481 str = sym_get_string_value(sym);
482 if (str[0] != '0' || (str[1] != 'x' && str[1] != 'X')) {
483 fprintf(out, "CONFIG_%s=%s\n", sym->name, str);
484 if (out_h)
485 fprintf(out_h, "#define CONFIG_%s 0x%s\n", sym->name, str);
486 break;
487 }
488 case S_INT:
489 str = sym_get_string_value(sym);
490 fprintf(out, "CONFIG_%s=%s\n", sym->name, str);
491 if (out_h)
492 fprintf(out_h, "#define CONFIG_%s %s\n", sym->name, str);
493 break;
494 }
495 }
496
497 next:
498 if (menu->list) {
499 menu = menu->list;
500 continue;
501 }
502 if (menu->next)
503 menu = menu->next;
504 else while ((menu = menu->parent)) {
505 if (menu->next) {
506 menu = menu->next;
507 break;
508 }
509 }
510 }
511 fclose(out);
512 if (out_h) {
513 fclose(out_h);
514 rename(".tmpconfig.h", "include/linux/autoconf.h");
515 file_write_dep(NULL);
516 }
517 if (!name || basename != conf_def_filename) {
518 if (!name)
519 name = conf_def_filename;
520 sprintf(tmpname, "%s.old", name);
521 rename(name, tmpname);
522 }
523 sprintf(tmpname, "%s%s", dirname, basename);
524 if (rename(newname, tmpname))
525 return 1;
526
527 sym_change_count = 0;
528
529 return 0;
530}