1 /* @(#)verify.c 8.1 (Berkeley) 6/6/93 */ 2 /* $NetBSD: verify.c,v 1.46 2015/01/23 20:28:24 christos Exp $ */ 3 4 /*- 5 * Copyright (c) 1990, 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 #if HAVE_NBTOOL_CONFIG_H 34 #include "nbtool_config.h" 35 #endif 36 37 #include <sys/param.h> 38 #include <sys/stat.h> 39 40 #if ! HAVE_NBTOOL_CONFIG_H 41 #include <dirent.h> 42 #endif 43 44 #include <errno.h> 45 #include <fnmatch.h> 46 #include <stdio.h> 47 #include <string.h> 48 #include <unistd.h> 49 50 #include "extern.h" 51 52 static NODE *root; 53 static char path[MAXPATHLEN]; 54 55 static void miss(NODE *, char *); 56 static int vwalk(void); 57 58 int 59 verify(FILE *fi) 60 { 61 int rval; 62 63 root = spec(fi); 64 rval = vwalk(); 65 miss(root, path); 66 return (rval); 67 } 68 69 static int 70 vwalk(void) 71 { 72 FTS *t; 73 FTSENT *p; 74 NODE *ep, *level; 75 int specdepth, rval; 76 char *argv[2]; 77 char dot[] = "."; 78 argv[0] = dot; 79 argv[1] = NULL; 80 81 if ((t = fts_open(argv, ftsoptions, NULL)) == NULL) 82 mtree_err("fts_open: %s", strerror(errno)); 83 level = root; 84 specdepth = rval = 0; 85 while ((p = fts_read(t)) != NULL) { 86 if (check_excludes(p->fts_name, p->fts_path)) { 87 fts_set(t, p, FTS_SKIP); 88 continue; 89 } 90 if (!find_only(p->fts_path)) { 91 fts_set(t, p, FTS_SKIP); 92 continue; 93 } 94 switch(p->fts_info) { 95 case FTS_D: 96 case FTS_SL: 97 break; 98 case FTS_DP: 99 if (specdepth > p->fts_level) { 100 for (level = level->parent; level->prev; 101 level = level->prev) 102 continue; 103 --specdepth; 104 } 105 continue; 106 case FTS_DNR: 107 case FTS_ERR: 108 case FTS_NS: 109 warnx("%s: %s", RP(p), strerror(p->fts_errno)); 110 continue; 111 default: 112 if (dflag) 113 continue; 114 } 115 116 if (specdepth != p->fts_level) 117 goto extra; 118 for (ep = level; ep; ep = ep->next) 119 if ((ep->flags & F_MAGIC && 120 !fnmatch(ep->name, p->fts_name, FNM_PATHNAME)) || 121 !strcmp(ep->name, p->fts_name)) { 122 ep->flags |= F_VISIT; 123 if ((ep->flags & F_NOCHANGE) == 0 && 124 compare(ep, p)) 125 rval = MISMATCHEXIT; 126 if (!(ep->flags & F_IGN) && 127 ep->type == F_DIR && 128 p->fts_info == FTS_D) { 129 if (ep->child) { 130 level = ep->child; 131 ++specdepth; 132 } 133 } else 134 fts_set(t, p, FTS_SKIP); 135 break; 136 } 137 138 if (ep) 139 continue; 140 extra: 141 if (!eflag && !(dflag && p->fts_info == FTS_SL)) { 142 printf("extra: %s", RP(p)); 143 if (rflag) { 144 #if HAVE_STRUCT_STAT_ST_FLAGS 145 if (rflag > 1 && 146 lchflags(p->fts_accpath, 0) == -1) 147 printf(" (chflags %s)", 148 strerror(errno)); 149 #endif 150 if ((S_ISDIR(p->fts_statp->st_mode) 151 ? rmdir : unlink)(p->fts_accpath)) { 152 printf(", not removed: %s", 153 strerror(errno)); 154 } else 155 printf(", removed"); 156 } 157 putchar('\n'); 158 } 159 fts_set(t, p, FTS_SKIP); 160 } 161 fts_close(t); 162 if (sflag) 163 warnx("%s checksum: %u", fullpath, crc_total); 164 return (rval); 165 } 166 167 static void 168 miss(NODE *p, char *tail) 169 { 170 int create; 171 char *tp; 172 const char *type; 173 u_int32_t flags; 174 175 for (; p; p = p->next) { 176 if (p->flags & F_OPT && !(p->flags & F_VISIT)) 177 continue; 178 if (p->type != F_DIR && (dflag || p->flags & F_VISIT)) 179 continue; 180 strcpy(tail, p->name); 181 if (!(p->flags & F_VISIT)) { 182 /* Don't print missing message if file exists as a 183 symbolic link and the -q flag is set. */ 184 struct stat statbuf; 185 186 if (qflag && stat(path, &statbuf) == 0 && 187 S_ISDIR(statbuf.st_mode)) 188 p->flags |= F_VISIT; 189 else 190 (void)printf("%s missing", path); 191 } 192 switch (p->type) { 193 case F_BLOCK: 194 case F_CHAR: 195 type = "device"; 196 break; 197 case F_DIR: 198 type = "directory"; 199 break; 200 case F_LINK: 201 type = "symlink"; 202 break; 203 default: 204 putchar('\n'); 205 continue; 206 } 207 208 create = 0; 209 if (!(p->flags & F_VISIT) && uflag) { 210 if (mtree_Wflag || p->type == F_LINK) 211 goto createit; 212 if (!(p->flags & (F_UID | F_UNAME))) 213 printf( 214 " (%s not created: user not specified)", type); 215 else if (!(p->flags & (F_GID | F_GNAME))) 216 printf( 217 " (%s not created: group not specified)", type); 218 else if (!(p->flags & F_MODE)) 219 printf( 220 " (%s not created: mode not specified)", type); 221 else 222 createit: 223 switch (p->type) { 224 case F_BLOCK: 225 case F_CHAR: 226 if (mtree_Wflag) 227 continue; 228 if (!(p->flags & F_DEV)) 229 printf( 230 " (%s not created: device not specified)", 231 type); 232 else if (mknod(path, 233 p->st_mode | nodetoino(p->type), 234 p->st_rdev) == -1) 235 printf(" (%s not created: %s)\n", 236 type, strerror(errno)); 237 else 238 create = 1; 239 break; 240 case F_LINK: 241 if (!(p->flags & F_SLINK)) 242 printf( 243 " (%s not created: link not specified)\n", 244 type); 245 else if (symlink(p->slink, path)) 246 printf( 247 " (%s not created: %s)\n", 248 type, strerror(errno)); 249 else 250 create = 1; 251 break; 252 case F_DIR: 253 if (mkdir(path, S_IRWXU|S_IRWXG|S_IRWXO)) 254 printf(" (not created: %s)", 255 strerror(errno)); 256 else 257 create = 1; 258 break; 259 default: 260 mtree_err("can't create create %s", 261 nodetype(p->type)); 262 } 263 } 264 if (create) 265 printf(" (created)"); 266 if (p->type == F_DIR) { 267 if (!(p->flags & F_VISIT)) 268 putchar('\n'); 269 for (tp = tail; *tp; ++tp) 270 continue; 271 *tp = '/'; 272 miss(p->child, tp + 1); 273 *tp = '\0'; 274 } else 275 putchar('\n'); 276 277 if (!create || mtree_Wflag) 278 continue; 279 if ((p->flags & (F_UID | F_UNAME)) && 280 (p->flags & (F_GID | F_GNAME)) && 281 (lchown(path, p->st_uid, p->st_gid))) { 282 printf("%s: user/group/mode not modified: %s\n", 283 path, strerror(errno)); 284 printf("%s: warning: file mode %snot set\n", path, 285 (p->flags & F_FLAGS) ? "and file flags " : ""); 286 continue; 287 } 288 if (p->flags & F_MODE) { 289 if (lchmod(path, p->st_mode)) 290 printf("%s: permissions not set: %s\n", 291 path, strerror(errno)); 292 } 293 #if HAVE_STRUCT_STAT_ST_FLAGS 294 if ((p->flags & F_FLAGS) && p->st_flags) { 295 if (iflag) 296 flags = p->st_flags; 297 else 298 flags = p->st_flags & ~SP_FLGS; 299 if (lchflags(path, flags)) 300 printf("%s: file flags not set: %s\n", 301 path, strerror(errno)); 302 } 303 #endif /* HAVE_STRUCT_STAT_ST_FLAGS */ 304 } 305 } 306