2 * Copyright (c) 2018, 2019 Stefan Sperling <stsp@openbsd.org>
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 #include <sys/types.h>
18 #include <sys/queue.h>
21 #include <sys/syslimits.h>
34 #include "got_error.h"
35 #include "got_object.h"
38 #include "got_lib_delta.h"
39 #include "got_lib_delta_cache.h"
40 #include "got_lib_object.h"
41 #include "got_lib_object_cache.h"
42 #include "got_lib_object_parse.h"
43 #include "got_lib_privsep.h"
44 #include "got_lib_pack.h"
46 static volatile sig_atomic_t sigint_received;
49 catch_sigint(int signo)
54 static const struct got_error *
55 open_object(struct got_object **obj, struct got_pack *pack,
56 struct got_packidx *packidx, int idx, struct got_object_id *id,
57 struct got_object_cache *objcache)
59 const struct got_error *err;
61 err = got_packfile_open_object(obj, pack, packidx, idx, id);
66 err = got_object_cache_add(objcache, id, *obj);
68 if (err->code == GOT_ERR_OBJ_EXISTS ||
69 err->code == GOT_ERR_OBJ_TOO_LARGE)
77 static const struct got_error *
78 object_request(struct imsg *imsg, struct imsgbuf *ibuf, struct got_pack *pack,
79 struct got_packidx *packidx, struct got_object_cache *objcache)
81 const struct got_error *err = NULL;
82 struct got_imsg_packed_object iobj;
83 struct got_object *obj;
84 struct got_object_id id;
87 datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
88 if (datalen != sizeof(iobj))
89 return got_error(GOT_ERR_PRIVSEP_LEN);
90 memcpy(&iobj, imsg->data, sizeof(iobj));
91 memcpy(id.sha1, iobj.id, SHA1_DIGEST_LENGTH);
93 obj = got_object_cache_get(objcache, &id);
97 err = open_object(&obj, pack, packidx, iobj.idx, &id,
103 err = got_privsep_send_obj(ibuf, obj);
105 got_object_close(obj);
109 static const struct got_error *
110 commit_request(struct imsg *imsg, struct imsgbuf *ibuf, struct got_pack *pack,
111 struct got_packidx *packidx, struct got_object_cache *objcache)
113 const struct got_error *err = NULL;
114 struct got_imsg_packed_object iobj;
115 struct got_object *obj = NULL;
116 struct got_commit_object *commit = NULL;
119 struct got_object_id id;
122 datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
123 if (datalen != sizeof(iobj))
124 return got_error(GOT_ERR_PRIVSEP_LEN);
125 memcpy(&iobj, imsg->data, sizeof(iobj));
126 memcpy(id.sha1, iobj.id, SHA1_DIGEST_LENGTH);
128 obj = got_object_cache_get(objcache, &id);
132 err = open_object(&obj, pack, packidx, iobj.idx, &id,
138 err = got_packfile_extract_object_to_mem(&buf, &len, obj, pack);
143 err = got_object_parse_commit(&commit, buf, len);
147 err = got_privsep_send_commit(ibuf, commit);
150 got_object_close(obj);
152 got_object_commit_close(commit);
154 if (err->code == GOT_ERR_PRIVSEP_PIPE)
157 got_privsep_send_error(ibuf, err);
163 static const struct got_error *
164 tree_request(struct imsg *imsg, struct imsgbuf *ibuf, struct got_pack *pack,
165 struct got_packidx *packidx, struct got_object_cache *objcache)
167 const struct got_error *err = NULL;
168 struct got_imsg_packed_object iobj;
169 struct got_object *obj = NULL;
170 struct got_pathlist_head entries;
174 struct got_object_id id;
177 TAILQ_INIT(&entries);
179 datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
180 if (datalen != sizeof(iobj))
181 return got_error(GOT_ERR_PRIVSEP_LEN);
182 memcpy(&iobj, imsg->data, sizeof(iobj));
183 memcpy(id.sha1, iobj.id, SHA1_DIGEST_LENGTH);
185 obj = got_object_cache_get(objcache, &id);
189 err = open_object(&obj, pack, packidx, iobj.idx, &id,
195 err = got_packfile_extract_object_to_mem(&buf, &len, obj, pack);
200 err = got_object_parse_tree(&entries, &nentries, buf, len);
204 err = got_privsep_send_tree(ibuf, &entries, nentries);
206 got_object_parsed_tree_entries_free(&entries);
208 got_object_close(obj);
210 if (err->code == GOT_ERR_PRIVSEP_PIPE)
213 got_privsep_send_error(ibuf, err);
219 static const struct got_error *
220 receive_file(FILE **f, struct imsgbuf *ibuf, int imsg_code)
222 const struct got_error *err;
226 err = got_privsep_recv_imsg(&imsg, ibuf, 0);
230 if (imsg.hdr.type != imsg_code) {
231 err = got_error(GOT_ERR_PRIVSEP_MSG);
235 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
237 err = got_error(GOT_ERR_PRIVSEP_LEN);
241 err = got_error(GOT_ERR_PRIVSEP_NO_FD);
245 *f = fdopen(imsg.fd, "w+");
247 err = got_error_from_errno("fdopen");
256 static const struct got_error *
257 blob_request(struct imsg *imsg, struct imsgbuf *ibuf, struct got_pack *pack,
258 struct got_packidx *packidx, struct got_object_cache *objcache)
260 const struct got_error *err = NULL;
261 struct got_imsg_packed_object iobj;
262 struct got_object *obj = NULL;
263 FILE *outfile = NULL, *basefile = NULL, *accumfile = NULL;
264 struct got_object_id id;
269 datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
270 if (datalen != sizeof(iobj))
271 return got_error(GOT_ERR_PRIVSEP_LEN);
272 memcpy(&iobj, imsg->data, sizeof(iobj));
273 memcpy(id.sha1, iobj.id, SHA1_DIGEST_LENGTH);
275 obj = got_object_cache_get(objcache, &id);
279 err = open_object(&obj, pack, packidx, iobj.idx, &id,
285 err = receive_file(&outfile, ibuf, GOT_IMSG_BLOB_OUTFD);
288 err = receive_file(&basefile, ibuf, GOT_IMSG_TMPFD);
291 err = receive_file(&accumfile, ibuf, GOT_IMSG_TMPFD);
295 if (obj->flags & GOT_OBJ_FLAG_DELTIFIED) {
296 err = got_pack_get_max_delta_object_size(&blob_size, obj, pack);
300 blob_size = obj->size;
302 if (blob_size <= GOT_PRIVSEP_INLINE_BLOB_DATA_MAX)
303 err = got_packfile_extract_object_to_mem(&buf, &obj->size,
306 err = got_packfile_extract_object(pack, obj, outfile, basefile,
311 err = got_privsep_send_blob(ibuf, obj->size, obj->hdrlen, buf);
314 if (outfile && fclose(outfile) != 0 && err == NULL)
315 err = got_error_from_errno("fclose");
316 if (basefile && fclose(basefile) != 0 && err == NULL)
317 err = got_error_from_errno("fclose");
318 if (accumfile && fclose(accumfile) != 0 && err == NULL)
319 err = got_error_from_errno("fclose");
320 got_object_close(obj);
321 if (err && err->code != GOT_ERR_PRIVSEP_PIPE)
322 got_privsep_send_error(ibuf, err);
327 static const struct got_error *
328 tag_request(struct imsg *imsg, struct imsgbuf *ibuf, struct got_pack *pack,
329 struct got_packidx *packidx, struct got_object_cache *objcache)
331 const struct got_error *err = NULL;
332 struct got_imsg_packed_object iobj;
333 struct got_object *obj = NULL;
334 struct got_tag_object *tag = NULL;
337 struct got_object_id id;
340 datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
341 if (datalen != sizeof(iobj))
342 return got_error(GOT_ERR_PRIVSEP_LEN);
343 memcpy(&iobj, imsg->data, sizeof(iobj));
344 memcpy(id.sha1, iobj.id, SHA1_DIGEST_LENGTH);
346 obj = got_object_cache_get(objcache, &id);
350 err = open_object(&obj, pack, packidx, iobj.idx, &id,
356 err = got_packfile_extract_object_to_mem(&buf, &len, obj, pack);
361 err = got_object_parse_tag(&tag, buf, len);
365 err = got_privsep_send_tag(ibuf, tag);
368 got_object_close(obj);
370 got_object_tag_close(tag);
372 if (err->code == GOT_ERR_PRIVSEP_PIPE)
375 got_privsep_send_error(ibuf, err);
381 static const struct got_error *
382 receive_packidx(struct got_packidx **packidx, struct imsgbuf *ibuf)
384 const struct got_error *err = NULL;
386 struct got_imsg_packidx ipackidx;
388 struct got_packidx *p;
392 err = got_privsep_recv_imsg(&imsg, ibuf, 0);
396 p = calloc(1, sizeof(*p));
398 err = got_error_from_errno("calloc");
402 if (imsg.hdr.type != GOT_IMSG_PACKIDX) {
403 err = got_error(GOT_ERR_PRIVSEP_MSG);
408 err = got_error(GOT_ERR_PRIVSEP_NO_FD);
412 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
413 if (datalen != sizeof(ipackidx)) {
414 err = got_error(GOT_ERR_PRIVSEP_LEN);
417 memcpy(&ipackidx, imsg.data, sizeof(ipackidx));
419 p->len = ipackidx.len;
420 p->fd = dup(imsg.fd);
422 err = got_error_from_errno("dup");
425 if (lseek(p->fd, 0, SEEK_SET) == -1) {
426 err = got_error_from_errno("lseek");
430 #ifndef GOT_PACK_NO_MMAP
431 p->map = mmap(NULL, p->len, PROT_READ, MAP_PRIVATE, p->fd, 0);
432 if (p->map == MAP_FAILED)
433 p->map = NULL; /* fall back to read(2) */
435 err = got_packidx_init_hdr(p, 1);
440 got_packidx_close(p);
447 static const struct got_error *
448 receive_pack(struct got_pack **packp, struct imsgbuf *ibuf)
450 const struct got_error *err = NULL;
452 struct got_imsg_pack ipack;
454 struct got_pack *pack;
458 err = got_privsep_recv_imsg(&imsg, ibuf, 0);
462 pack = calloc(1, sizeof(*pack));
464 err = got_error_from_errno("calloc");
468 if (imsg.hdr.type != GOT_IMSG_PACK) {
469 err = got_error(GOT_ERR_PRIVSEP_MSG);
474 err = got_error(GOT_ERR_PRIVSEP_NO_FD);
478 datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
479 if (datalen != sizeof(ipack)) {
480 err = got_error(GOT_ERR_PRIVSEP_LEN);
483 memcpy(&ipack, imsg.data, sizeof(ipack));
485 pack->filesize = ipack.filesize;
486 pack->fd = dup(imsg.fd);
487 if (pack->fd == -1) {
488 err = got_error_from_errno("dup");
491 if (lseek(pack->fd, 0, SEEK_SET) == -1) {
492 err = got_error_from_errno("lseek");
495 pack->path_packfile = strdup(ipack.path_packfile);
496 if (pack->path_packfile == NULL) {
497 err = got_error_from_errno("strdup");
501 pack->delta_cache = got_delta_cache_alloc(100,
502 GOT_DELTA_RESULT_SIZE_CACHED_MAX);
503 if (pack->delta_cache == NULL) {
504 err = got_error_from_errno("got_delta_cache_alloc");
508 #ifndef GOT_PACK_NO_MMAP
509 pack->map = mmap(NULL, pack->filesize, PROT_READ, MAP_PRIVATE,
511 if (pack->map == MAP_FAILED)
512 pack->map = NULL; /* fall back to read(2) */
526 main(int argc, char *argv[])
528 const struct got_error *err = NULL;
531 struct got_packidx *packidx = NULL;
532 struct got_pack *pack = NULL;
533 struct got_object_cache objcache;
535 //static int attached;
536 //while (!attached) sleep(1);
538 signal(SIGINT, catch_sigint);
540 imsg_init(&ibuf, GOT_IMSG_FD_CHILD);
542 err = got_object_cache_init(&objcache, GOT_OBJECT_CACHE_TYPE_OBJ);
544 err = got_error_from_errno("got_object_cache_init");
545 got_privsep_send_error(&ibuf, err);
550 /* revoke access to most system calls */
551 if (pledge("stdio recvfd", NULL) == -1) {
552 err = got_error_from_errno("pledge");
553 got_privsep_send_error(&ibuf, err);
558 err = receive_packidx(&packidx, &ibuf);
560 got_privsep_send_error(&ibuf, err);
564 err = receive_pack(&pack, &ibuf);
566 got_privsep_send_error(&ibuf, err);
573 if (sigint_received) {
574 err = got_error(GOT_ERR_CANCELLED);
578 err = got_privsep_recv_imsg(&imsg, &ibuf, 0);
580 if (err->code == GOT_ERR_PRIVSEP_PIPE)
585 if (imsg.hdr.type == GOT_IMSG_STOP)
588 switch (imsg.hdr.type) {
589 case GOT_IMSG_PACKED_OBJECT_REQUEST:
590 err = object_request(&imsg, &ibuf, pack, packidx,
593 case GOT_IMSG_COMMIT_REQUEST:
594 err = commit_request(&imsg, &ibuf, pack, packidx,
597 case GOT_IMSG_TREE_REQUEST:
598 err = tree_request(&imsg, &ibuf, pack, packidx,
601 case GOT_IMSG_BLOB_REQUEST:
602 err = blob_request(&imsg, &ibuf, pack, packidx,
605 case GOT_IMSG_TAG_REQUEST:
606 err = tag_request(&imsg, &ibuf, pack, packidx,
610 err = got_error(GOT_ERR_PRIVSEP_MSG);
614 if (imsg.fd != -1 && close(imsg.fd) != 0 && err == NULL)
615 err = got_error_from_errno("close");
622 got_packidx_close(packidx);
624 got_pack_close(pack);
625 got_object_cache_close(&objcache);
628 if (!sigint_received && err->code != GOT_ERR_PRIVSEP_PIPE) {
629 fprintf(stderr, "%s: %s\n", getprogname(), err->msg);
630 got_privsep_send_error(&ibuf, err);
633 if (close(GOT_IMSG_FD_CHILD) != 0 && err == NULL)
634 err = got_error_from_errno("close");