Merge branch 'maint'
[git] / connect.c
1 #include "git-compat-util.h"
2 #include "cache.h"
3 #include "pkt-line.h"
4 #include "quote.h"
5 #include "refs.h"
6 #include <sys/wait.h>
7 #include <sys/socket.h>
8 #include <netinet/in.h>
9 #include <arpa/inet.h>
10 #include <netdb.h>
11 #include <signal.h>
12
13 static char *server_capabilities;
14
15 static int check_ref(const char *name, int len, unsigned int flags)
16 {
17         if (!flags)
18                 return 1;
19
20         if (len < 5 || memcmp(name, "refs/", 5))
21                 return 0;
22
23         /* Skip the "refs/" part */
24         name += 5;
25         len -= 5;
26
27         /* REF_NORMAL means that we don't want the magic fake tag refs */
28         if ((flags & REF_NORMAL) && check_ref_format(name) < 0)
29                 return 0;
30
31         /* REF_HEADS means that we want regular branch heads */
32         if ((flags & REF_HEADS) && !memcmp(name, "heads/", 6))
33                 return 1;
34
35         /* REF_TAGS means that we want tags */
36         if ((flags & REF_TAGS) && !memcmp(name, "tags/", 5))
37                 return 1;
38
39         /* All type bits clear means that we are ok with anything */
40         return !(flags & ~REF_NORMAL);
41 }
42
43 /*
44  * Read all the refs from the other end
45  */
46 struct ref **get_remote_heads(int in, struct ref **list,
47                               int nr_match, char **match,
48                               unsigned int flags)
49 {
50         *list = NULL;
51         for (;;) {
52                 struct ref *ref;
53                 unsigned char old_sha1[20];
54                 static char buffer[1000];
55                 char *name;
56                 int len, name_len;
57
58                 len = packet_read_line(in, buffer, sizeof(buffer));
59                 if (!len)
60                         break;
61                 if (buffer[len-1] == '\n')
62                         buffer[--len] = 0;
63
64                 if (len < 42 || get_sha1_hex(buffer, old_sha1) || buffer[40] != ' ')
65                         die("protocol error: expected sha/ref, got '%s'", buffer);
66                 name = buffer + 41;
67
68                 name_len = strlen(name);
69                 if (len != name_len + 41) {
70                         if (server_capabilities)
71                                 free(server_capabilities);
72                         server_capabilities = xstrdup(name + name_len + 1);
73                 }
74
75                 if (!check_ref(name, name_len, flags))
76                         continue;
77                 if (nr_match && !path_match(name, nr_match, match))
78                         continue;
79                 ref = xcalloc(1, sizeof(*ref) + len - 40);
80                 hashcpy(ref->old_sha1, old_sha1);
81                 memcpy(ref->name, buffer + 41, len - 40);
82                 *list = ref;
83                 list = &ref->next;
84         }
85         return list;
86 }
87
88 int server_supports(const char *feature)
89 {
90         return server_capabilities &&
91                 strstr(server_capabilities, feature) != NULL;
92 }
93
94 int get_ack(int fd, unsigned char *result_sha1)
95 {
96         static char line[1000];
97         int len = packet_read_line(fd, line, sizeof(line));
98
99         if (!len)
100                 die("git-fetch-pack: expected ACK/NAK, got EOF");
101         if (line[len-1] == '\n')
102                 line[--len] = 0;
103         if (!strcmp(line, "NAK"))
104                 return 0;
105         if (!strncmp(line, "ACK ", 4)) {
106                 if (!get_sha1_hex(line+4, result_sha1)) {
107                         if (strstr(line+45, "continue"))
108                                 return 2;
109                         return 1;
110                 }
111         }
112         die("git-fetch_pack: expected ACK/NAK, got '%s'", line);
113 }
114
115 int path_match(const char *path, int nr, char **match)
116 {
117         int i;
118         int pathlen = strlen(path);
119
120         for (i = 0; i < nr; i++) {
121                 char *s = match[i];
122                 int len = strlen(s);
123
124                 if (!len || len > pathlen)
125                         continue;
126                 if (memcmp(path + pathlen - len, s, len))
127                         continue;
128                 if (pathlen > len && path[pathlen - len - 1] != '/')
129                         continue;
130                 *s = 0;
131                 return (i + 1);
132         }
133         return 0;
134 }
135
136 struct refspec {
137         char *src;
138         char *dst;
139         char force;
140 };
141
142 /*
143  * A:B means fast forward remote B with local A.
144  * +A:B means overwrite remote B with local A.
145  * +A is a shorthand for +A:A.
146  * A is a shorthand for A:A.
147  * :B means delete remote B.
148  */
149 static struct refspec *parse_ref_spec(int nr_refspec, char **refspec)
150 {
151         int i;
152         struct refspec *rs = xcalloc(sizeof(*rs), (nr_refspec + 1));
153         for (i = 0; i < nr_refspec; i++) {
154                 char *sp, *dp, *ep;
155                 sp = refspec[i];
156                 if (*sp == '+') {
157                         rs[i].force = 1;
158                         sp++;
159                 }
160                 ep = strchr(sp, ':');
161                 if (ep) {
162                         dp = ep + 1;
163                         *ep = 0;
164                 }
165                 else
166                         dp = sp;
167                 rs[i].src = sp;
168                 rs[i].dst = dp;
169         }
170         rs[nr_refspec].src = rs[nr_refspec].dst = NULL;
171         return rs;
172 }
173
174 static int count_refspec_match(const char *pattern,
175                                struct ref *refs,
176                                struct ref **matched_ref)
177 {
178         int patlen = strlen(pattern);
179         struct ref *matched_weak = NULL;
180         struct ref *matched = NULL;
181         int weak_match = 0;
182         int match = 0;
183
184         for (weak_match = match = 0; refs; refs = refs->next) {
185                 char *name = refs->name;
186                 int namelen = strlen(name);
187                 int weak_match;
188
189                 if (namelen < patlen ||
190                     memcmp(name + namelen - patlen, pattern, patlen))
191                         continue;
192                 if (namelen != patlen && name[namelen - patlen - 1] != '/')
193                         continue;
194
195                 /* A match is "weak" if it is with refs outside
196                  * heads or tags, and did not specify the pattern
197                  * in full (e.g. "refs/remotes/origin/master") or at
198                  * least from the toplevel (e.g. "remotes/origin/master");
199                  * otherwise "git push $URL master" would result in
200                  * ambiguity between remotes/origin/master and heads/master
201                  * at the remote site.
202                  */
203                 if (namelen != patlen &&
204                     patlen != namelen - 5 &&
205                     strncmp(name, "refs/heads/", 11) &&
206                     strncmp(name, "refs/tags/", 10)) {
207                         /* We want to catch the case where only weak
208                          * matches are found and there are multiple
209                          * matches, and where more than one strong
210                          * matches are found, as ambiguous.  One
211                          * strong match with zero or more weak matches
212                          * are acceptable as a unique match.
213                          */
214                         matched_weak = refs;
215                         weak_match++;
216                 }
217                 else {
218                         matched = refs;
219                         match++;
220                 }
221         }
222         if (!matched) {
223                 *matched_ref = matched_weak;
224                 return weak_match;
225         }
226         else {
227                 *matched_ref = matched;
228                 return match;
229         }
230 }
231
232 static void link_dst_tail(struct ref *ref, struct ref ***tail)
233 {
234         **tail = ref;
235         *tail = &ref->next;
236         **tail = NULL;
237 }
238
239 static struct ref *try_explicit_object_name(const char *name)
240 {
241         unsigned char sha1[20];
242         struct ref *ref;
243         int len;
244
245         if (!*name) {
246                 ref = xcalloc(1, sizeof(*ref) + 20);
247                 strcpy(ref->name, "(delete)");
248                 hashclr(ref->new_sha1);
249                 return ref;
250         }
251         if (get_sha1(name, sha1))
252                 return NULL;
253         len = strlen(name) + 1;
254         ref = xcalloc(1, sizeof(*ref) + len);
255         memcpy(ref->name, name, len);
256         hashcpy(ref->new_sha1, sha1);
257         return ref;
258 }
259
260 static int match_explicit_refs(struct ref *src, struct ref *dst,
261                                struct ref ***dst_tail, struct refspec *rs)
262 {
263         int i, errs;
264         for (i = errs = 0; rs[i].src; i++) {
265                 struct ref *matched_src, *matched_dst;
266
267                 matched_src = matched_dst = NULL;
268                 switch (count_refspec_match(rs[i].src, src, &matched_src)) {
269                 case 1:
270                         break;
271                 case 0:
272                         /* The source could be in the get_sha1() format
273                          * not a reference name.  :refs/other is a
274                          * way to delete 'other' ref at the remote end.
275                          */
276                         matched_src = try_explicit_object_name(rs[i].src);
277                         if (matched_src)
278                                 break;
279                         errs = 1;
280                         error("src refspec %s does not match any.",
281                               rs[i].src);
282                         break;
283                 default:
284                         errs = 1;
285                         error("src refspec %s matches more than one.",
286                               rs[i].src);
287                         break;
288                 }
289                 switch (count_refspec_match(rs[i].dst, dst, &matched_dst)) {
290                 case 1:
291                         break;
292                 case 0:
293                         if (!memcmp(rs[i].dst, "refs/", 5)) {
294                                 int len = strlen(rs[i].dst) + 1;
295                                 matched_dst = xcalloc(1, sizeof(*dst) + len);
296                                 memcpy(matched_dst->name, rs[i].dst, len);
297                                 link_dst_tail(matched_dst, dst_tail);
298                         }
299                         else if (!strcmp(rs[i].src, rs[i].dst) &&
300                                  matched_src) {
301                                 /* pushing "master:master" when
302                                  * remote does not have master yet.
303                                  */
304                                 int len = strlen(matched_src->name) + 1;
305                                 matched_dst = xcalloc(1, sizeof(*dst) + len);
306                                 memcpy(matched_dst->name, matched_src->name,
307                                        len);
308                                 link_dst_tail(matched_dst, dst_tail);
309                         }
310                         else {
311                                 errs = 1;
312                                 error("dst refspec %s does not match any "
313                                       "existing ref on the remote and does "
314                                       "not start with refs/.", rs[i].dst);
315                         }
316                         break;
317                 default:
318                         errs = 1;
319                         error("dst refspec %s matches more than one.",
320                               rs[i].dst);
321                         break;
322                 }
323                 if (errs)
324                         continue;
325                 if (matched_dst->peer_ref) {
326                         errs = 1;
327                         error("dst ref %s receives from more than one src.",
328                               matched_dst->name);
329                 }
330                 else {
331                         matched_dst->peer_ref = matched_src;
332                         matched_dst->force = rs[i].force;
333                 }
334         }
335         return -errs;
336 }
337
338 static struct ref *find_ref_by_name(struct ref *list, const char *name)
339 {
340         for ( ; list; list = list->next)
341                 if (!strcmp(list->name, name))
342                         return list;
343         return NULL;
344 }
345
346 int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,
347                int nr_refspec, char **refspec, int all)
348 {
349         struct refspec *rs = parse_ref_spec(nr_refspec, refspec);
350
351         if (nr_refspec)
352                 return match_explicit_refs(src, dst, dst_tail, rs);
353
354         /* pick the remainder */
355         for ( ; src; src = src->next) {
356                 struct ref *dst_peer;
357                 if (src->peer_ref)
358                         continue;
359                 dst_peer = find_ref_by_name(dst, src->name);
360                 if ((dst_peer && dst_peer->peer_ref) || (!dst_peer && !all))
361                         continue;
362                 if (!dst_peer) {
363                         /* Create a new one and link it */
364                         int len = strlen(src->name) + 1;
365                         dst_peer = xcalloc(1, sizeof(*dst_peer) + len);
366                         memcpy(dst_peer->name, src->name, len);
367                         hashcpy(dst_peer->new_sha1, src->new_sha1);
368                         link_dst_tail(dst_peer, dst_tail);
369                 }
370                 dst_peer->peer_ref = src;
371         }
372         return 0;
373 }
374
375 enum protocol {
376         PROTO_LOCAL = 1,
377         PROTO_SSH,
378         PROTO_GIT,
379 };
380
381 static enum protocol get_protocol(const char *name)
382 {
383         if (!strcmp(name, "ssh"))
384                 return PROTO_SSH;
385         if (!strcmp(name, "git"))
386                 return PROTO_GIT;
387         if (!strcmp(name, "git+ssh"))
388                 return PROTO_SSH;
389         if (!strcmp(name, "ssh+git"))
390                 return PROTO_SSH;
391         die("I don't handle protocol '%s'", name);
392 }
393
394 #define STR_(s) # s
395 #define STR(s)  STR_(s)
396
397 #ifndef NO_IPV6
398
399 /*
400  * Returns a connected socket() fd, or else die()s.
401  */
402 static int git_tcp_connect_sock(char *host)
403 {
404         int sockfd = -1, saved_errno = 0;
405         char *colon, *end;
406         const char *port = STR(DEFAULT_GIT_PORT);
407         struct addrinfo hints, *ai0, *ai;
408         int gai;
409
410         if (host[0] == '[') {
411                 end = strchr(host + 1, ']');
412                 if (end) {
413                         *end = 0;
414                         end++;
415                         host++;
416                 } else
417                         end = host;
418         } else
419                 end = host;
420         colon = strchr(end, ':');
421
422         if (colon) {
423                 *colon = 0;
424                 port = colon + 1;
425         }
426
427         memset(&hints, 0, sizeof(hints));
428         hints.ai_socktype = SOCK_STREAM;
429         hints.ai_protocol = IPPROTO_TCP;
430
431         gai = getaddrinfo(host, port, &hints, &ai);
432         if (gai)
433                 die("Unable to look up %s (%s)", host, gai_strerror(gai));
434
435         for (ai0 = ai; ai; ai = ai->ai_next) {
436                 sockfd = socket(ai->ai_family,
437                                 ai->ai_socktype, ai->ai_protocol);
438                 if (sockfd < 0) {
439                         saved_errno = errno;
440                         continue;
441                 }
442                 if (connect(sockfd, ai->ai_addr, ai->ai_addrlen) < 0) {
443                         saved_errno = errno;
444                         close(sockfd);
445                         sockfd = -1;
446                         continue;
447                 }
448                 break;
449         }
450
451         freeaddrinfo(ai0);
452
453         if (sockfd < 0)
454                 die("unable to connect a socket (%s)", strerror(saved_errno));
455
456         return sockfd;
457 }
458
459 #else /* NO_IPV6 */
460
461 /*
462  * Returns a connected socket() fd, or else die()s.
463  */
464 static int git_tcp_connect_sock(char *host)
465 {
466         int sockfd = -1, saved_errno = 0;
467         char *colon, *end;
468         char *port = STR(DEFAULT_GIT_PORT), *ep;
469         struct hostent *he;
470         struct sockaddr_in sa;
471         char **ap;
472         unsigned int nport;
473
474         if (host[0] == '[') {
475                 end = strchr(host + 1, ']');
476                 if (end) {
477                         *end = 0;
478                         end++;
479                         host++;
480                 } else
481                         end = host;
482         } else
483                 end = host;
484         colon = strchr(end, ':');
485
486         if (colon) {
487                 *colon = 0;
488                 port = colon + 1;
489         }
490
491         he = gethostbyname(host);
492         if (!he)
493                 die("Unable to look up %s (%s)", host, hstrerror(h_errno));
494         nport = strtoul(port, &ep, 10);
495         if ( ep == port || *ep ) {
496                 /* Not numeric */
497                 struct servent *se = getservbyname(port,"tcp");
498                 if ( !se )
499                         die("Unknown port %s\n", port);
500                 nport = se->s_port;
501         }
502
503         for (ap = he->h_addr_list; *ap; ap++) {
504                 sockfd = socket(he->h_addrtype, SOCK_STREAM, 0);
505                 if (sockfd < 0) {
506                         saved_errno = errno;
507                         continue;
508                 }
509
510                 memset(&sa, 0, sizeof sa);
511                 sa.sin_family = he->h_addrtype;
512                 sa.sin_port = htons(nport);
513                 memcpy(&sa.sin_addr, *ap, he->h_length);
514
515                 if (connect(sockfd, (struct sockaddr *)&sa, sizeof sa) < 0) {
516                         saved_errno = errno;
517                         close(sockfd);
518                         sockfd = -1;
519                         continue;
520                 }
521                 break;
522         }
523
524         if (sockfd < 0)
525                 die("unable to connect a socket (%s)", strerror(saved_errno));
526
527         return sockfd;
528 }
529
530 #endif /* NO_IPV6 */
531
532
533 static void git_tcp_connect(int fd[2], char *host)
534 {
535         int sockfd = git_tcp_connect_sock(host);
536
537         fd[0] = sockfd;
538         fd[1] = sockfd;
539 }
540
541
542 static char *git_proxy_command;
543 static const char *rhost_name;
544 static int rhost_len;
545
546 static int git_proxy_command_options(const char *var, const char *value)
547 {
548         if (!strcmp(var, "core.gitproxy")) {
549                 const char *for_pos;
550                 int matchlen = -1;
551                 int hostlen;
552
553                 if (git_proxy_command)
554                         return 0;
555                 /* [core]
556                  * ;# matches www.kernel.org as well
557                  * gitproxy = netcatter-1 for kernel.org
558                  * gitproxy = netcatter-2 for sample.xz
559                  * gitproxy = netcatter-default
560                  */
561                 for_pos = strstr(value, " for ");
562                 if (!for_pos)
563                         /* matches everybody */
564                         matchlen = strlen(value);
565                 else {
566                         hostlen = strlen(for_pos + 5);
567                         if (rhost_len < hostlen)
568                                 matchlen = -1;
569                         else if (!strncmp(for_pos + 5,
570                                           rhost_name + rhost_len - hostlen,
571                                           hostlen) &&
572                                  ((rhost_len == hostlen) ||
573                                   rhost_name[rhost_len - hostlen -1] == '.'))
574                                 matchlen = for_pos - value;
575                         else
576                                 matchlen = -1;
577                 }
578                 if (0 <= matchlen) {
579                         /* core.gitproxy = none for kernel.org */
580                         if (matchlen == 4 && 
581                             !memcmp(value, "none", 4))
582                                 matchlen = 0;
583                         git_proxy_command = xmalloc(matchlen + 1);
584                         memcpy(git_proxy_command, value, matchlen);
585                         git_proxy_command[matchlen] = 0;
586                 }
587                 return 0;
588         }
589
590         return git_default_config(var, value);
591 }
592
593 static int git_use_proxy(const char *host)
594 {
595         rhost_name = host;
596         rhost_len = strlen(host);
597         git_proxy_command = getenv("GIT_PROXY_COMMAND");
598         git_config(git_proxy_command_options);
599         rhost_name = NULL;
600         return (git_proxy_command && *git_proxy_command);
601 }
602
603 static void git_proxy_connect(int fd[2], char *host)
604 {
605         const char *port = STR(DEFAULT_GIT_PORT);
606         char *colon, *end;
607         int pipefd[2][2];
608         pid_t pid;
609
610         if (host[0] == '[') {
611                 end = strchr(host + 1, ']');
612                 if (end) {
613                         *end = 0;
614                         end++;
615                         host++;
616                 } else
617                         end = host;
618         } else
619                 end = host;
620         colon = strchr(end, ':');
621
622         if (colon) {
623                 *colon = 0;
624                 port = colon + 1;
625         }
626
627         if (pipe(pipefd[0]) < 0 || pipe(pipefd[1]) < 0)
628                 die("unable to create pipe pair for communication");
629         pid = fork();
630         if (!pid) {
631                 dup2(pipefd[1][0], 0);
632                 dup2(pipefd[0][1], 1);
633                 close(pipefd[0][0]);
634                 close(pipefd[0][1]);
635                 close(pipefd[1][0]);
636                 close(pipefd[1][1]);
637                 execlp(git_proxy_command, git_proxy_command, host, port, NULL);
638                 die("exec failed");
639         }
640         if (pid < 0)
641                 die("fork failed");
642         fd[0] = pipefd[0][0];
643         fd[1] = pipefd[1][1];
644         close(pipefd[0][1]);
645         close(pipefd[1][0]);
646 }
647
648 #define MAX_CMD_LEN 1024
649
650 /*
651  * This returns 0 if the transport protocol does not need fork(2),
652  * or a process id if it does.  Once done, finish the connection
653  * with finish_connect() with the value returned from this function
654  * (it is safe to call finish_connect() with 0 to support the former
655  * case).
656  *
657  * Does not return a negative value on error; it just dies.
658  */
659 pid_t git_connect(int fd[2], char *url, const char *prog)
660 {
661         char *host, *path = url;
662         char *end;
663         int c;
664         int pipefd[2][2];
665         pid_t pid;
666         enum protocol protocol = PROTO_LOCAL;
667         int free_path = 0;
668
669         /* Without this we cannot rely on waitpid() to tell
670          * what happened to our children.
671          */
672         signal(SIGCHLD, SIG_DFL);
673
674         host = strstr(url, "://");
675         if(host) {
676                 *host = '\0';
677                 protocol = get_protocol(url);
678                 host += 3;
679                 c = '/';
680         } else {
681                 host = url;
682                 c = ':';
683         }
684
685         if (host[0] == '[') {
686                 end = strchr(host + 1, ']');
687                 if (end) {
688                         *end = 0;
689                         end++;
690                         host++;
691                 } else
692                         end = host;
693         } else
694                 end = host;
695
696         path = strchr(end, c);
697         if (c == ':') {
698                 if (path) {
699                         protocol = PROTO_SSH;
700                         *path++ = '\0';
701                 } else
702                         path = host;
703         }
704
705         if (!path || !*path)
706                 die("No path specified. See 'man git-pull' for valid url syntax");
707
708         /*
709          * null-terminate hostname and point path to ~ for URL's like this:
710          *    ssh://host.xz/~user/repo
711          */
712         if (protocol != PROTO_LOCAL && host != url) {
713                 char *ptr = path;
714                 if (path[1] == '~')
715                         path++;
716                 else {
717                         path = xstrdup(ptr);
718                         free_path = 1;
719                 }
720
721                 *ptr = '\0';
722         }
723
724         if (protocol == PROTO_GIT) {
725                 /* These underlying connection commands die() if they
726                  * cannot connect.
727                  */
728                 char *target_host = xstrdup(host);
729                 if (git_use_proxy(host))
730                         git_proxy_connect(fd, host);
731                 else
732                         git_tcp_connect(fd, host);
733                 /*
734                  * Separate original protocol components prog and path
735                  * from extended components with a NUL byte.
736                  */
737                 packet_write(fd[1],
738                              "%s %s%chost=%s%c",
739                              prog, path, 0,
740                              target_host, 0);
741                 free(target_host);
742                 if (free_path)
743                         free(path);
744                 return 0;
745         }
746
747         if (pipe(pipefd[0]) < 0 || pipe(pipefd[1]) < 0)
748                 die("unable to create pipe pair for communication");
749         pid = fork();
750         if (pid < 0)
751                 die("unable to fork");
752         if (!pid) {
753                 char command[MAX_CMD_LEN];
754                 char *posn = command;
755                 int size = MAX_CMD_LEN;
756                 int of = 0;
757
758                 of |= add_to_string(&posn, &size, prog, 0);
759                 of |= add_to_string(&posn, &size, " ", 0);
760                 of |= add_to_string(&posn, &size, path, 1);
761
762                 if (of)
763                         die("command line too long");
764
765                 dup2(pipefd[1][0], 0);
766                 dup2(pipefd[0][1], 1);
767                 close(pipefd[0][0]);
768                 close(pipefd[0][1]);
769                 close(pipefd[1][0]);
770                 close(pipefd[1][1]);
771                 if (protocol == PROTO_SSH) {
772                         const char *ssh, *ssh_basename;
773                         ssh = getenv("GIT_SSH");
774                         if (!ssh) ssh = "ssh";
775                         ssh_basename = strrchr(ssh, '/');
776                         if (!ssh_basename)
777                                 ssh_basename = ssh;
778                         else
779                                 ssh_basename++;
780                         execlp(ssh, ssh_basename, host, command, NULL);
781                 }
782                 else {
783                         unsetenv(ALTERNATE_DB_ENVIRONMENT);
784                         unsetenv(DB_ENVIRONMENT);
785                         unsetenv(GIT_DIR_ENVIRONMENT);
786                         unsetenv(GRAFT_ENVIRONMENT);
787                         unsetenv(INDEX_ENVIRONMENT);
788                         execlp("sh", "sh", "-c", command, NULL);
789                 }
790                 die("exec failed");
791         }
792         fd[0] = pipefd[0][0];
793         fd[1] = pipefd[1][1];
794         close(pipefd[0][1]);
795         close(pipefd[1][0]);
796         if (free_path)
797                 free(path);
798         return pid;
799 }
800
801 int finish_connect(pid_t pid)
802 {
803         if (pid == 0)
804                 return 0;
805
806         while (waitpid(pid, NULL, 0) < 0) {
807                 if (errno != EINTR)
808                         return -1;
809         }
810         return 0;
811 }