verify.c revision 256281
1178172Simp/*-
2178172Simp * Copyright (c) 1990, 1993
3178172Simp *	The Regents of the University of California.  All rights reserved.
4178172Simp *
5178172Simp * Redistribution and use in source and binary forms, with or without
6178172Simp * modification, are permitted provided that the following conditions
7178172Simp * are met:
8178172Simp * 1. Redistributions of source code must retain the above copyright
9178172Simp *    notice, this list of conditions and the following disclaimer.
10178172Simp * 2. Redistributions in binary form must reproduce the above copyright
11178172Simp *    notice, this list of conditions and the following disclaimer in the
12178172Simp *    documentation and/or other materials provided with the distribution.
13178172Simp * 3. Neither the name of the University nor the names of its contributors
14178172Simp *    may be used to endorse or promote products derived from this software
15178172Simp *    without specific prior written permission.
16178172Simp *
17178172Simp * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18178172Simp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19178172Simp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20178172Simp * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21178172Simp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22178172Simp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23178172Simp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24178172Simp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25178172Simp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26178172Simp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27178172Simp * SUCH DAMAGE.
28178172Simp */
29178172Simp
30178172Simp#if 0
31178172Simp#ifndef lint
32178172Simpstatic char sccsid[] = "@(#)verify.c	8.1 (Berkeley) 6/6/93";
33178172Simp#endif /* not lint */
34178172Simp#endif
35178172Simp#include <sys/cdefs.h>
36178172Simp__FBSDID("$FreeBSD: stable/10/usr.sbin/mtree/verify.c 174403 2007-12-07 12:22:38Z des $");
37178172Simp
38178172Simp#include <sys/param.h>
39178172Simp#include <sys/stat.h>
40178172Simp#include <dirent.h>
41178172Simp#include <err.h>
42178172Simp#include <errno.h>
43178172Simp#include <fts.h>
44178172Simp#include <fnmatch.h>
45178172Simp#include <stdio.h>
46178172Simp#include <unistd.h>
47178172Simp#include "mtree.h"
48178172Simp#include "extern.h"
49178172Simp
50178172Simpstatic NODE *root;
51178172Simpstatic char path[MAXPATHLEN];
52178172Simp
53178172Simpstatic void	miss(NODE *, char *);
54178172Simpstatic int	vwalk(void);
55178172Simp
56178172Simpint
57178172Simpmtree_verifyspec(FILE *fi)
58178172Simp{
59178172Simp	int rval;
60178172Simp
61178172Simp	root = mtree_readspec(fi);
62178172Simp	rval = vwalk();
63178172Simp	miss(root, path);
64178172Simp	return (rval);
65178172Simp}
66178172Simp
67178172Simpstatic int
68178172Simpnsort(const FTSENT * const *a, const FTSENT * const *b)
69178172Simp{
70178172Simp	return (strcmp((*a)->fts_name, (*b)->fts_name));
71178172Simp}
72178172Simp
73178172Simpstatic int
74178172Simpvwalk(void)
75178172Simp{
76178172Simp	FTS *t;
77178172Simp	FTSENT *p;
78178172Simp	NODE *ep, *level;
79178172Simp	int specdepth, rval;
80178172Simp	char *argv[2];
81178172Simp	char dot[] = ".";
82178172Simp
83178172Simp	argv[0] = dot;
84178172Simp	argv[1] = NULL;
85178172Simp	if ((t = fts_open(argv, ftsoptions, nsort)) == NULL)
86178172Simp		err(1, "line %d: fts_open", lineno);
87178172Simp	level = root;
88178172Simp	specdepth = rval = 0;
89178172Simp	while ((p = fts_read(t))) {
90178172Simp		if (check_excludes(p->fts_name, p->fts_path)) {
91178172Simp			fts_set(t, p, FTS_SKIP);
92178172Simp			continue;
93178172Simp		}
94178172Simp		switch(p->fts_info) {
95178172Simp		case FTS_D:
96178172Simp		case FTS_SL:
97178172Simp			break;
98178172Simp		case FTS_DP:
99178172Simp			if (specdepth > p->fts_level) {
100178172Simp				for (level = level->parent; level->prev;
101178172Simp				      level = level->prev);
102178172Simp				--specdepth;
103178172Simp			}
104178172Simp			continue;
105178172Simp		case FTS_DNR:
106178172Simp		case FTS_ERR:
107178172Simp		case FTS_NS:
108178172Simp			warnx("%s: %s", RP(p), strerror(p->fts_errno));
109178172Simp			continue;
110178172Simp		default:
111211159Sneel			if (dflag)
112211159Sneel				continue;
113211159Sneel		}
114211159Sneel
115211159Sneel		if (specdepth != p->fts_level)
116211159Sneel			goto extra;
117178172Simp		for (ep = level; ep; ep = ep->next)
118178172Simp			if ((ep->flags & F_MAGIC &&
119178172Simp			    !fnmatch(ep->name, p->fts_name, FNM_PATHNAME)) ||
120178172Simp			    !strcmp(ep->name, p->fts_name)) {
121178172Simp				ep->flags |= F_VISIT;
122178172Simp				if ((ep->flags & F_NOCHANGE) == 0 &&
123178172Simp				    compare(ep->name, ep, p))
124178172Simp					rval = MISMATCHEXIT;
125178172Simp				if (ep->flags & F_IGN)
126178172Simp					(void)fts_set(t, p, FTS_SKIP);
127178172Simp				else if (ep->child && ep->type == F_DIR &&
128178172Simp				    p->fts_info == FTS_D) {
129178172Simp					level = ep->child;
130178172Simp					++specdepth;
131178172Simp				}
132178172Simp				break;
133178172Simp			}
134178172Simp
135178172Simp		if (ep)
136178172Simp			continue;
137178172Simpextra:
138178172Simp		if (!eflag) {
139178172Simp			(void)printf("%s extra", RP(p));
140178172Simp			if (rflag) {
141178172Simp				if ((S_ISDIR(p->fts_statp->st_mode)
142178172Simp				    ? rmdir : unlink)(p->fts_accpath)) {
143178172Simp					(void)printf(", not removed: %s",
144178172Simp					    strerror(errno));
145178172Simp				} else
146178172Simp					(void)printf(", removed");
147			}
148			(void)putchar('\n');
149		}
150		(void)fts_set(t, p, FTS_SKIP);
151	}
152	(void)fts_close(t);
153	if (sflag)
154		warnx("%s checksum: %lu", fullpath, (unsigned long)crc_total);
155	return (rval);
156}
157
158static void
159miss(NODE *p, char *tail)
160{
161	int create;
162	char *tp;
163	const char *type, *what;
164	int serr;
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("%s missing", path);
181		}
182		if (p->type != F_DIR && p->type != F_LINK) {
183			putchar('\n');
184			continue;
185		}
186
187		create = 0;
188		if (p->type == F_LINK)
189			type = "symlink";
190		else
191			type = "directory";
192		if (!(p->flags & F_VISIT) && uflag) {
193			if (!(p->flags & (F_UID | F_UNAME)))
194				(void)printf(" (%s not created: user not specified)", type);
195			else if (!(p->flags & (F_GID | F_GNAME)))
196				(void)printf(" (%s not created: group not specified)", type);
197			else if (p->type == F_LINK) {
198				if (symlink(p->slink, path))
199					(void)printf(" (symlink not created: %s)\n",
200					    strerror(errno));
201				else
202					(void)printf(" (created)\n");
203				if (lchown(path, p->st_uid, p->st_gid) == -1) {
204					serr = errno;
205					if (p->st_uid == (uid_t)-1)
206						what = "group";
207					else if (lchown(path, (uid_t)-1,
208					    p->st_gid) == -1)
209						what = "user & group";
210					else {
211						what = "user";
212						errno = serr;
213					}
214					(void)printf("%s: %s not modified: %s"
215					    "\n", path, what, strerror(errno));
216				}
217				continue;
218			} else if (!(p->flags & F_MODE))
219			    (void)printf(" (directory not created: mode not specified)");
220			else if (mkdir(path, S_IRWXU))
221				(void)printf(" (directory not created: %s)",
222				    strerror(errno));
223			else {
224				create = 1;
225				(void)printf(" (created)");
226			}
227		}
228		if (!(p->flags & F_VISIT))
229			(void)putchar('\n');
230
231		for (tp = tail; *tp; ++tp);
232		*tp = '/';
233		miss(p->child, tp + 1);
234		*tp = '\0';
235
236		if (!create)
237			continue;
238		if (chown(path, p->st_uid, p->st_gid) == -1) {
239			serr = errno;
240			if (p->st_uid == (uid_t)-1)
241				what = "group";
242			else if (chown(path, (uid_t)-1, p->st_gid) == -1)
243				what = "user & group";
244			else {
245				what = "user";
246				errno = serr;
247			}
248			(void)printf("%s: %s not modified: %s\n",
249			    path, what, strerror(errno));
250		}
251		if (chmod(path, p->st_mode))
252			(void)printf("%s: permissions not set: %s\n",
253			    path, strerror(errno));
254		if ((p->flags & F_FLAGS) && p->st_flags &&
255		    chflags(path, p->st_flags))
256			(void)printf("%s: file flags not set: %s\n",
257			    path, strerror(errno));
258	}
259}
260