busybox/scripts/kconfig/confdata.c
<<
>>
Prefs
   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                } else { /* bbox */
 408                        strcpy(buf, "#define AUTOCONF_TIMESTAMP \"\"\n");
 409                }
 410                fprintf(out_h, "/*\n"
 411                               " * Automatically generated C config: don't edit\n"
 412                               " * Busybox version: %s\n"
 413                               " */\n"
 414                               "%s"
 415                               "\n",
 416                               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);
 440/* bbox: we want to see all syms
 441                        if (!(sym->flags & SYMBOL_WRITE))
 442                                goto next;
 443*/
 444                        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}
 572