1 /* $NetBSD: compare.c,v 1.11 1996/09/05 09:56:48 mycroft Exp $ */ 2 /* $OpenBSD: compare.c,v 1.17 2003/06/02 23:36:54 millert 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 #ifndef lint 34 #if 0 35 static const char sccsid[] = "@(#)compare.c 8.1 (Berkeley) 6/6/93"; 36 #else 37 static const char rcsid[] = "$OpenBSD: compare.c,v 1.17 2003/06/02 23:36:54 millert Exp $"; 38 #endif 39 #endif /* not lint */ 40 41 #include <sys/param.h> 42 #include <sys/stat.h> 43 #include <fcntl.h> 44 #include <fts.h> 45 #include <errno.h> 46 #include <stdio.h> 47 #include <time.h> 48 #include <unistd.h> 49 #include <md5.h> 50 #include <sha1.h> 51 #include <rmd160.h> 52 #include "mtree.h" 53 #include "extern.h" 54 55 extern int lflag, tflag, uflag; 56 57 static char *ftype(u_int); 58 59 #define INDENTNAMELEN 8 60 #define LABEL \ 61 if (!label++) { \ 62 len = printf("%s: ", RP(p)); \ 63 if (len > INDENTNAMELEN) { \ 64 tab = "\t"; \ 65 (void)printf("\n"); \ 66 } else { \ 67 tab = ""; \ 68 (void)printf("%*s", INDENTNAMELEN - (int)len, ""); \ 69 } \ 70 } 71 72 #define REPLACE_COMMA(x) \ 73 do { \ 74 char *l; \ 75 for (l = x; *l; l++) { \ 76 if (*l == ',') \ 77 *l = ' '; \ 78 } \ 79 } while (0) \ 80 81 int 82 compare(name, s, p) 83 char *name; 84 NODE *s; 85 FTSENT *p; 86 { 87 u_int32_t len, val; 88 int fd, label; 89 char *cp, *tab = ""; 90 91 label = 0; 92 switch(s->type) { 93 case F_BLOCK: 94 if (!S_ISBLK(p->fts_statp->st_mode)) 95 goto typeerr; 96 break; 97 case F_CHAR: 98 if (!S_ISCHR(p->fts_statp->st_mode)) 99 goto typeerr; 100 break; 101 case F_DIR: 102 if (!S_ISDIR(p->fts_statp->st_mode)) 103 goto typeerr; 104 break; 105 case F_FIFO: 106 if (!S_ISFIFO(p->fts_statp->st_mode)) 107 goto typeerr; 108 break; 109 case F_FILE: 110 if (!S_ISREG(p->fts_statp->st_mode)) 111 goto typeerr; 112 break; 113 case F_LINK: 114 if (!S_ISLNK(p->fts_statp->st_mode)) 115 goto typeerr; 116 break; 117 case F_SOCK: 118 if (!S_ISSOCK(p->fts_statp->st_mode)) { 119 typeerr: LABEL; 120 (void)printf("\ttype (%s, %s)\n", 121 ftype(s->type), inotype(p->fts_statp->st_mode)); 122 } 123 break; 124 } 125 /* Set the uid/gid first, then set the mode. */ 126 if (s->flags & (F_UID | F_UNAME) && s->st_uid != p->fts_statp->st_uid) { 127 LABEL; 128 (void)printf("%suser (%u, %u", 129 tab, s->st_uid, p->fts_statp->st_uid); 130 if (uflag) 131 if (chown(p->fts_accpath, s->st_uid, -1)) 132 (void)printf(", not modified: %s)\n", 133 strerror(errno)); 134 else 135 (void)printf(", modified)\n"); 136 else 137 (void)printf(")\n"); 138 tab = "\t"; 139 } 140 if (s->flags & (F_GID | F_GNAME) && s->st_gid != p->fts_statp->st_gid) { 141 LABEL; 142 (void)printf("%sgid (%u, %u", 143 tab, s->st_gid, p->fts_statp->st_gid); 144 if (uflag) 145 if (chown(p->fts_accpath, -1, s->st_gid)) 146 (void)printf(", not modified: %s)\n", 147 strerror(errno)); 148 else 149 (void)printf(", modified)\n"); 150 else 151 (void)printf(")\n"); 152 tab = "\t"; 153 } 154 if (s->flags & F_MODE && 155 s->st_mode != (p->fts_statp->st_mode & MBITS)) { 156 if (lflag) { 157 mode_t tmode, mode; 158 159 tmode = s->st_mode; 160 mode = p->fts_statp->st_mode & MBITS; 161 /* 162 * if none of the suid/sgid/etc bits are set, 163 * then if the mode is a subset of the target, 164 * skip. 165 */ 166 if (!((tmode & ~(S_IRWXU|S_IRWXG|S_IRWXO)) || 167 (mode & ~(S_IRWXU|S_IRWXG|S_IRWXO)))) 168 if ((mode | tmode) == tmode) 169 goto skip; 170 } 171 LABEL; 172 (void)printf("%spermissions (%#o, %#o", 173 tab, s->st_mode, p->fts_statp->st_mode & MBITS); 174 if (uflag) 175 if (chmod(p->fts_accpath, s->st_mode)) 176 (void)printf(", not modified: %s)\n", 177 strerror(errno)); 178 else 179 (void)printf(", modified)\n"); 180 else 181 (void)printf(")\n"); 182 tab = "\t"; 183 skip: 184 ; 185 } 186 if (s->flags & F_NLINK && s->type != F_DIR && 187 s->st_nlink != p->fts_statp->st_nlink) { 188 LABEL; 189 (void)printf("%slink count (%u, %u)\n", 190 tab, s->st_nlink, p->fts_statp->st_nlink); 191 tab = "\t"; 192 } 193 if (s->flags & F_SIZE && s->st_size != p->fts_statp->st_size) { 194 LABEL; 195 (void)printf("%ssize (%qd, %qd)\n", 196 tab, s->st_size, p->fts_statp->st_size); 197 tab = "\t"; 198 } 199 /* 200 * XXX 201 * Since utimes(2) only takes a timeval, there's no point in 202 * comparing the low bits of the timespec nanosecond field. This 203 * will only result in mismatches that we can never fix. 204 * 205 * Doesn't display microsecond differences. 206 */ 207 if (s->flags & F_TIME) { 208 struct timeval tv[2]; 209 210 TIMESPEC_TO_TIMEVAL(&tv[0], &s->st_mtimespec); 211 TIMESPEC_TO_TIMEVAL(&tv[1], &p->fts_statp->st_mtimespec); 212 if (tv[0].tv_sec != tv[1].tv_sec || 213 tv[0].tv_usec != tv[1].tv_usec) { 214 LABEL; 215 (void)printf("%smodification time (%.24s, ", 216 tab, ctime(&s->st_mtimespec.tv_sec)); 217 (void)printf("%.24s", 218 ctime(&p->fts_statp->st_mtimespec.tv_sec)); 219 if (tflag) { 220 tv[1] = tv[0]; 221 if (utimes(p->fts_accpath, tv)) 222 (void)printf(", not modified: %s)\n", 223 strerror(errno)); 224 else 225 (void)printf(", modified)\n"); 226 } else 227 (void)printf(")\n"); 228 tab = "\t"; 229 } 230 } 231 if (s->flags & F_CKSUM) { 232 if ((fd = open(p->fts_accpath, O_RDONLY, 0)) < 0) { 233 LABEL; 234 (void)printf("%scksum: %s: %s\n", 235 tab, p->fts_accpath, strerror(errno)); 236 tab = "\t"; 237 } else if (crc(fd, &val, &len)) { 238 (void)close(fd); 239 LABEL; 240 (void)printf("%scksum: %s: %s\n", 241 tab, p->fts_accpath, strerror(errno)); 242 tab = "\t"; 243 } else { 244 (void)close(fd); 245 if (s->cksum != val) { 246 LABEL; 247 (void)printf("%scksum (%u, %u)\n", 248 tab, s->cksum, val); 249 } 250 tab = "\t"; 251 } 252 } 253 if (s->flags & F_MD5) { 254 char *new_digest, buf[33]; 255 256 new_digest = MD5File(p->fts_accpath, buf); 257 if (!new_digest) { 258 LABEL; 259 printf("%sMD5File: %s: %s\n", tab, p->fts_accpath, 260 strerror(errno)); 261 tab = "\t"; 262 } else if (strcmp(new_digest, s->md5digest)) { 263 LABEL; 264 printf("%sMD5 (%s, %s)\n", tab, s->md5digest, 265 new_digest); 266 tab = "\t"; 267 } 268 } 269 if (s->flags & F_RMD160) { 270 char *new_digest, buf[41]; 271 272 new_digest = RMD160File(p->fts_accpath, buf); 273 if (!new_digest) { 274 LABEL; 275 printf("%sRMD160File: %s: %s\n", tab, p->fts_accpath, 276 strerror(errno)); 277 tab = "\t"; 278 } else if (strcmp(new_digest, s->rmd160digest)) { 279 LABEL; 280 printf("%sRMD160 (%s, %s)\n", tab, s->rmd160digest, 281 new_digest); 282 tab = "\t"; 283 } 284 } 285 if (s->flags & F_SHA1) { 286 char *new_digest, buf[41]; 287 288 new_digest = SHA1File(p->fts_accpath, buf); 289 if (!new_digest) { 290 LABEL; 291 printf("%sSHA1File: %s: %s\n", tab, p->fts_accpath, 292 strerror(errno)); 293 tab = "\t"; 294 } else if (strcmp(new_digest, s->sha1digest)) { 295 LABEL; 296 printf("%sSHA1 (%s, %s)\n", tab, s->sha1digest, 297 new_digest); 298 tab = "\t"; 299 } 300 } 301 if (s->flags & F_SLINK && strcmp(cp = rlink(name), s->slink)) { 302 LABEL; 303 (void)printf("%slink ref (%s, %s)\n", tab, cp, s->slink); 304 } 305 if (s->flags & F_FLAGS && s->file_flags != p->fts_statp->st_flags) { 306 char *db_flags = NULL; 307 char *cur_flags = NULL; 308 309 if ((db_flags = fflagstostr(s->file_flags)) == NULL || 310 (cur_flags = fflagstostr(p->fts_statp->st_flags)) == NULL) { 311 LABEL; 312 (void)printf("%sflags: %s %s\n", tab, p->fts_accpath, 313 strerror(errno)); 314 tab = "\t"; 315 if (db_flags != NULL) 316 free(db_flags); 317 if (cur_flags != NULL) 318 free(cur_flags); 319 } else { 320 LABEL; 321 REPLACE_COMMA(db_flags); 322 REPLACE_COMMA(cur_flags); 323 printf("%sflags (%s, %s", tab, (*db_flags == '\0') ? 324 "-" : db_flags, 325 (*cur_flags == '\0') ? 326 "-" : cur_flags); 327 tab = "\t"; 328 if (uflag) 329 if (chflags(p->fts_accpath, s->file_flags)) 330 (void)printf(", not modified: %s)\n", 331 strerror(errno)); 332 else 333 (void)printf(", modified)\n"); 334 else 335 (void)printf(")\n"); 336 tab = "\t"; 337 338 free(db_flags); 339 free(cur_flags); 340 } 341 } 342 return (label); 343 } 344 345 char * 346 inotype(type) 347 u_int type; 348 { 349 switch(type & S_IFMT) { 350 case S_IFBLK: 351 return ("block"); 352 case S_IFCHR: 353 return ("char"); 354 case S_IFDIR: 355 return ("dir"); 356 case S_IFIFO: 357 return ("fifo"); 358 case S_IFREG: 359 return ("file"); 360 case S_IFLNK: 361 return ("link"); 362 case S_IFSOCK: 363 return ("socket"); 364 default: 365 return ("unknown"); 366 } 367 /* NOTREACHED */ 368 } 369 370 static char * 371 ftype(type) 372 u_int type; 373 { 374 switch(type) { 375 case F_BLOCK: 376 return ("block"); 377 case F_CHAR: 378 return ("char"); 379 case F_DIR: 380 return ("dir"); 381 case F_FIFO: 382 return ("fifo"); 383 case F_FILE: 384 return ("file"); 385 case F_LINK: 386 return ("link"); 387 case F_SOCK: 388 return ("socket"); 389 default: 390 return ("unknown"); 391 } 392 /* NOTREACHED */ 393 } 394 395 char * 396 rlink(name) 397 char *name; 398 { 399 static char lbuf[MAXPATHLEN]; 400 int len; 401 402 if ((len = readlink(name, lbuf, sizeof(lbuf)-1)) == -1) 403 error("%s: %s", name, strerror(errno)); 404 lbuf[len] = '\0'; 405 return (lbuf); 406 } 407