commit: 72d22dfc73e342d0754fcfb6ce5b13c80edffecb
parent abaacce6fa9ab134e8f7bcaa0abc71c0f44882d8
Author: Michael Forney <mforney@mforney.org>
Date: Wed, 19 Jun 2019 09:55:12 -0700
Add merge driver for .perms
Diffstat:
3 files changed, 168 insertions(+), 0 deletions(-)
diff --git a/src/gen.lua b/src/gen.lua
@@ -5,5 +5,6 @@ cflags{
}
file('libexec/applyperms', '755', exe('applyperms', {'applyperms.c'}))
+file('libexec/mergeperms', '755', exe('mergeperms', {'mergeperms.c'}))
file('libexec/shutdown', '755', exe('shutdown', {'shutdown.c'}))
file('bin/syslogd', '755', exe('syslogd', {'syslogd.c'}))
diff --git a/src/mergeperms.c b/src/mergeperms.c
@@ -0,0 +1,164 @@
+#define _POSIX_C_SOURCE 200112L
+#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;
+}
diff --git a/template/config b/template/config
@@ -3,3 +3,6 @@
sparseCheckout = true
[oasis]
root = .
+[merge "perms"]
+ name = .perms merge driver
+ driver = ./libexec/mergeperms %O %A %B