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 die("bad config file line %d in %s", config_linenr, config_file_name); 279 } 280 281 static int parse_unit_factor(const char *end, unsigned long *val) 282 { 283 if (!*end) 284 return 1; 285 else if (!strcasecmp(end, "k")) { 286 *val *= 1024; 287 return 1; 288 } 289 else if (!strcasecmp(end, "m")) { 290 *val *= 1024 * 1024; 291 return 1; 292 } 293 else if (!strcasecmp(end, "g")) { 294 *val *= 1024 * 1024 * 1024; 295 return 1; 296 } 297 return 0; 298 } 299 300 static int perf_parse_llong(const char *value, long long *ret) 301 { 302 if (value && *value) { 303 char *end; 304 long long val = strtoll(value, &end, 0); 305 unsigned long factor = 1; 306 307 if (!parse_unit_factor(end, &factor)) 308 return 0; 309 *ret = val * factor; 310 return 1; 311 } 312 return 0; 313 } 314 315 static int perf_parse_long(const char *value, long *ret) 316 { 317 if (value && *value) { 318 char *end; 319 long val = strtol(value, &end, 0); 320 unsigned long factor = 1; 321 if (!parse_unit_factor(end, &factor)) 322 return 0; 323 *ret = val * factor; 324 return 1; 325 } 326 return 0; 327 } 328 329 static void die_bad_config(const char *name) 330 { 331 if (config_file_name) 332 die("bad config value for '%s' in %s", name, config_file_name); 333 die("bad config value for '%s'", name); 334 } 335 336 u64 perf_config_u64(const char *name, const char *value) 337 { 338 long long ret = 0; 339 340 if (!perf_parse_llong(value, &ret)) 341 die_bad_config(name); 342 return (u64) ret; 343 } 344 345 int perf_config_int(const char *name, const char *value) 346 { 347 long ret = 0; 348 if (!perf_parse_long(value, &ret)) 349 die_bad_config(name); 350 return ret; 351 } 352 353 static int perf_config_bool_or_int(const char *name, const char *value, int *is_bool) 354 { 355 *is_bool = 1; 356 if (!value) 357 return 1; 358 if (!*value) 359 return 0; 360 if (!strcasecmp(value, "true") || !strcasecmp(value, "yes") || !strcasecmp(value, "on")) 361 return 1; 362 if (!strcasecmp(value, "false") || !strcasecmp(value, "no") || !strcasecmp(value, "off")) 363 return 0; 364 *is_bool = 0; 365 return perf_config_int(name, value); 366 } 367 368 int perf_config_bool(const char *name, const char *value) 369 { 370 int discard; 371 return !!perf_config_bool_or_int(name, value, &discard); 372 } 373 374 const char *perf_config_dirname(const char *name, const char *value) 375 { 376 if (!name) 377 return NULL; 378 return value; 379 } 380 381 static int perf_buildid_config(const char *var, const char *value) 382 { 383 /* same dir for all commands */ 384 if (!strcmp(var, "buildid.dir")) { 385 const char *dir = perf_config_dirname(var, value); 386 387 if (!dir) 388 return -1; 389 strncpy(buildid_dir, dir, MAXPATHLEN-1); 390 buildid_dir[MAXPATHLEN-1] = '\0'; 391 } 392 393 return 0; 394 } 395 396 static int perf_default_core_config(const char *var __maybe_unused, 397 const char *value __maybe_unused) 398 { 399 /* Add other config variables here. */ 400 return 0; 401 } 402 403 static int perf_ui_config(const char *var, const char *value) 404 { 405 /* Add other config variables here. */ 406 if (!strcmp(var, "ui.show-headers")) { 407 symbol_conf.show_hist_headers = perf_config_bool(var, value); 408 return 0; 409 } 410 return 0; 411 } 412 413 int perf_default_config(const char *var, const char *value, 414 void *dummy __maybe_unused) 415 { 416 if (!prefixcmp(var, "core.")) 417 return perf_default_core_config(var, value); 418 419 if (!prefixcmp(var, "hist.")) 420 return perf_hist_config(var, value); 421 422 if (!prefixcmp(var, "ui.")) 423 return perf_ui_config(var, value); 424 425 if (!prefixcmp(var, "call-graph.")) 426 return perf_callchain_config(var, value); 427 428 if (!prefixcmp(var, "llvm.")) 429 return perf_llvm_config(var, value); 430 431 if (!prefixcmp(var, "buildid.")) 432 return perf_buildid_config(var, value); 433 434 /* Add other config variables here. */ 435 return 0; 436 } 437 438 static int perf_config_from_file(config_fn_t fn, const char *filename, void *data) 439 { 440 int ret; 441 FILE *f = fopen(filename, "r"); 442 443 ret = -1; 444 if (f) { 445 config_file = f; 446 config_file_name = filename; 447 config_linenr = 1; 448 config_file_eof = 0; 449 ret = perf_parse_file(fn, data); 450 fclose(f); 451 config_file_name = NULL; 452 } 453 return ret; 454 } 455 456 const char *perf_etc_perfconfig(void) 457 { 458 static const char *system_wide; 459 if (!system_wide) 460 system_wide = system_path(ETC_PERFCONFIG); 461 return system_wide; 462 } 463 464 static int perf_env_bool(const char *k, int def) 465 { 466 const char *v = getenv(k); 467 return v ? perf_config_bool(k, v) : def; 468 } 469 470 static int perf_config_system(void) 471 { 472 return !perf_env_bool("PERF_CONFIG_NOSYSTEM", 0); 473 } 474 475 static int perf_config_global(void) 476 { 477 return !perf_env_bool("PERF_CONFIG_NOGLOBAL", 0); 478 } 479 480 int perf_config(config_fn_t fn, void *data) 481 { 482 int ret = 0, found = 0; 483 const char *home = NULL; 484 485 /* Setting $PERF_CONFIG makes perf read _only_ the given config file. */ 486 if (config_exclusive_filename) 487 return perf_config_from_file(fn, config_exclusive_filename, data); 488 if (perf_config_system() && !access(perf_etc_perfconfig(), R_OK)) { 489 ret += perf_config_from_file(fn, perf_etc_perfconfig(), 490 data); 491 found += 1; 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 found += 1; 519 out_free: 520 free(user_config); 521 } 522 out: 523 if (found == 0) 524 return -1; 525 return ret; 526 } 527 528 static struct perf_config_section *find_section(struct list_head *sections, 529 const char *section_name) 530 { 531 struct perf_config_section *section; 532 533 list_for_each_entry(section, sections, node) 534 if (!strcmp(section->name, section_name)) 535 return section; 536 537 return NULL; 538 } 539 540 static struct perf_config_item *find_config_item(const char *name, 541 struct perf_config_section *section) 542 { 543 struct perf_config_item *item; 544 545 list_for_each_entry(item, §ion->items, node) 546 if (!strcmp(item->name, name)) 547 return item; 548 549 return NULL; 550 } 551 552 static struct perf_config_section *add_section(struct list_head *sections, 553 const char *section_name) 554 { 555 struct perf_config_section *section = zalloc(sizeof(*section)); 556 557 if (!section) 558 return NULL; 559 560 INIT_LIST_HEAD(§ion->items); 561 section->name = strdup(section_name); 562 if (!section->name) { 563 pr_debug("%s: strdup failed\n", __func__); 564 free(section); 565 return NULL; 566 } 567 568 list_add_tail(§ion->node, sections); 569 return section; 570 } 571 572 static struct perf_config_item *add_config_item(struct perf_config_section *section, 573 const char *name) 574 { 575 struct perf_config_item *item = zalloc(sizeof(*item)); 576 577 if (!item) 578 return NULL; 579 580 item->name = strdup(name); 581 if (!item->name) { 582 pr_debug("%s: strdup failed\n", __func__); 583 free(item); 584 return NULL; 585 } 586 587 list_add_tail(&item->node, §ion->items); 588 return item; 589 } 590 591 static int set_value(struct perf_config_item *item, const char *value) 592 { 593 char *val = strdup(value); 594 595 if (!val) 596 return -1; 597 598 zfree(&item->value); 599 item->value = val; 600 return 0; 601 } 602 603 static int collect_config(const char *var, const char *value, 604 void *perf_config_set) 605 { 606 int ret = -1; 607 char *ptr, *key; 608 char *section_name, *name; 609 struct perf_config_section *section = NULL; 610 struct perf_config_item *item = NULL; 611 struct perf_config_set *set = perf_config_set; 612 struct list_head *sections = &set->sections; 613 614 key = ptr = strdup(var); 615 if (!key) { 616 pr_debug("%s: strdup failed\n", __func__); 617 return -1; 618 } 619 620 section_name = strsep(&ptr, "."); 621 name = ptr; 622 if (name == NULL || value == NULL) 623 goto out_free; 624 625 section = find_section(sections, section_name); 626 if (!section) { 627 section = add_section(sections, section_name); 628 if (!section) 629 goto out_free; 630 } 631 632 item = find_config_item(name, section); 633 if (!item) { 634 item = add_config_item(section, name); 635 if (!item) 636 goto out_free; 637 } 638 639 ret = set_value(item, value); 640 return ret; 641 642 out_free: 643 free(key); 644 perf_config_set__delete(set); 645 return -1; 646 } 647 648 struct perf_config_set *perf_config_set__new(void) 649 { 650 struct perf_config_set *set = zalloc(sizeof(*set)); 651 652 if (set) { 653 INIT_LIST_HEAD(&set->sections); 654 perf_config(collect_config, set); 655 } 656 657 return set; 658 } 659 660 static void perf_config_item__delete(struct perf_config_item *item) 661 { 662 zfree(&item->name); 663 zfree(&item->value); 664 free(item); 665 } 666 667 static void perf_config_section__purge(struct perf_config_section *section) 668 { 669 struct perf_config_item *item, *tmp; 670 671 list_for_each_entry_safe(item, tmp, §ion->items, node) { 672 list_del_init(&item->node); 673 perf_config_item__delete(item); 674 } 675 } 676 677 static void perf_config_section__delete(struct perf_config_section *section) 678 { 679 perf_config_section__purge(section); 680 zfree(§ion->name); 681 free(section); 682 } 683 684 static void perf_config_set__purge(struct perf_config_set *set) 685 { 686 struct perf_config_section *section, *tmp; 687 688 list_for_each_entry_safe(section, tmp, &set->sections, node) { 689 list_del_init(§ion->node); 690 perf_config_section__delete(section); 691 } 692 } 693 694 void perf_config_set__delete(struct perf_config_set *set) 695 { 696 perf_config_set__purge(set); 697 free(set); 698 } 699 700 /* 701 * Call this to report error for your variable that should not 702 * get a boolean value (i.e. "[my] var" means "true"). 703 */ 704 int config_error_nonbool(const char *var) 705 { 706 return error("Missing value for '%s'", var); 707 } 708 709 void set_buildid_dir(const char *dir) 710 { 711 if (dir) 712 scnprintf(buildid_dir, MAXPATHLEN-1, "%s", dir); 713 714 /* default to $HOME/.debug */ 715 if (buildid_dir[0] == '\0') { 716 char *home = getenv("HOME"); 717 718 if (home) { 719 snprintf(buildid_dir, MAXPATHLEN-1, "%s/%s", 720 home, DEBUG_CACHE_DIR); 721 } else { 722 strncpy(buildid_dir, DEBUG_CACHE_DIR, MAXPATHLEN-1); 723 } 724 buildid_dir[MAXPATHLEN-1] = '\0'; 725 } 726 /* for communicating with external commands */ 727 setenv("PERF_BUILDID_DIR", buildid_dir, 1); 728 } 729