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;
372 done:
373 if (err) {
374 free(*my_capabilities);
375 *my_capabilities = NULL;
377 return err;
380 static const struct got_error *
381 send_upload_progress(struct imsgbuf *ibuf, off_t bytes)
383 if (imsg_compose(ibuf, GOT_IMSG_SEND_UPLOAD_PROGRESS, 0, 0, -1,
384 &bytes, sizeof(bytes)) == -1)
385 return got_error_from_errno(
386 "imsg_compose SEND_UPLOAD_PROGRESS");
388 return got_privsep_flush_imsg(ibuf);
391 static const struct got_error *
392 send_pack_request(struct imsgbuf *ibuf)
394 if (imsg_compose(ibuf, GOT_IMSG_SEND_PACK_REQUEST, 0, 0, -1,
395 NULL, 0) == -1)
396 return got_error_from_errno("imsg_compose SEND_PACK_REQUEST");
397 return got_privsep_flush_imsg(ibuf);
400 static const struct got_error *
401 send_done(struct imsgbuf *ibuf)
403 if (imsg_compose(ibuf, GOT_IMSG_SEND_DONE, 0, 0, -1, NULL, 0) == -1)
404 return got_error_from_errno("imsg_compose SEND_DONE");
405 return got_privsep_flush_imsg(ibuf);
408 static const struct got_error *
409 recv_packfd(int *packfd, struct imsgbuf *ibuf)
411 const struct got_error *err;
412 struct imsg imsg;
414 *packfd = -1;
416 err = got_privsep_recv_imsg(&imsg, ibuf, 0);
417 if (err)
418 return err;
420 if (imsg.hdr.type == GOT_IMSG_STOP) {
421 err = got_error(GOT_ERR_CANCELLED);
422 goto done;
425 if (imsg.hdr.type != GOT_IMSG_SEND_PACKFD) {
426 err = got_error(GOT_ERR_PRIVSEP_MSG);
427 goto done;
430 if (imsg.hdr.len - IMSG_HEADER_SIZE != 0) {
431 err = got_error(GOT_ERR_PRIVSEP_LEN);
432 goto done;
435 *packfd = imsg.fd;
436 done:
437 imsg_free(&imsg);
438 return err;
441 static const struct got_error *
442 send_pack_file(int sendfd, int packfd, struct imsgbuf *ibuf)
444 const struct got_error *err;
445 unsigned char buf[8192];
446 ssize_t r, w;
447 off_t wtotal = 0;
449 if (lseek(packfd, 0L, SEEK_SET) == -1)
450 return got_error_from_errno("lseek");
452 for (;;) {
453 r = read(packfd, buf, sizeof(buf));
454 if (r == -1)
455 return got_error_from_errno("read");
456 if (r == 0)
457 break;
458 w = write(sendfd, buf, r);
459 if (w == -1)
460 return got_error_from_errno("write");
461 if (w != r)
462 return got_error(GOT_ERR_IO);
463 wtotal += w;
464 err = send_upload_progress(ibuf, wtotal);
465 if (err)
466 return err;
469 return NULL;
472 static const struct got_error *
473 send_error(const char *buf, size_t len)
475 static char msg[1024];
476 size_t i;
478 for (i = 0; i < len && i < sizeof(msg) - 1; i++) {
479 if (!isprint(buf[i]))
480 return got_error_msg(GOT_ERR_BAD_PACKET,
481 "non-printable error message received from server");
482 msg[i] = buf[i];
484 msg[i] = '\0';
485 return got_error_msg(GOT_ERR_SEND_FAILED, msg);
488 static const struct got_error *
489 send_their_ref(struct imsgbuf *ibuf, struct got_object_id *refid,
490 const char *refname)
492 const struct got_error *err = NULL;
493 struct ibuf *wbuf;
494 size_t len, reflen = strlen(refname);
496 len = sizeof(struct got_imsg_send_remote_ref) + reflen;
497 if (len >= MAX_IMSGSIZE - IMSG_HEADER_SIZE)
498 return got_error(GOT_ERR_NO_SPACE);
500 wbuf = imsg_create(ibuf, GOT_IMSG_SEND_REMOTE_REF, 0, 0, len);
501 if (wbuf == NULL)
502 return got_error_from_errno("imsg_create SEND_REMOTE_REF");
504 /* Keep in sync with struct got_imsg_send_remote_ref definition! */
505 if (imsg_add(wbuf, refid->sha1, SHA1_DIGEST_LENGTH) == -1) {
506 err = got_error_from_errno("imsg_add SEND_REMOTE_REF");
507 ibuf_free(wbuf);
508 return err;
510 if (imsg_add(wbuf, &reflen, sizeof(reflen)) == -1) {
511 err = got_error_from_errno("imsg_add SEND_REMOTE_REF");
512 ibuf_free(wbuf);
513 return err;
515 if (imsg_add(wbuf, refname, reflen) == -1) {
516 err = got_error_from_errno("imsg_add SEND_REMOTE_REF");
517 ibuf_free(wbuf);
518 return err;
521 wbuf->fd = -1;
522 imsg_close(ibuf, wbuf);
523 return got_privsep_flush_imsg(ibuf);
526 static const struct got_error *
527 send_ref_status(struct imsgbuf *ibuf, const char *refname, int success,
528 struct got_pathlist_head *refs, struct got_pathlist_head *delete_refs)
531 const struct got_error *err = NULL;
532 struct ibuf *wbuf;
533 size_t len, reflen = strlen(refname);
534 struct got_pathlist_entry *pe;
535 int ref_valid = 0;
536 char *eol;
538 eol = strchr(refname, '\n');
539 if (eol == NULL) {
540 return got_error_msg(GOT_ERR_BAD_PACKET,
541 "unexpected message from server");
543 *eol = '\0';
545 TAILQ_FOREACH(pe, refs, entry) {
546 if (strcmp(refname, pe->path) == 0) {
547 ref_valid = 1;
548 break;
551 if (!ref_valid) {
552 TAILQ_FOREACH(pe, delete_refs, entry) {
553 if (strcmp(refname, pe->path) == 0) {
554 ref_valid = 1;
555 break;
559 if (!ref_valid) {
560 return got_error_msg(GOT_ERR_BAD_PACKET,
561 "unexpected message from server");
564 len = sizeof(struct got_imsg_send_ref_status) + reflen;
565 if (len >= MAX_IMSGSIZE - IMSG_HEADER_SIZE)
566 return got_error(GOT_ERR_NO_SPACE);
568 wbuf = imsg_create(ibuf, GOT_IMSG_SEND_REF_STATUS,
569 0, 0, len);
570 if (wbuf == NULL)
571 return got_error_from_errno("imsg_create SEND_REF_STATUS");
573 /* Keep in sync with struct got_imsg_send_ref_status definition! */
574 if (imsg_add(wbuf, &success, sizeof(success)) == -1) {
575 err = got_error_from_errno("imsg_add SEND_REF_STATUS");
576 ibuf_free(wbuf);
577 return err;
579 if (imsg_add(wbuf, &reflen, sizeof(reflen)) == -1) {
580 err = got_error_from_errno("imsg_add SEND_REF_STATUS");
581 ibuf_free(wbuf);
582 return err;
584 if (imsg_add(wbuf, refname, reflen) == -1) {
585 err = got_error_from_errno("imsg_add SEND_REF_STATUS");
586 ibuf_free(wbuf);
587 return err;
590 wbuf->fd = -1;
591 imsg_close(ibuf, wbuf);
592 return got_privsep_flush_imsg(ibuf);
595 static const struct got_error *
596 describe_refchange(int *n, int *sent_my_capabilites,
597 const char *my_capabilities, char *buf, size_t bufsize,
598 const char *refname, const char *old_hashstr, const char *new_hashstr)
600 *n = snprintf(buf, bufsize, "%s %s %s",
601 old_hashstr, new_hashstr, refname);
602 if (*n >= bufsize)
603 return got_error(GOT_ERR_NO_SPACE);
605 /*
606 * We must announce our capabilities along with the first
607 * reference. Unfortunately, the protocol requires an embedded
608 * NUL as a separator between reference name and capabilities,
609 * which we have to deal with here.
610 * It also requires a linefeed for terminating packet data.
611 */
612 if (!*sent_my_capabilites && my_capabilities != NULL) {
613 int m;
614 if (*n >= bufsize - 1)
615 return got_error(GOT_ERR_NO_SPACE);
616 m = snprintf(buf + *n + 1, /* offset after '\0' */
617 bufsize - (*n + 1), "%s\n", my_capabilities);
618 if (*n + m >= bufsize)
619 return got_error(GOT_ERR_NO_SPACE);
620 *n += m;
621 *sent_my_capabilites = 1;
622 } else {
623 *n = strlcat(buf, "\n", bufsize);
624 if (*n >= bufsize)
625 return got_error(GOT_ERR_NO_SPACE);
628 return NULL;
631 static const struct got_error *
632 send_pack(int fd, struct got_pathlist_head *refs,
633 struct got_pathlist_head *delete_refs, struct imsgbuf *ibuf)
635 const struct got_error *err = NULL;
636 char buf[GOT_FETCH_PKTMAX];
637 unsigned char zero_id[SHA1_DIGEST_LENGTH] = { 0 };
638 char old_hashstr[SHA1_DIGEST_STRING_LENGTH];
639 char new_hashstr[SHA1_DIGEST_STRING_LENGTH];
640 struct got_pathlist_head their_refs;
641 int is_firstpkt = 1;
642 int n, nsent = 0;
643 int packfd = -1;
644 char *id_str = NULL, *refname = NULL;
645 struct got_object_id *id = NULL;
646 char *server_capabilities = NULL, *my_capabilities = NULL;
647 struct got_pathlist_entry *pe;
648 int sent_my_capabilites = 0;
650 TAILQ_INIT(&their_refs);
652 if (TAILQ_EMPTY(refs) && TAILQ_EMPTY(delete_refs))
653 return got_error(GOT_ERR_SEND_EMPTY);
655 while (1) {
656 err = readpkt(&n, fd, buf, sizeof(buf));
657 if (err)
658 goto done;
659 if (n == 0)
660 break;
661 if (n >= 4 && strncmp(buf, "ERR ", 4) == 0) {
662 err = send_error(&buf[4], n - 4);
663 goto done;
665 err = parse_refline(&id_str, &refname, &server_capabilities,
666 buf, n);
667 if (err)
668 goto done;
669 if (is_firstpkt) {
670 if (chattygot && server_capabilities[0] != '\0')
671 fprintf(stderr, "%s: server capabilities: %s\n",
672 getprogname(), server_capabilities);
673 err = match_capabilities(&my_capabilities,
674 server_capabilities);
675 if (err)
676 goto done;
677 if (chattygot)
678 fprintf(stderr, "%s: my capabilities:%s\n",
679 getprogname(), my_capabilities);
680 is_firstpkt = 0;
682 if (strstr(refname, "^{}")) {
683 if (chattygot) {
684 fprintf(stderr, "%s: ignoring %s\n",
685 getprogname(), refname);
687 continue;
690 id = malloc(sizeof(*id));
691 if (id == NULL) {
692 err = got_error_from_errno("malloc");
693 goto done;
695 if (!got_parse_sha1_digest(id->sha1, id_str)) {
696 err = got_error(GOT_ERR_BAD_OBJ_ID_STR);
697 goto done;
699 err = send_their_ref(ibuf, id, refname);
700 if (err)
701 goto done;
703 err = got_pathlist_append(&their_refs, refname, id);
704 if (chattygot)
705 fprintf(stderr, "%s: remote has %s %s\n",
706 getprogname(), refname, id_str);
707 free(id_str);
708 id_str = NULL;
709 refname = NULL; /* do not free; owned by their_refs */
710 id = NULL; /* do not free; owned by their_refs */
713 if (!TAILQ_EMPTY(delete_refs)) {
714 if (my_capabilities == NULL ||
715 strstr(my_capabilities, GOT_CAPA_DELETE_REFS) == NULL) {
716 err = got_error(GOT_ERR_CAPA_DELETE_REFS);
717 goto done;
721 TAILQ_FOREACH(pe, delete_refs, entry) {
722 const char *refname = pe->path;
723 struct got_pathlist_entry *their_pe;
724 struct got_object_id *their_id = NULL;
726 TAILQ_FOREACH(their_pe, &their_refs, entry) {
727 const char *their_refname = their_pe->path;
728 if (got_path_cmp(refname, their_refname,
729 strlen(refname), strlen(their_refname)) == 0) {
730 their_id = their_pe->data;
731 break;
734 if (their_id == NULL) {
735 err = got_error_fmt(GOT_ERR_NOT_REF,
736 "%s does not exist in remote repository",
737 refname);
738 goto done;
741 got_sha1_digest_to_str(their_id->sha1, old_hashstr,
742 sizeof(old_hashstr));
743 got_sha1_digest_to_str(zero_id, new_hashstr,
744 sizeof(new_hashstr));
745 err = describe_refchange(&n, &sent_my_capabilites,
746 my_capabilities, buf, sizeof(buf), refname,
747 old_hashstr, new_hashstr);
748 if (err)
749 goto done;
750 err = writepkt(fd, buf, n);
751 if (err)
752 goto done;
753 if (chattygot) {
754 fprintf(stderr, "%s: deleting %s %s\n",
755 getprogname(), refname, old_hashstr);
757 nsent++;
760 TAILQ_FOREACH(pe, refs, entry) {
761 const char *refname = pe->path;
762 struct got_object_id *id = pe->data;
763 struct got_object_id *their_id = NULL;
764 struct got_pathlist_entry *their_pe;
766 TAILQ_FOREACH(their_pe, &their_refs, entry) {
767 const char *their_refname = their_pe->path;
768 if (got_path_cmp(refname, their_refname,
769 strlen(refname), strlen(their_refname)) == 0) {
770 their_id = their_pe->data;
771 break;
774 if (their_id) {
775 if (got_object_id_cmp(id, their_id) == 0) {
776 if (chattygot) {
777 fprintf(stderr,
778 "%s: no change for %s\n",
779 getprogname(), refname);
781 continue;
783 got_sha1_digest_to_str(their_id->sha1, old_hashstr,
784 sizeof(old_hashstr));
785 } else {
786 got_sha1_digest_to_str(zero_id, old_hashstr,
787 sizeof(old_hashstr));
789 got_sha1_digest_to_str(id->sha1, new_hashstr,
790 sizeof(new_hashstr));
791 err = describe_refchange(&n, &sent_my_capabilites,
792 my_capabilities, buf, sizeof(buf), refname,
793 old_hashstr, new_hashstr);
794 if (err)
795 goto done;
796 err = writepkt(fd, buf, n);
797 if (err)
798 goto done;
799 if (chattygot) {
800 if (their_id) {
801 fprintf(stderr, "%s: updating %s %s -> %s\n",
802 getprogname(), refname, old_hashstr,
803 new_hashstr);
804 } else {
805 fprintf(stderr, "%s: creating %s %s\n",
806 getprogname(), refname, new_hashstr);
809 nsent++;
811 err = flushpkt(fd);
812 if (err)
813 goto done;
815 err = send_pack_request(ibuf);
816 if (err)
817 goto done;
819 err = recv_packfd(&packfd, ibuf);
820 if (err)
821 goto done;
823 if (packfd != -1) {
824 err = send_pack_file(fd, packfd, ibuf);
825 if (err)
826 goto done;
829 err = readpkt(&n, fd, buf, sizeof(buf));
830 if (err)
831 goto done;
832 if (n >= 4 && strncmp(buf, "ERR ", 4) == 0) {
833 err = send_error(&buf[4], n - 4);
834 goto done;
835 } else if (n < 10 || strncmp(buf, "unpack ok\n", 10) != 0) {
836 err = got_error_msg(GOT_ERR_BAD_PACKET,
837 "unexpected message from server");
838 goto done;
841 while (nsent > 0) {
842 err = readpkt(&n, fd, buf, sizeof(buf));
843 if (err)
844 goto done;
845 if (n < 3) {
846 err = got_error_msg(GOT_ERR_BAD_PACKET,
847 "unexpected message from server");
848 goto done;
849 } else if (strncmp(buf, "ok ", 3) == 0) {
850 err = send_ref_status(ibuf, buf + 3, 1,
851 refs, delete_refs);
852 if (err)
853 goto done;
854 } else if (strncmp(buf, "ng ", 3) == 0) {
855 err = send_ref_status(ibuf, buf + 3, 0,
856 refs, delete_refs);
857 if (err)
858 goto done;
859 } else {
860 err = got_error_msg(GOT_ERR_BAD_PACKET,
861 "unexpected message from server");
862 goto done;
864 nsent--;
867 err = send_done(ibuf);
868 done:
869 TAILQ_FOREACH(pe, &their_refs, entry) {
870 free((void *)pe->path);
871 free(pe->data);
873 got_pathlist_free(&their_refs);
874 free(id_str);
875 free(id);
876 free(refname);
877 free(server_capabilities);
878 return err;
881 int
882 main(int argc, char **argv)
884 const struct got_error *err = NULL;
885 int sendfd, i;
886 struct imsgbuf ibuf;
887 struct imsg imsg;
888 struct got_pathlist_head refs;
889 struct got_pathlist_head delete_refs;
890 struct got_pathlist_entry *pe;
891 struct got_imsg_send_request send_req;
892 struct got_imsg_send_ref href;
893 size_t datalen;
894 #if 0
895 static int attached;
896 while (!attached)
897 sleep (1);
898 #endif
900 TAILQ_INIT(&refs);
901 TAILQ_INIT(&delete_refs);
903 imsg_init(&ibuf, GOT_IMSG_FD_CHILD);
904 #ifndef PROFILE
905 /* revoke access to most system calls */
906 if (pledge("stdio recvfd", NULL) == -1) {
907 err = got_error_from_errno("pledge");
908 got_privsep_send_error(&ibuf, err);
909 return 1;
911 #endif
912 if ((err = got_privsep_recv_imsg(&imsg, &ibuf, 0)) != 0) {
913 if (err->code == GOT_ERR_PRIVSEP_PIPE)
914 err = NULL;
915 goto done;
917 if (imsg.hdr.type == GOT_IMSG_STOP)
918 goto done;
919 if (imsg.hdr.type != GOT_IMSG_SEND_REQUEST) {
920 err = got_error(GOT_ERR_PRIVSEP_MSG);
921 goto done;
923 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
924 if (datalen < sizeof(send_req)) {
925 err = got_error(GOT_ERR_PRIVSEP_LEN);
926 goto done;
928 memcpy(&send_req, imsg.data, sizeof(send_req));
929 sendfd = imsg.fd;
930 imsg_free(&imsg);
932 if (send_req.verbosity > 0)
933 chattygot += send_req.verbosity;
935 for (i = 0; i < send_req.nrefs; i++) {
936 struct got_object_id *id;
937 char *refname;
939 if ((err = got_privsep_recv_imsg(&imsg, &ibuf, 0)) != 0) {
940 if (err->code == GOT_ERR_PRIVSEP_PIPE)
941 err = NULL;
942 goto done;
944 if (imsg.hdr.type == GOT_IMSG_STOP)
945 goto done;
946 if (imsg.hdr.type != GOT_IMSG_SEND_REF) {
947 err = got_error(GOT_ERR_PRIVSEP_MSG);
948 goto done;
950 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
951 if (datalen < sizeof(href)) {
952 err = got_error(GOT_ERR_PRIVSEP_LEN);
953 goto done;
955 memcpy(&href, imsg.data, sizeof(href));
956 if (datalen - sizeof(href) < href.name_len) {
957 err = got_error(GOT_ERR_PRIVSEP_LEN);
958 goto done;
960 refname = malloc(href.name_len + 1);
961 if (refname == NULL) {
962 err = got_error_from_errno("malloc");
963 goto done;
965 memcpy(refname, imsg.data + sizeof(href), href.name_len);
966 refname[href.name_len] = '\0';
968 /*
969 * Prevent sending of references that won't make any
970 * sense outside the local repository's context.
971 */
972 if (strncmp(refname, "refs/got/", 9) == 0 ||
973 strncmp(refname, "refs/remotes/", 13) == 0) {
974 err = got_error_fmt(GOT_ERR_SEND_BAD_REF,
975 "%s", refname);
976 goto done;
979 id = malloc(sizeof(*id));
980 if (id == NULL) {
981 free(refname);
982 err = got_error_from_errno("malloc");
983 goto done;
985 memcpy(id->sha1, href.id, SHA1_DIGEST_LENGTH);
986 if (href.delete)
987 err = got_pathlist_append(&delete_refs, refname, id);
988 else
989 err = got_pathlist_append(&refs, refname, id);
990 if (err) {
991 free(refname);
992 free(id);
993 goto done;
996 imsg_free(&imsg);
999 err = send_pack(sendfd, &refs, &delete_refs, &ibuf);
1000 done:
1001 TAILQ_FOREACH(pe, &refs, entry) {
1002 free((char *)pe->path);
1003 free(pe->data);
1005 got_pathlist_free(&refs);
1006 TAILQ_FOREACH(pe, &delete_refs, entry) {
1007 free((char *)pe->path);
1008 free(pe->data);
1010 got_pathlist_free(&delete_refs);
1011 if (sendfd != -1 && close(sendfd) == -1 && err == NULL)
1012 err = got_error_from_errno("close");
1013 if (err != NULL && err->code != GOT_ERR_CANCELLED) {
1014 fprintf(stderr, "%s: %s\n", getprogname(), err->msg);
1015 got_privsep_send_error(&ibuf, err);
1018 exit(0);