Blob


1 /*
2 * Copyright (c) 2019 Ori Bernstein <ori@openbsd.org>
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
17 #include <sys/types.h>
18 #include <sys/queue.h>
19 #include <sys/uio.h>
20 #include <sys/time.h>
21 #include <sys/stat.h>
22 #include <sys/syslimits.h>
24 #include <stdint.h>
25 #include <errno.h>
26 #include <imsg.h>
27 #include <limits.h>
28 #include <signal.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <ctype.h>
33 #include <sha1.h>
34 #include <fcntl.h>
35 #include <zlib.h>
36 #include <err.h>
38 #include "got_error.h"
39 #include "got_object.h"
40 #include "got_path.h"
41 #include "got_version.h"
43 #include "got_lib_sha1.h"
44 #include "got_lib_delta.h"
45 #include "got_lib_object.h"
46 #include "got_lib_object_parse.h"
47 #include "got_lib_privsep.h"
48 #include "got_lib_pack.h"
50 #ifndef nitems
51 #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
52 #endif
54 #define GOT_PKTMAX 65536
56 struct got_object *indexed;
57 static int chattygit;
58 static char *fetchbranch;
59 static struct got_object_id zhash = {.sha1={0}};
61 static const struct got_error *
62 readn(ssize_t *off, int fd, void *buf, size_t n)
63 {
64 ssize_t r;
66 *off = 0;
67 while (*off != n) {
68 r = read(fd, buf + *off, n - *off);
69 if (r == -1)
70 return got_error_from_errno("read");
71 if (r == 0)
72 return NULL;
73 *off += r;
74 }
75 return NULL;
76 }
78 static const struct got_error *
79 flushpkt(int fd)
80 {
81 ssize_t w;
83 if (chattygit)
84 fprintf(stderr, "writepkt: 0000\n");
86 w = write(fd, "0000", 4);
87 if (w == -1)
88 return got_error_from_errno("write");
89 if (w != 4)
90 return got_error(GOT_ERR_IO);
91 return NULL;
92 }
94 /*
95 * Packet header contains a 4-byte hexstring which specifies the length
96 * of data which follows.
97 */
98 static const struct got_error *
99 read_pkthdr(int *datalen, int fd)
101 static const struct got_error *err = NULL;
102 char lenstr[5];
103 long len;
104 char *e;
105 int n, i;
106 ssize_t r;
108 *datalen = 0;
110 err = readn(&r, fd, lenstr, 4);
111 if (err)
112 return err;
113 if (r == 0) /* implicit "0000" */
114 return NULL;
115 if (r != 4)
116 return got_error_msg(GOT_ERR_BAD_PACKET,
117 "wrong packet header length");
119 lenstr[4] = '\0';
120 for (i = 0; i < 4; i++) {
121 if (!isxdigit(lenstr[i]))
122 return got_error_msg(GOT_ERR_BAD_PACKET,
123 "packet length not specified in hex");
125 errno = 0;
126 len = strtol(lenstr, &e, 16);
127 if (lenstr[0] == '\0' || *e != '\0')
128 return got_error(GOT_ERR_BAD_PACKET);
129 if (errno == ERANGE && (len == LONG_MAX || len == LONG_MIN))
130 return got_error_msg(GOT_ERR_BAD_PACKET, "bad packet length");
131 if (len > INT_MAX || len < INT_MIN)
132 return got_error_msg(GOT_ERR_BAD_PACKET, "bad packet length");
133 n = len;
134 if (n == 0)
135 return NULL;
136 if (n <= 4)
137 return got_error_msg(GOT_ERR_BAD_PACKET, "packet too short");
138 n -= 4;
140 *datalen = n;
141 return NULL;
144 static const struct got_error *
145 readpkt(int *outlen, int fd, char *buf, int buflen)
147 const struct got_error *err = NULL;
148 int datalen;
149 ssize_t n;
151 err = read_pkthdr(&datalen, fd);
152 if (err)
153 return err;
155 if (datalen > buflen)
156 return got_error(GOT_ERR_NO_SPACE);
158 err = readn(&n, fd, buf, datalen);
159 if (err)
160 return err;
161 if (n != datalen)
162 return got_error_msg(GOT_ERR_BAD_PACKET, "short packet");
164 *outlen = n;
165 return NULL;
168 static const struct got_error *
169 writepkt(int fd, char *buf, int nbuf)
171 char len[5];
172 int i;
173 ssize_t w;
175 if (snprintf(len, sizeof(len), "%04x", nbuf + 4) >= sizeof(len))
176 return got_error(GOT_ERR_NO_SPACE);
177 w = write(fd, len, 4);
178 if (w == -1)
179 return got_error_from_errno("write");
180 if (w != 4)
181 return got_error(GOT_ERR_IO);
182 w = write(fd, buf, nbuf);
183 if (w == -1)
184 return got_error_from_errno("write");
185 if (w != nbuf)
186 return got_error(GOT_ERR_IO);
187 if (chattygit) {
188 fprintf(stderr, "writepkt: %s:\t", len);
189 fwrite(buf, 1, nbuf, stderr);
190 for (i = 0; i < nbuf; i++) {
191 if (isprint(buf[i]))
192 fputc(buf[i], stderr);
194 fputc('\n', stderr);
196 return NULL;
199 static const struct got_error *
200 match_remote_ref(struct got_pathlist_head *have_refs, struct got_object_id *id,
201 char *refname, char *id_str)
203 struct got_pathlist_entry *pe;
205 memset(id, 0, sizeof(*id));
207 TAILQ_FOREACH(pe, have_refs, entry) {
208 if (strcmp(pe->path, refname) == 0) {
209 if (!got_parse_sha1_digest(id->sha1, id_str))
210 return got_error(GOT_ERR_BAD_OBJ_ID_STR);
211 break;
214 return NULL;
217 static const struct got_error *
218 check_pack_hash(int fd, size_t sz, uint8_t *hcomp)
220 const struct got_error *err = NULL;
221 SHA1_CTX ctx;
222 uint8_t hexpect[SHA1_DIGEST_LENGTH];
223 uint8_t buf[32 * 1024];
224 ssize_t n, r, nr;
226 if (sz < sizeof(struct got_packfile_hdr) + SHA1_DIGEST_LENGTH)
227 return got_error(GOT_ERR_BAD_PACKFILE);
229 n = 0;
230 SHA1Init(&ctx);
231 while (n < sz - 20) {
232 nr = sizeof(buf);
233 if (sz - n - 20 < sizeof(buf))
234 nr = sz - n - 20;
235 err = readn(&r, fd, buf, nr);
236 if (err)
237 return err;
238 if (r != nr)
239 return got_error(GOT_ERR_BAD_PACKFILE);
240 SHA1Update(&ctx, buf, nr);
241 n += r;
243 SHA1Final(hcomp, &ctx);
245 err = readn(&r, fd, hexpect, sizeof(hexpect));
246 if (err)
247 return err;
248 if (r != sizeof(hexpect))
249 return got_error(GOT_ERR_BAD_PACKFILE);
250 if (memcmp(hcomp, hexpect, SHA1_DIGEST_LENGTH) != 0)
251 return got_error(GOT_ERR_BAD_PACKFILE);
252 return NULL;
255 static int
256 match_branch(char *br, char *pat)
258 char name[128];
260 if (strstr(pat, "refs/heads") == pat) {
261 if (snprintf(name, sizeof(name), "%s", pat) >= sizeof(name))
262 return -1;
263 } else if (strstr(pat, "heads")) {
264 if (snprintf(name, sizeof(name), "refs/%s", pat)
265 >= sizeof(name))
266 return -1;
267 } else {
268 if (snprintf(name, sizeof(name), "refs/heads/%s", pat)
269 >= sizeof(name))
270 return -1;
272 return strcmp(br, name) == 0;
275 static const struct got_error *
276 tokenize_refline(char **tokens, char *line, int len, int maxtokens)
278 const struct got_error *err = NULL;
279 char *p;
280 size_t i, n = 0;
282 for (i = 0; i < maxtokens; i++)
283 tokens[i] = NULL;
285 for (i = 0; n < len && i < maxtokens; i++) {
286 while (isspace(*line)) {
287 line++;
288 n++;
290 p = line;
291 while (*line != '\0' &&
292 (!isspace(*line) || i == maxtokens - 1)) {
293 line++;
294 n++;
296 tokens[i] = strndup(p, line - p);
297 if (tokens[i] == NULL) {
298 err = got_error_from_errno("strndup");
299 goto done;
301 /* Skip \0 field-delimiter at end of token. */
302 while (line[0] == '\0' && n < len) {
303 line++;
304 n++;
307 if (i <= 2)
308 err = got_error(GOT_ERR_NOT_REF);
309 done:
310 if (err) {
311 int j;
312 for (j = 0; j < i; j++)
313 free(tokens[j]);
314 tokens[j] = NULL;
316 return err;
319 static const struct got_error *
320 parse_refline(char **id_str, char **refname, char **server_capabilities,
321 char *line, int len)
323 const struct got_error *err = NULL;
324 char *tokens[3];
326 err = tokenize_refline(tokens, line, len, nitems(tokens));
327 if (err)
328 return err;
330 if (tokens[0])
331 *id_str = tokens[0];
332 if (tokens[1])
333 *refname = tokens[1];
334 if (tokens[2])
335 *server_capabilities = tokens[2];
337 return NULL;
340 #define GOT_CAPA_AGENT "agent"
341 #define GOT_CAPA_OFS_DELTA "ofs-delta"
342 #define GOT_CAPA_SIDE_BAND_64K "side-band-64k"
344 #define GOT_SIDEBAND_PACKFILE_DATA 1
345 #define GOT_SIDEBAND_PROGRESS_INFO 2
346 #define GOT_SIDEBAND_ERROR_INFO 3
349 struct got_capability {
350 const char *key;
351 const char *value;
352 };
353 static const struct got_capability got_capabilities[] = {
354 { GOT_CAPA_AGENT, "got/" GOT_VERSION_STR },
355 { GOT_CAPA_OFS_DELTA, NULL },
356 { GOT_CAPA_SIDE_BAND_64K, NULL },
357 };
359 static const struct got_error *
360 match_capability(char **my_capabilities, const char *capa,
361 const struct got_capability *mycapa)
363 char *equalsign;
364 char *s;
366 equalsign = strchr(capa, '=');
367 if (equalsign) {
368 if (strncmp(capa, mycapa->key, equalsign - capa) != 0)
369 return NULL;
370 } else {
371 if (strcmp(capa, mycapa->key) != 0)
372 return NULL;
375 if (asprintf(&s, "%s%s%s%s%s",
376 *my_capabilities != NULL ? *my_capabilities : "",
377 *my_capabilities != NULL ? " " : "",
378 mycapa->key,
379 mycapa->value != NULL ? "=" : "",
380 mycapa->value != NULL? mycapa->value : "") == -1)
381 return got_error_from_errno("asprintf");
383 free(*my_capabilities);
384 *my_capabilities = s;
385 return NULL;
388 static const struct got_error *
389 add_symref(struct got_pathlist_head *symrefs, char *capa)
391 const struct got_error *err = NULL;
392 char *colon, *name = NULL, *target = NULL;
394 /* Need at least "A:B" */
395 if (strlen(capa) < 3)
396 return NULL;
398 colon = strchr(capa, ':');
399 if (colon == NULL)
400 return NULL;
402 *colon = '\0';
403 name = strdup(capa);
404 if (name == NULL)
405 return got_error_from_errno("strdup");
407 target = strdup(colon + 1);
408 if (target == NULL) {
409 err = got_error_from_errno("strdup");
410 goto done;
413 /* We can't validate the ref itself here. The main process will. */
414 err = got_pathlist_append(symrefs, name, target);
415 done:
416 if (err) {
417 free(name);
418 free(target);
420 return err;
423 static const struct got_error *
424 match_capabilities(char **my_capabilities, struct got_pathlist_head *symrefs,
425 char *server_capabilities)
427 const struct got_error *err = NULL;
428 char *capa, *equalsign;
429 int i;
431 *my_capabilities = NULL;
432 do {
433 capa = strsep(&server_capabilities, " ");
434 if (capa == NULL)
435 return NULL;
437 equalsign = strchr(capa, '=');
438 if (equalsign != NULL &&
439 strncmp(capa, "symref", equalsign - capa) == 0) {
440 err = add_symref(symrefs, equalsign + 1);
441 if (err)
442 break;
443 continue;
446 for (i = 0; i < nitems(got_capabilities); i++) {
447 err = match_capability(my_capabilities,
448 capa, &got_capabilities[i]);
449 if (err)
450 break;
452 } while (capa);
454 return err;
457 static const struct got_error *
458 fetch_progress(struct imsgbuf *ibuf, const char *buf, size_t len)
460 int i;
463 if (len == 0)
464 return NULL;
466 /*
467 * Truncate messages which exceed the maximum imsg payload size.
468 * Server may send up to 64k.
469 */
470 if (len > MAX_IMSGSIZE - IMSG_HEADER_SIZE)
471 len = MAX_IMSGSIZE - IMSG_HEADER_SIZE;
473 /* Only allow printable ASCII. */
474 for (i = 0; i < len; i++) {
475 if (isprint((unsigned char)buf[i]) ||
476 isspace((unsigned char)buf[i]))
477 continue;
478 return got_error_msg(GOT_ERR_BAD_PACKET,
479 "non-printable progress message received from server");
482 return got_privsep_send_fetch_server_progress(ibuf, buf, len);
485 static const struct got_error *
486 fetch_error(const char *buf, size_t len)
488 static char msg[1024];
489 int i;
491 for (i = 0; i < len && i < sizeof(msg) - 1; i++) {
492 if (!isprint(buf[i]))
493 return got_error_msg(GOT_ERR_BAD_PACKET,
494 "non-printable error message received from server");
495 msg[i] = buf[i];
497 msg[i] = '\0';
498 return got_error_msg(GOT_ERR_FETCH_FAILED, msg);
501 static const struct got_error *
502 fetch_pack(int fd, int packfd, struct got_object_id *packid,
503 struct got_pathlist_head *have_refs, struct imsgbuf *ibuf)
505 const struct got_error *err = NULL;
506 char buf[GOT_PKTMAX];
507 char hashstr[SHA1_DIGEST_STRING_LENGTH];
508 struct got_object_id *have, *want;
509 int is_firstpkt = 1, nref = 0, refsz = 16;
510 int i, n, req;
511 off_t packsz;
512 char *id_str = NULL, *refname = NULL;
513 char *server_capabilities = NULL, *my_capabilities = NULL;
514 struct got_pathlist_head symrefs;
515 struct got_pathlist_entry *pe;
516 int have_sidebands = 0;
517 uint32_t nobjects = 0;
519 TAILQ_INIT(&symrefs);
521 have = malloc(refsz * sizeof(have[0]));
522 if (have == NULL)
523 return got_error_from_errno("malloc");
524 want = malloc(refsz * sizeof(want[0]));
525 if (want == NULL) {
526 err = got_error_from_errno("malloc");
527 goto done;
529 if (chattygit)
530 fprintf(stderr, "starting fetch\n");
531 while (1) {
532 err = readpkt(&n, fd, buf, sizeof(buf));
533 if (err)
534 goto done;
535 if (n == 0)
536 break;
537 if (n >= 4 && strncmp(buf, "ERR ", 4) == 0) {
538 err = fetch_error(&buf[4], n - 4);
539 goto done;
541 err = parse_refline(&id_str, &refname, &server_capabilities,
542 buf, n);
543 if (err)
544 goto done;
545 if (chattygit && server_capabilities[0] != '\0')
546 fprintf(stderr, "server capabilities: %s\n",
547 server_capabilities);
548 if (is_firstpkt) {
549 err = match_capabilities(&my_capabilities, &symrefs,
550 server_capabilities);
551 if (err)
552 goto done;
553 if (chattygit && my_capabilities)
554 fprintf(stderr, "my matched capabilities: %s\n",
555 my_capabilities);
556 err = got_privsep_send_fetch_symrefs(ibuf, &symrefs);
557 if (err)
558 goto done;
560 is_firstpkt = 0;
561 if (strstr(refname, "^{}"))
562 continue;
563 if (fetchbranch && !match_branch(refname, fetchbranch))
564 continue;
565 if (refsz == nref + 1) {
566 refsz *= 2;
567 have = reallocarray(have, refsz, sizeof(have[0]));
568 if (have == NULL) {
569 err = got_error_from_errno("reallocarray");
570 goto done;
572 want = reallocarray(want, refsz, sizeof(want[0]));
573 if (want == NULL) {
574 err = got_error_from_errno("reallocarray");
575 goto done;
578 if (!got_parse_sha1_digest(want[nref].sha1, id_str)) {
579 err = got_error(GOT_ERR_BAD_OBJ_ID_STR);
580 goto done;
583 err = match_remote_ref(have_refs, &have[nref], id_str, refname);
584 if (err)
585 goto done;
587 err = got_privsep_send_fetch_ref(ibuf, &want[nref],
588 refname);
589 if (err)
590 goto done;
591 if (chattygit)
592 fprintf(stderr, "remote %s\n", refname);
593 nref++;
596 req = 0;
597 for (i = 0; i < nref; i++) {
598 if (got_object_id_cmp(&have[i], &want[i]) == 0)
599 continue;
600 got_sha1_digest_to_str(want[i].sha1, hashstr, sizeof(hashstr));
601 n = snprintf(buf, sizeof(buf), "want %s%s%s\n", hashstr,
602 i == 0 && my_capabilities ? " " : "",
603 i == 0 && my_capabilities ? my_capabilities : "");
604 if (n >= sizeof(buf)) {
605 err = got_error(GOT_ERR_NO_SPACE);
606 goto done;
608 err = writepkt(fd, buf, n);
609 if (err)
610 goto done;
611 req = 1;
613 err = flushpkt(fd);
614 if (err)
615 goto done;
616 for (i = 0; i < nref; i++) {
617 if (got_object_id_cmp(&have[i], &zhash) == 0)
618 continue;
619 got_sha1_digest_to_str(want[i].sha1, hashstr, sizeof(hashstr));
620 n = snprintf(buf, sizeof(buf), "have %s\n", hashstr);
621 if (n >= sizeof(buf)) {
622 err = got_error(GOT_ERR_NO_SPACE);
623 goto done;
625 err = writepkt(fd, buf, n + 1);
626 if (err)
627 goto done;
629 if (!req) {
630 if (chattygit)
631 fprintf(stderr, "up to date\n");
632 err = flushpkt(fd);
633 if (err)
634 goto done;
636 n = snprintf(buf, sizeof(buf), "done\n");
637 err = writepkt(fd, buf, n);
638 if (err)
639 goto done;
640 if (!req)
641 return 0;
643 err = readpkt(&n, fd, buf, sizeof(buf));
644 if (err)
645 goto done;
646 /*
647 * For now, we only support a full clone, in which case the server
648 * will now send a "NAK" (meaning no common objects were found).
649 */
650 if (n != 4 || strncmp(buf, "NAK\n", n) != 0) {
651 err = got_error_msg(GOT_ERR_BAD_PACKET,
652 "unexpected message from server");
653 goto done;
656 if (chattygit)
657 fprintf(stderr, "fetching...\n");
659 if (my_capabilities != NULL &&
660 strstr(my_capabilities, GOT_CAPA_SIDE_BAND_64K) != NULL)
661 have_sidebands = 1;
663 packsz = 0;
664 while (1) {
665 ssize_t r = 0, w;
666 int datalen = -1;
668 if (have_sidebands) {
669 err = read_pkthdr(&datalen, fd);
670 if (err)
671 goto done;
672 if (datalen <= 0)
673 break;
675 /* Read sideband channel ID (one byte). */
676 r = read(fd, buf, 1);
677 if (r == -1) {
678 err = got_error_from_errno("read");
679 goto done;
681 if (r != 1) {
682 err = got_error_msg(GOT_ERR_BAD_PACKET,
683 "short packet");
684 goto done;
686 if (datalen > sizeof(buf) - 5) {
687 err = got_error_msg(GOT_ERR_BAD_PACKET,
688 "bad packet length");
689 goto done;
691 datalen--; /* sideband ID has been read */
692 if (buf[0] == GOT_SIDEBAND_PACKFILE_DATA) {
693 /* Read packfile data. */
694 err = readn(&r, fd, buf, datalen);
695 if (err)
696 goto done;
697 if (r != datalen) {
698 err = got_error_msg(GOT_ERR_BAD_PACKET,
699 "packet too short");
700 goto done;
702 } else if (buf[0] == GOT_SIDEBAND_PROGRESS_INFO) {
703 err = readn(&r, fd, buf, datalen);
704 if (err)
705 goto done;
706 if (r != datalen) {
707 err = got_error_msg(GOT_ERR_BAD_PACKET,
708 "packet too short");
709 goto done;
711 err = fetch_progress(ibuf, buf, r);
712 if (err)
713 goto done;
714 continue;
715 } else if (buf[0] == GOT_SIDEBAND_ERROR_INFO) {
716 err = readn(&r, fd, buf, datalen);
717 if (err)
718 goto done;
719 if (r != datalen) {
720 err = got_error_msg(GOT_ERR_BAD_PACKET,
721 "packet too short");
722 goto done;
724 err = fetch_error(buf, r);
725 goto done;
726 } else {
727 err = got_error_msg(GOT_ERR_BAD_PACKET,
728 "unknown side-band received from server");
729 goto done;
731 } else {
732 /* No sideband channel. Every byte is packfile data. */
733 err = readn(&r, fd, buf, sizeof buf);
734 if (err)
735 goto done;
736 if (r <= 0)
737 break;
740 /* Check pack file header. */
741 if (nobjects == 0) {
742 struct got_packfile_hdr *hdr = (void *)buf;
743 if (r < sizeof(*hdr)) {
744 err = got_error_msg(GOT_ERR_BAD_PACKFILE,
745 "short packfile header");
746 goto done;
748 if (hdr->signature != htobe32(GOT_PACKFILE_SIGNATURE)) {
749 err = got_error_msg(GOT_ERR_BAD_PACKFILE,
750 "bad packfile signature");
751 goto done;
753 if (hdr->version != htobe32(GOT_PACKFILE_VERSION)) {
754 err = got_error_msg(GOT_ERR_BAD_PACKFILE,
755 "bad packfile version");
756 goto done;
758 nobjects = betoh32(hdr->nobjects);
759 if (nobjects == 0) {
760 err = got_error_msg(GOT_ERR_BAD_PACKFILE,
761 "bad packfile with zero objects");
762 goto done;
766 /* Write packfile data to temporary pack file. */
767 w = write(packfd, buf, r);
768 if (w == -1) {
769 err = got_error_from_errno("write");
770 goto done;
772 if (w != r) {
773 err = got_error(GOT_ERR_IO);
774 goto done;
776 packsz += w;
778 if (lseek(packfd, 0, SEEK_SET) == -1) {
779 err = got_error_from_errno("lseek");
780 goto done;
782 err = check_pack_hash(packfd, packsz, packid->sha1);
783 done:
784 TAILQ_FOREACH(pe, &symrefs, entry) {
785 free((void *)pe->path);
786 free(pe->data);
788 got_pathlist_free(&symrefs);
789 free(have);
790 free(want);
791 free(id_str);
792 free(refname);
793 free(server_capabilities);
794 return err;
798 int
799 main(int argc, char **argv)
801 const struct got_error *err = NULL;
802 int fetchfd, packfd = -1;
803 struct got_object_id packid;
804 struct imsgbuf ibuf;
805 struct imsg imsg;
806 struct got_pathlist_head have_refs;
807 struct got_imsg_fetch_have_refs *fetch_have_refs = NULL;
808 size_t datalen;
810 TAILQ_INIT(&have_refs);
812 if (getenv("GOT_DEBUG") != NULL) {
813 fprintf(stderr, "fetch-pack being chatty!\n");
814 chattygit = 1;
817 imsg_init(&ibuf, GOT_IMSG_FD_CHILD);
818 #ifndef PROFILE
819 /* revoke access to most system calls */
820 if (pledge("stdio recvfd", NULL) == -1) {
821 err = got_error_from_errno("pledge");
822 got_privsep_send_error(&ibuf, err);
823 return 1;
825 #endif
826 if ((err = got_privsep_recv_imsg(&imsg, &ibuf, 0)) != 0) {
827 if (err->code == GOT_ERR_PRIVSEP_PIPE)
828 err = NULL;
829 goto done;
831 if (imsg.hdr.type == GOT_IMSG_STOP)
832 goto done;
833 if (imsg.hdr.type != GOT_IMSG_FETCH_REQUEST) {
834 err = got_error(GOT_ERR_PRIVSEP_MSG);
835 goto done;
837 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
838 if (datalen < sizeof(struct got_imsg_fetch_have_refs)) {
839 err = got_error(GOT_ERR_PRIVSEP_LEN);
840 goto done;
842 fetch_have_refs = (struct got_imsg_fetch_have_refs *)imsg.data;
843 if (datalen != sizeof(struct got_imsg_fetch_have_refs) +
844 sizeof(struct got_imsg_fetch_have_ref) *
845 fetch_have_refs->n_have_refs) {
846 err = got_error(GOT_ERR_PRIVSEP_LEN);
847 goto done;
849 if (fetch_have_refs->n_have_refs != 0) {
850 /* TODO: Incremental fetch support */
851 err = got_error(GOT_ERR_NOT_IMPL);
852 goto done;
854 fetchfd = imsg.fd;
856 if ((err = got_privsep_recv_imsg(&imsg, &ibuf, 0)) != 0) {
857 if (err->code == GOT_ERR_PRIVSEP_PIPE)
858 err = NULL;
859 goto done;
861 if (imsg.hdr.type == GOT_IMSG_STOP)
862 goto done;
863 if (imsg.hdr.type != GOT_IMSG_TMPFD) {
864 err = got_error(GOT_ERR_PRIVSEP_MSG);
865 goto done;
867 if (imsg.hdr.len - IMSG_HEADER_SIZE != 0) {
868 err = got_error(GOT_ERR_PRIVSEP_LEN);
869 goto done;
871 packfd = imsg.fd;
873 err = fetch_pack(fetchfd, packfd, &packid, &have_refs, &ibuf);
874 done:
875 if (packfd != -1 && close(packfd) == -1 && err == NULL)
876 err = got_error_from_errno("close");
877 if (err != NULL)
878 got_privsep_send_error(&ibuf, err);
879 else
880 err = got_privsep_send_fetch_done(&ibuf, packid);
881 if (err != NULL) {
882 fprintf(stderr, "%s: %s\n", getprogname(), err->msg);
883 got_privsep_send_error(&ibuf, err);
886 exit(0);