1 /*-
2 * Copyright (c) 1990, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * %sccs.include.redist.c%
6 */
7
8 #ifndef lint
9 static char sccsid[] = "@(#)verify.c 8.1 (Berkeley) 06/06/93";
10 #endif /* not lint */
11
12 #include <sys/param.h>
13 #include <sys/stat.h>
14 #include <dirent.h>
15 #include <fts.h>
16 #include <fnmatch.h>
17 #include <unistd.h>
18 #include <errno.h>
19 #include <stdio.h>
20 #include "mtree.h"
21 #include "extern.h"
22
23 extern int crc_total, ftsoptions;
24 extern int dflag, eflag, rflag, sflag, uflag;
25 extern char fullpath[MAXPATHLEN];
26
27 static NODE *root;
28 static char path[MAXPATHLEN];
29
30 static void miss __P((NODE *, char *));
31 static int vwalk __P((void));
32
33 int
verify()34 verify()
35 {
36 int rval;
37
38 root = spec();
39 rval = vwalk();
40 miss(root, path);
41 return (rval);
42 }
43
44 static int
vwalk()45 vwalk()
46 {
47 register FTS *t;
48 register FTSENT *p;
49 register NODE *ep, *level;
50 int ftsdepth, specdepth, rval;
51 char *argv[2];
52
53 argv[0] = ".";
54 argv[1] = NULL;
55 if ((t = fts_open(argv, ftsoptions, NULL)) == NULL)
56 err("fts_open: %s", strerror(errno));
57 level = root;
58 ftsdepth = specdepth = rval = 0;
59 while (p = fts_read(t)) {
60 switch(p->fts_info) {
61 case FTS_D:
62 ++ftsdepth;
63 break;
64 case FTS_DP:
65 --ftsdepth;
66 if (specdepth > ftsdepth) {
67 for (level = level->parent; level->prev;
68 level = level->prev);
69 --specdepth;
70 }
71 continue;
72 case FTS_DNR:
73 case FTS_ERR:
74 case FTS_NS:
75 (void)fprintf(stderr, "mtree: %s: %s\n",
76 RP(p), strerror(errno));
77 continue;
78 default:
79 if (dflag)
80 continue;
81 }
82
83 for (ep = level; ep; ep = ep->next)
84 if (ep->flags & F_MAGIC &&
85 !fnmatch(ep->name, p->fts_name, FNM_PATHNAME) ||
86 !strcmp(ep->name, p->fts_name)) {
87 ep->flags |= F_VISIT;
88 if (compare(ep->name, ep, p))
89 rval = MISMATCHEXIT;
90 if (ep->flags & F_IGN)
91 (void)fts_set(t, p, FTS_SKIP);
92 else if (ep->child && ep->type == F_DIR &&
93 p->fts_info == FTS_D) {
94 level = ep->child;
95 ++specdepth;
96 }
97 break;
98 }
99
100 if (ep)
101 continue;
102 if (!eflag) {
103 (void)printf("extra: %s", RP(p));
104 if (rflag) {
105 if (unlink(p->fts_accpath)) {
106 (void)printf(", not removed: %s",
107 strerror(errno));
108 } else
109 (void)printf(", removed");
110 }
111 (void)putchar('\n');
112 }
113 (void)fts_set(t, p, FTS_SKIP);
114 }
115 (void)fts_close(t);
116 if (sflag)
117 (void)fprintf(stderr,
118 "mtree: %s checksum: %lu\n", fullpath, crc_total);
119 return (rval);
120 }
121
122 static void
miss(p,tail)123 miss(p, tail)
124 register NODE *p;
125 register char *tail;
126 {
127 register int create;
128 register char *tp;
129
130 for (; p; p = p->next) {
131 if (p->type != F_DIR && (dflag || p->flags & F_VISIT))
132 continue;
133 (void)strcpy(tail, p->name);
134 if (!(p->flags & F_VISIT))
135 (void)printf("missing: %s", path);
136 if (p->type != F_DIR) {
137 putchar('\n');
138 continue;
139 }
140
141 create = 0;
142 if (!(p->flags & F_VISIT) && uflag)
143 if (!(p->flags & (F_UID | F_UNAME)))
144 (void)printf(" (not created: user not specified)");
145 else if (!(p->flags & (F_GID | F_GNAME)))
146 (void)printf(" (not created: group not specified)");
147 else if (!(p->flags & F_MODE))
148 (void)printf(" (not created: mode not specified)");
149 else if (mkdir(path, S_IRWXU))
150 (void)printf(" (not created: %s)",
151 strerror(errno));
152 else {
153 create = 1;
154 (void)printf(" (created)");
155 }
156
157 if (!(p->flags & F_VISIT))
158 (void)putchar('\n');
159
160 for (tp = tail; *tp; ++tp);
161 *tp = '/';
162 miss(p->child, tp + 1);
163 *tp = '\0';
164
165 if (!create)
166 continue;
167 if (chown(path, p->st_uid, p->st_gid)) {
168 (void)printf("%s: user/group/mode not modified: %s\n",
169 path, strerror(errno));
170 continue;
171 }
172 if (chmod(path, p->st_mode))
173 (void)printf("%s: permissions not set: %s\n",
174 path, strerror(errno));
175 }
176 }
177