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