diff options
Diffstat (limited to 'connect.c')
-rw-r--r-- | connect.c | 110 |
1 files changed, 62 insertions, 48 deletions
@@ -5,6 +5,7 @@ #include "refs.h" #include "run-command.h" #include "remote.h" +#include "url.h" static char *server_capabilities; @@ -131,7 +132,7 @@ int path_match(const char *path, int nr, char **match) enum protocol { PROTO_LOCAL = 1, PROTO_SSH, - PROTO_GIT, + PROTO_GIT }; static enum protocol get_protocol(const char *name) @@ -191,7 +192,8 @@ static const char *ai_name(const struct addrinfo *ai) */ static int git_tcp_connect_sock(char *host, int flags) { - int sockfd = -1, saved_errno = 0; + struct strbuf error_message = STRBUF_INIT; + int sockfd = -1; const char *port = STR(DEFAULT_GIT_PORT); struct addrinfo hints, *ai0, *ai; int gai; @@ -215,21 +217,15 @@ static int git_tcp_connect_sock(char *host, int flags) if (flags & CONNECT_VERBOSE) fprintf(stderr, "done.\nConnecting to %s (port %s) ... ", host, port); - for (ai0 = ai; ai; ai = ai->ai_next) { + for (ai0 = ai; ai; ai = ai->ai_next, cnt++) { sockfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); - if (sockfd < 0) { - saved_errno = errno; - continue; - } - if (connect(sockfd, ai->ai_addr, ai->ai_addrlen) < 0) { - saved_errno = errno; - fprintf(stderr, "%s[%d: %s]: errno=%s\n", - host, - cnt, - ai_name(ai), - strerror(saved_errno)); - close(sockfd); + if ((sockfd < 0) || + (connect(sockfd, ai->ai_addr, ai->ai_addrlen) < 0)) { + strbuf_addf(&error_message, "%s[%d: %s]: errno=%s\n", + host, cnt, ai_name(ai), strerror(errno)); + if (0 <= sockfd) + close(sockfd); sockfd = -1; continue; } @@ -241,11 +237,13 @@ static int git_tcp_connect_sock(char *host, int flags) freeaddrinfo(ai0); if (sockfd < 0) - die("unable to connect a socket (%s)", strerror(saved_errno)); + die("unable to connect to %s:\n%s", host, error_message.buf); if (flags & CONNECT_VERBOSE) fprintf(stderr, "done.\n"); + strbuf_release(&error_message); + return sockfd; } @@ -256,7 +254,8 @@ static int git_tcp_connect_sock(char *host, int flags) */ static int git_tcp_connect_sock(char *host, int flags) { - int sockfd = -1, saved_errno = 0; + struct strbuf error_message = STRBUF_INIT; + int sockfd = -1; const char *port = STR(DEFAULT_GIT_PORT); char *ep; struct hostent *he; @@ -286,25 +285,21 @@ static int git_tcp_connect_sock(char *host, int flags) fprintf(stderr, "done.\nConnecting to %s (port %s) ... ", host, port); for (cnt = 0, ap = he->h_addr_list; *ap; ap++, cnt++) { - sockfd = socket(he->h_addrtype, SOCK_STREAM, 0); - if (sockfd < 0) { - saved_errno = errno; - continue; - } - memset(&sa, 0, sizeof sa); sa.sin_family = he->h_addrtype; sa.sin_port = htons(nport); memcpy(&sa.sin_addr, *ap, he->h_length); - if (connect(sockfd, (struct sockaddr *)&sa, sizeof sa) < 0) { - saved_errno = errno; - fprintf(stderr, "%s[%d: %s]: errno=%s\n", + sockfd = socket(he->h_addrtype, SOCK_STREAM, 0); + if ((sockfd < 0) || + connect(sockfd, (struct sockaddr *)&sa, sizeof sa) < 0) { + strbuf_addf(&error_message, "%s[%d: %s]: errno=%s\n", host, cnt, inet_ntoa(*(struct in_addr *)&sa.sin_addr), - strerror(saved_errno)); - close(sockfd); + strerror(errno)); + if (0 <= sockfd) + close(sockfd); sockfd = -1; continue; } @@ -315,7 +310,7 @@ static int git_tcp_connect_sock(char *host, int flags) } if (sockfd < 0) - die("unable to connect a socket (%s)", strerror(saved_errno)); + die("unable to connect to %s:\n%s", host, error_message.buf); if (flags & CONNECT_VERBOSE) fprintf(stderr, "done.\n"); @@ -394,26 +389,28 @@ static int git_use_proxy(const char *host) return (git_proxy_command && *git_proxy_command); } -static void git_proxy_connect(int fd[2], char *host) +static struct child_process *git_proxy_connect(int fd[2], char *host) { const char *port = STR(DEFAULT_GIT_PORT); - const char *argv[4]; - struct child_process proxy; + const char **argv; + struct child_process *proxy; get_host_and_port(&host, &port); + argv = xmalloc(sizeof(*argv) * 4); argv[0] = git_proxy_command; argv[1] = host; argv[2] = port; argv[3] = NULL; - memset(&proxy, 0, sizeof(proxy)); - proxy.argv = argv; - proxy.in = -1; - proxy.out = -1; - if (start_command(&proxy)) + proxy = xcalloc(1, sizeof(*proxy)); + proxy->argv = argv; + proxy->in = -1; + proxy->out = -1; + if (start_command(proxy)) die("cannot start proxy %s", argv[0]); - fd[0] = proxy.out; /* read from proxy stdout */ - fd[1] = proxy.in; /* write to proxy stdin */ + fd[0] = proxy->out; /* read from proxy stdout */ + fd[1] = proxy->in; /* write to proxy stdin */ + return proxy; } #define MAX_CMD_LEN 1024 @@ -450,11 +447,11 @@ static struct child_process no_fork; struct child_process *git_connect(int fd[2], const char *url_orig, const char *prog, int flags) { - char *url = xstrdup(url_orig); + char *url; char *host, *path; char *end; int c; - struct child_process *conn; + struct child_process *conn = &no_fork; enum protocol protocol = PROTO_LOCAL; int free_path = 0; char *port = NULL; @@ -466,6 +463,11 @@ struct child_process *git_connect(int fd[2], const char *url_orig, */ signal(SIGCHLD, SIG_DFL); + if (is_url(url_orig)) + url = url_decode(url_orig); + else + url = xstrdup(url_orig); + host = strstr(url, "://"); if (host) { *host = '\0'; @@ -534,7 +536,7 @@ struct child_process *git_connect(int fd[2], const char *url_orig, */ char *target_host = xstrdup(host); if (git_use_proxy(host)) - git_proxy_connect(fd, host); + conn = git_proxy_connect(fd, host); else git_tcp_connect(fd, host, flags); /* @@ -552,7 +554,7 @@ struct child_process *git_connect(int fd[2], const char *url_orig, free(url); if (free_path) free(path); - return &no_fork; + return conn; } conn = xcalloc(1, sizeof(*conn)); @@ -601,10 +603,15 @@ struct child_process *git_connect(int fd[2], const char *url_orig, return conn; } +int git_connection_is_socket(struct child_process *conn) +{ + return conn == &no_fork; +} + int finish_connect(struct child_process *conn) { int code; - if (!conn || conn == &no_fork) + if (!conn || git_connection_is_socket(conn)) return 0; code = finish_command(conn); @@ -615,15 +622,22 @@ int finish_connect(struct child_process *conn) char *git_getpass(const char *prompt) { - char *askpass; + const char *askpass; struct child_process pass; const char *args[3]; static struct strbuf buffer = STRBUF_INIT; askpass = getenv("GIT_ASKPASS"); - - if (!askpass || !(*askpass)) - return getpass(prompt); + if (!askpass) + askpass = askpass_program; + if (!askpass) + askpass = getenv("SSH_ASKPASS"); + if (!askpass || !(*askpass)) { + char *result = getpass(prompt); + if (!result) + die_errno("Could not read password"); + return result; + } args[0] = askpass; args[1] = prompt; |