]>
Commit | Line | Data |
---|---|---|
f7192598 | 1 | #include "cache.h" |
41cb7488 | 2 | #include "pkt-line.h" |
b10d0ec7 | 3 | #include "quote.h" |
f7192598 | 4 | #include <sys/wait.h> |
2386d658 LT |
5 | #include <sys/socket.h> |
6 | #include <netinet/in.h> | |
7 | #include <arpa/inet.h> | |
8 | #include <netdb.h> | |
f7192598 | 9 | |
41cb7488 LT |
10 | int get_ack(int fd, unsigned char *result_sha1) |
11 | { | |
12 | static char line[1000]; | |
13 | int len = packet_read_line(fd, line, sizeof(line)); | |
14 | ||
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; | |
24 | } | |
25 | die("git-fetch_pack: expected ACK/NAK, got '%s'", line); | |
26 | } | |
27 | ||
013e7c7f LT |
28 | int path_match(const char *path, int nr, char **match) |
29 | { | |
30 | int i; | |
31 | int pathlen = strlen(path); | |
32 | ||
33 | for (i = 0; i < nr; i++) { | |
34 | char *s = match[i]; | |
35 | int len = strlen(s); | |
36 | ||
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; | |
45 | } | |
46 | return 0; | |
47 | } | |
48 | ||
2386d658 LT |
49 | enum protocol { |
50 | PROTO_LOCAL = 1, | |
51 | PROTO_SSH, | |
52 | PROTO_GIT, | |
53 | }; | |
54 | ||
55 | static enum protocol get_protocol(const char *name) | |
56 | { | |
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); | |
62 | } | |
63 | ||
64 | static void lookup_host(const char *host, struct sockaddr *in) | |
65 | { | |
66 | struct addrinfo *res; | |
67 | int ret; | |
68 | ||
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); | |
74 | } | |
75 | ||
76 | static int git_tcp_connect(int fd[2], const char *prog, char *host, char *path) | |
77 | { | |
78 | struct sockaddr addr; | |
79 | int port = DEFAULT_GIT_PORT, sockfd; | |
80 | char *colon; | |
81 | ||
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; | |
89 | } | |
90 | } | |
91 | ||
92 | lookup_host(host, &addr); | |
93 | ((struct sockaddr_in *)&addr)->sin_port = htons(port); | |
94 | ||
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; | |
104 | } | |
105 | ||
f7192598 LT |
106 | /* |
107 | * Yeah, yeah, fixme. Need to pass in the heads etc. | |
108 | */ | |
109 | int git_connect(int fd[2], char *url, const char *prog) | |
110 | { | |
111 | char command[1024]; | |
2386d658 | 112 | char *host, *path; |
f7192598 LT |
113 | char *colon; |
114 | int pipefd[2][2]; | |
115 | pid_t pid; | |
2386d658 | 116 | enum protocol protocol; |
f7192598 | 117 | |
f7192598 LT |
118 | host = NULL; |
119 | path = url; | |
120 | colon = strchr(url, ':'); | |
2386d658 | 121 | protocol = PROTO_LOCAL; |
f7192598 LT |
122 | if (colon) { |
123 | *colon = 0; | |
124 | host = url; | |
125 | path = colon+1; | |
2386d658 LT |
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; | |
136 | } | |
137 | } | |
f7192598 | 138 | } |
2386d658 LT |
139 | |
140 | if (protocol == PROTO_GIT) | |
141 | return git_tcp_connect(fd, prog, host, path); | |
142 | ||
f7192598 LT |
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) { | |
b10d0ec7 JH |
147 | snprintf(command, sizeof(command), "%s %s", prog, |
148 | sq_quote(path)); | |
f7192598 LT |
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]); | |
2386d658 | 155 | if (protocol == PROTO_SSH) |
f7192598 LT |
156 | execlp("ssh", "ssh", host, command, NULL); |
157 | else | |
158 | execlp("sh", "sh", "-c", command, NULL); | |
159 | die("exec failed"); | |
160 | } | |
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; | |
166 | } | |
167 | ||
168 | int finish_connect(pid_t pid) | |
169 | { | |
170 | int ret; | |
171 | ||
172 | for (;;) { | |
173 | ret = waitpid(pid, NULL, 0); | |
174 | if (!ret) | |
175 | break; | |
176 | if (errno != EINTR) | |
177 | break; | |
178 | } | |
179 | return ret; | |
180 | } |