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