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