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