compare.c revision 54375
1111500Sobrien/*-
2111500Sobrien * Copyright (c) 1989, 1993
3111500Sobrien *	The Regents of the University of California.  All rights reserved.
4111500Sobrien *
5111500Sobrien * Redistribution and use in source and binary forms, with or without
6111500Sobrien * modification, are permitted provided that the following conditions
7111500Sobrien * are met:
8111500Sobrien * 1. Redistributions of source code must retain the above copyright
9111500Sobrien *    notice, this list of conditions and the following disclaimer.
10111500Sobrien * 2. Redistributions in binary form must reproduce the above copyright
11111500Sobrien *    notice, this list of conditions and the following disclaimer in the
12111500Sobrien *    documentation and/or other materials provided with the distribution.
13111500Sobrien * 3. All advertising materials mentioning features or use of this software
14117121Stmm *    must display the following acknowledgement:
15111500Sobrien *	This product includes software developed by the University of
16111500Sobrien *	California, Berkeley and its contributors.
17111500Sobrien * 4. Neither the name of the University nor the names of its contributors
18111500Sobrien *    may be used to endorse or promote products derived from this software
19111500Sobrien *    without specific prior written permission.
20111500Sobrien *
21111500Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22111500Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23111500Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24111500Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25111500Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26111500Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27111500Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28111500Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29111500Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30111500Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31111500Sobrien * SUCH DAMAGE.
32111500Sobrien */
33111500Sobrien
34111500Sobrien#ifndef lint
35111500Sobrien#if 0
36133909Smariusstatic char sccsid[] = "@(#)compare.c	8.1 (Berkeley) 6/6/93";
37137814Smarius#endif
38137822Smariusstatic const char rcsid[] =
39137822Smarius  "$FreeBSD: head/usr.sbin/mtree/compare.c 54375 1999-12-09 20:38:36Z joe $";
40206451Smarius#endif /* not lint */
41111500Sobrien
42111500Sobrien#include <sys/param.h>
43111500Sobrien#include <sys/stat.h>
44111500Sobrien#include <err.h>
45111500Sobrien#include <errno.h>
46136301Syongari#include <fcntl.h>
47202587Smarius#include <fts.h>
48146483Smarius#ifdef MD5
49146483Smarius#include <md5.h>
50133909Smarius#endif
51133909Smarius#ifdef SHA1
52133909Smarius#include <sha.h>
53133909Smarius#endif
54163535Sdes#ifdef RMD160
55163535Sdes#include <ripemd.h>
56163535Sdes#endif
57163535Sdes#include <stdio.h>
58163535Sdes#include <time.h>
59163535Sdes#include <unistd.h>
60163535Sdes#include "mtree.h"
61163535Sdes#include "extern.h"
62163535Sdes
63163535Sdesextern int uflag;
64163535Sdesextern int lineno;
65163535Sdes
66163535Sdesstatic char *ftype __P((u_int));
67163535Sdes
68163627Sru#define	INDENTNAMELEN	8
69163627Sru#define	LABEL \
70163627Sru	if (!label++) { \
71163627Sru		len = printf("%s: ", RP(p)); \
72163535Sdes		if (len > INDENTNAMELEN) { \
73163535Sdes			tab = "\t"; \
74163535Sdes			(void)printf("\n"); \
75163535Sdes		} else { \
76163535Sdes			tab = ""; \
77163535Sdes			(void)printf("%*s", INDENTNAMELEN - (int)len, ""); \
78163535Sdes		} \
79163890Smarius	}
80163890Smarius
81163890Smariusint
82163890Smariuscompare(name, s, p)
83163890Smarius	char *name;
84163890Smarius	register NODE *s;
85163890Smarius	register FTSENT *p;
86163890Smarius{
87163890Smarius	extern int uflag;
88163890Smarius	u_long len, val;
89111500Sobrien	int fd, label;
90111500Sobrien	char *cp, *tab = "";
91111500Sobrien
92111500Sobrien	label = 0;
93111500Sobrien	switch(s->type) {
94140243Sru	case F_BLOCK:
95111500Sobrien		if (!S_ISBLK(p->fts_statp->st_mode))
96111500Sobrien			goto typeerr;
97111500Sobrien		break;
98111500Sobrien	case F_CHAR:
99137812Smarius		if (!S_ISCHR(p->fts_statp->st_mode))
100137812Smarius			goto typeerr;
101133909Smarius		break;
102137812Smarius	case F_DIR:
103133909Smarius		if (!S_ISDIR(p->fts_statp->st_mode))
104137812Smarius			goto typeerr;
105137812Smarius		break;
106133909Smarius	case F_FIFO:
107137812Smarius		if (!S_ISFIFO(p->fts_statp->st_mode))
108133909Smarius			goto typeerr;
109133909Smarius		break;
110133909Smarius	case F_FILE:
111137812Smarius		if (!S_ISREG(p->fts_statp->st_mode))
112133909Smarius			goto typeerr;
113133909Smarius		break;
114137812Smarius	case F_LINK:
115137812Smarius		if (!S_ISLNK(p->fts_statp->st_mode))
116133909Smarius			goto typeerr;
117133909Smarius		break;
118137812Smarius	case F_SOCK:
119137812Smarius		if (!S_ISSOCK(p->fts_statp->st_mode)) {
120137812Smariustypeerr:		LABEL;
121133909Smarius			(void)printf("\ttype (%s, %s)\n",
122133909Smarius			    ftype(s->type), inotype(p->fts_statp->st_mode));
123111500Sobrien		}
124111500Sobrien		break;
125111500Sobrien	}
126111500Sobrien	/* Set the uid/gid first, then set the mode. */
127111500Sobrien	if (s->flags & (F_UID | F_UNAME) && s->st_uid != p->fts_statp->st_uid) {
128111582Sru		LABEL;
129111582Sru		(void)printf("%suser (%lu, %lu",
130111582Sru		    tab, (u_long)s->st_uid, (u_long)p->fts_statp->st_uid);
131111582Sru		if (uflag)
132111582Sru			if (chown(p->fts_accpath, s->st_uid, -1))
133133909Smarius				(void)printf(", not modified: %s)\n",
134201410Smarius				    strerror(errno));
135111582Sru			else
136111582Sru				(void)printf(", modified)\n");
137111582Sru		else
138111582Sru			(void)printf(")\n");
139111582Sru		tab = "\t";
140111582Sru	}
141111582Sru	if (s->flags & (F_GID | F_GNAME) && s->st_gid != p->fts_statp->st_gid) {
142111582Sru		LABEL;
143111582Sru		(void)printf("%sgid (%lu, %lu",
144111582Sru		    tab, (u_long)s->st_gid, (u_long)p->fts_statp->st_gid);
145111582Sru		if (uflag)
146111582Sru			if (chown(p->fts_accpath, -1, s->st_gid))
147111582Sru				(void)printf(", not modified: %s)\n",
148111582Sru				    strerror(errno));
149111582Sru			else
150111582Sru				(void)printf(", modified)\n");
151111582Sru		else
152111582Sru			(void)printf(")\n");
153111582Sru		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	/*
220	 * XXX
221	 * since chflags(2) will reset file times, the utimes() above
222	 * may have been useless!  oh well, we'd rather have correct
223	 * flags, rather than times?
224	 */
225	if ((s->flags & F_FLAGS) && s->st_flags != p->fts_statp->st_flags) {
226		LABEL;
227		(void)printf("%sflags (\"%s\" is not ", tab,
228		    flags_to_string(s->st_flags, "none"));
229		(void)printf("\"%s\"",
230		    flags_to_string(p->fts_statp->st_flags, "none"));
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("%sMD5File: %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 (%s, %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("%sSHA1_File: %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 (%s, %s)\n", tab, s->sha1digest,
272			       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_File: %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 (%s, %s)\n", tab, s->rmd160digest,
290			       new_digest);
291			tab = "\t";
292		}
293	}
294#endif /* RMD160 */
295
296	if (s->flags & F_SLINK && strcmp(cp = rlink(name), s->slink)) {
297		LABEL;
298		(void)printf("%slink ref (%s, %s)\n", tab, cp, s->slink);
299	}
300	return (label);
301}
302
303char *
304inotype(type)
305	u_int type;
306{
307	switch(type & S_IFMT) {
308	case S_IFBLK:
309		return ("block");
310	case S_IFCHR:
311		return ("char");
312	case S_IFDIR:
313		return ("dir");
314	case S_IFIFO:
315		return ("fifo");
316	case S_IFREG:
317		return ("file");
318	case S_IFLNK:
319		return ("link");
320	case S_IFSOCK:
321		return ("socket");
322	default:
323		return ("unknown");
324	}
325	/* NOTREACHED */
326}
327
328static char *
329ftype(type)
330	u_int type;
331{
332	switch(type) {
333	case F_BLOCK:
334		return ("block");
335	case F_CHAR:
336		return ("char");
337	case F_DIR:
338		return ("dir");
339	case F_FIFO:
340		return ("fifo");
341	case F_FILE:
342		return ("file");
343	case F_LINK:
344		return ("link");
345	case F_SOCK:
346		return ("socket");
347	default:
348		return ("unknown");
349	}
350	/* NOTREACHED */
351}
352
353char *
354rlink(name)
355	char *name;
356{
357	static char lbuf[MAXPATHLEN];
358	register int len;
359
360	if ((len = readlink(name, lbuf, sizeof(lbuf) - 1)) == -1)
361		err(1, "line %d: %s", lineno, name);
362	lbuf[len] = '\0';
363	return (lbuf);
364}
365