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