Esempio n. 1
0
int print_config_from_gitmodules(struct repository *repo, const char *key)
{
	int ret;
	char *store_key;

	ret = git_config_parse_key(key, &store_key, NULL);
	if (ret < 0)
		return CONFIG_INVALID_KEY;

	config_from_gitmodules(config_print_callback, repo, store_key);

	free(store_key);
	return 0;
}
Esempio n. 2
0
static int get_value(const char *key_, const char *regex_)
{
    int ret = -1;
    char *global = NULL, *xdg = NULL, *repo_config = NULL;
    const char *system_wide = NULL, *local;
    struct config_include_data inc = CONFIG_INCLUDE_INIT;
    config_fn_t fn;
    void *data;

    local = given_config_file;
    if (!local) {
        local = repo_config = git_pathdup("config");
        if (git_config_system())
            system_wide = git_etc_gitconfig();
        home_config_paths(&global, &xdg, "config");
    }

    if (use_key_regexp) {
        char *tl;

        /*
         * NEEDSWORK: this naive pattern lowercasing obviously does not
         * work for more complex patterns like "^[^.]*Foo.*bar".
         * Perhaps we should deprecate this altogether someday.
         */

        key = xstrdup(key_);
        for (tl = key + strlen(key) - 1;
                tl >= key && *tl != '.';
                tl--)
            *tl = tolower(*tl);
        for (tl = key; *tl && *tl != '.'; tl++)
            *tl = tolower(*tl);

        key_regexp = (regex_t*)xmalloc(sizeof(regex_t));
        if (regcomp(key_regexp, key, REG_EXTENDED)) {
            fprintf(stderr, "Invalid key pattern: %s\n", key_);
            free(key);
            goto free_strings;
        }
    } else {
        if (git_config_parse_key(key_, &key, NULL))
            goto free_strings;
    }

    if (regex_) {
        if (regex_[0] == '!') {
            do_not_match = 1;
            regex_++;
        }

        regexp = (regex_t*)xmalloc(sizeof(regex_t));
        if (regcomp(regexp, regex_, REG_EXTENDED)) {
            fprintf(stderr, "Invalid pattern: %s\n", regex_);
            goto free_strings;
        }
    }

    fn = show_config;
    data = NULL;
    if (respect_includes) {
        inc.fn = fn;
        inc.data = data;
        fn = git_config_include;
        data = &inc;
    }

    if (do_all && system_wide)
        git_config_from_file(fn, system_wide, data);
    if (do_all && xdg)
        git_config_from_file(fn, xdg, data);
    if (do_all && global)
        git_config_from_file(fn, global, data);
    if (do_all)
        git_config_from_file(fn, local, data);
    git_config_from_parameters(fn, data);
    if (!do_all && !seen)
        git_config_from_file(fn, local, data);
    if (!do_all && !seen && global)
        git_config_from_file(fn, global, data);
    if (!do_all && !seen && xdg)
        git_config_from_file(fn, xdg, data);
    if (!do_all && !seen && system_wide)
        git_config_from_file(fn, system_wide, data);

    free(key);
    if (regexp) {
        regfree(regexp);
        free(regexp);
    }

    if (do_all)
        ret = !seen;
    else
        ret = (seen == 1) ? 0 : seen > 1 ? 2 : 1;

free_strings:
    free(repo_config);
    free(global);
    free(xdg);
    return ret;
}
Esempio n. 3
0
static int get_value(const char *key_, const char *regex_)
{
	int ret = -1;
	char *global = NULL, *repo_config = NULL;
	const char *system_wide = NULL, *local;

	local = config_exclusive_filename;
	if (!local) {
		const char *home = getenv("HOME");
		local = repo_config = git_pathdup("config");
		if (home)
			global = xstrdup(mkpath("%s/.gitconfig", home));
		if (git_config_system())
			system_wide = git_etc_gitconfig();
	}

	if (use_key_regexp) {
		char *tl;

		/*
		 * NEEDSWORK: this naive pattern lowercasing obviously does not
		 * work for more complex patterns like "^[^.]*Foo.*bar".
		 * Perhaps we should deprecate this altogether someday.
		 */

		key = xstrdup(key_);
		for (tl = key + strlen(key) - 1;
		     tl >= key && *tl != '.';
		     tl--)
			*tl = tolower(*tl);
		for (tl = key; *tl && *tl != '.'; tl++)
			*tl = tolower(*tl);

		key_regexp = (regex_t*)xmalloc(sizeof(regex_t));
		if (regcomp(key_regexp, key, REG_EXTENDED)) {
			fprintf(stderr, "Invalid key pattern: %s\n", key_);
			free(key);
			goto free_strings;
		}
	} else {
		if (git_config_parse_key(key_, &key, NULL))
			goto free_strings;
	}

	if (regex_) {
		if (regex_[0] == '!') {
			do_not_match = 1;
			regex_++;
		}

		regexp = (regex_t*)xmalloc(sizeof(regex_t));
		if (regcomp(regexp, regex_, REG_EXTENDED)) {
			fprintf(stderr, "Invalid pattern: %s\n", regex_);
			goto free_strings;
		}
	}

	if (do_all && system_wide)
		git_config_from_file(show_config, system_wide, NULL);
	if (do_all && global)
		git_config_from_file(show_config, global, NULL);
	if (do_all)
		git_config_from_file(show_config, local, NULL);
	git_config_from_parameters(show_config, NULL);
	if (!do_all && !seen)
		git_config_from_file(show_config, local, NULL);
	if (!do_all && !seen && global)
		git_config_from_file(show_config, global, NULL);
	if (!do_all && !seen && system_wide)
		git_config_from_file(show_config, system_wide, NULL);

	free(key);
	if (regexp) {
		regfree(regexp);
		free(regexp);
	}

	if (do_all)
		ret = !seen;
	else
		ret = (seen == 1) ? 0 : seen > 1 ? 2 : 1;

free_strings:
	free(repo_config);
	free(global);
	return ret;
}
Esempio n. 4
0
/*
 * If value==NULL, unset in (remove from) config,
 * if value_regex!=NULL, disregard key/value pairs where value does not match.
 * 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.
 *
 * 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,
	const char *value_regex, int multi_replace)
{
	int fd = -1, in_fd;
	int ret;
	char *config_filename;
	struct lock_file *lock = NULL;

	if (config_exclusive_filename)
		config_filename = xstrdup(config_exclusive_filename);
	else
		config_filename = git_pathdup("config");

	/* parse-key returns negative; flip the sign to feed exit(3) */
	ret = 0 - git_config_parse_key(key, &store.key, &store.baselen);
	if (ret)
		goto out_free;

	store.multi_replace = multi_replace;


	/*
	 * The lock serves a purpose in addition to locking: the new
	 * contents of .git/config will be written into it.
	 */
	lock = xcalloc(sizeof(struct lock_file), 1);
	fd = hold_lock_file_for_update(lock, config_filename, 0);
	if (fd < 0) {
		error("could not lock config file %s: %s", config_filename, strerror(errno));
		free(store.key);
		ret = -1;
		goto out_free;
	}

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

		if ( ENOENT != errno ) {
			error("opening %s: %s", config_filename,
			      strerror(errno));
			ret = 3; /* same as "invalid config file" */
			goto out_free;
		}
		/* if nothing to unset, error out */
		if (value == NULL) {
			ret = 5;
			goto out_free;
		}

		store.key = (char *)key;
		if (!store_write_section(fd, key) ||
		    !store_write_pair(fd, key, value))
			goto write_err_out;
	} else {
		struct stat st;
		char *contents;
		size_t contents_sz, copy_begin, copy_end;
		int i, new_line = 0;

		if (value_regex == NULL)
			store.value_regex = NULL;
		else {
			if (value_regex[0] == '!') {
				store.do_not_match = 1;
				value_regex++;
			} else
				store.do_not_match = 0;

			store.value_regex = (regex_t*)xmalloc(sizeof(regex_t));
			if (regcomp(store.value_regex, value_regex,
					REG_EXTENDED)) {
				error("invalid pattern: %s", value_regex);
				free(store.value_regex);
				ret = 6;
				goto out_free;
			}
		}

		store.offset[0] = 0;
		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.
		 */
		if (git_config_from_file(store_aux, config_filename, NULL)) {
			error("invalid config file %s", config_filename);
			free(store.key);
			if (store.value_regex != NULL) {
				regfree(store.value_regex);
				free(store.value_regex);
			}
			ret = 3;
			goto out_free;
		}

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

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

		fstat(in_fd, &st);
		contents_sz = xsize_t(st.st_size);
		contents = xmmap(NULL, contents_sz, PROT_READ,
			MAP_PRIVATE, in_fd, 0);
		close(in_fd);

		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 = contents_sz;
			} else if (store.state != KEY_SEEN) {
				copy_end = store.offset[i];
			} else
				copy_end = find_beginning_of_line(
					contents, contents_sz,
					store.offset[i]-2, &new_line);

			if (copy_end > 0 && contents[copy_end-1] != '\n')
				new_line = 1;

			/* write the first part of the config */
			if (copy_end > copy_begin) {
				if (write_in_full(fd, contents + copy_begin,
						  copy_end - copy_begin) <
				    copy_end - copy_begin)
					goto write_err_out;
				if (new_line &&
				    write_str_in_full(fd, "\n") != 1)
					goto write_err_out;
			}
			copy_begin = store.offset[i];
		}

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

		/* write the rest of the config */
		if (copy_begin < contents_sz)
			if (write_in_full(fd, contents + copy_begin,
					  contents_sz - copy_begin) <
			    contents_sz - copy_begin)
				goto write_err_out;

		munmap(contents, contents_sz);
	}

	if (commit_lock_file(lock) < 0) {
		error("could not commit config file %s", config_filename);
		ret = 4;
		goto out_free;
	}

	/*
	 * lock is committed, so don't try to roll it back below.
	 * NOTE: Since lockfile.c keeps a linked list of all created
	 * lock_file structures, it isn't safe to free(lock).  It's
	 * better to just leave it hanging around.
	 */
	lock = NULL;
	ret = 0;

out_free:
	if (lock)
		rollback_lock_file(lock);
	free(config_filename);
	return ret;

write_err_out:
	ret = write_error(lock->filename);
	goto out_free;

}