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