compare.c revision 66746
1158795Sdelphij/*-
2141261Sdelphij * Copyright (c) 1989, 1993
3141261Sdelphij *	The Regents of the University of California.  All rights reserved.
4141261Sdelphij *
5158795Sdelphij * Redistribution and use in source and binary forms, with or without
6141261Sdelphij * modification, are permitted provided that the following conditions
7141261Sdelphij * are met:
8141261Sdelphij * 1. Redistributions of source code must retain the above copyright
9141261Sdelphij *    notice, this list of conditions and the following disclaimer.
10141261Sdelphij * 2. Redistributions in binary form must reproduce the above copyright
11141261Sdelphij *    notice, this list of conditions and the following disclaimer in the
12141261Sdelphij *    documentation and/or other materials provided with the distribution.
13141261Sdelphij * 3. All advertising materials mentioning features or use of this software
14141261Sdelphij *    must display the following acknowledgement:
15141261Sdelphij *	This product includes software developed by the University of
16141261Sdelphij *	California, Berkeley and its contributors.
17141261Sdelphij * 4. Neither the name of the University nor the names of its contributors
18141261Sdelphij *    may be used to endorse or promote products derived from this software
19141261Sdelphij *    without specific prior written permission.
20141261Sdelphij *
21141261Sdelphij * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22141261Sdelphij * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23141261Sdelphij * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24141261Sdelphij * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25141261Sdelphij * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26141261Sdelphij * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27141261Sdelphij * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28141261Sdelphij * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29141261Sdelphij * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30141261Sdelphij * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31141261Sdelphij * SUCH DAMAGE.
32141261Sdelphij */
33141261Sdelphij
34141261Sdelphij#ifndef lint
35141261Sdelphij#if 0
36141261Sdelphijstatic char sccsid[] = "@(#)compare.c	8.1 (Berkeley) 6/6/93";
37141261Sdelphij#endif
38141261Sdelphijstatic const char rcsid[] =
39141261Sdelphij  "$FreeBSD: head/usr.sbin/mtree/compare.c 66746 2000-10-06 12:27:36Z phk $";
40158795Sdelphij#endif /* not lint */
41158795Sdelphij
42158795Sdelphij#include <sys/param.h>
43141261Sdelphij#include <sys/stat.h>
44141261Sdelphij#include <err.h>
45141261Sdelphij#include <errno.h>
46141261Sdelphij#include <fcntl.h>
47141261Sdelphij#include <fts.h>
48141261Sdelphij#ifdef MD5
49141261Sdelphij#include <md5.h>
50141261Sdelphij#endif
51141261Sdelphij#ifdef SHA1
52141261Sdelphij#include <sha.h>
53158795Sdelphij#endif
54158795Sdelphij#ifdef RMD160
55141261Sdelphij#include <ripemd.h>
56158795Sdelphij#endif
57158795Sdelphij#include <stdio.h>
58158795Sdelphij#include <time.h>
59158795Sdelphij#include <unistd.h>
60141261Sdelphij#include "mtree.h"
61158795Sdelphij#include "extern.h"
62158795Sdelphij
63158795Sdelphijextern int uflag;
64141261Sdelphijextern int lineno;
65158795Sdelphij
66158795Sdelphijstatic char *ftype __P((u_int));
67141261Sdelphij
68158795Sdelphij#define	INDENTNAMELEN	8
69158795Sdelphij#define	LABEL \
70158795Sdelphij	if (!label++) { \
71158795Sdelphij		len = printf("%s changed\n", RP(p)); \
72158795Sdelphij		tab = "\t"; \
73158795Sdelphij	}
74158795Sdelphij
75158795Sdelphijint
76158795Sdelphijcompare(name, s, p)
77158795Sdelphij	char *name;
78158795Sdelphij	register NODE *s;
79158795Sdelphij	register FTSENT *p;
80141261Sdelphij{
81158795Sdelphij	extern int uflag;
82158795Sdelphij	u_long len, val;
83158795Sdelphij	int fd, label;
84158795Sdelphij	char *cp, *tab = "";
85158795Sdelphij	char *fflags;
86158795Sdelphij
87158795Sdelphij	label = 0;
88141261Sdelphij	switch(s->type) {
89141261Sdelphij	case F_BLOCK:
90141261Sdelphij		if (!S_ISBLK(p->fts_statp->st_mode))
91158795Sdelphij			goto typeerr;
92141261Sdelphij		break;
93158795Sdelphij	case F_CHAR:
94141261Sdelphij		if (!S_ISCHR(p->fts_statp->st_mode))
95141261Sdelphij			goto typeerr;
96141261Sdelphij		break;
97141261Sdelphij	case F_DIR:
98158795Sdelphij		if (!S_ISDIR(p->fts_statp->st_mode))
99141261Sdelphij			goto typeerr;
100141261Sdelphij		break;
101141261Sdelphij	case F_FIFO:
102141261Sdelphij		if (!S_ISFIFO(p->fts_statp->st_mode))
103141261Sdelphij			goto typeerr;
104141261Sdelphij		break;
105141261Sdelphij	case F_FILE:
106141261Sdelphij		if (!S_ISREG(p->fts_statp->st_mode))
107141261Sdelphij			goto typeerr;
108141261Sdelphij		break;
109141261Sdelphij	case F_LINK:
110141261Sdelphij		if (!S_ISLNK(p->fts_statp->st_mode))
111141261Sdelphij			goto typeerr;
112158795Sdelphij		break;
113158795Sdelphij	case F_SOCK:
114158795Sdelphij		if (!S_ISSOCK(p->fts_statp->st_mode)) {
115158795Sdelphijtypeerr:		LABEL;
116158795Sdelphij			(void)printf("\ttype expected %s found %s\n",
117158795Sdelphij			    ftype(s->type), inotype(p->fts_statp->st_mode));
118158795Sdelphij		}
119158795Sdelphij		break;
120158795Sdelphij	}
121158795Sdelphij	/* Set the uid/gid first, then set the mode. */
122158795Sdelphij	if (s->flags & (F_UID | F_UNAME) && s->st_uid != p->fts_statp->st_uid) {
123158795Sdelphij		LABEL;
124158795Sdelphij		(void)printf("%suser expected %lu found %lu",
125141261Sdelphij		    tab, (u_long)s->st_uid, (u_long)p->fts_statp->st_uid);
126158795Sdelphij		if (uflag)
127158795Sdelphij			if (chown(p->fts_accpath, s->st_uid, -1))
128158795Sdelphij				(void)printf(" not modified: %s\n",
129158795Sdelphij				    strerror(errno));
130141261Sdelphij			else
131158795Sdelphij				(void)printf(" modified\n");
132158795Sdelphij		else
133141261Sdelphij			(void)printf("\n");
134158795Sdelphij		tab = "\t";
135158795Sdelphij	}
136158795Sdelphij	if (s->flags & (F_GID | F_GNAME) && s->st_gid != p->fts_statp->st_gid) {
137158795Sdelphij		LABEL;
138141261Sdelphij		(void)printf("%sgid expected %lu found %lu",
139158795Sdelphij		    tab, (u_long)s->st_gid, (u_long)p->fts_statp->st_gid);
140141261Sdelphij		if (uflag)
141141261Sdelphij			if (chown(p->fts_accpath, -1, s->st_gid))
142141261Sdelphij				(void)printf(" not modified: %s\n",
143141261Sdelphij				    strerror(errno));
144158795Sdelphij			else
145158795Sdelphij				(void)printf(" modified\n");
146158795Sdelphij		else
147158795Sdelphij			(void)printf("\n");
148158795Sdelphij		tab = "\t";
149158795Sdelphij	}
150158795Sdelphij	if (s->flags & F_MODE &&
151158795Sdelphij	    !S_ISLNK(p->fts_statp->st_mode) &&
152158795Sdelphij	    s->st_mode != (p->fts_statp->st_mode & MBITS)) {
153158795Sdelphij		LABEL;
154141261Sdelphij		(void)printf("%spermissions expected %#o found %#o",
155141261Sdelphij		    tab, s->st_mode, p->fts_statp->st_mode & MBITS);
156141261Sdelphij		if (uflag)
157158795Sdelphij			if (chmod(p->fts_accpath, s->st_mode))
158141261Sdelphij				(void)printf(" not modified: %s\n",
159158795Sdelphij				    strerror(errno));
160158795Sdelphij			else
161158795Sdelphij				(void)printf(" modified\n");
162158795Sdelphij		else
163141261Sdelphij			(void)printf("\n");
164141261Sdelphij		tab = "\t";
165141261Sdelphij	}
166141261Sdelphij	if (s->flags & F_NLINK && s->type != F_DIR &&
167141261Sdelphij	    s->st_nlink != p->fts_statp->st_nlink) {
168158795Sdelphij		LABEL;
169141261Sdelphij		(void)printf("%slink_count expected %u found %u\n",
170158795Sdelphij		    tab, s->st_nlink, p->fts_statp->st_nlink);
171141261Sdelphij		tab = "\t";
172158795Sdelphij	}
173158795Sdelphij	if (s->flags & F_SIZE && s->st_size != p->fts_statp->st_size &&
174158795Sdelphij		!S_ISDIR(p->fts_statp->st_mode)) {
175158795Sdelphij		LABEL;
176141261Sdelphij		(void)printf("%ssize expected %qd found %qd\n",
177158795Sdelphij		    tab, s->st_size, p->fts_statp->st_size);
178141261Sdelphij		tab = "\t";
179158795Sdelphij	}
180158795Sdelphij	/*
181158795Sdelphij	 * XXX
182141261Sdelphij	 * Catches nano-second differences, but doesn't display them.
183158795Sdelphij	 */
184158795Sdelphij	if ((s->flags & F_TIME) &&
185158795Sdelphij	     ((s->st_mtimespec.tv_sec != p->fts_statp->st_mtimespec.tv_sec) ||
186158795Sdelphij	     (s->st_mtimespec.tv_nsec != p->fts_statp->st_mtimespec.tv_nsec))) {
187158795Sdelphij		LABEL;
188158795Sdelphij		(void)printf("%smodification time expected %.24s ",
189158795Sdelphij		    tab, ctime(&s->st_mtimespec.tv_sec));
190158795Sdelphij		(void)printf("found %.24s\n",
191158795Sdelphij		    ctime(&p->fts_statp->st_mtimespec.tv_sec));
192158795Sdelphij		tab = "\t";
193158795Sdelphij	}
194158795Sdelphij	if (s->flags & F_CKSUM) {
195158795Sdelphij		if ((fd = open(p->fts_accpath, O_RDONLY, 0)) < 0) {
196158795Sdelphij			LABEL;
197158795Sdelphij			(void)printf("%scksum: %s: %s\n",
198158795Sdelphij			    tab, p->fts_accpath, strerror(errno));
199158795Sdelphij			tab = "\t";
200158795Sdelphij		} else if (crc(fd, &val, &len)) {
201158795Sdelphij			(void)close(fd);
202158795Sdelphij			LABEL;
203158795Sdelphij			(void)printf("%scksum: %s: %s\n",
204158795Sdelphij			    tab, p->fts_accpath, strerror(errno));
205158795Sdelphij			tab = "\t";
206158795Sdelphij		} else {
207158795Sdelphij			(void)close(fd);
208158795Sdelphij			if (s->cksum != val) {
209158795Sdelphij				LABEL;
210158795Sdelphij				(void)printf("%scksum expected %lu found %lu\n",
211158795Sdelphij				    tab, s->cksum, val);
212158795Sdelphij			}
213158795Sdelphij			tab = "\t";
214158795Sdelphij		}
215158795Sdelphij	}
216158795Sdelphij	/*
217158795Sdelphij	 * XXX
218158795Sdelphij	 * since chflags(2) will reset file times, the utimes() above
219158795Sdelphij	 * may have been useless!  oh well, we'd rather have correct
220141261Sdelphij	 * flags, rather than times?
221158795Sdelphij	 */
222158795Sdelphij	if ((s->flags & F_FLAGS) && s->st_flags != p->fts_statp->st_flags) {
223158795Sdelphij		LABEL;
224158795Sdelphij		fflags = flags_to_string(s->st_flags);
225158795Sdelphij		(void)printf("%sflags expected \"%s\"", tab, fflags);
226141261Sdelphij		free(fflags);
227158795Sdelphij
228141261Sdelphij		fflags = flags_to_string(p->fts_statp->st_flags);
229158795Sdelphij		(void)printf(" found \"%s\"", fflags);
230141261Sdelphij		free(fflags);
231158795Sdelphij
232158795Sdelphij		if (uflag)
233158795Sdelphij			if (chflags(p->fts_accpath, s->st_flags))
234158795Sdelphij				(void)printf(" not modified: %s\n",
235141261Sdelphij				    strerror(errno));
236141261Sdelphij			else
237141261Sdelphij				(void)printf(" modified\n");
238158795Sdelphij		else
239158795Sdelphij			(void)printf("\n");
240141261Sdelphij		tab = "\t";
241158795Sdelphij	}
242141261Sdelphij#ifdef MD5
243158795Sdelphij	if (s->flags & F_MD5) {
244158795Sdelphij		char *new_digest, buf[33];
245158795Sdelphij
246141261Sdelphij		new_digest = MD5File(p->fts_accpath, buf);
247158795Sdelphij		if (!new_digest) {
248141261Sdelphij			LABEL;
249158795Sdelphij			printf("%sMD5: %s: %s\n", tab, p->fts_accpath,
250141261Sdelphij			       strerror(errno));
251158795Sdelphij			tab = "\t";
252141261Sdelphij		} else if (strcmp(new_digest, s->md5digest)) {
253141261Sdelphij			LABEL;
254141261Sdelphij			printf("%sMD5 expected %s found %s\n", tab, s->md5digest,
255141261Sdelphij			       new_digest);
256141261Sdelphij			tab = "\t";
257158795Sdelphij		}
258141261Sdelphij	}
259141261Sdelphij#endif /* MD5 */
260141261Sdelphij#ifdef SHA1
261141261Sdelphij	if (s->flags & F_SHA1) {
262158795Sdelphij		char *new_digest, buf[41];
263141261Sdelphij
264141261Sdelphij		new_digest = SHA1_File(p->fts_accpath, buf);
265141261Sdelphij		if (!new_digest) {
266158795Sdelphij			LABEL;
267141261Sdelphij			printf("%sSHA-1: %s: %s\n", tab, p->fts_accpath,
268141261Sdelphij			       strerror(errno));
269158795Sdelphij			tab = "\t";
270158795Sdelphij		} else if (strcmp(new_digest, s->sha1digest)) {
271141261Sdelphij			LABEL;
272141261Sdelphij			printf("%sSHA-1 expected %s found %s\n",
273158795Sdelphij			       tab, s->sha1digest, new_digest);
274141261Sdelphij			tab = "\t";
275158795Sdelphij		}
276141261Sdelphij	}
277158795Sdelphij#endif /* SHA1 */
278158795Sdelphij#ifdef RMD160
279158795Sdelphij	if (s->flags & F_RMD160) {
280158795Sdelphij		char *new_digest, buf[41];
281158795Sdelphij
282158795Sdelphij		new_digest = RIPEMD160_File(p->fts_accpath, buf);
283158795Sdelphij		if (!new_digest) {
284158795Sdelphij			LABEL;
285158795Sdelphij			printf("%sRIPEMD160: %s: %s\n", tab,
286158795Sdelphij			       p->fts_accpath, strerror(errno));
287158795Sdelphij			tab = "\t";
288158795Sdelphij		} else if (strcmp(new_digest, s->rmd160digest)) {
289158795Sdelphij			LABEL;
290158795Sdelphij			printf("%sRIPEMD160 expected %s found %s\n",
291158795Sdelphij			       tab, s->rmd160digest, new_digest);
292158795Sdelphij			tab = "\t";
293158795Sdelphij		}
294158795Sdelphij	}
295158795Sdelphij#endif /* RMD160 */
296158795Sdelphij
297158795Sdelphij	if (s->flags & F_SLINK &&
298158795Sdelphij	    strcmp(cp = rlink(p->fts_accpath), s->slink)) {
299158795Sdelphij		LABEL;
300158795Sdelphij		(void)printf("%slink_ref expected %s found %s\n",
301158795Sdelphij		      tab, cp, s->slink);
302158795Sdelphij	}
303158795Sdelphij	return (label);
304158795Sdelphij}
305158795Sdelphij
306158795Sdelphijchar *
307158795Sdelphijinotype(type)
308158795Sdelphij	u_int type;
309158795Sdelphij{
310158795Sdelphij	switch(type & S_IFMT) {
311158795Sdelphij	case S_IFBLK:
312158795Sdelphij		return ("block");
313158795Sdelphij	case S_IFCHR:
314141261Sdelphij		return ("char");
315141261Sdelphij	case S_IFDIR:
316141261Sdelphij		return ("dir");
317141261Sdelphij	case S_IFIFO:
318141261Sdelphij		return ("fifo");
319158795Sdelphij	case S_IFREG:
320158795Sdelphij		return ("file");
321141261Sdelphij	case S_IFLNK:
322158795Sdelphij		return ("link");
323141261Sdelphij	case S_IFSOCK:
324158795Sdelphij		return ("socket");
325141261Sdelphij	default:
326		return ("unknown");
327	}
328	/* NOTREACHED */
329}
330
331static char *
332ftype(type)
333	u_int type;
334{
335	switch(type) {
336	case F_BLOCK:
337		return ("block");
338	case F_CHAR:
339		return ("char");
340	case F_DIR:
341		return ("dir");
342	case F_FIFO:
343		return ("fifo");
344	case F_FILE:
345		return ("file");
346	case F_LINK:
347		return ("link");
348	case F_SOCK:
349		return ("socket");
350	default:
351		return ("unknown");
352	}
353	/* NOTREACHED */
354}
355
356char *
357rlink(name)
358	char *name;
359{
360	static char lbuf[MAXPATHLEN];
361	register int len;
362
363	if ((len = readlink(name, lbuf, sizeof(lbuf) - 1)) == -1)
364		err(1, "line %d: %s", lineno, name);
365	lbuf[len] = '\0';
366	return (lbuf);
367}
368