mirror of
https://github.com/oasislinux/oasis.git
synced 2026-10-12 14:59:19 +02:00
165 lines
3.1 KiB
C
165 lines
3.1 KiB
C
#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;
|
|
}
|