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 "util/stat.h"  /* perf_stat__set_big_num */
  21#include "build-id.h"
  22#include "debug.h"
  23#include "config.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
 455static int perf_stat_config(const char *var, const char *value)
 456{
 457        if (!strcmp(var, "stat.big-num"))
 458                perf_stat__set_big_num(perf_config_bool(var, value));
 459
 460        /* Add other config variables here. */
 461        return 0;
 462}
 463
 464int perf_default_config(const char *var, const char *value,
 465                        void *dummy __maybe_unused)
 466{
 467        if (strstarts(var, "core."))
 468                return perf_default_core_config(var, value);
 469
 470        if (strstarts(var, "hist."))
 471                return perf_hist_config(var, value);
 472
 473        if (strstarts(var, "ui."))
 474                return perf_ui_config(var, value);
 475
 476        if (strstarts(var, "call-graph."))
 477                return perf_callchain_config(var, value);
 478
 479        if (strstarts(var, "llvm."))
 480                return perf_llvm_config(var, value);
 481
 482        if (strstarts(var, "buildid."))
 483                return perf_buildid_config(var, value);
 484
 485        if (strstarts(var, "stat."))
 486                return perf_stat_config(var, value);
 487
 488        /* Add other config variables here. */
 489        return 0;
 490}
 491
 492static int perf_config_from_file(config_fn_t fn, const char *filename, void *data)
 493{
 494        int ret;
 495        FILE *f = fopen(filename, "r");
 496
 497        ret = -1;
 498        if (f) {
 499                config_file = f;
 500                config_file_name = filename;
 501                config_linenr = 1;
 502                config_file_eof = 0;
 503                ret = perf_parse_file(fn, data);
 504                fclose(f);
 505                config_file_name = NULL;
 506        }
 507        return ret;
 508}
 509
 510const char *perf_etc_perfconfig(void)
 511{
 512        static const char *system_wide;
 513        if (!system_wide)
 514                system_wide = system_path(ETC_PERFCONFIG);
 515        return system_wide;
 516}
 517
 518static int perf_env_bool(const char *k, int def)
 519{
 520        const char *v = getenv(k);
 521        return v ? perf_config_bool(k, v) : def;
 522}
 523
 524int perf_config_system(void)
 525{
 526        return !perf_env_bool("PERF_CONFIG_NOSYSTEM", 0);
 527}
 528
 529int perf_config_global(void)
 530{
 531        return !perf_env_bool("PERF_CONFIG_NOGLOBAL", 0);
 532}
 533
 534static char *home_perfconfig(void)
 535{
 536        const char *home = NULL;
 537        char *config;
 538        struct stat st;
 539
 540        home = getenv("HOME");
 541
 542        /*
 543         * Skip reading user config if:
 544         *   - there is no place to read it from (HOME)
 545         *   - we are asked not to (PERF_CONFIG_NOGLOBAL=1)
 546         */
 547        if (!home || !*home || !perf_config_global())
 548                return NULL;
 549
 550        config = strdup(mkpath("%s/.perfconfig", home));
 551        if (config == NULL) {
 552                pr_warning("Not enough memory to process %s/.perfconfig, ignoring it.", home);
 553                return NULL;
 554        }
 555
 556        if (stat(config, &st) < 0)
 557                goto out_free;
 558
 559        if (st.st_uid && (st.st_uid != geteuid())) {
 560                pr_warning("File %s not owned by current user or root, ignoring it.", config);
 561                goto out_free;
 562        }
 563
 564        if (st.st_size)
 565                return config;
 566
 567out_free:
 568        free(config);
 569        return NULL;
 570}
 571
 572const char *perf_home_perfconfig(void)
 573{
 574        static const char *config;
 575        static bool failed;
 576
 577        config = failed ? NULL : home_perfconfig();
 578        if (!config)
 579                failed = true;
 580
 581        return config;
 582}
 583
 584static struct perf_config_section *find_section(struct list_head *sections,
 585                                                const char *section_name)
 586{
 587        struct perf_config_section *section;
 588
 589        list_for_each_entry(section, sections, node)
 590                if (!strcmp(section->name, section_name))
 591                        return section;
 592
 593        return NULL;
 594}
 595
 596static struct perf_config_item *find_config_item(const char *name,
 597                                                 struct perf_config_section *section)
 598{
 599        struct perf_config_item *item;
 600
 601        list_for_each_entry(item, &section->items, node)
 602                if (!strcmp(item->name, name))
 603                        return item;
 604
 605        return NULL;
 606}
 607
 608static struct perf_config_section *add_section(struct list_head *sections,
 609                                               const char *section_name)
 610{
 611        struct perf_config_section *section = zalloc(sizeof(*section));
 612
 613        if (!section)
 614                return NULL;
 615
 616        INIT_LIST_HEAD(&section->items);
 617        section->name = strdup(section_name);
 618        if (!section->name) {
 619                pr_debug("%s: strdup failed\n", __func__);
 620                free(section);
 621                return NULL;
 622        }
 623
 624        list_add_tail(&section->node, sections);
 625        return section;
 626}
 627
 628static struct perf_config_item *add_config_item(struct perf_config_section *section,
 629                                                const char *name)
 630{
 631        struct perf_config_item *item = zalloc(sizeof(*item));
 632
 633        if (!item)
 634                return NULL;
 635
 636        item->name = strdup(name);
 637        if (!item->name) {
 638                pr_debug("%s: strdup failed\n", __func__);
 639                free(item);
 640                return NULL;
 641        }
 642
 643        list_add_tail(&item->node, &section->items);
 644        return item;
 645}
 646
 647static int set_value(struct perf_config_item *item, const char *value)
 648{
 649        char *val = strdup(value);
 650
 651        if (!val)
 652                return -1;
 653
 654        zfree(&item->value);
 655        item->value = val;
 656        return 0;
 657}
 658
 659static int collect_config(const char *var, const char *value,
 660                          void *perf_config_set)
 661{
 662        int ret = -1;
 663        char *ptr, *key;
 664        char *section_name, *name;
 665        struct perf_config_section *section = NULL;
 666        struct perf_config_item *item = NULL;
 667        struct perf_config_set *set = perf_config_set;
 668        struct list_head *sections;
 669
 670        if (set == NULL)
 671                return -1;
 672
 673        sections = &set->sections;
 674        key = ptr = strdup(var);
 675        if (!key) {
 676                pr_debug("%s: strdup failed\n", __func__);
 677                return -1;
 678        }
 679
 680        section_name = strsep(&ptr, ".");
 681        name = ptr;
 682        if (name == NULL || value == NULL)
 683                goto out_free;
 684
 685        section = find_section(sections, section_name);
 686        if (!section) {
 687                section = add_section(sections, section_name);
 688                if (!section)
 689                        goto out_free;
 690        }
 691
 692        item = find_config_item(name, section);
 693        if (!item) {
 694                item = add_config_item(section, name);
 695                if (!item)
 696                        goto out_free;
 697        }
 698
 699        /* perf_config_set can contain both user and system config items.
 700         * So we should know where each value is from.
 701         * The classification would be needed when a particular config file
 702         * is overwrited by setting feature i.e. set_config().
 703         */
 704        if (strcmp(config_file_name, perf_etc_perfconfig()) == 0) {
 705                section->from_system_config = true;
 706                item->from_system_config = true;
 707        } else {
 708                section->from_system_config = false;
 709                item->from_system_config = false;
 710        }
 711
 712        ret = set_value(item, value);
 713
 714out_free:
 715        free(key);
 716        return ret;
 717}
 718
 719int perf_config_set__collect(struct perf_config_set *set, const char *file_name,
 720                             const char *var, const char *value)
 721{
 722        config_file_name = file_name;
 723        return collect_config(var, value, set);
 724}
 725
 726static int perf_config_set__init(struct perf_config_set *set)
 727{
 728        int ret = -1;
 729
 730        /* Setting $PERF_CONFIG makes perf read _only_ the given config file. */
 731        if (config_exclusive_filename)
 732                return perf_config_from_file(collect_config, config_exclusive_filename, set);
 733        if (perf_config_system() && !access(perf_etc_perfconfig(), R_OK)) {
 734                if (perf_config_from_file(collect_config, perf_etc_perfconfig(), set) < 0)
 735                        goto out;
 736        }
 737        if (perf_config_global() && perf_home_perfconfig()) {
 738                if (perf_config_from_file(collect_config, perf_home_perfconfig(), set) < 0)
 739                        goto out;
 740        }
 741
 742out:
 743        return ret;
 744}
 745
 746struct perf_config_set *perf_config_set__new(void)
 747{
 748        struct perf_config_set *set = zalloc(sizeof(*set));
 749
 750        if (set) {
 751                INIT_LIST_HEAD(&set->sections);
 752                perf_config_set__init(set);
 753        }
 754
 755        return set;
 756}
 757
 758struct perf_config_set *perf_config_set__load_file(const char *file)
 759{
 760        struct perf_config_set *set = zalloc(sizeof(*set));
 761
 762        if (set) {
 763                INIT_LIST_HEAD(&set->sections);
 764                perf_config_from_file(collect_config, file, set);
 765        }
 766
 767        return set;
 768}
 769
 770static int perf_config__init(void)
 771{
 772        if (config_set == NULL)
 773                config_set = perf_config_set__new();
 774
 775        return config_set == NULL;
 776}
 777
 778int perf_config_set(struct perf_config_set *set,
 779                    config_fn_t fn, void *data)
 780{
 781        int ret = 0;
 782        char key[BUFSIZ];
 783        struct perf_config_section *section;
 784        struct perf_config_item *item;
 785
 786        perf_config_set__for_each_entry(set, section, item) {
 787                char *value = item->value;
 788
 789                if (value) {
 790                        scnprintf(key, sizeof(key), "%s.%s",
 791                                  section->name, item->name);
 792                        ret = fn(key, value, data);
 793                        if (ret < 0) {
 794                                pr_err("Error: wrong config key-value pair %s=%s\n",
 795                                       key, value);
 796                                /*
 797                                 * Can't be just a 'break', as perf_config_set__for_each_entry()
 798                                 * expands to two nested for() loops.
 799                                 */
 800                                goto out;
 801                        }
 802                }
 803        }
 804out:
 805        return ret;
 806}
 807
 808int perf_config(config_fn_t fn, void *data)
 809{
 810        if (config_set == NULL && perf_config__init())
 811                return -1;
 812
 813        return perf_config_set(config_set, fn, data);
 814}
 815
 816void perf_config__exit(void)
 817{
 818        perf_config_set__delete(config_set);
 819        config_set = NULL;
 820}
 821
 822void perf_config__refresh(void)
 823{
 824        perf_config__exit();
 825        perf_config__init();
 826}
 827
 828static void perf_config_item__delete(struct perf_config_item *item)
 829{
 830        zfree(&item->name);
 831        zfree(&item->value);
 832        free(item);
 833}
 834
 835static void perf_config_section__purge(struct perf_config_section *section)
 836{
 837        struct perf_config_item *item, *tmp;
 838
 839        list_for_each_entry_safe(item, tmp, &section->items, node) {
 840                list_del_init(&item->node);
 841                perf_config_item__delete(item);
 842        }
 843}
 844
 845static void perf_config_section__delete(struct perf_config_section *section)
 846{
 847        perf_config_section__purge(section);
 848        zfree(&section->name);
 849        free(section);
 850}
 851
 852static void perf_config_set__purge(struct perf_config_set *set)
 853{
 854        struct perf_config_section *section, *tmp;
 855
 856        list_for_each_entry_safe(section, tmp, &set->sections, node) {
 857                list_del_init(&section->node);
 858                perf_config_section__delete(section);
 859        }
 860}
 861
 862void perf_config_set__delete(struct perf_config_set *set)
 863{
 864        if (set == NULL)
 865                return;
 866
 867        perf_config_set__purge(set);
 868        free(set);
 869}
 870
 871/*
 872 * Call this to report error for your variable that should not
 873 * get a boolean value (i.e. "[my] var" means "true").
 874 */
 875int config_error_nonbool(const char *var)
 876{
 877        pr_err("Missing value for '%s'", var);
 878        return -1;
 879}
 880
 881void set_buildid_dir(const char *dir)
 882{
 883        if (dir)
 884                scnprintf(buildid_dir, MAXPATHLEN, "%s", dir);
 885
 886        /* default to $HOME/.debug */
 887        if (buildid_dir[0] == '\0') {
 888                char *home = getenv("HOME");
 889
 890                if (home) {
 891                        snprintf(buildid_dir, MAXPATHLEN, "%s/%s",
 892                                 home, DEBUG_CACHE_DIR);
 893                } else {
 894                        strncpy(buildid_dir, DEBUG_CACHE_DIR, MAXPATHLEN-1);
 895                }
 896                buildid_dir[MAXPATHLEN-1] = '\0';
 897        }
 898        /* for communicating with external commands */
 899        setenv("PERF_BUILDID_DIR", buildid_dir, 1);
 900}
 901