commit - 55afbf19d730ecbbee0228be686ff3f5e57a13e8
commit + ad242220adab01ebd55a97a5701733d7256b2d32
blob - bbe1fafa84266d496fa4f4aacc7acb3f45f14ae7
blob + 2f31fc45cd1c490ae0c867d0db07e38ad57d3d1a
--- got/Makefile
+++ got/Makefile
object_idset.c object_parse.c opentemp.c path.c pack.c \
privsep.c reference.c repository.c sha1.c worktree.c inflate.c
-CPPFLAGS = -I${.CURDIR}/../include -I${.CURDIR}/../lib
+GOT_LIBEXECDIR = ${HOME}/bin
+CPPFLAGS = -I${.CURDIR}/../include -I${.CURDIR}/../lib \
+ -DGOT_LIBEXECDIR=${GOT_LIBEXECDIR}
LDADD = -lutil -lz
DPADD = ${LIBZ} ${LIBUTIL}
.if defined(PROFILE)
blob - b44481ec74030fde08672be477030467b239550e
blob + be58cf339b920db7909cf38049c0b61c5d291788
--- got/got.c
+++ got/got.c
argv += optind;
#ifndef PROFILE
- if (pledge("stdio rpath wpath cpath flock proc", NULL) == -1)
+ if (pledge("stdio rpath wpath cpath flock proc exec sendfd", NULL)
+ == -1)
err(1, "pledge");
#endif
if (argc == 1) {
const char *errstr;
#ifndef PROFILE
- if (pledge("stdio rpath wpath cpath flock proc", NULL) == -1)
+ if (pledge("stdio rpath wpath cpath flock proc exec sendfd", NULL)
+ == -1)
err(1, "pledge");
#endif
if (obj)
got_object_close(obj);
free(id);
- if (repo)
- got_repo_close(repo);
+ if (repo) {
+ const struct got_error *repo_error;
+ repo_error = got_repo_close(repo);
+ if (error == NULL)
+ error = repo_error;
+ }
return error;
}
int ch;
#ifndef PROFILE
- if (pledge("stdio rpath wpath cpath flock proc", NULL) == -1)
+ if (pledge("stdio rpath wpath cpath flock proc exec sendfd", NULL)
+ == -1)
err(1, "pledge");
#endif
free(id1);
if (id2)
free(id2);
- if (repo)
- got_repo_close(repo);
+ if (repo) {
+ const struct got_error *repo_error;
+ repo_error = got_repo_close(repo);
+ if (error == NULL)
+ error = repo_error;
+ }
return error;
}
int ch;
#ifndef PROFILE
- if (pledge("stdio rpath wpath cpath flock proc", NULL) == -1)
+ if (pledge("stdio rpath wpath cpath flock proc exec sendfd", NULL)
+ == -1)
err(1, "pledge");
#endif
free(repo_path);
free(cwd);
free(commit_id);
- if (repo)
- got_repo_close(repo);
+ if (repo) {
+ const struct got_error *repo_error;
+ repo_error = got_repo_close(repo);
+ if (error == NULL)
+ error = repo_error;
+ }
return error;
}
blob - 3f8ef8cb512966482a3b4410b0c4b51505fa5063
blob + 2fd4ddd312ea5fb19ea1ae92f79f49a045bb517b
--- include/got_repository.h
+++ include/got_repository.h
/* Open and close repositories. */
const struct got_error *got_repo_open(struct got_repository**, const char *);
-void got_repo_close(struct got_repository*);
+const struct got_error *got_repo_close(struct got_repository*);
/*
* Obtain paths to various directories within a repository.
blob - /dev/null
blob + b1d1830b01b36ea576c29ee80aba577fc0adf4ae (mode 644)
--- /dev/null
+++ lib/got_lib_object_parse.h
+/*
+ * Copyright (c) 2018 Stefan Sperling <stsp@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+struct got_commit_object *got_object_commit_alloc_partial(void);
+struct got_tree_entry *got_alloc_tree_entry_partial(void);
+const struct got_error *got_object_read_header_privsep(struct got_object**,
+ struct got_repository *repo, int);
+const struct got_error *got_object_read_blob_privsep(size_t *, int, int,
+ struct got_repository *repo);
+const struct got_error *got_object_read_commit_privsep(
+ struct got_commit_object **, struct got_object *, int,
+ struct got_repository *);
+const struct got_error *got_object_read_tree_privsep(struct got_tree_object **,
+ struct got_object *, int, struct got_repository *);
+
+const struct got_error *got_object_parse_commit(struct got_commit_object **,
+ char *, size_t);
+const struct got_error *got_object_parse_tree(struct got_tree_object **,
+ uint8_t *, size_t);
+const struct got_error *got_read_file_to_mem(uint8_t **, size_t *, FILE *);
+
+void got_object_tree_entry_close(struct got_tree_entry *);
blob - 67a687b619f5daf43ec02cb885bec570058db386
blob + 7a7a85a25f9d4f084f4143150b87d65af7e4485f
--- lib/got_lib_privsep.h
+++ lib/got_lib_privsep.h
* if necessary. File descriptors are used in cases where this is impractical,
* such as when accessing pack files or when transferring large blobs.
*
- * We currently do not exec(2) after a fork(2).
- * To achieve fork+exec, relevant parts of our library functionality could
- * be made accessible via separate executables in a libexec directory.
+ * We exec(2) after a fork(2). Parts of our library functionality are
+ * accessible via separate executables in a libexec directory.
*/
+#define GOT_IMSG_FD_CHILD (STDERR_FILENO + 1)
+
+#ifndef GOT_LIBEXECDIR
+#define GOT_LIBEXECDIR /usr/libexec
+#endif
+
+/* Names of helper programs in libexec directory */
+#define GOT_PROG_READ_OBJECT got-read-object
+#define GOT_PROG_READ_TREE got-read-tree
+#define GOT_PROG_READ_COMMIT got-read-commit
+#define GOT_PROG_READ_BLOB got-read-blob
+
+#define GOT_STRINGIFY(x) #x
+#define GOT_STRINGVAL(x) GOT_STRINGIFY(x)
+
+/* Paths to helper programs in libexec directory */
+#define GOT_PATH_PROG_READ_OBJECT \
+ GOT_STRINGVAL(GOT_LIBEXECDIR) "/" GOT_STRINGVAL(GOT_PROG_READ_OBJECT)
+#define GOT_PATH_PROG_READ_TREE \
+ GOT_STRINGVAL(GOT_LIBEXECDIR) "/" GOT_STRINGVAL(GOT_PROG_READ_TREE)
+#define GOT_PATH_PROG_READ_COMMIT \
+ GOT_STRINGVAL(GOT_LIBEXECDIR) "/" GOT_STRINGVAL(GOT_PROG_READ_COMMIT)
+#define GOT_PATH_PROG_READ_BLOB \
+ GOT_STRINGVAL(GOT_LIBEXECDIR) "/" GOT_STRINGVAL(GOT_PROG_READ_BLOB)
+
enum got_imsg_type {
/* An error occured while processing a request. */
GOT_IMSG_ERROR,
- /* Messages for transmitting deltas and associated delta streams. */
- GOT_IMSG_DELTA,
- GOT_IMSG_DELTA_STREAM,
+ /* Stop the child process. */
+ GOT_IMSG_STOP,
/*
* Messages concerned with read access to objects in a repository.
* separate process which runs under pledge("stdio").
* This sandboxes our own repository parsing code, as well as zlib.
*/
+ GOT_IMSG_OBJECT_REQUEST,
GOT_IMSG_OBJECT,
+ GOT_IMSG_COMMIT_REQUEST,
GOT_IMSG_COMMIT,
+ GOT_IMSG_TREE_REQUEST,
GOT_IMSG_TREE,
GOT_IMSG_TREE_ENTRY,
+ GOT_IMSG_BLOB_REQUEST,
+ GOT_IMSG_BLOB_OUTFD,
GOT_IMSG_BLOB,
+ /* Messages for transmitting deltas and associated delta streams: */
+ GOT_IMSG_DELTA,
+ GOT_IMSG_DELTA_STREAM,
};
/* Structure for GOT_IMSG_ERROR. */
*/
};
-/* Structure for GOT_IMSG_OBJECT data. */
+/*
+ * Structure for GOT_IMSG_TREE_REQUEST, GOT_IMSG_COMMIT_REQUEST,
+ * and GOT_IMSG_OBJECT data.
+ */
struct got_imsg_object {
/* These fields are the same as in struct got_object. */
int type;
size_t size;
};
+const struct got_error *got_privsep_send_stop(int);
+const struct got_error *got_privsep_recv_imsg(struct imsg *, struct imsgbuf *,
+ size_t);
void got_privsep_send_error(struct imsgbuf *, const struct got_error *);
+const struct got_error *got_privsep_send_obj_req(struct imsgbuf *, int,
+ struct got_object *);
+const struct got_error *got_privsep_send_blob_req(struct imsgbuf *, int, int);
const struct got_error *got_privsep_send_obj(struct imsgbuf *,
struct got_object *, int);
const struct got_error *got_privsep_recv_obj(struct got_object **,
blob - 24122e83d302d604ba05b7698aaad60bc5ea8e16
blob + ea058702e40e67e713aa1321c05e22edb72d9700
--- lib/got_lib_repository.h
+++ lib/got_lib_repository.h
int cache_miss;
};
+struct got_privsep_child {
+ int imsg_fd;
+ pid_t pid;
+};
+
struct got_repository {
char *path;
char *path_git_dir;
/* Open file handles for pack files. */
struct got_pack packs[GOT_PACK_CACHE_SIZE];
- /* Caches for opened objects. */
+ /* Handles to child processes for reading pack files. */
+ struct got_privsep_child pack_privsep_children[GOT_PACK_CACHE_SIZE];
+
+ /* Handles to child processes for reading loose objects. */
+ struct got_privsep_child privsep_children[4];
+#define GOT_REPO_PRIVSEP_CHILD_OBJECT 0
+#define GOT_REPO_PRIVSEP_CHILD_COMMIT 1
+#define GOT_REPO_PRIVSEP_CHILD_TREE 2
+#define GOT_REPO_PRIVSEP_CHILD_BLOB 3
+
+ /* Caches for open objects. */
struct got_object_cache objcache;
struct got_object_cache treecache;
struct got_object_cache commitcache;
blob - e8d569b12eb5b9f74cbe5fdf362abe1b0c79c118
blob + 11b768f43c29b5eed657ffb5684b11607d28a63b
--- lib/object.c
+++ lib/object.c
#include "got_lib_path.h"
#include "got_lib_inflate.h"
#include "got_lib_object.h"
-#include "got_lib_object_parse.h"
#include "got_lib_privsep.h"
+#include "got_lib_object_parse.h"
#include "got_lib_repository.h"
#ifndef MIN
if (*obj == NULL)
err = got_error(GOT_ERR_NO_OBJ);
} else {
- err = got_object_read_header_privsep(obj, fd);
+ err = got_object_read_header_privsep(obj, repo, fd);
if (err)
goto done;
memcpy((*obj)->id.sha1, id->sha1, SHA1_DIGEST_LENGTH);
err = open_loose_object(&fd, obj, repo);
if (err)
return err;
- err = got_object_read_commit_privsep(commit, obj, fd);
+ err = got_object_read_commit_privsep(commit, obj, fd, repo);
close(fd);
}
err = open_loose_object(&fd, obj, repo);
if (err)
return err;
- err = got_object_read_tree_privsep(tree, obj, fd);
+ err = got_object_read_tree_privsep(tree, obj, fd, repo);
close(fd);
}
goto done;
}
- err = got_object_read_blob_privsep(&size, outfd, infd);
+ err = got_object_read_blob_privsep(&size, outfd, infd, repo);
close(infd);
if (err)
goto done;
blob - 3b98216fb5dfe9e4e4624f8f9e53ed461cea01e9
blob + d4f209240efa15b01cc928f166088b0c268144ef
--- lib/object_parse.c
+++ lib/object_parse.c
#include <limits.h>
#include <imsg.h>
#include <time.h>
+#include <unistd.h>
#include "got_error.h"
#include "got_object.h"
#include "got_lib_sha1.h"
#include "got_lib_delta.h"
+#include "got_lib_privsep.h"
#include "got_lib_pack.h"
#include "got_lib_inflate.h"
#include "got_lib_object.h"
-#include "got_lib_privsep.h"
+#include "got_lib_repository.h"
#ifndef nitems
#define nitems(_a) (sizeof(_a) / sizeof((_a)[0]))
}
static const struct got_error *
-parse_object_header(struct got_object **obj, char *buf, size_t len)
+request_object(struct got_object **obj, struct got_repository *repo, int fd)
{
- const char *obj_tags[] = {
- GOT_OBJ_TAG_COMMIT,
- GOT_OBJ_TAG_TREE,
- GOT_OBJ_TAG_BLOB
- };
- const int obj_types[] = {
- GOT_OBJ_TYPE_COMMIT,
- GOT_OBJ_TYPE_TREE,
- GOT_OBJ_TYPE_BLOB,
- };
- int type = 0;
- size_t size = 0, hdrlen = 0;
- int i;
- char *p = strchr(buf, '\0');
+ const struct got_error *err = NULL;
+ struct imsgbuf ibuf;
- if (p == NULL)
- return got_error(GOT_ERR_BAD_OBJ_HDR);
+ imsg_init(&ibuf,
+ repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_OBJECT].imsg_fd);
- hdrlen = strlen(buf) + 1 /* '\0' */;
-
- for (i = 0; i < nitems(obj_tags); i++) {
- const char *tag = obj_tags[i];
- size_t tlen = strlen(tag);
- const char *errstr;
-
- if (strncmp(buf, tag, tlen) != 0)
- continue;
-
- type = obj_types[i];
- if (len <= tlen)
- return got_error(GOT_ERR_BAD_OBJ_HDR);
- size = strtonum(buf + tlen, 0, LONG_MAX, &errstr);
- if (errstr != NULL)
- return got_error(GOT_ERR_BAD_OBJ_HDR);
- break;
- }
-
- if (type == 0)
- return got_error(GOT_ERR_BAD_OBJ_HDR);
-
- *obj = calloc(1, sizeof(**obj));
- if (*obj == NULL)
- return got_error_from_errno();
- (*obj)->type = type;
- (*obj)->hdrlen = hdrlen;
- (*obj)->size = size;
- return NULL;
-}
-
-static const struct got_error *
-read_object_header(struct got_object **obj, int fd)
-{
- const struct got_error *err;
- struct got_zstream_buf zb;
- char *buf;
- const size_t zbsize = 64;
- size_t outlen, totlen;
- int nbuf = 1;
-
- buf = malloc(zbsize);
- if (buf == NULL)
- return got_error_from_errno();
-
- err = got_inflate_init(&zb, buf, zbsize);
+ err = got_privsep_send_obj_req(&ibuf, fd, NULL);
if (err)
- return err;
-
- totlen = 0;
- do {
- err = got_inflate_read_fd(&zb, fd, &outlen);
- if (err)
- goto done;
- if (outlen == 0)
- break;
- totlen += outlen;
- if (strchr(zb.outbuf, '\0') == NULL) {
- char *newbuf;
- nbuf++;
- newbuf = recallocarray(buf, nbuf - 1, nbuf, zbsize);
- if (newbuf == NULL) {
- err = got_error_from_errno();
- goto done;
- }
- buf = newbuf;
- zb.outbuf = newbuf + totlen;
- zb.outlen = (nbuf * zbsize) - totlen;
- }
- } while (strchr(zb.outbuf, '\0') == NULL);
-
- err = parse_object_header(obj, buf, totlen);
+ goto done;
+ err = got_privsep_recv_obj(obj, &ibuf);
done:
- free(buf);
- got_inflate_end(&zb);
+ imsg_clear(&ibuf);
return err;
}
static void
-read_object_header_privsep_child(int obj_fd, int imsg_fds[2])
+exec_privsep_child(int imsg_fds[2], const char *path)
{
- const struct got_error *err = NULL;
- struct got_object *obj = NULL;
- struct imsgbuf ibuf;
- int status = 0;
-
- setproctitle("read object header");
close(imsg_fds[0]);
- imsg_init(&ibuf, imsg_fds[1]);
- /* revoke access to most system calls */
- if (pledge("stdio", NULL) == -1) {
- err = got_error_from_errno();
- goto done;
+ if (dup2(imsg_fds[1], GOT_IMSG_FD_CHILD) == -1) {
+ fprintf(stderr, "%s: %s\n", getprogname(),
+ strerror(errno));
+ _exit(1);
}
+ if (closefrom(GOT_IMSG_FD_CHILD + 1) == -1) {
+ fprintf(stderr, "%s: %s\n", getprogname(),
+ strerror(errno));
+ _exit(1);
+ }
- err = read_object_header(&obj, obj_fd);
- if (err)
- goto done;
-
- err = got_privsep_send_obj(&ibuf, obj, 0);
-done:
- if (obj)
- got_object_close(obj);
- if (err) {
- got_privsep_send_error(&ibuf, err);
- status = 1;
+ if (execl(path, path, (char *)NULL) == -1) {
+ fprintf(stderr, "%s: %s: %s\n", getprogname(), path,
+ strerror(errno));
+ _exit(1);
}
- close(obj_fd);
- imsg_clear(&ibuf);
- close(imsg_fds[1]);
- _exit(status);
}
-static const struct got_error *
-wait_for_child(pid_t pid)
-{
- int child_status;
-
- waitpid(pid, &child_status, 0);
-
- if (!WIFEXITED(child_status))
- return got_error(GOT_ERR_PRIVSEP_DIED);
-
- if (WEXITSTATUS(child_status) != 0)
- return got_error(GOT_ERR_PRIVSEP_EXIT);
-
- return NULL;
-}
-
const struct got_error *
-got_object_read_header_privsep(struct got_object **obj, int fd)
+got_object_read_header_privsep(struct got_object **obj,
+ struct got_repository *repo, int obj_fd)
{
- struct imsgbuf parent_ibuf;
int imsg_fds[2];
- const struct got_error *err = NULL, *err_child = NULL;
pid_t pid;
+ if (repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_OBJECT].imsg_fd != -1)
+ return request_object(obj, repo, obj_fd);
+
if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, imsg_fds) == -1)
return got_error_from_errno();
if (pid == -1)
return got_error_from_errno();
else if (pid == 0) {
- read_object_header_privsep_child(fd, imsg_fds);
+ exec_privsep_child(imsg_fds, GOT_PATH_PROG_READ_OBJECT);
/* not reached */
}
close(imsg_fds[1]);
- imsg_init(&parent_ibuf, imsg_fds[0]);
- err = got_privsep_recv_obj(obj, &parent_ibuf);
- imsg_clear(&parent_ibuf);
- err_child = wait_for_child(pid);
- close(imsg_fds[0]);
- return err ? err : err_child;
+ repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_OBJECT].imsg_fd =
+ imsg_fds[0];
+ repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_OBJECT].pid = pid;
+
+ return request_object(obj, repo, obj_fd);
}
struct got_commit_object *
return err;
}
-static void
-tree_entry_close(struct got_tree_entry *te)
+void
+got_object_tree_entry_close(struct got_tree_entry *te)
{
free(te->id);
free(te->name);
while (!SIMPLEQ_EMPTY(&tree->entries.head)) {
te = SIMPLEQ_FIRST(&tree->entries.head);
SIMPLEQ_REMOVE_HEAD(&tree->entries.head, entry);
- tree_entry_close(te);
+ got_object_tree_entry_close(te);
}
free(tree);
*elen += SHA1_DIGEST_LENGTH;
done:
if (err) {
- tree_entry_close(*te);
+ got_object_tree_entry_close(*te);
*te = NULL;
}
return err;
return NULL;
}
-static const struct got_error *
-read_to_mem(uint8_t **outbuf, size_t *outlen, FILE *f)
+const struct got_error *
+got_read_file_to_mem(uint8_t **outbuf, size_t *outlen, FILE *f)
{
const struct got_error *err = NULL;
static const size_t blocksize = 512;
}
static const struct got_error *
-read_commit_object(struct got_commit_object **commit, struct got_object *obj,
- FILE *f)
+request_commit(struct got_commit_object **commit, struct got_repository *repo,
+ struct got_object *obj, int fd)
{
const struct got_error *err = NULL;
- size_t len;
- uint8_t *p;
+ struct imsgbuf ibuf;
- if (obj->flags & GOT_OBJ_FLAG_PACKED)
- err = read_to_mem(&p, &len, f);
- else
- err = got_inflate_to_mem(&p, &len, f);
- if (err)
- return err;
-
- if (len < obj->hdrlen + obj->size) {
- err = got_error(GOT_ERR_BAD_OBJ_DATA);
- goto done;
- }
-
- /* Skip object header. */
- len -= obj->hdrlen;
- err = got_object_parse_commit(commit, p + obj->hdrlen, len);
- free(p);
-done:
- return err;
-}
-
-static void
-read_commit_object_privsep_child(struct got_object *obj, int obj_fd,
- int imsg_fds[2])
-{
- const struct got_error *err = NULL;
- struct got_commit_object *commit = NULL;
- struct imsgbuf ibuf;
- FILE *f = NULL;
- int status = 0;
-
- setproctitle("read commit object");
- close(imsg_fds[0]);
- imsg_init(&ibuf, imsg_fds[1]);
+ imsg_init(&ibuf,
+ repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_COMMIT].imsg_fd);
- /* revoke access to most system calls */
- if (pledge("stdio", NULL) == -1) {
- err = got_error_from_errno();
- goto done;
- }
-
- f = fdopen(obj_fd, "rb");
- if (f == NULL) {
- err = got_error_from_errno();
- close(obj_fd);
- goto done;
- }
-
- err = read_commit_object(&commit, obj, f);
+ err = got_privsep_send_obj_req(&ibuf, fd,obj);
if (err)
goto done;
- err = got_privsep_send_commit(&ibuf, commit);
+ err = got_privsep_recv_commit(commit, &ibuf);
done:
- if (commit)
- got_object_commit_close(commit);
- if (err) {
- got_privsep_send_error(&ibuf, err);
- status = 1;
- }
- if (f)
- fclose(f);
imsg_clear(&ibuf);
- close(imsg_fds[1]);
- _exit(status);
+ return err;
}
const struct got_error *
got_object_read_commit_privsep(struct got_commit_object **commit,
- struct got_object *obj, int fd)
+ struct got_object *obj, int obj_fd, struct got_repository *repo)
{
- const struct got_error *err = NULL, *err_child = NULL;
- struct imsgbuf parent_ibuf;
int imsg_fds[2];
pid_t pid;
+ if (repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_COMMIT].imsg_fd != -1)
+ return request_commit(commit, repo, obj, obj_fd);
+
if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, imsg_fds) == -1)
return got_error_from_errno();
if (pid == -1)
return got_error_from_errno();
else if (pid == 0) {
- read_commit_object_privsep_child(obj, fd, imsg_fds);
+ exec_privsep_child(imsg_fds, GOT_PATH_PROG_READ_COMMIT);
/* not reached */
}
close(imsg_fds[1]);
- imsg_init(&parent_ibuf, imsg_fds[0]);
- err = got_privsep_recv_commit(commit, &parent_ibuf);
- imsg_clear(&parent_ibuf);
- err_child = wait_for_child(pid);
- close(imsg_fds[0]);
- return err ? err : err_child;
+ repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_COMMIT].imsg_fd =
+ imsg_fds[0];
+ repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_COMMIT].pid = pid;
+
+ return request_commit(commit, repo, obj, obj_fd);
}
static const struct got_error *
-read_tree_object(struct got_tree_object **tree, struct got_object *obj, FILE *f)
+request_tree(struct got_tree_object **tree, struct got_repository *repo,
+ struct got_object *obj, int fd)
{
const struct got_error *err = NULL;
- size_t len;
- uint8_t *p;
-
- if (obj->flags & GOT_OBJ_FLAG_PACKED)
- err = read_to_mem(&p, &len, f);
- else
- err = got_inflate_to_mem(&p, &len, f);
- if (err)
- return err;
-
- if (len < obj->hdrlen + obj->size) {
- err = got_error(GOT_ERR_BAD_OBJ_DATA);
- goto done;
- }
-
- /* Skip object header. */
- len -= obj->hdrlen;
- err = got_object_parse_tree(tree, p + obj->hdrlen, len);
- free(p);
-done:
- return err;
-}
-
-static void
-read_tree_object_privsep_child(struct got_object *obj, int obj_fd,
- int imsg_fds[2])
-{
- const struct got_error *err = NULL;
- struct got_tree_object *tree = NULL;
struct imsgbuf ibuf;
- FILE *f = NULL;
- int status = 0;
- setproctitle("read tree object");
- close(imsg_fds[0]);
- imsg_init(&ibuf, imsg_fds[1]);
+ imsg_init(&ibuf,
+ repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_TREE].imsg_fd);
- /* revoke access to most system calls */
- if (pledge("stdio", NULL) == -1) {
- err = got_error_from_errno();
- goto done;
- }
-
- f = fdopen(obj_fd, "rb");
- if (f == NULL) {
- err = got_error_from_errno();
- close(obj_fd);
- goto done;
- }
-
- err = read_tree_object(&tree, obj, f);
+ err = got_privsep_send_obj_req(&ibuf, fd,obj);
if (err)
goto done;
- err = got_privsep_send_tree(&ibuf, tree);
+ err = got_privsep_recv_tree(tree, &ibuf);
done:
- if (tree)
- got_object_tree_close(tree);
- if (err) {
- got_privsep_send_error(&ibuf, err);
- status = 1;
- }
- if (f)
- fclose(f);
imsg_clear(&ibuf);
- close(imsg_fds[1]);
- _exit(status);
+ return err;
}
const struct got_error *
got_object_read_tree_privsep(struct got_tree_object **tree,
- struct got_object *obj, int fd)
+ struct got_object *obj, int obj_fd, struct got_repository *repo)
{
- const struct got_error *err = NULL, *err_child = NULL;
- struct imsgbuf parent_ibuf;
int imsg_fds[2];
pid_t pid;
+ if (repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_TREE].imsg_fd != -1)
+ return request_tree(tree, repo, obj, obj_fd);
+
if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, imsg_fds) == -1)
return got_error_from_errno();
if (pid == -1)
return got_error_from_errno();
else if (pid == 0) {
- read_tree_object_privsep_child(obj, fd, imsg_fds);
+ exec_privsep_child(imsg_fds, GOT_PATH_PROG_READ_TREE);
/* not reached */
}
close(imsg_fds[1]);
- imsg_init(&parent_ibuf, imsg_fds[0]);
- err = got_privsep_recv_tree(tree, &parent_ibuf);
- imsg_clear(&parent_ibuf);
- err_child = wait_for_child(pid);
- close(imsg_fds[0]);
- return err ? err : err_child;
+ repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_TREE].imsg_fd =
+ imsg_fds[0];
+ repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_TREE].pid = pid;
+
+ return request_tree(tree, repo, obj, obj_fd);
}
static const struct got_error *
-read_blob_object_privsep_child(int outfd, int infd, int imsg_fds[2])
+request_blob(size_t *size, int outfd, int infd, struct got_repository *repo)
{
const struct got_error *err = NULL;
struct imsgbuf ibuf;
- int status = 0;
- size_t size;
- FILE *infile = NULL;
+ int outfd_child;
- setproctitle("read blob object");
- close(imsg_fds[0]);
- imsg_init(&ibuf, imsg_fds[1]);
+ outfd_child = dup(outfd);
+ if (outfd_child == -1)
+ return got_error_from_errno();
- /* revoke access to most system calls */
- if (pledge("stdio", NULL) == -1) {
- err = got_error_from_errno();
- goto done;
- }
+ imsg_init(&ibuf,
+ repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_BLOB].imsg_fd);
- infile = fdopen(infd, "rb");
- if (infile == NULL) {
- err = got_error_from_errno();
- close(infd);
+ err = got_privsep_send_blob_req(&ibuf, outfd_child, infd);
+ if (err)
goto done;
- }
- err = got_inflate_to_fd(&size, infile, outfd);
- fclose(infile);
+
+ err = got_privsep_recv_blob(size, &ibuf);
if (err)
goto done;
- err = got_privsep_send_blob(&ibuf, size);
+ if (lseek(outfd, SEEK_SET, 0) == -1)
+ err = got_error_from_errno();
done:
- if (err) {
- got_privsep_send_error(&ibuf, err);
- status = 1;
- }
- close(outfd);
imsg_clear(&ibuf);
- close(imsg_fds[1]);
- _exit(status);
+ return err;
}
const struct got_error *
-got_object_read_blob_privsep(size_t *size, int outfd, int infd)
+got_object_read_blob_privsep(size_t *size, int outfd, int infd,
+ struct got_repository *repo)
{
- struct imsgbuf parent_ibuf;
int imsg_fds[2];
- const struct got_error *err = NULL, *err_child = NULL;
pid_t pid;
+ if (repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_BLOB].imsg_fd != -1)
+ return request_blob(size, outfd, infd, repo);
+
if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, imsg_fds) == -1)
return got_error_from_errno();
if (pid == -1)
return got_error_from_errno();
else if (pid == 0) {
- read_blob_object_privsep_child(outfd, infd, imsg_fds);
+ exec_privsep_child(imsg_fds, GOT_PATH_PROG_READ_BLOB);
/* not reached */
}
close(imsg_fds[1]);
- imsg_init(&parent_ibuf, imsg_fds[0]);
- err = got_privsep_recv_blob(size, &parent_ibuf);
- imsg_clear(&parent_ibuf);
- err_child = wait_for_child(pid);
- close(imsg_fds[0]);
- if (lseek(outfd, SEEK_SET, 0) == -1)
- err = got_error_from_errno();
- return err ? err : err_child;
+ repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_BLOB].imsg_fd =
+ imsg_fds[0];
+ repo->privsep_children[GOT_REPO_PRIVSEP_CHILD_BLOB].pid = pid;
+
+ return request_blob(size, outfd, infd, repo);
}
blob - 7b2c957fd762f6d53cbcf3927a6b89c82d207f12
blob + e01100b024d9a4e2277b55413469962af808b8c4
--- lib/privsep.c
+++ lib/privsep.c
return NULL;
}
-static const struct got_error *
-recv_one_imsg(struct imsg *imsg, struct imsgbuf *ibuf, size_t min_datalen)
+const struct got_error *
+got_privsep_recv_imsg(struct imsg *imsg, struct imsgbuf *ibuf, size_t min_datalen)
{
const struct got_error *err;
ssize_t n;
return got_error_from_errno();
return NULL;
+}
+
+const struct got_error *
+got_privsep_send_stop(int fd)
+{
+ const struct got_error *err = NULL;
+ struct imsgbuf ibuf;
+
+ imsg_init(&ibuf, fd);
+
+ if (imsg_compose(&ibuf, GOT_IMSG_STOP, 0, 0, -1, NULL, 0) == -1)
+ return got_error_from_errno();
+
+ err = flush_imsg(&ibuf);
+ imsg_clear(&ibuf);
+ return err;
+}
+
+const struct got_error *
+got_privsep_send_obj_req(struct imsgbuf *ibuf, int fd, struct got_object *obj)
+{
+ struct got_imsg_object iobj, *iobjp = NULL;
+ size_t iobj_size = 0;
+ int imsg_code = GOT_IMSG_OBJECT_REQUEST;
+
+ if (obj) {
+ switch (obj->type) {
+ case GOT_OBJ_TYPE_TREE:
+ imsg_code = GOT_IMSG_TREE_REQUEST;
+ break;
+ case GOT_OBJ_TYPE_COMMIT:
+ imsg_code = GOT_IMSG_COMMIT_REQUEST;
+ break;
+ default:
+ return got_error(GOT_ERR_OBJ_TYPE);
+ }
+
+ iobj.type = obj->type;
+ iobj.flags = obj->flags;
+ iobj.hdrlen = obj->hdrlen;
+ iobj.size = obj->size;
+ iobj.ndeltas = 0;
+
+ iobjp = &iobj;
+ iobj_size = sizeof(iobj);
+ }
+
+ if (imsg_compose(ibuf, imsg_code, 0, 0, fd, iobjp, iobj_size) == -1)
+ return got_error_from_errno();
+
+ return flush_imsg(ibuf);
}
const struct got_error *
+got_privsep_send_blob_req(struct imsgbuf *ibuf, int outfd, int infd)
+{
+ const struct got_error *err = NULL;
+
+ if (imsg_compose(ibuf, GOT_IMSG_BLOB_REQUEST, 0, 0, infd, NULL, 0)
+ == -1) {
+ close(infd);
+ close(outfd);
+ return got_error_from_errno();
+ }
+
+ err = flush_imsg(ibuf);
+ if (err) {
+ close(outfd);
+ return err;
+ }
+
+ if (imsg_compose(ibuf, GOT_IMSG_BLOB_OUTFD, 0, 0, outfd, NULL, 0)
+ == -1) {
+ close(outfd);
+ return got_error_from_errno();
+ }
+
+ return flush_imsg(ibuf);
+}
+
+const struct got_error *
got_privsep_send_obj(struct imsgbuf *ibuf, struct got_object *obj, int ndeltas)
{
struct got_imsg_object iobj;
*obj = NULL;
- err = recv_one_imsg(&imsg, ibuf, min_datalen);
+ err = got_privsep_recv_imsg(&imsg, ibuf, min_datalen);
if (err)
return err;
*commit = NULL;
- err = recv_one_imsg(&imsg, ibuf, min_datalen);
+ err = got_privsep_recv_imsg(&imsg, ibuf, min_datalen);
if (err)
return err;
struct got_imsg_blob iblob;
size_t datalen;
- err = recv_one_imsg(&imsg, ibuf, 0);
+ err = got_privsep_recv_imsg(&imsg, ibuf, 0);
if (err)
return err;
blob - 59b728c96939fc5eb660e65375c48497faa5fb0d
blob + 7ebf16fd18566adf4b16ba0bb1c5c0d7bde1ea09
--- lib/repository.c
+++ lib/repository.c
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include <sys/types.h>
#include <sys/queue.h>
+#include <sys/uio.h>
#include <sys/stat.h>
+#include <sys/wait.h>
#include <limits.h>
#include <stdlib.h>
#include <zlib.h>
#include <errno.h>
#include <libgen.h>
+#include <stdint.h>
+#include <imsg.h>
#include "got_error.h"
#include "got_reference.h"
#include "got_lib_repository.h"
#include "got_lib_worktree.h"
#include "got_lib_object_idcache.h"
+#include "got_lib_privsep.h"
#ifndef nitems
#define nitems(_a) (sizeof(_a) / sizeof((_a)[0]))
struct got_repository *repo = NULL;
const struct got_error *err = NULL;
char *abspath, *normpath = NULL;
- int tried_root = 0;
+ int i, tried_root = 0;
*repop = NULL;
goto done;
}
+ for (i = 0; i < nitems(repo->privsep_children); i++) {
+ repo->privsep_children[i].imsg_fd = -1;
+ repo->privsep_children[i].pid = 0;
+ }
+
repo->objcache.type = GOT_OBJECT_CACHE_TYPE_OBJ;
repo->objcache.size = GOT_OBJECT_CACHE_SIZE_OBJ;
repo->objcache.idcache = got_object_idcache_alloc(repo->objcache.size);
} while (path);
done:
if (err)
- got_repo_close(repo);
+ err = got_repo_close(repo);
else
*repop = repo;
free(abspath);
}
#endif
-void
+static const struct got_error *
+wait_for_child(pid_t pid)
+{
+ int child_status;
+
+ waitpid(pid, &child_status, 0);
+
+ if (!WIFEXITED(child_status))
+ return got_error(GOT_ERR_PRIVSEP_DIED);
+
+ if (WEXITSTATUS(child_status) != 0)
+ return got_error(GOT_ERR_PRIVSEP_EXIT);
+
+ return NULL;
+}
+
+const struct got_error *
got_repo_close(struct got_repository *repo)
{
+ const struct got_error *err = NULL, *child_err;
int i;
for (i = 0; i < nitems(repo->packidx_cache); i++) {
got_object_idcache_free(repo->treecache.idcache);
if (repo->commitcache.idcache)
got_object_idcache_free(repo->commitcache.idcache);
+
+ for (i = 0; i < nitems(repo->privsep_children); i++) {
+ if (repo->privsep_children[i].imsg_fd == -1)
+ continue;
+ err = got_privsep_send_stop(repo->privsep_children[i].imsg_fd);
+ child_err = wait_for_child(repo->privsep_children[i].pid);
+ if (child_err && err == NULL)
+ err = child_err;
+ close(repo->privsep_children[i].imsg_fd);
+ }
free(repo);
+
+ return err;
}
const struct got_error *
blob - ee47b5d17c6579fcc0d5a562dbb73b3a98a3da3b
blob + 2ee86e361958414c674a933d5a2e1494ea250b7d
--- regress/repository/Makefile
+++ regress/repository/Makefile
pack.c privsep.c delta.c fileindex.c worktree.c inflate.c \
repository_test.c
-CPPFLAGS = -I${.CURDIR}/../../include -I${.CURDIR}/../../lib
+GOT_LIBEXECDIR = ${HOME}/bin
+CPPFLAGS = -I${.CURDIR}/../../include -I${.CURDIR}/../../lib \
+ -DGOT_LIBEXECDIR=${GOT_LIBEXECDIR}
LDADD = -lutil -lz
DEBUG = -O0 -g
CFLAGS += -Werror -Wall -Wstrict-prototypes -Wunused-variable
blob - 8b5fcb740be61c3312fcb4ccff3900cb9df69a77
blob + d5fe6d3ef1904416bca7e896855adc989a99b553
--- regress/repository/repository_test.c
+++ regress/repository/repository_test.c
const char *repo_path;
int ch;
- if (pledge("stdio rpath wpath cpath proc", NULL) == -1)
+ if (pledge("stdio rpath wpath cpath proc exec sendfd", NULL) == -1)
err(1, "pledge");
while ((ch = getopt(argc, argv, "v")) != -1) {
blob - 4a2eb3aad111c9c4ebda609be120828e2da69773
blob + 181971230c2c141420272c6cad96af4dabed1dab
--- regress/worktree/Makefile
+++ regress/worktree/Makefile
object_parse.c opentemp.c path.c error.c reference.c sha1.c pack.c \
privsep.c delta.c inflate.c fileindex.c worktree_test.c
-CPPFLAGS = -I${.CURDIR}/../../include -I${.CURDIR}/../../lib
+GOT_LIBEXECDIR = ${HOME}/bin
+CPPFLAGS = -I${.CURDIR}/../../include -I${.CURDIR}/../../lib \
+ -DGOT_LIBEXECDIR=${GOT_LIBEXECDIR}
LDADD = -lutil -lz
DEBUG = -O0 -g
CFLAGS += -Werror -Wall -Wstrict-prototypes -Wunused-variable
blob - a1d1e49fe8037949908f248557e97cfb381a9757
blob + c6ece3a0c62118b22c4b7acc12dbef54dbb5e14a
--- regress/worktree/worktree_test.c
+++ regress/worktree/worktree_test.c
const char *repo_path;
int ch;
- if (pledge("stdio rpath wpath cpath flock proc", NULL) == -1)
+ if (pledge("stdio rpath wpath cpath flock proc exec sendfd", NULL)
+ == -1)
err(1, "pledge");
while ((ch = getopt(argc, argv, "v")) != -1) {
blob - /dev/null
blob + 261f1cc59455aad5fbbd415b6933ecf56a74f571 (mode 644)
--- /dev/null
+++ libexec/got-read-blob/Makefile
+.PATH:${.CURDIR}/../../lib
+
+PROG= got-read-blob
+SRCS= got-read-blob.c delta.c error.c inflate.c object_parse.c \
+ privsep.c sha1.c
+
+CPPFLAGS = -I${.CURDIR}/../../include -I${.CURDIR}/../../lib
+LDADD = -lutil -lz
+DPADD = ${LIBZ} ${LIBUTIL}
+.if defined(PROFILE)
+CC = gcc
+CPPFLAGS += -DPROFILE
+DEBUG = -O0 -pg
+.else
+DEBUG = -O0 -g
+.endif
+CFLAGS += -Werror -Wall -Wstrict-prototypes -Wunused-variable
+#CFLAGS += -DGOT_PACK_NO_MMAP
+#CFLAGS += -DGOT_NO_OBJ_CACHE
+
+# For now, default to installing binary in ~/bin
+LIBEXECDIR = ${HOME}/bin
+GROUP!=id -g -n
+install:
+ ${INSTALL} ${INSTALL_COPY} -o ${USER} -g ${GROUP} \
+ -m ${BINMODE} ${PROG} ${LIBEXECDIR}/${PROG}
+
+# Don't install man pages yet
+NOMAN = Yes
+
+.include <bsd.prog.mk>
blob - /dev/null
blob + 2302e711eaaf23075b4319ef22ba5cc36caefdff (mode 644)
--- /dev/null
+++ libexec/got-read-blob/got-read-blob.c
+/*
+ * Copyright (c) 2018 Stefan Sperling <stsp@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <sys/uio.h>
+#include <sys/time.h>
+#include <sys/limits.h>
+
+#include <stdint.h>
+#include <imsg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sha1.h>
+#include <zlib.h>
+
+#include "got_error.h"
+#include "got_object.h"
+
+#include "got_lib_delta.h"
+#include "got_lib_inflate.h"
+#include "got_lib_object.h"
+#include "got_lib_object_parse.h"
+#include "got_lib_privsep.h"
+
+int
+main(int argc, char *argv[])
+{
+ const struct got_error *err = NULL;
+ struct imsgbuf ibuf;
+ size_t datalen;
+
+ imsg_init(&ibuf, GOT_IMSG_FD_CHILD);
+
+ /* revoke access to most system calls */
+ if (pledge("stdio recvfd", NULL) == -1) {
+ err = got_error_from_errno();
+ got_privsep_send_error(&ibuf, err);
+ return 1;
+ }
+
+ while (1) {
+ struct imsg imsg, imsg_outfd;
+ FILE *f = NULL;
+ size_t size;
+
+ imsg.fd = -1;
+ imsg_outfd.fd = -1;
+
+ err = got_privsep_recv_imsg(&imsg, &ibuf, 0);
+ if (err) {
+ if (imsg.hdr.len == 0)
+ err = NULL;
+ break;
+ }
+
+ if (imsg.hdr.type == GOT_IMSG_STOP)
+ break;
+
+ if (imsg.hdr.type != GOT_IMSG_BLOB_REQUEST) {
+ err = got_error(GOT_ERR_PRIVSEP_MSG);
+ goto done;
+ }
+
+ datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
+ if (datalen != 0) {
+ err = got_error(GOT_ERR_PRIVSEP_LEN);
+ goto done;
+ }
+ if (imsg.fd == -1) {
+ err = got_error(GOT_ERR_PRIVSEP_NO_FD);
+ goto done;
+ }
+
+ err = got_privsep_recv_imsg(&imsg_outfd, &ibuf, 0);
+ if (err) {
+ if (imsg.hdr.len == 0)
+ err = NULL;
+ break;
+ }
+
+ if (imsg_outfd.hdr.type == GOT_IMSG_STOP)
+ break;
+
+ if (imsg_outfd.hdr.type != GOT_IMSG_BLOB_OUTFD) {
+ err = got_error(GOT_ERR_PRIVSEP_MSG);
+ goto done;
+ }
+
+ datalen = imsg_outfd.hdr.len - IMSG_HEADER_SIZE;
+ if (datalen != 0) {
+ err = got_error(GOT_ERR_PRIVSEP_LEN);
+ goto done;
+ }
+ if (imsg_outfd.fd == -1) {
+ err = got_error(GOT_ERR_PRIVSEP_NO_FD);
+ goto done;
+ }
+
+ f = fdopen(imsg.fd, "rb");
+ if (f == NULL) {
+ err = got_error_from_errno();
+ goto done;
+ }
+
+ err = got_inflate_to_fd(&size, f, imsg_outfd.fd);
+ if (err)
+ goto done;
+
+ err = got_privsep_send_blob(&ibuf, size);
+done:
+ if (f)
+ fclose(f);
+ else if (imsg.fd != -1)
+ close(imsg.fd);
+ if (imsg_outfd.fd != -1)
+ close(imsg_outfd.fd);
+ imsg_free(&imsg);
+ imsg_free(&imsg_outfd);
+ if (err) {
+ got_privsep_send_error(&ibuf, err);
+ break;
+ }
+ }
+
+ imsg_clear(&ibuf);
+ if (err)
+ fprintf(stderr, "%s: %s\n", getprogname(), err->msg);
+ close(GOT_IMSG_FD_CHILD);
+ return err ? 1 : 0;
+}
blob - /dev/null
blob + fe091982cd9735bf9abd120934bf0c1a6417b8d4 (mode 644)
--- /dev/null
+++ libexec/got-read-commit/Makefile
+.PATH:${.CURDIR}/../../lib
+
+PROG= got-read-commit
+SRCS= got-read-commit.c delta.c error.c inflate.c object_parse.c \
+ privsep.c sha1.c
+
+CPPFLAGS = -I${.CURDIR}/../../include -I${.CURDIR}/../../lib
+LDADD = -lutil -lz
+DPADD = ${LIBZ} ${LIBUTIL}
+.if defined(PROFILE)
+CC = gcc
+CPPFLAGS += -DPROFILE
+DEBUG = -O0 -pg
+.else
+DEBUG = -O0 -g
+.endif
+CFLAGS += -Werror -Wall -Wstrict-prototypes -Wunused-variable
+#CFLAGS += -DGOT_PACK_NO_MMAP
+#CFLAGS += -DGOT_NO_OBJ_CACHE
+
+# For now, default to installing binary in ~/bin
+LIBEXECDIR = ${HOME}/bin
+GROUP!=id -g -n
+install:
+ ${INSTALL} ${INSTALL_COPY} -o ${USER} -g ${GROUP} \
+ -m ${BINMODE} ${PROG} ${LIBEXECDIR}/${PROG}
+
+# Don't install man pages yet
+NOMAN = Yes
+
+.include <bsd.prog.mk>
blob - /dev/null
blob + 178dd961e87c303cc67120aaa8d9878f9fb741b2 (mode 644)
--- /dev/null
+++ libexec/got-read-commit/got-read-commit.c
+/*
+ * Copyright (c) 2018 Stefan Sperling <stsp@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <sys/uio.h>
+#include <sys/time.h>
+#include <sys/limits.h>
+
+#include <stdint.h>
+#include <imsg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sha1.h>
+#include <zlib.h>
+
+#include "got_error.h"
+#include "got_object.h"
+
+#include "got_lib_delta.h"
+#include "got_lib_inflate.h"
+#include "got_lib_object.h"
+#include "got_lib_object_parse.h"
+#include "got_lib_privsep.h"
+
+static const struct got_error *
+read_commit_object(struct got_commit_object **commit, struct got_object *obj,
+ FILE *f)
+{
+ const struct got_error *err = NULL;
+ size_t len;
+ uint8_t *p;
+
+ if (obj->flags & GOT_OBJ_FLAG_PACKED)
+ err = got_read_file_to_mem(&p, &len, f);
+ else
+ err = got_inflate_to_mem(&p, &len, f);
+ if (err)
+ return err;
+
+ if (len < obj->hdrlen + obj->size) {
+ err = got_error(GOT_ERR_BAD_OBJ_DATA);
+ goto done;
+ }
+
+ /* Skip object header. */
+ len -= obj->hdrlen;
+ err = got_object_parse_commit(commit, p + obj->hdrlen, len);
+ free(p);
+done:
+ return err;
+}
+
+int
+main(int argc, char *argv[])
+{
+ const struct got_error *err = NULL;
+ struct got_commit_object *commit = NULL;
+ struct imsgbuf ibuf;
+ size_t datalen;
+
+ imsg_init(&ibuf, GOT_IMSG_FD_CHILD);
+
+ /* revoke access to most system calls */
+ if (pledge("stdio recvfd", NULL) == -1) {
+ err = got_error_from_errno();
+ got_privsep_send_error(&ibuf, err);
+ return 1;
+ }
+
+ while (1) {
+ struct imsg imsg;
+ struct got_imsg_object iobj;
+ FILE *f = NULL;
+ struct got_object *obj = NULL;
+
+ err = got_privsep_recv_imsg(&imsg, &ibuf, 0);
+ if (err) {
+ if (imsg.hdr.len == 0)
+ err = NULL;
+ break;
+ }
+
+ if (imsg.hdr.type == GOT_IMSG_STOP)
+ break;
+
+ if (imsg.hdr.type != GOT_IMSG_COMMIT_REQUEST) {
+ err = got_error(GOT_ERR_PRIVSEP_MSG);
+ goto done;
+ }
+
+ datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
+ if (datalen != sizeof(iobj)) {
+ err = got_error(GOT_ERR_PRIVSEP_LEN);
+ goto done;
+ }
+
+ memcpy(&iobj, imsg.data, sizeof(iobj));
+ if (iobj.type != GOT_OBJ_TYPE_COMMIT) {
+ err = got_error(GOT_ERR_OBJ_TYPE);
+ goto done;
+ }
+
+ if (imsg.fd == -1) {
+ err = got_error(GOT_ERR_PRIVSEP_NO_FD);
+ goto done;
+ }
+
+ obj = calloc(1, sizeof(*obj));
+ if (obj == NULL) {
+ err = got_error_from_errno();
+ goto done;
+ }
+ obj->type = iobj.type;
+ obj->hdrlen = iobj.hdrlen;
+ obj->size = iobj.size;
+
+ /* Always assume file offset zero. */
+ f = fdopen(imsg.fd, "rb");
+ if (f == NULL) {
+ err = got_error_from_errno();
+ goto done;
+ }
+
+ err = read_commit_object(&commit, obj, f);
+ if (err)
+ goto done;
+
+ err = got_privsep_send_commit(&ibuf, commit);
+done:
+ if (f)
+ fclose(f);
+ else if (imsg.fd != -1)
+ close(imsg.fd);
+ imsg_free(&imsg);
+ if (obj)
+ got_object_close(obj);
+ if (err) {
+ got_privsep_send_error(&ibuf, err);
+ break;
+ }
+ }
+
+ imsg_clear(&ibuf);
+ if (err)
+ fprintf(stderr, "%s: %s\n", getprogname(), err->msg);
+ close(GOT_IMSG_FD_CHILD);
+ return err ? 1 : 0;
+}
blob - /dev/null
blob + 71a0ac872de0db8584350f20eb5986bdd75fc46f (mode 644)
--- /dev/null
+++ libexec/got-read-object/Makefile
+.PATH:${.CURDIR}/../../lib
+
+PROG= got-read-object
+SRCS= got-read-object.c delta.c error.c inflate.c object_parse.c \
+ privsep.c sha1.c
+
+CPPFLAGS = -I${.CURDIR}/../../include -I${.CURDIR}/../../lib
+LDADD = -lutil -lz
+DPADD = ${LIBZ} ${LIBUTIL}
+.if defined(PROFILE)
+CC = gcc
+CPPFLAGS += -DPROFILE
+DEBUG = -O0 -pg
+.else
+DEBUG = -O0 -g
+.endif
+CFLAGS += -Werror -Wall -Wstrict-prototypes -Wunused-variable
+#CFLAGS += -DGOT_PACK_NO_MMAP
+#CFLAGS += -DGOT_NO_OBJ_CACHE
+
+# For now, default to installing binary in ~/bin
+LIBEXECDIR = ${HOME}/bin
+GROUP!=id -g -n
+install:
+ ${INSTALL} ${INSTALL_COPY} -o ${USER} -g ${GROUP} \
+ -m ${BINMODE} ${PROG} ${LIBEXECDIR}/${PROG}
+
+# Don't install man pages yet
+NOMAN = Yes
+
+.include <bsd.prog.mk>
blob - /dev/null
blob + 0911e80092f384fa5eec6a65e28f5b24b5849066 (mode 644)
--- /dev/null
+++ libexec/got-read-object/got-read-object.c
+/*
+ * Copyright (c) 2018 Stefan Sperling <stsp@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <sys/uio.h>
+#include <sys/time.h>
+#include <sys/limits.h>
+
+#include <stdint.h>
+#include <imsg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sha1.h>
+#include <zlib.h>
+
+#include "got_error.h"
+#include "got_object.h"
+
+#include "got_lib_delta.h"
+#include "got_lib_inflate.h"
+#include "got_lib_object.h"
+#include "got_lib_privsep.h"
+
+#ifndef nitems
+#define nitems(_a) (sizeof(_a) / sizeof((_a)[0]))
+#endif
+
+#define GOT_OBJ_TAG_COMMIT "commit"
+#define GOT_OBJ_TAG_TREE "tree"
+#define GOT_OBJ_TAG_BLOB "blob"
+
+static const struct got_error *
+parse_object_header(struct got_object **obj, char *buf, size_t len)
+{
+ const char *obj_tags[] = {
+ GOT_OBJ_TAG_COMMIT,
+ GOT_OBJ_TAG_TREE,
+ GOT_OBJ_TAG_BLOB
+ };
+ const int obj_types[] = {
+ GOT_OBJ_TYPE_COMMIT,
+ GOT_OBJ_TYPE_TREE,
+ GOT_OBJ_TYPE_BLOB,
+ };
+ int type = 0;
+ size_t size = 0, hdrlen = 0;
+ int i;
+ char *p = strchr(buf, '\0');
+
+ if (p == NULL)
+ return got_error(GOT_ERR_BAD_OBJ_HDR);
+
+ hdrlen = strlen(buf) + 1 /* '\0' */;
+
+ for (i = 0; i < nitems(obj_tags); i++) {
+ const char *tag = obj_tags[i];
+ size_t tlen = strlen(tag);
+ const char *errstr;
+
+ if (strncmp(buf, tag, tlen) != 0)
+ continue;
+
+ type = obj_types[i];
+ if (len <= tlen)
+ return got_error(GOT_ERR_BAD_OBJ_HDR);
+ size = strtonum(buf + tlen, 0, LONG_MAX, &errstr);
+ if (errstr != NULL)
+ return got_error(GOT_ERR_BAD_OBJ_HDR);
+ break;
+ }
+
+ if (type == 0)
+ return got_error(GOT_ERR_BAD_OBJ_HDR);
+
+ *obj = calloc(1, sizeof(**obj));
+ if (*obj == NULL)
+ return got_error_from_errno();
+ (*obj)->type = type;
+ (*obj)->hdrlen = hdrlen;
+ (*obj)->size = size;
+ return NULL;
+}
+
+static const struct got_error *
+read_object_header(struct got_object **obj, int fd)
+{
+ const struct got_error *err;
+ struct got_zstream_buf zb;
+ char *buf;
+ const size_t zbsize = 64;
+ size_t outlen, totlen;
+ int nbuf = 1;
+
+ buf = malloc(zbsize);
+ if (buf == NULL)
+ return got_error_from_errno();
+
+ err = got_inflate_init(&zb, buf, zbsize);
+ if (err)
+ return err;
+
+ totlen = 0;
+ do {
+ err = got_inflate_read_fd(&zb, fd, &outlen);
+ if (err)
+ goto done;
+ if (outlen == 0)
+ break;
+ totlen += outlen;
+ if (strchr(zb.outbuf, '\0') == NULL) {
+ char *newbuf;
+ nbuf++;
+ newbuf = recallocarray(buf, nbuf - 1, nbuf, zbsize);
+ if (newbuf == NULL) {
+ err = got_error_from_errno();
+ goto done;
+ }
+ buf = newbuf;
+ zb.outbuf = newbuf + totlen;
+ zb.outlen = (nbuf * zbsize) - totlen;
+ }
+ } while (strchr(zb.outbuf, '\0') == NULL);
+
+ err = parse_object_header(obj, buf, totlen);
+done:
+ free(buf);
+ got_inflate_end(&zb);
+ return err;
+}
+
+
+int
+main(int argc, char *argv[])
+{
+ const struct got_error *err = NULL;
+ struct got_object *obj = NULL;
+ struct imsg imsg;
+ struct imsgbuf ibuf;
+ size_t datalen;
+
+ imsg_init(&ibuf, GOT_IMSG_FD_CHILD);
+
+ /* revoke access to most system calls */
+ if (pledge("stdio recvfd", NULL) == -1) {
+ err = got_error_from_errno();
+ got_privsep_send_error(&ibuf, err);
+ return 1;
+ }
+
+ while (1) {
+ err = got_privsep_recv_imsg(&imsg, &ibuf, 0);
+ if (err) {
+ if (imsg.hdr.len == 0)
+ err = NULL;
+ break;
+ }
+
+ if (imsg.hdr.type == GOT_IMSG_STOP)
+ break;
+
+ if (imsg.hdr.type != GOT_IMSG_OBJECT_REQUEST) {
+ err = got_error(GOT_ERR_PRIVSEP_MSG);
+ goto done;
+ }
+
+ datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
+ if (datalen != 0) {
+ err = got_error(GOT_ERR_PRIVSEP_LEN);
+ goto done;
+ }
+
+ err = read_object_header(&obj, imsg.fd);
+ if (err)
+ goto done;
+
+ err = got_privsep_send_obj(&ibuf, obj, 0);
+done:
+ close(imsg.fd);
+ imsg_free(&imsg);
+ if (obj)
+ got_object_close(obj);
+ if (err) {
+ got_privsep_send_error(&ibuf, err);
+ break;
+ }
+ }
+
+ imsg_clear(&ibuf);
+ if (err)
+ fprintf(stderr, "%s: %s\n", getprogname(), err->msg);
+ close(GOT_IMSG_FD_CHILD);
+ return err ? 1 : 0;
+}
blob - /dev/null
blob + c6079e3ec721fb0b95f0662d62d4e6b2275372f1 (mode 644)
--- /dev/null
+++ libexec/got-read-tree/Makefile
+.PATH:${.CURDIR}/../../lib
+
+PROG= got-read-tree
+SRCS= got-read-tree.c delta.c error.c inflate.c object_parse.c \
+ privsep.c sha1.c
+
+CPPFLAGS = -I${.CURDIR}/../../include -I${.CURDIR}/../../lib
+LDADD = -lutil -lz
+DPADD = ${LIBZ} ${LIBUTIL}
+.if defined(PROFILE)
+CC = gcc
+CPPFLAGS += -DPROFILE
+DEBUG = -O0 -pg
+.else
+DEBUG = -O0 -g
+.endif
+CFLAGS += -Werror -Wall -Wstrict-prototypes -Wunused-variable
+#CFLAGS += -DGOT_PACK_NO_MMAP
+#CFLAGS += -DGOT_NO_OBJ_CACHE
+
+# For now, default to installing binary in ~/bin
+LIBEXECDIR = ${HOME}/bin
+GROUP!=id -g -n
+install:
+ ${INSTALL} ${INSTALL_COPY} -o ${USER} -g ${GROUP} \
+ -m ${BINMODE} ${PROG} ${LIBEXECDIR}/${PROG}
+
+# Don't install man pages yet
+NOMAN = Yes
+
+.include <bsd.prog.mk>
blob - /dev/null
blob + 43696a70aa71949a1566e43e2e43d3f9b0076481 (mode 644)
--- /dev/null
+++ libexec/got-read-tree/got-read-tree.c
+/*
+ * Copyright (c) 2018 Stefan Sperling <stsp@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <sys/uio.h>
+#include <sys/time.h>
+#include <sys/limits.h>
+
+#include <stdint.h>
+#include <imsg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sha1.h>
+#include <zlib.h>
+
+#include "got_error.h"
+#include "got_object.h"
+
+#include "got_lib_delta.h"
+#include "got_lib_inflate.h"
+#include "got_lib_object.h"
+#include "got_lib_object_parse.h"
+#include "got_lib_privsep.h"
+
+static const struct got_error *
+read_tree_object(struct got_tree_object **tree, struct got_object *obj, FILE *f)
+{
+ const struct got_error *err = NULL;
+ size_t len;
+ uint8_t *p;
+
+ if (obj->flags & GOT_OBJ_FLAG_PACKED)
+ err = got_read_file_to_mem(&p, &len, f);
+ else
+ err = got_inflate_to_mem(&p, &len, f);
+ if (err)
+ return err;
+
+ if (len < obj->hdrlen + obj->size) {
+ err = got_error(GOT_ERR_BAD_OBJ_DATA);
+ goto done;
+ }
+
+ /* Skip object header. */
+ len -= obj->hdrlen;
+ err = got_object_parse_tree(tree, p + obj->hdrlen, len);
+ free(p);
+done:
+ return err;
+}
+
+int
+main(int argc, char *argv[])
+{
+ const struct got_error *err = NULL;
+ struct got_tree_object *tree = NULL;
+ struct imsgbuf ibuf;
+ size_t datalen;
+
+ imsg_init(&ibuf, GOT_IMSG_FD_CHILD);
+
+ /* revoke access to most system calls */
+ if (pledge("stdio recvfd", NULL) == -1) {
+ err = got_error_from_errno();
+ got_privsep_send_error(&ibuf, err);
+ return 1;
+ }
+
+ while (1) {
+ struct imsg imsg;
+ struct got_imsg_object iobj;
+ FILE *f = NULL;
+ struct got_object *obj = NULL;
+
+ err = got_privsep_recv_imsg(&imsg, &ibuf, 0);
+ if (err) {
+ if (imsg.hdr.len == 0)
+ err = NULL;
+ break;
+ }
+
+ if (imsg.hdr.type == GOT_IMSG_STOP)
+ break;
+
+ if (imsg.hdr.type != GOT_IMSG_TREE_REQUEST) {
+ err = got_error(GOT_ERR_PRIVSEP_MSG);
+ goto done;
+ }
+
+ datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
+ if (datalen != sizeof(iobj)) {
+ err = got_error(GOT_ERR_PRIVSEP_LEN);
+ goto done;
+ }
+
+ memcpy(&iobj, imsg.data, sizeof(iobj));
+ if (iobj.type != GOT_OBJ_TYPE_TREE) {
+ err = got_error(GOT_ERR_OBJ_TYPE);
+ goto done;
+ }
+
+ if (imsg.fd == -1) {
+ err = got_error(GOT_ERR_PRIVSEP_NO_FD);
+ goto done;
+ }
+
+ obj = calloc(1, sizeof(*obj));
+ if (obj == NULL) {
+ err = got_error_from_errno();
+ goto done;
+ }
+ obj->type = iobj.type;
+ obj->hdrlen = iobj.hdrlen;
+ obj->size = iobj.size;
+
+ /* Always assume file offset zero. */
+ f = fdopen(imsg.fd, "rb");
+ if (f == NULL) {
+ err = got_error_from_errno();
+ goto done;
+ }
+
+ err = read_tree_object(&tree, obj, f);
+ if (err)
+ goto done;
+
+ err = got_privsep_send_tree(&ibuf, tree);
+done:
+ if (f)
+ fclose(f);
+ else if (imsg.fd != -1)
+ close(imsg.fd);
+ imsg_free(&imsg);
+ if (obj)
+ got_object_close(obj);
+ if (err) {
+ got_privsep_send_error(&ibuf, err);
+ break;
+ }
+ }
+
+ imsg_clear(&ibuf);
+ if (err)
+ fprintf(stderr, "%s: %s\n", getprogname(), err->msg);
+ close(GOT_IMSG_FD_CHILD);
+ return err ? 1 : 0;
+}
blob - ab8d78df0d3be8f6a5d681827f8c9ee32971fd07
blob + a3a05e3992bcc9bdc949b5bad8d348bdbad84b8d
--- tog/Makefile
+++ tog/Makefile
privsep.c reference.c repository.c sha1.c worktree.c \
utf8.c inflate.c
-CPPFLAGS = -I${.CURDIR}/../include -I${.CURDIR}/../lib
+GOT_LIBEXECDIR = ${HOME}/bin
+CPPFLAGS = -I${.CURDIR}/../include -I${.CURDIR}/../lib \
+ -DGOT_LIBEXECDIR=${GOT_LIBEXECDIR}
LDADD = -lpanel -lncursesw -lutil -lz -lpthread
DPADD = ${LIBZ} ${LIBUTIL}
.if defined(PROFILE)
blob - 1588ddcc15f3d237c38309143807c857ea2fa96d
blob + d302f3408ca7c7d8b22d2bb3b9c1a45545986874
--- tog/tog.c
+++ tog/tog.c
struct tog_view *view;
#ifndef PROFILE
- if (pledge("stdio rpath wpath cpath flock proc tty", NULL) == -1)
+ if (pledge("stdio rpath wpath cpath flock proc tty exec sendfd", NULL)
+ == -1)
err(1, "pledge");
#endif
struct tog_view *view;
#ifndef PROFILE
- if (pledge("stdio rpath wpath cpath flock proc tty", NULL) == -1)
+ if (pledge("stdio rpath wpath cpath flock proc tty exec sendfd", NULL)
+ == -1)
err(1, "pledge");
#endif
struct tog_view *view;
#ifndef PROFILE
- if (pledge("stdio rpath wpath cpath flock proc tty", NULL) == -1)
+ if (pledge("stdio rpath wpath cpath flock proc tty exec sendfd", NULL)
+ == -1)
err(1, "pledge");
#endif
struct tog_view *view;
#ifndef PROFILE
- if (pledge("stdio rpath wpath cpath flock proc tty", NULL) == -1)
+ if (pledge("stdio rpath wpath cpath flock proc tty exec sendfd", NULL)
+ == -1)
err(1, "pledge");
#endif