opkg

statically linked package installer
git clone anongit@rnpnr.xyz:opkg.git
Log | Files | Refs | Feed | Submodules | README | LICENSE

mergeperms.c (3164B)


      1 #define _POSIX_C_SOURCE 200809L
      2 #include <errno.h>
      3 #include <stdarg.h>
      4 #include <stdint.h>
      5 #include <stdio.h>
      6 #include <stdlib.h>
      7 #include <stdnoreturn.h>
      8 #include <string.h>
      9 #include <sys/stat.h>
     10 
     11 struct perm {
     12 	char *name;
     13 	mode_t mode;
     14 };
     15 
     16 static struct perm *perms;
     17 static size_t permslen, permscap;
     18 
     19 static noreturn void
     20 fatal(const char *fmt, ...)
     21 {
     22 	va_list ap;
     23 
     24 	va_start(ap, fmt);
     25 	vfprintf(stderr, fmt, ap);
     26 	va_end(ap);
     27 	if (fmt[0] && fmt[strlen(fmt) - 1] == ':') {
     28 		fputc(' ', stderr);
     29 		perror(NULL);
     30 	} else {
     31 		fputc('\n', stderr);
     32 	}
     33 	exit(1);
     34 }
     35 
     36 static void
     37 addperm(struct perm *p)
     38 {
     39 	if (permslen == permscap) {
     40 		permscap = permscap ? permscap * 2 : 64;
     41 		if (permscap > SIZE_MAX / sizeof(perms[0])) {
     42 			errno = ENOMEM;
     43 			fatal("realloc:");
     44 		}
     45 		perms = realloc(perms, permscap * sizeof(perms[0]));
     46 		if (!perms)
     47 			fatal("realloc:");
     48 	}
     49 	perms[permslen++] = *p;
     50 }
     51 
     52 static void
     53 readperm(FILE *file, struct perm *perm)
     54 {
     55 	static char *line;
     56 	static size_t size;
     57 	ssize_t n;
     58 	char *s, *mode;
     59 
     60 	n = getline(&line, &size, file);
     61 	if (n < 0) {
     62 		if (ferror(file))
     63 			fatal("getline:");
     64 		perm->name = NULL;
     65 		return;
     66 	}
     67 	if (n && line[n - 1] == '\n')
     68 		line[n - 1] = '\0';
     69 	mode = s = line;
     70 	s = strchr(s, ' ');
     71 	if (!s || s == mode)
     72 		fatal("invalid permissions file");
     73 	*s++ = '\0';
     74 	perm->name = strdup(s);
     75 	if (!perm->name)
     76 		fatal("strdup:");
     77 	perm->mode = strtoul(mode, &s, 8);
     78 	if (*s)
     79 		fatal("invalid mode '%s'", mode);
     80 }
     81 
     82 static int
     83 permcmp(struct perm *a, struct perm *b)
     84 {
     85 	return a->name ? b->name ? strcmp(a->name, b->name) : -1 : !!b->name;
     86 }
     87 
     88 static noreturn void
     89 usage(void)
     90 {
     91 	fprintf(stderr, "usage: mergeperms old cur new\n");
     92 	exit(2);
     93 }
     94 
     95 int
     96 main(int argc, char *argv[])
     97 {
     98 	FILE *oldf, *curf, *newf;
     99 	struct perm old, cur, new;
    100 	int ij, ik, jk;
    101 	int ret;
    102 
    103 	if (argc != 4)
    104 		usage();
    105 
    106 	ret = 0;
    107 	oldf = fopen(argv[1], "r");
    108 	if (!oldf)
    109 		fatal("open %s:", argv[1]);
    110 	curf = fopen(argv[2], "r");
    111 	if (!curf)
    112 		fatal("open %s:", argv[2]);
    113 	newf = fopen(argv[3], "r");
    114 	if (!newf)
    115 		fatal("open %s:", argv[3]);
    116 
    117 	readperm(oldf, &old);
    118 	readperm(curf, &cur);
    119 	readperm(newf, &new);
    120 	for (;;) {
    121 		ij = permcmp(&old, &cur);
    122 		ik = permcmp(&old, &new);
    123 		if (ij < 0 && ik < 0 && old.name) {
    124 			readperm(oldf, &old);
    125 			continue;
    126 		}
    127 		if (!old.name && !cur.name && !new.name)
    128 			break;
    129 		jk = permcmp(&cur, &new);
    130 		if ((jk < 0 && ij == 0 && old.mode == cur.mode) || (jk > 0 && ik == 0 && old.mode == new.mode)) {
    131 			/* deleted in cur or new and unchanged in the other */
    132 		} else if (jk < 0) {
    133 			if (ij == 0)
    134 				ret = 3;
    135 			addperm(&cur);
    136 		} else if (jk > 0) {
    137 			if (ik == 0)
    138 				ret = 3;
    139 			addperm(&new);
    140 		} else if (ij == 0 && old.mode == cur.mode) {
    141 			addperm(&new);
    142 		} else {
    143 			if (cur.mode != new.mode && (ik != 0 || old.mode != new.mode))
    144 				ret = 3;
    145 			addperm(&cur);
    146 		}
    147 		if (jk <= 0)
    148 			readperm(curf, &cur);
    149 		if (jk >= 0)
    150 			readperm(newf, &new);
    151 	}
    152 
    153 	fclose(curf);
    154 	curf = fopen(argv[2], "w");
    155 	if (!curf)
    156 		fatal("open %s:", argv[1]);
    157 	for (; permslen > 0; --permslen, ++perms)
    158 		fprintf(curf, "%#o %s\n", perms->mode, perms->name);
    159 	fflush(curf);
    160 	if (ferror(curf))
    161 		fatal("write error");
    162 
    163 	return ret;
    164 }