1 /* $NetBSD: specspec.c,v 1.4 2017/12/14 18:34:41 christos Exp $ */ 2 3 /*- 4 * Copyright (c) 2003 Poul-Henning Kamp 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <err.h> 30 #include <grp.h> 31 #include <pwd.h> 32 #include <time.h> 33 #include <stdio.h> 34 #include <stdint.h> 35 #include <stdlib.h> 36 #include <string.h> 37 #include <unistd.h> 38 #include "mtree.h" 39 #include "extern.h" 40 41 #define FF(a, b, c, d) \ 42 (((a)->flags & (c)) && ((b)->flags & (c)) && ((a)->d) != ((b)->d)) 43 #define FS(a, b, c, d) \ 44 (((a)->flags & (c)) && ((b)->flags & (c)) && strcmp((a)->d,(b)->d)) 45 #define FM(a, b, c, d) \ 46 (((a)->flags & (c)) && ((b)->flags & (c)) && memcmp(&(a)->d,&(b)->d, sizeof (a)->d)) 47 48 static void 49 shownode(NODE *n, int f, char const *path) 50 { 51 struct group *gr; 52 struct passwd *pw; 53 54 printf("%s%s %s", path, n->name, inotype(nodetoino(n->type))); 55 if (f & F_CKSUM) 56 printf(" cksum=%lu", n->cksum); 57 if (f & F_GID) 58 printf(" gid=%d", n->st_gid); 59 if (f & F_GNAME) { 60 gr = getgrgid(n->st_gid); 61 if (gr == NULL) 62 printf(" gid=%d", n->st_gid); 63 else 64 printf(" gname=%s", gr->gr_name); 65 } 66 if (f & F_MODE) 67 printf(" mode=%o", n->st_mode); 68 if (f & F_NLINK) 69 printf(" nlink=%ju", (uintmax_t)n->st_nlink); 70 if (f & F_SIZE) 71 printf(" size=%jd", (intmax_t)n->st_size); 72 if (f & F_UID) 73 printf(" uid=%d", n->st_uid); 74 if (f & F_UNAME) { 75 pw = getpwuid(n->st_uid); 76 if (pw == NULL) 77 printf(" uid=%d", n->st_uid); 78 else 79 printf(" uname=%s", pw->pw_name); 80 } 81 if (f & F_MD5) 82 printf(" %s=%s", MD5KEY, n->md5digest); 83 if (f & F_SHA1) 84 printf(" %s=%s", SHA1KEY, n->sha1digest); 85 if (f & F_RMD160) 86 printf(" %s=%s", RMD160KEY, n->rmd160digest); 87 if (f & F_SHA256) 88 printf(" %s=%s", SHA256KEY, n->sha256digest); 89 if (f & F_SHA384) 90 printf(" %s=%s", SHA384KEY, n->sha384digest); 91 if (f & F_SHA512) 92 printf(" %s=%s", SHA512KEY, n->sha512digest); 93 if (f & F_FLAGS) 94 printf(" flags=%s", flags_to_string(n->st_flags, "none")); 95 printf("\n"); 96 } 97 98 static int 99 mismatch(NODE *n1, NODE *n2, int differ, char const *path) 100 { 101 102 if (n2 == NULL) { 103 shownode(n1, differ, path); 104 return (1); 105 } 106 if (n1 == NULL) { 107 printf("\t"); 108 shownode(n2, differ, path); 109 return (1); 110 } 111 if (!(differ & keys)) 112 return(0); 113 printf("\t\t"); 114 shownode(n1, differ, path); 115 printf("\t\t"); 116 shownode(n2, differ, path); 117 return (1); 118 } 119 120 static int 121 compare_nodes(NODE *n1, NODE *n2, char const *path) 122 { 123 int differs; 124 125 if (n1 != NULL && n1->type == F_LINK) 126 n1->flags &= ~F_MODE; 127 if (n2 != NULL && n2->type == F_LINK) 128 n2->flags &= ~F_MODE; 129 differs = 0; 130 if (n1 == NULL && n2 != NULL) { 131 differs = n2->flags; 132 mismatch(n1, n2, differs, path); 133 return (1); 134 } 135 if (n1 != NULL && n2 == NULL) { 136 differs = n1->flags; 137 mismatch(n1, n2, differs, path); 138 return (1); 139 } 140 if (n1->type != n2->type) { 141 differs = 0; 142 mismatch(n1, n2, differs, path); 143 return (1); 144 } 145 if (FF(n1, n2, F_CKSUM, cksum)) 146 differs |= F_CKSUM; 147 if (FF(n1, n2, F_GID, st_gid)) 148 differs |= F_GID; 149 if (FF(n1, n2, F_GNAME, st_gid)) 150 differs |= F_GNAME; 151 if (FF(n1, n2, F_MODE, st_mode)) 152 differs |= F_MODE; 153 if (FF(n1, n2, F_NLINK, st_nlink)) 154 differs |= F_NLINK; 155 if (FF(n1, n2, F_SIZE, st_size)) 156 differs |= F_SIZE; 157 if (FS(n1, n2, F_SLINK, slink)) 158 differs |= F_SLINK; 159 if (FM(n1, n2, F_TIME, st_mtimespec)) 160 differs |= F_TIME; 161 if (FF(n1, n2, F_UID, st_uid)) 162 differs |= F_UID; 163 if (FF(n1, n2, F_UNAME, st_uid)) 164 differs |= F_UNAME; 165 if (FS(n1, n2, F_MD5, md5digest)) 166 differs |= F_MD5; 167 if (FS(n1, n2, F_SHA1, sha1digest)) 168 differs |= F_SHA1; 169 if (FS(n1, n2, F_RMD160, rmd160digest)) 170 differs |= F_RMD160; 171 if (FS(n1, n2, F_SHA256, sha256digest)) 172 differs |= F_SHA256; 173 if (FS(n1, n2, F_SHA384, sha384digest)) 174 differs |= F_SHA384; 175 if (FS(n1, n2, F_SHA512, sha512digest)) 176 differs |= F_SHA512; 177 if (FF(n1, n2, F_FLAGS, st_flags)) 178 differs |= F_FLAGS; 179 if (differs) { 180 mismatch(n1, n2, differs, path); 181 return (1); 182 } 183 return (0); 184 } 185 static int 186 walk_in_the_forest(NODE *t1, NODE *t2, char const *path) 187 { 188 int r, i; 189 NODE *c1, *c2, *n1, *n2; 190 char *np; 191 192 r = 0; 193 194 if (t1 != NULL) 195 c1 = t1->child; 196 else 197 c1 = NULL; 198 if (t2 != NULL) 199 c2 = t2->child; 200 else 201 c2 = NULL; 202 while (c1 != NULL || c2 != NULL) { 203 n1 = n2 = NULL; 204 if (c1 != NULL) 205 n1 = c1->next; 206 if (c2 != NULL) 207 n2 = c2->next; 208 if (c1 != NULL && c2 != NULL) { 209 if (c1->type != F_DIR && c2->type == F_DIR) { 210 n2 = c2; 211 c2 = NULL; 212 } else if (c1->type == F_DIR && c2->type != F_DIR) { 213 n1 = c1; 214 c1 = NULL; 215 } else { 216 i = strcmp(c1->name, c2->name); 217 if (i > 0) { 218 n1 = c1; 219 c1 = NULL; 220 } else if (i < 0) { 221 n2 = c2; 222 c2 = NULL; 223 } 224 } 225 } 226 if (c1 == NULL && c2->type == F_DIR) { 227 asprintf(&np, "%s%s/", path, c2->name); 228 i = walk_in_the_forest(c1, c2, np); 229 free(np); 230 i += compare_nodes(c1, c2, path); 231 } else if (c2 == NULL && c1->type == F_DIR) { 232 asprintf(&np, "%s%s/", path, c1->name); 233 i = walk_in_the_forest(c1, c2, np); 234 free(np); 235 i += compare_nodes(c1, c2, path); 236 } else if (c1 == NULL || c2 == NULL) { 237 i = compare_nodes(c1, c2, path); 238 } else if (c1->type == F_DIR && c2->type == F_DIR) { 239 asprintf(&np, "%s%s/", path, c1->name); 240 i = walk_in_the_forest(c1, c2, np); 241 free(np); 242 i += compare_nodes(c1, c2, path); 243 } else { 244 i = compare_nodes(c1, c2, path); 245 } 246 r += i; 247 c1 = n1; 248 c2 = n2; 249 } 250 return (r); 251 } 252 253 int 254 mtree_specspec(FILE *fi, FILE *fj) 255 { 256 int rval; 257 NODE *root1, *root2; 258 259 root1 = spec(fi); 260 root2 = spec(fj); 261 rval = walk_in_the_forest(root1, root2, ""); 262 rval += compare_nodes(root1, root2, ""); 263 if (rval > 0) 264 return (MISMATCHEXIT); 265 return (0); 266 } 267