xref: /minix3/usr.sbin/mtree/compare.c (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
184d9c625SLionel Sambuc /*	$NetBSD: compare.c,v 1.58 2013/11/21 18:39:50 christos Exp $	*/
2d433a562SThomas Veerman 
3d433a562SThomas Veerman /*-
4d433a562SThomas Veerman  * Copyright (c) 1989, 1993
5d433a562SThomas Veerman  *	The Regents of the University of California.  All rights reserved.
6d433a562SThomas Veerman  *
7d433a562SThomas Veerman  * Redistribution and use in source and binary forms, with or without
8d433a562SThomas Veerman  * modification, are permitted provided that the following conditions
9d433a562SThomas Veerman  * are met:
10d433a562SThomas Veerman  * 1. Redistributions of source code must retain the above copyright
11d433a562SThomas Veerman  *    notice, this list of conditions and the following disclaimer.
12d433a562SThomas Veerman  * 2. Redistributions in binary form must reproduce the above copyright
13d433a562SThomas Veerman  *    notice, this list of conditions and the following disclaimer in the
14d433a562SThomas Veerman  *    documentation and/or other materials provided with the distribution.
15d433a562SThomas Veerman  * 3. Neither the name of the University nor the names of its contributors
16d433a562SThomas Veerman  *    may be used to endorse or promote products derived from this software
17d433a562SThomas Veerman  *    without specific prior written permission.
18d433a562SThomas Veerman  *
19d433a562SThomas Veerman  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20d433a562SThomas Veerman  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21d433a562SThomas Veerman  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22d433a562SThomas Veerman  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23d433a562SThomas Veerman  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24d433a562SThomas Veerman  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25d433a562SThomas Veerman  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26d433a562SThomas Veerman  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27d433a562SThomas Veerman  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28d433a562SThomas Veerman  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29d433a562SThomas Veerman  * SUCH DAMAGE.
30d433a562SThomas Veerman  */
31d433a562SThomas Veerman 
32d433a562SThomas Veerman #if HAVE_NBTOOL_CONFIG_H
33d433a562SThomas Veerman #include "nbtool_config.h"
34d433a562SThomas Veerman #endif
35d433a562SThomas Veerman 
36d433a562SThomas Veerman #include <sys/cdefs.h>
37d433a562SThomas Veerman #if defined(__RCSID) && !defined(lint)
38d433a562SThomas Veerman #if 0
39d433a562SThomas Veerman static char sccsid[] = "@(#)compare.c	8.1 (Berkeley) 6/6/93";
40d433a562SThomas Veerman #else
4184d9c625SLionel Sambuc __RCSID("$NetBSD: compare.c,v 1.58 2013/11/21 18:39:50 christos Exp $");
42d433a562SThomas Veerman #endif
43d433a562SThomas Veerman #endif /* not lint */
44d433a562SThomas Veerman 
45d433a562SThomas Veerman #include <sys/param.h>
46a8ef0910SBen Gras #include <sys/stat.h>
47d433a562SThomas Veerman 
48d433a562SThomas Veerman #include <errno.h>
49d433a562SThomas Veerman #include <fcntl.h>
50d433a562SThomas Veerman #include <stdio.h>
5184d9c625SLionel Sambuc #include <stdint.h>
52d433a562SThomas Veerman #include <stdlib.h>
53d433a562SThomas Veerman #include <string.h>
54d433a562SThomas Veerman #include <time.h>
55d433a562SThomas Veerman #include <unistd.h>
56d433a562SThomas Veerman 
57d433a562SThomas Veerman #ifndef NO_MD5
58d433a562SThomas Veerman #include <md5.h>
59d433a562SThomas Veerman #endif
60d433a562SThomas Veerman #ifndef NO_RMD160
61d433a562SThomas Veerman #include <rmd160.h>
62d433a562SThomas Veerman #endif
63d433a562SThomas Veerman #ifndef NO_SHA1
64d433a562SThomas Veerman #include <sha1.h>
65d433a562SThomas Veerman #endif
66d433a562SThomas Veerman #ifndef NO_SHA2
67d433a562SThomas Veerman #include <sha2.h>
68d433a562SThomas Veerman #endif
69d433a562SThomas Veerman 
70d433a562SThomas Veerman #include "extern.h"
71d433a562SThomas Veerman 
72d433a562SThomas Veerman #define	INDENTNAMELEN	8
73d433a562SThomas Veerman #define MARK								\
74d433a562SThomas Veerman do {									\
7584d9c625SLionel Sambuc 	if (flavor == F_FREEBSD9) {					\
7684d9c625SLionel Sambuc 		len = printf("%s changed\n", RP(p));			\
7784d9c625SLionel Sambuc 		tab = "\t";						\
7884d9c625SLionel Sambuc 	} else {							\
79d433a562SThomas Veerman 		len = printf("%s: ", RP(p));				\
80d433a562SThomas Veerman 		if (len > INDENTNAMELEN) {				\
81d433a562SThomas Veerman 			tab = "\t";					\
82d433a562SThomas Veerman 			printf("\n");					\
83d433a562SThomas Veerman 		} else {						\
84d433a562SThomas Veerman 			tab = "";					\
85d433a562SThomas Veerman 			printf("%*s", INDENTNAMELEN - (int)len, "");	\
86d433a562SThomas Veerman 		}							\
8784d9c625SLionel Sambuc 	}								\
88d433a562SThomas Veerman } while (0)
89d433a562SThomas Veerman #define	LABEL if (!label++) MARK
90d433a562SThomas Veerman 
91d433a562SThomas Veerman #if HAVE_STRUCT_STAT_ST_FLAGS
92d433a562SThomas Veerman 
93a8ef0910SBen Gras 
94d433a562SThomas Veerman #define CHANGEFLAGS							\
95d433a562SThomas Veerman 	if (flags != p->fts_statp->st_flags) {				\
96d433a562SThomas Veerman 		char *sf;						\
97d433a562SThomas Veerman 		if (!label) {						\
98d433a562SThomas Veerman 			MARK;						\
99d433a562SThomas Veerman 			sf = flags_to_string(p->fts_statp->st_flags, "none"); \
100d433a562SThomas Veerman 			printf("%sflags (\"%s\"", tab, sf);		\
101d433a562SThomas Veerman 			free(sf);					\
102d433a562SThomas Veerman 		}							\
103d433a562SThomas Veerman 		if (lchflags(p->fts_accpath, flags)) {			\
104d433a562SThomas Veerman 			label++;					\
105d433a562SThomas Veerman 			printf(", not modified: %s)\n",			\
106d433a562SThomas Veerman 			    strerror(errno));				\
107d433a562SThomas Veerman 		} else {						\
108d433a562SThomas Veerman 			sf = flags_to_string(flags, "none");		\
109d433a562SThomas Veerman 			printf(", modified to \"%s\")\n", sf);		\
110d433a562SThomas Veerman 			free(sf);					\
111d433a562SThomas Veerman 		}							\
112d433a562SThomas Veerman 	}
113d433a562SThomas Veerman 
114d433a562SThomas Veerman /* SETFLAGS:
115d433a562SThomas Veerman  * given pflags, additionally set those flags specified in s->st_flags and
116d433a562SThomas Veerman  * selected by mask (the other flags are left unchanged).
117d433a562SThomas Veerman  */
118d433a562SThomas Veerman #define SETFLAGS(pflags, mask)						\
119d433a562SThomas Veerman do {									\
120d433a562SThomas Veerman 	flags = (s->st_flags & (mask)) | (pflags);			\
121d433a562SThomas Veerman 	CHANGEFLAGS;							\
122d433a562SThomas Veerman } while (0)
123d433a562SThomas Veerman 
124d433a562SThomas Veerman /* CLEARFLAGS:
125d433a562SThomas Veerman  * given pflags, reset the flags specified in s->st_flags and selected by mask
126d433a562SThomas Veerman  * (the other flags are left unchanged).
127d433a562SThomas Veerman  */
128d433a562SThomas Veerman #define CLEARFLAGS(pflags, mask)					\
129d433a562SThomas Veerman do {									\
130d433a562SThomas Veerman 	flags = (~(s->st_flags & (mask)) & CH_MASK) & (pflags);		\
131d433a562SThomas Veerman 	CHANGEFLAGS;							\
132d433a562SThomas Veerman } while (0)
133d433a562SThomas Veerman #endif	/* HAVE_STRUCT_STAT_ST_FLAGS */
134d433a562SThomas Veerman 
135d433a562SThomas Veerman int
compare(NODE * s,FTSENT * p)136d433a562SThomas Veerman compare(NODE *s, FTSENT *p)
137d433a562SThomas Veerman {
138*0a6a1f1dSLionel Sambuc 	u_int32_t len, val, flags;
139d433a562SThomas Veerman 	int fd, label;
140d433a562SThomas Veerman 	const char *cp, *tab;
141d433a562SThomas Veerman #if !defined(NO_MD5) || !defined(NO_RMD160) || !defined(NO_SHA1) || !defined(NO_SHA2)
142d433a562SThomas Veerman 	char *digestbuf;
143d433a562SThomas Veerman #endif
144d433a562SThomas Veerman 
145d433a562SThomas Veerman 	tab = NULL;
146d433a562SThomas Veerman 	label = 0;
147d433a562SThomas Veerman 	switch(s->type) {
148d433a562SThomas Veerman 	case F_BLOCK:
149d433a562SThomas Veerman 		if (!S_ISBLK(p->fts_statp->st_mode))
150d433a562SThomas Veerman 			goto typeerr;
151d433a562SThomas Veerman 		break;
152d433a562SThomas Veerman 	case F_CHAR:
153d433a562SThomas Veerman 		if (!S_ISCHR(p->fts_statp->st_mode))
154d433a562SThomas Veerman 			goto typeerr;
155d433a562SThomas Veerman 		break;
156d433a562SThomas Veerman 	case F_DIR:
157d433a562SThomas Veerman 		if (!S_ISDIR(p->fts_statp->st_mode))
158d433a562SThomas Veerman 			goto typeerr;
159d433a562SThomas Veerman 		break;
160d433a562SThomas Veerman 	case F_FIFO:
161d433a562SThomas Veerman 		if (!S_ISFIFO(p->fts_statp->st_mode))
162d433a562SThomas Veerman 			goto typeerr;
163d433a562SThomas Veerman 		break;
164d433a562SThomas Veerman 	case F_FILE:
165d433a562SThomas Veerman 		if (!S_ISREG(p->fts_statp->st_mode))
166d433a562SThomas Veerman 			goto typeerr;
167d433a562SThomas Veerman 		break;
168d433a562SThomas Veerman 	case F_LINK:
169d433a562SThomas Veerman 		if (!S_ISLNK(p->fts_statp->st_mode))
170d433a562SThomas Veerman 			goto typeerr;
171d433a562SThomas Veerman 		break;
172d433a562SThomas Veerman #ifdef S_ISSOCK
173d433a562SThomas Veerman 	case F_SOCK:
174d433a562SThomas Veerman 		if (!S_ISSOCK(p->fts_statp->st_mode))
175d433a562SThomas Veerman 			goto typeerr;
176d433a562SThomas Veerman 		break;
177d433a562SThomas Veerman #endif
178d433a562SThomas Veerman typeerr:		LABEL;
17984d9c625SLionel Sambuc 		printf(flavor == F_FREEBSD9 ?
18084d9c625SLionel Sambuc 		    "\ttype expected %s found %s\n" : "\ttype (%s, %s)\n",
181d433a562SThomas Veerman 		    nodetype(s->type), inotype(p->fts_statp->st_mode));
182d433a562SThomas Veerman 		return (label);
183d433a562SThomas Veerman 	}
184d433a562SThomas Veerman 	if (mtree_Wflag)
185d433a562SThomas Veerman 		goto afterpermwhack;
186a8ef0910SBen Gras #if HAVE_STRUCT_STAT_ST_FLAGS
187d433a562SThomas Veerman 	if (iflag && !uflag) {
188d433a562SThomas Veerman 		if (s->flags & F_FLAGS)
189d433a562SThomas Veerman 		    SETFLAGS(p->fts_statp->st_flags, SP_FLGS);
190d433a562SThomas Veerman 		return (label);
191d433a562SThomas Veerman         }
192d433a562SThomas Veerman 	if (mflag && !uflag) {
193d433a562SThomas Veerman 		if (s->flags & F_FLAGS)
194d433a562SThomas Veerman 		    CLEARFLAGS(p->fts_statp->st_flags, SP_FLGS);
195d433a562SThomas Veerman 		return (label);
196d433a562SThomas Veerman         }
197d433a562SThomas Veerman #endif
198d433a562SThomas Veerman 	if (s->flags & F_DEV &&
199d433a562SThomas Veerman 	    (s->type == F_BLOCK || s->type == F_CHAR) &&
200d433a562SThomas Veerman 	    s->st_rdev != p->fts_statp->st_rdev) {
201d433a562SThomas Veerman 		LABEL;
20284d9c625SLionel Sambuc 		printf(flavor == F_FREEBSD9 ?
20384d9c625SLionel Sambuc 		    "%sdevice expected %#jx found %#jx" :
20484d9c625SLionel Sambuc 		    "%sdevice (%#jx, %#jx",
20584d9c625SLionel Sambuc 		    tab, (uintmax_t)s->st_rdev,
20684d9c625SLionel Sambuc 		    (uintmax_t)p->fts_statp->st_rdev);
207d433a562SThomas Veerman 		if (uflag) {
208d433a562SThomas Veerman 			if ((unlink(p->fts_accpath) == -1) ||
209d433a562SThomas Veerman 			    (mknod(p->fts_accpath,
210d433a562SThomas Veerman 			      s->st_mode | nodetoino(s->type),
211d433a562SThomas Veerman 			      s->st_rdev) == -1) ||
212d433a562SThomas Veerman 			    (lchown(p->fts_accpath, p->fts_statp->st_uid,
213d433a562SThomas Veerman 			      p->fts_statp->st_gid) == -1) )
21484d9c625SLionel Sambuc 				printf(", not modified: %s%s\n",
21584d9c625SLionel Sambuc 				    strerror(errno),
21684d9c625SLionel Sambuc 				    flavor == F_FREEBSD9 ? "" : ")");
217d433a562SThomas Veerman 			 else
21884d9c625SLionel Sambuc 				printf(", modified%s\n",
21984d9c625SLionel Sambuc 				    flavor == F_FREEBSD9 ? "" : ")");
220d433a562SThomas Veerman 		} else
221d433a562SThomas Veerman 			printf(")\n");
222d433a562SThomas Veerman 		tab = "\t";
223d433a562SThomas Veerman 	}
224d433a562SThomas Veerman 	/* Set the uid/gid first, then set the mode. */
225d433a562SThomas Veerman 	if (s->flags & (F_UID | F_UNAME) && s->st_uid != p->fts_statp->st_uid) {
226d433a562SThomas Veerman 		LABEL;
22784d9c625SLionel Sambuc 		printf(flavor == F_FREEBSD9 ?
22884d9c625SLionel Sambuc 		    "%suser expected %lu found %lu" : "%suser (%lu, %lu",
229d433a562SThomas Veerman 		    tab, (u_long)s->st_uid, (u_long)p->fts_statp->st_uid);
230d433a562SThomas Veerman 		if (uflag) {
231d433a562SThomas Veerman 			if (lchown(p->fts_accpath, s->st_uid, -1))
23284d9c625SLionel Sambuc 				printf(", not modified: %s%s\n",
23384d9c625SLionel Sambuc 				    strerror(errno),
23484d9c625SLionel Sambuc 				    flavor == F_FREEBSD9 ? "" : ")");
235d433a562SThomas Veerman 			else
23684d9c625SLionel Sambuc 				printf(", modified%s\n",
23784d9c625SLionel Sambuc 				    flavor == F_FREEBSD9 ? "" : ")");
238d433a562SThomas Veerman 		} else
239d433a562SThomas Veerman 			printf(")\n");
240d433a562SThomas Veerman 		tab = "\t";
241d433a562SThomas Veerman 	}
242d433a562SThomas Veerman 	if (s->flags & (F_GID | F_GNAME) && s->st_gid != p->fts_statp->st_gid) {
243d433a562SThomas Veerman 		LABEL;
24484d9c625SLionel Sambuc 		printf(flavor == F_FREEBSD9 ?
24584d9c625SLionel Sambuc 		    "%sgid expected %lu found %lu" : "%sgid (%lu, %lu",
246d433a562SThomas Veerman 		    tab, (u_long)s->st_gid, (u_long)p->fts_statp->st_gid);
247d433a562SThomas Veerman 		if (uflag) {
248d433a562SThomas Veerman 			if (lchown(p->fts_accpath, -1, s->st_gid))
24984d9c625SLionel Sambuc 				printf(", not modified: %s%s\n",
25084d9c625SLionel Sambuc 				    strerror(errno),
25184d9c625SLionel Sambuc 				    flavor == F_FREEBSD9 ? "" : ")");
252d433a562SThomas Veerman 			else
25384d9c625SLionel Sambuc 				printf(", modified%s\n",
25484d9c625SLionel Sambuc 				    flavor == F_FREEBSD9 ? "" : ")");
255d433a562SThomas Veerman 		}
256d433a562SThomas Veerman 		else
257d433a562SThomas Veerman 			printf(")\n");
258d433a562SThomas Veerman 		tab = "\t";
259d433a562SThomas Veerman 	}
260d433a562SThomas Veerman 	if (s->flags & F_MODE &&
261d433a562SThomas Veerman 	    s->st_mode != (p->fts_statp->st_mode & MBITS)) {
262d433a562SThomas Veerman 		if (lflag) {
263d433a562SThomas Veerman 			mode_t tmode, mode;
264d433a562SThomas Veerman 
265d433a562SThomas Veerman 			tmode = s->st_mode;
266d433a562SThomas Veerman 			mode = p->fts_statp->st_mode & MBITS;
267d433a562SThomas Veerman 			/*
268d433a562SThomas Veerman 			 * if none of the suid/sgid/etc bits are set,
269d433a562SThomas Veerman 			 * then if the mode is a subset of the target,
270d433a562SThomas Veerman 			 * skip.
271d433a562SThomas Veerman 			 */
272d433a562SThomas Veerman 			if (!((tmode & ~(S_IRWXU|S_IRWXG|S_IRWXO)) ||
273d433a562SThomas Veerman 			    (mode & ~(S_IRWXU|S_IRWXG|S_IRWXO))))
274d433a562SThomas Veerman 				if ((mode | tmode) == tmode)
275d433a562SThomas Veerman 					goto skip;
276d433a562SThomas Veerman 		}
277d433a562SThomas Veerman 
278d433a562SThomas Veerman 		LABEL;
27984d9c625SLionel Sambuc 		printf(flavor == F_FREEBSD9 ?
28084d9c625SLionel Sambuc 		    "%spermissions expcted %#lo found %#lo" :
28184d9c625SLionel Sambuc 		    "%spermissions (%#lo, %#lo",
282d433a562SThomas Veerman 		    tab, (u_long)s->st_mode,
283d433a562SThomas Veerman 		    (u_long)p->fts_statp->st_mode & MBITS);
284d433a562SThomas Veerman 		if (uflag) {
285d433a562SThomas Veerman 			if (lchmod(p->fts_accpath, s->st_mode))
28684d9c625SLionel Sambuc 				printf(", not modified: %s%s\n",
28784d9c625SLionel Sambuc 				    strerror(errno),
28884d9c625SLionel Sambuc 				    flavor == F_FREEBSD9 ? "" : ")");
289d433a562SThomas Veerman 			else
29084d9c625SLionel Sambuc 				printf(", modified%s\n",
29184d9c625SLionel Sambuc 				    flavor == F_FREEBSD9 ? "" : ")");
292d433a562SThomas Veerman 		}
293d433a562SThomas Veerman 		else
294d433a562SThomas Veerman 			printf(")\n");
295d433a562SThomas Veerman 		tab = "\t";
296d433a562SThomas Veerman 	skip:	;
297d433a562SThomas Veerman 	}
298d433a562SThomas Veerman 	if (s->flags & F_NLINK && s->type != F_DIR &&
299d433a562SThomas Veerman 	    s->st_nlink != p->fts_statp->st_nlink) {
300d433a562SThomas Veerman 		LABEL;
30184d9c625SLionel Sambuc 		printf(flavor == F_FREEBSD9 ?
30284d9c625SLionel Sambuc 		    "%slink count expected %lu found %lu\n" :
30384d9c625SLionel Sambuc 		    "%slink count (%lu, %lu)\n",
304d433a562SThomas Veerman 		    tab, (u_long)s->st_nlink, (u_long)p->fts_statp->st_nlink);
305d433a562SThomas Veerman 		tab = "\t";
306d433a562SThomas Veerman 	}
307d433a562SThomas Veerman 	if (s->flags & F_SIZE && s->st_size != p->fts_statp->st_size) {
308d433a562SThomas Veerman 		LABEL;
30984d9c625SLionel Sambuc 		printf(flavor == F_FREEBSD9 ?
31084d9c625SLionel Sambuc 		    "%ssize expected %ju found %ju\n" : "%ssize (%ju, %ju)\n",
31184d9c625SLionel Sambuc 		    tab, (uintmax_t)s->st_size,
31284d9c625SLionel Sambuc 		    (uintmax_t)p->fts_statp->st_size);
313d433a562SThomas Veerman 		tab = "\t";
314d433a562SThomas Veerman 	}
315d433a562SThomas Veerman 	/*
316d433a562SThomas Veerman 	 * XXX
317d433a562SThomas Veerman 	 * Since utimes(2) only takes a timeval, there's no point in
318d433a562SThomas Veerman 	 * comparing the low bits of the timespec nanosecond field.  This
319d433a562SThomas Veerman 	 * will only result in mismatches that we can never fix.
320d433a562SThomas Veerman 	 *
321d433a562SThomas Veerman 	 * Doesn't display microsecond differences.
322d433a562SThomas Veerman 	 */
323d433a562SThomas Veerman 	if (s->flags & F_TIME) {
324d433a562SThomas Veerman 		struct timeval tv[2];
325d433a562SThomas Veerman 		struct stat *ps = p->fts_statp;
326d433a562SThomas Veerman 		time_t smtime = s->st_mtimespec.tv_sec;
327d433a562SThomas Veerman 
328d433a562SThomas Veerman #if defined(BSD4_4) && !defined(HAVE_NBTOOL_CONFIG_H)
329d433a562SThomas Veerman 		time_t pmtime = ps->st_mtimespec.tv_sec;
330d433a562SThomas Veerman 
331d433a562SThomas Veerman 		TIMESPEC_TO_TIMEVAL(&tv[0], &s->st_mtimespec);
332d433a562SThomas Veerman 		TIMESPEC_TO_TIMEVAL(&tv[1], &ps->st_mtimespec);
333d433a562SThomas Veerman #else
334d433a562SThomas Veerman 		time_t pmtime = (time_t)ps->st_mtime;
335d433a562SThomas Veerman 
336d433a562SThomas Veerman 		tv[0].tv_sec = smtime;
337d433a562SThomas Veerman 		tv[0].tv_usec = 0;
338d433a562SThomas Veerman 		tv[1].tv_sec = pmtime;
339d433a562SThomas Veerman 		tv[1].tv_usec = 0;
340d433a562SThomas Veerman #endif
341d433a562SThomas Veerman 
342d433a562SThomas Veerman 		if (tv[0].tv_sec != tv[1].tv_sec ||
343d433a562SThomas Veerman 		    tv[0].tv_usec != tv[1].tv_usec) {
344d433a562SThomas Veerman 			LABEL;
34584d9c625SLionel Sambuc 			printf(flavor == F_FREEBSD9 ?
34684d9c625SLionel Sambuc 			    "%smodification time expected %.24s found " :
34784d9c625SLionel Sambuc 			    "%smodification time (%.24s, ",
348d433a562SThomas Veerman 			    tab, ctime(&smtime));
349d433a562SThomas Veerman 			printf("%.24s", ctime(&pmtime));
350d433a562SThomas Veerman 			if (tflag) {
351d433a562SThomas Veerman 				tv[1] = tv[0];
352d433a562SThomas Veerman 				if (utimes(p->fts_accpath, tv))
35384d9c625SLionel Sambuc 					printf(", not modified: %s%s\n",
35484d9c625SLionel Sambuc 					    strerror(errno),
35584d9c625SLionel Sambuc 					    flavor == F_FREEBSD9 ? "" : ")");
356d433a562SThomas Veerman 				else
35784d9c625SLionel Sambuc 					printf(", modified%s\n",
35884d9c625SLionel Sambuc 					    flavor == F_FREEBSD9 ? "" : ")");
359d433a562SThomas Veerman 			} else
36084d9c625SLionel Sambuc 				printf("%s\n", flavor == F_FREEBSD9 ? "" : ")");
361d433a562SThomas Veerman 			tab = "\t";
362d433a562SThomas Veerman 		}
363d433a562SThomas Veerman 	}
364a8ef0910SBen Gras #if HAVE_STRUCT_STAT_ST_FLAGS
365d433a562SThomas Veerman 	/*
366d433a562SThomas Veerman 	 * XXX
367d433a562SThomas Veerman 	 * since lchflags(2) will reset file times, the utimes() above
368d433a562SThomas Veerman 	 * may have been useless!  oh well, we'd rather have correct
369d433a562SThomas Veerman 	 * flags, rather than times?
370d433a562SThomas Veerman 	 */
371d433a562SThomas Veerman         if ((s->flags & F_FLAGS) && ((s->st_flags != p->fts_statp->st_flags)
372d433a562SThomas Veerman 	    || mflag || iflag)) {
373d433a562SThomas Veerman 		if (s->st_flags != p->fts_statp->st_flags) {
374d433a562SThomas Veerman 			char *f_s;
375d433a562SThomas Veerman 			LABEL;
376d433a562SThomas Veerman 			f_s = flags_to_string(s->st_flags, "none");
37784d9c625SLionel Sambuc 			printf(flavor == F_FREEBSD9 ?
37884d9c625SLionel Sambuc 			    "%sflags expected \"%s\" found " :
37984d9c625SLionel Sambuc 			    "%sflags (\"%s\" is not ", tab, f_s);
380d433a562SThomas Veerman 			free(f_s);
381d433a562SThomas Veerman 			f_s = flags_to_string(p->fts_statp->st_flags, "none");
382d433a562SThomas Veerman 			printf("\"%s\"", f_s);
383d433a562SThomas Veerman 			free(f_s);
384d433a562SThomas Veerman 		}
385d433a562SThomas Veerman 		if (uflag) {
386d433a562SThomas Veerman 			if (iflag)
387d433a562SThomas Veerman 				SETFLAGS(0, CH_MASK);
388d433a562SThomas Veerman 			else if (mflag)
389d433a562SThomas Veerman 				CLEARFLAGS(0, SP_FLGS);
390d433a562SThomas Veerman 			else
391d433a562SThomas Veerman 				SETFLAGS(0, (~SP_FLGS & CH_MASK));
392d433a562SThomas Veerman 		} else
39384d9c625SLionel Sambuc 			printf("%s\n", flavor == F_FREEBSD9 ? "" : ")");
394d433a562SThomas Veerman 		tab = "\t";
395d433a562SThomas Veerman 	}
396d433a562SThomas Veerman #endif	/* HAVE_STRUCT_STAT_ST_FLAGS */
397d433a562SThomas Veerman 
398d433a562SThomas Veerman 	/*
399d433a562SThomas Veerman 	 * from this point, no more permission checking or whacking
400d433a562SThomas Veerman 	 * occurs, only checking of stuff like checksums and symlinks.
401d433a562SThomas Veerman 	 */
402d433a562SThomas Veerman  afterpermwhack:
403d433a562SThomas Veerman 	if (s->flags & F_CKSUM) {
404d433a562SThomas Veerman 		if ((fd = open(p->fts_accpath, O_RDONLY, 0)) < 0) {
405d433a562SThomas Veerman 			LABEL;
406d433a562SThomas Veerman 			printf("%scksum: %s: %s\n",
407d433a562SThomas Veerman 			    tab, p->fts_accpath, strerror(errno));
408d433a562SThomas Veerman 			tab = "\t";
409d433a562SThomas Veerman 		} else if (crc(fd, &val, &len)) {
410d433a562SThomas Veerman 			close(fd);
411d433a562SThomas Veerman 			LABEL;
412d433a562SThomas Veerman 			printf("%scksum: %s: %s\n",
413d433a562SThomas Veerman 			    tab, p->fts_accpath, strerror(errno));
414d433a562SThomas Veerman 			tab = "\t";
415d433a562SThomas Veerman 		} else {
416d433a562SThomas Veerman 			close(fd);
417d433a562SThomas Veerman 			if (s->cksum != val) {
418d433a562SThomas Veerman 				LABEL;
41984d9c625SLionel Sambuc 				printf(flavor == F_FREEBSD9 ?
42084d9c625SLionel Sambuc 				    "%scksum expected %lu found %lu\n" :
42184d9c625SLionel Sambuc 				    "%scksum (%lu, %lu)\n",
422d433a562SThomas Veerman 				    tab, s->cksum, (unsigned long)val);
423d433a562SThomas Veerman 			}
424d433a562SThomas Veerman 			tab = "\t";
425d433a562SThomas Veerman 		}
426d433a562SThomas Veerman 	}
427d433a562SThomas Veerman #ifndef NO_MD5
428d433a562SThomas Veerman 	if (s->flags & F_MD5) {
429d433a562SThomas Veerman 		if ((digestbuf = MD5File(p->fts_accpath, NULL)) == NULL) {
430d433a562SThomas Veerman 			LABEL;
431a8ef0910SBen Gras 			printf("%s%s: %s: %s\n",
432a8ef0910SBen Gras 			    tab, MD5KEY, p->fts_accpath, strerror(errno));
433d433a562SThomas Veerman 			tab = "\t";
434d433a562SThomas Veerman 		} else {
435d433a562SThomas Veerman 			if (strcmp(s->md5digest, digestbuf)) {
436d433a562SThomas Veerman 				LABEL;
43784d9c625SLionel Sambuc 				printf(flavor == F_FREEBSD9 ?
43884d9c625SLionel Sambuc 				    "%s%s expected %s found %s\n" :
43984d9c625SLionel Sambuc 				    "%s%s (0x%s, 0x%s)\n",
440a8ef0910SBen Gras 				    tab, MD5KEY, s->md5digest, digestbuf);
441d433a562SThomas Veerman 			}
442d433a562SThomas Veerman 			tab = "\t";
443d433a562SThomas Veerman 			free(digestbuf);
444d433a562SThomas Veerman 		}
445d433a562SThomas Veerman 	}
446d433a562SThomas Veerman #endif	/* ! NO_MD5 */
447d433a562SThomas Veerman #ifndef NO_RMD160
448d433a562SThomas Veerman 	if (s->flags & F_RMD160) {
449d433a562SThomas Veerman 		if ((digestbuf = RMD160File(p->fts_accpath, NULL)) == NULL) {
450d433a562SThomas Veerman 			LABEL;
451a8ef0910SBen Gras 			printf("%s%s: %s: %s\n",
452a8ef0910SBen Gras 			    tab, RMD160KEY, p->fts_accpath, strerror(errno));
453d433a562SThomas Veerman 			tab = "\t";
454d433a562SThomas Veerman 		} else {
455d433a562SThomas Veerman 			if (strcmp(s->rmd160digest, digestbuf)) {
456d433a562SThomas Veerman 				LABEL;
45784d9c625SLionel Sambuc 				printf(flavor == F_FREEBSD9 ?
45884d9c625SLionel Sambuc 				    "%s%s expected %s found %s\n" :
45984d9c625SLionel Sambuc 				    "%s%s (0x%s, 0x%s)\n",
460a8ef0910SBen Gras 				    tab, RMD160KEY, s->rmd160digest, digestbuf);
461d433a562SThomas Veerman 			}
462d433a562SThomas Veerman 			tab = "\t";
463d433a562SThomas Veerman 			free(digestbuf);
464d433a562SThomas Veerman 		}
465d433a562SThomas Veerman 	}
466d433a562SThomas Veerman #endif	/* ! NO_RMD160 */
467d433a562SThomas Veerman #ifndef NO_SHA1
468d433a562SThomas Veerman 	if (s->flags & F_SHA1) {
469d433a562SThomas Veerman 		if ((digestbuf = SHA1File(p->fts_accpath, NULL)) == NULL) {
470d433a562SThomas Veerman 			LABEL;
471a8ef0910SBen Gras 			printf("%s%s: %s: %s\n",
472a8ef0910SBen Gras 			    tab, SHA1KEY, p->fts_accpath, strerror(errno));
473d433a562SThomas Veerman 			tab = "\t";
474d433a562SThomas Veerman 		} else {
475d433a562SThomas Veerman 			if (strcmp(s->sha1digest, digestbuf)) {
476d433a562SThomas Veerman 				LABEL;
47784d9c625SLionel Sambuc 				printf(flavor == F_FREEBSD9 ?
47884d9c625SLionel Sambuc 				    "%s%s expected %s found %s\n" :
47984d9c625SLionel Sambuc 				    "%s%s (0x%s, 0x%s)\n",
480a8ef0910SBen Gras 				    tab, SHA1KEY, s->sha1digest, digestbuf);
481d433a562SThomas Veerman 			}
482d433a562SThomas Veerman 			tab = "\t";
483d433a562SThomas Veerman 			free(digestbuf);
484d433a562SThomas Veerman 		}
485d433a562SThomas Veerman 	}
486d433a562SThomas Veerman #endif	/* ! NO_SHA1 */
487d433a562SThomas Veerman #ifndef NO_SHA2
488d433a562SThomas Veerman 	if (s->flags & F_SHA256) {
489d433a562SThomas Veerman 		if ((digestbuf = SHA256_File(p->fts_accpath, NULL)) == NULL) {
490d433a562SThomas Veerman 			LABEL;
491a8ef0910SBen Gras 			printf("%s%s: %s: %s\n",
492a8ef0910SBen Gras 			    tab, SHA256KEY, p->fts_accpath, strerror(errno));
493d433a562SThomas Veerman 			tab = "\t";
494d433a562SThomas Veerman 		} else {
495d433a562SThomas Veerman 			if (strcmp(s->sha256digest, digestbuf)) {
496d433a562SThomas Veerman 				LABEL;
49784d9c625SLionel Sambuc 				printf(flavor == F_FREEBSD9 ?
49884d9c625SLionel Sambuc 				    "%s%s expected %s found %s\n" :
49984d9c625SLionel Sambuc 				    "%s%s (0x%s, 0x%s)\n",
500a8ef0910SBen Gras 				    tab, SHA256KEY, s->sha256digest, digestbuf);
501d433a562SThomas Veerman 			}
502d433a562SThomas Veerman 			tab = "\t";
503d433a562SThomas Veerman 			free(digestbuf);
504d433a562SThomas Veerman 		}
505d433a562SThomas Veerman 	}
506a8ef0910SBen Gras #ifdef SHA384_BLOCK_LENGTH
507d433a562SThomas Veerman 	if (s->flags & F_SHA384) {
508d433a562SThomas Veerman 		if ((digestbuf = SHA384_File(p->fts_accpath, NULL)) == NULL) {
509d433a562SThomas Veerman 			LABEL;
510a8ef0910SBen Gras 			printf("%s%s: %s: %s\n",
511a8ef0910SBen Gras 			    tab, SHA384KEY, p->fts_accpath, strerror(errno));
512d433a562SThomas Veerman 			tab = "\t";
513d433a562SThomas Veerman 		} else {
514d433a562SThomas Veerman 			if (strcmp(s->sha384digest, digestbuf)) {
515d433a562SThomas Veerman 				LABEL;
51684d9c625SLionel Sambuc 				printf(flavor == F_FREEBSD9 ?
51784d9c625SLionel Sambuc 				    "%s%s expected %s found %s\n" :
51884d9c625SLionel Sambuc 				    "%s%s (0x%s, 0x%s)\n",
519a8ef0910SBen Gras 				    tab, SHA384KEY, s->sha384digest, digestbuf);
520d433a562SThomas Veerman 			}
521d433a562SThomas Veerman 			tab = "\t";
522d433a562SThomas Veerman 			free(digestbuf);
523d433a562SThomas Veerman 		}
524d433a562SThomas Veerman 	}
525a8ef0910SBen Gras #endif
526d433a562SThomas Veerman 	if (s->flags & F_SHA512) {
527d433a562SThomas Veerman 		if ((digestbuf = SHA512_File(p->fts_accpath, NULL)) == NULL) {
528d433a562SThomas Veerman 			LABEL;
529a8ef0910SBen Gras 			printf("%s%s: %s: %s\n",
530a8ef0910SBen Gras 			    tab, SHA512KEY, p->fts_accpath, strerror(errno));
531d433a562SThomas Veerman 			tab = "\t";
532d433a562SThomas Veerman 		} else {
533d433a562SThomas Veerman 			if (strcmp(s->sha512digest, digestbuf)) {
534d433a562SThomas Veerman 				LABEL;
53584d9c625SLionel Sambuc 				printf(flavor == F_FREEBSD9 ?
53684d9c625SLionel Sambuc 				    "%s%s expected %s found %s\n" :
53784d9c625SLionel Sambuc 				    "%s%s (0x%s, 0x%s)\n",
538a8ef0910SBen Gras 				    tab, SHA512KEY, s->sha512digest, digestbuf);
539d433a562SThomas Veerman 			}
540d433a562SThomas Veerman 			tab = "\t";
541d433a562SThomas Veerman 			free(digestbuf);
542d433a562SThomas Veerman 		}
543d433a562SThomas Veerman 	}
544d433a562SThomas Veerman #endif	/* ! NO_SHA2 */
545d433a562SThomas Veerman 	if (s->flags & F_SLINK &&
546d433a562SThomas Veerman 	    strcmp(cp = rlink(p->fts_accpath), s->slink)) {
547d433a562SThomas Veerman 		LABEL;
54884d9c625SLionel Sambuc 		printf(flavor == F_FREEBSD9 ?
54984d9c625SLionel Sambuc 		    "%slink ref expected %s found %s" :
55084d9c625SLionel Sambuc 		    "%slink ref (%s, %s", tab, cp, s->slink);
551d433a562SThomas Veerman 		if (uflag) {
552d433a562SThomas Veerman 			if ((unlink(p->fts_accpath) == -1) ||
553d433a562SThomas Veerman 			    (symlink(s->slink, p->fts_accpath) == -1) )
55484d9c625SLionel Sambuc 				printf(", not modified: %s%s\n",
55584d9c625SLionel Sambuc 				    strerror(errno),
55684d9c625SLionel Sambuc 				    flavor == F_FREEBSD9 ? "" : ")");
557d433a562SThomas Veerman 			else
55884d9c625SLionel Sambuc 				printf(", modified%s\n",
55984d9c625SLionel Sambuc 				    flavor == F_FREEBSD9 ? "" : ")");
560d433a562SThomas Veerman 		} else
56184d9c625SLionel Sambuc 			printf("%s\n", flavor == F_FREEBSD9 ? "" : ")");
562d433a562SThomas Veerman 	}
563d433a562SThomas Veerman 	return (label);
564d433a562SThomas Veerman }
565d433a562SThomas Veerman 
566d433a562SThomas Veerman const char *
rlink(const char * name)567d433a562SThomas Veerman rlink(const char *name)
568d433a562SThomas Veerman {
569d433a562SThomas Veerman 	static char lbuf[MAXPATHLEN];
570d433a562SThomas Veerman 	int len;
571d433a562SThomas Veerman 
572d433a562SThomas Veerman 	if ((len = readlink(name, lbuf, sizeof(lbuf) - 1)) == -1)
573d433a562SThomas Veerman 		mtree_err("%s: %s", name, strerror(errno));
574d433a562SThomas Veerman 	lbuf[len] = '\0';
575d433a562SThomas Veerman 	return (lbuf);
576d433a562SThomas Veerman }
577