Implement FreeBSD's -f spec1 -f spec2 spec comparision function. This

is more useful than -C and diff because it highlights the keys that have
changed value so for example, you can see that the size of a file has
not changed but the contents have. (brooks)
This commit is contained in:
christos 2012-10-05 01:26:56 +00:00
parent d07df9451a
commit 9e84d4e8c2
7 changed files with 327 additions and 18 deletions

View File

@ -1,4 +1,4 @@
# $NetBSD: Makefile,v 1.32 2009/04/22 15:23:05 lukem Exp $
# $NetBSD: Makefile,v 1.33 2012/10/05 01:26:56 christos Exp $
# from: @(#)Makefile 8.2 (Berkeley) 4/27/95
.include <bsd.own.mk>
@ -7,8 +7,8 @@ PROG= mtree
#CPPFLAGS+=-DDEBUG
CPPFLAGS+= -DMTREE
MAN= mtree.8
SRCS= compare.c crc.c create.c excludes.c misc.c mtree.c spec.c verify.c \
getid.c pack_dev.c
SRCS= compare.c crc.c create.c excludes.c misc.c mtree.c spec.c specspec.c \
verify.c getid.c pack_dev.c
.if (${HOSTPROG:U} == "")
DPADD+= ${LIBUTIL}
LDADD+= -lutil

View File

