Hello,

here is a patch that adds the -X option to /usr/sbin/mtree. This
option is described in the man page as follows:

"The specified file contains fnmatch(3) patterns matching
files to be excluded from the specification, one to a line."

The code is taken from NetBSD's mtree. Also at least FreeBSD
and Mac OS X have the same option available.

I have been using the patch in 4.7 and it seems to work
fine for me. I hope one of you can check that it is OK
and commit into OpenBSD CVS. I did not touch licenses etc.

If you have further questions or want to say how it should
have been done, cc me, as I don't subscribe to tech.

Thanks,
Teemu

Here it is, 260 lines between the tags:

<patch>
--- /dev/null   Sun Sep 12 01:52:21 2010
+++ excludes.c  Wed Jun 30 01:12:51 2010
@@ -0,0 +1,114 @@
+/*      $NetBSD: excludes.c,v 1.13 2004/06/20 22:20:18 jmc Exp $        */
+
+/*
+ * Copyright 2000 Massachusetts Institute of Technology
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby
+ * granted, provided that both the above copyright notice and this
+ * permission notice appear in all copies, that both the above
+ * copyright notice and this permission notice appear in all
+ * supporting documentation, and that the name of M.I.T. not be used
+ * in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.  M.I.T. makes
+ * no representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied
+ * warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''.  M.I.T. DISCLAIMS
+ * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
+ * SHALL M.I.T. 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>
+
+#if defined(__RCSID) && !defined(lint)
+__RCSID("$NetBSD: excludes.c,v 1.13 2004/06/20 22:20:18 jmc Exp $");
+#endif
+
+#include <sys/types.h>
+#include <sys/queue.h>
+
+#include <fnmatch.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <util.h>
+
+#include "extern.h"
+
+/*
+ * We're assuming that there won't be a whole lot of excludes,
+ * so it's OK to use a stupid algorithm.
+ */
+struct exclude {
+        LIST_ENTRY(exclude) link;
+        const char *glob;
+        int pathname;
+};
+static LIST_HEAD(, exclude) excludes;
+
+void
+init_excludes(void)
+{
+        LIST_INIT(&excludes);
+}
+
+void
+read_excludes_file(const char *name)
+{
+        FILE *fp;
+        char *line;
+        struct exclude *e;
+
+        fp = fopen(name, "r");
+        if (fp == 0)
+                err(1, "%s", name);
+
+        while ((line = fparseln(fp, NULL, NULL, NULL,
+            FPARSELN_UNESCCOMM | FPARSELN_UNESCCONT | FPARSELN_UNESCESC))
+            != NULL) {
+                if (line[0] == '\0')
+                        continue;
+
+                if ((e = malloc(sizeof *e)) == NULL)
+                        error("memory allocation error");
+
+                e->glob = line;
+                if (strchr(e->glob, '/') != NULL)
+                        e->pathname = 1;
+                else
+                        e->pathname = 0;
+                LIST_INSERT_HEAD(&excludes, e, link);
+        }
+        fclose(fp);
+}
+
+int
+check_excludes(const char *fname, const char *path)
+{
+        struct exclude *e;
+
+        /* fnmatch(3) has a funny return value convention... */
+#define MATCH(g, n) (fnmatch((g), (n), FNM_PATHNAME) == 0)
+
+        e = LIST_FIRST(&excludes);
+        while (e) {
+                if ((e->pathname && MATCH(e->glob, path))
+                    || MATCH(e->glob, fname)) {
+                        return (1);
+                }
+                e = LIST_NEXT(e, link);
+        }
+        return (0);
+}
Index: Makefile
===================================================================
RCS file: /cvs/src/usr.sbin/mtree/Makefile,v
retrieving revision 1.7
diff -u -r1.7 Makefile
--- Makefile    2 May 2004 17:55:53 -0000       1.7
+++ Makefile    11 Sep 2010 22:52:42 -0000
@@ -2,7 +2,8 @@
 
 PROG=  mtree
 #CFLAGS+=-DDEBUG
+LDFLAGS+=-O2 -pipe -lutil
 MAN=   mtree.8
-SRCS=  compare.c crc.c create.c misc.c mtree.c spec.c verify.c
+SRCS=  compare.c crc.c create.c excludes.c misc.c mtree.c spec.c verify.c
 
 .include <bsd.prog.mk>
