Blame


1 ae7c1b78 2023-01-10 stsp /*
2 ae7c1b78 2023-01-10 stsp * Copyright (c) 2022, 2023 Stefan Sperling <stsp@openbsd.org>
3 ae7c1b78 2023-01-10 stsp *
4 ae7c1b78 2023-01-10 stsp * Permission to use, copy, modify, and distribute this software for any
5 ae7c1b78 2023-01-10 stsp * purpose with or without fee is hereby granted, provided that the above
6 ae7c1b78 2023-01-10 stsp * copyright notice and this permission notice appear in all copies.
7 ae7c1b78 2023-01-10 stsp *
8 ae7c1b78 2023-01-10 stsp * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 ae7c1b78 2023-01-10 stsp * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 ae7c1b78 2023-01-10 stsp * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 ae7c1b78 2023-01-10 stsp * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 ae7c1b78 2023-01-10 stsp * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 ae7c1b78 2023-01-10 stsp * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 ae7c1b78 2023-01-10 stsp * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 ae7c1b78 2023-01-10 stsp */
16 ae7c1b78 2023-01-10 stsp
17 ae7c1b78 2023-01-10 stsp #include <sys/types.h>
18 ae7c1b78 2023-01-10 stsp #include <sys/queue.h>
19 ae7c1b78 2023-01-10 stsp #include <sys/tree.h>
20 ae7c1b78 2023-01-10 stsp #include <sys/socket.h>
21 839bbaae 2023-02-01 op #include <sys/stat.h>
22 ae7c1b78 2023-01-10 stsp #include <sys/uio.h>
23 ae7c1b78 2023-01-10 stsp
24 ae7c1b78 2023-01-10 stsp #include <errno.h>
25 ae7c1b78 2023-01-10 stsp #include <event.h>
26 ae7c1b78 2023-01-10 stsp #include <limits.h>
27 ae7c1b78 2023-01-10 stsp #include <sha1.h>
28 5822e79e 2023-02-23 op #include <sha2.h>
29 ae7c1b78 2023-01-10 stsp #include <signal.h>
30 ae7c1b78 2023-01-10 stsp #include <stdint.h>
31 ae7c1b78 2023-01-10 stsp #include <stdio.h>
32 ae7c1b78 2023-01-10 stsp #include <stdlib.h>
33 ae7c1b78 2023-01-10 stsp #include <string.h>
34 ae7c1b78 2023-01-10 stsp #include <imsg.h>
35 ae7c1b78 2023-01-10 stsp #include <unistd.h>
36 ae7c1b78 2023-01-10 stsp
37 ae7c1b78 2023-01-10 stsp #include "got_error.h"
38 ae7c1b78 2023-01-10 stsp #include "got_repository.h"
39 ae7c1b78 2023-01-10 stsp #include "got_object.h"
40 ae7c1b78 2023-01-10 stsp #include "got_path.h"
41 ae7c1b78 2023-01-10 stsp #include "got_reference.h"
42 ae7c1b78 2023-01-10 stsp #include "got_opentemp.h"
43 ae7c1b78 2023-01-10 stsp
44 53bf0b54 2023-02-23 op #include "got_lib_hash.h"
45 ae7c1b78 2023-01-10 stsp #include "got_lib_delta.h"
46 ae7c1b78 2023-01-10 stsp #include "got_lib_object.h"
47 ae7c1b78 2023-01-10 stsp #include "got_lib_object_cache.h"
48 ae7c1b78 2023-01-10 stsp #include "got_lib_pack.h"
49 ae7c1b78 2023-01-10 stsp #include "got_lib_repository.h"
50 ae7c1b78 2023-01-10 stsp #include "got_lib_gitproto.h"
51 ae7c1b78 2023-01-10 stsp
52 ae7c1b78 2023-01-10 stsp #include "gotd.h"
53 ae7c1b78 2023-01-10 stsp #include "log.h"
54 ae7c1b78 2023-01-10 stsp #include "session.h"
55 ae7c1b78 2023-01-10 stsp
56 ba97b2d7 2024-03-20 stsp struct gotd_session_notif {
57 ba97b2d7 2024-03-20 stsp STAILQ_ENTRY(gotd_session_notif) entry;
58 ba97b2d7 2024-03-20 stsp int fd;
59 ba97b2d7 2024-03-20 stsp enum gotd_notification_action action;
60 ba97b2d7 2024-03-20 stsp char *refname;
61 ba97b2d7 2024-03-20 stsp struct got_object_id old_id;
62 ba97b2d7 2024-03-20 stsp struct got_object_id new_id;
63 ba97b2d7 2024-03-20 stsp };
64 ba97b2d7 2024-03-20 stsp STAILQ_HEAD(gotd_session_notifications, gotd_session_notif) notifications;
65 ae7c1b78 2023-01-10 stsp
66 ae7c1b78 2023-01-10 stsp static struct gotd_session {
67 ae7c1b78 2023-01-10 stsp pid_t pid;
68 ae7c1b78 2023-01-10 stsp const char *title;
69 ae7c1b78 2023-01-10 stsp struct got_repository *repo;
70 ba97b2d7 2024-03-20 stsp struct gotd_repo *repo_cfg;
71 ae7c1b78 2023-01-10 stsp int *pack_fds;
72 ae7c1b78 2023-01-10 stsp int *temp_fds;
73 ae7c1b78 2023-01-10 stsp struct gotd_imsgev parent_iev;
74 ba97b2d7 2024-03-20 stsp struct gotd_imsgev notifier_iev;
75 ae7c1b78 2023-01-10 stsp struct timeval request_timeout;
76 b0614828 2023-06-19 stsp enum gotd_procid proc_id;
77 ae7c1b78 2023-01-10 stsp } gotd_session;
78 ae7c1b78 2023-01-10 stsp
79 ae7c1b78 2023-01-10 stsp static struct gotd_session_client {
80 eac23c30 2023-01-10 stsp enum gotd_session_state state;
81 ae7c1b78 2023-01-10 stsp int is_writing;
82 ae7c1b78 2023-01-10 stsp struct gotd_client_capability *capabilities;
83 ae7c1b78 2023-01-10 stsp size_t ncapa_alloc;
84 ae7c1b78 2023-01-10 stsp size_t ncapabilities;
85 ae7c1b78 2023-01-10 stsp uint32_t id;
86 ae7c1b78 2023-01-10 stsp int fd;
87 ae7c1b78 2023-01-10 stsp int delta_cache_fd;
88 ae7c1b78 2023-01-10 stsp struct gotd_imsgev iev;
89 ae7c1b78 2023-01-10 stsp struct gotd_imsgev repo_child_iev;
90 ae7c1b78 2023-01-10 stsp struct event tmo;
91 ae7c1b78 2023-01-10 stsp uid_t euid;
92 ae7c1b78 2023-01-10 stsp gid_t egid;
93 ba97b2d7 2024-03-20 stsp char *username;
94 ae7c1b78 2023-01-10 stsp char *packfile_path;
95 ae7c1b78 2023-01-10 stsp char *packidx_path;
96 ae7c1b78 2023-01-10 stsp int nref_updates;
97 3448a19a 2023-01-21 stsp int accept_flush_pkt;
98 808264b2 2023-08-22 stsp int flush_disconnect;
99 ae7c1b78 2023-01-10 stsp } gotd_session_client;
100 ae7c1b78 2023-01-10 stsp
101 ae7c1b78 2023-01-10 stsp void gotd_session_sighdlr(int sig, short event, void *arg);
102 ae7c1b78 2023-01-10 stsp static void gotd_session_shutdown(void);
103 ae7c1b78 2023-01-10 stsp
104 ae7c1b78 2023-01-10 stsp static void
105 ae7c1b78 2023-01-10 stsp disconnect(struct gotd_session_client *client)
106 ae7c1b78 2023-01-10 stsp {
107 ae7c1b78 2023-01-10 stsp log_debug("uid %d: disconnecting", client->euid);
108 ae7c1b78 2023-01-10 stsp
109 ae7c1b78 2023-01-10 stsp if (gotd_imsg_compose_event(&gotd_session.parent_iev,
110 b0614828 2023-06-19 stsp GOTD_IMSG_DISCONNECT, gotd_session.proc_id, -1, NULL, 0) == -1)
111 ae7c1b78 2023-01-10 stsp log_warn("imsg compose DISCONNECT");
112 ae7c1b78 2023-01-10 stsp
113 ae7c1b78 2023-01-10 stsp imsg_clear(&client->repo_child_iev.ibuf);
114 ae7c1b78 2023-01-10 stsp event_del(&client->repo_child_iev.ev);
115 ae7c1b78 2023-01-10 stsp evtimer_del(&client->tmo);
116 ae7c1b78 2023-01-10 stsp close(client->fd);
117 ae7c1b78 2023-01-10 stsp if (client->delta_cache_fd != -1)
118 ae7c1b78 2023-01-10 stsp close(client->delta_cache_fd);
119 ae7c1b78 2023-01-10 stsp if (client->packfile_path) {
120 ae7c1b78 2023-01-10 stsp if (unlink(client->packfile_path) == -1 && errno != ENOENT)
121 ae7c1b78 2023-01-10 stsp log_warn("unlink %s: ", client->packfile_path);
122 ae7c1b78 2023-01-10 stsp free(client->packfile_path);
123 ae7c1b78 2023-01-10 stsp }
124 ae7c1b78 2023-01-10 stsp if (client->packidx_path) {
125 ae7c1b78 2023-01-10 stsp if (unlink(client->packidx_path) == -1 && errno != ENOENT)
126 ae7c1b78 2023-01-10 stsp log_warn("unlink %s: ", client->packidx_path);
127 ae7c1b78 2023-01-10 stsp free(client->packidx_path);
128 ae7c1b78 2023-01-10 stsp }
129 ae7c1b78 2023-01-10 stsp free(client->capabilities);
130 ae7c1b78 2023-01-10 stsp
131 ae7c1b78 2023-01-10 stsp gotd_session_shutdown();
132 ae7c1b78 2023-01-10 stsp }
133 ae7c1b78 2023-01-10 stsp
134 ae7c1b78 2023-01-10 stsp static void
135 ae7c1b78 2023-01-10 stsp disconnect_on_error(struct gotd_session_client *client,
136 ae7c1b78 2023-01-10 stsp const struct got_error *err)
137 ae7c1b78 2023-01-10 stsp {
138 ae7c1b78 2023-01-10 stsp struct imsgbuf ibuf;
139 ae7c1b78 2023-01-10 stsp
140 ae7c1b78 2023-01-10 stsp if (err->code != GOT_ERR_EOF) {
141 1050403b 2023-08-11 stsp log_warnx("uid %d: %s", client->euid, err->msg);
142 ae7c1b78 2023-01-10 stsp imsg_init(&ibuf, client->fd);
143 b0614828 2023-06-19 stsp gotd_imsg_send_error(&ibuf, 0, gotd_session.proc_id, err);
144 ae7c1b78 2023-01-10 stsp imsg_clear(&ibuf);
145 ae7c1b78 2023-01-10 stsp }
146 ae7c1b78 2023-01-10 stsp
147 ae7c1b78 2023-01-10 stsp disconnect(client);
148 ae7c1b78 2023-01-10 stsp }
149 ae7c1b78 2023-01-10 stsp
150 ae7c1b78 2023-01-10 stsp static void
151 ae7c1b78 2023-01-10 stsp gotd_request_timeout(int fd, short events, void *arg)
152 ae7c1b78 2023-01-10 stsp {
153 ae7c1b78 2023-01-10 stsp struct gotd_session_client *client = arg;
154 ae7c1b78 2023-01-10 stsp
155 ae7c1b78 2023-01-10 stsp log_debug("disconnecting uid %d due to timeout", client->euid);
156 ae7c1b78 2023-01-10 stsp disconnect(client);
157 ae7c1b78 2023-01-10 stsp }
158 ae7c1b78 2023-01-10 stsp
159 ae7c1b78 2023-01-10 stsp void
160 ae7c1b78 2023-01-10 stsp gotd_session_sighdlr(int sig, short event, void *arg)
161 ae7c1b78 2023-01-10 stsp {
162 ae7c1b78 2023-01-10 stsp /*
163 ae7c1b78 2023-01-10 stsp * Normal signal handler rules don't apply because libevent
164 ae7c1b78 2023-01-10 stsp * decouples for us.
165 ae7c1b78 2023-01-10 stsp */
166 ae7c1b78 2023-01-10 stsp
167 ae7c1b78 2023-01-10 stsp switch (sig) {
168 ae7c1b78 2023-01-10 stsp case SIGHUP:
169 ae7c1b78 2023-01-10 stsp log_info("%s: ignoring SIGHUP", __func__);
170 ae7c1b78 2023-01-10 stsp break;
171 ae7c1b78 2023-01-10 stsp case SIGUSR1:
172 ae7c1b78 2023-01-10 stsp log_info("%s: ignoring SIGUSR1", __func__);
173 ae7c1b78 2023-01-10 stsp break;
174 ae7c1b78 2023-01-10 stsp case SIGTERM:
175 ae7c1b78 2023-01-10 stsp case SIGINT:
176 ae7c1b78 2023-01-10 stsp gotd_session_shutdown();
177 ae7c1b78 2023-01-10 stsp /* NOTREACHED */
178 ae7c1b78 2023-01-10 stsp break;
179 ae7c1b78 2023-01-10 stsp default:
180 ae7c1b78 2023-01-10 stsp fatalx("unexpected signal");
181 ae7c1b78 2023-01-10 stsp }
182 ae7c1b78 2023-01-10 stsp }
183 ae7c1b78 2023-01-10 stsp
184 ae7c1b78 2023-01-10 stsp static const struct got_error *
185 ae7c1b78 2023-01-10 stsp recv_packfile_done(uint32_t *client_id, struct imsg *imsg)
186 ae7c1b78 2023-01-10 stsp {
187 ae7c1b78 2023-01-10 stsp struct gotd_imsg_packfile_done idone;
188 ae7c1b78 2023-01-10 stsp size_t datalen;
189 ae7c1b78 2023-01-10 stsp
190 ae7c1b78 2023-01-10 stsp log_debug("packfile-done received");
191 ae7c1b78 2023-01-10 stsp
192 ae7c1b78 2023-01-10 stsp datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
193 ae7c1b78 2023-01-10 stsp if (datalen != sizeof(idone))
194 ae7c1b78 2023-01-10 stsp return got_error(GOT_ERR_PRIVSEP_LEN);
195 ae7c1b78 2023-01-10 stsp memcpy(&idone, imsg->data, sizeof(idone));
196 ae7c1b78 2023-01-10 stsp
197 ae7c1b78 2023-01-10 stsp *client_id = idone.client_id;
198 ae7c1b78 2023-01-10 stsp return NULL;
199 ae7c1b78 2023-01-10 stsp }
200 ae7c1b78 2023-01-10 stsp
201 ae7c1b78 2023-01-10 stsp static const struct got_error *
202 ae7c1b78 2023-01-10 stsp recv_packfile_install(uint32_t *client_id, struct imsg *imsg)
203 ae7c1b78 2023-01-10 stsp {
204 ae7c1b78 2023-01-10 stsp struct gotd_imsg_packfile_install inst;
205 ae7c1b78 2023-01-10 stsp size_t datalen;
206 ae7c1b78 2023-01-10 stsp
207 ae7c1b78 2023-01-10 stsp log_debug("packfile-install received");
208 ae7c1b78 2023-01-10 stsp
209 ae7c1b78 2023-01-10 stsp datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
210 ae7c1b78 2023-01-10 stsp if (datalen != sizeof(inst))
211 ae7c1b78 2023-01-10 stsp return got_error(GOT_ERR_PRIVSEP_LEN);
212 ae7c1b78 2023-01-10 stsp memcpy(&inst, imsg->data, sizeof(inst));
213 ae7c1b78 2023-01-10 stsp
214 ae7c1b78 2023-01-10 stsp *client_id = inst.client_id;
215 ae7c1b78 2023-01-10 stsp return NULL;
216 ae7c1b78 2023-01-10 stsp }
217 ae7c1b78 2023-01-10 stsp
218 ae7c1b78 2023-01-10 stsp static const struct got_error *
219 ae7c1b78 2023-01-10 stsp recv_ref_updates_start(uint32_t *client_id, struct imsg *imsg)
220 ae7c1b78 2023-01-10 stsp {
221 ae7c1b78 2023-01-10 stsp struct gotd_imsg_ref_updates_start istart;
222 ae7c1b78 2023-01-10 stsp size_t datalen;
223 ae7c1b78 2023-01-10 stsp
224 ae7c1b78 2023-01-10 stsp log_debug("ref-updates-start received");
225 ae7c1b78 2023-01-10 stsp
226 ae7c1b78 2023-01-10 stsp datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
227 ae7c1b78 2023-01-10 stsp if (datalen != sizeof(istart))
228 ae7c1b78 2023-01-10 stsp return got_error(GOT_ERR_PRIVSEP_LEN);
229 ae7c1b78 2023-01-10 stsp memcpy(&istart, imsg->data, sizeof(istart));
230 ae7c1b78 2023-01-10 stsp
231 ae7c1b78 2023-01-10 stsp *client_id = istart.client_id;
232 ae7c1b78 2023-01-10 stsp return NULL;
233 ae7c1b78 2023-01-10 stsp }
234 ae7c1b78 2023-01-10 stsp
235 ae7c1b78 2023-01-10 stsp static const struct got_error *
236 ae7c1b78 2023-01-10 stsp recv_ref_update(uint32_t *client_id, struct imsg *imsg)
237 ae7c1b78 2023-01-10 stsp {
238 ae7c1b78 2023-01-10 stsp struct gotd_imsg_ref_update iref;
239 ae7c1b78 2023-01-10 stsp size_t datalen;
240 ae7c1b78 2023-01-10 stsp
241 ae7c1b78 2023-01-10 stsp log_debug("ref-update received");
242 ae7c1b78 2023-01-10 stsp
243 ae7c1b78 2023-01-10 stsp datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
244 ae7c1b78 2023-01-10 stsp if (datalen < sizeof(iref))
245 ae7c1b78 2023-01-10 stsp return got_error(GOT_ERR_PRIVSEP_LEN);
246 ae7c1b78 2023-01-10 stsp memcpy(&iref, imsg->data, sizeof(iref));
247 ae7c1b78 2023-01-10 stsp
248 ae7c1b78 2023-01-10 stsp *client_id = iref.client_id;
249 ae7c1b78 2023-01-10 stsp return NULL;
250 ae7c1b78 2023-01-10 stsp }
251 ae7c1b78 2023-01-10 stsp
252 ae7c1b78 2023-01-10 stsp static const struct got_error *
253 ae7c1b78 2023-01-10 stsp send_ref_update_ok(struct gotd_session_client *client,
254 ae7c1b78 2023-01-10 stsp struct gotd_imsg_ref_update *iref, const char *refname)
255 ae7c1b78 2023-01-10 stsp {
256 ae7c1b78 2023-01-10 stsp struct gotd_imsg_ref_update_ok iok;
257 ae7c1b78 2023-01-10 stsp struct gotd_imsgev *iev = &client->iev;
258 ae7c1b78 2023-01-10 stsp struct ibuf *wbuf;
259 ae7c1b78 2023-01-10 stsp size_t len;
260 ae7c1b78 2023-01-10 stsp
261 ae7c1b78 2023-01-10 stsp memset(&iok, 0, sizeof(iok));
262 ae7c1b78 2023-01-10 stsp iok.client_id = client->id;
263 ae7c1b78 2023-01-10 stsp memcpy(iok.old_id, iref->old_id, SHA1_DIGEST_LENGTH);
264 ae7c1b78 2023-01-10 stsp memcpy(iok.new_id, iref->new_id, SHA1_DIGEST_LENGTH);
265 ae7c1b78 2023-01-10 stsp iok.name_len = strlen(refname);
266 ae7c1b78 2023-01-10 stsp
267 ae7c1b78 2023-01-10 stsp len = sizeof(iok) + iok.name_len;
268 ae7c1b78 2023-01-10 stsp wbuf = imsg_create(&iev->ibuf, GOTD_IMSG_REF_UPDATE_OK,
269 b0614828 2023-06-19 stsp gotd_session.proc_id, gotd_session.pid, len);
270 ae7c1b78 2023-01-10 stsp if (wbuf == NULL)
271 ae7c1b78 2023-01-10 stsp return got_error_from_errno("imsg_create REF_UPDATE_OK");
272 ae7c1b78 2023-01-10 stsp
273 ae7c1b78 2023-01-10 stsp if (imsg_add(wbuf, &iok, sizeof(iok)) == -1)
274 ae7c1b78 2023-01-10 stsp return got_error_from_errno("imsg_add REF_UPDATE_OK");
275 ae7c1b78 2023-01-10 stsp if (imsg_add(wbuf, refname, iok.name_len) == -1)
276 ae7c1b78 2023-01-10 stsp return got_error_from_errno("imsg_add REF_UPDATE_OK");
277 ae7c1b78 2023-01-10 stsp
278 ae7c1b78 2023-01-10 stsp imsg_close(&iev->ibuf, wbuf);
279 ae7c1b78 2023-01-10 stsp gotd_imsg_event_add(iev);
280 ae7c1b78 2023-01-10 stsp return NULL;
281 ae7c1b78 2023-01-10 stsp }
282 ae7c1b78 2023-01-10 stsp
283 ae7c1b78 2023-01-10 stsp static void
284 ae7c1b78 2023-01-10 stsp send_refs_updated(struct gotd_session_client *client)
285 ae7c1b78 2023-01-10 stsp {
286 ae7c1b78 2023-01-10 stsp if (gotd_imsg_compose_event(&client->iev, GOTD_IMSG_REFS_UPDATED,
287 b0614828 2023-06-19 stsp gotd_session.proc_id, -1, NULL, 0) == -1)
288 ae7c1b78 2023-01-10 stsp log_warn("imsg compose REFS_UPDATED");
289 ae7c1b78 2023-01-10 stsp }
290 ae7c1b78 2023-01-10 stsp
291 ae7c1b78 2023-01-10 stsp static const struct got_error *
292 ae7c1b78 2023-01-10 stsp send_ref_update_ng(struct gotd_session_client *client,
293 ae7c1b78 2023-01-10 stsp struct gotd_imsg_ref_update *iref, const char *refname,
294 ae7c1b78 2023-01-10 stsp const char *reason)
295 ae7c1b78 2023-01-10 stsp {
296 ae7c1b78 2023-01-10 stsp const struct got_error *ng_err;
297 ae7c1b78 2023-01-10 stsp struct gotd_imsg_ref_update_ng ing;
298 ae7c1b78 2023-01-10 stsp struct gotd_imsgev *iev = &client->iev;
299 ae7c1b78 2023-01-10 stsp struct ibuf *wbuf;
300 ae7c1b78 2023-01-10 stsp size_t len;
301 ae7c1b78 2023-01-10 stsp
302 ae7c1b78 2023-01-10 stsp memset(&ing, 0, sizeof(ing));
303 ae7c1b78 2023-01-10 stsp ing.client_id = client->id;
304 ae7c1b78 2023-01-10 stsp memcpy(ing.old_id, iref->old_id, SHA1_DIGEST_LENGTH);
305 ae7c1b78 2023-01-10 stsp memcpy(ing.new_id, iref->new_id, SHA1_DIGEST_LENGTH);
306 ae7c1b78 2023-01-10 stsp ing.name_len = strlen(refname);
307 ae7c1b78 2023-01-10 stsp
308 ae7c1b78 2023-01-10 stsp ng_err = got_error_fmt(GOT_ERR_REF_BUSY, "%s", reason);
309 ae7c1b78 2023-01-10 stsp ing.reason_len = strlen(ng_err->msg);
310 ae7c1b78 2023-01-10 stsp
311 ae7c1b78 2023-01-10 stsp len = sizeof(ing) + ing.name_len + ing.reason_len;
312 ae7c1b78 2023-01-10 stsp wbuf = imsg_create(&iev->ibuf, GOTD_IMSG_REF_UPDATE_NG,
313 b0614828 2023-06-19 stsp gotd_session.proc_id, gotd_session.pid, len);
314 ae7c1b78 2023-01-10 stsp if (wbuf == NULL)
315 ae7c1b78 2023-01-10 stsp return got_error_from_errno("imsg_create REF_UPDATE_NG");
316 ae7c1b78 2023-01-10 stsp
317 ae7c1b78 2023-01-10 stsp if (imsg_add(wbuf, &ing, sizeof(ing)) == -1)
318 ae7c1b78 2023-01-10 stsp return got_error_from_errno("imsg_add REF_UPDATE_NG");
319 ae7c1b78 2023-01-10 stsp if (imsg_add(wbuf, refname, ing.name_len) == -1)
320 ae7c1b78 2023-01-10 stsp return got_error_from_errno("imsg_add REF_UPDATE_NG");
321 ae7c1b78 2023-01-10 stsp if (imsg_add(wbuf, ng_err->msg, ing.reason_len) == -1)
322 ae7c1b78 2023-01-10 stsp return got_error_from_errno("imsg_add REF_UPDATE_NG");
323 ae7c1b78 2023-01-10 stsp
324 ae7c1b78 2023-01-10 stsp imsg_close(&iev->ibuf, wbuf);
325 ae7c1b78 2023-01-10 stsp gotd_imsg_event_add(iev);
326 ae7c1b78 2023-01-10 stsp return NULL;
327 ae7c1b78 2023-01-10 stsp }
328 ae7c1b78 2023-01-10 stsp
329 ae7c1b78 2023-01-10 stsp static const struct got_error *
330 ae7c1b78 2023-01-10 stsp install_pack(struct gotd_session_client *client, const char *repo_path,
331 ae7c1b78 2023-01-10 stsp struct imsg *imsg)
332 ae7c1b78 2023-01-10 stsp {
333 ae7c1b78 2023-01-10 stsp const struct got_error *err = NULL;
334 ae7c1b78 2023-01-10 stsp struct gotd_imsg_packfile_install inst;
335 ae7c1b78 2023-01-10 stsp char hex[SHA1_DIGEST_STRING_LENGTH];
336 ae7c1b78 2023-01-10 stsp size_t datalen;
337 ae7c1b78 2023-01-10 stsp char *packfile_path = NULL, *packidx_path = NULL;
338 ae7c1b78 2023-01-10 stsp
339 ae7c1b78 2023-01-10 stsp datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
340 ae7c1b78 2023-01-10 stsp if (datalen != sizeof(inst))
341 ae7c1b78 2023-01-10 stsp return got_error(GOT_ERR_PRIVSEP_LEN);
342 ae7c1b78 2023-01-10 stsp memcpy(&inst, imsg->data, sizeof(inst));
343 ae7c1b78 2023-01-10 stsp
344 ae7c1b78 2023-01-10 stsp if (client->packfile_path == NULL)
345 ae7c1b78 2023-01-10 stsp return got_error_msg(GOT_ERR_BAD_REQUEST,
346 ae7c1b78 2023-01-10 stsp "client has no pack file");
347 ae7c1b78 2023-01-10 stsp if (client->packidx_path == NULL)
348 ae7c1b78 2023-01-10 stsp return got_error_msg(GOT_ERR_BAD_REQUEST,
349 ae7c1b78 2023-01-10 stsp "client has no pack file index");
350 ae7c1b78 2023-01-10 stsp
351 ae7c1b78 2023-01-10 stsp if (got_sha1_digest_to_str(inst.pack_sha1, hex, sizeof(hex)) == NULL)
352 ae7c1b78 2023-01-10 stsp return got_error_msg(GOT_ERR_NO_SPACE,
353 ae7c1b78 2023-01-10 stsp "could not convert pack file SHA1 to hex");
354 ae7c1b78 2023-01-10 stsp
355 ae7c1b78 2023-01-10 stsp if (asprintf(&packfile_path, "/%s/%s/pack-%s.pack",
356 ae7c1b78 2023-01-10 stsp repo_path, GOT_OBJECTS_PACK_DIR, hex) == -1) {
357 ae7c1b78 2023-01-10 stsp err = got_error_from_errno("asprintf");
358 ae7c1b78 2023-01-10 stsp goto done;
359 ae7c1b78 2023-01-10 stsp }
360 ae7c1b78 2023-01-10 stsp
361 ae7c1b78 2023-01-10 stsp if (asprintf(&packidx_path, "/%s/%s/pack-%s.idx",
362 ae7c1b78 2023-01-10 stsp repo_path, GOT_OBJECTS_PACK_DIR, hex) == -1) {
363 ae7c1b78 2023-01-10 stsp err = got_error_from_errno("asprintf");
364 ae7c1b78 2023-01-10 stsp goto done;
365 ae7c1b78 2023-01-10 stsp }
366 ae7c1b78 2023-01-10 stsp
367 ae7c1b78 2023-01-10 stsp if (rename(client->packfile_path, packfile_path) == -1) {
368 ae7c1b78 2023-01-10 stsp err = got_error_from_errno3("rename", client->packfile_path,
369 ae7c1b78 2023-01-10 stsp packfile_path);
370 ae7c1b78 2023-01-10 stsp goto done;
371 ae7c1b78 2023-01-10 stsp }
372 ae7c1b78 2023-01-10 stsp
373 ae7c1b78 2023-01-10 stsp free(client->packfile_path);
374 ae7c1b78 2023-01-10 stsp client->packfile_path = NULL;
375 ae7c1b78 2023-01-10 stsp
376 ae7c1b78 2023-01-10 stsp if (rename(client->packidx_path, packidx_path) == -1) {
377 ae7c1b78 2023-01-10 stsp err = got_error_from_errno3("rename", client->packidx_path,
378 ae7c1b78 2023-01-10 stsp packidx_path);
379 ae7c1b78 2023-01-10 stsp goto done;
380 ae7c1b78 2023-01-10 stsp }
381 30a624fb 2024-03-19 stsp
382 30a624fb 2024-03-19 stsp /* Ensure we re-read the pack index list upon next access. */
383 30a624fb 2024-03-19 stsp gotd_session.repo->pack_path_mtime.tv_sec = 0;
384 30a624fb 2024-03-19 stsp gotd_session.repo->pack_path_mtime.tv_nsec = 0;
385 ae7c1b78 2023-01-10 stsp
386 ae7c1b78 2023-01-10 stsp free(client->packidx_path);
387 ae7c1b78 2023-01-10 stsp client->packidx_path = NULL;
388 ae7c1b78 2023-01-10 stsp done:
389 ae7c1b78 2023-01-10 stsp free(packfile_path);
390 ae7c1b78 2023-01-10 stsp free(packidx_path);
391 ae7c1b78 2023-01-10 stsp return err;
392 ae7c1b78 2023-01-10 stsp }
393 ae7c1b78 2023-01-10 stsp
394 ae7c1b78 2023-01-10 stsp static const struct got_error *
395 ae7c1b78 2023-01-10 stsp begin_ref_updates(struct gotd_session_client *client, struct imsg *imsg)
396 ae7c1b78 2023-01-10 stsp {
397 ae7c1b78 2023-01-10 stsp struct gotd_imsg_ref_updates_start istart;
398 ae7c1b78 2023-01-10 stsp size_t datalen;
399 ae7c1b78 2023-01-10 stsp
400 ae7c1b78 2023-01-10 stsp if (client->nref_updates != -1)
401 ae7c1b78 2023-01-10 stsp return got_error(GOT_ERR_PRIVSEP_MSG);
402 ae7c1b78 2023-01-10 stsp
403 ae7c1b78 2023-01-10 stsp datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
404 ae7c1b78 2023-01-10 stsp if (datalen != sizeof(istart))
405 ae7c1b78 2023-01-10 stsp return got_error(GOT_ERR_PRIVSEP_LEN);
406 ae7c1b78 2023-01-10 stsp memcpy(&istart, imsg->data, sizeof(istart));
407 ae7c1b78 2023-01-10 stsp
408 ae7c1b78 2023-01-10 stsp if (istart.nref_updates <= 0)
409 ae7c1b78 2023-01-10 stsp return got_error(GOT_ERR_PRIVSEP_MSG);
410 ae7c1b78 2023-01-10 stsp
411 ae7c1b78 2023-01-10 stsp client->nref_updates = istart.nref_updates;
412 ba97b2d7 2024-03-20 stsp return NULL;
413 ba97b2d7 2024-03-20 stsp }
414 ba97b2d7 2024-03-20 stsp
415 ba97b2d7 2024-03-20 stsp static const struct got_error *
416 ba97b2d7 2024-03-20 stsp validate_namespace(const char *namespace)
417 ba97b2d7 2024-03-20 stsp {
418 ba97b2d7 2024-03-20 stsp size_t len = strlen(namespace);
419 ba97b2d7 2024-03-20 stsp
420 ba97b2d7 2024-03-20 stsp if (len < 5 || strncmp("refs/", namespace, 5) != 0 ||
421 ba97b2d7 2024-03-20 stsp namespace[len - 1] != '/') {
422 ba97b2d7 2024-03-20 stsp return got_error_fmt(GOT_ERR_BAD_REF_NAME,
423 ba97b2d7 2024-03-20 stsp "reference namespace '%s'", namespace);
424 ba97b2d7 2024-03-20 stsp }
425 ba97b2d7 2024-03-20 stsp
426 ae7c1b78 2023-01-10 stsp return NULL;
427 ae7c1b78 2023-01-10 stsp }
428 ae7c1b78 2023-01-10 stsp
429 ae7c1b78 2023-01-10 stsp static const struct got_error *
430 ba97b2d7 2024-03-20 stsp queue_notification(struct got_object_id *old_id, struct got_object_id *new_id,
431 ba97b2d7 2024-03-20 stsp struct got_repository *repo, struct got_reference *ref)
432 ba97b2d7 2024-03-20 stsp {
433 ba97b2d7 2024-03-20 stsp const struct got_error *err = NULL;
434 ba97b2d7 2024-03-20 stsp struct gotd_session_client *client = &gotd_session_client;
435 ba97b2d7 2024-03-20 stsp struct gotd_repo *repo_cfg = gotd_session.repo_cfg;
436 ba97b2d7 2024-03-20 stsp struct gotd_imsgev *iev = &client->repo_child_iev;
437 ba97b2d7 2024-03-20 stsp struct got_pathlist_entry *pe;
438 ba97b2d7 2024-03-20 stsp struct gotd_session_notif *notif;
439 ba97b2d7 2024-03-20 stsp
440 ba97b2d7 2024-03-20 stsp if (iev->ibuf.fd == -1 ||
441 ba97b2d7 2024-03-20 stsp STAILQ_EMPTY(&repo_cfg->notification_targets))
442 ba97b2d7 2024-03-20 stsp return NULL; /* notifications unused */
443 ba97b2d7 2024-03-20 stsp
444 ba97b2d7 2024-03-20 stsp TAILQ_FOREACH(pe, &repo_cfg->notification_refs, entry) {
445 ba97b2d7 2024-03-20 stsp const char *refname = pe->path;
446 ba97b2d7 2024-03-20 stsp if (strcmp(got_ref_get_name(ref), refname) == 0)
447 ba97b2d7 2024-03-20 stsp break;
448 ba97b2d7 2024-03-20 stsp }
449 ba97b2d7 2024-03-20 stsp if (pe == NULL) {
450 ba97b2d7 2024-03-20 stsp TAILQ_FOREACH(pe, &repo_cfg->notification_ref_namespaces,
451 ba97b2d7 2024-03-20 stsp entry) {
452 ba97b2d7 2024-03-20 stsp const char *namespace = pe->path;
453 ba97b2d7 2024-03-20 stsp
454 ba97b2d7 2024-03-20 stsp err = validate_namespace(namespace);
455 ba97b2d7 2024-03-20 stsp if (err)
456 ba97b2d7 2024-03-20 stsp return err;
457 ba97b2d7 2024-03-20 stsp if (strncmp(namespace, got_ref_get_name(ref),
458 ba97b2d7 2024-03-20 stsp strlen(namespace)) == 0)
459 ba97b2d7 2024-03-20 stsp break;
460 ba97b2d7 2024-03-20 stsp }
461 ba97b2d7 2024-03-20 stsp }
462 ba97b2d7 2024-03-20 stsp
463 ba97b2d7 2024-03-20 stsp /*
464 ba97b2d7 2024-03-20 stsp * If a branch or a reference namespace was specified in the
465 ba97b2d7 2024-03-20 stsp * configuration file then only send notifications if a match
466 ba97b2d7 2024-03-20 stsp * was found.
467 ba97b2d7 2024-03-20 stsp */
468 ba97b2d7 2024-03-20 stsp if (pe == NULL && (!TAILQ_EMPTY(&repo_cfg->notification_refs) ||
469 ba97b2d7 2024-03-20 stsp !TAILQ_EMPTY(&repo_cfg->notification_ref_namespaces)))
470 ba97b2d7 2024-03-20 stsp return NULL;
471 ba97b2d7 2024-03-20 stsp
472 ba97b2d7 2024-03-20 stsp notif = calloc(1, sizeof(*notif));
473 ba97b2d7 2024-03-20 stsp if (notif == NULL)
474 ba97b2d7 2024-03-20 stsp return got_error_from_errno("calloc");
475 ba97b2d7 2024-03-20 stsp
476 ba97b2d7 2024-03-20 stsp notif->fd = -1;
477 ba97b2d7 2024-03-20 stsp
478 ba97b2d7 2024-03-20 stsp if (old_id == NULL)
479 ba97b2d7 2024-03-20 stsp notif->action = GOTD_NOTIF_ACTION_CREATED;
480 ba97b2d7 2024-03-20 stsp else if (new_id == NULL)
481 ba97b2d7 2024-03-20 stsp notif->action = GOTD_NOTIF_ACTION_REMOVED;
482 ba97b2d7 2024-03-20 stsp else
483 ba97b2d7 2024-03-20 stsp notif->action = GOTD_NOTIF_ACTION_CHANGED;
484 ba97b2d7 2024-03-20 stsp
485 ba97b2d7 2024-03-20 stsp if (old_id != NULL)
486 ba97b2d7 2024-03-20 stsp memcpy(&notif->old_id, old_id, sizeof(notif->old_id));
487 ba97b2d7 2024-03-20 stsp if (new_id != NULL)
488 ba97b2d7 2024-03-20 stsp memcpy(&notif->new_id, new_id, sizeof(notif->new_id));
489 ba97b2d7 2024-03-20 stsp
490 ba97b2d7 2024-03-20 stsp notif->refname = strdup(got_ref_get_name(ref));
491 ba97b2d7 2024-03-20 stsp if (notif->refname == NULL) {
492 ba97b2d7 2024-03-20 stsp err = got_error_from_errno("strdup");
493 ba97b2d7 2024-03-20 stsp goto done;
494 ba97b2d7 2024-03-20 stsp }
495 ba97b2d7 2024-03-20 stsp
496 ba97b2d7 2024-03-20 stsp STAILQ_INSERT_TAIL(&notifications, notif, entry);
497 ba97b2d7 2024-03-20 stsp done:
498 ba97b2d7 2024-03-20 stsp if (err && notif) {
499 ba97b2d7 2024-03-20 stsp free(notif->refname);
500 ba97b2d7 2024-03-20 stsp free(notif);
501 ba97b2d7 2024-03-20 stsp }
502 ba97b2d7 2024-03-20 stsp return err;
503 ba97b2d7 2024-03-20 stsp }
504 ba97b2d7 2024-03-20 stsp
505 ba97b2d7 2024-03-20 stsp /* Forward notification content to the NOTIFY process. */
506 ba97b2d7 2024-03-20 stsp static const struct got_error *
507 ba97b2d7 2024-03-20 stsp forward_notification(struct gotd_session_client *client, struct imsg *imsg)
508 ba97b2d7 2024-03-20 stsp {
509 ba97b2d7 2024-03-20 stsp const struct got_error *err = NULL;
510 ba97b2d7 2024-03-20 stsp struct gotd_imsgev *iev = &gotd_session.notifier_iev;
511 ba97b2d7 2024-03-20 stsp struct gotd_session_notif *notif;
512 ba97b2d7 2024-03-20 stsp struct gotd_imsg_notification_content icontent;
513 ba97b2d7 2024-03-20 stsp char *refname = NULL;
514 ba97b2d7 2024-03-20 stsp size_t datalen;
515 ba97b2d7 2024-03-20 stsp struct gotd_imsg_notify inotify;
516 ba97b2d7 2024-03-20 stsp const char *action;
517 ba97b2d7 2024-03-20 stsp
518 ba97b2d7 2024-03-20 stsp memset(&inotify, 0, sizeof(inotify));
519 ba97b2d7 2024-03-20 stsp
520 ba97b2d7 2024-03-20 stsp datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
521 ba97b2d7 2024-03-20 stsp if (datalen < sizeof(icontent))
522 ba97b2d7 2024-03-20 stsp return got_error(GOT_ERR_PRIVSEP_LEN);
523 ba97b2d7 2024-03-20 stsp memcpy(&icontent, imsg->data, sizeof(icontent));
524 ba97b2d7 2024-03-20 stsp if (datalen != sizeof(icontent) + icontent.refname_len)
525 ba97b2d7 2024-03-20 stsp return got_error(GOT_ERR_PRIVSEP_LEN);
526 ba97b2d7 2024-03-20 stsp refname = strndup(imsg->data + sizeof(icontent), icontent.refname_len);
527 ba97b2d7 2024-03-20 stsp if (refname == NULL)
528 ba97b2d7 2024-03-20 stsp return got_error_from_errno("strndup");
529 ba97b2d7 2024-03-20 stsp
530 ba97b2d7 2024-03-20 stsp notif = STAILQ_FIRST(&notifications);
531 ba97b2d7 2024-03-20 stsp if (notif == NULL)
532 ba97b2d7 2024-03-20 stsp return got_error(GOT_ERR_PRIVSEP_MSG);
533 ba97b2d7 2024-03-20 stsp
534 ba97b2d7 2024-03-20 stsp STAILQ_REMOVE(&notifications, notif, gotd_session_notif, entry);
535 ba97b2d7 2024-03-20 stsp
536 ba97b2d7 2024-03-20 stsp if (notif->action != icontent.action || notif->fd == -1 ||
537 ba97b2d7 2024-03-20 stsp strcmp(notif->refname, refname) != 0) {
538 ba97b2d7 2024-03-20 stsp err = got_error(GOT_ERR_PRIVSEP_MSG);
539 ba97b2d7 2024-03-20 stsp goto done;
540 ba97b2d7 2024-03-20 stsp }
541 ba97b2d7 2024-03-20 stsp if (notif->action == GOTD_NOTIF_ACTION_CREATED) {
542 ba97b2d7 2024-03-20 stsp if (memcmp(notif->new_id.sha1, icontent.new_id,
543 ba97b2d7 2024-03-20 stsp SHA1_DIGEST_LENGTH) != 0) {
544 ba97b2d7 2024-03-20 stsp err = got_error_msg(GOT_ERR_PRIVSEP_MSG,
545 ba97b2d7 2024-03-20 stsp "received notification content for unknown event");
546 ba97b2d7 2024-03-20 stsp goto done;
547 ba97b2d7 2024-03-20 stsp }
548 ba97b2d7 2024-03-20 stsp } else if (notif->action == GOTD_NOTIF_ACTION_REMOVED) {
549 ba97b2d7 2024-03-20 stsp if (memcmp(notif->old_id.sha1, icontent.old_id,
550 ba97b2d7 2024-03-20 stsp SHA1_DIGEST_LENGTH) != 0) {
551 ba97b2d7 2024-03-20 stsp err = got_error_msg(GOT_ERR_PRIVSEP_MSG,
552 ba97b2d7 2024-03-20 stsp "received notification content for unknown event");
553 ba97b2d7 2024-03-20 stsp goto done;
554 ba97b2d7 2024-03-20 stsp }
555 ba97b2d7 2024-03-20 stsp } else if (memcmp(notif->old_id.sha1, icontent.old_id,
556 ba97b2d7 2024-03-20 stsp SHA1_DIGEST_LENGTH) != 0 ||
557 ba97b2d7 2024-03-20 stsp memcmp(notif->new_id.sha1, icontent.new_id,
558 ba97b2d7 2024-03-20 stsp SHA1_DIGEST_LENGTH) != 0) {
559 ba97b2d7 2024-03-20 stsp err = got_error_msg(GOT_ERR_PRIVSEP_MSG,
560 ba97b2d7 2024-03-20 stsp "received notification content for unknown event");
561 ba97b2d7 2024-03-20 stsp goto done;
562 ba97b2d7 2024-03-20 stsp }
563 ba97b2d7 2024-03-20 stsp
564 ba97b2d7 2024-03-20 stsp switch (notif->action) {
565 ba97b2d7 2024-03-20 stsp case GOTD_NOTIF_ACTION_CREATED:
566 ba97b2d7 2024-03-20 stsp action = "created";
567 ba97b2d7 2024-03-20 stsp break;
568 ba97b2d7 2024-03-20 stsp case GOTD_NOTIF_ACTION_REMOVED:
569 ba97b2d7 2024-03-20 stsp action = "removed";
570 ba97b2d7 2024-03-20 stsp break;
571 ba97b2d7 2024-03-20 stsp case GOTD_NOTIF_ACTION_CHANGED:
572 ba97b2d7 2024-03-20 stsp action = "changed";
573 ba97b2d7 2024-03-20 stsp break;
574 ba97b2d7 2024-03-20 stsp default:
575 ba97b2d7 2024-03-20 stsp err = got_error(GOT_ERR_PRIVSEP_MSG);
576 ba97b2d7 2024-03-20 stsp goto done;
577 ba97b2d7 2024-03-20 stsp }
578 ba97b2d7 2024-03-20 stsp
579 ba97b2d7 2024-03-20 stsp strlcpy(inotify.repo_name, gotd_session.repo_cfg->name,
580 ba97b2d7 2024-03-20 stsp sizeof(inotify.repo_name));
581 ba97b2d7 2024-03-20 stsp
582 ba97b2d7 2024-03-20 stsp snprintf(inotify.subject_line, sizeof(inotify.subject_line),
583 ba97b2d7 2024-03-20 stsp "%s: %s %s %s", gotd_session.repo_cfg->name,
584 ba97b2d7 2024-03-20 stsp client->username, action, notif->refname);
585 ba97b2d7 2024-03-20 stsp
586 ba97b2d7 2024-03-20 stsp if (gotd_imsg_compose_event(iev, GOTD_IMSG_NOTIFY,
587 ba97b2d7 2024-03-20 stsp PROC_SESSION_WRITE, notif->fd, &inotify, sizeof(inotify))
588 ba97b2d7 2024-03-20 stsp == -1) {
589 ba97b2d7 2024-03-20 stsp err = got_error_from_errno("imsg compose NOTIFY");
590 ba97b2d7 2024-03-20 stsp goto done;
591 ba97b2d7 2024-03-20 stsp }
592 ba97b2d7 2024-03-20 stsp notif->fd = -1;
593 ba97b2d7 2024-03-20 stsp done:
594 ba97b2d7 2024-03-20 stsp if (notif->fd != -1)
595 ba97b2d7 2024-03-20 stsp close(notif->fd);
596 ba97b2d7 2024-03-20 stsp free(notif);
597 ba97b2d7 2024-03-20 stsp free(refname);
598 ba97b2d7 2024-03-20 stsp return err;
599 ba97b2d7 2024-03-20 stsp }
600 ba97b2d7 2024-03-20 stsp
601 ba97b2d7 2024-03-20 stsp /* Request notification content from REPO_WRITE process. */
602 ba97b2d7 2024-03-20 stsp static const struct got_error *
603 ba97b2d7 2024-03-20 stsp request_notification(struct gotd_session_notif *notif)
604 ba97b2d7 2024-03-20 stsp {
605 ba97b2d7 2024-03-20 stsp const struct got_error *err = NULL;
606 ba97b2d7 2024-03-20 stsp struct gotd_session_client *client = &gotd_session_client;
607 ba97b2d7 2024-03-20 stsp struct gotd_imsgev *iev = &client->repo_child_iev;
608 ba97b2d7 2024-03-20 stsp struct gotd_imsg_notification_content icontent;
609 ba97b2d7 2024-03-20 stsp struct ibuf *wbuf;
610 ba97b2d7 2024-03-20 stsp size_t len;
611 ba97b2d7 2024-03-20 stsp int fd;
612 ba97b2d7 2024-03-20 stsp
613 ba97b2d7 2024-03-20 stsp fd = got_opentempfd();
614 ba97b2d7 2024-03-20 stsp if (fd == -1)
615 ba97b2d7 2024-03-20 stsp return got_error_from_errno("got_opentemp");
616 ba97b2d7 2024-03-20 stsp
617 ba97b2d7 2024-03-20 stsp memset(&icontent, 0, sizeof(icontent));
618 ba97b2d7 2024-03-20 stsp icontent.client_id = client->id;
619 ba97b2d7 2024-03-20 stsp
620 ba97b2d7 2024-03-20 stsp icontent.action = notif->action;
621 ba97b2d7 2024-03-20 stsp memcpy(&icontent.old_id, &notif->old_id, sizeof(notif->old_id));
622 ba97b2d7 2024-03-20 stsp memcpy(&icontent.new_id, &notif->new_id, sizeof(notif->new_id));
623 ba97b2d7 2024-03-20 stsp icontent.refname_len = strlen(notif->refname);
624 ba97b2d7 2024-03-20 stsp
625 ba97b2d7 2024-03-20 stsp len = sizeof(icontent) + icontent.refname_len;
626 ba97b2d7 2024-03-20 stsp wbuf = imsg_create(&iev->ibuf, GOTD_IMSG_NOTIFY,
627 ba97b2d7 2024-03-20 stsp gotd_session.proc_id, gotd_session.pid, len);
628 ba97b2d7 2024-03-20 stsp if (wbuf == NULL) {
629 ba97b2d7 2024-03-20 stsp err = got_error_from_errno("imsg_create NOTIFY");
630 ba97b2d7 2024-03-20 stsp goto done;
631 ba97b2d7 2024-03-20 stsp }
632 ba97b2d7 2024-03-20 stsp if (imsg_add(wbuf, &icontent, sizeof(icontent)) == -1) {
633 ba97b2d7 2024-03-20 stsp err = got_error_from_errno("imsg_add NOTIFY");
634 ba97b2d7 2024-03-20 stsp goto done;
635 ba97b2d7 2024-03-20 stsp }
636 ba97b2d7 2024-03-20 stsp if (imsg_add(wbuf, notif->refname, icontent.refname_len) == -1) {
637 ba97b2d7 2024-03-20 stsp err = got_error_from_errno("imsg_add NOTIFY");
638 ba97b2d7 2024-03-20 stsp goto done;
639 ba97b2d7 2024-03-20 stsp }
640 ba97b2d7 2024-03-20 stsp
641 ba97b2d7 2024-03-20 stsp notif->fd = dup(fd);
642 ba97b2d7 2024-03-20 stsp if (notif->fd == -1) {
643 ba97b2d7 2024-03-20 stsp err = got_error_from_errno("dup");
644 ba97b2d7 2024-03-20 stsp goto done;
645 ba97b2d7 2024-03-20 stsp }
646 ba97b2d7 2024-03-20 stsp
647 ba97b2d7 2024-03-20 stsp ibuf_fd_set(wbuf, fd);
648 ba97b2d7 2024-03-20 stsp fd = -1;
649 ba97b2d7 2024-03-20 stsp
650 ba97b2d7 2024-03-20 stsp imsg_close(&iev->ibuf, wbuf);
651 ba97b2d7 2024-03-20 stsp gotd_imsg_event_add(iev);
652 ba97b2d7 2024-03-20 stsp done:
653 ba97b2d7 2024-03-20 stsp if (err && fd != -1)
654 ba97b2d7 2024-03-20 stsp close(fd);
655 ba97b2d7 2024-03-20 stsp return err;
656 ba97b2d7 2024-03-20 stsp }
657 ba97b2d7 2024-03-20 stsp
658 ba97b2d7 2024-03-20 stsp static const struct got_error *
659 0ff2c315 2023-01-18 stsp update_ref(int *shut, struct gotd_session_client *client,
660 0ff2c315 2023-01-18 stsp const char *repo_path, struct imsg *imsg)
661 ae7c1b78 2023-01-10 stsp {
662 ae7c1b78 2023-01-10 stsp const struct got_error *err = NULL;
663 10477b5a 2024-03-19 stsp struct got_repository *repo = gotd_session.repo;
664 ae7c1b78 2023-01-10 stsp struct got_reference *ref = NULL;
665 ae7c1b78 2023-01-10 stsp struct gotd_imsg_ref_update iref;
666 ae7c1b78 2023-01-10 stsp struct got_object_id old_id, new_id;
667 ba97b2d7 2024-03-20 stsp struct gotd_session_notif *notif;
668 ae7c1b78 2023-01-10 stsp struct got_object_id *id = NULL;
669 ae7c1b78 2023-01-10 stsp char *refname = NULL;
670 ae7c1b78 2023-01-10 stsp size_t datalen;
671 ae7c1b78 2023-01-10 stsp int locked = 0;
672 1df1761f 2023-06-16 stsp char hex1[SHA1_DIGEST_STRING_LENGTH];
673 1df1761f 2023-06-16 stsp char hex2[SHA1_DIGEST_STRING_LENGTH];
674 ae7c1b78 2023-01-10 stsp
675 ae7c1b78 2023-01-10 stsp log_debug("update-ref from uid %d", client->euid);
676 ae7c1b78 2023-01-10 stsp
677 ae7c1b78 2023-01-10 stsp if (client->nref_updates <= 0)
678 ae7c1b78 2023-01-10 stsp return got_error(GOT_ERR_PRIVSEP_MSG);
679 ae7c1b78 2023-01-10 stsp
680 ae7c1b78 2023-01-10 stsp datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
681 ae7c1b78 2023-01-10 stsp if (datalen < sizeof(iref))
682 ae7c1b78 2023-01-10 stsp return got_error(GOT_ERR_PRIVSEP_LEN);
683 ae7c1b78 2023-01-10 stsp memcpy(&iref, imsg->data, sizeof(iref));
684 ae7c1b78 2023-01-10 stsp if (datalen != sizeof(iref) + iref.name_len)
685 ae7c1b78 2023-01-10 stsp return got_error(GOT_ERR_PRIVSEP_LEN);
686 00b3e9ae 2023-01-11 op refname = strndup(imsg->data + sizeof(iref), iref.name_len);
687 ae7c1b78 2023-01-10 stsp if (refname == NULL)
688 00b3e9ae 2023-01-11 op return got_error_from_errno("strndup");
689 ae7c1b78 2023-01-10 stsp
690 ae7c1b78 2023-01-10 stsp log_debug("updating ref %s for uid %d", refname, client->euid);
691 ae7c1b78 2023-01-10 stsp
692 ae7c1b78 2023-01-10 stsp memcpy(old_id.sha1, iref.old_id, SHA1_DIGEST_LENGTH);
693 ae7c1b78 2023-01-10 stsp memcpy(new_id.sha1, iref.new_id, SHA1_DIGEST_LENGTH);
694 510b4555 2023-12-31 stsp err = got_repo_find_object_id(iref.delete_ref ? &old_id : &new_id,
695 510b4555 2023-12-31 stsp repo);
696 ae7c1b78 2023-01-10 stsp if (err)
697 ae7c1b78 2023-01-10 stsp goto done;
698 ae7c1b78 2023-01-10 stsp
699 ae7c1b78 2023-01-10 stsp if (iref.ref_is_new) {
700 ae7c1b78 2023-01-10 stsp err = got_ref_open(&ref, repo, refname, 0);
701 ae7c1b78 2023-01-10 stsp if (err) {
702 ae7c1b78 2023-01-10 stsp if (err->code != GOT_ERR_NOT_REF)
703 ae7c1b78 2023-01-10 stsp goto done;
704 ae7c1b78 2023-01-10 stsp err = got_ref_alloc(&ref, refname, &new_id);
705 ae7c1b78 2023-01-10 stsp if (err)
706 ae7c1b78 2023-01-10 stsp goto done;
707 ae7c1b78 2023-01-10 stsp err = got_ref_write(ref, repo); /* will lock/unlock */
708 ae7c1b78 2023-01-10 stsp if (err)
709 ae7c1b78 2023-01-10 stsp goto done;
710 ba97b2d7 2024-03-20 stsp err = queue_notification(NULL, &new_id, repo, ref);
711 ba97b2d7 2024-03-20 stsp if (err)
712 ba97b2d7 2024-03-20 stsp goto done;
713 ae7c1b78 2023-01-10 stsp } else {
714 1df1761f 2023-06-16 stsp err = got_ref_resolve(&id, repo, ref);
715 1df1761f 2023-06-16 stsp if (err)
716 1df1761f 2023-06-16 stsp goto done;
717 1df1761f 2023-06-16 stsp got_object_id_hex(&new_id, hex1, sizeof(hex1));
718 1df1761f 2023-06-16 stsp got_object_id_hex(id, hex2, sizeof(hex2));
719 ae7c1b78 2023-01-10 stsp err = got_error_fmt(GOT_ERR_REF_BUSY,
720 1df1761f 2023-06-16 stsp "Addition %s: %s failed; %s: %s has been "
721 1df1761f 2023-06-16 stsp "created by someone else while transaction "
722 1df1761f 2023-06-16 stsp "was in progress",
723 1df1761f 2023-06-16 stsp got_ref_get_name(ref), hex1,
724 1df1761f 2023-06-16 stsp got_ref_get_name(ref), hex2);
725 ae7c1b78 2023-01-10 stsp goto done;
726 ae7c1b78 2023-01-10 stsp }
727 9a8e357c 2023-01-28 op } else if (iref.delete_ref) {
728 9a8e357c 2023-01-28 op err = got_ref_open(&ref, repo, refname, 1 /* lock */);
729 9a8e357c 2023-01-28 op if (err)
730 9a8e357c 2023-01-28 op goto done;
731 9a8e357c 2023-01-28 op locked = 1;
732 9a8e357c 2023-01-28 op
733 9a8e357c 2023-01-28 op err = got_ref_resolve(&id, repo, ref);
734 9a8e357c 2023-01-28 op if (err)
735 9a8e357c 2023-01-28 op goto done;
736 9a8e357c 2023-01-28 op
737 9a8e357c 2023-01-28 op if (got_object_id_cmp(id, &old_id) != 0) {
738 1df1761f 2023-06-16 stsp got_object_id_hex(&old_id, hex1, sizeof(hex1));
739 1df1761f 2023-06-16 stsp got_object_id_hex(id, hex2, sizeof(hex2));
740 9a8e357c 2023-01-28 op err = got_error_fmt(GOT_ERR_REF_BUSY,
741 1df1761f 2023-06-16 stsp "Deletion %s: %s failed; %s: %s has been "
742 1df1761f 2023-06-16 stsp "created by someone else while transaction "
743 1df1761f 2023-06-16 stsp "was in progress",
744 1df1761f 2023-06-16 stsp got_ref_get_name(ref), hex1,
745 1df1761f 2023-06-16 stsp got_ref_get_name(ref), hex2);
746 9a8e357c 2023-01-28 op goto done;
747 9a8e357c 2023-01-28 op }
748 9a8e357c 2023-01-28 op
749 9a8e357c 2023-01-28 op err = got_ref_delete(ref, repo);
750 9a8e357c 2023-01-28 op if (err)
751 9a8e357c 2023-01-28 op goto done;
752 ba97b2d7 2024-03-20 stsp err = queue_notification(&old_id, NULL, repo, ref);
753 ba97b2d7 2024-03-20 stsp if (err)
754 ba97b2d7 2024-03-20 stsp goto done;
755 9a8e357c 2023-01-28 op free(id);
756 9a8e357c 2023-01-28 op id = NULL;
757 ae7c1b78 2023-01-10 stsp } else {
758 ae7c1b78 2023-01-10 stsp err = got_ref_open(&ref, repo, refname, 1 /* lock */);
759 ae7c1b78 2023-01-10 stsp if (err)
760 ae7c1b78 2023-01-10 stsp goto done;
761 ae7c1b78 2023-01-10 stsp locked = 1;
762 ae7c1b78 2023-01-10 stsp
763 ae7c1b78 2023-01-10 stsp err = got_ref_resolve(&id, repo, ref);
764 ae7c1b78 2023-01-10 stsp if (err)
765 ae7c1b78 2023-01-10 stsp goto done;
766 ae7c1b78 2023-01-10 stsp
767 ae7c1b78 2023-01-10 stsp if (got_object_id_cmp(id, &old_id) != 0) {
768 1df1761f 2023-06-16 stsp got_object_id_hex(&old_id, hex1, sizeof(hex1));
769 1df1761f 2023-06-16 stsp got_object_id_hex(id, hex2, sizeof(hex2));
770 ae7c1b78 2023-01-10 stsp err = got_error_fmt(GOT_ERR_REF_BUSY,
771 1df1761f 2023-06-16 stsp "Update %s: %s failed; %s: %s has been "
772 1df1761f 2023-06-16 stsp "created by someone else while transaction "
773 1df1761f 2023-06-16 stsp "was in progress",
774 1df1761f 2023-06-16 stsp got_ref_get_name(ref), hex1,
775 1df1761f 2023-06-16 stsp got_ref_get_name(ref), hex2);
776 ae7c1b78 2023-01-10 stsp goto done;
777 ae7c1b78 2023-01-10 stsp }
778 ae7c1b78 2023-01-10 stsp
779 f8780fee 2023-06-16 stsp if (got_object_id_cmp(&new_id, &old_id) != 0) {
780 f8780fee 2023-06-16 stsp err = got_ref_change_ref(ref, &new_id);
781 f8780fee 2023-06-16 stsp if (err)
782 f8780fee 2023-06-16 stsp goto done;
783 f8780fee 2023-06-16 stsp err = got_ref_write(ref, repo);
784 f8780fee 2023-06-16 stsp if (err)
785 f8780fee 2023-06-16 stsp goto done;
786 ba97b2d7 2024-03-20 stsp err = queue_notification(&old_id, &new_id, repo, ref);
787 ba97b2d7 2024-03-20 stsp if (err)
788 ba97b2d7 2024-03-20 stsp goto done;
789 f8780fee 2023-06-16 stsp }
790 ae7c1b78 2023-01-10 stsp
791 ae7c1b78 2023-01-10 stsp free(id);
792 ae7c1b78 2023-01-10 stsp id = NULL;
793 ae7c1b78 2023-01-10 stsp }
794 ae7c1b78 2023-01-10 stsp done:
795 ae7c1b78 2023-01-10 stsp if (err) {
796 ae7c1b78 2023-01-10 stsp if (err->code == GOT_ERR_LOCKFILE_TIMEOUT) {
797 ae7c1b78 2023-01-10 stsp err = got_error_fmt(GOT_ERR_LOCKFILE_TIMEOUT,
798 ae7c1b78 2023-01-10 stsp "could not acquire exclusive file lock for %s",
799 ae7c1b78 2023-01-10 stsp refname);
800 ae7c1b78 2023-01-10 stsp }
801 ae7c1b78 2023-01-10 stsp send_ref_update_ng(client, &iref, refname, err->msg);
802 ae7c1b78 2023-01-10 stsp } else
803 ae7c1b78 2023-01-10 stsp send_ref_update_ok(client, &iref, refname);
804 ae7c1b78 2023-01-10 stsp
805 ae7c1b78 2023-01-10 stsp if (client->nref_updates > 0) {
806 ae7c1b78 2023-01-10 stsp client->nref_updates--;
807 0ff2c315 2023-01-18 stsp if (client->nref_updates == 0) {
808 ae7c1b78 2023-01-10 stsp send_refs_updated(client);
809 ba97b2d7 2024-03-20 stsp notif = STAILQ_FIRST(&notifications);
810 ba97b2d7 2024-03-20 stsp if (notif) {
811 ba97b2d7 2024-03-20 stsp client->state = GOTD_STATE_NOTIFY;
812 ba97b2d7 2024-03-20 stsp err = request_notification(notif);
813 ba97b2d7 2024-03-20 stsp if (err) {
814 ba97b2d7 2024-03-20 stsp log_warn("could not send notification: "
815 ba97b2d7 2024-03-20 stsp "%s", err->msg);
816 ba97b2d7 2024-03-20 stsp client->flush_disconnect = 1;
817 ba97b2d7 2024-03-20 stsp }
818 ba97b2d7 2024-03-20 stsp } else
819 ba97b2d7 2024-03-20 stsp client->flush_disconnect = 1;
820 0ff2c315 2023-01-18 stsp }
821 ae7c1b78 2023-01-10 stsp
822 ae7c1b78 2023-01-10 stsp }
823 ae7c1b78 2023-01-10 stsp if (locked) {
824 ae7c1b78 2023-01-10 stsp const struct got_error *unlock_err;
825 ae7c1b78 2023-01-10 stsp unlock_err = got_ref_unlock(ref);
826 ae7c1b78 2023-01-10 stsp if (unlock_err && err == NULL)
827 ae7c1b78 2023-01-10 stsp err = unlock_err;
828 ae7c1b78 2023-01-10 stsp }
829 ae7c1b78 2023-01-10 stsp if (ref)
830 ae7c1b78 2023-01-10 stsp got_ref_close(ref);
831 ae7c1b78 2023-01-10 stsp free(refname);
832 ae7c1b78 2023-01-10 stsp free(id);
833 ae7c1b78 2023-01-10 stsp return err;
834 ae7c1b78 2023-01-10 stsp }
835 ae7c1b78 2023-01-10 stsp
836 ba97b2d7 2024-03-20 stsp static const struct got_error *
837 ba97b2d7 2024-03-20 stsp recv_notification_content(uint32_t *client_id, struct imsg *imsg)
838 ba97b2d7 2024-03-20 stsp {
839 ba97b2d7 2024-03-20 stsp struct gotd_imsg_notification_content inotif;
840 ba97b2d7 2024-03-20 stsp size_t datalen;
841 ba97b2d7 2024-03-20 stsp
842 ba97b2d7 2024-03-20 stsp datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
843 ba97b2d7 2024-03-20 stsp if (datalen < sizeof(inotif))
844 ba97b2d7 2024-03-20 stsp return got_error(GOT_ERR_PRIVSEP_LEN);
845 ba97b2d7 2024-03-20 stsp memcpy(&inotif, imsg->data, sizeof(inotif));
846 ba97b2d7 2024-03-20 stsp
847 ba97b2d7 2024-03-20 stsp *client_id = inotif.client_id;
848 ba97b2d7 2024-03-20 stsp return NULL;
849 ba97b2d7 2024-03-20 stsp }
850 ba97b2d7 2024-03-20 stsp
851 ae7c1b78 2023-01-10 stsp static void
852 ae7c1b78 2023-01-10 stsp session_dispatch_repo_child(int fd, short event, void *arg)
853 ae7c1b78 2023-01-10 stsp {
854 ae7c1b78 2023-01-10 stsp struct gotd_imsgev *iev = arg;
855 ae7c1b78 2023-01-10 stsp struct imsgbuf *ibuf = &iev->ibuf;
856 ae7c1b78 2023-01-10 stsp struct gotd_session_client *client = &gotd_session_client;
857 ae7c1b78 2023-01-10 stsp ssize_t n;
858 ae7c1b78 2023-01-10 stsp int shut = 0;
859 ae7c1b78 2023-01-10 stsp struct imsg imsg;
860 ae7c1b78 2023-01-10 stsp
861 ae7c1b78 2023-01-10 stsp if (event & EV_READ) {
862 ae7c1b78 2023-01-10 stsp if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
863 ae7c1b78 2023-01-10 stsp fatal("imsg_read error");
864 ae7c1b78 2023-01-10 stsp if (n == 0) {
865 ae7c1b78 2023-01-10 stsp /* Connection closed. */
866 ae7c1b78 2023-01-10 stsp shut = 1;
867 ae7c1b78 2023-01-10 stsp goto done;
868 ae7c1b78 2023-01-10 stsp }
869 ae7c1b78 2023-01-10 stsp }
870 ae7c1b78 2023-01-10 stsp
871 ae7c1b78 2023-01-10 stsp if (event & EV_WRITE) {
872 ae7c1b78 2023-01-10 stsp n = msgbuf_write(&ibuf->w);
873 ae7c1b78 2023-01-10 stsp if (n == -1 && errno != EAGAIN)
874 ae7c1b78 2023-01-10 stsp fatal("msgbuf_write");
875 ae7c1b78 2023-01-10 stsp if (n == 0) {
876 ae7c1b78 2023-01-10 stsp /* Connection closed. */
877 ae7c1b78 2023-01-10 stsp shut = 1;
878 ae7c1b78 2023-01-10 stsp goto done;
879 ae7c1b78 2023-01-10 stsp }
880 ae7c1b78 2023-01-10 stsp }
881 ae7c1b78 2023-01-10 stsp
882 ae7c1b78 2023-01-10 stsp for (;;) {
883 ae7c1b78 2023-01-10 stsp const struct got_error *err = NULL;
884 ae7c1b78 2023-01-10 stsp uint32_t client_id = 0;
885 ae7c1b78 2023-01-10 stsp int do_disconnect = 0;
886 ae7c1b78 2023-01-10 stsp int do_ref_updates = 0, do_ref_update = 0;
887 ba97b2d7 2024-03-20 stsp int do_packfile_install = 0, do_notify = 0;
888 ae7c1b78 2023-01-10 stsp
889 ae7c1b78 2023-01-10 stsp if ((n = imsg_get(ibuf, &imsg)) == -1)
890 ae7c1b78 2023-01-10 stsp fatal("%s: imsg_get error", __func__);
891 ae7c1b78 2023-01-10 stsp if (n == 0) /* No more messages. */
892 ae7c1b78 2023-01-10 stsp break;
893 ae7c1b78 2023-01-10 stsp
894 ae7c1b78 2023-01-10 stsp switch (imsg.hdr.type) {
895 ae7c1b78 2023-01-10 stsp case GOTD_IMSG_ERROR:
896 ae7c1b78 2023-01-10 stsp do_disconnect = 1;
897 ae7c1b78 2023-01-10 stsp err = gotd_imsg_recv_error(&client_id, &imsg);
898 ae7c1b78 2023-01-10 stsp break;
899 ae7c1b78 2023-01-10 stsp case GOTD_IMSG_PACKFILE_DONE:
900 ae7c1b78 2023-01-10 stsp do_disconnect = 1;
901 ae7c1b78 2023-01-10 stsp err = recv_packfile_done(&client_id, &imsg);
902 ae7c1b78 2023-01-10 stsp break;
903 ae7c1b78 2023-01-10 stsp case GOTD_IMSG_PACKFILE_INSTALL:
904 ae7c1b78 2023-01-10 stsp err = recv_packfile_install(&client_id, &imsg);
905 ae7c1b78 2023-01-10 stsp if (err == NULL)
906 ae7c1b78 2023-01-10 stsp do_packfile_install = 1;
907 ae7c1b78 2023-01-10 stsp break;
908 ae7c1b78 2023-01-10 stsp case GOTD_IMSG_REF_UPDATES_START:
909 ae7c1b78 2023-01-10 stsp err = recv_ref_updates_start(&client_id, &imsg);
910 ae7c1b78 2023-01-10 stsp if (err == NULL)
911 ae7c1b78 2023-01-10 stsp do_ref_updates = 1;
912 ae7c1b78 2023-01-10 stsp break;
913 ae7c1b78 2023-01-10 stsp case GOTD_IMSG_REF_UPDATE:
914 ae7c1b78 2023-01-10 stsp err = recv_ref_update(&client_id, &imsg);
915 ae7c1b78 2023-01-10 stsp if (err == NULL)
916 ae7c1b78 2023-01-10 stsp do_ref_update = 1;
917 ae7c1b78 2023-01-10 stsp break;
918 ba97b2d7 2024-03-20 stsp case GOTD_IMSG_NOTIFY:
919 ba97b2d7 2024-03-20 stsp err = recv_notification_content(&client_id, &imsg);
920 ba97b2d7 2024-03-20 stsp if (err == NULL)
921 ba97b2d7 2024-03-20 stsp do_notify = 1;
922 ba97b2d7 2024-03-20 stsp break;
923 ae7c1b78 2023-01-10 stsp default:
924 ae7c1b78 2023-01-10 stsp log_debug("unexpected imsg %d", imsg.hdr.type);
925 ae7c1b78 2023-01-10 stsp break;
926 ae7c1b78 2023-01-10 stsp }
927 ae7c1b78 2023-01-10 stsp
928 ae7c1b78 2023-01-10 stsp if (do_disconnect) {
929 ae7c1b78 2023-01-10 stsp if (err)
930 ae7c1b78 2023-01-10 stsp disconnect_on_error(client, err);
931 ae7c1b78 2023-01-10 stsp else
932 ae7c1b78 2023-01-10 stsp disconnect(client);
933 ae7c1b78 2023-01-10 stsp } else {
934 ba97b2d7 2024-03-20 stsp struct gotd_session_notif *notif;
935 ba97b2d7 2024-03-20 stsp
936 ae7c1b78 2023-01-10 stsp if (do_packfile_install)
937 ae7c1b78 2023-01-10 stsp err = install_pack(client,
938 ae7c1b78 2023-01-10 stsp gotd_session.repo->path, &imsg);
939 ae7c1b78 2023-01-10 stsp else if (do_ref_updates)
940 ae7c1b78 2023-01-10 stsp err = begin_ref_updates(client, &imsg);
941 ae7c1b78 2023-01-10 stsp else if (do_ref_update)
942 0ff2c315 2023-01-18 stsp err = update_ref(&shut, client,
943 ae7c1b78 2023-01-10 stsp gotd_session.repo->path, &imsg);
944 ba97b2d7 2024-03-20 stsp else if (do_notify)
945 ba97b2d7 2024-03-20 stsp err = forward_notification(client, &imsg);
946 ae7c1b78 2023-01-10 stsp if (err)
947 ae7c1b78 2023-01-10 stsp log_warnx("uid %d: %s", client->euid, err->msg);
948 ba97b2d7 2024-03-20 stsp
949 ba97b2d7 2024-03-20 stsp notif = STAILQ_FIRST(&notifications);
950 ba97b2d7 2024-03-20 stsp if (notif && do_notify) {
951 ba97b2d7 2024-03-20 stsp /* Request content for next notification. */
952 ba97b2d7 2024-03-20 stsp err = request_notification(notif);
953 ba97b2d7 2024-03-20 stsp if (err) {
954 ba97b2d7 2024-03-20 stsp log_warn("could not send notification: "
955 ba97b2d7 2024-03-20 stsp "%s", err->msg);
956 ba97b2d7 2024-03-20 stsp shut = 1;
957 ba97b2d7 2024-03-20 stsp }
958 ba97b2d7 2024-03-20 stsp }
959 ae7c1b78 2023-01-10 stsp }
960 ae7c1b78 2023-01-10 stsp imsg_free(&imsg);
961 ae7c1b78 2023-01-10 stsp }
962 ae7c1b78 2023-01-10 stsp done:
963 ae7c1b78 2023-01-10 stsp if (!shut) {
964 ae7c1b78 2023-01-10 stsp gotd_imsg_event_add(iev);
965 ae7c1b78 2023-01-10 stsp } else {
966 ae7c1b78 2023-01-10 stsp /* This pipe is dead. Remove its event handler */
967 ae7c1b78 2023-01-10 stsp event_del(&iev->ev);
968 ae7c1b78 2023-01-10 stsp event_loopexit(NULL);
969 ae7c1b78 2023-01-10 stsp }
970 ae7c1b78 2023-01-10 stsp }
971 ae7c1b78 2023-01-10 stsp
972 ae7c1b78 2023-01-10 stsp static const struct got_error *
973 ae7c1b78 2023-01-10 stsp recv_capabilities(struct gotd_session_client *client, struct imsg *imsg)
974 ae7c1b78 2023-01-10 stsp {
975 ae7c1b78 2023-01-10 stsp struct gotd_imsg_capabilities icapas;
976 ae7c1b78 2023-01-10 stsp size_t datalen;
977 ae7c1b78 2023-01-10 stsp
978 ae7c1b78 2023-01-10 stsp datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
979 ae7c1b78 2023-01-10 stsp if (datalen != sizeof(icapas))
980 ae7c1b78 2023-01-10 stsp return got_error(GOT_ERR_PRIVSEP_LEN);
981 ae7c1b78 2023-01-10 stsp memcpy(&icapas, imsg->data, sizeof(icapas));
982 ae7c1b78 2023-01-10 stsp
983 ae7c1b78 2023-01-10 stsp client->ncapa_alloc = icapas.ncapabilities;
984 ae7c1b78 2023-01-10 stsp client->capabilities = calloc(client->ncapa_alloc,
985 ae7c1b78 2023-01-10 stsp sizeof(*client->capabilities));
986 ae7c1b78 2023-01-10 stsp if (client->capabilities == NULL) {
987 ae7c1b78 2023-01-10 stsp client->ncapa_alloc = 0;
988 ae7c1b78 2023-01-10 stsp return got_error_from_errno("calloc");
989 ae7c1b78 2023-01-10 stsp }
990 ae7c1b78 2023-01-10 stsp
991 ae7c1b78 2023-01-10 stsp log_debug("expecting %zu capabilities from uid %d",
992 ae7c1b78 2023-01-10 stsp client->ncapa_alloc, client->euid);
993 ae7c1b78 2023-01-10 stsp return NULL;
994 ae7c1b78 2023-01-10 stsp }
995 ae7c1b78 2023-01-10 stsp
996 ae7c1b78 2023-01-10 stsp static const struct got_error *
997 ae7c1b78 2023-01-10 stsp recv_capability(struct gotd_session_client *client, struct imsg *imsg)
998 ae7c1b78 2023-01-10 stsp {
999 ae7c1b78 2023-01-10 stsp struct gotd_imsg_capability icapa;
1000 ae7c1b78 2023-01-10 stsp struct gotd_client_capability *capa;
1001 ae7c1b78 2023-01-10 stsp size_t datalen;
1002 ae7c1b78 2023-01-10 stsp char *key, *value = NULL;
1003 ae7c1b78 2023-01-10 stsp
1004 ae7c1b78 2023-01-10 stsp if (client->capabilities == NULL ||
1005 ae7c1b78 2023-01-10 stsp client->ncapabilities >= client->ncapa_alloc) {
1006 ae7c1b78 2023-01-10 stsp return got_error_msg(GOT_ERR_BAD_REQUEST,
1007 ae7c1b78 2023-01-10 stsp "unexpected capability received");
1008 ae7c1b78 2023-01-10 stsp }
1009 ae7c1b78 2023-01-10 stsp
1010 ae7c1b78 2023-01-10 stsp memset(&icapa, 0, sizeof(icapa));
1011 ae7c1b78 2023-01-10 stsp
1012 ae7c1b78 2023-01-10 stsp datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
1013 ae7c1b78 2023-01-10 stsp if (datalen < sizeof(icapa))
1014 ae7c1b78 2023-01-10 stsp return got_error(GOT_ERR_PRIVSEP_LEN);
1015 ae7c1b78 2023-01-10 stsp memcpy(&icapa, imsg->data, sizeof(icapa));
1016 ae7c1b78 2023-01-10 stsp
1017 ae7c1b78 2023-01-10 stsp if (datalen != sizeof(icapa) + icapa.key_len + icapa.value_len)
1018 ae7c1b78 2023-01-10 stsp return got_error(GOT_ERR_PRIVSEP_LEN);
1019 ae7c1b78 2023-01-10 stsp
1020 00b3e9ae 2023-01-11 op key = strndup(imsg->data + sizeof(icapa), icapa.key_len);
1021 ae7c1b78 2023-01-10 stsp if (key == NULL)
1022 00b3e9ae 2023-01-11 op return got_error_from_errno("strndup");
1023 ae7c1b78 2023-01-10 stsp if (icapa.value_len > 0) {
1024 00b3e9ae 2023-01-11 op value = strndup(imsg->data + sizeof(icapa) + icapa.key_len,
1025 00b3e9ae 2023-01-11 op icapa.value_len);
1026 ae7c1b78 2023-01-10 stsp if (value == NULL) {
1027 ae7c1b78 2023-01-10 stsp free(key);
1028 00b3e9ae 2023-01-11 op return got_error_from_errno("strndup");
1029 ae7c1b78 2023-01-10 stsp }
1030 ae7c1b78 2023-01-10 stsp }
1031 ae7c1b78 2023-01-10 stsp
1032 ae7c1b78 2023-01-10 stsp capa = &client->capabilities[client->ncapabilities++];
1033 ae7c1b78 2023-01-10 stsp capa->key = key;
1034 ae7c1b78 2023-01-10 stsp capa->value = value;
1035 ae7c1b78 2023-01-10 stsp
1036 ae7c1b78 2023-01-10 stsp if (value)
1037 ae7c1b78 2023-01-10 stsp log_debug("uid %d: capability %s=%s", client->euid, key, value);
1038 ae7c1b78 2023-01-10 stsp else
1039 ae7c1b78 2023-01-10 stsp log_debug("uid %d: capability %s", client->euid, key);
1040 ae7c1b78 2023-01-10 stsp
1041 ae7c1b78 2023-01-10 stsp return NULL;
1042 ae7c1b78 2023-01-10 stsp }
1043 ae7c1b78 2023-01-10 stsp
1044 ae7c1b78 2023-01-10 stsp static const struct got_error *
1045 ae7c1b78 2023-01-10 stsp ensure_client_is_reading(struct gotd_session_client *client)
1046 ae7c1b78 2023-01-10 stsp {
1047 ae7c1b78 2023-01-10 stsp if (client->is_writing) {
1048 ae7c1b78 2023-01-10 stsp return got_error_fmt(GOT_ERR_BAD_PACKET,
1049 ae7c1b78 2023-01-10 stsp "uid %d made a read-request but is not reading from "
1050 ae7c1b78 2023-01-10 stsp "a repository", client->euid);
1051 ae7c1b78 2023-01-10 stsp }
1052 ae7c1b78 2023-01-10 stsp
1053 ae7c1b78 2023-01-10 stsp return NULL;
1054 ae7c1b78 2023-01-10 stsp }
1055 ae7c1b78 2023-01-10 stsp
1056 ae7c1b78 2023-01-10 stsp static const struct got_error *
1057 ae7c1b78 2023-01-10 stsp ensure_client_is_writing(struct gotd_session_client *client)
1058 ae7c1b78 2023-01-10 stsp {
1059 ae7c1b78 2023-01-10 stsp if (!client->is_writing) {
1060 ae7c1b78 2023-01-10 stsp return got_error_fmt(GOT_ERR_BAD_PACKET,
1061 ae7c1b78 2023-01-10 stsp "uid %d made a write-request but is not writing to "
1062 ae7c1b78 2023-01-10 stsp "a repository", client->euid);
1063 ae7c1b78 2023-01-10 stsp }
1064 ae7c1b78 2023-01-10 stsp
1065 ae7c1b78 2023-01-10 stsp return NULL;
1066 ae7c1b78 2023-01-10 stsp }
1067 ae7c1b78 2023-01-10 stsp
1068 ae7c1b78 2023-01-10 stsp static const struct got_error *
1069 ae7c1b78 2023-01-10 stsp forward_want(struct gotd_session_client *client, struct imsg *imsg)
1070 ae7c1b78 2023-01-10 stsp {
1071 ae7c1b78 2023-01-10 stsp struct gotd_imsg_want ireq;
1072 ae7c1b78 2023-01-10 stsp struct gotd_imsg_want iwant;
1073 ae7c1b78 2023-01-10 stsp size_t datalen;
1074 ae7c1b78 2023-01-10 stsp
1075 ae7c1b78 2023-01-10 stsp datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
1076 ae7c1b78 2023-01-10 stsp if (datalen != sizeof(ireq))
1077 ae7c1b78 2023-01-10 stsp return got_error(GOT_ERR_PRIVSEP_LEN);
1078 ae7c1b78 2023-01-10 stsp
1079 ae7c1b78 2023-01-10 stsp memcpy(&ireq, imsg->data, datalen);
1080 ae7c1b78 2023-01-10 stsp
1081 ae7c1b78 2023-01-10 stsp memset(&iwant, 0, sizeof(iwant));
1082 ae7c1b78 2023-01-10 stsp memcpy(iwant.object_id, ireq.object_id, SHA1_DIGEST_LENGTH);
1083 ae7c1b78 2023-01-10 stsp iwant.client_id = client->id;
1084 ae7c1b78 2023-01-10 stsp
1085 ae7c1b78 2023-01-10 stsp if (gotd_imsg_compose_event(&client->repo_child_iev, GOTD_IMSG_WANT,
1086 b0614828 2023-06-19 stsp gotd_session.proc_id, -1, &iwant, sizeof(iwant)) == -1)
1087 ae7c1b78 2023-01-10 stsp return got_error_from_errno("imsg compose WANT");
1088 ae7c1b78 2023-01-10 stsp
1089 ae7c1b78 2023-01-10 stsp return NULL;
1090 ae7c1b78 2023-01-10 stsp }
1091 ae7c1b78 2023-01-10 stsp
1092 ae7c1b78 2023-01-10 stsp static const struct got_error *
1093 ae7c1b78 2023-01-10 stsp forward_ref_update(struct gotd_session_client *client, struct imsg *imsg)
1094 ae7c1b78 2023-01-10 stsp {
1095 ae7c1b78 2023-01-10 stsp const struct got_error *err = NULL;
1096 ae7c1b78 2023-01-10 stsp struct gotd_imsg_ref_update ireq;
1097 ae7c1b78 2023-01-10 stsp struct gotd_imsg_ref_update *iref = NULL;
1098 ae7c1b78 2023-01-10 stsp size_t datalen;
1099 ae7c1b78 2023-01-10 stsp
1100 ae7c1b78 2023-01-10 stsp datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
1101 ae7c1b78 2023-01-10 stsp if (datalen < sizeof(ireq))
1102 ae7c1b78 2023-01-10 stsp return got_error(GOT_ERR_PRIVSEP_LEN);
1103 ae7c1b78 2023-01-10 stsp memcpy(&ireq, imsg->data, sizeof(ireq));
1104 ae7c1b78 2023-01-10 stsp if (datalen != sizeof(ireq) + ireq.name_len)
1105 ae7c1b78 2023-01-10 stsp return got_error(GOT_ERR_PRIVSEP_LEN);
1106 ae7c1b78 2023-01-10 stsp
1107 ae7c1b78 2023-01-10 stsp iref = malloc(datalen);
1108 ae7c1b78 2023-01-10 stsp if (iref == NULL)
1109 ae7c1b78 2023-01-10 stsp return got_error_from_errno("malloc");
1110 ae7c1b78 2023-01-10 stsp memcpy(iref, imsg->data, datalen);
1111 ae7c1b78 2023-01-10 stsp
1112 ae7c1b78 2023-01-10 stsp iref->client_id = client->id;
1113 ae7c1b78 2023-01-10 stsp if (gotd_imsg_compose_event(&client->repo_child_iev,
1114 b0614828 2023-06-19 stsp GOTD_IMSG_REF_UPDATE, gotd_session.proc_id, -1,
1115 b0614828 2023-06-19 stsp iref, datalen) == -1)
1116 ae7c1b78 2023-01-10 stsp err = got_error_from_errno("imsg compose REF_UPDATE");
1117 ae7c1b78 2023-01-10 stsp free(iref);
1118 ae7c1b78 2023-01-10 stsp return err;
1119 ae7c1b78 2023-01-10 stsp }
1120 ae7c1b78 2023-01-10 stsp
1121 ae7c1b78 2023-01-10 stsp static const struct got_error *
1122 ae7c1b78 2023-01-10 stsp forward_have(struct gotd_session_client *client, struct imsg *imsg)
1123 ae7c1b78 2023-01-10 stsp {
1124 ae7c1b78 2023-01-10 stsp struct gotd_imsg_have ireq;
1125 ae7c1b78 2023-01-10 stsp struct gotd_imsg_have ihave;
1126 ae7c1b78 2023-01-10 stsp size_t datalen;
1127 ae7c1b78 2023-01-10 stsp
1128 ae7c1b78 2023-01-10 stsp datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
1129 ae7c1b78 2023-01-10 stsp if (datalen != sizeof(ireq))
1130 ae7c1b78 2023-01-10 stsp return got_error(GOT_ERR_PRIVSEP_LEN);
1131 ae7c1b78 2023-01-10 stsp
1132 ae7c1b78 2023-01-10 stsp memcpy(&ireq, imsg->data, datalen);
1133 ae7c1b78 2023-01-10 stsp
1134 ae7c1b78 2023-01-10 stsp memset(&ihave, 0, sizeof(ihave));
1135 ae7c1b78 2023-01-10 stsp memcpy(ihave.object_id, ireq.object_id, SHA1_DIGEST_LENGTH);
1136 ae7c1b78 2023-01-10 stsp ihave.client_id = client->id;
1137 ae7c1b78 2023-01-10 stsp
1138 ae7c1b78 2023-01-10 stsp if (gotd_imsg_compose_event(&client->repo_child_iev, GOTD_IMSG_HAVE,
1139 b0614828 2023-06-19 stsp gotd_session.proc_id, -1, &ihave, sizeof(ihave)) == -1)
1140 ae7c1b78 2023-01-10 stsp return got_error_from_errno("imsg compose HAVE");
1141 ae7c1b78 2023-01-10 stsp
1142 ae7c1b78 2023-01-10 stsp return NULL;
1143 ae7c1b78 2023-01-10 stsp }
1144 ae7c1b78 2023-01-10 stsp
1145 ae7c1b78 2023-01-10 stsp static int
1146 ae7c1b78 2023-01-10 stsp client_has_capability(struct gotd_session_client *client, const char *capastr)
1147 ae7c1b78 2023-01-10 stsp {
1148 ae7c1b78 2023-01-10 stsp struct gotd_client_capability *capa;
1149 ae7c1b78 2023-01-10 stsp size_t i;
1150 ae7c1b78 2023-01-10 stsp
1151 ae7c1b78 2023-01-10 stsp if (client->ncapabilities == 0)
1152 ae7c1b78 2023-01-10 stsp return 0;
1153 ae7c1b78 2023-01-10 stsp
1154 ae7c1b78 2023-01-10 stsp for (i = 0; i < client->ncapabilities; i++) {
1155 ae7c1b78 2023-01-10 stsp capa = &client->capabilities[i];
1156 ae7c1b78 2023-01-10 stsp if (strcmp(capa->key, capastr) == 0)
1157 ae7c1b78 2023-01-10 stsp return 1;
1158 ae7c1b78 2023-01-10 stsp }
1159 ae7c1b78 2023-01-10 stsp
1160 ae7c1b78 2023-01-10 stsp return 0;
1161 ae7c1b78 2023-01-10 stsp }
1162 ae7c1b78 2023-01-10 stsp
1163 ae7c1b78 2023-01-10 stsp static const struct got_error *
1164 ae7c1b78 2023-01-10 stsp recv_packfile(struct gotd_session_client *client)
1165 ae7c1b78 2023-01-10 stsp {
1166 ae7c1b78 2023-01-10 stsp const struct got_error *err = NULL;
1167 ae7c1b78 2023-01-10 stsp struct gotd_imsg_recv_packfile ipack;
1168 ae7c1b78 2023-01-10 stsp struct gotd_imsg_packfile_pipe ipipe;
1169 ae7c1b78 2023-01-10 stsp struct gotd_imsg_packidx_file ifile;
1170 ae7c1b78 2023-01-10 stsp char *basepath = NULL, *pack_path = NULL, *idx_path = NULL;
1171 ae7c1b78 2023-01-10 stsp int packfd = -1, idxfd = -1;
1172 ae7c1b78 2023-01-10 stsp int pipe[2] = { -1, -1 };
1173 ae7c1b78 2023-01-10 stsp
1174 ae7c1b78 2023-01-10 stsp if (client->packfile_path) {
1175 ae7c1b78 2023-01-10 stsp return got_error_fmt(GOT_ERR_PRIVSEP_MSG,
1176 ae7c1b78 2023-01-10 stsp "uid %d already has a pack file", client->euid);
1177 ae7c1b78 2023-01-10 stsp }
1178 ae7c1b78 2023-01-10 stsp
1179 ae7c1b78 2023-01-10 stsp if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe) == -1)
1180 ae7c1b78 2023-01-10 stsp return got_error_from_errno("socketpair");
1181 ae7c1b78 2023-01-10 stsp
1182 ae7c1b78 2023-01-10 stsp memset(&ipipe, 0, sizeof(ipipe));
1183 ae7c1b78 2023-01-10 stsp ipipe.client_id = client->id;
1184 ae7c1b78 2023-01-10 stsp
1185 ae7c1b78 2023-01-10 stsp /* Send pack pipe end 0 to repo child process. */
1186 ae7c1b78 2023-01-10 stsp if (gotd_imsg_compose_event(&client->repo_child_iev,
1187 b0614828 2023-06-19 stsp GOTD_IMSG_PACKFILE_PIPE, gotd_session.proc_id, pipe[0],
1188 ae7c1b78 2023-01-10 stsp &ipipe, sizeof(ipipe)) == -1) {
1189 ae7c1b78 2023-01-10 stsp err = got_error_from_errno("imsg compose PACKFILE_PIPE");
1190 ae7c1b78 2023-01-10 stsp pipe[0] = -1;
1191 ae7c1b78 2023-01-10 stsp goto done;
1192 ae7c1b78 2023-01-10 stsp }
1193 ae7c1b78 2023-01-10 stsp pipe[0] = -1;
1194 ae7c1b78 2023-01-10 stsp
1195 ae7c1b78 2023-01-10 stsp /* Send pack pipe end 1 to gotsh(1) (expects just an fd, no data). */
1196 ae7c1b78 2023-01-10 stsp if (gotd_imsg_compose_event(&client->iev,
1197 b0614828 2023-06-19 stsp GOTD_IMSG_PACKFILE_PIPE, gotd_session.proc_id, pipe[1],
1198 b0614828 2023-06-19 stsp NULL, 0) == -1)
1199 ae7c1b78 2023-01-10 stsp err = got_error_from_errno("imsg compose PACKFILE_PIPE");
1200 ae7c1b78 2023-01-10 stsp pipe[1] = -1;
1201 ae7c1b78 2023-01-10 stsp
1202 ae7c1b78 2023-01-10 stsp if (asprintf(&basepath, "%s/%s/receiving-from-uid-%d.pack",
1203 ae7c1b78 2023-01-10 stsp got_repo_get_path(gotd_session.repo), GOT_OBJECTS_PACK_DIR,
1204 ae7c1b78 2023-01-10 stsp client->euid) == -1) {
1205 ae7c1b78 2023-01-10 stsp err = got_error_from_errno("asprintf");
1206 ae7c1b78 2023-01-10 stsp goto done;
1207 ae7c1b78 2023-01-10 stsp }
1208 ae7c1b78 2023-01-10 stsp
1209 ae7c1b78 2023-01-10 stsp err = got_opentemp_named_fd(&pack_path, &packfd, basepath, "");
1210 ae7c1b78 2023-01-10 stsp if (err)
1211 ae7c1b78 2023-01-10 stsp goto done;
1212 839bbaae 2023-02-01 op if (fchmod(packfd, GOT_DEFAULT_PACK_MODE) == -1) {
1213 839bbaae 2023-02-01 op err = got_error_from_errno2("fchmod", pack_path);
1214 839bbaae 2023-02-01 op goto done;
1215 839bbaae 2023-02-01 op }
1216 ae7c1b78 2023-01-10 stsp
1217 ae7c1b78 2023-01-10 stsp free(basepath);
1218 ae7c1b78 2023-01-10 stsp if (asprintf(&basepath, "%s/%s/receiving-from-uid-%d.idx",
1219 ae7c1b78 2023-01-10 stsp got_repo_get_path(gotd_session.repo), GOT_OBJECTS_PACK_DIR,
1220 ae7c1b78 2023-01-10 stsp client->euid) == -1) {
1221 ae7c1b78 2023-01-10 stsp err = got_error_from_errno("asprintf");
1222 ae7c1b78 2023-01-10 stsp basepath = NULL;
1223 ae7c1b78 2023-01-10 stsp goto done;
1224 ae7c1b78 2023-01-10 stsp }
1225 ae7c1b78 2023-01-10 stsp err = got_opentemp_named_fd(&idx_path, &idxfd, basepath, "");
1226 ae7c1b78 2023-01-10 stsp if (err)
1227 ae7c1b78 2023-01-10 stsp goto done;
1228 839bbaae 2023-02-01 op if (fchmod(idxfd, GOT_DEFAULT_PACK_MODE) == -1) {
1229 839bbaae 2023-02-01 op err = got_error_from_errno2("fchmod", idx_path);
1230 839bbaae 2023-02-01 op goto done;
1231 839bbaae 2023-02-01 op }
1232 ae7c1b78 2023-01-10 stsp
1233 ae7c1b78 2023-01-10 stsp memset(&ifile, 0, sizeof(ifile));
1234 ae7c1b78 2023-01-10 stsp ifile.client_id = client->id;
1235 ae7c1b78 2023-01-10 stsp if (gotd_imsg_compose_event(&client->repo_child_iev,
1236 b0614828 2023-06-19 stsp GOTD_IMSG_PACKIDX_FILE, gotd_session.proc_id,
1237 ae7c1b78 2023-01-10 stsp idxfd, &ifile, sizeof(ifile)) == -1) {
1238 ae7c1b78 2023-01-10 stsp err = got_error_from_errno("imsg compose PACKIDX_FILE");
1239 ae7c1b78 2023-01-10 stsp idxfd = -1;
1240 ae7c1b78 2023-01-10 stsp goto done;
1241 ae7c1b78 2023-01-10 stsp }
1242 ae7c1b78 2023-01-10 stsp idxfd = -1;
1243 ae7c1b78 2023-01-10 stsp
1244 ae7c1b78 2023-01-10 stsp memset(&ipack, 0, sizeof(ipack));
1245 ae7c1b78 2023-01-10 stsp ipack.client_id = client->id;
1246 ae7c1b78 2023-01-10 stsp if (client_has_capability(client, GOT_CAPA_REPORT_STATUS))
1247 ae7c1b78 2023-01-10 stsp ipack.report_status = 1;
1248 ae7c1b78 2023-01-10 stsp
1249 ae7c1b78 2023-01-10 stsp if (gotd_imsg_compose_event(&client->repo_child_iev,
1250 b0614828 2023-06-19 stsp GOTD_IMSG_RECV_PACKFILE, gotd_session.proc_id, packfd,
1251 ae7c1b78 2023-01-10 stsp &ipack, sizeof(ipack)) == -1) {
1252 ae7c1b78 2023-01-10 stsp err = got_error_from_errno("imsg compose RECV_PACKFILE");
1253 ae7c1b78 2023-01-10 stsp packfd = -1;
1254 ae7c1b78 2023-01-10 stsp goto done;
1255 ae7c1b78 2023-01-10 stsp }
1256 ae7c1b78 2023-01-10 stsp packfd = -1;
1257 ae7c1b78 2023-01-10 stsp
1258 ae7c1b78 2023-01-10 stsp done:
1259 ae7c1b78 2023-01-10 stsp free(basepath);
1260 ae7c1b78 2023-01-10 stsp if (pipe[0] != -1 && close(pipe[0]) == -1 && err == NULL)
1261 ae7c1b78 2023-01-10 stsp err = got_error_from_errno("close");
1262 ae7c1b78 2023-01-10 stsp if (pipe[1] != -1 && close(pipe[1]) == -1 && err == NULL)
1263 ae7c1b78 2023-01-10 stsp err = got_error_from_errno("close");
1264 ae7c1b78 2023-01-10 stsp if (packfd != -1 && close(packfd) == -1 && err == NULL)
1265 ae7c1b78 2023-01-10 stsp err = got_error_from_errno("close");
1266 ae7c1b78 2023-01-10 stsp if (idxfd != -1 && close(idxfd) == -1 && err == NULL)
1267 ae7c1b78 2023-01-10 stsp err = got_error_from_errno("close");
1268 ae7c1b78 2023-01-10 stsp if (err) {
1269 ae7c1b78 2023-01-10 stsp free(pack_path);
1270 ae7c1b78 2023-01-10 stsp free(idx_path);
1271 ae7c1b78 2023-01-10 stsp } else {
1272 ae7c1b78 2023-01-10 stsp client->packfile_path = pack_path;
1273 ae7c1b78 2023-01-10 stsp client->packidx_path = idx_path;
1274 ae7c1b78 2023-01-10 stsp }
1275 ae7c1b78 2023-01-10 stsp return err;
1276 ae7c1b78 2023-01-10 stsp }
1277 ae7c1b78 2023-01-10 stsp
1278 ae7c1b78 2023-01-10 stsp static const struct got_error *
1279 ae7c1b78 2023-01-10 stsp send_packfile(struct gotd_session_client *client)
1280 ae7c1b78 2023-01-10 stsp {
1281 ae7c1b78 2023-01-10 stsp const struct got_error *err = NULL;
1282 ae7c1b78 2023-01-10 stsp struct gotd_imsg_send_packfile ipack;
1283 ae7c1b78 2023-01-10 stsp struct gotd_imsg_packfile_pipe ipipe;
1284 ae7c1b78 2023-01-10 stsp int pipe[2];
1285 ae7c1b78 2023-01-10 stsp
1286 ae7c1b78 2023-01-10 stsp if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe) == -1)
1287 ae7c1b78 2023-01-10 stsp return got_error_from_errno("socketpair");
1288 ae7c1b78 2023-01-10 stsp
1289 ae7c1b78 2023-01-10 stsp memset(&ipack, 0, sizeof(ipack));
1290 ae7c1b78 2023-01-10 stsp memset(&ipipe, 0, sizeof(ipipe));
1291 ae7c1b78 2023-01-10 stsp
1292 ae7c1b78 2023-01-10 stsp ipack.client_id = client->id;
1293 ae7c1b78 2023-01-10 stsp if (client_has_capability(client, GOT_CAPA_SIDE_BAND_64K))
1294 ae7c1b78 2023-01-10 stsp ipack.report_progress = 1;
1295 ae7c1b78 2023-01-10 stsp
1296 ae7c1b78 2023-01-10 stsp client->delta_cache_fd = got_opentempfd();
1297 ae7c1b78 2023-01-10 stsp if (client->delta_cache_fd == -1)
1298 ae7c1b78 2023-01-10 stsp return got_error_from_errno("got_opentempfd");
1299 ae7c1b78 2023-01-10 stsp
1300 ae7c1b78 2023-01-10 stsp if (gotd_imsg_compose_event(&client->repo_child_iev,
1301 ae7c1b78 2023-01-10 stsp GOTD_IMSG_SEND_PACKFILE, PROC_GOTD, client->delta_cache_fd,
1302 ae7c1b78 2023-01-10 stsp &ipack, sizeof(ipack)) == -1) {
1303 ae7c1b78 2023-01-10 stsp err = got_error_from_errno("imsg compose SEND_PACKFILE");
1304 ae7c1b78 2023-01-10 stsp close(pipe[0]);
1305 ae7c1b78 2023-01-10 stsp close(pipe[1]);
1306 ae7c1b78 2023-01-10 stsp return err;
1307 ae7c1b78 2023-01-10 stsp }
1308 ae7c1b78 2023-01-10 stsp
1309 ae7c1b78 2023-01-10 stsp ipipe.client_id = client->id;
1310 ae7c1b78 2023-01-10 stsp
1311 ae7c1b78 2023-01-10 stsp /* Send pack pipe end 0 to repo child process. */
1312 ae7c1b78 2023-01-10 stsp if (gotd_imsg_compose_event(&client->repo_child_iev,
1313 ae7c1b78 2023-01-10 stsp GOTD_IMSG_PACKFILE_PIPE, PROC_GOTD,
1314 ae7c1b78 2023-01-10 stsp pipe[0], &ipipe, sizeof(ipipe)) == -1) {
1315 ae7c1b78 2023-01-10 stsp err = got_error_from_errno("imsg compose PACKFILE_PIPE");
1316 ae7c1b78 2023-01-10 stsp close(pipe[1]);
1317 ae7c1b78 2023-01-10 stsp return err;
1318 ae7c1b78 2023-01-10 stsp }
1319 ae7c1b78 2023-01-10 stsp
1320 ae7c1b78 2023-01-10 stsp /* Send pack pipe end 1 to gotsh(1) (expects just an fd, no data). */
1321 ae7c1b78 2023-01-10 stsp if (gotd_imsg_compose_event(&client->iev,
1322 ae7c1b78 2023-01-10 stsp GOTD_IMSG_PACKFILE_PIPE, PROC_GOTD, pipe[1], NULL, 0) == -1)
1323 ae7c1b78 2023-01-10 stsp err = got_error_from_errno("imsg compose PACKFILE_PIPE");
1324 ae7c1b78 2023-01-10 stsp
1325 ae7c1b78 2023-01-10 stsp return err;
1326 ae7c1b78 2023-01-10 stsp }
1327 ae7c1b78 2023-01-10 stsp
1328 ae7c1b78 2023-01-10 stsp static void
1329 3931a8a4 2023-02-03 stsp session_dispatch_client(int fd, short events, void *arg)
1330 ae7c1b78 2023-01-10 stsp {
1331 ae7c1b78 2023-01-10 stsp struct gotd_imsgev *iev = arg;
1332 ae7c1b78 2023-01-10 stsp struct imsgbuf *ibuf = &iev->ibuf;
1333 ae7c1b78 2023-01-10 stsp struct gotd_session_client *client = &gotd_session_client;
1334 ae7c1b78 2023-01-10 stsp const struct got_error *err = NULL;
1335 ae7c1b78 2023-01-10 stsp struct imsg imsg;
1336 ae7c1b78 2023-01-10 stsp ssize_t n;
1337 ae7c1b78 2023-01-10 stsp
1338 ae7c1b78 2023-01-10 stsp if (events & EV_WRITE) {
1339 ae7c1b78 2023-01-10 stsp while (ibuf->w.queued) {
1340 ae7c1b78 2023-01-10 stsp n = msgbuf_write(&ibuf->w);
1341 ae7c1b78 2023-01-10 stsp if (n == -1 && errno == EPIPE) {
1342 ae7c1b78 2023-01-10 stsp /*
1343 ae7c1b78 2023-01-10 stsp * The client has closed its socket.
1344 ae7c1b78 2023-01-10 stsp * This can happen when Git clients are
1345 ae7c1b78 2023-01-10 stsp * done sending pack file data.
1346 ae7c1b78 2023-01-10 stsp */
1347 ae7c1b78 2023-01-10 stsp msgbuf_clear(&ibuf->w);
1348 ae7c1b78 2023-01-10 stsp continue;
1349 ae7c1b78 2023-01-10 stsp } else if (n == -1 && errno != EAGAIN) {
1350 ae7c1b78 2023-01-10 stsp err = got_error_from_errno("imsg_flush");
1351 ae7c1b78 2023-01-10 stsp disconnect_on_error(client, err);
1352 ae7c1b78 2023-01-10 stsp return;
1353 ae7c1b78 2023-01-10 stsp }
1354 ae7c1b78 2023-01-10 stsp if (n == 0) {
1355 ae7c1b78 2023-01-10 stsp /* Connection closed. */
1356 ae7c1b78 2023-01-10 stsp err = got_error(GOT_ERR_EOF);
1357 ae7c1b78 2023-01-10 stsp disconnect_on_error(client, err);
1358 ae7c1b78 2023-01-10 stsp return;
1359 ae7c1b78 2023-01-10 stsp }
1360 808264b2 2023-08-22 stsp }
1361 808264b2 2023-08-22 stsp
1362 808264b2 2023-08-22 stsp if (client->flush_disconnect) {
1363 808264b2 2023-08-22 stsp disconnect(client);
1364 808264b2 2023-08-22 stsp return;
1365 ae7c1b78 2023-01-10 stsp }
1366 ae7c1b78 2023-01-10 stsp }
1367 ae7c1b78 2023-01-10 stsp
1368 ae7c1b78 2023-01-10 stsp if ((events & EV_READ) == 0)
1369 ae7c1b78 2023-01-10 stsp return;
1370 ae7c1b78 2023-01-10 stsp
1371 ae7c1b78 2023-01-10 stsp memset(&imsg, 0, sizeof(imsg));
1372 ae7c1b78 2023-01-10 stsp
1373 ae7c1b78 2023-01-10 stsp while (err == NULL) {
1374 ae7c1b78 2023-01-10 stsp err = gotd_imsg_recv(&imsg, ibuf, 0);
1375 ae7c1b78 2023-01-10 stsp if (err) {
1376 ae7c1b78 2023-01-10 stsp if (err->code == GOT_ERR_PRIVSEP_READ)
1377 ae7c1b78 2023-01-10 stsp err = NULL;
1378 baaae615 2023-06-07 stsp else if (err->code == GOT_ERR_EOF &&
1379 baaae615 2023-06-07 stsp client->state == GOTD_STATE_EXPECT_CAPABILITIES) {
1380 baaae615 2023-06-07 stsp /*
1381 baaae615 2023-06-07 stsp * The client has closed its socket before
1382 baaae615 2023-06-07 stsp * sending its capability announcement.
1383 baaae615 2023-06-07 stsp * This can happen when Git clients have
1384 baaae615 2023-06-07 stsp * no ref-updates to send.
1385 baaae615 2023-06-07 stsp */
1386 baaae615 2023-06-07 stsp disconnect_on_error(client, err);
1387 baaae615 2023-06-07 stsp return;
1388 baaae615 2023-06-07 stsp }
1389 ae7c1b78 2023-01-10 stsp break;
1390 ae7c1b78 2023-01-10 stsp }
1391 ae7c1b78 2023-01-10 stsp
1392 ae7c1b78 2023-01-10 stsp evtimer_del(&client->tmo);
1393 ae7c1b78 2023-01-10 stsp
1394 ae7c1b78 2023-01-10 stsp switch (imsg.hdr.type) {
1395 ae7c1b78 2023-01-10 stsp case GOTD_IMSG_CAPABILITIES:
1396 ae7c1b78 2023-01-10 stsp if (client->state != GOTD_STATE_EXPECT_CAPABILITIES) {
1397 ae7c1b78 2023-01-10 stsp err = got_error_msg(GOT_ERR_BAD_REQUEST,
1398 ae7c1b78 2023-01-10 stsp "unexpected capabilities received");
1399 ae7c1b78 2023-01-10 stsp break;
1400 ae7c1b78 2023-01-10 stsp }
1401 ae7c1b78 2023-01-10 stsp log_debug("receiving capabilities from uid %d",
1402 ae7c1b78 2023-01-10 stsp client->euid);
1403 ae7c1b78 2023-01-10 stsp err = recv_capabilities(client, &imsg);
1404 ae7c1b78 2023-01-10 stsp break;
1405 ae7c1b78 2023-01-10 stsp case GOTD_IMSG_CAPABILITY:
1406 ae7c1b78 2023-01-10 stsp if (client->state != GOTD_STATE_EXPECT_CAPABILITIES) {
1407 ae7c1b78 2023-01-10 stsp err = got_error_msg(GOT_ERR_BAD_REQUEST,
1408 ae7c1b78 2023-01-10 stsp "unexpected capability received");
1409 ae7c1b78 2023-01-10 stsp break;
1410 ae7c1b78 2023-01-10 stsp }
1411 ae7c1b78 2023-01-10 stsp err = recv_capability(client, &imsg);
1412 ae7c1b78 2023-01-10 stsp if (err || client->ncapabilities < client->ncapa_alloc)
1413 ae7c1b78 2023-01-10 stsp break;
1414 ae7c1b78 2023-01-10 stsp if (!client->is_writing) {
1415 ae7c1b78 2023-01-10 stsp client->state = GOTD_STATE_EXPECT_WANT;
1416 3448a19a 2023-01-21 stsp client->accept_flush_pkt = 1;
1417 ae7c1b78 2023-01-10 stsp log_debug("uid %d: expecting want-lines",
1418 ae7c1b78 2023-01-10 stsp client->euid);
1419 ae7c1b78 2023-01-10 stsp } else if (client->is_writing) {
1420 ae7c1b78 2023-01-10 stsp client->state = GOTD_STATE_EXPECT_REF_UPDATE;
1421 3448a19a 2023-01-21 stsp client->accept_flush_pkt = 1;
1422 ae7c1b78 2023-01-10 stsp log_debug("uid %d: expecting ref-update-lines",
1423 ae7c1b78 2023-01-10 stsp client->euid);
1424 ae7c1b78 2023-01-10 stsp } else
1425 ae7c1b78 2023-01-10 stsp fatalx("client %d is both reading and writing",
1426 ae7c1b78 2023-01-10 stsp client->euid);
1427 ae7c1b78 2023-01-10 stsp break;
1428 ae7c1b78 2023-01-10 stsp case GOTD_IMSG_WANT:
1429 ae7c1b78 2023-01-10 stsp if (client->state != GOTD_STATE_EXPECT_WANT) {
1430 ae7c1b78 2023-01-10 stsp err = got_error_msg(GOT_ERR_BAD_REQUEST,
1431 ae7c1b78 2023-01-10 stsp "unexpected want-line received");
1432 ae7c1b78 2023-01-10 stsp break;
1433 ae7c1b78 2023-01-10 stsp }
1434 ae7c1b78 2023-01-10 stsp log_debug("received want-line from uid %d",
1435 ae7c1b78 2023-01-10 stsp client->euid);
1436 ae7c1b78 2023-01-10 stsp err = ensure_client_is_reading(client);
1437 ae7c1b78 2023-01-10 stsp if (err)
1438 ae7c1b78 2023-01-10 stsp break;
1439 3448a19a 2023-01-21 stsp client->accept_flush_pkt = 1;
1440 ae7c1b78 2023-01-10 stsp err = forward_want(client, &imsg);
1441 ae7c1b78 2023-01-10 stsp break;
1442 ae7c1b78 2023-01-10 stsp case GOTD_IMSG_REF_UPDATE:
1443 6da1c69c 2023-01-18 stsp if (client->state != GOTD_STATE_EXPECT_REF_UPDATE &&
1444 6da1c69c 2023-01-18 stsp client->state !=
1445 6da1c69c 2023-01-18 stsp GOTD_STATE_EXPECT_MORE_REF_UPDATES) {
1446 ae7c1b78 2023-01-10 stsp err = got_error_msg(GOT_ERR_BAD_REQUEST,
1447 ae7c1b78 2023-01-10 stsp "unexpected ref-update-line received");
1448 ae7c1b78 2023-01-10 stsp break;
1449 ae7c1b78 2023-01-10 stsp }
1450 ae7c1b78 2023-01-10 stsp log_debug("received ref-update-line from uid %d",
1451 ae7c1b78 2023-01-10 stsp client->euid);
1452 ae7c1b78 2023-01-10 stsp err = ensure_client_is_writing(client);
1453 ae7c1b78 2023-01-10 stsp if (err)
1454 ae7c1b78 2023-01-10 stsp break;
1455 ae7c1b78 2023-01-10 stsp err = forward_ref_update(client, &imsg);
1456 ae7c1b78 2023-01-10 stsp if (err)
1457 ae7c1b78 2023-01-10 stsp break;
1458 ae7c1b78 2023-01-10 stsp client->state = GOTD_STATE_EXPECT_MORE_REF_UPDATES;
1459 3448a19a 2023-01-21 stsp client->accept_flush_pkt = 1;
1460 ae7c1b78 2023-01-10 stsp break;
1461 ae7c1b78 2023-01-10 stsp case GOTD_IMSG_HAVE:
1462 ae7c1b78 2023-01-10 stsp if (client->state != GOTD_STATE_EXPECT_HAVE) {
1463 ae7c1b78 2023-01-10 stsp err = got_error_msg(GOT_ERR_BAD_REQUEST,
1464 ae7c1b78 2023-01-10 stsp "unexpected have-line received");
1465 ae7c1b78 2023-01-10 stsp break;
1466 ae7c1b78 2023-01-10 stsp }
1467 ae7c1b78 2023-01-10 stsp log_debug("received have-line from uid %d",
1468 ae7c1b78 2023-01-10 stsp client->euid);
1469 ae7c1b78 2023-01-10 stsp err = ensure_client_is_reading(client);
1470 ae7c1b78 2023-01-10 stsp if (err)
1471 ae7c1b78 2023-01-10 stsp break;
1472 ae7c1b78 2023-01-10 stsp err = forward_have(client, &imsg);
1473 ae7c1b78 2023-01-10 stsp if (err)
1474 ae7c1b78 2023-01-10 stsp break;
1475 3448a19a 2023-01-21 stsp client->accept_flush_pkt = 1;
1476 ae7c1b78 2023-01-10 stsp break;
1477 ae7c1b78 2023-01-10 stsp case GOTD_IMSG_FLUSH:
1478 ae7c1b78 2023-01-10 stsp if (client->state == GOTD_STATE_EXPECT_WANT ||
1479 ae7c1b78 2023-01-10 stsp client->state == GOTD_STATE_EXPECT_HAVE) {
1480 ae7c1b78 2023-01-10 stsp err = ensure_client_is_reading(client);
1481 ae7c1b78 2023-01-10 stsp if (err)
1482 ae7c1b78 2023-01-10 stsp break;
1483 ae7c1b78 2023-01-10 stsp } else if (client->state ==
1484 ae7c1b78 2023-01-10 stsp GOTD_STATE_EXPECT_MORE_REF_UPDATES) {
1485 ae7c1b78 2023-01-10 stsp err = ensure_client_is_writing(client);
1486 ae7c1b78 2023-01-10 stsp if (err)
1487 ae7c1b78 2023-01-10 stsp break;
1488 f9550d47 2023-01-18 stsp } else if (client->state != GOTD_STATE_EXPECT_DONE) {
1489 3448a19a 2023-01-21 stsp err = got_error_msg(GOT_ERR_BAD_REQUEST,
1490 3448a19a 2023-01-21 stsp "unexpected flush-pkt received");
1491 3448a19a 2023-01-21 stsp break;
1492 3448a19a 2023-01-21 stsp }
1493 3448a19a 2023-01-21 stsp if (!client->accept_flush_pkt) {
1494 ae7c1b78 2023-01-10 stsp err = got_error_msg(GOT_ERR_BAD_REQUEST,
1495 ae7c1b78 2023-01-10 stsp "unexpected flush-pkt received");
1496 ae7c1b78 2023-01-10 stsp break;
1497 ae7c1b78 2023-01-10 stsp }
1498 3448a19a 2023-01-21 stsp
1499 3448a19a 2023-01-21 stsp /*
1500 3448a19a 2023-01-21 stsp * Accept just one flush packet at a time.
1501 3448a19a 2023-01-21 stsp * Future client state transitions will set this flag
1502 3448a19a 2023-01-21 stsp * again if another flush packet is expected.
1503 3448a19a 2023-01-21 stsp */
1504 3448a19a 2023-01-21 stsp client->accept_flush_pkt = 0;
1505 3448a19a 2023-01-21 stsp
1506 ae7c1b78 2023-01-10 stsp log_debug("received flush-pkt from uid %d",
1507 ae7c1b78 2023-01-10 stsp client->euid);
1508 ae7c1b78 2023-01-10 stsp if (client->state == GOTD_STATE_EXPECT_WANT) {
1509 ae7c1b78 2023-01-10 stsp client->state = GOTD_STATE_EXPECT_HAVE;
1510 ae7c1b78 2023-01-10 stsp log_debug("uid %d: expecting have-lines",
1511 ae7c1b78 2023-01-10 stsp client->euid);
1512 ae7c1b78 2023-01-10 stsp } else if (client->state == GOTD_STATE_EXPECT_HAVE) {
1513 ae7c1b78 2023-01-10 stsp client->state = GOTD_STATE_EXPECT_DONE;
1514 3448a19a 2023-01-21 stsp client->accept_flush_pkt = 1;
1515 ae7c1b78 2023-01-10 stsp log_debug("uid %d: expecting 'done'",
1516 ae7c1b78 2023-01-10 stsp client->euid);
1517 ae7c1b78 2023-01-10 stsp } else if (client->state ==
1518 ae7c1b78 2023-01-10 stsp GOTD_STATE_EXPECT_MORE_REF_UPDATES) {
1519 ae7c1b78 2023-01-10 stsp client->state = GOTD_STATE_EXPECT_PACKFILE;
1520 ae7c1b78 2023-01-10 stsp log_debug("uid %d: expecting packfile",
1521 ae7c1b78 2023-01-10 stsp client->euid);
1522 ae7c1b78 2023-01-10 stsp err = recv_packfile(client);
1523 f9550d47 2023-01-18 stsp } else if (client->state != GOTD_STATE_EXPECT_DONE) {
1524 ae7c1b78 2023-01-10 stsp /* should not happen, see above */
1525 ae7c1b78 2023-01-10 stsp err = got_error_msg(GOT_ERR_BAD_REQUEST,
1526 ae7c1b78 2023-01-10 stsp "unexpected client state");
1527 ae7c1b78 2023-01-10 stsp break;
1528 ae7c1b78 2023-01-10 stsp }
1529 ae7c1b78 2023-01-10 stsp break;
1530 ae7c1b78 2023-01-10 stsp case GOTD_IMSG_DONE:
1531 ae7c1b78 2023-01-10 stsp if (client->state != GOTD_STATE_EXPECT_HAVE &&
1532 ae7c1b78 2023-01-10 stsp client->state != GOTD_STATE_EXPECT_DONE) {
1533 ae7c1b78 2023-01-10 stsp err = got_error_msg(GOT_ERR_BAD_REQUEST,
1534 ae7c1b78 2023-01-10 stsp "unexpected flush-pkt received");
1535 ae7c1b78 2023-01-10 stsp break;
1536 ae7c1b78 2023-01-10 stsp }
1537 ae7c1b78 2023-01-10 stsp log_debug("received 'done' from uid %d", client->euid);
1538 ae7c1b78 2023-01-10 stsp err = ensure_client_is_reading(client);
1539 ae7c1b78 2023-01-10 stsp if (err)
1540 ae7c1b78 2023-01-10 stsp break;
1541 ae7c1b78 2023-01-10 stsp client->state = GOTD_STATE_DONE;
1542 3448a19a 2023-01-21 stsp client->accept_flush_pkt = 1;
1543 ae7c1b78 2023-01-10 stsp err = send_packfile(client);
1544 ae7c1b78 2023-01-10 stsp break;
1545 ae7c1b78 2023-01-10 stsp default:
1546 ae7c1b78 2023-01-10 stsp log_debug("unexpected imsg %d", imsg.hdr.type);
1547 ae7c1b78 2023-01-10 stsp err = got_error(GOT_ERR_PRIVSEP_MSG);
1548 ae7c1b78 2023-01-10 stsp break;
1549 ae7c1b78 2023-01-10 stsp }
1550 ae7c1b78 2023-01-10 stsp
1551 ae7c1b78 2023-01-10 stsp imsg_free(&imsg);
1552 ae7c1b78 2023-01-10 stsp }
1553 ae7c1b78 2023-01-10 stsp
1554 ae7c1b78 2023-01-10 stsp if (err) {
1555 ae7c1b78 2023-01-10 stsp if (err->code != GOT_ERR_EOF ||
1556 ae7c1b78 2023-01-10 stsp client->state != GOTD_STATE_EXPECT_PACKFILE)
1557 ae7c1b78 2023-01-10 stsp disconnect_on_error(client, err);
1558 ae7c1b78 2023-01-10 stsp } else {
1559 ae7c1b78 2023-01-10 stsp gotd_imsg_event_add(iev);
1560 ae7c1b78 2023-01-10 stsp evtimer_add(&client->tmo, &gotd_session.request_timeout);
1561 ae7c1b78 2023-01-10 stsp }
1562 ae7c1b78 2023-01-10 stsp }
1563 ae7c1b78 2023-01-10 stsp
1564 ae7c1b78 2023-01-10 stsp static const struct got_error *
1565 ae7c1b78 2023-01-10 stsp list_refs_request(void)
1566 ae7c1b78 2023-01-10 stsp {
1567 ae7c1b78 2023-01-10 stsp static const struct got_error *err;
1568 ae7c1b78 2023-01-10 stsp struct gotd_session_client *client = &gotd_session_client;
1569 ae7c1b78 2023-01-10 stsp struct gotd_imsgev *iev = &client->repo_child_iev;
1570 ae7c1b78 2023-01-10 stsp struct gotd_imsg_list_refs_internal ilref;
1571 ae7c1b78 2023-01-10 stsp int fd;
1572 ae7c1b78 2023-01-10 stsp
1573 ae7c1b78 2023-01-10 stsp if (client->state != GOTD_STATE_EXPECT_LIST_REFS)
1574 ae7c1b78 2023-01-10 stsp return got_error(GOT_ERR_PRIVSEP_MSG);
1575 ae7c1b78 2023-01-10 stsp
1576 ae7c1b78 2023-01-10 stsp memset(&ilref, 0, sizeof(ilref));
1577 ae7c1b78 2023-01-10 stsp ilref.client_id = client->id;
1578 ae7c1b78 2023-01-10 stsp
1579 ae7c1b78 2023-01-10 stsp fd = dup(client->fd);
1580 ae7c1b78 2023-01-10 stsp if (fd == -1)
1581 ae7c1b78 2023-01-10 stsp return got_error_from_errno("dup");
1582 ae7c1b78 2023-01-10 stsp
1583 ae7c1b78 2023-01-10 stsp if (gotd_imsg_compose_event(iev, GOTD_IMSG_LIST_REFS_INTERNAL,
1584 b0614828 2023-06-19 stsp gotd_session.proc_id, fd, &ilref, sizeof(ilref)) == -1) {
1585 ae7c1b78 2023-01-10 stsp err = got_error_from_errno("imsg compose LIST_REFS_INTERNAL");
1586 ae7c1b78 2023-01-10 stsp close(fd);
1587 ae7c1b78 2023-01-10 stsp return err;
1588 ae7c1b78 2023-01-10 stsp }
1589 ae7c1b78 2023-01-10 stsp
1590 ae7c1b78 2023-01-10 stsp client->state = GOTD_STATE_EXPECT_CAPABILITIES;
1591 ae7c1b78 2023-01-10 stsp log_debug("uid %d: expecting capabilities", client->euid);
1592 ae7c1b78 2023-01-10 stsp return NULL;
1593 ae7c1b78 2023-01-10 stsp }
1594 ae7c1b78 2023-01-10 stsp
1595 ae7c1b78 2023-01-10 stsp static const struct got_error *
1596 ae7c1b78 2023-01-10 stsp recv_connect(struct imsg *imsg)
1597 ae7c1b78 2023-01-10 stsp {
1598 ae7c1b78 2023-01-10 stsp struct gotd_session_client *client = &gotd_session_client;
1599 ae7c1b78 2023-01-10 stsp struct gotd_imsg_connect iconnect;
1600 ae7c1b78 2023-01-10 stsp size_t datalen;
1601 ae7c1b78 2023-01-10 stsp
1602 ae7c1b78 2023-01-10 stsp if (client->state != GOTD_STATE_EXPECT_LIST_REFS)
1603 ae7c1b78 2023-01-10 stsp return got_error(GOT_ERR_PRIVSEP_MSG);
1604 ae7c1b78 2023-01-10 stsp
1605 ae7c1b78 2023-01-10 stsp datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
1606 ba97b2d7 2024-03-20 stsp if (datalen < sizeof(iconnect))
1607 ae7c1b78 2023-01-10 stsp return got_error(GOT_ERR_PRIVSEP_LEN);
1608 ae7c1b78 2023-01-10 stsp memcpy(&iconnect, imsg->data, sizeof(iconnect));
1609 ba97b2d7 2024-03-20 stsp if (iconnect.username_len == 0 ||
1610 ba97b2d7 2024-03-20 stsp datalen != sizeof(iconnect) + iconnect.username_len)
1611 ba97b2d7 2024-03-20 stsp return got_error(GOT_ERR_PRIVSEP_LEN);
1612 ae7c1b78 2023-01-10 stsp
1613 ae7c1b78 2023-01-10 stsp client->euid = iconnect.euid;
1614 ae7c1b78 2023-01-10 stsp client->egid = iconnect.egid;
1615 2c52c623 2024-01-30 op client->fd = imsg_get_fd(imsg);
1616 2c52c623 2024-01-30 op if (client->fd == -1)
1617 2c52c623 2024-01-30 op return got_error(GOT_ERR_PRIVSEP_NO_FD);
1618 ae7c1b78 2023-01-10 stsp
1619 ba97b2d7 2024-03-20 stsp client->username = strndup(imsg->data + sizeof(iconnect),
1620 ba97b2d7 2024-03-20 stsp iconnect.username_len);
1621 ba97b2d7 2024-03-20 stsp if (client->username == NULL)
1622 ba97b2d7 2024-03-20 stsp return got_error_from_errno("strndup");
1623 ba97b2d7 2024-03-20 stsp
1624 ae7c1b78 2023-01-10 stsp imsg_init(&client->iev.ibuf, client->fd);
1625 3931a8a4 2023-02-03 stsp client->iev.handler = session_dispatch_client;
1626 ae7c1b78 2023-01-10 stsp client->iev.events = EV_READ;
1627 ae7c1b78 2023-01-10 stsp client->iev.handler_arg = NULL;
1628 ae7c1b78 2023-01-10 stsp event_set(&client->iev.ev, client->iev.ibuf.fd, EV_READ,
1629 3931a8a4 2023-02-03 stsp session_dispatch_client, &client->iev);
1630 ae7c1b78 2023-01-10 stsp gotd_imsg_event_add(&client->iev);
1631 ae7c1b78 2023-01-10 stsp evtimer_set(&client->tmo, gotd_request_timeout, client);
1632 ae7c1b78 2023-01-10 stsp
1633 ae7c1b78 2023-01-10 stsp return NULL;
1634 ae7c1b78 2023-01-10 stsp }
1635 ae7c1b78 2023-01-10 stsp
1636 ba97b2d7 2024-03-20 stsp static void
1637 ba97b2d7 2024-03-20 stsp session_dispatch_notifier(int fd, short event, void *arg)
1638 ba97b2d7 2024-03-20 stsp {
1639 ba97b2d7 2024-03-20 stsp const struct got_error *err;
1640 ba97b2d7 2024-03-20 stsp struct gotd_session_client *client = &gotd_session_client;
1641 ba97b2d7 2024-03-20 stsp struct gotd_imsgev *iev = arg;
1642 ba97b2d7 2024-03-20 stsp struct imsgbuf *ibuf = &iev->ibuf;
1643 ba97b2d7 2024-03-20 stsp ssize_t n;
1644 ba97b2d7 2024-03-20 stsp int shut = 0;
1645 ba97b2d7 2024-03-20 stsp struct imsg imsg;
1646 ba97b2d7 2024-03-20 stsp struct gotd_session_notif *notif;
1647 ba97b2d7 2024-03-20 stsp
1648 ba97b2d7 2024-03-20 stsp if (event & EV_READ) {
1649 ba97b2d7 2024-03-20 stsp if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
1650 ba97b2d7 2024-03-20 stsp fatal("imsg_read error");
1651 ba97b2d7 2024-03-20 stsp if (n == 0) {
1652 ba97b2d7 2024-03-20 stsp /* Connection closed. */
1653 ba97b2d7 2024-03-20 stsp shut = 1;
1654 ba97b2d7 2024-03-20 stsp goto done;
1655 ba97b2d7 2024-03-20 stsp }
1656 ba97b2d7 2024-03-20 stsp }
1657 ba97b2d7 2024-03-20 stsp
1658 ba97b2d7 2024-03-20 stsp if (event & EV_WRITE) {
1659 ba97b2d7 2024-03-20 stsp n = msgbuf_write(&ibuf->w);
1660 ba97b2d7 2024-03-20 stsp if (n == -1 && errno != EAGAIN)
1661 ba97b2d7 2024-03-20 stsp fatal("msgbuf_write");
1662 ba97b2d7 2024-03-20 stsp if (n == 0) {
1663 ba97b2d7 2024-03-20 stsp /* Connection closed. */
1664 ba97b2d7 2024-03-20 stsp shut = 1;
1665 ba97b2d7 2024-03-20 stsp goto done;
1666 ba97b2d7 2024-03-20 stsp }
1667 ba97b2d7 2024-03-20 stsp }
1668 ba97b2d7 2024-03-20 stsp
1669 ba97b2d7 2024-03-20 stsp for (;;) {
1670 ba97b2d7 2024-03-20 stsp if ((n = imsg_get(ibuf, &imsg)) == -1)
1671 ba97b2d7 2024-03-20 stsp fatal("%s: imsg_get error", __func__);
1672 ba97b2d7 2024-03-20 stsp if (n == 0) /* No more messages. */
1673 ba97b2d7 2024-03-20 stsp break;
1674 ba97b2d7 2024-03-20 stsp
1675 ba97b2d7 2024-03-20 stsp switch (imsg.hdr.type) {
1676 ba97b2d7 2024-03-20 stsp case GOTD_IMSG_NOTIFICATION_SENT:
1677 ba97b2d7 2024-03-20 stsp if (client->state != GOTD_STATE_NOTIFY) {
1678 ba97b2d7 2024-03-20 stsp log_warn("unexpected imsg %d", imsg.hdr.type);
1679 ba97b2d7 2024-03-20 stsp break;
1680 ba97b2d7 2024-03-20 stsp }
1681 ba97b2d7 2024-03-20 stsp notif = STAILQ_FIRST(&notifications);
1682 ba97b2d7 2024-03-20 stsp if (notif == NULL) {
1683 ba97b2d7 2024-03-20 stsp disconnect(client);
1684 ba97b2d7 2024-03-20 stsp break; /* NOTREACHED */
1685 ba97b2d7 2024-03-20 stsp }
1686 ba97b2d7 2024-03-20 stsp /* Request content for the next notification. */
1687 ba97b2d7 2024-03-20 stsp err = request_notification(notif);
1688 ba97b2d7 2024-03-20 stsp if (err) {
1689 ba97b2d7 2024-03-20 stsp log_warn("could not send notification: %s",
1690 ba97b2d7 2024-03-20 stsp err->msg);
1691 ba97b2d7 2024-03-20 stsp disconnect(client);
1692 ba97b2d7 2024-03-20 stsp }
1693 ba97b2d7 2024-03-20 stsp break;
1694 ba97b2d7 2024-03-20 stsp default:
1695 ba97b2d7 2024-03-20 stsp log_debug("unexpected imsg %d", imsg.hdr.type);
1696 ba97b2d7 2024-03-20 stsp break;
1697 ba97b2d7 2024-03-20 stsp }
1698 ba97b2d7 2024-03-20 stsp
1699 ba97b2d7 2024-03-20 stsp imsg_free(&imsg);
1700 ba97b2d7 2024-03-20 stsp }
1701 ba97b2d7 2024-03-20 stsp done:
1702 ba97b2d7 2024-03-20 stsp if (!shut) {
1703 ba97b2d7 2024-03-20 stsp gotd_imsg_event_add(iev);
1704 ba97b2d7 2024-03-20 stsp } else {
1705 ba97b2d7 2024-03-20 stsp /* This pipe is dead. Remove its event handler */
1706 ba97b2d7 2024-03-20 stsp event_del(&iev->ev);
1707 ba97b2d7 2024-03-20 stsp imsg_clear(&iev->ibuf);
1708 ba97b2d7 2024-03-20 stsp imsg_init(&iev->ibuf, -1);
1709 ba97b2d7 2024-03-20 stsp }
1710 ba97b2d7 2024-03-20 stsp }
1711 ba97b2d7 2024-03-20 stsp
1712 ae7c1b78 2023-01-10 stsp static const struct got_error *
1713 ba97b2d7 2024-03-20 stsp recv_notifier(struct imsg *imsg)
1714 ba97b2d7 2024-03-20 stsp {
1715 ba97b2d7 2024-03-20 stsp struct gotd_imsgev *iev = &gotd_session.notifier_iev;
1716 ba97b2d7 2024-03-20 stsp struct gotd_session_client *client = &gotd_session_client;
1717 ba97b2d7 2024-03-20 stsp size_t datalen;
1718 ba97b2d7 2024-03-20 stsp int fd;
1719 ba97b2d7 2024-03-20 stsp
1720 ba97b2d7 2024-03-20 stsp if (client->state != GOTD_STATE_EXPECT_LIST_REFS)
1721 ba97b2d7 2024-03-20 stsp return got_error(GOT_ERR_PRIVSEP_MSG);
1722 ba97b2d7 2024-03-20 stsp
1723 ba97b2d7 2024-03-20 stsp /* We should already have received a pipe to the listener. */
1724 ba97b2d7 2024-03-20 stsp if (client->fd == -1)
1725 ba97b2d7 2024-03-20 stsp return got_error(GOT_ERR_PRIVSEP_MSG);
1726 ba97b2d7 2024-03-20 stsp
1727 ba97b2d7 2024-03-20 stsp datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
1728 ba97b2d7 2024-03-20 stsp if (datalen != 0)
1729 ba97b2d7 2024-03-20 stsp return got_error(GOT_ERR_PRIVSEP_LEN);
1730 ba97b2d7 2024-03-20 stsp
1731 ba97b2d7 2024-03-20 stsp fd = imsg_get_fd(imsg);
1732 ba97b2d7 2024-03-20 stsp if (fd == -1)
1733 ba97b2d7 2024-03-20 stsp return NULL; /* notifications unused */
1734 ba97b2d7 2024-03-20 stsp
1735 ba97b2d7 2024-03-20 stsp imsg_init(&iev->ibuf, fd);
1736 ba97b2d7 2024-03-20 stsp iev->handler = session_dispatch_notifier;
1737 ba97b2d7 2024-03-20 stsp iev->events = EV_READ;
1738 ba97b2d7 2024-03-20 stsp iev->handler_arg = NULL;
1739 ba97b2d7 2024-03-20 stsp event_set(&iev->ev, iev->ibuf.fd, EV_READ,
1740 ba97b2d7 2024-03-20 stsp session_dispatch_notifier, iev);
1741 ba97b2d7 2024-03-20 stsp gotd_imsg_event_add(iev);
1742 ba97b2d7 2024-03-20 stsp
1743 ba97b2d7 2024-03-20 stsp return NULL;
1744 ba97b2d7 2024-03-20 stsp }
1745 ba97b2d7 2024-03-20 stsp
1746 ba97b2d7 2024-03-20 stsp static const struct got_error *
1747 ae7c1b78 2023-01-10 stsp recv_repo_child(struct imsg *imsg)
1748 ae7c1b78 2023-01-10 stsp {
1749 ae7c1b78 2023-01-10 stsp struct gotd_imsg_connect_repo_child ichild;
1750 ae7c1b78 2023-01-10 stsp struct gotd_session_client *client = &gotd_session_client;
1751 ae7c1b78 2023-01-10 stsp size_t datalen;
1752 2c52c623 2024-01-30 op int fd;
1753 ae7c1b78 2023-01-10 stsp
1754 ae7c1b78 2023-01-10 stsp if (client->state != GOTD_STATE_EXPECT_LIST_REFS)
1755 ae7c1b78 2023-01-10 stsp return got_error(GOT_ERR_PRIVSEP_MSG);
1756 ae7c1b78 2023-01-10 stsp
1757 ae7c1b78 2023-01-10 stsp /* We should already have received a pipe to the listener. */
1758 ae7c1b78 2023-01-10 stsp if (client->fd == -1)
1759 ae7c1b78 2023-01-10 stsp return got_error(GOT_ERR_PRIVSEP_MSG);
1760 ae7c1b78 2023-01-10 stsp
1761 ae7c1b78 2023-01-10 stsp datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
1762 ae7c1b78 2023-01-10 stsp if (datalen != sizeof(ichild))
1763 ae7c1b78 2023-01-10 stsp return got_error(GOT_ERR_PRIVSEP_LEN);
1764 ae7c1b78 2023-01-10 stsp
1765 ae7c1b78 2023-01-10 stsp memcpy(&ichild, imsg->data, sizeof(ichild));
1766 ae7c1b78 2023-01-10 stsp
1767 ae7c1b78 2023-01-10 stsp client->id = ichild.client_id;
1768 ae7c1b78 2023-01-10 stsp if (ichild.proc_id == PROC_REPO_WRITE)
1769 ae7c1b78 2023-01-10 stsp client->is_writing = 1;
1770 ae7c1b78 2023-01-10 stsp else if (ichild.proc_id == PROC_REPO_READ)
1771 ae7c1b78 2023-01-10 stsp client->is_writing = 0;
1772 ae7c1b78 2023-01-10 stsp else
1773 ae7c1b78 2023-01-10 stsp return got_error_msg(GOT_ERR_PRIVSEP_MSG,
1774 ae7c1b78 2023-01-10 stsp "bad child process type");
1775 da76b651 2023-02-03 mark
1776 2c52c623 2024-01-30 op fd = imsg_get_fd(imsg);
1777 2c52c623 2024-01-30 op if (fd == -1)
1778 ae7c1b78 2023-01-10 stsp return got_error(GOT_ERR_PRIVSEP_NO_FD);
1779 ae7c1b78 2023-01-10 stsp
1780 2c52c623 2024-01-30 op imsg_init(&client->repo_child_iev.ibuf, fd);
1781 ae7c1b78 2023-01-10 stsp client->repo_child_iev.handler = session_dispatch_repo_child;
1782 ae7c1b78 2023-01-10 stsp client->repo_child_iev.events = EV_READ;
1783 ae7c1b78 2023-01-10 stsp client->repo_child_iev.handler_arg = NULL;
1784 ae7c1b78 2023-01-10 stsp event_set(&client->repo_child_iev.ev, client->repo_child_iev.ibuf.fd,
1785 ae7c1b78 2023-01-10 stsp EV_READ, session_dispatch_repo_child, &client->repo_child_iev);
1786 ae7c1b78 2023-01-10 stsp gotd_imsg_event_add(&client->repo_child_iev);
1787 ae7c1b78 2023-01-10 stsp
1788 ae7c1b78 2023-01-10 stsp /* The "recvfd" pledge promise is no longer needed. */
1789 ae7c1b78 2023-01-10 stsp if (pledge("stdio rpath wpath cpath sendfd fattr flock", NULL) == -1)
1790 ae7c1b78 2023-01-10 stsp fatal("pledge");
1791 ae7c1b78 2023-01-10 stsp
1792 ae7c1b78 2023-01-10 stsp return NULL;
1793 ae7c1b78 2023-01-10 stsp }
1794 ae7c1b78 2023-01-10 stsp
1795 ae7c1b78 2023-01-10 stsp static void
1796 ae7c1b78 2023-01-10 stsp session_dispatch(int fd, short event, void *arg)
1797 ae7c1b78 2023-01-10 stsp {
1798 ae7c1b78 2023-01-10 stsp struct gotd_imsgev *iev = arg;
1799 ae7c1b78 2023-01-10 stsp struct imsgbuf *ibuf = &iev->ibuf;
1800 ae7c1b78 2023-01-10 stsp struct gotd_session_client *client = &gotd_session_client;
1801 ae7c1b78 2023-01-10 stsp ssize_t n;
1802 ae7c1b78 2023-01-10 stsp int shut = 0;
1803 ae7c1b78 2023-01-10 stsp struct imsg imsg;
1804 ae7c1b78 2023-01-10 stsp
1805 ae7c1b78 2023-01-10 stsp if (event & EV_READ) {
1806 ae7c1b78 2023-01-10 stsp if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
1807 ae7c1b78 2023-01-10 stsp fatal("imsg_read error");
1808 ae7c1b78 2023-01-10 stsp if (n == 0) {
1809 ae7c1b78 2023-01-10 stsp /* Connection closed. */
1810 ae7c1b78 2023-01-10 stsp shut = 1;
1811 ae7c1b78 2023-01-10 stsp goto done;
1812 ae7c1b78 2023-01-10 stsp }
1813 ae7c1b78 2023-01-10 stsp }
1814 ae7c1b78 2023-01-10 stsp
1815 ae7c1b78 2023-01-10 stsp if (event & EV_WRITE) {
1816 ae7c1b78 2023-01-10 stsp n = msgbuf_write(&ibuf->w);
1817 ae7c1b78 2023-01-10 stsp if (n == -1 && errno != EAGAIN)
1818 ae7c1b78 2023-01-10 stsp fatal("msgbuf_write");
1819 ae7c1b78 2023-01-10 stsp if (n == 0) {
1820 ae7c1b78 2023-01-10 stsp /* Connection closed. */
1821 ae7c1b78 2023-01-10 stsp shut = 1;
1822 ae7c1b78 2023-01-10 stsp goto done;
1823 ae7c1b78 2023-01-10 stsp }
1824 ae7c1b78 2023-01-10 stsp }
1825 ae7c1b78 2023-01-10 stsp
1826 ae7c1b78 2023-01-10 stsp for (;;) {
1827 ae7c1b78 2023-01-10 stsp const struct got_error *err = NULL;
1828 ae7c1b78 2023-01-10 stsp uint32_t client_id = 0;
1829 ae7c1b78 2023-01-10 stsp int do_disconnect = 0, do_list_refs = 0;
1830 ae7c1b78 2023-01-10 stsp
1831 ae7c1b78 2023-01-10 stsp if ((n = imsg_get(ibuf, &imsg)) == -1)
1832 ae7c1b78 2023-01-10 stsp fatal("%s: imsg_get error", __func__);
1833 ae7c1b78 2023-01-10 stsp if (n == 0) /* No more messages. */
1834 ae7c1b78 2023-01-10 stsp break;
1835 ae7c1b78 2023-01-10 stsp
1836 ae7c1b78 2023-01-10 stsp switch (imsg.hdr.type) {
1837 ae7c1b78 2023-01-10 stsp case GOTD_IMSG_ERROR:
1838 ae7c1b78 2023-01-10 stsp do_disconnect = 1;
1839 ae7c1b78 2023-01-10 stsp err = gotd_imsg_recv_error(&client_id, &imsg);
1840 ae7c1b78 2023-01-10 stsp break;
1841 ae7c1b78 2023-01-10 stsp case GOTD_IMSG_CONNECT:
1842 ae7c1b78 2023-01-10 stsp err = recv_connect(&imsg);
1843 ae7c1b78 2023-01-10 stsp break;
1844 ae7c1b78 2023-01-10 stsp case GOTD_IMSG_DISCONNECT:
1845 ae7c1b78 2023-01-10 stsp do_disconnect = 1;
1846 ae7c1b78 2023-01-10 stsp break;
1847 ba97b2d7 2024-03-20 stsp case GOTD_IMSG_CONNECT_NOTIFIER:
1848 ba97b2d7 2024-03-20 stsp err = recv_notifier(&imsg);
1849 ba97b2d7 2024-03-20 stsp break;
1850 ae7c1b78 2023-01-10 stsp case GOTD_IMSG_CONNECT_REPO_CHILD:
1851 ae7c1b78 2023-01-10 stsp err = recv_repo_child(&imsg);
1852 ae7c1b78 2023-01-10 stsp if (err)
1853 ae7c1b78 2023-01-10 stsp break;
1854 ae7c1b78 2023-01-10 stsp do_list_refs = 1;
1855 ae7c1b78 2023-01-10 stsp break;
1856 ae7c1b78 2023-01-10 stsp default:
1857 ae7c1b78 2023-01-10 stsp log_debug("unexpected imsg %d", imsg.hdr.type);
1858 ae7c1b78 2023-01-10 stsp break;
1859 ae7c1b78 2023-01-10 stsp }
1860 ae7c1b78 2023-01-10 stsp imsg_free(&imsg);
1861 ae7c1b78 2023-01-10 stsp
1862 ae7c1b78 2023-01-10 stsp if (do_disconnect) {
1863 ae7c1b78 2023-01-10 stsp if (err)
1864 ae7c1b78 2023-01-10 stsp disconnect_on_error(client, err);
1865 ae7c1b78 2023-01-10 stsp else
1866 ae7c1b78 2023-01-10 stsp disconnect(client);
1867 ae7c1b78 2023-01-10 stsp } else if (do_list_refs)
1868 ae7c1b78 2023-01-10 stsp err = list_refs_request();
1869 ae7c1b78 2023-01-10 stsp
1870 ae7c1b78 2023-01-10 stsp if (err)
1871 ae7c1b78 2023-01-10 stsp log_warnx("uid %d: %s", client->euid, err->msg);
1872 ae7c1b78 2023-01-10 stsp }
1873 ae7c1b78 2023-01-10 stsp done:
1874 ae7c1b78 2023-01-10 stsp if (!shut) {
1875 ae7c1b78 2023-01-10 stsp gotd_imsg_event_add(iev);
1876 ae7c1b78 2023-01-10 stsp } else {
1877 ae7c1b78 2023-01-10 stsp /* This pipe is dead. Remove its event handler */
1878 ae7c1b78 2023-01-10 stsp event_del(&iev->ev);
1879 ae7c1b78 2023-01-10 stsp event_loopexit(NULL);
1880 da76b651 2023-02-03 mark }
1881 ae7c1b78 2023-01-10 stsp }
1882 ae7c1b78 2023-01-10 stsp
1883 ae7c1b78 2023-01-10 stsp void
1884 ae7c1b78 2023-01-10 stsp session_main(const char *title, const char *repo_path,
1885 b0614828 2023-06-19 stsp int *pack_fds, int *temp_fds, struct timeval *request_timeout,
1886 ba97b2d7 2024-03-20 stsp struct gotd_repo *repo_cfg, enum gotd_procid proc_id)
1887 ae7c1b78 2023-01-10 stsp {
1888 ae7c1b78 2023-01-10 stsp const struct got_error *err = NULL;
1889 ae7c1b78 2023-01-10 stsp struct event evsigint, evsigterm, evsighup, evsigusr1;
1890 ae7c1b78 2023-01-10 stsp
1891 ba97b2d7 2024-03-20 stsp STAILQ_INIT(&notifications);
1892 ba97b2d7 2024-03-20 stsp
1893 ae7c1b78 2023-01-10 stsp gotd_session.title = title;
1894 ae7c1b78 2023-01-10 stsp gotd_session.pid = getpid();
1895 ae7c1b78 2023-01-10 stsp gotd_session.pack_fds = pack_fds;
1896 ae7c1b78 2023-01-10 stsp gotd_session.temp_fds = temp_fds;
1897 ae7c1b78 2023-01-10 stsp memcpy(&gotd_session.request_timeout, request_timeout,
1898 ae7c1b78 2023-01-10 stsp sizeof(gotd_session.request_timeout));
1899 ba97b2d7 2024-03-20 stsp gotd_session.repo_cfg = repo_cfg;
1900 b0614828 2023-06-19 stsp gotd_session.proc_id = proc_id;
1901 ae7c1b78 2023-01-10 stsp
1902 ba97b2d7 2024-03-20 stsp imsg_init(&gotd_session.notifier_iev.ibuf, -1);
1903 ba97b2d7 2024-03-20 stsp
1904 ae7c1b78 2023-01-10 stsp err = got_repo_open(&gotd_session.repo, repo_path, NULL, pack_fds);
1905 ae7c1b78 2023-01-10 stsp if (err)
1906 ae7c1b78 2023-01-10 stsp goto done;
1907 ae7c1b78 2023-01-10 stsp if (!got_repo_is_bare(gotd_session.repo)) {
1908 ae7c1b78 2023-01-10 stsp err = got_error_msg(GOT_ERR_NOT_GIT_REPO,
1909 ae7c1b78 2023-01-10 stsp "bare git repository required");
1910 ae7c1b78 2023-01-10 stsp goto done;
1911 ae7c1b78 2023-01-10 stsp }
1912 ae7c1b78 2023-01-10 stsp
1913 ae7c1b78 2023-01-10 stsp got_repo_temp_fds_set(gotd_session.repo, temp_fds);
1914 ae7c1b78 2023-01-10 stsp
1915 ae7c1b78 2023-01-10 stsp signal_set(&evsigint, SIGINT, gotd_session_sighdlr, NULL);
1916 ae7c1b78 2023-01-10 stsp signal_set(&evsigterm, SIGTERM, gotd_session_sighdlr, NULL);
1917 ae7c1b78 2023-01-10 stsp signal_set(&evsighup, SIGHUP, gotd_session_sighdlr, NULL);
1918 ae7c1b78 2023-01-10 stsp signal_set(&evsigusr1, SIGUSR1, gotd_session_sighdlr, NULL);
1919 ae7c1b78 2023-01-10 stsp signal(SIGPIPE, SIG_IGN);
1920 ae7c1b78 2023-01-10 stsp
1921 ae7c1b78 2023-01-10 stsp signal_add(&evsigint, NULL);
1922 ae7c1b78 2023-01-10 stsp signal_add(&evsigterm, NULL);
1923 ae7c1b78 2023-01-10 stsp signal_add(&evsighup, NULL);
1924 ae7c1b78 2023-01-10 stsp signal_add(&evsigusr1, NULL);
1925 ae7c1b78 2023-01-10 stsp
1926 ae7c1b78 2023-01-10 stsp gotd_session_client.state = GOTD_STATE_EXPECT_LIST_REFS;
1927 ae7c1b78 2023-01-10 stsp gotd_session_client.fd = -1;
1928 ae7c1b78 2023-01-10 stsp gotd_session_client.nref_updates = -1;
1929 2fc51af0 2023-01-10 stsp gotd_session_client.delta_cache_fd = -1;
1930 3448a19a 2023-01-21 stsp gotd_session_client.accept_flush_pkt = 1;
1931 ae7c1b78 2023-01-10 stsp
1932 ae7c1b78 2023-01-10 stsp imsg_init(&gotd_session.parent_iev.ibuf, GOTD_FILENO_MSG_PIPE);
1933 ae7c1b78 2023-01-10 stsp gotd_session.parent_iev.handler = session_dispatch;
1934 ae7c1b78 2023-01-10 stsp gotd_session.parent_iev.events = EV_READ;
1935 ae7c1b78 2023-01-10 stsp gotd_session.parent_iev.handler_arg = NULL;
1936 ae7c1b78 2023-01-10 stsp event_set(&gotd_session.parent_iev.ev, gotd_session.parent_iev.ibuf.fd,
1937 ae7c1b78 2023-01-10 stsp EV_READ, session_dispatch, &gotd_session.parent_iev);
1938 ae7c1b78 2023-01-10 stsp if (gotd_imsg_compose_event(&gotd_session.parent_iev,
1939 b0614828 2023-06-19 stsp GOTD_IMSG_CLIENT_SESSION_READY, gotd_session.proc_id,
1940 b0614828 2023-06-19 stsp -1, NULL, 0) == -1) {
1941 ae7c1b78 2023-01-10 stsp err = got_error_from_errno("imsg compose CLIENT_SESSION_READY");
1942 ae7c1b78 2023-01-10 stsp goto done;
1943 ae7c1b78 2023-01-10 stsp }
1944 ae7c1b78 2023-01-10 stsp
1945 ae7c1b78 2023-01-10 stsp event_dispatch();
1946 ae7c1b78 2023-01-10 stsp done:
1947 ae7c1b78 2023-01-10 stsp if (err)
1948 ae7c1b78 2023-01-10 stsp log_warnx("%s: %s", title, err->msg);
1949 ae7c1b78 2023-01-10 stsp gotd_session_shutdown();
1950 ae7c1b78 2023-01-10 stsp }
1951 ae7c1b78 2023-01-10 stsp
1952 ae7c1b78 2023-01-10 stsp void
1953 ae7c1b78 2023-01-10 stsp gotd_session_shutdown(void)
1954 ae7c1b78 2023-01-10 stsp {
1955 ba97b2d7 2024-03-20 stsp struct gotd_session_notif *notif;
1956 ba97b2d7 2024-03-20 stsp
1957 2ec74a9e 2023-02-08 op log_debug("shutting down");
1958 ba97b2d7 2024-03-20 stsp
1959 ba97b2d7 2024-03-20 stsp while (!STAILQ_EMPTY(&notifications)) {
1960 ba97b2d7 2024-03-20 stsp notif = STAILQ_FIRST(&notifications);
1961 ba97b2d7 2024-03-20 stsp STAILQ_REMOVE_HEAD(&notifications, entry);
1962 ba97b2d7 2024-03-20 stsp if (notif->fd != -1)
1963 ba97b2d7 2024-03-20 stsp close(notif->fd);
1964 ba97b2d7 2024-03-20 stsp free(notif->refname);
1965 ba97b2d7 2024-03-20 stsp free(notif);
1966 ba97b2d7 2024-03-20 stsp }
1967 ba97b2d7 2024-03-20 stsp
1968 ae7c1b78 2023-01-10 stsp if (gotd_session.repo)
1969 ae7c1b78 2023-01-10 stsp got_repo_close(gotd_session.repo);
1970 ae7c1b78 2023-01-10 stsp got_repo_pack_fds_close(gotd_session.pack_fds);
1971 ae7c1b78 2023-01-10 stsp got_repo_temp_fds_close(gotd_session.temp_fds);
1972 ba97b2d7 2024-03-20 stsp free(gotd_session_client.username);
1973 ae7c1b78 2023-01-10 stsp exit(0);
1974 ae7c1b78 2023-01-10 stsp }