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