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