blob: 1b8882ddbc74fed0fbed2c22f8dd317b6de0106b [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;
Jan Beulichdc9a49a2006-03-09 14:47:46 +0100377 file_write_dep(NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378 }
Sam Ravnborg2244cbd2006-01-16 12:12:12 +0100379 sym = sym_lookup("KERNELVERSION", 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380 sym_calc_value(sym);
381 time(&now);
382 env = getenv("KCONFIG_NOTIMESTAMP");
383 if (env && *env)
384 use_timestamp = 0;
385
Arnaldo Carvalho de Melo3b9fa092005-05-05 15:09:46 -0700386 fprintf(out, _("#\n"
387 "# Automatically generated make config: don't edit\n"
388 "# Linux kernel version: %s\n"
389 "%s%s"
390 "#\n"),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 sym_get_string_value(sym),
392 use_timestamp ? "# " : "",
393 use_timestamp ? ctime(&now) : "");
394 if (out_h)
395 fprintf(out_h, "/*\n"
396 " * Automatically generated C config: don't edit\n"
397 " * Linux kernel version: %s\n"
398 "%s%s"
399 " */\n"
400 "#define AUTOCONF_INCLUDED\n",
401 sym_get_string_value(sym),
402 use_timestamp ? " * " : "",
403 use_timestamp ? ctime(&now) : "");
404
405 if (!sym_change_count)
406 sym_clear_all_valid();
407
408 menu = rootmenu.list;
409 while (menu) {
410 sym = menu->sym;
411 if (!sym) {
412 if (!menu_is_visible(menu))
413 goto next;
414 str = menu_get_prompt(menu);
415 fprintf(out, "\n"
416 "#\n"
417 "# %s\n"
418 "#\n", str);
419 if (out_h)
420 fprintf(out_h, "\n"
421 "/*\n"
422 " * %s\n"
423 " */\n", str);
424 } else if (!(sym->flags & SYMBOL_CHOICE)) {
425 sym_calc_value(sym);
426 if (!(sym->flags & SYMBOL_WRITE))
427 goto next;
428 sym->flags &= ~SYMBOL_WRITE;
429 type = sym->type;
430 if (type == S_TRISTATE) {
431 sym_calc_value(modules_sym);
432 if (modules_sym->curr.tri == no)
433 type = S_BOOLEAN;
434 }
435 switch (type) {
436 case S_BOOLEAN:
437 case S_TRISTATE:
438 switch (sym_get_tristate_value(sym)) {
439 case no:
440 fprintf(out, "# CONFIG_%s is not set\n", sym->name);
441 if (out_h)
442 fprintf(out_h, "#undef CONFIG_%s\n", sym->name);
443 break;
444 case mod:
445 fprintf(out, "CONFIG_%s=m\n", sym->name);
446 if (out_h)
447 fprintf(out_h, "#define CONFIG_%s_MODULE 1\n", sym->name);
448 break;
449 case yes:
450 fprintf(out, "CONFIG_%s=y\n", sym->name);
451 if (out_h)
452 fprintf(out_h, "#define CONFIG_%s 1\n", sym->name);
453 break;
454 }
455 break;
456 case S_STRING:
457 // fix me
458 str = sym_get_string_value(sym);
459 fprintf(out, "CONFIG_%s=\"", sym->name);
460 if (out_h)
461 fprintf(out_h, "#define CONFIG_%s \"", sym->name);
462 do {
463 l = strcspn(str, "\"\\");
464 if (l) {
465 fwrite(str, l, 1, out);
466 if (out_h)
467 fwrite(str, l, 1, out_h);
468 }
469 str += l;
470 while (*str == '\\' || *str == '"') {
471 fprintf(out, "\\%c", *str);
472 if (out_h)
473 fprintf(out_h, "\\%c", *str);
474 str++;
475 }
476 } while (*str);
477 fputs("\"\n", out);
478 if (out_h)
479 fputs("\"\n", out_h);
480 break;
481 case S_HEX:
482 str = sym_get_string_value(sym);
483 if (str[0] != '0' || (str[1] != 'x' && str[1] != 'X')) {
484 fprintf(out, "CONFIG_%s=%s\n", sym->name, str);
485 if (out_h)
486 fprintf(out_h, "#define CONFIG_%s 0x%s\n", sym->name, str);
487 break;
488 }
489 case S_INT:
490 str = sym_get_string_value(sym);
491 fprintf(out, "CONFIG_%s=%s\n", sym->name, str);
492 if (out_h)
493 fprintf(out_h, "#define CONFIG_%s %s\n", sym->name, str);
494 break;
495 }
496 }
497
498 next:
499 if (menu->list) {
500 menu = menu->list;
501 continue;
502 }
503 if (menu->next)
504 menu = menu->next;
505 else while ((menu = menu->parent)) {
506 if (menu->next) {
507 menu = menu->next;
508 break;
509 }
510 }
511 }
512 fclose(out);
513 if (out_h) {
514 fclose(out_h);
515 rename(".tmpconfig.h", "include/linux/autoconf.h");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516 }
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}