File: | libexec/got-read-gitconfig/../../lib/privsep.c |
Warning: | line 1960, column 8 Array access (via field 'refs') results in a null pointer dereference |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* | |||
2 | * Copyright (c) 2018, 2019, 2020 Stefan Sperling <stsp@openbsd.org> | |||
3 | * Copyright (c) 2020 Ori Bernstein <ori@openbsd.org> | |||
4 | * | |||
5 | * Permission to use, copy, modify, and distribute this software for any | |||
6 | * purpose with or without fee is hereby granted, provided that the above | |||
7 | * copyright notice and this permission notice appear in all copies. | |||
8 | * | |||
9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
10 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
11 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
12 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
13 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
14 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
15 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
16 | */ | |||
17 | ||||
18 | #include <sys/types.h> | |||
19 | #include <sys/queue.h> | |||
20 | #include <sys/uio.h> | |||
21 | #include <sys/wait.h> | |||
22 | ||||
23 | #include <ctype.h> | |||
24 | #include <limits.h> | |||
25 | #include <signal.h> | |||
26 | #include <stdio.h> | |||
27 | #include <stdlib.h> | |||
28 | #include <string.h> | |||
29 | #include <errno(*__errno()).h> | |||
30 | #include <stdint.h> | |||
31 | #include <poll.h> | |||
32 | #include <imsg.h> | |||
33 | #include <sha1.h> | |||
34 | #include <unistd.h> | |||
35 | #include <zlib.h> | |||
36 | #include <time.h> | |||
37 | ||||
38 | #include "got_object.h" | |||
39 | #include "got_error.h" | |||
40 | #include "got_path.h" | |||
41 | #include "got_repository.h" | |||
42 | ||||
43 | #include "got_lib_sha1.h" | |||
44 | #include "got_lib_delta.h" | |||
45 | #include "got_lib_inflate.h" | |||
46 | #include "got_lib_object.h" | |||
47 | #include "got_lib_object_parse.h" | |||
48 | #include "got_lib_privsep.h" | |||
49 | #include "got_lib_pack.h" | |||
50 | ||||
51 | #ifndef MIN | |||
52 | #define MIN(_a,_b)((_a) < (_b) ? (_a) : (_b)) ((_a) < (_b) ? (_a) : (_b)) | |||
53 | #endif | |||
54 | ||||
55 | #ifndef nitems | |||
56 | #define nitems(_a)(sizeof((_a)) / sizeof((_a)[0])) (sizeof((_a)) / sizeof((_a)[0])) | |||
57 | #endif | |||
58 | ||||
59 | static const struct got_error * | |||
60 | poll_fd(int fd, int events, int timeout) | |||
61 | { | |||
62 | struct pollfd pfd[1]; | |||
63 | struct timespec ts; | |||
64 | sigset_t sigset; | |||
65 | int n; | |||
66 | ||||
67 | pfd[0].fd = fd; | |||
68 | pfd[0].events = events; | |||
69 | ||||
70 | ts.tv_sec = timeout; | |||
71 | ts.tv_nsec = 0; | |||
72 | ||||
73 | if (sigemptyset(&sigset) == -1) | |||
74 | return got_error_from_errno("sigemptyset"); | |||
75 | if (sigaddset(&sigset, SIGWINCH28) == -1) | |||
76 | return got_error_from_errno("sigaddset"); | |||
77 | ||||
78 | n = ppoll(pfd, 1, timeout == INFTIM(-1) ? NULL((void *)0) : &ts, &sigset); | |||
79 | if (n == -1) | |||
80 | return got_error_from_errno("ppoll"); | |||
81 | if (n == 0) | |||
82 | return got_error(GOT_ERR_TIMEOUT33); | |||
83 | if (pfd[0].revents & (POLLERR0x0008 | POLLNVAL0x0020)) | |||
84 | return got_error_from_errno("poll error"); | |||
85 | if (pfd[0].revents & (events | POLLHUP0x0010)) | |||
86 | return NULL((void *)0); | |||
87 | ||||
88 | return got_error(GOT_ERR_INTERRUPT34); | |||
89 | } | |||
90 | ||||
91 | static const struct got_error * | |||
92 | read_imsg(struct imsgbuf *ibuf) | |||
93 | { | |||
94 | const struct got_error *err; | |||
95 | size_t n; | |||
96 | ||||
97 | err = poll_fd(ibuf->fd, POLLIN0x0001, INFTIM(-1)); | |||
98 | if (err) | |||
99 | return err; | |||
100 | ||||
101 | n = imsg_read(ibuf); | |||
102 | if (n == -1) { | |||
103 | if (errno(*__errno()) == EAGAIN35) /* Could be a file-descriptor leak. */ | |||
104 | return got_error(GOT_ERR_PRIVSEP_NO_FD38); | |||
105 | return got_error(GOT_ERR_PRIVSEP_READ35); | |||
106 | } | |||
107 | if (n == 0) | |||
108 | return got_error(GOT_ERR_PRIVSEP_PIPE37); | |||
109 | ||||
110 | return NULL((void *)0); | |||
111 | } | |||
112 | ||||
113 | const struct got_error * | |||
114 | got_privsep_wait_for_child(pid_t pid) | |||
115 | { | |||
116 | int child_status; | |||
117 | ||||
118 | if (waitpid(pid, &child_status, 0) == -1) | |||
119 | return got_error_from_errno("waitpid"); | |||
120 | ||||
121 | if (!WIFEXITED(child_status)(((child_status) & 0177) == 0)) | |||
122 | return got_error(GOT_ERR_PRIVSEP_DIED40); | |||
123 | ||||
124 | if (WEXITSTATUS(child_status)(int)(((unsigned)(child_status) >> 8) & 0xff) != 0) | |||
125 | return got_error(GOT_ERR_PRIVSEP_EXIT41); | |||
126 | ||||
127 | return NULL((void *)0); | |||
128 | } | |||
129 | ||||
130 | static const struct got_error * | |||
131 | recv_imsg_error(struct imsg *imsg, size_t datalen) | |||
132 | { | |||
133 | struct got_imsg_error *ierr; | |||
134 | ||||
135 | if (datalen != sizeof(*ierr)) | |||
136 | return got_error(GOT_ERR_PRIVSEP_LEN36); | |||
137 | ||||
138 | ierr = imsg->data; | |||
139 | if (ierr->code == GOT_ERR_ERRNO1) { | |||
140 | static struct got_error serr; | |||
141 | serr.code = GOT_ERR_ERRNO1; | |||
142 | serr.msg = strerror(ierr->errno_code); | |||
143 | return &serr; | |||
144 | } | |||
145 | ||||
146 | return got_error(ierr->code); | |||
147 | } | |||
148 | ||||
149 | const struct got_error * | |||
150 | got_privsep_recv_imsg(struct imsg *imsg, struct imsgbuf *ibuf, | |||
151 | size_t min_datalen) | |||
152 | { | |||
153 | const struct got_error *err; | |||
154 | ssize_t n; | |||
155 | ||||
156 | n = imsg_get(ibuf, imsg); | |||
157 | if (n == -1) | |||
158 | return got_error_from_errno("imsg_get"); | |||
159 | ||||
160 | while (n == 0) { | |||
161 | err = read_imsg(ibuf); | |||
162 | if (err) | |||
163 | return err; | |||
164 | n = imsg_get(ibuf, imsg); | |||
165 | if (n == -1) | |||
166 | return got_error_from_errno("imsg_get"); | |||
167 | } | |||
168 | ||||
169 | if (imsg->hdr.len < IMSG_HEADER_SIZEsizeof(struct imsg_hdr) + min_datalen) | |||
170 | return got_error(GOT_ERR_PRIVSEP_LEN36); | |||
171 | ||||
172 | if (imsg->hdr.type == GOT_IMSG_ERROR) { | |||
173 | size_t datalen = imsg->hdr.len - IMSG_HEADER_SIZEsizeof(struct imsg_hdr); | |||
174 | return recv_imsg_error(imsg, datalen); | |||
175 | } | |||
176 | ||||
177 | return NULL((void *)0); | |||
178 | } | |||
179 | ||||
180 | /* Attempt to send an error in an imsg. Complain on stderr as a last resort. */ | |||
181 | void | |||
182 | got_privsep_send_error(struct imsgbuf *ibuf, const struct got_error *err) | |||
183 | { | |||
184 | const struct got_error *poll_err; | |||
185 | struct got_imsg_error ierr; | |||
186 | int ret; | |||
187 | ||||
188 | ierr.code = err->code; | |||
189 | if (err->code == GOT_ERR_ERRNO1) | |||
190 | ierr.errno_code = errno(*__errno()); | |||
191 | else | |||
192 | ierr.errno_code = 0; | |||
193 | ret = imsg_compose(ibuf, GOT_IMSG_ERROR, 0, 0, -1, &ierr, sizeof(ierr)); | |||
194 | if (ret == -1) { | |||
195 | fprintf(stderr(&__sF[2]), "%s: error %d \"%s\": imsg_compose: %s\n", | |||
196 | getprogname(), err->code, err->msg, strerror(errno(*__errno()))); | |||
197 | return; | |||
198 | } | |||
199 | ||||
200 | poll_err = poll_fd(ibuf->fd, POLLOUT0x0004, INFTIM(-1)); | |||
201 | if (poll_err) { | |||
202 | fprintf(stderr(&__sF[2]), "%s: error %d \"%s\": poll: %s\n", | |||
203 | getprogname(), err->code, err->msg, poll_err->msg); | |||
204 | return; | |||
205 | } | |||
206 | ||||
207 | ret = imsg_flush(ibuf); | |||
208 | if (ret == -1) { | |||
209 | fprintf(stderr(&__sF[2]), "%s: error %d \"%s\": imsg_flush: %s\n", | |||
210 | getprogname(), err->code, err->msg, strerror(errno(*__errno()))); | |||
211 | return; | |||
212 | } | |||
213 | } | |||
214 | ||||
215 | static const struct got_error * | |||
216 | flush_imsg(struct imsgbuf *ibuf) | |||
217 | { | |||
218 | const struct got_error *err; | |||
219 | ||||
220 | err = poll_fd(ibuf->fd, POLLOUT0x0004, INFTIM(-1)); | |||
221 | if (err) | |||
222 | return err; | |||
223 | ||||
224 | if (imsg_flush(ibuf) == -1) | |||
225 | return got_error_from_errno("imsg_flush"); | |||
226 | ||||
227 | return NULL((void *)0); | |||
228 | } | |||
229 | ||||
230 | const struct got_error * | |||
231 | got_privsep_flush_imsg(struct imsgbuf *ibuf) | |||
232 | { | |||
233 | return flush_imsg(ibuf); | |||
234 | } | |||
235 | ||||
236 | const struct got_error * | |||
237 | got_privsep_send_stop(int fd) | |||
238 | { | |||
239 | const struct got_error *err = NULL((void *)0); | |||
240 | struct imsgbuf ibuf; | |||
241 | ||||
242 | imsg_init(&ibuf, fd); | |||
243 | ||||
244 | if (imsg_compose(&ibuf, GOT_IMSG_STOP, 0, 0, -1, NULL((void *)0), 0) == -1) | |||
245 | return got_error_from_errno("imsg_compose STOP"); | |||
246 | ||||
247 | err = flush_imsg(&ibuf); | |||
248 | imsg_clear(&ibuf); | |||
249 | return err; | |||
250 | } | |||
251 | ||||
252 | const struct got_error * | |||
253 | got_privsep_send_obj_req(struct imsgbuf *ibuf, int fd) | |||
254 | { | |||
255 | if (imsg_compose(ibuf, GOT_IMSG_OBJECT_REQUEST, 0, 0, fd, NULL((void *)0), 0) | |||
256 | == -1) | |||
257 | return got_error_from_errno("imsg_compose OBJECT_REQUEST"); | |||
258 | ||||
259 | return flush_imsg(ibuf); | |||
260 | } | |||
261 | ||||
262 | const struct got_error * | |||
263 | got_privsep_send_raw_obj_req(struct imsgbuf *ibuf, int fd) | |||
264 | { | |||
265 | if (imsg_compose(ibuf, GOT_IMSG_RAW_OBJECT_REQUEST, 0, 0, fd, NULL((void *)0), 0) | |||
266 | == -1) | |||
267 | return got_error_from_errno("imsg_compose RAW_OBJECT_REQUEST"); | |||
268 | ||||
269 | return flush_imsg(ibuf); | |||
270 | } | |||
271 | ||||
272 | const struct got_error * | |||
273 | got_privsep_send_raw_obj_outfd(struct imsgbuf *ibuf, int outfd) | |||
274 | { | |||
275 | const struct got_error *err = NULL((void *)0); | |||
276 | ||||
277 | if (imsg_compose(ibuf, GOT_IMSG_RAW_OBJECT_OUTFD, 0, 0, outfd, NULL((void *)0), 0) | |||
278 | == -1) { | |||
279 | err = got_error_from_errno("imsg_compose RAW_OBJECT_OUTFD"); | |||
280 | close(outfd); | |||
281 | return err; | |||
282 | } | |||
283 | ||||
284 | return flush_imsg(ibuf); | |||
285 | } | |||
286 | ||||
287 | const struct got_error * | |||
288 | got_privsep_send_raw_obj(struct imsgbuf *ibuf, off_t size, size_t hdrlen, | |||
289 | uint8_t *data) | |||
290 | { | |||
291 | const struct got_error *err = NULL((void *)0); | |||
292 | struct got_imsg_raw_obj iobj; | |||
293 | size_t len = sizeof(iobj); | |||
294 | struct ibuf *wbuf; | |||
295 | ||||
296 | iobj.hdrlen = hdrlen; | |||
297 | iobj.size = size; | |||
298 | ||||
299 | if (data && size <= GOT_PRIVSEP_INLINE_OBJECT_DATA_MAX(16384 - sizeof(struct imsg_hdr) - sizeof(struct got_imsg_raw_obj ))) | |||
300 | len += (size_t)size; | |||
301 | ||||
302 | wbuf = imsg_create(ibuf, GOT_IMSG_RAW_OBJECT, 0, 0, len); | |||
303 | if (wbuf == NULL((void *)0)) { | |||
304 | err = got_error_from_errno("imsg_create RAW_OBJECT"); | |||
305 | return err; | |||
306 | } | |||
307 | ||||
308 | if (imsg_add(wbuf, &iobj, sizeof(iobj)) == -1) { | |||
309 | err = got_error_from_errno("imsg_add RAW_OBJECT"); | |||
310 | ibuf_free(wbuf); | |||
311 | return err; | |||
312 | } | |||
313 | ||||
314 | if (data && size <= GOT_PRIVSEP_INLINE_OBJECT_DATA_MAX(16384 - sizeof(struct imsg_hdr) - sizeof(struct got_imsg_raw_obj ))) { | |||
315 | if (imsg_add(wbuf, data, size) == -1) { | |||
316 | err = got_error_from_errno("imsg_add RAW_OBJECT"); | |||
317 | ibuf_free(wbuf); | |||
318 | return err; | |||
319 | } | |||
320 | } | |||
321 | ||||
322 | wbuf->fd = -1; | |||
323 | imsg_close(ibuf, wbuf); | |||
324 | ||||
325 | return flush_imsg(ibuf); | |||
326 | } | |||
327 | ||||
328 | const struct got_error * | |||
329 | got_privsep_recv_raw_obj(uint8_t **outbuf, off_t *size, size_t *hdrlen, | |||
330 | struct imsgbuf *ibuf) | |||
331 | { | |||
332 | const struct got_error *err = NULL((void *)0); | |||
333 | struct imsg imsg; | |||
334 | struct got_imsg_raw_obj *iobj; | |||
335 | size_t datalen; | |||
336 | ||||
337 | *outbuf = NULL((void *)0); | |||
338 | ||||
339 | err = got_privsep_recv_imsg(&imsg, ibuf, 0); | |||
340 | if (err) | |||
341 | return err; | |||
342 | ||||
343 | datalen = imsg.hdr.len - IMSG_HEADER_SIZEsizeof(struct imsg_hdr); | |||
344 | ||||
345 | switch (imsg.hdr.type) { | |||
346 | case GOT_IMSG_RAW_OBJECT: | |||
347 | if (datalen < sizeof(*iobj)) { | |||
348 | err = got_error(GOT_ERR_PRIVSEP_LEN36); | |||
349 | break; | |||
350 | } | |||
351 | iobj = imsg.data; | |||
352 | *size = iobj->size; | |||
353 | *hdrlen = iobj->hdrlen; | |||
354 | ||||
355 | if (datalen == sizeof(*iobj)) { | |||
356 | /* Data has been written to file descriptor. */ | |||
357 | break; | |||
358 | } | |||
359 | ||||
360 | if (*size > GOT_PRIVSEP_INLINE_OBJECT_DATA_MAX(16384 - sizeof(struct imsg_hdr) - sizeof(struct got_imsg_raw_obj ))) { | |||
361 | err = got_error(GOT_ERR_PRIVSEP_LEN36); | |||
362 | break; | |||
363 | } | |||
364 | ||||
365 | *outbuf = malloc(*size); | |||
366 | if (*outbuf == NULL((void *)0)) { | |||
367 | err = got_error_from_errno("malloc"); | |||
368 | break; | |||
369 | } | |||
370 | memcpy(*outbuf, imsg.data + sizeof(*iobj), *size); | |||
371 | break; | |||
372 | default: | |||
373 | err = got_error(GOT_ERR_PRIVSEP_MSG39); | |||
374 | break; | |||
375 | } | |||
376 | ||||
377 | imsg_free(&imsg); | |||
378 | ||||
379 | return err; | |||
380 | } | |||
381 | ||||
382 | const struct got_error * | |||
383 | got_privsep_send_commit_req(struct imsgbuf *ibuf, int fd, | |||
384 | struct got_object_id *id, int pack_idx) | |||
385 | { | |||
386 | const struct got_error *err = NULL((void *)0); | |||
387 | struct got_imsg_packed_object iobj, *iobjp; | |||
388 | size_t len; | |||
389 | ||||
390 | if (id) { /* commit is packed */ | |||
391 | iobj.idx = pack_idx; | |||
392 | memcpy(iobj.id, id->sha1, sizeof(iobj.id)); | |||
393 | iobjp = &iobj; | |||
394 | len = sizeof(iobj); | |||
395 | } else { | |||
396 | iobjp = NULL((void *)0); | |||
397 | len = 0; | |||
398 | } | |||
399 | ||||
400 | if (imsg_compose(ibuf, GOT_IMSG_COMMIT_REQUEST, 0, 0, fd, iobjp, len) | |||
401 | == -1) { | |||
402 | err = got_error_from_errno("imsg_compose COMMIT_REQUEST"); | |||
403 | close(fd); | |||
404 | return err; | |||
405 | } | |||
406 | ||||
407 | return flush_imsg(ibuf); | |||
408 | } | |||
409 | ||||
410 | const struct got_error * | |||
411 | got_privsep_send_tree_req(struct imsgbuf *ibuf, int fd, | |||
412 | struct got_object_id *id, int pack_idx) | |||
413 | { | |||
414 | const struct got_error *err = NULL((void *)0); | |||
415 | struct ibuf *wbuf; | |||
416 | size_t len = id ? sizeof(struct got_imsg_packed_object) : 0; | |||
417 | ||||
418 | wbuf = imsg_create(ibuf, GOT_IMSG_TREE_REQUEST, 0, 0, len); | |||
419 | if (wbuf == NULL((void *)0)) | |||
420 | return got_error_from_errno("imsg_create TREE_REQUEST"); | |||
421 | ||||
422 | if (id) { /* tree is packed */ | |||
423 | if (imsg_add(wbuf, id->sha1, SHA1_DIGEST_LENGTH20) == -1) { | |||
424 | err = got_error_from_errno("imsg_add TREE_ENTRY"); | |||
425 | ibuf_free(wbuf); | |||
426 | return err; | |||
427 | } | |||
428 | ||||
429 | if (imsg_add(wbuf, &pack_idx, sizeof(pack_idx)) == -1) { | |||
430 | err = got_error_from_errno("imsg_add TREE_ENTRY"); | |||
431 | ibuf_free(wbuf); | |||
432 | return err; | |||
433 | } | |||
434 | } | |||
435 | ||||
436 | wbuf->fd = fd; | |||
437 | imsg_close(ibuf, wbuf); | |||
438 | ||||
439 | return flush_imsg(ibuf); | |||
440 | } | |||
441 | ||||
442 | const struct got_error * | |||
443 | got_privsep_send_tag_req(struct imsgbuf *ibuf, int fd, | |||
444 | struct got_object_id *id, int pack_idx) | |||
445 | { | |||
446 | struct got_imsg_packed_object iobj, *iobjp; | |||
447 | size_t len; | |||
448 | ||||
449 | if (id) { /* tag is packed */ | |||
450 | iobj.idx = pack_idx; | |||
451 | memcpy(iobj.id, id->sha1, sizeof(iobj.id)); | |||
452 | iobjp = &iobj; | |||
453 | len = sizeof(iobj); | |||
454 | } else { | |||
455 | iobjp = NULL((void *)0); | |||
456 | len = 0; | |||
457 | } | |||
458 | ||||
459 | if (imsg_compose(ibuf, GOT_IMSG_TAG_REQUEST, 0, 0, fd, iobjp, len) | |||
460 | == -1) | |||
461 | return got_error_from_errno("imsg_compose TAG_REQUEST"); | |||
462 | ||||
463 | return flush_imsg(ibuf); | |||
464 | } | |||
465 | ||||
466 | const struct got_error * | |||
467 | got_privsep_send_blob_req(struct imsgbuf *ibuf, int infd, | |||
468 | struct got_object_id *id, int pack_idx) | |||
469 | { | |||
470 | const struct got_error *err = NULL((void *)0); | |||
471 | struct got_imsg_packed_object iobj, *iobjp; | |||
472 | size_t len; | |||
473 | ||||
474 | if (id) { /* blob is packed */ | |||
475 | iobj.idx = pack_idx; | |||
476 | memcpy(iobj.id, id->sha1, sizeof(iobj.id)); | |||
477 | iobjp = &iobj; | |||
478 | len = sizeof(iobj); | |||
479 | } else { | |||
480 | iobjp = NULL((void *)0); | |||
481 | len = 0; | |||
482 | } | |||
483 | ||||
484 | if (imsg_compose(ibuf, GOT_IMSG_BLOB_REQUEST, 0, 0, infd, iobjp, len) | |||
485 | == -1) { | |||
486 | err = got_error_from_errno("imsg_compose BLOB_REQUEST"); | |||
487 | close(infd); | |||
488 | return err; | |||
489 | } | |||
490 | ||||
491 | return flush_imsg(ibuf); | |||
492 | } | |||
493 | ||||
494 | const struct got_error * | |||
495 | got_privsep_send_blob_outfd(struct imsgbuf *ibuf, int outfd) | |||
496 | { | |||
497 | const struct got_error *err = NULL((void *)0); | |||
498 | ||||
499 | if (imsg_compose(ibuf, GOT_IMSG_BLOB_OUTFD, 0, 0, outfd, NULL((void *)0), 0) | |||
500 | == -1) { | |||
501 | err = got_error_from_errno("imsg_compose BLOB_OUTFD"); | |||
502 | close(outfd); | |||
503 | return err; | |||
504 | } | |||
505 | ||||
506 | return flush_imsg(ibuf); | |||
507 | } | |||
508 | ||||
509 | static const struct got_error * | |||
510 | send_fd(struct imsgbuf *ibuf, int imsg_code, int fd) | |||
511 | { | |||
512 | const struct got_error *err = NULL((void *)0); | |||
513 | ||||
514 | if (imsg_compose(ibuf, imsg_code, 0, 0, fd, NULL((void *)0), 0) == -1) { | |||
515 | err = got_error_from_errno("imsg_compose TMPFD"); | |||
516 | close(fd); | |||
517 | return err; | |||
518 | } | |||
519 | ||||
520 | return flush_imsg(ibuf); | |||
521 | } | |||
522 | ||||
523 | const struct got_error * | |||
524 | got_privsep_send_tmpfd(struct imsgbuf *ibuf, int fd) | |||
525 | { | |||
526 | return send_fd(ibuf, GOT_IMSG_TMPFD, fd); | |||
527 | } | |||
528 | ||||
529 | const struct got_error * | |||
530 | got_privsep_send_obj(struct imsgbuf *ibuf, struct got_object *obj) | |||
531 | { | |||
532 | struct got_imsg_object iobj; | |||
533 | ||||
534 | memcpy(iobj.id, obj->id.sha1, sizeof(iobj.id)); | |||
535 | iobj.type = obj->type; | |||
536 | iobj.flags = obj->flags; | |||
537 | iobj.hdrlen = obj->hdrlen; | |||
538 | iobj.size = obj->size; | |||
539 | if (iobj.flags & GOT_OBJ_FLAG_PACKED0x01) { | |||
540 | iobj.pack_offset = obj->pack_offset; | |||
541 | iobj.pack_idx = obj->pack_idx; | |||
542 | } | |||
543 | ||||
544 | if (imsg_compose(ibuf, GOT_IMSG_OBJECT, 0, 0, -1, &iobj, sizeof(iobj)) | |||
545 | == -1) | |||
546 | return got_error_from_errno("imsg_compose OBJECT"); | |||
547 | ||||
548 | return flush_imsg(ibuf); | |||
549 | } | |||
550 | ||||
551 | const struct got_error * | |||
552 | got_privsep_send_fetch_req(struct imsgbuf *ibuf, int fd, | |||
553 | struct got_pathlist_head *have_refs, int fetch_all_branches, | |||
554 | struct got_pathlist_head *wanted_branches, | |||
555 | struct got_pathlist_head *wanted_refs, int list_refs_only, int verbosity) | |||
556 | { | |||
557 | const struct got_error *err = NULL((void *)0); | |||
558 | struct ibuf *wbuf; | |||
559 | size_t len; | |||
560 | struct got_pathlist_entry *pe; | |||
561 | struct got_imsg_fetch_request fetchreq; | |||
562 | ||||
563 | memset(&fetchreq, 0, sizeof(fetchreq)); | |||
564 | fetchreq.fetch_all_branches = fetch_all_branches; | |||
565 | fetchreq.list_refs_only = list_refs_only; | |||
566 | fetchreq.verbosity = verbosity; | |||
567 | TAILQ_FOREACH(pe, have_refs, entry)for((pe) = ((have_refs)->tqh_first); (pe) != ((void *)0); ( pe) = ((pe)->entry.tqe_next)) | |||
568 | fetchreq.n_have_refs++; | |||
569 | TAILQ_FOREACH(pe, wanted_branches, entry)for((pe) = ((wanted_branches)->tqh_first); (pe) != ((void * )0); (pe) = ((pe)->entry.tqe_next)) | |||
570 | fetchreq.n_wanted_branches++; | |||
571 | TAILQ_FOREACH(pe, wanted_refs, entry)for((pe) = ((wanted_refs)->tqh_first); (pe) != ((void *)0) ; (pe) = ((pe)->entry.tqe_next)) | |||
572 | fetchreq.n_wanted_refs++; | |||
573 | len = sizeof(struct got_imsg_fetch_request); | |||
574 | if (len >= MAX_IMSGSIZE16384 - IMSG_HEADER_SIZEsizeof(struct imsg_hdr)) { | |||
575 | close(fd); | |||
576 | return got_error(GOT_ERR_NO_SPACE9); | |||
577 | } | |||
578 | ||||
579 | if (imsg_compose(ibuf, GOT_IMSG_FETCH_REQUEST, 0, 0, fd, | |||
580 | &fetchreq, sizeof(fetchreq)) == -1) | |||
581 | return got_error_from_errno( | |||
582 | "imsg_compose FETCH_SERVER_PROGRESS"); | |||
583 | ||||
584 | err = flush_imsg(ibuf); | |||
585 | if (err) { | |||
586 | close(fd); | |||
587 | return err; | |||
588 | } | |||
589 | fd = -1; | |||
590 | ||||
591 | TAILQ_FOREACH(pe, have_refs, entry)for((pe) = ((have_refs)->tqh_first); (pe) != ((void *)0); ( pe) = ((pe)->entry.tqe_next)) { | |||
592 | const char *name = pe->path; | |||
593 | size_t name_len = pe->path_len; | |||
594 | struct got_object_id *id = pe->data; | |||
595 | ||||
596 | len = sizeof(struct got_imsg_fetch_have_ref) + name_len; | |||
597 | wbuf = imsg_create(ibuf, GOT_IMSG_FETCH_HAVE_REF, 0, 0, len); | |||
598 | if (wbuf == NULL((void *)0)) | |||
599 | return got_error_from_errno("imsg_create FETCH_HAVE_REF"); | |||
600 | ||||
601 | /* Keep in sync with struct got_imsg_fetch_have_ref! */ | |||
602 | if (imsg_add(wbuf, id->sha1, sizeof(id->sha1)) == -1) { | |||
603 | err = got_error_from_errno("imsg_add FETCH_HAVE_REF"); | |||
604 | ibuf_free(wbuf); | |||
605 | return err; | |||
606 | } | |||
607 | if (imsg_add(wbuf, &name_len, sizeof(name_len)) == -1) { | |||
608 | err = got_error_from_errno("imsg_add FETCH_HAVE_REF"); | |||
609 | ibuf_free(wbuf); | |||
610 | return err; | |||
611 | } | |||
612 | if (imsg_add(wbuf, name, name_len) == -1) { | |||
613 | err = got_error_from_errno("imsg_add FETCH_HAVE_REF"); | |||
614 | ibuf_free(wbuf); | |||
615 | return err; | |||
616 | } | |||
617 | ||||
618 | wbuf->fd = -1; | |||
619 | imsg_close(ibuf, wbuf); | |||
620 | err = flush_imsg(ibuf); | |||
621 | if (err) | |||
622 | return err; | |||
623 | } | |||
624 | ||||
625 | TAILQ_FOREACH(pe, wanted_branches, entry)for((pe) = ((wanted_branches)->tqh_first); (pe) != ((void * )0); (pe) = ((pe)->entry.tqe_next)) { | |||
626 | const char *name = pe->path; | |||
627 | size_t name_len = pe->path_len; | |||
628 | ||||
629 | len = sizeof(struct got_imsg_fetch_wanted_branch) + name_len; | |||
630 | wbuf = imsg_create(ibuf, GOT_IMSG_FETCH_WANTED_BRANCH, 0, 0, | |||
631 | len); | |||
632 | if (wbuf == NULL((void *)0)) | |||
633 | return got_error_from_errno( | |||
634 | "imsg_create FETCH_WANTED_BRANCH"); | |||
635 | ||||
636 | /* Keep in sync with struct got_imsg_fetch_wanted_branch! */ | |||
637 | if (imsg_add(wbuf, &name_len, sizeof(name_len)) == -1) { | |||
638 | err = got_error_from_errno( | |||
639 | "imsg_add FETCH_WANTED_BRANCH"); | |||
640 | ibuf_free(wbuf); | |||
641 | return err; | |||
642 | } | |||
643 | if (imsg_add(wbuf, name, name_len) == -1) { | |||
644 | err = got_error_from_errno( | |||
645 | "imsg_add FETCH_WANTED_BRANCH"); | |||
646 | ibuf_free(wbuf); | |||
647 | return err; | |||
648 | } | |||
649 | ||||
650 | wbuf->fd = -1; | |||
651 | imsg_close(ibuf, wbuf); | |||
652 | err = flush_imsg(ibuf); | |||
653 | if (err) | |||
654 | return err; | |||
655 | } | |||
656 | ||||
657 | TAILQ_FOREACH(pe, wanted_refs, entry)for((pe) = ((wanted_refs)->tqh_first); (pe) != ((void *)0) ; (pe) = ((pe)->entry.tqe_next)) { | |||
658 | const char *name = pe->path; | |||
659 | size_t name_len = pe->path_len; | |||
660 | ||||
661 | len = sizeof(struct got_imsg_fetch_wanted_ref) + name_len; | |||
662 | wbuf = imsg_create(ibuf, GOT_IMSG_FETCH_WANTED_REF, 0, 0, | |||
663 | len); | |||
664 | if (wbuf == NULL((void *)0)) | |||
665 | return got_error_from_errno( | |||
666 | "imsg_create FETCH_WANTED_REF"); | |||
667 | ||||
668 | /* Keep in sync with struct got_imsg_fetch_wanted_ref! */ | |||
669 | if (imsg_add(wbuf, &name_len, sizeof(name_len)) == -1) { | |||
670 | err = got_error_from_errno( | |||
671 | "imsg_add FETCH_WANTED_REF"); | |||
672 | ibuf_free(wbuf); | |||
673 | return err; | |||
674 | } | |||
675 | if (imsg_add(wbuf, name, name_len) == -1) { | |||
676 | err = got_error_from_errno( | |||
677 | "imsg_add FETCH_WANTED_REF"); | |||
678 | ibuf_free(wbuf); | |||
679 | return err; | |||
680 | } | |||
681 | ||||
682 | wbuf->fd = -1; | |||
683 | imsg_close(ibuf, wbuf); | |||
684 | err = flush_imsg(ibuf); | |||
685 | if (err) | |||
686 | return err; | |||
687 | } | |||
688 | ||||
689 | ||||
690 | return NULL((void *)0); | |||
691 | ||||
692 | } | |||
693 | ||||
694 | const struct got_error * | |||
695 | got_privsep_send_fetch_outfd(struct imsgbuf *ibuf, int fd) | |||
696 | { | |||
697 | return send_fd(ibuf, GOT_IMSG_FETCH_OUTFD, fd); | |||
698 | } | |||
699 | ||||
700 | const struct got_error * | |||
701 | got_privsep_recv_fetch_progress(int *done, struct got_object_id **id, | |||
702 | char **refname, struct got_pathlist_head *symrefs, char **server_progress, | |||
703 | off_t *packfile_size, uint8_t *pack_sha1, struct imsgbuf *ibuf) | |||
704 | { | |||
705 | const struct got_error *err = NULL((void *)0); | |||
706 | struct imsg imsg; | |||
707 | size_t datalen; | |||
708 | struct got_imsg_fetch_symrefs *isymrefs = NULL((void *)0); | |||
709 | size_t n, remain; | |||
710 | off_t off; | |||
711 | int i; | |||
712 | ||||
713 | *done = 0; | |||
714 | *id = NULL((void *)0); | |||
715 | *refname = NULL((void *)0); | |||
716 | *server_progress = NULL((void *)0); | |||
717 | *packfile_size = 0; | |||
718 | memset(pack_sha1, 0, SHA1_DIGEST_LENGTH20); | |||
719 | ||||
720 | err = got_privsep_recv_imsg(&imsg, ibuf, 0); | |||
721 | if (err) | |||
722 | return err; | |||
723 | ||||
724 | datalen = imsg.hdr.len - IMSG_HEADER_SIZEsizeof(struct imsg_hdr); | |||
725 | switch (imsg.hdr.type) { | |||
726 | case GOT_IMSG_ERROR: | |||
727 | if (datalen < sizeof(struct got_imsg_error)) { | |||
728 | err = got_error(GOT_ERR_PRIVSEP_LEN36); | |||
729 | break; | |||
730 | } | |||
731 | err = recv_imsg_error(&imsg, datalen); | |||
732 | break; | |||
733 | case GOT_IMSG_FETCH_SYMREFS: | |||
734 | if (datalen < sizeof(*isymrefs)) { | |||
735 | err = got_error(GOT_ERR_PRIVSEP_LEN36); | |||
736 | break; | |||
737 | } | |||
738 | if (isymrefs != NULL((void *)0)) { | |||
739 | err = got_error(GOT_ERR_PRIVSEP_MSG39); | |||
740 | break; | |||
741 | } | |||
742 | isymrefs = (struct got_imsg_fetch_symrefs *)imsg.data; | |||
743 | off = sizeof(*isymrefs); | |||
744 | remain = datalen - off; | |||
745 | for (n = 0; n < isymrefs->nsymrefs; n++) { | |||
746 | struct got_imsg_fetch_symref *s; | |||
747 | char *name, *target; | |||
748 | if (remain < sizeof(struct got_imsg_fetch_symref)) { | |||
749 | err = got_error(GOT_ERR_PRIVSEP_LEN36); | |||
750 | goto done; | |||
751 | } | |||
752 | s = (struct got_imsg_fetch_symref *)(imsg.data + off); | |||
753 | off += sizeof(*s); | |||
754 | remain -= sizeof(*s); | |||
755 | if (remain < s->name_len) { | |||
756 | err = got_error(GOT_ERR_PRIVSEP_LEN36); | |||
757 | goto done; | |||
758 | } | |||
759 | name = strndup(imsg.data + off, s->name_len); | |||
760 | if (name == NULL((void *)0)) { | |||
761 | err = got_error_from_errno("strndup"); | |||
762 | goto done; | |||
763 | } | |||
764 | off += s->name_len; | |||
765 | remain -= s->name_len; | |||
766 | if (remain < s->target_len) { | |||
767 | err = got_error(GOT_ERR_PRIVSEP_LEN36); | |||
768 | free(name); | |||
769 | goto done; | |||
770 | } | |||
771 | target = strndup(imsg.data + off, s->target_len); | |||
772 | if (target == NULL((void *)0)) { | |||
773 | err = got_error_from_errno("strndup"); | |||
774 | free(name); | |||
775 | goto done; | |||
776 | } | |||
777 | off += s->target_len; | |||
778 | remain -= s->target_len; | |||
779 | err = got_pathlist_append(symrefs, name, target); | |||
780 | if (err) { | |||
781 | free(name); | |||
782 | free(target); | |||
783 | goto done; | |||
784 | } | |||
785 | } | |||
786 | break; | |||
787 | case GOT_IMSG_FETCH_REF: | |||
788 | if (datalen <= SHA1_DIGEST_LENGTH20) { | |||
789 | err = got_error(GOT_ERR_PRIVSEP_MSG39); | |||
790 | break; | |||
791 | } | |||
792 | *id = malloc(sizeof(**id)); | |||
793 | if (*id == NULL((void *)0)) { | |||
794 | err = got_error_from_errno("malloc"); | |||
795 | break; | |||
796 | } | |||
797 | memcpy((*id)->sha1, imsg.data, SHA1_DIGEST_LENGTH20); | |||
798 | *refname = strndup(imsg.data + SHA1_DIGEST_LENGTH20, | |||
799 | datalen - SHA1_DIGEST_LENGTH20); | |||
800 | if (*refname == NULL((void *)0)) { | |||
801 | err = got_error_from_errno("strndup"); | |||
802 | break; | |||
803 | } | |||
804 | break; | |||
805 | case GOT_IMSG_FETCH_SERVER_PROGRESS: | |||
806 | if (datalen == 0) { | |||
807 | err = got_error(GOT_ERR_PRIVSEP_LEN36); | |||
808 | break; | |||
809 | } | |||
810 | *server_progress = strndup(imsg.data, datalen); | |||
811 | if (*server_progress == NULL((void *)0)) { | |||
812 | err = got_error_from_errno("strndup"); | |||
813 | break; | |||
814 | } | |||
815 | for (i = 0; i < datalen; i++) { | |||
816 | if (!isprint((unsigned char)(*server_progress)[i]) && | |||
817 | !isspace((unsigned char)(*server_progress)[i])) { | |||
818 | err = got_error(GOT_ERR_PRIVSEP_MSG39); | |||
819 | free(*server_progress); | |||
820 | *server_progress = NULL((void *)0); | |||
821 | goto done; | |||
822 | } | |||
823 | } | |||
824 | break; | |||
825 | case GOT_IMSG_FETCH_DOWNLOAD_PROGRESS: | |||
826 | if (datalen < sizeof(*packfile_size)) { | |||
827 | err = got_error(GOT_ERR_PRIVSEP_MSG39); | |||
828 | break; | |||
829 | } | |||
830 | memcpy(packfile_size, imsg.data, sizeof(*packfile_size)); | |||
831 | break; | |||
832 | case GOT_IMSG_FETCH_DONE: | |||
833 | if (datalen != SHA1_DIGEST_LENGTH20) { | |||
834 | err = got_error(GOT_ERR_PRIVSEP_MSG39); | |||
835 | break; | |||
836 | } | |||
837 | memcpy(pack_sha1, imsg.data, SHA1_DIGEST_LENGTH20); | |||
838 | *done = 1; | |||
839 | break; | |||
840 | default: | |||
841 | err = got_error(GOT_ERR_PRIVSEP_MSG39); | |||
842 | break; | |||
843 | } | |||
844 | done: | |||
845 | if (err) { | |||
846 | free(*id); | |||
847 | *id = NULL((void *)0); | |||
848 | free(*refname); | |||
849 | *refname = NULL((void *)0); | |||
850 | } | |||
851 | imsg_free(&imsg); | |||
852 | return err; | |||
853 | } | |||
854 | ||||
855 | const struct got_error * | |||
856 | got_privsep_send_index_pack_req(struct imsgbuf *ibuf, uint8_t *pack_sha1, | |||
857 | int fd) | |||
858 | { | |||
859 | const struct got_error *err = NULL((void *)0); | |||
860 | ||||
861 | /* Keep in sync with struct got_imsg_index_pack_request */ | |||
862 | if (imsg_compose(ibuf, GOT_IMSG_IDXPACK_REQUEST, 0, 0, fd, | |||
863 | pack_sha1, SHA1_DIGEST_LENGTH20) == -1) { | |||
864 | err = got_error_from_errno("imsg_compose INDEX_REQUEST"); | |||
865 | close(fd); | |||
866 | return err; | |||
867 | } | |||
868 | return flush_imsg(ibuf); | |||
869 | } | |||
870 | ||||
871 | const struct got_error * | |||
872 | got_privsep_send_index_pack_outfd(struct imsgbuf *ibuf, int fd) | |||
873 | { | |||
874 | return send_fd(ibuf, GOT_IMSG_IDXPACK_OUTFD, fd); | |||
875 | } | |||
876 | ||||
877 | const struct got_error * | |||
878 | got_privsep_recv_index_progress(int *done, int *nobj_total, | |||
879 | int *nobj_indexed, int *nobj_loose, int *nobj_resolved, | |||
880 | struct imsgbuf *ibuf) | |||
881 | { | |||
882 | const struct got_error *err = NULL((void *)0); | |||
883 | struct imsg imsg; | |||
884 | struct got_imsg_index_pack_progress *iprogress; | |||
885 | size_t datalen; | |||
886 | ||||
887 | *done = 0; | |||
888 | *nobj_total = 0; | |||
889 | *nobj_indexed = 0; | |||
890 | *nobj_resolved = 0; | |||
891 | ||||
892 | err = got_privsep_recv_imsg(&imsg, ibuf, 0); | |||
893 | if (err) | |||
894 | return err; | |||
895 | ||||
896 | datalen = imsg.hdr.len - IMSG_HEADER_SIZEsizeof(struct imsg_hdr); | |||
897 | switch (imsg.hdr.type) { | |||
898 | case GOT_IMSG_ERROR: | |||
899 | if (datalen < sizeof(struct got_imsg_error)) { | |||
900 | err = got_error(GOT_ERR_PRIVSEP_LEN36); | |||
901 | break; | |||
902 | } | |||
903 | err = recv_imsg_error(&imsg, datalen); | |||
904 | break; | |||
905 | case GOT_IMSG_IDXPACK_PROGRESS: | |||
906 | if (datalen < sizeof(*iprogress)) { | |||
907 | err = got_error(GOT_ERR_PRIVSEP_LEN36); | |||
908 | break; | |||
909 | } | |||
910 | iprogress = (struct got_imsg_index_pack_progress *)imsg.data; | |||
911 | *nobj_total = iprogress->nobj_total; | |||
912 | *nobj_indexed = iprogress->nobj_indexed; | |||
913 | *nobj_loose = iprogress->nobj_loose; | |||
914 | *nobj_resolved = iprogress->nobj_resolved; | |||
915 | break; | |||
916 | case GOT_IMSG_IDXPACK_DONE: | |||
917 | if (datalen != 0) { | |||
918 | err = got_error(GOT_ERR_PRIVSEP_LEN36); | |||
919 | break; | |||
920 | } | |||
921 | *done = 1; | |||
922 | break; | |||
923 | default: | |||
924 | err = got_error(GOT_ERR_PRIVSEP_MSG39); | |||
925 | break; | |||
926 | } | |||
927 | ||||
928 | imsg_free(&imsg); | |||
929 | return err; | |||
930 | } | |||
931 | ||||
932 | const struct got_error * | |||
933 | got_privsep_get_imsg_obj(struct got_object **obj, struct imsg *imsg, | |||
934 | struct imsgbuf *ibuf) | |||
935 | { | |||
936 | const struct got_error *err = NULL((void *)0); | |||
937 | struct got_imsg_object *iobj; | |||
938 | size_t datalen = imsg->hdr.len - IMSG_HEADER_SIZEsizeof(struct imsg_hdr); | |||
939 | ||||
940 | if (datalen != sizeof(*iobj)) | |||
941 | return got_error(GOT_ERR_PRIVSEP_LEN36); | |||
942 | iobj = imsg->data; | |||
943 | ||||
944 | *obj = calloc(1, sizeof(**obj)); | |||
945 | if (*obj == NULL((void *)0)) | |||
946 | return got_error_from_errno("calloc"); | |||
947 | ||||
948 | memcpy((*obj)->id.sha1, iobj->id, SHA1_DIGEST_LENGTH20); | |||
949 | (*obj)->type = iobj->type; | |||
950 | (*obj)->flags = iobj->flags; | |||
951 | (*obj)->hdrlen = iobj->hdrlen; | |||
952 | (*obj)->size = iobj->size; | |||
953 | /* path_packfile is handled by caller */ | |||
954 | if (iobj->flags & GOT_OBJ_FLAG_PACKED0x01) { | |||
955 | (*obj)->pack_offset = iobj->pack_offset; | |||
956 | (*obj)->pack_idx = iobj->pack_idx; | |||
957 | } | |||
958 | ||||
959 | return err; | |||
960 | } | |||
961 | ||||
962 | const struct got_error * | |||
963 | got_privsep_recv_obj(struct got_object **obj, struct imsgbuf *ibuf) | |||
964 | { | |||
965 | const struct got_error *err = NULL((void *)0); | |||
966 | struct imsg imsg; | |||
967 | const size_t min_datalen = | |||
968 | MIN(sizeof(struct got_imsg_error), sizeof(struct got_imsg_object))((sizeof(struct got_imsg_error)) < (sizeof(struct got_imsg_object )) ? (sizeof(struct got_imsg_error)) : (sizeof(struct got_imsg_object ))); | |||
969 | ||||
970 | *obj = NULL((void *)0); | |||
971 | ||||
972 | err = got_privsep_recv_imsg(&imsg, ibuf, min_datalen); | |||
973 | if (err) | |||
974 | return err; | |||
975 | ||||
976 | switch (imsg.hdr.type) { | |||
977 | case GOT_IMSG_OBJECT: | |||
978 | err = got_privsep_get_imsg_obj(obj, &imsg, ibuf); | |||
979 | break; | |||
980 | default: | |||
981 | err = got_error(GOT_ERR_PRIVSEP_MSG39); | |||
982 | break; | |||
983 | } | |||
984 | ||||
985 | imsg_free(&imsg); | |||
986 | ||||
987 | return err; | |||
988 | } | |||
989 | ||||
990 | static const struct got_error * | |||
991 | send_commit_logmsg(struct imsgbuf *ibuf, struct got_commit_object *commit, | |||
992 | size_t logmsg_len) | |||
993 | { | |||
994 | const struct got_error *err = NULL((void *)0); | |||
995 | size_t offset, remain; | |||
996 | ||||
997 | offset = 0; | |||
998 | remain = logmsg_len; | |||
999 | while (remain > 0) { | |||
1000 | size_t n = MIN(MAX_IMSGSIZE - IMSG_HEADER_SIZE, remain)((16384 - sizeof(struct imsg_hdr)) < (remain) ? (16384 - sizeof (struct imsg_hdr)) : (remain)); | |||
1001 | ||||
1002 | if (imsg_compose(ibuf, GOT_IMSG_COMMIT_LOGMSG, 0, 0, -1, | |||
1003 | commit->logmsg + offset, n) == -1) { | |||
1004 | err = got_error_from_errno("imsg_compose " | |||
1005 | "COMMIT_LOGMSG"); | |||
1006 | break; | |||
1007 | } | |||
1008 | ||||
1009 | err = flush_imsg(ibuf); | |||
1010 | if (err) | |||
1011 | break; | |||
1012 | ||||
1013 | offset += n; | |||
1014 | remain -= n; | |||
1015 | } | |||
1016 | ||||
1017 | return err; | |||
1018 | } | |||
1019 | ||||
1020 | const struct got_error * | |||
1021 | got_privsep_send_commit(struct imsgbuf *ibuf, struct got_commit_object *commit) | |||
1022 | { | |||
1023 | const struct got_error *err = NULL((void *)0); | |||
1024 | struct got_imsg_commit_object *icommit; | |||
1025 | uint8_t *buf; | |||
1026 | size_t len, total; | |||
1027 | struct got_object_qid *qid; | |||
1028 | size_t author_len = strlen(commit->author); | |||
1029 | size_t committer_len = strlen(commit->committer); | |||
1030 | size_t logmsg_len = strlen(commit->logmsg); | |||
1031 | ||||
1032 | total = sizeof(*icommit) + author_len + committer_len + | |||
1033 | commit->nparents * SHA1_DIGEST_LENGTH20; | |||
1034 | ||||
1035 | buf = malloc(total); | |||
1036 | if (buf == NULL((void *)0)) | |||
1037 | return got_error_from_errno("malloc"); | |||
1038 | ||||
1039 | icommit = (struct got_imsg_commit_object *)buf; | |||
1040 | memcpy(icommit->tree_id, commit->tree_id->sha1, | |||
1041 | sizeof(icommit->tree_id)); | |||
1042 | icommit->author_len = author_len; | |||
1043 | icommit->author_time = commit->author_time; | |||
1044 | icommit->author_gmtoff = commit->author_gmtoff; | |||
1045 | icommit->committer_len = committer_len; | |||
1046 | icommit->committer_time = commit->committer_time; | |||
1047 | icommit->committer_gmtoff = commit->committer_gmtoff; | |||
1048 | icommit->logmsg_len = logmsg_len; | |||
1049 | icommit->nparents = commit->nparents; | |||
1050 | ||||
1051 | len = sizeof(*icommit); | |||
1052 | memcpy(buf + len, commit->author, author_len); | |||
1053 | len += author_len; | |||
1054 | memcpy(buf + len, commit->committer, committer_len); | |||
1055 | len += committer_len; | |||
1056 | SIMPLEQ_FOREACH(qid, &commit->parent_ids, entry)for((qid) = ((&commit->parent_ids)->sqh_first); (qid ) != ((void *)0); (qid) = ((qid)->entry.sqe_next)) { | |||
1057 | memcpy(buf + len, qid->id, SHA1_DIGEST_LENGTH20); | |||
1058 | len += SHA1_DIGEST_LENGTH20; | |||
1059 | } | |||
1060 | ||||
1061 | if (imsg_compose(ibuf, GOT_IMSG_COMMIT, 0, 0, -1, buf, len) == -1) { | |||
1062 | err = got_error_from_errno("imsg_compose COMMIT"); | |||
1063 | goto done; | |||
1064 | } | |||
1065 | ||||
1066 | if (logmsg_len == 0 || | |||
1067 | logmsg_len + len > MAX_IMSGSIZE16384 - IMSG_HEADER_SIZEsizeof(struct imsg_hdr)) { | |||
1068 | err = flush_imsg(ibuf); | |||
1069 | if (err) | |||
1070 | goto done; | |||
1071 | } | |||
1072 | err = send_commit_logmsg(ibuf, commit, logmsg_len); | |||
1073 | done: | |||
1074 | free(buf); | |||
1075 | return err; | |||
1076 | } | |||
1077 | ||||
1078 | static const struct got_error * | |||
1079 | get_commit_from_imsg(struct got_commit_object **commit, | |||
1080 | struct imsg *imsg, size_t datalen, struct imsgbuf *ibuf) | |||
1081 | { | |||
1082 | const struct got_error *err = NULL((void *)0); | |||
1083 | struct got_imsg_commit_object *icommit; | |||
1084 | size_t len = 0; | |||
1085 | int i; | |||
1086 | ||||
1087 | if (datalen < sizeof(*icommit)) | |||
1088 | return got_error(GOT_ERR_PRIVSEP_LEN36); | |||
1089 | ||||
1090 | icommit = imsg->data; | |||
1091 | if (datalen != sizeof(*icommit) + icommit->author_len + | |||
1092 | icommit->committer_len + | |||
1093 | icommit->nparents * SHA1_DIGEST_LENGTH20) | |||
1094 | return got_error(GOT_ERR_PRIVSEP_LEN36); | |||
1095 | ||||
1096 | if (icommit->nparents < 0) | |||
1097 | return got_error(GOT_ERR_PRIVSEP_LEN36); | |||
1098 | ||||
1099 | len += sizeof(*icommit); | |||
1100 | ||||
1101 | *commit = got_object_commit_alloc_partial(); | |||
1102 | if (*commit == NULL((void *)0)) | |||
1103 | return got_error_from_errno( | |||
1104 | "got_object_commit_alloc_partial"); | |||
1105 | ||||
1106 | memcpy((*commit)->tree_id->sha1, icommit->tree_id, | |||
1107 | SHA1_DIGEST_LENGTH20); | |||
1108 | (*commit)->author_time = icommit->author_time; | |||
1109 | (*commit)->author_gmtoff = icommit->author_gmtoff; | |||
1110 | (*commit)->committer_time = icommit->committer_time; | |||
1111 | (*commit)->committer_gmtoff = icommit->committer_gmtoff; | |||
1112 | ||||
1113 | if (icommit->author_len == 0) { | |||
1114 | (*commit)->author = strdup(""); | |||
1115 | if ((*commit)->author == NULL((void *)0)) { | |||
1116 | err = got_error_from_errno("strdup"); | |||
1117 | goto done; | |||
1118 | } | |||
1119 | } else { | |||
1120 | (*commit)->author = malloc(icommit->author_len + 1); | |||
1121 | if ((*commit)->author == NULL((void *)0)) { | |||
1122 | err = got_error_from_errno("malloc"); | |||
1123 | goto done; | |||
1124 | } | |||
1125 | memcpy((*commit)->author, imsg->data + len, | |||
1126 | icommit->author_len); | |||
1127 | (*commit)->author[icommit->author_len] = '\0'; | |||
1128 | } | |||
1129 | len += icommit->author_len; | |||
1130 | ||||
1131 | if (icommit->committer_len == 0) { | |||
1132 | (*commit)->committer = strdup(""); | |||
1133 | if ((*commit)->committer == NULL((void *)0)) { | |||
1134 | err = got_error_from_errno("strdup"); | |||
1135 | goto done; | |||
1136 | } | |||
1137 | } else { | |||
1138 | (*commit)->committer = | |||
1139 | malloc(icommit->committer_len + 1); | |||
1140 | if ((*commit)->committer == NULL((void *)0)) { | |||
1141 | err = got_error_from_errno("malloc"); | |||
1142 | goto done; | |||
1143 | } | |||
1144 | memcpy((*commit)->committer, imsg->data + len, | |||
1145 | icommit->committer_len); | |||
1146 | (*commit)->committer[icommit->committer_len] = '\0'; | |||
1147 | } | |||
1148 | len += icommit->committer_len; | |||
1149 | ||||
1150 | if (icommit->logmsg_len == 0) { | |||
1151 | (*commit)->logmsg = strdup(""); | |||
1152 | if ((*commit)->logmsg == NULL((void *)0)) { | |||
1153 | err = got_error_from_errno("strdup"); | |||
1154 | goto done; | |||
1155 | } | |||
1156 | } else { | |||
1157 | size_t offset = 0, remain = icommit->logmsg_len; | |||
1158 | ||||
1159 | (*commit)->logmsg = malloc(icommit->logmsg_len + 1); | |||
1160 | if ((*commit)->logmsg == NULL((void *)0)) { | |||
1161 | err = got_error_from_errno("malloc"); | |||
1162 | goto done; | |||
1163 | } | |||
1164 | while (remain > 0) { | |||
1165 | struct imsg imsg_log; | |||
1166 | size_t n = MIN(MAX_IMSGSIZE - IMSG_HEADER_SIZE,((16384 - sizeof(struct imsg_hdr)) < (remain) ? (16384 - sizeof (struct imsg_hdr)) : (remain)) | |||
1167 | remain)((16384 - sizeof(struct imsg_hdr)) < (remain) ? (16384 - sizeof (struct imsg_hdr)) : (remain)); | |||
1168 | ||||
1169 | err = got_privsep_recv_imsg(&imsg_log, ibuf, n); | |||
1170 | if (err) | |||
1171 | goto done; | |||
1172 | ||||
1173 | if (imsg_log.hdr.type != GOT_IMSG_COMMIT_LOGMSG) { | |||
1174 | err = got_error(GOT_ERR_PRIVSEP_MSG39); | |||
1175 | goto done; | |||
1176 | } | |||
1177 | ||||
1178 | memcpy((*commit)->logmsg + offset, | |||
1179 | imsg_log.data, n); | |||
1180 | imsg_free(&imsg_log); | |||
1181 | offset += n; | |||
1182 | remain -= n; | |||
1183 | } | |||
1184 | (*commit)->logmsg[icommit->logmsg_len] = '\0'; | |||
1185 | } | |||
1186 | ||||
1187 | for (i = 0; i < icommit->nparents; i++) { | |||
1188 | struct got_object_qid *qid; | |||
1189 | ||||
1190 | err = got_object_qid_alloc_partial(&qid); | |||
1191 | if (err) | |||
1192 | break; | |||
1193 | memcpy(qid->id, imsg->data + len + | |||
1194 | i * SHA1_DIGEST_LENGTH20, sizeof(*qid->id)); | |||
1195 | SIMPLEQ_INSERT_TAIL(&(*commit)->parent_ids, qid, entry)do { (qid)->entry.sqe_next = ((void *)0); *(&(*commit) ->parent_ids)->sqh_last = (qid); (&(*commit)->parent_ids )->sqh_last = &(qid)->entry.sqe_next; } while (0); | |||
1196 | (*commit)->nparents++; | |||
1197 | } | |||
1198 | done: | |||
1199 | if (err) { | |||
1200 | got_object_commit_close(*commit); | |||
1201 | *commit = NULL((void *)0); | |||
1202 | } | |||
1203 | return err; | |||
1204 | } | |||
1205 | ||||
1206 | const struct got_error * | |||
1207 | got_privsep_recv_commit(struct got_commit_object **commit, struct imsgbuf *ibuf) | |||
1208 | { | |||
1209 | const struct got_error *err = NULL((void *)0); | |||
1210 | struct imsg imsg; | |||
1211 | size_t datalen; | |||
1212 | const size_t min_datalen = | |||
1213 | MIN(sizeof(struct got_imsg_error),((sizeof(struct got_imsg_error)) < (sizeof(struct got_imsg_commit_object )) ? (sizeof(struct got_imsg_error)) : (sizeof(struct got_imsg_commit_object ))) | |||
1214 | sizeof(struct got_imsg_commit_object))((sizeof(struct got_imsg_error)) < (sizeof(struct got_imsg_commit_object )) ? (sizeof(struct got_imsg_error)) : (sizeof(struct got_imsg_commit_object ))); | |||
1215 | ||||
1216 | *commit = NULL((void *)0); | |||
1217 | ||||
1218 | err = got_privsep_recv_imsg(&imsg, ibuf, min_datalen); | |||
1219 | if (err) | |||
1220 | return err; | |||
1221 | ||||
1222 | datalen = imsg.hdr.len - IMSG_HEADER_SIZEsizeof(struct imsg_hdr); | |||
1223 | ||||
1224 | switch (imsg.hdr.type) { | |||
1225 | case GOT_IMSG_COMMIT: | |||
1226 | err = get_commit_from_imsg(commit, &imsg, datalen, ibuf); | |||
1227 | break; | |||
1228 | default: | |||
1229 | err = got_error(GOT_ERR_PRIVSEP_MSG39); | |||
1230 | break; | |||
1231 | } | |||
1232 | ||||
1233 | imsg_free(&imsg); | |||
1234 | ||||
1235 | return err; | |||
1236 | } | |||
1237 | ||||
1238 | const struct got_error * | |||
1239 | got_privsep_send_tree(struct imsgbuf *ibuf, struct got_pathlist_head *entries, | |||
1240 | int nentries) | |||
1241 | { | |||
1242 | const struct got_error *err = NULL((void *)0); | |||
1243 | struct got_imsg_tree_object itree; | |||
1244 | struct got_pathlist_entry *pe; | |||
1245 | size_t totlen; | |||
1246 | int nimsg; /* number of imsg queued in ibuf */ | |||
1247 | ||||
1248 | itree.nentries = nentries; | |||
1249 | if (imsg_compose(ibuf, GOT_IMSG_TREE, 0, 0, -1, &itree, sizeof(itree)) | |||
1250 | == -1) | |||
1251 | return got_error_from_errno("imsg_compose TREE"); | |||
1252 | ||||
1253 | totlen = sizeof(itree); | |||
1254 | nimsg = 1; | |||
1255 | TAILQ_FOREACH(pe, entries, entry)for((pe) = ((entries)->tqh_first); (pe) != ((void *)0); (pe ) = ((pe)->entry.tqe_next)) { | |||
1256 | const char *name = pe->path; | |||
1257 | struct got_parsed_tree_entry *pte = pe->data; | |||
1258 | struct ibuf *wbuf; | |||
1259 | size_t namelen = strlen(name); | |||
1260 | size_t len = sizeof(struct got_imsg_tree_entry) + namelen; | |||
1261 | ||||
1262 | if (len > MAX_IMSGSIZE16384) | |||
1263 | return got_error(GOT_ERR_NO_SPACE9); | |||
1264 | ||||
1265 | nimsg++; | |||
1266 | if (totlen + len >= MAX_IMSGSIZE16384 - (IMSG_HEADER_SIZEsizeof(struct imsg_hdr) * nimsg)) { | |||
1267 | err = flush_imsg(ibuf); | |||
1268 | if (err) | |||
1269 | return err; | |||
1270 | nimsg = 0; | |||
1271 | } | |||
1272 | ||||
1273 | wbuf = imsg_create(ibuf, GOT_IMSG_TREE_ENTRY, 0, 0, len); | |||
1274 | if (wbuf == NULL((void *)0)) | |||
1275 | return got_error_from_errno("imsg_create TREE_ENTRY"); | |||
1276 | ||||
1277 | /* Keep in sync with struct got_imsg_tree_object definition! */ | |||
1278 | if (imsg_add(wbuf, pte->id, SHA1_DIGEST_LENGTH20) == -1) { | |||
1279 | err = got_error_from_errno("imsg_add TREE_ENTRY"); | |||
1280 | ibuf_free(wbuf); | |||
1281 | return err; | |||
1282 | } | |||
1283 | if (imsg_add(wbuf, &pte->mode, sizeof(pte->mode)) == -1) { | |||
1284 | err = got_error_from_errno("imsg_add TREE_ENTRY"); | |||
1285 | ibuf_free(wbuf); | |||
1286 | return err; | |||
1287 | } | |||
1288 | ||||
1289 | if (imsg_add(wbuf, name, namelen) == -1) { | |||
1290 | err = got_error_from_errno("imsg_add TREE_ENTRY"); | |||
1291 | ibuf_free(wbuf); | |||
1292 | return err; | |||
1293 | } | |||
1294 | ||||
1295 | wbuf->fd = -1; | |||
1296 | imsg_close(ibuf, wbuf); | |||
1297 | ||||
1298 | totlen += len; | |||
1299 | } | |||
1300 | ||||
1301 | return flush_imsg(ibuf); | |||
1302 | } | |||
1303 | ||||
1304 | const struct got_error * | |||
1305 | got_privsep_recv_tree(struct got_tree_object **tree, struct imsgbuf *ibuf) | |||
1306 | { | |||
1307 | const struct got_error *err = NULL((void *)0); | |||
1308 | const size_t min_datalen = | |||
1309 | MIN(sizeof(struct got_imsg_error),((sizeof(struct got_imsg_error)) < (sizeof(struct got_imsg_tree_object )) ? (sizeof(struct got_imsg_error)) : (sizeof(struct got_imsg_tree_object ))) | |||
1310 | sizeof(struct got_imsg_tree_object))((sizeof(struct got_imsg_error)) < (sizeof(struct got_imsg_tree_object )) ? (sizeof(struct got_imsg_error)) : (sizeof(struct got_imsg_tree_object ))); | |||
1311 | struct got_imsg_tree_object *itree; | |||
1312 | int nentries = 0; | |||
1313 | ||||
1314 | *tree = NULL((void *)0); | |||
1315 | get_more: | |||
1316 | err = read_imsg(ibuf); | |||
1317 | if (err) | |||
1318 | goto done; | |||
1319 | ||||
1320 | for (;;) { | |||
1321 | struct imsg imsg; | |||
1322 | size_t n; | |||
1323 | size_t datalen; | |||
1324 | struct got_imsg_tree_entry *ite; | |||
1325 | struct got_tree_entry *te = NULL((void *)0); | |||
1326 | ||||
1327 | n = imsg_get(ibuf, &imsg); | |||
1328 | if (n == 0) { | |||
1329 | if (*tree && (*tree)->nentries != nentries) | |||
1330 | goto get_more; | |||
1331 | break; | |||
1332 | } | |||
1333 | ||||
1334 | if (imsg.hdr.len < IMSG_HEADER_SIZEsizeof(struct imsg_hdr) + min_datalen) { | |||
1335 | imsg_free(&imsg); | |||
1336 | err = got_error(GOT_ERR_PRIVSEP_LEN36); | |||
1337 | break; | |||
1338 | } | |||
1339 | ||||
1340 | datalen = imsg.hdr.len - IMSG_HEADER_SIZEsizeof(struct imsg_hdr); | |||
1341 | ||||
1342 | switch (imsg.hdr.type) { | |||
1343 | case GOT_IMSG_ERROR: | |||
1344 | err = recv_imsg_error(&imsg, datalen); | |||
1345 | break; | |||
1346 | case GOT_IMSG_TREE: | |||
1347 | /* This message should only appear once. */ | |||
1348 | if (*tree != NULL((void *)0)) { | |||
1349 | err = got_error(GOT_ERR_PRIVSEP_MSG39); | |||
1350 | break; | |||
1351 | } | |||
1352 | if (datalen != sizeof(*itree)) { | |||
1353 | err = got_error(GOT_ERR_PRIVSEP_LEN36); | |||
1354 | break; | |||
1355 | } | |||
1356 | itree = imsg.data; | |||
1357 | *tree = malloc(sizeof(**tree)); | |||
1358 | if (*tree == NULL((void *)0)) { | |||
1359 | err = got_error_from_errno("malloc"); | |||
1360 | break; | |||
1361 | } | |||
1362 | (*tree)->entries = calloc(itree->nentries, | |||
1363 | sizeof(struct got_tree_entry)); | |||
1364 | if ((*tree)->entries == NULL((void *)0)) { | |||
1365 | err = got_error_from_errno("malloc"); | |||
1366 | break; | |||
1367 | } | |||
1368 | (*tree)->nentries = itree->nentries; | |||
1369 | (*tree)->refcnt = 0; | |||
1370 | break; | |||
1371 | case GOT_IMSG_TREE_ENTRY: | |||
1372 | /* This message should be preceeded by GOT_IMSG_TREE. */ | |||
1373 | if (*tree == NULL((void *)0)) { | |||
1374 | err = got_error(GOT_ERR_PRIVSEP_MSG39); | |||
1375 | break; | |||
1376 | } | |||
1377 | if (datalen < sizeof(*ite) || datalen > MAX_IMSGSIZE16384) { | |||
1378 | err = got_error(GOT_ERR_PRIVSEP_LEN36); | |||
1379 | break; | |||
1380 | } | |||
1381 | ||||
1382 | /* Remaining data contains the entry's name. */ | |||
1383 | datalen -= sizeof(*ite); | |||
1384 | if (datalen == 0 || datalen > MAX_IMSGSIZE16384) { | |||
1385 | err = got_error(GOT_ERR_PRIVSEP_LEN36); | |||
1386 | break; | |||
1387 | } | |||
1388 | ite = imsg.data; | |||
1389 | ||||
1390 | if (datalen + 1 > sizeof(te->name)) { | |||
1391 | err = got_error(GOT_ERR_NO_SPACE9); | |||
1392 | break; | |||
1393 | } | |||
1394 | te = &(*tree)->entries[nentries]; | |||
1395 | memcpy(te->name, imsg.data + sizeof(*ite), datalen); | |||
1396 | te->name[datalen] = '\0'; | |||
1397 | ||||
1398 | memcpy(te->id.sha1, ite->id, SHA1_DIGEST_LENGTH20); | |||
1399 | te->mode = ite->mode; | |||
1400 | te->idx = nentries; | |||
1401 | nentries++; | |||
1402 | break; | |||
1403 | default: | |||
1404 | err = got_error(GOT_ERR_PRIVSEP_MSG39); | |||
1405 | break; | |||
1406 | } | |||
1407 | ||||
1408 | imsg_free(&imsg); | |||
1409 | if (err) | |||
1410 | break; | |||
1411 | } | |||
1412 | done: | |||
1413 | if (*tree && (*tree)->nentries != nentries) { | |||
1414 | if (err == NULL((void *)0)) | |||
1415 | err = got_error(GOT_ERR_PRIVSEP_LEN36); | |||
1416 | got_object_tree_close(*tree); | |||
1417 | *tree = NULL((void *)0); | |||
1418 | } | |||
1419 | ||||
1420 | return err; | |||
1421 | } | |||
1422 | ||||
1423 | const struct got_error * | |||
1424 | got_privsep_send_blob(struct imsgbuf *ibuf, size_t size, size_t hdrlen, | |||
1425 | const uint8_t *data) | |||
1426 | { | |||
1427 | struct got_imsg_blob iblob; | |||
1428 | ||||
1429 | iblob.size = size; | |||
1430 | iblob.hdrlen = hdrlen; | |||
1431 | ||||
1432 | if (data) { | |||
1433 | uint8_t *buf; | |||
1434 | ||||
1435 | if (size > GOT_PRIVSEP_INLINE_BLOB_DATA_MAX(16384 - sizeof(struct imsg_hdr) - sizeof(struct got_imsg_blob ))) | |||
1436 | return got_error(GOT_ERR_NO_SPACE9); | |||
1437 | ||||
1438 | buf = malloc(sizeof(iblob) + size); | |||
1439 | if (buf == NULL((void *)0)) | |||
1440 | return got_error_from_errno("malloc"); | |||
1441 | ||||
1442 | memcpy(buf, &iblob, sizeof(iblob)); | |||
1443 | memcpy(buf + sizeof(iblob), data, size); | |||
1444 | if (imsg_compose(ibuf, GOT_IMSG_BLOB, 0, 0, -1, buf, | |||
1445 | sizeof(iblob) + size) == -1) { | |||
1446 | free(buf); | |||
1447 | return got_error_from_errno("imsg_compose BLOB"); | |||
1448 | } | |||
1449 | free(buf); | |||
1450 | } else { | |||
1451 | /* Data has already been written to file descriptor. */ | |||
1452 | if (imsg_compose(ibuf, GOT_IMSG_BLOB, 0, 0, -1, &iblob, | |||
1453 | sizeof(iblob)) == -1) | |||
1454 | return got_error_from_errno("imsg_compose BLOB"); | |||
1455 | } | |||
1456 | ||||
1457 | ||||
1458 | return flush_imsg(ibuf); | |||
1459 | } | |||
1460 | ||||
1461 | const struct got_error * | |||
1462 | got_privsep_recv_blob(uint8_t **outbuf, size_t *size, size_t *hdrlen, | |||
1463 | struct imsgbuf *ibuf) | |||
1464 | { | |||
1465 | const struct got_error *err = NULL((void *)0); | |||
1466 | struct imsg imsg; | |||
1467 | struct got_imsg_blob *iblob; | |||
1468 | size_t datalen; | |||
1469 | ||||
1470 | *outbuf = NULL((void *)0); | |||
1471 | ||||
1472 | err = got_privsep_recv_imsg(&imsg, ibuf, 0); | |||
1473 | if (err) | |||
1474 | return err; | |||
1475 | ||||
1476 | datalen = imsg.hdr.len - IMSG_HEADER_SIZEsizeof(struct imsg_hdr); | |||
1477 | ||||
1478 | switch (imsg.hdr.type) { | |||
1479 | case GOT_IMSG_BLOB: | |||
1480 | if (datalen < sizeof(*iblob)) { | |||
1481 | err = got_error(GOT_ERR_PRIVSEP_LEN36); | |||
1482 | break; | |||
1483 | } | |||
1484 | iblob = imsg.data; | |||
1485 | *size = iblob->size; | |||
1486 | *hdrlen = iblob->hdrlen; | |||
1487 | ||||
1488 | if (datalen == sizeof(*iblob)) { | |||
1489 | /* Data has been written to file descriptor. */ | |||
1490 | break; | |||
1491 | } | |||
1492 | ||||
1493 | if (*size > GOT_PRIVSEP_INLINE_BLOB_DATA_MAX(16384 - sizeof(struct imsg_hdr) - sizeof(struct got_imsg_blob ))) { | |||
1494 | err = got_error(GOT_ERR_PRIVSEP_LEN36); | |||
1495 | break; | |||
1496 | } | |||
1497 | ||||
1498 | *outbuf = malloc(*size); | |||
1499 | if (*outbuf == NULL((void *)0)) { | |||
1500 | err = got_error_from_errno("malloc"); | |||
1501 | break; | |||
1502 | } | |||
1503 | memcpy(*outbuf, imsg.data + sizeof(*iblob), *size); | |||
1504 | break; | |||
1505 | default: | |||
1506 | err = got_error(GOT_ERR_PRIVSEP_MSG39); | |||
1507 | break; | |||
1508 | } | |||
1509 | ||||
1510 | imsg_free(&imsg); | |||
1511 | ||||
1512 | return err; | |||
1513 | } | |||
1514 | ||||
1515 | static const struct got_error * | |||
1516 | send_tagmsg(struct imsgbuf *ibuf, struct got_tag_object *tag, size_t tagmsg_len) | |||
1517 | { | |||
1518 | const struct got_error *err = NULL((void *)0); | |||
1519 | size_t offset, remain; | |||
1520 | ||||
1521 | offset = 0; | |||
1522 | remain = tagmsg_len; | |||
1523 | while (remain > 0) { | |||
1524 | size_t n = MIN(MAX_IMSGSIZE - IMSG_HEADER_SIZE, remain)((16384 - sizeof(struct imsg_hdr)) < (remain) ? (16384 - sizeof (struct imsg_hdr)) : (remain)); | |||
1525 | ||||
1526 | if (imsg_compose(ibuf, GOT_IMSG_TAG_TAGMSG, 0, 0, -1, | |||
1527 | tag->tagmsg + offset, n) == -1) { | |||
1528 | err = got_error_from_errno("imsg_compose TAG_TAGMSG"); | |||
1529 | break; | |||
1530 | } | |||
1531 | ||||
1532 | err = flush_imsg(ibuf); | |||
1533 | if (err) | |||
1534 | break; | |||
1535 | ||||
1536 | offset += n; | |||
1537 | remain -= n; | |||
1538 | } | |||
1539 | ||||
1540 | return err; | |||
1541 | } | |||
1542 | ||||
1543 | const struct got_error * | |||
1544 | got_privsep_send_tag(struct imsgbuf *ibuf, struct got_tag_object *tag) | |||
1545 | { | |||
1546 | const struct got_error *err = NULL((void *)0); | |||
1547 | struct got_imsg_tag_object *itag; | |||
1548 | uint8_t *buf; | |||
1549 | size_t len, total; | |||
1550 | size_t tag_len = strlen(tag->tag); | |||
1551 | size_t tagger_len = strlen(tag->tagger); | |||
1552 | size_t tagmsg_len = strlen(tag->tagmsg); | |||
1553 | ||||
1554 | total = sizeof(*itag) + tag_len + tagger_len + tagmsg_len; | |||
1555 | ||||
1556 | buf = malloc(total); | |||
1557 | if (buf == NULL((void *)0)) | |||
1558 | return got_error_from_errno("malloc"); | |||
1559 | ||||
1560 | itag = (struct got_imsg_tag_object *)buf; | |||
1561 | memcpy(itag->id, tag->id.sha1, sizeof(itag->id)); | |||
1562 | itag->obj_type = tag->obj_type; | |||
1563 | itag->tag_len = tag_len; | |||
1564 | itag->tagger_len = tagger_len; | |||
1565 | itag->tagger_time = tag->tagger_time; | |||
1566 | itag->tagger_gmtoff = tag->tagger_gmtoff; | |||
1567 | itag->tagmsg_len = tagmsg_len; | |||
1568 | ||||
1569 | len = sizeof(*itag); | |||
1570 | memcpy(buf + len, tag->tag, tag_len); | |||
1571 | len += tag_len; | |||
1572 | memcpy(buf + len, tag->tagger, tagger_len); | |||
1573 | len += tagger_len; | |||
1574 | ||||
1575 | if (imsg_compose(ibuf, GOT_IMSG_TAG, 0, 0, -1, buf, len) == -1) { | |||
1576 | err = got_error_from_errno("imsg_compose TAG"); | |||
1577 | goto done; | |||
1578 | } | |||
1579 | ||||
1580 | if (tagmsg_len == 0 || | |||
1581 | tagmsg_len + len > MAX_IMSGSIZE16384 - IMSG_HEADER_SIZEsizeof(struct imsg_hdr)) { | |||
1582 | err = flush_imsg(ibuf); | |||
1583 | if (err) | |||
1584 | goto done; | |||
1585 | } | |||
1586 | err = send_tagmsg(ibuf, tag, tagmsg_len); | |||
1587 | done: | |||
1588 | free(buf); | |||
1589 | return err; | |||
1590 | } | |||
1591 | ||||
1592 | const struct got_error * | |||
1593 | got_privsep_recv_tag(struct got_tag_object **tag, struct imsgbuf *ibuf) | |||
1594 | { | |||
1595 | const struct got_error *err = NULL((void *)0); | |||
1596 | struct imsg imsg; | |||
1597 | struct got_imsg_tag_object *itag; | |||
1598 | size_t len, datalen; | |||
1599 | const size_t min_datalen = | |||
1600 | MIN(sizeof(struct got_imsg_error),((sizeof(struct got_imsg_error)) < (sizeof(struct got_imsg_tag_object )) ? (sizeof(struct got_imsg_error)) : (sizeof(struct got_imsg_tag_object ))) | |||
1601 | sizeof(struct got_imsg_tag_object))((sizeof(struct got_imsg_error)) < (sizeof(struct got_imsg_tag_object )) ? (sizeof(struct got_imsg_error)) : (sizeof(struct got_imsg_tag_object ))); | |||
1602 | ||||
1603 | *tag = NULL((void *)0); | |||
1604 | ||||
1605 | err = got_privsep_recv_imsg(&imsg, ibuf, min_datalen); | |||
1606 | if (err) | |||
1607 | return err; | |||
1608 | ||||
1609 | datalen = imsg.hdr.len - IMSG_HEADER_SIZEsizeof(struct imsg_hdr); | |||
1610 | len = 0; | |||
1611 | ||||
1612 | switch (imsg.hdr.type) { | |||
1613 | case GOT_IMSG_TAG: | |||
1614 | if (datalen < sizeof(*itag)) { | |||
1615 | err = got_error(GOT_ERR_PRIVSEP_LEN36); | |||
1616 | break; | |||
1617 | } | |||
1618 | itag = imsg.data; | |||
1619 | if (datalen != sizeof(*itag) + itag->tag_len + | |||
1620 | itag->tagger_len) { | |||
1621 | err = got_error(GOT_ERR_PRIVSEP_LEN36); | |||
1622 | break; | |||
1623 | } | |||
1624 | len += sizeof(*itag); | |||
1625 | ||||
1626 | *tag = calloc(1, sizeof(**tag)); | |||
1627 | if (*tag == NULL((void *)0)) { | |||
1628 | err = got_error_from_errno("calloc"); | |||
1629 | break; | |||
1630 | } | |||
1631 | ||||
1632 | memcpy((*tag)->id.sha1, itag->id, SHA1_DIGEST_LENGTH20); | |||
1633 | ||||
1634 | if (itag->tag_len == 0) { | |||
1635 | (*tag)->tag = strdup(""); | |||
1636 | if ((*tag)->tag == NULL((void *)0)) { | |||
1637 | err = got_error_from_errno("strdup"); | |||
1638 | break; | |||
1639 | } | |||
1640 | } else { | |||
1641 | (*tag)->tag = malloc(itag->tag_len + 1); | |||
1642 | if ((*tag)->tag == NULL((void *)0)) { | |||
1643 | err = got_error_from_errno("malloc"); | |||
1644 | break; | |||
1645 | } | |||
1646 | memcpy((*tag)->tag, imsg.data + len, | |||
1647 | itag->tag_len); | |||
1648 | (*tag)->tag[itag->tag_len] = '\0'; | |||
1649 | } | |||
1650 | len += itag->tag_len; | |||
1651 | ||||
1652 | (*tag)->obj_type = itag->obj_type; | |||
1653 | (*tag)->tagger_time = itag->tagger_time; | |||
1654 | (*tag)->tagger_gmtoff = itag->tagger_gmtoff; | |||
1655 | ||||
1656 | if (itag->tagger_len == 0) { | |||
1657 | (*tag)->tagger = strdup(""); | |||
1658 | if ((*tag)->tagger == NULL((void *)0)) { | |||
1659 | err = got_error_from_errno("strdup"); | |||
1660 | break; | |||
1661 | } | |||
1662 | } else { | |||
1663 | (*tag)->tagger = malloc(itag->tagger_len + 1); | |||
1664 | if ((*tag)->tagger == NULL((void *)0)) { | |||
1665 | err = got_error_from_errno("malloc"); | |||
1666 | break; | |||
1667 | } | |||
1668 | memcpy((*tag)->tagger, imsg.data + len, | |||
1669 | itag->tagger_len); | |||
1670 | (*tag)->tagger[itag->tagger_len] = '\0'; | |||
1671 | } | |||
1672 | len += itag->tagger_len; | |||
1673 | ||||
1674 | if (itag->tagmsg_len == 0) { | |||
1675 | (*tag)->tagmsg = strdup(""); | |||
1676 | if ((*tag)->tagmsg == NULL((void *)0)) { | |||
1677 | err = got_error_from_errno("strdup"); | |||
1678 | break; | |||
1679 | } | |||
1680 | } else { | |||
1681 | size_t offset = 0, remain = itag->tagmsg_len; | |||
1682 | ||||
1683 | (*tag)->tagmsg = malloc(itag->tagmsg_len + 1); | |||
1684 | if ((*tag)->tagmsg == NULL((void *)0)) { | |||
1685 | err = got_error_from_errno("malloc"); | |||
1686 | break; | |||
1687 | } | |||
1688 | while (remain > 0) { | |||
1689 | struct imsg imsg_log; | |||
1690 | size_t n = MIN(MAX_IMSGSIZE - IMSG_HEADER_SIZE,((16384 - sizeof(struct imsg_hdr)) < (remain) ? (16384 - sizeof (struct imsg_hdr)) : (remain)) | |||
1691 | remain)((16384 - sizeof(struct imsg_hdr)) < (remain) ? (16384 - sizeof (struct imsg_hdr)) : (remain)); | |||
1692 | ||||
1693 | err = got_privsep_recv_imsg(&imsg_log, ibuf, n); | |||
1694 | if (err) | |||
1695 | return err; | |||
1696 | ||||
1697 | if (imsg_log.hdr.type != GOT_IMSG_TAG_TAGMSG) | |||
1698 | return got_error(GOT_ERR_PRIVSEP_MSG39); | |||
1699 | ||||
1700 | memcpy((*tag)->tagmsg + offset, imsg_log.data, | |||
1701 | n); | |||
1702 | imsg_free(&imsg_log); | |||
1703 | offset += n; | |||
1704 | remain -= n; | |||
1705 | } | |||
1706 | (*tag)->tagmsg[itag->tagmsg_len] = '\0'; | |||
1707 | } | |||
1708 | ||||
1709 | break; | |||
1710 | default: | |||
1711 | err = got_error(GOT_ERR_PRIVSEP_MSG39); | |||
1712 | break; | |||
1713 | } | |||
1714 | ||||
1715 | imsg_free(&imsg); | |||
1716 | ||||
1717 | return err; | |||
1718 | } | |||
1719 | ||||
1720 | const struct got_error * | |||
1721 | got_privsep_init_pack_child(struct imsgbuf *ibuf, struct got_pack *pack, | |||
1722 | struct got_packidx *packidx) | |||
1723 | { | |||
1724 | const struct got_error *err = NULL((void *)0); | |||
1725 | struct got_imsg_packidx ipackidx; | |||
1726 | struct got_imsg_pack ipack; | |||
1727 | int fd; | |||
1728 | ||||
1729 | ipackidx.len = packidx->len; | |||
1730 | fd = dup(packidx->fd); | |||
1731 | if (fd == -1) | |||
1732 | return got_error_from_errno("dup"); | |||
1733 | ||||
1734 | if (imsg_compose(ibuf, GOT_IMSG_PACKIDX, 0, 0, fd, &ipackidx, | |||
1735 | sizeof(ipackidx)) == -1) { | |||
1736 | err = got_error_from_errno("imsg_compose PACKIDX"); | |||
1737 | close(fd); | |||
1738 | return err; | |||
1739 | } | |||
1740 | ||||
1741 | if (strlcpy(ipack.path_packfile, pack->path_packfile, | |||
1742 | sizeof(ipack.path_packfile)) >= sizeof(ipack.path_packfile)) | |||
1743 | return got_error(GOT_ERR_NO_SPACE9); | |||
1744 | ipack.filesize = pack->filesize; | |||
1745 | ||||
1746 | fd = dup(pack->fd); | |||
1747 | if (fd == -1) | |||
1748 | return got_error_from_errno("dup"); | |||
1749 | ||||
1750 | if (imsg_compose(ibuf, GOT_IMSG_PACK, 0, 0, fd, &ipack, sizeof(ipack)) | |||
1751 | == -1) { | |||
1752 | err = got_error_from_errno("imsg_compose PACK"); | |||
1753 | close(fd); | |||
1754 | return err; | |||
1755 | } | |||
1756 | ||||
1757 | return flush_imsg(ibuf); | |||
1758 | } | |||
1759 | ||||
1760 | const struct got_error * | |||
1761 | got_privsep_send_packed_obj_req(struct imsgbuf *ibuf, int idx, | |||
1762 | struct got_object_id *id) | |||
1763 | { | |||
1764 | struct got_imsg_packed_object iobj; | |||
1765 | ||||
1766 | iobj.idx = idx; | |||
1767 | memcpy(iobj.id, id->sha1, sizeof(iobj.id)); | |||
1768 | ||||
1769 | if (imsg_compose(ibuf, GOT_IMSG_PACKED_OBJECT_REQUEST, 0, 0, -1, | |||
1770 | &iobj, sizeof(iobj)) == -1) | |||
1771 | return got_error_from_errno("imsg_compose " | |||
1772 | "PACKED_OBJECT_REQUEST"); | |||
1773 | ||||
1774 | return flush_imsg(ibuf); | |||
1775 | } | |||
1776 | ||||
1777 | const struct got_error * | |||
1778 | got_privsep_send_packed_raw_obj_req(struct imsgbuf *ibuf, int idx, | |||
1779 | struct got_object_id *id) | |||
1780 | { | |||
1781 | struct got_imsg_packed_object iobj; | |||
1782 | ||||
1783 | iobj.idx = idx; | |||
1784 | memcpy(iobj.id, id->sha1, sizeof(iobj.id)); | |||
1785 | ||||
1786 | if (imsg_compose(ibuf, GOT_IMSG_PACKED_RAW_OBJECT_REQUEST, 0, 0, -1, | |||
1787 | &iobj, sizeof(iobj)) == -1) | |||
1788 | return got_error_from_errno("imsg_compose " | |||
1789 | "PACKED_OBJECT_REQUEST"); | |||
1790 | ||||
1791 | return flush_imsg(ibuf); | |||
1792 | } | |||
1793 | ||||
1794 | const struct got_error * | |||
1795 | got_privsep_send_gitconfig_parse_req(struct imsgbuf *ibuf, int fd) | |||
1796 | { | |||
1797 | const struct got_error *err = NULL((void *)0); | |||
1798 | ||||
1799 | if (imsg_compose(ibuf, GOT_IMSG_GITCONFIG_PARSE_REQUEST, 0, 0, fd, | |||
1800 | NULL((void *)0), 0) == -1) { | |||
1801 | err = got_error_from_errno("imsg_compose " | |||
1802 | "GITCONFIG_PARSE_REQUEST"); | |||
1803 | close(fd); | |||
1804 | return err; | |||
1805 | } | |||
1806 | ||||
1807 | return flush_imsg(ibuf); | |||
1808 | } | |||
1809 | ||||
1810 | const struct got_error * | |||
1811 | got_privsep_send_gitconfig_repository_format_version_req(struct imsgbuf *ibuf) | |||
1812 | { | |||
1813 | if (imsg_compose(ibuf, | |||
1814 | GOT_IMSG_GITCONFIG_REPOSITORY_FORMAT_VERSION_REQUEST, 0, 0, -1, | |||
1815 | NULL((void *)0), 0) == -1) | |||
1816 | return got_error_from_errno("imsg_compose " | |||
1817 | "GITCONFIG_REPOSITORY_FORMAT_VERSION_REQUEST"); | |||
1818 | ||||
1819 | return flush_imsg(ibuf); | |||
1820 | } | |||
1821 | ||||
1822 | const struct got_error * | |||
1823 | got_privsep_send_gitconfig_repository_extensions_req(struct imsgbuf *ibuf) | |||
1824 | { | |||
1825 | if (imsg_compose(ibuf, | |||
1826 | GOT_IMSG_GITCONFIG_REPOSITORY_EXTENSIONS_REQUEST, 0, 0, -1, | |||
1827 | NULL((void *)0), 0) == -1) | |||
1828 | return got_error_from_errno("imsg_compose " | |||
1829 | "GITCONFIG_REPOSITORY_EXTENSIONS_REQUEST"); | |||
1830 | ||||
1831 | return flush_imsg(ibuf); | |||
1832 | } | |||
1833 | ||||
1834 | ||||
1835 | const struct got_error * | |||
1836 | got_privsep_send_gitconfig_author_name_req(struct imsgbuf *ibuf) | |||
1837 | { | |||
1838 | if (imsg_compose(ibuf, | |||
1839 | GOT_IMSG_GITCONFIG_AUTHOR_NAME_REQUEST, 0, 0, -1, NULL((void *)0), 0) == -1) | |||
1840 | return got_error_from_errno("imsg_compose " | |||
1841 | "GITCONFIG_AUTHOR_NAME_REQUEST"); | |||
1842 | ||||
1843 | return flush_imsg(ibuf); | |||
1844 | } | |||
1845 | ||||
1846 | const struct got_error * | |||
1847 | got_privsep_send_gitconfig_author_email_req(struct imsgbuf *ibuf) | |||
1848 | { | |||
1849 | if (imsg_compose(ibuf, | |||
1850 | GOT_IMSG_GITCONFIG_AUTHOR_EMAIL_REQUEST, 0, 0, -1, NULL((void *)0), 0) == -1) | |||
1851 | return got_error_from_errno("imsg_compose " | |||
1852 | "GITCONFIG_AUTHOR_EMAIL_REQUEST"); | |||
1853 | ||||
1854 | return flush_imsg(ibuf); | |||
1855 | } | |||
1856 | ||||
1857 | const struct got_error * | |||
1858 | got_privsep_send_gitconfig_remotes_req(struct imsgbuf *ibuf) | |||
1859 | { | |||
1860 | if (imsg_compose(ibuf, | |||
1861 | GOT_IMSG_GITCONFIG_REMOTES_REQUEST, 0, 0, -1, NULL((void *)0), 0) == -1) | |||
1862 | return got_error_from_errno("imsg_compose " | |||
1863 | "GITCONFIG_REMOTE_REQUEST"); | |||
1864 | ||||
1865 | return flush_imsg(ibuf); | |||
1866 | } | |||
1867 | ||||
1868 | const struct got_error * | |||
1869 | got_privsep_send_gitconfig_owner_req(struct imsgbuf *ibuf) | |||
1870 | { | |||
1871 | if (imsg_compose(ibuf, | |||
1872 | GOT_IMSG_GITCONFIG_OWNER_REQUEST, 0, 0, -1, NULL((void *)0), 0) == -1) | |||
1873 | return got_error_from_errno("imsg_compose " | |||
1874 | "GITCONFIG_OWNER_REQUEST"); | |||
1875 | ||||
1876 | return flush_imsg(ibuf); | |||
1877 | } | |||
1878 | ||||
1879 | const struct got_error * | |||
1880 | got_privsep_recv_gitconfig_str(char **str, struct imsgbuf *ibuf) | |||
1881 | { | |||
1882 | const struct got_error *err = NULL((void *)0); | |||
1883 | struct imsg imsg; | |||
1884 | size_t datalen; | |||
1885 | const size_t min_datalen = 0; | |||
1886 | ||||
1887 | *str = NULL((void *)0); | |||
1888 | ||||
1889 | err = got_privsep_recv_imsg(&imsg, ibuf, min_datalen); | |||
1890 | if (err) | |||
1891 | return err; | |||
1892 | datalen = imsg.hdr.len - IMSG_HEADER_SIZEsizeof(struct imsg_hdr); | |||
1893 | ||||
1894 | switch (imsg.hdr.type) { | |||
1895 | case GOT_IMSG_GITCONFIG_STR_VAL: | |||
1896 | if (datalen == 0) | |||
1897 | break; | |||
1898 | /* datalen does not include terminating \0 */ | |||
1899 | *str = malloc(datalen + 1); | |||
1900 | if (*str == NULL((void *)0)) { | |||
1901 | err = got_error_from_errno("malloc"); | |||
1902 | break; | |||
1903 | } | |||
1904 | memcpy(*str, imsg.data, datalen); | |||
1905 | (*str)[datalen] = '\0'; | |||
1906 | break; | |||
1907 | default: | |||
1908 | err = got_error(GOT_ERR_PRIVSEP_MSG39); | |||
1909 | break; | |||
1910 | } | |||
1911 | ||||
1912 | imsg_free(&imsg); | |||
1913 | return err; | |||
1914 | } | |||
1915 | ||||
1916 | const struct got_error * | |||
1917 | got_privsep_recv_gitconfig_int(int *val, struct imsgbuf *ibuf) | |||
1918 | { | |||
1919 | const struct got_error *err = NULL((void *)0); | |||
1920 | struct imsg imsg; | |||
1921 | size_t datalen; | |||
1922 | const size_t min_datalen = | |||
1923 | MIN(sizeof(struct got_imsg_error), sizeof(int))((sizeof(struct got_imsg_error)) < (sizeof(int)) ? (sizeof (struct got_imsg_error)) : (sizeof(int))); | |||
1924 | ||||
1925 | *val = 0; | |||
1926 | ||||
1927 | err = got_privsep_recv_imsg(&imsg, ibuf, min_datalen); | |||
1928 | if (err) | |||
1929 | return err; | |||
1930 | datalen = imsg.hdr.len - IMSG_HEADER_SIZEsizeof(struct imsg_hdr); | |||
1931 | ||||
1932 | switch (imsg.hdr.type) { | |||
1933 | case GOT_IMSG_GITCONFIG_INT_VAL: | |||
1934 | if (datalen != sizeof(*val)) { | |||
1935 | err = got_error(GOT_ERR_PRIVSEP_LEN36); | |||
1936 | break; | |||
1937 | } | |||
1938 | memcpy(val, imsg.data, sizeof(*val)); | |||
1939 | break; | |||
1940 | default: | |||
1941 | err = got_error(GOT_ERR_PRIVSEP_MSG39); | |||
1942 | break; | |||
1943 | } | |||
1944 | ||||
1945 | imsg_free(&imsg); | |||
1946 | return err; | |||
1947 | } | |||
1948 | ||||
1949 | static void | |||
1950 | free_remote_data(struct got_remote_repo *remote) | |||
1951 | { | |||
1952 | int i; | |||
1953 | ||||
1954 | free(remote->name); | |||
1955 | free(remote->url); | |||
1956 | for (i = 0; i < remote->nbranches; i++) | |||
1957 | free(remote->branches[i]); | |||
1958 | free(remote->branches); | |||
1959 | for (i = 0; i < remote->nrefs; i++) | |||
1960 | free(remote->refs[i]); | |||
| ||||
1961 | free(remote->refs); | |||
1962 | } | |||
1963 | ||||
1964 | const struct got_error * | |||
1965 | got_privsep_recv_gitconfig_remotes(struct got_remote_repo **remotes, | |||
1966 | int *nremotes, struct imsgbuf *ibuf) | |||
1967 | { | |||
1968 | const struct got_error *err = NULL((void *)0); | |||
1969 | struct imsg imsg; | |||
1970 | size_t datalen; | |||
1971 | struct got_imsg_remotes iremotes; | |||
1972 | struct got_imsg_remote iremote; | |||
1973 | ||||
1974 | *remotes = NULL((void *)0); | |||
1975 | *nremotes = 0; | |||
1976 | iremotes.nremotes = 0; | |||
1977 | ||||
1978 | err = got_privsep_recv_imsg(&imsg, ibuf, sizeof(iremotes)); | |||
1979 | if (err) | |||
1980 | return err; | |||
1981 | datalen = imsg.hdr.len - IMSG_HEADER_SIZEsizeof(struct imsg_hdr); | |||
1982 | ||||
1983 | switch (imsg.hdr.type) { | |||
1984 | case GOT_IMSG_GITCONFIG_REMOTES: | |||
1985 | if (datalen != sizeof(iremotes)) { | |||
1986 | err = got_error(GOT_ERR_PRIVSEP_LEN36); | |||
1987 | break; | |||
1988 | } | |||
1989 | memcpy(&iremotes, imsg.data, sizeof(iremotes)); | |||
1990 | if (iremotes.nremotes == 0) { | |||
1991 | imsg_free(&imsg); | |||
1992 | return NULL((void *)0); | |||
1993 | } | |||
1994 | break; | |||
1995 | default: | |||
1996 | imsg_free(&imsg); | |||
1997 | return got_error(GOT_ERR_PRIVSEP_MSG39); | |||
1998 | } | |||
1999 | ||||
2000 | imsg_free(&imsg); | |||
2001 | ||||
2002 | *remotes = recallocarray(NULL((void *)0), 0, iremotes.nremotes, sizeof(**remotes)); | |||
2003 | if (*remotes == NULL((void *)0)) | |||
2004 | return got_error_from_errno("recallocarray"); | |||
2005 | ||||
2006 | while (*nremotes < iremotes.nremotes) { | |||
2007 | struct got_remote_repo *remote; | |||
2008 | ||||
2009 | err = got_privsep_recv_imsg(&imsg, ibuf, sizeof(iremote)); | |||
2010 | if (err) | |||
2011 | break; | |||
2012 | datalen = imsg.hdr.len - IMSG_HEADER_SIZEsizeof(struct imsg_hdr); | |||
2013 | ||||
2014 | switch (imsg.hdr.type) { | |||
2015 | case GOT_IMSG_GITCONFIG_REMOTE: | |||
2016 | remote = &(*remotes)[*nremotes]; | |||
2017 | memset(remote, 0, sizeof(*remote)); | |||
2018 | if (datalen < sizeof(iremote)) { | |||
2019 | err = got_error(GOT_ERR_PRIVSEP_LEN36); | |||
2020 | break; | |||
2021 | } | |||
2022 | memcpy(&iremote, imsg.data, sizeof(iremote)); | |||
2023 | if (iremote.name_len == 0 || iremote.url_len == 0 || | |||
2024 | (sizeof(iremote) + iremote.name_len + | |||
2025 | iremote.url_len) > datalen) { | |||
2026 | err = got_error(GOT_ERR_PRIVSEP_LEN36); | |||
2027 | break; | |||
2028 | } | |||
2029 | remote->name = strndup(imsg.data + sizeof(iremote), | |||
2030 | iremote.name_len); | |||
2031 | if (remote->name == NULL((void *)0)) { | |||
2032 | err = got_error_from_errno("strndup"); | |||
2033 | break; | |||
2034 | } | |||
2035 | remote->url = strndup(imsg.data + sizeof(iremote) + | |||
2036 | iremote.name_len, iremote.url_len); | |||
2037 | if (remote->url == NULL((void *)0)) { | |||
2038 | err = got_error_from_errno("strndup"); | |||
2039 | free_remote_data(remote); | |||
2040 | break; | |||
2041 | } | |||
2042 | remote->mirror_references = iremote.mirror_references; | |||
2043 | remote->fetch_all_branches = iremote.fetch_all_branches; | |||
2044 | remote->nbranches = 0; | |||
2045 | remote->branches = NULL((void *)0); | |||
2046 | remote->nrefs = 0; | |||
2047 | remote->refs = NULL((void *)0); | |||
2048 | (*nremotes)++; | |||
2049 | break; | |||
2050 | default: | |||
2051 | err = got_error(GOT_ERR_PRIVSEP_MSG39); | |||
2052 | break; | |||
2053 | } | |||
2054 | ||||
2055 | imsg_free(&imsg); | |||
2056 | if (err) | |||
2057 | break; | |||
2058 | } | |||
2059 | ||||
2060 | if (err) { | |||
2061 | int i; | |||
2062 | for (i = 0; i < *nremotes; i++) | |||
2063 | free_remote_data(&(*remotes)[i]); | |||
2064 | free(*remotes); | |||
2065 | *remotes = NULL((void *)0); | |||
2066 | *nremotes = 0; | |||
2067 | } | |||
2068 | return err; | |||
2069 | } | |||
2070 | ||||
2071 | const struct got_error * | |||
2072 | got_privsep_send_gotconfig_parse_req(struct imsgbuf *ibuf, int fd) | |||
2073 | { | |||
2074 | const struct got_error *err = NULL((void *)0); | |||
2075 | ||||
2076 | if (imsg_compose(ibuf, GOT_IMSG_GOTCONFIG_PARSE_REQUEST, 0, 0, fd, | |||
2077 | NULL((void *)0), 0) == -1) { | |||
2078 | err = got_error_from_errno("imsg_compose " | |||
2079 | "GOTCONFIG_PARSE_REQUEST"); | |||
2080 | close(fd); | |||
2081 | return err; | |||
2082 | } | |||
2083 | ||||
2084 | return flush_imsg(ibuf); | |||
2085 | } | |||
2086 | ||||
2087 | const struct got_error * | |||
2088 | got_privsep_send_gotconfig_author_req(struct imsgbuf *ibuf) | |||
2089 | { | |||
2090 | if (imsg_compose(ibuf, | |||
2091 | GOT_IMSG_GOTCONFIG_AUTHOR_REQUEST, 0, 0, -1, NULL((void *)0), 0) == -1) | |||
2092 | return got_error_from_errno("imsg_compose " | |||
2093 | "GOTCONFIG_AUTHOR_REQUEST"); | |||
2094 | ||||
2095 | return flush_imsg(ibuf); | |||
2096 | } | |||
2097 | ||||
2098 | const struct got_error * | |||
2099 | got_privsep_send_gotconfig_remotes_req(struct imsgbuf *ibuf) | |||
2100 | { | |||
2101 | if (imsg_compose(ibuf, | |||
2102 | GOT_IMSG_GOTCONFIG_REMOTES_REQUEST, 0, 0, -1, NULL((void *)0), 0) == -1) | |||
2103 | return got_error_from_errno("imsg_compose " | |||
2104 | "GOTCONFIG_REMOTE_REQUEST"); | |||
2105 | ||||
2106 | return flush_imsg(ibuf); | |||
2107 | } | |||
2108 | ||||
2109 | const struct got_error * | |||
2110 | got_privsep_recv_gotconfig_str(char **str, struct imsgbuf *ibuf) | |||
2111 | { | |||
2112 | const struct got_error *err = NULL((void *)0); | |||
2113 | struct imsg imsg; | |||
2114 | size_t datalen; | |||
2115 | const size_t min_datalen = 0; | |||
2116 | ||||
2117 | *str = NULL((void *)0); | |||
2118 | ||||
2119 | err = got_privsep_recv_imsg(&imsg, ibuf, min_datalen); | |||
2120 | if (err) | |||
2121 | return err; | |||
2122 | datalen = imsg.hdr.len - IMSG_HEADER_SIZEsizeof(struct imsg_hdr); | |||
2123 | ||||
2124 | switch (imsg.hdr.type) { | |||
2125 | case GOT_IMSG_ERROR: | |||
2126 | if (datalen < sizeof(struct got_imsg_error)) { | |||
2127 | err = got_error(GOT_ERR_PRIVSEP_LEN36); | |||
2128 | break; | |||
2129 | } | |||
2130 | err = recv_imsg_error(&imsg, datalen); | |||
2131 | break; | |||
2132 | case GOT_IMSG_GOTCONFIG_STR_VAL: | |||
2133 | if (datalen == 0) | |||
2134 | break; | |||
2135 | /* datalen does not include terminating \0 */ | |||
2136 | *str = malloc(datalen + 1); | |||
2137 | if (*str == NULL((void *)0)) { | |||
2138 | err = got_error_from_errno("malloc"); | |||
2139 | break; | |||
2140 | } | |||
2141 | memcpy(*str, imsg.data, datalen); | |||
2142 | (*str)[datalen] = '\0'; | |||
2143 | break; | |||
2144 | default: | |||
2145 | err = got_error(GOT_ERR_PRIVSEP_MSG39); | |||
2146 | break; | |||
2147 | } | |||
2148 | ||||
2149 | imsg_free(&imsg); | |||
2150 | return err; | |||
2151 | } | |||
2152 | ||||
2153 | ||||
2154 | const struct got_error * | |||
2155 | got_privsep_recv_gotconfig_remotes(struct got_remote_repo **remotes, | |||
2156 | int *nremotes, struct imsgbuf *ibuf) | |||
2157 | { | |||
2158 | const struct got_error *err = NULL((void *)0); | |||
2159 | struct imsg imsg; | |||
2160 | size_t datalen; | |||
2161 | struct got_imsg_remotes iremotes; | |||
2162 | struct got_imsg_remote iremote; | |||
2163 | const size_t min_datalen = | |||
2164 | MIN(sizeof(struct got_imsg_error), sizeof(iremotes))((sizeof(struct got_imsg_error)) < (sizeof(iremotes)) ? (sizeof (struct got_imsg_error)) : (sizeof(iremotes))); | |||
| ||||
2165 | ||||
2166 | *remotes = NULL((void *)0); | |||
2167 | *nremotes = 0; | |||
2168 | iremotes.nremotes = 0; | |||
2169 | ||||
2170 | err = got_privsep_recv_imsg(&imsg, ibuf, min_datalen); | |||
2171 | if (err) | |||
2172 | return err; | |||
2173 | datalen = imsg.hdr.len - IMSG_HEADER_SIZEsizeof(struct imsg_hdr); | |||
2174 | ||||
2175 | switch (imsg.hdr.type) { | |||
2176 | case GOT_IMSG_ERROR: | |||
2177 | if (datalen < sizeof(struct got_imsg_error)) { | |||
2178 | err = got_error(GOT_ERR_PRIVSEP_LEN36); | |||
2179 | break; | |||
2180 | } | |||
2181 | err = recv_imsg_error(&imsg, datalen); | |||
2182 | break; | |||
2183 | case GOT_IMSG_GOTCONFIG_REMOTES: | |||
2184 | if (datalen != sizeof(iremotes)) { | |||
2185 | err = got_error(GOT_ERR_PRIVSEP_LEN36); | |||
2186 | break; | |||
2187 | } | |||
2188 | memcpy(&iremotes, imsg.data, sizeof(iremotes)); | |||
2189 | if (iremotes.nremotes == 0) { | |||
2190 | imsg_free(&imsg); | |||
2191 | return NULL((void *)0); | |||
2192 | } | |||
2193 | break; | |||
2194 | default: | |||
2195 | imsg_free(&imsg); | |||
2196 | return got_error(GOT_ERR_PRIVSEP_MSG39); | |||
2197 | } | |||
2198 | ||||
2199 | imsg_free(&imsg); | |||
2200 | ||||
2201 | *remotes = recallocarray(NULL((void *)0), 0, iremotes.nremotes, sizeof(**remotes)); | |||
2202 | if (*remotes == NULL((void *)0)) | |||
2203 | return got_error_from_errno("recallocarray"); | |||
2204 | ||||
2205 | while (*nremotes < iremotes.nremotes) { | |||
2206 | struct got_remote_repo *remote; | |||
2207 | const size_t min_datalen = | |||
2208 | MIN(sizeof(struct got_imsg_error), sizeof(iremote))((sizeof(struct got_imsg_error)) < (sizeof(iremote)) ? (sizeof (struct got_imsg_error)) : (sizeof(iremote))); | |||
2209 | int i; | |||
2210 | ||||
2211 | err = got_privsep_recv_imsg(&imsg, ibuf, min_datalen); | |||
2212 | if (err) | |||
2213 | break; | |||
2214 | datalen = imsg.hdr.len - IMSG_HEADER_SIZEsizeof(struct imsg_hdr); | |||
2215 | ||||
2216 | switch (imsg.hdr.type) { | |||
2217 | case GOT_IMSG_ERROR: | |||
2218 | if (datalen < sizeof(struct got_imsg_error)) { | |||
2219 | err = got_error(GOT_ERR_PRIVSEP_LEN36); | |||
2220 | break; | |||
2221 | } | |||
2222 | err = recv_imsg_error(&imsg, datalen); | |||
2223 | break; | |||
2224 | case GOT_IMSG_GOTCONFIG_REMOTE: | |||
2225 | remote = &(*remotes)[*nremotes]; | |||
2226 | memset(remote, 0, sizeof(*remote)); | |||
2227 | if (datalen < sizeof(iremote)) { | |||
2228 | err = got_error(GOT_ERR_PRIVSEP_LEN36); | |||
2229 | break; | |||
2230 | } | |||
2231 | memcpy(&iremote, imsg.data, sizeof(iremote)); | |||
2232 | if (iremote.name_len == 0 || iremote.url_len == 0 || | |||
2233 | (sizeof(iremote) + iremote.name_len + | |||
2234 | iremote.url_len) > datalen) { | |||
2235 | err = got_error(GOT_ERR_PRIVSEP_LEN36); | |||
2236 | break; | |||
2237 | } | |||
2238 | remote->name = strndup(imsg.data + sizeof(iremote), | |||
2239 | iremote.name_len); | |||
2240 | if (remote->name == NULL((void *)0)) { | |||
2241 | err = got_error_from_errno("strndup"); | |||
2242 | break; | |||
2243 | } | |||
2244 | remote->url = strndup(imsg.data + sizeof(iremote) + | |||
2245 | iremote.name_len, iremote.url_len); | |||
2246 | if (remote->url == NULL((void *)0)) { | |||
2247 | err = got_error_from_errno("strndup"); | |||
2248 | free_remote_data(remote); | |||
2249 | break; | |||
2250 | } | |||
2251 | remote->mirror_references = iremote.mirror_references; | |||
2252 | remote->fetch_all_branches = iremote.fetch_all_branches; | |||
2253 | if (iremote.nbranches > 0) { | |||
2254 | remote->branches = recallocarray(NULL((void *)0), 0, | |||
2255 | iremote.nbranches, sizeof(char *)); | |||
2256 | if (remote->branches == NULL((void *)0)) { | |||
2257 | err = got_error_from_errno("calloc"); | |||
2258 | free_remote_data(remote); | |||
2259 | break; | |||
2260 | } | |||
2261 | } | |||
2262 | remote->nbranches = 0; | |||
2263 | for (i = 0; i
| |||
2264 | char *branch; | |||
2265 | err = got_privsep_recv_gotconfig_str(&branch, | |||
2266 | ibuf); | |||
2267 | if (err) { | |||
2268 | free_remote_data(remote); | |||
2269 | goto done; | |||
2270 | } | |||
2271 | remote->branches[i] = branch; | |||
2272 | remote->nbranches++; | |||
2273 | } | |||
2274 | if (iremote.nrefs > 0) { | |||
2275 | remote->refs = recallocarray(NULL((void *)0), 0, | |||
2276 | iremote.nrefs, sizeof(char *)); | |||
2277 | if (remote->refs == NULL((void *)0)) { | |||
2278 | err = got_error_from_errno("calloc"); | |||
2279 | free_remote_data(remote); | |||
2280 | break; | |||
2281 | } | |||
2282 | } | |||
2283 | remote->nrefs = 0; | |||
2284 | for (i = 0; i < iremote.nrefs; i++) { | |||
2285 | char *ref; | |||
2286 | err = got_privsep_recv_gotconfig_str(&ref, | |||
2287 | ibuf); | |||
2288 | if (err) { | |||
2289 | free_remote_data(remote); | |||
2290 | goto done; | |||
2291 | } | |||
2292 | remote->refs[i] = ref; | |||
2293 | remote->nrefs++; | |||
2294 | } | |||
2295 | (*nremotes)++; | |||
2296 | break; | |||
2297 | default: | |||
2298 | err = got_error(GOT_ERR_PRIVSEP_MSG39); | |||
2299 | break; | |||
2300 | } | |||
2301 | ||||
2302 | imsg_free(&imsg); | |||
2303 | if (err) | |||
2304 | break; | |||
2305 | } | |||
2306 | done: | |||
2307 | if (err) { | |||
2308 | int i; | |||
2309 | for (i = 0; i < *nremotes; i++) | |||
2310 | free_remote_data(&(*remotes)[i]); | |||
2311 | free(*remotes); | |||
2312 | *remotes = NULL((void *)0); | |||
2313 | *nremotes = 0; | |||
2314 | } | |||
2315 | return err; | |||
2316 | } | |||
2317 | ||||
2318 | const struct got_error * | |||
2319 | got_privsep_send_commit_traversal_request(struct imsgbuf *ibuf, | |||
2320 | struct got_object_id *id, int idx, const char *path) | |||
2321 | { | |||
2322 | const struct got_error *err = NULL((void *)0); | |||
2323 | struct ibuf *wbuf; | |||
2324 | size_t path_len = strlen(path) + 1; | |||
2325 | ||||
2326 | wbuf = imsg_create(ibuf, GOT_IMSG_COMMIT_TRAVERSAL_REQUEST, 0, 0, | |||
2327 | sizeof(struct got_imsg_commit_traversal_request) + path_len); | |||
2328 | if (wbuf == NULL((void *)0)) | |||
2329 | return got_error_from_errno( | |||
2330 | "imsg_create COMMIT_TRAVERSAL_REQUEST"); | |||
2331 | if (imsg_add(wbuf, id->sha1, SHA1_DIGEST_LENGTH20) == -1) { | |||
2332 | err = got_error_from_errno("imsg_add COMMIT_TRAVERSAL_REQUEST"); | |||
2333 | ibuf_free(wbuf); | |||
2334 | return err; | |||
2335 | } | |||
2336 | if (imsg_add(wbuf, &idx, sizeof(idx)) == -1) { | |||
2337 | err = got_error_from_errno("imsg_add COMMIT_TRAVERSAL_REQUEST"); | |||
2338 | ibuf_free(wbuf); | |||
2339 | return err; | |||
2340 | } | |||
2341 | if (imsg_add(wbuf, path, path_len) == -1) { | |||
2342 | err = got_error_from_errno("imsg_add COMMIT_TRAVERSAL_REQUEST"); | |||
2343 | ibuf_free(wbuf); | |||
2344 | return err; | |||
2345 | } | |||
2346 | ||||
2347 | wbuf->fd = -1; | |||
2348 | imsg_close(ibuf, wbuf); | |||
2349 | ||||
2350 | return flush_imsg(ibuf); | |||
2351 | } | |||
2352 | ||||
2353 | const struct got_error * | |||
2354 | got_privsep_recv_traversed_commits(struct got_commit_object **changed_commit, | |||
2355 | struct got_object_id **changed_commit_id, | |||
2356 | struct got_object_id_queue *commit_ids, struct imsgbuf *ibuf) | |||
2357 | { | |||
2358 | const struct got_error *err = NULL((void *)0); | |||
2359 | struct imsg imsg; | |||
2360 | struct got_imsg_traversed_commits *icommits; | |||
2361 | size_t datalen; | |||
2362 | int i, done = 0; | |||
2363 | ||||
2364 | *changed_commit = NULL((void *)0); | |||
2365 | *changed_commit_id = NULL((void *)0); | |||
2366 | ||||
2367 | while (!done) { | |||
2368 | err = got_privsep_recv_imsg(&imsg, ibuf, 0); | |||
2369 | if (err) | |||
2370 | return err; | |||
2371 | ||||
2372 | datalen = imsg.hdr.len - IMSG_HEADER_SIZEsizeof(struct imsg_hdr); | |||
2373 | switch (imsg.hdr.type) { | |||
2374 | case GOT_IMSG_TRAVERSED_COMMITS: | |||
2375 | icommits = imsg.data; | |||
2376 | if (datalen != sizeof(*icommits) + | |||
2377 | icommits->ncommits * SHA1_DIGEST_LENGTH20) { | |||
2378 | err = got_error(GOT_ERR_PRIVSEP_LEN36); | |||
2379 | break; | |||
2380 | } | |||
2381 | for (i = 0; i < icommits->ncommits; i++) { | |||
2382 | struct got_object_qid *qid; | |||
2383 | uint8_t *sha1 = (uint8_t *)imsg.data + | |||
2384 | sizeof(*icommits) + i * SHA1_DIGEST_LENGTH20; | |||
2385 | err = got_object_qid_alloc_partial(&qid); | |||
2386 | if (err) | |||
2387 | break; | |||
2388 | memcpy(qid->id->sha1, sha1, SHA1_DIGEST_LENGTH20); | |||
2389 | SIMPLEQ_INSERT_TAIL(commit_ids, qid, entry)do { (qid)->entry.sqe_next = ((void *)0); *(commit_ids)-> sqh_last = (qid); (commit_ids)->sqh_last = &(qid)-> entry.sqe_next; } while (0); | |||
2390 | ||||
2391 | /* The last commit may contain a change. */ | |||
2392 | if (i == icommits->ncommits - 1) { | |||
2393 | *changed_commit_id = | |||
2394 | got_object_id_dup(qid->id); | |||
2395 | if (*changed_commit_id == NULL((void *)0)) { | |||
2396 | err = got_error_from_errno( | |||
2397 | "got_object_id_dup"); | |||
2398 | break; | |||
2399 | } | |||
2400 | } | |||
2401 | } | |||
2402 | break; | |||
2403 | case GOT_IMSG_COMMIT: | |||
2404 | if (*changed_commit_id == NULL((void *)0)) { | |||
2405 | err = got_error(GOT_ERR_PRIVSEP_MSG39); | |||
2406 | break; | |||
2407 | } | |||
2408 | err = get_commit_from_imsg(changed_commit, &imsg, | |||
2409 | datalen, ibuf); | |||
2410 | break; | |||
2411 | case GOT_IMSG_COMMIT_TRAVERSAL_DONE: | |||
2412 | done = 1; | |||
2413 | break; | |||
2414 | default: | |||
2415 | err = got_error(GOT_ERR_PRIVSEP_MSG39); | |||
2416 | break; | |||
2417 | } | |||
2418 | ||||
2419 | imsg_free(&imsg); | |||
2420 | if (err) | |||
2421 | break; | |||
2422 | } | |||
2423 | ||||
2424 | if (err) | |||
2425 | got_object_id_queue_free(commit_ids); | |||
2426 | return err; | |||
2427 | } | |||
2428 | ||||
2429 | const struct got_error * | |||
2430 | got_privsep_unveil_exec_helpers(void) | |||
2431 | { | |||
2432 | const char *helpers[] = { | |||
2433 | GOT_PATH_PROG_READ_PACK"/home/ben/bin" "/" "got-read-pack", | |||
2434 | GOT_PATH_PROG_READ_OBJECT"/home/ben/bin" "/" "got-read-object", | |||
2435 | GOT_PATH_PROG_READ_COMMIT"/home/ben/bin" "/" "got-read-commit", | |||
2436 | GOT_PATH_PROG_READ_TREE"/home/ben/bin" "/" "got-read-tree", | |||
2437 | GOT_PATH_PROG_READ_BLOB"/home/ben/bin" "/" "got-read-blob", | |||
2438 | GOT_PATH_PROG_READ_TAG"/home/ben/bin" "/" "got-read-tag", | |||
2439 | GOT_PATH_PROG_READ_GITCONFIG"/home/ben/bin" "/" "got-read-gitconfig", | |||
2440 | GOT_PATH_PROG_READ_GOTCONFIG"/home/ben/bin" "/" "got-read-gotconfig", | |||
2441 | GOT_PATH_PROG_FETCH_PACK"/home/ben/bin" "/" "got-fetch-pack", | |||
2442 | GOT_PATH_PROG_INDEX_PACK"/home/ben/bin" "/" "got-index-pack", | |||
2443 | }; | |||
2444 | size_t i; | |||
2445 | ||||
2446 | for (i = 0; i < nitems(helpers)(sizeof((helpers)) / sizeof((helpers)[0])); i++) { | |||
2447 | if (unveil(helpers[i], "x") == 0) | |||
2448 | continue; | |||
2449 | return got_error_from_errno2("unveil", helpers[i]); | |||
2450 | } | |||
2451 | ||||
2452 | return NULL((void *)0); | |||
2453 | } | |||
2454 | ||||
2455 | void | |||
2456 | got_privsep_exec_child(int imsg_fds[2], const char *path, const char *repo_path) | |||
2457 | { | |||
2458 | if (close(imsg_fds[0]) == -1) { | |||
2459 | fprintf(stderr(&__sF[2]), "%s: %s\n", getprogname(), strerror(errno(*__errno()))); | |||
2460 | _exit(1); | |||
2461 | } | |||
2462 | ||||
2463 | if (dup2(imsg_fds[1], GOT_IMSG_FD_CHILD(2 + 1)) == -1) { | |||
2464 | fprintf(stderr(&__sF[2]), "%s: %s\n", getprogname(), strerror(errno(*__errno()))); | |||
2465 | _exit(1); | |||
2466 | } | |||
2467 | if (closefrom(GOT_IMSG_FD_CHILD(2 + 1) + 1) == -1) { | |||
2468 | fprintf(stderr(&__sF[2]), "%s: %s\n", getprogname(), strerror(errno(*__errno()))); | |||
2469 | _exit(1); | |||
2470 | } | |||
2471 | ||||
2472 | if (execl(path, path, repo_path, (char *)NULL((void *)0)) == -1) { | |||
2473 | fprintf(stderr(&__sF[2]), "%s: %s: %s\n", getprogname(), path, | |||
2474 | strerror(errno(*__errno()))); | |||
2475 | _exit(1); | |||
2476 | } | |||
2477 | } |