config.c 15.1 KB
Newer Older
1 2 3 4 5 6 7
/*
 * GIT - The information manager from hell
 *
 * Copyright (C) Linus Torvalds, 2005
 * Copyright (C) Johannes Schindelin, 2005
 *
 */
L
Linus Torvalds 已提交
8
#include "cache.h"
9
#include <regex.h>
L
Linus Torvalds 已提交
10 11 12 13

#define MAXNAME (256)

static FILE *config_file;
14
static const char *config_file_name;
L
Linus Torvalds 已提交
15 16 17 18 19 20 21 22 23
static int config_linenr;
static int get_next_char(void)
{
	int c;
	FILE *f;

	c = '\n';
	if ((f = config_file) != NULL) {
		c = fgetc(f);
24 25 26 27 28 29 30 31
		if (c == '\r') {
			/* DOS like systems */
			c = fgetc(f);
			if (c != '\n') {
				ungetc(c, f);
				c = '\r';
			}
		}
L
Linus Torvalds 已提交
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
		if (c == '\n')
			config_linenr++;
		if (c == EOF) {
			config_file = NULL;
			c = '\n';
		}
	}
	return c;
}

static char *parse_value(void)
{
	static char value[1024];
	int quote = 0, comment = 0, len = 0, space = 0;

	for (;;) {
		int c = get_next_char();
		if (len >= sizeof(value))
			return NULL;
		if (c == '\n') {
			if (quote)
				return NULL;
			value[len] = 0;
			return value;
		}
		if (comment)
			continue;
		if (isspace(c) && !quote) {
			space = 1;
			continue;
		}
63 64 65 66 67 68
		if (!quote) {
			if (c == ';' || c == '#') {
				comment = 1;
				continue;
			}
		}
L
Linus Torvalds 已提交
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
		if (space) {
			if (len)
				value[len++] = ' ';
			space = 0;
		}
		if (c == '\\') {
			c = get_next_char();
			switch (c) {
			case '\n':
				continue;
			case 't':
				c = '\t';
				break;
			case 'b':
				c = '\b';
				break;
			case 'n':
				c = '\n';
				break;
88 89 90 91 92 93
			/* Some characters escape as themselves */
			case '\\': case '"':
				break;
			/* Reject unknown escape sequences */
			default:
				return NULL;
L
Linus Torvalds 已提交
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
			}
			value[len++] = c;
			continue;
		}
		if (c == '"') {
			quote = 1-quote;
			continue;
		}
		value[len++] = c;
	}
}

static int get_value(config_fn_t fn, char *name, unsigned int len)
{
	int c;
	char *value;

	/* Get the full name */
	for (;;) {
		c = get_next_char();
		if (c == EOF)
			break;
		if (!isalnum(c))
			break;
		name[len++] = tolower(c);
		if (len >= MAXNAME)
			return -1;
	}
	name[len] = 0;
	while (c == ' ' || c == '\t')
		c = get_next_char();

	value = NULL;
	if (c != '\n') {
		if (c != '=')
			return -1;
		value = parse_value();
		if (!value)
			return -1;
	}
	return fn(name, value);
}

L
Linus Torvalds 已提交
137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
static int get_extended_base_var(char *name, int baselen, int c)
{
	do {
		if (c == '\n')
			return -1;
		c = get_next_char();
	} while (isspace(c));

	/* We require the format to be '[base "extension"]' */
	if (c != '"')
		return -1;
	name[baselen++] = '.';

	for (;;) {
		int c = get_next_char();
		if (c == '\n')
			return -1;
		if (c == '"')
			break;
		if (c == '\\') {
			c = get_next_char();
			if (c == '\n')
				return -1;
		}
		name[baselen++] = c;
		if (baselen > MAXNAME / 2)
			return -1;
	}

	/* Final ']' */
	if (get_next_char() != ']')
		return -1;
	return baselen;
}

L
Linus Torvalds 已提交
172 173 174 175 176 177 178 179 180 181
static int get_base_var(char *name)
{
	int baselen = 0;

	for (;;) {
		int c = get_next_char();
		if (c == EOF)
			return -1;
		if (c == ']')
			return baselen;
L
Linus Torvalds 已提交
182 183
		if (isspace(c))
			return get_extended_base_var(name, baselen, c);
184
		if (!isalnum(c) && c != '.')
L
Linus Torvalds 已提交
185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222
			return -1;
		if (baselen > MAXNAME / 2)
			return -1;
		name[baselen++] = tolower(c);
	}
}

