1249293Sed/*	$NetBSD: verify.c,v 1.44 2013/02/03 19:15:17 christos Exp $	*/
2244541Sbrooks
3244541Sbrooks/*-
4244541Sbrooks * Copyright (c) 1990, 1993
5244541Sbrooks *	The Regents of the University of California.  All rights reserved.
6244541Sbrooks *
7244541Sbrooks * Redistribution and use in source and binary forms, with or without
8244541Sbrooks * modification, are permitted provided that the following conditions
9244541Sbrooks * are met:
10244541Sbrooks * 1. Redistributions of source code must retain the above copyright
11244541Sbrooks *    notice, this list of conditions and the following disclaimer.
12244541Sbrooks * 2. Redistributions in binary form must reproduce the above copyright
13244541Sbrooks *    notice, this list of conditions and the following disclaimer in the
14244541Sbrooks *    documentation and/or other materials provided with the distribution.
15244541Sbrooks * 3. Neither the name of the University nor the names of its contributors
16244541Sbrooks *    may be used to endorse or promote products derived from this software
17244541Sbrooks *    without specific prior written permission.
18244541Sbrooks *
19244541Sbrooks * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20244541Sbrooks * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21244541Sbrooks * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22244541Sbrooks * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23244541Sbrooks * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24244541Sbrooks * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25244541Sbrooks * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26244541Sbrooks * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27244541Sbrooks * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28244541Sbrooks * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29244541Sbrooks * SUCH DAMAGE.
30244541Sbrooks */
31244541Sbrooks
32244541Sbrooks#if HAVE_NBTOOL_CONFIG_H
33244541Sbrooks#include "nbtool_config.h"
34244541Sbrooks#endif
35244541Sbrooks
36244541Sbrooks#include <sys/cdefs.h>
37244541Sbrooks#if defined(__RCSID) && !defined(lint)
38244541Sbrooks#if 0
39244541Sbrooksstatic char sccsid[] = "@(#)verify.c	8.1 (Berkeley) 6/6/93";
40244541Sbrooks#else
41249293Sed__RCSID("$NetBSD: verify.c,v 1.44 2013/02/03 19:15:17 christos Exp $");
42244541Sbrooks#endif
43244541Sbrooks#endif /* not lint */
44244541Sbrooks
45244541Sbrooks#include <sys/param.h>
46244541Sbrooks#include <sys/stat.h>
47244541Sbrooks
48244541Sbrooks#if ! HAVE_NBTOOL_CONFIG_H
49244541Sbrooks#include <dirent.h>
50244541Sbrooks#endif
51244541Sbrooks
52244541Sbrooks#include <errno.h>
53244541Sbrooks#include <fnmatch.h>
54244541Sbrooks#include <stdio.h>
55244541Sbrooks#include <string.h>
56244541Sbrooks#include <unistd.h>
57244541Sbrooks
58244541Sbrooks#include "extern.h"
59244541Sbrooks
60244541Sbrooksstatic NODE *root;
61244541Sbrooksstatic char path[MAXPATHLEN];
62244541Sbrooks
63244541Sbrooksstatic void	miss(NODE *, char *);
64244541Sbrooksstatic int	vwalk(void);
65244541Sbrooks
66244541Sbrooksint
67244541Sbrooksverify(FILE *fi)
68244541Sbrooks{
69244541Sbrooks	int rval;
70244541Sbrooks
71244541Sbrooks	root = spec(fi);
72244541Sbrooks	rval = vwalk();
73244541Sbrooks	miss(root, path);
74244541Sbrooks	return (rval);
75244541Sbrooks}
76244541Sbrooks
77244541Sbrooksstatic int
78244541Sbrooksvwalk(void)
79244541Sbrooks{
80244541Sbrooks	FTS *t;
81244541Sbrooks	FTSENT *p;
82244541Sbrooks	NODE *ep, *level;
83244541Sbrooks	int specdepth, rval;
84244541Sbrooks	char *argv[2];
85244541Sbrooks	char  dot[] = ".";
86244541Sbrooks	argv[0] = dot;
87244541Sbrooks	argv[1] = NULL;
88244541Sbrooks
89244541Sbrooks	if ((t = fts_open(argv, ftsoptions, NULL)) == NULL)
90244541Sbrooks		mtree_err("fts_open: %s", strerror(errno));
91244541Sbrooks	level = root;
92244541Sbrooks	specdepth = rval = 0;
93244541Sbrooks	while ((p = fts_read(t)) != NULL) {
94244541Sbrooks		if (check_excludes(p->fts_name, p->fts_path)) {
95244541Sbrooks			fts_set(t, p, FTS_SKIP);
96244541Sbrooks			continue;
97244541Sbrooks		}
98249293Sed		if (!find_only(p->fts_path)) {
99249293Sed			fts_set(t, p, FTS_SKIP);
100249293Sed			continue;
101249293Sed		}
102244541Sbrooks		switch(p->fts_info) {
103244541Sbrooks		case FTS_D:
104244541Sbrooks		case FTS_SL:
105244541Sbrooks			break;
106244541Sbrooks		case FTS_DP:
107244541Sbrooks			if (specdepth > p->fts_level) {
108244541Sbrooks				for (level = level->parent; level->prev;
109244541Sbrooks				    level = level->prev)
110244541Sbrooks					continue;
111244541Sbrooks				--specdepth;
112244541Sbrooks			}
113244541Sbrooks			continue;
114244541Sbrooks		case FTS_DNR:
115244541Sbrooks		case FTS_ERR:
116244541Sbrooks		case FTS_NS:
117244541Sbrooks			warnx("%s: %s", RP(p), strerror(p->fts_errno));
118244541Sbrooks			continue;
119244541Sbrooks		default:
120244541Sbrooks			if (dflag)
121244541Sbrooks				continue;
122244541Sbrooks		}
123244541Sbrooks
124244541Sbrooks		if (specdepth != p->fts_level)
125244541Sbrooks			goto extra;
126244541Sbrooks		for (ep = level; ep; ep = ep->next)
127244541Sbrooks			if ((ep->flags & F_MAGIC &&
128244541Sbrooks			    !fnmatch(ep->name, p->fts_name, FNM_PATHNAME)) ||
129244541Sbrooks			    !strcmp(ep->name, p->fts_name)) {
130244541Sbrooks				ep->flags |= F_VISIT;
131244541Sbrooks				if ((ep->flags & F_NOCHANGE) == 0 &&
132244541Sbrooks				    compare(ep, p))
133244541Sbrooks					rval = MISMATCHEXIT;
134244541Sbrooks				if (!(ep->flags & F_IGN) &&
135244541Sbrooks				    ep->type == F_DIR &&
136244541Sbrooks				    p->fts_info == FTS_D) {
137244541Sbrooks					if (ep->child) {
138244541Sbrooks						level = ep->child;
139244541Sbrooks						++specdepth;
140244541Sbrooks					}
141244541Sbrooks				} else
142244541Sbrooks					fts_set(t, p, FTS_SKIP);
143244541Sbrooks				break;
144244541Sbrooks			}
145244541Sbrooks
146244541Sbrooks		if (ep)
147244541Sbrooks			continue;
148244541Sbrooks extra:
149244541Sbrooks		if (!eflag && !(dflag && p->fts_info == FTS_SL)) {
150244541Sbrooks			printf("extra: %s", RP(p));
151244541Sbrooks			if (rflag) {
152244541Sbrooks				if ((S_ISDIR(p->fts_statp->st_mode)
153244541Sbrooks				    ? rmdir : unlink)(p->fts_accpath)) {
154244541Sbrooks					printf(", not removed: %s",
155244541Sbrooks					    strerror(errno));
156244541Sbrooks				} else
157244541Sbrooks					printf(", removed");
158244541Sbrooks			}
159244541Sbrooks			putchar('\n');
160244541Sbrooks		}
161244541Sbrooks		fts_set(t, p, FTS_SKIP);
162244541Sbrooks	}
163244541Sbrooks	fts_close(t);
164244541Sbrooks	if (sflag)
165244541Sbrooks		warnx("%s checksum: %u", fullpath, crc_total);
166244541Sbrooks	return (rval);
167244541Sbrooks}
168244541Sbrooks
169244541Sbrooksstatic void
170244541Sbrooksmiss(NODE *p, char *tail)
171244541Sbrooks{
172244541Sbrooks	int create;
173244541Sbrooks	char *tp;
174244541Sbrooks	const char *type;
175244541Sbrooks	u_int32_t flags;
176244541Sbrooks
177244541Sbrooks	for (; p; p = p->next) {
178244541Sbrooks		if (p->flags & F_OPT && !(p->flags & F_VISIT))
179244541Sbrooks			continue;
180244541Sbrooks		if (p->type != F_DIR && (dflag || p->flags & F_VISIT))
181244541Sbrooks			continue;
182244541Sbrooks		strcpy(tail, p->name);
183244541Sbrooks		if (!(p->flags & F_VISIT)) {
184244541Sbrooks			/* Don't print missing message if file exists as a
185244541Sbrooks			   symbolic link and the -q flag is set. */
186244541Sbrooks			struct stat statbuf;
187244541Sbrooks
188244541Sbrooks			if (qflag && stat(path, &statbuf) == 0 &&
189244541Sbrooks			    S_ISDIR(statbuf.st_mode))
190244541Sbrooks				p->flags |= F_VISIT;
191244541Sbrooks			else
192244541Sbrooks				(void)printf("%s missing", path);
193244541Sbrooks		}
194244541Sbrooks		switch (p->type) {
195244541Sbrooks		case F_BLOCK:
196244541Sbrooks		case F_CHAR:
197244541Sbrooks			type = "device";
198244541Sbrooks			break;
199244541Sbrooks		case F_DIR:
200244541Sbrooks			type = "directory";
201244541Sbrooks			break;
202244541Sbrooks		case F_LINK:
203244541Sbrooks			type = "symlink";
204244541Sbrooks			break;
205244541Sbrooks		default:
206244541Sbrooks			putchar('\n');
207244541Sbrooks			continue;
208244541Sbrooks		}
209244541Sbrooks
210244541Sbrooks		create = 0;
211244541Sbrooks		if (!(p->flags & F_VISIT) && uflag) {
212244541Sbrooks			if (mtree_Wflag || p->type == F_LINK)
213244541Sbrooks				goto createit;
214244541Sbrooks			if (!(p->flags & (F_UID | F_UNAME)))
215244541Sbrooks			    printf(
216244541Sbrooks				" (%s not created: user not specified)", type);
217244541Sbrooks			else if (!(p->flags & (F_GID | F_GNAME)))
218244541Sbrooks			    printf(
219244541Sbrooks				" (%s not created: group not specified)", type);
220244541Sbrooks			else if (!(p->flags & F_MODE))
221244541Sbrooks			    printf(
222244541Sbrooks				" (%s not created: mode not specified)", type);
223244541Sbrooks			else
224244541Sbrooks createit:
225244541Sbrooks			switch (p->type) {
226244541Sbrooks			case F_BLOCK:
227244541Sbrooks			case F_CHAR:
228244541Sbrooks				if (mtree_Wflag)
229244541Sbrooks					continue;
230244541Sbrooks				if (!(p->flags & F_DEV))
231244541Sbrooks					printf(
232244541Sbrooks				    " (%s not created: device not specified)",
233244541Sbrooks					    type);
234244541Sbrooks				else if (mknod(path,
235244541Sbrooks				    p->st_mode | nodetoino(p->type),
236244541Sbrooks				    p->st_rdev) == -1)
237244541Sbrooks					printf(" (%s not created: %s)\n",
238244541Sbrooks					    type, strerror(errno));
239244541Sbrooks				else
240244541Sbrooks					create = 1;
241244541Sbrooks				break;
242244541Sbrooks			case F_LINK:
243244541Sbrooks				if (!(p->flags & F_SLINK))
244244541Sbrooks					printf(
245244541Sbrooks				    " (%s not created: link not specified)\n",
246244541Sbrooks					    type);
247244541Sbrooks				else if (symlink(p->slink, path))
248244541Sbrooks					printf(
249244541Sbrooks					    " (%s not created: %s)\n",
250244541Sbrooks					    type, strerror(errno));
251244541Sbrooks				else
252244541Sbrooks					create = 1;
253244541Sbrooks				break;
254244541Sbrooks			case F_DIR:
255244541Sbrooks				if (mkdir(path, S_IRWXU|S_IRWXG|S_IRWXO))
256244541Sbrooks					printf(" (not created: %s)",
257244541Sbrooks					    strerror(errno));
258244541Sbrooks				else
259244541Sbrooks					create = 1;
260244541Sbrooks				break;
261244541Sbrooks			default:
262244541Sbrooks				mtree_err("can't create create %s",
263244541Sbrooks				    nodetype(p->type));
264244541Sbrooks			}
265244541Sbrooks		}
266244541Sbrooks		if (create)
267244541Sbrooks			printf(" (created)");
268244541Sbrooks		if (p->type == F_DIR) {
269244541Sbrooks			if (!(p->flags & F_VISIT))
270244541Sbrooks				putchar('\n');
271244541Sbrooks			for (tp = tail; *tp; ++tp)
272244541Sbrooks				continue;
273244541Sbrooks			*tp = '/';
274244541Sbrooks			miss(p->child, tp + 1);
275244541Sbrooks			*tp = '\0';
276244541Sbrooks		} else
277244541Sbrooks			putchar('\n');
278244541Sbrooks
279244541Sbrooks		if (!create || mtree_Wflag)
280244541Sbrooks			continue;
281244541Sbrooks		if ((p->flags & (F_UID | F_UNAME)) &&
282244541Sbrooks		    (p->flags & (F_GID | F_GNAME)) &&
283244541Sbrooks		    (lchown(path, p->st_uid, p->st_gid))) {
284244541Sbrooks			printf("%s: user/group/mode not modified: %s\n",
285244541Sbrooks			    path, strerror(errno));
286244541Sbrooks			printf("%s: warning: file mode %snot set\n", path,
287244541Sbrooks			    (p->flags & F_FLAGS) ? "and file flags " : "");
288244541Sbrooks			continue;
289244541Sbrooks		}
290244541Sbrooks		if (p->flags & F_MODE) {
291244541Sbrooks			if (lchmod(path, p->st_mode))
292244541Sbrooks				printf("%s: permissions not set: %s\n",
293244541Sbrooks				    path, strerror(errno));
294244541Sbrooks		}
295244541Sbrooks#if HAVE_STRUCT_STAT_ST_FLAGS
296244541Sbrooks		if ((p->flags & F_FLAGS) && p->st_flags) {
297244541Sbrooks			if (iflag)
298244541Sbrooks				flags = p->st_flags;
299244541Sbrooks			else
300244541Sbrooks				flags = p->st_flags & ~SP_FLGS;
301244541Sbrooks			if (lchflags(path, flags))
302244541Sbrooks				printf("%s: file flags not set: %s\n",
303244541Sbrooks				    path, strerror(errno));
304244541Sbrooks		}
305244541Sbrooks#endif	/* HAVE_STRUCT_STAT_ST_FLAGS */
306244541Sbrooks	}
307244541Sbrooks}
308