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