blob: d38bbba93aaf797f9006aecfe6fc02c4222c5ee8 [file] [log] [blame]
Denis Vlasenko7d219aa2006-10-05 10:17:08 +00001/*
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
17static 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
23const char conf_def_filename[] = ".config";
24
Denis Vlasenkoa3310522006-10-05 18:26:35 +000025const char conf_defname[] = "scripts/defconfig";
Denis Vlasenko7d219aa2006-10-05 10:17:08 +000026
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
36static 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
47static char *conf_expand_value(const char *in)
48{
49 struct symbol *sym;
50 const char *src;
51 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
89int conf_read_simple(const char *name)
90{
91 FILE *in = NULL;
92 char line[1024];
93 char *p, *p2;
94 struct symbol *sym;
95 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) {
105 printf(_("#\n"
106 "# using defaults found in %s\n"
107 "#\n"), name);
108 break;
109 }
110 }
111 }
112 if (!in)
113 return 1;
114
115 conf_filename = name;
116 conf_lineno = 0;
117 conf_warnings = 0;
118 conf_unsaved = 0;
119
120 for_all_symbols(i, sym) {
121 sym->flags |= SYMBOL_NEW | SYMBOL_CHANGED;
122 if (sym_is_choice(sym))
123 sym->flags &= ~SYMBOL_NEW;
124 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)) {
138 conf_lineno++;
139 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) {
152 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);
156 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':
169 if (memcmp(line, "CONFIG_", 7)) {
170 conf_warning("unexpected data");
171 continue;
172 }
173 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) {
182 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);
186 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 }
206 conf_warning("symbol value '%s' invalid for %s", p, sym->name);
207 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) {
219 conf_warning("invalid string found");
220 continue;
221 }
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 {
228 conf_warning("symbol value '%s' invalid for %s", p, sym->name);
229 continue;
230 }
231 break;
232 default:
233 ;
234 }
235 break;
236 case '\n':
237 break;
238 default:
239 conf_warning("unexpected data");
240 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:
248 if (cs->user.tri == yes) {
249 conf_warning("%s creates inconsistent choice state", sym->name);
250 cs->flags |= SYMBOL_NEW;
251 }
252 break;
253 case yes:
254 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;
259 break;
260 }
261 cs->user.tri = E_OR(cs->user.tri, sym->user.tri);
262 }
263 }
264 fclose(in);
265
266 if (modules_sym)
267 sym_calc_value(modules_sym);
268 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
281 for_all_symbols(i, sym) {
282 sym_calc_value(sym);
283 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:
305 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:
312 if (!sym_string_within_range(sym, sym->user.val)) {
313 sym->flags |= SYMBOL_NEW;
314 sym->flags &= ~SYMBOL_VALID;
315 }
316 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
328 sym_change_count = conf_warnings || conf_unsaved;
329
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 file_write_dep(NULL);
378 }
379 sym = sym_lookup("KERNELVERSION", 0);
380 sym_calc_value(sym);
381 time(&now);
382 env = getenv("KCONFIG_NOTIMESTAMP");
383 if (env && *env)
384 use_timestamp = 0;
385
386 fprintf(out, _("#\n"
387 "# Automatically generated make config: don't edit\n"
388 "# Linux kernel version: %s\n"
389 "%s%s"
390 "#\n"),
391 sym_get_string_value(sym),
392 use_timestamp ? "# " : "",
393 use_timestamp ? ctime(&now) : "");
394 if (out_h) {
395 char buf[sizeof("#define AUTOCONF_TIMESTAMP "
396 "\"YYYY-MM-DD HH:MM:SS some_timezone\"\n")];
397 buf[0] = '\0';
398 if (use_timestamp)
399 strftime(buf, sizeof(buf), "#define AUTOCONF_TIMESTAMP "
400 "\"%Y-%m-%d %H:%M:%S %Z\"\n", localtime(&now));
401 fprintf(out_h, "/*\n"
402 " * Automatically generated C config: don't edit\n"
403 " * Linux kernel version: %s\n"
404 " */\n"
405 "%s"
406 "#define AUTOCONF_INCLUDED\n",
407 sym_get_string_value(sym),
408 buf);
409 }
410 if (!sym_change_count)
411 sym_clear_all_valid();
412
413 menu = rootmenu.list;
414 while (menu) {
415 sym = menu->sym;
416 if (!sym) {
417 if (!menu_is_visible(menu))
418 goto next;
419 str = menu_get_prompt(menu);
420 fprintf(out, "\n"
421 "#\n"
422 "# %s\n"
423 "#\n", str);
424 if (out_h)
425 fprintf(out_h, "\n"
426 "/*\n"
427 " * %s\n"
428 " */\n", str);
429 } else if (!(sym->flags & SYMBOL_CHOICE)) {
430 sym_calc_value(sym);
Denis Vlasenkob79b87a2006-10-19 22:17:44 +0000431/* bbox: we want to all syms
Denis Vlasenko7d219aa2006-10-05 10:17:08 +0000432 if (!(sym->flags & SYMBOL_WRITE))
433 goto next;
Denis Vlasenkob79b87a2006-10-19 22:17:44 +0000434*/
Denis Vlasenko7d219aa2006-10-05 10:17:08 +0000435 sym->flags &= ~SYMBOL_WRITE;
436 type = sym->type;
437 if (type == S_TRISTATE) {
438 sym_calc_value(modules_sym);
439 if (modules_sym->curr.tri == no)
440 type = S_BOOLEAN;
441 }
442 switch (type) {
443 case S_BOOLEAN:
444 case S_TRISTATE:
445 switch (sym_get_tristate_value(sym)) {
446 case no:
447 fprintf(out, "# CONFIG_%s is not set\n", sym->name);
448 if (out_h) {
449 fprintf(out_h, "#undef CONFIG_%s\n", sym->name);
450 /* bbox */
451 fprintf(out_h, "#define ENABLE_%s 0\n", sym->name);
452 fprintf(out_h, "#define USE_%s(...)\n", sym->name);
453 fprintf(out_h, "#define SKIP_%s(...) __VA_ARGS__\n", sym->name);
454 }
455 break;
456 case mod:
457 fprintf(out, "CONFIG_%s=m\n", sym->name);
458 if (out_h)
459 fprintf(out_h, "#define CONFIG_%s_MODULE 1\n", sym->name);
460 break;
461 case yes:
462 fprintf(out, "CONFIG_%s=y\n", sym->name);
463 if (out_h) {
464 fprintf(out_h, "#define CONFIG_%s 1\n", sym->name);
465 /* bbox */
466 fprintf(out_h, "#define ENABLE_%s 1\n", sym->name);
467 fprintf(out_h, "#define USE_%s(...) __VA_ARGS__\n", sym->name);
468 fprintf(out_h, "#define SKIP_%s(...)\n", sym->name);
469 }
470 break;
471 }
472 break;
473 case S_STRING:
474 // fix me
475 str = sym_get_string_value(sym);
476 fprintf(out, "CONFIG_%s=\"", sym->name);
477 if (out_h)
478 fprintf(out_h, "#define CONFIG_%s \"", sym->name);
479 do {
480 l = strcspn(str, "\"\\");
481 if (l) {
482 fwrite(str, l, 1, out);
483 if (out_h)
484 fwrite(str, l, 1, out_h);
485 }
486 str += l;
487 while (*str == '\\' || *str == '"') {
488 fprintf(out, "\\%c", *str);
489 if (out_h)
490 fprintf(out_h, "\\%c", *str);
491 str++;
492 }
493 } while (*str);
494 fputs("\"\n", out);
495 if (out_h) {
496 fputs("\"\n", out_h);
497 /* bbox */
498 fprintf(out_h, "#define ENABLE_%s 1\n", sym->name);
499 fprintf(out_h, "#define USE_%s(...) __VA_ARGS__\n", sym->name);
500 fprintf(out_h, "#define SKIP_%s(...)\n", sym->name);
501 }
502 break;
503 case S_HEX:
504 str = sym_get_string_value(sym);
505 if (str[0] != '0' || (str[1] != 'x' && str[1] != 'X')) {
506 fprintf(out, "CONFIG_%s=%s\n", sym->name, str);
507 if (out_h) {
508 fprintf(out_h, "#define CONFIG_%s 0x%s\n", sym->name, str);
509 /* bbox */
510 fprintf(out_h, "#define ENABLE_%s 1\n", sym->name);
511 fprintf(out_h, "#define USE_%s(...) __VA_ARGS__\n", sym->name);
512 fprintf(out_h, "#define SKIP_%s(...)\n", sym->name);
513 }
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 if (out_h) {
520 fprintf(out_h, "#define CONFIG_%s %s\n", sym->name, str);
521 /* bbox */
522 fprintf(out_h, "#define ENABLE_%s 1\n", sym->name);
523 fprintf(out_h, "#define USE_%s(...) __VA_ARGS__\n", sym->name);
524 fprintf(out_h, "#define SKIP_%s(...)\n", sym->name);
525 }
526 break;
527 }
528 }
529
530 next:
531 if (menu->list) {
532 menu = menu->list;
533 continue;
534 }
535 if (menu->next)
536 menu = menu->next;
537 else while ((menu = menu->parent)) {
538 if (menu->next) {
539 menu = menu->next;
540 break;
541 }
542 }
543 }
544 fclose(out);
545 if (out_h) {
546 fclose(out_h);
547 rename(".tmpconfig.h", "include/autoconf.h");
548 }
549 if (!name || basename != conf_def_filename) {
550 if (!name)
551 name = conf_def_filename;
552 sprintf(tmpname, "%s.old", name);
553 rename(name, tmpname);
554 }
555 sprintf(tmpname, "%s%s", dirname, basename);
556 if (rename(newname, tmpname))
557 return 1;
558
559 sym_change_count = 0;
560
561 return 0;
562}