compare.c revision 66584
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 66584 2000-10-03 13:13:47Z phk $";
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 __P((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		}
119		break;
120	}
121	/* Set the uid/gid first, then set the mode. */
122	if (s->flags & (F_UID | F_UNAME) && s->st_uid != p->fts_statp->st_uid) {
123		LABEL;
124		(void)printf("%suser expected %lu found %lu",
125		    tab, (u_long)s->st_uid, (u_long)p->fts_statp->st_uid);
126		if (uflag)
127			if (chown(p->fts_accpath, s->st_uid, -1))
128				(void)printf(" not modified: %s\n",
129				    strerror(errno));
130			else
131				(void)printf(" modified\n");
132		else
133			(void)printf("\n");
134		tab = "\t";
135	}
136	if (s->flags & (F_GID | F_GNAME) && s->st_gid != p->fts_statp->st_gid) {
137		LABEL;
138		(void)printf("%sgid expected %lu found %lu",
139		    tab, (u_long)s->st_gid, (u_long)p->fts_statp->st_gid);
140		if (uflag)
141			if (chown(p->fts_accpath, -1, s->st_gid))
142				(void)printf(" not modified: %s\n",
143				    strerror(errno));
144			else
145				(void)printf(" modified\n");
146		else
147			(void)printf("\n");
148		tab = "\t";
149	}
150	if (s->flags & F_MODE &&
151	    s->st_mode != (p->fts_statp->st_mode & MBITS)) {
152		LABEL;
153		(void)printf("%spermissions expected %#o found %#o",
154		    tab, s->st_mode, p->fts_statp->st_mode & MBITS);
155		if (uflag)
156			if (chmod(p->fts_accpath, s->st_mode))
157				(void)printf(" not modified: %s\n",
158				    strerror(errno));
159			else
160				(void)printf(" modified\n");
161		else
162			(void)printf("\n");
163		tab = "\t";
164	}
165	if (s->flags & F_NLINK && s->type != F_DIR &&
166	    s->st_nlink != p->fts_statp->st_nlink) {
167		LABEL;
168		(void)printf("%slink_count expected %u found %u\n",
169		    tab, s->st_nlink, p->fts_statp->st_nlink);
170		tab = "\t";
171	}
172	if (s->flags & F_SIZE && s->st_size != p->fts_statp->st_size &&
173		!S_ISDIR(p->fts_statp->st_mode)) {
174		LABEL;
175		(void)printf("%ssize expected %qd found %qd\n",
176		    tab, s->st_size, p->fts_statp->st_size);
177		tab = "\t";
178	}
179	/*
180	 * XXX
181	 * Catches nano-second differences, but doesn't display them.
182	 */
183	if ((s->flags & F_TIME) &&
184	     ((s->st_mtimespec.tv_sec != p->fts_statp->st_mtimespec.tv_sec) ||
185	     (s->st_mtimespec.tv_nsec != p->fts_statp->st_mtimespec.tv_nsec))) {
186		LABEL;
187		(void)printf("%smodification time expected %.24s ",
188		    tab, ctime(&s->st_mtimespec.tv_sec));
189		(void)printf("found %.24s\n",
190		    ctime(&p->fts_statp->st_mtimespec.tv_sec));
191		tab = "\t";
192	}
193	if (s->flags & F_CKSUM) {
194		if ((fd = open(p->fts_accpath, O_RDONLY, 0)) < 0) {
195			LABEL;
196			(void)printf("%scksum: %s: %s\n",
197			    tab, p->fts_accpath, strerror(errno));
198			tab = "\t";
199		} else if (crc(fd, &val, &len)) {
200			(void)close(fd);
201			LABEL;
202			(void)printf("%scksum: %s: %s\n",
203			    tab, p->fts_accpath, strerror(errno));
204			tab = "\t";
205		} else {
206			(void)close(fd);
207			if (s->cksum != val) {
208				LABEL;
209				(void)printf("%scksum expected %lu found %lu\n",
210				    tab, s->cksum, val);
211			}
212			tab = "\t";
213		}
214	}
215	/*
216	 * XXX
217	 * since chflags(2) will reset file times, the utimes() above
218	 * may have been useless!  oh well, we'd rather have correct
219	 * flags, rather than times?
220	 */
221	if ((s->flags & F_FLAGS) && s->st_flags != p->fts_statp->st_flags) {
222		LABEL;
223		fflags = flags_to_string(s->st_flags);
224		(void)printf("%sflags expected \"%s\"", tab, fflags);
225		free(fflags);
226
227		fflags = flags_to_string(p->fts_statp->st_flags);
228		(void)printf(" found \"%s\"", fflags);
229		free(fflags);
230
231		if (uflag)
232			if (chflags(p->fts_accpath, s->st_flags))
233				(void)printf(" not modified: %s\n",
234				    strerror(errno));
235			else
236				(void)printf(" modified\n");
237		else
238			(void)printf("\n");
239		tab = "\t";
240	}
241#ifdef MD5
242	if (s->flags & F_MD5) {
243		char *new_digest, buf[33];
244
245		new_digest = MD5File(p->fts_accpath, buf);
246		if (!new_digest) {
247			LABEL;
248			printf("%sMD5: %s: %s\n", tab, p->fts_accpath,
249			       strerror(errno));
250			tab = "\t";
251		} else if (strcmp(new_digest, s->md5digest)) {
252			LABEL;
253			printf("%sMD5 expected %s found %s\n", tab, s->md5digest,
254			       new_digest);
255			tab = "\t";
256		}
257	}
258#endif /* MD5 */
259#ifdef SHA1
260	if (s->flags & F_SHA1) {
261		char *new_digest, buf[41];
262
263		new_digest = SHA1_File(p->fts_accpath, buf);
264		if (!new_digest) {
265			LABEL;
266			printf("%sSHA-1: %s: %s\n", tab, p->fts_accpath,
267			       strerror(errno));
268			tab = "\t";
269		} else if (strcmp(new_digest, s->sha1digest)) {
270			LABEL;
271			printf("%sSHA-1 expected %s found %s\n",
272			       tab, s->sha1digest, new_digest);
273			tab = "\t";
274		}
275	}
276#endif /* SHA1 */
277#ifdef RMD160
278	if (s->flags & F_RMD160) {
279		char *new_digest, buf[41];
280
281		new_digest = RIPEMD160_File(p->fts_accpath, buf);
282		if (!new_digest) {
283			LABEL;
284			printf("%sRIPEMD160: %s: %s\n", tab,
285			       p->fts_accpath, strerror(errno));
286			tab = "\t";
287		} else if (strcmp(new_digest, s->rmd160digest)) {
288			LABEL;
289			printf("%sRIPEMD160 expected %s found %s\n",
290			       tab, s->rmd160digest, new_digest);
291			tab = "\t";
292		}
293	}
294#endif /* RMD160 */
295
296	if (s->flags & F_SLINK &&
297	    strcmp(cp = rlink(p->fts_accpath), s->slink)) {
298		LABEL;
299		(void)printf("%slink_ref expected %s found %s\n",
300		      tab, cp, s->slink);
301	}
302	return (label);
303}
304
305char *
306inotype(type)
307	u_int type;
308{
309	switch(type & S_IFMT) {
310	case S_IFBLK:
311		return ("block");
312	case S_IFCHR:
313		return ("char");
314	case S_IFDIR:
315		return ("dir");
316	case S_IFIFO:
317		return ("fifo");
318	case S_IFREG:
319		return ("file");
320	case S_IFLNK:
321		return ("link");
322	case S_IFSOCK:
323		return ("socket");
324	default:
325		return ("unknown");
326	}
327	/* NOTREACHED */
328}
329
330static char *
331ftype(type)
332	u_int type;
333{
334	switch(type) {
335	case F_BLOCK:
336		return ("block");
337	case F_CHAR:
338		return ("char");
339	case F_DIR:
340		return ("dir");
341	case F_FIFO:
342		return ("fifo");
343	case F_FILE:
344		return ("file");
345	case F_LINK:
346		return ("link");
347	case F_SOCK:
348		return ("socket");
349	default:
350		return ("unknown");
351	}
352	/* NOTREACHED */
353}
354
355char *
356rlink(name)
357	char *name;
358{
359	static char lbuf[MAXPATHLEN];
360	register int len;
361
362	if ((len = readlink(name, lbuf, sizeof(lbuf) - 1)) == -1)
363		err(1, "line %d: %s", lineno, name);
364	lbuf[len] = '\0';
365	return (lbuf);
366}
367