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 "got_compat.h"
19 #include <sys/queue.h>
20 #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"
41 #include "got_lib_delta.h"
42 #include "got_lib_object.h"
43 #include "got_lib_object_idset.h"
44 #include "got_lib_hash.h"
45 #include "got_lib_pack.h"
46 #include "got_lib_ratelimit.h"
47 #include "got_lib_pack_create.h"
48 #include "got_lib_poll.h"
52 #include "repo_read.h"
55 #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
58 static struct repo_read
{
61 struct got_repository
*repo
;
65 struct gotd_imsgev session_iev
;
69 static struct repo_read_client
{
75 struct got_object_idset
*want_ids
;
76 struct got_object_idset
*have_ids
;
79 static volatile sig_atomic_t sigint_received
;
80 static volatile sig_atomic_t sigterm_received
;
83 catch_sigint(int signo
)
89 catch_sigterm(int signo
)
94 static const struct got_error
*
95 check_cancelled(void *arg
)
97 if (sigint_received
|| sigterm_received
)
98 return got_error(GOT_ERR_CANCELLED
);
103 static const struct got_error
*
104 send_symref(struct got_reference
*symref
, struct got_object_id
*target_id
,
105 struct imsgbuf
*ibuf
)
107 const struct got_error
*err
= NULL
;
108 struct gotd_imsg_symref isymref
;
109 const char *refname
= got_ref_get_name(symref
);
110 const char *target
= got_ref_get_symref_target(symref
);
114 memset(&isymref
, 0, sizeof(isymref
));
115 isymref
.name_len
= strlen(refname
);
116 isymref
.target_len
= strlen(target
);
117 memcpy(isymref
.target_id
, target_id
->hash
, sizeof(isymref
.target_id
));
119 len
= sizeof(isymref
) + isymref
.name_len
+ isymref
.target_len
;
120 if (len
> MAX_IMSGSIZE
- IMSG_HEADER_SIZE
) {
121 err
= got_error(GOT_ERR_NO_SPACE
);
125 wbuf
= imsg_create(ibuf
, GOTD_IMSG_SYMREF
, 0, 0, len
);
127 err
= got_error_from_errno("imsg_create SYMREF");
131 if (imsg_add(wbuf
, &isymref
, sizeof(isymref
)) == -1) {
132 err
= got_error_from_errno("imsg_add SYMREF");
135 if (imsg_add(wbuf
, refname
, isymref
.name_len
) == -1) {
136 err
= got_error_from_errno("imsg_add SYMREF");
139 if (imsg_add(wbuf
, target
, isymref
.target_len
) == -1) {
140 err
= got_error_from_errno("imsg_add SYMREF");
144 imsg_close(ibuf
, wbuf
);
150 static const struct got_error
*
151 send_peeled_tag_ref(struct got_reference
*ref
, struct got_object
*obj
,
152 struct imsgbuf
*ibuf
)
154 const struct got_error
*err
= NULL
;
155 struct got_tag_object
*tag
;
157 char *peeled_refname
= NULL
;
158 struct got_object_id
*id
;
161 err
= got_object_tag_open(&tag
, repo_read
.repo
, obj
);
165 if (asprintf(&peeled_refname
, "%s^{}", got_ref_get_name(ref
)) == -1) {
166 err
= got_error_from_errno("asprintf");
170 id
= got_object_tag_get_object_id(tag
);
171 namelen
= strlen(peeled_refname
);
173 len
= sizeof(struct gotd_imsg_ref
) + namelen
;
174 if (len
> MAX_IMSGSIZE
- IMSG_HEADER_SIZE
) {
175 err
= got_error(GOT_ERR_NO_SPACE
);
179 wbuf
= imsg_create(ibuf
, GOTD_IMSG_REF
, PROC_REPO_READ
,
182 err
= got_error_from_errno("imsg_create MREF");
186 /* Keep in sync with struct gotd_imsg_ref definition. */
187 if (imsg_add(wbuf
, id
->hash
, SHA1_DIGEST_LENGTH
) == -1) {
188 err
= got_error_from_errno("imsg_add REF");
191 if (imsg_add(wbuf
, &namelen
, sizeof(namelen
)) == -1) {
192 err
= got_error_from_errno("imsg_add REF");
195 if (imsg_add(wbuf
, peeled_refname
, namelen
) == -1) {
196 err
= got_error_from_errno("imsg_add REF");
200 imsg_close(ibuf
, wbuf
);
202 got_object_tag_close(tag
);
206 static const struct got_error
*
207 send_ref(struct got_reference
*ref
, struct imsgbuf
*ibuf
)
209 const struct got_error
*err
;
210 const char *refname
= got_ref_get_name(ref
);
212 struct got_object_id
*id
= NULL
;
213 struct got_object
*obj
= NULL
;
217 namelen
= strlen(refname
);
219 len
= sizeof(struct gotd_imsg_ref
) + namelen
;
220 if (len
> MAX_IMSGSIZE
- IMSG_HEADER_SIZE
)
221 return got_error(GOT_ERR_NO_SPACE
);
223 err
= got_ref_resolve(&id
, repo_read
.repo
, ref
);
227 wbuf
= imsg_create(ibuf
, GOTD_IMSG_REF
, PROC_REPO_READ
,
230 err
= got_error_from_errno("imsg_create REF");
234 /* Keep in sync with struct gotd_imsg_ref definition. */
235 if (imsg_add(wbuf
, id
->hash
, SHA1_DIGEST_LENGTH
) == -1)
236 return got_error_from_errno("imsg_add REF");
237 if (imsg_add(wbuf
, &namelen
, sizeof(namelen
)) == -1)
238 return got_error_from_errno("imsg_add REF");
239 if (imsg_add(wbuf
, refname
, namelen
) == -1)
240 return got_error_from_errno("imsg_add REF");
242 imsg_close(ibuf
, wbuf
);
244 err
= got_object_open(&obj
, repo_read
.repo
, id
);
247 if (obj
->type
== GOT_OBJ_TYPE_TAG
)
248 err
= send_peeled_tag_ref(ref
, obj
, ibuf
);
251 got_object_close(obj
);
256 static const struct got_error
*
257 list_refs(struct imsg
*imsg
)
259 const struct got_error
*err
;
260 struct repo_read_client
*client
= &repo_read_client
;
261 struct got_reflist_head refs
;
262 struct got_reflist_entry
*re
;
264 struct gotd_imsg_reflist irefs
;
266 struct got_object_id
*head_target_id
= NULL
;
270 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
272 return got_error(GOT_ERR_PRIVSEP_LEN
);
274 if (repo_read
.refs_listed
) {
275 return got_error_msg(GOT_ERR_CLIENT_ID
,
276 "duplicate list-refs request");
278 repo_read
.refs_listed
= 1;
280 client
->fd
= imsg_get_fd(imsg
);
281 if (client
->fd
== -1)
282 return got_error(GOT_ERR_PRIVSEP_NO_FD
);
284 if (imsgbuf_init(&ibuf
, client
->fd
) == -1)
285 return got_error_from_errno("imsgbuf_init");
286 imsgbuf_allow_fdpass(&ibuf
);
288 err
= got_ref_list(&refs
, repo_read
.repo
, "",
289 got_ref_cmp_by_name
, NULL
);
293 memset(&irefs
, 0, sizeof(irefs
));
294 TAILQ_FOREACH(re
, &refs
, entry
) {
295 struct got_object_id
*id
;
298 if (got_ref_is_symbolic(re
->ref
)) {
299 const char *refname
= got_ref_get_name(re
->ref
);
300 if (strcmp(refname
, GOT_REF_HEAD
) != 0)
302 err
= got_ref_resolve(&head_target_id
, repo_read
.repo
,
305 if (err
->code
!= GOT_ERR_NOT_REF
)
308 * HEAD points to a non-existent branch.
309 * Do not advertise it.
310 * Matches git-daemon's behaviour.
312 head_target_id
= NULL
;
321 /* Account for a peeled tag refs. */
322 err
= got_ref_resolve(&id
, repo_read
.repo
, re
->ref
);
325 err
= got_object_get_type(&obj_type
, repo_read
.repo
, id
);
329 if (obj_type
== GOT_OBJ_TYPE_TAG
)
333 if (imsg_compose(&ibuf
, GOTD_IMSG_REFLIST
, PROC_REPO_READ
,
334 repo_read
.pid
, -1, &irefs
, sizeof(irefs
)) == -1) {
335 err
= got_error_from_errno("imsg_compose REFLIST");
340 * Send the HEAD symref first. In Git-protocol versions < 2
341 * the HEAD symref must be announced on the initial line of
342 * the server's ref advertisement.
343 * For now, we do not advertise symrefs other than HEAD.
345 TAILQ_FOREACH(re
, &refs
, entry
) {
346 if (!got_ref_is_symbolic(re
->ref
) ||
347 strcmp(got_ref_get_name(re
->ref
), GOT_REF_HEAD
) != 0 ||
348 head_target_id
== NULL
)
350 err
= send_symref(re
->ref
, head_target_id
, &ibuf
);
355 TAILQ_FOREACH(re
, &refs
, entry
) {
356 if (got_ref_is_symbolic(re
->ref
))
358 err
= send_ref(re
->ref
, &ibuf
);
363 err
= gotd_imsg_flush(&ibuf
);
365 got_ref_list_free(&refs
);
366 imsgbuf_clear(&ibuf
);
370 static const struct got_error
*
371 append_object_id(struct got_object_id
*id
, void *data
, void *arg
)
373 struct gotd_object_id_array
*array
= arg
;
374 const size_t alloc_chunksz
= 256;
376 if (array
->ids
== NULL
) {
377 array
->ids
= reallocarray(NULL
, alloc_chunksz
,
378 sizeof(*array
->ids
));
379 if (array
->ids
== NULL
)
380 return got_error_from_errno("reallocarray");
381 array
->nalloc
= alloc_chunksz
;
383 } else if (array
->nalloc
<= array
->nids
) {
384 struct got_object_id
**new;
385 new = recallocarray(array
->ids
, array
->nalloc
,
386 array
->nalloc
+ alloc_chunksz
, sizeof(*new));
388 return got_error_from_errno("recallocarray");
390 array
->nalloc
+= alloc_chunksz
;
393 array
->ids
[array
->nids
] = id
;
398 static const struct got_error
*
399 recv_want(struct imsg
*imsg
)
401 const struct got_error
*err
;
402 struct repo_read_client
*client
= &repo_read_client
;
403 struct gotd_imsg_want iwant
;
405 char hex
[SHA1_DIGEST_STRING_LENGTH
];
406 struct got_object_id id
;
410 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
411 if (datalen
!= sizeof(iwant
))
412 return got_error(GOT_ERR_PRIVSEP_LEN
);
413 memcpy(&iwant
, imsg
->data
, sizeof(iwant
));
415 memset(&id
, 0, sizeof(id
));
416 memcpy(id
.hash
, iwant
.object_id
, SHA1_DIGEST_LENGTH
);
418 if (log_getverbose() > 0 &&
419 got_object_id_hex(&id
, hex
, sizeof(hex
)))
420 log_debug("client wants %s", hex
);
422 if (imsgbuf_init(&ibuf
, client
->fd
) == -1)
423 return got_error_from_errno("imsgbuf_init");
424 imsgbuf_allow_fdpass(&ibuf
);
426 err
= got_object_get_type(&obj_type
, repo_read
.repo
, &id
);
430 if (obj_type
!= GOT_OBJ_TYPE_COMMIT
&&
431 obj_type
!= GOT_OBJ_TYPE_TAG
)
432 return got_error(GOT_ERR_OBJ_TYPE
);
434 if (!got_object_idset_contains(client
->want_ids
, &id
)) {
435 err
= got_object_idset_add(client
->want_ids
, &id
, NULL
);
440 gotd_imsg_send_ack(&id
, &ibuf
, PROC_REPO_READ
, repo_read
.pid
);
441 imsgbuf_clear(&ibuf
);
445 static const struct got_error
*
446 recv_have(struct imsg
*imsg
)
448 const struct got_error
*err
;
449 struct repo_read_client
*client
= &repo_read_client
;
450 struct gotd_imsg_have ihave
;
452 char hex
[SHA1_DIGEST_STRING_LENGTH
];
453 struct got_object_id id
;
457 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
458 if (datalen
!= sizeof(ihave
))
459 return got_error(GOT_ERR_PRIVSEP_LEN
);
460 memcpy(&ihave
, imsg
->data
, sizeof(ihave
));
462 memset(&id
, 0, sizeof(id
));
463 memcpy(id
.hash
, ihave
.object_id
, SHA1_DIGEST_LENGTH
);
465 if (log_getverbose() > 0 &&
466 got_object_id_hex(&id
, hex
, sizeof(hex
)))
467 log_debug("client has %s", hex
);
469 if (imsgbuf_init(&ibuf
, client
->fd
) == -1)
470 return got_error_from_errno("imsgbuf_init");
471 imsgbuf_allow_fdpass(&ibuf
);
473 err
= got_object_get_type(&obj_type
, repo_read
.repo
, &id
);
475 if (err
->code
== GOT_ERR_NO_OBJ
) {
476 gotd_imsg_send_nak(&id
, &ibuf
,
477 PROC_REPO_READ
, repo_read
.pid
);
483 if (obj_type
!= GOT_OBJ_TYPE_COMMIT
&&
484 obj_type
!= GOT_OBJ_TYPE_TAG
) {
485 gotd_imsg_send_nak(&id
, &ibuf
, PROC_REPO_READ
, repo_read
.pid
);
486 err
= got_error(GOT_ERR_OBJ_TYPE
);
490 if (!got_object_idset_contains(client
->have_ids
, &id
)) {
491 err
= got_object_idset_add(client
->have_ids
, &id
, NULL
);
496 gotd_imsg_send_ack(&id
, &ibuf
, PROC_REPO_READ
, repo_read
.pid
);
498 imsgbuf_clear(&ibuf
);
502 struct repo_read_pack_progress_arg
{
504 struct imsgbuf
*ibuf
;
508 static const struct got_error
*
509 pack_progress(void *arg
, int ncolored
, int nfound
, int ntrees
,
510 off_t packfile_size
, int ncommits
, int nobj_total
, int nobj_deltify
,
511 int nobj_written
, int pack_done
)
513 struct repo_read_pack_progress_arg
*a
= arg
;
514 struct gotd_imsg_packfile_progress iprog
;
517 if (!a
->report_progress
)
519 if (packfile_size
> 0 && a
->sent_ready
)
522 memset(&iprog
, 0, sizeof(iprog
));
523 iprog
.ncolored
= ncolored
;
524 iprog
.nfound
= nfound
;
525 iprog
.ntrees
= ntrees
;
526 iprog
.packfile_size
= packfile_size
;
527 iprog
.ncommits
= ncommits
;
528 iprog
.nobj_total
= nobj_total
;
529 iprog
.nobj_deltify
= nobj_deltify
;
530 iprog
.nobj_written
= nobj_written
;
532 /* Using synchronous writes since we are blocking the event loop. */
533 if (packfile_size
== 0) {
534 ret
= imsg_compose(a
->ibuf
, GOTD_IMSG_PACKFILE_PROGRESS
,
535 PROC_REPO_READ
, repo_read
.pid
, -1, &iprog
, sizeof(iprog
));
537 return got_error_from_errno("imsg compose "
538 "PACKFILE_PROGRESS");
542 ret
= imsg_compose(a
->ibuf
, GOTD_IMSG_PACKFILE_READY
,
543 PROC_REPO_READ
, repo_read
.pid
, -1, &iprog
, sizeof(iprog
));
545 return got_error_from_errno("imsg compose "
550 return gotd_imsg_flush(a
->ibuf
);
553 static const struct got_error
*
554 receive_delta_cache_fd(struct imsg
*imsg
,
555 struct gotd_imsgev
*iev
)
557 struct repo_read_client
*client
= &repo_read_client
;
558 struct gotd_imsg_send_packfile ireq
;
561 log_debug("receiving delta cache file");
563 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
564 if (datalen
!= sizeof(ireq
))
565 return got_error(GOT_ERR_PRIVSEP_LEN
);
566 memcpy(&ireq
, imsg
->data
, sizeof(ireq
));
568 if (client
->delta_cache_fd
!= -1)
569 return got_error(GOT_ERR_PRIVSEP_MSG
);
571 client
->delta_cache_fd
= imsg_get_fd(imsg
);
572 if (client
->delta_cache_fd
== -1)
573 return got_error(GOT_ERR_PRIVSEP_NO_FD
);
575 client
->report_progress
= ireq
.report_progress
;
579 static const struct got_error
*
580 receive_pack_pipe(struct imsg
*imsg
, struct gotd_imsgev
*iev
)
582 struct repo_read_client
*client
= &repo_read_client
;
585 log_debug("receiving pack pipe descriptor");
587 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
589 return got_error(GOT_ERR_PRIVSEP_LEN
);
591 if (client
->pack_pipe
!= -1)
592 return got_error(GOT_ERR_PRIVSEP_MSG
);
594 client
->pack_pipe
= imsg_get_fd(imsg
);
595 if (client
->pack_pipe
== -1)
596 return got_error(GOT_ERR_PRIVSEP_NO_FD
);
601 static const struct got_error
*
602 send_packfile(struct imsg
*imsg
, struct gotd_imsgev
*iev
)
604 const struct got_error
*err
= NULL
;
605 struct repo_read_client
*client
= &repo_read_client
;
606 struct got_object_id packhash
;
607 char hex
[GOT_HASH_DIGEST_STRING_MAXLEN
];
608 FILE *delta_cache
= NULL
;
610 struct repo_read_pack_progress_arg pa
;
611 struct got_ratelimit rl
;
612 struct gotd_object_id_array want_ids
;
613 struct gotd_object_id_array have_ids
;
615 log_debug("packfile request received");
617 memset(&want_ids
, 0, sizeof(want_ids
));
618 memset(&have_ids
, 0, sizeof(have_ids
));
620 got_ratelimit_init(&rl
, 2, 0);
622 if (client
->delta_cache_fd
== -1 || client
->pack_pipe
== -1)
623 return got_error(GOT_ERR_PRIVSEP_NO_FD
);
625 if (imsgbuf_init(&ibuf
, client
->fd
) == -1)
626 return got_error_from_errno("imsgbuf_init");
627 imsgbuf_allow_fdpass(&ibuf
);
629 delta_cache
= fdopen(client
->delta_cache_fd
, "w+");
630 if (delta_cache
== NULL
) {
631 err
= got_error_from_errno("fdopen");
634 client
->delta_cache_fd
= -1;
636 memset(&pa
, 0, sizeof(pa
));
638 pa
.report_progress
= client
->report_progress
;
640 err
= got_object_idset_for_each(client
->want_ids
,
641 append_object_id
, &want_ids
);
644 err
= got_object_idset_for_each(client
->have_ids
,
645 append_object_id
, &have_ids
);
649 err
= got_pack_create(&packhash
, client
->pack_pipe
, delta_cache
,
650 have_ids
.ids
, have_ids
.nids
, want_ids
.ids
, want_ids
.nids
,
651 repo_read
.repo
, 0, 1, 0, pack_progress
, &pa
, &rl
,
652 check_cancelled
, NULL
);
656 if (log_getverbose() > 0 &&
657 got_hash_digest_to_str(packhash
.hash
, hex
, sizeof(hex
),
659 log_debug("sent pack-%s.pack", hex
);
661 if (gotd_imsg_compose_event(iev
, GOTD_IMSG_PACKFILE_DONE
,
662 PROC_REPO_READ
, -1, NULL
, 0) == -1)
663 err
= got_error_from_errno("imsg compose PACKFILE_DONE");
665 if (client
->delta_cache_fd
!= -1 &&
666 close(client
->delta_cache_fd
) == -1 && err
== NULL
)
667 err
= got_error_from_errno("close");
668 client
->delta_cache_fd
= -1;
669 if (delta_cache
!= NULL
&& fclose(delta_cache
) == EOF
&& err
== NULL
)
670 err
= got_error_from_errno("fclose");
671 imsgbuf_clear(&ibuf
);
678 repo_read_dispatch_session(int fd
, short event
, void *arg
)
680 const struct got_error
*err
= NULL
;
681 struct gotd_imsgev
*iev
= arg
;
682 struct imsgbuf
*ibuf
= &iev
->ibuf
;
686 struct repo_read_client
*client
= &repo_read_client
;
688 if (event
& EV_READ
) {
689 if ((n
= imsgbuf_read(ibuf
)) == -1)
690 fatal("imsgbuf_read error");
691 if (n
== 0) /* Connection closed. */
695 if (event
& EV_WRITE
) {
696 err
= gotd_imsg_flush(ibuf
);
698 fatalx("%s", err
->msg
);
701 while (err
== NULL
&& check_cancelled(NULL
) == NULL
) {
702 if ((n
= imsg_get(ibuf
, &imsg
)) == -1)
703 fatal("%s: imsg_get", __func__
);
704 if (n
== 0) /* No more messages. */
707 if (imsg
.hdr
.type
!= GOTD_IMSG_LIST_REFS_INTERNAL
&&
708 !repo_read
.refs_listed
) {
709 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
713 switch (imsg
.hdr
.type
) {
714 case GOTD_IMSG_LIST_REFS_INTERNAL
:
715 err
= list_refs(&imsg
);
717 log_warnx("ls-refs: %s", err
->msg
);
720 err
= recv_want(&imsg
);
722 log_warnx("want-line: %s", err
->msg
);
725 err
= recv_have(&imsg
);
727 log_warnx("have-line: %s", err
->msg
);
729 case GOTD_IMSG_SEND_PACKFILE
:
730 err
= receive_delta_cache_fd(&imsg
, iev
);
732 log_warnx("receiving delta cache: %s",
735 case GOTD_IMSG_PACKFILE_PIPE
:
736 err
= receive_pack_pipe(&imsg
, iev
);
738 log_warnx("receiving pack pipe: %s", err
->msg
);
741 err
= send_packfile(&imsg
, iev
);
743 log_warnx("sending packfile: %s", err
->msg
);
746 log_debug("unexpected imsg %d", imsg
.hdr
.type
);
753 if (!shut
&& check_cancelled(NULL
) == NULL
) {
755 gotd_imsg_send_error_event(iev
, PROC_REPO_READ
,
756 client
->id
, err
) == -1) {
757 log_warnx("could not send error to parent: %s",
760 gotd_imsg_event_add(iev
);
762 /* This pipe is dead. Remove its event handler */
764 event_loopexit(NULL
);
768 static const struct got_error
*
769 recv_connect(struct imsg
*imsg
)
771 struct gotd_imsgev
*iev
= &repo_read
.session_iev
;
774 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
776 return got_error(GOT_ERR_PRIVSEP_LEN
);
778 if (repo_read
.session_fd
!= -1)
779 return got_error(GOT_ERR_PRIVSEP_MSG
);
781 repo_read
.session_fd
= imsg_get_fd(imsg
);
782 if (repo_read
.session_fd
== -1)
783 return got_error(GOT_ERR_PRIVSEP_NO_FD
);
785 if (imsgbuf_init(&iev
->ibuf
, repo_read
.session_fd
) == -1)
786 return got_error_from_errno("imsgbuf_init");
787 imsgbuf_allow_fdpass(&iev
->ibuf
);
788 iev
->handler
= repo_read_dispatch_session
;
789 iev
->events
= EV_READ
;
790 iev
->handler_arg
= NULL
;
791 event_set(&iev
->ev
, iev
->ibuf
.fd
, EV_READ
,
792 repo_read_dispatch_session
, iev
);
793 gotd_imsg_event_add(iev
);
799 repo_read_dispatch(int fd
, short event
, void *arg
)
801 const struct got_error
*err
= NULL
;
802 struct gotd_imsgev
*iev
= arg
;
803 struct imsgbuf
*ibuf
= &iev
->ibuf
;
807 struct repo_read_client
*client
= &repo_read_client
;
809 if (event
& EV_READ
) {
810 if ((n
= imsgbuf_read(ibuf
)) == -1)
811 fatal("imsgbuf_read error");
812 if (n
== 0) /* Connection closed. */
816 if (event
& EV_WRITE
) {
817 err
= gotd_imsg_flush(ibuf
);
819 fatalx("%s", err
->msg
);
822 while (err
== NULL
&& check_cancelled(NULL
) == NULL
) {
823 if ((n
= imsg_get(ibuf
, &imsg
)) == -1)
824 fatal("%s: imsg_get", __func__
);
825 if (n
== 0) /* No more messages. */
828 switch (imsg
.hdr
.type
) {
829 case GOTD_IMSG_CONNECT_REPO_CHILD
:
830 err
= recv_connect(&imsg
);
833 log_debug("unexpected imsg %d", imsg
.hdr
.type
);
840 if (!shut
&& check_cancelled(NULL
) == NULL
) {
842 gotd_imsg_send_error_event(iev
, PROC_REPO_READ
,
843 client
->id
, err
) == -1) {
844 log_warnx("could not send error to parent: %s",
847 gotd_imsg_event_add(iev
);
849 /* This pipe is dead. Remove its event handler */
851 event_loopexit(NULL
);
856 repo_read_main(const char *title
, const char *repo_path
,
857 int *pack_fds
, int *temp_fds
)
859 const struct got_error
*err
= NULL
;
860 struct repo_read_client
*client
= &repo_read_client
;
861 struct gotd_imsgev iev
;
864 client
->delta_cache_fd
= -1;
865 client
->pack_pipe
= -1;
866 client
->have_ids
= got_object_idset_alloc();
867 if (client
->have_ids
== NULL
) {
868 err
= got_error_from_errno("got_object_idset_alloc");
871 client
->want_ids
= got_object_idset_alloc();
872 if (client
->want_ids
== NULL
) {
873 err
= got_error_from_errno("got_object_idset_alloc");
877 repo_read
.title
= title
;
878 repo_read
.pid
= getpid();
879 repo_read
.pack_fds
= pack_fds
;
880 repo_read
.temp_fds
= temp_fds
;
881 repo_read
.session_fd
= -1;
882 repo_read
.session_iev
.ibuf
.fd
= -1;
884 err
= got_repo_open(&repo_read
.repo
, repo_path
, NULL
, pack_fds
);
887 if (!got_repo_is_bare(repo_read
.repo
)) {
888 err
= got_error_msg(GOT_ERR_NOT_GIT_REPO
,
889 "bare git repository required");
892 if (got_repo_get_object_format(repo_read
.repo
) != GOT_HASH_SHA1
) {
893 err
= got_error_msg(GOT_ERR_NOT_IMPL
,
894 "sha256 object IDs unsupported in network protocol");
898 got_repo_temp_fds_set(repo_read
.repo
, temp_fds
);
900 signal(SIGINT
, catch_sigint
);
901 signal(SIGTERM
, catch_sigterm
);
902 signal(SIGPIPE
, SIG_IGN
);
903 signal(SIGHUP
, SIG_IGN
);
905 if (imsgbuf_init(&iev
.ibuf
, GOTD_FILENO_MSG_PIPE
) == -1) {
906 err
= got_error_from_errno("imsgbuf_init");
909 imsgbuf_allow_fdpass(&iev
.ibuf
);
910 iev
.handler
= repo_read_dispatch
;
911 iev
.events
= EV_READ
;
912 iev
.handler_arg
= NULL
;
913 event_set(&iev
.ev
, iev
.ibuf
.fd
, EV_READ
, repo_read_dispatch
, &iev
);
915 if (gotd_imsg_compose_event(&iev
, GOTD_IMSG_REPO_CHILD_READY
,
916 PROC_REPO_READ
, -1, NULL
, 0) == -1) {
917 err
= got_error_from_errno("imsg compose REPO_CHILD_READY");
924 log_warnx("%s: %s", title
, err
->msg
);
925 repo_read_shutdown();
929 repo_read_shutdown(void)
931 struct repo_read_client
*client
= &repo_read_client
;
933 log_debug("%s: shutting down", repo_read
.title
);
935 if (client
->have_ids
)
936 got_object_idset_free(client
->have_ids
);
937 if (client
->want_ids
)
938 got_object_idset_free(client
->want_ids
);
939 if (client
->fd
!= -1)
941 if (client
->delta_cache_fd
!= -1)
942 close(client
->delta_cache_fd
);
943 if (client
->pack_pipe
!= -1)
944 close(client
->pack_pipe
);
947 got_repo_close(repo_read
.repo
);
948 got_repo_pack_fds_close(repo_read
.pack_fds
);
949 got_repo_temp_fds_close(repo_read
.temp_fds
);
950 if (repo_read
.session_fd
!= -1)
951 close(repo_read
.session_fd
);