@ -1,4 +1,4 @@
/* $NetBSD: extern.h,v 1.35 2012/10/05 01:13:50 christos Exp $ */
/* $NetBSD: extern.h,v 1.36 2012/10/05 01:26:56 christos Exp $ */
/*-
* Copyright (c) 1991, 1993
@ -67,7 +67,7 @@ void parsetags(slist_t *, char *);
u_int parsetype(const char *);
void read_excludes_file(const char *);
const char *rlink(const char *);
int verify(void);
int verify(FILE *);
extern int dflag, eflag, iflag, jflag, lflag, mflag,
nflag, qflag, rflag, sflag, tflag, uflag;

View File

@ -1,4 +1,4 @@
.\" $NetBSD: mtree.8,v 1.59 2012/10/05 01:19:54 christos Exp $
.\" $NetBSD: mtree.8,v 1.60 2012/10/05 01:26:56 christos Exp $
.\"
.\" Copyright (c) 1989, 1990, 1993
.\" The Regents of the University of California. All rights reserved.
@ -144,6 +144,18 @@ specification.
Read the specification from
.Ar file ,
instead of from the standard input.
.Pp
If this option is specified twice, the two specifications are compared
to each other rather than to the file hierarchy.
The specifications will be sorted like output generated using
.Fl c .
The output format in this case is somewhat remniscent of
.Xr comm 1 ,
having "in first spec only", "in second spec only", and "different"
columns, prefixed by zero, one and two TAB characters respectively.
Each entry in the "different" column occupies two lines, one from each
specifica
tion.
.It Fl I Ar tags
Add the comma separated tags to the
.Dq inclusion

View File

@ -1,4 +1,4 @@
/* $NetBSD: mtree.c,v 1.40 2012/10/05 01:13:50 christos Exp $ */
/* $NetBSD: mtree.c,v 1.41 2012/10/05 01:26:56 christos Exp $ */
/*-
* Copyright (c) 1989, 1990, 1993
@ -43,7 +43,7 @@ __COPYRIGHT("@(#) Copyright (c) 1989, 1990, 1993\
#if 0
static char sccsid[] = "@(#)mtree.c 8.1 (Berkeley) 6/6/93";
#else
__RCSID("$NetBSD: mtree.c,v 1.40 2012/10/05 01:13:50 christos Exp $");
__RCSID("$NetBSD: mtree.c,v 1.41 2012/10/05 01:26:56 christos Exp $");
#endif
#endif /* not lint */
@ -70,11 +70,14 @@ main(int argc, char **argv)
{
int ch, status;
char *dir, *p;
FILE *spec1, *spec2;
setprogname(argv[0]);
dir = NULL;
init_excludes();
spec1 = stdin;
spec2 = NULL;
while ((ch = getopt(argc, argv,
"cCdDeE:f:I:ik:K:lLmMnN:p:PqrR:s:StuUWxX:"))
@ -99,8 +102,18 @@ main(int argc, char **argv)
eflag = 1;
break;
case 'f':
if (!(freopen(optarg, "r", stdin)))
mtree_err("%s: %s", optarg, strerror(errno));
if (spec1 == stdin) {
spec1 = fopen(optarg, "r");
if (spec1 == NULL)
mtree_err("%s: %s", optarg,
strerror(errno));
} else if (spec2 == NULL) {
spec2 = fopen(optarg, "r");
if (spec2 == NULL)
mtree_err("%s: %s", optarg,
strerror(errno));
} else
usage();
break;
case 'i':
iflag = 1;
@ -200,6 +213,13 @@ main(int argc, char **argv)
if (argc)
usage();
if (spec2 && (cflag || Cflag || Dflag))
mtree_err("Double -f, -c, -C and -D flags are mutually "
"exclusive");
if (dir && spec2)
mtree_err("Double -f and -p flags are mutually exclusive");
if (dir && chdir(dir))
mtree_err("%s: %s", dir, strerror(errno));
@ -220,10 +240,13 @@ main(int argc, char **argv)
exit(0);
}
if (Cflag || Dflag) {
dump_nodes("", spec(stdin), Dflag);
dump_nodes("", spec(spec1), Dflag);
exit(0);
}
status = verify();
if (spec2 != NULL)
status = mtree_specspec(spec1, spec2);
else
status = verify(spec1);
if (Uflag && (status == MISMATCHEXIT))
status = 0;
exit(status);
@ -234,7 +257,8 @@ usage(void)
{
fprintf(stderr,
"usage: %s [-CcDdeLlMnPrSUuWx] [-i|-m] [-E tags] [-f spec]\n"
"usage: %s [-CcDdeLlMnPrSUuWx] [-i|-m] [-E tags]\n"
"\t\t[-f spec] [-f spec]\n"
"\t\t[-I tags] [-K keywords] [-k keywords] [-N dbdir] [-p path]\n"
"\t\t[-R keywords] [-s seed] [-X exclude-file]\n",
getprogname());

View File

@ -1,4 +1,4 @@
/* $NetBSD: mtree.h,v 1.28 2012/10/05 00:59:35 christos Exp $ */
/* $NetBSD: mtree.h,v 1.29 2012/10/05 01:26:56 christos Exp $ */
/*-
* Copyright (c) 1990, 1993
@ -120,6 +120,7 @@ const char *inotype(u_int);
u_int nodetoino(u_int);
int setup_getid(const char *);
NODE *spec(FILE *);
int mtree_specspec(FILE *, FILE *);
void free_nodes(NODE *);
char *vispath(const char *);

272
usr.sbin/mtree/specspec.c Normal file
View File

@ -0,0 +1,272 @@
/* $NetBSD: specspec.c,v 1.1 2012/10/05 01:26:56 christos Exp $ */
/*-
* Copyright (c) 2003 Poul-Henning Kamp
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if HAVE_NBTOOL_CONFIG_H
#include "nbtool_config.h"
#endif
#include <sys/cdefs.h>
__RCSID("$NetBSD: specspec.c,v 1.1 2012/10/05 01:26:56 christos Exp $");
#include <err.h>
#include <grp.h>
#include <pwd.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "mtree.h"
#include "extern.h"
#define FF(a, b, c, d) \
(((a)->flags & (c)) && ((b)->flags & (c)) && ((a)->d) != ((b)->d))
#define FS(a, b, c, d) \
(((a)->flags & (c)) && ((b)->flags & (c)) && strcmp((a)->d,(b)->d))
#define FM(a, b, c, d) \
(((a)->flags & (c)) && ((b)->flags & (c)) && memcmp(&(a)->d,&(b)->d, sizeof (a)->d))
static void
shownode(NODE *n, int f, char const *path)
{
struct group *gr;
struct passwd *pw;
printf("%s%s %s", path, n->name, inotype(nodetoino(n->type)));
if (f & F_CKSUM)
printf(" cksum=%lu", n->cksum);
if (f & F_GID)
printf(" gid=%d", n->st_gid);
if (f & F_GNAME) {
gr = getgrgid(n->st_gid);
if (gr == NULL)
printf(" gid=%d", n->st_gid);
else
printf(" gname=%s", gr->gr_name);
}
if (f & F_MODE)
printf(" mode=%o", n->st_mode);
if (f & F_NLINK)
printf(" nlink=%d", n->st_nlink);
if (f & F_SIZE)
printf(" size=%jd", (intmax_t)n->st_size);
if (f & F_UID)
printf(" uid=%d", n->st_uid);
if (f & F_UNAME) {
pw = getpwuid(n->st_uid);
if (pw == NULL)
printf(" uid=%d", n->st_uid);
else
printf(" uname=%s", pw->pw_name);
}
if (f & F_MD5)
printf(" %s=%s", MD5KEY, n->md5digest);
if (f & F_SHA1)
printf(" %s=%s", SHA1KEY, n->sha1digest);
if (f & F_RMD160)
printf(" %s=%s", RMD160KEY, n->rmd160digest);
if (f & F_SHA256)
printf(" %s=%s", SHA256KEY, n->sha256digest);
if (f & F_SHA384)
printf(" %s=%s", SHA384KEY, n->sha384digest);
if (f & F_SHA512)
printf(" %s=%s", SHA512KEY, n->sha512digest);
if (f & F_FLAGS)
printf(" flags=%s", flags_to_string(n->st_flags, "none"));
printf("\n");
}
static int
mismatch(NODE *n1, NODE *n2, int differ, char const *path)
{
if (n2 == NULL) {
shownode(n1, differ, path);
return (1);
}
if (n1 == NULL) {
printf("\t");
shownode(n2, differ, path);
return (1);
}
if (!(differ & keys))
return(0);
printf("\t\t");
shownode(n1, differ, path);
printf("\t\t");
shownode(n2, differ, path);
return (1);
}
static int
compare_nodes(NODE *n1, NODE *n2, char const *path)
{
int differs;
if (n1 != NULL && n1->type == F_LINK)
n1->flags &= ~F_MODE;
if (n2 != NULL && n2->type == F_LINK)
n2->flags &= ~F_MODE;
differs = 0;
if (n1 == NULL && n2 != NULL) {
differs = n2->flags;
mismatch(n1, n2, differs, path);
return (1);
}
if (n1 != NULL && n2 == NULL) {
differs = n1->flags;
mismatch(n1, n2, differs, path);
return (1);
}
if (n1->type != n2->type) {
differs = 0;
mismatch(n1, n2, differs, path);
return (1);
}
if (FF(n1, n2, F_CKSUM, cksum))
differs |= F_CKSUM;
if (FF(n1, n2, F_GID, st_gid))
differs |= F_GID;
if (FF(n1, n2, F_GNAME, st_gid))
differs |= F_GNAME;
if (FF(n1, n2, F_MODE, st_mode))
differs |= F_MODE;
if (FF(n1, n2, F_NLINK, st_nlink))
differs |= F_NLINK;
if (FF(n1, n2, F_SIZE, st_size))
differs |= F_SIZE;
if (FS(n1, n2, F_SLINK, slink))
differs |= F_SLINK;
if (FM(n1, n2, F_TIME, st_mtimespec))
differs |= F_TIME;
if (FF(n1, n2, F_UID, st_uid))
differs |= F_UID;
if (FF(n1, n2, F_UNAME, st_uid))
differs |= F_UNAME;
if (FS(n1, n2, F_MD5, md5digest))
differs |= F_MD5;
if (FS(n1, n2, F_SHA1, sha1digest))
differs |= F_SHA1;
if (FS(n1, n2, F_RMD160, rmd160digest))
differs |= F_RMD160;
if (FS(n1, n2, F_SHA256, sha256digest))
differs |= F_SHA256;
if (FS(n1, n2, F_SHA384, sha384digest))
differs |= F_SHA384;
if (FS(n1, n2, F_SHA512, sha512digest))
differs |= F_SHA512;
if (FF(n1, n2, F_FLAGS, st_flags))
differs |= F_FLAGS;
if (differs) {
mismatch(n1, n2, differs, path);
return (1);
}
return (0);
}
static int
walk_in_the_forest(NODE *t1, NODE *t2, char const *path)
{
int r, i;
NODE *c1, *c2, *n1, *n2;
char *np;
r = 0;
if (t1 != NULL)
c1 = t1->child;
else
c1 = NULL;
if (t2 != NULL)
c2 = t2->child;
else
c2 = NULL;
while (c1 != NULL || c2 != NULL) {
n1 = n2 = NULL;
if (c1 != NULL)
n1 = c1->next;
if (c2 != NULL)
n2 = c2->next;
if (c1 != NULL && c2 != NULL) {
if (c1->type != F_DIR && c2->type == F_DIR) {
n2 = c2;
c2 = NULL;
} else if (c1->type == F_DIR && c2->type != F_DIR) {
n1 = c1;
c1 = NULL;
} else {
i = strcmp(c1->name, c2->name);
if (i > 0) {
n1 = c1;
c1 = NULL;
} else if (i < 0) {
n2 = c2;
c2 = NULL;
}
}
}
if (c1 == NULL && c2->type == F_DIR) {
asprintf(&np, "%s%s/", path, c2->name);
i = walk_in_the_forest(c1, c2, np);
free(np);
i += compare_nodes(c1, c2, path);
} else if (c2 == NULL && c1->type == F_DIR) {
asprintf(&np, "%s%s/", path, c1->name);
i = walk_in_the_forest(c1, c2, np);
free(np);
i += compare_nodes(c1, c2, path);
} else if (c1 == NULL || c2 == NULL) {
i = compare_nodes(c1, c2, path);
} else if (c1->type == F_DIR && c2->type == F_DIR) {
asprintf(&np, "%s%s/", path, c1->name);
i = walk_in_the_forest(c1, c2, np);
free(np);
i += compare_nodes(c1, c2, path);
} else {
i = compare_nodes(c1, c2, path);
}
r += i;
c1 = n1;
c2 = n2;
}
return (r);
}
int
mtree_specspec(FILE *fi, FILE *fj)
{
int rval;
NODE *root1, *root2;
root1 = spec(fi);
root2 = spec(fj);
rval = walk_in_the_forest(root1, root2, "");
rval += compare_nodes(root1, root2, "");
if (rval > 0)
return (MISMATCHEXIT);
return (0);
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: verify.c,v 1.41 2012/10/05 01:05:14 christos Exp $ */
/* $NetBSD: verify.c,v 1.42 2012/10/05 01:26:56 christos Exp $ */
/*-
* Copyright (c) 1990, 1993
@ -38,7 +38,7 @@
#if 0
static char sccsid[] = "@(#)verify.c 8.1 (Berkeley) 6/6/93";
#else
__RCSID("$NetBSD: verify.c,v 1.41 2012/10/05 01:05:14 christos Exp $");
__RCSID("$NetBSD: verify.c,v 1.42 2012/10/05 01:26:56 christos Exp $");
#endif
#endif /* not lint */
@ -64,11 +64,11 @@ static void miss(NODE *, char *);
static int vwalk(void);
int
verify(void)
verify(FILE *fi)
{
int rval;
root = spec(stdin);
root = spec(fi);
rval = vwalk();
miss(root, path);
return (rval);