Blob


1 /*
2 * Copyright (c) 2019 Ori Bernstein <ori@openbsd.org>
3 * Copyright (c) 2021 Stefan Sperling <stsp@openbsd.org>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
18 #include <sys/types.h>
19 #include <sys/queue.h>
20 #include <sys/uio.h>
21 #include <sys/time.h>
22 #include <sys/stat.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 <unistd.h>
36 #include <zlib.h>
37 #include <err.h>
39 #include "got_error.h"
40 #include "got_object.h"
41 #include "got_path.h"
42 #include "got_version.h"
43 #include "got_fetch.h"
44 #include "got_reference.h"
46 #include "got_lib_sha1.h"
47 #include "got_lib_delta.h"
48 #include "got_lib_object.h"
49 #include "got_lib_object_parse.h"
50 #include "got_lib_privsep.h"
51 #include "got_lib_pack.h"
53 #ifndef nitems
54 #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
55 #endif
57 struct got_object *indexed;
58 static int chattygot;
60 static const struct got_error *
61 readn(ssize_t *off, int fd, void *buf, size_t n)
62 {
63 ssize_t r;
65 *off = 0;
66 while (*off != n) {
67 r = read(fd, buf + *off, n - *off);
68 if (r == -1)
69 return got_error_from_errno("read");
70 if (r == 0)
71 return NULL;
72 *off += r;
73 }
74 return NULL;
75 }
77 static const struct got_error *
78 flushpkt(int fd)
79 {
80 ssize_t w;
82 if (chattygot > 1)
83 fprintf(stderr, "%s: writepkt: 0000\n", getprogname());
85 w = write(fd, "0000", 4);
86 if (w == -1)
87 return got_error_from_errno("write");
88 if (w != 4)
89 return got_error(GOT_ERR_IO);
90 return NULL;
91 }
93 /*
94 * Packet header contains a 4-byte hexstring which specifies the length
95 * of data which follows.
96 */
97 static const struct got_error *
98 read_pkthdr(int *datalen, int fd)
99 {
100 static const struct got_error *err = NULL;
101 char lenstr[5];
102 long len;
103 char *e;
104 int n, i;
105 ssize_t r;
107 *datalen = 0;
109 err = readn(&r, fd, lenstr, 4);
110 if (err)
111 return err;
112 if (r == 0) {
113 /* implicit "0000" */
114 if (chattygot > 1)
115 fprintf(stderr, "%s: readpkt: 0000\n", getprogname());
116 return NULL;
118 if (r != 4)
119 return got_error_msg(GOT_ERR_BAD_PACKET,
120 "wrong packet header length");
122 lenstr[4] = '\0';
123 for (i = 0; i < 4; i++) {
124 if (!isprint((unsigned char)lenstr[i]))
125 return got_error_msg(GOT_ERR_BAD_PACKET,
126 "unprintable character in packet length field");
128 for (i = 0; i < 4; i++) {
129 if (!isxdigit((unsigned char)lenstr[i])) {
130 if (chattygot)
131 fprintf(stderr, "%s: bad length: '%s'\n",
132 getprogname(), lenstr);
133 return got_error_msg(GOT_ERR_BAD_PACKET,
134 "packet length not specified in hex");
137 errno = 0;
138 len = strtol(lenstr, &e, 16);
139 if (lenstr[0] == '\0' || *e != '\0')
140 return got_error(GOT_ERR_BAD_PACKET);
141 if (errno == ERANGE && (len == LONG_MAX || len == LONG_MIN))
142 return got_error_msg(GOT_ERR_BAD_PACKET, "bad packet length");
143 if (len > INT_MAX || len < INT_MIN)
144 return got_error_msg(GOT_ERR_BAD_PACKET, "bad packet length");
145 n = len;
146 if (n == 0)
147 return NULL;
148 if (n <= 4)
149 return got_error_msg(GOT_ERR_BAD_PACKET, "packet too short");
150 n -= 4;
152 *datalen = n;
153 return NULL;
156 static const struct got_error *
157 readpkt(int *outlen, int fd, char *buf, int buflen)
159 const struct got_error *err = NULL;
160 int datalen, i;
161 ssize_t n;
163 err = read_pkthdr(&datalen, fd);
164 if (err)
165 return err;
167 if (datalen > buflen)
168 return got_error(GOT_ERR_NO_SPACE);
170 err = readn(&n, fd, buf, datalen);
171 if (err)
172 return err;
173 if (n != datalen)
174 return got_error_msg(GOT_ERR_BAD_PACKET, "short packet");
176 if (chattygot > 1) {
177 fprintf(stderr, "%s: readpkt: %zd:\t", getprogname(), n);
178 for (i = 0; i < n; i++) {
179 if (isprint(buf[i]))
180 fputc(buf[i], stderr);
181 else
182 fprintf(stderr, "[0x%.2x]", buf[i]);
184 fputc('\n', stderr);
187 *outlen = n;
188 return NULL;
191 static const struct got_error *
192 writepkt(int fd, char *buf, int nbuf)
194 char len[5];
195 int i;
196 ssize_t w;
198 if (snprintf(len, sizeof(len), "%04x", nbuf + 4) >= sizeof(len))
199 return got_error(GOT_ERR_NO_SPACE);
200 w = write(fd, len, 4);
201 if (w == -1)
202 return got_error_from_errno("write");
203 if (w != 4)
204 return got_error(GOT_ERR_IO);
205 w = write(fd, buf, nbuf);
206 if (w == -1)
207 return got_error_from_errno("write");
208 if (w != nbuf)
209 return got_error(GOT_ERR_IO);
210 if (chattygot > 1) {
211 fprintf(stderr, "%s: writepkt: %s:\t", getprogname(), len);
212 for (i = 0; i < nbuf; i++) {
213 if (isprint(buf[i]))
214 fputc(buf[i], stderr);
215 else
216 fprintf(stderr, "[0x%.2x]", buf[i]);
218 fputc('\n', stderr);
220 return NULL;
223 static const struct got_error *
224 tokenize_refline(char **tokens, char *line, int len, int maxtokens)
226 const struct got_error *err = NULL;
227 char *p;
228 size_t i, n = 0;
230 for (i = 0; i < maxtokens; i++)
231 tokens[i] = NULL;
233 for (i = 0; n < len && i < maxtokens; i++) {
234 while (isspace(*line)) {
235 line++;
236 n++;
238 p = line;
239 while (*line != '\0' && n < len &&
240 (!isspace(*line) || i == maxtokens - 1)) {
241 line++;
242 n++;
244 tokens[i] = strndup(p, line - p);
245 if (tokens[i] == NULL) {
246 err = got_error_from_errno("strndup");
247 goto done;
249 /* Skip \0 field-delimiter at end of token. */
250 while (line[0] == '\0' && n < len) {
251 line++;
252 n++;
255 if (i <= 2)
256 err = got_error(GOT_ERR_NOT_REF);
257 done:
258 if (err) {
259 int j;
260 for (j = 0; j < i; j++) {
261 free(tokens[j]);
262 tokens[j] = NULL;
265 return err;
268 static const struct got_error *
269 parse_refline(char **id_str, char **refname, char **server_capabilities,
270 char *line, int len)
272 const struct got_error *err = NULL;
273 char *tokens[3];
275 err = tokenize_refline(tokens, line, len, nitems(tokens));
276 if (err)
277 return err;
279 if (tokens[0])
280 *id_str = tokens[0];
281 if (tokens[1])
282 *refname = tokens[1];
283 if (tokens[2]) {
284 char *p;
285 *server_capabilities = tokens[2];
286 p = strrchr(*server_capabilities, '\n');
287 if (p)
288 *p = '\0';
291 return NULL;
294 #define GOT_CAPA_AGENT "agent"
295 #define GOT_CAPA_OFS_DELTA "ofs-delta"
296 #define GOT_CAPA_SIDE_BAND_64K "side-band-64k"
297 #define GOT_CAPA_REPORT_STATUS "report-status"
298 #define GOT_CAPA_DELETE_REFS "delete-refs"
300 #define GOT_SIDEBAND_PACKFILE_DATA 1
301 #define GOT_SIDEBAND_PROGRESS_INFO 2
302 #define GOT_SIDEBAND_ERROR_INFO 3
305 struct got_capability {
306 const char *key;
307 const char *value;
308 };
309 static const struct got_capability got_capabilities[] = {
310 { GOT_CAPA_AGENT, "got/" GOT_VERSION_STR },
311 { GOT_CAPA_OFS_DELTA, NULL },
312 #if 0
313 { GOT_CAPA_SIDE_BAND_64K, NULL },
314 #endif
315 { GOT_CAPA_REPORT_STATUS, NULL },
316 { GOT_CAPA_DELETE_REFS, NULL },
317 };
319 static const struct got_error *
320 match_capability(char **my_capabilities, const char *capa,
321 const struct got_capability *mycapa)
323 char *equalsign;
324 char *s;
326 equalsign = strchr(capa, '=');
327 if (equalsign) {
328 if (strncmp(capa, mycapa->key, equalsign - capa) != 0)
329 return NULL;
330 } else {
331 if (strcmp(capa, mycapa->key) != 0)
332 return NULL;
335 if (asprintf(&s, "%s %s%s%s",
336 *my_capabilities != NULL ? *my_capabilities : "",
337 mycapa->key,
338 mycapa->value != NULL ? "=" : "",
339 mycapa->value != NULL? mycapa->value : "") == -1)
340 return got_error_from_errno("asprintf");
342 free(*my_capabilities);
343 *my_capabilities = s;
344 return NULL;
347 static const struct got_error *
348 match_capabilities(char **my_capabilities, char *server_capabilities)
350 const struct got_error *err = NULL;
351 char *capa;
352 size_t i;
354 *my_capabilities = NULL;
355 do {
356 capa = strsep(&server_capabilities, " ");
357 for (i = 0; capa != NULL && i < nitems(got_capabilities); i++) {
358 err = match_capability(my_capabilities,
359 capa, &got_capabilities[i]);
360 if (err)
361 goto done;
363 } while (capa);
365 if (*my_capabilities == NULL) {
366 *my_capabilities = strdup("");
367 if (*my_capabilities == NULL) {
368 err = got_error_from_errno("strdup");
369 goto done;
373 /*
374 * Workaround for github.
376 * Github will accept the pack but fail to update the references
377 * if we don't have capabilities advertised. Report-status seems
378 * harmless to add, so we add it.
380 * Github doesn't advertise any capabilities, so we can't check
381 * for compatibility. We just need to add it blindly.
382 */
383 if (strstr(*my_capabilities, GOT_CAPA_REPORT_STATUS) == NULL) {
384 char *s;
385 if (asprintf(&s, "%s %s", *my_capabilities,
386 GOT_CAPA_REPORT_STATUS) == -1) {
387 err = got_error_from_errno("asprintf");
388 goto done;
390 free(*my_capabilities);
391 *my_capabilities = s;
393 done:
394 if (err) {
395 free(*my_capabilities);
396 *my_capabilities = NULL;
398 return err;
401 static const struct got_error *
402 send_upload_progress(struct imsgbuf *ibuf, off_t bytes)
404 if (imsg_compose(ibuf, GOT_IMSG_SEND_UPLOAD_PROGRESS, 0, 0, -1,
405 &bytes, sizeof(bytes)) == -1)
406 return got_error_from_errno(
407 "imsg_compose SEND_UPLOAD_PROGRESS");
409 return got_privsep_flush_imsg(ibuf);
412 static const struct got_error *
413 send_pack_request(struct imsgbuf *ibuf)
415 if (imsg_compose(ibuf, GOT_IMSG_SEND_PACK_REQUEST, 0, 0, -1,
416 NULL, 0) == -1)
417 return got_error_from_errno("imsg_compose SEND_PACK_REQUEST");
418 return got_privsep_flush_imsg(ibuf);
421 static const struct got_error *
422 send_done(struct imsgbuf *ibuf)
424 if (imsg_compose(ibuf, GOT_IMSG_SEND_DONE, 0, 0, -1, NULL, 0) == -1)
425 return got_error_from_errno("imsg_compose SEND_DONE");
426 return got_privsep_flush_imsg(ibuf);
429 static const struct got_error *
430 recv_packfd(int *packfd, struct imsgbuf *ibuf)
432 const struct got_error *err;
433 struct imsg imsg;
435 *packfd = -1;
437 err = got_privsep_recv_imsg(&imsg, ibuf, 0);
438 if (err)
439 return err;
441 if (imsg.hdr.type == GOT_IMSG_STOP) {
442 err = got_error(GOT_ERR_CANCELLED);
443 goto done;
446 if (imsg.hdr.type != GOT_IMSG_SEND_PACKFD) {
447 err = got_error(GOT_ERR_PRIVSEP_MSG);
448 goto done;
451 if (imsg.hdr.len - IMSG_HEADER_SIZE != 0) {
452 err = got_error(GOT_ERR_PRIVSEP_LEN);
453 goto done;
456 *packfd = imsg.fd;
457 done:
458 imsg_free(&imsg);
459 return err;
462 static const struct got_error *
463 send_pack_file(int sendfd, int packfd, struct imsgbuf *ibuf)
465 const struct got_error *err;
466 unsigned char buf[8192];
467 ssize_t r, w;
468 off_t wtotal = 0;
470 if (lseek(packfd, 0L, SEEK_SET) == -1)
471 return got_error_from_errno("lseek");
473 for (;;) {
474 r = read(packfd, buf, sizeof(buf));
475 if (r == -1)
476 return got_error_from_errno("read");
477 if (r == 0)
478 break;
479 w = write(sendfd, buf, r);
480 if (w == -1)
481 return got_error_from_errno("write");
482 if (w != r)
483 return got_error(GOT_ERR_IO);
484 wtotal += w;
485 err = send_upload_progress(ibuf, wtotal);
486 if (err)
487 return err;
490 return NULL;
493 static const struct got_error *
494 send_error(const char *buf, size_t len)
496 static char msg[1024];
497 size_t i;
499 for (i = 0; i < len && i < sizeof(msg) - 1; i++) {
500 if (!isprint(buf[i]))
501 return got_error_msg(GOT_ERR_BAD_PACKET,
502 "non-printable error message received from server");
503 msg[i] = buf[i];
505 msg[i] = '\0';
506 return got_error_msg(GOT_ERR_SEND_FAILED, msg);
509 static const struct got_error *
510 send_their_ref(struct imsgbuf *ibuf, struct got_object_id *refid,
511 const char *refname)
513 const struct got_error *err = NULL;
514 struct ibuf *wbuf;
515 size_t len, reflen = strlen(refname);
517 len = sizeof(struct got_imsg_send_remote_ref) + reflen;
518 if (len >= MAX_IMSGSIZE - IMSG_HEADER_SIZE)
519 return got_error(GOT_ERR_NO_SPACE);
521 wbuf = imsg_create(ibuf, GOT_IMSG_SEND_REMOTE_REF, 0, 0, len);
522 if (wbuf == NULL)
523 return got_error_from_errno("imsg_create SEND_REMOTE_REF");
525 /* Keep in sync with struct got_imsg_send_remote_ref definition! */
526 if (imsg_add(wbuf, refid->sha1, SHA1_DIGEST_LENGTH) == -1) {
527 err = got_error_from_errno("imsg_add SEND_REMOTE_REF");
528 ibuf_free(wbuf);
529 return err;
531 if (imsg_add(wbuf, &reflen, sizeof(reflen)) == -1) {
532 err = got_error_from_errno("imsg_add SEND_REMOTE_REF");
533 ibuf_free(wbuf);
534 return err;
536 if (imsg_add(wbuf, refname, reflen) == -1) {
537 err = got_error_from_errno("imsg_add SEND_REMOTE_REF");
538 ibuf_free(wbuf);
539 return err;
542 wbuf->fd = -1;
543 imsg_close(ibuf, wbuf);
544 return got_privsep_flush_imsg(ibuf);
547 static const struct got_error *
548 send_ref_status(struct imsgbuf *ibuf, const char *refname, int success,
549 struct got_pathlist_head *refs, struct got_pathlist_head *delete_refs)
552 const struct got_error *err = NULL;
553 struct ibuf *wbuf;
554 size_t len, reflen = strlen(refname);
555 struct got_pathlist_entry *pe;
556 int ref_valid = 0;
557 char *eol;
559 eol = strchr(refname, '\n');
560 if (eol == NULL) {
561 return got_error_msg(GOT_ERR_BAD_PACKET,
562 "unexpected message from server");
564 *eol = '\0';
566 TAILQ_FOREACH(pe, refs, entry) {
567 if (strcmp(refname, pe->path) == 0) {
568 ref_valid = 1;
569 break;
572 if (!ref_valid) {
573 TAILQ_FOREACH(pe, delete_refs, entry) {
574 if (strcmp(refname, pe->path) == 0) {
575 ref_valid = 1;
576 break;
580 if (!ref_valid) {
581 return got_error_msg(GOT_ERR_BAD_PACKET,
582 "unexpected message from server");
585 len = sizeof(struct got_imsg_send_ref_status) + reflen;
586 if (len >= MAX_IMSGSIZE - IMSG_HEADER_SIZE)
587 return got_error(GOT_ERR_NO_SPACE);
589 wbuf = imsg_create(ibuf, GOT_IMSG_SEND_REF_STATUS,
590 0, 0, len);
591 if (wbuf == NULL)
592 return got_error_from_errno("imsg_create SEND_REF_STATUS");
594 /* Keep in sync with struct got_imsg_send_ref_status definition! */
595 if (imsg_add(wbuf, &success, sizeof(success)) == -1) {
596 err = got_error_from_errno("imsg_add SEND_REF_STATUS");
597 ibuf_free(wbuf);
598 return err;
600 if (imsg_add(wbuf, &reflen, sizeof(reflen)) == -1) {
601 err = got_error_from_errno("imsg_add SEND_REF_STATUS");
602 ibuf_free(wbuf);
603 return err;
605 if (imsg_add(wbuf, refname, reflen) == -1) {
606 err = got_error_from_errno("imsg_add SEND_REF_STATUS");
607 ibuf_free(wbuf);
608 return err;
611 wbuf->fd = -1;
612 imsg_close(ibuf, wbuf);
613 return got_privsep_flush_imsg(ibuf);
616 static const struct got_error *
617 describe_refchange(int *n, int *sent_my_capabilites,
618 const char *my_capabilities, char *buf, size_t bufsize,
619 const char *refname, const char *old_hashstr, const char *new_hashstr)
621 *n = snprintf(buf, bufsize, "%s %s %s",
622 old_hashstr, new_hashstr, refname);
623 if (*n >= bufsize)
624 return got_error(GOT_ERR_NO_SPACE);
626 /*
627 * We must announce our capabilities along with the first
628 * reference. Unfortunately, the protocol requires an embedded
629 * NUL as a separator between reference name and capabilities,
630 * which we have to deal with here.
631 * It also requires a linefeed for terminating packet data.
632 */
633 if (!*sent_my_capabilites && my_capabilities != NULL) {
634 int m;
635 if (*n >= bufsize - 1)
636 return got_error(GOT_ERR_NO_SPACE);
637 m = snprintf(buf + *n + 1, /* offset after '\0' */
638 bufsize - (*n + 1), "%s\n", my_capabilities);
639 if (*n + m >= bufsize)
640 return got_error(GOT_ERR_NO_SPACE);
641 *n += m;
642 *sent_my_capabilites = 1;
643 } else {
644 *n = strlcat(buf, "\n", bufsize);
645 if (*n >= bufsize)
646 return got_error(GOT_ERR_NO_SPACE);
649 return NULL;
652 static const struct got_error *
653 send_pack(int fd, struct got_pathlist_head *refs,
654 struct got_pathlist_head *delete_refs, struct imsgbuf *ibuf)
656 const struct got_error *err = NULL;
657 char buf[GOT_FETCH_PKTMAX];
658 unsigned char zero_id[SHA1_DIGEST_LENGTH] = { 0 };
659 char old_hashstr[SHA1_DIGEST_STRING_LENGTH];
660 char new_hashstr[SHA1_DIGEST_STRING_LENGTH];
661 struct got_pathlist_head their_refs;
662 int is_firstpkt = 1;
663 int n, nsent = 0;
664 int packfd = -1;
665 char *id_str = NULL, *refname = NULL;
666 struct got_object_id *id = NULL;
667 char *server_capabilities = NULL, *my_capabilities = NULL;
668 struct got_pathlist_entry *pe;
669 int sent_my_capabilites = 0;
671 TAILQ_INIT(&their_refs);
673 if (TAILQ_EMPTY(refs) && TAILQ_EMPTY(delete_refs))
674 return got_error(GOT_ERR_SEND_EMPTY);
676 while (1) {
677 err = readpkt(&n, fd, buf, sizeof(buf));
678 if (err)
679 goto done;
680 if (n == 0)
681 break;
682 if (n >= 4 && strncmp(buf, "ERR ", 4) == 0) {
683 err = send_error(&buf[4], n - 4);
684 goto done;
686 err = parse_refline(&id_str, &refname, &server_capabilities,
687 buf, n);
688 if (err)
689 goto done;
690 if (is_firstpkt) {
691 if (chattygot && server_capabilities[0] != '\0')
692 fprintf(stderr, "%s: server capabilities: %s\n",
693 getprogname(), server_capabilities);
694 err = match_capabilities(&my_capabilities,
695 server_capabilities);
696 if (err)
697 goto done;
698 if (chattygot)
699 fprintf(stderr, "%s: my capabilities:%s\n",
700 getprogname(), my_capabilities);
701 is_firstpkt = 0;
703 if (strstr(refname, "^{}")) {
704 if (chattygot) {
705 fprintf(stderr, "%s: ignoring %s\n",
706 getprogname(), refname);
708 continue;
711 id = malloc(sizeof(*id));
712 if (id == NULL) {
713 err = got_error_from_errno("malloc");
714 goto done;
716 if (!got_parse_sha1_digest(id->sha1, id_str)) {
717 err = got_error(GOT_ERR_BAD_OBJ_ID_STR);
718 goto done;
720 err = send_their_ref(ibuf, id, refname);
721 if (err)
722 goto done;
724 err = got_pathlist_append(&their_refs, refname, id);
725 if (chattygot)
726 fprintf(stderr, "%s: remote has %s %s\n",
727 getprogname(), refname, id_str);
728 free(id_str);
729 id_str = NULL;
730 refname = NULL; /* do not free; owned by their_refs */
731 id = NULL; /* do not free; owned by their_refs */
734 if (!TAILQ_EMPTY(delete_refs)) {
735 if (my_capabilities == NULL ||
736 strstr(my_capabilities, GOT_CAPA_DELETE_REFS) == NULL) {
737 err = got_error(GOT_ERR_CAPA_DELETE_REFS);
738 goto done;
742 TAILQ_FOREACH(pe, delete_refs, entry) {
743 const char *refname = pe->path;
744 struct got_pathlist_entry *their_pe;
745 struct got_object_id *their_id = NULL;
747 TAILQ_FOREACH(their_pe, &their_refs, entry) {
748 const char *their_refname = their_pe->path;
749 if (got_path_cmp(refname, their_refname,
750 strlen(refname), strlen(their_refname)) == 0) {
751 their_id = their_pe->data;
752 break;
755 if (their_id == NULL) {
756 err = got_error_fmt(GOT_ERR_NOT_REF,
757 "%s does not exist in remote repository",
758 refname);
759 goto done;
762 got_sha1_digest_to_str(their_id->sha1, old_hashstr,
763 sizeof(old_hashstr));
764 got_sha1_digest_to_str(zero_id, new_hashstr,
765 sizeof(new_hashstr));
766 err = describe_refchange(&n, &sent_my_capabilites,
767 my_capabilities, buf, sizeof(buf), refname,
768 old_hashstr, new_hashstr);
769 if (err)
770 goto done;
771 err = writepkt(fd, buf, n);
772 if (err)
773 goto done;
774 if (chattygot) {
775 fprintf(stderr, "%s: deleting %s %s\n",
776 getprogname(), refname, old_hashstr);
778 nsent++;
781 TAILQ_FOREACH(pe, refs, entry) {
782 const char *refname = pe->path;
783 struct got_object_id *id = pe->data;
784 struct got_object_id *their_id = NULL;
785 struct got_pathlist_entry *their_pe;
787 TAILQ_FOREACH(their_pe, &their_refs, entry) {
788 const char *their_refname = their_pe->path;
789 if (got_path_cmp(refname, their_refname,
790 strlen(refname), strlen(their_refname)) == 0) {
791 their_id = their_pe->data;
792 break;
795 if (their_id) {
796 if (got_object_id_cmp(id, their_id) == 0) {
797 if (chattygot) {
798 fprintf(stderr,
799 "%s: no change for %s\n",
800 getprogname(), refname);
802 continue;
804 got_sha1_digest_to_str(their_id->sha1, old_hashstr,
805 sizeof(old_hashstr));
806 } else {
807 got_sha1_digest_to_str(zero_id, old_hashstr,
808 sizeof(old_hashstr));
810 got_sha1_digest_to_str(id->sha1, new_hashstr,
811 sizeof(new_hashstr));
812 err = describe_refchange(&n, &sent_my_capabilites,
813 my_capabilities, buf, sizeof(buf), refname,
814 old_hashstr, new_hashstr);
815 if (err)
816 goto done;
817 err = writepkt(fd, buf, n);
818 if (err)
819 goto done;
820 if (chattygot) {
821 if (their_id) {
822 fprintf(stderr, "%s: updating %s %s -> %s\n",
823 getprogname(), refname, old_hashstr,
824 new_hashstr);
825 } else {
826 fprintf(stderr, "%s: creating %s %s\n",
827 getprogname(), refname, new_hashstr);
830 nsent++;
832 err = flushpkt(fd);
833 if (err)
834 goto done;
836 err = send_pack_request(ibuf);
837 if (err)
838 goto done;
840 err = recv_packfd(&packfd, ibuf);
841 if (err)
842 goto done;
844 err = send_pack_file(fd, packfd, ibuf);
845 if (err)
846 goto done;
848 err = readpkt(&n, fd, buf, sizeof(buf));
849 if (err)
850 goto done;
851 if (n >= 4 && strncmp(buf, "ERR ", 4) == 0) {
852 err = send_error(&buf[4], n - 4);
853 goto done;
854 } else if (n < 10 || strncmp(buf, "unpack ok\n", 10) != 0) {
855 err = got_error_msg(GOT_ERR_BAD_PACKET,
856 "unexpected message from server");
857 goto done;
860 while (nsent > 0) {
861 err = readpkt(&n, fd, buf, sizeof(buf));
862 if (err)
863 goto done;
864 if (n < 3) {
865 err = got_error_msg(GOT_ERR_BAD_PACKET,
866 "unexpected message from server");
867 goto done;
868 } else if (strncmp(buf, "ok ", 3) == 0) {
869 err = send_ref_status(ibuf, buf + 3, 1,
870 refs, delete_refs);
871 if (err)
872 goto done;
873 } else if (strncmp(buf, "ng ", 3) == 0) {
874 err = send_ref_status(ibuf, buf + 3, 0,
875 refs, delete_refs);
876 if (err)
877 goto done;
878 } else {
879 err = got_error_msg(GOT_ERR_BAD_PACKET,
880 "unexpected message from server");
881 goto done;
883 nsent--;
886 err = send_done(ibuf);
887 done:
888 TAILQ_FOREACH(pe, &their_refs, entry) {
889 free((void *)pe->path);
890 free(pe->data);
892 got_pathlist_free(&their_refs);
893 free(id_str);
894 free(id);
895 free(refname);
896 free(server_capabilities);
897 return err;
900 int
901 main(int argc, char **argv)
903 const struct got_error *err = NULL;
904 int sendfd, i;
905 struct imsgbuf ibuf;
906 struct imsg imsg;
907 struct got_pathlist_head refs;
908 struct got_pathlist_head delete_refs;
909 struct got_pathlist_entry *pe;
910 struct got_imsg_send_request send_req;
911 struct got_imsg_send_ref href;
912 size_t datalen;
913 #if 0
914 static int attached;
915 while (!attached)
916 sleep (1);
917 #endif
919 TAILQ_INIT(&refs);
920 TAILQ_INIT(&delete_refs);
922 imsg_init(&ibuf, GOT_IMSG_FD_CHILD);
923 #ifndef PROFILE
924 /* revoke access to most system calls */
925 if (pledge("stdio recvfd", NULL) == -1) {
926 err = got_error_from_errno("pledge");
927 got_privsep_send_error(&ibuf, err);
928 return 1;
930 #endif
931 if ((err = got_privsep_recv_imsg(&imsg, &ibuf, 0)) != 0) {
932 if (err->code == GOT_ERR_PRIVSEP_PIPE)
933 err = NULL;
934 goto done;
936 if (imsg.hdr.type == GOT_IMSG_STOP)
937 goto done;
938 if (imsg.hdr.type != GOT_IMSG_SEND_REQUEST) {
939 err = got_error(GOT_ERR_PRIVSEP_MSG);
940 goto done;
942 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
943 if (datalen < sizeof(send_req)) {
944 err = got_error(GOT_ERR_PRIVSEP_LEN);
945 goto done;
947 memcpy(&send_req, imsg.data, sizeof(send_req));
948 sendfd = imsg.fd;
949 imsg_free(&imsg);
951 if (send_req.verbosity > 0)
952 chattygot += send_req.verbosity;
954 for (i = 0; i < send_req.nrefs; i++) {
955 struct got_object_id *id;
956 char *refname;
958 if ((err = got_privsep_recv_imsg(&imsg, &ibuf, 0)) != 0) {
959 if (err->code == GOT_ERR_PRIVSEP_PIPE)
960 err = NULL;
961 goto done;
963 if (imsg.hdr.type == GOT_IMSG_STOP)
964 goto done;
965 if (imsg.hdr.type != GOT_IMSG_SEND_REF) {
966 err = got_error(GOT_ERR_PRIVSEP_MSG);
967 goto done;
969 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
970 if (datalen < sizeof(href)) {
971 err = got_error(GOT_ERR_PRIVSEP_LEN);
972 goto done;
974 memcpy(&href, imsg.data, sizeof(href));
975 if (datalen - sizeof(href) < href.name_len) {
976 err = got_error(GOT_ERR_PRIVSEP_LEN);
977 goto done;
979 refname = malloc(href.name_len + 1);
980 if (refname == NULL) {
981 err = got_error_from_errno("malloc");
982 goto done;
984 memcpy(refname, imsg.data + sizeof(href), href.name_len);
985 refname[href.name_len] = '\0';
987 /*
988 * Prevent sending of references that won't make any
989 * sense outside the local repository's context.
990 */
991 if (strncmp(refname, "refs/got/", 9) == 0 ||
992 strncmp(refname, "refs/remotes/", 13) == 0) {
993 err = got_error_fmt(GOT_ERR_SEND_BAD_REF,
994 "%s", refname);
995 goto done;
998 id = malloc(sizeof(*id));
999 if (id == NULL) {
1000 free(refname);
1001 err = got_error_from_errno("malloc");
1002 goto done;
1004 memcpy(id->sha1, href.id, SHA1_DIGEST_LENGTH);
1005 if (href.delete)
1006 err = got_pathlist_append(&delete_refs, refname, id);
1007 else
1008 err = got_pathlist_append(&refs, refname, id);
1009 if (err) {
1010 free(refname);
1011 free(id);
1012 goto done;
1015 imsg_free(&imsg);
1018 err = send_pack(sendfd, &refs, &delete_refs, &ibuf);
1019 done:
1020 TAILQ_FOREACH(pe, &refs, entry) {
1021 free((char *)pe->path);
1022 free(pe->data);
1024 got_pathlist_free(&refs);
1025 TAILQ_FOREACH(pe, &delete_refs, entry) {
1026 free((char *)pe->path);
1027 free(pe->data);
1029 got_pathlist_free(&delete_refs);
1030 if (sendfd != -1 && close(sendfd) == -1 && err == NULL)
1031 err = got_error_from_errno("close");
1032 if (err != NULL && err->code != GOT_ERR_CANCELLED) {
1033 fprintf(stderr, "%s: %s\n", getprogname(), err->msg);
1034 got_privsep_send_error(&ibuf, err);
1037 exit(0);