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 #if HAVE_NBTOOL_CONFIG_H 30 #include "nbtool_config.h" 31 #endif 32 33 #include <err.h> 34 #include <grp.h> 35 #include <pwd.h> 36 #include <time.h> 37 #include <stdio.h> 38 #include <stdint.h> 39 #include <stdlib.h> 40 #include <string.h> 41 #include <unistd.h> 42 #include "mtree.h" 43 #include "extern.h" 44 45 #define FF(a, b, c, d) \ 46 (((a)->flags & (c)) && ((b)->flags & (c)) && ((a)->d) != ((b)->d)) 47 #define FS(a, b, c, d) \ 48 (((a)->flags & (c)) && ((b)->flags & (c)) && strcmp((a)->d,(b)->d)) 49 #define FM(a, b, c, d) \ 50 (((a)->flags & (c)) && ((b)->flags & (c)) && memcmp(&(a)->d,&(b)->d, sizeof (a)->d)) 51 52 static void 53 shownode(NODE *n, int f, char const *path) 54 { 55 struct group *gr; 56 struct passwd *pw; 57 58 printf("%s%s %s", path, n->name, inotype(nodetoino(n->type))); 59 if (f & F_CKSUM) 60 printf(" cksum=%lu", n->cksum); 61 if (f & F_GID) 62 printf(" gid=%d", n->st_gid); 63 if (f & F_GNAME) { 64 gr = getgrgid(n->st_gid); 65 if (gr == NULL) 66 printf(" gid=%d", n->st_gid); 67 else 68 printf(" gname=%s", gr->gr_name); 69 } 70 if (f & F_MODE) 71 printf(" mode=%o", n->st_mode); 72 if (f & F_NLINK) 73 printf(" nlink=%ju", (uintmax_t)n->st_nlink); 74 if (f & F_SIZE) 75 printf(" size=%jd", (intmax_t)n->st_size); 76 if (f & F_UID) 77 printf(" uid=%d", n->st_uid); 78 if (f & F_UNAME) { 79 pw = getpwuid(n->st_uid); 80 if (pw == NULL) 81 printf(" uid=%d", n->st_uid); 82 else 83 printf(" uname=%s", pw->pw_name); 84 } 85 if (f & F_MD5) 86 printf(" %s=%s", MD5KEY, n->md5digest); 87 if (f & F_SHA1) 88 printf(" %s=%s", SHA1KEY, n->sha1digest); 89 if (f & F_RMD160) 90 printf(" %s=%s", RMD160KEY, n->rmd160digest); 91 if (f & F_SHA256) 92 printf(" %s=%s", SHA256KEY, n->sha256digest); 93 if (f & F_SHA384) 94 printf(" %s=%s", SHA384KEY, n->sha384digest); 95 if (f & F_SHA512) 96 printf(" %s=%s", SHA512KEY, n->sha512digest); 97 if (f & F_FLAGS) 98 printf(" flags=%s", flags_to_string(n->st_flags, "none")); 99 printf("\n"); 100 } 101 102 static int 103 mismatch(NODE *n1, NODE *n2, int differ, char const *path) 104 { 105 106 if (n2 == NULL) { 107 shownode(n1, differ, path); 108 return (1); 109 } 110 if (n1 == NULL) { 111 printf("\t"); 112 shownode(n2, differ, path); 113 return (1); 114 } 115 if (!(differ & keys)) 116 return(0); 117 printf("\t\t"); 118 shownode(n1, differ, path); 119 printf("\t\t"); 120 shownode(n2, differ, path); 121 return (1); 122 } 123 124 static int 125 compare_nodes(NODE *n1, NODE *n2, char const *path) 126 { 127 int differs; 128 129 if (n1 != NULL && n1->type == F_LINK) 130 n1->flags &= ~F_MODE; 131 if (n2 != NULL && n2->type == F_LINK) 132 n2->flags &= ~F_MODE; 133 differs = 0; 134 if (n1 == NULL && n2 != NULL) { 135 differs = n2->flags; 136 mismatch(n1, n2, differs, path); 137 return (1); 138 } 139 if (n1 != NULL && n2 == NULL) { 140 differs = n1->flags; 141 mismatch(n1, n2, differs, path); 142 return (1); 143 } 144 if (n1->type != n2->type) { 145 differs = 0; 146 mismatch(n1, n2, differs, path); 147 return (1); 148 } 149 if (FF(n1, n2, F_CKSUM, cksum)) 150 differs |= F_CKSUM; 151 if (FF(n1, n2, F_GID, st_gid)) 152 differs |= F_GID; 153 if (FF(n1, n2, F_GNAME, st_gid)) 154 differs |= F_GNAME; 155 if (FF(n1, n2, F_MODE, st_mode)) 156 differs |= F_MODE; 157 if (FF(n1, n2, F_NLINK, st_nlink)) 158 differs |= F_NLINK; 159 if (FF(n1, n2, F_SIZE, st_size)) 160 differs |= F_SIZE; 161 if (FS(n1, n2, F_SLINK, slink)) 162 differs |= F_SLINK; 163 if (FM(n1, n2, F_TIME, st_mtimespec)) 164 differs |= F_TIME; 165 if (FF(n1, n2, F_UID, st_uid)) 166 differs |= F_UID; 167 if (FF(n1, n2, F_UNAME, st_uid)) 168 differs |= F_UNAME; 169 if (FS(n1, n2, F_MD5, md5digest)) 170 differs |= F_MD5; 171 if (FS(n1, n2, F_SHA1, sha1digest)) 172 differs |= F_SHA1; 173 if (FS(n1, n2, F_RMD160, rmd160digest)) 174 differs |= F_RMD160; 175 if (FS(n1, n2, F_SHA256, sha256digest)) 176 differs |= F_SHA256; 177 if (FS(n1, n2, F_SHA384, sha384digest)) 178 differs |= F_SHA384; 179 if (FS(n1, n2, F_SHA512, sha512digest)) 180 differs |= F_SHA512; 181 if (FF(n1, n2, F_FLAGS, st_flags)) 182 differs |= F_FLAGS; 183 if (differs) { 184 mismatch(n1, n2, differs, path); 185 return (1); 186 } 187 return (0); 188 } 189 static int 190 walk_in_the_forest(NODE *t1, NODE *t2, char const *path) 191 { 192 int r, i; 193 NODE *c1, *c2, *n1, *n2; 194 char *np; 195 196 r = 0; 197 198 if (t1 != NULL) 199 c1 = t1->child; 200 else 201 c1 = NULL; 202 if (t2 != NULL) 203 c2 = t2->child; 204 else 205 c2 = NULL; 206 while (c1 != NULL || c2 != NULL) { 207 n1 = n2 = NULL; 208 if (c1 != NULL) 209 n1 = c1->next; 210 if (c2 != NULL) 211 n2 = c2->next; 212 if (c1 != NULL && c2 != NULL) { 213 if (c1->type != F_DIR && c2->type == F_DIR) { 214 n2 = c2; 215 c2 = NULL; 216 } else if (c1->type == F_DIR && c2->type != F_DIR) { 217 n1 = c1; 218 c1 = NULL; 219 } else { 220 i = strcmp(c1->name, c2->name); 221 if (i > 0) { 222 n1 = c1; 223 c1 = NULL; 224 } else if (i < 0) { 225 n2 = c2; 226 c2 = NULL; 227 } 228 } 229 } 230 if (c1 == NULL && c2->type == F_DIR) { 231 asprintf(&np, "%s%s/", path, c2->name); 232 i = walk_in_the_forest(c1, c2, np); 233 free(np); 234 i += compare_nodes(c1, c2, path); 235 } else if (c2 == NULL && c1->type == F_DIR) { 236 asprintf(&np, "%s%s/", path, c1->name); 237 i = walk_in_the_forest(c1, c2, np); 238 free(np); 239 i += compare_nodes(c1, c2, path); 240 } else if (c1 == NULL || c2 == NULL) { 241 i = compare_nodes(c1, c2, path); 242 } else if (c1->type == F_DIR && c2->type == F_DIR) { 243 asprintf(&np, "%s%s/", path, c1->name); 244 i = walk_in_the_forest(c1, c2, np); 245 free(np); 246 i += compare_nodes(c1, c2, path); 247 } else { 248 i = compare_nodes(c1, c2, path); 249 } 250 r += i; 251 c1 = n1; 252 c2 = n2; 253 } 254 return (r); 255 } 256 257 int 258 mtree_specspec(FILE *fi, FILE *fj) 259 { 260 int rval; 261 NODE *root1, *root2; 262 263 root1 = spec(fi); 264 root2 = spec(fj); 265 rval = walk_in_the_forest(root1, root2, ""); 266 rval += compare_nodes(root1, root2, ""); 267 if (rval > 0) 268 return (MISMATCHEXIT); 269 return (0); 270 } 271