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