1/*- 2 * Copyright (c) 1989, 1993 3 * The Regents of the University of California. 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 * 3. Neither the name of the University nor the names of its contributors 14 * may be used to endorse or promote products derived from this software 15 * without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30#if 0 31#ifndef lint 32static char sccsid[] = "@(#)compare.c 8.1 (Berkeley) 6/6/93"; 33#endif /* not lint */ 34#endif 35#include <sys/cdefs.h> 36__FBSDID("$FreeBSD: src/usr.sbin/mtree/compare.c,v 1.34 2005/03/29 11:44:17 tobez Exp $"); 37 38#include <sys/param.h> 39#include <sys/stat.h> 40#include <sys/time.h> 41 42#include <err.h> 43#include <errno.h> 44#include <fcntl.h> 45#include <fts.h> 46#ifndef __APPLE__ 47#ifdef ENABLE_MD5 48#include <md5.h> 49#endif 50#ifdef ENABLE_RMD160 51#include <ripemd.h> 52#endif 53#ifdef ENABLE_SHA1 54#include <sha.h> 55#endif 56#ifdef ENABLE_SHA256 57#include <sha256.h> 58#endif 59#endif /* !__APPLE__ */ 60#include <stdint.h> 61#include <stdio.h> 62#include <time.h> 63#include <unistd.h> 64#include <vis.h> 65 66#include "mtree.h" 67#include "extern.h" 68 69#ifdef __APPLE__ 70#include "commoncrypto.h" 71#endif /* __APPLE__ */ 72 73#define INDENTNAMELEN 8 74#define LABEL \ 75 if (!label++) { \ 76 len = printf("%s changed\n", RP(p)); \ 77 tab = "\t"; \ 78 } 79 80int 81compare(char *name __unused, NODE *s, FTSENT *p) 82{ 83 struct timeval tv[2]; 84 uint32_t val; 85 int fd, label; 86 off_t len; 87 char *cp; 88 const char *tab = ""; 89 char *fflags; 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)) { 119typeerr: LABEL; 120 (void)printf("\ttype expected %s found %s\n", 121 ftype(s->type), inotype(p->fts_statp->st_mode)); 122 return (label); 123 } 124 break; 125 } 126 /* Set the uid/gid first, then set the mode. */ 127 if (s->flags & (F_UID | F_UNAME) && s->st_uid != p->fts_statp->st_uid) { 128 LABEL; 129 (void)printf("%suser expected %lu found %lu", 130 tab, (u_long)s->st_uid, (u_long)p->fts_statp->st_uid); 131 if (uflag) 132 if (chown(p->fts_accpath, s->st_uid, -1)) 133 (void)printf(" not modified: %s\n", 134 strerror(errno)); 135 else 136 (void)printf(" modified\n"); 137 else 138 (void)printf("\n"); 139 tab = "\t"; 140 } 141 if (s->flags & (F_GID | F_GNAME) && s->st_gid != p->fts_statp->st_gid) { 142 LABEL; 143 (void)printf("%sgid expected %lu found %lu", 144 tab, (u_long)s->st_gid, (u_long)p->fts_statp->st_gid); 145 if (uflag) 146 if (chown(p->fts_accpath, -1, s->st_gid)) 147 (void)printf(" not modified: %s\n", 148 strerror(errno)); 149 else 150 (void)printf(" modified\n"); 151 else 152 (void)printf("\n"); 153 tab = "\t"; 154 } 155 if (s->flags & F_MODE && 156 !S_ISLNK(p->fts_statp->st_mode) && 157 s->st_mode != (p->fts_statp->st_mode & MBITS)) { 158 LABEL; 159 (void)printf("%spermissions expected %#o found %#o", 160 tab, s->st_mode, p->fts_statp->st_mode & MBITS); 161 if (uflag) 162 if (chmod(p->fts_accpath, s->st_mode)) 163 (void)printf(" not modified: %s\n", 164 strerror(errno)); 165 else 166 (void)printf(" modified\n"); 167 else 168 (void)printf("\n"); 169 tab = "\t"; 170 } 171 if (s->flags & F_NLINK && s->type != F_DIR && 172 s->st_nlink != p->fts_statp->st_nlink) { 173 LABEL; 174 (void)printf("%slink_count expected %u found %u\n", 175 tab, s->st_nlink, p->fts_statp->st_nlink); 176 tab = "\t"; 177 } 178 if (s->flags & F_SIZE && s->st_size != p->fts_statp->st_size && 179 !S_ISDIR(p->fts_statp->st_mode)) { 180 LABEL; 181 (void)printf("%ssize expected %jd found %jd\n", tab, 182 (intmax_t)s->st_size, (intmax_t)p->fts_statp->st_size); 183 tab = "\t"; 184 } 185 /* 186 * XXX 187 * Catches nano-second differences, but doesn't display them. 188 */ 189 if ((s->flags & F_TIME) && 190 ((s->st_mtimespec.tv_sec != p->fts_statp->st_mtimespec.tv_sec) || 191 (s->st_mtimespec.tv_nsec != p->fts_statp->st_mtimespec.tv_nsec))) { 192 LABEL; 193 (void)printf("%smodification time expected %.24s ", 194 tab, ctime(&s->st_mtimespec.tv_sec)); 195 (void)printf("found %.24s", 196 ctime(&p->fts_statp->st_mtimespec.tv_sec)); 197 if (uflag) { 198 tv[0].tv_sec = s->st_mtimespec.tv_sec; 199 tv[0].tv_usec = s->st_mtimespec.tv_nsec / 1000; 200 tv[1] = tv[0]; 201 if (utimes(p->fts_accpath, tv)) 202 (void)printf(" not modified: %s\n", 203 strerror(errno)); 204 else 205 (void)printf(" modified\n"); 206 } else 207 (void)printf("\n"); 208 tab = "\t"; 209 } 210 if (s->flags & F_CKSUM) { 211 if ((fd = open(p->fts_accpath, O_RDONLY, 0)) < 0) { 212 LABEL; 213 (void)printf("%scksum: %s: %s\n", 214 tab, p->fts_accpath, strerror(errno)); 215 tab = "\t"; 216 } else if (crc(fd, &val, &len)) { 217 (void)close(fd); 218 LABEL; 219 (void)printf("%scksum: %s: %s\n", 220 tab, p->fts_accpath, strerror(errno)); 221 tab = "\t"; 222 } else { 223 (void)close(fd); 224 if (s->cksum != val) { 225 LABEL; 226 (void)printf("%scksum expected %lu found %lu\n", 227 tab, s->cksum, (unsigned long)val); 228 tab = "\t"; 229 } 230 } 231 } 232 if ((s->flags & F_FLAGS) && s->st_flags != p->fts_statp->st_flags) { 233 LABEL; 234 fflags = flags_to_string(s->st_flags); 235 (void)printf("%sflags expected \"%s\"", tab, fflags); 236 free(fflags); 237 238 fflags = flags_to_string(p->fts_statp->st_flags); 239 (void)printf(" found \"%s\"", fflags); 240 free(fflags); 241 242 if (uflag) 243 if (chflags(p->fts_accpath, (u_int)s->st_flags)) 244 (void)printf(" not modified: %s\n", 245 strerror(errno)); 246 else 247 (void)printf(" modified\n"); 248 else 249 (void)printf("\n"); 250 tab = "\t"; 251 } 252#ifdef ENABLE_MD5 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("%sMD5: %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 expected %s found %s\n", tab, s->md5digest, 265 new_digest); 266 tab = "\t"; 267 } 268 } 269#endif /* ENABLE_MD5 */ 270#ifdef ENABLE_SHA1 271 if (s->flags & F_SHA1) { 272 char *new_digest, buf[41]; 273 274 new_digest = SHA1_File(p->fts_accpath, buf); 275 if (!new_digest) { 276 LABEL; 277 printf("%sSHA-1: %s: %s\n", tab, p->fts_accpath, 278 strerror(errno)); 279 tab = "\t"; 280 } else if (strcmp(new_digest, s->sha1digest)) { 281 LABEL; 282 printf("%sSHA-1 expected %s found %s\n", 283 tab, s->sha1digest, new_digest); 284 tab = "\t"; 285 } 286 } 287#endif /* ENABLE_SHA1 */ 288#ifdef ENABLE_RMD160 289 if (s->flags & F_RMD160) { 290 char *new_digest, buf[41]; 291 292 new_digest = RIPEMD160_File(p->fts_accpath, buf); 293 if (!new_digest) { 294 LABEL; 295 printf("%sRIPEMD160: %s: %s\n", tab, 296 p->fts_accpath, strerror(errno)); 297 tab = "\t"; 298 } else if (strcmp(new_digest, s->rmd160digest)) { 299 LABEL; 300 printf("%sRIPEMD160 expected %s found %s\n", 301 tab, s->rmd160digest, new_digest); 302 tab = "\t"; 303 } 304 } 305#endif /* ENABLE_RMD160 */ 306#ifdef ENABLE_SHA256 307 if (s->flags & F_SHA256) { 308 char *new_digest, buf[65]; 309 310 new_digest = SHA256_File(p->fts_accpath, buf); 311 if (!new_digest) { 312 LABEL; 313 printf("%sSHA-256: %s: %s\n", tab, p->fts_accpath, 314 strerror(errno)); 315 tab = "\t"; 316 } else if (strcmp(new_digest, s->sha256digest)) { 317 LABEL; 318 printf("%sSHA-256 expected %s found %s\n", 319 tab, s->sha256digest, new_digest); 320 tab = "\t"; 321 } 322 } 323#endif /* ENABLE_SHA256 */ 324 325 if (s->flags & F_SLINK && 326 strcmp(cp = rlink(p->fts_accpath), s->slink)) { 327 LABEL; 328 (void)printf("%slink_ref expected %s found %s\n", 329 tab, s->slink, cp); 330 } 331 return (label); 332} 333 334const char * 335inotype(u_int type) 336{ 337 switch(type & S_IFMT) { 338 case S_IFBLK: 339 return ("block"); 340 case S_IFCHR: 341 return ("char"); 342 case S_IFDIR: 343 return ("dir"); 344 case S_IFIFO: 345 return ("fifo"); 346 case S_IFREG: 347 return ("file"); 348 case S_IFLNK: 349 return ("link"); 350 case S_IFSOCK: 351 return ("socket"); 352 default: 353 return ("unknown"); 354 } 355 /* NOTREACHED */ 356} 357 358const char * 359ftype(u_int type) 360{ 361 switch(type) { 362 case F_BLOCK: 363 return ("block"); 364 case F_CHAR: 365 return ("char"); 366 case F_DIR: 367 return ("dir"); 368 case F_FIFO: 369 return ("fifo"); 370 case F_FILE: 371 return ("file"); 372 case F_LINK: 373 return ("link"); 374 case F_SOCK: 375 return ("socket"); 376 default: 377 return ("unknown"); 378 } 379 /* NOTREACHED */ 380} 381 382char * 383rlink(char *name) 384{ 385 static char lbuf[MAXPATHLEN]; 386 ssize_t len; 387 388 if ((len = readlink(name, lbuf, sizeof(lbuf) - 1)) == -1) 389 err(1, "line %d: %s", lineno, name); 390 lbuf[len] = '\0'; 391 return (lbuf); 392} 393