Fix git-fetch-script breakage
[git/gitweb.git] / connect.c
blobf01b547574636d109f14c791287e6f4e52502de2
1 #include "cache.h"
2 #include "pkt-line.h"
3 #include "quote.h"
4 #include <sys/wait.h>
5 #include <sys/socket.h>
6 #include <netinet/in.h>
7 #include <arpa/inet.h>
8 #include <netdb.h>
10 int get_ack(int fd, unsigned char *result_sha1)
12 static char line[1000];
13 int len = packet_read_line(fd, line, sizeof(line));
15 if (!len)
16 die("git-fetch-pack: expected ACK/NAK, got EOF");
17 if (line[len-1] == '\n')
18 line[--len] = 0;
19 if (!strcmp(line, "NAK"))
20 return 0;
21 if (!strncmp(line, "ACK ", 3)) {
22 if (!get_sha1_hex(line+4, result_sha1))
23 return 1;
25 die("git-fetch_pack: expected ACK/NAK, got '%s'", line);
28 int path_match(const char *path, int nr, char **match)
30 int i;
31 int pathlen = strlen(path);
33 for (i = 0; i < nr; i++) {
34 char *s = match[i];
35 int len = strlen(s);
37 if (!len || len > pathlen)
38 continue;
39 if (memcmp(path + pathlen - len, s, len))
40 continue;
41 if (pathlen > len && path[pathlen - len - 1] != '/')
42 continue;
43 *s = 0;
44 return 1;
46 return 0;
49 enum protocol {
50 PROTO_LOCAL = 1,
51 PROTO_SSH,
52 PROTO_GIT,
55 static enum protocol get_protocol(const char *name)
57 if (!strcmp(name, "ssh"))
58 return PROTO_SSH;
59 if (!strcmp(name, "git"))
60 return PROTO_GIT;
61 die("I don't handle protocol '%s'", name);
64 static void lookup_host(const char *host, struct sockaddr *in)
66 struct addrinfo *res;
67 int ret;
69 ret = getaddrinfo(host, NULL, NULL, &res);
70 if (ret)
71 die("Unable to look up %s (%s)", host, gai_strerror(ret));
72 *in = *res->ai_addr;
73 freeaddrinfo(res);
76 static int git_tcp_connect(int fd[2], const char *prog, char *host, char *path)
78 struct sockaddr addr;
79 int port = DEFAULT_GIT_PORT, sockfd;
80 char *colon;
82 colon = strchr(host, ':');
83 if (colon) {
84 char *end;
85 unsigned long n = strtoul(colon+1, &end, 0);
86 if (colon[1] && !*end) {
87 *colon = 0;
88 port = n;
92 lookup_host(host, &addr);
93 ((struct sockaddr_in *)&addr)->sin_port = htons(port);
95 sockfd = socket(PF_INET, SOCK_STREAM, IPPROTO_IP);
96 if (sockfd < 0)
97 die("unable to create socket (%s)", strerror(errno));
98 if (connect(sockfd, (void *)&addr, sizeof(addr)) < 0)
99 die("unable to connect (%s)", strerror(errno));
100 fd[0] = sockfd;
101 fd[1] = sockfd;
102 packet_write(sockfd, "%s %s\n", prog, path);
103 return 0;
107 * Yeah, yeah, fixme. Need to pass in the heads etc.
109 int git_connect(int fd[2], char *url, const char *prog)
111 char command[1024];
112 char *host, *path;
113 char *colon;
114 int pipefd[2][2];
115 pid_t pid;
116 enum protocol protocol;
118 host = NULL;
119 path = url;
120 colon = strchr(url, ':');
121 protocol = PROTO_LOCAL;
122 if (colon) {
123 *colon = 0;
124 host = url;
125 path = colon+1;
126 protocol = PROTO_SSH;
127 if (!memcmp(path, "//", 2)) {
128 char *slash = strchr(path + 2, '/');
129 if (slash) {
130 int nr = slash - path - 2;
131 memmove(path, path+2, nr);
132 path[nr] = 0;
133 protocol = get_protocol(url);
134 host = path;
135 path = slash;
140 if (protocol == PROTO_GIT)
141 return git_tcp_connect(fd, prog, host, path);
143 if (pipe(pipefd[0]) < 0 || pipe(pipefd[1]) < 0)
144 die("unable to create pipe pair for communication");
145 pid = fork();
146 if (!pid) {
147 snprintf(command, sizeof(command), "%s %s", prog,
148 sq_quote(path));
149 dup2(pipefd[1][0], 0);
150 dup2(pipefd[0][1], 1);
151 close(pipefd[0][0]);
152 close(pipefd[0][1]);
153 close(pipefd[1][0]);
154 close(pipefd[1][1]);
155 if (protocol == PROTO_SSH)
156 execlp("ssh", "ssh", host, command, NULL);
157 else
158 execlp("sh", "sh", "-c", command, NULL);
159 die("exec failed");
161 fd[0] = pipefd[0][0];
162 fd[1] = pipefd[1][1];
163 close(pipefd[0][1]);
164 close(pipefd[1][0]);
165 return pid;
168 int finish_connect(pid_t pid)
170 int ret;
172 for (;;) {
173 ret = waitpid(pid, NULL, 0);
174 if (!ret)
175 break;
176 if (errno != EINTR)
177 break;
179 return ret;