Index: create.c
===================================================================
RCS file: /cvs/src/usr.sbin/mtree/create.c,v
retrieving revision 1.26
diff -u -r1.26 create.c
--- create.c    27 Oct 2009 23:59:53 -0000      1.26
+++ create.c    11 Sep 2010 22:52:42 -0000
@@ -87,6 +87,10 @@
        if ((t = fts_open(argv, ftsoptions, dsort)) == NULL)
                error("fts_open: %s", strerror(errno));
        while ((p = fts_read(t))) {
+               if (check_excludes(p->fts_name, p->fts_path)) {
+                        fts_set(t, p, FTS_SKIP);
+                        continue;
+                }
                if (iflag)
                        indent = p->fts_level * 4;
                switch(p->fts_info) {
Index: extern.h
===================================================================
RCS file: /cvs/src/usr.sbin/mtree/extern.h,v
retrieving revision 1.8
diff -u -r1.8 extern.h
--- extern.h    10 Aug 2005 00:42:09 -0000      1.8
+++ extern.h    11 Sep 2010 22:52:42 -0000
@@ -46,3 +46,6 @@
 char           *rlink(char *);
 struct _node   *spec(void);
 int             verify(void);
+void           init_excludes(void);
+void           read_excludes_file(const char *);
+int            check_excludes(const char *, const char *);
Index: mtree.8
===================================================================
RCS file: /cvs/src/usr.sbin/mtree/mtree.8,v
retrieving revision 1.32
diff -u -r1.32 mtree.8
--- mtree.8     31 May 2007 19:20:26 -0000      1.32
+++ mtree.8     11 Sep 2010 22:52:42 -0000
@@ -45,6 +45,7 @@
 .Op Fl k Ar keywords
 .Op Fl p Ar path
 .Op Fl s Ar seed
+.Op Fl X Ar exclude-file
 .Ek
 .Sh DESCRIPTION
 The utility
@@ -147,6 +148,20 @@
 did not match the specification.
 .It Fl x
 Don't descend below mount points in the file hierarchy.
+.It Fl X Ar exclude-file
+The specified file contains
+.Xr fnmatch 3
+patterns matching files to be excluded from
+the specification, one to a line.
+If the pattern contains a
+.Ql \&/
+character, it will be matched against entire pathnames (relative to
+the starting directory); otherwise,
+it will be matched against basenames only.
+Comments are permitted in
+the
+.Ar exclude-list
+file.
 .El
 .Pp
 Specifications are mostly composed of
Index: mtree.c
===================================================================
RCS file: /cvs/src/usr.sbin/mtree/mtree.c,v
retrieving revision 1.20
diff -u -r1.20 mtree.c
--- mtree.c     27 Oct 2009 23:59:53 -0000      1.20
+++ mtree.c     11 Sep 2010 22:52:42 -0000
@@ -58,9 +58,11 @@
        char *dir, *p;
        int status;
 
+       init_excludes();
+
        dir = NULL;
        keys = KEYDEFAULT;
-       while ((ch = getopt(argc, argv, "cdef:iK:k:lnp:qrs:tUux")) != -1)
+       while ((ch = getopt(argc, argv, "cdef:iK:k:lnp:qrs:tUuX:x")) != -1)
                switch((char)ch) {
                case 'c':
                        cflag = 1;
@@ -123,6 +125,9 @@
                case 'x':
                        ftsoptions |= FTS_XDEV;
                        break;
+               case 'X':
+                       read_excludes_file(optarg);
+                       break;
                case '?':
                default:
                        usage();
@@ -157,7 +162,7 @@
 {
        (void)fprintf(stderr,
            "usage: mtree [-cdeilnqrtUux] [-f spec] [-K keywords] "
-           "[-k keywords] [-p path]\n"
-           "             [-s seed]\n");
+           "[-k keywords]\n"
+           "             [-X exclude-file] [-p path] [-s seed]\n");
        exit(1);
 }
Index: verify.c
===================================================================
RCS file: /cvs/src/usr.sbin/mtree/verify.c,v
retrieving revision 1.19
diff -u -r1.19 verify.c
--- verify.c    27 Oct 2009 23:59:53 -0000      1.19
+++ verify.c    11 Sep 2010 22:52:42 -0000
@@ -79,6 +79,10 @@
        level = root;
        specdepth = rval = 0;
        while ((p = fts_read(t))) {
+               if (check_excludes(p->fts_name, p->fts_path)) {
+                       fts_set(t, p, FTS_SKIP);
+                       continue;
+               }
                switch(p->fts_info) {
                case FTS_D:
                        break;
</patch>

Reply via email to