static int git_parse_file(config_fn_t fn)
{
	int comment = 0;
	int baselen = 0;
	static char var[MAXNAME];

	for (;;) {
		int c = get_next_char();
		if (c == '\n') {
			/* EOF? */
			if (!config_file)
				return 0;
			comment = 0;
			continue;
		}
		if (comment || isspace(c))
			continue;
		if (c == '#' || c == ';') {
			comment = 1;
			continue;
		}
		if (c == '[') {
			baselen = get_base_var(var);
			if (baselen <= 0)
				break;
			var[baselen++] = '.';
			var[baselen] = 0;
			continue;
		}
		if (!isalpha(c))
			break;
223
		var[baselen] = tolower(c);
L
Linus Torvalds 已提交
224 225 226
		if (get_value(fn, var, baselen+1) < 0)
			break;
	}
227
	die("bad config file line %d in %s", config_linenr, config_file_name);
L
Linus Torvalds 已提交
228 229 230 231 232 233 234 235 236 237
}

int git_config_int(const char *name, const char *value)
{
	if (value && *value) {
		char *end;
		int val = strtol(value, &end, 0);
		if (!*end)
			return val;
	}
238
	die("bad config value for '%s' in %s", name, config_file_name);
L
Linus Torvalds 已提交
239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261
}

int git_config_bool(const char *name, const char *value)
{
	if (!value)
		return 1;
	if (!*value)
		return 0;
	if (!strcasecmp(value, "true"))
		return 1;
	if (!strcasecmp(value, "false"))
		return 0;
	return git_config_int(name, value) != 0;
}

int git_default_config(const char *var, const char *value)
{
	/* This needs a better name */
	if (!strcmp(var, "core.filemode")) {
		trust_executable_bit = git_config_bool(var, value);
		return 0;
	}

J
Junio C Hamano 已提交
262 263 264 265 266
	if (!strcmp(var, "core.ignorestat")) {
		assume_unchanged = git_config_bool(var, value);
		return 0;
	}

267 268
	if (!strcmp(var, "core.prefersymlinkrefs")) {
		prefer_symlink_refs = git_config_bool(var, value);
269 270 271
		return 0;
	}

272 273 274 275 276
	if (!strcmp(var, "core.logallrefupdates")) {
		log_all_ref_updates = git_config_bool(var, value);
		return 0;
	}

277 278 279 280 281
	if (!strcmp(var, "core.warnambiguousrefs")) {
		warn_ambiguous_refs = git_config_bool(var, value);
		return 0;
	}

282
	if (!strcmp(var, "user.name")) {
283
		safe_strncpy(git_default_name, value, sizeof(git_default_name));
284 285 286 287
		return 0;
	}

	if (!strcmp(var, "user.email")) {
288
		safe_strncpy(git_default_email, value, sizeof(git_default_email));
289 290 291
		return 0;
	}

J
Junio C Hamano 已提交
292
	if (!strcmp(var, "i18n.commitencoding")) {
293
		safe_strncpy(git_commit_encoding, value, sizeof(git_commit_encoding));
J
Junio C Hamano 已提交
294 295 296
		return 0;
	}

P
Petr Baudis 已提交
297
	/* Add other config variables here and to Documentation/config.txt. */
L
Linus Torvalds 已提交
298 299 300
	return 0;
}

301
int git_config_from_file(config_fn_t fn, const char *filename)
L
Linus Torvalds 已提交
302 303
{
	int ret;
304
	FILE *f = fopen(filename, "r");
L
Linus Torvalds 已提交
305 306 307 308

	ret = -1;
	if (f) {
		config_file = f;
309
		config_file_name = filename;
L
Linus Torvalds 已提交
310 311 312
		config_linenr = 1;
		ret = git_parse_file(fn);
		fclose(f);
313
		config_file_name = NULL;
L
Linus Torvalds 已提交
314 315 316
	}
	return ret;
}
317

