static void setup_pager_env(struct argv_array *env) { const char **argv; int i; char *pager_env = xstrdup(PAGER_ENV); int n = split_cmdline(pager_env, &argv); if (n < 0) die("malformed build-time PAGER_ENV: %s", split_cmdline_strerror(n)); for (i = 0; i < n; i++) { char *cp = strchr(argv[i], '='); if (!cp) die("malformed build-time PAGER_ENV"); *cp = '\0'; if (!getenv(argv[i])) { *cp = '='; argv_array_push(env, argv[i]); } } free(pager_env); free(argv); }
static void run_shell(void) { int done = 0; static const char *help_argv[] = { HELP_COMMAND, NULL }; /* Print help if enabled */ run_command_v_opt(help_argv, RUN_SILENT_EXEC_FAILURE); do { struct strbuf line = STRBUF_INIT; const char *prog; char *full_cmd; char *rawargs; char *split_args; const char **argv; int code; int count; fprintf(stderr, "git> "); if (strbuf_getline(&line, stdin, '\n') == EOF) { fprintf(stderr, "\n"); strbuf_release(&line); break; } strbuf_trim(&line); rawargs = strbuf_detach(&line, NULL); split_args = xstrdup(rawargs); count = split_cmdline(split_args, &argv); if (count < 0) { fprintf(stderr, "invalid command format '%s': %s\n", rawargs, split_cmdline_strerror(count)); free(split_args); free(rawargs); continue; } prog = argv[0]; if (!strcmp(prog, "")) { } else if (!strcmp(prog, "quit") || !strcmp(prog, "logout") || !strcmp(prog, "exit") || !strcmp(prog, "bye")) { done = 1; } else if (is_valid_cmd_name(prog)) { full_cmd = make_cmd(prog); argv[0] = full_cmd; code = run_command_v_opt(argv, RUN_SILENT_EXEC_FAILURE); if (code == -1 && errno == ENOENT) { fprintf(stderr, "unrecognized command '%s'\n", prog); } free(full_cmd); } else { fprintf(stderr, "invalid command format '%s'\n", prog); } free(argv); free(rawargs); } while (!done); }
static void parse_branch_merge_options(char *bmo) { const char **argv; int argc; if (!bmo) return; argc = split_cmdline(bmo, &argv); if (argc < 0) die(_("Bad branch.%s.mergeoptions string: %s"), branch, split_cmdline_strerror(argc)); argv = xrealloc(argv, sizeof(*argv) * (argc + 2)); memmove(argv + 1, argv, sizeof(*argv) * (argc + 1)); argc++; argv[0] = "branch.*.mergeoptions"; parse_options(argc, argv, NULL, builtin_merge_options, builtin_merge_usage, 0); free(argv); }
static int git_merge_config(const char *k, const char *v, void *cb) { if (branch && !prefixcmp(k, "branch.") && !prefixcmp(k + 7, branch) && !strcmp(k + 7 + strlen(branch), ".mergeoptions")) { const char **argv; int argc; char *buf; buf = xstrdup(v); argc = split_cmdline(buf, &argv); if (argc < 0) die("Bad branch.%s.mergeoptions string: %s", branch, split_cmdline_strerror(argc)); argv = xrealloc(argv, sizeof(*argv) * (argc + 2)); memmove(argv + 1, argv, sizeof(*argv) * (argc + 1)); argc++; parse_options(argc, argv, NULL, builtin_merge_options, builtin_merge_usage, 0); free(buf); } if (!strcmp(k, "merge.diffstat") || !strcmp(k, "merge.stat")) show_diffstat = git_config_bool(k, v); else if (!strcmp(k, "pull.twohead")) return git_config_string(&pull_twohead, k, v); else if (!strcmp(k, "pull.octopus")) return git_config_string(&pull_octopus, k, v); else if (!strcmp(k, "merge.renormalize")) option_renormalize = git_config_bool(k, v); else if (!strcmp(k, "merge.log") || !strcmp(k, "merge.summary")) { int is_bool; shortlog_len = git_config_bool_or_int(k, v, &is_bool); if (!is_bool && shortlog_len < 0) return error("%s: negative length %s", k, v); if (is_bool && shortlog_len) shortlog_len = DEFAULT_MERGE_LOG_LEN; return 0; } return git_diff_ui_config(k, v, cb); }
static int handle_alias(int *argcp, const char ***argv) { int envchanged = 0, ret = 0, saved_errno = errno; int count, option_count; const char **new_argv; const char *alias_command; char *alias_string; alias_command = (*argv)[0]; alias_string = alias_lookup(alias_command); if (alias_string) { if (alias_string[0] == '!') { struct child_process child = CHILD_PROCESS_INIT; int nongit_ok; /* Aliases expect GIT_PREFIX, GIT_DIR etc to be set */ setup_git_directory_gently(&nongit_ok); commit_pager_choice(); child.use_shell = 1; argv_array_push(&child.args, alias_string + 1); argv_array_pushv(&child.args, (*argv) + 1); ret = run_command(&child); if (ret >= 0) /* normal exit */ exit(ret); die_errno("while expanding alias '%s': '%s'", alias_command, alias_string + 1); } count = split_cmdline(alias_string, &new_argv); if (count < 0) die("Bad alias.%s string: %s", alias_command, split_cmdline_strerror(count)); option_count = handle_options(&new_argv, &count, &envchanged); if (envchanged) die("alias '%s' changes environment variables.\n" "You can use '!git' in the alias to do this", alias_command); memmove(new_argv - option_count, new_argv, count * sizeof(char *)); new_argv -= option_count; if (count < 1) die("empty alias for %s", alias_command); if (!strcmp(alias_command, new_argv[0])) die("recursive alias: %s", alias_command); trace_argv_printf(new_argv, "trace: alias expansion: %s =>", alias_command); REALLOC_ARRAY(new_argv, count + *argcp); /* insert after command name */ memcpy(new_argv + count, *argv + 1, sizeof(char *) * *argcp); *argv = new_argv; *argcp += count - 1; ret = 1; } errno = saved_errno; return ret; }
int main(int argc, char **argv) { char *prog; const char **user_argv; struct commands *cmd; int devnull_fd; int count; git_setup_gettext(); git_extract_argv0_path(argv[0]); /* * Always open file descriptors 0/1/2 to avoid clobbering files * in die(). It also avoids not messing up when the pipes are * dup'ed onto stdin/stdout/stderr in the child processes we spawn. */ devnull_fd = open("/dev/null", O_RDWR); while (devnull_fd >= 0 && devnull_fd <= 2) devnull_fd = dup(devnull_fd); if (devnull_fd == -1) die_errno("opening /dev/null failed"); close (devnull_fd); /* * Special hack to pretend to be a CVS server */ if (argc == 2 && !strcmp(argv[1], "cvs server")) { argv--; } else if (argc == 1) { /* Allow the user to run an interactive shell */ cd_to_homedir(); if (access(COMMAND_DIR, R_OK | X_OK) == -1) { die("Interactive git shell is not enabled.\n" "hint: ~/" COMMAND_DIR " should exist " "and have read and execute access."); } run_shell(); exit(0); } else if (argc != 3 || strcmp(argv[1], "-c")) { /* * We do not accept any other modes except "-c" followed by * "cmd arg", where "cmd" is a very limited subset of git * commands or a command in the COMMAND_DIR */ die("Run with no arguments or with -c cmd"); } prog = xstrdup(argv[2]); if (!strncmp(prog, "git", 3) && isspace(prog[3])) /* Accept "git foo" as if the caller said "git-foo". */ prog[3] = '-'; for (cmd = cmd_list ; cmd->name ; cmd++) { int len = strlen(cmd->name); char *arg; if (strncmp(cmd->name, prog, len)) continue; arg = NULL; switch (prog[len]) { case '\0': arg = NULL; break; case ' ': arg = prog + len + 1; break; default: continue; } exit(cmd->exec(cmd->name, arg)); } cd_to_homedir(); count = split_cmdline(prog, &user_argv); if (count >= 0) { if (is_valid_cmd_name(user_argv[0])) { prog = make_cmd(user_argv[0]); user_argv[0] = prog; execv(user_argv[0], (char *const *) user_argv); } free(prog); free(user_argv); die("unrecognized command '%s'", argv[2]); } else { free(prog); die("invalid command format '%s': %s", argv[2], split_cmdline_strerror(count)); } }
static int handle_alias(int *argcp, const char ***argv) { int envchanged = 0, ret = 0, saved_errno = errno; const char *subdir; int count, option_count; const char **new_argv; const char *alias_command; char *alias_string; int unused_nongit; subdir = setup_git_directory_gently(&unused_nongit); alias_command = (*argv)[0]; alias_string = alias_lookup(alias_command); if (alias_string) { if (alias_string[0] == '!') { commit_pager_choice(); if (*argcp > 1) { struct strbuf buf; strbuf_init(&buf, PATH_MAX); strbuf_addstr(&buf, alias_string); sq_quote_argv(&buf, (*argv) + 1, PATH_MAX); free(alias_string); alias_string = buf.buf; } trace_printf("trace: alias to shell cmd: %s => %s\n", alias_command, alias_string + 1); ret = system(alias_string + 1); if (ret >= 0 && WIFEXITED(ret) && WEXITSTATUS(ret) != 127) exit(WEXITSTATUS(ret)); die("Failed to run '%s' when expanding alias '%s'", alias_string + 1, alias_command); } count = split_cmdline(alias_string, &new_argv); if (count < 0) die("Bad alias.%s string: %s", alias_command, split_cmdline_strerror(count)); option_count = handle_options(&new_argv, &count, &envchanged); if (envchanged) die("alias '%s' changes environment variables\n" "You can use '!git' in the alias to do this.", alias_command); memmove(new_argv - option_count, new_argv, count * sizeof(char *)); new_argv -= option_count; if (count < 1) die("empty alias for %s", alias_command); if (!strcmp(alias_command, new_argv[0])) die("recursive alias: %s", alias_command); trace_argv_printf(new_argv, "trace: alias expansion: %s =>", alias_command); new_argv = xrealloc(new_argv, sizeof(char *) * (count + *argcp)); /* insert after command name */ memcpy(new_argv + count, *argv + 1, sizeof(char *) * *argcp); *argv = new_argv; *argcp += count - 1; ret = 1; } if (subdir && chdir(subdir)) die_errno("Cannot change to '%s'", subdir); errno = saved_errno; return ret; }
static int handle_alias(int *argcp, const char ***argv) { int envchanged = 0, ret = 0, saved_errno = errno; const char *subdir; int count, option_count; const char **new_argv; const char *alias_command; char *alias_string; int unused_nongit; subdir = setup_git_directory_gently(&unused_nongit); alias_command = (*argv)[0]; alias_string = alias_lookup(alias_command); if (alias_string) { if (alias_string[0] == '!') { const char **alias_argv; int argc = *argcp, i; commit_pager_choice(); /* build alias_argv */ alias_argv = xmalloc(sizeof(*alias_argv) * (argc + 1)); alias_argv[0] = alias_string + 1; for (i = 1; i < argc; ++i) alias_argv[i] = (*argv)[i]; alias_argv[argc] = NULL; ret = run_command_v_opt(alias_argv, RUN_USING_SHELL); if (ret >= 0) /* normal exit */ exit(ret); die_errno("While expanding alias '%s': '%s'", alias_command, alias_string + 1); } count = split_cmdline(alias_string, &new_argv); if (count < 0) die("Bad alias.%s string: %s", alias_command, split_cmdline_strerror(count)); option_count = handle_options(&new_argv, &count, &envchanged); if (envchanged) die("alias '%s' changes environment variables\n" "You can use '!git' in the alias to do this.", alias_command); memmove(new_argv - option_count, new_argv, count * sizeof(char *)); new_argv -= option_count; if (count < 1) die("empty alias for %s", alias_command); if (!strcmp(alias_command, new_argv[0])) die("recursive alias: %s", alias_command); trace_argv_printf(new_argv, "trace: alias expansion: %s =>", alias_command); new_argv = xrealloc(new_argv, sizeof(char *) * (count + *argcp)); /* insert after command name */ memcpy(new_argv + count, *argv + 1, sizeof(char *) * *argcp); *argv = new_argv; *argcp += count - 1; ret = 1; } if (subdir && chdir(subdir)) die_errno("Cannot change to '%s'", subdir); errno = saved_errno; return ret; }
int cmd_main(int argc, const char **argv) { char *prog; const char **user_argv; struct commands *cmd; int count; /* * Special hack to pretend to be a CVS server */ if (argc == 2 && !strcmp(argv[1], "cvs server")) { argv--; } else if (argc == 1) { /* Allow the user to run an interactive shell */ cd_to_homedir(); if (access(COMMAND_DIR, R_OK | X_OK) == -1) { die("Interactive git shell is not enabled.\n" "hint: ~/" COMMAND_DIR " should exist " "and have read and execute access."); } run_shell(); exit(0); } else if (argc != 3 || strcmp(argv[1], "-c")) { /* * We do not accept any other modes except "-c" followed by * "cmd arg", where "cmd" is a very limited subset of git * commands or a command in the COMMAND_DIR */ die("Run with no arguments or with -c cmd"); } prog = xstrdup(argv[2]); if (!strncmp(prog, "git", 3) && isspace(prog[3])) /* Accept "git foo" as if the caller said "git-foo". */ prog[3] = '-'; for (cmd = cmd_list ; cmd->name ; cmd++) { int len = strlen(cmd->name); char *arg; if (strncmp(cmd->name, prog, len)) continue; arg = NULL; switch (prog[len]) { case '\0': arg = NULL; break; case ' ': arg = prog + len + 1; break; default: continue; } exit(cmd->exec(cmd->name, arg)); } cd_to_homedir(); count = split_cmdline(prog, &user_argv); if (count >= 0) { if (is_valid_cmd_name(user_argv[0])) { prog = make_cmd(user_argv[0]); user_argv[0] = prog; execv(user_argv[0], (char *const *) user_argv); } free(prog); free(user_argv); die("unrecognized command '%s'", argv[2]); } else { free(prog); die("invalid command format '%s': %s", argv[2], split_cmdline_strerror(count)); } }