1 /* 2 * GIT - The information manager from hell 3 * 4 * Copyright (C) Linus Torvalds, 2005 5 * Copyright (C) Johannes Schindelin, 2005 6 * 7 */ 8 #include "util.h" 9 #include "cache.h" 10 #include "exec_cmd.h" 11 12 #define MAXNAME (256) 13 14 static FILE *config_file; 15 static const char *config_file_name; 16 static int config_linenr; 17 static int config_file_eof; 18 19 const char *config_exclusive_filename = NULL; 20 21 static int get_next_char(void) 22 { 23 int c; 24 FILE *f; 25 26 c = '\n'; 27 if ((f = config_file) != NULL) { 28 c = fgetc(f); 29 if (c == '\r') { 30 /* DOS like systems */ 31 c = fgetc(f); 32 if (c != '\n') { 33 ungetc(c, f); 34 c = '\r'; 35 } 36 } 37 if (c == '\n') 38 config_linenr++; 39 if (c == EOF) { 40 config_file_eof = 1; 41 c = '\n'; 42 } 43 } 44 return c; 45 } 46 47 static char *parse_value(void) 48 { 49 static char value[1024]; 50 int quote = 0, comment = 0, len = 0, space = 0; 51 52 for (;;) { 53 int c = get_next_char(); 54 if (len >= sizeof(value) - 1) 55 return NULL; 56 if (c == '\n') { 57 if (quote) 58 return NULL; 59 value[len] = 0; 60 return value; 61 } 62 if (comment) 63 continue; 64 if (isspace(c) && !quote) { 65 space = 1; 66 continue; 67 } 68 if (!quote) { 69 if (c == ';' || c == '#') { 70 comment = 1; 71 continue; 72 } 73 } 74 if (space) { 75 if (len) 76 value[len++] = ' '; 77 space = 0; 78 } 79 if (c == '\\') { 80 c = get_next_char(); 81 switch (c) { 82 case '\n': 83 continue; 84 case 't': 85 c = '\t'; 86 break; 87 case 'b': 88 c = '\b'; 89 break; 90 case 'n': 91 c = '\n'; 92 break; 93 /* Some characters escape as themselves */ 94 case '\\': case '"': 95 break; 96 /* Reject unknown escape sequences */ 97 default: 98 return NULL; 99 } 100 value[len++] = c; 101 continue; 102 } 103 if (c == '"') { 104 quote = 1-quote; 105 continue; 106 } 107 value[len++] = c; 108 } 109 } 110 111 static inline int iskeychar(int c) 112 { 113 return isalnum(c) || c == '-'; 114 } 115 116 static int get_value(config_fn_t fn, void *data, char *name, unsigned int len) 117 { 118 int c; 119 char *value; 120 121 /* Get the full name */ 122 for (;;) { 123 c = get_next_char(); 124 if (config_file_eof) 125 break; 126 if (!iskeychar(c)) 127 break; 128 name[len++] = tolower(c); 129 if (len >= MAXNAME) 130 return -1; 131 } 132 name[len] = 0; 133 while (c == ' ' || c == '\t') 134 c = get_next_char(); 135 136 value = NULL; 137 if (c != '\n') { 138 if (c != '=') 139 return -1; 140 value = parse_value(); 141 if (!value) 142 return -1; 143 } 144 return fn(name, value, data); 145 } 146 147 static int get_extended_base_var(char *name, int baselen, int c) 148 { 149 do { 150 if (c == '\n') 151 return -1; 152 c = get_next_char(); 153 } while (isspace(c)); 154 155 /* We require the format to be '[base "extension"]' */ 156 if (c != '"') 157 return -1; 158 name[baselen++] = '.'; 159 160 for (;;) { 161 int c = get_next_char(); 162 if (c == '\n') 163 return -1; 164 if (c == '"') 165 break; 166 if (c == '\\') { 167 c = get_next_char(); 168 if (c == '\n') 169 return -1; 170 } 171 name[baselen++] = c; 172 if (baselen > MAXNAME / 2) 173 return -1; 174 } 175 176 /* Final ']' */ 177 if (get_next_char() != ']') 178 return -1; 179 return baselen; 180 } 181 182 static int get_base_var(char *name) 183 { 184 int baselen = 0; 185 186 for (;;) { 187 int c = get_next_char(); 188 if (config_file_eof) 189 return -1; 190 if (c == ']') 191 return baselen; 192 if (isspace(c)) 193 return get_extended_base_var(name, baselen, c); 194 if (!iskeychar(c) && c != '.') 195 return -1; 196 if (baselen > MAXNAME / 2) 197 return -1; 198 name[baselen++] = tolower(c); 199 } 200 } 201 202 static int perf_parse_file(config_fn_t fn, void *data) 203 { 204 int comment = 0; 205 int baselen = 0; 206 static char var[MAXNAME]; 207 208 /* U+FEFF Byte Order Mark in UTF8 */ 209 static const unsigned char *utf8_bom = (unsigned char *) "\xef\xbb\xbf"; 210 const unsigned char *bomptr = utf8_bom; 211 212 for (;;) { 213 int c = get_next_char(); 214 if (bomptr && *bomptr) { 215 /* We are at the file beginning; skip UTF8-encoded BOM 216 * if present. Sane editors won't put this in on their 217 * own, but e.g. Windows Notepad will do it happily. */ 218 if ((unsigned char) c == *bomptr) { 219 bomptr++; 220 continue; 221 } else { 222 /* Do not tolerate partial BOM. */ 223 if (bomptr != utf8_bom) 224 break; 225 /* No BOM at file beginning. Cool. */ 226 bomptr = NULL; 227 } 228 } 229 if (c == '\n') { 230 if (config_file_eof) 231 return 0; 232 comment = 0; 233 continue; 234 } 235 if (comment || isspace(c)) 236 continue; 237 if (c == '#' || c == ';') { 238 comment = 1; 239 continue; 240 } 241 if (c == '[') { 242 baselen = get_base_var(var); 243 if (baselen <= 0) 244 break; 245 var[baselen++] = '.'; 246 var[baselen] = 0; 247 continue; 248 } 249 if (!isalpha(c)) 250 break; 251 var[baselen] = tolower(c); 252 if (get_value(fn, data, var, baselen+1) < 0) 253 break; 254 } 255 die("bad config file line %d in %s", config_linenr, config_file_name); 256 } 257 258 static int parse_unit_factor(const char *end, unsigned long *val) 259 { 260 if (!*end) 261 return 1; 262 else if (!strcasecmp(end, "k")) { 263 *val *= 1024; 264 return 1; 265 } 266 else if (!strcasecmp(end, "m")) { 267 *val *= 1024 * 1024; 268 return 1; 269 } 270 else if (!strcasecmp(end, "g")) { 271 *val *= 1024 * 1024 * 1024; 272 return 1; 273 } 274 return 0; 275 } 276 277 static int perf_parse_long(const char *value, long *ret) 278 { 279 if (value && *value) { 280 char *end; 281 long val = strtol(value, &end, 0); 282 unsigned long factor = 1; 283 if (!parse_unit_factor(end, &factor)) 284 return 0; 285 *ret = val * factor; 286 return 1; 287 } 288 return 0; 289 } 290 291 int perf_parse_ulong(const char *value, unsigned long *ret) 292 { 293 if (value && *value) { 294 char *end; 295 unsigned long val = strtoul(value, &end, 0); 296 if (!parse_unit_factor(end, &val)) 297 return 0; 298 *ret = val; 299 return 1; 300 } 301 return 0; 302 } 303 304 static void die_bad_config(const char *name) 305 { 306 if (config_file_name) 307 die("bad config value for '%s' in %s", name, config_file_name); 308 die("bad config value for '%s'", name); 309 } 310 311 int perf_config_int(const char *name, const char *value) 312 { 313 long ret = 0; 314 if (!perf_parse_long(value, &ret)) 315 die_bad_config(name); 316 return ret; 317 } 318 319 unsigned long perf_config_ulong(const char *name, const char *value) 320 { 321 unsigned long ret; 322 if (!perf_parse_ulong(value, &ret)) 323 die_bad_config(name); 324 return ret; 325 } 326 327 int perf_config_bool_or_int(const char *name, const char *value, int *is_bool) 328 { 329 *is_bool = 1; 330 if (!value) 331 return 1; 332 if (!*value) 333 return 0; 334 if (!strcasecmp(value, "true") || !strcasecmp(value, "yes") || !strcasecmp(value, "on")) 335 return 1; 336 if (!strcasecmp(value, "false") || !strcasecmp(value, "no") || !strcasecmp(value, "off")) 337 return 0; 338 *is_bool = 0; 339 return perf_config_int(name, value); 340 } 341 342 int perf_config_bool(const char *name, const char *value) 343 { 344 int discard; 345 return !!perf_config_bool_or_int(name, value, &discard); 346 } 347 348 int perf_config_string(const char **dest, const char *var, const char *value) 349 { 350 if (!value) 351 return config_error_nonbool(var); 352 *dest = strdup(value); 353 return 0; 354 } 355 356 static int perf_default_core_config(const char *var, const char *value) 357 { 358 /* Add other config variables here and to Documentation/config.txt. */ 359 return 0; 360 } 361 362 int perf_default_config(const char *var, const char *value, void *dummy) 363 { 364 if (!prefixcmp(var, "core.")) 365 return perf_default_core_config(var, value); 366 367 /* Add other config variables here and to Documentation/config.txt. */ 368 return 0; 369 } 370 371 int perf_config_from_file(config_fn_t fn, const char *filename, void *data) 372 { 373 int ret; 374 FILE *f = fopen(filename, "r"); 375 376 ret = -1; 377 if (f) { 378 config_file = f; 379 config_file_name = filename; 380 config_linenr = 1; 381 config_file_eof = 0; 382 ret = perf_parse_file(fn, data); 383 fclose(f); 384 config_file_name = NULL; 385 } 386 return ret; 387 } 388 389 const char *perf_etc_perfconfig(void) 390 { 391 static const char *system_wide; 392 if (!system_wide) 393 system_wide = system_path(ETC_PERFCONFIG); 394 return system_wide; 395 } 396 397 static int perf_env_bool(const char *k, int def) 398 { 399 const char *v = getenv(k); 400 return v ? perf_config_bool(k, v) : def; 401 } 402 403 int perf_config_system(void) 404 { 405 return !perf_env_bool("PERF_CONFIG_NOSYSTEM", 0); 406 } 407 408 int perf_config_global(void) 409 { 410 return !perf_env_bool("PERF_CONFIG_NOGLOBAL", 0); 411 } 412 413 int perf_config(config_fn_t fn, void *data) 414 { 415 int ret = 0, found = 0; 416 char *repo_config = NULL; 417 const char *home = NULL; 418 419 /* Setting $PERF_CONFIG makes perf read _only_ the given config file. */ 420 if (config_exclusive_filename) 421 return perf_config_from_file(fn, config_exclusive_filename, data); 422 if (perf_config_system() && !access(perf_etc_perfconfig(), R_OK)) { 423 ret += perf_config_from_file(fn, perf_etc_perfconfig(), 424 data); 425 found += 1; 426 } 427 428 home = getenv("HOME"); 429 if (perf_config_global() && home) { 430 char *user_config = strdup(mkpath("%s/.perfconfig", home)); 431 if (!access(user_config, R_OK)) { 432 ret += perf_config_from_file(fn, user_config, data); 433 found += 1; 434 } 435 free(user_config); 436 } 437 438 repo_config = perf_pathdup("config"); 439 if (!access(repo_config, R_OK)) { 440 ret += perf_config_from_file(fn, repo_config, data); 441 found += 1; 442 } 443 free(repo_config); 444 if (found == 0) 445 return -1; 446 return ret; 447 } 448 449 /* 450 * Find all the stuff for perf_config_set() below. 451 */ 452 453 #define MAX_MATCHES 512 454 455 static struct { 456 int baselen; 457 char* key; 458 int do_not_match; 459 regex_t* value_regex; 460 int multi_replace; 461 size_t offset[MAX_MATCHES]; 462 enum { START, SECTION_SEEN, SECTION_END_SEEN, KEY_SEEN } state; 463 int seen; 464 } store; 465 466 static int matches(const char* key, const char* value) 467 { 468 return !strcmp(key, store.key) && 469 (store.value_regex == NULL || 470 (store.do_not_match ^ 471 !regexec(store.value_regex, value, 0, NULL, 0))); 472 } 473 474 static int store_aux(const char* key, const char* value, void *cb) 475 { 476 const char *ep; 477 size_t section_len; 478 479 switch (store.state) { 480 case KEY_SEEN: 481 if (matches(key, value)) { 482 if (store.seen == 1 && store.multi_replace == 0) { 483 warning("%s has multiple values", key); 484 } else if (store.seen >= MAX_MATCHES) { 485 error("too many matches for %s", key); 486 return 1; 487 } 488 489 store.offset[store.seen] = ftell(config_file); 490 store.seen++; 491 } 492 break; 493 case SECTION_SEEN: 494 /* 495 * What we are looking for is in store.key (both 496 * section and var), and its section part is baselen 497 * long. We found key (again, both section and var). 498 * We would want to know if this key is in the same 499 * section as what we are looking for. We already 500 * know we are in the same section as what should 501 * hold store.key. 502 */ 503 ep = strrchr(key, '.'); 504 section_len = ep - key; 505 506 if ((section_len != store.baselen) || 507 memcmp(key, store.key, section_len+1)) { 508 store.state = SECTION_END_SEEN; 509 break; 510 } 511 512 /* 513 * Do not increment matches: this is no match, but we 514 * just made sure we are in the desired section. 515 */ 516 store.offset[store.seen] = ftell(config_file); 517 /* fallthru */ 518 case SECTION_END_SEEN: 519 case START: 520 if (matches(key, value)) { 521 store.offset[store.seen] = ftell(config_file); 522 store.state = KEY_SEEN; 523 store.seen++; 524 } else { 525 if (strrchr(key, '.') - key == store.baselen && 526 !strncmp(key, store.key, store.baselen)) { 527 store.state = SECTION_SEEN; 528 store.offset[store.seen] = ftell(config_file); 529 } 530 } 531 } 532 return 0; 533 } 534 535 static int store_write_section(int fd, const char* key) 536 { 537 const char *dot; 538 int i, success; 539 struct strbuf sb = STRBUF_INIT; 540 541 dot = memchr(key, '.', store.baselen); 542 if (dot) { 543 strbuf_addf(&sb, "[%.*s \"", (int)(dot - key), key); 544 for (i = dot - key + 1; i < store.baselen; i++) { 545 if (key[i] == '"' || key[i] == '\\') 546 strbuf_addch(&sb, '\\'); 547 strbuf_addch(&sb, key[i]); 548 } 549 strbuf_addstr(&sb, "\"]\n"); 550 } else { 551 strbuf_addf(&sb, "[%.*s]\n", store.baselen, key); 552 } 553 554 success = write_in_full(fd, sb.buf, sb.len) == sb.len; 555 strbuf_release(&sb); 556 557 return success; 558 } 559 560 static int store_write_pair(int fd, const char* key, const char* value) 561 { 562 int i, success; 563 int length = strlen(key + store.baselen + 1); 564 const char *quote = ""; 565 struct strbuf sb = STRBUF_INIT; 566 567 /* 568 * Check to see if the value needs to be surrounded with a dq pair. 569 * Note that problematic characters are always backslash-quoted; this 570 * check is about not losing leading or trailing SP and strings that 571 * follow beginning-of-comment characters (i.e. ';' and '#') by the 572 * configuration parser. 573 */ 574 if (value[0] == ' ') 575 quote = "\""; 576 for (i = 0; value[i]; i++) 577 if (value[i] == ';' || value[i] == '#') 578 quote = "\""; 579 if (i && value[i - 1] == ' ') 580 quote = "\""; 581 582 strbuf_addf(&sb, "\t%.*s = %s", 583 length, key + store.baselen + 1, quote); 584 585 for (i = 0; value[i]; i++) 586 switch (value[i]) { 587 case '\n': 588 strbuf_addstr(&sb, "\\n"); 589 break; 590 case '\t': 591 strbuf_addstr(&sb, "\\t"); 592 break; 593 case '"': 594 case '\\': 595 strbuf_addch(&sb, '\\'); 596 default: 597 strbuf_addch(&sb, value[i]); 598 break; 599 } 600 strbuf_addf(&sb, "%s\n", quote); 601 602 success = write_in_full(fd, sb.buf, sb.len) == sb.len; 603 strbuf_release(&sb); 604 605 return success; 606 } 607 608 static ssize_t find_beginning_of_line(const char* contents, size_t size, 609 size_t offset_, int* found_bracket) 610 { 611 size_t equal_offset = size, bracket_offset = size; 612 ssize_t offset; 613 614 contline: 615 for (offset = offset_-2; offset > 0 616 && contents[offset] != '\n'; offset--) 617 switch (contents[offset]) { 618 case '=': equal_offset = offset; break; 619 case ']': bracket_offset = offset; break; 620 } 621 if (offset > 0 && contents[offset-1] == '\\') { 622 offset_ = offset; 623 goto contline; 624 } 625 if (bracket_offset < equal_offset) { 626 *found_bracket = 1; 627 offset = bracket_offset+1; 628 } else 629 offset++; 630 631 return offset; 632 } 633 634 int perf_config_set(const char* key, const char* value) 635 { 636 return perf_config_set_multivar(key, value, NULL, 0); 637 } 638 639 /* 640 * If value==NULL, unset in (remove from) config, 641 * if value_regex!=NULL, disregard key/value pairs where value does not match. 642 * if multi_replace==0, nothing, or only one matching key/value is replaced, 643 * else all matching key/values (regardless how many) are removed, 644 * before the new pair is written. 645 * 646 * Returns 0 on success. 647 * 648 * This function does this: 649 * 650 * - it locks the config file by creating ".perf/config.lock" 651 * 652 * - it then parses the config using store_aux() as validator to find 653 * the position on the key/value pair to replace. If it is to be unset, 654 * it must be found exactly once. 655 * 656 * - the config file is mmap()ed and the part before the match (if any) is 657 * written to the lock file, then the changed part and the rest. 658 * 659 * - the config file is removed and the lock file rename()d to it. 660 * 661 */ 662 int perf_config_set_multivar(const char* key, const char* value, 663 const char* value_regex, int multi_replace) 664 { 665 int i, dot; 666 int fd = -1, in_fd; 667 int ret = 0; 668 char* config_filename; 669 const char* last_dot = strrchr(key, '.'); 670 671 if (config_exclusive_filename) 672 config_filename = strdup(config_exclusive_filename); 673 else 674 config_filename = perf_pathdup("config"); 675 676 /* 677 * Since "key" actually contains the section name and the real 678 * key name separated by a dot, we have to know where the dot is. 679 */ 680 681 if (last_dot == NULL) { 682 error("key does not contain a section: %s", key); 683 ret = 2; 684 goto out_free; 685 } 686 store.baselen = last_dot - key; 687 688 store.multi_replace = multi_replace; 689 690 /* 691 * Validate the key and while at it, lower case it for matching. 692 */ 693 store.key = malloc(strlen(key) + 1); 694 dot = 0; 695 for (i = 0; key[i]; i++) { 696 unsigned char c = key[i]; 697 if (c == '.') 698 dot = 1; 699 /* Leave the extended basename untouched.. */ 700 if (!dot || i > store.baselen) { 701 if (!iskeychar(c) || (i == store.baselen+1 && !isalpha(c))) { 702 error("invalid key: %s", key); 703 free(store.key); 704 ret = 1; 705 goto out_free; 706 } 707 c = tolower(c); 708 } else if (c == '\n') { 709 error("invalid key (newline): %s", key); 710 free(store.key); 711 ret = 1; 712 goto out_free; 713 } 714 store.key[i] = c; 715 } 716 store.key[i] = 0; 717 718 /* 719 * If .perf/config does not exist yet, write a minimal version. 720 */ 721 in_fd = open(config_filename, O_RDONLY); 722 if ( in_fd < 0 ) { 723 free(store.key); 724 725 if ( ENOENT != errno ) { 726 error("opening %s: %s", config_filename, 727 strerror(errno)); 728 ret = 3; /* same as "invalid config file" */ 729 goto out_free; 730 } 731 /* if nothing to unset, error out */ 732 if (value == NULL) { 733 ret = 5; 734 goto out_free; 735 } 736 737 store.key = (char*)key; 738 if (!store_write_section(fd, key) || 739 !store_write_pair(fd, key, value)) 740 goto write_err_out; 741 } else { 742 struct stat st; 743 char* contents; 744 size_t contents_sz, copy_begin, copy_end; 745 int i, new_line = 0; 746 747 if (value_regex == NULL) 748 store.value_regex = NULL; 749 else { 750 if (value_regex[0] == '!') { 751 store.do_not_match = 1; 752 value_regex++; 753 } else 754 store.do_not_match = 0; 755 756 store.value_regex = (regex_t*)malloc(sizeof(regex_t)); 757 if (regcomp(store.value_regex, value_regex, 758 REG_EXTENDED)) { 759 error("invalid pattern: %s", value_regex); 760 free(store.value_regex); 761 ret = 6; 762 goto out_free; 763 } 764 } 765 766 store.offset[0] = 0; 767 store.state = START; 768 store.seen = 0; 769 770 /* 771 * After this, store.offset will contain the *end* offset 772 * of the last match, or remain at 0 if no match was found. 773 * As a side effect, we make sure to transform only a valid 774 * existing config file. 775 */ 776 if (perf_config_from_file(store_aux, config_filename, NULL)) { 777 error("invalid config file %s", config_filename); 778 free(store.key); 779 if (store.value_regex != NULL) { 780 regfree(store.value_regex); 781 free(store.value_regex); 782 } 783 ret = 3; 784 goto out_free; 785 } 786 787 free(store.key); 788 if (store.value_regex != NULL) { 789 regfree(store.value_regex); 790 free(store.value_regex); 791 } 792 793 /* if nothing to unset, or too many matches, error out */ 794 if ((store.seen == 0 && value == NULL) || 795 (store.seen > 1 && multi_replace == 0)) { 796 ret = 5; 797 goto out_free; 798 } 799 800 fstat(in_fd, &st); 801 contents_sz = xsize_t(st.st_size); 802 contents = mmap(NULL, contents_sz, PROT_READ, 803 MAP_PRIVATE, in_fd, 0); 804 close(in_fd); 805 806 if (store.seen == 0) 807 store.seen = 1; 808 809 for (i = 0, copy_begin = 0; i < store.seen; i++) { 810 if (store.offset[i] == 0) { 811 store.offset[i] = copy_end = contents_sz; 812 } else if (store.state != KEY_SEEN) { 813 copy_end = store.offset[i]; 814 } else 815 copy_end = find_beginning_of_line( 816 contents, contents_sz, 817 store.offset[i]-2, &new_line); 818 819 if (copy_end > 0 && contents[copy_end-1] != '\n') 820 new_line = 1; 821 822 /* write the first part of the config */ 823 if (copy_end > copy_begin) { 824 if (write_in_full(fd, contents + copy_begin, 825 copy_end - copy_begin) < 826 copy_end - copy_begin) 827 goto write_err_out; 828 if (new_line && 829 write_in_full(fd, "\n", 1) != 1) 830 goto write_err_out; 831 } 832 copy_begin = store.offset[i]; 833 } 834 835 /* write the pair (value == NULL means unset) */ 836 if (value != NULL) { 837 if (store.state == START) { 838 if (!store_write_section(fd, key)) 839 goto write_err_out; 840 } 841 if (!store_write_pair(fd, key, value)) 842 goto write_err_out; 843 } 844 845 /* write the rest of the config */ 846 if (copy_begin < contents_sz) 847 if (write_in_full(fd, contents + copy_begin, 848 contents_sz - copy_begin) < 849 contents_sz - copy_begin) 850 goto write_err_out; 851 852 munmap(contents, contents_sz); 853 } 854 855 ret = 0; 856 857 out_free: 858 free(config_filename); 859 return ret; 860 861 write_err_out: 862 goto out_free; 863 864 } 865 866 /* 867 * Call this to report error for your variable that should not 868 * get a boolean value (i.e. "[my] var" means "true"). 869 */ 870 int config_error_nonbool(const char *var) 871 { 872 return error("Missing value for '%s'", var); 873 } 874