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[] = "/dev/null"; //bbox
  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((unsigned char)*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 = NULL;
  74        char *env, *name;
  75
  76        name = conf_expand_value(conf_defname);
  77        env = getenv(SRCTREE);
  78        if (env) {
  79                fullname = realloc(fullname, strlen(env) + strlen(name) + 2);
  80                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                        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];
 338        char tmpname[256];
 339        char newname[256];
 340        int type, l;
 341        const char *str;
 342        time_t now;
 343        int use_timestamp = 1;
 344        char *env;
 345        char *source_date_epoch;
 346        struct tm *build_time;
 347
 348        dirname[0] = 0;
 349        if (name && name[0]) {
 350                struct stat st;
 351                char *slash;
 352
 353                if (!stat(name, &st) && S_ISDIR(st.st_mode)) {
 354                        strcpy(dirname, name);
 355                        strcat(dirname, "/");
 356                        basename = conf_def_filename;
 357                } else if ((slash = strrchr(name, '/'))) {
 358                        int size = slash - name + 1;
 359                        memcpy(dirname, name, size);
 360                        dirname[size] = 0;
 361                        if (slash[1])
 362                                basename = slash + 1;
 363                        else
 364                                basename = conf_def_filename;
 365                } else
 366                        basename = name;
 367        } else
 368                basename = conf_def_filename;
 369
 370        sprintf(newname, "%s.tmpconfig.%d", dirname, (int)getpid());
 371        out = fopen(newname, "w");
 372        if (!out)
 373                return 1;
 374        out_h = NULL;
 375        if (!name) {
 376                out_h = fopen(".tmpconfig.h", "w");
 377                if (!out_h)
 378                        return 1;
 379                file_write_dep(NULL);
 380        }
 381        sym = sym_lookup("KERNELVERSION", 0);
 382        sym_calc_value(sym);
 383
 384        source_date_epoch = getenv("SOURCE_DATE_EPOCH");
 385        if (source_date_epoch && *source_date_epoch) {
 386                now = strtoull(source_date_epoch, NULL, 10);
 387                build_time = gmtime(&now);
 388        } else {
 389                time(&now);
 390                build_time = localtime(&now);
 391        }
 392
 393        env = getenv("KCONFIG_NOTIMESTAMP");
 394        if (env && *env)
 395                use_timestamp = 0;
 396
 397        fprintf(out, _("#\n"
 398                       "# Automatically generated make config: don't edit\n"
 399                       "# Busybox version: %s\n"
 400                       "%s%s"
 401                       "#\n"),
 402                     sym_get_string_value(sym),
 403                     use_timestamp ? "# " : "",
 404                     use_timestamp ? ctime(&now) : "");
 405        if (out_h) {
 406                char buf[sizeof("#define AUTOCONF_TIMESTAMP "
 407                                "\"YYYY-MM-DD HH:MM:SS some_timezone\"\n")];
 408                buf[0] = '\0';
 409                if (use_timestamp) {
 410                        size_t ret = \
 411                                strftime(buf, sizeof(buf), "#define AUTOCONF_TIMESTAMP "
 412                                        "\"%Y-%m-%d %H:%M:%S %Z\"\n", build_time);
 413                        /* if user has Factory timezone or some other odd install, the
 414                         * %Z above will overflow the string leaving us with undefined
 415                         * results ... so let's try again without the timezone.
 416                         */
 417                        if (ret == 0)
 418                                strftime(buf, sizeof(buf), "#define AUTOCONF_TIMESTAMP "
 419                                        "\"%Y-%m-%d %H:%M:%S\"\n", build_time);
 420                } else { /* bbox */
 421                        strcpy(buf, "#define AUTOCONF_TIMESTAMP \"\"\n");
 422                }
 423                fprintf(out_h, "/*\n"
 424                               " * Automatically generated C config: don't edit\n"
 425                               " * Busybox version: %s\n"
 426                               " */\n"
 427                               "%s"
 428                               "\n",
 429                               sym_get_string_value(sym),
 430                               buf);
 431        }
 432        if (!sym_change_count)
 433                sym_clear_all_valid();
 434
 435        menu = rootmenu.list;
 436        while (menu) {
 437                sym = menu->sym;
 438                if (!sym) {
 439                        if (!menu_is_visible(menu))
 440                                goto next;
 441                        str = menu_get_prompt(menu);
 442                        fprintf(out, "\n"
 443                                     "#\n"
 444                                     "# %s\n"
 445                                     "#\n", str);
 446                        if (out_h)
 447                                fprintf(out_h, "\n"
 448                                               "/*\n"
 449                                               " * %s\n"
 450                                               " */\n", str);
 451                } else if (!(sym->flags & SYMBOL_CHOICE)) {
 452                        sym_calc_value(sym);
 453/* bbox: we want to see all syms
 454                        if (!(sym->flags & SYMBOL_WRITE))
 455                                goto next;
 456*/
 457                        sym->flags &= ~SYMBOL_WRITE;
 458                        type = sym->type;
 459                        if (type == S_TRISTATE) {
 460                                sym_calc_value(modules_sym);
 461                                if (modules_sym->curr.tri == no)
 462                                        type = S_BOOLEAN;
 463                        }
 464                        switch (type) {
 465                        case S_BOOLEAN:
 466                        case S_TRISTATE:
 467                                switch (sym_get_tristate_value(sym)) {
 468                                case no:
 469                                        fprintf(out, "# CONFIG_%s is not set\n", sym->name);
 470                                        if (out_h) {
 471                                                fprintf(out_h, "#undef CONFIG_%s\n", sym->name);
 472                                                /* bbox */
 473                                                fprintf(out_h, "#define ENABLE_%s 0\n", sym->name);
 474                                                fprintf(out_h, "#define IF_%s(...)\n", sym->name);
 475                                                fprintf(out_h, "#define IF_NOT_%s(...) __VA_ARGS__\n", sym->name);
 476                                        }
 477                                        break;
 478                                case mod:
 479                                        fprintf(out, "CONFIG_%s=m\n", sym->name);
 480                                        if (out_h)
 481                                                fprintf(out_h, "#define CONFIG_%s_MODULE 1\n", sym->name);
 482                                        break;
 483                                case yes:
 484                                        fprintf(out, "CONFIG_%s=y\n", sym->name);
 485                                        if (out_h) {
 486                                                fprintf(out_h, "#define CONFIG_%s 1\n", sym->name);
 487                                                /* bbox */
 488                                                fprintf(out_h, "#define ENABLE_%s 1\n", sym->name);
 489                                                fprintf(out_h, "#ifdef MAKE_SUID\n");
 490                                                fprintf(out_h, "# define IF_%s(...) __VA_ARGS__ \"CONFIG_%s\"\n", sym->name, sym->name);
 491                                                fprintf(out_h, "#else\n");
 492                                                fprintf(out_h, "# define IF_%s(...) __VA_ARGS__\n", sym->name);
 493                                                fprintf(out_h, "#endif\n");
 494                                                fprintf(out_h, "#define IF_NOT_%s(...)\n", sym->name);
 495                                        }
 496                                        break;
 497                                }
 498                                break;
 499                        case S_STRING:
 500                                // fix me
 501                                str = sym_get_string_value(sym);
 502                                fprintf(out, "CONFIG_%s=\"", sym->name);
 503                                if (out_h)
 504                                        fprintf(out_h, "#define CONFIG_%s \"", sym->name);
 505                                do {
 506                                        l = strcspn(str, "\"\\");
 507                                        if (l) {
 508                                                fwrite(str, l, 1, out);
 509                                                if (out_h)
 510                                                        fwrite(str, l, 1, out_h);
 511                                        }
 512                                        str += l;
 513                                        while (*str == '\\' || *str == '"') {
 514                                                fprintf(out, "\\%c", *str);
 515                                                if (out_h)
 516                                                        fprintf(out_h, "\\%c", *str);
 517                                                str++;
 518                                        }
 519                                } while (*str);
 520                                fputs("\"\n", out);
 521                                if (out_h) {
 522                                        fputs("\"\n", out_h);
 523                                        /* bbox */
 524                                        fprintf(out_h, "#define ENABLE_%s 1\n", sym->name);
 525                                        fprintf(out_h, "#ifdef MAKE_SUID\n");
 526                                        fprintf(out_h, "# define IF_%s(...) __VA_ARGS__ \"CONFIG_%s\"\n", sym->name, sym->name);
 527                                        fprintf(out_h, "#else\n");
 528                                        fprintf(out_h, "# define IF_%s(...) __VA_ARGS__\n", sym->name);
 529                                        fprintf(out_h, "#endif\n");
 530                                        fprintf(out_h, "#define IF_NOT_%s(...)\n", sym->name);
 531                                }
 532                                break;
 533                        case S_HEX:
 534                                str = sym_get_string_value(sym);
 535                                if (str[0] != '0' || (str[1] != 'x' && str[1] != 'X')) {
 536                                        fprintf(out, "CONFIG_%s=%s\n", sym->name, str);
 537                                        if (out_h) {
 538                                                fprintf(out_h, "#define CONFIG_%s 0x%s\n", sym->name, str);
 539                                                /* bbox */
 540                                                fprintf(out_h, "#define ENABLE_%s 1\n", sym->name);
 541                                                fprintf(out_h, "#ifdef MAKE_SUID\n");
 542                                                fprintf(out_h, "# define IF_%s(...) __VA_ARGS__ \"CONFIG_%s\"\n", sym->name, sym->name);
 543                                                fprintf(out_h, "#else\n");
 544                                                fprintf(out_h, "# define IF_%s(...) __VA_ARGS__\n", sym->name);
 545                                                fprintf(out_h, "#endif\n");
 546                                                fprintf(out_h, "#define IF_NOT_%s(...)\n", sym->name);
 547                                        }
 548                                        break;
 549                                }
 550                        case S_INT:
 551                                str = sym_get_string_value(sym);
 552                                if (!str[0])
 553                                        str = "0";
 554                                fprintf(out, "CONFIG_%s=%s\n", sym->name, str);
 555                                if (out_h) {
 556                                        fprintf(out_h, "#define CONFIG_%s %s\n", sym->name, str);
 557                                        /* bbox */
 558                                        fprintf(out_h, "#define ENABLE_%s 1\n", sym->name);
 559                                        fprintf(out_h, "#ifdef MAKE_SUID\n");
 560                                        fprintf(out_h, "# define IF_%s(...) __VA_ARGS__ \"CONFIG_%s\"\n", sym->name, sym->name);
 561                                        fprintf(out_h, "#else\n");
 562                                        fprintf(out_h, "# define IF_%s(...) __VA_ARGS__\n", sym->name);
 563                                        fprintf(out_h, "#endif\n");
 564                                        fprintf(out_h, "#define IF_NOT_%s(...)\n", sym->name);
 565                                }
 566                                break;
 567                        }
 568                }
 569
 570        next:
 571                if (menu->list) {
 572                        menu = menu->list;
 573                        continue;
 574                }
 575                if (menu->next)
 576                        menu = menu->next;
 577                else while ((menu = menu->parent)) {
 578                        if (menu->next) {
 579                                menu = menu->next;
 580                                break;
 581                        }
 582                }
 583        }
 584        fclose(out);
 585        if (out_h) {
 586                fclose(out_h);
 587                rename(".tmpconfig.h", "include/autoconf.h");
 588        }
 589        if (!name || basename != conf_def_filename) {
 590                if (!name)
 591                        name = conf_def_filename;
 592                sprintf(tmpname, "%s.old", name);
 593                rename(name, tmpname);
 594        }
 595        sprintf(tmpname, "%s%s", dirname, basename);
 596        if (rename(newname, tmpname))
 597                return 1;
 598
 599        sym_change_count = 0;
 600
 601        return 0;
 602}
 603