blob: 303df0be7295b450976265b8003649d0e279a436 [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
Denys Vlasenko2f32bf82010-06-06 04:14:28 +020025const char conf_defname[] = "/dev/null"; //bbox
Denis Vlasenko7d219aa2006-10-05 10:17:08 +000026
27const char *conf_confnames[] = {
Denis Vlasenkod67a6062007-06-21 12:57:29 +000028 conf_def_filename,
Denis Vlasenko7d219aa2006-10-05 10:17:08 +000029 conf_defname,
30 NULL,
31};
32
33static void conf_warning(const char *fmt, ...)
34{
35 va_list ap;
36 va_start(ap, fmt);
37 fprintf(stderr, "%s:%d:warning: ", conf_filename, conf_lineno);
38 vfprintf(stderr, fmt, ap);
39 fprintf(stderr, "\n");
40 va_end(ap);
41 conf_warnings++;
42}
43
44static char *conf_expand_value(const char *in)
45{
46 struct symbol *sym;
47 const char *src;
48 static char res_value[SYMBOL_MAXLENGTH];
49 char *dst, name[SYMBOL_MAXLENGTH];
50
51 res_value[0] = 0;
52 dst = name;
53 while ((src = strchr(in, '$'))) {
54 strncat(res_value, in, src - in);
55 src++;
56 dst = name;
57 while (isalnum(*src) || *src == '_')
58 *dst++ = *src++;
59 *dst = 0;
60 sym = sym_lookup(name, 0);
61 sym_calc_value(sym);
62 strcat(res_value, sym_get_string_value(sym));
63 in = src;
64 }
65 strcat(res_value, in);
66
67 return res_value;
68}
69
70char *conf_get_default_confname(void)
71{
72 struct stat buf;
Jérémie Koenigfbedacf2010-03-26 19:08:53 +010073 static char *fullname = NULL;
Denis Vlasenko7d219aa2006-10-05 10:17:08 +000074 char *env, *name;
75
76 name = conf_expand_value(conf_defname);
77 env = getenv(SRCTREE);
78 if (env) {
Jérémie Koenigfbedacf2010-03-26 19:08:53 +010079 fullname = realloc(fullname, strlen(env) + strlen(name) + 2);
Denis Vlasenko7d219aa2006-10-05 10:17:08 +000080 sprintf(fullname, "%s/%s", env, name);
81 if (!stat(fullname, &buf))
82 return fullname;
83 }
84 return name;
85}
86
87int conf_read_simple(const char *name)
88{
89 FILE *in = NULL;
90 char line[1024];
91 char *p, *p2;
92 struct symbol *sym;
93 int i;
94
95 if (name) {
96 in = zconf_fopen(name);
97 } else {
98 const char **names = conf_confnames;
99 while ((name = *names++)) {
100 name = conf_expand_value(name);
101 in = zconf_fopen(name);
102 if (in) {
103 printf(_("#\n"
104 "# using defaults found in %s\n"
105 "#\n"), name);
106 break;
107 }
108 }
109 }
110 if (!in)
111 return 1;
112
113 conf_filename = name;
114 conf_lineno = 0;
115 conf_warnings = 0;
116 conf_unsaved = 0;
117
118 for_all_symbols(i, sym) {
119 sym->flags |= SYMBOL_NEW | SYMBOL_CHANGED;
120 if (sym_is_choice(sym))
121 sym->flags &= ~SYMBOL_NEW;
122 sym->flags &= ~SYMBOL_VALID;
123 switch (sym->type) {
124 case S_INT:
125 case S_HEX:
126 case S_STRING:
127 if (sym->user.val)
128 free(sym->user.val);
129 default:
130 sym->user.val = NULL;
131 sym->user.tri = no;
132 }
133 }
134
135 while (fgets(line, sizeof(line), in)) {
136 conf_lineno++;
137 sym = NULL;
138 switch (line[0]) {
139 case '#':
140 if (memcmp(line + 2, "CONFIG_", 7))
141 continue;
142 p = strchr(line + 9, ' ');
143 if (!p)
144 continue;
145 *p++ = 0;
146 if (strncmp(p, "is not set", 10))
147 continue;
148 sym = sym_find(line + 9);
149 if (!sym) {
150 conf_warning("trying to assign nonexistent symbol %s", line + 9);
151 break;
152 } else if (!(sym->flags & SYMBOL_NEW)) {
153 conf_warning("trying to reassign symbol %s", sym->name);
154 break;
155 }
156 switch (sym->type) {
157 case S_BOOLEAN:
158 case S_TRISTATE:
159 sym->user.tri = no;
160 sym->flags &= ~SYMBOL_NEW;
161 break;
162 default:
163 ;
164 }
165 break;
166 case 'C':
167 if (memcmp(line, "CONFIG_", 7)) {
168 conf_warning("unexpected data");
169 continue;
170 }
171 p = strchr(line + 7, '=');
172 if (!p)
173 continue;
174 *p++ = 0;
175 p2 = strchr(p, '\n');
176 if (p2)
177 *p2 = 0;
178 sym = sym_find(line + 7);
179 if (!sym) {
180 conf_warning("trying to assign nonexistent symbol %s", line + 7);
181 break;
182 } else if (!(sym->flags & SYMBOL_NEW)) {
183 conf_warning("trying to reassign symbol %s", sym->name);
184 break;
185 }
186 switch (sym->type) {
187 case S_TRISTATE:
188 if (p[0] == 'm') {
189 sym->user.tri = mod;
190 sym->flags &= ~SYMBOL_NEW;
191 break;
192 }
193 case S_BOOLEAN:
194 if (p[0] == 'y') {
195 sym->user.tri = yes;
196 sym->flags &= ~SYMBOL_NEW;
197 break;
198 }
199 if (p[0] == 'n') {
200 sym->user.tri = no;
201 sym->flags &= ~SYMBOL_NEW;
202 break;
203 }
204 conf_warning("symbol value '%s' invalid for %s", p, sym->name);
205 break;
206 case S_STRING:
207 if (*p++ != '"')
208 break;
209 for (p2 = p; (p2 = strpbrk(p2, "\"\\")); p2++) {
210 if (*p2 == '"') {
211 *p2 = 0;
212 break;
213 }
214 memmove(p2, p2 + 1, strlen(p2));
215 }
216 if (!p2) {
217 conf_warning("invalid string found");
218 continue;
219 }
220 case S_INT:
221 case S_HEX:
222 if (sym_string_valid(sym, p)) {
223 sym->user.val = strdup(p);
224 sym->flags &= ~SYMBOL_NEW;
225 } else {
Denis Vlasenko028f2d62007-08-23 14:11:30 +0000226 if (p[0]) /* bbox */
227 conf_warning("symbol value '%s' invalid for %s", p, sym->name);
Denis Vlasenko7d219aa2006-10-05 10:17:08 +0000228 continue;
229 }
230 break;
231 default:
232 ;
233 }
234 break;
235 case '\n':
236 break;
237 default:
238 conf_warning("unexpected data");
239 continue;
240 }
241 if (sym && sym_is_choice_value(sym)) {
242 struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym));
243 switch (sym->user.tri) {
244 case no:
245 break;
246 case mod:
247 if (cs->user.tri == yes) {
248 conf_warning("%s creates inconsistent choice state", sym->name);
249 cs->flags |= SYMBOL_NEW;
250 }
251 break;
252 case yes:
253 if (cs->user.tri != no) {
254 conf_warning("%s creates inconsistent choice state", sym->name);
255 cs->flags |= SYMBOL_NEW;
256 } else
257 cs->user.val = sym;
258 break;
259 }
260 cs->user.tri = E_OR(cs->user.tri, sym->user.tri);
261 }
262 }
263 fclose(in);
264
265 if (modules_sym)
266 sym_calc_value(modules_sym);
267 return 0;
268}
269
270int conf_read(const char *name)
271{
272 struct symbol *sym;
273 struct property *prop;
274 struct expr *e;
275 int i;
276
277 if (conf_read_simple(name))
278 return 1;
279
280 for_all_symbols(i, sym) {
281 sym_calc_value(sym);
282 if (sym_is_choice(sym) || (sym->flags & SYMBOL_AUTO))
283 goto sym_ok;
284 if (sym_has_value(sym) && (sym->flags & SYMBOL_WRITE)) {
285 /* check that calculated value agrees with saved value */
286 switch (sym->type) {
287 case S_BOOLEAN:
288 case S_TRISTATE:
289 if (sym->user.tri != sym_get_tristate_value(sym))
290 break;
291 if (!sym_is_choice(sym))
292 goto sym_ok;
293 default:
294 if (!strcmp(sym->curr.val, sym->user.val))
295 goto sym_ok;
296 break;
297 }
298 } else if (!sym_has_value(sym) && !(sym->flags & SYMBOL_WRITE))
299 /* no previous value and not saved */
300 goto sym_ok;
301 conf_unsaved++;
302 /* maybe print value in verbose mode... */
303 sym_ok:
304 if (sym_has_value(sym) && !sym_is_choice_value(sym)) {
305 if (sym->visible == no)
306 sym->flags |= SYMBOL_NEW;
307 switch (sym->type) {
308 case S_STRING:
309 case S_INT:
310 case S_HEX:
311 if (!sym_string_within_range(sym, sym->user.val)) {
312 sym->flags |= SYMBOL_NEW;
313 sym->flags &= ~SYMBOL_VALID;
314 }
315 default:
316 break;
317 }
318 }
319 if (!sym_is_choice(sym))
320 continue;
321 prop = sym_get_choice_prop(sym);
322 for (e = prop->expr; e; e = e->left.expr)
323 if (e->right.sym->visible != no)
324 sym->flags |= e->right.sym->flags & SYMBOL_NEW;
325 }
326
327 sym_change_count = conf_warnings || conf_unsaved;
328
329 return 0;
330}
331
332int conf_write(const char *name)
333{
334 FILE *out, *out_h;
335 struct symbol *sym;
336 struct menu *menu;
337 const char *basename;
338 char dirname[128], tmpname[128], newname[128];
339 int type, l;
340 const char *str;
341 time_t now;
342 int use_timestamp = 1;
343 char *env;
344
345 dirname[0] = 0;
346 if (name && name[0]) {
347 struct stat st;
348 char *slash;
349
350 if (!stat(name, &st) && S_ISDIR(st.st_mode)) {
351 strcpy(dirname, name);
352 strcat(dirname, "/");
353 basename = conf_def_filename;
354 } else if ((slash = strrchr(name, '/'))) {
355 int size = slash - name + 1;
356 memcpy(dirname, name, size);
357 dirname[size] = 0;
358 if (slash[1])
359 basename = slash + 1;
360 else
361 basename = conf_def_filename;
362 } else
363 basename = name;
364 } else
365 basename = conf_def_filename;
366
367 sprintf(newname, "%s.tmpconfig.%d", dirname, (int)getpid());
368 out = fopen(newname, "w");
369 if (!out)
370 return 1;
371 out_h = NULL;
372 if (!name) {
373 out_h = fopen(".tmpconfig.h", "w");
374 if (!out_h)
375 return 1;
376 file_write_dep(NULL);
377 }
378 sym = sym_lookup("KERNELVERSION", 0);
379 sym_calc_value(sym);
380 time(&now);
381 env = getenv("KCONFIG_NOTIMESTAMP");
382 if (env && *env)
383 use_timestamp = 0;
384
385 fprintf(out, _("#\n"
386 "# Automatically generated make config: don't edit\n"
Bernhard Reutner-Fischer9e8df932007-01-17 19:36:01 +0000387 "# Busybox version: %s\n"
Denis Vlasenko7d219aa2006-10-05 10:17:08 +0000388 "%s%s"
389 "#\n"),
390 sym_get_string_value(sym),
391 use_timestamp ? "# " : "",
392 use_timestamp ? ctime(&now) : "");
393 if (out_h) {
394 char buf[sizeof("#define AUTOCONF_TIMESTAMP "
395 "\"YYYY-MM-DD HH:MM:SS some_timezone\"\n")];
396 buf[0] = '\0';
Mike Frysinger68ffb9a2006-12-30 19:43:35 +0000397 if (use_timestamp) {
398 size_t ret = \
399 strftime(buf, sizeof(buf), "#define AUTOCONF_TIMESTAMP "
400 "\"%Y-%m-%d %H:%M:%S %Z\"\n", localtime(&now));
401 /* if user has Factory timezone or some other odd install, the
402 * %Z above will overflow the string leaving us with undefined
403 * results ... so let's try again without the timezone.
404 */
405 if (ret == 0)
406 strftime(buf, sizeof(buf), "#define AUTOCONF_TIMESTAMP "
407 "\"%Y-%m-%d %H:%M:%S\"\n", localtime(&now));
Denis Vlasenkob140edd2008-04-25 19:00:39 +0000408 } else { /* bbox */
409 strcpy(buf, "#define AUTOCONF_TIMESTAMP \"\"\n");
Mike Frysinger68ffb9a2006-12-30 19:43:35 +0000410 }
Denis Vlasenko7d219aa2006-10-05 10:17:08 +0000411 fprintf(out_h, "/*\n"
412 " * Automatically generated C config: don't edit\n"
Bernhard Reutner-Fischer9e8df932007-01-17 19:36:01 +0000413 " * Busybox version: %s\n"
Denis Vlasenko7d219aa2006-10-05 10:17:08 +0000414 " */\n"
415 "%s"
Mike Frysinger1b3e8172006-12-30 19:46:38 +0000416 "\n",
Denis Vlasenko7d219aa2006-10-05 10:17:08 +0000417 sym_get_string_value(sym),
418 buf);
419 }
420 if (!sym_change_count)
421 sym_clear_all_valid();
422
423 menu = rootmenu.list;
424 while (menu) {
425 sym = menu->sym;
426 if (!sym) {
427 if (!menu_is_visible(menu))
428 goto next;
429 str = menu_get_prompt(menu);
430 fprintf(out, "\n"
431 "#\n"
432 "# %s\n"
433 "#\n", str);
434 if (out_h)
435 fprintf(out_h, "\n"
436 "/*\n"
437 " * %s\n"
438 " */\n", str);
439 } else if (!(sym->flags & SYMBOL_CHOICE)) {
440 sym_calc_value(sym);
Denis Vlasenko417e2402008-05-28 11:59:32 +0000441/* bbox: we want to see all syms
Denis Vlasenko7d219aa2006-10-05 10:17:08 +0000442 if (!(sym->flags & SYMBOL_WRITE))
443 goto next;
Denis Vlasenkob79b87a2006-10-19 22:17:44 +0000444*/
Denis Vlasenko7d219aa2006-10-05 10:17:08 +0000445 sym->flags &= ~SYMBOL_WRITE;
446 type = sym->type;
447 if (type == S_TRISTATE) {
448 sym_calc_value(modules_sym);
449 if (modules_sym->curr.tri == no)
450 type = S_BOOLEAN;
451 }
452 switch (type) {
453 case S_BOOLEAN:
454 case S_TRISTATE:
455 switch (sym_get_tristate_value(sym)) {
456 case no:
457 fprintf(out, "# CONFIG_%s is not set\n", sym->name);
458 if (out_h) {
459 fprintf(out_h, "#undef CONFIG_%s\n", sym->name);
460 /* bbox */
461 fprintf(out_h, "#define ENABLE_%s 0\n", sym->name);
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000462 fprintf(out_h, "#define IF_%s(...)\n", sym->name);
463 fprintf(out_h, "#define IF_NOT_%s(...) __VA_ARGS__\n", sym->name);
Denis Vlasenko7d219aa2006-10-05 10:17:08 +0000464 }
465 break;
466 case mod:
467 fprintf(out, "CONFIG_%s=m\n", sym->name);
468 if (out_h)
469 fprintf(out_h, "#define CONFIG_%s_MODULE 1\n", sym->name);
470 break;
471 case yes:
472 fprintf(out, "CONFIG_%s=y\n", sym->name);
473 if (out_h) {
474 fprintf(out_h, "#define CONFIG_%s 1\n", sym->name);
475 /* bbox */
476 fprintf(out_h, "#define ENABLE_%s 1\n", sym->name);
Bernhard Reutner-Fischer90786332013-06-10 17:08:22 +0200477 fprintf(out_h, "#ifdef MAKE_SUID\n");
478 fprintf(out_h, "# define IF_%s(...) __VA_ARGS__ \"CONFIG_%s\"\n", sym->name, sym->name);
479 fprintf(out_h, "#else\n");
480 fprintf(out_h, "# define IF_%s(...) __VA_ARGS__\n", sym->name);
481 fprintf(out_h, "#endif\n");
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000482 fprintf(out_h, "#define IF_NOT_%s(...)\n", sym->name);
Denis Vlasenko7d219aa2006-10-05 10:17:08 +0000483 }
484 break;
485 }
486 break;
487 case S_STRING:
488 // fix me
489 str = sym_get_string_value(sym);
490 fprintf(out, "CONFIG_%s=\"", sym->name);
491 if (out_h)
492 fprintf(out_h, "#define CONFIG_%s \"", sym->name);
493 do {
494 l = strcspn(str, "\"\\");
495 if (l) {
496 fwrite(str, l, 1, out);
497 if (out_h)
498 fwrite(str, l, 1, out_h);
499 }
500 str += l;
501 while (*str == '\\' || *str == '"') {
502 fprintf(out, "\\%c", *str);
503 if (out_h)
504 fprintf(out_h, "\\%c", *str);
505 str++;
506 }
507 } while (*str);
508 fputs("\"\n", out);
509 if (out_h) {
510 fputs("\"\n", out_h);
511 /* bbox */
512 fprintf(out_h, "#define ENABLE_%s 1\n", sym->name);
Bernhard Reutner-Fischer90786332013-06-10 17:08:22 +0200513 fprintf(out_h, "#ifdef MAKE_SUID\n");
514 fprintf(out_h, "# define IF_%s(...) __VA_ARGS__ \"CONFIG_%s\"\n", sym->name, sym->name);
515 fprintf(out_h, "#else\n");
516 fprintf(out_h, "# define IF_%s(...) __VA_ARGS__\n", sym->name);
517 fprintf(out_h, "#endif\n");
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000518 fprintf(out_h, "#define IF_NOT_%s(...)\n", sym->name);
Denis Vlasenko7d219aa2006-10-05 10:17:08 +0000519 }
520 break;
521 case S_HEX:
522 str = sym_get_string_value(sym);
523 if (str[0] != '0' || (str[1] != 'x' && str[1] != 'X')) {
524 fprintf(out, "CONFIG_%s=%s\n", sym->name, str);
525 if (out_h) {
526 fprintf(out_h, "#define CONFIG_%s 0x%s\n", sym->name, str);
527 /* bbox */
528 fprintf(out_h, "#define ENABLE_%s 1\n", sym->name);
Bernhard Reutner-Fischer90786332013-06-10 17:08:22 +0200529 fprintf(out_h, "#ifdef MAKE_SUID\n");
530 fprintf(out_h, "# define IF_%s(...) __VA_ARGS__ \"CONFIG_%s\"\n", sym->name, sym->name);
531 fprintf(out_h, "#else\n");
532 fprintf(out_h, "# define IF_%s(...) __VA_ARGS__\n", sym->name);
533 fprintf(out_h, "#endif\n");
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000534 fprintf(out_h, "#define IF_NOT_%s(...)\n", sym->name);
Denis Vlasenko7d219aa2006-10-05 10:17:08 +0000535 }
536 break;
537 }
538 case S_INT:
539 str = sym_get_string_value(sym);
Denis Vlasenkoc6ab0852009-02-15 12:01:14 +0000540 if (!str[0])
541 str = "0";
Denis Vlasenko7d219aa2006-10-05 10:17:08 +0000542 fprintf(out, "CONFIG_%s=%s\n", sym->name, str);
543 if (out_h) {
544 fprintf(out_h, "#define CONFIG_%s %s\n", sym->name, str);
545 /* bbox */
546 fprintf(out_h, "#define ENABLE_%s 1\n", sym->name);
Bernhard Reutner-Fischer90786332013-06-10 17:08:22 +0200547 fprintf(out_h, "#ifdef MAKE_SUID\n");
548 fprintf(out_h, "# define IF_%s(...) __VA_ARGS__ \"CONFIG_%s\"\n", sym->name, sym->name);
549 fprintf(out_h, "#else\n");
550 fprintf(out_h, "# define IF_%s(...) __VA_ARGS__\n", sym->name);
551 fprintf(out_h, "#endif\n");
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000552 fprintf(out_h, "#define IF_NOT_%s(...)\n", sym->name);
Denis Vlasenko7d219aa2006-10-05 10:17:08 +0000553 }
554 break;
555 }
556 }
557
558 next:
559 if (menu->list) {
560 menu = menu->list;
561 continue;
562 }
563 if (menu->next)
564 menu = menu->next;
565 else while ((menu = menu->parent)) {
566 if (menu->next) {
567 menu = menu->next;
568 break;
569 }
570 }
571 }
572 fclose(out);
573 if (out_h) {
574 fclose(out_h);
575 rename(".tmpconfig.h", "include/autoconf.h");
576 }
577 if (!name || basename != conf_def_filename) {
578 if (!name)
579 name = conf_def_filename;
580 sprintf(tmpname, "%s.old", name);
581 rename(name, tmpname);
582 }
583 sprintf(tmpname, "%s%s", dirname, basename);
584 if (rename(newname, tmpname))
585 return 1;
586
587 sym_change_count = 0;
588
589 return 0;
590}