logo

oasis

Own branch of Oasis Linux (upstream: <https://git.sr.ht/~mcf/oasis/>) git clone https://anongit.hacktivis.me/git/oasis.git

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