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