]> git.ipfire.org Git - thirdparty/git.git/blame - daemon.c
[PATCH] Update git-daemon documentation wrt. the --verbose parameter
[thirdparty/git.git] / daemon.c
CommitLineData
a87e8be2
LT
1#include "cache.h"
2#include "pkt-line.h"
eaa94919
LT
3#include <signal.h>
4#include <sys/wait.h>
a87e8be2 5#include <sys/socket.h>
3cd6ecda 6#include <sys/time.h>
df076bdb 7#include <netdb.h>
a87e8be2 8#include <netinet/in.h>
f8ff0c06
PB
9#include <arpa/inet.h>
10
11static int verbose;
12
13static const char daemon_usage[] = "git-daemon [--verbose] [--inetd | --port=n]";
14
15
16static void logreport(const char *err, va_list params)
17{
18 /* We should do a single write so that it is atomic and output
19 * of several processes do not get intermingled. */
20 char buf[1024];
21 int buflen;
22 int maxlen, msglen;
23
24 /* sizeof(buf) should be big enough for "[pid] \n" */
1bedd4ca 25 buflen = snprintf(buf, sizeof(buf), "[%ld] ", (long) getpid());
f8ff0c06
PB
26
27 maxlen = sizeof(buf) - buflen - 1; /* -1 for our own LF */
28 msglen = vsnprintf(buf + buflen, maxlen, err, params);
29
30 /* maxlen counted our own LF but also counts space given to
31 * vsnprintf for the terminating NUL. We want to make sure that
32 * we have space for our own LF and NUL after the "meat" of the
33 * message, so truncate it at maxlen - 1.
34 */
35 if (msglen > maxlen - 1)
36 msglen = maxlen - 1;
37 else if (msglen < 0)
38 msglen = 0; /* Protect against weird return values. */
39 buflen += msglen;
40
41 buf[buflen++] = '\n';
42 buf[buflen] = '\0';
43
44 write(2, buf, buflen);
45}
46
47void logerror(const char *err, ...)
48{
49 va_list params;
50 va_start(params, err);
51 logreport(err, params);
52 va_end(params);
53}
54
55void lognotice(const char *err, ...)
56{
57 va_list params;
58 if (!verbose)
59 return;
60 va_start(params, err);
61 logreport(err, params);
62 va_end(params);
63}
a87e8be2 64
a87e8be2
LT
65
66static int upload(char *dir, int dirlen)
67{
f8ff0c06
PB
68 lognotice("Request for '%s'", dir);
69 if (chdir(dir) < 0) {
70 logerror("Cannot chdir('%s'): %s", dir, strerror(errno));
a87e8be2 71 return -1;
f8ff0c06 72 }
a87e8be2
LT
73 chdir(".git");
74
75 /*
76 * Security on the cheap.
77 *
78 * We want a readable HEAD, usable "objects" directory, and
79 * a "git-daemon-export-ok" flag that says that the other side
80 * is ok with us doing this.
81 */
82 if (access("git-daemon-export-ok", F_OK) ||
83 access("objects/00", X_OK) ||
f8ff0c06
PB
84 access("HEAD", R_OK)) {
85 logerror("Not a valid gitd-enabled repository: '%s'", dir);
a87e8be2 86 return -1;
f8ff0c06 87 }
a87e8be2 88
02d57da4
LT
89 /*
90 * We'll ignore SIGTERM from now on, we have a
91 * good client.
92 */
93 signal(SIGTERM, SIG_IGN);
94
a87e8be2
LT
95 /* git-upload-pack only ever reads stuff, so this is safe */
96 execlp("git-upload-pack", "git-upload-pack", ".", NULL);
97 return -1;
98}
99
7d80694a 100static int execute(void)
a87e8be2 101{
7d80694a
LT
102 static char line[1000];
103 int len;
104
105 len = packet_read_line(0, line, sizeof(line));
106
107 if (len && line[len-1] == '\n')
108 line[--len] = 0;
109
a87e8be2
LT
110 if (!strncmp("git-upload-pack /", line, 17))
111 return upload(line + 16, len - 16);
112
f8ff0c06 113 logerror("Protocol error: '%s'", line);
a87e8be2
LT
114 return -1;
115}
116
66e631de
LT
117
118/*
119 * We count spawned/reaped separately, just to avoid any
120 * races when updating them from signals. The SIGCHLD handler
121 * will only update children_reaped, and the fork logic will
122 * only update children_spawned.
123 *
124 * MAX_CHILDREN should be a power-of-two to make the modulus
125 * operation cheap. It should also be at least twice
126 * the maximum number of connections we will ever allow.
127 */
128#define MAX_CHILDREN 128
129
130static int max_connections = 25;
131
132/* These are updated by the signal handler */
133static volatile unsigned int children_reaped = 0;
4d8fa916 134static pid_t dead_child[MAX_CHILDREN];
66e631de
LT
135
136/* These are updated by the main loop */
137static unsigned int children_spawned = 0;
138static unsigned int children_deleted = 0;
139
4d8fa916 140static struct child {
66e631de 141 pid_t pid;
7fa09084 142 int addrlen;
df076bdb 143 struct sockaddr_storage address;
66e631de
LT
144} live_child[MAX_CHILDREN];
145
7fa09084 146static void add_child(int idx, pid_t pid, struct sockaddr *addr, int addrlen)
66e631de
LT
147{
148 live_child[idx].pid = pid;
149 live_child[idx].addrlen = addrlen;
df076bdb 150 memcpy(&live_child[idx].address, addr, addrlen);
66e631de
LT
151}
152
153/*
154 * Walk from "deleted" to "spawned", and remove child "pid".
155 *
156 * We move everything up by one, since the new "deleted" will
157 * be one higher.
158 */
159static void remove_child(pid_t pid, unsigned deleted, unsigned spawned)
160{
161 struct child n;
162
163 deleted %= MAX_CHILDREN;
164 spawned %= MAX_CHILDREN;
165 if (live_child[deleted].pid == pid) {
166 live_child[deleted].pid = -1;
167 return;
168 }
169 n = live_child[deleted];
170 for (;;) {
171 struct child m;
172 deleted = (deleted + 1) % MAX_CHILDREN;
173 if (deleted == spawned)
174 die("could not find dead child %d\n", pid);
175 m = live_child[deleted];
176 live_child[deleted] = n;
177 if (m.pid == pid)
178 return;
179 n = m;
180 }
181}
182
183/*
184 * This gets called if the number of connections grows
185 * past "max_connections".
186 *
187 * We _should_ start off by searching for connections
188 * from the same IP, and if there is some address wth
189 * multiple connections, we should kill that first.
190 *
191 * As it is, we just "randomly" kill 25% of the connections,
192 * and our pseudo-random generator sucks too. I have no
193 * shame.
194 *
195 * Really, this is just a place-holder for a _real_ algorithm.
196 */
02d57da4 197static void kill_some_children(int signo, unsigned start, unsigned stop)
66e631de
LT
198{
199 start %= MAX_CHILDREN;
200 stop %= MAX_CHILDREN;
201 while (start != stop) {
202 if (!(start & 3))
02d57da4 203 kill(live_child[start].pid, signo);
66e631de
LT
204 start = (start + 1) % MAX_CHILDREN;
205 }
206}
207
02d57da4 208static void check_max_connections(void)
a87e8be2 209{
02d57da4 210 for (;;) {
eaa94919 211 int active;
66e631de 212 unsigned spawned, reaped, deleted;
eaa94919 213
66e631de 214 spawned = children_spawned;
66e631de
LT
215 reaped = children_reaped;
216 deleted = children_deleted;
217
218 while (deleted < reaped) {
219 pid_t pid = dead_child[deleted % MAX_CHILDREN];
220 remove_child(pid, deleted, spawned);
221 deleted++;
222 }
223 children_deleted = deleted;
224
225 active = spawned - deleted;
02d57da4
LT
226 if (active <= max_connections)
227 break;
66e631de 228
02d57da4
LT
229 /* Kill some unstarted connections with SIGTERM */
230 kill_some_children(SIGTERM, deleted, spawned);
231 if (active <= max_connections << 1)
232 break;
233
234 /* If the SIGTERM thing isn't helping use SIGKILL */
235 kill_some_children(SIGKILL, deleted, spawned);
236 sleep(1);
237 }
238}
239
7fa09084 240static void handle(int incoming, struct sockaddr *addr, int addrlen)
02d57da4
LT
241{
242 pid_t pid = fork();
f8ff0c06
PB
243 char addrbuf[256] = "";
244 int port = -1;
02d57da4
LT
245
246 if (pid) {
247 unsigned idx;
248
249 close(incoming);
250 if (pid < 0)
251 return;
252
253 idx = children_spawned % MAX_CHILDREN;
254 children_spawned++;
255 add_child(idx, pid, addr, addrlen);
66e631de 256
02d57da4 257 check_max_connections();
a87e8be2
LT
258 return;
259 }
260
261 dup2(incoming, 0);
262 dup2(incoming, 1);
263 close(incoming);
f8ff0c06
PB
264
265 if (addr->sa_family == AF_INET) {
266 struct sockaddr_in *sin_addr = (void *) addr;
267 inet_ntop(AF_INET, &sin_addr->sin_addr, addrbuf, sizeof(addrbuf));
268 port = sin_addr->sin_port;
269
270 } else if (addr->sa_family == AF_INET6) {
271 struct sockaddr_in6 *sin6_addr = (void *) addr;
272
273 char *buf = addrbuf;
274 *buf++ = '['; *buf = '\0'; /* stpcpy() is cool */
275 inet_ntop(AF_INET6, &sin6_addr->sin6_addr, buf, sizeof(addrbuf) - 1);
276 strcat(buf, "]");
277
278 port = sin6_addr->sin6_port;
279 }
280 lognotice("Connection from %s:%d", addrbuf, port);
281
7d80694a 282 exit(execute());
a87e8be2
LT
283}
284
eaa94919
LT
285static void child_handler(int signo)
286{
287 for (;;) {
66e631de
LT
288 pid_t pid = waitpid(-1, NULL, WNOHANG);
289
290 if (pid > 0) {
291 unsigned reaped = children_reaped;
292 dead_child[reaped % MAX_CHILDREN] = pid;
293 children_reaped = reaped + 1;
f8ff0c06
PB
294 /* XXX: Custom logging, since we don't wanna getpid() */
295 if (verbose)
296 fprintf(stderr, "[%d] Disconnected\n", pid);
eaa94919
LT
297 continue;
298 }
299 break;
300 }
301}
302
a87e8be2
LT
303static int serve(int port)
304{
df076bdb
YH
305 struct addrinfo hints, *ai0, *ai;
306 int gai;
307 int socknum = 0, *socklist = NULL;
308 int maxfd = -1;
309 fd_set fds_init, fds;
310 char pbuf[NI_MAXSERV];
a87e8be2 311
eaa94919 312 signal(SIGCHLD, child_handler);
df076bdb
YH
313
314 sprintf(pbuf, "%d", port);
315 memset(&hints, 0, sizeof(hints));
316 hints.ai_family = AF_UNSPEC;
317 hints.ai_socktype = SOCK_STREAM;
318 hints.ai_protocol = IPPROTO_TCP;
319 hints.ai_flags = AI_PASSIVE;
320
321 gai = getaddrinfo(NULL, pbuf, &hints, &ai0);
322 if (gai)
323 die("getaddrinfo() failed: %s\n", gai_strerror(gai));
324
325 FD_ZERO(&fds_init);
326
327 for (ai = ai0; ai; ai = ai->ai_next) {
328 int sockfd;
329 int *newlist;
330
331 sockfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
332 if (sockfd < 0)
333 continue;
334 if (sockfd >= FD_SETSIZE) {
335 error("too large socket descriptor.");
336 close(sockfd);
337 continue;
338 }
339
340#ifdef IPV6_V6ONLY
341 if (ai->ai_family == AF_INET6) {
342 int on = 1;
343 setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY,
344 &on, sizeof(on));
345 /* Note: error is not fatal */
346 }
347#endif
348
349 if (bind(sockfd, ai->ai_addr, ai->ai_addrlen) < 0) {
350 close(sockfd);
351 continue; /* not fatal */
352 }
353 if (listen(sockfd, 5) < 0) {
354 close(sockfd);
355 continue; /* not fatal */
356 }
357
358 newlist = realloc(socklist, sizeof(int) * (socknum + 1));
359 if (!newlist)
360 die("memory allocation failed: %s", strerror(errno));
361
362 socklist = newlist;
363 socklist[socknum++] = sockfd;
364
365 FD_SET(sockfd, &fds_init);
366 if (maxfd < sockfd)
367 maxfd = sockfd;
368 }
369
370 freeaddrinfo(ai0);
371
372 if (socknum == 0)
373 die("unable to allocate any listen sockets on port %u", port);
a87e8be2
LT
374
375 for (;;) {
df076bdb
YH
376 int i;
377 fds = fds_init;
378
379 if (select(maxfd + 1, &fds, NULL, NULL, NULL) < 0) {
1eef0b33
JH
380 if (errno != EINTR) {
381 error("select failed, resuming: %s",
382 strerror(errno));
383 sleep(1);
384 }
df076bdb
YH
385 continue;
386 }
387
388 for (i = 0; i < socknum; i++) {
389 int sockfd = socklist[i];
390
391 if (FD_ISSET(sockfd, &fds)) {
392 struct sockaddr_storage ss;
7fa09084 393 int sslen = sizeof(ss);
df076bdb
YH
394 int incoming = accept(sockfd, (struct sockaddr *)&ss, &sslen);
395 if (incoming < 0) {
396 switch (errno) {
397 case EAGAIN:
398 case EINTR:
399 case ECONNABORTED:
400 continue;
401 default:
402 die("accept returned %s", strerror(errno));
403 }
404 }
405 handle(incoming, (struct sockaddr *)&ss, sslen);
a87e8be2
LT
406 }
407 }
a87e8be2
LT
408 }
409}
410
411int main(int argc, char **argv)
412{
413 int port = DEFAULT_GIT_PORT;
e64e1b79 414 int inetd_mode = 0;
a87e8be2
LT
415 int i;
416
417 for (i = 1; i < argc; i++) {
418 char *arg = argv[i];
419
420 if (!strncmp(arg, "--port=", 7)) {
421 char *end;
422 unsigned long n;
423 n = strtoul(arg+7, &end, 0);
424 if (arg[7] && !*end) {
425 port = n;
426 continue;
427 }
428 }
e64e1b79
LT
429
430 if (!strcmp(arg, "--inetd")) {
431 inetd_mode = 1;
432 continue;
433 }
f8ff0c06
PB
434 if (!strcmp(arg, "--verbose")) {
435 verbose = 1;
436 continue;
437 }
e64e1b79 438
a87e8be2
LT
439 usage(daemon_usage);
440 }
441
7c3693f1
LD
442 if (inetd_mode) {
443 fclose(stderr); //FIXME: workaround
e64e1b79 444 return execute();
7c3693f1 445 }
e64e1b79 446
a87e8be2
LT
447 return serve(port);
448}