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