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