static struct child_process *git_proxy_connect(int fd[2], char *host) { const char *port = STR(DEFAULT_GIT_PORT); struct child_process *proxy; get_host_and_port(&host, &port); if (looks_like_command_line_option(host)) die("strange hostname '%s' blocked", host); if (looks_like_command_line_option(port)) die("strange port '%s' blocked", port); proxy = xmalloc(sizeof(*proxy)); child_process_init(proxy); argv_array_push(&proxy->args, git_proxy_command); argv_array_push(&proxy->args, host); argv_array_push(&proxy->args, port); proxy->in = -1; proxy->out = -1; if (start_command(proxy)) die("cannot start proxy %s", git_proxy_command); fd[0] = proxy->out; /* read from proxy stdout */ fd[1] = proxy->in; /* write to proxy stdin */ return proxy; }
/* Prepare a child_process for use by Git's SSH-tunneled transport. */ static void fill_ssh_args(struct child_process *conn, const char *ssh_host, const char *port, enum protocol_version version, int flags) { const char *ssh; enum ssh_variant variant; if (looks_like_command_line_option(ssh_host)) die(_("strange hostname '%s' blocked"), ssh_host); ssh = get_ssh_command(); if (ssh) { variant = determine_ssh_variant(ssh, 1); } else { /* * GIT_SSH is the no-shell version of * GIT_SSH_COMMAND (and must remain so for * historical compatibility). */ conn->use_shell = 0; ssh = getenv("GIT_SSH"); if (!ssh) ssh = "ssh"; variant = determine_ssh_variant(ssh, 0); } if (variant == VARIANT_AUTO) { struct child_process detect = CHILD_PROCESS_INIT; detect.use_shell = conn->use_shell; detect.no_stdin = detect.no_stdout = detect.no_stderr = 1; argv_array_push(&detect.args, ssh); argv_array_push(&detect.args, "-G"); push_ssh_options(&detect.args, &detect.env_array, VARIANT_SSH, port, version, flags); argv_array_push(&detect.args, ssh_host); variant = run_command(&detect) ? VARIANT_SIMPLE : VARIANT_SSH; } argv_array_push(&conn->args, ssh); push_ssh_options(&conn->args, &conn->env_array, variant, port, version, flags); argv_array_push(&conn->args, ssh_host); }
/* * This returns the dummy child_process `no_fork` if the transport protocol * does not need fork(2), or a struct child_process object if it does. Once * done, finish the connection with finish_connect() with the value returned * from this function (it is safe to call finish_connect() with NULL to * support the former case). * * If it returns, the connect is successful; it just dies on errors (this * will hopefully be changed in a libification effort, to return NULL when * the connection failed). */ struct child_process *git_connect(int fd[2], const char *url, const char *prog, int flags) { char *hostandport, *path; struct child_process *conn; enum protocol protocol; /* Without this we cannot rely on waitpid() to tell * what happened to our children. */ signal(SIGCHLD, SIG_DFL); protocol = parse_connect_url(url, &hostandport, &path); if ((flags & CONNECT_DIAG_URL) && (protocol != PROTO_SSH)) { printf("Diag: url=%s\n", url ? url : "NULL"); printf("Diag: protocol=%s\n", prot_name(protocol)); printf("Diag: hostandport=%s\n", hostandport ? hostandport : "NULL"); printf("Diag: path=%s\n", path ? path : "NULL"); conn = NULL; } else if (protocol == PROTO_GIT) { conn = git_connect_git(fd, hostandport, path, prog, flags); } else { struct strbuf cmd = STRBUF_INIT; const char *const *var; conn = xmalloc(sizeof(*conn)); child_process_init(conn); if (looks_like_command_line_option(path)) die("strange pathname '%s' blocked", path); strbuf_addstr(&cmd, prog); strbuf_addch(&cmd, ' '); sq_quote_buf(&cmd, path); /* remove repo-local variables from the environment */ for (var = local_repo_env; *var; var++) argv_array_push(&conn->env_array, *var); conn->use_shell = 1; conn->in = conn->out = -1; if (protocol == PROTO_SSH) { char *ssh_host = hostandport; const char *port = NULL; transport_check_allowed("ssh"); get_host_and_port(&ssh_host, &port); if (!port) port = get_port(ssh_host); if (flags & CONNECT_DIAG_URL) { printf("Diag: url=%s\n", url ? url : "NULL"); printf("Diag: protocol=%s\n", prot_name(protocol)); printf("Diag: userandhost=%s\n", ssh_host ? ssh_host : "NULL"); printf("Diag: port=%s\n", port ? port : "NONE"); printf("Diag: path=%s\n", path ? path : "NULL"); free(hostandport); free(path); free(conn); strbuf_release(&cmd); return NULL; } fill_ssh_args(conn, ssh_host, port, flags); } else { transport_check_allowed("file"); if (get_protocol_version_config() > 0) { argv_array_pushf(&conn->env_array, GIT_PROTOCOL_ENVIRONMENT "=version=%d", get_protocol_version_config()); } } argv_array_push(&conn->args, cmd.buf); if (start_command(conn)) die("unable to fork"); fd[0] = conn->out; /* read from child's stdout */ fd[1] = conn->in; /* write to child's stdin */ strbuf_release(&cmd); } free(hostandport); free(path); return conn; }
static int parse_config(const char *var, const char *value, void *data) { struct parse_config_parameter *me = data; struct submodule *submodule; struct strbuf name = STRBUF_INIT, item = STRBUF_INIT; int ret = 0; /* this also ensures that we only parse submodule entries */ if (!name_and_item_from_var(var, &name, &item)) return 0; submodule = lookup_or_create_by_name(me->cache, me->gitmodules_oid, name.buf); if (!strcmp(item.buf, "path")) { if (!value) ret = config_error_nonbool(var); else if (looks_like_command_line_option(value)) warn_command_line_option(var, value); else if (!me->overwrite && submodule->path) warn_multiple_config(me->treeish_name, submodule->name, "path"); else { if (submodule->path) cache_remove_path(me->cache, submodule); free((void *) submodule->path); submodule->path = xstrdup(value); cache_put_path(me->cache, submodule); } } else if (!strcmp(item.buf, "fetchrecursesubmodules")) { /* when parsing worktree configurations we can die early */ int die_on_error = is_null_oid(me->gitmodules_oid); if (!me->overwrite && submodule->fetch_recurse != RECURSE_SUBMODULES_NONE) warn_multiple_config(me->treeish_name, submodule->name, "fetchrecursesubmodules"); else submodule->fetch_recurse = parse_fetch_recurse( var, value, die_on_error); } else if (!strcmp(item.buf, "ignore")) { if (!value) ret = config_error_nonbool(var); else if (!me->overwrite && submodule->ignore) warn_multiple_config(me->treeish_name, submodule->name, "ignore"); else if (strcmp(value, "untracked") && strcmp(value, "dirty") && strcmp(value, "all") && strcmp(value, "none")) warning("Invalid parameter '%s' for config option " "'submodule.%s.ignore'", value, name.buf); else { free((void *) submodule->ignore); submodule->ignore = xstrdup(value); } } else if (!strcmp(item.buf, "url")) { if (!value) { ret = config_error_nonbool(var); } else if (looks_like_command_line_option(value)) { warn_command_line_option(var, value); } else if (!me->overwrite && submodule->url) { warn_multiple_config(me->treeish_name, submodule->name, "url"); } else { free((void *) submodule->url); submodule->url = xstrdup(value); } } else if (!strcmp(item.buf, "update")) { if (!value) ret = config_error_nonbool(var); else if (!me->overwrite && submodule->update_strategy.type != SM_UPDATE_UNSPECIFIED) warn_multiple_config(me->treeish_name, submodule->name, "update"); else if (parse_submodule_update_strategy(value, &submodule->update_strategy) < 0) die(_("invalid value for %s"), var); } else if (!strcmp(item.buf, "shallow")) { if (!me->overwrite && submodule->recommend_shallow != -1) warn_multiple_config(me->treeish_name, submodule->name, "shallow"); else submodule->recommend_shallow = git_config_bool(var, value); } else if (!strcmp(item.buf, "branch")) { if (!me->overwrite && submodule->branch) warn_multiple_config(me->treeish_name, submodule->name, "branch"); else { free((void *)submodule->branch); submodule->branch = xstrdup(value); } } strbuf_release(&name); strbuf_release(&item); return ret; }