compare.c revision 99800
1/*-
2 * Copyright (c) 1989, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 *    must display the following acknowledgement:
15 *	This product includes software developed by the University of
16 *	California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#ifndef lint
35#if 0
36static char sccsid[] = "@(#)compare.c	8.1 (Berkeley) 6/6/93";
37#endif
38static const char rcsid[] =
39  "$FreeBSD: head/usr.sbin/mtree/compare.c 99800 2002-07-11 18:31:16Z alfred $";
40#endif /* not lint */
41
42#include <sys/param.h>
43#include <sys/stat.h>
44#include <err.h>
45#include <errno.h>
46#include <fcntl.h>
47#include <fts.h>
48#ifdef MD5
49#include <md5.h>
50#endif
51#ifdef SHA1
52#include <sha.h>
53#endif
54#ifdef RMD160
55#include <ripemd.h>
56#endif
57#include <stdio.h>
58#include <time.h>
59#include <unistd.h>
60#include "mtree.h"
61#include "extern.h"
62
63extern int uflag;
64extern int lineno;
65
66static char *ftype(u_int);
67
68#define	INDENTNAMELEN	8
69#define	LABEL \
70	if (!label++) { \
71		len = printf("%s changed\n", RP(p)); \
72		tab = "\t"; \
73	}
74
75int
76compare(name, s, p)
77	char *name;
78	register NODE *s;
79	register FTSENT *p;
80{
81	extern int uflag;
82	u_long len, val;
83	int fd, label;
84	char *cp, *tab = "";
85	char *fflags;
86
87	label = 0;
88	switch(s->type) {
89	case F_BLOCK:
90		if (!S_ISBLK(p->fts_statp->st_mode))
91			goto typeerr;
92		break;
93	case F_CHAR:
94		if (!S_ISCHR(p->fts_statp->st_mode))
95			goto typeerr;
96		break;
97	case F_DIR:
98		if (!S_ISDIR(p->fts_statp->st_mode))
99			goto typeerr;
100		break;
101	case F_FIFO:
102		if (!S_ISFIFO(p->fts_statp->st_mode))
103			goto typeerr;
104		break;
105	case F_FILE:
106		if (!S_ISREG(p->fts_statp->st_mode))
107			goto typeerr;
108		break;
109	case F_LINK:
110		if (!S_ISLNK(p->fts_statp->st_mode))
111			goto typeerr;
112		break;
113	case F_SOCK:
114		if (!S_ISSOCK(p->fts_statp->st_mode)) {
115typeerr:		LABEL;
116			(void)printf("\ttype expected %s found %s\n",
117			    ftype(s->type), inotype(p->fts_statp->st_mode));
118			return (label);
119		}
120		break;
121	}
122	/* Set the uid/gid first, then set the mode. */
123	if (s->flags & (F_UID | F_UNAME) && s->st_uid != p->fts_statp->st_uid) {
124		LABEL;
125		(void)printf("%suser expected %lu found %lu",
126		    tab, (u_long)s->st_uid, (u_long)p->fts_statp->st_uid);
127		if (uflag)
128			if (chown(p->fts_accpath, s->st_uid, -1))
129				(void)printf(" not modified: %s\n",
130				    strerror(errno));
131			else
132				(void)printf(" modified\n");
133		else
134			(void)printf("\n");
135		tab = "\t";
136	}
137	if (s->flags & (F_GID | F_GNAME) && s->st_gid != p->fts_statp->st_gid) {
138		LABEL;
139		(void)printf("%sgid expected %lu found %lu",
140		    tab, (u_long)s->st_gid, (u_long)p->fts_statp->st_gid);
141		if (uflag)
142			if (chown(p->fts_accpath, -1, s->st_gid))
143				(void)printf(" not modified: %s\n",
144				    strerror(errno));
145			else
146				(void)printf(" modified\n");
147		else
148			(void)printf("\n");
149		tab = "\t";
150	}
151	if (s->flags & F_MODE &&
152	    !S_ISLNK(p->fts_statp->st_mode) &&
153	    s->st_mode != (p->fts_statp->st_mode & MBITS)) {
154		LABEL;
155		(void)printf("%spermissions expected %#o found %#o",
156		    tab, s->st_mode, p->fts_statp->st_mode & MBITS);
157		if (uflag)
158			if (chmod(p->fts_accpath, s->st_mode))
159				(void)printf(" not modified: %s\n",
160				    strerror(errno));
161			else
162				(void)printf(" modified\n");
163		else
164			(void)printf("\n");
165		tab = "\t";
166	}
167	if (s->flags & F_NLINK && s->type != F_DIR &&
168	    s->st_nlink != p->fts_statp->st_nlink) {
169		LABEL;
170		(void)printf("%slink_count expected %u found %u\n",
171		    tab, s->st_nlink, p->fts_statp->st_nlink);
172		tab = "\t";
173	}
174	if (s->flags & F_SIZE && s->st_size != p->fts_statp->st_size &&
175		!S_ISDIR(p->fts_statp->st_mode)) {
176		LABEL;
177		(void)printf("%ssize expected %qd found %qd\n",
178		    tab, s->st_size, p->fts_statp->st_size);
179		tab = "\t";
180	}
181	/*
182	 * XXX
183	 * Catches nano-second differences, but doesn't display them.
184	 */
185	if ((s->flags & F_TIME) &&
186	     ((s->st_mtimespec.tv_sec != p->fts_statp->st_mtimespec.tv_sec) ||
187	     (s->st_mtimespec.tv_nsec != p->fts_statp->st_mtimespec.tv_nsec))) {
188		LABEL;
189		(void)printf("%smodification time expected %.24s ",
190		    tab, ctime(&s->st_mtimespec.tv_sec));
191		(void)printf("found %.24s\n",
192		    ctime(&p->fts_statp->st_mtimespec.tv_sec));
193		tab = "\t";
194	}
195	if (s->flags & F_CKSUM) {
196		if ((fd = open(p->fts_accpath, O_RDONLY, 0)) < 0) {
197			LABEL;
198			(void)printf("%scksum: %s: %s\n",
199			    tab, p->fts_accpath, strerror(errno));
200			tab = "\t";
201		} else if (crc(fd, &val, &len)) {
202			(void)close(fd);
203			LABEL;
204			(void)printf("%scksum: %s: %s\n",
205			    tab, p->fts_accpath, strerror(errno));
206			tab = "\t";
207		} else {
208			(void)close(fd);
209			if (s->cksum != val) {
210				LABEL;
211				(void)printf("%scksum expected %lu found %lu\n",
212				    tab, s->cksum, val);
213			}
214			tab = "\t";
215		}
216	}
217	/*
218	 * XXX
219	 * since chflags(2) will reset file times, the utimes() above
220	 * may have been useless!  oh well, we'd rather have correct
221	 * flags, rather than times?
222	 */
223	if ((s->flags & F_FLAGS) && s->st_flags != p->fts_statp->st_flags) {
224		LABEL;
225		fflags = flags_to_string(s->st_flags);
226		(void)printf("%sflags expected \"%s\"", tab, fflags);
227		free(fflags);
228
229		fflags = flags_to_string(p->fts_statp->st_flags);
230		(void)printf(" found \"%s\"", fflags);
231		free(fflags);
232
233		if (uflag)
234			if (chflags(p->fts_accpath, s->st_flags))
235				(void)printf(" not modified: %s\n",
236				    strerror(errno));
237			else
238				(void)printf(" modified\n");
239		else
240			(void)printf("\n");
241		tab = "\t";
242	}
243#ifdef MD5
244	if (s->flags & F_MD5) {
245		char *new_digest, buf[33];
246
247		new_digest = MD5File(p->fts_accpath, buf);
248		if (!new_digest) {
249			LABEL;
250			printf("%sMD5: %s: %s\n", tab, p->fts_accpath,
251			       strerror(errno));
252			tab = "\t";
253		} else if (strcmp(new_digest, s->md5digest)) {
254			LABEL;
255			printf("%sMD5 expected %s found %s\n", tab, s->md5digest,
256			       new_digest);
257			tab = "\t";
258		}
259	}
260#endif /* MD5 */
261#ifdef SHA1
262	if (s->flags & F_SHA1) {
263		char *new_digest, buf[41];
264
265		new_digest = SHA1_File(p->fts_accpath, buf);
266		if (!new_digest) {
267			LABEL;
268			printf("%sSHA-1: %s: %s\n", tab, p->fts_accpath,
269			       strerror(errno));
270			tab = "\t";
271		} else if (strcmp(new_digest, s->sha1digest)) {
272			LABEL;
273			printf("%sSHA-1 expected %s found %s\n",
274			       tab, s->sha1digest, new_digest);
275			tab = "\t";
276		}
277	}
278#endif /* SHA1 */
279#ifdef RMD160
280	if (s->flags & F_RMD160) {
281		char *new_digest, buf[41];
282
283		new_digest = RIPEMD160_File(p->fts_accpath, buf);
284		if (!new_digest) {
285			LABEL;
286			printf("%sRIPEMD160: %s: %s\n", tab,
287			       p->fts_accpath, strerror(errno));
288			tab = "\t";
289		} else if (strcmp(new_digest, s->rmd160digest)) {
290			LABEL;
291			printf("%sRIPEMD160 expected %s found %s\n",
292			       tab, s->rmd160digest, new_digest);
293			tab = "\t";
294		}
295	}
296#endif /* RMD160 */
297
298	if (s->flags & F_SLINK &&
299	    strcmp(cp = rlink(p->fts_accpath), s->slink)) {
300		LABEL;
301		(void)printf("%slink_ref expected %s found %s\n",
302		      tab, cp, s->slink);
303	}
304	return (label);
305}
306
307char *
308inotype(type)
309	u_int type;
310{
311	switch(type & S_IFMT) {
312	case S_IFBLK:
313		return ("block");
314	case S_IFCHR:
315		return ("char");
316	case S_IFDIR:
317		return ("dir");
318	case S_IFIFO:
319		return ("fifo");
320	case S_IFREG:
321		return ("file");
322	case S_IFLNK:
323		return ("link");
324	case S_IFSOCK:
325		return ("socket");
326	default:
327		return ("unknown");
328	}
329	/* NOTREACHED */
330}
331
332static char *
333ftype(type)
334	u_int type;
335{
336	switch(type) {
337	case F_BLOCK:
338		return ("block");
339	case F_CHAR:
340		return ("char");
341	case F_DIR:
342		return ("dir");
343	case F_FIFO:
344		return ("fifo");
345	case F_FILE:
346		return ("file");
347	case F_LINK:
348		return ("link");
349	case F_SOCK:
350		return ("socket");
351	default:
352		return ("unknown");
353	}
354	/* NOTREACHED */
355}
356
357char *
358rlink(name)
359	char *name;
360{
361	static char lbuf[MAXPATHLEN];
362	register int len;
363
364	if ((len = readlink(name, lbuf, sizeof(lbuf) - 1)) == -1)
365		err(1, "line %d: %s", lineno, name);
366	lbuf[len] = '\0';
367	return (lbuf);
368}
369