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