1 1.50 christos /* $NetBSD: verify.c,v 1.50 2024/12/11 14:52:26 christos Exp $ */ 2 1.9 cgd 3 1.1 cgd /*- 4 1.8 cgd * Copyright (c) 1990, 1993 5 1.8 cgd * The Regents of the University of California. All rights reserved. 6 1.1 cgd * 7 1.1 cgd * Redistribution and use in source and binary forms, with or without 8 1.1 cgd * modification, are permitted provided that the following conditions 9 1.1 cgd * are met: 10 1.1 cgd * 1. Redistributions of source code must retain the above copyright 11 1.1 cgd * notice, this list of conditions and the following disclaimer. 12 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 cgd * notice, this list of conditions and the following disclaimer in the 14 1.1 cgd * documentation and/or other materials provided with the distribution. 15 1.35 agc * 3. Neither the name of the University nor the names of its contributors 16 1.1 cgd * may be used to endorse or promote products derived from this software 17 1.1 cgd * without specific prior written permission. 18 1.1 cgd * 19 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 1.1 cgd * SUCH DAMAGE. 30 1.1 cgd */ 31 1.1 cgd 32 1.37 jmc #if HAVE_NBTOOL_CONFIG_H 33 1.37 jmc #include "nbtool_config.h" 34 1.37 jmc #endif 35 1.37 jmc 36 1.13 lukem #include <sys/cdefs.h> 37 1.27 tv #if defined(__RCSID) && !defined(lint) 38 1.9 cgd #if 0 39 1.8 cgd static char sccsid[] = "@(#)verify.c 8.1 (Berkeley) 6/6/93"; 40 1.9 cgd #else 41 1.50 christos __RCSID("$NetBSD: verify.c,v 1.50 2024/12/11 14:52:26 christos Exp $"); 42 1.9 cgd #endif 43 1.1 cgd #endif /* not lint */ 44 1.1 cgd 45 1.1 cgd #include <sys/param.h> 46 1.1 cgd #include <sys/stat.h> 47 1.18 simonb 48 1.36 lukem #if ! HAVE_NBTOOL_CONFIG_H 49 1.1 cgd #include <dirent.h> 50 1.26 tv #endif 51 1.26 tv 52 1.18 simonb #include <errno.h> 53 1.18 simonb #include <fnmatch.h> 54 1.18 simonb #include <stdio.h> 55 1.22 lukem #include <string.h> 56 1.1 cgd #include <unistd.h> 57 1.18 simonb 58 1.6 cgd #include "extern.h" 59 1.1 cgd 60 1.6 cgd static NODE *root; 61 1.25 lukem static char path[MAXPATHLEN]; 62 1.1 cgd 63 1.18 simonb static void miss(NODE *, char *); 64 1.18 simonb static int vwalk(void); 65 1.6 cgd 66 1.6 cgd int 67 1.42 christos verify(FILE *fi) 68 1.1 cgd { 69 1.6 cgd int rval; 70 1.6 cgd 71 1.42 christos root = spec(fi); 72 1.6 cgd rval = vwalk(); 73 1.1 cgd miss(root, path); 74 1.6 cgd return (rval); 75 1.1 cgd } 76 1.1 cgd 77 1.6 cgd static int 78 1.18 simonb vwalk(void) 79 1.1 cgd { 80 1.13 lukem FTS *t; 81 1.13 lukem FTSENT *p; 82 1.13 lukem NODE *ep, *level; 83 1.24 lukem int specdepth, rval; 84 1.33 grant char *argv[2]; 85 1.33 grant char dot[] = "."; 86 1.33 grant argv[0] = dot; 87 1.33 grant argv[1] = NULL; 88 1.1 cgd 89 1.49 christos if ((t = fts_open(argv, ftsoptions, dcmp)) == NULL) 90 1.15 wsanchez mtree_err("fts_open: %s", strerror(errno)); 91 1.1 cgd level = root; 92 1.24 lukem specdepth = rval = 0; 93 1.12 mikel while ((p = fts_read(t)) != NULL) { 94 1.24 lukem if (check_excludes(p->fts_name, p->fts_path)) { 95 1.24 lukem fts_set(t, p, FTS_SKIP); 96 1.24 lukem continue; 97 1.24 lukem } 98 1.44 christos if (!find_only(p->fts_path)) { 99 1.44 christos fts_set(t, p, FTS_SKIP); 100 1.44 christos continue; 101 1.44 christos } 102 1.1 cgd switch(p->fts_info) { 103 1.1 cgd case FTS_D: 104 1.24 lukem case FTS_SL: 105 1.1 cgd break; 106 1.1 cgd case FTS_DP: 107 1.24 lukem if (specdepth > p->fts_level) { 108 1.1 cgd for (level = level->parent; level->prev; 109 1.24 lukem level = level->prev) 110 1.24 lukem continue; 111 1.6 cgd --specdepth; 112 1.1 cgd } 113 1.1 cgd continue; 114 1.1 cgd case FTS_DNR: 115 1.1 cgd case FTS_ERR: 116 1.1 cgd case FTS_NS: 117 1.24 lukem warnx("%s: %s", RP(p), strerror(p->fts_errno)); 118 1.1 cgd continue; 119 1.1 cgd default: 120 1.1 cgd if (dflag) 121 1.1 cgd continue; 122 1.1 cgd } 123 1.1 cgd 124 1.24 lukem if (specdepth != p->fts_level) 125 1.24 lukem goto extra; 126 1.1 cgd for (ep = level; ep; ep = ep->next) 127 1.12 mikel if ((ep->flags & F_MAGIC && 128 1.12 mikel !fnmatch(ep->name, p->fts_name, FNM_PATHNAME)) || 129 1.1 cgd !strcmp(ep->name, p->fts_name)) { 130 1.1 cgd ep->flags |= F_VISIT; 131 1.43 christos if ((ep->flags & F_NOCHANGE) == 0 && 132 1.43 christos compare(ep, p)) 133 1.6 cgd rval = MISMATCHEXIT; 134 1.11 lukem if (!(ep->flags & F_IGN) && 135 1.39 elad ep->type == F_DIR && 136 1.1 cgd p->fts_info == FTS_D) { 137 1.39 elad if (ep->child) { 138 1.39 elad level = ep->child; 139 1.39 elad ++specdepth; 140 1.39 elad } 141 1.11 lukem } else 142 1.24 lukem fts_set(t, p, FTS_SKIP); 143 1.1 cgd break; 144 1.1 cgd } 145 1.1 cgd 146 1.1 cgd if (ep) 147 1.1 cgd continue; 148 1.24 lukem extra: 149 1.40 christos if (!eflag && !(dflag && p->fts_info == FTS_SL)) { 150 1.50 christos printf(flavor == F_FREEBSD9 ? "%s extra" : "extra: %s", 151 1.50 christos RP(p)); 152 1.1 cgd if (rflag) { 153 1.46 christos #if HAVE_STRUCT_STAT_ST_FLAGS 154 1.45 christos if (rflag > 1 && 155 1.45 christos lchflags(p->fts_accpath, 0) == -1) 156 1.45 christos printf(" (chflags %s)", 157 1.45 christos strerror(errno)); 158 1.46 christos #endif 159 1.24 lukem if ((S_ISDIR(p->fts_statp->st_mode) 160 1.24 lukem ? rmdir : unlink)(p->fts_accpath)) { 161 1.24 lukem printf(", not removed: %s", 162 1.1 cgd strerror(errno)); 163 1.1 cgd } else 164 1.24 lukem printf(", removed"); 165 1.1 cgd } 166 1.24 lukem putchar('\n'); 167 1.1 cgd } 168 1.24 lukem fts_set(t, p, FTS_SKIP); 169 1.1 cgd } 170 1.48 christos if (errno != 0) 171 1.48 christos mtree_err("fts_read: %s", strerror(errno)); 172 1.24 lukem fts_close(t); 173 1.6 cgd if (sflag) 174 1.24 lukem warnx("%s checksum: %u", fullpath, crc_total); 175 1.6 cgd return (rval); 176 1.1 cgd } 177 1.1 cgd 178 1.6 cgd static void 179 1.18 simonb miss(NODE *p, char *tail) 180 1.1 cgd { 181 1.13 lukem int create; 182 1.13 lukem char *tp; 183 1.24 lukem const char *type; 184 1.49 christos u_long flags; 185 1.1 cgd 186 1.1 cgd for (; p; p = p->next) { 187 1.10 cgd if (p->flags & F_OPT && !(p->flags & F_VISIT)) 188 1.10 cgd continue; 189 1.1 cgd if (p->type != F_DIR && (dflag || p->flags & F_VISIT)) 190 1.1 cgd continue; 191 1.24 lukem strcpy(tail, p->name); 192 1.41 christos if (!(p->flags & F_VISIT)) { 193 1.41 christos /* Don't print missing message if file exists as a 194 1.41 christos symbolic link and the -q flag is set. */ 195 1.41 christos struct stat statbuf; 196 1.41 christos 197 1.41 christos if (qflag && stat(path, &statbuf) == 0 && 198 1.41 christos S_ISDIR(statbuf.st_mode)) 199 1.41 christos p->flags |= F_VISIT; 200 1.41 christos else 201 1.41 christos (void)printf("%s missing", path); 202 1.41 christos } 203 1.24 lukem switch (p->type) { 204 1.24 lukem case F_BLOCK: 205 1.24 lukem case F_CHAR: 206 1.24 lukem type = "device"; 207 1.24 lukem break; 208 1.24 lukem case F_DIR: 209 1.24 lukem type = "directory"; 210 1.24 lukem break; 211 1.24 lukem case F_LINK: 212 1.24 lukem type = "symlink"; 213 1.24 lukem break; 214 1.24 lukem default: 215 1.1 cgd putchar('\n'); 216 1.1 cgd continue; 217 1.1 cgd } 218 1.1 cgd 219 1.1 cgd create = 0; 220 1.14 ross if (!(p->flags & F_VISIT) && uflag) { 221 1.38 lukem if (mtree_Wflag || p->type == F_LINK) 222 1.29 lukem goto createit; 223 1.6 cgd if (!(p->flags & (F_UID | F_UNAME))) 224 1.24 lukem printf( 225 1.24 lukem " (%s not created: user not specified)", type); 226 1.6 cgd else if (!(p->flags & (F_GID | F_GNAME))) 227 1.24 lukem printf( 228 1.24 lukem " (%s not created: group not specified)", type); 229 1.29 lukem else if (!(p->flags & F_MODE)) 230 1.24 lukem printf( 231 1.24 lukem " (%s not created: mode not specified)", type); 232 1.24 lukem else 233 1.29 lukem createit: 234 1.24 lukem switch (p->type) { 235 1.24 lukem case F_BLOCK: 236 1.24 lukem case F_CHAR: 237 1.38 lukem if (mtree_Wflag) 238 1.24 lukem continue; 239 1.24 lukem if (!(p->flags & F_DEV)) 240 1.24 lukem printf( 241 1.24 lukem " (%s not created: device not specified)", 242 1.24 lukem type); 243 1.24 lukem else if (mknod(path, 244 1.24 lukem p->st_mode | nodetoino(p->type), 245 1.24 lukem p->st_rdev) == -1) 246 1.24 lukem printf(" (%s not created: %s)\n", 247 1.24 lukem type, strerror(errno)); 248 1.24 lukem else 249 1.29 lukem create = 1; 250 1.29 lukem break; 251 1.24 lukem case F_LINK: 252 1.29 lukem if (!(p->flags & F_SLINK)) 253 1.24 lukem printf( 254 1.29 lukem " (%s not created: link not specified)\n", 255 1.24 lukem type); 256 1.24 lukem else if (symlink(p->slink, path)) 257 1.24 lukem printf( 258 1.24 lukem " (%s not created: %s)\n", 259 1.24 lukem type, strerror(errno)); 260 1.24 lukem else 261 1.29 lukem create = 1; 262 1.29 lukem break; 263 1.24 lukem case F_DIR: 264 1.34 lukem if (mkdir(path, S_IRWXU|S_IRWXG|S_IRWXO)) 265 1.24 lukem printf(" (not created: %s)", 266 1.24 lukem strerror(errno)); 267 1.29 lukem else 268 1.24 lukem create = 1; 269 1.24 lukem break; 270 1.24 lukem default: 271 1.24 lukem mtree_err("can't create create %s", 272 1.24 lukem nodetype(p->type)); 273 1.1 cgd } 274 1.14 ross } 275 1.29 lukem if (create) 276 1.29 lukem printf(" (created)"); 277 1.29 lukem if (p->type == F_DIR) { 278 1.29 lukem if (!(p->flags & F_VISIT)) 279 1.29 lukem putchar('\n'); 280 1.29 lukem for (tp = tail; *tp; ++tp) 281 1.29 lukem continue; 282 1.29 lukem *tp = '/'; 283 1.29 lukem miss(p->child, tp + 1); 284 1.29 lukem *tp = '\0'; 285 1.29 lukem } else 286 1.24 lukem putchar('\n'); 287 1.1 cgd 288 1.38 lukem if (!create || mtree_Wflag) 289 1.1 cgd continue; 290 1.29 lukem if ((p->flags & (F_UID | F_UNAME)) && 291 1.29 lukem (p->flags & (F_GID | F_GNAME)) && 292 1.29 lukem (lchown(path, p->st_uid, p->st_gid))) { 293 1.24 lukem printf("%s: user/group/mode not modified: %s\n", 294 1.1 cgd path, strerror(errno)); 295 1.24 lukem printf("%s: warning: file mode %snot set\n", path, 296 1.16 mrg (p->flags & F_FLAGS) ? "and file flags " : ""); 297 1.1 cgd continue; 298 1.1 cgd } 299 1.30 tv if (p->flags & F_MODE) { 300 1.30 tv if (lchmod(path, p->st_mode)) 301 1.30 tv printf("%s: permissions not set: %s\n", 302 1.30 tv path, strerror(errno)); 303 1.30 tv } 304 1.26 tv #if HAVE_STRUCT_STAT_ST_FLAGS 305 1.17 mrg if ((p->flags & F_FLAGS) && p->st_flags) { 306 1.17 mrg if (iflag) 307 1.17 mrg flags = p->st_flags; 308 1.17 mrg else 309 1.17 mrg flags = p->st_flags & ~SP_FLGS; 310 1.29 lukem if (lchflags(path, flags)) 311 1.24 lukem printf("%s: file flags not set: %s\n", 312 1.17 mrg path, strerror(errno)); 313 1.17 mrg } 314 1.31 lukem #endif /* HAVE_STRUCT_STAT_ST_FLAGS */ 315 1.1 cgd } 316 1.1 cgd } 317