11553Srgrimes/*-
21553Srgrimes * Copyright (c) 1989, 1993
31553Srgrimes *	The Regents of the University of California.  All rights reserved.
41553Srgrimes *
51553Srgrimes * Redistribution and use in source and binary forms, with or without
61553Srgrimes * modification, are permitted provided that the following conditions
71553Srgrimes * are met:
81553Srgrimes * 1. Redistributions of source code must retain the above copyright
91553Srgrimes *    notice, this list of conditions and the following disclaimer.
101553Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111553Srgrimes *    notice, this list of conditions and the following disclaimer in the
121553Srgrimes *    documentation and/or other materials provided with the distribution.
13121300Sphk * 3. Neither the name of the University nor the names of its contributors
141553Srgrimes *    may be used to endorse or promote products derived from this software
151553Srgrimes *    without specific prior written permission.
161553Srgrimes *
171553Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
181553Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
191553Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
201553Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
211553Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
221553Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
231553Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
241553Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
251553Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
261553Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
271553Srgrimes * SUCH DAMAGE.
281553Srgrimes */
291553Srgrimes
30114601Sobrien#if 0
311553Srgrimes#ifndef lint
321553Srgrimesstatic char sccsid[] = "@(#)compare.c	8.1 (Berkeley) 6/6/93";
33114601Sobrien#endif /* not lint */
3430027Scharnier#endif
35114601Sobrien#include <sys/cdefs.h>
36114601Sobrien__FBSDID("$FreeBSD$");
371553Srgrimes
381553Srgrimes#include <sys/param.h>
391553Srgrimes#include <sys/stat.h>
40121853Sbde#include <sys/time.h>
41121853Sbde
4230027Scharnier#include <err.h>
4330027Scharnier#include <errno.h>
441553Srgrimes#include <fcntl.h>
451553Srgrimes#include <fts.h>
4644303Swollman#ifdef MD5
4730027Scharnier#include <md5.h>
4844303Swollman#endif
49121853Sbde#ifdef RMD160
50121853Sbde#include <ripemd.h>
51121853Sbde#endif
5244303Swollman#ifdef SHA1
5344303Swollman#include <sha.h>
5444303Swollman#endif
55144295Stobez#ifdef SHA256
56144295Stobez#include <sha256.h>
57144295Stobez#endif
58100070Sdes#include <stdint.h>
591553Srgrimes#include <stdio.h>
601553Srgrimes#include <time.h>
611553Srgrimes#include <unistd.h>
62121853Sbde#include <vis.h>
63121853Sbde
641553Srgrimes#include "mtree.h"
651553Srgrimes#include "extern.h"
661553Srgrimes
671553Srgrimes#define	INDENTNAMELEN	8
681553Srgrimes#define	LABEL \
691553Srgrimes	if (!label++) { \
7066584Sphk		len = printf("%s changed\n", RP(p)); \
7166584Sphk		tab = "\t"; \
721553Srgrimes	}
731553Srgrimes
741553Srgrimesint
75121299Sphkcompare(char *name __unused, NODE *s, FTSENT *p)
761553Srgrimes{
77121853Sbde	struct timeval tv[2];
78112214Srobert	uint32_t val;
791553Srgrimes	int fd, label;
80112214Srobert	off_t len;
8199802Salfred	char *cp;
8299802Salfred	const char *tab = "";
8361749Sjoe	char *fflags;
841553Srgrimes
851553Srgrimes	label = 0;
861553Srgrimes	switch(s->type) {
871553Srgrimes	case F_BLOCK:
881553Srgrimes		if (!S_ISBLK(p->fts_statp->st_mode))
891553Srgrimes			goto typeerr;
901553Srgrimes		break;
911553Srgrimes	case F_CHAR:
921553Srgrimes		if (!S_ISCHR(p->fts_statp->st_mode))
931553Srgrimes			goto typeerr;
941553Srgrimes		break;
951553Srgrimes	case F_DIR:
961553Srgrimes		if (!S_ISDIR(p->fts_statp->st_mode))
971553Srgrimes			goto typeerr;
981553Srgrimes		break;
991553Srgrimes	case F_FIFO:
1001553Srgrimes		if (!S_ISFIFO(p->fts_statp->st_mode))
1011553Srgrimes			goto typeerr;
1021553Srgrimes		break;
1031553Srgrimes	case F_FILE:
1041553Srgrimes		if (!S_ISREG(p->fts_statp->st_mode))
1051553Srgrimes			goto typeerr;
1061553Srgrimes		break;
1071553Srgrimes	case F_LINK:
1081553Srgrimes		if (!S_ISLNK(p->fts_statp->st_mode))
1091553Srgrimes			goto typeerr;
1101553Srgrimes		break;
1111553Srgrimes	case F_SOCK:
1121553Srgrimes		if (!S_ISSOCK(p->fts_statp->st_mode)) {
1131553Srgrimestypeerr:		LABEL;
11466584Sphk			(void)printf("\ttype expected %s found %s\n",
1151553Srgrimes			    ftype(s->type), inotype(p->fts_statp->st_mode));
11666747Sphk			return (label);
1171553Srgrimes		}
1181553Srgrimes		break;
1191553Srgrimes	}
1201553Srgrimes	/* Set the uid/gid first, then set the mode. */
1211553Srgrimes	if (s->flags & (F_UID | F_UNAME) && s->st_uid != p->fts_statp->st_uid) {
1221553Srgrimes		LABEL;
12366584Sphk		(void)printf("%suser expected %lu found %lu",
12438020Sbde		    tab, (u_long)s->st_uid, (u_long)p->fts_statp->st_uid);
1251553Srgrimes		if (uflag)
1261553Srgrimes			if (chown(p->fts_accpath, s->st_uid, -1))
12766584Sphk				(void)printf(" not modified: %s\n",
1281553Srgrimes				    strerror(errno));
1291553Srgrimes			else
13066584Sphk				(void)printf(" modified\n");
1311553Srgrimes		else
13266584Sphk			(void)printf("\n");
1331553Srgrimes		tab = "\t";
1341553Srgrimes	}
1351553Srgrimes	if (s->flags & (F_GID | F_GNAME) && s->st_gid != p->fts_statp->st_gid) {
1361553Srgrimes		LABEL;
13766584Sphk		(void)printf("%sgid expected %lu found %lu",
13838020Sbde		    tab, (u_long)s->st_gid, (u_long)p->fts_statp->st_gid);
1391553Srgrimes		if (uflag)
1401553Srgrimes			if (chown(p->fts_accpath, -1, s->st_gid))
14166584Sphk				(void)printf(" not modified: %s\n",
1421553Srgrimes				    strerror(errno));
1431553Srgrimes			else
14466584Sphk				(void)printf(" modified\n");
1451553Srgrimes		else
14666584Sphk			(void)printf("\n");
1471553Srgrimes		tab = "\t";
1481553Srgrimes	}
1491553Srgrimes	if (s->flags & F_MODE &&
15066746Sphk	    !S_ISLNK(p->fts_statp->st_mode) &&
1511553Srgrimes	    s->st_mode != (p->fts_statp->st_mode & MBITS)) {
1521553Srgrimes		LABEL;
15366584Sphk		(void)printf("%spermissions expected %#o found %#o",
1541553Srgrimes		    tab, s->st_mode, p->fts_statp->st_mode & MBITS);
1551553Srgrimes		if (uflag)
1561553Srgrimes			if (chmod(p->fts_accpath, s->st_mode))
15766584Sphk				(void)printf(" not modified: %s\n",
1581553Srgrimes				    strerror(errno));
1591553Srgrimes			else
16066584Sphk				(void)printf(" modified\n");
1611553Srgrimes		else
16266584Sphk			(void)printf("\n");
1631553Srgrimes		tab = "\t";
1641553Srgrimes	}
1651553Srgrimes	if (s->flags & F_NLINK && s->type != F_DIR &&
1661553Srgrimes	    s->st_nlink != p->fts_statp->st_nlink) {
1671553Srgrimes		LABEL;
16866584Sphk		(void)printf("%slink_count expected %u found %u\n",
1691553Srgrimes		    tab, s->st_nlink, p->fts_statp->st_nlink);
1701553Srgrimes		tab = "\t";
1711553Srgrimes	}
17266584Sphk	if (s->flags & F_SIZE && s->st_size != p->fts_statp->st_size &&
17366584Sphk		!S_ISDIR(p->fts_statp->st_mode)) {
1741553Srgrimes		LABEL;
175100070Sdes		(void)printf("%ssize expected %jd found %jd\n", tab,
176100070Sdes		    (intmax_t)s->st_size, (intmax_t)p->fts_statp->st_size);
1771553Srgrimes		tab = "\t";
1781553Srgrimes	}
1791553Srgrimes	/*
1801553Srgrimes	 * XXX
1811553Srgrimes	 * Catches nano-second differences, but doesn't display them.
1821553Srgrimes	 */
1833052Sdg	if ((s->flags & F_TIME) &&
184205793Sed	     ((s->st_mtimespec.tv_sec != p->fts_statp->st_mtim.tv_sec) ||
185205793Sed	     (s->st_mtimespec.tv_nsec != p->fts_statp->st_mtim.tv_nsec))) {
1861553Srgrimes		LABEL;
18766584Sphk		(void)printf("%smodification time expected %.24s ",
18818404Snate		    tab, ctime(&s->st_mtimespec.tv_sec));
189121798Sphk		(void)printf("found %.24s",
190205793Sed		    ctime(&p->fts_statp->st_mtim.tv_sec));
191121798Sphk		if (uflag) {
192121798Sphk			tv[0].tv_sec = s->st_mtimespec.tv_sec;
193121798Sphk			tv[0].tv_usec = s->st_mtimespec.tv_nsec / 1000;
194121798Sphk			tv[1] = tv[0];
195121798Sphk			if (utimes(p->fts_accpath, tv))
196121798Sphk				(void)printf(" not modified: %s\n",
197121798Sphk				    strerror(errno));
198121798Sphk			else
199121798Sphk				(void)printf(" modified\n");
200121798Sphk		} else
201121798Sphk			(void)printf("\n");
2021553Srgrimes		tab = "\t";
2031553Srgrimes	}
20451705Sbillf	if (s->flags & F_CKSUM) {
2051553Srgrimes		if ((fd = open(p->fts_accpath, O_RDONLY, 0)) < 0) {
2061553Srgrimes			LABEL;
2071553Srgrimes			(void)printf("%scksum: %s: %s\n",
2081553Srgrimes			    tab, p->fts_accpath, strerror(errno));
2091553Srgrimes			tab = "\t";
2101553Srgrimes		} else if (crc(fd, &val, &len)) {
2111553Srgrimes			(void)close(fd);
2121553Srgrimes			LABEL;
2131553Srgrimes			(void)printf("%scksum: %s: %s\n",
2141553Srgrimes			    tab, p->fts_accpath, strerror(errno));
2151553Srgrimes			tab = "\t";
2161553Srgrimes		} else {
2171553Srgrimes			(void)close(fd);
2181553Srgrimes			if (s->cksum != val) {
2191553Srgrimes				LABEL;
22066584Sphk				(void)printf("%scksum expected %lu found %lu\n",
221112214Srobert				    tab, s->cksum, (unsigned long)val);
222112194Stobez				tab = "\t";
2231553Srgrimes			}
2241553Srgrimes		}
22551705Sbillf	}
22654375Sjoe	if ((s->flags & F_FLAGS) && s->st_flags != p->fts_statp->st_flags) {
22754375Sjoe		LABEL;
22861749Sjoe		fflags = flags_to_string(s->st_flags);
22966584Sphk		(void)printf("%sflags expected \"%s\"", tab, fflags);
23061749Sjoe		free(fflags);
23161749Sjoe
23261749Sjoe		fflags = flags_to_string(p->fts_statp->st_flags);
23366584Sphk		(void)printf(" found \"%s\"", fflags);
23461749Sjoe		free(fflags);
23561749Sjoe
23654375Sjoe		if (uflag)
23754375Sjoe			if (chflags(p->fts_accpath, s->st_flags))
23866584Sphk				(void)printf(" not modified: %s\n",
23954375Sjoe				    strerror(errno));
24054375Sjoe			else
24166584Sphk				(void)printf(" modified\n");
24254375Sjoe		else
24366584Sphk			(void)printf("\n");
24454375Sjoe		tab = "\t";
24554375Sjoe	}
24644303Swollman#ifdef MD5
2476286Swollman	if (s->flags & F_MD5) {
2489490Sphk		char *new_digest, buf[33];
2498857Srgrimes
25044303Swollman		new_digest = MD5File(p->fts_accpath, buf);
2516286Swollman		if (!new_digest) {
2526286Swollman			LABEL;
25366584Sphk			printf("%sMD5: %s: %s\n", tab, p->fts_accpath,
2546286Swollman			       strerror(errno));
2556286Swollman			tab = "\t";
2566286Swollman		} else if (strcmp(new_digest, s->md5digest)) {
2576286Swollman			LABEL;
25866584Sphk			printf("%sMD5 expected %s found %s\n", tab, s->md5digest,
2596286Swollman			       new_digest);
2606286Swollman			tab = "\t";
2616286Swollman		}
2626286Swollman	}
26344303Swollman#endif /* MD5 */
26444303Swollman#ifdef SHA1
26544303Swollman	if (s->flags & F_SHA1) {
26644303Swollman		char *new_digest, buf[41];
2676286Swollman
26844303Swollman		new_digest = SHA1_File(p->fts_accpath, buf);
26944303Swollman		if (!new_digest) {
27044303Swollman			LABEL;
27166584Sphk			printf("%sSHA-1: %s: %s\n", tab, p->fts_accpath,
27244303Swollman			       strerror(errno));
27344303Swollman			tab = "\t";
27444303Swollman		} else if (strcmp(new_digest, s->sha1digest)) {
27544303Swollman			LABEL;
276121300Sphk			printf("%sSHA-1 expected %s found %s\n",
27766584Sphk			       tab, s->sha1digest, new_digest);
27844303Swollman			tab = "\t";
27944303Swollman		}
28044303Swollman	}
28144303Swollman#endif /* SHA1 */
28244303Swollman#ifdef RMD160
28344303Swollman	if (s->flags & F_RMD160) {
28444303Swollman		char *new_digest, buf[41];
28544303Swollman
28644303Swollman		new_digest = RIPEMD160_File(p->fts_accpath, buf);
28744303Swollman		if (!new_digest) {
28844303Swollman			LABEL;
28966584Sphk			printf("%sRIPEMD160: %s: %s\n", tab,
29044303Swollman			       p->fts_accpath, strerror(errno));
29144303Swollman			tab = "\t";
29244303Swollman		} else if (strcmp(new_digest, s->rmd160digest)) {
29344303Swollman			LABEL;
29466584Sphk			printf("%sRIPEMD160 expected %s found %s\n",
29566584Sphk			       tab, s->rmd160digest, new_digest);
29644303Swollman			tab = "\t";
29744303Swollman		}
29844303Swollman	}
29944303Swollman#endif /* RMD160 */
300144295Stobez#ifdef SHA256
301144295Stobez	if (s->flags & F_SHA256) {
302144295Stobez		char *new_digest, buf[65];
30344303Swollman
304144295Stobez		new_digest = SHA256_File(p->fts_accpath, buf);
305144295Stobez		if (!new_digest) {
306144295Stobez			LABEL;
307144295Stobez			printf("%sSHA-256: %s: %s\n", tab, p->fts_accpath,
308144295Stobez			       strerror(errno));
309144295Stobez			tab = "\t";
310144295Stobez		} else if (strcmp(new_digest, s->sha256digest)) {
311144295Stobez			LABEL;
312144295Stobez			printf("%sSHA-256 expected %s found %s\n",
313144295Stobez			       tab, s->sha256digest, new_digest);
314144295Stobez			tab = "\t";
315144295Stobez		}
316144295Stobez	}
317144295Stobez#endif /* SHA256 */
318144295Stobez
31965812Ssheldonh	if (s->flags & F_SLINK &&
32065812Ssheldonh	    strcmp(cp = rlink(p->fts_accpath), s->slink)) {
3211553Srgrimes		LABEL;
32266584Sphk		(void)printf("%slink_ref expected %s found %s\n",
323112194Stobez		      tab, s->slink, cp);
3241553Srgrimes	}
3251553Srgrimes	return (label);
3261553Srgrimes}
3271553Srgrimes
32899802Salfredconst char *
329121299Sphkinotype(u_int type)
3301553Srgrimes{
3311553Srgrimes	switch(type & S_IFMT) {
3321553Srgrimes	case S_IFBLK:
3331553Srgrimes		return ("block");
3341553Srgrimes	case S_IFCHR:
3351553Srgrimes		return ("char");
3361553Srgrimes	case S_IFDIR:
3371553Srgrimes		return ("dir");
3381553Srgrimes	case S_IFIFO:
3391553Srgrimes		return ("fifo");
3401553Srgrimes	case S_IFREG:
3411553Srgrimes		return ("file");
3421553Srgrimes	case S_IFLNK:
3431553Srgrimes		return ("link");
3441553Srgrimes	case S_IFSOCK:
3451553Srgrimes		return ("socket");
3461553Srgrimes	default:
3471553Srgrimes		return ("unknown");
3481553Srgrimes	}
3491553Srgrimes	/* NOTREACHED */
3501553Srgrimes}
3511553Srgrimes
352122141Sphkconst char *
353121299Sphkftype(u_int type)
3541553Srgrimes{
3551553Srgrimes	switch(type) {
3561553Srgrimes	case F_BLOCK:
3571553Srgrimes		return ("block");
3581553Srgrimes	case F_CHAR:
3591553Srgrimes		return ("char");
3601553Srgrimes	case F_DIR:
3611553Srgrimes		return ("dir");
3621553Srgrimes	case F_FIFO:
3631553Srgrimes		return ("fifo");
3641553Srgrimes	case F_FILE:
3651553Srgrimes		return ("file");
3661553Srgrimes	case F_LINK:
3671553Srgrimes		return ("link");
3681553Srgrimes	case F_SOCK:
3691553Srgrimes		return ("socket");
3701553Srgrimes	default:
3711553Srgrimes		return ("unknown");
3721553Srgrimes	}
3731553Srgrimes	/* NOTREACHED */
3741553Srgrimes}
3751553Srgrimes
3761553Srgrimeschar *
377121299Sphkrlink(char *name)
3781553Srgrimes{
379121734Sphk	static char lbuf[MAXPATHLEN * 4];
380121299Sphk	int len;
381121853Sbde	char tbuf[MAXPATHLEN];
3821553Srgrimes
383121734Sphk	if ((len = readlink(name, tbuf, sizeof(tbuf) - 1)) == -1)
38430027Scharnier		err(1, "line %d: %s", lineno, name);
385121734Sphk	tbuf[len] = '\0';
386121734Sphk	strvis(lbuf, tbuf, VIS_WHITE | VIS_OCTAL);
3871553Srgrimes	return (lbuf);
3881553Srgrimes}
389