blob: f3f76dd999a7e15f03475a538d8739bcb105cd8e [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",
Bernhard Reutner-Fischer9e8df932007-01-17 19:36:01 +000030 "/etc/busybox-config",
Denis Vlasenko7d219aa2006-10-05 10:17:08 +000031 "/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"
Bernhard Reutner-Fischer9e8df932007-01-17 19:36:01 +0000388 "# Busybox version: %s\n"
Denis Vlasenko7d219aa2006-10-05 10:17:08 +0000389 "%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';
Mike Frysinger68ffb9a2006-12-30 19:43:35 +0000398 if (use_timestamp) {
399 size_t ret = \
400 strftime(buf, sizeof(buf), "#define AUTOCONF_TIMESTAMP "
401 "\"%Y-%m-%d %H:%M:%S %Z\"\n", localtime(&now));
402 /* if user has Factory timezone or some other odd install, the
403 * %Z above will overflow the string leaving us with undefined
404 * results ... so let's try again without the timezone.
405 */
406 if (ret == 0)
407 strftime(buf, sizeof(buf), "#define AUTOCONF_TIMESTAMP "
408 "\"%Y-%m-%d %H:%M:%S\"\n", localtime(&now));
409 }
Denis Vlasenko7d219aa2006-10-05 10:17:08 +0000410 fprintf(out_h, "/*\n"
411 " * Automatically generated C config: don't edit\n"
Bernhard Reutner-Fischer9e8df932007-01-17 19:36:01 +0000412 " * Busybox version: %s\n"
Denis Vlasenko7d219aa2006-10-05 10:17:08 +0000413 " */\n"
414 "%s"
Mike Frysinger1b3e8172006-12-30 19:46:38 +0000415 "\n",
Denis Vlasenko7d219aa2006-10-05 10:17:08 +0000416 sym_get_string_value(sym),
417 buf);
418 }
419 if (!sym_change_count)
420 sym_clear_all_valid();
421
422 menu = rootmenu.list;
423 while (menu) {
424 sym = menu->sym;
425 if (!sym) {
426 if (!menu_is_visible(menu))
427 goto next;
428 str = menu_get_prompt(menu);
429 fprintf(out, "\n"
430 "#\n"
431 "# %s\n"
432 "#\n", str);
433 if (out_h)
434 fprintf(out_h, "\n"
435 "/*\n"
436 " * %s\n"
437 " */\n", str);
438 } else if (!(sym->flags & SYMBOL_CHOICE)) {
439 sym_calc_value(sym);
Denis Vlasenkob79b87a2006-10-19 22:17:44 +0000440/* bbox: we want to all syms
Denis Vlasenko7d219aa2006-10-05 10:17:08 +0000441 if (!(sym->flags & SYMBOL_WRITE))
442 goto next;
Denis Vlasenkob79b87a2006-10-19 22:17:44 +0000443*/
Denis Vlasenko7d219aa2006-10-05 10:17:08 +0000444 sym->flags &= ~SYMBOL_WRITE;
445 type = sym->type;
446 if (type == S_TRISTATE) {
447 sym_calc_value(modules_sym);
448 if (modules_sym->curr.tri == no)
449 type = S_BOOLEAN;
450 }
451 switch (type) {
452 case S_BOOLEAN:
453 case S_TRISTATE:
454 switch (sym_get_tristate_value(sym)) {
455 case no:
456 fprintf(out, "# CONFIG_%s is not set\n", sym->name);
457 if (out_h) {
458 fprintf(out_h, "#undef CONFIG_%s\n", sym->name);
459 /* bbox */
460 fprintf(out_h, "#define ENABLE_%s 0\n", sym->name);
461 fprintf(out_h, "#define USE_%s(...)\n", sym->name);
462 fprintf(out_h, "#define SKIP_%s(...) __VA_ARGS__\n", sym->name);
463 }
464 break;
465 case mod:
466 fprintf(out, "CONFIG_%s=m\n", sym->name);
467 if (out_h)
468 fprintf(out_h, "#define CONFIG_%s_MODULE 1\n", sym->name);
469 break;
470 case yes:
471 fprintf(out, "CONFIG_%s=y\n", sym->name);
472 if (out_h) {
473 fprintf(out_h, "#define CONFIG_%s 1\n", sym->name);
474 /* bbox */
475 fprintf(out_h, "#define ENABLE_%s 1\n", sym->name);
476 fprintf(out_h, "#define USE_%s(...) __VA_ARGS__\n", sym->name);
477 fprintf(out_h, "#define SKIP_%s(...)\n", sym->name);
478 }
479 break;
480 }
481 break;
482 case S_STRING:
483 // fix me
484 str = sym_get_string_value(sym);
485 fprintf(out, "CONFIG_%s=\"", sym->name);
486 if (out_h)
487 fprintf(out_h, "#define CONFIG_%s \"", sym->name);
488 do {
489 l = strcspn(str, "\"\\");
490 if (l) {
491 fwrite(str, l, 1, out);
492 if (out_h)
493 fwrite(str, l, 1, out_h);
494 }
495 str += l;
496 while (*str == '\\' || *str == '"') {
497 fprintf(out, "\\%c", *str);
498 if (out_h)
499 fprintf(out_h, "\\%c", *str);
500 str++;
501 }
502 } while (*str);
503 fputs("\"\n", out);
504 if (out_h) {
505 fputs("\"\n", out_h);
506 /* bbox */
507 fprintf(out_h, "#define ENABLE_%s 1\n", sym->name);
508 fprintf(out_h, "#define USE_%s(...) __VA_ARGS__\n", sym->name);
509 fprintf(out_h, "#define SKIP_%s(...)\n", sym->name);
510 }
511 break;
512 case S_HEX:
513 str = sym_get_string_value(sym);
514 if (str[0] != '0' || (str[1] != 'x' && str[1] != 'X')) {
515 fprintf(out, "CONFIG_%s=%s\n", sym->name, str);
516 if (out_h) {
517 fprintf(out_h, "#define CONFIG_%s 0x%s\n", sym->name, str);
518 /* bbox */
519 fprintf(out_h, "#define ENABLE_%s 1\n", sym->name);
520 fprintf(out_h, "#define USE_%s(...) __VA_ARGS__\n", sym->name);
521 fprintf(out_h, "#define SKIP_%s(...)\n", sym->name);
522 }
523 break;
524 }
525 case S_INT:
526 str = sym_get_string_value(sym);
527 fprintf(out, "CONFIG_%s=%s\n", sym->name, str);
528 if (out_h) {
529 fprintf(out_h, "#define CONFIG_%s %s\n", sym->name, str);
530 /* bbox */
531 fprintf(out_h, "#define ENABLE_%s 1\n", sym->name);
532 fprintf(out_h, "#define USE_%s(...) __VA_ARGS__\n", sym->name);
533 fprintf(out_h, "#define SKIP_%s(...)\n", sym->name);
534 }
535 break;
536 }
537 }
538
539 next:
540 if (menu->list) {
541 menu = menu->list;
542 continue;
543 }
544 if (menu->next)
545 menu = menu->next;
546 else while ((menu = menu->parent)) {
547 if (menu->next) {
548 menu = menu->next;
549 break;
550 }
551 }
552 }
553 fclose(out);
554 if (out_h) {
555 fclose(out_h);
556 rename(".tmpconfig.h", "include/autoconf.h");
557 }
558 if (!name || basename != conf_def_filename) {
559 if (!name)
560 name = conf_def_filename;
561 sprintf(tmpname, "%s.old", name);
562 rename(name, tmpname);
563 }
564 sprintf(tmpname, "%s%s", dirname, basename);
565 if (rename(newname, tmpname))
566 return 1;
567
568 sym_change_count = 0;
569
570 return 0;
571}