]> git.ipfire.org Git - thirdparty/git.git/blame - connect.c
git-send-pack: add "--all" option to send all refs to the other side
[thirdparty/git.git] / connect.c
CommitLineData
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
10int 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
28int 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
49enum protocol {
50 PROTO_LOCAL = 1,
51 PROTO_SSH,
52 PROTO_GIT,
53};
54
55static 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
64static 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
76static 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 */
109int 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
168int 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}