Blame


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