blob: a9e3b6abf66104c3450636ee67557b7ecb5c8a8e [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;
Roman Zippelddc97ca2006-06-08 22:12:38 -0700101 name = *names++;
102 if (!name)
103 return 1;
104 in = zconf_fopen(name);
105 if (in)
106 goto load;
107 sym_change_count++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108 while ((name = *names++)) {
109 name = conf_expand_value(name);
110 in = zconf_fopen(name);
111 if (in) {
Arnaldo Carvalho de Melo3b9fa092005-05-05 15:09:46 -0700112 printf(_("#\n"
Roman Zippelddc97ca2006-06-08 22:12:38 -0700113 "# using defaults found in %s\n"
114 "#\n"), name);
115 goto load;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116 }
117 }
118 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119 if (!in)
120 return 1;
121
Roman Zippelddc97ca2006-06-08 22:12:38 -0700122load:
Roman Zippelc1a0f5e2005-11-08 21:34:54 -0800123 conf_filename = name;
124 conf_lineno = 0;
125 conf_warnings = 0;
126 conf_unsaved = 0;
127
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128 for_all_symbols(i, sym) {
129 sym->flags |= SYMBOL_NEW | SYMBOL_CHANGED;
Roman Zippelc1a0f5e2005-11-08 21:34:54 -0800130 if (sym_is_choice(sym))
131 sym->flags &= ~SYMBOL_NEW;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132 sym->flags &= ~SYMBOL_VALID;
133 switch (sym->type) {
134 case S_INT:
135 case S_HEX:
136 case S_STRING:
137 if (sym->user.val)
138 free(sym->user.val);
139 default:
140 sym->user.val = NULL;
141 sym->user.tri = no;
142 }
143 }
144
145 while (fgets(line, sizeof(line), in)) {
Roman Zippelc1a0f5e2005-11-08 21:34:54 -0800146 conf_lineno++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147 sym = NULL;
148 switch (line[0]) {
149 case '#':
150 if (memcmp(line + 2, "CONFIG_", 7))
151 continue;
152 p = strchr(line + 9, ' ');
153 if (!p)
154 continue;
155 *p++ = 0;
156 if (strncmp(p, "is not set", 10))
157 continue;
158 sym = sym_find(line + 9);
159 if (!sym) {
Roman Zippelc1a0f5e2005-11-08 21:34:54 -0800160 conf_warning("trying to assign nonexistent symbol %s", line + 9);
161 break;
162 } else if (!(sym->flags & SYMBOL_NEW)) {
163 conf_warning("trying to reassign symbol %s", sym->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164 break;
165 }
166 switch (sym->type) {
167 case S_BOOLEAN:
168 case S_TRISTATE:
169 sym->user.tri = no;
170 sym->flags &= ~SYMBOL_NEW;
171 break;
172 default:
173 ;
174 }
175 break;
176 case 'C':
Roman Zippelc1a0f5e2005-11-08 21:34:54 -0800177 if (memcmp(line, "CONFIG_", 7)) {
178 conf_warning("unexpected data");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179 continue;
Roman Zippelc1a0f5e2005-11-08 21:34:54 -0800180 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181 p = strchr(line + 7, '=');
182 if (!p)
183 continue;
184 *p++ = 0;
185 p2 = strchr(p, '\n');
186 if (p2)
187 *p2 = 0;
188 sym = sym_find(line + 7);
189 if (!sym) {
Roman Zippelc1a0f5e2005-11-08 21:34:54 -0800190 conf_warning("trying to assign nonexistent symbol %s", line + 7);
191 break;
192 } else if (!(sym->flags & SYMBOL_NEW)) {
193 conf_warning("trying to reassign symbol %s", sym->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194 break;
195 }
196 switch (sym->type) {
197 case S_TRISTATE:
198 if (p[0] == 'm') {
199 sym->user.tri = mod;
200 sym->flags &= ~SYMBOL_NEW;
201 break;
202 }
203 case S_BOOLEAN:
204 if (p[0] == 'y') {
205 sym->user.tri = yes;
206 sym->flags &= ~SYMBOL_NEW;
207 break;
208 }
209 if (p[0] == 'n') {
210 sym->user.tri = no;
211 sym->flags &= ~SYMBOL_NEW;
212 break;
213 }
Roman Zippelc1a0f5e2005-11-08 21:34:54 -0800214 conf_warning("symbol value '%s' invalid for %s", p, sym->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215 break;
216 case S_STRING:
217 if (*p++ != '"')
218 break;
219 for (p2 = p; (p2 = strpbrk(p2, "\"\\")); p2++) {
220 if (*p2 == '"') {
221 *p2 = 0;
222 break;
223 }
224 memmove(p2, p2 + 1, strlen(p2));
225 }
226 if (!p2) {
Roman Zippelc1a0f5e2005-11-08 21:34:54 -0800227 conf_warning("invalid string found");
228 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229 }
230 case S_INT:
231 case S_HEX:
232 if (sym_string_valid(sym, p)) {
233 sym->user.val = strdup(p);
234 sym->flags &= ~SYMBOL_NEW;
235 } else {
Roman Zippelc1a0f5e2005-11-08 21:34:54 -0800236 conf_warning("symbol value '%s' invalid for %s", p, sym->name);
237 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238 }
239 break;
240 default:
241 ;
242 }
243 break;
244 case '\n':
245 break;
246 default:
Roman Zippelc1a0f5e2005-11-08 21:34:54 -0800247 conf_warning("unexpected data");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248 continue;
249 }
250 if (sym && sym_is_choice_value(sym)) {
251 struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym));
252 switch (sym->user.tri) {
253 case no:
254 break;
255 case mod:
Roman Zippelc1a0f5e2005-11-08 21:34:54 -0800256 if (cs->user.tri == yes) {
257 conf_warning("%s creates inconsistent choice state", sym->name);
258 cs->flags |= SYMBOL_NEW;
259 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260 break;
261 case yes:
Roman Zippelc1a0f5e2005-11-08 21:34:54 -0800262 if (cs->user.tri != no) {
263 conf_warning("%s creates inconsistent choice state", sym->name);
264 cs->flags |= SYMBOL_NEW;
265 } else
266 cs->user.val = sym;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267 break;
268 }
269 cs->user.tri = E_OR(cs->user.tri, sym->user.tri);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270 }
271 }
272 fclose(in);
273
274 if (modules_sym)
275 sym_calc_value(modules_sym);
Roman Zippel90389162005-11-08 21:34:49 -0800276 return 0;
277}
278
279int conf_read(const char *name)
280{
281 struct symbol *sym;
282 struct property *prop;
283 struct expr *e;
284 int i;
285
Roman Zippelddc97ca2006-06-08 22:12:38 -0700286 sym_change_count = 0;
287
Roman Zippel90389162005-11-08 21:34:49 -0800288 if (conf_read_simple(name))
289 return 1;
290
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291 for_all_symbols(i, sym) {
292 sym_calc_value(sym);
Roman Zippelc1a0f5e2005-11-08 21:34:54 -0800293 if (sym_is_choice(sym) || (sym->flags & SYMBOL_AUTO))
294 goto sym_ok;
295 if (sym_has_value(sym) && (sym->flags & SYMBOL_WRITE)) {
296 /* check that calculated value agrees with saved value */
297 switch (sym->type) {
298 case S_BOOLEAN:
299 case S_TRISTATE:
300 if (sym->user.tri != sym_get_tristate_value(sym))
301 break;
302 if (!sym_is_choice(sym))
303 goto sym_ok;
304 default:
305 if (!strcmp(sym->curr.val, sym->user.val))
306 goto sym_ok;
307 break;
308 }
309 } else if (!sym_has_value(sym) && !(sym->flags & SYMBOL_WRITE))
310 /* no previous value and not saved */
311 goto sym_ok;
312 conf_unsaved++;
313 /* maybe print value in verbose mode... */
314 sym_ok:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315 if (sym_has_value(sym) && !sym_is_choice_value(sym)) {
316 if (sym->visible == no)
317 sym->flags |= SYMBOL_NEW;
318 switch (sym->type) {
319 case S_STRING:
320 case S_INT:
321 case S_HEX:
Roman Zippelc1a0f5e2005-11-08 21:34:54 -0800322 if (!sym_string_within_range(sym, sym->user.val)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323 sym->flags |= SYMBOL_NEW;
Roman Zippelc1a0f5e2005-11-08 21:34:54 -0800324 sym->flags &= ~SYMBOL_VALID;
325 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326 default:
327 break;
328 }
329 }
330 if (!sym_is_choice(sym))
331 continue;
332 prop = sym_get_choice_prop(sym);
333 for (e = prop->expr; e; e = e->left.expr)
334 if (e->right.sym->visible != no)
335 sym->flags |= e->right.sym->flags & SYMBOL_NEW;
336 }
337
Roman Zippelddc97ca2006-06-08 22:12:38 -0700338 sym_change_count += conf_warnings || conf_unsaved;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339
340 return 0;
341}
342
343int conf_write(const char *name)
344{
345 FILE *out, *out_h;
346 struct symbol *sym;
347 struct menu *menu;
348 const char *basename;
349 char dirname[128], tmpname[128], newname[128];
350 int type, l;
351 const char *str;
352 time_t now;
353 int use_timestamp = 1;
354 char *env;
355
356 dirname[0] = 0;
357 if (name && name[0]) {
358 struct stat st;
359 char *slash;
360
361 if (!stat(name, &st) && S_ISDIR(st.st_mode)) {
362 strcpy(dirname, name);
363 strcat(dirname, "/");
364 basename = conf_def_filename;
365 } else if ((slash = strrchr(name, '/'))) {
366 int size = slash - name + 1;
367 memcpy(dirname, name, size);
368 dirname[size] = 0;
369 if (slash[1])
370 basename = slash + 1;
371 else
372 basename = conf_def_filename;
373 } else
374 basename = name;
375 } else
376 basename = conf_def_filename;
377
378 sprintf(newname, "%s.tmpconfig.%d", dirname, (int)getpid());
379 out = fopen(newname, "w");
380 if (!out)
381 return 1;
382 out_h = NULL;
383 if (!name) {
384 out_h = fopen(".tmpconfig.h", "w");
385 if (!out_h)
386 return 1;
Jan Beulichdc9a49a2006-03-09 14:47:46 +0100387 file_write_dep(NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 }
Sam Ravnborg2244cbd2006-01-16 12:12:12 +0100389 sym = sym_lookup("KERNELVERSION", 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390 sym_calc_value(sym);
391 time(&now);
392 env = getenv("KCONFIG_NOTIMESTAMP");
393 if (env && *env)
394 use_timestamp = 0;
395
Arnaldo Carvalho de Melo3b9fa092005-05-05 15:09:46 -0700396 fprintf(out, _("#\n"
397 "# Automatically generated make config: don't edit\n"
398 "# Linux kernel version: %s\n"
399 "%s%s"
400 "#\n"),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401 sym_get_string_value(sym),
402 use_timestamp ? "# " : "",
403 use_timestamp ? ctime(&now) : "");
404 if (out_h)
405 fprintf(out_h, "/*\n"
406 " * Automatically generated C config: don't edit\n"
407 " * Linux kernel version: %s\n"
408 "%s%s"
409 " */\n"
410 "#define AUTOCONF_INCLUDED\n",
411 sym_get_string_value(sym),
412 use_timestamp ? " * " : "",
413 use_timestamp ? ctime(&now) : "");
414
415 if (!sym_change_count)
416 sym_clear_all_valid();
417
418 menu = rootmenu.list;
419 while (menu) {
420 sym = menu->sym;
421 if (!sym) {
422 if (!menu_is_visible(menu))
423 goto next;
424 str = menu_get_prompt(menu);
425 fprintf(out, "\n"
426 "#\n"
427 "# %s\n"
428 "#\n", str);
429 if (out_h)
430 fprintf(out_h, "\n"
431 "/*\n"
432 " * %s\n"
433 " */\n", str);
434 } else if (!(sym->flags & SYMBOL_CHOICE)) {
435 sym_calc_value(sym);
436 if (!(sym->flags & SYMBOL_WRITE))
437 goto next;
438 sym->flags &= ~SYMBOL_WRITE;
439 type = sym->type;
440 if (type == S_TRISTATE) {
441 sym_calc_value(modules_sym);
442 if (modules_sym->curr.tri == no)
443 type = S_BOOLEAN;
444 }
445 switch (type) {
446 case S_BOOLEAN:
447 case S_TRISTATE:
448 switch (sym_get_tristate_value(sym)) {
449 case no:
450 fprintf(out, "# CONFIG_%s is not set\n", sym->name);
451 if (out_h)
452 fprintf(out_h, "#undef CONFIG_%s\n", sym->name);
453 break;
454 case mod:
455 fprintf(out, "CONFIG_%s=m\n", sym->name);
456 if (out_h)
457 fprintf(out_h, "#define CONFIG_%s_MODULE 1\n", sym->name);
458 break;
459 case yes:
460 fprintf(out, "CONFIG_%s=y\n", sym->name);
461 if (out_h)
462 fprintf(out_h, "#define CONFIG_%s 1\n", sym->name);
463 break;
464 }
465 break;
466 case S_STRING:
467 // fix me
468 str = sym_get_string_value(sym);
469 fprintf(out, "CONFIG_%s=\"", sym->name);
470 if (out_h)
471 fprintf(out_h, "#define CONFIG_%s \"", sym->name);
472 do {
473 l = strcspn(str, "\"\\");
474 if (l) {
475 fwrite(str, l, 1, out);
476 if (out_h)
477 fwrite(str, l, 1, out_h);
478 }
479 str += l;
480 while (*str == '\\' || *str == '"') {
481 fprintf(out, "\\%c", *str);
482 if (out_h)
483 fprintf(out_h, "\\%c", *str);
484 str++;
485 }
486 } while (*str);
487 fputs("\"\n", out);
488 if (out_h)
489 fputs("\"\n", out_h);
490 break;
491 case S_HEX:
492 str = sym_get_string_value(sym);
493 if (str[0] != '0' || (str[1] != 'x' && str[1] != 'X')) {
494 fprintf(out, "CONFIG_%s=%s\n", sym->name, str);
495 if (out_h)
496 fprintf(out_h, "#define CONFIG_%s 0x%s\n", sym->name, str);
497 break;
498 }
499 case S_INT:
500 str = sym_get_string_value(sym);
501 fprintf(out, "CONFIG_%s=%s\n", sym->name, str);
502 if (out_h)
503 fprintf(out_h, "#define CONFIG_%s %s\n", sym->name, str);
504 break;
505 }
506 }
507
508 next:
509 if (menu->list) {
510 menu = menu->list;
511 continue;
512 }
513 if (menu->next)
514 menu = menu->next;
515 else while ((menu = menu->parent)) {
516 if (menu->next) {
517 menu = menu->next;
518 break;
519 }
520 }
521 }
522 fclose(out);
523 if (out_h) {
524 fclose(out_h);
525 rename(".tmpconfig.h", "include/linux/autoconf.h");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526 }
527 if (!name || basename != conf_def_filename) {
528 if (!name)
529 name = conf_def_filename;
530 sprintf(tmpname, "%s.old", name);
531 rename(name, tmpname);
532 }
533 sprintf(tmpname, "%s%s", dirname, basename);
534 if (rename(newname, tmpname))
535 return 1;
536
Roman Zippelddc97ca2006-06-08 22:12:38 -0700537 printf(_("#\n"
538 "# configuration written to %s\n"
539 "#\n"), tmpname);
540
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541 sym_change_count = 0;
542
543 return 0;
544}