2 * Copyright (c) 2022, 2023 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/types.h>
20 #include <sys/queue.h>
21 #include <sys/socket.h>
36 #include "got_error.h"
37 #include "got_repository.h"
38 #include "got_object.h"
40 #include "got_reference.h"
41 #include "got_opentemp.h"
43 #include "got_lib_hash.h"
44 #include "got_lib_delta.h"
45 #include "got_lib_object.h"
46 #include "got_lib_object_cache.h"
47 #include "got_lib_pack.h"
48 #include "got_lib_repository.h"
49 #include "got_lib_gitproto.h"
53 #include "session_read.h"
55 enum gotd_session_read_state
{
56 GOTD_STATE_EXPECT_LIST_REFS
,
57 GOTD_STATE_EXPECT_CAPABILITIES
,
58 GOTD_STATE_EXPECT_WANT
,
59 GOTD_STATE_EXPECT_HAVE_OR_DONE
,
63 static struct gotd_session_read
{
66 struct got_repository
*repo
;
67 struct gotd_repo
*repo_cfg
;
70 struct gotd_imsgev parent_iev
;
71 struct gotd_imsgev notifier_iev
;
72 struct timeval request_timeout
;
73 enum gotd_session_read_state state
;
74 struct gotd_imsgev repo_child_iev
;
77 static struct gotd_session_client
{
78 struct gotd_client_capability
*capabilities
;
84 struct gotd_imsgev iev
;
94 } gotd_session_client
;
96 static void session_read_shutdown(void);
99 disconnect(struct gotd_session_client
*client
)
101 log_debug("uid %d: disconnecting", client
->euid
);
103 if (gotd_imsg_compose_event(&gotd_session
.parent_iev
,
104 GOTD_IMSG_DISCONNECT
, PROC_SESSION_READ
, -1, NULL
, 0) == -1)
105 log_warn("imsg compose DISCONNECT");
107 imsgbuf_clear(&gotd_session
.repo_child_iev
.ibuf
);
108 event_del(&gotd_session
.repo_child_iev
.ev
);
109 evtimer_del(&client
->tmo
);
111 if (client
->delta_cache_fd
!= -1)
112 close(client
->delta_cache_fd
);
113 if (client
->packfile_path
) {
114 if (unlink(client
->packfile_path
) == -1 && errno
!= ENOENT
)
115 log_warn("unlink %s: ", client
->packfile_path
);
116 free(client
->packfile_path
);
118 if (client
->packidx_path
) {
119 if (unlink(client
->packidx_path
) == -1 && errno
!= ENOENT
)
120 log_warn("unlink %s: ", client
->packidx_path
);
121 free(client
->packidx_path
);
123 free(client
->capabilities
);
125 session_read_shutdown();
129 disconnect_on_error(struct gotd_session_client
*client
,
130 const struct got_error
*err
)
134 if (err
->code
!= GOT_ERR_EOF
) {
135 log_warnx("uid %d: %s", client
->euid
, err
->msg
);
136 if (imsgbuf_init(&ibuf
, client
->fd
) == -1) {
137 log_warn("imsgbuf_init");
139 gotd_imsg_send_error(&ibuf
, 0, PROC_SESSION_READ
, err
);
140 imsgbuf_clear(&ibuf
);
148 gotd_request_timeout(int fd
, short events
, void *arg
)
150 struct gotd_session_client
*client
= arg
;
152 log_warnx("disconnecting uid %d due to timeout", client
->euid
);
157 session_read_sighdlr(int sig
, short event
, void *arg
)
160 * Normal signal handler rules don't apply because libevent
166 log_info("%s: ignoring SIGHUP", __func__
);
169 log_info("%s: ignoring SIGUSR1", __func__
);
173 session_read_shutdown();
177 fatalx("unexpected signal");
181 static const struct got_error
*
182 recv_packfile_done(struct imsg
*imsg
)
186 log_debug("packfile-done received");
188 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
190 return got_error(GOT_ERR_PRIVSEP_LEN
);
196 session_dispatch_repo_child(int fd
, short event
, void *arg
)
198 const struct got_error
*err
= NULL
;
199 struct gotd_imsgev
*iev
= arg
;
200 struct imsgbuf
*ibuf
= &iev
->ibuf
;
201 struct gotd_session_client
*client
= &gotd_session_client
;
206 if (event
& EV_READ
) {
207 if ((n
= imsgbuf_read(ibuf
)) == -1)
208 fatal("imsgbuf_read error");
210 /* Connection closed. */
216 if (event
& EV_WRITE
) {
217 err
= gotd_imsg_flush(ibuf
);
219 fatalx("%s", err
->msg
);
223 const struct got_error
*err
= NULL
;
224 uint32_t client_id
= 0;
225 int do_disconnect
= 0;
227 if ((n
= imsg_get(ibuf
, &imsg
)) == -1)
228 fatal("%s: imsg_get error", __func__
);
229 if (n
== 0) /* No more messages. */
232 switch (imsg
.hdr
.type
) {
233 case GOTD_IMSG_ERROR
:
235 err
= gotd_imsg_recv_error(&client_id
, &imsg
);
237 case GOTD_IMSG_PACKFILE_DONE
:
239 err
= recv_packfile_done(&imsg
);
242 log_debug("unexpected imsg %d", imsg
.hdr
.type
);
248 disconnect_on_error(client
, err
);
253 log_warnx("uid %d: %s", client
->euid
, err
->msg
);
259 gotd_imsg_event_add(iev
);
261 /* This pipe is dead. Remove its event handler */
263 event_loopexit(NULL
);
267 static const struct got_error
*
268 recv_capabilities(struct gotd_session_client
*client
, struct imsg
*imsg
)
270 struct gotd_imsg_capabilities icapas
;
273 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
274 if (datalen
!= sizeof(icapas
))
275 return got_error(GOT_ERR_PRIVSEP_LEN
);
276 memcpy(&icapas
, imsg
->data
, sizeof(icapas
));
278 client
->ncapa_alloc
= icapas
.ncapabilities
;
279 client
->capabilities
= calloc(client
->ncapa_alloc
,
280 sizeof(*client
->capabilities
));
281 if (client
->capabilities
== NULL
) {
282 client
->ncapa_alloc
= 0;
283 return got_error_from_errno("calloc");
286 log_debug("expecting %zu capabilities from uid %d",
287 client
->ncapa_alloc
, client
->euid
);
291 static const struct got_error
*
292 recv_capability(struct gotd_session_client
*client
, struct imsg
*imsg
)
294 struct gotd_imsg_capability icapa
;
295 struct gotd_client_capability
*capa
;
297 char *key
, *value
= NULL
;
299 if (client
->capabilities
== NULL
||
300 client
->ncapabilities
>= client
->ncapa_alloc
) {
301 return got_error_msg(GOT_ERR_BAD_REQUEST
,
302 "unexpected capability received");
305 memset(&icapa
, 0, sizeof(icapa
));
307 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
308 if (datalen
< sizeof(icapa
))
309 return got_error(GOT_ERR_PRIVSEP_LEN
);
310 memcpy(&icapa
, imsg
->data
, sizeof(icapa
));
312 if (datalen
!= sizeof(icapa
) + icapa
.key_len
+ icapa
.value_len
)
313 return got_error(GOT_ERR_PRIVSEP_LEN
);
315 key
= strndup(imsg
->data
+ sizeof(icapa
), icapa
.key_len
);
317 return got_error_from_errno("strndup");
318 if (icapa
.value_len
> 0) {
319 value
= strndup(imsg
->data
+ sizeof(icapa
) + icapa
.key_len
,
323 return got_error_from_errno("strndup");
327 capa
= &client
->capabilities
[client
->ncapabilities
++];
332 log_debug("uid %d: capability %s=%s", client
->euid
, key
, value
);
334 log_debug("uid %d: capability %s", client
->euid
, key
);
339 static const struct got_error
*
340 forward_want(struct gotd_session_client
*client
, struct imsg
*imsg
)
342 struct gotd_imsg_want ireq
;
343 struct gotd_imsg_want iwant
;
346 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
347 if (datalen
!= sizeof(ireq
))
348 return got_error(GOT_ERR_PRIVSEP_LEN
);
350 memcpy(&ireq
, imsg
->data
, datalen
);
352 memset(&iwant
, 0, sizeof(iwant
));
353 memcpy(iwant
.object_id
, ireq
.object_id
, SHA1_DIGEST_LENGTH
);
355 if (gotd_imsg_compose_event(&gotd_session
.repo_child_iev
,
356 GOTD_IMSG_WANT
, PROC_SESSION_READ
, -1,
357 &iwant
, sizeof(iwant
)) == -1)
358 return got_error_from_errno("imsg compose WANT");
363 static const struct got_error
*
364 forward_have(struct gotd_session_client
*client
, struct imsg
*imsg
)
366 struct gotd_imsg_have ireq
;
367 struct gotd_imsg_have ihave
;
370 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
371 if (datalen
!= sizeof(ireq
))
372 return got_error(GOT_ERR_PRIVSEP_LEN
);
374 memcpy(&ireq
, imsg
->data
, datalen
);
376 memset(&ihave
, 0, sizeof(ihave
));
377 memcpy(ihave
.object_id
, ireq
.object_id
, SHA1_DIGEST_LENGTH
);
379 if (gotd_imsg_compose_event(&gotd_session
.repo_child_iev
,
380 GOTD_IMSG_HAVE
, PROC_SESSION_READ
, -1,
381 &ihave
, sizeof(ihave
)) == -1)
382 return got_error_from_errno("imsg compose HAVE");
388 client_has_capability(struct gotd_session_client
*client
, const char *capastr
)
390 struct gotd_client_capability
*capa
;
393 if (client
->ncapabilities
== 0)
396 for (i
= 0; i
< client
->ncapabilities
; i
++) {
397 capa
= &client
->capabilities
[i
];
398 if (strcmp(capa
->key
, capastr
) == 0)
405 static const struct got_error
*
406 send_packfile(struct gotd_session_client
*client
)
408 const struct got_error
*err
= NULL
;
409 struct gotd_imsg_send_packfile ipack
;
412 if (socketpair(AF_UNIX
, SOCK_STREAM
, PF_UNSPEC
, pipe
) == -1)
413 return got_error_from_errno("socketpair");
415 memset(&ipack
, 0, sizeof(ipack
));
417 if (client_has_capability(client
, GOT_CAPA_SIDE_BAND_64K
))
418 ipack
.report_progress
= 1;
420 client
->delta_cache_fd
= got_opentempfd();
421 if (client
->delta_cache_fd
== -1)
422 return got_error_from_errno("got_opentempfd");
424 if (gotd_imsg_compose_event(&gotd_session
.repo_child_iev
,
425 GOTD_IMSG_SEND_PACKFILE
, PROC_GOTD
, client
->delta_cache_fd
,
426 &ipack
, sizeof(ipack
)) == -1) {
427 err
= got_error_from_errno("imsg compose SEND_PACKFILE");
433 /* Send pack pipe end 0 to repo child process. */
434 if (gotd_imsg_compose_event(&gotd_session
.repo_child_iev
,
435 GOTD_IMSG_PACKFILE_PIPE
, PROC_GOTD
, pipe
[0], NULL
, 0) == -1) {
436 err
= got_error_from_errno("imsg compose PACKFILE_PIPE");
441 /* Send pack pipe end 1 to gotsh(1) (expects just an fd, no data). */
442 if (gotd_imsg_compose_event(&client
->iev
,
443 GOTD_IMSG_PACKFILE_PIPE
, PROC_GOTD
, pipe
[1], NULL
, 0) == -1)
444 err
= got_error_from_errno("imsg compose PACKFILE_PIPE");
450 session_dispatch_client(int fd
, short events
, void *arg
)
452 struct gotd_imsgev
*iev
= arg
;
453 struct imsgbuf
*ibuf
= &iev
->ibuf
;
454 struct gotd_session_client
*client
= &gotd_session_client
;
455 const struct got_error
*err
= NULL
;
459 if (events
& EV_WRITE
) {
460 err
= gotd_imsg_flush(ibuf
);
462 disconnect_on_error(client
, err
);
466 if (client
->flush_disconnect
) {
472 if (events
& EV_READ
) {
473 n
= imsgbuf_read(ibuf
);
475 err
= got_error_from_errno("imsgbuf_read");
476 disconnect_on_error(client
, err
);
480 err
= got_error(GOT_ERR_EOF
);
481 disconnect_on_error(client
, err
);
486 while (err
== NULL
) {
487 n
= imsg_get(ibuf
, &imsg
);
489 err
= got_error_from_errno("imsg_get");
495 evtimer_del(&client
->tmo
);
497 switch (imsg
.hdr
.type
) {
498 case GOTD_IMSG_CAPABILITIES
:
499 if (gotd_session
.state
!=
500 GOTD_STATE_EXPECT_CAPABILITIES
) {
501 err
= got_error_msg(GOT_ERR_BAD_REQUEST
,
502 "unexpected capabilities received");
505 log_debug("receiving capabilities from uid %d",
507 err
= recv_capabilities(client
, &imsg
);
509 case GOTD_IMSG_CAPABILITY
:
510 if (gotd_session
.state
!= GOTD_STATE_EXPECT_CAPABILITIES
) {
511 err
= got_error_msg(GOT_ERR_BAD_REQUEST
,
512 "unexpected capability received");
515 err
= recv_capability(client
, &imsg
);
516 if (err
|| client
->ncapabilities
< client
->ncapa_alloc
)
518 gotd_session
.state
= GOTD_STATE_EXPECT_WANT
;
519 client
->accept_flush_pkt
= 1;
520 log_debug("uid %d: expecting want-lines", client
->euid
);
523 if (gotd_session
.state
!= GOTD_STATE_EXPECT_WANT
) {
524 err
= got_error_msg(GOT_ERR_BAD_REQUEST
,
525 "unexpected want-line received");
528 log_debug("received want-line from uid %d",
530 client
->accept_flush_pkt
= 1;
531 err
= forward_want(client
, &imsg
);
534 if (gotd_session
.state
!=
535 GOTD_STATE_EXPECT_HAVE_OR_DONE
) {
536 err
= got_error_msg(GOT_ERR_BAD_REQUEST
,
537 "unexpected have-line received");
540 log_debug("received have-line from uid %d",
542 err
= forward_have(client
, &imsg
);
545 client
->accept_flush_pkt
= 1;
547 case GOTD_IMSG_FLUSH
:
548 if (gotd_session
.state
!= GOTD_STATE_EXPECT_WANT
&&
549 gotd_session
.state
!=
550 GOTD_STATE_EXPECT_HAVE_OR_DONE
) {
551 err
= got_error_msg(GOT_ERR_BAD_REQUEST
,
552 "unexpected flush-pkt received");
555 if (!client
->accept_flush_pkt
) {
556 err
= got_error_msg(GOT_ERR_BAD_REQUEST
,
557 "unexpected flush-pkt received");
562 * Accept just one flush packet at a time.
563 * Future client state transitions will set this flag
564 * again if another flush packet is expected.
566 client
->accept_flush_pkt
= 0;
568 log_debug("received flush-pkt from uid %d",
570 if (gotd_session
.state
== GOTD_STATE_EXPECT_WANT
) {
572 GOTD_STATE_EXPECT_HAVE_OR_DONE
;
573 log_debug("uid %d: expecting have-lines "
574 "or 'done'", client
->euid
);
575 } else if (gotd_session
.state
==
576 GOTD_STATE_EXPECT_HAVE_OR_DONE
) {
577 client
->accept_flush_pkt
= 1;
578 log_debug("uid %d: expecting more have-lines "
579 "or 'done'", client
->euid
);
580 } else if (gotd_session
.state
!=
581 GOTD_STATE_EXPECT_HAVE_OR_DONE
) {
582 /* should not happen, see above */
583 err
= got_error_msg(GOT_ERR_BAD_REQUEST
,
584 "unexpected client state");
589 if (gotd_session
.state
!=
590 GOTD_STATE_EXPECT_HAVE_OR_DONE
) {
591 err
= got_error_msg(GOT_ERR_BAD_REQUEST
,
592 "unexpected flush-pkt received");
595 log_debug("received 'done' from uid %d", client
->euid
);
596 gotd_session
.state
= GOTD_STATE_DONE
;
597 client
->accept_flush_pkt
= 1;
598 err
= send_packfile(client
);
601 log_debug("unexpected imsg %d", imsg
.hdr
.type
);
602 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
610 if (err
->code
!= GOT_ERR_EOF
)
611 disconnect_on_error(client
, err
);
613 gotd_imsg_event_add(iev
);
614 evtimer_add(&client
->tmo
, &gotd_session
.request_timeout
);
618 static const struct got_error
*
619 list_refs_request(void)
621 static const struct got_error
*err
;
622 struct gotd_session_client
*client
= &gotd_session_client
;
623 struct gotd_imsgev
*iev
= &gotd_session
.repo_child_iev
;
626 if (gotd_session
.state
!= GOTD_STATE_EXPECT_LIST_REFS
)
627 return got_error(GOT_ERR_PRIVSEP_MSG
);
629 fd
= dup(client
->fd
);
631 return got_error_from_errno("dup");
633 if (gotd_imsg_compose_event(iev
, GOTD_IMSG_LIST_REFS_INTERNAL
,
634 PROC_SESSION_READ
, fd
, NULL
, 0) == -1) {
635 err
= got_error_from_errno("imsg compose LIST_REFS_INTERNAL");
640 gotd_session
.state
= GOTD_STATE_EXPECT_CAPABILITIES
;
641 log_debug("uid %d: expecting capabilities", client
->euid
);
645 static const struct got_error
*
646 recv_connect(struct imsg
*imsg
)
648 struct gotd_session_client
*client
= &gotd_session_client
;
649 struct gotd_imsg_connect iconnect
;
652 if (gotd_session
.state
!= GOTD_STATE_EXPECT_LIST_REFS
)
653 return got_error(GOT_ERR_PRIVSEP_MSG
);
655 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
656 if (datalen
< sizeof(iconnect
))
657 return got_error(GOT_ERR_PRIVSEP_LEN
);
658 memcpy(&iconnect
, imsg
->data
, sizeof(iconnect
));
659 if (iconnect
.username_len
== 0 ||
660 datalen
!= sizeof(iconnect
) + iconnect
.username_len
)
661 return got_error(GOT_ERR_PRIVSEP_LEN
);
663 client
->euid
= iconnect
.euid
;
664 client
->egid
= iconnect
.egid
;
665 client
->fd
= imsg_get_fd(imsg
);
666 if (client
->fd
== -1)
667 return got_error(GOT_ERR_PRIVSEP_NO_FD
);
669 client
->username
= strndup(imsg
->data
+ sizeof(iconnect
),
670 iconnect
.username_len
);
671 if (client
->username
== NULL
)
672 return got_error_from_errno("strndup");
674 if (imsgbuf_init(&client
->iev
.ibuf
, client
->fd
) == -1)
675 return got_error_from_errno("imsgbuf_init");
676 imsgbuf_allow_fdpass(&client
->iev
.ibuf
);
677 client
->iev
.handler
= session_dispatch_client
;
678 client
->iev
.events
= EV_READ
;
679 client
->iev
.handler_arg
= NULL
;
680 event_set(&client
->iev
.ev
, client
->iev
.ibuf
.fd
, EV_READ
,
681 session_dispatch_client
, &client
->iev
);
682 gotd_imsg_event_add(&client
->iev
);
683 evtimer_set(&client
->tmo
, gotd_request_timeout
, client
);
684 evtimer_add(&client
->tmo
, &gotd_session
.request_timeout
);
689 static const struct got_error
*
690 recv_repo_child(struct imsg
*imsg
)
692 struct gotd_imsg_connect_repo_child ichild
;
693 struct gotd_session_client
*client
= &gotd_session_client
;
697 if (gotd_session
.state
!= GOTD_STATE_EXPECT_LIST_REFS
)
698 return got_error(GOT_ERR_PRIVSEP_MSG
);
700 /* We should already have received a pipe to the listener. */
701 if (client
->fd
== -1)
702 return got_error(GOT_ERR_PRIVSEP_MSG
);
704 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
705 if (datalen
!= sizeof(ichild
))
706 return got_error(GOT_ERR_PRIVSEP_LEN
);
708 memcpy(&ichild
, imsg
->data
, sizeof(ichild
));
710 if (ichild
.proc_id
!= PROC_REPO_READ
)
711 return got_error_msg(GOT_ERR_PRIVSEP_MSG
,
712 "bad child process type");
714 fd
= imsg_get_fd(imsg
);
716 return got_error(GOT_ERR_PRIVSEP_NO_FD
);
718 if (imsgbuf_init(&gotd_session
.repo_child_iev
.ibuf
, fd
)) {
720 return got_error_from_errno("imsgbuf_init");
722 imsgbuf_allow_fdpass(&gotd_session
.repo_child_iev
.ibuf
);
723 gotd_session
.repo_child_iev
.handler
= session_dispatch_repo_child
;
724 gotd_session
.repo_child_iev
.events
= EV_READ
;
725 gotd_session
.repo_child_iev
.handler_arg
= NULL
;
726 event_set(&gotd_session
.repo_child_iev
.ev
,
727 gotd_session
.repo_child_iev
.ibuf
.fd
, EV_READ
,
728 session_dispatch_repo_child
, &gotd_session
.repo_child_iev
);
729 gotd_imsg_event_add(&gotd_session
.repo_child_iev
);
731 /* The "recvfd" pledge promise is no longer needed. */
732 if (pledge("stdio rpath wpath cpath sendfd fattr flock", NULL
) == -1)
739 session_dispatch(int fd
, short event
, void *arg
)
741 const struct got_error
*err
= NULL
;
742 struct gotd_imsgev
*iev
= arg
;
743 struct imsgbuf
*ibuf
= &iev
->ibuf
;
744 struct gotd_session_client
*client
= &gotd_session_client
;
749 if (event
& EV_READ
) {
750 if ((n
= imsgbuf_read(ibuf
)) == -1)
751 fatal("imsgbuf_read error");
753 /* Connection closed. */
759 if (event
& EV_WRITE
) {
760 err
= gotd_imsg_flush(ibuf
);
762 fatalx("%s", err
->msg
);
766 const struct got_error
*err
= NULL
;
767 uint32_t client_id
= 0;
768 int do_disconnect
= 0, do_list_refs
= 0;
770 if ((n
= imsg_get(ibuf
, &imsg
)) == -1)
771 fatal("%s: imsg_get error", __func__
);
772 if (n
== 0) /* No more messages. */
775 switch (imsg
.hdr
.type
) {
776 case GOTD_IMSG_ERROR
:
778 err
= gotd_imsg_recv_error(&client_id
, &imsg
);
780 case GOTD_IMSG_CONNECT
:
781 err
= recv_connect(&imsg
);
783 case GOTD_IMSG_DISCONNECT
:
786 case GOTD_IMSG_CONNECT_REPO_CHILD
:
787 err
= recv_repo_child(&imsg
);
793 log_debug("unexpected imsg %d", imsg
.hdr
.type
);
800 disconnect_on_error(client
, err
);
803 } else if (do_list_refs
)
804 err
= list_refs_request();
807 log_warnx("uid %d: %s", client
->euid
, err
->msg
);
811 gotd_imsg_event_add(iev
);
813 /* This pipe is dead. Remove its event handler */
815 event_loopexit(NULL
);
820 session_read_main(const char *title
, const char *repo_path
,
821 int *pack_fds
, int *temp_fds
, struct timeval
*request_timeout
,
822 struct gotd_repo
*repo_cfg
)
824 const struct got_error
*err
= NULL
;
825 struct event evsigint
, evsigterm
, evsighup
, evsigusr1
;
827 gotd_session
.title
= title
;
828 gotd_session
.pid
= getpid();
829 gotd_session
.pack_fds
= pack_fds
;
830 gotd_session
.temp_fds
= temp_fds
;
831 memcpy(&gotd_session
.request_timeout
, request_timeout
,
832 sizeof(gotd_session
.request_timeout
));
833 gotd_session
.repo_cfg
= repo_cfg
;
835 if (imsgbuf_init(&gotd_session
.notifier_iev
.ibuf
, -1) == -1) {
836 err
= got_error_from_errno("imsgbuf_init");
839 imsgbuf_allow_fdpass(&gotd_session
.notifier_iev
.ibuf
);
841 err
= got_repo_open(&gotd_session
.repo
, repo_path
, NULL
, pack_fds
);
844 if (!got_repo_is_bare(gotd_session
.repo
)) {
845 err
= got_error_msg(GOT_ERR_NOT_GIT_REPO
,
846 "bare git repository required");
849 if (got_repo_get_object_format(gotd_session
.repo
) != GOT_HASH_SHA1
) {
850 err
= got_error_msg(GOT_ERR_NOT_IMPL
,
851 "sha256 object IDs unsupported in network protocol");
855 got_repo_temp_fds_set(gotd_session
.repo
, temp_fds
);
857 signal_set(&evsigint
, SIGINT
, session_read_sighdlr
, NULL
);
858 signal_set(&evsigterm
, SIGTERM
, session_read_sighdlr
, NULL
);
859 signal_set(&evsighup
, SIGHUP
, session_read_sighdlr
, NULL
);
860 signal_set(&evsigusr1
, SIGUSR1
, session_read_sighdlr
, NULL
);
861 signal(SIGPIPE
, SIG_IGN
);
863 signal_add(&evsigint
, NULL
);
864 signal_add(&evsigterm
, NULL
);
865 signal_add(&evsighup
, NULL
);
866 signal_add(&evsigusr1
, NULL
);
868 gotd_session
.state
= GOTD_STATE_EXPECT_LIST_REFS
;
870 gotd_session_client
.fd
= -1;
871 gotd_session_client
.nref_updates
= -1;
872 gotd_session_client
.delta_cache_fd
= -1;
873 gotd_session_client
.accept_flush_pkt
= 1;
875 if (imsgbuf_init(&gotd_session
.parent_iev
.ibuf
, GOTD_FILENO_MSG_PIPE
)
877 err
= got_error_from_errno("imsgbuf_init");
880 imsgbuf_allow_fdpass(&gotd_session
.parent_iev
.ibuf
);
881 gotd_session
.parent_iev
.handler
= session_dispatch
;
882 gotd_session
.parent_iev
.events
= EV_READ
;
883 gotd_session
.parent_iev
.handler_arg
= NULL
;
884 event_set(&gotd_session
.parent_iev
.ev
, gotd_session
.parent_iev
.ibuf
.fd
,
885 EV_READ
, session_dispatch
, &gotd_session
.parent_iev
);
886 if (gotd_imsg_compose_event(&gotd_session
.parent_iev
,
887 GOTD_IMSG_CLIENT_SESSION_READY
, PROC_SESSION_READ
,
888 -1, NULL
, 0) == -1) {
889 err
= got_error_from_errno("imsg compose CLIENT_SESSION_READY");
896 log_warnx("%s: %s", title
, err
->msg
);
897 session_read_shutdown();
901 session_read_shutdown(void)
903 log_debug("%s: shutting down", gotd_session
.title
);
905 if (gotd_session
.repo
)
906 got_repo_close(gotd_session
.repo
);
907 got_repo_pack_fds_close(gotd_session
.pack_fds
);
908 got_repo_temp_fds_close(gotd_session
.temp_fds
);
909 free(gotd_session_client
.username
);