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