1 /*- 2 * Copyright (c) 1990, 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. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #ifndef lint 35 #if 0 36 static char sccsid[] = "@(#)verify.c 8.1 (Berkeley) 6/6/93"; 37 #endif 38 static const char rcsid[] = 39 "$FreeBSD: src/usr.sbin/mtree/verify.c,v 1.10.2.2 2001/01/12 19:17:18 phk Exp $"; 40 #endif /* not lint */ 41 42 #include <sys/param.h> 43 #include <sys/stat.h> 44 #include <dirent.h> 45 #include <err.h> 46 #include <errno.h> 47 #include <fts.h> 48 #include <fnmatch.h> 49 #include <stdio.h> 50 #include <unistd.h> 51 #include "mtree.h" 52 #include "extern.h" 53 54 extern long int crc_total; 55 extern int ftsoptions; 56 extern int dflag, eflag, qflag, rflag, sflag, uflag; 57 extern char fullpath[MAXPATHLEN]; 58 extern int lineno; 59 60 static NODE *root; 61 static char path[MAXPATHLEN]; 62 63 static void miss __P((NODE *, char *)); 64 static int vwalk __P((void)); 65 66 int 67 verify() 68 { 69 int rval; 70 71 root = spec(); 72 rval = vwalk(); 73 miss(root, path); 74 return (rval); 75 } 76 77 static int 78 vwalk() 79 { 80 register FTS *t; 81 register FTSENT *p; 82 register NODE *ep, *level; 83 int specdepth, rval; 84 char *argv[2]; 85 86 argv[0] = "."; 87 argv[1] = NULL; 88 if ((t = fts_open(argv, ftsoptions, NULL)) == NULL) 89 err(1, "line %d: fts_open", lineno); 90 level = root; 91 specdepth = rval = 0; 92 while ((p = fts_read(t))) { 93 if (check_excludes(p->fts_name, p->fts_path)) { 94 fts_set(t, p, FTS_SKIP); 95 continue; 96 } 97 switch(p->fts_info) { 98 case FTS_D: 99 case FTS_SL: 100 break; 101 case FTS_DP: 102 if (specdepth > p->fts_level) { 103 for (level = level->parent; level->prev; 104 level = level->prev); 105 --specdepth; 106 } 107 continue; 108 case FTS_DNR: 109 case FTS_ERR: 110 case FTS_NS: 111 warnx("%s: %s", RP(p), strerror(p->fts_errno)); 112 continue; 113 default: 114 if (dflag) 115 continue; 116 } 117 118 if (specdepth != p->fts_level) 119 goto extra; 120 for (ep = level; ep; ep = ep->next) 121 if ((ep->flags & F_MAGIC && 122 !fnmatch(ep->name, p->fts_name, FNM_PATHNAME)) || 123 !strcmp(ep->name, p->fts_name)) { 124 ep->flags |= F_VISIT; 125 if ((ep->flags & F_NOCHANGE) == 0 && 126 compare(ep->name, ep, p)) 127 rval = MISMATCHEXIT; 128 if (ep->flags & F_IGN) 129 (void)fts_set(t, p, FTS_SKIP); 130 else if (ep->child && ep->type == F_DIR && 131 p->fts_info == FTS_D) { 132 level = ep->child; 133 ++specdepth; 134 } 135 break; 136 } 137 138 if (ep) 139 continue; 140 extra: 141 if (!eflag) { 142 (void)printf("%s extra", RP(p)); 143 if (rflag) { 144 if ((S_ISDIR(p->fts_statp->st_mode) 145 ? rmdir : unlink)(p->fts_accpath)) { 146 (void)printf(", not removed: %s", 147 strerror(errno)); 148 } else 149 (void)printf(", removed"); 150 } 151 (void)putchar('\n'); 152 } 153 (void)fts_set(t, p, FTS_SKIP); 154 } 155 (void)fts_close(t); 156 if (sflag) 157 warnx("%s checksum: %lu", fullpath, crc_total); 158 return (rval); 159 } 160 161 static void 162 miss(p, tail) 163 register NODE *p; 164 register char *tail; 165 { 166 register int create; 167 register char *tp; 168 const char *type; 169 170 for (; p; p = p->next) { 171 if (p->type != F_DIR && (dflag || p->flags & F_VISIT)) 172 continue; 173 (void)strcpy(tail, p->name); 174 if (!(p->flags & F_VISIT)) { 175 /* Don't print missing message if file exists as a 176 symbolic link and the -q flag is set. */ 177 struct stat statbuf; 178 179 if (qflag && stat(path, &statbuf) == 0) 180 p->flags |= F_VISIT; 181 else 182 (void)printf("%s missing", path); 183 } 184 if (p->type != F_DIR && p->type != F_LINK) { 185 putchar('\n'); 186 continue; 187 } 188 189 create = 0; 190 if (p->type == F_LINK) 191 type = "symlink"; 192 else 193 type = "directory"; 194 if (!(p->flags & F_VISIT) && uflag) { 195 if (!(p->flags & (F_UID | F_UNAME))) 196 (void)printf(" (%s not created: user not specified)", type); 197 else if (!(p->flags & (F_GID | F_GNAME))) 198 (void)printf(" (%s not created: group not specified)", type); 199 else if (p->type == F_LINK) { 200 if (symlink(p->slink, path)) 201 (void)printf(" (symlink not created: %s)\n", 202 strerror(errno)); 203 else 204 (void)printf(" (created)\n"); 205 if (lchown(path, p->st_uid, p->st_gid)) 206 (void)printf("%s: user/group not modified: %s\n", 207 path, strerror(errno)); 208 continue; 209 } else if (!(p->flags & F_MODE)) 210 (void)printf(" (directory not created: mode not specified)"); 211 else if (mkdir(path, S_IRWXU)) 212 (void)printf(" (directory not created: %s)", 213 strerror(errno)); 214 else { 215 create = 1; 216 (void)printf(" (created)"); 217 } 218 } 219 if (!(p->flags & F_VISIT)) 220 (void)putchar('\n'); 221 222 for (tp = tail; *tp; ++tp); 223 *tp = '/'; 224 miss(p->child, tp + 1); 225 *tp = '\0'; 226 227 if (!create) 228 continue; 229 if (chown(path, p->st_uid, p->st_gid)) { 230 (void)printf("%s: user/group/mode not modified: %s\n", 231 path, strerror(errno)); 232 (void)printf("%s: warning: file mode %snot set\n", path, 233 (p->flags & F_FLAGS) ? "and file flags " : ""); 234 continue; 235 } 236 if (chmod(path, p->st_mode)) 237 (void)printf("%s: permissions not set: %s\n", 238 path, strerror(errno)); 239 if ((p->flags & F_FLAGS) && p->st_flags && 240 chflags(path, p->st_flags)) 241 (void)printf("%s: file flags not set: %s\n", 242 path, strerror(errno)); 243 } 244 } 245