1122141Sphk/*-
2122141Sphk * Copyright (c) 2003 Poul-Henning Kamp
3122141Sphk * All rights reserved.
4122141Sphk *
5133249Simp * Redistribution and use in source and binary forms, with or without
6133249Simp * modification, are permitted provided that the following conditions
7133249Simp * are met:
8133249Simp * 1. Redistributions of source code must retain the above copyright
9133249Simp *    notice, this list of conditions and the following disclaimer.
10133249Simp * 2. Redistributions in binary form must reproduce the above copyright
11133249Simp *    notice, this list of conditions and the following disclaimer in the
12133249Simp *    documentation and/or other materials provided with the distribution.
13133249Simp *
14133249Simp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15133249Simp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16133249Simp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17133249Simp * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18133249Simp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19133249Simp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20133249Simp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21133249Simp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22133249Simp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23133249Simp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24133249Simp * SUCH DAMAGE.
25122141Sphk */
26122141Sphk
27122141Sphk#include <sys/cdefs.h>
28122141Sphk__FBSDID("$FreeBSD$");
29122141Sphk
30122141Sphk#include <err.h>
31122141Sphk#include <grp.h>
32122141Sphk#include <pwd.h>
33122141Sphk#include <stdio.h>
34122141Sphk#include <stdint.h>
35122141Sphk#include <unistd.h>
36122141Sphk#include "mtree.h"
37122141Sphk#include "extern.h"
38122141Sphk
39122141Sphk#define FF(a, b, c, d) \
40122141Sphk	(((a)->flags & (c)) && ((b)->flags & (c)) && ((a)->d) != ((b)->d))
41122141Sphk#define FS(a, b, c, d) \
42122141Sphk	(((a)->flags & (c)) && ((b)->flags & (c)) && strcmp((a)->d,(b)->d))
43122141Sphk#define FM(a, b, c, d) \
44122141Sphk	(((a)->flags & (c)) && ((b)->flags & (c)) && memcmp(&(a)->d,&(b)->d, sizeof (a)->d))
45122141Sphk
46122141Sphkstatic void
47122141Sphkshownode(NODE *n, int f, char const *path)
48122141Sphk{
49122141Sphk	struct group *gr;
50122141Sphk	struct passwd *pw;
51122141Sphk
52122141Sphk	printf("%s%s %s", path, n->name, ftype(n->type));
53122141Sphk	if (f & F_CKSUM)
54122141Sphk		printf(" cksum=%lu", n->cksum);
55122141Sphk	if (f & F_GID)
56122141Sphk		printf(" gid=%d", n->st_gid);
57122141Sphk	if (f & F_GNAME) {
58122141Sphk		gr = getgrgid(n->st_gid);
59122141Sphk		if (gr == NULL)
60122141Sphk			printf(" gid=%d", n->st_gid);
61122141Sphk		else
62122141Sphk			printf(" gname=%s", gr->gr_name);
63122141Sphk	}
64122141Sphk	if (f & F_MODE)
65122141Sphk		printf(" mode=%o", n->st_mode);
66122141Sphk	if (f & F_NLINK)
67122141Sphk		printf(" nlink=%d", n->st_nlink);
68122141Sphk	if (f & F_SIZE)
69122141Sphk		printf(" size=%jd", (intmax_t)n->st_size);
70122141Sphk	if (f & F_UID)
71122141Sphk		printf(" uid=%d", n->st_uid);
72122141Sphk	if (f & F_UNAME) {
73122141Sphk		pw = getpwuid(n->st_uid);
74122141Sphk		if (pw == NULL)
75122141Sphk			printf(" uid=%d", n->st_uid);
76122141Sphk		else
77122141Sphk			printf(" uname=%s", pw->pw_name);
78122141Sphk	}
79122141Sphk	if (f & F_MD5)
80122141Sphk		printf(" md5digest=%s", n->md5digest);
81122141Sphk	if (f & F_SHA1)
82122141Sphk		printf(" sha1digest=%s", n->sha1digest);
83122141Sphk	if (f & F_RMD160)
84122141Sphk		printf(" rmd160digest=%s", n->rmd160digest);
85144295Stobez	if (f & F_SHA256)
86144295Stobez		printf(" sha256digest=%s", n->sha256digest);
87122141Sphk	if (f & F_FLAGS)
88122141Sphk		printf(" flags=%s", flags_to_string(n->st_flags));
89122141Sphk	printf("\n");
90122141Sphk}
91122141Sphk
92122141Sphkstatic int
93122141Sphkmismatch(NODE *n1, NODE *n2, int differ, char const *path)
94122141Sphk{
95123067Sphk
96122141Sphk	if (n2 == NULL) {
97122141Sphk		shownode(n1, differ, path);
98122141Sphk		return (1);
99122141Sphk	}
100122141Sphk	if (n1 == NULL) {
101122141Sphk		printf("\t");
102122141Sphk		shownode(n2, differ, path);
103122141Sphk		return (1);
104122141Sphk	}
105130455Sphk	if (!(differ & keys))
106130455Sphk		return(0);
107122141Sphk	printf("\t\t");
108122141Sphk	shownode(n1, differ, path);
109122141Sphk	printf("\t\t");
110122141Sphk	shownode(n2, differ, path);
111122141Sphk	return (1);
112122141Sphk}
113122141Sphk
114122141Sphkstatic int
115122141Sphkcompare_nodes(NODE *n1, NODE *n2, char const *path)
116122141Sphk{
117122141Sphk	int differs;
118122141Sphk
119130455Sphk	if (n1 != NULL && n1->type == F_LINK)
120130455Sphk		n1->flags &= ~F_MODE;
121130455Sphk	if (n2 != NULL && n2->type == F_LINK)
122130455Sphk		n2->flags &= ~F_MODE;
123122141Sphk	differs = 0;
124122141Sphk	if (n1 == NULL && n2 != NULL) {
125122141Sphk		differs = n2->flags;
126122141Sphk		mismatch(n1, n2, differs, path);
127122141Sphk		return (1);
128122141Sphk	}
129122141Sphk	if (n1 != NULL && n2 == NULL) {
130122141Sphk		differs = n1->flags;
131122141Sphk		mismatch(n1, n2, differs, path);
132122141Sphk		return (1);
133122141Sphk	}
134122141Sphk	if (n1->type != n2->type) {
135122141Sphk		differs = 0;
136122141Sphk		mismatch(n1, n2, differs, path);
137122141Sphk		return (1);
138122141Sphk	}
139122141Sphk	if (FF(n1, n2, F_CKSUM, cksum))
140122141Sphk		differs |= F_CKSUM;
141122141Sphk	if (FF(n1, n2, F_GID, st_gid))
142122141Sphk		differs |= F_GID;
143122141Sphk	if (FF(n1, n2, F_GNAME, st_gid))
144122141Sphk		differs |= F_GNAME;
145122141Sphk	if (FF(n1, n2, F_MODE, st_mode))
146122141Sphk		differs |= F_MODE;
147122141Sphk	if (FF(n1, n2, F_NLINK, st_nlink))
148122141Sphk		differs |= F_NLINK;
149122141Sphk	if (FF(n1, n2, F_SIZE, st_size))
150122141Sphk		differs |= F_SIZE;
151122141Sphk	if (FS(n1, n2, F_SLINK, slink))
152122141Sphk		differs |= F_SLINK;
153122141Sphk	if (FM(n1, n2, F_TIME, st_mtimespec))
154122141Sphk		differs |= F_TIME;
155122141Sphk	if (FF(n1, n2, F_UID, st_uid))
156122141Sphk		differs |= F_UID;
157122141Sphk	if (FF(n1, n2, F_UNAME, st_uid))
158122141Sphk		differs |= F_UNAME;
159122141Sphk	if (FS(n1, n2, F_MD5, md5digest))
160122141Sphk		differs |= F_MD5;
161122141Sphk	if (FS(n1, n2, F_SHA1, sha1digest))
162122141Sphk		differs |= F_SHA1;
163122141Sphk	if (FS(n1, n2, F_RMD160, rmd160digest))
164122141Sphk		differs |= F_RMD160;
165144295Stobez	if (FS(n1, n2, F_SHA256, sha256digest))
166144295Stobez		differs |= F_SHA256;
167122141Sphk	if (FF(n1, n2, F_FLAGS, st_flags))
168122141Sphk		differs |= F_FLAGS;
169122141Sphk	if (differs) {
170122141Sphk		mismatch(n1, n2, differs, path);
171122141Sphk		return (1);
172122141Sphk	}
173122141Sphk	return (0);
174122141Sphk}
175122141Sphkstatic int
176122141Sphkwalk_in_the_forest(NODE *t1, NODE *t2, char const *path)
177122141Sphk{
178122141Sphk	int r, i;
179122141Sphk	NODE *c1, *c2, *n1, *n2;
180122141Sphk	char *np;
181122141Sphk
182122141Sphk	r = 0;
183122141Sphk
184123067Sphk	if (t1 != NULL)
185123067Sphk		c1 = t1->child;
186123067Sphk	else
187123067Sphk		c1 = NULL;
188123067Sphk	if (t2 != NULL)
189123067Sphk		c2 = t2->child;
190123067Sphk	else
191123067Sphk		c2 = NULL;
192122141Sphk	while (c1 != NULL || c2 != NULL) {
193122141Sphk		n1 = n2 = NULL;
194122141Sphk		if (c1 != NULL)
195122141Sphk			n1 = c1->next;
196122141Sphk		if (c2 != NULL)
197122141Sphk			n2 = c2->next;
198122141Sphk		if (c1 != NULL && c2 != NULL) {
199123067Sphk			if (c1->type != F_DIR && c2->type == F_DIR) {
200123067Sphk				n2 = c2;
201123067Sphk				c2 = NULL;
202123067Sphk			} else if (c1->type == F_DIR && c2->type != F_DIR) {
203122141Sphk				n1 = c1;
204122141Sphk				c1 = NULL;
205123067Sphk			} else {
206123067Sphk				i = strcmp(c1->name, c2->name);
207123067Sphk				if (i > 0) {
208123067Sphk					n1 = c1;
209123067Sphk					c1 = NULL;
210123067Sphk				} else if (i < 0) {
211123067Sphk					n2 = c2;
212123067Sphk					c2 = NULL;
213123067Sphk				}
214122141Sphk			}
215122141Sphk		}
216130455Sphk		if (c1 == NULL && c2->type == F_DIR) {
217130455Sphk			asprintf(&np, "%s%s/", path, c2->name);
218130455Sphk			i = walk_in_the_forest(c1, c2, np);
219130455Sphk			free(np);
220144295Stobez			i += compare_nodes(c1, c2, path);
221130455Sphk		} else if (c2 == NULL && c1->type == F_DIR) {
222122141Sphk			asprintf(&np, "%s%s/", path, c1->name);
223122141Sphk			i = walk_in_the_forest(c1, c2, np);
224122141Sphk			free(np);
225144295Stobez			i += compare_nodes(c1, c2, path);
226130455Sphk		} else if (c1 == NULL || c2 == NULL) {
227130455Sphk			i = compare_nodes(c1, c2, path);
228130455Sphk		} else if (c1->type == F_DIR && c2->type == F_DIR) {
229130455Sphk			asprintf(&np, "%s%s/", path, c1->name);
230130455Sphk			i = walk_in_the_forest(c1, c2, np);
231130455Sphk			free(np);
232144295Stobez			i += compare_nodes(c1, c2, path);
233122141Sphk		} else {
234122141Sphk			i = compare_nodes(c1, c2, path);
235122141Sphk		}
236122141Sphk		r += i;
237122141Sphk		c1 = n1;
238122141Sphk		c2 = n2;
239122141Sphk	}
240122141Sphk	return (r);
241122141Sphk}
242122141Sphk
243122141Sphkint
244122141Sphkmtree_specspec(FILE *fi, FILE *fj)
245122141Sphk{
246122141Sphk	int rval;
247122141Sphk	NODE *root1, *root2;
248122141Sphk
249122141Sphk	root1 = mtree_readspec(fi);
250122141Sphk	root2 = mtree_readspec(fj);
251122141Sphk	rval = walk_in_the_forest(root1, root2, "");
252130455Sphk	rval += compare_nodes(root1, root2, "");
253122141Sphk	if (rval > 0)
254122141Sphk		return (MISMATCHEXIT);
255122141Sphk	return (0);
256122141Sphk}
257