1244541Sbrooks/*	$NetBSD: specspec.c,v 1.2 2012/10/05 01:27:29 christos Exp $	*/
2244541Sbrooks
3244541Sbrooks/*-
4244541Sbrooks * Copyright (c) 2003 Poul-Henning Kamp
5244541Sbrooks * All rights reserved.
6244541Sbrooks *
7244541Sbrooks * Redistribution and use in source and binary forms, with or without
8244541Sbrooks * modification, are permitted provided that the following conditions
9244541Sbrooks * are met:
10244541Sbrooks * 1. Redistributions of source code must retain the above copyright
11244541Sbrooks *    notice, this list of conditions and the following disclaimer.
12244541Sbrooks * 2. Redistributions in binary form must reproduce the above copyright
13244541Sbrooks *    notice, this list of conditions and the following disclaimer in the
14244541Sbrooks *    documentation and/or other materials provided with the distribution.
15244541Sbrooks *
16244541Sbrooks * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17244541Sbrooks * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18244541Sbrooks * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19244541Sbrooks * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20244541Sbrooks * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21244541Sbrooks * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22244541Sbrooks * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23244541Sbrooks * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24244541Sbrooks * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25244541Sbrooks * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26244541Sbrooks * SUCH DAMAGE.
27244541Sbrooks */
28244541Sbrooks
29244541Sbrooks#if HAVE_NBTOOL_CONFIG_H
30244541Sbrooks#include "nbtool_config.h"
31244541Sbrooks#endif
32244541Sbrooks
33244541Sbrooks#include <sys/cdefs.h>
34244541Sbrooks__RCSID("$NetBSD: specspec.c,v 1.2 2012/10/05 01:27:29 christos Exp $");
35244541Sbrooks
36244541Sbrooks#include <err.h>
37244541Sbrooks#include <grp.h>
38244541Sbrooks#include <pwd.h>
39244541Sbrooks#include <time.h>
40244541Sbrooks#include <stdio.h>
41244541Sbrooks#include <stdint.h>
42244541Sbrooks#include <stdlib.h>
43244541Sbrooks#include <string.h>
44244541Sbrooks#include <unistd.h>
45244541Sbrooks#include "mtree.h"
46244541Sbrooks#include "extern.h"
47244541Sbrooks
48244541Sbrooks#define FF(a, b, c, d) \
49244541Sbrooks	(((a)->flags & (c)) && ((b)->flags & (c)) && ((a)->d) != ((b)->d))
50244541Sbrooks#define FS(a, b, c, d) \
51244541Sbrooks	(((a)->flags & (c)) && ((b)->flags & (c)) && strcmp((a)->d,(b)->d))
52244541Sbrooks#define FM(a, b, c, d) \
53244541Sbrooks	(((a)->flags & (c)) && ((b)->flags & (c)) && memcmp(&(a)->d,&(b)->d, sizeof (a)->d))
54244541Sbrooks
55244541Sbrooksstatic void
56244541Sbrooksshownode(NODE *n, int f, char const *path)
57244541Sbrooks{
58244541Sbrooks	struct group *gr;
59244541Sbrooks	struct passwd *pw;
60244541Sbrooks
61244541Sbrooks	printf("%s%s %s", path, n->name, inotype(nodetoino(n->type)));
62244541Sbrooks	if (f & F_CKSUM)
63244541Sbrooks		printf(" cksum=%lu", n->cksum);
64244541Sbrooks	if (f & F_GID)
65244541Sbrooks		printf(" gid=%d", n->st_gid);
66244541Sbrooks	if (f & F_GNAME) {
67244541Sbrooks		gr = getgrgid(n->st_gid);
68244541Sbrooks		if (gr == NULL)
69244541Sbrooks			printf(" gid=%d", n->st_gid);
70244541Sbrooks		else
71244541Sbrooks			printf(" gname=%s", gr->gr_name);
72244541Sbrooks	}
73244541Sbrooks	if (f & F_MODE)
74244541Sbrooks		printf(" mode=%o", n->st_mode);
75244541Sbrooks	if (f & F_NLINK)
76312072Skib		printf(" nlink=%ju", (uintmax_t)n->st_nlink);
77244541Sbrooks	if (f & F_SIZE)
78244541Sbrooks		printf(" size=%jd", (intmax_t)n->st_size);
79244541Sbrooks	if (f & F_UID)
80244541Sbrooks		printf(" uid=%d", n->st_uid);
81244541Sbrooks	if (f & F_UNAME) {
82244541Sbrooks		pw = getpwuid(n->st_uid);
83244541Sbrooks		if (pw == NULL)
84244541Sbrooks			printf(" uid=%d", n->st_uid);
85244541Sbrooks		else
86244541Sbrooks			printf(" uname=%s", pw->pw_name);
87244541Sbrooks	}
88244541Sbrooks	if (f & F_MD5)
89244541Sbrooks		printf(" %s=%s", MD5KEY, n->md5digest);
90244541Sbrooks	if (f & F_SHA1)
91244541Sbrooks		printf(" %s=%s", SHA1KEY, n->sha1digest);
92244541Sbrooks	if (f & F_RMD160)
93244541Sbrooks		printf(" %s=%s", RMD160KEY, n->rmd160digest);
94244541Sbrooks	if (f & F_SHA256)
95244541Sbrooks		printf(" %s=%s", SHA256KEY, n->sha256digest);
96244541Sbrooks	if (f & F_SHA384)
97244541Sbrooks		printf(" %s=%s", SHA384KEY, n->sha384digest);
98244541Sbrooks	if (f & F_SHA512)
99244541Sbrooks		printf(" %s=%s", SHA512KEY, n->sha512digest);
100244541Sbrooks	if (f & F_FLAGS)
101244541Sbrooks		printf(" flags=%s", flags_to_string(n->st_flags, "none"));
102244541Sbrooks	printf("\n");
103244541Sbrooks}
104244541Sbrooks
105244541Sbrooksstatic int
106244541Sbrooksmismatch(NODE *n1, NODE *n2, int differ, char const *path)
107244541Sbrooks{
108244541Sbrooks
109244541Sbrooks	if (n2 == NULL) {
110244541Sbrooks		shownode(n1, differ, path);
111244541Sbrooks		return (1);
112244541Sbrooks	}
113244541Sbrooks	if (n1 == NULL) {
114244541Sbrooks		printf("\t");
115244541Sbrooks		shownode(n2, differ, path);
116244541Sbrooks		return (1);
117244541Sbrooks	}
118244541Sbrooks	if (!(differ & keys))
119244541Sbrooks		return(0);
120244541Sbrooks	printf("\t\t");
121244541Sbrooks	shownode(n1, differ, path);
122244541Sbrooks	printf("\t\t");
123244541Sbrooks	shownode(n2, differ, path);
124244541Sbrooks	return (1);
125244541Sbrooks}
126244541Sbrooks
127244541Sbrooksstatic int
128244541Sbrookscompare_nodes(NODE *n1, NODE *n2, char const *path)
129244541Sbrooks{
130244541Sbrooks	int differs;
131244541Sbrooks
132244541Sbrooks	if (n1 != NULL && n1->type == F_LINK)
133244541Sbrooks		n1->flags &= ~F_MODE;
134244541Sbrooks	if (n2 != NULL && n2->type == F_LINK)
135244541Sbrooks		n2->flags &= ~F_MODE;
136244541Sbrooks	differs = 0;
137244541Sbrooks	if (n1 == NULL && n2 != NULL) {
138244541Sbrooks		differs = n2->flags;
139244541Sbrooks		mismatch(n1, n2, differs, path);
140244541Sbrooks		return (1);
141244541Sbrooks	}
142244541Sbrooks	if (n1 != NULL && n2 == NULL) {
143244541Sbrooks		differs = n1->flags;
144244541Sbrooks		mismatch(n1, n2, differs, path);
145244541Sbrooks		return (1);
146244541Sbrooks	}
147244541Sbrooks	if (n1->type != n2->type) {
148356533Sbdrewery		differs = F_TYPE;
149244541Sbrooks		mismatch(n1, n2, differs, path);
150244541Sbrooks		return (1);
151244541Sbrooks	}
152244541Sbrooks	if (FF(n1, n2, F_CKSUM, cksum))
153244541Sbrooks		differs |= F_CKSUM;
154244541Sbrooks	if (FF(n1, n2, F_GID, st_gid))
155244541Sbrooks		differs |= F_GID;
156244541Sbrooks	if (FF(n1, n2, F_GNAME, st_gid))
157244541Sbrooks		differs |= F_GNAME;
158244541Sbrooks	if (FF(n1, n2, F_MODE, st_mode))
159244541Sbrooks		differs |= F_MODE;
160244541Sbrooks	if (FF(n1, n2, F_NLINK, st_nlink))
161244541Sbrooks		differs |= F_NLINK;
162244541Sbrooks	if (FF(n1, n2, F_SIZE, st_size))
163244541Sbrooks		differs |= F_SIZE;
164244541Sbrooks	if (FS(n1, n2, F_SLINK, slink))
165244541Sbrooks		differs |= F_SLINK;
166244541Sbrooks	if (FM(n1, n2, F_TIME, st_mtimespec))
167244541Sbrooks		differs |= F_TIME;
168244541Sbrooks	if (FF(n1, n2, F_UID, st_uid))
169244541Sbrooks		differs |= F_UID;
170244541Sbrooks	if (FF(n1, n2, F_UNAME, st_uid))
171244541Sbrooks		differs |= F_UNAME;
172244541Sbrooks	if (FS(n1, n2, F_MD5, md5digest))
173244541Sbrooks		differs |= F_MD5;
174244541Sbrooks	if (FS(n1, n2, F_SHA1, sha1digest))
175244541Sbrooks		differs |= F_SHA1;
176244541Sbrooks	if (FS(n1, n2, F_RMD160, rmd160digest))
177244541Sbrooks		differs |= F_RMD160;
178244541Sbrooks	if (FS(n1, n2, F_SHA256, sha256digest))
179244541Sbrooks		differs |= F_SHA256;
180244541Sbrooks	if (FS(n1, n2, F_SHA384, sha384digest))
181244541Sbrooks		differs |= F_SHA384;
182244541Sbrooks	if (FS(n1, n2, F_SHA512, sha512digest))
183244541Sbrooks		differs |= F_SHA512;
184244541Sbrooks	if (FF(n1, n2, F_FLAGS, st_flags))
185244541Sbrooks		differs |= F_FLAGS;
186244541Sbrooks	if (differs) {
187244541Sbrooks		mismatch(n1, n2, differs, path);
188244541Sbrooks		return (1);
189244541Sbrooks	}
190244541Sbrooks	return (0);
191244541Sbrooks}
192244541Sbrooksstatic int
193244541Sbrookswalk_in_the_forest(NODE *t1, NODE *t2, char const *path)
194244541Sbrooks{
195244541Sbrooks	int r, i;
196244541Sbrooks	NODE *c1, *c2, *n1, *n2;
197244541Sbrooks	char *np;
198244541Sbrooks
199244541Sbrooks	r = 0;
200244541Sbrooks
201244541Sbrooks	if (t1 != NULL)
202244541Sbrooks		c1 = t1->child;
203244541Sbrooks	else
204244541Sbrooks		c1 = NULL;
205244541Sbrooks	if (t2 != NULL)
206244541Sbrooks		c2 = t2->child;
207244541Sbrooks	else
208244541Sbrooks		c2 = NULL;
209244541Sbrooks	while (c1 != NULL || c2 != NULL) {
210244541Sbrooks		n1 = n2 = NULL;
211244541Sbrooks		if (c1 != NULL)
212244541Sbrooks			n1 = c1->next;
213244541Sbrooks		if (c2 != NULL)
214244541Sbrooks			n2 = c2->next;
215244541Sbrooks		if (c1 != NULL && c2 != NULL) {
216244541Sbrooks			if (c1->type != F_DIR && c2->type == F_DIR) {
217244541Sbrooks				n2 = c2;
218244541Sbrooks				c2 = NULL;
219244541Sbrooks			} else if (c1->type == F_DIR && c2->type != F_DIR) {
220244541Sbrooks				n1 = c1;
221244541Sbrooks				c1 = NULL;
222244541Sbrooks			} else {
223244541Sbrooks				i = strcmp(c1->name, c2->name);
224244541Sbrooks				if (i > 0) {
225244541Sbrooks					n1 = c1;
226244541Sbrooks					c1 = NULL;
227244541Sbrooks				} else if (i < 0) {
228244541Sbrooks					n2 = c2;
229244541Sbrooks					c2 = NULL;
230244541Sbrooks				}
231244541Sbrooks			}
232244541Sbrooks		}
233244541Sbrooks		if (c1 == NULL && c2->type == F_DIR) {
234244541Sbrooks			asprintf(&np, "%s%s/", path, c2->name);
235244541Sbrooks			i = walk_in_the_forest(c1, c2, np);
236244541Sbrooks			free(np);
237244541Sbrooks			i += compare_nodes(c1, c2, path);
238244541Sbrooks		} else if (c2 == NULL && c1->type == F_DIR) {
239244541Sbrooks			asprintf(&np, "%s%s/", path, c1->name);
240244541Sbrooks			i = walk_in_the_forest(c1, c2, np);
241244541Sbrooks			free(np);
242244541Sbrooks			i += compare_nodes(c1, c2, path);
243244541Sbrooks		} else if (c1 == NULL || c2 == NULL) {
244244541Sbrooks			i = compare_nodes(c1, c2, path);
245244541Sbrooks		} else if (c1->type == F_DIR && c2->type == F_DIR) {
246244541Sbrooks			asprintf(&np, "%s%s/", path, c1->name);
247244541Sbrooks			i = walk_in_the_forest(c1, c2, np);
248244541Sbrooks			free(np);
249244541Sbrooks			i += compare_nodes(c1, c2, path);
250244541Sbrooks		} else {
251244541Sbrooks			i = compare_nodes(c1, c2, path);
252244541Sbrooks		}
253244541Sbrooks		r += i;
254244541Sbrooks		c1 = n1;
255244541Sbrooks		c2 = n2;
256244541Sbrooks	}
257244541Sbrooks	return (r);
258244541Sbrooks}
259244541Sbrooks
260244541Sbrooksint
261244541Sbrooksmtree_specspec(FILE *fi, FILE *fj)
262244541Sbrooks{
263244541Sbrooks	int rval;
264244541Sbrooks	NODE *root1, *root2;
265244541Sbrooks
266244541Sbrooks	root1 = spec(fi);
267244541Sbrooks	root2 = spec(fj);
268244541Sbrooks	rval = walk_in_the_forest(root1, root2, "");
269244541Sbrooks	rval += compare_nodes(root1, root2, "");
270244541Sbrooks	if (rval > 0)
271244541Sbrooks		return (MISMATCHEXIT);
272244541Sbrooks	return (0);
273244541Sbrooks}
274