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