1/* 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 25const char conf_defname[] = "scripts/defconfig"; 26 27const char *conf_confnames[] = { 28 conf_def_filename, 29 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; 73 static char fullname[PATH_MAX+1]; 74 char *env, *name; 75 76 name = conf_expand_value(conf_defname); 77 env = getenv(SRCTREE); 78 if (env) { 79 sprintf(fullname, "%s/%s", env, name); 80 if (!stat(fullname, &buf)) 81 return fullname; 82 } 83 return name; 84} 85 86int conf_read_simple(const char *name) 87{ 88 FILE *in = NULL; 89 char line[1024]; 90 char *p, *p2; 91 struct symbol *sym; 92 int i; 93 94 if (name) { 95 in = zconf_fopen(name); 96 } else { 97 const char **names = conf_confnames; 98 while ((name = *names++)) { 99 name = conf_expand_value(name); 100 in = zconf_fopen(name); 101 if (in) { 102 printf(_("#\n" 103 "# using defaults found in %s\n" 104 "#\n"), name); 105 break; 106 } 107 } 108 } 109 if (!in) 110 return 1; 111 112 conf_filename = name; 113 conf_lineno = 0; 114 conf_warnings = 0; 115 conf_unsaved = 0; 116 117 for_all_symbols(i, sym) { 118 sym->flags |= SYMBOL_NEW | SYMBOL_CHANGED; 119 if (sym_is_choice(sym)) 120 sym->flags &= ~SYMBOL_NEW; 121 sym->flags &= ~SYMBOL_VALID; 122 switch (sym->type) { 123 case S_INT: 124 case S_HEX: 125 case S_STRING: 126 if (sym->user.val) 127 free(sym->user.val); 128 default: 129 sym->user.val = NULL; 130 sym->user.tri = no; 131 } 132 } 133 134 while (fgets(line, sizeof(line), in)) { 135 conf_lineno++; 136 sym = NULL; 137 switch (line[0]) { 138 case '#': 139 if (memcmp(line + 2, "CONFIG_", 7)) 140 continue; 141 p = strchr(line + 9, ' '); 142 if (!p) 143 continue; 144 *p++ = 0; 145 if (strncmp(p, "is not set", 10)) 146 continue; 147 sym = sym_find(line + 9); 148 if (!sym) { 149 conf_warning("trying to assign nonexistent symbol %s", line + 9); 150 break; 151 } else if (!(sym->flags & SYMBOL_NEW)) { 152 conf_warning("trying to reassign symbol %s", sym->name); 153 break; 154 } 155 switch (sym->type) { 156 case S_BOOLEAN: 157 case S_TRISTATE: 158 sym->user.tri = no; 159 sym->flags &= ~SYMBOL_NEW; 160 break; 161 default: 162 ; 163 } 164 break; 165 case 'C': 166 if (memcmp(line, "CONFIG_", 7)) { 167 conf_warning("unexpected data"); 168 continue; 169 } 170 p = strchr(line + 7, '='); 171 if (!p) 172 continue; 173 *p++ = 0; 174 p2 = strchr(p, '\n'); 175 if (p2) 176 *p2 = 0; 177 sym = sym_find(line + 7); 178 if (!sym) { 179 conf_warning("trying to assign nonexistent symbol %s", line + 7); 180 break; 181 } else if (!(sym->flags & SYMBOL_NEW)) { 182 conf_warning("trying to reassign symbol %s", sym->name); 183 break; 184 } 185 switch (sym->type) { 186 case S_TRISTATE: 187 if (p[0] == 'm') { 188 sym->user.tri = mod; 189 sym->flags &= ~SYMBOL_NEW; 190 break; 191 } 192 case S_BOOLEAN: 193 if (p[0] == 'y') { 194 sym->user.tri = yes; 195 sym->flags &= ~SYMBOL_NEW; 196 break; 197 } 198 if (p[0] == 'n') { 199 sym->user.tri = no; 200 sym->flags &= ~SYMBOL_NEW; 201 break; 202 } 203 conf_warning("symbol value '%s' invalid for %s", p, sym->name); 204 break; 205 case S_STRING: 206 if (*p++ != '"') 207 break; 208 for (p2 = p; (p2 = strpbrk(p2, "\"\\")); p2++) { 209 if (*p2 == '"') { 210 *p2 = 0; 211 break; 212 } 213 memmove(p2, p2 + 1, strlen(p2)); 214 } 215 if (!p2) { 216 conf_warning("invalid string found"); 217 continue; 218 } 219 case S_INT: 220 case S_HEX: 221 if (sym_string_valid(sym, p)) { 222 sym->user.val = strdup(p); 223 sym->flags &= ~SYMBOL_NEW; 224 } else { 225 if (p[0]) /* bbox */ 226 conf_warning("symbol value '%s' invalid for %s", p, sym->name); 227 continue; 228 } 229 break; 230 default: 231 ; 232 } 233 break; 234 case '\n': 235 break; 236 default: 237 conf_warning("unexpected data"); 238 continue; 239 } 240 if (sym && sym_is_choice_value(sym)) { 241 struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym)); 242 switch (sym->user.tri) { 243 case no: 244 break; 245 case mod: 246 if (cs->user.tri == yes) { 247 conf_warning("%s creates inconsistent choice state", sym->name); 248 cs->flags |= SYMBOL_NEW; 249 } 250 break; 251 case yes: 252 if (cs->user.tri != no) { 253 conf_warning("%s creates inconsistent choice state", sym->name); 254 cs->flags |= SYMBOL_NEW; 255 } else 256 cs->user.val = sym; 257 break; 258 } 259 cs->user.tri = E_OR(cs->user.tri, sym->user.tri); 260 } 261 } 262 fclose(in); 263 264 if (modules_sym) 265 sym_calc_value(modules_sym); 266 return 0; 267} 268 269int conf_read(const char *name) 270{ 271 struct symbol *sym; 272 struct property *prop; 273 struct expr *e; 274 int i; 275 276 if (conf_read_simple(name)) 277 return 1; 278 279 for_all_symbols(i, sym) { 280 sym_calc_value(sym); 281 if (sym_is_choice(sym) || (sym->flags & SYMBOL_AUTO)) 282 goto sym_ok; 283 if (sym_has_value(sym) && (sym->flags & SYMBOL_WRITE)) { 284 /* check that calculated value agrees with saved value */ 285 switch (sym->type) { 286 case S_BOOLEAN: 287 case S_TRISTATE: 288 if (sym->user.tri != sym_get_tristate_value(sym)) 289 break; 290 if (!sym_is_choice(sym)) 291 goto sym_ok; 292 default: 293 if (!strcmp(sym->curr.val, sym->user.val)) 294 goto sym_ok; 295 break; 296 } 297 } else if (!sym_has_value(sym) && !(sym->flags & SYMBOL_WRITE)) 298 /* no previous value and not saved */ 299 goto sym_ok; 300 conf_unsaved++; 301 /* maybe print value in verbose mode... */ 302 sym_ok: 303 if (sym_has_value(sym) && !sym_is_choice_value(sym)) { 304 if (sym->visible == no) 305 sym->flags |= SYMBOL_NEW; 306 switch (sym->type) { 307 case S_STRING: 308 case S_INT: 309 case S_HEX: 310 if (!sym_string_within_range(sym, sym->user.val)) { 311 sym->flags |= SYMBOL_NEW; 312 sym->flags &= ~SYMBOL_VALID; 313 } 314 default: 315 break; 316 } 317 } 318 if (!sym_is_choice(sym)) 319 continue; 320 prop = sym_get_choice_prop(sym); 321 for (e = prop->expr; e; e = e->left.expr) 322 if (e->right.sym->visible != no) 323 sym->flags |= e->right.sym->flags & SYMBOL_NEW; 324 } 325 326 sym_change_count = conf_warnings || conf_unsaved; 327 328 return 0; 329} 330 331int conf_write(const char *name) 332{ 333 FILE *out, *out_h; 334 struct symbol *sym; 335 struct menu *menu; 336 const char *basename; 337 char dirname[128], tmpname[128], newname[128]; 338 int type, l; 339 const char *str; 340 time_t now; 341 int use_timestamp = 1; 342 char *env; 343 344 dirname[0] = 0; 345 if (name && name[0]) { 346 struct stat st; 347 char *slash; 348 349 if (!stat(name, &st) && S_ISDIR(st.st_mode)) { 350 strcpy(dirname, name); 351 strcat(dirname, "/"); 352 basename = conf_def_filename; 353 } else if ((slash = strrchr(name, '/'))) { 354 int size = slash - name + 1; 355 memcpy(dirname, name, size); 356 dirname[size] = 0; 357 if (slash[1]) 358 basename = slash + 1; 359 else 360 basename = conf_def_filename; 361 } else 362 basename = name; 363 } else 364 basename = conf_def_filename; 365 366 sprintf(newname, "%s.tmpconfig.%d", dirname, (int)getpid()); 367 out = fopen(newname, "w"); 368 if (!out) 369 return 1; 370 out_h = NULL; 371 if (!name) { 372 out_h = fopen(".tmpconfig.h", "w"); 373 if (!out_h) 374 return 1; 375 file_write_dep(NULL); 376 } 377 sym = sym_lookup("KERNELVERSION", 0); 378 sym_calc_value(sym); 379 time(&now); 380 env = getenv("KCONFIG_NOTIMESTAMP"); 381 if (env && *env) 382 use_timestamp = 0; 383 384 fprintf(out, _("#\n" 385 "# Automatically generated make config: don't edit\n" 386 "# Busybox version: %s\n" 387 "%s%s" 388 "#\n"), 389 sym_get_string_value(sym), 390 use_timestamp ? "# " : "", 391 use_timestamp ? ctime(&now) : ""); 392 if (out_h) { 393 char buf[sizeof("#define AUTOCONF_TIMESTAMP " 394 "\"YYYY-MM-DD HH:MM:SS some_timezone\"\n")]; 395 buf[0] = '\0'; 396 if (use_timestamp) { 397 size_t ret = \ 398 strftime(buf, sizeof(buf), "#define AUTOCONF_TIMESTAMP " 399 "\"%Y-%m-%d %H:%M:%S %Z\"\n", localtime(&now)); 400 /* if user has Factory timezone or some other odd install, the 401 * %Z above will overflow the string leaving us with undefined 402 * results ... so let's try again without the timezone. 403 */ 404 if (ret == 0) 405 strftime(buf, sizeof(buf), "#define AUTOCONF_TIMESTAMP " 406 "\"%Y-%m-%d %H:%M:%S\"\n", localtime(&now)); 407 } 408 fprintf(out_h, "/*\n" 409 " * Automatically generated C config: don't edit\n" 410 " * Busybox version: %s\n" 411 " */\n" 412 "%s" 413 "\n", 414 sym_get_string_value(sym), 415 buf); 416 } 417 if (!sym_change_count) 418 sym_clear_all_valid(); 419 420 menu = rootmenu.list; 421 while (menu) { 422 sym = menu->sym; 423 if (!sym) { 424 if (!menu_is_visible(menu)) 425 goto next; 426 str = menu_get_prompt(menu); 427 fprintf(out, "\n" 428 "#\n" 429 "# %s\n" 430 "#\n", str); 431 if (out_h) 432 fprintf(out_h, "\n" 433 "/*\n" 434 " * %s\n" 435 " */\n", str); 436 } else if (!(sym->flags & SYMBOL_CHOICE)) { 437 sym_calc_value(sym); 438/* bbox: we want to all syms 439 if (!(sym->flags & SYMBOL_WRITE)) 440 goto next; 441*/ 442 sym->flags &= ~SYMBOL_WRITE; 443 type = sym->type; 444 if (type == S_TRISTATE) { 445 sym_calc_value(modules_sym); 446 if (modules_sym->curr.tri == no) 447 type = S_BOOLEAN; 448 } 449 switch (type) { 450 case S_BOOLEAN: 451 case S_TRISTATE: 452 switch (sym_get_tristate_value(sym)) { 453 case no: 454 fprintf(out, "# CONFIG_%s is not set\n", sym->name); 455 if (out_h) { 456 fprintf(out_h, "#undef CONFIG_%s\n", sym->name); 457 /* bbox */ 458 fprintf(out_h, "#define ENABLE_%s 0\n", sym->name); 459 fprintf(out_h, "#define USE_%s(...)\n", sym->name); 460 fprintf(out_h, "#define SKIP_%s(...) __VA_ARGS__\n", sym->name); 461 } 462 break; 463 case mod: 464 fprintf(out, "CONFIG_%s=m\n", sym->name); 465 if (out_h) 466 fprintf(out_h, "#define CONFIG_%s_MODULE 1\n", sym->name); 467 break; 468 case yes: 469 fprintf(out, "CONFIG_%s=y\n", sym->name); 470 if (out_h) { 471 fprintf(out_h, "#define CONFIG_%s 1\n", sym->name); 472 /* bbox */ 473 fprintf(out_h, "#define ENABLE_%s 1\n", sym->name); 474 fprintf(out_h, "#define USE_%s(...) __VA_ARGS__\n", sym->name); 475 fprintf(out_h, "#define SKIP_%s(...)\n", sym->name); 476 } 477 break; 478 } 479 break; 480 case S_STRING: 481 // fix me 482 str = sym_get_string_value(sym); 483 fprintf(out, "CONFIG_%s=\"", sym->name); 484 if (out_h) 485 fprintf(out_h, "#define CONFIG_%s \"", sym->name); 486 do { 487 l = strcspn(str, "\"\\"); 488 if (l) { 489 fwrite(str, l, 1, out); 490 if (out_h) 491 fwrite(str, l, 1, out_h); 492 } 493 str += l; 494 while (*str == '\\' || *str == '"') { 495 fprintf(out, "\\%c", *str); 496 if (out_h) 497 fprintf(out_h, "\\%c", *str); 498 str++; 499 } 500 } while (*str); 501 fputs("\"\n", out); 502 if (out_h) { 503 fputs("\"\n", out_h); 504 /* bbox */ 505 fprintf(out_h, "#define ENABLE_%s 1\n", sym->name); 506 fprintf(out_h, "#define USE_%s(...) __VA_ARGS__\n", sym->name); 507 fprintf(out_h, "#define SKIP_%s(...)\n", sym->name); 508 } 509 break; 510 case S_HEX: 511 str = sym_get_string_value(sym); 512 if (str[0] != '0' || (str[1] != 'x' && str[1] != 'X')) { 513 fprintf(out, "CONFIG_%s=%s\n", sym->name, str); 514 if (out_h) { 515 fprintf(out_h, "#define CONFIG_%s 0x%s\n", sym->name, str); 516 /* bbox */ 517 fprintf(out_h, "#define ENABLE_%s 1\n", sym->name); 518 fprintf(out_h, "#define USE_%s(...) __VA_ARGS__\n", sym->name); 519 fprintf(out_h, "#define SKIP_%s(...)\n", sym->name); 520 } 521 break; 522 } 523 case S_INT: 524 str = sym_get_string_value(sym); 525 fprintf(out, "CONFIG_%s=%s\n", sym->name, str); 526 if (out_h) { 527 fprintf(out_h, "#define CONFIG_%s %s\n", sym->name, str); 528 /* bbox */ 529 fprintf(out_h, "#define ENABLE_%s 1\n", sym->name); 530 fprintf(out_h, "#define USE_%s(...) __VA_ARGS__\n", sym->name); 531 fprintf(out_h, "#define SKIP_%s(...)\n", sym->name); 532 } 533 break; 534 } 535 } 536 537 next: 538 if (menu->list) { 539 menu = menu->list; 540 continue; 541 } 542 if (menu->next) 543 menu = menu->next; 544 else while ((menu = menu->parent)) { 545 if (menu->next) { 546 menu = menu->next; 547 break; 548 } 549 } 550 } 551 fclose(out); 552 if (out_h) { 553 fclose(out_h); 554 rename(".tmpconfig.h", "include/autoconf.h"); 555 } 556 if (!name || basename != conf_def_filename) { 557 if (!name) 558 name = conf_def_filename; 559 sprintf(tmpname, "%s.old", name); 560 rename(name, tmpname); 561 } 562 sprintf(tmpname, "%s%s", dirname, basename); 563 if (rename(newname, tmpname)) 564 return 1; 565 566 sym_change_count = 0; 567 568 return 0; 569} 570