linux/tools/perf/util/config.c
<<
>>
Prefs
   1/*
   2 * config.c
   3 *
   4 * Helper functions for parsing config items.
   5 * Originally copied from GIT source.
   6 *
   7 * Copyright (C) Linus Torvalds, 2005
   8 * Copyright (C) Johannes Schindelin, 2005
   9 *
  10 */
  11#include "util.h"
  12#include "cache.h"
  13#include <subcmd/exec-cmd.h>
  14#include "util/hist.h"  /* perf_hist_config */
  15#include "util/llvm-utils.h"   /* perf_llvm_config */
  16#include "config.h"
  17
  18#define MAXNAME (256)
  19
  20#define DEBUG_CACHE_DIR ".debug"
  21
  22
  23char buildid_dir[MAXPATHLEN]; /* root dir for buildid, binary cache */
  24
  25static FILE *config_file;
  26static const char *config_file_name;
  27static int config_linenr;
  28static int config_file_eof;
  29
  30const char *config_exclusive_filename;
  31
  32static int get_next_char(void)
  33{
  34        int c;
  35        FILE *f;
  36
  37        c = '\n';
  38        if ((f = config_file) != NULL) {
  39                c = fgetc(f);
  40                if (c == '\r') {
  41                        /* DOS like systems */
  42                        c = fgetc(f);
  43                        if (c != '\n') {
  44                                ungetc(c, f);
  45                                c = '\r';
  46                        }
  47                }
  48                if (c == '\n')
  49                        config_linenr++;
  50                if (c == EOF) {
  51                        config_file_eof = 1;
  52                        c = '\n';
  53                }
  54        }
  55        return c;
  56}
  57
  58static char *parse_value(void)
  59{
  60        static char value[1024];
  61        int quote = 0, comment = 0, space = 0;
  62        size_t len = 0;
  63
  64        for (;;) {
  65                int c = get_next_char();
  66
  67                if (len >= sizeof(value) - 1)
  68                        return NULL;
  69                if (c == '\n') {
  70                        if (quote)
  71                                return NULL;
  72                        value[len] = 0;
  73                        return value;
  74                }
  75                if (comment)
  76                        continue;
  77                if (isspace(c) && !quote) {
  78                        space = 1;
  79                        continue;
  80                }
  81                if (!quote) {
  82                        if (c == ';' || c == '#') {
  83                                comment = 1;
  84                                continue;
  85                        }
  86                }
  87                if (space) {
  88                        if (len)
  89                                value[len++] = ' ';
  90                        space = 0;
  91                }
  92                if (c == '\\') {
  93                        c = get_next_char();
  94                        switch (c) {
  95                        case '\n':
  96                                continue;
  97                        case 't':
  98                                c = '\t';
  99                                break;
 100                        case 'b':
 101                                c = '\b';
 102                                break;
 103                        case 'n':
 104                                c = '\n';
 105                                break;
 106                        /* Some characters escape as themselves */
 107                        case '\\': case '"':
 108                                break;
 109                        /* Reject unknown escape sequences */
 110                        default:
 111                                return NULL;
 112                        }
 113                        value[len++] = c;
 114                        continue;
 115                }
 116                if (c == '"') {
 117                        quote = 1-quote;
 118                        continue;
 119                }
 120                value[len++] = c;
 121        }
 122}
 123
 124static inline int iskeychar(int c)
 125{
 126        return isalnum(c) || c == '-' || c == '_';
 127}
 128
 129static int get_value(config_fn_t fn, void *data, char *name, unsigned int len)
 130{
 131        int c;
 132        char *value;
 133
 134        /* Get the full name */
 135        for (;;) {
 136                c = get_next_char();
 137                if (config_file_eof)
 138                        break;
 139                if (!iskeychar(c))
 140                        break;
 141                name[len++] = c;
 142                if (len >= MAXNAME)
 143                        return -1;
 144        }
 145        name[len] = 0;
 146        while (c == ' ' || c == '\t')
 147                c = get_next_char();
 148
 149        value = NULL;
 150        if (c != '\n') {
 151                if (c != '=')
 152                        return -1;
 153                value = parse_value();
 154                if (!value)
 155                        return -1;
 156        }
 157        return fn(name, value, data);
 158}
 159
 160static int get_extended_base_var(char *name, int baselen, int c)
 161{
 162        do {
 163                if (c == '\n')
 164                        return -1;
 165                c = get_next_char();
 166        } while (isspace(c));
 167
 168        /* We require the format to be '[base "extension"]' */
 169        if (c != '"')
 170                return -1;
 171        name[baselen++] = '.';
 172
 173        for (;;) {
 174                int ch = get_next_char();
 175
 176                if (ch == '\n')
 177                        return -1;
 178                if (ch == '"')
 179                        break;
 180                if (ch == '\\') {
 181                        ch = get_next_char();
 182                        if (ch == '\n')
 183                                return -1;
 184                }
 185                name[baselen++] = ch;
 186                if (baselen > MAXNAME / 2)
 187                        return -1;
 188        }
 189
 190        /* Final ']' */
 191        if (get_next_char() != ']')
 192                return -1;
 193        return baselen;
 194}
 195
 196static int get_base_var(char *name)
 197{
 198        int baselen = 0;
 199
 200        for (;;) {
 201                int c = get_next_char();
 202                if (config_file_eof)
 203                        return -1;
 204                if (c == ']')
 205                        return baselen;
 206                if (isspace(c))
 207                        return get_extended_base_var(name, baselen, c);
 208                if (!iskeychar(c) && c != '.')
 209                        return -1;
 210                if (baselen > MAXNAME / 2)
 211                        return -1;
 212                name[baselen++] = tolower(c);
 213        }
 214}
 215
 216static int perf_parse_file(config_fn_t fn, void *data)
 217{
 218        int comment = 0;
 219        int baselen = 0;
 220        static char var[MAXNAME];
 221
 222        /* U+FEFF Byte Order Mark in UTF8 */
 223        static const unsigned char *utf8_bom = (unsigned char *) "\xef\xbb\xbf";
 224        const unsigned char *bomptr = utf8_bom;
 225
 226        for (;;) {
 227                int line, c = get_next_char();
 228
 229                if (bomptr && *bomptr) {
 230                        /* We are at the file beginning; skip UTF8-encoded BOM
 231                         * if present. Sane editors won't put this in on their
 232                         * own, but e.g. Windows Notepad will do it happily. */
 233                        if ((unsigned char) c == *bomptr) {
 234                                bomptr++;
 235                                continue;
 236                        } else {
 237                                /* Do not tolerate partial BOM. */
 238                                if (bomptr != utf8_bom)
 239                                        break;
 240                                /* No BOM at file beginning. Cool. */
 241                                bomptr = NULL;
 242                        }
 243                }
 244                if (c == '\n') {
 245                        if (config_file_eof)
 246                                return 0;
 247                        comment = 0;
 248                        continue;
 249                }
 250                if (comment || isspace(c))
 251                        continue;
 252                if (c == '#' || c == ';') {
 253                        comment = 1;
 254                        continue;
 255                }
 256                if (c == '[') {
 257                        baselen = get_base_var(var);
 258                        if (baselen <= 0)
 259                                break;
 260                        var[baselen++] = '.';
 261                        var[baselen] = 0;
 262                        continue;
 263                }
 264                if (!isalpha(c))
 265                        break;
 266                var[baselen] = tolower(c);
 267
 268                /*
 269                 * The get_value function might or might not reach the '\n',
 270                 * so saving the current line number for error reporting.
 271                 */
 272                line = config_linenr;
 273                if (get_value(fn, data, var, baselen+1) < 0) {
 274                        config_linenr = line;
 275                        break;
 276                }
 277        }
 278        die("bad config file line %d in %s", config_linenr, config_file_name);
 279}
 280
 281static int parse_unit_factor(const char *end, unsigned long *val)
 282{
 283        if (!*end)
 284                return 1;
 285        else if (!strcasecmp(end, "k")) {
 286                *val *= 1024;
 287                return 1;
 288        }
 289        else if (!strcasecmp(end, "m")) {
 290                *val *= 1024 * 1024;
 291                return 1;
 292        }
 293        else if (!strcasecmp(end, "g")) {
 294                *val *= 1024 * 1024 * 1024;
 295                return 1;
 296        }
 297        return 0;
 298}
 299
 300static int perf_parse_llong(const char *value, long long *ret)
 301{
 302        if (value && *value) {
 303                char *end;
 304                long long val = strtoll(value, &end, 0);
 305                unsigned long factor = 1;
 306
 307                if (!parse_unit_factor(end, &factor))
 308                        return 0;
 309                *ret = val * factor;
 310                return 1;
 311        }
 312        return 0;
 313}
 314
 315static int perf_parse_long(const char *value, long *ret)
 316{
 317        if (value && *value) {
 318                char *end;
 319                long val = strtol(value, &end, 0);
 320                unsigned long factor = 1;
 321                if (!parse_unit_factor(end, &factor))
 322                        return 0;
 323                *ret = val * factor;
 324                return 1;
 325        }
 326        return 0;
 327}
 328
 329static void die_bad_config(const char *name)
 330{
 331        if (config_file_name)
 332                die("bad config value for '%s' in %s", name, config_file_name);
 333        die("bad config value for '%s'", name);
 334}
 335
 336u64 perf_config_u64(const char *name, const char *value)
 337{
 338        long long ret = 0;
 339
 340        if (!perf_parse_llong(value, &ret))
 341                die_bad_config(name);
 342        return (u64) ret;
 343}
 344
 345int perf_config_int(const char *name, const char *value)
 346{
 347        long ret = 0;
 348        if (!perf_parse_long(value, &ret))
 349                die_bad_config(name);
 350        return ret;
 351}
 352
 353static int perf_config_bool_or_int(const char *name, const char *value, int *is_bool)
 354{
 355        *is_bool = 1;
 356        if (!value)
 357                return 1;
 358        if (!*value)
 359                return 0;
 360        if (!strcasecmp(value, "true") || !strcasecmp(value, "yes") || !strcasecmp(value, "on"))
 361                return 1;
 362        if (!strcasecmp(value, "false") || !strcasecmp(value, "no") || !strcasecmp(value, "off"))
 363                return 0;
 364        *is_bool = 0;
 365        return perf_config_int(name, value);
 366}
 367
 368int perf_config_bool(const char *name, const char *value)
 369{
 370        int discard;
 371        return !!perf_config_bool_or_int(name, value, &discard);
 372}
 373
 374const char *perf_config_dirname(const char *name, const char *value)
 375{
 376        if (!name)
 377                return NULL;
 378        return value;
 379}
 380
 381static int perf_buildid_config(const char *var, const char *value)
 382{
 383        /* same dir for all commands */
 384        if (!strcmp(var, "buildid.dir")) {
 385                const char *dir = perf_config_dirname(var, value);
 386
 387                if (!dir)
 388                        return -1;
 389                strncpy(buildid_dir, dir, MAXPATHLEN-1);
 390                buildid_dir[MAXPATHLEN-1] = '\0';
 391        }
 392
 393        return 0;
 394}
 395
 396static int perf_default_core_config(const char *var __maybe_unused,
 397                                    const char *value __maybe_unused)
 398{
 399        /* Add other config variables here. */
 400        return 0;
 401}
 402
 403static int perf_ui_config(const char *var, const char *value)
 404{
 405        /* Add other config variables here. */
 406        if (!strcmp(var, "ui.show-headers")) {
 407                symbol_conf.show_hist_headers = perf_config_bool(var, value);
 408                return 0;
 409        }
 410        return 0;
 411}
 412
 413int perf_default_config(const char *var, const char *value,
 414                        void *dummy __maybe_unused)
 415{
 416        if (!prefixcmp(var, "core."))
 417                return perf_default_core_config(var, value);
 418
 419        if (!prefixcmp(var, "hist."))
 420                return perf_hist_config(var, value);
 421
 422        if (!prefixcmp(var, "ui."))
 423                return perf_ui_config(var, value);
 424
 425        if (!prefixcmp(var, "call-graph."))
 426                return perf_callchain_config(var, value);
 427
 428        if (!prefixcmp(var, "llvm."))
 429                return perf_llvm_config(var, value);
 430
 431        if (!prefixcmp(var, "buildid."))
 432                return perf_buildid_config(var, value);
 433
 434        /* Add other config variables here. */
 435        return 0;
 436}
 437
 438static int perf_config_from_file(config_fn_t fn, const char *filename, void *data)
 439{
 440        int ret;
 441        FILE *f = fopen(filename, "r");
 442
 443        ret = -1;
 444        if (f) {
 445                config_file = f;
 446                config_file_name = filename;
 447                config_linenr = 1;
 448                config_file_eof = 0;
 449                ret = perf_parse_file(fn, data);
 450                fclose(f);
 451                config_file_name = NULL;
 452        }
 453        return ret;
 454}
 455
 456const char *perf_etc_perfconfig(void)
 457{
 458        static const char *system_wide;
 459        if (!system_wide)
 460                system_wide = system_path(ETC_PERFCONFIG);
 461        return system_wide;
 462}
 463
 464static int perf_env_bool(const char *k, int def)
 465{
 466        const char *v = getenv(k);
 467        return v ? perf_config_bool(k, v) : def;
 468}
 469
 470static int perf_config_system(void)
 471{
 472        return !perf_env_bool("PERF_CONFIG_NOSYSTEM", 0);
 473}
 474
 475static int perf_config_global(void)
 476{
 477        return !perf_env_bool("PERF_CONFIG_NOGLOBAL", 0);
 478}
 479
 480int perf_config(config_fn_t fn, void *data)
 481{
 482        int ret = 0, found = 0;
 483        const char *home = NULL;
 484
 485        /* Setting $PERF_CONFIG makes perf read _only_ the given config file. */
 486        if (config_exclusive_filename)
 487                return perf_config_from_file(fn, config_exclusive_filename, data);
 488        if (perf_config_system() && !access(perf_etc_perfconfig(), R_OK)) {
 489                ret += perf_config_from_file(fn, perf_etc_perfconfig(),
 490                                            data);
 491                found += 1;
 492        }
 493
 494        home = getenv("HOME");
 495        if (perf_config_global() && home) {
 496                char *user_config = strdup(mkpath("%s/.perfconfig", home));
 497                struct stat st;
 498
 499                if (user_config == NULL) {
 500                        warning("Not enough memory to process %s/.perfconfig, "
 501                                "ignoring it.", home);
 502                        goto out;
 503                }
 504
 505                if (stat(user_config, &st) < 0)
 506                        goto out_free;
 507
 508                if (st.st_uid && (st.st_uid != geteuid())) {
 509                        warning("File %s not owned by current user or root, "
 510                                "ignoring it.", user_config);
 511                        goto out_free;
 512                }
 513
 514                if (!st.st_size)
 515                        goto out_free;
 516
 517                ret += perf_config_from_file(fn, user_config, data);
 518                found += 1;
 519out_free:
 520                free(user_config);
 521        }
 522out:
 523        if (found == 0)
 524                return -1;
 525        return ret;
 526}
 527
 528static struct perf_config_section *find_section(struct list_head *sections,
 529                                                const char *section_name)
 530{
 531        struct perf_config_section *section;
 532
 533        list_for_each_entry(section, sections, node)
 534                if (!strcmp(section->name, section_name))
 535                        return section;
 536
 537        return NULL;
 538}
 539
 540static struct perf_config_item *find_config_item(const char *name,
 541                                                 struct perf_config_section *section)
 542{
 543        struct perf_config_item *item;
 544
 545        list_for_each_entry(item, &section->items, node)
 546                if (!strcmp(item->name, name))
 547                        return item;
 548
 549        return NULL;
 550}
 551
 552static struct perf_config_section *add_section(struct list_head *sections,
 553                                               const char *section_name)
 554{
 555        struct perf_config_section *section = zalloc(sizeof(*section));
 556
 557        if (!section)
 558                return NULL;
 559
 560        INIT_LIST_HEAD(&section->items);
 561        section->name = strdup(section_name);
 562        if (!section->name) {
 563                pr_debug("%s: strdup failed\n", __func__);
 564                free(section);
 565                return NULL;
 566        }
 567
 568        list_add_tail(&section->node, sections);
 569        return section;
 570}
 571
 572static struct perf_config_item *add_config_item(struct perf_config_section *section,
 573                                                const char *name)
 574{
 575        struct perf_config_item *item = zalloc(sizeof(*item));
 576
 577        if (!item)
 578                return NULL;
 579
 580        item->name = strdup(name);
 581        if (!item->name) {
 582                pr_debug("%s: strdup failed\n", __func__);
 583                free(item);
 584                return NULL;
 585        }
 586
 587        list_add_tail(&item->node, &section->items);
 588        return item;
 589}
 590
 591static int set_value(struct perf_config_item *item, const char *value)
 592{
 593        char *val = strdup(value);
 594
 595        if (!val)
 596                return -1;
 597
 598        zfree(&item->value);
 599        item->value = val;
 600        return 0;
 601}
 602
 603static int collect_config(const char *var, const char *value,
 604                          void *perf_config_set)
 605{
 606        int ret = -1;
 607        char *ptr, *key;
 608        char *section_name, *name;
 609        struct perf_config_section *section = NULL;
 610        struct perf_config_item *item = NULL;
 611        struct perf_config_set *set = perf_config_set;
 612        struct list_head *sections = &set->sections;
 613
 614        key = ptr = strdup(var);
 615        if (!key) {
 616                pr_debug("%s: strdup failed\n", __func__);
 617                return -1;
 618        }
 619
 620        section_name = strsep(&ptr, ".");
 621        name = ptr;
 622        if (name == NULL || value == NULL)
 623                goto out_free;
 624
 625        section = find_section(sections, section_name);
 626        if (!section) {
 627                section = add_section(sections, section_name);
 628                if (!section)
 629                        goto out_free;
 630        }
 631
 632        item = find_config_item(name, section);
 633        if (!item) {
 634                item = add_config_item(section, name);
 635                if (!item)
 636                        goto out_free;
 637        }
 638
 639        ret = set_value(item, value);
 640        return ret;
 641
 642out_free:
 643        free(key);
 644        perf_config_set__delete(set);
 645        return -1;
 646}
 647
 648struct perf_config_set *perf_config_set__new(void)
 649{
 650        struct perf_config_set *set = zalloc(sizeof(*set));
 651
 652        if (set) {
 653                INIT_LIST_HEAD(&set->sections);
 654                perf_config(collect_config, set);
 655        }
 656
 657        return set;
 658}
 659
 660static void perf_config_item__delete(struct perf_config_item *item)
 661{
 662        zfree(&item->name);
 663        zfree(&item->value);
 664        free(item);
 665}
 666
 667static void perf_config_section__purge(struct perf_config_section *section)
 668{
 669        struct perf_config_item *item, *tmp;
 670
 671        list_for_each_entry_safe(item, tmp, &section->items, node) {
 672                list_del_init(&item->node);
 673                perf_config_item__delete(item);
 674        }
 675}
 676
 677static void perf_config_section__delete(struct perf_config_section *section)
 678{
 679        perf_config_section__purge(section);
 680        zfree(&section->name);
 681        free(section);
 682}
 683
 684static void perf_config_set__purge(struct perf_config_set *set)
 685{
 686        struct perf_config_section *section, *tmp;
 687
 688        list_for_each_entry_safe(section, tmp, &set->sections, node) {
 689                list_del_init(&section->node);
 690                perf_config_section__delete(section);
 691        }
 692}
 693
 694void perf_config_set__delete(struct perf_config_set *set)
 695{
 696        perf_config_set__purge(set);
 697        free(set);
 698}
 699
 700/*
 701 * Call this to report error for your variable that should not
 702 * get a boolean value (i.e. "[my] var" means "true").
 703 */
 704int config_error_nonbool(const char *var)
 705{
 706        return error("Missing value for '%s'", var);
 707}
 708
 709void set_buildid_dir(const char *dir)
 710{
 711        if (dir)
 712                scnprintf(buildid_dir, MAXPATHLEN-1, "%s", dir);
 713
 714        /* default to $HOME/.debug */
 715        if (buildid_dir[0] == '\0') {
 716                char *home = getenv("HOME");
 717
 718                if (home) {
 719                        snprintf(buildid_dir, MAXPATHLEN-1, "%s/%s",
 720                                 home, DEBUG_CACHE_DIR);
 721                } else {
 722                        strncpy(buildid_dir, DEBUG_CACHE_DIR, MAXPATHLEN-1);
 723                }
 724                buildid_dir[MAXPATHLEN-1] = '\0';
 725        }
 726        /* for communicating with external commands */
 727        setenv("PERF_BUILDID_DIR", buildid_dir, 1);
 728}
 729