318 319
int git_config(config_fn_t fn)
{
320 321 322 323 324 325 326 327 328 329 330
	int ret = 0;
	char *repo_config = NULL;
	const char *home = NULL, *filename;

	/* $GIT_CONFIG makes git read _only_ the given config file,
	 * $GIT_CONFIG_LOCAL will make it process it in addition to the
	 * global config file, the same way it would the per-repository
	 * config file otherwise. */
	filename = getenv("GIT_CONFIG");
	if (!filename) {
		home = getenv("HOME");
331
		filename = getenv("GIT_CONFIG_LOCAL");
332 333
		if (!filename)
			filename = repo_config = strdup(git_path("config"));
334
	}
335 336 337

	if (home) {
		char *user_config = strdup(mkpath("%s/.gitconfig", home));
338
		if (!access(user_config, R_OK))
339 340 341 342 343 344 345 346
			ret = git_config_from_file(fn, user_config);
		free(user_config);
	}

	ret += git_config_from_file(fn, filename);
	if (repo_config)
		free(repo_config);
	return ret;
347 348
}

349 350 351
/*
 * Find all the stuff for git_config_set() below.
 */
352 353 354

#define MAX_MATCHES 512

355 356 357
static struct {
	int baselen;
	char* key;
358
	int do_not_match;
359
	regex_t* value_regex;
360 361
	int multi_replace;
	off_t offset[MAX_MATCHES];
362 363 364 365
	enum { START, SECTION_SEEN, SECTION_END_SEEN, KEY_SEEN } state;
	int seen;
} store;

366 367 368 369 370 371 372 373
static int matches(const char* key, const char* value)
{
	return !strcmp(key, store.key) &&
		(store.value_regex == NULL ||
		 (store.do_not_match ^
		  !regexec(store.value_regex, value, 0, NULL, 0)));
}

374 375 376 377
static int store_aux(const char* key, const char* value)
{
	switch (store.state) {
	case KEY_SEEN:
378
		if (matches(key, value)) {
379
			if (store.seen == 1 && store.multi_replace == 0) {
380 381 382
				fprintf(stderr,
					"Warning: %s has multiple values\n",
					key);
383 384 385
			} else if (store.seen >= MAX_MATCHES) {
				fprintf(stderr, "Too many matches\n");
				return 1;
386
			}
387 388

			store.offset[store.seen] = ftell(config_file);
389 390 391 392 393 394 395 396
			store.seen++;
		}
		break;
	case SECTION_SEEN:
		if (strncmp(key, store.key, store.baselen+1)) {
			store.state = SECTION_END_SEEN;
			break;
		} else
397 398
			/* do not increment matches: this is no match */
			store.offset[store.seen] = ftell(config_file);
399 400 401
		/* fallthru */
	case SECTION_END_SEEN:
	case START:
402
		if (matches(key, value)) {
403
			store.offset[store.seen] = ftell(config_file);
404 405
			store.state = KEY_SEEN;
			store.seen++;
L
Linus Torvalds 已提交
406 407
		} else {
			if (strrchr(key, '.') - key == store.baselen &&
S
sean 已提交
408
			      !strncmp(key, store.key, store.baselen)) {
S
sean 已提交
409
					store.state = SECTION_SEEN;
S
sean 已提交
410
					store.offset[store.seen] = ftell(config_file);
L
Linus Torvalds 已提交
411
			}
S
sean 已提交
412
		}
413 414 415 416 417 418
	}
	return 0;
}

static void store_write_section(int fd, const char* key)
{
L
Linus Torvalds 已提交
419 420 421 422 423 424 425 426 427 428 429 430
	const char *dot = strchr(key, '.');
	int len1 = store.baselen, len2 = -1;

	dot = strchr(key, '.');
	if (dot) {
		int dotlen = dot - key;
		if (dotlen < len1) {
			len2 = len1 - dotlen - 1;
			len1 = dotlen;
		}
	}

431
	write(fd, "[", 1);
L
Linus Torvalds 已提交
432 433 434 435 436 437 438 439 440 441 442
	write(fd, key, len1);
	if (len2 >= 0) {
		write(fd, " \"", 2);
		while (--len2 >= 0) {
			unsigned char c = *++dot;
			if (c == '"')
				write(fd, "\\", 1);
			write(fd, &c, 1);
		}
		write(fd, "\"", 1);
	}
443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463
	write(fd, "]\n", 2);
}

static void store_write_pair(int fd, const char* key, const char* value)
{
	int i;

	write(fd, "\t", 1);
	write(fd, key+store.baselen+1,
		strlen(key+store.baselen+1));
	write(fd, " = ", 3);
	for (i = 0; value[i]; i++)
		switch (value[i]) {
		case '\n': write(fd, "\\n", 2); break;
		case '\t': write(fd, "\\t", 2); break;
		case '"': case '\\': write(fd, "\\", 1);
		default: write(fd, value+i, 1);
	}
	write(fd, "\n", 1);
}

