xref: /dflybsd-src/usr.sbin/mtree/specspec.c (revision 27a796753626c4fca2de1d161fddbac6d6930ecc)
1*a43287ccSSascha Wildner /*	$NetBSD: specspec.c,v 1.4 2017/12/14 18:34:41 christos Exp $	*/
2*a43287ccSSascha Wildner 
3*a43287ccSSascha Wildner /*-
4*a43287ccSSascha Wildner  * Copyright (c) 2003 Poul-Henning Kamp
5*a43287ccSSascha Wildner  * All rights reserved.
6*a43287ccSSascha Wildner  *
7*a43287ccSSascha Wildner  * Redistribution and use in source and binary forms, with or without
8*a43287ccSSascha Wildner  * modification, are permitted provided that the following conditions
9*a43287ccSSascha Wildner  * are met:
10*a43287ccSSascha Wildner  * 1. Redistributions of source code must retain the above copyright
11*a43287ccSSascha Wildner  *    notice, this list of conditions and the following disclaimer.
12*a43287ccSSascha Wildner  * 2. Redistributions in binary form must reproduce the above copyright
13*a43287ccSSascha Wildner  *    notice, this list of conditions and the following disclaimer in the
14*a43287ccSSascha Wildner  *    documentation and/or other materials provided with the distribution.
15*a43287ccSSascha Wildner  *
16*a43287ccSSascha Wildner  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17*a43287ccSSascha Wildner  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18*a43287ccSSascha Wildner  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19*a43287ccSSascha Wildner  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20*a43287ccSSascha Wildner  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21*a43287ccSSascha Wildner  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22*a43287ccSSascha Wildner  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23*a43287ccSSascha Wildner  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24*a43287ccSSascha Wildner  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25*a43287ccSSascha Wildner  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26*a43287ccSSascha Wildner  * SUCH DAMAGE.
27*a43287ccSSascha Wildner  */
28*a43287ccSSascha Wildner 
29*a43287ccSSascha Wildner #include <err.h>
30*a43287ccSSascha Wildner #include <grp.h>
31*a43287ccSSascha Wildner #include <pwd.h>
32*a43287ccSSascha Wildner #include <time.h>
33*a43287ccSSascha Wildner #include <stdio.h>
34*a43287ccSSascha Wildner #include <stdint.h>
35*a43287ccSSascha Wildner #include <stdlib.h>
36*a43287ccSSascha Wildner #include <string.h>
37*a43287ccSSascha Wildner #include <unistd.h>
38*a43287ccSSascha Wildner #include "mtree.h"
39*a43287ccSSascha Wildner #include "extern.h"
40*a43287ccSSascha Wildner 
41*a43287ccSSascha Wildner #define FF(a, b, c, d) \
42*a43287ccSSascha Wildner 	(((a)->flags & (c)) && ((b)->flags & (c)) && ((a)->d) != ((b)->d))
43*a43287ccSSascha Wildner #define FS(a, b, c, d) \
44*a43287ccSSascha Wildner 	(((a)->flags & (c)) && ((b)->flags & (c)) && strcmp((a)->d,(b)->d))
45*a43287ccSSascha Wildner #define FM(a, b, c, d) \
46*a43287ccSSascha Wildner 	(((a)->flags & (c)) && ((b)->flags & (c)) && memcmp(&(a)->d,&(b)->d, sizeof (a)->d))
47*a43287ccSSascha Wildner 
48*a43287ccSSascha Wildner static void
shownode(NODE * n,int f,char const * path)49*a43287ccSSascha Wildner shownode(NODE *n, int f, char const *path)
50*a43287ccSSascha Wildner {
51*a43287ccSSascha Wildner 	struct group *gr;
52*a43287ccSSascha Wildner 	struct passwd *pw;
53*a43287ccSSascha Wildner 
54*a43287ccSSascha Wildner 	printf("%s%s %s", path, n->name, inotype(nodetoino(n->type)));
55*a43287ccSSascha Wildner 	if (f & F_CKSUM)
56*a43287ccSSascha Wildner 		printf(" cksum=%lu", n->cksum);
57*a43287ccSSascha Wildner 	if (f & F_GID)
58*a43287ccSSascha Wildner 		printf(" gid=%d", n->st_gid);
59*a43287ccSSascha Wildner 	if (f & F_GNAME) {
60*a43287ccSSascha Wildner 		gr = getgrgid(n->st_gid);
61*a43287ccSSascha Wildner 		if (gr == NULL)
62*a43287ccSSascha Wildner 			printf(" gid=%d", n->st_gid);
63*a43287ccSSascha Wildner 		else
64*a43287ccSSascha Wildner 			printf(" gname=%s", gr->gr_name);
65*a43287ccSSascha Wildner 	}
66*a43287ccSSascha Wildner 	if (f & F_MODE)
67*a43287ccSSascha Wildner 		printf(" mode=%o", n->st_mode);
68*a43287ccSSascha Wildner 	if (f & F_NLINK)
69*a43287ccSSascha Wildner 		printf(" nlink=%ju", (uintmax_t)n->st_nlink);
70*a43287ccSSascha Wildner 	if (f & F_SIZE)
71*a43287ccSSascha Wildner 		printf(" size=%jd", (intmax_t)n->st_size);
72*a43287ccSSascha Wildner 	if (f & F_UID)
73*a43287ccSSascha Wildner 		printf(" uid=%d", n->st_uid);
74*a43287ccSSascha Wildner 	if (f & F_UNAME) {
75*a43287ccSSascha Wildner 		pw = getpwuid(n->st_uid);
76*a43287ccSSascha Wildner 		if (pw == NULL)
77*a43287ccSSascha Wildner 			printf(" uid=%d", n->st_uid);
78*a43287ccSSascha Wildner 		else
79*a43287ccSSascha Wildner 			printf(" uname=%s", pw->pw_name);
80*a43287ccSSascha Wildner 	}
81*a43287ccSSascha Wildner 	if (f & F_MD5)
82*a43287ccSSascha Wildner 		printf(" %s=%s", MD5KEY, n->md5digest);
83*a43287ccSSascha Wildner 	if (f & F_SHA1)
84*a43287ccSSascha Wildner 		printf(" %s=%s", SHA1KEY, n->sha1digest);
85*a43287ccSSascha Wildner 	if (f & F_RMD160)
86*a43287ccSSascha Wildner 		printf(" %s=%s", RMD160KEY, n->rmd160digest);
87*a43287ccSSascha Wildner 	if (f & F_SHA256)
88*a43287ccSSascha Wildner 		printf(" %s=%s", SHA256KEY, n->sha256digest);
89*a43287ccSSascha Wildner 	if (f & F_SHA384)
90*a43287ccSSascha Wildner 		printf(" %s=%s", SHA384KEY, n->sha384digest);
91*a43287ccSSascha Wildner 	if (f & F_SHA512)
92*a43287ccSSascha Wildner 		printf(" %s=%s", SHA512KEY, n->sha512digest);
93*a43287ccSSascha Wildner 	if (f & F_FLAGS)
94*a43287ccSSascha Wildner 		printf(" flags=%s", flags_to_string(n->st_flags, "none"));
95*a43287ccSSascha Wildner 	printf("\n");
96*a43287ccSSascha Wildner }
97*a43287ccSSascha Wildner 
98*a43287ccSSascha Wildner static int
mismatch(NODE * n1,NODE * n2,int differ,char const * path)99*a43287ccSSascha Wildner mismatch(NODE *n1, NODE *n2, int differ, char const *path)
100*a43287ccSSascha Wildner {
101*a43287ccSSascha Wildner 
102*a43287ccSSascha Wildner 	if (n2 == NULL) {
103*a43287ccSSascha Wildner 		shownode(n1, differ, path);
104*a43287ccSSascha Wildner 		return (1);
105*a43287ccSSascha Wildner 	}
106*a43287ccSSascha Wildner 	if (n1 == NULL) {
107*a43287ccSSascha Wildner 		printf("\t");
108*a43287ccSSascha Wildner 		shownode(n2, differ, path);
109*a43287ccSSascha Wildner 		return (1);
110*a43287ccSSascha Wildner 	}
111*a43287ccSSascha Wildner 	if (!(differ & keys))
112*a43287ccSSascha Wildner 		return(0);
113*a43287ccSSascha Wildner 	printf("\t\t");
114*a43287ccSSascha Wildner 	shownode(n1, differ, path);
115*a43287ccSSascha Wildner 	printf("\t\t");
116*a43287ccSSascha Wildner 	shownode(n2, differ, path);
117*a43287ccSSascha Wildner 	return (1);
118*a43287ccSSascha Wildner }
119*a43287ccSSascha Wildner 
120*a43287ccSSascha Wildner static int
compare_nodes(NODE * n1,NODE * n2,char const * path)121*a43287ccSSascha Wildner compare_nodes(NODE *n1, NODE *n2, char const *path)
122*a43287ccSSascha Wildner {
123*a43287ccSSascha Wildner 	int differs;
124*a43287ccSSascha Wildner 
125*a43287ccSSascha Wildner 	if (n1 != NULL && n1->type == F_LINK)
126*a43287ccSSascha Wildner 		n1->flags &= ~F_MODE;
127*a43287ccSSascha Wildner 	if (n2 != NULL && n2->type == F_LINK)
128*a43287ccSSascha Wildner 		n2->flags &= ~F_MODE;
129*a43287ccSSascha Wildner 	differs = 0;
130*a43287ccSSascha Wildner 	if (n1 == NULL && n2 != NULL) {
131*a43287ccSSascha Wildner 		differs = n2->flags;
132*a43287ccSSascha Wildner 		mismatch(n1, n2, differs, path);
133*a43287ccSSascha Wildner 		return (1);
134*a43287ccSSascha Wildner 	}
135*a43287ccSSascha Wildner 	if (n1 != NULL && n2 == NULL) {
136*a43287ccSSascha Wildner 		differs = n1->flags;
137*a43287ccSSascha Wildner 		mismatch(n1, n2, differs, path);
138*a43287ccSSascha Wildner 		return (1);
139*a43287ccSSascha Wildner 	}
140*a43287ccSSascha Wildner 	if (n1->type != n2->type) {
141*a43287ccSSascha Wildner 		differs = 0;
142*a43287ccSSascha Wildner 		mismatch(n1, n2, differs, path);
143*a43287ccSSascha Wildner 		return (1);
144*a43287ccSSascha Wildner 	}
145*a43287ccSSascha Wildner 	if (FF(n1, n2, F_CKSUM, cksum))
146*a43287ccSSascha Wildner 		differs |= F_CKSUM;
147*a43287ccSSascha Wildner 	if (FF(n1, n2, F_GID, st_gid))
148*a43287ccSSascha Wildner 		differs |= F_GID;
149*a43287ccSSascha Wildner 	if (FF(n1, n2, F_GNAME, st_gid))
150*a43287ccSSascha Wildner 		differs |= F_GNAME;
151*a43287ccSSascha Wildner 	if (FF(n1, n2, F_MODE, st_mode))
152*a43287ccSSascha Wildner 		differs |= F_MODE;
153*a43287ccSSascha Wildner 	if (FF(n1, n2, F_NLINK, st_nlink))
154*a43287ccSSascha Wildner 		differs |= F_NLINK;
155*a43287ccSSascha Wildner 	if (FF(n1, n2, F_SIZE, st_size))
156*a43287ccSSascha Wildner 		differs |= F_SIZE;
157*a43287ccSSascha Wildner 	if (FS(n1, n2, F_SLINK, slink))
158*a43287ccSSascha Wildner 		differs |= F_SLINK;
159*a43287ccSSascha Wildner 	if (FM(n1, n2, F_TIME, st_mtimespec))
160*a43287ccSSascha Wildner 		differs |= F_TIME;
161*a43287ccSSascha Wildner 	if (FF(n1, n2, F_UID, st_uid))
162*a43287ccSSascha Wildner 		differs |= F_UID;
163*a43287ccSSascha Wildner 	if (FF(n1, n2, F_UNAME, st_uid))
164*a43287ccSSascha Wildner 		differs |= F_UNAME;
165*a43287ccSSascha Wildner 	if (FS(n1, n2, F_MD5, md5digest))
166*a43287ccSSascha Wildner 		differs |= F_MD5;
167*a43287ccSSascha Wildner 	if (FS(n1, n2, F_SHA1, sha1digest))
168*a43287ccSSascha Wildner 		differs |= F_SHA1;
169*a43287ccSSascha Wildner 	if (FS(n1, n2, F_RMD160, rmd160digest))
170*a43287ccSSascha Wildner 		differs |= F_RMD160;
171*a43287ccSSascha Wildner 	if (FS(n1, n2, F_SHA256, sha256digest))
172*a43287ccSSascha Wildner 		differs |= F_SHA256;
173*a43287ccSSascha Wildner 	if (FS(n1, n2, F_SHA384, sha384digest))
174*a43287ccSSascha Wildner 		differs |= F_SHA384;
175*a43287ccSSascha Wildner 	if (FS(n1, n2, F_SHA512, sha512digest))
176*a43287ccSSascha Wildner 		differs |= F_SHA512;
177*a43287ccSSascha Wildner 	if (FF(n1, n2, F_FLAGS, st_flags))
178*a43287ccSSascha Wildner 		differs |= F_FLAGS;
179*a43287ccSSascha Wildner 	if (differs) {
180*a43287ccSSascha Wildner 		mismatch(n1, n2, differs, path);
181*a43287ccSSascha Wildner 		return (1);
182*a43287ccSSascha Wildner 	}
183*a43287ccSSascha Wildner 	return (0);
184*a43287ccSSascha Wildner }
185*a43287ccSSascha Wildner static int
walk_in_the_forest(NODE * t1,NODE * t2,char const * path)186*a43287ccSSascha Wildner walk_in_the_forest(NODE *t1, NODE *t2, char const *path)
187*a43287ccSSascha Wildner {
188*a43287ccSSascha Wildner 	int r, i;
189*a43287ccSSascha Wildner 	NODE *c1, *c2, *n1, *n2;
190*a43287ccSSascha Wildner 	char *np;
191*a43287ccSSascha Wildner 
192*a43287ccSSascha Wildner 	r = 0;
193*a43287ccSSascha Wildner 
194*a43287ccSSascha Wildner 	if (t1 != NULL)
195*a43287ccSSascha Wildner 		c1 = t1->child;
196*a43287ccSSascha Wildner 	else
197*a43287ccSSascha Wildner 		c1 = NULL;
198*a43287ccSSascha Wildner 	if (t2 != NULL)
199*a43287ccSSascha Wildner 		c2 = t2->child;
200*a43287ccSSascha Wildner 	else
201*a43287ccSSascha Wildner 		c2 = NULL;
202*a43287ccSSascha Wildner 	while (c1 != NULL || c2 != NULL) {
203*a43287ccSSascha Wildner 		n1 = n2 = NULL;
204*a43287ccSSascha Wildner 		if (c1 != NULL)
205*a43287ccSSascha Wildner 			n1 = c1->next;
206*a43287ccSSascha Wildner 		if (c2 != NULL)
207*a43287ccSSascha Wildner 			n2 = c2->next;
208*a43287ccSSascha Wildner 		if (c1 != NULL && c2 != NULL) {
209*a43287ccSSascha Wildner 			if (c1->type != F_DIR && c2->type == F_DIR) {
210*a43287ccSSascha Wildner 				n2 = c2;
211*a43287ccSSascha Wildner 				c2 = NULL;
212*a43287ccSSascha Wildner 			} else if (c1->type == F_DIR && c2->type != F_DIR) {
213*a43287ccSSascha Wildner 				n1 = c1;
214*a43287ccSSascha Wildner 				c1 = NULL;
215*a43287ccSSascha Wildner 			} else {
216*a43287ccSSascha Wildner 				i = strcmp(c1->name, c2->name);
217*a43287ccSSascha Wildner 				if (i > 0) {
218*a43287ccSSascha Wildner 					n1 = c1;
219*a43287ccSSascha Wildner 					c1 = NULL;
220*a43287ccSSascha Wildner 				} else if (i < 0) {
221*a43287ccSSascha Wildner 					n2 = c2;
222*a43287ccSSascha Wildner 					c2 = NULL;
223*a43287ccSSascha Wildner 				}
224*a43287ccSSascha Wildner 			}
225*a43287ccSSascha Wildner 		}
226*a43287ccSSascha Wildner 		if (c1 == NULL && c2->type == F_DIR) {
227*a43287ccSSascha Wildner 			asprintf(&np, "%s%s/", path, c2->name);
228*a43287ccSSascha Wildner 			i = walk_in_the_forest(c1, c2, np);
229*a43287ccSSascha Wildner 			free(np);
230*a43287ccSSascha Wildner 			i += compare_nodes(c1, c2, path);
231*a43287ccSSascha Wildner 		} else if (c2 == NULL && c1->type == F_DIR) {
232*a43287ccSSascha Wildner 			asprintf(&np, "%s%s/", path, c1->name);
233*a43287ccSSascha Wildner 			i = walk_in_the_forest(c1, c2, np);
234*a43287ccSSascha Wildner 			free(np);
235*a43287ccSSascha Wildner 			i += compare_nodes(c1, c2, path);
236*a43287ccSSascha Wildner 		} else if (c1 == NULL || c2 == NULL) {
237*a43287ccSSascha Wildner 			i = compare_nodes(c1, c2, path);
238*a43287ccSSascha Wildner 		} else if (c1->type == F_DIR && c2->type == F_DIR) {
239*a43287ccSSascha Wildner 			asprintf(&np, "%s%s/", path, c1->name);
240*a43287ccSSascha Wildner 			i = walk_in_the_forest(c1, c2, np);
241*a43287ccSSascha Wildner 			free(np);
242*a43287ccSSascha Wildner 			i += compare_nodes(c1, c2, path);
243*a43287ccSSascha Wildner 		} else {
244*a43287ccSSascha Wildner 			i = compare_nodes(c1, c2, path);
245*a43287ccSSascha Wildner 		}
246*a43287ccSSascha Wildner 		r += i;
247*a43287ccSSascha Wildner 		c1 = n1;
248*a43287ccSSascha Wildner 		c2 = n2;
249*a43287ccSSascha Wildner 	}
250*a43287ccSSascha Wildner 	return (r);
251*a43287ccSSascha Wildner }
252*a43287ccSSascha Wildner 
253*a43287ccSSascha Wildner int
mtree_specspec(FILE * fi,FILE * fj)254*a43287ccSSascha Wildner mtree_specspec(FILE *fi, FILE *fj)
255*a43287ccSSascha Wildner {
256*a43287ccSSascha Wildner 	int rval;
257*a43287ccSSascha Wildner 	NODE *root1, *root2;
258*a43287ccSSascha Wildner 
259*a43287ccSSascha Wildner 	root1 = spec(fi);
260*a43287ccSSascha Wildner 	root2 = spec(fj);
261*a43287ccSSascha Wildner 	rval = walk_in_the_forest(root1, root2, "");
262*a43287ccSSascha Wildner 	rval += compare_nodes(root1, root2, "");
263*a43287ccSSascha Wildner 	if (rval > 0)
264*a43287ccSSascha Wildner 		return (MISMATCHEXIT);
265*a43287ccSSascha Wildner 	return (0);
266*a43287ccSSascha Wildner }
267