1 /* $NetBSD: compare.c,v 1.11 1996/09/05 09:56:48 mycroft Exp $ */ 2 /* $OpenBSD: compare.c,v 1.25 2015/12/21 19:37:21 mmcc Exp $ */ 3 4 /*- 5 * Copyright (c) 1989, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 #include <sys/stat.h> 34 #include <fcntl.h> 35 #include <fts.h> 36 #include <errno.h> 37 #include <stdio.h> 38 #include <time.h> 39 #include <unistd.h> 40 #include <limits.h> 41 #include <md5.h> 42 #include <rmd160.h> 43 #include <sha1.h> 44 #include <sha2.h> 45 #include "mtree.h" 46 #include "extern.h" 47 48 extern int lflag, tflag, uflag; 49 50 static char *ftype(u_int); 51 52 #define INDENTNAMELEN 8 53 #define LABEL \ 54 if (!label++) { \ 55 len = printf("%s: ", RP(p)); \ 56 if (len > INDENTNAMELEN) { \ 57 tab = "\t"; \ 58 (void)printf("\n"); \ 59 } else { \ 60 tab = ""; \ 61 (void)printf("%*s", INDENTNAMELEN - (int)len, ""); \ 62 } \ 63 } 64 65 #define REPLACE_COMMA(x) \ 66 do { \ 67 char *l; \ 68 for (l = x; *l; l++) { \ 69 if (*l == ',') \ 70 *l = ' '; \ 71 } \ 72 } while (0) \ 73 74 int 75 compare(char *name, NODE *s, FTSENT *p) 76 { 77 u_int32_t len, val; 78 int fd, label; 79 char *cp, *tab = ""; 80 81 label = 0; 82 switch(s->type) { 83 case F_BLOCK: 84 if (!S_ISBLK(p->fts_statp->st_mode)) 85 goto typeerr; 86 break; 87 case F_CHAR: 88 if (!S_ISCHR(p->fts_statp->st_mode)) 89 goto typeerr; 90 break; 91 case F_DIR: 92 if (!S_ISDIR(p->fts_statp->st_mode)) 93 goto typeerr; 94 break; 95 case F_FIFO: 96 if (!S_ISFIFO(p->fts_statp->st_mode)) 97 goto typeerr; 98 break; 99 case F_FILE: 100 if (!S_ISREG(p->fts_statp->st_mode)) 101 goto typeerr; 102 break; 103 case F_LINK: 104 if (!S_ISLNK(p->fts_statp->st_mode)) 105 goto typeerr; 106 break; 107 case F_SOCK: 108 if (!S_ISSOCK(p->fts_statp->st_mode)) { 109 typeerr: LABEL; 110 (void)printf("\ttype (%s, %s)\n", 111 ftype(s->type), inotype(p->fts_statp->st_mode)); 112 } 113 break; 114 } 115 /* Set the uid/gid first, then set the mode. */ 116 if (s->flags & (F_UID | F_UNAME) && s->st_uid != p->fts_statp->st_uid) { 117 LABEL; 118 (void)printf("%suser (%u, %u", 119 tab, s->st_uid, p->fts_statp->st_uid); 120 if (uflag) 121 if (chown(p->fts_accpath, s->st_uid, -1)) 122 (void)printf(", not modified: %s)\n", 123 strerror(errno)); 124 else 125 (void)printf(", modified)\n"); 126 else 127 (void)printf(")\n"); 128 tab = "\t"; 129 } 130 if (s->flags & (F_GID | F_GNAME) && s->st_gid != p->fts_statp->st_gid) { 131 LABEL; 132 (void)printf("%sgid (%u, %u", 133 tab, s->st_gid, p->fts_statp->st_gid); 134 if (uflag) 135 if (chown(p->fts_accpath, -1, s->st_gid)) 136 (void)printf(", not modified: %s)\n", 137 strerror(errno)); 138 else 139 (void)printf(", modified)\n"); 140 else 141 (void)printf(")\n"); 142 tab = "\t"; 143 } 144 if (s->flags & F_MODE && 145 s->st_mode != (p->fts_statp->st_mode & MBITS)) { 146 if (lflag) { 147 mode_t tmode, mode; 148 149 tmode = s->st_mode; 150 mode = p->fts_statp->st_mode & MBITS; 151 /* 152 * if none of the suid/sgid/etc bits are set, 153 * then if the mode is a subset of the target, 154 * skip. 155 */ 156 if (!((tmode & ~(S_IRWXU|S_IRWXG|S_IRWXO)) || 157 (mode & ~(S_IRWXU|S_IRWXG|S_IRWXO)))) 158 if ((mode | tmode) == tmode) 159 goto skip; 160 } 161 LABEL; 162 (void)printf("%spermissions (%#o, %#o", 163 tab, s->st_mode, p->fts_statp->st_mode & MBITS); 164 if (uflag) 165 if (chmod(p->fts_accpath, s->st_mode)) 166 (void)printf(", not modified: %s)\n", 167 strerror(errno)); 168 else 169 (void)printf(", modified)\n"); 170 else 171 (void)printf(")\n"); 172 tab = "\t"; 173 skip: 174 ; 175 } 176 if (s->flags & F_NLINK && s->type != F_DIR && 177 s->st_nlink != p->fts_statp->st_nlink) { 178 LABEL; 179 (void)printf("%slink count (%u, %u)\n", 180 tab, s->st_nlink, p->fts_statp->st_nlink); 181 tab = "\t"; 182 } 183 if (s->flags & F_SIZE && s->st_size != p->fts_statp->st_size) { 184 LABEL; 185 (void)printf("%ssize (%qd, %qd)\n", 186 tab, s->st_size, p->fts_statp->st_size); 187 tab = "\t"; 188 } 189 /* 190 * XXX 191 * Since utimes(2) only takes a timeval, there's no point in 192 * comparing the low bits of the timespec nanosecond field. This 193 * will only result in mismatches that we can never fix. 194 * 195 * Doesn't display microsecond differences. 196 */ 197 if (s->flags & F_TIME) { 198 struct timeval tv[2]; 199 200 TIMESPEC_TO_TIMEVAL(&tv[0], &s->st_mtimespec); 201 TIMESPEC_TO_TIMEVAL(&tv[1], &p->fts_statp->st_mtimespec); 202 if (tv[0].tv_sec != tv[1].tv_sec || 203 tv[0].tv_usec != tv[1].tv_usec) { 204 LABEL; 205 (void)printf("%smodification time (%.24s, ", 206 tab, ctime(&s->st_mtimespec.tv_sec)); 207 (void)printf("%.24s", 208 ctime(&p->fts_statp->st_mtimespec.tv_sec)); 209 if (tflag) { 210 tv[1] = tv[0]; 211 if (utimes(p->fts_accpath, tv)) 212 (void)printf(", not modified: %s)\n", 213 strerror(errno)); 214 else 215 (void)printf(", modified)\n"); 216 } else 217 (void)printf(")\n"); 218 tab = "\t"; 219 } 220 } 221 if (s->flags & F_CKSUM) { 222 if ((fd = open(p->fts_accpath, MTREE_O_FLAGS, 0)) < 0) { 223 LABEL; 224 (void)printf("%scksum: %s: %s\n", 225 tab, p->fts_accpath, strerror(errno)); 226 tab = "\t"; 227 } else if (crc(fd, &val, &len)) { 228 (void)close(fd); 229 LABEL; 230 (void)printf("%scksum: %s: %s\n", 231 tab, p->fts_accpath, strerror(errno)); 232 tab = "\t"; 233 } else { 234 (void)close(fd); 235 if (s->cksum != val) { 236 LABEL; 237 (void)printf("%scksum (%u, %u)\n", 238 tab, s->cksum, val); 239 } 240 tab = "\t"; 241 } 242 } 243 if (s->flags & F_MD5) { 244 char *new_digest, buf[MD5_DIGEST_STRING_LENGTH]; 245 246 new_digest = MD5File(p->fts_accpath, buf); 247 if (!new_digest) { 248 LABEL; 249 printf("%sMD5File: %s: %s\n", tab, p->fts_accpath, 250 strerror(errno)); 251 tab = "\t"; 252 } else if (strcmp(new_digest, s->md5digest)) { 253 LABEL; 254 printf("%sMD5 (%s, %s)\n", tab, s->md5digest, 255 new_digest); 256 tab = "\t"; 257 } 258 } 259 if (s->flags & F_RMD160) { 260 char *new_digest, buf[RMD160_DIGEST_STRING_LENGTH]; 261 262 new_digest = RMD160File(p->fts_accpath, buf); 263 if (!new_digest) { 264 LABEL; 265 printf("%sRMD160File: %s: %s\n", tab, p->fts_accpath, 266 strerror(errno)); 267 tab = "\t"; 268 } else if (strcmp(new_digest, s->rmd160digest)) { 269 LABEL; 270 printf("%sRMD160 (%s, %s)\n", tab, s->rmd160digest, 271 new_digest); 272 tab = "\t"; 273 } 274 } 275 if (s->flags & F_SHA1) { 276 char *new_digest, buf[SHA1_DIGEST_STRING_LENGTH]; 277 278 new_digest = SHA1File(p->fts_accpath, buf); 279 if (!new_digest) { 280 LABEL; 281 printf("%sSHA1File: %s: %s\n", tab, p->fts_accpath, 282 strerror(errno)); 283 tab = "\t"; 284 } else if (strcmp(new_digest, s->sha1digest)) { 285 LABEL; 286 printf("%sSHA1 (%s, %s)\n", tab, s->sha1digest, 287 new_digest); 288 tab = "\t"; 289 } 290 } 291 if (s->flags & F_SHA256) { 292 char *new_digest, buf[SHA256_DIGEST_STRING_LENGTH]; 293 294 new_digest = SHA256File(p->fts_accpath, buf); 295 if (!new_digest) { 296 LABEL; 297 printf("%sSHA256File: %s: %s\n", tab, p->fts_accpath, 298 strerror(errno)); 299 tab = "\t"; 300 } else if (strcmp(new_digest, s->sha256digest)) { 301 LABEL; 302 printf("%sSHA256 (%s, %s)\n", tab, s->sha256digest, 303 new_digest); 304 tab = "\t"; 305 } 306 } 307 if (s->flags & F_SLINK && strcmp(cp = rlink(name), s->slink)) { 308 LABEL; 309 (void)printf("%slink ref (%s, %s)\n", tab, cp, s->slink); 310 } 311 if (s->flags & F_FLAGS && s->file_flags != p->fts_statp->st_flags) { 312 char *db_flags = NULL; 313 char *cur_flags = NULL; 314 315 if ((db_flags = fflagstostr(s->file_flags)) == NULL || 316 (cur_flags = fflagstostr(p->fts_statp->st_flags)) == NULL) { 317 LABEL; 318 (void)printf("%sflags: %s %s\n", tab, p->fts_accpath, 319 strerror(errno)); 320 tab = "\t"; 321 free(db_flags); 322 free(cur_flags); 323 } else { 324 LABEL; 325 REPLACE_COMMA(db_flags); 326 REPLACE_COMMA(cur_flags); 327 printf("%sflags (%s, %s", tab, (*db_flags == '\0') ? 328 "-" : db_flags, 329 (*cur_flags == '\0') ? 330 "-" : cur_flags); 331 tab = "\t"; 332 if (uflag) 333 if (chflags(p->fts_accpath, s->file_flags)) 334 (void)printf(", not modified: %s)\n", 335 strerror(errno)); 336 else 337 (void)printf(", modified)\n"); 338 else 339 (void)printf(")\n"); 340 tab = "\t"; 341 342 free(db_flags); 343 free(cur_flags); 344 } 345 } 346 return (label); 347 } 348 349 char * 350 inotype(u_int type) 351 { 352 switch(type & S_IFMT) { 353 case S_IFBLK: 354 return ("block"); 355 case S_IFCHR: 356 return ("char"); 357 case S_IFDIR: 358 return ("dir"); 359 case S_IFIFO: 360 return ("fifo"); 361 case S_IFREG: 362 return ("file"); 363 case S_IFLNK: 364 return ("link"); 365 case S_IFSOCK: 366 return ("socket"); 367 default: 368 return ("unknown"); 369 } 370 /* NOTREACHED */ 371 } 372 373 static char * 374 ftype(u_int type) 375 { 376 switch(type) { 377 case F_BLOCK: 378 return ("block"); 379 case F_CHAR: 380 return ("char"); 381 case F_DIR: 382 return ("dir"); 383 case F_FIFO: 384 return ("fifo"); 385 case F_FILE: 386 return ("file"); 387 case F_LINK: 388 return ("link"); 389 case F_SOCK: 390 return ("socket"); 391 default: 392 return ("unknown"); 393 } 394 /* NOTREACHED */ 395 } 396 397 char * 398 rlink(char *name) 399 { 400 static char lbuf[PATH_MAX]; 401 int len; 402 403 if ((len = readlink(name, lbuf, sizeof(lbuf)-1)) == -1) 404 error("%s: %s", name, strerror(errno)); 405 lbuf[len] = '\0'; 406 return (lbuf); 407 } 408