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 * @(#)compare.c 8.1 (Berkeley) 6/6/93 30 * $FreeBSD: src/usr.sbin/mtree/compare.c,v 1.15.2.4 2003/05/07 17:55:17 tobez Exp $ 31 * $DragonFly: src/usr.sbin/mtree/compare.c,v 1.5 2004/03/15 16:24:22 dillon Exp $ 32 */ 33 34 #include <sys/param.h> 35 #include <sys/stat.h> 36 #include <err.h> 37 #include <errno.h> 38 #include <fcntl.h> 39 #include <fts.h> 40 #ifdef USE_MD5 41 #include <md5.h> 42 #endif 43 #ifdef USE_SHA1 44 #include <sha.h> 45 #include "../../sbin/md5/sha1hl.h" 46 #endif 47 #ifdef USE_RMD160 48 #include <ripemd.h> 49 #endif 50 #include <stdio.h> 51 #include <time.h> 52 #include <unistd.h> 53 #include "mtree.h" 54 #include "extern.h" 55 56 static const char *ftype(u_int); 57 58 #define INDENTNAMELEN 8 59 #define LABEL \ 60 if (!label++) { \ 61 len = printf("%s changed\n", RP(p)); \ 62 tab = "\t"; \ 63 } 64 65 int 66 compare(NODE *s, FTSENT *p) 67 { 68 u_long len, val; 69 int fd, label; 70 char *cp, *fflags; 71 const char *tab = ""; 72 73 label = 0; 74 switch(s->type) { 75 case F_BLOCK: 76 if (!S_ISBLK(p->fts_statp->st_mode)) 77 goto typeerr; 78 break; 79 case F_CHAR: 80 if (!S_ISCHR(p->fts_statp->st_mode)) 81 goto typeerr; 82 break; 83 case F_DIR: 84 if (!S_ISDIR(p->fts_statp->st_mode)) 85 goto typeerr; 86 break; 87 case F_FIFO: 88 if (!S_ISFIFO(p->fts_statp->st_mode)) 89 goto typeerr; 90 break; 91 case F_FILE: 92 if (!S_ISREG(p->fts_statp->st_mode)) 93 goto typeerr; 94 break; 95 case F_LINK: 96 if (!S_ISLNK(p->fts_statp->st_mode)) 97 goto typeerr; 98 break; 99 case F_SOCK: 100 if (!S_ISSOCK(p->fts_statp->st_mode)) { 101 typeerr: LABEL; 102 printf("\ttype expected %s found %s\n", 103 ftype(s->type), inotype(p->fts_statp->st_mode)); 104 return (label); 105 } 106 break; 107 } 108 /* Set the uid/gid first, then set the mode. */ 109 if (s->flags & (F_UID | F_UNAME) && s->st_uid != p->fts_statp->st_uid) { 110 LABEL; 111 printf("%suser expected %lu found %lu", 112 tab, (u_long)s->st_uid, (u_long)p->fts_statp->st_uid); 113 if (uflag) 114 if (chown(p->fts_accpath, s->st_uid, -1)) 115 printf(" not modified: %s\n", 116 strerror(errno)); 117 else 118 printf(" modified\n"); 119 else 120 printf("\n"); 121 tab = "\t"; 122 } 123 if (s->flags & (F_GID | F_GNAME) && s->st_gid != p->fts_statp->st_gid) { 124 LABEL; 125 printf("%sgid expected %lu found %lu", 126 tab, (u_long)s->st_gid, (u_long)p->fts_statp->st_gid); 127 if (uflag) 128 if (chown(p->fts_accpath, -1, s->st_gid)) 129 printf(" not modified: %s\n", 130 strerror(errno)); 131 else 132 printf(" modified\n"); 133 else 134 printf("\n"); 135 tab = "\t"; 136 } 137 if (s->flags & F_MODE && 138 !S_ISLNK(p->fts_statp->st_mode) && 139 s->st_mode != (p->fts_statp->st_mode & MBITS)) { 140 LABEL; 141 printf("%spermissions expected %#o found %#o", 142 tab, s->st_mode, p->fts_statp->st_mode & MBITS); 143 if (uflag) 144 if (chmod(p->fts_accpath, s->st_mode)) 145 printf(" not modified: %s\n", 146 strerror(errno)); 147 else 148 printf(" modified\n"); 149 else 150 printf("\n"); 151 tab = "\t"; 152 } 153 if (s->flags & F_NLINK && s->type != F_DIR && 154 s->st_nlink != p->fts_statp->st_nlink) { 155 LABEL; 156 printf("%slink_count expected %u found %u\n", 157 tab, s->st_nlink, p->fts_statp->st_nlink); 158 tab = "\t"; 159 } 160 if (s->flags & F_SIZE && s->st_size != p->fts_statp->st_size && 161 !S_ISDIR(p->fts_statp->st_mode)) { 162 LABEL; 163 printf("%ssize expected %jd found %jd\n", tab, 164 (intmax_t)s->st_size, (intmax_t)p->fts_statp->st_size); 165 tab = "\t"; 166 } 167 /* 168 * XXX 169 * Catches nano-second differences, but doesn't display them. 170 */ 171 if ((s->flags & F_TIME) && 172 ((s->st_mtimespec.tv_sec != p->fts_statp->st_mtimespec.tv_sec) || 173 (s->st_mtimespec.tv_nsec != p->fts_statp->st_mtimespec.tv_nsec))) { 174 LABEL; 175 printf("%smodification time expected %.24s ", 176 tab, ctime(&s->st_mtimespec.tv_sec)); 177 printf("found %.24s\n", 178 ctime(&p->fts_statp->st_mtimespec.tv_sec)); 179 tab = "\t"; 180 } 181 if (s->flags & F_CKSUM) { 182 if ((fd = open(p->fts_accpath, O_RDONLY, 0)) < 0) { 183 LABEL; 184 printf("%scksum: %s: %s\n", 185 tab, p->fts_accpath, strerror(errno)); 186 tab = "\t"; 187 } else if (crc(fd, &val, &len)) { 188 close(fd); 189 LABEL; 190 printf("%scksum: %s: %s\n", 191 tab, p->fts_accpath, strerror(errno)); 192 tab = "\t"; 193 } else { 194 close(fd); 195 if (s->cksum != val) { 196 LABEL; 197 printf("%scksum expected %lu found %lu\n", 198 tab, s->cksum, val); 199 tab = "\t"; 200 } 201 } 202 } 203 /* 204 * XXX 205 * since chflags(2) will reset file times, the utimes() above 206 * may have been useless! oh well, we'd rather have correct 207 * flags, rather than times? 208 */ 209 if ((s->flags & F_FLAGS) && s->st_flags != p->fts_statp->st_flags) { 210 LABEL; 211 fflags = flags_to_string(s->st_flags); 212 printf("%sflags expected \"%s\"", tab, fflags); 213 free(fflags); 214 215 fflags = flags_to_string(p->fts_statp->st_flags); 216 printf(" found \"%s\"", fflags); 217 free(fflags); 218 219 if (uflag) 220 if (chflags(p->fts_accpath, s->st_flags)) 221 printf(" not modified: %s\n", 222 strerror(errno)); 223 else 224 printf(" modified\n"); 225 else 226 printf("\n"); 227 tab = "\t"; 228 } 229 #ifdef USE_MD5 230 if (s->flags & F_MD5) { 231 char *new_digest, buf[33]; 232 233 new_digest = MD5File(p->fts_accpath, buf); 234 if (!new_digest) { 235 LABEL; 236 printf("%sMD5: %s: %s\n", tab, p->fts_accpath, 237 strerror(errno)); 238 tab = "\t"; 239 } else if (strcmp(new_digest, s->md5digest)) { 240 LABEL; 241 printf("%sMD5 expected %s found %s\n", tab, s->md5digest, 242 new_digest); 243 tab = "\t"; 244 } 245 } 246 #endif /* MD5 */ 247 #ifdef USE_SHA1 248 if (s->flags & F_SHA1) { 249 char *new_digest, buf[41]; 250 251 new_digest = SHA1_File(p->fts_accpath, buf); 252 if (!new_digest) { 253 LABEL; 254 printf("%sSHA-1: %s: %s\n", tab, p->fts_accpath, 255 strerror(errno)); 256 tab = "\t"; 257 } else if (strcmp(new_digest, s->sha1digest)) { 258 LABEL; 259 printf("%sSHA-1 expected %s found %s\n", 260 tab, s->sha1digest, new_digest); 261 tab = "\t"; 262 } 263 } 264 #endif /* SHA1 */ 265 #ifdef USE_RMD160 266 if (s->flags & F_RMD160) { 267 char *new_digest, buf[41]; 268 269 new_digest = RIPEMD160_File(p->fts_accpath, buf); 270 if (!new_digest) { 271 LABEL; 272 printf("%sRIPEMD160: %s: %s\n", tab, 273 p->fts_accpath, strerror(errno)); 274 tab = "\t"; 275 } else if (strcmp(new_digest, s->rmd160digest)) { 276 LABEL; 277 printf("%sRIPEMD160 expected %s found %s\n", 278 tab, s->rmd160digest, new_digest); 279 tab = "\t"; 280 } 281 } 282 #endif /* RMD160 */ 283 284 if (s->flags & F_SLINK && 285 strcmp(cp = rlink(p->fts_accpath), s->slink)) { 286 LABEL; 287 printf("%slink_ref expected %s found %s\n", 288 tab, s->slink, cp); 289 } 290 return (label); 291 } 292 293 const char * 294 inotype(u_int type) 295 { 296 switch(type & S_IFMT) { 297 case S_IFBLK: 298 return ("block"); 299 case S_IFCHR: 300 return ("char"); 301 case S_IFDIR: 302 return ("dir"); 303 case S_IFIFO: 304 return ("fifo"); 305 case S_IFREG: 306 return ("file"); 307 case S_IFLNK: 308 return ("link"); 309 case S_IFSOCK: 310 return ("socket"); 311 default: 312 return ("unknown"); 313 } 314 /* NOTREACHED */ 315 } 316 317 static const char * 318 ftype(u_int type) 319 { 320 switch(type) { 321 case F_BLOCK: 322 return ("block"); 323 case F_CHAR: 324 return ("char"); 325 case F_DIR: 326 return ("dir"); 327 case F_FIFO: 328 return ("fifo"); 329 case F_FILE: 330 return ("file"); 331 case F_LINK: 332 return ("link"); 333 case F_SOCK: 334 return ("socket"); 335 default: 336 return ("unknown"); 337 } 338 /* NOTREACHED */ 339 } 340 341 char * 342 rlink(char *name) 343 { 344 static char lbuf[MAXPATHLEN]; 345 int len; 346 347 if ((len = readlink(name, lbuf, sizeof(lbuf) - 1)) == -1) 348 err(1, "line %d: %s", lineno, name); 349 lbuf[len] = '\0'; 350 return (lbuf); 351 } 352