From a02412b3637ff39935c2df2cce98d274b7eab480 Mon Sep 17 00:00:00 2001 From: Michael Forney Date: Sat, 24 Jul 2021 18:05:26 -0700 Subject: Move oasis git helpers to skeleton package --- gen.lua | 7 +- pkg/skeleton/applyperms.c | 443 ++++++++++++++++++++++++++++++++++++++++++++++ pkg/skeleton/gen.lua | 5 + pkg/skeleton/mergeperms.c | 164 +++++++++++++++++ src/applyperms.c | 443 ---------------------------------------------- src/gen.lua | 7 - src/mergeperms.c | 164 ----------------- 7 files changed, 618 insertions(+), 615 deletions(-) create mode 100644 pkg/skeleton/applyperms.c create mode 100644 pkg/skeleton/mergeperms.c delete mode 100644 src/applyperms.c delete mode 100644 src/gen.lua delete mode 100644 src/mergeperms.c diff --git a/gen.lua b/gen.lua index feae180f..da92ebee 100644 --- a/gen.lua +++ b/gen.lua @@ -16,7 +16,6 @@ toolchain(config.target) subgen 'probe' subgen 'pkg' -subgen 'src' build('awk', '$outdir/root.perms', {'$outdir/tree.fspec', '|', '$basedir/scripts/perms.awk'}, { expr='-f $basedir/scripts/perms.awk', @@ -31,6 +30,12 @@ build('phony', 'commit', '$builddir/root.commit') build('fspec-sort', '$outdir/root.fspec', {'$outdir/tree.fspec', '|', '$builddir/pkg/fspec-sync/host/fspec-sort'}) build('fspec-tar', '$outdir/root.tar.zst', {'$outdir/root.fspec', '|', '$builddir/pkg/fspec-sync/host/fspec-tar'}) +--build('awk', '$outdir/root.sqfslist', {'$outdir/root.fspec', '|', '$basedir/scripts/squashfs.awk'}, { +-- expr='-f $basedir/scripts/squashfs.awk', +--}) +--rule('gensquashfs', 'gensquashfs -F $in -D . -f -c gzip $out') +--build('gensquashfs', '$outdir/root.squashfs', {'$outdir/root.sqfslist'}) + build('phony', 'build.ninja', 'ninja', {generator='1'}) io.write('default $builddir/root.tree\n') diff --git a/pkg/skeleton/applyperms.c b/pkg/skeleton/applyperms.c new file mode 100644 index 00000000..8e446d39 --- /dev/null +++ b/pkg/skeleton/applyperms.c @@ -0,0 +1,443 @@ +/* +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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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/pkg/skeleton/gen.lua b/pkg/skeleton/gen.lua index efd8dd61..e55ecddb 100644 --- a/pkg/skeleton/gen.lua +++ b/pkg/skeleton/gen.lua @@ -1,3 +1,5 @@ +set('srcdir', '$dir') + dir('bin', '755') sym('bin/plumb', '../etc/plumb') dir('boot', '755') @@ -17,3 +19,6 @@ dir('var/log', '755') sym('usr/bin', '../bin') gitfile('.gitignore', '644', '$dir/gitignore') + +file('libexec/applyperms', '755', exe('applyperms', {'applyperms.c'})) +file('libexec/mergeperms', '755', exe('mergeperms', {'mergeperms.c'})) diff --git a/pkg/skeleton/mergeperms.c b/pkg/skeleton/mergeperms.c new file mode 100644 index 00000000..94ba7e3d --- /dev/null +++ b/pkg/skeleton/mergeperms.c @@ -0,0 +1,164 @@ +#define _POSIX_C_SOURCE 200809L +#include +#include +#include +#include +#include +#include +#include +#include + +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; +} 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#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 -#include -#include -#include -#include -#include -#include -#include - -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; -} -- cgit v1.2.3