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