464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484
static int find_beginning_of_line(const char* contents, int size,
	int offset_, int* found_bracket)
{
	int equal_offset = size, bracket_offset = size;
	int offset;

	for (offset = offset_-2; offset > 0 
			&& contents[offset] != '\n'; offset--)
		switch (contents[offset]) {
			case '=': equal_offset = offset; break;
			case ']': bracket_offset = offset; break;
		}
	if (bracket_offset < equal_offset) {
		*found_bracket = 1;
		offset = bracket_offset+1;
	} else
		offset++;

	return offset;
}

485 486
int git_config_set(const char* key, const char* value)
{
487
	return git_config_set_multivar(key, value, NULL, 0);
488 489 490 491 492
}

/*
 * If value==NULL, unset in (remove from) config,
 * if value_regex!=NULL, disregard key/value pairs where value does not match.
493 494 495
 * if multi_replace==0, nothing, or only one matching key/value is replaced,
 *     else all matching key/values (regardless how many) are removed,
 *     before the new pair is written.
496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513
 *
 * Returns 0 on success.
 *
 * This function does this:
 *
 * - it locks the config file by creating ".git/config.lock"
 *
 * - it then parses the config using store_aux() as validator to find
 *   the position on the key/value pair to replace. If it is to be unset,
 *   it must be found exactly once.
 *
 * - the config file is mmap()ed and the part before the match (if any) is
 *   written to the lock file, then the changed part and the rest.
 *
 * - the config file is removed and the lock file rename()d to it.
 *
 */
int git_config_set_multivar(const char* key, const char* value,
514
	const char* value_regex, int multi_replace)
