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