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