verify.c revision 122135
1168404Spjd/*-
2168404Spjd * Copyright (c) 1990, 1993
3168404Spjd *	The Regents of the University of California.  All rights reserved.
4168404Spjd *
5168404Spjd * Redistribution and use in source and binary forms, with or without
6168404Spjd * modification, are permitted provided that the following conditions
7168404Spjd * are met:
8168404Spjd * 1. Redistributions of source code must retain the above copyright
9168404Spjd *    notice, this list of conditions and the following disclaimer.
10168404Spjd * 2. Redistributions in binary form must reproduce the above copyright
11168404Spjd *    notice, this list of conditions and the following disclaimer in the
12168404Spjd *    documentation and/or other materials provided with the distribution.
13168404Spjd * 3. Neither the name of the University nor the names of its contributors
14168404Spjd *    may be used to endorse or promote products derived from this software
15168404Spjd *    without specific prior written permission.
16168404Spjd *
17168404Spjd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18168404Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19168404Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20168404Spjd * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21168404Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22168404Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23168404Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24168404Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25168404Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26168404Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27168404Spjd * SUCH DAMAGE.
28168404Spjd */
29168404Spjd
30168404Spjd#if 0
31168404Spjd#ifndef lint
32168404Spjdstatic char sccsid[] = "@(#)verify.c	8.1 (Berkeley) 6/6/93";
33168404Spjd#endif /* not lint */
34168404Spjd#endif
35168404Spjd#include <sys/cdefs.h>
36168404Spjd__FBSDID("$FreeBSD: head/usr.sbin/mtree/verify.c 122135 2003-11-05 20:07:40Z phk $");
37168404Spjd
38168404Spjd#include <sys/param.h>
39168404Spjd#include <sys/stat.h>
40168404Spjd#include <dirent.h>
41168404Spjd#include <err.h>
42168404Spjd#include <errno.h>
43168404Spjd#include <fts.h>
44168404Spjd#include <fnmatch.h>
45168404Spjd#include <stdio.h>
46168404Spjd#include <unistd.h>
47168404Spjd#include "mtree.h"
48168404Spjd#include "extern.h"
49168404Spjd
50168404Spjdextern int ftsoptions;
51168404Spjdextern int dflag, eflag, qflag, rflag, sflag, uflag;
52168404Spjdextern char fullpath[MAXPATHLEN];
53168404Spjdextern int lineno;
54168404Spjd
55168404Spjdstatic NODE *root;
56168404Spjdstatic char path[MAXPATHLEN];
57168404Spjd
58168404Spjdstatic void	miss(NODE *, char *);
59168404Spjdstatic int	vwalk(void);
60168404Spjd
61168404Spjdint
62168404Spjdmtree_verifyspec(FILE *fi)
63168404Spjd{
64168404Spjd	int rval;
65168404Spjd
66168404Spjd	root = mtree_readspec(fi);
67168404Spjd	rval = vwalk();
68168404Spjd	miss(root, path);
69168404Spjd	return (rval);
70168404Spjd}
71168404Spjd
72168404Spjdstatic int
73168404Spjdvwalk(void)
74168404Spjd{
75168404Spjd	FTS *t;
76168404Spjd	FTSENT *p;
77168404Spjd	NODE *ep, *level;
78168404Spjd	int specdepth, rval;
79168404Spjd	char *argv[2];
80168404Spjd	char dot[] = ".";
81168404Spjd
82168404Spjd	argv[0] = dot;
83168404Spjd	argv[1] = NULL;
84168404Spjd	if ((t = fts_open(argv, ftsoptions, NULL)) == NULL)
85168404Spjd		err(1, "line %d: fts_open", lineno);
86168404Spjd	level = root;
87168404Spjd	specdepth = rval = 0;
88168404Spjd	while ((p = fts_read(t))) {
89168404Spjd		if (check_excludes(p->fts_name, p->fts_path)) {
90168404Spjd			fts_set(t, p, FTS_SKIP);
91168404Spjd			continue;
92168404Spjd		}
93168404Spjd		switch(p->fts_info) {
94168404Spjd		case FTS_D:
95168404Spjd		case FTS_SL:
96168404Spjd			break;
97168404Spjd		case FTS_DP:
98168404Spjd			if (specdepth > p->fts_level) {
99168404Spjd				for (level = level->parent; level->prev;
100168404Spjd				      level = level->prev);
101168404Spjd				--specdepth;
102168404Spjd			}
103168404Spjd			continue;
104168404Spjd		case FTS_DNR:
105168404Spjd		case FTS_ERR:
106168404Spjd		case FTS_NS:
107168404Spjd			warnx("%s: %s", RP(p), strerror(p->fts_errno));
108168404Spjd			continue;
109168404Spjd		default:
110168404Spjd			if (dflag)
111168404Spjd				continue;
112168404Spjd		}
113168404Spjd
114168404Spjd		if (specdepth != p->fts_level)
115168404Spjd			goto extra;
116168404Spjd		for (ep = level; ep; ep = ep->next)
117168404Spjd			if ((ep->flags & F_MAGIC &&
118168404Spjd			    !fnmatch(ep->name, p->fts_name, FNM_PATHNAME)) ||
119168404Spjd			    !strcmp(ep->name, p->fts_name)) {
120168404Spjd				ep->flags |= F_VISIT;
121168404Spjd				if ((ep->flags & F_NOCHANGE) == 0 &&
122168404Spjd				    compare(ep->name, ep, p))
123168404Spjd					rval = MISMATCHEXIT;
124168404Spjd				if (ep->flags & F_IGN)
125168404Spjd					(void)fts_set(t, p, FTS_SKIP);
126168404Spjd				else if (ep->child && ep->type == F_DIR &&
127168404Spjd				    p->fts_info == FTS_D) {
128168404Spjd					level = ep->child;
129168404Spjd					++specdepth;
130168404Spjd				}
131168404Spjd				break;
132168404Spjd			}
133168404Spjd
134168404Spjd		if (ep)
135168404Spjd			continue;
136168404Spjdextra:
137168404Spjd		if (!eflag) {
138168404Spjd			(void)printf("%s extra", RP(p));
139168404Spjd			if (rflag) {
140168404Spjd				if ((S_ISDIR(p->fts_statp->st_mode)
141168404Spjd				    ? rmdir : unlink)(p->fts_accpath)) {
142168404Spjd					(void)printf(", not removed: %s",
143168404Spjd					    strerror(errno));
144168404Spjd				} else
145168404Spjd					(void)printf(", removed");
146168404Spjd			}
147168404Spjd			(void)putchar('\n');
148168404Spjd		}
149168404Spjd		(void)fts_set(t, p, FTS_SKIP);
150168404Spjd	}
151168404Spjd	(void)fts_close(t);
152168404Spjd	if (sflag)
153168404Spjd		warnx("%s checksum: %lu", fullpath, (unsigned long)crc_total);
154168404Spjd	return (rval);
155168404Spjd}
156168404Spjd
157168404Spjdstatic void
158168404Spjdmiss(NODE *p, char *tail)
159168404Spjd{
160168404Spjd	int create;
161168404Spjd	char *tp;
162168404Spjd	const char *type;
163168404Spjd
164168404Spjd	for (; p; p = p->next) {
165168404Spjd		if (p->type != F_DIR && (dflag || p->flags & F_VISIT))
166168404Spjd			continue;
167168404Spjd		(void)strcpy(tail, p->name);
168168404Spjd		if (!(p->flags & F_VISIT)) {
169168404Spjd			/* Don't print missing message if file exists as a
170168404Spjd			   symbolic link and the -q flag is set. */
171168404Spjd			struct stat statbuf;
172168404Spjd
173168404Spjd			if (qflag && stat(path, &statbuf) == 0)
174168404Spjd				p->flags |= F_VISIT;
175168404Spjd			else
176168404Spjd				(void)printf("%s missing", path);
177168404Spjd		}
178168404Spjd		if (p->type != F_DIR && p->type != F_LINK) {
179168404Spjd			putchar('\n');
180168404Spjd			continue;
181168404Spjd		}
182168404Spjd
183168404Spjd		create = 0;
184168404Spjd		if (p->type == F_LINK)
185168404Spjd			type = "symlink";
186168404Spjd		else
187168404Spjd			type = "directory";
188168404Spjd		if (!(p->flags & F_VISIT) && uflag) {
189168404Spjd			if (!(p->flags & (F_UID | F_UNAME)))
190168404Spjd				(void)printf(" (%s not created: user not specified)", type);
191168404Spjd			else if (!(p->flags & (F_GID | F_GNAME)))
192168404Spjd				(void)printf(" (%s not created: group not specified)", type);
193168404Spjd			else if (p->type == F_LINK) {
194168404Spjd				if (symlink(p->slink, path))
195168404Spjd					(void)printf(" (symlink not created: %s)\n",
196168404Spjd					    strerror(errno));
197168404Spjd				else
198168404Spjd					(void)printf(" (created)\n");
199168404Spjd				if (lchown(path, p->st_uid, p->st_gid))
200168404Spjd					(void)printf("%s: user/group not modified: %s\n",
201168404Spjd					    path, strerror(errno));
202168404Spjd				continue;
203168404Spjd			} else if (!(p->flags & F_MODE))
204168404Spjd			    (void)printf(" (directory not created: mode not specified)");
205168404Spjd			else if (mkdir(path, S_IRWXU))
206168404Spjd				(void)printf(" (directory not created: %s)",
207168404Spjd				    strerror(errno));
208168404Spjd			else {
209168404Spjd				create = 1;
210168404Spjd				(void)printf(" (created)");
211168404Spjd			}
212168404Spjd		}
213168404Spjd		if (!(p->flags & F_VISIT))
214168404Spjd			(void)putchar('\n');
215168404Spjd
216168404Spjd		for (tp = tail; *tp; ++tp);
217168404Spjd		*tp = '/';
218168404Spjd		miss(p->child, tp + 1);
219168404Spjd		*tp = '\0';
220168404Spjd
221168404Spjd		if (!create)
222168404Spjd			continue;
223168404Spjd		if (chown(path, p->st_uid, p->st_gid)) {
224168404Spjd			(void)printf("%s: user/group/mode not modified: %s\n",
225168404Spjd			    path, strerror(errno));
226168404Spjd			(void)printf("%s: warning: file mode %snot set\n", path,
227168404Spjd			    (p->flags & F_FLAGS) ? "and file flags " : "");
228168404Spjd			continue;
229168404Spjd		}
230168404Spjd		if (chmod(path, p->st_mode))
231168404Spjd			(void)printf("%s: permissions not set: %s\n",
232168404Spjd			    path, strerror(errno));
233168404Spjd		if ((p->flags & F_FLAGS) && p->st_flags &&
234168404Spjd		    chflags(path, p->st_flags))
235168404Spjd			(void)printf("%s: file flags not set: %s\n",
236168404Spjd			    path, strerror(errno));
237168404Spjd	}
238168404Spjd}
239168404Spjd