2 * Copyright (c) 2022 Stefan Sperling <stsp@openbsd.org>
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.
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.
17 #include <sys/queue.h>
18 #include <sys/types.h>
33 #include "got_error.h"
34 #include "got_cancel.h"
35 #include "got_object.h"
36 #include "got_repository.h"
37 #include "got_reference.h"
38 #include "got_repository_admin.h"
40 #include "got_lib_delta.h"
41 #include "got_lib_object.h"
42 #include "got_lib_object_idset.h"
43 #include "got_lib_sha1.h"
44 #include "got_lib_pack.h"
45 #include "got_lib_ratelimit.h"
46 #include "got_lib_pack_create.h"
47 #include "got_lib_poll.h"
51 #include "repo_read.h"
54 #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
57 static struct repo_read {
60 struct got_repository *repo;
65 struct repo_read_client {
66 STAILQ_ENTRY(repo_read_client) entry;
72 struct gotd_object_id_array want_ids;
73 struct gotd_object_id_array have_ids;
75 STAILQ_HEAD(repo_read_clients, repo_read_client);
77 static struct repo_read_clients repo_read_clients[GOTD_CLIENT_TABLE_SIZE];
78 static SIPHASH_KEY clients_hash_key;
81 client_hash(uint32_t client_id)
83 return SipHash24(&clients_hash_key, &client_id, sizeof(client_id));
87 add_client(struct repo_read_client *client, uint32_t client_id, int fd)
91 client->id = client_id;
93 client->delta_cache_fd = -1;
94 client->pack_pipe[0] = -1;
95 client->pack_pipe[1] = -1;
96 slot = client_hash(client->id) % nitems(repo_read_clients);
97 STAILQ_INSERT_HEAD(&repo_read_clients[slot], client, entry);
100 static struct repo_read_client *
101 find_client(uint32_t client_id)
104 struct repo_read_client *c;
106 slot = client_hash(client_id) % nitems(repo_read_clients);
107 STAILQ_FOREACH(c, &repo_read_clients[slot], entry) {
108 if (c->id == client_id)
115 static volatile sig_atomic_t sigint_received;
116 static volatile sig_atomic_t sigterm_received;
119 catch_sigint(int signo)
125 catch_sigterm(int signo)
127 sigterm_received = 1;
130 static const struct got_error *
131 check_cancelled(void *arg)
133 if (sigint_received || sigterm_received)
134 return got_error(GOT_ERR_CANCELLED);
139 static const struct got_error *
140 send_symref(struct got_reference *symref, struct imsgbuf *ibuf)
142 const struct got_error *err = NULL;
143 struct gotd_imsg_symref isymref;
144 const char *refname = got_ref_get_name(symref);
145 const char *target = got_ref_get_symref_target(symref);
148 struct got_object_id *target_id;
150 err = got_ref_resolve(&target_id, repo_read.repo, symref);
154 memset(&isymref, 0, sizeof(isymref));
155 isymref.name_len = strlen(refname);
156 isymref.target_len = strlen(target);
157 memcpy(isymref.target_id, target_id->sha1, sizeof(isymref.target_id));
159 len = sizeof(isymref) + isymref.name_len + isymref.target_len;
160 if (len > MAX_IMSGSIZE - IMSG_HEADER_SIZE) {
161 err = got_error(GOT_ERR_NO_SPACE);
165 wbuf = imsg_create(ibuf, GOTD_IMSG_SYMREF, 0, 0, len);
167 err = got_error_from_errno("imsg_create SYMREF");
171 if (imsg_add(wbuf, &isymref, sizeof(isymref)) == -1) {
172 err = got_error_from_errno("imsg_add SYMREF");
175 if (imsg_add(wbuf, refname, isymref.name_len) == -1) {
176 err = got_error_from_errno("imsg_add SYMREF");
179 if (imsg_add(wbuf, target, isymref.target_len) == -1) {
180 err = got_error_from_errno("imsg_add SYMREF");
185 imsg_close(ibuf, wbuf);
191 static const struct got_error *
192 send_peeled_tag_ref(struct got_reference *ref, struct got_object *obj,
193 struct imsgbuf *ibuf)
195 const struct got_error *err = NULL;
196 struct got_tag_object *tag;
198 char *peeled_refname = NULL;
199 struct got_object_id *id;
202 err = got_object_tag_open(&tag, repo_read.repo, obj);
206 if (asprintf(&peeled_refname, "%s^{}", got_ref_get_name(ref)) == -1) {
207 err = got_error_from_errno("asprintf");
211 id = got_object_tag_get_object_id(tag);
212 namelen = strlen(peeled_refname);
214 len = sizeof(struct gotd_imsg_ref) + namelen;
215 if (len > MAX_IMSGSIZE - IMSG_HEADER_SIZE) {
216 err = got_error(GOT_ERR_NO_SPACE);
220 wbuf = imsg_create(ibuf, GOTD_IMSG_REF, PROC_REPO_READ,
223 err = got_error_from_errno("imsg_create MREF");
227 /* Keep in sync with struct gotd_imsg_ref definition. */
228 if (imsg_add(wbuf, id->sha1, SHA1_DIGEST_LENGTH) == -1) {
229 err = got_error_from_errno("imsg_add REF");
232 if (imsg_add(wbuf, &namelen, sizeof(namelen)) == -1) {
233 err = got_error_from_errno("imsg_add REF");
236 if (imsg_add(wbuf, peeled_refname, namelen) == -1) {
237 err = got_error_from_errno("imsg_add REF");
242 imsg_close(ibuf, wbuf);
244 got_object_tag_close(tag);
248 static const struct got_error *
249 send_ref(struct got_reference *ref, struct imsgbuf *ibuf)
251 const struct got_error *err;
252 const char *refname = got_ref_get_name(ref);
254 struct got_object_id *id = NULL;
255 struct got_object *obj = NULL;
259 namelen = strlen(refname);
261 len = sizeof(struct gotd_imsg_ref) + namelen;
262 if (len > MAX_IMSGSIZE - IMSG_HEADER_SIZE)
263 return got_error(GOT_ERR_NO_SPACE);
265 err = got_ref_resolve(&id, repo_read.repo, ref);
269 wbuf = imsg_create(ibuf, GOTD_IMSG_REF, PROC_REPO_READ,
272 err = got_error_from_errno("imsg_create REF");
276 /* Keep in sync with struct gotd_imsg_ref definition. */
277 if (imsg_add(wbuf, id->sha1, SHA1_DIGEST_LENGTH) == -1)
278 return got_error_from_errno("imsg_add REF");
279 if (imsg_add(wbuf, &namelen, sizeof(namelen)) == -1)
280 return got_error_from_errno("imsg_add REF");
281 if (imsg_add(wbuf, refname, namelen) == -1)
282 return got_error_from_errno("imsg_add REF");
285 imsg_close(ibuf, wbuf);
287 err = got_object_open(&obj, repo_read.repo, id);
290 if (obj->type == GOT_OBJ_TYPE_TAG)
291 err = send_peeled_tag_ref(ref, obj, ibuf);
294 got_object_close(obj);
299 static const struct got_error *
300 list_refs(struct repo_read_client **client, struct imsg *imsg)
302 const struct got_error *err;
303 struct got_reflist_head refs;
304 struct got_reflist_entry *re;
305 struct gotd_imsg_list_refs_internal ireq;
307 struct gotd_imsg_reflist irefs;
309 int client_fd = imsg->fd;
314 return got_error(GOT_ERR_PRIVSEP_NO_FD);
316 datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
317 if (datalen != sizeof(ireq))
318 return got_error(GOT_ERR_PRIVSEP_LEN);
319 memcpy(&ireq, imsg->data, sizeof(ireq));
321 *client = find_client(ireq.client_id);
323 return got_error_msg(GOT_ERR_CLIENT_ID, "duplicate client ID");
325 *client = calloc(1, sizeof(**client));
327 return got_error_from_errno("calloc");
328 add_client(*client, ireq.client_id, client_fd);
330 imsg_init(&ibuf, client_fd);
332 err = got_ref_list(&refs, repo_read.repo, "",
333 got_ref_cmp_by_name, NULL);
337 memset(&irefs, 0, sizeof(irefs));
338 TAILQ_FOREACH(re, &refs, entry) {
339 struct got_object_id *id;
342 if (got_ref_is_symbolic(re->ref)) {
343 const char *refname = got_ref_get_name(re->ref);
344 if (strcmp(refname, GOT_REF_HEAD) == 0)
351 /* Account for a peeled tag refs. */
352 err = got_ref_resolve(&id, repo_read.repo, re->ref);
355 err = got_object_get_type(&obj_type, repo_read.repo, id);
359 if (obj_type == GOT_OBJ_TYPE_TAG)
363 if (imsg_compose(&ibuf, GOTD_IMSG_REFLIST, PROC_REPO_READ,
364 repo_read.pid, -1, &irefs, sizeof(irefs)) == -1) {
365 err = got_error_from_errno("imsg_compose REFLIST");
370 * Send the HEAD symref first. In Git-protocol versions < 2
371 * the HEAD symref must be announced on the initial line of
372 * the server's ref advertisement.
373 * For now, we do not advertise symrefs other than HEAD.
375 TAILQ_FOREACH(re, &refs, entry) {
376 if (!got_ref_is_symbolic(re->ref) ||
377 strcmp(got_ref_get_name(re->ref), GOT_REF_HEAD) != 0)
379 err = send_symref(re->ref, &ibuf);
384 TAILQ_FOREACH(re, &refs, entry) {
385 if (got_ref_is_symbolic(re->ref))
387 err = send_ref(re->ref, &ibuf);
392 err = gotd_imsg_flush(&ibuf);
394 got_ref_list_free(&refs);
399 static const struct got_error *
400 record_object_id(struct gotd_object_id_array *array, struct got_object_id *id)
402 const size_t alloc_chunksz = 256;
404 if (array->ids == NULL) {
405 array->ids = reallocarray(NULL, alloc_chunksz,
406 sizeof(*array->ids));
407 if (array->ids == NULL)
408 return got_error_from_errno("reallocarray");
409 array->nalloc = alloc_chunksz;
411 } else if (array->nalloc <= array->nids) {
412 struct got_object_id **new;
413 new = recallocarray(array->ids, array->nalloc,
414 array->nalloc + alloc_chunksz, sizeof(*new));
416 return got_error_from_errno("recallocarray");
418 array->nalloc += alloc_chunksz;
421 array->ids[array->nids] = got_object_id_dup(id);
422 if (array->ids[array->nids] == NULL)
423 return got_error_from_errno("got_object_id_dup");
429 free_object_ids(struct gotd_object_id_array *array)
433 for (i = 0; i < array->nids; i++)
442 static const struct got_error *
443 recv_want(struct repo_read_client **client, struct imsg *imsg)
445 const struct got_error *err;
446 struct gotd_imsg_want iwant;
448 char hex[SHA1_DIGEST_STRING_LENGTH];
449 struct got_object_id id;
453 datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
454 if (datalen != sizeof(iwant))
455 return got_error(GOT_ERR_PRIVSEP_LEN);
456 memcpy(&iwant, imsg->data, sizeof(iwant));
458 memset(&id, 0, sizeof(id));
459 memcpy(id.sha1, iwant.object_id, SHA1_DIGEST_LENGTH);
461 if (log_getverbose() > 0 &&
462 got_sha1_digest_to_str(id.sha1, hex, sizeof(hex)))
463 log_debug("client wants %s", hex);
465 *client = find_client(iwant.client_id);
467 return got_error(GOT_ERR_CLIENT_ID);
469 imsg_init(&ibuf, (*client)->fd);
471 err = got_object_get_type(&obj_type, repo_read.repo, &id);
475 if (obj_type != GOT_OBJ_TYPE_COMMIT &&
476 obj_type != GOT_OBJ_TYPE_TAG)
477 return got_error(GOT_ERR_OBJ_TYPE);
479 err = record_object_id(&(*client)->want_ids, &id);
483 gotd_imsg_send_ack(&id, &ibuf, PROC_REPO_READ, repo_read.pid);
488 static const struct got_error *
489 recv_have(struct repo_read_client **client, struct imsg *imsg)
491 const struct got_error *err;
492 struct gotd_imsg_have ihave;
494 char hex[SHA1_DIGEST_STRING_LENGTH];
495 struct got_object_id id;
499 datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
500 if (datalen != sizeof(ihave))
501 return got_error(GOT_ERR_PRIVSEP_LEN);
502 memcpy(&ihave, imsg->data, sizeof(ihave));
504 memset(&id, 0, sizeof(id));
505 memcpy(id.sha1, ihave.object_id, SHA1_DIGEST_LENGTH);
507 if (log_getverbose() > 0 &&
508 got_sha1_digest_to_str(id.sha1, hex, sizeof(hex)))
509 log_debug("client has %s", hex);
511 *client = find_client(ihave.client_id);
513 return got_error(GOT_ERR_CLIENT_ID);
515 imsg_init(&ibuf, (*client)->fd);
517 err = got_object_get_type(&obj_type, repo_read.repo, &id);
519 if (err->code == GOT_ERR_NO_OBJ) {
520 gotd_imsg_send_nak(&id, &ibuf,
521 PROC_REPO_READ, repo_read.pid);
527 if (obj_type != GOT_OBJ_TYPE_COMMIT &&
528 obj_type != GOT_OBJ_TYPE_TAG) {
529 gotd_imsg_send_nak(&id, &ibuf, PROC_REPO_READ, repo_read.pid);
530 err = got_error(GOT_ERR_OBJ_TYPE);
534 err = record_object_id(&(*client)->have_ids, &id);
538 gotd_imsg_send_ack(&id, &ibuf, PROC_REPO_READ, repo_read.pid);
544 struct repo_read_pack_progress_arg {
546 struct imsgbuf *ibuf;
550 static const struct got_error *
551 pack_progress(void *arg, int ncolored, int nfound, int ntrees,
552 off_t packfile_size, int ncommits, int nobj_total, int nobj_deltify,
555 struct repo_read_pack_progress_arg *a = arg;
556 struct gotd_imsg_packfile_progress iprog;
559 if (!a->report_progress)
561 if (packfile_size > 0 && a->sent_ready)
564 memset(&iprog, 0, sizeof(iprog));
565 iprog.ncolored = ncolored;
566 iprog.nfound = nfound;
567 iprog.ntrees = ntrees;
568 iprog.packfile_size = packfile_size;
569 iprog.ncommits = ncommits;
570 iprog.nobj_total = nobj_total;
571 iprog.nobj_deltify = nobj_deltify;
572 iprog.nobj_written = nobj_written;
574 /* Using synchronous writes since we are blocking the event loop. */
575 if (packfile_size == 0) {
576 ret = imsg_compose(a->ibuf, GOTD_IMSG_PACKFILE_PROGRESS,
577 PROC_REPO_READ, repo_read.pid, -1, &iprog, sizeof(iprog));
579 return got_error_from_errno("imsg compose "
580 "PACKFILE_PROGRESS");
584 ret = imsg_compose(a->ibuf, GOTD_IMSG_PACKFILE_READY,
585 PROC_REPO_READ, repo_read.pid, -1, &iprog, sizeof(iprog));
587 return got_error_from_errno("imsg compose "
592 return gotd_imsg_flush(a->ibuf);
595 static const struct got_error *
596 receive_delta_cache_fd(struct repo_read_client **client, struct imsg *imsg,
597 struct gotd_imsgev *iev)
599 struct gotd_imsg_send_packfile ireq;
602 log_debug("receving delta cache file");
605 return got_error(GOT_ERR_PRIVSEP_NO_FD);
607 datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
608 if (datalen != sizeof(ireq))
609 return got_error(GOT_ERR_PRIVSEP_LEN);
610 memcpy(&ireq, imsg->data, sizeof(ireq));
612 *client = find_client(ireq.client_id);
614 return got_error(GOT_ERR_CLIENT_ID);
616 if ((*client)->delta_cache_fd != -1)
617 return got_error(GOT_ERR_PRIVSEP_MSG);
619 (*client)->delta_cache_fd = imsg->fd;
620 (*client)->report_progress = ireq.report_progress;
624 static const struct got_error *
625 receive_pack_pipe(struct repo_read_client **client, struct imsg *imsg,
626 struct gotd_imsgev *iev)
628 struct gotd_imsg_packfile_pipe ireq;
631 log_debug("receving pack pipe descriptor");
634 return got_error(GOT_ERR_PRIVSEP_NO_FD);
636 datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
637 if (datalen != sizeof(ireq))
638 return got_error(GOT_ERR_PRIVSEP_LEN);
639 memcpy(&ireq, imsg->data, sizeof(ireq));
641 *client = find_client(ireq.client_id);
643 return got_error(GOT_ERR_CLIENT_ID);
644 if ((*client)->pack_pipe[1] != -1)
645 return got_error(GOT_ERR_PRIVSEP_MSG);
647 if ((*client)->pack_pipe[0] == -1)
648 (*client)->pack_pipe[0] = imsg->fd;
650 (*client)->pack_pipe[1] = imsg->fd;
655 static const struct got_error *
656 send_packfile(struct repo_read_client *client, struct imsg *imsg,
657 struct gotd_imsgev *iev)
659 const struct got_error *err = NULL;
660 struct gotd_imsg_packfile_done idone;
661 uint8_t packsha1[SHA1_DIGEST_LENGTH];
662 char hex[SHA1_DIGEST_STRING_LENGTH];
663 FILE *delta_cache = NULL;
665 struct repo_read_pack_progress_arg pa;
666 struct got_ratelimit rl;
668 log_debug("packfile request received");
670 got_ratelimit_init(&rl, 2, 0);
672 if (client->delta_cache_fd == -1 ||
673 client->pack_pipe[0] == -1 ||
674 client->pack_pipe[1] == -1)
675 return got_error(GOT_ERR_PRIVSEP_NO_FD);
677 imsg_init(&ibuf, client->fd);
679 /* Send pack file pipe to gotsh(1). */
680 if (imsg_compose(&ibuf, GOTD_IMSG_PACKFILE_PIPE, PROC_REPO_READ,
681 repo_read.pid, client->pack_pipe[1], NULL, 0) == -1) {
682 err = got_error_from_errno("imsg_compose ACK");
686 client->pack_pipe[1] = -1;
687 err = gotd_imsg_flush(&ibuf);
691 delta_cache = fdopen(client->delta_cache_fd, "w+");
692 if (delta_cache == NULL) {
693 err = got_error_from_errno("fdopen");
696 client->delta_cache_fd = -1;
698 memset(&pa, 0, sizeof(pa));
700 pa.report_progress = client->report_progress;
702 err = got_pack_create(packsha1, client->pack_pipe[0], delta_cache,
703 client->have_ids.ids, client->have_ids.nids,
704 client->want_ids.ids, client->want_ids.nids,
705 repo_read.repo, 0, 1, pack_progress, &pa, &rl,
706 check_cancelled, NULL);
710 if (log_getverbose() > 0 &&
711 got_sha1_digest_to_str(packsha1, hex, sizeof(hex)))
712 log_debug("sent pack-%s.pack", hex);
714 memset(&idone, 0, sizeof(idone));
715 idone.client_id = client->id;
716 if (gotd_imsg_compose_event(iev, GOTD_IMSG_PACKFILE_DONE,
717 PROC_REPO_READ, -1, &idone, sizeof(idone)) == -1)
718 err = got_error_from_errno("imsg compose PACKFILE_DONE");
720 if (delta_cache != NULL && fclose(delta_cache) == EOF && err == NULL)
721 err = got_error_from_errno("fclose");
726 static const struct got_error *
727 recv_disconnect(struct imsg *imsg)
729 const struct got_error *err = NULL;
730 struct gotd_imsg_disconnect idisconnect;
732 int client_fd, delta_cache_fd, pipe[2];
733 struct repo_read_client *client = NULL;
736 datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
737 if (datalen != sizeof(idisconnect))
738 return got_error(GOT_ERR_PRIVSEP_LEN);
739 memcpy(&idisconnect, imsg->data, sizeof(idisconnect));
741 log_debug("client disconnecting");
743 client = find_client(idisconnect.client_id);
745 return got_error(GOT_ERR_CLIENT_ID);
747 slot = client_hash(client->id) % nitems(repo_read_clients);
748 STAILQ_REMOVE(&repo_read_clients[slot], client, repo_read_client,
750 free_object_ids(&client->have_ids);
751 free_object_ids(&client->want_ids);
752 client_fd = client->fd;
753 delta_cache_fd = client->delta_cache_fd;
754 pipe[0] = client->pack_pipe[0];
755 pipe[1] = client->pack_pipe[1];
757 if (close(client_fd) == -1)
758 err = got_error_from_errno("close");
759 if (delta_cache_fd != -1 && close(delta_cache_fd) == -1 && err == NULL)
760 return got_error_from_errno("close");
761 if (pipe[0] != -1 && close(pipe[0]) == -1 && err == NULL)
762 return got_error_from_errno("close");
763 if (pipe[1] != -1 && close(pipe[1]) == -1 && err == NULL)
764 return got_error_from_errno("close");
769 repo_read_dispatch(int fd, short event, void *arg)
771 const struct got_error *err = NULL;
772 struct gotd_imsgev *iev = arg;
773 struct imsgbuf *ibuf = &iev->ibuf;
777 struct repo_read_client *client = NULL;
779 if (event & EV_READ) {
780 if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
781 fatal("imsg_read error");
782 if (n == 0) /* Connection closed. */
786 if (event & EV_WRITE) {
787 n = msgbuf_write(&ibuf->w);
788 if (n == -1 && errno != EAGAIN)
789 fatal("msgbuf_write");
790 if (n == 0) /* Connection closed. */
794 while (err == NULL && check_cancelled(NULL) == NULL) {
796 if ((n = imsg_get(ibuf, &imsg)) == -1)
797 fatal("%s: imsg_get", __func__);
798 if (n == 0) /* No more messages. */
801 switch (imsg.hdr.type) {
802 case GOTD_IMSG_LIST_REFS_INTERNAL:
803 err = list_refs(&client, &imsg);
805 log_warnx("%s: ls-refs: %s", repo_read.title,
809 err = recv_want(&client, &imsg);
811 log_warnx("%s: want-line: %s", repo_read.title,
815 err = recv_have(&client, &imsg);
817 log_warnx("%s: have-line: %s", repo_read.title,
820 case GOTD_IMSG_SEND_PACKFILE:
821 err = receive_delta_cache_fd(&client, &imsg, iev);
823 log_warnx("%s: receiving delta cache: %s",
824 repo_read.title, err->msg);
826 case GOTD_IMSG_PACKFILE_PIPE:
827 err = receive_pack_pipe(&client, &imsg, iev);
829 log_warnx("%s: receiving pack pipe: %s",
830 repo_read.title, err->msg);
833 if (client->pack_pipe[1] == -1)
835 err = send_packfile(client, &imsg, iev);
837 log_warnx("%s: sending packfile: %s",
838 repo_read.title, err->msg);
840 case GOTD_IMSG_DISCONNECT:
841 err = recv_disconnect(&imsg);
843 log_warnx("%s: disconnect: %s",
844 repo_read.title, err->msg);
847 log_debug("%s: unexpected imsg %d", repo_read.title,
855 if (!shut && check_cancelled(NULL) == NULL) {
857 gotd_imsg_send_error_event(iev, PROC_REPO_READ,
858 client ? client->id : 0, err) == -1) {
859 log_warnx("could not send error to parent: %s",
862 gotd_imsg_event_add(iev);
864 /* This pipe is dead. Remove its event handler */
866 event_loopexit(NULL);
871 repo_read_main(const char *title, int *pack_fds, int *temp_fds)
873 const struct got_error *err = NULL;
874 struct gotd_imsgev iev;
876 repo_read.title = title;
877 repo_read.pid = getpid();
878 repo_read.pack_fds = pack_fds;
879 repo_read.temp_fds = temp_fds;
881 arc4random_buf(&clients_hash_key, sizeof(clients_hash_key));
884 * Open a repository in the root directory.
885 * We are already in chroot at this point.
887 err = got_repo_open(&repo_read.repo, "/", NULL, pack_fds);
890 if (!got_repo_is_bare(repo_read.repo)) {
891 err = got_error_msg(GOT_ERR_NOT_GIT_REPO,
892 "bare git repository required");
896 got_repo_temp_fds_set(repo_read.repo, temp_fds);
898 signal(SIGINT, catch_sigint);
899 signal(SIGTERM, catch_sigterm);
900 signal(SIGPIPE, SIG_IGN);
901 signal(SIGHUP, SIG_IGN);
903 imsg_init(&iev.ibuf, GOTD_SOCK_FILENO);
904 iev.handler = repo_read_dispatch;
905 iev.events = EV_READ;
906 iev.handler_arg = NULL;
907 event_set(&iev.ev, iev.ibuf.fd, EV_READ, repo_read_dispatch, &iev);
908 if (event_add(&iev.ev, NULL) == -1) {
909 err = got_error_from_errno("event_add");
916 log_warnx("%s: %s", title, err->msg);
917 repo_read_shutdown();
921 repo_read_shutdown(void)
923 log_debug("%s: shutting down", repo_read.title);
925 got_repo_close(repo_read.repo);
926 got_repo_pack_fds_close(repo_read.pack_fds);
927 got_repo_temp_fds_close(repo_read.temp_fds);