1258437Sbrooks/*	$NetBSD: compare.c,v 1.58 2013/11/21 18:39:50 christos Exp $	*/
2244541Sbrooks
3244541Sbrooks/*-
4244541Sbrooks * Copyright (c) 1989, 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[] = "@(#)compare.c	8.1 (Berkeley) 6/6/93";
40244541Sbrooks#else
41258437Sbrooks__RCSID("$NetBSD: compare.c,v 1.58 2013/11/21 18:39:50 christos Exp $");
42244541Sbrooks#endif
43244541Sbrooks#endif /* not lint */
44244541Sbrooks
45244541Sbrooks#include <sys/param.h>
46244541Sbrooks#include <sys/stat.h>
47244541Sbrooks
48244541Sbrooks#include <errno.h>
49244541Sbrooks#include <fcntl.h>
50258437Sbrooks#include <stdio.h>
51256687Sbrooks#include <stdint.h>
52244541Sbrooks#include <stdlib.h>
53244541Sbrooks#include <string.h>
54244541Sbrooks#include <time.h>
55244541Sbrooks#include <unistd.h>
56244541Sbrooks
57244541Sbrooks#ifndef NO_MD5
58244541Sbrooks#include <md5.h>
59244541Sbrooks#endif
60244541Sbrooks#ifndef NO_RMD160
61244541Sbrooks#include <rmd160.h>
62244541Sbrooks#endif
63244541Sbrooks#ifndef NO_SHA1
64244541Sbrooks#include <sha1.h>
65244541Sbrooks#endif
66244541Sbrooks#ifndef NO_SHA2
67244541Sbrooks#include <sha2.h>
68244541Sbrooks#endif
69244541Sbrooks
70244541Sbrooks#include "extern.h"
71244541Sbrooks
72244541Sbrooks#define	INDENTNAMELEN	8
73244541Sbrooks#define MARK								\
74244541Sbrooksdo {									\
75258437Sbrooks	if (flavor == F_FREEBSD9) {					\
76258437Sbrooks		len = printf("%s changed\n", RP(p));			\
77244541Sbrooks		tab = "\t";						\
78244541Sbrooks	} else {							\
79258437Sbrooks		len = printf("%s: ", RP(p));				\
80258437Sbrooks		if (len > INDENTNAMELEN) {				\
81258437Sbrooks			tab = "\t";					\
82258437Sbrooks			printf("\n");					\
83258437Sbrooks		} else {						\
84258437Sbrooks			tab = "";					\
85258437Sbrooks			printf("%*s", INDENTNAMELEN - (int)len, "");	\
86258437Sbrooks		}							\
87244541Sbrooks	}								\
88244541Sbrooks} while (0)
89244541Sbrooks#define	LABEL if (!label++) MARK
90244541Sbrooks
91244541Sbrooks#if HAVE_STRUCT_STAT_ST_FLAGS
92244541Sbrooks
93244541Sbrooks
94244541Sbrooks#define CHANGEFLAGS							\
95244541Sbrooks	if (flags != p->fts_statp->st_flags) {				\
96244541Sbrooks		char *sf;						\
97244541Sbrooks		if (!label) {						\
98244541Sbrooks			MARK;						\
99244541Sbrooks			sf = flags_to_string(p->fts_statp->st_flags, "none"); \
100244541Sbrooks			printf("%sflags (\"%s\"", tab, sf);		\
101244541Sbrooks			free(sf);					\
102244541Sbrooks		}							\
103244541Sbrooks		if (lchflags(p->fts_accpath, flags)) {			\
104244541Sbrooks			label++;					\
105244541Sbrooks			printf(", not modified: %s)\n",			\
106244541Sbrooks			    strerror(errno));				\
107244541Sbrooks		} else {						\
108244541Sbrooks			sf = flags_to_string(flags, "none");		\
109244541Sbrooks			printf(", modified to \"%s\")\n", sf);		\
110244541Sbrooks			free(sf);					\
111244541Sbrooks		}							\
112244541Sbrooks	}
113244541Sbrooks
114244541Sbrooks/* SETFLAGS:
115244541Sbrooks * given pflags, additionally set those flags specified in s->st_flags and
116244541Sbrooks * selected by mask (the other flags are left unchanged).
117244541Sbrooks */
118244541Sbrooks#define SETFLAGS(pflags, mask)						\
119244541Sbrooksdo {									\
120244541Sbrooks	flags = (s->st_flags & (mask)) | (pflags);			\
121244541Sbrooks	CHANGEFLAGS;							\
122244541Sbrooks} while (0)
123244541Sbrooks
124244541Sbrooks/* CLEARFLAGS:
125244541Sbrooks * given pflags, reset the flags specified in s->st_flags and selected by mask
126244541Sbrooks * (the other flags are left unchanged).
127244541Sbrooks */
128244541Sbrooks#define CLEARFLAGS(pflags, mask)					\
129244541Sbrooksdo {									\
130244541Sbrooks	flags = (~(s->st_flags & (mask)) & CH_MASK) & (pflags);		\
131244541Sbrooks	CHANGEFLAGS;							\
132244541Sbrooks} while (0)
133244541Sbrooks#endif	/* HAVE_STRUCT_STAT_ST_FLAGS */
134244541Sbrooks
135244541Sbrooksint
136244541Sbrookscompare(NODE *s, FTSENT *p)
137244541Sbrooks{
138244541Sbrooks	u_int32_t len, val, flags;
139244541Sbrooks	int fd, label;
140244541Sbrooks	const char *cp, *tab;
141244541Sbrooks#if !defined(NO_MD5) || !defined(NO_RMD160) || !defined(NO_SHA1) || !defined(NO_SHA2)
142244541Sbrooks	char *digestbuf;
143244541Sbrooks#endif
144244541Sbrooks
145244541Sbrooks	tab = NULL;
146244541Sbrooks	label = 0;
147244541Sbrooks	switch(s->type) {
148244541Sbrooks	case F_BLOCK:
149244541Sbrooks		if (!S_ISBLK(p->fts_statp->st_mode))
150244541Sbrooks			goto typeerr;
151244541Sbrooks		break;
152244541Sbrooks	case F_CHAR:
153244541Sbrooks		if (!S_ISCHR(p->fts_statp->st_mode))
154244541Sbrooks			goto typeerr;
155244541Sbrooks		break;
156244541Sbrooks	case F_DIR:
157244541Sbrooks		if (!S_ISDIR(p->fts_statp->st_mode))
158244541Sbrooks			goto typeerr;
159244541Sbrooks		break;
160244541Sbrooks	case F_FIFO:
161244541Sbrooks		if (!S_ISFIFO(p->fts_statp->st_mode))
162244541Sbrooks			goto typeerr;
163244541Sbrooks		break;
164244541Sbrooks	case F_FILE:
165244541Sbrooks		if (!S_ISREG(p->fts_statp->st_mode))
166244541Sbrooks			goto typeerr;
167244541Sbrooks		break;
168244541Sbrooks	case F_LINK:
169244541Sbrooks		if (!S_ISLNK(p->fts_statp->st_mode))
170244541Sbrooks			goto typeerr;
171244541Sbrooks		break;
172244541Sbrooks#ifdef S_ISSOCK
173244541Sbrooks	case F_SOCK:
174244541Sbrooks		if (!S_ISSOCK(p->fts_statp->st_mode))
175244541Sbrooks			goto typeerr;
176244541Sbrooks		break;
177244541Sbrooks#endif
178244541Sbrookstypeerr:		LABEL;
179258437Sbrooks		printf(flavor == F_FREEBSD9 ?
180258437Sbrooks		    "\ttype expected %s found %s\n" : "\ttype (%s, %s)\n",
181244541Sbrooks		    nodetype(s->type), inotype(p->fts_statp->st_mode));
182244541Sbrooks		return (label);
183244541Sbrooks	}
184244541Sbrooks	if (mtree_Wflag)
185244541Sbrooks		goto afterpermwhack;
186244541Sbrooks#if HAVE_STRUCT_STAT_ST_FLAGS
187244541Sbrooks	if (iflag && !uflag) {
188244541Sbrooks		if (s->flags & F_FLAGS)
189244541Sbrooks		    SETFLAGS(p->fts_statp->st_flags, SP_FLGS);
190244541Sbrooks		return (label);
191244541Sbrooks        }
192244541Sbrooks	if (mflag && !uflag) {
193244541Sbrooks		if (s->flags & F_FLAGS)
194244541Sbrooks		    CLEARFLAGS(p->fts_statp->st_flags, SP_FLGS);
195244541Sbrooks		return (label);
196244541Sbrooks        }
197244541Sbrooks#endif
198244541Sbrooks	if (s->flags & F_DEV &&
199244541Sbrooks	    (s->type == F_BLOCK || s->type == F_CHAR) &&
200244541Sbrooks	    s->st_rdev != p->fts_statp->st_rdev) {
201244541Sbrooks		LABEL;
202258437Sbrooks		printf(flavor == F_FREEBSD9 ?
203258437Sbrooks		    "%sdevice expected %#jx found %#jx" :
204258437Sbrooks		    "%sdevice (%#jx, %#jx",
205256687Sbrooks		    tab, (uintmax_t)s->st_rdev,
206256687Sbrooks		    (uintmax_t)p->fts_statp->st_rdev);
207244541Sbrooks		if (uflag) {
208244541Sbrooks			if ((unlink(p->fts_accpath) == -1) ||
209244541Sbrooks			    (mknod(p->fts_accpath,
210244541Sbrooks			      s->st_mode | nodetoino(s->type),
211244541Sbrooks			      s->st_rdev) == -1) ||
212244541Sbrooks			    (lchown(p->fts_accpath, p->fts_statp->st_uid,
213244541Sbrooks			      p->fts_statp->st_gid) == -1) )
214258437Sbrooks				printf(", not modified: %s%s\n",
215258437Sbrooks				    strerror(errno),
216258437Sbrooks				    flavor == F_FREEBSD9 ? "" : ")");
217244541Sbrooks			 else
218258437Sbrooks				printf(", modified%s\n",
219258437Sbrooks				    flavor == F_FREEBSD9 ? "" : ")");
220244541Sbrooks		} else
221244541Sbrooks			printf(")\n");
222244541Sbrooks		tab = "\t";
223244541Sbrooks	}
224244541Sbrooks	/* Set the uid/gid first, then set the mode. */
225244541Sbrooks	if (s->flags & (F_UID | F_UNAME) && s->st_uid != p->fts_statp->st_uid) {
226244541Sbrooks		LABEL;
227258437Sbrooks		printf(flavor == F_FREEBSD9 ?
228258437Sbrooks		    "%suser expected %lu found %lu" : "%suser (%lu, %lu",
229244541Sbrooks		    tab, (u_long)s->st_uid, (u_long)p->fts_statp->st_uid);
230244541Sbrooks		if (uflag) {
231244541Sbrooks			if (lchown(p->fts_accpath, s->st_uid, -1))
232258437Sbrooks				printf(", not modified: %s%s\n",
233258437Sbrooks				    strerror(errno),
234258437Sbrooks				    flavor == F_FREEBSD9 ? "" : ")");
235244541Sbrooks			else
236258437Sbrooks				printf(", modified%s\n",
237258437Sbrooks				    flavor == F_FREEBSD9 ? "" : ")");
238244541Sbrooks		} else
239244541Sbrooks			printf(")\n");
240244541Sbrooks		tab = "\t";
241244541Sbrooks	}
242244541Sbrooks	if (s->flags & (F_GID | F_GNAME) && s->st_gid != p->fts_statp->st_gid) {
243244541Sbrooks		LABEL;
244258437Sbrooks		printf(flavor == F_FREEBSD9 ?
245258437Sbrooks		    "%sgid expected %lu found %lu" : "%sgid (%lu, %lu",
246244541Sbrooks		    tab, (u_long)s->st_gid, (u_long)p->fts_statp->st_gid);
247244541Sbrooks		if (uflag) {
248244541Sbrooks			if (lchown(p->fts_accpath, -1, s->st_gid))
249258437Sbrooks				printf(", not modified: %s%s\n",
250258437Sbrooks				    strerror(errno),
251258437Sbrooks				    flavor == F_FREEBSD9 ? "" : ")");
252244541Sbrooks			else
253258437Sbrooks				printf(", modified%s\n",
254258437Sbrooks				    flavor == F_FREEBSD9 ? "" : ")");
255244541Sbrooks		}
256244541Sbrooks		else
257244541Sbrooks			printf(")\n");
258244541Sbrooks		tab = "\t";
259244541Sbrooks	}
260244541Sbrooks	if (s->flags & F_MODE &&
261244541Sbrooks	    s->st_mode != (p->fts_statp->st_mode & MBITS)) {
262244541Sbrooks		if (lflag) {
263244541Sbrooks			mode_t tmode, mode;
264244541Sbrooks
265244541Sbrooks			tmode = s->st_mode;
266244541Sbrooks			mode = p->fts_statp->st_mode & MBITS;
267244541Sbrooks			/*
268244541Sbrooks			 * if none of the suid/sgid/etc bits are set,
269244541Sbrooks			 * then if the mode is a subset of the target,
270244541Sbrooks			 * skip.
271244541Sbrooks			 */
272244541Sbrooks			if (!((tmode & ~(S_IRWXU|S_IRWXG|S_IRWXO)) ||
273244541Sbrooks			    (mode & ~(S_IRWXU|S_IRWXG|S_IRWXO))))
274244541Sbrooks				if ((mode | tmode) == tmode)
275244541Sbrooks					goto skip;
276244541Sbrooks		}
277244541Sbrooks
278244541Sbrooks		LABEL;
279258437Sbrooks		printf(flavor == F_FREEBSD9 ?
280258437Sbrooks		    "%spermissions expcted %#lo found %#lo" :
281258437Sbrooks		    "%spermissions (%#lo, %#lo",
282244541Sbrooks		    tab, (u_long)s->st_mode,
283244541Sbrooks		    (u_long)p->fts_statp->st_mode & MBITS);
284244541Sbrooks		if (uflag) {
285244541Sbrooks			if (lchmod(p->fts_accpath, s->st_mode))
286258437Sbrooks				printf(", not modified: %s%s\n",
287258437Sbrooks				    strerror(errno),
288258437Sbrooks				    flavor == F_FREEBSD9 ? "" : ")");
289244541Sbrooks			else
290258437Sbrooks				printf(", modified%s\n",
291258437Sbrooks				    flavor == F_FREEBSD9 ? "" : ")");
292244541Sbrooks		}
293244541Sbrooks		else
294244541Sbrooks			printf(")\n");
295244541Sbrooks		tab = "\t";
296244541Sbrooks	skip:	;
297244541Sbrooks	}
298244541Sbrooks	if (s->flags & F_NLINK && s->type != F_DIR &&
299244541Sbrooks	    s->st_nlink != p->fts_statp->st_nlink) {
300244541Sbrooks		LABEL;
301258437Sbrooks		printf(flavor == F_FREEBSD9 ?
302258437Sbrooks		    "%slink count expected %lu found %lu\n" :
303258437Sbrooks		    "%slink count (%lu, %lu)\n",
304244541Sbrooks		    tab, (u_long)s->st_nlink, (u_long)p->fts_statp->st_nlink);
305244541Sbrooks		tab = "\t";
306244541Sbrooks	}
307244541Sbrooks	if (s->flags & F_SIZE && s->st_size != p->fts_statp->st_size) {
308244541Sbrooks		LABEL;
309258437Sbrooks		printf(flavor == F_FREEBSD9 ?
310258437Sbrooks		    "%ssize expected %ju found %ju\n" : "%ssize (%ju, %ju)\n",
311256687Sbrooks		    tab, (uintmax_t)s->st_size,
312256687Sbrooks		    (uintmax_t)p->fts_statp->st_size);
313244541Sbrooks		tab = "\t";
314244541Sbrooks	}
315244541Sbrooks	/*
316244541Sbrooks	 * XXX
317244541Sbrooks	 * Since utimes(2) only takes a timeval, there's no point in
318244541Sbrooks	 * comparing the low bits of the timespec nanosecond field.  This
319244541Sbrooks	 * will only result in mismatches that we can never fix.
320244541Sbrooks	 *
321244541Sbrooks	 * Doesn't display microsecond differences.
322244541Sbrooks	 */
323244541Sbrooks	if (s->flags & F_TIME) {
324244541Sbrooks		struct timeval tv[2];
325244541Sbrooks		struct stat *ps = p->fts_statp;
326244541Sbrooks		time_t smtime = s->st_mtimespec.tv_sec;
327244541Sbrooks
328244541Sbrooks#if defined(BSD4_4) && !defined(HAVE_NBTOOL_CONFIG_H)
329244541Sbrooks		time_t pmtime = ps->st_mtimespec.tv_sec;
330244541Sbrooks
331244541Sbrooks		TIMESPEC_TO_TIMEVAL(&tv[0], &s->st_mtimespec);
332244541Sbrooks		TIMESPEC_TO_TIMEVAL(&tv[1], &ps->st_mtimespec);
333244541Sbrooks#else
334244541Sbrooks		time_t pmtime = (time_t)ps->st_mtime;
335244541Sbrooks
336244541Sbrooks		tv[0].tv_sec = smtime;
337244541Sbrooks		tv[0].tv_usec = 0;
338244541Sbrooks		tv[1].tv_sec = pmtime;
339244541Sbrooks		tv[1].tv_usec = 0;
340244541Sbrooks#endif
341244541Sbrooks
342244541Sbrooks		if (tv[0].tv_sec != tv[1].tv_sec ||
343244541Sbrooks		    tv[0].tv_usec != tv[1].tv_usec) {
344244541Sbrooks			LABEL;
345258437Sbrooks			printf(flavor == F_FREEBSD9 ?
346258437Sbrooks			    "%smodification time expected %.24s found " :
347258437Sbrooks			    "%smodification time (%.24s, ",
348244541Sbrooks			    tab, ctime(&smtime));
349244541Sbrooks			printf("%.24s", ctime(&pmtime));
350244541Sbrooks			if (tflag) {
351244541Sbrooks				tv[1] = tv[0];
352244541Sbrooks				if (utimes(p->fts_accpath, tv))
353258437Sbrooks					printf(", not modified: %s%s\n",
354258437Sbrooks					    strerror(errno),
355258437Sbrooks					    flavor == F_FREEBSD9 ? "" : ")");
356244541Sbrooks				else
357258437Sbrooks					printf(", modified%s\n",
358258437Sbrooks					    flavor == F_FREEBSD9 ? "" : ")");
359244541Sbrooks			} else
360258437Sbrooks				printf("%s\n", flavor == F_FREEBSD9 ? "" : ")");
361244541Sbrooks			tab = "\t";
362244541Sbrooks		}
363244541Sbrooks	}
364244541Sbrooks#if HAVE_STRUCT_STAT_ST_FLAGS
365244541Sbrooks	/*
366244541Sbrooks	 * XXX
367244541Sbrooks	 * since lchflags(2) will reset file times, the utimes() above
368244541Sbrooks	 * may have been useless!  oh well, we'd rather have correct
369244541Sbrooks	 * flags, rather than times?
370244541Sbrooks	 */
371244541Sbrooks        if ((s->flags & F_FLAGS) && ((s->st_flags != p->fts_statp->st_flags)
372244541Sbrooks	    || mflag || iflag)) {
373244541Sbrooks		if (s->st_flags != p->fts_statp->st_flags) {
374244541Sbrooks			char *f_s;
375244541Sbrooks			LABEL;
376244541Sbrooks			f_s = flags_to_string(s->st_flags, "none");
377258437Sbrooks			printf(flavor == F_FREEBSD9 ?
378258437Sbrooks			    "%sflags expected \"%s\" found " :
379258437Sbrooks			    "%sflags (\"%s\" is not ", tab, f_s);
380244541Sbrooks			free(f_s);
381244541Sbrooks			f_s = flags_to_string(p->fts_statp->st_flags, "none");
382244541Sbrooks			printf("\"%s\"", f_s);
383244541Sbrooks			free(f_s);
384244541Sbrooks		}
385244541Sbrooks		if (uflag) {
386244541Sbrooks			if (iflag)
387244541Sbrooks				SETFLAGS(0, CH_MASK);
388244541Sbrooks			else if (mflag)
389244541Sbrooks				CLEARFLAGS(0, SP_FLGS);
390244541Sbrooks			else
391244541Sbrooks				SETFLAGS(0, (~SP_FLGS & CH_MASK));
392244541Sbrooks		} else
393258437Sbrooks			printf("%s\n", flavor == F_FREEBSD9 ? "" : ")");
394244541Sbrooks		tab = "\t";
395244541Sbrooks	}
396244541Sbrooks#endif	/* HAVE_STRUCT_STAT_ST_FLAGS */
397244541Sbrooks
398244541Sbrooks	/*
399244541Sbrooks	 * from this point, no more permission checking or whacking
400244541Sbrooks	 * occurs, only checking of stuff like checksums and symlinks.
401244541Sbrooks	 */
402244541Sbrooks afterpermwhack:
403244541Sbrooks	if (s->flags & F_CKSUM) {
404244541Sbrooks		if ((fd = open(p->fts_accpath, O_RDONLY, 0)) < 0) {
405244541Sbrooks			LABEL;
406244541Sbrooks			printf("%scksum: %s: %s\n",
407244541Sbrooks			    tab, p->fts_accpath, strerror(errno));
408244541Sbrooks			tab = "\t";
409244541Sbrooks		} else if (crc(fd, &val, &len)) {
410244541Sbrooks			close(fd);
411244541Sbrooks			LABEL;
412244541Sbrooks			printf("%scksum: %s: %s\n",
413244541Sbrooks			    tab, p->fts_accpath, strerror(errno));
414244541Sbrooks			tab = "\t";
415244541Sbrooks		} else {
416244541Sbrooks			close(fd);
417244541Sbrooks			if (s->cksum != val) {
418244541Sbrooks				LABEL;
419258437Sbrooks				printf(flavor == F_FREEBSD9 ?
420258437Sbrooks				    "%scksum expected %lu found %lu\n" :
421258437Sbrooks				    "%scksum (%lu, %lu)\n",
422244541Sbrooks				    tab, s->cksum, (unsigned long)val);
423244541Sbrooks			}
424244541Sbrooks			tab = "\t";
425244541Sbrooks		}
426244541Sbrooks	}
427244541Sbrooks#ifndef NO_MD5
428244541Sbrooks	if (s->flags & F_MD5) {
429244541Sbrooks		if ((digestbuf = MD5File(p->fts_accpath, NULL)) == NULL) {
430244541Sbrooks			LABEL;
431244541Sbrooks			printf("%s%s: %s: %s\n",
432244541Sbrooks			    tab, MD5KEY, p->fts_accpath, strerror(errno));
433244541Sbrooks			tab = "\t";
434244541Sbrooks		} else {
435244541Sbrooks			if (strcmp(s->md5digest, digestbuf)) {
436244541Sbrooks				LABEL;
437258437Sbrooks				printf(flavor == F_FREEBSD9 ?
438258437Sbrooks				    "%s%s expected %s found %s\n" :
439258437Sbrooks				    "%s%s (0x%s, 0x%s)\n",
440244541Sbrooks				    tab, MD5KEY, s->md5digest, digestbuf);
441244541Sbrooks			}
442244541Sbrooks			tab = "\t";
443244541Sbrooks			free(digestbuf);
444244541Sbrooks		}
445244541Sbrooks	}
446244541Sbrooks#endif	/* ! NO_MD5 */
447244541Sbrooks#ifndef NO_RMD160
448244541Sbrooks	if (s->flags & F_RMD160) {
449244541Sbrooks		if ((digestbuf = RMD160File(p->fts_accpath, NULL)) == NULL) {
450244541Sbrooks			LABEL;
451244541Sbrooks			printf("%s%s: %s: %s\n",
452244541Sbrooks			    tab, RMD160KEY, p->fts_accpath, strerror(errno));
453244541Sbrooks			tab = "\t";
454244541Sbrooks		} else {
455244541Sbrooks			if (strcmp(s->rmd160digest, digestbuf)) {
456244541Sbrooks				LABEL;
457258437Sbrooks				printf(flavor == F_FREEBSD9 ?
458258437Sbrooks				    "%s%s expected %s found %s\n" :
459258437Sbrooks				    "%s%s (0x%s, 0x%s)\n",
460244541Sbrooks				    tab, RMD160KEY, s->rmd160digest, digestbuf);
461244541Sbrooks			}
462244541Sbrooks			tab = "\t";
463244541Sbrooks			free(digestbuf);
464244541Sbrooks		}
465244541Sbrooks	}
466244541Sbrooks#endif	/* ! NO_RMD160 */
467244541Sbrooks#ifndef NO_SHA1
468244541Sbrooks	if (s->flags & F_SHA1) {
469244541Sbrooks		if ((digestbuf = SHA1File(p->fts_accpath, NULL)) == NULL) {
470244541Sbrooks			LABEL;
471244541Sbrooks			printf("%s%s: %s: %s\n",
472244541Sbrooks			    tab, SHA1KEY, p->fts_accpath, strerror(errno));
473244541Sbrooks			tab = "\t";
474244541Sbrooks		} else {
475244541Sbrooks			if (strcmp(s->sha1digest, digestbuf)) {
476244541Sbrooks				LABEL;
477258437Sbrooks				printf(flavor == F_FREEBSD9 ?
478258437Sbrooks				    "%s%s expected %s found %s\n" :
479258437Sbrooks				    "%s%s (0x%s, 0x%s)\n",
480244541Sbrooks				    tab, SHA1KEY, s->sha1digest, digestbuf);
481244541Sbrooks			}
482244541Sbrooks			tab = "\t";
483244541Sbrooks			free(digestbuf);
484244541Sbrooks		}
485244541Sbrooks	}
486244541Sbrooks#endif	/* ! NO_SHA1 */
487244541Sbrooks#ifndef NO_SHA2
488244541Sbrooks	if (s->flags & F_SHA256) {
489244541Sbrooks		if ((digestbuf = SHA256_File(p->fts_accpath, NULL)) == NULL) {
490244541Sbrooks			LABEL;
491244541Sbrooks			printf("%s%s: %s: %s\n",
492244541Sbrooks			    tab, SHA256KEY, p->fts_accpath, strerror(errno));
493244541Sbrooks			tab = "\t";
494244541Sbrooks		} else {
495244541Sbrooks			if (strcmp(s->sha256digest, digestbuf)) {
496244541Sbrooks				LABEL;
497258437Sbrooks				printf(flavor == F_FREEBSD9 ?
498258437Sbrooks				    "%s%s expected %s found %s\n" :
499258437Sbrooks				    "%s%s (0x%s, 0x%s)\n",
500244541Sbrooks				    tab, SHA256KEY, s->sha256digest, digestbuf);
501244541Sbrooks			}
502244541Sbrooks			tab = "\t";
503244541Sbrooks			free(digestbuf);
504244541Sbrooks		}
505244541Sbrooks	}
506244541Sbrooks#ifdef SHA384_BLOCK_LENGTH
507244541Sbrooks	if (s->flags & F_SHA384) {
508244541Sbrooks		if ((digestbuf = SHA384_File(p->fts_accpath, NULL)) == NULL) {
509244541Sbrooks			LABEL;
510244541Sbrooks			printf("%s%s: %s: %s\n",
511244541Sbrooks			    tab, SHA384KEY, p->fts_accpath, strerror(errno));
512244541Sbrooks			tab = "\t";
513244541Sbrooks		} else {
514244541Sbrooks			if (strcmp(s->sha384digest, digestbuf)) {
515244541Sbrooks				LABEL;
516258437Sbrooks				printf(flavor == F_FREEBSD9 ?
517258437Sbrooks				    "%s%s expected %s found %s\n" :
518258437Sbrooks				    "%s%s (0x%s, 0x%s)\n",
519244541Sbrooks				    tab, SHA384KEY, s->sha384digest, digestbuf);
520244541Sbrooks			}
521244541Sbrooks			tab = "\t";
522244541Sbrooks			free(digestbuf);
523244541Sbrooks		}
524244541Sbrooks	}
525244541Sbrooks#endif
526244541Sbrooks	if (s->flags & F_SHA512) {
527244541Sbrooks		if ((digestbuf = SHA512_File(p->fts_accpath, NULL)) == NULL) {
528244541Sbrooks			LABEL;
529244541Sbrooks			printf("%s%s: %s: %s\n",
530244541Sbrooks			    tab, SHA512KEY, p->fts_accpath, strerror(errno));
531244541Sbrooks			tab = "\t";
532244541Sbrooks		} else {
533244541Sbrooks			if (strcmp(s->sha512digest, digestbuf)) {
534244541Sbrooks				LABEL;
535258437Sbrooks				printf(flavor == F_FREEBSD9 ?
536258437Sbrooks				    "%s%s expected %s found %s\n" :
537258437Sbrooks				    "%s%s (0x%s, 0x%s)\n",
538244541Sbrooks				    tab, SHA512KEY, s->sha512digest, digestbuf);
539244541Sbrooks			}
540244541Sbrooks			tab = "\t";
541244541Sbrooks			free(digestbuf);
542244541Sbrooks		}
543244541Sbrooks	}
544244541Sbrooks#endif	/* ! NO_SHA2 */
545244541Sbrooks	if (s->flags & F_SLINK &&
546244541Sbrooks	    strcmp(cp = rlink(p->fts_accpath), s->slink)) {
547244541Sbrooks		LABEL;
548258437Sbrooks		printf(flavor == F_FREEBSD9 ?
549258437Sbrooks		    "%slink ref expected %s found %s" :
550258437Sbrooks		    "%slink ref (%s, %s", tab, cp, s->slink);
551244541Sbrooks		if (uflag) {
552244541Sbrooks			if ((unlink(p->fts_accpath) == -1) ||
553244541Sbrooks			    (symlink(s->slink, p->fts_accpath) == -1) )
554258437Sbrooks				printf(", not modified: %s%s\n",
555258437Sbrooks				    strerror(errno),
556258437Sbrooks				    flavor == F_FREEBSD9 ? "" : ")");
557244541Sbrooks			else
558258437Sbrooks				printf(", modified%s\n",
559258437Sbrooks				    flavor == F_FREEBSD9 ? "" : ")");
560244541Sbrooks		} else
561258437Sbrooks			printf("%s\n", flavor == F_FREEBSD9 ? "" : ")");
562244541Sbrooks	}
563244541Sbrooks	return (label);
564244541Sbrooks}
565244541Sbrooks
566244541Sbrooksconst char *
567244541Sbrooksrlink(const char *name)
568244541Sbrooks{
569244541Sbrooks	static char lbuf[MAXPATHLEN];
570244541Sbrooks	int len;
571244541Sbrooks
572244541Sbrooks	if ((len = readlink(name, lbuf, sizeof(lbuf) - 1)) == -1)
573244541Sbrooks		mtree_err("%s: %s", name, strerror(errno));
574244541Sbrooks	lbuf[len] = '\0';
575244541Sbrooks	return (lbuf);
576244541Sbrooks}
577