Hi, FreeBSD's mtree(1) has the option to specify the '-f' option twice, resulting in a comparison of the two specified source files (currently, our mtree only does file-fs or fs-file). I'm currently working on something where you really need this, otherwise you had to scan the whole fs tree twice. FreeBSD's mtree: http://www.freebsd.org/cgi/man.cgi?query=mtree Changes: http://svnweb.freebsd.org/base?view=revision&revision=122141 So, I ported this for NetBSD's mtree, but didn't test it as thoroughly as I could (would do that before committing). Comments? Regards, Julian
? .mtree.c.swp ? specspec.c Index: Makefile =================================================================== RCS file: /cvsroot/src/usr.sbin/mtree/Makefile,v retrieving revision 1.32 diff -u -r1.32 Makefile --- Makefile 22 Apr 2009 15:23:05 -0000 1.32 +++ Makefile 20 Jul 2012 17:45:57 -0000 @@ -8,7 +8,7 @@ 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 + getid.c pack_dev.c specspec.c .if (${HOSTPROG:U} == "") DPADD+= ${LIBUTIL} LDADD+= -lutil Index: extern.h =================================================================== RCS file: /cvsroot/src/usr.sbin/mtree/extern.h,v retrieving revision 1.32 diff -u -r1.32 extern.h --- extern.h 29 Aug 2011 20:37:43 -0000 1.32 +++ extern.h 20 Jul 2012 17:45:57 -0000 @@ -68,6 +68,7 @@ void read_excludes_file(const char *); const char *rlink(const char *); int verify(void); +int specspec(FILE *fi, FILE *fj); extern int dflag, eflag, iflag, lflag, mflag, rflag, sflag, tflag, uflag; extern int mtree_Mflag, mtree_Sflag, mtree_Wflag; Index: mtree.c =================================================================== RCS file: /cvsroot/src/usr.sbin/mtree/mtree.c,v retrieving revision 1.37 diff -u -r1.37 mtree.c --- mtree.c 29 Aug 2011 20:37:43 -0000 1.37 +++ mtree.c 20 Jul 2012 17:45:57 -0000 @@ -60,7 +60,7 @@ int ftsoptions = FTS_PHYSICAL; int cflag, Cflag, dflag, Dflag, eflag, iflag, lflag, mflag, - rflag, sflag, tflag, uflag, Uflag; + rflag, sflag, tflag, uflag, Uflag, f2flag; char fullpath[MAXPATHLEN]; __dead static void usage(void); @@ -68,6 +68,7 @@ int main(int argc, char **argv) { + FILE *spec1, *spec2; int ch, status; char *dir, *p; @@ -75,6 +76,8 @@ dir = NULL; init_excludes(); + spec1 = stdin; + spec2 = NULL; while ((ch = getopt(argc, argv, "cCdDeE:f:I:ik:K:lLmMN:p:PrR:s:StuUWxX:")) @@ -99,8 +102,18 @@ 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) + err(1, "%s", optarg); + } else if (spec2 == NULL) { + f2flag = 1; + spec2 = fopen(optarg, "r"); + if (spec2 == NULL) + err(1, "%s", optarg); + } else { + usage(); + } break; case 'i': iflag = 1; @@ -191,6 +204,12 @@ if (argc) usage(); + if ((Dflag && f2flag) || (cflag && f2flag) || (Cflag && f2flag)) + mtree_err("Double -f, -c, -C and -D flags are mutually exclusive"); + + if (dir && f2flag) + mtree_err("Double -f and -p flags are mutually exclusive"); + if (dir && chdir(dir)) mtree_err("%s: %s", dir, strerror(errno)); @@ -214,7 +233,10 @@ dump_nodes("", spec(stdin), Dflag); exit(0); } - status = verify(); + if (spec2 != NULL) + status = specspec(spec1, spec2); + else + status = verify(); if (Uflag && (status == MISMATCHEXIT)) status = 0; exit(status);
/*- * 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. */ #include <sys/cdefs.h> #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 <util.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(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(" md5digest=%s", n->md5digest); if (f & F_SHA1) printf(" sha1digest=%s", n->sha1digest); if (f & F_RMD160) printf(" rmd160digest=%s", n->rmd160digest); if (f & F_SHA256) printf(" sha256digest=%s", n->sha256digest); 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 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); }
Attachment:
signature.asc
Description: PGP signature