515
{
L
Linus Torvalds 已提交
516
	int i, dot;
517
	int fd = -1, in_fd;
518
	int ret;
519 520
	char* config_filename;
	char* lock_file;
521
	const char* last_dot = strrchr(key, '.');
522

523 524 525 526 527 528 529 530 531
	config_filename = getenv("GIT_CONFIG");
	if (!config_filename) {
		config_filename = getenv("GIT_CONFIG_LOCAL");
		if (!config_filename)
			config_filename  = git_path("config");
	}
	config_filename = strdup(config_filename);
	lock_file = strdup(mkpath("%s.lock", config_filename));

532 533 534 535
	/*
	 * Since "key" actually contains the section name and the real
	 * key name separated by a dot, we have to know where the dot is.
	 */
536

537
	if (last_dot == NULL) {
538
		fprintf(stderr, "key does not contain a section: %s\n", key);
539 540
		ret = 2;
		goto out_free;
541
	}
542 543 544
	store.baselen = last_dot - key;

	store.multi_replace = multi_replace;
545 546 547 548 549

	/*
	 * Validate the key and while at it, lower case it for matching.
	 */
	store.key = (char*)malloc(strlen(key)+1);
L
Linus Torvalds 已提交
550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566
	dot = 0;
	for (i = 0; key[i]; i++) {
		unsigned char c = key[i];
		if (c == '.')
			dot = 1;
		/* Leave the extended basename untouched.. */
		if (!dot || i > store.baselen) {
			if (!isalnum(c) || (i == store.baselen+1 && !isalpha(c))) {
				fprintf(stderr, "invalid key: %s\n", key);
				free(store.key);
				ret = 1;
				goto out_free;
			}
			c = tolower(c);
		}
		store.key[i] = c;
	}
567
	store.key[i] = 0;
568 569 570 571 572 573

	/*
	 * The lock_file serves a purpose in addition to locking: the new
	 * contents of .git/config will be written into it.
	 */
	fd = open(lock_file, O_WRONLY | O_CREAT | O_EXCL, 0666);
574
	if (fd < 0 || adjust_shared_perm(lock_file)) {
575 576
		fprintf(stderr, "could not lock config file\n");
		free(store.key);
577 578
		ret = -1;
		goto out_free;
579 580 581 582 583
	}

	/*
	 * If .git/config does not exist yet, write a minimal version.
	 */
584 585
	in_fd = open(config_filename, O_RDONLY);
	if ( in_fd < 0 ) {
586 587
		free(store.key);

588 589 590
		if ( ENOENT != errno ) {
			error("opening %s: %s", config_filename,
			      strerror(errno));
591 592
			ret = 3; /* same as "invalid config file" */
			goto out_free;
593
		}
594 595
		/* if nothing to unset, error out */
		if (value == NULL) {
596 597
			ret = 5;
			goto out_free;
598 599 600 601 602 603
		}

		store.key = (char*)key;
		store_write_section(fd, key);
		store_write_pair(fd, key, value);
	} else{
604
		struct stat st;
605
		char* contents;
606
		int i, copy_begin, copy_end, new_line = 0;
607 608 609 610

		if (value_regex == NULL)
			store.value_regex = NULL;
		else {
611 612 613 614 615 616
			if (value_regex[0] == '!') {
				store.do_not_match = 1;
				value_regex++;
			} else
				store.do_not_match = 0;

617 618 619
			store.value_regex = (regex_t*)malloc(sizeof(regex_t));
			if (regcomp(store.value_regex, value_regex,
					REG_EXTENDED)) {
A
Alex Riesen 已提交
620
				fprintf(stderr, "Invalid pattern: %s\n",
621 622
					value_regex);
				free(store.value_regex);
623 624
				ret = 6;
				goto out_free;
625 626 627
			}
		}

628
		store.offset[0] = 0;
629 630 631 632 633 634 635 636 637
		store.state = START;
		store.seen = 0;

		/*
		 * After this, store.offset will contain the *end* offset
		 * of the last match, or remain at 0 if no match was found.
		 * As a side effect, we make sure to transform only a valid
		 * existing config file.
		 */
638
		if (git_config_from_file(store_aux, config_filename)) {
639 640 641 642 643 644
			fprintf(stderr, "invalid config file\n");
			free(store.key);
			if (store.value_regex != NULL) {
				regfree(store.value_regex);
				free(store.value_regex);
			}
645 646
			ret = 3;
			goto out_free;
647 648 649 650 651 652 653 654
		}

		free(store.key);
		if (store.value_regex != NULL) {
			regfree(store.value_regex);
			free(store.value_regex);
		}

655 656 657
		/* if nothing to unset, or too many matches, error out */
		if ((store.seen == 0 && value == NULL) ||
				(store.seen > 1 && multi_replace == 0)) {
658 659
			ret = 5;
			goto out_free;
660 661
		}

662
		fstat(in_fd, &st);
663 664 665 666
		contents = mmap(NULL, st.st_size, PROT_READ,
			MAP_PRIVATE, in_fd, 0);
		close(in_fd);

667 668 669 670 671 672 673 674
		if (store.seen == 0)
			store.seen = 1;

		for (i = 0, copy_begin = 0; i < store.seen; i++) {
			if (store.offset[i] == 0) {
				store.offset[i] = copy_end = st.st_size;
			} else if (store.state != KEY_SEEN) {
				copy_end = store.offset[i];
675
			} else
676 677 678 679 680 681 682 683 684 685 686 687
				copy_end = find_beginning_of_line(
					contents, st.st_size,
					store.offset[i]-2, &new_line);

			/* write the first part of the config */
			if (copy_end > copy_begin) {
				write(fd, contents + copy_begin,
				copy_end - copy_begin);
				if (new_line)
					write(fd, "\n", 1);
			}
			copy_begin = store.offset[i];
688 689 690 691 692 693 694 695 696 697
		}

		/* write the pair (value == NULL means unset) */
		if (value != NULL) {
			if (store.state == START)
				store_write_section(fd, key);
			store_write_pair(fd, key, value);
		}

		/* write the rest of the config */
698 699 700
		if (copy_begin < st.st_size)
			write(fd, contents + copy_begin,
				st.st_size - copy_begin);
701 702

		munmap(contents, st.st_size);
J
Junio C Hamano 已提交
703
		unlink(config_filename);
704 705
	}

J
Junio C Hamano 已提交
706
	if (rename(lock_file, config_filename) < 0) {
707
		fprintf(stderr, "Could not rename the lock file?\n");
708 709
		ret = 4;
		goto out_free;
710 711
	}

712 713 714
	ret = 0;

out_free:
715 716
	if (0 <= fd)
		close(fd);
717 718
	if (config_filename)
		free(config_filename);
719 720
	if (lock_file) {
		unlink(lock_file);
721
		free(lock_file);
722
	}
723
	return ret;
724 725
}

726