summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMichael Forney <mforney@mforney.org>2021-07-24 18:05:26 -0700
committerMichael Forney <mforney@mforney.org>2021-07-24 18:08:16 -0700
commita02412b3637ff39935c2df2cce98d274b7eab480 (patch)
tree2674fd520a6f4aaa79edc7ef3f993a451430ee7e /src
parent995b307746340db5a569d8c0f35f3a9938838d46 (diff)
Move oasis git helpers to skeleton package
Diffstat (limited to 'src')
-rw-r--r--src/applyperms.c443
-rw-r--r--src/gen.lua7
-rw-r--r--src/mergeperms.c164
3 files changed, 0 insertions, 614 deletions
diff --git a/src/applyperms.c b/src/applyperms.c
deleted file mode 100644
index 8e446d39..00000000
--- a/src/applyperms.c
+++ /dev/null
@@ -1,443 +0,0 @@
-/*
-See LICENSE file for copyright and license details.
-
-This program is meant to be run by a git hook to fix the permissions of files
-based on a .perms file in the repository
-
-It can also be run with the -d flag on any directory containing .perms in order
-to apply the permissions specified by that file.
-
-Security considerations:
-If the repository previously contained a world or group readable directory which
-has become secret, the names of the new files in that directory will become
-temporarily visible because git checks out the files before this program is run.
-*/
-#define _POSIX_C_SOURCE 200809L
-#include <errno.h>
-#include <fcntl.h>
-#include <libgen.h>
-#include <spawn.h>
-#include <stdarg.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdnoreturn.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/wait.h>
-#include <unistd.h>
-
-#define PERMS_FILE ".perms"
-
-struct perm {
- char *name;
- mode_t mode;
- bool attempted; /* whether we attempted to set permissions for this file */
- bool delete; /* marked for directories that only appear in old .perms */
-};
-
-struct special {
- struct perm *perms;
- int len;
-};
-
-extern char **environ;
-
-static char *prog;
-static dev_t rootdev;
-static int rootfd = AT_FDCWD;
-static struct special oldsp, newsp;
-static int status;
-
-static void
-verror(char *fmt, va_list ap)
-{
- status = 1;
- vfprintf(stderr, fmt, ap);
- if (fmt[0] && fmt[strlen(fmt)-1] == ':')
- fprintf(stderr, " %s", strerror(errno));
- fputc('\n', stderr);
-}
-
-static void
-error(char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- verror(fmt, ap);
- va_end(ap);
-}
-
-static noreturn void
-die(char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- verror(fmt, ap);
- va_end(ap);
-
- exit(1);
-}
-
-static FILE *
-spawn(char **argv, pid_t *pid)
-{
- FILE *f;
- int fd[2];
- posix_spawn_file_actions_t actions;
-
- if (pipe(fd) < 0)
- die("pipe:");
- f = fdopen(fd[0], "r");
- if (!f)
- die("fdopen:");
- if ((errno = posix_spawn_file_actions_init(&actions)) > 0)
- die("posix_spawn_file_actions_init:");
- if ((errno = posix_spawn_file_actions_addclose(&actions, fd[0])) > 0)
- die("posix_spawn_file_actions_adddup2:");
- if ((errno = posix_spawn_file_actions_adddup2(&actions, fd[1], 1)) > 0)
- die("posix_spawn_file_actions_adddup2:");
- if ((errno = posix_spawnp(pid, argv[0], &actions, NULL, argv, environ)) > 0)
- die("posix_spawnp %s:", argv[0]);
- posix_spawn_file_actions_destroy(&actions);
- close(fd[1]);
-
- return f;
-}
-
-static void
-readspecial(struct special *sp, FILE *f)
-{
- char *line = NULL, *s, *mode;
- size_t size = 0;
- ssize_t n;
-
- while ((n = getline(&line, &size, f)) >= 0) {
- if (line[n-1] == '\n')
- line[--n] = '\0';
- mode = s = line;
- s = strchr(s, ' ');
- if (!s || s == mode)
- die("malformed permissions file: %s", PERMS_FILE);
- *s++ = '\0';
- sp->perms = realloc(sp->perms, (sp->len + 1) * sizeof(*sp->perms));
- if (!sp->perms)
- die("realloc:");
- sp->perms[sp->len] = (struct perm){
- .name = strdup(s),
- .mode = strtoul(mode, &s, 8),
- };
- if (!sp->perms[sp->len].name)
- die("strdup:");
- if (*s)
- die("invalid mode: %s", mode);
- ++sp->len;
- }
-}
-
-static void
-gitspecial(struct special *sp, const char *rev)
-{
- char object[41 + sizeof(PERMS_FILE)];
- char *argv[] = {"git", "show", object, 0};
- FILE *f;
- pid_t pid;
- int st, n;
-
- n = snprintf(object, sizeof(object), "%s:%s", rev, PERMS_FILE);
- if (n < 0 || n >= (int)sizeof(object))
- die("revision is too large: %s", rev);
- f = spawn(argv, &pid);
- readspecial(sp, f);
- fclose(f);
-
- if (waitpid(pid, &st, 0) < 0)
- die("waitpid:");
- if (!(WIFEXITED(st) && WEXITSTATUS(st) == 0))
- die("child process failed");
-}
-
-static int
-chmod_v(const char *path, mode_t mode)
-{
- printf("chmod(\"%s\", %#o)\n", path, mode);
- return fchmodat(rootfd, path, mode, 0);
-}
-
-static int
-mkdir_v(const char *path, mode_t mode)
-{
- printf("mkdir(\"%s\", %#o)\n", path, mode);
- return mkdirat(rootfd, path, mode);
-}
-
-static int
-rmdir_v(const char *path)
-{
- printf("rmdir(\"%s\")\n", path);
- return unlinkat(rootfd, path, AT_REMOVEDIR);
-}
-
-static int
-defperm(const char *name)
-{
- struct stat st;
- mode_t mode;
-
- if (fstatat(rootfd, name, &st, AT_SYMLINK_NOFOLLOW) < 0)
- return -1;
- if (st.st_dev != rootdev) {
- errno = EXDEV;
- return -1;
- }
- switch (st.st_mode & S_IFMT) {
- case S_IFREG:
- mode = st.st_mode & S_IXUSR ? 0755 : 0644;
- break;
- case S_IFDIR:
- mode = 0755;
- break;
- case S_IFLNK:
- return 0;
- default:
- errno = EINVAL;
- return -1;
- }
- if ((st.st_mode & ~S_IFMT) == mode)
- return 0;
- return chmod_v(name, mode);
-}
-
-static int
-specialperm(struct perm *p)
-{
- struct stat st;
-
- if (p->attempted)
- return 0;
- p->attempted = true;
- if (fstatat(rootfd, p->name, &st, AT_SYMLINK_NOFOLLOW) < 0) {
- if (errno != ENOENT || !S_ISDIR(p->mode))
- return -1;
- return mkdir_v(p->name, p->mode & ~S_IFMT);
- }
- if (st.st_dev != rootdev) {
- errno = EXDEV;
- return -1;
- }
- if (st.st_mode == p->mode)
- return 0;
- if ((st.st_mode & S_IFMT) != (p->mode & S_IFMT)) {
- errno = EINVAL;
- return -1;
- }
- return chmod_v(p->name, p->mode & ~S_IFMT);
-}
-
-static void
-specialperms(void)
-{
- int i = 0, j = 0, n;
-
- while (i < oldsp.len || j < newsp.len) {
- if (i == oldsp.len)
- n = 1;
- else if (j == newsp.len)
- n = -1;
- else
- n = strcmp(oldsp.perms[i].name, newsp.perms[j].name);
- if (n >= 0) {
- if (specialperm(&newsp.perms[j]) < 0 && errno != EXDEV)
- error("specialperm:");
- ++j;
- if (n == 0)
- ++i;
- continue;
- }
- if ((oldsp.perms[i].mode & S_IFMT) == S_IFDIR) {
- oldsp.perms[i].delete = true;
- } else if (defperm(oldsp.perms[i].name) < 0) {
- switch (errno) {
- case ENOENT:
- case EXDEV:
- break;
- default:
- error("defperm:");
- }
- }
- ++i;
- }
- /* delete directories in reverse order */
- while (i > 0) {
- --i;
- if (oldsp.perms[i].delete && rmdir_v(oldsp.perms[i].name) < 0) {
- switch (errno) {
- case ENOENT:
- case ENOTEMPTY:
- break;
- default:
- error("rmdir:");
- }
- }
- }
-}
-
-static int
-setperm(const char *name)
-{
- int i;
-
- for (i = 0; i < newsp.len; ++i) {
- if (strcmp(name, newsp.perms[i].name) == 0)
- return specialperm(&newsp.perms[i]);
- }
- return defperm(name);
-}
-
-static void
-setroot(const char *root)
-{
- struct stat st;
-
- rootfd = open(root, O_RDONLY);
- if (rootfd < 0)
- die("open %s:", root);
- if (fstat(rootfd, &st) < 0)
- die("fstat:", root);
- rootdev = st.st_dev;
-}
-
-static void
-gitupdate(char *old, char *new)
-{
- char *argv_diff[] = {"git", "diff", "--name-only", "-z", old, new, 0};
- char *argv_new[] = {"git", "ls-tree", "--name-only", "--full-tree", "-z", "-r", new, 0};
- FILE *f;
- pid_t pid;
- struct {
- char *buf;
- size_t size;
- } lines[2] = {0};
- ssize_t n;
- int cur = 0, st;
- char *root, *path, *diff, *s;
-
- root = getenv("GIT_WORK_TREE");
- setroot(root ? root : ".");
- if (old)
- gitspecial(&oldsp, old);
- gitspecial(&newsp, new);
-
- f = spawn(old ? argv_diff : argv_new, &pid);
- umask(0);
- while ((n = getdelim(&lines[cur].buf, &lines[cur].size, '\0', f)) >= 0) {
- path = lines[cur].buf;
- if (strcmp(path, PERMS_FILE) == 0) {
- specialperms();
- continue;
- }
- if (setperm(path) < 0) switch (errno) {
- case ENOENT:
- continue;
- case EXDEV:
- break;
- default:
- error("setperm %s:", path);
- }
- /* find the first difference from the previous path */
- diff = path;
- if (lines[!cur].buf)
- for (s = lines[!cur].buf; *s && *s == *diff; ++s, ++diff);
- /* set permissions on each parent directory after that difference */
- for (s = path + n; s >= diff; --s) {
- if (*s != '/')
- continue;
- *s = '\0';
- if (setperm(path) < 0)
- error("setperm %s:", path);
- *s = '/';
- }
- cur = !cur;
- }
- fclose(f);
-
- if (waitpid(pid, &st, 0) < 0)
- die("waitpid:");
- if (!(WIFEXITED(st) && WEXITSTATUS(st) == 0))
- die("child process failed");
-}
-
-static void
-applyspecial(void)
-{
- int fd;
- FILE *f;
-
- fd = openat(rootfd, ".perms", O_RDONLY);
- if (fd < 0)
- die("open .perms:");
- f = fdopen(fd, "r");
- if (!f)
- die("fdopen:");
- readspecial(&newsp, f);
- fclose(f);
- umask(0);
- specialperms();
-}
-
-static void
-usage(void)
-{
- fprintf(stderr, "usage: %s [[old] new] | %s -d dir\n", prog, prog);
- exit(2);
-}
-
-int
-main(int argc, char *argv[])
-{
- int dflag = 0;
- char *old, *new;
-
- prog = basename(argv[0]);
- for (++argv, --argc; argc && (*argv)[0] == '-' && (*argv)[1]; ++argv, --argc) {
- switch ((*argv)[1]) {
- case 'd':
- if (!*++argv)
- usage();
- --argc;
- setroot(*argv);
- dflag = 1;
- break;
- default:
- usage();
- }
- }
-
- if (dflag) {
- if (argc)
- usage();
- applyspecial();
- return status;
- }
-
- switch (argc) {
- case 0:
- old = NULL;
- new = "HEAD";
- break;
- case 1:
- old = NULL;
- new = argv[0];
- break;
- case 2:
- old = argv[0];
- new = argv[1];
- break;
- default:
- usage();
- }
- gitupdate(old, new);
- return status;
-}
diff --git a/src/gen.lua b/src/gen.lua
deleted file mode 100644
index e2a04f5a..00000000
--- a/src/gen.lua
+++ /dev/null
@@ -1,7 +0,0 @@
-set('srcdir', '$dir')
-cflags{
- '-std=c11', '-Wall', '-Wextra', '-Wpedantic', '-Wno-unused-parameter',
-}
-
-file('libexec/applyperms', '755', exe('applyperms', {'applyperms.c'}))
-file('libexec/mergeperms', '755', exe('mergeperms', {'mergeperms.c'}))
diff --git a/src/mergeperms.c b/src/mergeperms.c
deleted file mode 100644
index 94ba7e3d..00000000
--- a/src/mergeperms.c
+++ /dev/null
@@ -1,164 +0,0 @@
-#define _POSIX_C_SOURCE 200809L
-#include <errno.h>
-#include <stdarg.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdnoreturn.h>
-#include <string.h>
-#include <sys/stat.h>
-
-struct perm {
- char *name;
- mode_t mode;
-};
-
-static struct perm *perms;
-static size_t permslen, permscap;
-
-static noreturn void
-fatal(const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- vfprintf(stderr, fmt, ap);
- va_end(ap);
- if (fmt[0] && fmt[strlen(fmt) - 1] == ':') {
- fputc(' ', stderr);
- perror(NULL);
- } else {
- fputc('\n', stderr);
- }
- exit(1);
-}
-
-static void
-addperm(struct perm *p)
-{
- if (permslen == permscap) {
- permscap = permscap ? permscap * 2 : 64;
- if (permscap > SIZE_MAX / sizeof(perms[0])) {
- errno = ENOMEM;
- fatal("realloc:");
- }
- perms = realloc(perms, permscap * sizeof(perms[0]));
- if (!perms)
- fatal("realloc:");
- }
- perms[permslen++] = *p;
-}
-
-static void
-readperm(FILE *file, struct perm *perm)
-{
- static char *line;
- static size_t size;
- ssize_t n;
- char *s, *mode;
-
- n = getline(&line, &size, file);
- if (n < 0) {
- if (ferror(file))
- fatal("getline:");
- perm->name = NULL;
- return;
- }
- if (n && line[n - 1] == '\n')
- line[n - 1] = '\0';
- mode = s = line;
- s = strchr(s, ' ');
- if (!s || s == mode)
- fatal("invalid permissions file");
- *s++ = '\0';
- perm->name = strdup(s);
- if (!perm->name)
- fatal("strdup:");
- perm->mode = strtoul(mode, &s, 8);
- if (*s)
- fatal("invalid mode '%s'", mode);
-}
-
-static int
-permcmp(struct perm *a, struct perm *b)
-{
- return a->name ? b->name ? strcmp(a->name, b->name) : -1 : !!b->name;
-}
-
-static noreturn void
-usage(void)
-{
- fprintf(stderr, "usage: mergeperms old cur new\n");
- exit(2);
-}
-
-int
-main(int argc, char *argv[])
-{
- FILE *oldf, *curf, *newf;
- struct perm old, cur, new;
- int ij, ik, jk;
- int ret;
-
- if (argc != 4)
- usage();
-
- ret = 0;
- oldf = fopen(argv[1], "r");
- if (!oldf)
- fatal("open %s:", argv[1]);
- curf = fopen(argv[2], "r");
- if (!curf)
- fatal("open %s:", argv[2]);
- newf = fopen(argv[3], "r");
- if (!newf)
- fatal("open %s:", argv[3]);
-
- readperm(oldf, &old);
- readperm(curf, &cur);
- readperm(newf, &new);
- for (;;) {
- ij = permcmp(&old, &cur);
- ik = permcmp(&old, &new);
- if (ij < 0 && ik < 0 && old.name) {
- readperm(oldf, &old);
- continue;
- }
- if (!old.name && !cur.name && !new.name)
- break;
- jk = permcmp(&cur, &new);
- if ((jk < 0 && ij == 0 && old.mode == cur.mode) || (jk > 0 && ik == 0 && old.mode == new.mode)) {
- /* deleted in cur or new and unchanged in the other */
- } else if (jk < 0) {
- if (ij == 0)
- ret = 3;
- addperm(&cur);
- } else if (jk > 0) {
- if (ik == 0)
- ret = 3;
- addperm(&new);
- } else if (ij == 0 && old.mode == cur.mode) {
- addperm(&new);
- } else {
- if (cur.mode != new.mode && (ik != 0 || old.mode != new.mode))
- ret = 3;
- addperm(&cur);
- }
- if (jk <= 0)
- readperm(curf, &cur);
- if (jk >= 0)
- readperm(newf, &new);
- }
-
- fclose(curf);
- curf = fopen(argv[2], "w");
- if (!curf)
- fatal("open %s:", argv[1]);
- for (; permslen > 0; --permslen, ++perms)
- fprintf(curf, "%#o %s\n", perms->mode, perms->name);
- fflush(curf);
- if (ferror(curf))
- fatal("write error");
-
- return ret;
-}