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
 377static int perf_config_bool_or_int(const char *name, const char *value, int *is_bool)
 378{
 379        int ret;
 380
 381        *is_bool = 1;
 382        if (!value)
 383                return 1;
 384        if (!*value)
 385                return 0;
 386        if (!strcasecmp(value, "true") || !strcasecmp(value, "yes") || !strcasecmp(value, "on"))
 387                return 1;
 388        if (!strcasecmp(value, "false") || !strcasecmp(value, "no") || !strcasecmp(value, "off"))
 389                return 0;
 390        *is_bool = 0;
 391        return perf_config_int(&ret, name, value) < 0 ? -1 : ret;
 392}
 393
 394int perf_config_bool(const char *name, const char *value)
 395{
 396        int discard;
 397        return !!perf_config_bool_or_int(name, value, &discard);
 398}
 399
 400static const char *perf_config_dirname(const char *name, const char *value)
 401{
 402        if (!name)
 403                return NULL;
 404        return value;
 405}
 406
 407static int perf_buildid_config(const char *var, const char *value)
 408{
 409        /* same dir for all commands */
 410        if (!strcmp(var, "buildid.dir")) {
 411                const char *dir = perf_config_dirname(var, value);
 412
 413                if (!dir) {
 414                        pr_err("Invalid buildid directory!\n");
 415                        return -1;
 416                }
 417                strncpy(buildid_dir, dir, MAXPATHLEN-1);
 418                buildid_dir[MAXPATHLEN-1] = '\0';
 419        }
 420
 421        return 0;
 422}
 423
 424static int perf_default_core_config(const char *var __maybe_unused,
 425                                    const char *value __maybe_unused)
 426{
 427        if (!strcmp(var, "core.proc-map-timeout"))
 428                proc_map_timeout = strtoul(value, NULL, 10);
 429
 430        /* Add other config variables here. */
 431        return 0;
 432}
 433
 434static int perf_ui_config(const char *var, const char *value)
 435{
 436        /* Add other config variables here. */
 437        if (!strcmp(var, "ui.show-headers"))
 438                symbol_conf.show_hist_headers = perf_config_bool(var, value);
 439
 440        return 0;
 441}
 442
 443int perf_default_config(const char *var, const char *value,
 444                        void *dummy __maybe_unused)
 445{
 446        if (strstarts(var, "core."))
 447                return perf_default_core_config(var, value);
 448
 449        if (strstarts(var, "hist."))
 450                return perf_hist_config(var, value);
 451
 452        if (strstarts(var, "ui."))
 453                return perf_ui_config(var, value);
 454
 455        if (strstarts(var, "call-graph."))
 456                return perf_callchain_config(var, value);
 457
 458        if (strstarts(var, "llvm."))
 459                return perf_llvm_config(var, value);
 460
 461        if (strstarts(var, "buildid."))
 462                return perf_buildid_config(var, value);
 463
 464        /* Add other config variables here. */
 465        return 0;
 466}
 467
 468static int perf_config_from_file(config_fn_t fn, const char *filename, void *data)
 469{
 470        int ret;
 471        FILE *f = fopen(filename, "r");
 472
 473        ret = -1;
 474        if (f) {
 475                config_file = f;
 476                config_file_name = filename;
 477                config_linenr = 1;
 478                config_file_eof = 0;
 479                ret = perf_parse_file(fn, data);
 480                fclose(f);
 481                config_file_name = NULL;
 482        }
 483        return ret;
 484}
 485
 486const char *perf_etc_perfconfig(void)
 487{
 488        static const char *system_wide;
 489        if (!system_wide)
 490                system_wide = system_path(ETC_PERFCONFIG);
 491        return system_wide;
 492}
 493
 494static int perf_env_bool(const char *k, int def)
 495{
 496        const char *v = getenv(k);
 497        return v ? perf_config_bool(k, v) : def;
 498}
 499
 500static int perf_config_system(void)
 501{
 502        return !perf_env_bool("PERF_CONFIG_NOSYSTEM", 0);
 503}
 504
 505static int perf_config_global(void)
 506{
 507        return !perf_env_bool("PERF_CONFIG_NOGLOBAL", 0);
 508}
 509
 510static struct perf_config_section *find_section(struct list_head *sections,
 511                                                const char *section_name)
 512{
 513        struct perf_config_section *section;
 514
 515        list_for_each_entry(section, sections, node)
 516                if (!strcmp(section->name, section_name))
 517                        return section;
 518
 519        return NULL;
 520}
 521
 522static struct perf_config_item *find_config_item(const char *name,
 523                                                 struct perf_config_section *section)
 524{
 525        struct perf_config_item *item;
 526
 527        list_for_each_entry(item, &section->items, node)
 528                if (!strcmp(item->name, name))
 529                        return item;
 530
 531        return NULL;
 532}
 533
 534static struct perf_config_section *add_section(struct list_head *sections,
 535                                               const char *section_name)
 536{
 537        struct perf_config_section *section = zalloc(sizeof(*section));
 538
 539        if (!section)
 540                return NULL;
 541
 542        INIT_LIST_HEAD(&section->items);
 543        section->name = strdup(section_name);
 544        if (!section->name) {
 545                pr_debug("%s: strdup failed\n", __func__);
 546                free(section);
 547                return NULL;
 548        }
 549
 550        list_add_tail(&section->node, sections);
 551        return section;
 552}
 553
 554static struct perf_config_item *add_config_item(struct perf_config_section *section,
 555                                                const char *name)
 556{
 557        struct perf_config_item *item = zalloc(sizeof(*item));
 558
 559        if (!item)
 560                return NULL;
 561
 562        item->name = strdup(name);
 563        if (!item->name) {
 564                pr_debug("%s: strdup failed\n", __func__);
 565                free(item);
 566                return NULL;
 567        }
 568
 569        list_add_tail(&item->node, &section->items);
 570        return item;
 571}
 572
 573static int set_value(struct perf_config_item *item, const char *value)
 574{
 575        char *val = strdup(value);
 576
 577        if (!val)
 578                return -1;
 579
 580        zfree(&item->value);
 581        item->value = val;
 582        return 0;
 583}
 584
 585static int collect_config(const char *var, const char *value,
 586                          void *perf_config_set)
 587{
 588        int ret = -1;
 589        char *ptr, *key;
 590        char *section_name, *name;
 591        struct perf_config_section *section = NULL;
 592        struct perf_config_item *item = NULL;
 593        struct perf_config_set *set = perf_config_set;
 594        struct list_head *sections;
 595
 596        if (set == NULL)
 597                return -1;
 598
 599        sections = &set->sections;
 600        key = ptr = strdup(var);
 601        if (!key) {
 602                pr_debug("%s: strdup failed\n", __func__);
 603                return -1;
 604        }
 605
 606        section_name = strsep(&ptr, ".");
 607        name = ptr;
 608        if (name == NULL || value == NULL)
 609                goto out_free;
 610
 611        section = find_section(sections, section_name);
 612        if (!section) {
 613                section = add_section(sections, section_name);
 614                if (!section)
 615                        goto out_free;
 616        }
 617
 618        item = find_config_item(name, section);
 619        if (!item) {
 620                item = add_config_item(section, name);
 621                if (!item)
 622                        goto out_free;
 623        }
 624
 625        /* perf_config_set can contain both user and system config items.
 626         * So we should know where each value is from.
 627         * The classification would be needed when a particular config file
 628         * is overwrited by setting feature i.e. set_config().
 629         */
 630        if (strcmp(config_file_name, perf_etc_perfconfig()) == 0) {
 631                section->from_system_config = true;
 632                item->from_system_config = true;
 633        } else {
 634                section->from_system_config = false;
 635                item->from_system_config = false;
 636        }
 637
 638        ret = set_value(item, value);
 639
 640out_free:
 641        free(key);
 642        return ret;
 643}
 644
 645int perf_config_set__collect(struct perf_config_set *set, const char *file_name,
 646                             const char *var, const char *value)
 647{
 648        config_file_name = file_name;
 649        return collect_config(var, value, set);
 650}
 651
 652static int perf_config_set__init(struct perf_config_set *set)
 653{
 654        int ret = -1;
 655        const char *home = NULL;
 656        char *user_config;
 657        struct stat st;
 658
 659        /* Setting $PERF_CONFIG makes perf read _only_ the given config file. */
 660        if (config_exclusive_filename)
 661                return perf_config_from_file(collect_config, config_exclusive_filename, set);
 662        if (perf_config_system() && !access(perf_etc_perfconfig(), R_OK)) {
 663                if (perf_config_from_file(collect_config, perf_etc_perfconfig(), set) < 0)
 664                        goto out;
 665        }
 666
 667        home = getenv("HOME");
 668
 669        /*
 670         * Skip reading user config if:
 671         *   - there is no place to read it from (HOME)
 672         *   - we are asked not to (PERF_CONFIG_NOGLOBAL=1)
 673         */
 674        if (!home || !*home || !perf_config_global())
 675                return 0;
 676
 677        user_config = strdup(mkpath("%s/.perfconfig", home));
 678        if (user_config == NULL) {
 679                pr_warning("Not enough memory to process %s/.perfconfig, ignoring it.", home);
 680                goto out;
 681        }
 682
 683        if (stat(user_config, &st) < 0) {
 684                if (errno == ENOENT)
 685                        ret = 0;
 686                goto out_free;
 687        }
 688
 689        ret = 0;
 690
 691        if (st.st_uid && (st.st_uid != geteuid())) {
 692                pr_warning("File %s not owned by current user or root, ignoring it.", user_config);
 693                goto out_free;
 694        }
 695
 696        if (st.st_size)
 697                ret = perf_config_from_file(collect_config, user_config, set);
 698
 699out_free:
 700        free(user_config);
 701out:
 702        return ret;
 703}
 704
 705struct perf_config_set *perf_config_set__new(void)
 706{
 707        struct perf_config_set *set = zalloc(sizeof(*set));
 708
 709        if (set) {
 710                INIT_LIST_HEAD(&set->sections);
 711                perf_config_set__init(set);
 712        }
 713
 714        return set;
 715}
 716
 717static int perf_config__init(void)
 718{
 719        if (config_set == NULL)
 720                config_set = perf_config_set__new();
 721
 722        return config_set == NULL;
 723}
 724
 725int perf_config(config_fn_t fn, void *data)
 726{
 727        int ret = 0;
 728        char key[BUFSIZ];
 729        struct perf_config_section *section;
 730        struct perf_config_item *item;
 731
 732        if (config_set == NULL && perf_config__init())
 733                return -1;
 734
 735        perf_config_set__for_each_entry(config_set, section, item) {
 736                char *value = item->value;
 737
 738                if (value) {
 739                        scnprintf(key, sizeof(key), "%s.%s",
 740                                  section->name, item->name);
 741                        ret = fn(key, value, data);
 742                        if (ret < 0) {
 743                                pr_err("Error: wrong config key-value pair %s=%s\n",
 744                                       key, value);
 745                                /*
 746                                 * Can't be just a 'break', as perf_config_set__for_each_entry()
 747                                 * expands to two nested for() loops.
 748                                 */
 749                                goto out;
 750                        }
 751                }
 752        }
 753out:
 754        return ret;
 755}
 756
 757void perf_config__exit(void)
 758{
 759        perf_config_set__delete(config_set);
 760        config_set = NULL;
 761}
 762
 763void perf_config__refresh(void)
 764{
 765        perf_config__exit();
 766        perf_config__init();
 767}
 768
 769static void perf_config_item__delete(struct perf_config_item *item)
 770{
 771        zfree(&item->name);
 772        zfree(&item->value);
 773        free(item);
 774}
 775
 776static void perf_config_section__purge(struct perf_config_section *section)
 777{
 778        struct perf_config_item *item, *tmp;
 779
 780        list_for_each_entry_safe(item, tmp, &section->items, node) {
 781                list_del_init(&item->node);
 782                perf_config_item__delete(item);
 783        }
 784}
 785
 786static void perf_config_section__delete(struct perf_config_section *section)
 787{
 788        perf_config_section__purge(section);
 789        zfree(&section->name);
 790        free(section);
 791}
 792
 793static void perf_config_set__purge(struct perf_config_set *set)
 794{
 795        struct perf_config_section *section, *tmp;
 796
 797        list_for_each_entry_safe(section, tmp, &set->sections, node) {
 798                list_del_init(&section->node);
 799                perf_config_section__delete(section);
 800        }
 801}
 802
 803void perf_config_set__delete(struct perf_config_set *set)
 804{
 805        if (set == NULL)
 806                return;
 807
 808        perf_config_set__purge(set);
 809        free(set);
 810}
 811
 812/*
 813 * Call this to report error for your variable that should not
 814 * get a boolean value (i.e. "[my] var" means "true").
 815 */
 816int config_error_nonbool(const char *var)
 817{
 818        pr_err("Missing value for '%s'", var);
 819        return -1;
 820}
 821
 822void set_buildid_dir(const char *dir)
 823{
 824        if (dir)
 825                scnprintf(buildid_dir, MAXPATHLEN, "%s", dir);
 826
 827        /* default to $HOME/.debug */
 828        if (buildid_dir[0] == '\0') {
 829                char *home = getenv("HOME");
 830
 831                if (home) {
 832                        snprintf(buildid_dir, MAXPATHLEN, "%s/%s",
 833                                 home, DEBUG_CACHE_DIR);
 834                } else {
 835                        strncpy(buildid_dir, DEBUG_CACHE_DIR, MAXPATHLEN-1);
 836                }
 837                buildid_dir[MAXPATHLEN-1] = '\0';
 838        }
 839        /* for communicating with external commands */
 840        setenv("PERF_BUILDID_DIR", buildid_dir, 1);
 841}
 842