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 <sys/types.h>
18 #include <sys/queue.h>
20 #include <sys/socket.h>
37 #include "got_error.h"
38 #include "got_repository.h"
39 #include "got_object.h"
41 #include "got_reference.h"
42 #include "got_opentemp.h"
44 #include "got_lib_hash.h"
45 #include "got_lib_delta.h"
46 #include "got_lib_object.h"
47 #include "got_lib_object_cache.h"
48 #include "got_lib_pack.h"
49 #include "got_lib_repository.h"
50 #include "got_lib_gitproto.h"
54 #include "session_read.h"
56 enum gotd_session_read_state
{
57 GOTD_STATE_EXPECT_LIST_REFS
,
58 GOTD_STATE_EXPECT_CAPABILITIES
,
59 GOTD_STATE_EXPECT_WANT
,
60 GOTD_STATE_EXPECT_HAVE
,
61 GOTD_STATE_EXPECT_DONE
,
65 static struct gotd_session_read
{
68 struct got_repository
*repo
;
69 struct gotd_repo
*repo_cfg
;
72 struct gotd_imsgev parent_iev
;
73 struct gotd_imsgev notifier_iev
;
74 struct timeval request_timeout
;
75 enum gotd_session_read_state state
;
76 struct gotd_imsgev repo_child_iev
;
79 static struct gotd_session_client
{
80 struct gotd_client_capability
*capabilities
;
86 struct gotd_imsgev iev
;
96 } gotd_session_client
;
98 static void session_read_shutdown(void);
101 disconnect(struct gotd_session_client
*client
)
103 log_debug("uid %d: disconnecting", client
->euid
);
105 if (gotd_imsg_compose_event(&gotd_session
.parent_iev
,
106 GOTD_IMSG_DISCONNECT
, PROC_SESSION_READ
, -1, NULL
, 0) == -1)
107 log_warn("imsg compose DISCONNECT");
109 imsg_clear(&gotd_session
.repo_child_iev
.ibuf
);
110 event_del(&gotd_session
.repo_child_iev
.ev
);
111 evtimer_del(&client
->tmo
);
113 if (client
->delta_cache_fd
!= -1)
114 close(client
->delta_cache_fd
);
115 if (client
->packfile_path
) {
116 if (unlink(client
->packfile_path
) == -1 && errno
!= ENOENT
)
117 log_warn("unlink %s: ", client
->packfile_path
);
118 free(client
->packfile_path
);
120 if (client
->packidx_path
) {
121 if (unlink(client
->packidx_path
) == -1 && errno
!= ENOENT
)
122 log_warn("unlink %s: ", client
->packidx_path
);
123 free(client
->packidx_path
);
125 free(client
->capabilities
);
127 session_read_shutdown();
131 disconnect_on_error(struct gotd_session_client
*client
,
132 const struct got_error
*err
)
136 if (err
->code
!= GOT_ERR_EOF
) {
137 log_warnx("uid %d: %s", client
->euid
, err
->msg
);
138 imsg_init(&ibuf
, client
->fd
);
139 gotd_imsg_send_error(&ibuf
, 0, PROC_SESSION_READ
, err
);
147 gotd_request_timeout(int fd
, short events
, void *arg
)
149 struct gotd_session_client
*client
= arg
;
151 log_debug("disconnecting uid %d due to timeout", client
->euid
);
156 session_read_sighdlr(int sig
, short event
, void *arg
)
159 * Normal signal handler rules don't apply because libevent
165 log_info("%s: ignoring SIGHUP", __func__
);
168 log_info("%s: ignoring SIGUSR1", __func__
);
172 session_read_shutdown();
176 fatalx("unexpected signal");
180 static const struct got_error
*
181 recv_packfile_done(struct imsg
*imsg
)
185 log_debug("packfile-done received");
187 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
189 return got_error(GOT_ERR_PRIVSEP_LEN
);
195 session_dispatch_repo_child(int fd
, short event
, void *arg
)
197 struct gotd_imsgev
*iev
= arg
;
198 struct imsgbuf
*ibuf
= &iev
->ibuf
;
199 struct gotd_session_client
*client
= &gotd_session_client
;
204 if (event
& EV_READ
) {
205 if ((n
= imsg_read(ibuf
)) == -1 && errno
!= EAGAIN
)
206 fatal("imsg_read error");
208 /* Connection closed. */
214 if (event
& EV_WRITE
) {
215 n
= msgbuf_write(&ibuf
->w
);
216 if (n
== -1 && errno
!= EAGAIN
)
217 fatal("msgbuf_write");
219 /* Connection closed. */
226 const struct got_error
*err
= NULL
;
227 uint32_t client_id
= 0;
228 int do_disconnect
= 0;
230 if ((n
= imsg_get(ibuf
, &imsg
)) == -1)
231 fatal("%s: imsg_get error", __func__
);
232 if (n
== 0) /* No more messages. */
235 switch (imsg
.hdr
.type
) {
236 case GOTD_IMSG_ERROR
:
238 err
= gotd_imsg_recv_error(&client_id
, &imsg
);
240 case GOTD_IMSG_PACKFILE_DONE
:
242 err
= recv_packfile_done(&imsg
);
245 log_debug("unexpected imsg %d", imsg
.hdr
.type
);
251 disconnect_on_error(client
, err
);
256 log_warnx("uid %d: %s", client
->euid
, err
->msg
);
262 gotd_imsg_event_add(iev
);
264 /* This pipe is dead. Remove its event handler */
266 event_loopexit(NULL
);
270 static const struct got_error
*
271 recv_capabilities(struct gotd_session_client
*client
, struct imsg
*imsg
)
273 struct gotd_imsg_capabilities icapas
;
276 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
277 if (datalen
!= sizeof(icapas
))
278 return got_error(GOT_ERR_PRIVSEP_LEN
);
279 memcpy(&icapas
, imsg
->data
, sizeof(icapas
));
281 client
->ncapa_alloc
= icapas
.ncapabilities
;
282 client
->capabilities
= calloc(client
->ncapa_alloc
,
283 sizeof(*client
->capabilities
));
284 if (client
->capabilities
== NULL
) {
285 client
->ncapa_alloc
= 0;
286 return got_error_from_errno("calloc");
289 log_debug("expecting %zu capabilities from uid %d",
290 client
->ncapa_alloc
, client
->euid
);
294 static const struct got_error
*
295 recv_capability(struct gotd_session_client
*client
, struct imsg
*imsg
)
297 struct gotd_imsg_capability icapa
;
298 struct gotd_client_capability
*capa
;
300 char *key
, *value
= NULL
;
302 if (client
->capabilities
== NULL
||
303 client
->ncapabilities
>= client
->ncapa_alloc
) {
304 return got_error_msg(GOT_ERR_BAD_REQUEST
,
305 "unexpected capability received");
308 memset(&icapa
, 0, sizeof(icapa
));
310 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
311 if (datalen
< sizeof(icapa
))
312 return got_error(GOT_ERR_PRIVSEP_LEN
);
313 memcpy(&icapa
, imsg
->data
, sizeof(icapa
));
315 if (datalen
!= sizeof(icapa
) + icapa
.key_len
+ icapa
.value_len
)
316 return got_error(GOT_ERR_PRIVSEP_LEN
);
318 key
= strndup(imsg
->data
+ sizeof(icapa
), icapa
.key_len
);
320 return got_error_from_errno("strndup");
321 if (icapa
.value_len
> 0) {
322 value
= strndup(imsg
->data
+ sizeof(icapa
) + icapa
.key_len
,
326 return got_error_from_errno("strndup");
330 capa
= &client
->capabilities
[client
->ncapabilities
++];
335 log_debug("uid %d: capability %s=%s", client
->euid
, key
, value
);
337 log_debug("uid %d: capability %s", client
->euid
, key
);
342 static const struct got_error
*
343 forward_want(struct gotd_session_client
*client
, struct imsg
*imsg
)
345 struct gotd_imsg_want ireq
;
346 struct gotd_imsg_want iwant
;
349 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
350 if (datalen
!= sizeof(ireq
))
351 return got_error(GOT_ERR_PRIVSEP_LEN
);
353 memcpy(&ireq
, imsg
->data
, datalen
);
355 memset(&iwant
, 0, sizeof(iwant
));
356 memcpy(iwant
.object_id
, ireq
.object_id
, SHA1_DIGEST_LENGTH
);
358 if (gotd_imsg_compose_event(&gotd_session
.repo_child_iev
,
359 GOTD_IMSG_WANT
, PROC_SESSION_READ
, -1,
360 &iwant
, sizeof(iwant
)) == -1)
361 return got_error_from_errno("imsg compose WANT");
366 static const struct got_error
*
367 forward_have(struct gotd_session_client
*client
, struct imsg
*imsg
)
369 struct gotd_imsg_have ireq
;
370 struct gotd_imsg_have ihave
;
373 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
374 if (datalen
!= sizeof(ireq
))
375 return got_error(GOT_ERR_PRIVSEP_LEN
);
377 memcpy(&ireq
, imsg
->data
, datalen
);
379 memset(&ihave
, 0, sizeof(ihave
));
380 memcpy(ihave
.object_id
, ireq
.object_id
, SHA1_DIGEST_LENGTH
);
382 if (gotd_imsg_compose_event(&gotd_session
.repo_child_iev
,
383 GOTD_IMSG_HAVE
, PROC_SESSION_READ
, -1,
384 &ihave
, sizeof(ihave
)) == -1)
385 return got_error_from_errno("imsg compose HAVE");
391 client_has_capability(struct gotd_session_client
*client
, const char *capastr
)
393 struct gotd_client_capability
*capa
;
396 if (client
->ncapabilities
== 0)
399 for (i
= 0; i
< client
->ncapabilities
; i
++) {
400 capa
= &client
->capabilities
[i
];
401 if (strcmp(capa
->key
, capastr
) == 0)
408 static const struct got_error
*
409 send_packfile(struct gotd_session_client
*client
)
411 const struct got_error
*err
= NULL
;
412 struct gotd_imsg_send_packfile ipack
;
415 if (socketpair(AF_UNIX
, SOCK_STREAM
, PF_UNSPEC
, pipe
) == -1)
416 return got_error_from_errno("socketpair");
418 memset(&ipack
, 0, sizeof(ipack
));
420 if (client_has_capability(client
, GOT_CAPA_SIDE_BAND_64K
))
421 ipack
.report_progress
= 1;
423 client
->delta_cache_fd
= got_opentempfd();
424 if (client
->delta_cache_fd
== -1)
425 return got_error_from_errno("got_opentempfd");
427 if (gotd_imsg_compose_event(&gotd_session
.repo_child_iev
,
428 GOTD_IMSG_SEND_PACKFILE
, PROC_GOTD
, client
->delta_cache_fd
,
429 &ipack
, sizeof(ipack
)) == -1) {
430 err
= got_error_from_errno("imsg compose SEND_PACKFILE");
436 /* Send pack pipe end 0 to repo child process. */
437 if (gotd_imsg_compose_event(&gotd_session
.repo_child_iev
,
438 GOTD_IMSG_PACKFILE_PIPE
, PROC_GOTD
, pipe
[0], NULL
, 0) == -1) {
439 err
= got_error_from_errno("imsg compose PACKFILE_PIPE");
444 /* Send pack pipe end 1 to gotsh(1) (expects just an fd, no data). */
445 if (gotd_imsg_compose_event(&client
->iev
,
446 GOTD_IMSG_PACKFILE_PIPE
, PROC_GOTD
, pipe
[1], NULL
, 0) == -1)
447 err
= got_error_from_errno("imsg compose PACKFILE_PIPE");
453 session_dispatch_client(int fd
, short events
, void *arg
)
455 struct gotd_imsgev
*iev
= arg
;
456 struct imsgbuf
*ibuf
= &iev
->ibuf
;
457 struct gotd_session_client
*client
= &gotd_session_client
;
458 const struct got_error
*err
= NULL
;
462 if (events
& EV_WRITE
) {
463 while (ibuf
->w
.queued
) {
464 n
= msgbuf_write(&ibuf
->w
);
465 if (n
== -1 && errno
== EPIPE
) {
467 * The client has closed its socket.
468 * This can happen when Git clients are
469 * done sending pack file data.
471 msgbuf_clear(&ibuf
->w
);
473 } else if (n
== -1 && errno
!= EAGAIN
) {
474 err
= got_error_from_errno("imsg_flush");
475 disconnect_on_error(client
, err
);
479 /* Connection closed. */
480 err
= got_error(GOT_ERR_EOF
);
481 disconnect_on_error(client
, err
);
486 if (client
->flush_disconnect
) {
492 if ((events
& EV_READ
) == 0)
495 memset(&imsg
, 0, sizeof(imsg
));
497 while (err
== NULL
) {
498 err
= gotd_imsg_recv(&imsg
, ibuf
, 0);
500 if (err
->code
== GOT_ERR_PRIVSEP_READ
)
502 else if (err
->code
== GOT_ERR_EOF
&&
503 gotd_session
.state
==
504 GOTD_STATE_EXPECT_CAPABILITIES
) {
506 * The client has closed its socket before
507 * sending its capability announcement.
508 * This can happen when Git clients have
509 * no ref-updates to send.
511 disconnect_on_error(client
, err
);
517 evtimer_del(&client
->tmo
);
519 switch (imsg
.hdr
.type
) {
520 case GOTD_IMSG_CAPABILITIES
:
521 if (gotd_session
.state
!=
522 GOTD_STATE_EXPECT_CAPABILITIES
) {
523 err
= got_error_msg(GOT_ERR_BAD_REQUEST
,
524 "unexpected capabilities received");
527 log_debug("receiving capabilities from uid %d",
529 err
= recv_capabilities(client
, &imsg
);
531 case GOTD_IMSG_CAPABILITY
:
532 if (gotd_session
.state
!= GOTD_STATE_EXPECT_CAPABILITIES
) {
533 err
= got_error_msg(GOT_ERR_BAD_REQUEST
,
534 "unexpected capability received");
537 err
= recv_capability(client
, &imsg
);
538 if (err
|| client
->ncapabilities
< client
->ncapa_alloc
)
540 gotd_session
.state
= GOTD_STATE_EXPECT_WANT
;
541 client
->accept_flush_pkt
= 1;
542 log_debug("uid %d: expecting want-lines", client
->euid
);
545 if (gotd_session
.state
!= GOTD_STATE_EXPECT_WANT
) {
546 err
= got_error_msg(GOT_ERR_BAD_REQUEST
,
547 "unexpected want-line received");
550 log_debug("received want-line from uid %d",
552 client
->accept_flush_pkt
= 1;
553 err
= forward_want(client
, &imsg
);
556 if (gotd_session
.state
!= GOTD_STATE_EXPECT_HAVE
) {
557 err
= got_error_msg(GOT_ERR_BAD_REQUEST
,
558 "unexpected have-line received");
561 log_debug("received have-line from uid %d",
563 err
= forward_have(client
, &imsg
);
566 client
->accept_flush_pkt
= 1;
568 case GOTD_IMSG_FLUSH
:
569 if (gotd_session
.state
!= GOTD_STATE_EXPECT_WANT
&&
570 gotd_session
.state
!= GOTD_STATE_EXPECT_HAVE
&&
571 gotd_session
.state
!= GOTD_STATE_EXPECT_DONE
) {
572 err
= got_error_msg(GOT_ERR_BAD_REQUEST
,
573 "unexpected flush-pkt received");
576 if (!client
->accept_flush_pkt
) {
577 err
= got_error_msg(GOT_ERR_BAD_REQUEST
,
578 "unexpected flush-pkt received");
583 * Accept just one flush packet at a time.
584 * Future client state transitions will set this flag
585 * again if another flush packet is expected.
587 client
->accept_flush_pkt
= 0;
589 log_debug("received flush-pkt from uid %d",
591 if (gotd_session
.state
== GOTD_STATE_EXPECT_WANT
) {
592 gotd_session
.state
= GOTD_STATE_EXPECT_HAVE
;
593 log_debug("uid %d: expecting have-lines",
595 } else if (gotd_session
.state
== GOTD_STATE_EXPECT_HAVE
) {
596 gotd_session
.state
= GOTD_STATE_EXPECT_DONE
;
597 client
->accept_flush_pkt
= 1;
598 log_debug("uid %d: expecting 'done'",
600 } else if (gotd_session
.state
!= GOTD_STATE_EXPECT_DONE
) {
601 /* should not happen, see above */
602 err
= got_error_msg(GOT_ERR_BAD_REQUEST
,
603 "unexpected client state");
608 if (gotd_session
.state
!= GOTD_STATE_EXPECT_HAVE
&&
609 gotd_session
.state
!= GOTD_STATE_EXPECT_DONE
) {
610 err
= got_error_msg(GOT_ERR_BAD_REQUEST
,
611 "unexpected flush-pkt received");
614 log_debug("received 'done' from uid %d", client
->euid
);
615 gotd_session
.state
= GOTD_STATE_DONE
;
616 client
->accept_flush_pkt
= 1;
617 err
= send_packfile(client
);
620 log_debug("unexpected imsg %d", imsg
.hdr
.type
);
621 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
629 if (err
->code
!= GOT_ERR_EOF
)
630 disconnect_on_error(client
, err
);
632 gotd_imsg_event_add(iev
);
633 evtimer_add(&client
->tmo
, &gotd_session
.request_timeout
);
637 static const struct got_error
*
638 list_refs_request(void)
640 static const struct got_error
*err
;
641 struct gotd_session_client
*client
= &gotd_session_client
;
642 struct gotd_imsgev
*iev
= &gotd_session
.repo_child_iev
;
645 if (gotd_session
.state
!= GOTD_STATE_EXPECT_LIST_REFS
)
646 return got_error(GOT_ERR_PRIVSEP_MSG
);
648 fd
= dup(client
->fd
);
650 return got_error_from_errno("dup");
652 if (gotd_imsg_compose_event(iev
, GOTD_IMSG_LIST_REFS_INTERNAL
,
653 PROC_SESSION_READ
, fd
, NULL
, 0) == -1) {
654 err
= got_error_from_errno("imsg compose LIST_REFS_INTERNAL");
659 gotd_session
.state
= GOTD_STATE_EXPECT_CAPABILITIES
;
660 log_debug("uid %d: expecting capabilities", client
->euid
);
664 static const struct got_error
*
665 recv_connect(struct imsg
*imsg
)
667 struct gotd_session_client
*client
= &gotd_session_client
;
668 struct gotd_imsg_connect iconnect
;
671 if (gotd_session
.state
!= GOTD_STATE_EXPECT_LIST_REFS
)
672 return got_error(GOT_ERR_PRIVSEP_MSG
);
674 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
675 if (datalen
< sizeof(iconnect
))
676 return got_error(GOT_ERR_PRIVSEP_LEN
);
677 memcpy(&iconnect
, imsg
->data
, sizeof(iconnect
));
678 if (iconnect
.username_len
== 0 ||
679 datalen
!= sizeof(iconnect
) + iconnect
.username_len
)
680 return got_error(GOT_ERR_PRIVSEP_LEN
);
682 client
->euid
= iconnect
.euid
;
683 client
->egid
= iconnect
.egid
;
684 client
->fd
= imsg_get_fd(imsg
);
685 if (client
->fd
== -1)
686 return got_error(GOT_ERR_PRIVSEP_NO_FD
);
688 client
->username
= strndup(imsg
->data
+ sizeof(iconnect
),
689 iconnect
.username_len
);
690 if (client
->username
== NULL
)
691 return got_error_from_errno("strndup");
693 imsg_init(&client
->iev
.ibuf
, client
->fd
);
694 client
->iev
.handler
= session_dispatch_client
;
695 client
->iev
.events
= EV_READ
;
696 client
->iev
.handler_arg
= NULL
;
697 event_set(&client
->iev
.ev
, client
->iev
.ibuf
.fd
, EV_READ
,
698 session_dispatch_client
, &client
->iev
);
699 gotd_imsg_event_add(&client
->iev
);
700 evtimer_set(&client
->tmo
, gotd_request_timeout
, client
);
705 static const struct got_error
*
706 recv_repo_child(struct imsg
*imsg
)
708 struct gotd_imsg_connect_repo_child ichild
;
709 struct gotd_session_client
*client
= &gotd_session_client
;
713 if (gotd_session
.state
!= GOTD_STATE_EXPECT_LIST_REFS
)
714 return got_error(GOT_ERR_PRIVSEP_MSG
);
716 /* We should already have received a pipe to the listener. */
717 if (client
->fd
== -1)
718 return got_error(GOT_ERR_PRIVSEP_MSG
);
720 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
721 if (datalen
!= sizeof(ichild
))
722 return got_error(GOT_ERR_PRIVSEP_LEN
);
724 memcpy(&ichild
, imsg
->data
, sizeof(ichild
));
726 if (ichild
.proc_id
!= PROC_REPO_READ
)
727 return got_error_msg(GOT_ERR_PRIVSEP_MSG
,
728 "bad child process type");
730 fd
= imsg_get_fd(imsg
);
732 return got_error(GOT_ERR_PRIVSEP_NO_FD
);
734 imsg_init(&gotd_session
.repo_child_iev
.ibuf
, fd
);
735 gotd_session
.repo_child_iev
.handler
= session_dispatch_repo_child
;
736 gotd_session
.repo_child_iev
.events
= EV_READ
;
737 gotd_session
.repo_child_iev
.handler_arg
= NULL
;
738 event_set(&gotd_session
.repo_child_iev
.ev
,
739 gotd_session
.repo_child_iev
.ibuf
.fd
, EV_READ
,
740 session_dispatch_repo_child
, &gotd_session
.repo_child_iev
);
741 gotd_imsg_event_add(&gotd_session
.repo_child_iev
);
743 /* The "recvfd" pledge promise is no longer needed. */
744 if (pledge("stdio rpath wpath cpath sendfd fattr flock", NULL
) == -1)
751 session_dispatch(int fd
, short event
, void *arg
)
753 struct gotd_imsgev
*iev
= arg
;
754 struct imsgbuf
*ibuf
= &iev
->ibuf
;
755 struct gotd_session_client
*client
= &gotd_session_client
;
760 if (event
& EV_READ
) {
761 if ((n
= imsg_read(ibuf
)) == -1 && errno
!= EAGAIN
)
762 fatal("imsg_read error");
764 /* Connection closed. */
770 if (event
& EV_WRITE
) {
771 n
= msgbuf_write(&ibuf
->w
);
772 if (n
== -1 && errno
!= EAGAIN
)
773 fatal("msgbuf_write");
775 /* Connection closed. */
782 const struct got_error
*err
= NULL
;
783 uint32_t client_id
= 0;
784 int do_disconnect
= 0, do_list_refs
= 0;
786 if ((n
= imsg_get(ibuf
, &imsg
)) == -1)
787 fatal("%s: imsg_get error", __func__
);
788 if (n
== 0) /* No more messages. */
791 switch (imsg
.hdr
.type
) {
792 case GOTD_IMSG_ERROR
:
794 err
= gotd_imsg_recv_error(&client_id
, &imsg
);
796 case GOTD_IMSG_CONNECT
:
797 err
= recv_connect(&imsg
);
799 case GOTD_IMSG_DISCONNECT
:
802 case GOTD_IMSG_CONNECT_REPO_CHILD
:
803 err
= recv_repo_child(&imsg
);
809 log_debug("unexpected imsg %d", imsg
.hdr
.type
);
816 disconnect_on_error(client
, err
);
819 } else if (do_list_refs
)
820 err
= list_refs_request();
823 log_warnx("uid %d: %s", client
->euid
, err
->msg
);
827 gotd_imsg_event_add(iev
);
829 /* This pipe is dead. Remove its event handler */
831 event_loopexit(NULL
);
836 session_read_main(const char *title
, const char *repo_path
,
837 int *pack_fds
, int *temp_fds
, struct timeval
*request_timeout
,
838 struct gotd_repo
*repo_cfg
)
840 const struct got_error
*err
= NULL
;
841 struct event evsigint
, evsigterm
, evsighup
, evsigusr1
;
843 gotd_session
.title
= title
;
844 gotd_session
.pid
= getpid();
845 gotd_session
.pack_fds
= pack_fds
;
846 gotd_session
.temp_fds
= temp_fds
;
847 memcpy(&gotd_session
.request_timeout
, request_timeout
,
848 sizeof(gotd_session
.request_timeout
));
849 gotd_session
.repo_cfg
= repo_cfg
;
851 imsg_init(&gotd_session
.notifier_iev
.ibuf
, -1);
853 err
= got_repo_open(&gotd_session
.repo
, repo_path
, NULL
, pack_fds
);
856 if (!got_repo_is_bare(gotd_session
.repo
)) {
857 err
= got_error_msg(GOT_ERR_NOT_GIT_REPO
,
858 "bare git repository required");
862 got_repo_temp_fds_set(gotd_session
.repo
, temp_fds
);
864 signal_set(&evsigint
, SIGINT
, session_read_sighdlr
, NULL
);
865 signal_set(&evsigterm
, SIGTERM
, session_read_sighdlr
, NULL
);
866 signal_set(&evsighup
, SIGHUP
, session_read_sighdlr
, NULL
);
867 signal_set(&evsigusr1
, SIGUSR1
, session_read_sighdlr
, NULL
);
868 signal(SIGPIPE
, SIG_IGN
);
870 signal_add(&evsigint
, NULL
);
871 signal_add(&evsigterm
, NULL
);
872 signal_add(&evsighup
, NULL
);
873 signal_add(&evsigusr1
, NULL
);
875 gotd_session
.state
= GOTD_STATE_EXPECT_LIST_REFS
;
877 gotd_session_client
.fd
= -1;
878 gotd_session_client
.nref_updates
= -1;
879 gotd_session_client
.delta_cache_fd
= -1;
880 gotd_session_client
.accept_flush_pkt
= 1;
882 imsg_init(&gotd_session
.parent_iev
.ibuf
, GOTD_FILENO_MSG_PIPE
);
883 gotd_session
.parent_iev
.handler
= session_dispatch
;
884 gotd_session
.parent_iev
.events
= EV_READ
;
885 gotd_session
.parent_iev
.handler_arg
= NULL
;
886 event_set(&gotd_session
.parent_iev
.ev
, gotd_session
.parent_iev
.ibuf
.fd
,
887 EV_READ
, session_dispatch
, &gotd_session
.parent_iev
);
888 if (gotd_imsg_compose_event(&gotd_session
.parent_iev
,
889 GOTD_IMSG_CLIENT_SESSION_READY
, PROC_SESSION_READ
,
890 -1, NULL
, 0) == -1) {
891 err
= got_error_from_errno("imsg compose CLIENT_SESSION_READY");
898 log_warnx("%s: %s", title
, err
->msg
);
899 session_read_shutdown();
903 session_read_shutdown(void)
905 log_debug("%s: shutting down", gotd_session
.title
);
907 if (gotd_session
.repo
)
908 got_repo_close(gotd_session
.repo
);
909 got_repo_pack_fds_close(gotd_session
.pack_fds
);
910 got_repo_temp_fds_close(gotd_session
.temp_fds
);
911 free(gotd_session_client
.username
);