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