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 imsg_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 imsg_init(&ibuf
, client
->fd
);
137 gotd_imsg_send_error(&ibuf
, 0, PROC_SESSION_READ
, err
);
145 gotd_request_timeout(int fd
, short events
, void *arg
)
147 struct gotd_session_client
*client
= arg
;
149 log_warnx("disconnecting uid %d due to timeout", client
->euid
);
154 session_read_sighdlr(int sig
, short event
, void *arg
)
157 * Normal signal handler rules don't apply because libevent
163 log_info("%s: ignoring SIGHUP", __func__
);
166 log_info("%s: ignoring SIGUSR1", __func__
);
170 session_read_shutdown();
174 fatalx("unexpected signal");
178 static const struct got_error
*
179 recv_packfile_done(struct imsg
*imsg
)
183 log_debug("packfile-done received");
185 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
187 return got_error(GOT_ERR_PRIVSEP_LEN
);
193 session_dispatch_repo_child(int fd
, short event
, void *arg
)
195 struct gotd_imsgev
*iev
= arg
;
196 struct imsgbuf
*ibuf
= &iev
->ibuf
;
197 struct gotd_session_client
*client
= &gotd_session_client
;
202 if (event
& EV_READ
) {
203 if ((n
= imsg_read(ibuf
)) == -1 && errno
!= EAGAIN
)
204 fatal("imsg_read error");
206 /* Connection closed. */
212 if (event
& EV_WRITE
) {
213 n
= msgbuf_write(&ibuf
->w
);
214 if (n
== -1 && errno
!= EAGAIN
)
215 fatal("msgbuf_write");
217 /* Connection closed. */
224 const struct got_error
*err
= NULL
;
225 uint32_t client_id
= 0;
226 int do_disconnect
= 0;
228 if ((n
= imsg_get(ibuf
, &imsg
)) == -1)
229 fatal("%s: imsg_get error", __func__
);
230 if (n
== 0) /* No more messages. */
233 switch (imsg
.hdr
.type
) {
234 case GOTD_IMSG_ERROR
:
236 err
= gotd_imsg_recv_error(&client_id
, &imsg
);
238 case GOTD_IMSG_PACKFILE_DONE
:
240 err
= recv_packfile_done(&imsg
);
243 log_debug("unexpected imsg %d", imsg
.hdr
.type
);
249 disconnect_on_error(client
, err
);
254 log_warnx("uid %d: %s", client
->euid
, err
->msg
);
260 gotd_imsg_event_add(iev
);
262 /* This pipe is dead. Remove its event handler */
264 event_loopexit(NULL
);
268 static const struct got_error
*
269 recv_capabilities(struct gotd_session_client
*client
, struct imsg
*imsg
)
271 struct gotd_imsg_capabilities icapas
;
274 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
275 if (datalen
!= sizeof(icapas
))
276 return got_error(GOT_ERR_PRIVSEP_LEN
);
277 memcpy(&icapas
, imsg
->data
, sizeof(icapas
));
279 client
->ncapa_alloc
= icapas
.ncapabilities
;
280 client
->capabilities
= calloc(client
->ncapa_alloc
,
281 sizeof(*client
->capabilities
));
282 if (client
->capabilities
== NULL
) {
283 client
->ncapa_alloc
= 0;
284 return got_error_from_errno("calloc");
287 log_debug("expecting %zu capabilities from uid %d",
288 client
->ncapa_alloc
, client
->euid
);
292 static const struct got_error
*
293 recv_capability(struct gotd_session_client
*client
, struct imsg
*imsg
)
295 struct gotd_imsg_capability icapa
;
296 struct gotd_client_capability
*capa
;
298 char *key
, *value
= NULL
;
300 if (client
->capabilities
== NULL
||
301 client
->ncapabilities
>= client
->ncapa_alloc
) {
302 return got_error_msg(GOT_ERR_BAD_REQUEST
,
303 "unexpected capability received");
306 memset(&icapa
, 0, sizeof(icapa
));
308 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
309 if (datalen
< sizeof(icapa
))
310 return got_error(GOT_ERR_PRIVSEP_LEN
);
311 memcpy(&icapa
, imsg
->data
, sizeof(icapa
));
313 if (datalen
!= sizeof(icapa
) + icapa
.key_len
+ icapa
.value_len
)
314 return got_error(GOT_ERR_PRIVSEP_LEN
);
316 key
= strndup(imsg
->data
+ sizeof(icapa
), icapa
.key_len
);
318 return got_error_from_errno("strndup");
319 if (icapa
.value_len
> 0) {
320 value
= strndup(imsg
->data
+ sizeof(icapa
) + icapa
.key_len
,
324 return got_error_from_errno("strndup");
328 capa
= &client
->capabilities
[client
->ncapabilities
++];
333 log_debug("uid %d: capability %s=%s", client
->euid
, key
, value
);
335 log_debug("uid %d: capability %s", client
->euid
, key
);
340 static const struct got_error
*
341 forward_want(struct gotd_session_client
*client
, struct imsg
*imsg
)
343 struct gotd_imsg_want ireq
;
344 struct gotd_imsg_want iwant
;
347 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
348 if (datalen
!= sizeof(ireq
))
349 return got_error(GOT_ERR_PRIVSEP_LEN
);
351 memcpy(&ireq
, imsg
->data
, datalen
);
353 memset(&iwant
, 0, sizeof(iwant
));
354 memcpy(iwant
.object_id
, ireq
.object_id
, SHA1_DIGEST_LENGTH
);
356 if (gotd_imsg_compose_event(&gotd_session
.repo_child_iev
,
357 GOTD_IMSG_WANT
, PROC_SESSION_READ
, -1,
358 &iwant
, sizeof(iwant
)) == -1)
359 return got_error_from_errno("imsg compose WANT");
364 static const struct got_error
*
365 forward_have(struct gotd_session_client
*client
, struct imsg
*imsg
)
367 struct gotd_imsg_have ireq
;
368 struct gotd_imsg_have ihave
;
371 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
372 if (datalen
!= sizeof(ireq
))
373 return got_error(GOT_ERR_PRIVSEP_LEN
);
375 memcpy(&ireq
, imsg
->data
, datalen
);
377 memset(&ihave
, 0, sizeof(ihave
));
378 memcpy(ihave
.object_id
, ireq
.object_id
, SHA1_DIGEST_LENGTH
);
380 if (gotd_imsg_compose_event(&gotd_session
.repo_child_iev
,
381 GOTD_IMSG_HAVE
, PROC_SESSION_READ
, -1,
382 &ihave
, sizeof(ihave
)) == -1)
383 return got_error_from_errno("imsg compose HAVE");
389 client_has_capability(struct gotd_session_client
*client
, const char *capastr
)
391 struct gotd_client_capability
*capa
;
394 if (client
->ncapabilities
== 0)
397 for (i
= 0; i
< client
->ncapabilities
; i
++) {
398 capa
= &client
->capabilities
[i
];
399 if (strcmp(capa
->key
, capastr
) == 0)
406 static const struct got_error
*
407 send_packfile(struct gotd_session_client
*client
)
409 const struct got_error
*err
= NULL
;
410 struct gotd_imsg_send_packfile ipack
;
413 if (socketpair(AF_UNIX
, SOCK_STREAM
, PF_UNSPEC
, pipe
) == -1)
414 return got_error_from_errno("socketpair");
416 memset(&ipack
, 0, sizeof(ipack
));
418 if (client_has_capability(client
, GOT_CAPA_SIDE_BAND_64K
))
419 ipack
.report_progress
= 1;
421 client
->delta_cache_fd
= got_opentempfd();
422 if (client
->delta_cache_fd
== -1)
423 return got_error_from_errno("got_opentempfd");
425 if (gotd_imsg_compose_event(&gotd_session
.repo_child_iev
,
426 GOTD_IMSG_SEND_PACKFILE
, PROC_GOTD
, client
->delta_cache_fd
,
427 &ipack
, sizeof(ipack
)) == -1) {
428 err
= got_error_from_errno("imsg compose SEND_PACKFILE");
434 /* Send pack pipe end 0 to repo child process. */
435 if (gotd_imsg_compose_event(&gotd_session
.repo_child_iev
,
436 GOTD_IMSG_PACKFILE_PIPE
, PROC_GOTD
, pipe
[0], NULL
, 0) == -1) {
437 err
= got_error_from_errno("imsg compose PACKFILE_PIPE");
442 /* Send pack pipe end 1 to gotsh(1) (expects just an fd, no data). */
443 if (gotd_imsg_compose_event(&client
->iev
,
444 GOTD_IMSG_PACKFILE_PIPE
, PROC_GOTD
, pipe
[1], NULL
, 0) == -1)
445 err
= got_error_from_errno("imsg compose PACKFILE_PIPE");
451 session_dispatch_client(int fd
, short events
, void *arg
)
453 struct gotd_imsgev
*iev
= arg
;
454 struct imsgbuf
*ibuf
= &iev
->ibuf
;
455 struct gotd_session_client
*client
= &gotd_session_client
;
456 const struct got_error
*err
= NULL
;
460 if (events
& EV_WRITE
) {
461 while (ibuf
->w
.queued
) {
462 n
= msgbuf_write(&ibuf
->w
);
463 if (n
== -1 && errno
!= EAGAIN
) {
464 err
= got_error_from_errno("imsg_flush");
465 disconnect_on_error(client
, err
);
469 /* Connection closed. */
470 err
= got_error(GOT_ERR_EOF
);
471 disconnect_on_error(client
, err
);
476 if (client
->flush_disconnect
) {
482 if ((events
& EV_READ
) == 0)
485 memset(&imsg
, 0, sizeof(imsg
));
487 while (err
== NULL
) {
488 err
= gotd_imsg_recv(&imsg
, ibuf
, 0);
490 if (err
->code
== GOT_ERR_PRIVSEP_READ
)
492 else if (err
->code
== GOT_ERR_EOF
&&
493 gotd_session
.state
==
494 GOTD_STATE_EXPECT_CAPABILITIES
) {
496 * The client has closed its socket before
497 * sending its capability announcement.
498 * This can happen when Git clients have
499 * no ref-updates to send.
501 disconnect_on_error(client
, err
);
507 evtimer_del(&client
->tmo
);
509 switch (imsg
.hdr
.type
) {
510 case GOTD_IMSG_CAPABILITIES
:
511 if (gotd_session
.state
!=
512 GOTD_STATE_EXPECT_CAPABILITIES
) {
513 err
= got_error_msg(GOT_ERR_BAD_REQUEST
,
514 "unexpected capabilities received");
517 log_debug("receiving capabilities from uid %d",
519 err
= recv_capabilities(client
, &imsg
);
521 case GOTD_IMSG_CAPABILITY
:
522 if (gotd_session
.state
!= GOTD_STATE_EXPECT_CAPABILITIES
) {
523 err
= got_error_msg(GOT_ERR_BAD_REQUEST
,
524 "unexpected capability received");
527 err
= recv_capability(client
, &imsg
);
528 if (err
|| client
->ncapabilities
< client
->ncapa_alloc
)
530 gotd_session
.state
= GOTD_STATE_EXPECT_WANT
;
531 client
->accept_flush_pkt
= 1;
532 log_debug("uid %d: expecting want-lines", client
->euid
);
535 if (gotd_session
.state
!= GOTD_STATE_EXPECT_WANT
) {
536 err
= got_error_msg(GOT_ERR_BAD_REQUEST
,
537 "unexpected want-line received");
540 log_debug("received want-line from uid %d",
542 client
->accept_flush_pkt
= 1;
543 err
= forward_want(client
, &imsg
);
546 if (gotd_session
.state
!=
547 GOTD_STATE_EXPECT_HAVE_OR_DONE
) {
548 err
= got_error_msg(GOT_ERR_BAD_REQUEST
,
549 "unexpected have-line received");
552 log_debug("received have-line from uid %d",
554 err
= forward_have(client
, &imsg
);
557 client
->accept_flush_pkt
= 1;
559 case GOTD_IMSG_FLUSH
:
560 if (gotd_session
.state
!= GOTD_STATE_EXPECT_WANT
&&
561 gotd_session
.state
!=
562 GOTD_STATE_EXPECT_HAVE_OR_DONE
) {
563 err
= got_error_msg(GOT_ERR_BAD_REQUEST
,
564 "unexpected flush-pkt received");
567 if (!client
->accept_flush_pkt
) {
568 err
= got_error_msg(GOT_ERR_BAD_REQUEST
,
569 "unexpected flush-pkt received");
574 * Accept just one flush packet at a time.
575 * Future client state transitions will set this flag
576 * again if another flush packet is expected.
578 client
->accept_flush_pkt
= 0;
580 log_debug("received flush-pkt from uid %d",
582 if (gotd_session
.state
== GOTD_STATE_EXPECT_WANT
) {
584 GOTD_STATE_EXPECT_HAVE_OR_DONE
;
585 log_debug("uid %d: expecting have-lines "
586 "or 'done'", client
->euid
);
587 } else if (gotd_session
.state
==
588 GOTD_STATE_EXPECT_HAVE_OR_DONE
) {
589 client
->accept_flush_pkt
= 1;
590 log_debug("uid %d: expecting more have-lines "
591 "or 'done'", client
->euid
);
592 } else if (gotd_session
.state
!=
593 GOTD_STATE_EXPECT_HAVE_OR_DONE
) {
594 /* should not happen, see above */
595 err
= got_error_msg(GOT_ERR_BAD_REQUEST
,
596 "unexpected client state");
601 if (gotd_session
.state
!=
602 GOTD_STATE_EXPECT_HAVE_OR_DONE
) {
603 err
= got_error_msg(GOT_ERR_BAD_REQUEST
,
604 "unexpected flush-pkt received");
607 log_debug("received 'done' from uid %d", client
->euid
);
608 gotd_session
.state
= GOTD_STATE_DONE
;
609 client
->accept_flush_pkt
= 1;
610 err
= send_packfile(client
);
613 log_debug("unexpected imsg %d", imsg
.hdr
.type
);
614 err
= got_error(GOT_ERR_PRIVSEP_MSG
);
622 if (err
->code
!= GOT_ERR_EOF
)
623 disconnect_on_error(client
, err
);
625 gotd_imsg_event_add(iev
);
626 evtimer_add(&client
->tmo
, &gotd_session
.request_timeout
);
630 static const struct got_error
*
631 list_refs_request(void)
633 static const struct got_error
*err
;
634 struct gotd_session_client
*client
= &gotd_session_client
;
635 struct gotd_imsgev
*iev
= &gotd_session
.repo_child_iev
;
638 if (gotd_session
.state
!= GOTD_STATE_EXPECT_LIST_REFS
)
639 return got_error(GOT_ERR_PRIVSEP_MSG
);
641 fd
= dup(client
->fd
);
643 return got_error_from_errno("dup");
645 if (gotd_imsg_compose_event(iev
, GOTD_IMSG_LIST_REFS_INTERNAL
,
646 PROC_SESSION_READ
, fd
, NULL
, 0) == -1) {
647 err
= got_error_from_errno("imsg compose LIST_REFS_INTERNAL");
652 gotd_session
.state
= GOTD_STATE_EXPECT_CAPABILITIES
;
653 log_debug("uid %d: expecting capabilities", client
->euid
);
657 static const struct got_error
*
658 recv_connect(struct imsg
*imsg
)
660 struct gotd_session_client
*client
= &gotd_session_client
;
661 struct gotd_imsg_connect iconnect
;
664 if (gotd_session
.state
!= GOTD_STATE_EXPECT_LIST_REFS
)
665 return got_error(GOT_ERR_PRIVSEP_MSG
);
667 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
668 if (datalen
< sizeof(iconnect
))
669 return got_error(GOT_ERR_PRIVSEP_LEN
);
670 memcpy(&iconnect
, imsg
->data
, sizeof(iconnect
));
671 if (iconnect
.username_len
== 0 ||
672 datalen
!= sizeof(iconnect
) + iconnect
.username_len
)
673 return got_error(GOT_ERR_PRIVSEP_LEN
);
675 client
->euid
= iconnect
.euid
;
676 client
->egid
= iconnect
.egid
;
677 client
->fd
= imsg_get_fd(imsg
);
678 if (client
->fd
== -1)
679 return got_error(GOT_ERR_PRIVSEP_NO_FD
);
681 client
->username
= strndup(imsg
->data
+ sizeof(iconnect
),
682 iconnect
.username_len
);
683 if (client
->username
== NULL
)
684 return got_error_from_errno("strndup");
686 imsg_init(&client
->iev
.ibuf
, client
->fd
);
687 client
->iev
.handler
= session_dispatch_client
;
688 client
->iev
.events
= EV_READ
;
689 client
->iev
.handler_arg
= NULL
;
690 event_set(&client
->iev
.ev
, client
->iev
.ibuf
.fd
, EV_READ
,
691 session_dispatch_client
, &client
->iev
);
692 gotd_imsg_event_add(&client
->iev
);
693 evtimer_set(&client
->tmo
, gotd_request_timeout
, client
);
694 evtimer_add(&client
->tmo
, &gotd_session
.request_timeout
);
699 static const struct got_error
*
700 recv_repo_child(struct imsg
*imsg
)
702 struct gotd_imsg_connect_repo_child ichild
;
703 struct gotd_session_client
*client
= &gotd_session_client
;
707 if (gotd_session
.state
!= GOTD_STATE_EXPECT_LIST_REFS
)
708 return got_error(GOT_ERR_PRIVSEP_MSG
);
710 /* We should already have received a pipe to the listener. */
711 if (client
->fd
== -1)
712 return got_error(GOT_ERR_PRIVSEP_MSG
);
714 datalen
= imsg
->hdr
.len
- IMSG_HEADER_SIZE
;
715 if (datalen
!= sizeof(ichild
))
716 return got_error(GOT_ERR_PRIVSEP_LEN
);
718 memcpy(&ichild
, imsg
->data
, sizeof(ichild
));
720 if (ichild
.proc_id
!= PROC_REPO_READ
)
721 return got_error_msg(GOT_ERR_PRIVSEP_MSG
,
722 "bad child process type");
724 fd
= imsg_get_fd(imsg
);
726 return got_error(GOT_ERR_PRIVSEP_NO_FD
);
728 imsg_init(&gotd_session
.repo_child_iev
.ibuf
, fd
);
729 gotd_session
.repo_child_iev
.handler
= session_dispatch_repo_child
;
730 gotd_session
.repo_child_iev
.events
= EV_READ
;
731 gotd_session
.repo_child_iev
.handler_arg
= NULL
;
732 event_set(&gotd_session
.repo_child_iev
.ev
,
733 gotd_session
.repo_child_iev
.ibuf
.fd
, EV_READ
,
734 session_dispatch_repo_child
, &gotd_session
.repo_child_iev
);
735 gotd_imsg_event_add(&gotd_session
.repo_child_iev
);
737 /* The "recvfd" pledge promise is no longer needed. */
738 if (pledge("stdio rpath wpath cpath sendfd fattr flock", NULL
) == -1)
745 session_dispatch(int fd
, short event
, void *arg
)
747 struct gotd_imsgev
*iev
= arg
;
748 struct imsgbuf
*ibuf
= &iev
->ibuf
;
749 struct gotd_session_client
*client
= &gotd_session_client
;
754 if (event
& EV_READ
) {
755 if ((n
= imsg_read(ibuf
)) == -1 && errno
!= EAGAIN
)
756 fatal("imsg_read error");
758 /* Connection closed. */
764 if (event
& EV_WRITE
) {
765 n
= msgbuf_write(&ibuf
->w
);
766 if (n
== -1 && errno
!= EAGAIN
)
767 fatal("msgbuf_write");
769 /* Connection closed. */
776 const struct got_error
*err
= NULL
;
777 uint32_t client_id
= 0;
778 int do_disconnect
= 0, do_list_refs
= 0;
780 if ((n
= imsg_get(ibuf
, &imsg
)) == -1)
781 fatal("%s: imsg_get error", __func__
);
782 if (n
== 0) /* No more messages. */
785 switch (imsg
.hdr
.type
) {
786 case GOTD_IMSG_ERROR
:
788 err
= gotd_imsg_recv_error(&client_id
, &imsg
);
790 case GOTD_IMSG_CONNECT
:
791 err
= recv_connect(&imsg
);
793 case GOTD_IMSG_DISCONNECT
:
796 case GOTD_IMSG_CONNECT_REPO_CHILD
:
797 err
= recv_repo_child(&imsg
);
803 log_debug("unexpected imsg %d", imsg
.hdr
.type
);
810 disconnect_on_error(client
, err
);
813 } else if (do_list_refs
)
814 err
= list_refs_request();
817 log_warnx("uid %d: %s", client
->euid
, err
->msg
);
821 gotd_imsg_event_add(iev
);
823 /* This pipe is dead. Remove its event handler */
825 event_loopexit(NULL
);
830 session_read_main(const char *title
, const char *repo_path
,
831 int *pack_fds
, int *temp_fds
, struct timeval
*request_timeout
,
832 struct gotd_repo
*repo_cfg
)
834 const struct got_error
*err
= NULL
;
835 struct event evsigint
, evsigterm
, evsighup
, evsigusr1
;
837 gotd_session
.title
= title
;
838 gotd_session
.pid
= getpid();
839 gotd_session
.pack_fds
= pack_fds
;
840 gotd_session
.temp_fds
= temp_fds
;
841 memcpy(&gotd_session
.request_timeout
, request_timeout
,
842 sizeof(gotd_session
.request_timeout
));
843 gotd_session
.repo_cfg
= repo_cfg
;
845 imsg_init(&gotd_session
.notifier_iev
.ibuf
, -1);
847 err
= got_repo_open(&gotd_session
.repo
, repo_path
, NULL
, pack_fds
);
850 if (!got_repo_is_bare(gotd_session
.repo
)) {
851 err
= got_error_msg(GOT_ERR_NOT_GIT_REPO
,
852 "bare git repository required");
856 got_repo_temp_fds_set(gotd_session
.repo
, temp_fds
);
858 signal_set(&evsigint
, SIGINT
, session_read_sighdlr
, NULL
);
859 signal_set(&evsigterm
, SIGTERM
, session_read_sighdlr
, NULL
);
860 signal_set(&evsighup
, SIGHUP
, session_read_sighdlr
, NULL
);
861 signal_set(&evsigusr1
, SIGUSR1
, session_read_sighdlr
, NULL
);
862 signal(SIGPIPE
, SIG_IGN
);
864 signal_add(&evsigint
, NULL
);
865 signal_add(&evsigterm
, NULL
);
866 signal_add(&evsighup
, NULL
);
867 signal_add(&evsigusr1
, NULL
);
869 gotd_session
.state
= GOTD_STATE_EXPECT_LIST_REFS
;
871 gotd_session_client
.fd
= -1;
872 gotd_session_client
.nref_updates
= -1;
873 gotd_session_client
.delta_cache_fd
= -1;
874 gotd_session_client
.accept_flush_pkt
= 1;
876 imsg_init(&gotd_session
.parent_iev
.ibuf
, GOTD_FILENO_MSG_PIPE
);
877 gotd_session
.parent_iev
.handler
= session_dispatch
;
878 gotd_session
.parent_iev
.events
= EV_READ
;
879 gotd_session
.parent_iev
.handler_arg
= NULL
;
880 event_set(&gotd_session
.parent_iev
.ev
, gotd_session
.parent_iev
.ibuf
.fd
,
881 EV_READ
, session_dispatch
, &gotd_session
.parent_iev
);
882 if (gotd_imsg_compose_event(&gotd_session
.parent_iev
,
883 GOTD_IMSG_CLIENT_SESSION_READY
, PROC_SESSION_READ
,
884 -1, NULL
, 0) == -1) {
885 err
= got_error_from_errno("imsg compose CLIENT_SESSION_READY");
892 log_warnx("%s: %s", title
, err
->msg
);
893 session_read_shutdown();
897 session_read_shutdown(void)
899 log_debug("%s: shutting down", gotd_session
.title
);
901 if (gotd_session
.repo
)
902 got_repo_close(gotd_session
.repo
);
903 got_repo_pack_fds_close(gotd_session
.pack_fds
);
904 got_repo_temp_fds_close(gotd_session
.temp_fds
);
905 free(gotd_session_client
.username
);