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