fts(3) updates
authorNate Willams <nate@FreeBSD.org>
Wed, 28 Jul 1993 01:50:07 +0000 (01:50 +0000)
committerNate Willams <nate@FreeBSD.org>
Wed, 28 Jul 1993 01:50:07 +0000 (01:50 +0000)
36 files changed:
bin/chmod/chmod.c
bin/df/Makefile
bin/df/df.1
bin/df/df.c
bin/df/getbsize.c [new file with mode: 0644]
bin/rm/rm.c
include/fts.h
include/glob.h
lib/libc/gen/fts.3
lib/libc/gen/fts.c
lib/libc/gen/glob.3
lib/libc/gen/glob.c
lib/libc/gen/syslog.c
usr.bin/du/Makefile
usr.bin/du/du.1
usr.bin/du/du.c
usr.bin/find/Makefile
usr.bin/find/extern.h
usr.bin/find/find.1
usr.bin/find/find.c
usr.bin/find/find.h
usr.bin/find/function.c
usr.bin/find/main.c
usr.bin/find/option.c
usr.sbin/mtree/Makefile
usr.sbin/mtree/compare.c
usr.sbin/mtree/create.c
usr.sbin/mtree/extern.h [new file with mode: 0644]
usr.sbin/mtree/misc.c [new file with mode: 0644]
usr.sbin/mtree/mtree.8 [new file with mode: 0644]
usr.sbin/mtree/mtree.c
usr.sbin/mtree/mtree.h
usr.sbin/mtree/spec.c
usr.sbin/mtree/verify.c
usr.sbin/swapinfo/Makefile
usr.sbin/swapinfo/swapinfo.c

index 99e08bb..a67e3f9 100644 (file)
@@ -38,30 +38,36 @@ char copyright[] =
 #endif /* not lint */
 
 #ifndef lint
 #endif /* not lint */
 
 #ifndef lint
-static char sccsid[] = "@(#)chmod.c    5.19 (Berkeley) 3/12/91";
+static char sccsid[] = "@(#)chmod.c    5.21 (Berkeley) 1/27/92";
 #endif /* not lint */
 
 #include <sys/types.h>
 #include <sys/stat.h>
 #endif /* not lint */
 
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <errno.h>
 #include <fts.h>
 #include <fts.h>
+#include <unistd.h>
 #include <stdio.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 
 #include <string.h>
 
-extern int errno;
 int retval;
 
 int retval;
 
+void err __P((const char *, ...));
+void error __P((char *));
+void usage __P((void));
+
+int
 main(argc, argv)
        int argc;
 main(argc, argv)
        int argc;
-       char **argv;
+       char *argv[];
 {
 {
-       extern int optind;
        register FTS *fts;
        register FTSENT *p;
        register int oct, omode;
        register FTS *fts;
        register FTSENT *p;
        register int oct, omode;
-       register char *mode;
-       mode_t *set, *setmode();
        struct stat sb;
        struct stat sb;
+       mode_t *set;
        int ch, fflag, rflag;
        int ch, fflag, rflag;
+       char *ep, *mode;
 
        fflag = rflag = 0;
        while ((ch = getopt(argc, argv, "Rfrwx")) != EOF)
 
        fflag = rflag = 0;
        while ((ch = getopt(argc, argv, "Rfrwx")) != EOF)
@@ -89,23 +95,21 @@ done:       argv += optind;
 
        mode = *argv;
        if (*mode >= '0' && *mode <= '7') {
 
        mode = *argv;
        if (*mode >= '0' && *mode <= '7') {
-               omode = (int)strtol(mode, (char **)NULL, 8);
+               omode = (int)strtol(mode, &ep, 8);
+               if (omode < 0 || *ep)
+                       err("invalid file mode: %s", mode);
                oct = 1;
        } else {
                oct = 1;
        } else {
-               if (!(set = setmode(mode))) {
-                       (void)fprintf(stderr, "chmod: invalid file mode.\n");
-                       exit(1);
-               }
+               if (!(set = setmode(mode)))
+                       err("invalid file mode: %s", mode);
                oct = 0;
        }
 
        retval = 0;
        if (rflag) {
                oct = 0;
        }
 
        retval = 0;
        if (rflag) {
-               if (!(fts = fts_open(++argv,
-                   oct ? FTS_NOSTAT|FTS_PHYSICAL : FTS_PHYSICAL, 0))) {
-                       (void)fprintf(stderr, "chmod: %s.\n", strerror(errno));
-                       exit(1);
-               }
+               if ((fts = fts_open(++argv,
+                   oct ? FTS_NOSTAT|FTS_PHYSICAL : FTS_PHYSICAL, 0)) == NULL)
+                       err("%s", strerror(errno));
                while (p = fts_read(fts))
                        switch(p->fts_info) {
                        case FTS_D:
                while (p = fts_read(fts))
                        switch(p->fts_info) {
                        case FTS_D:
@@ -113,12 +117,10 @@ done:     argv += optind;
                        case FTS_DNR:
                        case FTS_ERR:
                        case FTS_NS:
                        case FTS_DNR:
                        case FTS_ERR:
                        case FTS_NS:
-                               (void)fprintf(stderr, "chmod: %s: %s.\n",
-                                   p->fts_path, strerror(errno));
-                               exit(1);
+                               err("%s: %s", p->fts_path, strerror(errno));
                        default:
                                if (chmod(p->fts_accpath, oct ? omode :
                        default:
                                if (chmod(p->fts_accpath, oct ? omode :
-                                   getmode(set, p->fts_statb.st_mode)) &&
+                                   getmode(set, p->fts_statp->st_mode)) &&
                                    !fflag)
                                        error(p->fts_path);
                                break;
                                    !fflag)
                                        error(p->fts_path);
                                break;
@@ -137,15 +139,46 @@ done:     argv += optind;
        exit(retval);
 }
 
        exit(retval);
 }
 
+void
 error(name)
        char *name;
 {
 error(name)
        char *name;
 {
-       (void)fprintf(stderr, "chmod: %s: %s.\n", name, strerror(errno));
+       (void)fprintf(stderr, "chmod: %s: %s\n", name, strerror(errno));
        retval = 1;
 }
 
        retval = 1;
 }
 
+void
 usage()
 {
 usage()
 {
-       (void)fprintf(stderr, "chmod: chmod [-R] mode file ...\n");
+       (void)fprintf(stderr, "usage: chmod [-R] mode file ...\n");
+       exit(1);
+}
+
+#if __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+void
+#if __STDC__
+err(const char *fmt, ...)
+#else
+err(fmt, va_alist)
+       char *fmt;
+        va_dcl
+#endif
+{
+       va_list ap;
+#if __STDC__
+       va_start(ap, fmt);
+#else
+       va_start(ap);
+#endif
+       (void)fprintf(stderr, "chmod: ");
+       (void)vfprintf(stderr, fmt, ap);
+       va_end(ap);
+       (void)fprintf(stderr, "\n");
        exit(1);
        exit(1);
+       /* NOTREACHED */
 }
 }
index d0d329f..c987835 100644 (file)
@@ -1,6 +1,7 @@
 #      @(#)Makefile    5.3 (Berkeley) 5/11/90
 
 PROG=  df
 #      @(#)Makefile    5.3 (Berkeley) 5/11/90
 
 PROG=  df
+SRCS=  df.c getbsize.c
 CFLAGS+=-DCOMPAT_43
 BINGRP=        operator
 BINMODE=2555
 CFLAGS+=-DCOMPAT_43
 BINGRP=        operator
 BINMODE=2555
index 84ad660..558c7db 100644 (file)
@@ -29,9 +29,9 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.\"     @(#)df.1       6.9 (Berkeley) 6/17/91
+.\"     @(#)df.1       6.10 (Berkeley) 3/1/92
 .\"
 .\"
-.Dd June 17, 1991
+.Dd March 1, 1992
 .Dt DF 1
 .Os BSD 4
 .Sh NAME
 .Dt DF 1
 .Os BSD 4
 .Sh NAME
@@ -39,7 +39,7 @@
 .Nd display free disk space
 .Sh SYNOPSIS
 .Nm df
 .Nd display free disk space
 .Sh SYNOPSIS
 .Nm df
-.Op Fl ikn
+.Op Fl in
 .Op Ar file | Ar filesystem ...
 .Sh DESCRIPTION
 .Nm Df
 .Op Ar file | Ar filesystem ...
 .Sh DESCRIPTION
 .Nm Df
@@ -48,6 +48,7 @@ displays statistics about the amount of free disk space on the specified
 or on the filesystem of which
 .Ar file
 is a part.
 or on the filesystem of which
 .Ar file
 is a part.
+Values are displayed in 512-byte per block block counts.
 If neither a file or a filesystem operand is specified,
 statistics for all mounted filesystems are displayed.
 .Pp
 If neither a file or a filesystem operand is specified,
 statistics for all mounted filesystems are displayed.
 .Pp
@@ -55,11 +56,6 @@ The following options are available:
 .Bl -tag -width Ds
 .It Fl i
 Include statistics on the number of free inodes.
 .Bl -tag -width Ds
 .It Fl i
 Include statistics on the number of free inodes.
-.It Fl k
-By default, all sizes are reported in 512-byte block counts.
-The
-.Fl k
-option causes the numbers to be reported in kilobyte counts.
 .It Fl n
 Print out the previously obtained statistics from the filesystems.
 This option should be used if it is possible that one or more
 .It Fl n
 Print out the previously obtained statistics from the filesystems.
 This option should be used if it is possible that one or more
@@ -70,6 +66,13 @@ When this option is specified,
 will not request new statistics from the filesystems, but will respond
 with the possibly stale statistics that were previously obtained.
 .El
 will not request new statistics from the filesystems, but will respond
 with the possibly stale statistics that were previously obtained.
 .El
+.Sh ENVIRONMENTAL VARIABLES
+.Bl -tag -width BLOCKSIZE
+.It Ev BLOCKSIZE
+If the environmental variable
+.Ev BLOCKSIZE
+is set, the block counts will be displayed in units of that size block.
+.El
 .Sh BUGS
 The
 .Fl n
 .Sh BUGS
 The
 .Fl n
index 1ed82c7..58d5e4f 100644 (file)
@@ -38,54 +38,51 @@ char copyright[] =
 #endif /* not lint */
 
 #ifndef lint
 #endif /* not lint */
 
 #ifndef lint
-static char sccsid[] = "@(#)df.c       5.24 (Berkeley) 3/6/91";
+static char sccsid[] = "@(#)df.c       5.30 (Berkeley) 4/23/92";
 #endif /* not lint */
 
 #endif /* not lint */
 
-/*
- * df
- */
 #include <sys/param.h>
 #include <sys/stat.h>
 #include <sys/mount.h>
 #include <sys/param.h>
 #include <sys/stat.h>
 #include <sys/mount.h>
+#include <errno.h>
 #include <fcntl.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 
 #include <fcntl.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 
-char   *getmntpt();
-void   ufs_df(), prtstat();
-int    iflag, kflag, nflag;
+int     bread __P((long, char *, int));
+char   *getbsize __P((char *, int *, long *));
+char   *getmntpt __P((char *));
+void    prtstat __P((struct statfs *, long));
+void    ufs_df __P((char *, long));
+void    usage __P((void));
+
+int    iflag, nflag;
 struct ufs_args mdev;
 
 int
 main(argc, argv)
        int argc;
 struct ufs_args mdev;
 
 int
 main(argc, argv)
        int argc;
-       char **argv;
+       char *argv[];
 {
 {
-       extern int errno, optind;
-       int err, ch, i;
-       long width, maxwidth, mntsize;
-       char *mntpt, *mktemp();
        struct stat stbuf;
        struct statfs statfsbuf, *mntbuf;
        struct stat stbuf;
        struct statfs statfsbuf, *mntbuf;
+       long width, maxwidth, mntsize;
+       int err, ch, i;
+       char *mntpt;
 
 
-       while ((ch = getopt(argc, argv, "ikn")) != EOF)
+       while ((ch = getopt(argc, argv, "in")) != EOF)
                switch(ch) {
                case 'i':
                        iflag = 1;
                        break;
                switch(ch) {
                case 'i':
                        iflag = 1;
                        break;
-               case 'k':
-                       kflag = 1;
-                       break;
                case 'n':
                        nflag = 1;
                        break;
                case '?':
                default:
                case 'n':
                        nflag = 1;
                        break;
                case '?':
                default:
-                       fprintf(stderr,
-                           "usage: df [-ikn] [file | file_system ...]\n");
-                       exit(1);
+                       usage();
                }
        argc -= optind;
        argv += optind;
                }
        argc -= optind;
        argv += optind;
@@ -179,36 +176,38 @@ prtstat(sfsp, maxwidth)
        register struct statfs *sfsp;
        long maxwidth;
 {
        register struct statfs *sfsp;
        long maxwidth;
 {
+       static long blocksize;
+       static int headerlen, timesthrough;
+       static char *header;
        long used, availblks, inodes;
        long used, availblks, inodes;
-       static int timesthrough;
 
        if (maxwidth < 11)
                maxwidth = 11;
        if (++timesthrough == 1) {
 
        if (maxwidth < 11)
                maxwidth = 11;
        if (++timesthrough == 1) {
-               printf("%-*.*s%s    used   avail capacity",
-                   maxwidth, maxwidth, "Filesystem",
-                   kflag ? "  kbytes" : "512-blks");
+               header = getbsize("df", &headerlen, &blocksize);
+               (void)printf("%-*.*s %s    Used   Avail Capacity",
+                   maxwidth, maxwidth, "Filesystem", header);
                if (iflag)
                if (iflag)
-                       printf(" iused   ifree  %%iused");
-               printf("  Mounted on\n");
+                       (void)printf(" iused   ifree  %%iused");
+               (void)printf("  Mounted on\n");
        }
        }
-       printf("%-*.*s", maxwidth, maxwidth, sfsp->f_mntfromname);
+       (void)printf("%-*.*s", maxwidth, maxwidth, sfsp->f_mntfromname);
        used = sfsp->f_blocks - sfsp->f_bfree;
        availblks = sfsp->f_bavail + used;
        used = sfsp->f_blocks - sfsp->f_bfree;
        availblks = sfsp->f_bavail + used;
-       printf("%8ld%8ld%8ld",
-           sfsp->f_blocks * sfsp->f_fsize / (kflag ? 1024 : 512),
-           used * sfsp->f_fsize / (kflag ? 1024 : 512),
-           sfsp->f_bavail * sfsp->f_fsize / (kflag ? 1024 : 512));
-       printf("%6.0f%%",
+       (void)printf(" %*ld %7ld %7ld", headerlen,
+           sfsp->f_blocks * sfsp->f_fsize / blocksize,
+           used * sfsp->f_fsize / blocksize,
+           sfsp->f_bavail * sfsp->f_fsize / blocksize);
+       (void)printf(" %5.0f%%",
            availblks == 0 ? 100.0 : (double)used / (double)availblks * 100.0);
        if (iflag) {
                inodes = sfsp->f_files;
                used = inodes - sfsp->f_ffree;
            availblks == 0 ? 100.0 : (double)used / (double)availblks * 100.0);
        if (iflag) {
                inodes = sfsp->f_files;
                used = inodes - sfsp->f_ffree;
-               printf("%8ld%8ld%6.0f%% ", used, sfsp->f_ffree,
+               (void)printf(" %7ld %7ld %5.0f%% ", used, sfsp->f_ffree,
                   inodes == 0 ? 100.0 : (double)used / (double)inodes * 100.0);
        } else 
                   inodes == 0 ? 100.0 : (double)used / (double)inodes * 100.0);
        } else 
-               printf("  ");
-       printf("  %s\n", sfsp->f_mntonname);
+               (void)printf("  ");
+       (void)printf("  %s\n", sfsp->f_mntonname);
 }
 
 /*
 }
 
 /*
@@ -226,14 +225,12 @@ union {
 #define sblock sb.iu_fs
 
 int    fi;
 #define sblock sb.iu_fs
 
 int    fi;
-int    bread();
 
 void
 ufs_df(file, maxwidth)
        char *file;
        long maxwidth;
 {
 
 void
 ufs_df(file, maxwidth)
        char *file;
        long maxwidth;
 {
-       extern int errno;
        struct statfs statfsbuf;
        register struct statfs *sfsp;
        char *mntpt;
        struct statfs statfsbuf;
        register struct statfs *sfsp;
        char *mntpt;
@@ -243,18 +240,20 @@ ufs_df(file, maxwidth)
                sync();
 
        if ((fi = open(file, O_RDONLY)) < 0) {
                sync();
 
        if ((fi = open(file, O_RDONLY)) < 0) {
-               fprintf(stderr, "df: %s: %s\n", file, strerror(errno));
+               (void)fprintf(stderr, "df: %s: %s\n", file, strerror(errno));
                return;
        }
        if (bread((long)SBOFF, (char *)&sblock, SBSIZE) == 0) {
                return;
        }
        if (bread((long)SBOFF, (char *)&sblock, SBSIZE) == 0) {
-               (void) close(fi);
+               (void)close(fi);
                return;
        }
        sfsp = &statfsbuf;
        sfsp->f_type = MOUNT_UFS;
        sfsp->f_flags = 0;
                return;
        }
        sfsp = &statfsbuf;
        sfsp->f_type = MOUNT_UFS;
        sfsp->f_flags = 0;
-       sfsp->f_fsize = sblock.fs_fsize;
-       sfsp->f_bsize = sblock.fs_bsize;
+       sfsp->f_bsize = sblock.fs_fsize;
+#ifdef notyet
+       sfsp->f_iosize = sblock.fs_bsize;
+#endif
        sfsp->f_blocks = sblock.fs_dsize;
        sfsp->f_bfree = sblock.fs_cstotal.cs_nbfree * sblock.fs_frag +
                sblock.fs_cstotal.cs_nffree;
        sfsp->f_blocks = sblock.fs_dsize;
        sfsp->f_bfree = sblock.fs_cstotal.cs_nbfree * sblock.fs_frag +
                sblock.fs_cstotal.cs_nffree;
@@ -274,8 +273,6 @@ ufs_df(file, maxwidth)
        (void) close(fi);
 }
 
        (void) close(fi);
 }
 
-long lseek();
-
 int
 bread(off, buf, cnt)
        long off;
 int
 bread(off, buf, cnt)
        long off;
@@ -283,16 +280,22 @@ bread(off, buf, cnt)
        int cnt;
 {
        int n;
        int cnt;
 {
        int n;
-       extern errno;
 
        (void) lseek(fi, off, SEEK_SET);
        if ((n=read(fi, buf, cnt)) != cnt) {
                /* probably a dismounted disk if errno == EIO */
                if (errno != EIO) {
 
        (void) lseek(fi, off, SEEK_SET);
        if ((n=read(fi, buf, cnt)) != cnt) {
                /* probably a dismounted disk if errno == EIO */
                if (errno != EIO) {
-                       printf("\nread error off = %ld\n", off);
-                       printf("count = %d; errno = %d\n", n, errno);
+                       (void)printf("\nread error off = %ld\n", off);
+                       (void)printf("count = %d: %s\n", n, strerror(errno));
                }
                return (0);
        }
        return (1);
 }
                }
                return (0);
        }
        return (1);
 }
+
+void
+usage()
+{
+       (void)fprintf(stderr, "usage: df [-in] [file | file_system ...]\n");
+       exit(1);
+}
diff --git a/bin/df/getbsize.c b/bin/df/getbsize.c
new file mode 100644 (file)
index 0000000..a8da4ec
--- /dev/null
@@ -0,0 +1,107 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * 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.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)getbsize.c 5.3 (Berkeley) 3/9/92";
+#endif /* not lint */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+char *
+getbsize(prog, headerlenp, blocksizep)
+       char *prog;
+       int *headerlenp;
+       long *blocksizep;
+{
+       static char header[20];
+       long n, max, mul, blocksize;
+       char *ep, *p, *form;
+
+#define        KB      (1024L)
+#define        MB      (1024L * 1024L)
+#define        GB      (1024L * 1024L * 1024L)
+#define        MAXB    GB              /* No tera, peta, nor exa. */
+       form = "";
+       if ((p = getenv("BLOCKSIZE")) != NULL && *p != '\0') {
+               if ((n = strtol(p, &ep, 10)) < 0)
+                       goto underflow;
+               if (n == 0)
+                       n = 1;
+               if (*ep && ep[1])
+                       goto fmterr;
+               switch (*ep) {
+               case 'G': case 'g':
+                       form = "G";
+                       max = MAXB / GB;
+                       mul = GB;
+                       break;
+               case 'K': case 'k':
+                       form = "K";
+                       max = MAXB / KB;
+                       mul = KB;
+                       break;
+               case 'M': case 'm':
+                       form = "M";
+                       max = MAXB / MB;
+                       mul = MB;
+                       break;
+               case '\0':
+                       max = MAXB;
+                       mul = 1;
+                       break;
+               default:
+fmterr:                        (void)fprintf(stderr,
+                           "%s: %s: unknown blocksize\n", prog, p);
+                       n = 512;
+                       mul = 1;
+                       break;
+               }
+               if (n > max) {
+                       (void)fprintf(stderr,
+                           "%s: maximum blocksize is %dG\n", prog, MAXB / GB);
+                       n = max;
+               }
+               if ((blocksize = n * mul) < 512) {
+underflow:             (void)fprintf(stderr,
+                           "%s: minimum blocksize is 512\n", prog);
+                       form = "";
+                       blocksize = n = 512;
+               }
+       } else
+               blocksize = n = 512;
+
+       *headerlenp = snprintf(header, sizeof(header), "%d%s-blocks", n, form);
+       *blocksizep = blocksize;
+       return (header);
+}
index 739ef68..6b65b0c 100644 (file)
@@ -38,7 +38,7 @@ char copyright[] =
 #endif /* not lint */
 
 #ifndef lint
 #endif /* not lint */
 
 #ifndef lint
-static char sccsid[] = "@(#)rm.c       4.26 (Berkeley) 3/10/91";
+static char sccsid[] = "@(#)rm.c       4.27 (Berkeley) 1/27/92";
 #endif /* not lint */
 
 #include <sys/types.h>
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -154,7 +154,7 @@ rmtree(argv)
                /* Pre-order: give user chance to skip. */
                case FTS_D:
                        if (iflag && !check(p->fts_path, p->fts_accpath,
                /* Pre-order: give user chance to skip. */
                case FTS_D:
                        if (iflag && !check(p->fts_path, p->fts_accpath,
-                           &p->fts_statb)) {
+                           p->fts_statp)) {
                                (void)fts_set(fts, p, FTS_SKIP);
                                p->fts_number = SKIPPED;
                        }
                                (void)fts_set(fts, p, FTS_SKIP);
                                p->fts_number = SKIPPED;
                        }
@@ -167,7 +167,7 @@ rmtree(argv)
                }
 
                if (!fflag &&
                }
 
                if (!fflag &&
-                   !check(p->fts_path, p->fts_accpath, &p->fts_statb))
+                   !check(p->fts_path, p->fts_accpath, p->fts_statp))
                        continue;
 
                /*
                        continue;
 
                /*
index b7af5d5..c2ec64a 100644 (file)
@@ -30,7 +30,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- *     @(#)fts.h       5.14 (Berkeley) 4/3/91
+ *     @(#)fts.h       5.24 (Berkeley) 5/5/92
  */
 
 #ifndef        _FTS_H_
  */
 
 #ifndef        _FTS_H_
 typedef struct {
        struct _ftsent *fts_cur;        /* current node */
        struct _ftsent *fts_child;      /* linked list of children */
 typedef struct {
        struct _ftsent *fts_cur;        /* current node */
        struct _ftsent *fts_child;      /* linked list of children */
-       struct _ftsent *fts_savelink;   /* saved link if node had a cycle */
        struct _ftsent **fts_array;     /* sort array */
        struct _ftsent **fts_array;     /* sort array */
-       dev_t rdev;                     /* starting device # */
+       dev_t fts_dev;                  /* starting device # */
        char *fts_path;                 /* path for this descent */
        char *fts_path;                 /* path for this descent */
-       int fts_dfd;                    /* fd for directories */
        int fts_rfd;                    /* fd for root */
        int fts_pathlen;                /* sizeof(path) */
        int fts_nitems;                 /* elements in the sort array */
        int (*fts_compar)();            /* compare function */
 
        int fts_rfd;                    /* fd for root */
        int fts_pathlen;                /* sizeof(path) */
        int fts_nitems;                 /* elements in the sort array */
        int (*fts_compar)();            /* compare function */
 
-#define        FTS_LOGICAL     0x001           /* logical walk */
-#define        FTS_NOCHDIR     0x002           /* don't change directories */
-#define        FTS_NOSTAT      0x004           /* don't get stat info */
-#define        FTS_PHYSICAL    0x008           /* physical walk */
-#define        FTS_SEEDOT      0x010           /* return dot and dot-dot */
-#define        FTS_STOP        0x020           /* (private) unrecoverable error */
+#define        FTS_COMFOLLOW   0x001           /* follow command line symlinks */
+#define        FTS_LOGICAL     0x002           /* logical walk */
+#define        FTS_NOCHDIR     0x004           /* don't change directories */
+#define        FTS_NOSTAT      0x008           /* don't get stat info */
+#define        FTS_PHYSICAL    0x010           /* physical walk */
+#define        FTS_SEEDOT      0x020           /* return dot and dot-dot */
 #define        FTS_XDEV        0x040           /* don't cross devices */
 #define        FTS_XDEV        0x040           /* don't cross devices */
-       int fts_options;                /* openfts() options */
+#define        FTS_OPTIONMASK  0x07f           /* valid user option mask */
+
+#define        FTS_NAMEONLY    0x080           /* (private) child names only */
+#define        FTS_STOP        0x100           /* (private) unrecoverable error */
+       int fts_options;                /* fts_open options, global flags */
 } FTS;
 
 typedef struct _ftsent {
 } FTS;
 
 typedef struct _ftsent {
+       struct _ftsent *fts_cycle;      /* cycle node */
        struct _ftsent *fts_parent;     /* parent directory */
        struct _ftsent *fts_parent;     /* parent directory */
-       struct _ftsent *fts_link;       /* cycle or next file structure */
-       union {
-               long number;            /* local numeric value */
-               void *pointer;          /* local address value */
-       } fts_local;
-#define        fts_number      fts_local.number
-#define        fts_pointer     fts_local.pointer
+       struct _ftsent *fts_link;       /* next file in directory */
+       long fts_number;                /* local numeric value */
+       void *fts_pointer;              /* local address value */
        char *fts_accpath;              /* access path */
        char *fts_path;                 /* root path */
        char *fts_accpath;              /* access path */
        char *fts_path;                 /* root path */
-       int fts_cderr;                  /* chdir failed -- errno */
-       short fts_pathlen;              /* strlen(fts_path) */
-       short fts_namelen;              /* strlen(fts_name) */
+       int fts_errno;                  /* errno for this node */
+       int fts_symfd;                  /* fd for symlink */
+       u_short fts_pathlen;            /* strlen(fts_path) */
+       u_short fts_namelen;            /* strlen(fts_name) */
+
+       ino_t fts_ino;                  /* inode */
+       dev_t fts_dev;                  /* device */
+       nlink_t fts_nlink;              /* link count */
 
 #define        FTS_ROOTPARENTLEVEL     -1
 #define        FTS_ROOTLEVEL            0
 
 #define        FTS_ROOTPARENTLEVEL     -1
 #define        FTS_ROOTLEVEL            0
@@ -82,32 +86,38 @@ typedef struct _ftsent {
 #define        FTS_DC           2              /* directory that causes cycles */
 #define        FTS_DEFAULT      3              /* none of the above */
 #define        FTS_DNR          4              /* unreadable directory */
 #define        FTS_DC           2              /* directory that causes cycles */
 #define        FTS_DEFAULT      3              /* none of the above */
 #define        FTS_DNR          4              /* unreadable directory */
-#define        FTS_DP           5              /* postorder directory */
-#define        FTS_ERR          6              /* error; errno is set */
-#define        FTS_F            7              /* regular file */
-#define        FTS_NS           8              /* stat(2) failed */
-#define        FTS_NSOK         9              /* no stat(2) requested */
-#define        FTS_SL          10              /* symbolic link */
-#define        FTS_SLNONE      11              /* symbolic link without target */
+#define        FTS_DOT          5              /* dot or dot-dot */
+#define        FTS_DP           6              /* postorder directory */
+#define        FTS_ERR          7              /* error; errno is set */
+#define        FTS_F            8              /* regular file */
+#define        FTS_INIT         9              /* initialized only */
+#define        FTS_NS          10              /* stat(2) failed */
+#define        FTS_NSOK        11              /* no stat(2) requested */
+#define        FTS_SL          12              /* symbolic link */
+#define        FTS_SLNONE      13              /* symbolic link without target */
        u_short fts_info;               /* user flags for FTSENT structure */
 
        u_short fts_info;               /* user flags for FTSENT structure */
 
+#define        FTS_DONTCHDIR    0x01           /* don't chdir .. to the parent */
+#define        FTS_SYMFOLLOW    0x02           /* followed a symlink to get here */
+       u_short fts_flags;              /* private flags for FTSENT structure */
+
 #define        FTS_AGAIN        1              /* read node again */
 #define        FTS_FOLLOW       2              /* follow symbolic link */
 #define        FTS_NOINSTR      3              /* no instructions */
 #define        FTS_SKIP         4              /* discard node */
        u_short fts_instr;              /* fts_set() instructions */
 
 #define        FTS_AGAIN        1              /* read node again */
 #define        FTS_FOLLOW       2              /* follow symbolic link */
 #define        FTS_NOINSTR      3              /* no instructions */
 #define        FTS_SKIP         4              /* discard node */
        u_short fts_instr;              /* fts_set() instructions */
 
-       struct stat fts_statb;          /* stat(2) information */
+       struct stat *fts_statp;         /* stat(2) information */
        char fts_name[1];               /* file name */
 } FTSENT;
 
 #include <sys/cdefs.h>
 
 __BEGIN_DECLS
        char fts_name[1];               /* file name */
 } FTSENT;
 
 #include <sys/cdefs.h>
 
 __BEGIN_DECLS
-FTSENT *fts_children __P((FTS *));
+FTSENT *fts_children __P((FTS *, int));
 int     fts_close __P((FTS *));
 int     fts_close __P((FTS *));
-FTS    *fts_open
-           __P((char * const *, int, int (*)(const FTSENT *, const FTSENT *)));
+FTS    *fts_open __P((char * const *, int,
+           int (*)(const FTSENT **, const FTSENT **)));
 FTSENT *fts_read __P((FTS *));
 int     fts_set __P((FTS *, FTSENT *, int));
 __END_DECLS
 FTSENT *fts_read __P((FTS *));
 int     fts_set __P((FTS *, FTSENT *, int));
 __END_DECLS
index 4bc1320..cedabb2 100644 (file)
@@ -33,7 +33,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- *     @(#)glob.h      5.6 (Berkeley) 4/3/91
+ *     @(#)glob.h      5.8 (Berkeley) 12/2/92
  */
 
 #ifndef _GLOB_H_
  */
 
 #ifndef _GLOB_H_
@@ -45,20 +45,26 @@ typedef struct {
        int gl_offs;            /* reserved at beginning of gl_pathv */
        int gl_flags;           /* copy of flags parameter to glob() */
        int (*gl_errfunc)();    /* copy of errfunc parameter to glob() */
        int gl_offs;            /* reserved at beginning of gl_pathv */
        int gl_flags;           /* copy of flags parameter to glob() */
        int (*gl_errfunc)();    /* copy of errfunc parameter to glob() */
+       void *(*gl_opendir)();  /* alternate opendir() function for glob() */
+       struct dirent *(*gl_readdir)(); /* alternate readdir() function */
+       void (*gl_closedir)();  /* alternate closedir() function for glob() */
+       int (*gl_lstat)();      /* alternate lstat() function for glob() */
+       int (*gl_stat)();       /* alternate stat() function for glob() */
        char **gl_pathv;        /* list of paths matching pattern */
 } glob_t;
 
        char **gl_pathv;        /* list of paths matching pattern */
 } glob_t;
 
-#define        GLOB_APPEND     0x01    /* append to output from previous call */
-#define        GLOB_DOOFFS     0x02    /* use gl_offs */
-#define        GLOB_ERR        0x04    /* return on error */
-#ifndef _POSIX_SOURCE
-#define        GLOB_MAGCHAR    0x08    /* pattern had globbing characters */
-#endif
-#define        GLOB_MARK       0x10    /* append / to matching directories */
-#define        GLOB_NOCHECK    0x20    /* return pattern itself if nothing matches */
-#define        GLOB_NOSORT     0x40    /* don't sort */
+#define        GLOB_APPEND     0x001   /* append to output from previous call */
+#define        GLOB_DOOFFS     0x002   /* use gl_offs */
+#define        GLOB_ERR        0x004   /* return on error */
+#define        GLOB_MARK       0x008   /* append / to matching directories */
+#define        GLOB_NOCHECK    0x010   /* return pattern itself if nothing matches */
+#define        GLOB_NOSORT     0x020   /* don't sort */
+
 #ifndef _POSIX_SOURCE
 #ifndef _POSIX_SOURCE
-#define        GLOB_QUOTE      0x80    /* quote special chars with \ */
+#define        GLOB_MAGCHAR    0x040   /* pattern had globbing characters */
+#define        GLOB_NOMAGIC    0x080   /* GLOB_NOCHECK without magic chars (csh) */
+#define        GLOB_QUOTE      0x100   /* quote special chars with \ */
+#define        GLOB_ALTDIRFUNC 0x200   /* use alternately specified directory funcs */
 #endif
 
 #define        GLOB_NOSPACE    (-1)    /* malloc call failed */
 #endif
 
 #define        GLOB_NOSPACE    (-1)    /* malloc call failed */
@@ -67,8 +73,8 @@ typedef struct {
 #include <sys/cdefs.h>
 
 __BEGIN_DECLS
 #include <sys/cdefs.h>
 
 __BEGIN_DECLS
-int glob __P((const char *, int, int (*)(char *, int), glob_t *));
-void globfree __P((glob_t *));
+int    glob __P((const char *, int, int (*)(char *, int), glob_t *));
+void   globfree __P((glob_t *));
 __END_DECLS
 
 #endif /* !_GLOB_H_ */
 __END_DECLS
 
 #endif /* !_GLOB_H_ */
index 17adb13..746d8e2 100644 (file)
@@ -29,9 +29,9 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.\"     @(#)fts.3      5.11 (Berkeley) 7/31/91
+.\"     @(#)fts.3      5.21 (Berkeley) 3/5/92
 .\"
 .\"
-.Dd July 31, 1991
+.Dd March 5, 1992
 .Dt FTS 3
 .Os
 .Sh NAME
 .Dt FTS 3
 .Os
 .Sh NAME
 .Fd #include <sys/stat.h>
 .Fd #include <fts.h>
 .Ft FTS *
 .Fd #include <sys/stat.h>
 .Fd #include <fts.h>
 .Ft FTS *
-.Fn fts_open "char * const *path_argv" "int options" "int *compar(const FTSENT *, const FTSENT *)"
+.Fn fts_open "char * const *path_argv" "int options" "int *compar(const FTSENT **, const FTSENT **)"
 .Ft FTSENT *
 .Fn fts_read "FTS *ftsp"
 .Ft FTSENT *
 .Ft FTSENT *
 .Fn fts_read "FTS *ftsp"
 .Ft FTSENT *
-.Fn fts_children "FTS *ftsp"
+.Fn fts_children "FTS *ftsp" "int options"
 .Ft int
 .Fn fts_set "FTS ftsp" "FTSENT *f" "int options"
 .Ft int
 .Ft int
 .Fn fts_set "FTS ftsp" "FTSENT *f" "int options"
 .Ft int
@@ -57,13 +57,12 @@ The
 functions are provided for traversing
 .Tn UNIX
 file hierarchies.
 functions are provided for traversing
 .Tn UNIX
 file hierarchies.
-.Pp
-The simple overview is that the
+A simple overview is that the
 .Fn fts_open
 .Fn fts_open
-function returns a ``handle'' on a file hierarchy, which is supplied to
+function returns a ``handle'' on a file hierarchy, which is then supplied to
 the other
 .Nm fts
 the other
 .Nm fts
-functions to determine which hierarchy they operate on.
+functions.
 The function
 .Fn fts_read
 returns a pointer to a structure describing one of the files in the file
 The function
 .Fn fts_read
 returns a pointer to a structure describing one of the files in the file
@@ -84,7 +83,7 @@ Two structures are defined (and typedef'd) in the include file
 .Aq Pa fts.h .
 The first is
 .Fa FTS ,
 .Aq Pa fts.h .
 The first is
 .Fa FTS ,
-the structure that represents the file hierarchy stream.
+the structure that represents the file hierarchy itself.
 The second is
 .Fa FTSENT ,
 the structure that represents a file in the file
 The second is
 .Fa FTSENT ,
 the structure that represents a file in the file
@@ -110,11 +109,13 @@ typedef struct _ftsent {
        char *fts_name;                 /* file name */
        short fts_namelen;              /* strlen(fts_name) */
        short fts_level;                /* depth (\-1 to N) */
        char *fts_name;                 /* file name */
        short fts_namelen;              /* strlen(fts_name) */
        short fts_level;                /* depth (\-1 to N) */
+       int fts_error;                  /* file errno */
        long fts_number;                /* local numeric value */
        void *fts_pointer;              /* local address value */
        struct ftsent *fts_parent;      /* parent directory */
        long fts_number;                /* local numeric value */
        void *fts_pointer;              /* local address value */
        struct ftsent *fts_parent;      /* parent directory */
-       struct ftsent *fts_link;        /* cycle or next file structure */
-       struct stat fts_statb;          /* stat(2) information */
+       struct ftsent *fts_link;        /* next file structure */
+       struct ftsent *fts_cycle;       /* cycle structure */
+       struct stat *fts_statp;         /* stat(2) information */
 } FTSENT;
 .Ed
 .Pp
 } FTSENT;
 .Ed
 .Pp
@@ -136,7 +137,7 @@ A directory being visited in pre-order.
 .It Dv FTS_DC
 A directory that causes a cycle in the tree.
 (The
 .It Dv FTS_DC
 A directory that causes a cycle in the tree.
 (The
-.Fa fts_link
+.Fa fts_cycle
 field of the
 .Fa FTSENT
 structure will be filled in as well.)
 field of the
 .Fa FTSENT
 structure will be filled in as well.)
@@ -149,9 +150,9 @@ by one of the other
 values.
 .It Dv FTS_DNR
 A directory which cannot be read.
 values.
 .It Dv FTS_DNR
 A directory which cannot be read.
-An error return; the external variable
-.Va errno
-will be set to indicate the error.
+This is an error return, and the
+.Fa fts_errno
+field will be set to indicate what caused the error.
 .It Dv FTS_DOT
 A file named
 .Ql \&.
 .It Dv FTS_DOT
 A file named
 .Ql \&.
@@ -171,9 +172,9 @@ it was returned in pre-order, i.e. with the
 field set to
 .Dv FTS_D .
 .It Dv FTS_ERR
 field set to
 .Dv FTS_D .
 .It Dv FTS_ERR
-An error return; the external variable
-.Va errno
-will be set to indicate the error.
+This is an error return, and the
+.Fa fts_errno
+field will be set to indicate what caused the error.
 .It Dv FTS_F
 A regular file.
 .It Dv FTS_NS
 .It Dv FTS_F
 A regular file.
 .It Dv FTS_NS
@@ -181,25 +182,25 @@ A file for which no
 .Xr stat 2
 information was available.
 The contents of the
 .Xr stat 2
 information was available.
 The contents of the
-.Fa fts_statb
+.Fa fts_statp
 field are undefined.
 field are undefined.
-An error return; the external variable
-.Va errno
-will be set to indicate the error.
+This is an error return, and the
+.Fa fts_errno
+field will be set to indicate what caused the error.
 .It Dv FTS_NSOK
 A file for which no
 .Xr stat 2
 information was requested.
 The contents of the
 .It Dv FTS_NSOK
 A file for which no
 .Xr stat 2
 information was requested.
 The contents of the
-.Fa fts_statb
+.Fa fts_statp
 field are undefined.
 .It Dv FTS_SL
 A symbolic link.
 .It Dv FTS_SLNONE
 A symbolic link with a non-existent target.
 The contents of the
 field are undefined.
 .It Dv FTS_SL
 A symbolic link.
 .It Dv FTS_SLNONE
 A symbolic link with a non-existent target.
 The contents of the
-.Fa fts_statb
-field contain the file characteristic information for the symbolic link
+.Fa fts_statp
+field reference the file characteristic information for the symbolic link
 itself.
 .El
 .It Fa fts_accpath
 itself.
 .El
 .It Fa fts_accpath
@@ -227,17 +228,34 @@ of the traversal is numbered \-1, and the
 .Fa FTSENT
 structure for the root
 itself is numbered 0.
 .Fa FTSENT
 structure for the root
 itself is numbered 0.
+.It Fa fts_errno
+Upon return of a
+.Fa FTSENT
+structure from the
+.Fn fts_children
+or
+.Fn fts_read
+functions, with its
+.Fa fts_info
+field set to 
+.Dv FTS_DNR ,
+.Dv FTS_ERR
+or
+.Dv FTS_NS ,
+the
+.Fa fts_errno
+field contains the value of the external variable
+.Va errno
+specifying the cause of the error.
+Otherwise, the contents of the
+.Fa fts_errno
+field are undefined.
 .It Fa fts_number
 This field is provided for the use of the application program and is
 not modified by the
 .Nm fts
 functions.
 It is initialized to 0.
 .It Fa fts_number
 This field is provided for the use of the application program and is
 not modified by the
 .Nm fts
 functions.
 It is initialized to 0.
-The fields
-.Fa fts_number
-and
-.Fa fts_pointer
-occupy the same physical location; using both may cause undefined results.
 .It Fa fts_pointer
 This field is provided for the use of the application program and is
 not modified by the
 .It Fa fts_pointer
 This field is provided for the use of the application program and is
 not modified by the
@@ -245,11 +263,6 @@ not modified by the
 functions.
 It is initialized to
 .Dv NULL .
 functions.
 It is initialized to
 .Dv NULL .
-The fields
-.Fa fts_number
-and
-.Fa fts_pointer
-occupy the same physical location; using both may cause undefined results.
 .It Fa fts_parent
 A pointer to the
 .Fa FTSENT
 .It Fa fts_parent
 A pointer to the
 .Fa FTSENT
@@ -264,33 +277,62 @@ and
 .Fa fts_pointer
 fields are guaranteed to be initialized.
 .It Fa fts_link
 .Fa fts_pointer
 fields are guaranteed to be initialized.
 .It Fa fts_link
-The
+Upon return from the
+.Fn fts_children
+function, the
 .Fa fts_link
 .Fa fts_link
-field has two separate uses.
+field points to the next structure in the NULL-terminated linked list of
+directory members.
+Otherwise, the contents of the
+.Fa fts_link
+field are undefined.
+.It Fa fts_cycle
 If a directory causes a cycle in the hierarchy (see
 .Dv FTS_DC ) ,
 either because
 of a hard link between two directories, or a symbolic link pointing to a
 directory, the
 If a directory causes a cycle in the hierarchy (see
 .Dv FTS_DC ) ,
 either because
 of a hard link between two directories, or a symbolic link pointing to a
 directory, the
-.Fa fts_link
+.Fa fts_cycle
 field of the structure will point to the
 .Fa FTSENT
 field of the structure will point to the
 .Fa FTSENT
-structure in the hierarchy
-that references the same file as the current
+structure in the hierarchy that references the same file as the current
 .Fa FTSENT
 structure.
 .Fa FTSENT
 structure.
-Also, upon return from the
-.Fn fts_children
-function, the
-.Fa fts_link
-field points to the next structure in the linked list of directory members.
 Otherwise, the contents of the
 Otherwise, the contents of the
-.Fa fts_link
+.Fa fts_cycle
 field are undefined.
 field are undefined.
-.It Fa fts_statb
-.Xr Stat 2
+.It Fa fts_statp
+A pointer to
+.Xr stat 2
 information for the file.
 .El
 information for the file.
 .El
+.Pp
+A single buffer is used for all of the paths of all of the files in the
+file hierarchy.
+Therefore, the
+.Fa fts_path
+and
+.Fa fts_accpath
+fields are guaranteed to be
+.Dv NULL Ns -terminated
+.Em only
+for the file most recently returned by
+.Fn fts_read .
+To use these fields to reference any files represented by other
+.Fa FTSENT
+structures will require that the path buffer be modified using the
+information contained in that
+.Fa FTSENT
+structure's
+.Fa fts_pathlen
+field.
+Any such modifications should be undone before further calls to
+.Fn fts_read
+are attempted.
+The
+.Fa fts_name
+field is always
+.Dv NULL Ns -terminated.
 .Sh FTS_OPEN
 The
 .Fn fts_open
 .Sh FTS_OPEN
 The
 .Fn fts_open
@@ -310,6 +352,11 @@ The options are selected by
 .Em or Ns 'ing
 the following values:
 .Bl -tag -width "FTS_PHYSICAL"
 .Em or Ns 'ing
 the following values:
 .Bl -tag -width "FTS_PHYSICAL"
+.It Dv FTS_COMFOLLOW
+This option causes any symbolic link specified as a root path to be
+followed immediately whether or not
+.Dv FTS_LOGICAL
+is also specified.
 .It Dv FTS_LOGICAL
 This option causes the
 .Nm fts
 .It Dv FTS_LOGICAL
 This option causes the
 .Nm fts
@@ -349,9 +396,8 @@ pathnames were provided as arguments to
 .It Dv FTS_NOSTAT
 By default, returned
 .Fa FTSENT
 .It Dv FTS_NOSTAT
 By default, returned
 .Fa FTSENT
-structures contain file characteristic
-information (the
-.Fa statb
+structures reference file characteristic information (the
+.Fa statp
 field) for each file visited.
 This option relaxes that requirement as a performance optimization,
 allowing the
 field) for each file visited.
 This option relaxes that requirement as a performance optimization,
 allowing the
@@ -361,7 +407,7 @@ functions to set the
 field to
 .Dv FTS_NSOK
 and leave the contents of the
 field to
 .Dv FTS_NSOK
 and leave the contents of the
-.Fa statb
+.Fa statp
 field undefined.
 .It Dv FTS_PHYSICAL
 This option causes the
 field undefined.
 .It Dv FTS_PHYSICAL
 This option causes the
@@ -387,10 +433,9 @@ By default, unless they are specified as path arguments to
 .Fn fts_open ,
 any files named
 .Ql \&.
 .Fn fts_open ,
 any files named
 .Ql \&.
-and
+or
 .Ql ..
 .Ql ..
-encountered in the file hierarchy are
-ignored.
+encountered in the file hierarchy are ignored.
 This option causes the
 .Nm fts
 routines to return
 This option causes the
 .Nm fts
 routines to return
@@ -429,17 +474,18 @@ If the
 field is set to
 .Dv FTS_NS
 or
 field is set to
 .Dv FTS_NS
 or
-.DV FTS_NSOK ,
+.Dv FTS_NSOK ,
 the
 the
-.Fa fts_stab
+.Fa fts_statp
 field may not either.
 If the
 .Fn compar
 argument is
 .Dv NULL ,
 field may not either.
 If the
 .Fn compar
 argument is
 .Dv NULL ,
-the directory traversal order is unspecified except
-for the root paths which are traversed in the order listed in
-.Fa path_argv .
+the directory traversal order is in the order listed in
+.Fa path_argv
+for the root paths, and in the order listed in the directory for
+everything else.
 .Sh FTS_READ
 The
 .Fn fts_read
 .Sh FTS_READ
 The
 .Fn fts_read
@@ -496,8 +542,8 @@ The
 .Fn fts_children
 function returns a pointer to an
 .Fa FTSENT
 .Fn fts_children
 function returns a pointer to an
 .Fa FTSENT
-structure describing the first
-entry in a linked list of the files in the directory represented by the
+structure describing the first entry in a NULL-terminated linked list of
+the files in the directory represented by the
 .Fa FTSENT
 structure most recently returned by
 .Fn fts_read .
 .Fa FTSENT
 structure most recently returned by
 .Fn fts_read .
@@ -505,13 +551,20 @@ The list is linked through the
 .Fa fts_link
 field of the
 .Fa FTSENT
 .Fa fts_link
 field of the
 .Fa FTSENT
-structure, and is ordered by the user-specified
-comparison function, if any.
+structure, and is ordered by the user-specified comparison function, if any.
 Repeated calls to
 .Fn fts_children
 will recreate this linked list.
 .Pp
 Repeated calls to
 .Fn fts_children
 will recreate this linked list.
 .Pp
-If the
+As a special case, if
+.Fn fts_read
+has not yet been called for a hierarchy,
+.Fn fts_children
+will return a pointer to the files in the logical directory specified to
+.Fn fts_open ,
+i.e. the arguments specified to
+.Fn fts_open .
+Otherwise, if the
 .Fa FTSENT
 structure most recently returned by
 .Fn fts_read
 .Fa FTSENT
 structure most recently returned by
 .Fn fts_read
@@ -536,39 +589,24 @@ The
 structures returned by
 .Fn fts_children
 may be overwritten after a call to
 structures returned by
 .Fn fts_children
 may be overwritten after a call to
+.Fn fts_children ,
 .Fn fts_close
 .Fn fts_close
-on the same file hierarchy stream, or after a call to
-.Fn fts_children
 or
 .Fn fts_read
 on the same file hierarchy stream.
 .Pp
 or
 .Fn fts_read
 on the same file hierarchy stream.
 .Pp
-A single buffer is used for all of the paths of all of the files in the
-file hierarchy.
-Therefore, the
-.Fa fts_path
-and
-.Fa fts_accpath
-fields are guaranteed to be
-.Dv NULL Ns -terminated
-.Em only
-for the file most recently returned by
-.Fn fts_read .
-To use these fields to reference any files represented by other
-.Fa FTSENT
-structures will require that the path buffer be modified using the
-information contained in that
-.Fa FTSENT
-structure's
-.Fa fts_pathlen
-field.
-Any such modifications should be undone before further calls to
-.Fn fts_read
-are attempted.
-The
+.Em Option
+may be set to the following value:
+.Bl -tag -width FTS_NAMEONLY
+.It Dv FTS_NAMEONLY
+Only the names of the files are needed.
+The contents of all the fields in the returned linked list of structures
+are undefined with the exception of the
 .Fa fts_name
 .Fa fts_name
-field is always
-.Dv NULL Ns -terminated.
+and
+.Fa fts_namelen
+fields.
+.El
 .Sh FTS_SET
 The function
 .Fn fts_set
 .Sh FTS_SET
 The function
 .Fn fts_set
@@ -610,7 +648,7 @@ the next call to
 returns the file with the
 .Fa fts_info
 and
 returns the file with the
 .Fa fts_info
 and
-.Fa fts_statb
+.Fa fts_statp
 fields reinitialized to reflect the target of the symbolic link instead
 of the symbolic link itself.
 If the file is one of those most recently returned by
 fields reinitialized to reflect the target of the symbolic link instead
 of the symbolic link itself.
 If the file is one of those most recently returned by
@@ -618,7 +656,7 @@ If the file is one of those most recently returned by
 the
 .Fa fts_info
 and
 the
 .Fa fts_info
 and
-.Fa fts_statb
+.Fa fts_statp
 fields of the structure, when returned by
 .Fn fts_read ,
 will reflect the target of the symbolic link instead of the symbolic link
 fields of the structure, when returned by
 .Fn fts_read ,
 will reflect the target of the symbolic link instead of the symbolic link
@@ -655,32 +693,48 @@ returns 0 on success, and \-1 if an error occurs.
 .Sh ERRORS
 The function
 .Fn fts_open
 .Sh ERRORS
 The function
 .Fn fts_open
-may fail and set errno for any of the errors specified for the library
-functions
+may fail and set
+.Va errno
+for any of the errors specified for the library functions
 .Xr open 2
 and
 .Xr malloc 3 .
 .Pp
 The function
 .Fn fts_close
 .Xr open 2
 and
 .Xr malloc 3 .
 .Pp
 The function
 .Fn fts_close
-may fail and set errno for any of the errors specified for the library
-functions
+may fail and set
+.Va errno
+for any of the errors specified for the library functions
 .Xr chdir 2
 and
 .Xr close 2 .
 .Pp
 The functions
 .Xr chdir 2
 and
 .Xr close 2 .
 .Pp
 The functions
-.Fn Fts_read
+.Fn fts_read
 and
 .Fn fts_children
 and
 .Fn fts_children
-may fail and set errno for any of the errors specified for the library
-functions
+may fail and set
+.Va errno
+for any of the errors specified for the library functions
 .Xr chdir 2 ,
 .Xr malloc 3 ,
 .Xr opendir 3 ,
 .Xr readdir 3
 and
 .Xr stat 2 .
 .Xr chdir 2 ,
 .Xr malloc 3 ,
 .Xr opendir 3 ,
 .Xr readdir 3
 and
 .Xr stat 2 .
+.Pp
+In addition,
+.Fn fts_children ,
+.Fn fts_open
+and
+.Fn fts_set
+may fail and set
+.Va errno
+as follows:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The options were invalid.
+.EL
 .Sh SEE ALSO
 .Xr find 1 ,
 .Xr chdir 2 ,
 .Sh SEE ALSO
 .Xr find 1 ,
 .Xr chdir 2 ,
index e2958d3..0c9d10d 100644 (file)
  */
 
 #if defined(LIBC_SCCS) && !defined(lint)
  */
 
 #if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)fts.c      5.19 (Berkeley) 5/9/91";
+static char sccsid[] = "@(#)fts.c      5.40 (Berkeley) 7/23/92";
 #endif /* LIBC_SCCS and not lint */
 
 #endif /* LIBC_SCCS and not lint */
 
-#include <sys/cdefs.h>
 #include <sys/param.h>
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <dirent.h>
 #include <errno.h>
 #include <sys/param.h>
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <dirent.h>
 #include <errno.h>
-#include "fts.h"
+#include <fts.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 
-static FTSENT *fts_alloc(), *fts_build(), *fts_sort();
-static void fts_load(), fts_lfree();
-static u_short fts_stat();
-static char *fts_path();
+static FTSENT  *fts_alloc __P((FTS *, char *, int));
+static FTSENT  *fts_build __P((FTS *, int));
+static void     fts_lfree __P((FTSENT *));
+static void     fts_load __P((FTS *, FTSENT *));
+static size_t   fts_maxarglen __P((char * const *));
+static void     fts_padjust __P((FTS *, void *));
+static int      fts_palloc __P((FTS *, size_t));
+static FTSENT  *fts_sort __P((FTS *, FTSENT *, int));
+static u_short  fts_stat __P((FTS *, FTSENT *, int));
+
+#define        ISDOT(a)        (a[0] == '.' && (!a[1] || a[1] == '.' && !a[2]))
 
 #define        ISSET(opt)      (sp->fts_options & opt)
 #define        SET(opt)        (sp->fts_options |= opt)
 
 #define        ISSET(opt)      (sp->fts_options & opt)
 #define        SET(opt)        (sp->fts_options |= opt)
@@ -58,8 +64,9 @@ static char *fts_path();
 #define        FCHDIR(sp, fd)  (!ISSET(FTS_NOCHDIR) && fchdir(fd))
 
 /* fts_build flags */
 #define        FCHDIR(sp, fd)  (!ISSET(FTS_NOCHDIR) && fchdir(fd))
 
 /* fts_build flags */
-#define        BCHILD          1               /* from fts_children */
-#define        BREAD           2               /* from fts_read */
+#define        BCHILD          1               /* fts_children */
+#define        BNAMES          2               /* fts_children, names only */
+#define        BREAD           3               /* fts_read */
 
 FTS *
 fts_open(argv, options, compar)
 
 FTS *
 fts_open(argv, options, compar)
@@ -69,13 +76,19 @@ fts_open(argv, options, compar)
 {
        register FTS *sp;
        register FTSENT *p, *root;
 {
        register FTS *sp;
        register FTSENT *p, *root;
-       register int nitems, maxlen;
+       register int nitems;
        FTSENT *parent, *tmp;
        int len;
 
        FTSENT *parent, *tmp;
        int len;
 
+       /* Options check. */
+       if (options & ~FTS_OPTIONMASK) {
+               errno = EINVAL;
+               return (NULL);
+       }
+
        /* Allocate/initialize the stream */
        /* Allocate/initialize the stream */
-       if (!(sp = (FTS *)malloc((u_int)sizeof(FTS))))
-               return(NULL);
+       if ((sp = malloc((u_int)sizeof(FTS))) == NULL)
+               return (NULL);
        bzero(sp, sizeof(FTS));
        sp->fts_compar = compar;
        sp->fts_options = options;
        bzero(sp, sizeof(FTS));
        sp->fts_compar = compar;
        sp->fts_options = options;
@@ -84,23 +97,36 @@ fts_open(argv, options, compar)
        if (ISSET(FTS_LOGICAL))
                SET(FTS_NOCHDIR);
 
        if (ISSET(FTS_LOGICAL))
                SET(FTS_NOCHDIR);
 
-       /* Allocate/initialize root's parent. */
-       if (!(parent = fts_alloc(sp, "", 0)))
+       /*
+        * Start out with 1K of path space, and enough, in any case,
+        * to hold the user's paths.
+        */
+       if (fts_palloc(sp, MAX(fts_maxarglen(argv), MAXPATHLEN)))
                goto mem1;
                goto mem1;
+
+       /* Allocate/initialize root's parent. */
+       if ((parent = fts_alloc(sp, "", 0)) == NULL)
+               goto mem2;
        parent->fts_level = FTS_ROOTPARENTLEVEL;
 
        /* Allocate/initialize root(s). */
        parent->fts_level = FTS_ROOTPARENTLEVEL;
 
        /* Allocate/initialize root(s). */
-       maxlen = -1;
        for (root = NULL, nitems = 0; *argv; ++argv, ++nitems) {
        for (root = NULL, nitems = 0; *argv; ++argv, ++nitems) {
-               if (!(len = strlen(*argv))) {
+               /* Don't allow zero-length paths. */
+               if ((len = strlen(*argv)) == 0) {
                        errno = ENOENT;
                        errno = ENOENT;
-                       goto mem2;
+                       goto mem3;
                }
                }
-               if (maxlen < len)
-                       maxlen = len;
+
                p = fts_alloc(sp, *argv, len);
                p->fts_level = FTS_ROOTLEVEL;
                p->fts_parent = parent;
                p = fts_alloc(sp, *argv, len);
                p->fts_level = FTS_ROOTLEVEL;
                p->fts_parent = parent;
+               p->fts_accpath = p->fts_name;
+               p->fts_info = fts_stat(sp, p, ISSET(FTS_COMFOLLOW));
+
+               /* Command-line "." and ".." are real directories. */
+               if (p->fts_info == FTS_DOT)
+                       p->fts_info = FTS_D;
+
                /*
                 * If comparison routine supplied, traverse in sorted
                 * order; otherwise traverse in the order specified.
                /*
                 * If comparison routine supplied, traverse in sorted
                 * order; otherwise traverse in the order specified.
@@ -108,12 +134,9 @@ fts_open(argv, options, compar)
                if (compar) {
                        p->fts_link = root;
                        root = p;
                if (compar) {
                        p->fts_link = root;
                        root = p;
-                       p->fts_accpath = p->fts_name;
-                       if (!(options & FTS_NOSTAT))
-                               p->fts_info = fts_stat(sp, p, 0);
                } else {
                        p->fts_link = NULL;
                } else {
                        p->fts_link = NULL;
-                       if (!root)
+                       if (root == NULL)
                                tmp = root = p;
                        else {
                                tmp->fts_link = p;
                                tmp = root = p;
                        else {
                                tmp->fts_link = p;
@@ -126,17 +149,13 @@ fts_open(argv, options, compar)
 
        /*
         * Allocate a dummy pointer and make fts_read think that we've just
 
        /*
         * Allocate a dummy pointer and make fts_read think that we've just
-        * finished the node before the root(s); set p->fts_info to FTS_NS
+        * finished the node before the root(s); set p->fts_info to FTS_INIT
         * so that everything about the "current" node is ignored.
         */
         * so that everything about the "current" node is ignored.
         */
-       if (!(sp->fts_cur = fts_alloc(sp, "", 0)))
-               goto mem2;
-       sp->fts_cur->fts_link = root;
-       sp->fts_cur->fts_info = FTS_NS;
-
-       /* Start out with at least 1K+ of path space. */
-       if (!fts_path(sp, MAX(maxlen, MAXPATHLEN)))
+       if ((sp->fts_cur = fts_alloc(sp, "", 0)) == NULL)
                goto mem3;
                goto mem3;
+       sp->fts_cur->fts_link = root;
+       sp->fts_cur->fts_info = FTS_INIT;
 
        /*
         * If using chdir(2), grab a file descriptor pointing to dot to insure
 
        /*
         * If using chdir(2), grab a file descriptor pointing to dot to insure
@@ -148,13 +167,13 @@ fts_open(argv, options, compar)
        if (!ISSET(FTS_NOCHDIR) && (sp->fts_rfd = open(".", O_RDONLY, 0)) < 0)
                SET(FTS_NOCHDIR);
 
        if (!ISSET(FTS_NOCHDIR) && (sp->fts_rfd = open(".", O_RDONLY, 0)) < 0)
                SET(FTS_NOCHDIR);
 
-       return(sp);
+       return (sp);
 
 
-mem3:  free(sp->fts_cur);
-mem2:  fts_lfree(root);
+mem3:  fts_lfree(root);
        free(parent);
        free(parent);
+mem2:  free(sp->fts_path);
 mem1:  free(sp);
 mem1:  free(sp);
-       return(NULL);
+       return (NULL);
 }
 
 static void
 }
 
 static void
@@ -169,7 +188,8 @@ fts_load(sp, p)
         * Load the stream structure for the next traversal.  Since we don't
         * actually enter the directory until after the preorder visit, set
         * the fts_accpath field specially so the chdir gets done to the right
         * Load the stream structure for the next traversal.  Since we don't
         * actually enter the directory until after the preorder visit, set
         * the fts_accpath field specially so the chdir gets done to the right
-        * place and the user can access the first node.
+        * place and the user can access the first node.  From fts_open it's
+        * known that the path will fit.
         */
        len = p->fts_pathlen = p->fts_namelen;
        bcopy(p->fts_name, sp->fts_path, len + 1);
         */
        len = p->fts_pathlen = p->fts_namelen;
        bcopy(p->fts_name, sp->fts_path, len + 1);
@@ -179,24 +199,23 @@ fts_load(sp, p)
                p->fts_namelen = len;
        }
        p->fts_accpath = p->fts_path = sp->fts_path;
                p->fts_namelen = len;
        }
        p->fts_accpath = p->fts_path = sp->fts_path;
-
-       p->fts_info = fts_stat(sp, p, 0);
-       sp->rdev = p->fts_statb.st_dev;
+       sp->fts_dev = p->fts_dev;
 }
 
 }
 
+int
 fts_close(sp)
        FTS *sp;
 {
        register FTSENT *freep, *p;
        int saved_errno;
 
 fts_close(sp)
        FTS *sp;
 {
        register FTSENT *freep, *p;
        int saved_errno;
 
+       /*
+        * This still works if we haven't read anything -- the dummy structure
+        * points to the root list, so we step through to the end of the root
+        * list which has a valid parent pointer.
+        */
        if (sp->fts_cur) {
        if (sp->fts_cur) {
-               /*
-                * This still works if we haven't read anything -- the dummy
-                * structure points to the root list, so we step through to
-                * the end of the root list which has a valid parent pointer.
-                */
-               for (p = sp->fts_cur; p->fts_level > FTS_ROOTPARENTLEVEL;) {
+               for (p = sp->fts_cur; p->fts_level >= FTS_ROOTLEVEL;) {
                        freep = p;
                        p = p->fts_link ? p->fts_link : p->fts_parent;
                        free(freep);
                        freep = p;
                        p = p->fts_link ? p->fts_link : p->fts_parent;
                        free(freep);
@@ -223,17 +242,17 @@ fts_close(sp)
        /* Set errno and return. */
        if (!ISSET(FTS_NOCHDIR) && saved_errno) {
                errno = saved_errno;
        /* Set errno and return. */
        if (!ISSET(FTS_NOCHDIR) && saved_errno) {
                errno = saved_errno;
-               return(-1);
+               return (-1);
        }
        }
-       return(0);
+       return (0);
 }
 
 /*
 }
 
 /*
- * Special case a root of "/" so that slashes aren't appended causing
- * paths to be written as "//foo".
+ * Special case a root of "/" so that slashes aren't appended which would
+ * cause paths to be written as "//foo".
  */
  */
-#define        NAPPEND(p) \
-       (p->fts_level == FTS_ROOTLEVEL && p->fts_pathlen == 1 && \
+#define        NAPPEND(p)                                                      \
+       (p->fts_level == FTS_ROOTLEVEL && p->fts_pathlen == 1 &&        \
            p->fts_path[0] == '/' ? 0 : p->fts_pathlen)
 
 FTSENT *
            p->fts_path[0] == '/' ? 0 : p->fts_pathlen)
 
 FTSENT *
@@ -243,10 +262,11 @@ fts_read(sp)
        register FTSENT *p, *tmp;
        register int instr;
        register char *t;
        register FTSENT *p, *tmp;
        register int instr;
        register char *t;
+       int saved_errno;
 
        /* If finished or unrecoverable error, return NULL. */
 
        /* If finished or unrecoverable error, return NULL. */
-       if (!sp->fts_cur || ISSET(FTS_STOP))
-               return(NULL);
+       if (sp->fts_cur == NULL || ISSET(FTS_STOP))
+               return (NULL);
 
        /* Set current node pointer. */
        p = sp->fts_cur;
 
        /* Set current node pointer. */
        p = sp->fts_cur;
@@ -255,75 +275,83 @@ fts_read(sp)
        instr = p->fts_instr;
        p->fts_instr = FTS_NOINSTR;
 
        instr = p->fts_instr;
        p->fts_instr = FTS_NOINSTR;
 
-       /* If used fts_link pointer for cycle detection, restore it. */
-       if (sp->fts_savelink) {
-               p->fts_link = sp->fts_savelink;
-               sp->fts_savelink = NULL;
-       }
-
        /* Any type of file may be re-visited; re-stat and re-turn. */
        if (instr == FTS_AGAIN) {
                p->fts_info = fts_stat(sp, p, 0);
        /* Any type of file may be re-visited; re-stat and re-turn. */
        if (instr == FTS_AGAIN) {
                p->fts_info = fts_stat(sp, p, 0);
-               return(p);
+               return (p);
        }
 
        /*
         * Following a symlink -- SLNONE test allows application to see
        }
 
        /*
         * Following a symlink -- SLNONE test allows application to see
-        * SLNONE and recover.
+        * SLNONE and recover.  If indirecting through a symlink, have
+        * keep a pointer to current location.  If unable to get that
+        * pointer, follow fails.
         */
        if (instr == FTS_FOLLOW &&
            (p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE)) {
                p->fts_info = fts_stat(sp, p, 1);
         */
        if (instr == FTS_FOLLOW &&
            (p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE)) {
                p->fts_info = fts_stat(sp, p, 1);
-               return(p);
+               if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR))
+                       if ((p->fts_symfd = open(".", O_RDONLY, 0)) < 0) {
+                               p->fts_errno = errno;
+                               p->fts_info = FTS_ERR;
+                       } else
+                               p->fts_flags |= FTS_SYMFOLLOW;
+               return (p);
        }
 
        /* Directory in pre-order. */
        if (p->fts_info == FTS_D) {
                /* If skipped or crossed mount point, do post-order visit. */
                if (instr == FTS_SKIP ||
        }
 
        /* Directory in pre-order. */
        if (p->fts_info == FTS_D) {
                /* If skipped or crossed mount point, do post-order visit. */
                if (instr == FTS_SKIP ||
-                   ISSET(FTS_XDEV) && p->fts_statb.st_dev != sp->rdev) {
+                   ISSET(FTS_XDEV) && p->fts_dev != sp->fts_dev) {
+                       if (p->fts_flags & FTS_SYMFOLLOW)
+                               (void)close(p->fts_symfd);
                        if (sp->fts_child) {
                                fts_lfree(sp->fts_child);
                                sp->fts_child = NULL;
                        }
                        p->fts_info = FTS_DP;
                        if (sp->fts_child) {
                                fts_lfree(sp->fts_child);
                                sp->fts_child = NULL;
                        }
                        p->fts_info = FTS_DP;
-                       return(p);
+                       return (p);
                } 
 
                } 
 
+               /* Rebuild if only read the names and now traversing. */
+               if (sp->fts_child && sp->fts_options & FTS_NAMEONLY) {
+                       sp->fts_options &= ~FTS_NAMEONLY;
+                       fts_lfree(sp->fts_child);
+                       sp->fts_child = NULL;
+               }
+
                /*
                /*
-                * Cd to the subdirectory, reading it if haven't already.  If
-                * the read fails for any reason, or the directory is empty,
-                * the fts_info field of the current node is set by fts_build.
+                * Cd to the subdirectory.
+                *
                 * If have already read and now fail to chdir, whack the list
                 * If have already read and now fail to chdir, whack the list
-                * to make the names come out right, and set the parent state
+                * to make the names come out right, and set the parent errno
                 * so the application will eventually get an error condition.
                 * so the application will eventually get an error condition.
-                * If haven't read and fail to chdir, check to see if we're
-                * at the root node -- if so, we have to get back or the root
-                * node may be inaccessible.
+                * Set the FTS_DONTCHDIR flag so that when we logically change
+                * directories back to the parent we don't do a chdir.
+                *
+                * If haven't read do so.  If the read fails, fts_build sets
+                * FTS_STOP or the fts_info field of the node.
                 */
                if (sp->fts_child) {
                        if (CHDIR(sp, p->fts_accpath)) {
                 */
                if (sp->fts_child) {
                        if (CHDIR(sp, p->fts_accpath)) {
-                               p->fts_parent->fts_cderr = errno;
+                               p->fts_errno = errno;
+                               p->fts_flags |= FTS_DONTCHDIR;
                                for (p = sp->fts_child; p; p = p->fts_link)
                                        p->fts_accpath =
                                            p->fts_parent->fts_accpath;
                        }
                                for (p = sp->fts_child; p; p = p->fts_link)
                                        p->fts_accpath =
                                            p->fts_parent->fts_accpath;
                        }
-               } else if (!(sp->fts_child = fts_build(sp, BREAD))) {
-                       if ISSET(FTS_STOP)
-                               return(NULL);
-                       if (p->fts_level == FTS_ROOTLEVEL &&
-                           FCHDIR(sp, sp->fts_rfd)) {
-                               SET(FTS_STOP);
-                               return(NULL);
-                       }
-                       return(p);
+               } else if ((sp->fts_child = fts_build(sp, BREAD)) == NULL) {
+                       if (ISSET(FTS_STOP))
+                               return (NULL);
+                       return (p);
                }
                p = sp->fts_child;
                sp->fts_child = NULL;
                goto name;
        }
 
                }
                p = sp->fts_child;
                sp->fts_child = NULL;
                goto name;
        }
 
-       /* Move to next node on this level. */
+       /* Move to the next node on this level. */
 next:  tmp = p;
        if (p = p->fts_link) {
                free(tmp);
 next:  tmp = p;
        if (p = p->fts_link) {
                free(tmp);
@@ -331,21 +359,32 @@ next:     tmp = p;
                /* If reached the top, load the paths for the next root. */
                if (p->fts_level == FTS_ROOTLEVEL) {
                        fts_load(sp, p);
                /* If reached the top, load the paths for the next root. */
                if (p->fts_level == FTS_ROOTLEVEL) {
                        fts_load(sp, p);
-                       return(sp->fts_cur = p);
+                       return (sp->fts_cur = p);
                }
 
                }
 
-               /* User may have called fts_set on the node. */
+               /*
+                * User may have called fts_set on the node.  If skipped,
+                * ignore.  If followed, get a file descriptor so we can
+                * get back if necessary.
+                */
                if (p->fts_instr == FTS_SKIP)
                        goto next;
                if (p->fts_instr == FTS_FOLLOW) {
                        p->fts_info = fts_stat(sp, p, 1);
                if (p->fts_instr == FTS_SKIP)
                        goto next;
                if (p->fts_instr == FTS_FOLLOW) {
                        p->fts_info = fts_stat(sp, p, 1);
+                       if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR))
+                               if ((p->fts_symfd =
+                                   open(".", O_RDONLY, 0)) < 0) {
+                                       p->fts_errno = errno;
+                                       p->fts_info = FTS_ERR;
+                               } else
+                                       p->fts_flags |= FTS_SYMFOLLOW;
                        p->fts_instr = FTS_NOINSTR;
                }
 
 name:          t = sp->fts_path + NAPPEND(p->fts_parent);
                *t++ = '/';
                bcopy(p->fts_name, t, p->fts_namelen + 1);
                        p->fts_instr = FTS_NOINSTR;
                }
 
 name:          t = sp->fts_path + NAPPEND(p->fts_parent);
                *t++ = '/';
                bcopy(p->fts_name, t, p->fts_namelen + 1);
-               return(sp->fts_cur = p);
+               return (sp->fts_cur = p);
        }
 
        /* Move up to the parent node. */
        }
 
        /* Move up to the parent node. */
@@ -359,40 +398,39 @@ name:             t = sp->fts_path + NAPPEND(p->fts_parent);
                 */
                free(p);
                errno = 0;
                 */
                free(p);
                errno = 0;
-               return(sp->fts_cur = NULL);
+               return (sp->fts_cur = NULL);
        }
 
        }
 
+       /* Nul terminate the pathname. */
        sp->fts_path[p->fts_pathlen] = '\0';
 
        /*
        sp->fts_path[p->fts_pathlen] = '\0';
 
        /*
-        * Cd back up to the parent directory.  If at a root node, have to cd
-        * back to the original place, otherwise may not be able to access the
-        * original node on post-order.
+        * Return to the parent directory.  If at a root node or came through
+        * a symlink, go back through the file descriptor.  Otherwise, cd up
+        * one directory.
         */
        if (p->fts_level == FTS_ROOTLEVEL) {
         */
        if (p->fts_level == FTS_ROOTLEVEL) {
-               if (FCHDIR(sp, sp->fts_rfd)) {
+               if (!ISSET(FTS_NOCHDIR) && FCHDIR(sp, sp->fts_rfd)) {
                        SET(FTS_STOP);
                        SET(FTS_STOP);
-                       return(NULL);
+                       return (NULL);
+               }
+       } else if (p->fts_flags & FTS_SYMFOLLOW) {
+               if (FCHDIR(sp, p->fts_symfd)) {
+                       saved_errno = errno;
+                       (void)close(p->fts_symfd);
+                       errno = saved_errno;
+                       SET(FTS_STOP);
+                       return (NULL);
+               }
+               (void)close(p->fts_symfd);
+       } else if (!(p->fts_flags & FTS_DONTCHDIR)) {
+               if (CHDIR(sp, "..")) {
+                       SET(FTS_STOP);
+                       return (NULL);
                }
        }
                }
        }
-       else if (CHDIR(sp, "..")) {
-               SET(FTS_STOP);
-               return(NULL);
-       }
-
-       /* 
-        * If had a chdir error when trying to get into the directory, set the
-        * info field to reflect this, and restore errno.  The error indicator
-        * has to be reset to 0 so that if the user does an FTS_AGAIN, it all
-        * works.
-        */
-       if (p->fts_cderr) {
-               errno = p->fts_cderr;
-               p->fts_cderr = 0;
-               p->fts_info = FTS_ERR;
-       } else
-               p->fts_info = FTS_DP;
-       return(sp->fts_cur = p);
+       p->fts_info = p->fts_errno ? FTS_ERR : FTS_DP;
+       return (sp->fts_cur = p);
 }
 
 /*
 }
 
 /*
@@ -402,39 +440,69 @@ name:             t = sp->fts_path + NAPPEND(p->fts_parent);
  * reasons.
  */
 /* ARGSUSED */
  * reasons.
  */
 /* ARGSUSED */
+int
 fts_set(sp, p, instr)
        FTS *sp;
        FTSENT *p;
        int instr;
 {
 fts_set(sp, p, instr)
        FTS *sp;
        FTSENT *p;
        int instr;
 {
+       if (instr && instr != FTS_AGAIN && instr != FTS_FOLLOW &&
+           instr != FTS_NOINSTR && instr != FTS_SKIP) {
+               errno = EINVAL;
+               return (1);
+       }
        p->fts_instr = instr;
        p->fts_instr = instr;
-       return(0);
+       return (0);
 }
 
 FTSENT *
 }
 
 FTSENT *
-fts_children(sp)
+fts_children(sp, instr)
        register FTS *sp;
        register FTS *sp;
+       int instr;
 {
        register FTSENT *p;
        int fd;
 
 {
        register FTSENT *p;
        int fd;
 
+       if (instr && instr != FTS_NAMEONLY) {
+               errno = EINVAL;
+               return (NULL);
+       }
+
        /* Set current node pointer. */
        p = sp->fts_cur;
 
        /*
        /* Set current node pointer. */
        p = sp->fts_cur;
 
        /*
-        * Set errno to 0 so that user can tell the difference between an
-        * error and a directory without entries.  If not a directory being
-        * visited in *pre-order*, or we've already had fatal errors, return
-        * immediately.
+        * Errno set to 0 so user can distinguish empty directory from
+        * an error.
         */
        errno = 0;
         */
        errno = 0;
-       if (ISSET(FTS_STOP) || p->fts_info != FTS_D && p->fts_info != FTS_DNR)
-               return(NULL);
+
+       /* Fatal errors stop here. */
+       if (ISSET(FTS_STOP))
+               return (NULL);
+
+       /* Return logical hierarchy of user's arguments. */
+       if (p->fts_info == FTS_INIT)
+               return (p->fts_link);
+
+       /*
+        * If not a directory being visited in pre-order, stop here.  Could
+        * allow FTS_DNR, assuming the user has fixed the problem, but the
+        * same effect is available with FTS_AGAIN.
+        */
+       if (p->fts_info != FTS_D /* && p->fts_info != FTS_DNR */)
+               return (NULL);
 
        /* Free up any previous child list. */
        if (sp->fts_child)
                fts_lfree(sp->fts_child);
 
 
        /* Free up any previous child list. */
        if (sp->fts_child)
                fts_lfree(sp->fts_child);
 
+       if (instr == FTS_NAMEONLY) {
+               sp->fts_options |= FTS_NAMEONLY;
+               instr = BNAMES;
+       } else 
+               instr = BCHILD;
+
        /*
         * If using chdir on a relative path and called BEFORE fts_read does
         * its chdir to the root of a traversal, we can lose -- we need to
        /*
         * If using chdir on a relative path and called BEFORE fts_read does
         * its chdir to the root of a traversal, we can lose -- we need to
@@ -444,15 +512,15 @@ fts_children(sp)
         */
        if (p->fts_level != FTS_ROOTLEVEL || p->fts_accpath[0] == '/' ||
            ISSET(FTS_NOCHDIR))
         */
        if (p->fts_level != FTS_ROOTLEVEL || p->fts_accpath[0] == '/' ||
            ISSET(FTS_NOCHDIR))
-               return(sp->fts_child = fts_build(sp, BCHILD));
+               return (sp->fts_child = fts_build(sp, instr));
 
        if ((fd = open(".", O_RDONLY, 0)) < 0)
 
        if ((fd = open(".", O_RDONLY, 0)) < 0)
-               return(NULL);
-       sp->fts_child = fts_build(sp, BCHILD);
+               return (NULL);
+       sp->fts_child = fts_build(sp, instr);
        if (fchdir(fd))
        if (fchdir(fd))
-               return(NULL);
+               return (NULL);
        (void)close(fd);
        (void)close(fd);
-       return(sp->fts_child);
+       return (sp->fts_child);
 }
 
 /*
 }
 
 /*
@@ -467,8 +535,6 @@ fts_children(sp)
  * directories and for any nodes after the directories in the parent node have
  * been found.  This empirically cuts the stat calls by about 2/3.
  */
  * directories and for any nodes after the directories in the parent node have
  * been found.  This empirically cuts the stat calls by about 2/3.
  */
-#define        ISDOT(a)        (a[0] == '.' && (!a[1] || a[1] == '.' && !a[2]))
-
 static FTSENT *
 fts_build(sp, type)
        register FTS *sp;
 static FTSENT *
 fts_build(sp, type)
        register FTS *sp;
@@ -477,9 +543,10 @@ fts_build(sp, type)
        register struct dirent *dp;
        register FTSENT *p, *head;
        register int nitems;
        register struct dirent *dp;
        register FTSENT *p, *head;
        register int nitems;
-       FTSENT *cur;
+       FTSENT *cur, *tail;
        DIR *dirp;
        DIR *dirp;
-       int cderr, descend, len, level, maxlen, nlinks, saved_errno;
+       void *adjaddr;
+       int cderrno, descend, len, level, maxlen, nlinks, saved_errno;
        char *cp;
 
        /* Set current node pointer. */
        char *cp;
 
        /* Set current node pointer. */
@@ -489,10 +556,12 @@ fts_build(sp, type)
         * Open the directory for reading.  If this fails, we're done.
         * If being called from fts_read, set the fts_info field.
         */
         * Open the directory for reading.  If this fails, we're done.
         * If being called from fts_read, set the fts_info field.
         */
-       if (!(dirp = opendir(cur->fts_accpath))) {
-               if (type == BREAD)
+       if ((dirp = opendir(cur->fts_accpath)) == NULL) {
+               if (type == BREAD) {
                        cur->fts_info = FTS_DNR;
                        cur->fts_info = FTS_DNR;
-               return(NULL);
+                       cur->fts_errno = errno;
+               }
+               return (NULL);
        }
 
        /*
        }
 
        /*
@@ -500,31 +569,43 @@ fts_build(sp, type)
         * directory if we're cheating on stat calls, 0 if we're not doing
         * any stat calls at all, -1 if we're doing stats on everything.
         */
         * directory if we're cheating on stat calls, 0 if we're not doing
         * any stat calls at all, -1 if we're doing stats on everything.
         */
-       nlinks =
-           ISSET(FTS_NOSTAT) && ISSET(FTS_PHYSICAL) ?
-           cur->fts_statb.st_nlink - (ISSET(FTS_SEEDOT) ? 0 : 2) : -1;
+       if (type == BNAMES)
+               nlinks = 0;
+       else if (ISSET(FTS_NOSTAT) && ISSET(FTS_PHYSICAL))
+               nlinks = cur->fts_nlink - (ISSET(FTS_SEEDOT) ? 0 : 2);
+       else
+               nlinks = -1;
 
 
+#ifdef notdef
+       (void)printf("nlinks == %d (cur: %d)\n", nlinks, cur->fts_nlink);
+       (void)printf("NOSTAT %d PHYSICAL %d SEEDOT %d\n",
+           ISSET(FTS_NOSTAT), ISSET(FTS_PHYSICAL), ISSET(FTS_SEEDOT));
+#endif
        /*
         * If we're going to need to stat anything or we want to descend
        /*
         * If we're going to need to stat anything or we want to descend
-        * and stay in the directory, chdir.  If this fails we keep going.
+        * and stay in the directory, chdir.  If this fails we keep going,
+        * but set a flag so we don't chdir after the post-order visit.
         * We won't be able to stat anything, but we can still return the
         * names themselves.  Note, that since fts_read won't be able to
         * chdir into the directory, it will have to return different path
         * names than before, i.e. "a/b" instead of "b".  Since the node
         * has already been visited in pre-order, have to wait until the
         * We won't be able to stat anything, but we can still return the
         * names themselves.  Note, that since fts_read won't be able to
         * chdir into the directory, it will have to return different path
         * names than before, i.e. "a/b" instead of "b".  Since the node
         * has already been visited in pre-order, have to wait until the
-        * post-order visit to return the error.  This is all fairly nasty.
-        * If a program needed sorted entries or stat information, they had
-        * better be checking FTS_NS on the returned nodes.
+        * post-order visit to return the error.  There is a special case
+        * here, if there was nothing to stat then it's not an error to
+        * not be able to stat.  This is all fairly nasty.  If a program
+        * needed sorted entries or stat information, they had better be
+        * checking FTS_NS on the returned nodes.
         */
        if (nlinks || type == BREAD)
                if (FCHDIR(sp, dirfd(dirp))) {
         */
        if (nlinks || type == BREAD)
                if (FCHDIR(sp, dirfd(dirp))) {
-                       if (type == BREAD)
-                               cur->fts_cderr = errno;
-                       descend = nlinks = 0;
-                       cderr = 1;
+                       if (nlinks && type == BREAD)
+                               cur->fts_errno = errno;
+                       cur->fts_flags |= FTS_DONTCHDIR;
+                       descend = 0;
+                       cderrno = errno;
                } else {
                        descend = 1;
                } else {
                        descend = 1;
-                       cderr = 0;
+                       cderrno = 0;
                }
        else
                descend = 0;
                }
        else
                descend = 0;
@@ -536,8 +617,8 @@ fts_build(sp, type)
         * could do them in fts_read before returning the path, but it's a
         * lot easier here since the length is part of the dirent structure.
         *
         * could do them in fts_read before returning the path, but it's a
         * lot easier here since the length is part of the dirent structure.
         *
-        * If not changing directories set a pointer so that we can just
-        * append each new name into the path.
+        * If not changing directories set a pointer so that can just append
+        * each new name into the path.
         */
        maxlen = sp->fts_pathlen - cur->fts_pathlen - 1;
        len = NAPPEND(cur);
         */
        maxlen = sp->fts_pathlen - cur->fts_pathlen - 1;
        len = NAPPEND(cur);
@@ -549,14 +630,15 @@ fts_build(sp, type)
        level = cur->fts_level + 1;
 
        /* Read the directory, attaching each entry to the `link' pointer. */
        level = cur->fts_level + 1;
 
        /* Read the directory, attaching each entry to the `link' pointer. */
-       for (head = NULL, nitems = 0; dp = readdir(dirp);) {
+       adjaddr = NULL;
+       for (head = tail = NULL, nitems = 0; dp = readdir(dirp);) {
                if (!ISSET(FTS_SEEDOT) && ISDOT(dp->d_name))
                        continue;
 
                if (!ISSET(FTS_SEEDOT) && ISDOT(dp->d_name))
                        continue;
 
-               if (!(p = fts_alloc(sp, dp->d_name, (int)dp->d_namlen)))
+               if ((p = fts_alloc(sp, dp->d_name, (int)dp->d_namlen)) == NULL)
                        goto mem1;
                if (dp->d_namlen > maxlen) {
                        goto mem1;
                if (dp->d_namlen > maxlen) {
-                       if (!fts_path(sp, (int)dp->d_namlen)) {
+                       if (fts_palloc(sp, (size_t)dp->d_namlen)) {
                                /*
                                 * No more memory for path or structures.  Save
                                 * errno, free up the current structure and the
                                /*
                                 * No more memory for path or structures.  Save
                                 * errno, free up the current structure and the
@@ -570,8 +652,9 @@ mem1:                               saved_errno = errno;
                                errno = saved_errno;
                                cur->fts_info = FTS_ERR;
                                SET(FTS_STOP);
                                errno = saved_errno;
                                cur->fts_info = FTS_ERR;
                                SET(FTS_STOP);
-                               return(NULL);
+                               return (NULL);
                        }
                        }
+                       adjaddr = sp->fts_path;
                        maxlen = sp->fts_pathlen - sp->fts_cur->fts_pathlen - 1;
                }
 
                        maxlen = sp->fts_pathlen - sp->fts_cur->fts_pathlen - 1;
                }
 
@@ -579,7 +662,14 @@ mem1:                              saved_errno = errno;
                p->fts_parent = sp->fts_cur;
                p->fts_level = level;
 
                p->fts_parent = sp->fts_cur;
                p->fts_level = level;
 
-               if (nlinks) {
+               if (cderrno) {
+                       if (nlinks) {
+                               p->fts_info = FTS_NS;
+                               p->fts_errno = cderrno;
+                       } else
+                               p->fts_info = FTS_NSOK;
+                       p->fts_accpath = cur->fts_accpath;
+               } else if (nlinks) {
                        /* Build a file name for fts_stat to stat. */
                        if (ISSET(FTS_NOCHDIR)) {
                                p->fts_accpath = p->fts_path;
                        /* Build a file name for fts_stat to stat. */
                        if (ISSET(FTS_NOCHDIR)) {
                                p->fts_accpath = p->fts_path;
@@ -587,23 +677,34 @@ mem1:                             saved_errno = errno;
                        } else
                                p->fts_accpath = p->fts_name;
                        p->fts_info = fts_stat(sp, p, 0);
                        } else
                                p->fts_accpath = p->fts_name;
                        p->fts_info = fts_stat(sp, p, 0);
-                       if (nlinks > 0 && p->fts_info == FTS_D)
+                       if (nlinks > 0 && (p->fts_info == FTS_D ||
+                           p->fts_info == FTS_DC || p->fts_info == FTS_DOT))
                                --nlinks;
                                --nlinks;
-               } else if (cderr) {
-                       p->fts_info = ISSET(FTS_NOSTAT) ? FTS_NSOK : FTS_NS;
-                       p->fts_accpath = cur->fts_accpath;
                } else {
                        p->fts_accpath =
                            ISSET(FTS_NOCHDIR) ? p->fts_path : p->fts_name;
                        p->fts_info = FTS_NSOK;
                }
 
                } else {
                        p->fts_accpath =
                            ISSET(FTS_NOCHDIR) ? p->fts_path : p->fts_name;
                        p->fts_info = FTS_NSOK;
                }
 
-               p->fts_link = head;
-               head = p;
+               /* We walk in directory order so "ls -f" doesn't get upset. */
+               p->fts_link = NULL;
+               if (head == NULL)
+                       head = tail = p;
+               else {
+                       tail->fts_link = p;
+                       tail = p;
+               }
                ++nitems;
        }
        (void)closedir(dirp);
 
                ++nitems;
        }
        (void)closedir(dirp);
 
+       /*
+        * If had to realloc the path, adjust the addresses for the rest
+        * of the tree.
+        */
+       if (adjaddr)
+               fts_padjust(sp, adjaddr);
+
        /*
         * If not changing directories, reset the path back to original
         * state.
        /*
         * If not changing directories, reset the path back to original
         * state.
@@ -617,25 +718,25 @@ mem1:                             saved_errno = errno;
        /*
         * If descended after called from fts_children or called from
         * fts_read and didn't find anything, get back.  If can't get
        /*
         * If descended after called from fts_children or called from
         * fts_read and didn't find anything, get back.  If can't get
-        * back, we're done.
+        * back, done.
         */
        if (descend && (!nitems || type == BCHILD) && CHDIR(sp, "..")) {
                cur->fts_info = FTS_ERR;
                SET(FTS_STOP);
         */
        if (descend && (!nitems || type == BCHILD) && CHDIR(sp, "..")) {
                cur->fts_info = FTS_ERR;
                SET(FTS_STOP);
-               return(NULL);
+               return (NULL);
        }
 
        }
 
-       /* If we didn't find anything, just do the post-order visit */
+       /* If didn't find anything, return NULL. */
        if (!nitems) {
                if (type == BREAD)
                        cur->fts_info = FTS_DP;
        if (!nitems) {
                if (type == BREAD)
                        cur->fts_info = FTS_DP;
-               return(NULL);
+               return (NULL);
        }
 
        /* Sort the entries. */
        if (sp->fts_compar && nitems > 1)
                head = fts_sort(sp, head, nitems);
        }
 
        /* Sort the entries. */
        if (sp->fts_compar && nitems > 1)
                head = fts_sort(sp, head, nitems);
-       return(head);
+       return (head);
 }
 
 static u_short
 }
 
 static u_short
@@ -644,62 +745,72 @@ fts_stat(sp, p, follow)
        register FTSENT *p;
        int follow;
 {
        register FTSENT *p;
        int follow;
 {
+       register FTSENT *t;
+       register dev_t dev;
+       register ino_t ino;
+       struct stat *sbp, sb;
        int saved_errno;
 
        int saved_errno;
 
+       /* If user needs stat info, stat buffer already allocated. */
+       sbp = ISSET(FTS_NOSTAT) ? &sb : p->fts_statp;
+       
        /*
         * If doing a logical walk, or application requested FTS_FOLLOW, do
         * a stat(2).  If that fails, check for a non-existent symlink.  If
        /*
         * If doing a logical walk, or application requested FTS_FOLLOW, do
         * a stat(2).  If that fails, check for a non-existent symlink.  If
-        * fail, return the errno from the stat call.
+        * fail, set the errno from the stat call.
         */
        if (ISSET(FTS_LOGICAL) || follow) {
         */
        if (ISSET(FTS_LOGICAL) || follow) {
-               if (stat(p->fts_accpath, &p->fts_statb)) {
+               if (stat(p->fts_accpath, sbp)) {
                        saved_errno = errno;
                        saved_errno = errno;
-                       if (!lstat(p->fts_accpath, &p->fts_statb)) {
+                       if (!lstat(p->fts_accpath, sbp)) {
                                errno = 0;
                                errno = 0;
-                               return(FTS_SLNONE);
+                               return (FTS_SLNONE);
                        } 
                        } 
-                       errno = saved_errno;
-                       bzero(&p->fts_statb, sizeof(struct stat));
-                       return(FTS_NS);
+                       p->fts_errno = saved_errno;
+                       goto err;
                }
                }
-       } else if (lstat(p->fts_accpath, &p->fts_statb)) {
-               bzero(&p->fts_statb, sizeof(struct stat));
-               return(FTS_NS);
+       } else if (lstat(p->fts_accpath, sbp)) {
+               p->fts_errno = errno;
+err:           bzero(sbp, sizeof(struct stat));
+               return (FTS_NS);
        }
 
        }
 
-       /*
-        * Cycle detection is done as soon as we find a directory.  Detection
-        * is by brute force; if the tree gets deep enough or the number of
-        * symbolic links to directories high enough something faster might
-        * be worthwhile.
-        */
-       if (S_ISDIR(p->fts_statb.st_mode)) {
-               register FTSENT *t;
-               register dev_t dev;
-               register ino_t ino;
-
-               dev = p->fts_statb.st_dev;
-               ino = p->fts_statb.st_ino;
-               for (t = p->fts_parent; t->fts_level > FTS_ROOTLEVEL;
-                   t = t->fts_parent)
-                       if (ino == t->fts_statb.st_ino &&
-                           dev == t->fts_statb.st_dev) {
-                               sp->fts_savelink = p->fts_link;
-                               p->fts_link = t;
-                               return(FTS_DC);
+       if (S_ISDIR(sbp->st_mode)) {
+               /*
+                * Set the device/inode.  Used to find cycles and check for
+                * crossing mount points.  Also remember the link count, used
+                * in fts_build to limit the number of stat calls.  It is
+                * understood that these fields are only referenced if fts_info
+                * is set to FTS_D.
+                */
+               dev = p->fts_dev = sbp->st_dev;
+               ino = p->fts_ino = sbp->st_ino;
+               p->fts_nlink = sbp->st_nlink;
+
+               if (ISDOT(p->fts_name))
+                       return (FTS_DOT);
+
+               /*
+                * Cycle detection is done by brute force when the directory
+                * is first encountered.  If the tree gets deep enough or the
+                * number of symbolic links to directories is high enough,
+                * something faster might be worthwhile.
+                */
+               for (t = p->fts_parent;
+                   t->fts_level >= FTS_ROOTLEVEL; t = t->fts_parent)
+                       if (ino == t->fts_ino && dev == t->fts_dev) {
+                               p->fts_cycle = t;
+                               return (FTS_DC);
                        }
                        }
-               return(FTS_D);
+               return (FTS_D);
        }
        }
-       if (S_ISLNK(p->fts_statb.st_mode))
-               return(FTS_SL);
-       if (S_ISREG(p->fts_statb.st_mode))
-               return(FTS_F);
-       return(FTS_DEFAULT);
+       if (S_ISLNK(sbp->st_mode))
+               return (FTS_SL);
+       if (S_ISREG(sbp->st_mode))
+               return (FTS_F);
+       return (FTS_DEFAULT);
 }
 
 }
 
-#define        R(type, nelem, ptr) \
-       (type *)realloc((void *)ptr, (u_int)((nelem) * sizeof(type)))
-
 static FTSENT *
 fts_sort(sp, head, nitems)
        FTS *sp;
 static FTSENT *
 fts_sort(sp, head, nitems)
        FTS *sp;
@@ -713,14 +824,14 @@ fts_sort(sp, head, nitems)
         * Reassemble the array in the order returned by qsort.  If unable to
         * sort for memory reasons, return the directory entries in their
         * current order.  Allocate enough space for the current needs plus
         * Reassemble the array in the order returned by qsort.  If unable to
         * sort for memory reasons, return the directory entries in their
         * current order.  Allocate enough space for the current needs plus
-        * 40 so we don't realloc one entry at a time.
+        * 40 so don't realloc one entry at a time.
         */
        if (nitems > sp->fts_nitems) {
                sp->fts_nitems = nitems + 40;
         */
        if (nitems > sp->fts_nitems) {
                sp->fts_nitems = nitems + 40;
-               if (!(sp->fts_array =
-                   R(FTSENT *, sp->fts_nitems, sp->fts_array))) {
+               if ((sp->fts_array = realloc(sp->fts_array,
+                   (size_t)(sp->fts_nitems * sizeof(FTSENT *)))) == NULL) {
                        sp->fts_nitems = 0;
                        sp->fts_nitems = 0;
-                       return(head);
+                       return (head);
                }
        }
        for (ap = sp->fts_array, p = head; p; p = p->fts_link)
                }
        }
        for (ap = sp->fts_array, p = head; p; p = p->fts_link)
@@ -729,32 +840,45 @@ fts_sort(sp, head, nitems)
        for (head = *(ap = sp->fts_array); --nitems; ++ap)
                ap[0]->fts_link = ap[1];
        ap[0]->fts_link = NULL;
        for (head = *(ap = sp->fts_array); --nitems; ++ap)
                ap[0]->fts_link = ap[1];
        ap[0]->fts_link = NULL;
-       return(head);
+       return (head);
 }
 
 static FTSENT *
 }
 
 static FTSENT *
-fts_alloc(sp, name, len)
+fts_alloc(sp, name, namelen)
        FTS *sp;
        char *name;
        FTS *sp;
        char *name;
-       register int len;
+       register int namelen;
 {
        register FTSENT *p;
 {
        register FTSENT *p;
+       size_t len;
 
        /*
 
        /*
-        * Variable sized structures; the name is the last element so
-        * we allocate enough extra space after the structure to store
-        * it.
+        * The file name is a variable length array and no stat structure is
+        * necessary if the user has set the nostat bit.  Allocate the FTSENT
+        * structure, the file name and the stat structure in one chunk, but
+        * be careful that the stat structure is reasonably aligned.  Since the
+        * fts_name field is declared to be of size 1, the fts_name pointer is
+        * namelen + 2 before the first possible address of the stat structure.
         */
         */
-       if (!(p = (FTSENT *)malloc((size_t)(sizeof(FTSENT) + len))))
-               return(NULL);
-       bcopy(name, p->fts_name, len + 1);
-       p->fts_namelen = len;
+       len = sizeof(FTSENT) + namelen;
+       if (!ISSET(FTS_NOSTAT))
+               len += sizeof(struct stat) + ALIGNBYTES;
+       if ((p = malloc(len)) == NULL)
+               return (NULL);
+
+       /* Copy the name plus the trailing NULL. */
+       bcopy(name, p->fts_name, namelen + 1);
+
+       if (!ISSET(FTS_NOSTAT))
+               p->fts_statp = (struct stat *)ALIGN(p->fts_name + namelen + 2);
+       p->fts_namelen = namelen;
        p->fts_path = sp->fts_path;
        p->fts_path = sp->fts_path;
+       p->fts_errno = 0;
+       p->fts_flags = 0;
        p->fts_instr = FTS_NOINSTR;
        p->fts_instr = FTS_NOINSTR;
-       p->fts_cderr = 0;
        p->fts_number = 0;
        p->fts_pointer = NULL;
        p->fts_number = 0;
        p->fts_pointer = NULL;
-       return(p);
+       return (p);
 }
 
 static void
 }
 
 static void
@@ -771,17 +895,55 @@ fts_lfree(head)
 }
 
 /*
 }
 
 /*
- * Allow essentially unlimited paths; certain programs (find, rm, ls) need to
- * work on any tree.  Most systems will allow creation of paths much longer
- * than MAXPATHLEN, even though the kernel won't resolve them.  Add an extra
- * 128 bytes to the requested size so that we don't realloc the path 2 bytes
- * at a time.
+ * Allow essentially unlimited paths; find, rm, ls should all work on any tree.
+ * Most systems will allow creation of paths much longer than MAXPATHLEN, even
+ * though the kernel won't resolve them.  Add the size (not just what's needed)
+ * plus 256 bytes so don't realloc the path 2 bytes at a time. 
  */
  */
-static char *
-fts_path(sp, size)
+static int
+fts_palloc(sp, more)
        FTS *sp;
        FTS *sp;
-       int size;
+       size_t more;
 {
 {
-       sp->fts_pathlen += size + 128;
-       return(sp->fts_path = R(char, sp->fts_pathlen, sp->fts_path));
+       sp->fts_pathlen += more + 256;
+       sp->fts_path = realloc(sp->fts_path, (size_t)sp->fts_pathlen);
+       return (sp->fts_path == NULL);
+}
+
+/*
+ * When the path is realloc'd, have to fix all of the pointers in structures
+ * already returned.
+ */
+static void
+fts_padjust(sp, addr)
+       FTS *sp;
+       void *addr;
+{
+       FTSENT *p;
+
+#define        ADJUST(p) {                                                     \
+       (p)->fts_accpath = addr + ((p)->fts_accpath - (p)->fts_path);   \
+       (p)->fts_path = addr;                                           \
+}
+       /* Adjust the current set of children. */
+       for (p = sp->fts_child; p; p = p->fts_link)
+               ADJUST(p);
+
+       /* Adjust the rest of the tree. */
+       for (p = sp->fts_cur; p->fts_level >= FTS_ROOTLEVEL;) {
+               ADJUST(p);
+               p = p->fts_link ? p->fts_link : p->fts_parent;
+       }
+}
+
+static size_t
+fts_maxarglen(argv)
+       char * const *argv;
+{
+       size_t len, max;
+
+       for (max = 0; *argv; ++argv)
+               if ((len = strlen(*argv)) > max)
+                       max = len;
+       return (max);
 }
 }
index 5b2a140..d856fc8 100644 (file)
@@ -31,9 +31,9 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.\"     @(#)glob.3     5.6 (Berkeley) 7/31/91
+.\"     @(#)glob.3     5.7 (Berkeley) 12/2/92
 .\"
 .\"
-.Dd July 31, 1991
+.Dd December 2, 1992
 .Dt GLOB 3
 .Os
 .Sh NAME
 .Dt GLOB 3
 .Os
 .Sh NAME
@@ -209,6 +209,21 @@ Use the backslash
 character for quoting: every occurrence of
 a backslash followed by a character in the pattern is replaced by that
 character, avoiding any special interpretation of the character.
 character for quoting: every occurrence of
 a backslash followed by a character in the pattern is replaced by that
 character, avoiding any special interpretation of the character.
+.It Dv GLOB_ALTDIRFUNC
+The following additional fields in the pglob structure have been
+initialized with alternate functions for glob to use to open, read,
+and close directories and to get stat information on names found
+in those directories.
+.Bd -literal
+       void *(*gl_opendir)();
+       struct dirent *(*gl_readdir)();
+       void (*gl_closedir)();
+       int (*gl_lstat)();
+       int (*gl_stat)();
+.Ed
+.Pp
+This non-standard extension is provided to allow programs such
+as restore to provide globbing from directories stored on tape.
 .El
 .Pp
 If, during the search, a directory is encountered that cannot be opened
 .El
 .Pp
 If, during the search, a directory is encountered that cannot be opened
@@ -343,7 +358,9 @@ The
 function is expected to be
 .St -p1003.2
 compatible with the exception
 function is expected to be
 .St -p1003.2
 compatible with the exception
-that the flag 
+that the flags
+.Dv GLOB_ALTDIRFUNC
+and
 .Dv GLOB_QUOTE
 and the fields 
 .Fa gl_matchc
 .Dv GLOB_QUOTE
 and the fields 
 .Fa gl_matchc
index f53af54..4e48b4b 100644 (file)
@@ -35,7 +35,7 @@
  */
 
 #if defined(LIBC_SCCS) && !defined(lint)
  */
 
 #if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)glob.c     5.12 (Berkeley) 6/24/91";
+static char sccsid[] = "@(#)glob.c     5.18 (Berkeley) 12/4/92";
 #endif /* LIBC_SCCS and not lint */
 
 /*
 #endif /* LIBC_SCCS and not lint */
 
 /*
@@ -50,11 +50,15 @@ static char sccsid[] = "@(#)glob.c  5.12 (Berkeley) 6/24/91";
  *     character might have (except \ at end of string is retained).
  * GLOB_MAGCHAR:
  *     Set in gl_flags if pattern contained a globbing character.
  *     character might have (except \ at end of string is retained).
  * GLOB_MAGCHAR:
  *     Set in gl_flags if pattern contained a globbing character.
+ * GLOB_NOMAGIC:
+ *     Same as GLOB_NOCHECK, but it will only append pattern if it did
+ *     not contain any magic characters.  [Used in csh style globbing]
+ * GLOB_ALTDIRFUNC:
+ *     Use alternately specified directory access functions.
  * gl_matchc:
  *     Number of matches in the current invocation of glob.
  */
 
  * gl_matchc:
  *     Number of matches in the current invocation of glob.
  */
 
-#include <sys/cdefs.h>
 #include <sys/param.h>
 #include <sys/stat.h>
 #include <dirent.h>
 #include <sys/param.h>
 #include <sys/stat.h>
 #include <dirent.h>
@@ -98,10 +102,10 @@ typedef u_short Char;
 
 static int      compare __P((const void *, const void *));
 static void     g_Ctoc __P((Char *, char *));
 
 static int      compare __P((const void *, const void *));
 static void     g_Ctoc __P((Char *, char *));
-static int      g_lstat __P((Char *, struct stat *));
-static DIR     *g_opendir __P((Char *));
+static int      g_lstat __P((Char *, struct stat *, glob_t *));
+static DIR     *g_opendir __P((Char *, glob_t *));
 static Char    *g_strchr __P((Char *, int));
 static Char    *g_strchr __P((Char *, int));
-static int      g_stat __P((Char *, struct stat *));
+static int      g_stat __P((Char *, struct stat *, glob_t *));
 static int      glob1 __P((Char *, glob_t *));
 static int      glob2 __P((Char *, Char *, Char *, glob_t *));
 static int      glob3 __P((Char *, Char *, Char *, Char *, glob_t *));
 static int      glob1 __P((Char *, glob_t *));
 static int      glob2 __P((Char *, Char *, Char *, glob_t *));
 static int      glob3 __P((Char *, Char *, Char *, Char *, glob_t *));
@@ -167,7 +171,6 @@ glob(pattern, flags, errfunc, pglob)
        while ((c = *qpatnext++) != EOS) {
                switch (c) {
                case LBRACKET:
        while ((c = *qpatnext++) != EOS) {
                switch (c) {
                case LBRACKET:
-                       pglob->gl_flags |= GLOB_MAGCHAR;
                        c = *qpatnext;
                        if (c == NOT)
                                ++qpatnext;
                        c = *qpatnext;
                        if (c == NOT)
                                ++qpatnext;
@@ -191,6 +194,7 @@ glob(pattern, flags, errfunc, pglob)
                                        qpatnext += 2;
                                }
                        } while ((c = *qpatnext++) != RBRACKET);
                                        qpatnext += 2;
                                }
                        } while ((c = *qpatnext++) != RBRACKET);
+                       pglob->gl_flags |= GLOB_MAGCHAR;
                        *bufnext++ = M_END;
                        break;
                case QUESTION:
                        *bufnext++ = M_END;
                        break;
                case QUESTION:
@@ -199,7 +203,11 @@ glob(pattern, flags, errfunc, pglob)
                        break;
                case STAR:
                        pglob->gl_flags |= GLOB_MAGCHAR;
                        break;
                case STAR:
                        pglob->gl_flags |= GLOB_MAGCHAR;
-                       *bufnext++ = M_ALL;
+                       /* collapse adjacent stars to one, 
+                        * to avoid exponential behavior
+                        */
+                       if (bufnext == patbuf || bufnext[-1] != M_ALL)
+                           *bufnext++ = M_ALL;
                        break;
                default:
                        *bufnext++ = CHAR(c);
                        break;
                default:
                        *bufnext++ = CHAR(c);
@@ -214,7 +222,15 @@ glob(pattern, flags, errfunc, pglob)
        if ((err = glob1(patbuf, pglob)) != 0)
                return(err);
 
        if ((err = glob1(patbuf, pglob)) != 0)
                return(err);
 
-       if (pglob->gl_pathc == oldpathc && flags & GLOB_NOCHECK) {
+       /*
+        * If there was no match we are going to append the pattern 
+        * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was specified
+        * and the pattern did not contain any magic characters
+        * GLOB_NOMAGIC is there just for compatibility with csh.
+        */
+       if (pglob->gl_pathc == oldpathc && 
+           ((flags & GLOB_NOCHECK) || 
+            ((flags & GLOB_NOMAGIC) && !(pglob->gl_flags & GLOB_MAGCHAR)))) {
                if (!(flags & GLOB_QUOTE)) {
                        Char *dp = compilebuf;
                        const u_char *sp = compilepat;
                if (!(flags & GLOB_QUOTE)) {
                        Char *dp = compilebuf;
                        const u_char *sp = compilepat;
@@ -283,13 +299,13 @@ glob2(pathbuf, pathend, pattern, pglob)
        for (anymeta = 0;;) {
                if (*pattern == EOS) {          /* End of pattern? */
                        *pathend = EOS;
        for (anymeta = 0;;) {
                if (*pattern == EOS) {          /* End of pattern? */
                        *pathend = EOS;
-                       if (g_stat(pathbuf, &sb))
+                       if (g_lstat(pathbuf, &sb, pglob))
                                return(0);
                
                        if (((pglob->gl_flags & GLOB_MARK) &&
                            pathend[-1] != SEP) && (S_ISDIR(sb.st_mode)
                            || (S_ISLNK(sb.st_mode) &&
                                return(0);
                
                        if (((pglob->gl_flags & GLOB_MARK) &&
                            pathend[-1] != SEP) && (S_ISDIR(sb.st_mode)
                            || (S_ISLNK(sb.st_mode) &&
-                           (g_stat(pathbuf, &sb) == 0) &&
+                           (g_stat(pathbuf, &sb, pglob) == 0) &&
                            S_ISDIR(sb.st_mode)))) {
                                *pathend++ = SEP;
                                *pathend = EOS;
                            S_ISDIR(sb.st_mode)))) {
                                *pathend++ = SEP;
                                *pathend = EOS;
@@ -324,25 +340,33 @@ glob3(pathbuf, pathend, pattern, restpattern, pglob)
        glob_t *pglob;
 {
        register struct dirent *dp;
        glob_t *pglob;
 {
        register struct dirent *dp;
+       struct dirent *(*readdirfunc)();
        DIR *dirp;
        int len, err;
        DIR *dirp;
        int len, err;
+       char buf[MAXPATHLEN];
 
        *pathend = EOS;
        errno = 0;
            
 
        *pathend = EOS;
        errno = 0;
            
-       if (!(dirp = g_opendir(pathbuf)))
+       if ((dirp = g_opendir(pathbuf, pglob)) == NULL) {
                /* TODO: don't call for ENOENT or ENOTDIR? */
                /* TODO: don't call for ENOENT or ENOTDIR? */
-               if (pglob->gl_errfunc &&
-                   (*pglob->gl_errfunc)(pathbuf, errno) ||
-                   (pglob->gl_flags & GLOB_ERR))
-                       return(GLOB_ABEND);
-               else
-                       return(0);
+               if (pglob->gl_errfunc) {
+                       g_Ctoc(pathbuf, buf);
+                       if (pglob->gl_errfunc(buf, errno) ||
+                           pglob->gl_flags & GLOB_ERR)
+                               return (GLOB_ABEND);
+               }
+               return(0);
+       }
 
        err = 0;
 
        /* Search directory for matching names. */
 
        err = 0;
 
        /* Search directory for matching names. */
-       while ((dp = readdir(dirp))) {
+       if (pglob->gl_flags & GLOB_ALTDIRFUNC)
+               readdirfunc = pglob->gl_readdir;
+       else
+               readdirfunc = readdir;
+       while ((dp = (*readdirfunc)(dirp))) {
                register u_char *sc;
                register Char *dc;
 
                register u_char *sc;
                register Char *dc;
 
@@ -360,8 +384,10 @@ glob3(pathbuf, pathend, pattern, restpattern, pglob)
                        break;
        }
 
                        break;
        }
 
-       /* TODO: check error from readdir? */
-       (void)closedir(dirp);
+       if (pglob->gl_flags & GLOB_ALTDIRFUNC)
+               (*pglob->gl_closedir)(dirp);
+       else
+               closedir(dirp);
        return(err);
 }
 
        return(err);
 }
 
@@ -431,9 +457,10 @@ match(name, pat, patend)
                case M_ALL:
                        if (pat == patend)
                                return(1);
                case M_ALL:
                        if (pat == patend)
                                return(1);
-                       for (; *name != EOS; ++name)
-                               if (match(name, pat, patend))
-                                       return(1);
+                       do 
+                           if (match(name, pat, patend))
+                                   return(1);
+                       while (*name++ != EOS);
                        return(0);
                case M_ONE:
                        if (*name++ == EOS)
                        return(0);
                case M_ONE:
                        if (*name++ == EOS)
@@ -441,7 +468,8 @@ match(name, pat, patend)
                        break;
                case M_SET:
                        ok = 0;
                        break;
                case M_SET:
                        ok = 0;
-                       k = *name++;
+                       if ((k = *name++) == EOS)
+                               return(0);
                        if (negate_range = ((*pat & M_MASK) == M_NOT))
                                ++pat;
                        while (((c = *pat++) & M_MASK) != M_END)
                        if (negate_range = ((*pat & M_MASK) == M_NOT))
                                ++pat;
                        while (((c = *pat++) & M_MASK) != M_END)
@@ -481,36 +509,47 @@ globfree(pglob)
 }
 
 static DIR *
 }
 
 static DIR *
-g_opendir(str)
+g_opendir(str, pglob)
        register Char *str;
        register Char *str;
+       glob_t *pglob;
 {
        char buf[MAXPATHLEN];
 {
        char buf[MAXPATHLEN];
+       char *dirname;
 
        if (!*str)
 
        if (!*str)
-               return(opendir("."));
-       g_Ctoc(str, buf);
+               strcpy(buf, ".");
+       else
+               g_Ctoc(str, buf);
+       if (pglob->gl_flags & GLOB_ALTDIRFUNC)
+               return((*pglob->gl_opendir)(buf));
        return(opendir(buf));
 }
 
 static int
        return(opendir(buf));
 }
 
 static int
-g_lstat(fn, sb)
+g_lstat(fn, sb, pglob)
        register Char *fn;
        struct stat *sb;
        register Char *fn;
        struct stat *sb;
+       glob_t *pglob;
 {
        char buf[MAXPATHLEN];
 
        g_Ctoc(fn, buf);
 {
        char buf[MAXPATHLEN];
 
        g_Ctoc(fn, buf);
+       if (pglob->gl_flags & GLOB_ALTDIRFUNC)
+               return((*pglob->gl_lstat)(buf, sb));
        return(lstat(buf, sb));
 }
 
 static int
        return(lstat(buf, sb));
 }
 
 static int
-g_stat(fn, sb)
+g_stat(fn, sb, pglob)
        register Char *fn;
        struct stat *sb;
        register Char *fn;
        struct stat *sb;
+       glob_t *pglob;
 {
        char buf[MAXPATHLEN];
 
        g_Ctoc(fn, buf);
 {
        char buf[MAXPATHLEN];
 
        g_Ctoc(fn, buf);
+       if (pglob->gl_flags & GLOB_ALTDIRFUNC)
+               return((*pglob->gl_stat)(buf, sb));
        return(stat(buf, sb));
 }
 
        return(stat(buf, sb));
 }
 
@@ -544,13 +583,13 @@ qprintf(s)
        register Char *p;
 
        for (p = s; *p; p++)
        register Char *p;
 
        for (p = s; *p; p++)
-               (void)printf("%c", *p & 0xff);
+               (void)printf("%c", CHAR(*p));
        (void)printf("\n");
        for (p = s; *p; p++)
                (void)printf("%c", *p & M_PROTECT ? '"' : ' ');
        (void)printf("\n");
        for (p = s; *p; p++)
        (void)printf("\n");
        for (p = s; *p; p++)
                (void)printf("%c", *p & M_PROTECT ? '"' : ' ');
        (void)printf("\n");
        for (p = s; *p; p++)
-               (void)printf("%c", *p & M_META ? '_' : ' ');
+               (void)printf("%c", ismeta(*p) ? '_' : ' ');
        (void)printf("\n");
 }
 #endif
        (void)printf("\n");
 }
 #endif
index 59212a7..09d8ae8 100644 (file)
  */
 
 #if defined(LIBC_SCCS) && !defined(lint)
  */
 
 #if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)syslog.c   5.34 (Berkeley) 6/26/91";
+static char sccsid[] = "@(#)syslog.c   5.36 (Berkeley) 10/4/92";
 #endif /* LIBC_SCCS and not lint */
 
 #include <sys/types.h>
 #include <sys/socket.h>
 #endif /* LIBC_SCCS and not lint */
 
 #include <sys/types.h>
 #include <sys/socket.h>
-#include <sys/file.h>
 #include <sys/syslog.h>
 #include <sys/uio.h>
 #include <sys/syslog.h>
 #include <sys/uio.h>
-#include <sys/errno.h>
 #include <netdb.h>
 #include <netdb.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <paths.h>
+#include <stdio.h>
 #include <string.h>
 #include <string.h>
+#include <time.h>
+#include <unistd.h>
+
 #if __STDC__
 #include <stdarg.h>
 #else
 #include <varargs.h>
 #endif
 #if __STDC__
 #include <stdarg.h>
 #else
 #include <varargs.h>
 #endif
-#include <time.h>
-#include <unistd.h>
-#include <paths.h>
-#include <stdio.h>
 
 static int     LogFile = -1;           /* fd for log */
 static int     connected;              /* have done connect */
 
 static int     LogFile = -1;           /* fd for log */
 static int     connected;              /* have done connect */
@@ -93,13 +95,20 @@ vsyslog(pri, fmt, ap)
 {
        register int cnt;
        register char *p;
 {
        register int cnt;
        register char *p;
-       time_t now, time();
+       time_t now;
        int fd, saved_errno;
        int fd, saved_errno;
-       char tbuf[2048], fmt_cpy[1024], *stdp, *ctime();
+       char *stdp, tbuf[2048], fmt_cpy[1024];
+
+#define        INTERNALLOG     LOG_ERR|LOG_CONS|LOG_PERROR|LOG_PID
+       /* Check for invalid bits. */
+       if (pri & ~(LOG_PRIMASK|LOG_FACMASK)) {
+               syslog(INTERNALLOG,
+                   "syslog: unknown facility/priority: %x", pri);
+               pri &= LOG_PRIMASK|LOG_FACMASK;
+       }
 
 
-       /* check for invalid bits or no priority set */
-       if (!LOG_PRI(pri) || (pri &~ (LOG_PRIMASK|LOG_FACMASK)) ||
-           !(LOG_MASK(pri) & LogMask))
+       /* Check priority against setlogmask values. */
+       if (!LOG_MASK(LOG_PRI(pri)) & LogMask)
                return;
 
        saved_errno = errno;
                return;
 
        saved_errno = errno;
@@ -224,6 +233,7 @@ closelog()
 }
 
 /* setlogmask -- set the log mask level */
 }
 
 /* setlogmask -- set the log mask level */
+int
 setlogmask(pmask)
        int pmask;
 {
 setlogmask(pmask)
        int pmask;
 {
index ecf0e92..6b83bae 100644 (file)
@@ -1,5 +1,7 @@
-#      @(#)Makefile    5.3 (Berkeley) 5/11/90
+#      @(#)Makefile    5.4 (Berkeley) 3/1/92
 
 PROG=  du
 
 PROG=  du
+SRCS=  du.c getbsize.c
+.PATH: ${.CURDIR}/../../bin/df
 
 .include <bsd.prog.mk>
 
 .include <bsd.prog.mk>
index 07c754b..2ff6b5b 100644 (file)
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.\"     @(#)du.1       6.13 (Berkeley) 6/20/91
+.\"    @(#)du.1        6.15 (Berkeley) 3/1/92
 .\"
 .\"
-.Dd June 20, 1991
+.Dd March 1, 1992
 .Dt DU 1
 .Dt DU 1
-.Os BSD 4.4
+.Os
 .Sh NAME
 .Nm du
 .Nd Display disk usage statistics
 .Sh SYNOPSIS
 .Nm du
 .Op Fl a Li \&| Fl s
 .Sh NAME
 .Nm du
 .Nd Display disk usage statistics
 .Sh SYNOPSIS
 .Nm du
 .Op Fl a Li \&| Fl s
-.Op Fl kx
+.Op Fl x
 .Op Ar file ...
 .Sh DESCRIPTION
 The
 .Op Ar file ...
 .Sh DESCRIPTION
 The
@@ -50,22 +50,15 @@ and for each directory in the file hierarchy rooted in each directory
 argument.
 If no file is specified, the block usage of the hierarchy rooted in
 the current directory is displayed.
 argument.
 If no file is specified, the block usage of the hierarchy rooted in
 the current directory is displayed.
+The number of blocks are in the same units as that returned by the
+.Xr stat 2
+system call, i.e. 512-byte blocks.
+Partial numbers of blocks are rounded up.
 .Pp
 The options are as follows:
 .Bl -tag -width Ds
 .It Fl a
 Display an entry for each file in the file hierarchy.
 .Pp
 The options are as follows:
 .Bl -tag -width Ds
 .It Fl a
 Display an entry for each file in the file hierarchy.
-.It Fl k
-By default,
-.Nm du
-displays the number of blocks as returned by the
-.Xr stat  2
-system call, i.e. 512-byte blocks.
-If the
-.Fl k
-flag is specified, the number displayed is the number of 1024-byte
-blocks.
-Partial numbers of blocks are rounded up.
 .It Fl s
 Display only the grand total for the specified files.
 .It Fl x
 .It Fl s
 Display only the grand total for the specified files.
 .It Fl x
@@ -81,11 +74,18 @@ Files having multiple hard links are counted (and displayed) a single
 time per
 .Nm du
 execution.
 time per
 .Nm du
 execution.
+.Sh ENVIRONMENTAL VARIABLES
+.Bl -tag -width BLOCKSIZE
+.It Ev BLOCKSIZE
+If the environmental variable
+.Ev BLOCKSIZE
+is set, the block counts will be displayed in units of that size block.
+.El
 .Sh SEE ALSO
 .Xr df 1 ,
 .Xr quot 8
 .Sh HISTORY
 A
 .Sh SEE ALSO
 .Xr df 1 ,
 .Xr quot 8
 .Sh HISTORY
 A
-.Nm
+.Nm du
 command appeared in
 .At v6 .
 command appeared in
 .At v6 .
index fd3babf..3d0ce60 100644 (file)
@@ -41,7 +41,7 @@ char copyright[] =
 #endif /* not lint */
 
 #ifndef lint
 #endif /* not lint */
 
 #ifndef lint
-static char sccsid[] = "@(#)du.c       5.12 (Berkeley) 6/20/91";
+static char sccsid[] = "@(#)du.c       5.17 (Berkeley) 5/20/92";
 #endif /* not lint */
 
 #include <sys/param.h>
 #endif /* not lint */
 
 #include <sys/param.h>
@@ -53,29 +53,30 @@ static char sccsid[] = "@(#)du.c    5.12 (Berkeley) 6/20/91";
 #include <string.h>
 #include <stdlib.h>
 
 #include <string.h>
 #include <stdlib.h>
 
+void    err __P((const char *, ...));
+char   *getbsize __P((char *, int *, long *));
+int     linkchk __P((FTSENT *));
+void    usage __P((void));
+
 main(argc, argv)
        int argc;
 main(argc, argv)
        int argc;
-       char **argv;
+       char *argv[];
 {
 {
-       extern int optind;
        register FTS *fts;
        register FTSENT *p;
        register FTS *fts;
        register FTSENT *p;
-       register int kvalue, listdirs, listfiles;
-       int aflag, ch, ftsoptions, sflag;
+       register int listdirs, listfiles;
+       long blocksize;
+       int aflag, ch, ftsoptions, notused, sflag;
        char **save;
 
        ftsoptions = FTS_PHYSICAL;
        char **save;
 
        ftsoptions = FTS_PHYSICAL;
-       kvalue = 0;
        save = argv;
        aflag = sflag = 0;
        save = argv;
        aflag = sflag = 0;
-       while ((ch = getopt(argc, argv, "aksx")) != EOF)
+       while ((ch = getopt(argc, argv, "asx")) != EOF)
                switch(ch) {
                case 'a':
                        aflag = 1;
                        break;
                switch(ch) {
                case 'a':
                        aflag = 1;
                        break;
-               case 'k':
-                       kvalue = 1;
-                       break;
                case 's':
                        sflag = 1;
                        break;
                case 's':
                        sflag = 1;
                        break;
@@ -105,10 +106,11 @@ main(argc, argv)
                argv[1] = NULL;
        }
 
                argv[1] = NULL;
        }
 
-       if (!(fts = fts_open(argv, ftsoptions, (int (*)())NULL))) {
-               (void)fprintf(stderr, "du: %s.\n", strerror(errno));
-               exit(1);
-       }
+       (void)getbsize("du", &notused, &blocksize);
+       blocksize /= 512;
+
+       if ((fts = fts_open(argv, ftsoptions, NULL)) == NULL)
+               err("%s", strerror(errno));
 
        while (p = fts_read(fts))
                switch(p->fts_info) {
 
        while (p = fts_read(fts))
                switch(p->fts_info) {
@@ -116,22 +118,22 @@ main(argc, argv)
                        break;
                case FTS_DP:
                        p->fts_parent->fts_number += 
                        break;
                case FTS_DP:
                        p->fts_parent->fts_number += 
-                           p->fts_number += p->fts_statb.st_blocks;
+                           p->fts_number += p->fts_statp->st_blocks;
                        /*
                         * If listing each directory, or not listing files
                         * or directories and this is post-order of the
                         * root of a traversal, display the total.
                         */
                        if (listdirs || !listfiles && !p->fts_level)
                        /*
                         * If listing each directory, or not listing files
                         * or directories and this is post-order of the
                         * root of a traversal, display the total.
                         */
                        if (listdirs || !listfiles && !p->fts_level)
-                               (void)printf("%ld\t%s\n", kvalue ?
-                                   howmany(p->fts_number, 2) :
-                                   p->fts_number, p->fts_path);
+                               (void)printf("%ld\t%s\n",
+                                   howmany(p->fts_number, blocksize),
+                                   p->fts_path);
                        break;
                case FTS_DNR:
                case FTS_ERR:
                case FTS_NS:
                        (void)fprintf(stderr,
                        break;
                case FTS_DNR:
                case FTS_ERR:
                case FTS_NS:
                        (void)fprintf(stderr,
-                           "du: %s: %s.\n", p->fts_path, strerror(errno));
+                           "du: %s: %s\n", p->fts_path, strerror(errno));
                        break;
                case FTS_SL:
                        if (p->fts_level == FTS_ROOTLEVEL) {
                        break;
                case FTS_SL:
                        if (p->fts_level == FTS_ROOTLEVEL) {
@@ -140,18 +142,20 @@ main(argc, argv)
                        }
                        /* FALLTHROUGH */
                default:
                        }
                        /* FALLTHROUGH */
                default:
-                       if (p->fts_statb.st_nlink > 1 && linkchk(p))
+                       if (p->fts_statp->st_nlink > 1 && linkchk(p))
                                break;
                        /*
                         * If listing each file, or a non-directory file was
                         * the root of a traversal, display the total.
                         */
                        if (listfiles || !p->fts_level)
                                break;
                        /*
                         * If listing each file, or a non-directory file was
                         * the root of a traversal, display the total.
                         */
                        if (listfiles || !p->fts_level)
-                               (void)printf("%ld\t%s\n", kvalue ?
-                                   howmany(p->fts_statb.st_blocks, 2) :
-                                   p->fts_statb.st_blocks, p->fts_path);
-                       p->fts_parent->fts_number += p->fts_statb.st_blocks;
+                               (void)printf("%ld\t%s\n",
+                                   howmany(p->fts_statp->st_blocks, blocksize),
+                                   p->fts_path);
+                       p->fts_parent->fts_number += p->fts_statp->st_blocks;
                }
                }
+       if (errno)
+               err("%s", strerror(errno));
        exit(0);
 }
 
        exit(0);
 }
 
@@ -160,6 +164,7 @@ typedef struct _ID {
        ino_t   inode;
 } ID;
 
        ino_t   inode;
 } ID;
 
+int
 linkchk(p)
        register FTSENT *p;
 {
 linkchk(p)
        register FTSENT *p;
 {
@@ -169,26 +174,54 @@ linkchk(p)
        register ino_t ino;
        register dev_t dev;
 
        register ino_t ino;
        register dev_t dev;
 
-       ino = p->fts_statb.st_ino;
-       dev = p->fts_statb.st_dev;
+       ino = p->fts_statp->st_ino;
+       dev = p->fts_statp->st_dev;
        if (start = files)
                for (fp = start + nfiles - 1; fp >= start; --fp)
                        if (ino == fp->inode && dev == fp->dev)
                                return(1);
 
        if (start = files)
                for (fp = start + nfiles - 1; fp >= start; --fp)
                        if (ino == fp->inode && dev == fp->dev)
                                return(1);
 
-       if (nfiles == maxfiles && !(files = (ID *)realloc((char *)files,
-           (u_int)(sizeof(ID) * (maxfiles += 128))))) {
-               (void)fprintf(stderr, "du: %s\n", strerror(errno));
-               exit(1);
-       }
+       if (nfiles == maxfiles && (files = realloc((char *)files,
+           (u_int)(sizeof(ID) * (maxfiles += 128)))) == NULL)
+               err("%s", strerror(errno));
        files[nfiles].inode = ino;
        files[nfiles].dev = dev;
        ++nfiles;
        return(0);
 }
 
        files[nfiles].inode = ino;
        files[nfiles].dev = dev;
        ++nfiles;
        return(0);
 }
 
+void
 usage()
 {
 usage()
 {
-       (void)fprintf(stderr, "usage: du [-a | -s] [-kx] [file ...]\n");
+       (void)fprintf(stderr, "usage: du [-a | -s] [-x] [file ...]\n");
+       exit(1);
+}
+
+#if __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+void
+#if __STDC__
+err(const char *fmt, ...)
+#else
+err(fmt, va_alist)
+       char *fmt;
+        va_dcl
+#endif
+{
+       va_list ap;
+#if __STDC__
+       va_start(ap, fmt);
+#else
+       va_start(ap);
+#endif
+       (void)fprintf(stderr, "du: ");
+       (void)vfprintf(stderr, fmt, ap);
+       va_end(ap);
+       (void)fprintf(stderr, "\n");
        exit(1);
        exit(1);
+       /* NOTREACHED */
 }
 }
index 7fc747b..a541970 100644 (file)
@@ -1,4 +1,4 @@
-#      @(#)Makefile    5.2 (Berkeley) 5/24/91
+#      @(#)Makefile    5.3 (Berkeley) 8/19/91
 
 PROG=  find
 SRCS=  find.c function.c ls.c main.c misc.c operator.c option.c
 
 PROG=  find
 SRCS=  find.c function.c ls.c main.c misc.c operator.c option.c
index 750d633..beb5229 100644 (file)
@@ -30,7 +30,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- *     @(#)extern.h    5.2 (Berkeley) 5/24/91
+ *     @(#)extern.h    5.3 (Berkeley) 7/19/91
  */
 
 #include <sys/cdefs.h>
  */
 
 #include <sys/cdefs.h>
@@ -62,6 +62,7 @@ PLAN  *c_name __P((char *));
 PLAN   *c_newer __P((char *));
 PLAN   *c_nogroup __P((void));
 PLAN   *c_nouser __P((void));
 PLAN   *c_newer __P((char *));
 PLAN   *c_nogroup __P((void));
 PLAN   *c_nouser __P((void));
+PLAN   *c_path __P((char *));
 PLAN   *c_perm __P((char *));
 PLAN   *c_print __P((void));
 PLAN   *c_prune __P((void));
 PLAN   *c_perm __P((char *));
 PLAN   *c_print __P((void));
 PLAN   *c_prune __P((void));
index 9c8cb08..2f900b3 100644 (file)
@@ -32,9 +32,9 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.\"    @(#)find.1      6.29 (Berkeley) 7/29/91
+.\"    @(#)find.1      6.30 (Berkeley) 2/27/92
 .\"
 .\"
-.Dd July 29, 1991
+.Dd February 27, 1992
 .Dt FIND 1
 .Os
 .Sh NAME
 .Dt FIND 1
 .Os
 .Sh NAME
@@ -145,8 +145,8 @@ was executed.
 .It Ic -fstype Ar type 
 True if the file is contained in a file system of type
 .Ar type .
 .It Ic -fstype Ar type 
 True if the file is contained in a file system of type
 .Ar type .
-Currently supported types are ``local'', ``mfs'', ``nfs'', ``msdos'', ``isofs'',
-``fdesc'', ``kernfs'', ``rdonly'' and ``ufs''.
+Currently supported types are ``local'', ``mfs'', ``nfs'', ``pc'',
+``rdonly'' and ``ufs''.
 The types ``local'' and ``rdonly'' are not specific file system types.
 The former matches any file system physically mounted on the system where
 the
 The types ``local'' and ``rdonly'' are not specific file system types.
 The former matches any file system physically mounted on the system where
 the
@@ -373,10 +373,9 @@ that are newer than ``ttt''.
 .El
 .Sh SEE ALSO
 .Xr chmod 1 ,
 .El
 .Sh SEE ALSO
 .Xr chmod 1 ,
-.Xr sh 1 ,
+.Xr locate 1 ,
 .Xr test 1 ,
 .Xr stat 2 ,
 .Xr test 1 ,
 .Xr stat 2 ,
-.Xr umask 2 ,
 .Xr getpwent 3 ,
 .Xr getgrent 3 ,
 .Xr strmode 3
 .Xr getpwent 3 ,
 .Xr getgrent 3 ,
 .Xr strmode 3
index a332682..a950e1a 100644 (file)
@@ -35,7 +35,7 @@
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)find.c     5.3 (Berkeley) 5/25/91";
+static char sccsid[] = "@(#)find.c     5.5 (Berkeley) 5/5/92";
 #endif /* not lint */
 
 #include <sys/types.h>
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -57,8 +57,6 @@ find_formplan(argv)
        char **argv;
 {
        PLAN *plan, *tail, *new;
        char **argv;
 {
        PLAN *plan, *tail, *new;
-       PLAN *c_print(), *find_create(), *not_squish(), *or_squish();
-       PLAN *paren_squish();
 
        /*
         * for each argument in the command line, determine what kind of node
 
        /*
         * for each argument in the command line, determine what kind of node
@@ -163,6 +161,7 @@ find_execute(plan, paths)
                case FTS_DNR:
                case FTS_ERR:
                case FTS_NS:
                case FTS_DNR:
                case FTS_ERR:
                case FTS_NS:
+                       (void)fflush(stdout);
                        (void)fprintf(stderr, "find: %s: %s\n", 
                            entry->fts_path, strerror(errno));
                        continue;
                        (void)fprintf(stderr, "find: %s: %s\n", 
                            entry->fts_path, strerror(errno));
                        continue;
@@ -176,6 +175,7 @@ find_execute(plan, paths)
 
 #define        BADCH   " \t\n\\'\""
                if (isxargs && strpbrk(entry->fts_path, BADCH)) {
 
 #define        BADCH   " \t\n\\'\""
                if (isxargs && strpbrk(entry->fts_path, BADCH)) {
+                       (void)fflush(stdout);
                        (void)fprintf(stderr,
                            "find: illegal path: %s\n", entry->fts_path);
                        continue;
                        (void)fprintf(stderr,
                            "find: illegal path: %s\n", entry->fts_path);
                        continue;
index 8763f60..1756a78 100644 (file)
@@ -33,7 +33,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- *     @(#)find.h      5.8 (Berkeley) 5/24/91
+ *     @(#)find.h      5.9 (Berkeley) 7/19/91
  */
 
 /* node type */
  */
 
 /* node type */
@@ -41,14 +41,21 @@ enum ntype {
        N_AND = 1,                              /* must start > 0 */
        N_ATIME, N_CLOSEPAREN, N_CTIME, N_DEPTH, N_EXEC, N_EXPR, N_FOLLOW,
        N_FSTYPE, N_GROUP, N_INUM, N_LINKS, N_LS, N_MTIME, N_NAME, N_NEWER,
        N_AND = 1,                              /* must start > 0 */
        N_ATIME, N_CLOSEPAREN, N_CTIME, N_DEPTH, N_EXEC, N_EXPR, N_FOLLOW,
        N_FSTYPE, N_GROUP, N_INUM, N_LINKS, N_LS, N_MTIME, N_NAME, N_NEWER,
-       N_NOGROUP, N_NOT, N_NOUSER, N_OK, N_OPENPAREN, N_OR, N_PERM, N_PRINT,
-       N_PRUNE, N_SIZE, N_TYPE, N_USER, N_XDEV,
+       N_NOGROUP, N_NOT, N_NOUSER, N_OK, N_OPENPAREN, N_OR, N_PATH,
+       N_PERM, N_PRINT, N_PRUNE, N_SIZE, N_TYPE, N_USER, N_XDEV,
 };
 
 /* node definition */
 typedef struct _plandata {
        struct _plandata *next;                 /* next node */
        int (*eval)();                          /* node evaluation function */
 };
 
 /* node definition */
 typedef struct _plandata {
        struct _plandata *next;                 /* next node */
        int (*eval)();                          /* node evaluation function */
+#define        F_EQUAL         1                       /* [acm]time inum links size */
+#define        F_LESSTHAN      2
+#define        F_GREATER       3
+#define        F_NEEDOK        1                       /* exec ok */
+#define        F_MTFLAG        1                       /* fstype */
+#define        F_MTTYPE        2
+#define        F_ATLEAST       1                       /* perm */
        int flags;                              /* private flags */
        enum ntype type;                        /* plan node type */
        union {
        int flags;                              /* private flags */
        enum ntype type;                        /* plan node type */
        union {
@@ -59,6 +66,7 @@ typedef struct _plandata {
                off_t _o_data;                  /* file size */
                time_t _t_data;                 /* time value */
                uid_t _u_data;                  /* uid */
                off_t _o_data;                  /* file size */
                time_t _t_data;                 /* time value */
                uid_t _u_data;                  /* uid */
+               short _mt_data;                 /* mount flags */
                struct _plandata *_p_data[2];   /* PLAN trees */
                struct _ex {
                        char **_e_argv;         /* argv array */
                struct _plandata *_p_data[2];   /* PLAN trees */
                struct _ex {
                        char **_e_argv;         /* argv array */
@@ -67,14 +75,15 @@ typedef struct _plandata {
                } ex;
                char *_a_data[2];               /* array of char pointers */
                char *_c_data;                  /* char pointer */
                } ex;
                char *_a_data[2];               /* array of char pointers */
                char *_c_data;                  /* char pointer */
-               int _m_flags;                   /* mount flage for fstype */
        } p_un;
        } p_un;
+} PLAN;
 #define        a_data  p_un._a_data
 #define        c_data  p_un._c_data
 #define        i_data  p_un._i_data
 #define        g_data  p_un._g_data
 #define        l_data  p_un._l_data
 #define        m_data  p_un._m_data
 #define        a_data  p_un._a_data
 #define        c_data  p_un._c_data
 #define        i_data  p_un._i_data
 #define        g_data  p_un._g_data
 #define        l_data  p_un._l_data
 #define        m_data  p_un._m_data
+#define        mt_data p_un._mt_data
 #define        o_data  p_un._o_data
 #define        p_data  p_un._p_data
 #define        t_data  p_un._t_data
 #define        o_data  p_un._o_data
 #define        p_data  p_un._p_data
 #define        t_data  p_un._t_data
@@ -82,7 +91,5 @@ typedef struct _plandata {
 #define        e_argv  p_un.ex._e_argv
 #define        e_orig  p_un.ex._e_orig
 #define        e_len   p_un.ex._e_len
 #define        e_argv  p_un.ex._e_argv
 #define        e_orig  p_un.ex._e_orig
 #define        e_len   p_un.ex._e_len
-#define m_flags        p_un._m_flags
-} PLAN;
 
 #include "extern.h"
 
 #include "extern.h"
index f7eb8fd..1708b7c 100644 (file)
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)function.c 5.17 (Berkeley) 5/24/91";
+static char sccsid[] = "@(#)function.c 5.20 (Berkeley) 1/27/92";
 #endif /* not lint */
 
 #include <sys/param.h>
 #endif /* not lint */
 
 #include <sys/param.h>
+#include <sys/ucred.h>
 #include <sys/stat.h>
 #include <sys/wait.h>
 #include <sys/mount.h>
 #include <sys/stat.h>
 #include <sys/wait.h>
 #include <sys/mount.h>
@@ -47,24 +48,20 @@ static char sccsid[] = "@(#)function.c      5.17 (Berkeley) 5/24/91";
 #include <pwd.h>
 #include <fts.h>
 #include <unistd.h>
 #include <pwd.h>
 #include <fts.h>
 #include <unistd.h>
+#include <fnmatch.h>
 #include <tzfile.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <tzfile.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <fnmatch.h>
 #include "find.h"
 
 #include "find.h"
 
-#define        FIND_EQUAL      0
-#define        FIND_LESSTHAN   1
-#define        FIND_GREATER    2
-
 #define        COMPARE(a, b) { \
        switch(plan->flags) { \
 #define        COMPARE(a, b) { \
        switch(plan->flags) { \
-       case FIND_EQUAL: \
+       case F_EQUAL: \
                return(a == b); \
                return(a == b); \
-       case FIND_LESSTHAN: \
+       case F_LESSTHAN: \
                return(a < b); \
                return(a < b); \
-       case FIND_GREATER: \
+       case F_GREATER: \
                return(a > b); \
        } \
        return(0); \
                return(a > b); \
        } \
        return(0); \
@@ -88,14 +85,14 @@ find_parsenum(plan, option, str, endch)
        switch(*str) {
        case '+':
                ++str;
        switch(*str) {
        case '+':
                ++str;
-               plan->flags = FIND_GREATER;
+               plan->flags = F_GREATER;
                break;
        case '-':
                ++str;
                break;
        case '-':
                ++str;
-               plan->flags = FIND_LESSTHAN;
+               plan->flags = F_LESSTHAN;
                break;
        default:
                break;
        default:
-               plan->flags = FIND_EQUAL;
+               plan->flags = F_EQUAL;
                break;
        }
     
                break;
        }
     
@@ -126,7 +123,7 @@ f_atime(plan, entry)
 {
        extern time_t now;
 
 {
        extern time_t now;
 
-       COMPARE((now - entry->fts_statb.st_atime +
+       COMPARE((now - entry->fts_statp->st_atime +
            SECSPERDAY - 1) / SECSPERDAY, plan->t_data);
 }
  
            SECSPERDAY - 1) / SECSPERDAY, plan->t_data);
 }
  
@@ -154,7 +151,7 @@ f_ctime(plan, entry)
 {
        extern time_t now;
 
 {
        extern time_t now;
 
-       COMPARE((now - entry->fts_statb.st_ctime +
+       COMPARE((now - entry->fts_statp->st_ctime +
            SECSPERDAY - 1) / SECSPERDAY, plan->t_data);
 }
  
            SECSPERDAY - 1) / SECSPERDAY, plan->t_data);
 }
  
@@ -220,7 +217,7 @@ f_exec(plan, entry)
                        brace_subst(plan->e_orig[cnt], &plan->e_argv[cnt],
                            entry->fts_path, plan->e_len[cnt]);
 
                        brace_subst(plan->e_orig[cnt], &plan->e_argv[cnt],
                            entry->fts_path, plan->e_len[cnt]);
 
-       if (plan->flags && !queryuser(plan->e_argv))
+       if (plan->flags == F_NEEDOK && !queryuser(plan->e_argv))
                return(0);
 
        switch(pid = vfork()) {
                return(0);
 
        switch(pid = vfork()) {
@@ -261,7 +258,8 @@ c_exec(argvp, isok)
        isoutput = 1;
     
        new = palloc(N_EXEC, f_exec);
        isoutput = 1;
     
        new = palloc(N_EXEC, f_exec);
-       new->flags = isok;
+       if (isok)
+               new->flags = F_NEEDOK;
 
        for (ap = argv = *argvp;; ++ap) {
                if (!*ap)
 
        for (ap = argv = *argvp;; ++ap) {
                if (!*ap)
@@ -321,12 +319,13 @@ f_fstype(plan, entry)
 {
        static dev_t curdev;    /* need a guaranteed illegal dev value */
        static int first = 1;
 {
        static dev_t curdev;    /* need a guaranteed illegal dev value */
        static int first = 1;
-       static struct statfs sb;
+       struct statfs sb;
+       static short val;
        char *p, save[2];
 
        char *p, save[2];
 
-       /* only check when we cross mount point */
-       if (first || curdev != entry->fts_statb.st_dev) {
-               curdev = entry->fts_statb.st_dev;
+       /* Only check when we cross mount point. */
+       if (first || curdev != entry->fts_statp->st_dev) {
+               curdev = entry->fts_statp->st_dev;
 
                /*
                 * Statfs follows symlinks; find wants the link's file system,
 
                /*
                 * Statfs follows symlinks; find wants the link's file system,
@@ -355,9 +354,21 @@ f_fstype(plan, entry)
                }
 
                first = 0;
                }
 
                first = 0;
+               switch(plan->flags) {
+               case F_MTFLAG:
+                       val = sb.f_flags;
+                       break;
+               case F_MTTYPE:
+                       val = sb.f_type;
+                       break;
+               }
+       }
+       switch(plan->flags) {
+       case F_MTFLAG:
+               return(val & plan->mt_data);    
+       case F_MTTYPE:
+               return(val == plan->mt_data);
        }
        }
-       return(plan->flags == MOUNT_NONE ?
-           sb.f_flags & plan->m_flags : sb.f_type == plan->flags);
 }
  
 PLAN *
 }
  
 PLAN *
@@ -370,65 +381,47 @@ c_fstype(arg)
     
        new = palloc(N_FSTYPE, f_fstype);
        switch(*arg) {
     
        new = palloc(N_FSTYPE, f_fstype);
        switch(*arg) {
-       case 'f':
-               if (!strcmp(arg, "fdesc")) {
-#ifdef MOUNT_FDESC
-                       new->flags = MOUNT_FDESC;
-                       return(new);
-#else
-                       err("unknown file type %s", arg);
-#endif
-               }
-               break;
-       case 'i':
-               if (!strcmp(arg, "isofs")) {
-                       new->flags = MOUNT_ISOFS;
-                       return(new);
-               }
-               break;
-       case 'k':
-               if (!strcmp(arg, "kernfs")) {
-#ifdef MOUNT_KERNFS
-                       new->flags = MOUNT_KERNFS;
-                       return(new);
-#else
-                       err("unknown file type %s", arg);
-#endif
-               }
-               break;
        case 'l':
                if (!strcmp(arg, "local")) {
        case 'l':
                if (!strcmp(arg, "local")) {
-                       new->flags = MOUNT_NONE;
-                       new->m_flags = MNT_LOCAL;
+                       new->flags = F_MTFLAG;
+                       new->mt_data = MNT_LOCAL;
                        return(new);
                }
                break;
        case 'm':
                if (!strcmp(arg, "mfs")) {
                        return(new);
                }
                break;
        case 'm':
                if (!strcmp(arg, "mfs")) {
-                       new->flags = MOUNT_MFS;
-                       return(new);
-               }
-               if (!strcmp(arg, "msdos")) {
-                       new->flags = MOUNT_MSDOS;
+                       new->flags = F_MTTYPE;
+                       new->mt_data = MOUNT_MFS;
                        return(new);
                }
                break;
        case 'n':
                if (!strcmp(arg, "nfs")) {
                        return(new);
                }
                break;
        case 'n':
                if (!strcmp(arg, "nfs")) {
-                       new->flags = MOUNT_NFS;
+                       new->flags = F_MTTYPE;
+                       new->mt_data = MOUNT_NFS;
+                       return(new);
+               }
+               break;
+#ifdef PC_FSTYPE
+       case 'p':
+               if (!strcmp(arg, "pc")) {
+                       new->flags = F_MTTYPE;
+                       new->mt_data = MOUNT_PC;
                        return(new);
                }
                break;
                        return(new);
                }
                break;
+#endif
        case 'r':
                if (!strcmp(arg, "rdonly")) {
        case 'r':
                if (!strcmp(arg, "rdonly")) {
-                       new->flags = MOUNT_NONE;
-                       new->m_flags = MNT_RDONLY;
+                       new->flags = F_MTFLAG;
+                       new->mt_data = MNT_RDONLY;
                        return(new);
                }
                break;
        case 'u':
                if (!strcmp(arg, "ufs")) {
                        return(new);
                }
                break;
        case 'u':
                if (!strcmp(arg, "ufs")) {
-                       new->flags = MOUNT_UFS;
+                       new->flags = F_MTTYPE;
+                       new->mt_data = MOUNT_UFS;
                        return(new);
                }
                break;
                        return(new);
                }
                break;
@@ -448,7 +441,7 @@ f_group(plan, entry)
        PLAN *plan;
        FTSENT *entry;
 {
        PLAN *plan;
        FTSENT *entry;
 {
-       return(entry->fts_statb.st_gid == plan->g_data);
+       return(entry->fts_statp->st_gid == plan->g_data);
 }
  
 PLAN *
 }
  
 PLAN *
@@ -483,7 +476,7 @@ f_inum(plan, entry)
        PLAN *plan;
        FTSENT *entry;
 {
        PLAN *plan;
        FTSENT *entry;
 {
-       COMPARE(entry->fts_statb.st_ino, plan->i_data);
+       COMPARE(entry->fts_statp->st_ino, plan->i_data);
 }
  
 PLAN *
 }
  
 PLAN *
@@ -508,7 +501,7 @@ f_links(plan, entry)
        PLAN *plan;
        FTSENT *entry;
 {
        PLAN *plan;
        FTSENT *entry;
 {
-       COMPARE(entry->fts_statb.st_nlink, plan->l_data);
+       COMPARE(entry->fts_statp->st_nlink, plan->l_data);
 }
  
 PLAN *
 }
  
 PLAN *
@@ -534,7 +527,7 @@ f_ls(plan, entry)
        PLAN *plan;
        FTSENT *entry;
 {
        PLAN *plan;
        FTSENT *entry;
 {
-       printlong(entry->fts_path, entry->fts_accpath, &entry->fts_statb);
+       printlong(entry->fts_path, entry->fts_accpath, entry->fts_statp);
        return(1);
 }
  
        return(1);
 }
  
@@ -547,6 +540,35 @@ c_ls()
        return(palloc(N_LS, f_ls));
 }
 
        return(palloc(N_LS, f_ls));
 }
 
+/*
+ * -mtime n functions --
+ *
+ *     True if the difference between the file modification time and the
+ *     current time is n 24 hour periods.
+ */
+f_mtime(plan, entry)
+       PLAN *plan;
+       FTSENT *entry;
+{
+       extern time_t now;
+
+       COMPARE((now - entry->fts_statp->st_mtime + SECSPERDAY - 1) /
+           SECSPERDAY, plan->t_data);
+}
+PLAN *
+c_mtime(arg)
+       char *arg;
+{
+       PLAN *new;
+
+       ftsoptions &= ~FTS_NOSTAT;
+
+       new = palloc(N_MTIME, f_mtime);
+       new->t_data = find_parsenum(new, "-mtime", arg, (char *)NULL);
+       return(new);
+}
+
 /*
  * -name functions --
  *
 /*
  * -name functions --
  *
@@ -557,7 +579,7 @@ f_name(plan, entry)
        PLAN *plan;
        FTSENT *entry;
 {
        PLAN *plan;
        FTSENT *entry;
 {
-       return(!fnmatch(plan->c_data, entry->fts_name, 0));
+       return(!fnmatch(plan->c_data, entry->fts_name, FNM_PATHNAME));
 }
  
 PLAN *
 }
  
 PLAN *
@@ -582,7 +604,7 @@ f_newer(plan, entry)
        PLAN *plan;
        FTSENT *entry;
 {
        PLAN *plan;
        FTSENT *entry;
 {
-       return(entry->fts_statb.st_mtime > plan->t_data);
+       return(entry->fts_statp->st_mtime > plan->t_data);
 }
  
 PLAN *
 }
  
 PLAN *
@@ -614,7 +636,7 @@ f_nogroup(plan, entry)
 {
        char *group_from_gid();
 
 {
        char *group_from_gid();
 
-       return(group_from_gid(entry->fts_statb.st_gid, 1) ? 1 : 0);
+       return(group_from_gid(entry->fts_statp->st_gid, 1) ? 1 : 0);
 }
  
 PLAN *
 }
  
 PLAN *
@@ -638,7 +660,7 @@ f_nouser(plan, entry)
 {
        char *user_from_uid();
 
 {
        char *user_from_uid();
 
-       return(user_from_uid(entry->fts_statb.st_uid, 1) ? 1 : 0);
+       return(user_from_uid(entry->fts_statp->st_uid, 1) ? 1 : 0);
 }
  
 PLAN *
 }
  
 PLAN *
@@ -649,6 +671,30 @@ c_nouser()
        return(palloc(N_NOUSER, f_nouser));
 }
  
        return(palloc(N_NOUSER, f_nouser));
 }
  
+/*
+ * -path functions --
+ *
+ *     True if the path of the filename being examined
+ *     matches pattern using Pattern Matching Notation S3.14
+ */
+f_path(plan, entry)
+       PLAN *plan;
+       FTSENT *entry;
+{
+       return(!fnmatch(plan->c_data, entry->fts_path, FNM_PATHNAME));
+}
+PLAN *
+c_path(pattern)
+       char *pattern;
+{
+       PLAN *new;
+
+       new = palloc(N_NAME, f_path);
+       new->c_data = pattern;
+       return(new);
+}
 /*
  * -perm functions --
  *
 /*
  * -perm functions --
  *
@@ -662,9 +708,9 @@ f_perm(plan, entry)
 {
        mode_t mode;
 
 {
        mode_t mode;
 
-       mode = entry->fts_statb.st_mode &
+       mode = entry->fts_statp->st_mode &
            (S_ISUID|S_ISGID|S_ISTXT|S_IRWXU|S_IRWXG|S_IRWXO);
            (S_ISUID|S_ISGID|S_ISTXT|S_IRWXU|S_IRWXG|S_IRWXO);
-       if (plan->flags)
+       if (plan->flags == F_ATLEAST)
                return((plan->m_data | mode) == mode);
        else
                return(mode == plan->m_data);
                return((plan->m_data | mode) == mode);
        else
                return(mode == plan->m_data);
@@ -683,7 +729,7 @@ c_perm(perm)
        new = palloc(N_PERM, f_perm);
 
        if (*perm == '-') {
        new = palloc(N_PERM, f_perm);
 
        if (*perm == '-') {
-               new->flags = 1;
+               new->flags = F_ATLEAST;
                ++perm;
        }
 
                ++perm;
        }
 
@@ -756,8 +802,8 @@ f_size(plan, entry)
 {
        off_t size;
 
 {
        off_t size;
 
-       size = divsize ? (entry->fts_statb.st_size + FIND_SIZE - 1) /
-           FIND_SIZE : entry->fts_statb.st_size;
+       size = divsize ? (entry->fts_statp->st_size + FIND_SIZE - 1) /
+           FIND_SIZE : entry->fts_statp->st_size;
        COMPARE(size, plan->o_data);
 }
  
        COMPARE(size, plan->o_data);
 }
  
@@ -788,7 +834,7 @@ f_type(plan, entry)
        PLAN *plan;
        FTSENT *entry;
 {
        PLAN *plan;
        FTSENT *entry;
 {
-       return((entry->fts_statb.st_mode & S_IFMT) == plan->m_data);
+       return((entry->fts_statp->st_mode & S_IFMT) == plan->m_data);
 }
  
 PLAN *
 }
  
 PLAN *
@@ -842,7 +888,7 @@ f_user(plan, entry)
        PLAN *plan;
        FTSENT *entry;
 {
        PLAN *plan;
        FTSENT *entry;
 {
-       return(entry->fts_statb.st_uid == plan->u_data);
+       return(entry->fts_statp->st_uid == plan->u_data);
 }
  
 PLAN *
 }
  
 PLAN *
@@ -916,35 +962,6 @@ c_closeparen()
        return(palloc(N_CLOSEPAREN, (int (*)())-1));
 }
  
        return(palloc(N_CLOSEPAREN, (int (*)())-1));
 }
  
-/*
- * -mtime n functions --
- *
- *     True if the difference between the file modification time and the
- *     current time is n 24 hour periods.
- */
-f_mtime(plan, entry)
-       PLAN *plan;
-       FTSENT *entry;
-{
-       extern time_t now;
-
-       COMPARE((now - entry->fts_statb.st_mtime + SECSPERDAY - 1) /
-           SECSPERDAY, plan->t_data);
-}
-PLAN *
-c_mtime(arg)
-       char *arg;
-{
-       PLAN *new;
-
-       ftsoptions &= ~FTS_NOSTAT;
-
-       new = palloc(N_MTIME, f_mtime);
-       new->t_data = find_parsenum(new, "-mtime", arg, (char *)NULL);
-       return(new);
-}
-
 /*
  * ! expression functions --
  *
 /*
  * ! expression functions --
  *
index 114e8ef..cfa12c0 100644 (file)
@@ -32,7 +32,7 @@
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)main.c     5.9 (Berkeley) 5/24/91";
+static char sccsid[] = "@(#)main.c     5.10 (Berkeley) 12/5/91";
 #endif /* not lint */
 
 #include <sys/types.h>
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -109,6 +109,7 @@ main(argc, argv)
                err(".: %s", strerror(errno));
 
        find_execute(find_formplan(argv), start);
                err(".: %s", strerror(errno));
 
        find_execute(find_formplan(argv), start);
+       exit(0);
 }
 
 static void
 }
 
 static void
index 1585582..de3500c 100644 (file)
@@ -35,7 +35,7 @@
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)option.c   5.8 (Berkeley) 6/4/91";
+static char sccsid[] = "@(#)option.c   5.11 (Berkeley) 8/21/91";
 #endif /* not lint */
 
 #include <sys/types.h>
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -57,7 +57,8 @@ typedef struct _option {
        int flags;
 } OPTION;
 
        int flags;
 } OPTION;
 
-OPTION options[] = {
+/* NB: the following table must be sorted lexically. */
+static OPTION options[] = {
        "!",            N_NOT,          c_not,          O_ZERO,
        "(",            N_OPENPAREN,    c_openparen,    O_ZERO,
        ")",            N_CLOSEPAREN,   c_closeparen,   O_ZERO,
        "!",            N_NOT,          c_not,          O_ZERO,
        "(",            N_OPENPAREN,    c_openparen,    O_ZERO,
        ")",            N_CLOSEPAREN,   c_closeparen,   O_ZERO,
@@ -81,6 +82,7 @@ OPTION options[] = {
        "-o",           N_OR,           c_or,           O_ZERO,
        "-ok",          N_OK,           c_exec,         O_ARGVP,
        "-or",          N_OR,           c_or,           O_ZERO,
        "-o",           N_OR,           c_or,           O_ZERO,
        "-ok",          N_OK,           c_exec,         O_ARGVP,
        "-or",          N_OR,           c_or,           O_ZERO,
+       "-path",        N_PATH,         c_path,         O_ARGV,
        "-perm",        N_PERM,         c_perm,         O_ARGV,
        "-print",       N_PRINT,        c_print,        O_ZERO,
        "-prune",       N_PRUNE,        c_prune,        O_ZERO,
        "-perm",        N_PERM,         c_perm,         O_ARGV,
        "-print",       N_PRINT,        c_print,        O_ZERO,
        "-prune",       N_PRUNE,        c_prune,        O_ZERO,
index 4fdee69..176dbea 100644 (file)
@@ -1,7 +1,8 @@
-#      @(#)Makefile    5.4 (Berkeley) 5/25/90
+#      @(#)Makefile    5.6 (Berkeley) 2/19/92
 
 PROG=  mtree
 
 PROG=  mtree
-SRCS=  compare.c create.c mtree.c spec.c verify.c
-.PATH: ${.CURDIR}
+SRCS=  compare.c crc.c create.c misc.c mtree.c spec.c verify.c
+MAN8=  mtree.8
+.PATH: ${.CURDIR}/../../usr.bin/cksum
 
 .include <bsd.prog.mk>
 
 .include <bsd.prog.mk>
index 6de8e14..f33695a 100644 (file)
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)compare.c  5.7 (Berkeley) 5/25/90";
+static char sccsid[] = "@(#)compare.c  5.10 (Berkeley) 3/31/92";
 #endif /* not lint */
 
 #include <sys/param.h>
 #include <sys/stat.h>
 #endif /* not lint */
 
 #include <sys/param.h>
 #include <sys/stat.h>
+#include <fcntl.h>
 #include <fts.h>
 #include <errno.h>
 #include <stdio.h>
 #include <time.h>
 #include <fts.h>
 #include <errno.h>
 #include <stdio.h>
 #include <time.h>
+#include <unistd.h>
 #include "mtree.h"
 #include "mtree.h"
+#include "extern.h"
 
 
+extern int uflag;
+
+static char *ftype __P((u_int));
+
+#define        INDENTNAMELEN   8
 #define        LABEL \
 #define        LABEL \
-       if (!label++) \
-               (void)printf("%s: ", RP(p)); \
+       if (!label++) { \
+               len = printf("%s: ", RP(p)); \
+               if (len > INDENTNAMELEN) { \
+                       tab = "\t"; \
+                       (void)printf("\n"); \
+               } else { \
+                       tab = ""; \
+                       (void)printf("%*s", INDENTNAMELEN - len, ""); \
+               } \
+       }
 
 
+int
 compare(name, s, p)
        char *name;
        register NODE *s;
        register FTSENT *p;
 {
 compare(name, s, p)
        char *name;
        register NODE *s;
        register FTSENT *p;
 {
-       extern int exitval, uflag;
-       int label;
-       char *ftype(), *inotype(), *rlink();
+       extern int uflag;
+       u_long len, val;
+       int fd, label;
+       char *cp, *tab;
 
        label = 0;
        switch(s->type) {
        case F_BLOCK:
 
        label = 0;
        switch(s->type) {
        case F_BLOCK:
-               if (!S_ISBLK(p->fts_statb.st_mode))
+               if (!S_ISBLK(p->fts_statp->st_mode))
                        goto typeerr;
                break;
        case F_CHAR:
                        goto typeerr;
                break;
        case F_CHAR:
-               if (!S_ISCHR(p->fts_statb.st_mode))
+               if (!S_ISCHR(p->fts_statp->st_mode))
                        goto typeerr;
                break;
        case F_DIR:
                        goto typeerr;
                break;
        case F_DIR:
-               if (!S_ISDIR(p->fts_statb.st_mode))
+               if (!S_ISDIR(p->fts_statp->st_mode))
                        goto typeerr;
                break;
        case F_FIFO:
                        goto typeerr;
                break;
        case F_FIFO:
-               if (!S_ISFIFO(p->fts_statb.st_mode))
+               if (!S_ISFIFO(p->fts_statp->st_mode))
                        goto typeerr;
                break;
        case F_FILE:
                        goto typeerr;
                break;
        case F_FILE:
-               if (!S_ISREG(p->fts_statb.st_mode))
+               if (!S_ISREG(p->fts_statp->st_mode))
                        goto typeerr;
                break;
        case F_LINK:
                        goto typeerr;
                break;
        case F_LINK:
-               if (!S_ISLNK(p->fts_statb.st_mode))
+               if (!S_ISLNK(p->fts_statp->st_mode))
                        goto typeerr;
                break;
        case F_SOCK:
                        goto typeerr;
                break;
        case F_SOCK:
-               if (!S_ISFIFO(p->fts_statb.st_mode)) {
+               if (!S_ISSOCK(p->fts_statp->st_mode)) {
 typeerr:               LABEL;
 typeerr:               LABEL;
-                       (void)printf("\n\ttype (%s, %s)",
-                           ftype(s->type), inotype(p->fts_statb.st_mode));
+                       (void)printf("\ttype (%s, %s)\n",
+                           ftype(s->type), inotype(p->fts_statp->st_mode));
                }
                break;
        }
                }
                break;
        }
-       if (s->flags & F_MODE && s->st_mode != (p->fts_statb.st_mode & MBITS)) {
+       /* Set the uid/gid first, then set the mode. */
+       if (s->flags & (F_UID | F_UNAME) && s->st_uid != p->fts_statp->st_uid) {
                LABEL;
                LABEL;
-               (void)printf("\n\tpermissions (%#o, %#o%s",
-                   s->st_mode, p->fts_statb.st_mode & MBITS, uflag ? "" : ")");
+               (void)printf("%suser (%u, %u",
+                   tab, s->st_uid, p->fts_statp->st_uid);
                if (uflag)
                if (uflag)
-                       if (chmod(p->fts_accpath, s->st_mode))
-                               (void)printf(", not modified: %s)",
+                       if (chown(p->fts_accpath, s->st_uid, -1))
+                               (void)printf(", not modified: %s)\n",
                                    strerror(errno));
                        else
                                    strerror(errno));
                        else
-                               (void)printf(", modified)");
+                               (void)printf(", modified)\n");
+               else
+                       (void)printf(")\n");
+               tab = "\t";
        }
        }
-       if (s->flags & F_OWNER && s->st_uid != p->fts_statb.st_uid) {
+       if (s->flags & (F_GID | F_GNAME) && s->st_gid != p->fts_statp->st_gid) {
                LABEL;
                LABEL;
-               (void)printf("\n\towner (%u, %u%s",
-                   s->st_uid, p->fts_statb.st_uid, uflag ? "" : ")");
+               (void)printf("%sgid (%u, %u",
+                   tab, s->st_gid, p->fts_statp->st_gid);
                if (uflag)
                if (uflag)
-                       if (chown(p->fts_accpath, s->st_uid, -1))
+                       if (chown(p->fts_accpath, -1, s->st_gid))
                                (void)printf(", not modified: %s)",
                                    strerror(errno));
                        else
                                (void)printf(", modified)");
                                (void)printf(", not modified: %s)",
                                    strerror(errno));
                        else
                                (void)printf(", modified)");
+               else
+                       (void)printf(")\n");
+               tab = "\t";
        }
        }
-       if (s->flags & F_GROUP && s->st_gid != p->fts_statb.st_gid) {
+       if (s->flags & F_MODE &&
+           s->st_mode != (p->fts_statp->st_mode & MBITS)) {
                LABEL;
                LABEL;
-               (void)printf("\n\tgroup (%u, %u%s",
-                   s->st_gid, p->fts_statb.st_gid, uflag ? "" : ")");
+               (void)printf("%spermissions (%#o, %#o",
+                   tab, s->st_mode, p->fts_statp->st_mode & MBITS);
                if (uflag)
                if (uflag)
-                       if (chown(p->fts_accpath, -1, s->st_gid))
+                       if (chmod(p->fts_accpath, s->st_mode))
                                (void)printf(", not modified: %s)",
                                    strerror(errno));
                        else
                                (void)printf(", modified)");
                                (void)printf(", not modified: %s)",
                                    strerror(errno));
                        else
                                (void)printf(", modified)");
+               else
+                       (void)printf(")\n");
+               tab = "\t";
        }
        if (s->flags & F_NLINK && s->type != F_DIR &&
        }
        if (s->flags & F_NLINK && s->type != F_DIR &&
-           s->st_nlink != p->fts_statb.st_nlink) {
+           s->st_nlink != p->fts_statp->st_nlink) {
                LABEL;
                LABEL;
-               (void)printf("\n\tlink count (%u, %u)",
-                   s->st_nlink, p->fts_statb.st_nlink);
+               (void)printf("%slink count (%u, %u)\n",
+                   tab, s->st_nlink, p->fts_statp->st_nlink);
+               tab = "\t";
        }
        }
-       if (s->flags & F_SIZE && s->st_size != p->fts_statb.st_size) {
+       if (s->flags & F_SIZE && s->st_size != p->fts_statp->st_size) {
                LABEL;
                LABEL;
-               (void)printf("\n\tsize (%ld, %ld)",
-                   s->st_size, p->fts_statb.st_size);
+               (void)printf("%ssize (%ld, %ld)\n",
+                   tab, s->st_size, p->fts_statp->st_size);
+               tab = "\t";
        }
        }
-       if (s->flags & F_SLINK) {
-               char *cp;
-
-               if (strcmp(cp = rlink(name), s->slink)) {
+       if (s->flags & F_TIME && s->st_mtime != p->fts_statp->st_mtime) {
+               LABEL;
+               (void)printf("%smodification time (%.24s, ",
+                   tab, ctime(&s->st_mtime));
+               (void)printf("%.24s)\n", ctime(&p->fts_statp->st_mtime));
+               tab = "\t";
+       }
+       if (s->flags & F_CKSUM)
+               if ((fd = open(p->fts_accpath, O_RDONLY, 0)) < 0) {
                        LABEL;
                        LABEL;
-                       (void)printf("\n\tlink ref (%s, %s)", cp, s->slink);
+                       (void)printf("%scksum: %s: %s\n",
+                           tab, p->fts_accpath, strerror(errno));
+                       tab = "\t";
+               } else if (crc(fd, &val, &len)) {
+                       (void)close(fd);
+                       LABEL;
+                       (void)printf("%scksum: %s: %s\n",
+                           tab, p->fts_accpath, strerror(errno));
+                       tab = "\t";
+               } else {
+                       (void)close(fd);
+                       if (s->cksum != val) {
+                               LABEL;
+                               (void)printf("%scksum (%lu, %lu)\n", 
+                                   tab, s->cksum, val);
+                       }
+                       tab = "\t";
                }
                }
-       }
-       if (s->flags & F_TIME && s->st_mtime != p->fts_statb.st_mtime) {
+       if (s->flags & F_SLINK && strcmp(cp = rlink(name), s->slink)) {
                LABEL;
                LABEL;
-               (void)printf("\n\tmodification time (%.24s, ",
-                   ctime(&s->st_mtime));
-               (void)printf("%.24s)", ctime(&p->fts_statb.st_mtime));
-       }
-       if (label) {
-               exitval = 2;
-               putchar('\n');
+               (void)printf("%slink ref (%s, %s)\n", tab, cp, s->slink);
        }
        }
+       return (label);
 }
 
 char *
 inotype(type)
 }
 
 char *
 inotype(type)
-       mode_t type;
+       u_int type;
 {
        switch(type & S_IFMT) {
        case S_IFBLK:
 {
        switch(type & S_IFMT) {
        case S_IFBLK:
-               return("block");
+               return ("block");
        case S_IFCHR:
        case S_IFCHR:
-               return("char");
+               return ("char");
        case S_IFDIR:
        case S_IFDIR:
-               return("dir");
+               return ("dir");
+       case S_IFIFO:
+               return ("fifo");
        case S_IFREG:
        case S_IFREG:
-               return("file");
+               return ("file");
        case S_IFLNK:
        case S_IFLNK:
-               return("link");
+               return ("link");
        case S_IFSOCK:
        case S_IFSOCK:
-               return("socket");
+               return ("socket");
        default:
        default:
-               return("unknown");
+               return ("unknown");
        }
        /* NOTREACHED */
 }
 
        }
        /* NOTREACHED */
 }
 
-char *
+static char *
 ftype(type)
        u_int type;
 {
        switch(type) {
        case F_BLOCK:
 ftype(type)
        u_int type;
 {
        switch(type) {
        case F_BLOCK:
-               return("block");
+               return ("block");
        case F_CHAR:
        case F_CHAR:
-               return("char");
+               return ("char");
        case F_DIR:
        case F_DIR:
-               return("dir");
+               return ("dir");
        case F_FIFO:
        case F_FIFO:
-               return("fifo");
+               return ("fifo");
        case F_FILE:
        case F_FILE:
-               return("file");
+               return ("file");
        case F_LINK:
        case F_LINK:
-               return("link");
+               return ("link");
        case F_SOCK:
        case F_SOCK:
-               return("socket");
+               return ("socket");
        default:
        default:
-               return("unknown");
+               return ("unknown");
        }
        /* NOTREACHED */
 }
        }
        /* NOTREACHED */
 }
@@ -206,15 +254,11 @@ char *
 rlink(name)
        char *name;
 {
 rlink(name)
        char *name;
 {
-       register int len;
        static char lbuf[MAXPATHLEN];
        static char lbuf[MAXPATHLEN];
+       register int len;
 
 
-       len = readlink(name, lbuf, sizeof(lbuf));
-       if (len == -1) {
-               (void)fprintf(stderr, "mtree: %s: %s.\n",
-                   name, strerror(errno));
-               exit(1);
-       }
+       if ((len = readlink(name, lbuf, sizeof(lbuf))) == -1)
+               err("%s: %s", name, strerror(errno));
        lbuf[len] = '\0';
        lbuf[len] = '\0';
-       return(lbuf);
+       return (lbuf);
 }
 }
index 649da1f..ec21de6 100644 (file)
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)create.c   5.16 (Berkeley) 3/12/91";
+static char sccsid[] = "@(#)create.c   5.19 (Berkeley) 3/2/92";
 #endif /* not lint */
 
 #include <sys/param.h>
 #include <sys/stat.h>
 #include <time.h>
 #endif /* not lint */
 
 #include <sys/param.h>
 #include <sys/stat.h>
 #include <time.h>
+#include <fcntl.h>
 #include <fts.h>
 #include <dirent.h>
 #include <fts.h>
 #include <dirent.h>
+#include <grp.h>
+#include <pwd.h>
 #include <errno.h>
 #include <errno.h>
+#include <unistd.h>
 #include <stdio.h>
 #include "mtree.h"
 #include <stdio.h>
 #include "mtree.h"
+#include "extern.h"
 
 
-#define        LABEL \
-       if (label++) \
-               (void)putchar(' '); \
+#define        INDENTNAMELEN   15
+#define        MAXLINELEN      80
 
 
-int ftsoptions = FTS_PHYSICAL;
+extern int crc_total, ftsoptions;
+extern int dflag, sflag;
+extern u_short keys;
+extern char fullpath[MAXPATHLEN];
 
 
+static gid_t gid;
+static uid_t uid;
+static mode_t mode;
+
+static int     dsort __P((const FTSENT **, const FTSENT **));
+static void    output __P((int *, const char *, ...));
+static int     statd __P((FTS *, FTSENT *, uid_t *, gid_t *, mode_t *));
+static void    statf __P((FTSENT *));
+
+void
 cwalk()
 {
 cwalk()
 {
-       extern int dflag;
        register FTS *t;
        register FTSENT *p;
        register FTS *t;
        register FTSENT *p;
-       register int cnt, label, notset;
        time_t clock;
        time_t clock;
-       uid_t uid;
-       gid_t gid;
-       mode_t mode;
-       int tabs, dsort();
-       char *argv[2];
-       char curp[MAXPATHLEN], *inotype(), *getlogin(), *rlink();
-
-       if (!getwd(curp)) {
-               (void)fprintf(stderr, "mtree: %s\n", curp);
-               exit(1);
-       }
+       char *argv[2], host[MAXHOSTNAMELEN];
+
        (void)time(&clock);
        (void)time(&clock);
-       (void)printf("#\t  fs: %s\n#\t  by: %s\n#\tdate: %s\n",
-           curp, getlogin(), ctime(&clock));
+       (void)gethostname(host, sizeof(host));
+       (void)printf(
+           "#\t   user: %s\n#\tmachine: %s\n#\t   tree: %s\n#\t   date: %s",
+           getlogin(), host, fullpath, ctime(&clock));
 
        argv[0] = ".";
 
        argv[0] = ".";
-       argv[1] = (char *)NULL;
-       if (!(t = fts_open(argv, ftsoptions, dsort))) {
-               (void)fprintf(stderr,
-                   "mtree: fts_open: %s.\n", strerror(errno));
-               exit(1);
-       }
-       while (p = fts_read(t)) {
+       argv[1] = NULL;
+       if ((t = fts_open(argv, ftsoptions, dsort)) == NULL)
+               err("fts_open: %s", strerror(errno));
+       while (p = fts_read(t))
                switch(p->fts_info) {
                case FTS_D:
                switch(p->fts_info) {
                case FTS_D:
-                       if (dflag)
-                               notset = 1;
-                       else
-                               notset =
-                                   statdir(t, p, &uid, &gid, &mode, &tabs);
-                       if (!strcmp(p->fts_name, "."))
-                               continue;
+                       (void)printf("\n# %s\n", p->fts_path);
+                       statd(t, p, &uid, &gid, &mode);
+                       statf(p);
                        break;
                case FTS_DP:
                        break;
                case FTS_DP:
-                       if (p->fts_level <= 0)
-                               continue;
-                       for (cnt = p->fts_level - 1; cnt-- > 0; )
-                               (void)putchar('\t');
-                       (void)printf("..\n");
-                       continue;
+                       if (p->fts_level > 0)
+                               (void)printf("# %s\n..\n\n", p->fts_path);
+                       break;
                case FTS_DNR:
                case FTS_ERR:
                case FTS_NS:
                case FTS_DNR:
                case FTS_ERR:
                case FTS_NS:
-                       (void)fprintf(stderr, "mtree: %s: %s.\n",
-                           p->fts_path, strerror(errno));
-                       continue;
+                       (void)fprintf(stderr,
+                           "mtree: %s: %s\n", p->fts_path, strerror(errno));
+                       break;
                default:
                default:
-                       if (dflag)
-                               continue;
+                       if (!dflag)
+                               statf(p);
+                       break;
+                       
                }
                }
+       (void)fts_close(t);
+       if (sflag && keys & F_CKSUM)
+               (void)fprintf(stderr,
+                   "mtree: %s checksum: %lu\n", fullpath, crc_total);
+}
 
 
-               for (cnt = p->fts_level - 1; cnt-- > 0; )
-                       (void)putchar('\t');
-               (void)printf("%s", p->fts_name);
-               if (p->fts_info == FTS_D)
-                       (void)putchar('\t');
-               else {
-                       if (tabs > 1 && p->fts_namelen < 8)
-                               (void)putchar('\t');
-                       (void)putchar('\t');
-               }
+static void
+statf(p)
+       FTSENT *p;
+{
+       struct group *gr;
+       struct passwd *pw;
+       u_long len, val;
+       int fd, indent;
 
 
-               label = 0;
-               if (!S_ISREG(p->fts_statb.st_mode) || notset) {
-                       LABEL;
-                       (void)printf("type=%s", inotype(p->fts_statb.st_mode));
-               }
-               if (p->fts_statb.st_uid != uid || notset) {
-                       LABEL;
-                       (void)printf("owner=%u", p->fts_statb.st_uid);
-               }
-               if (p->fts_statb.st_gid != gid || notset) {
-                       LABEL;
-                       (void)printf("group=%u", p->fts_statb.st_gid);
-               }
-               if ((p->fts_statb.st_mode & MBITS) != mode || notset) {
-                       LABEL;
-                       (void)printf("mode=%#o", p->fts_statb.st_mode & MBITS);
-               }
-               if (p->fts_statb.st_nlink != 1 || notset) {
-                       LABEL;
-                       (void)printf("nlink=%u", p->fts_statb.st_nlink);
-               }
-               LABEL;
-               (void)printf("size=%ld", p->fts_statb.st_size);
-               LABEL;
-               (void)printf("time=%ld", p->fts_statb.st_mtime);
-
-               if (p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE) {
-                       LABEL;
-                       (void)printf("link=%s", rlink(p->fts_accpath));
-               }
-               (void)putchar('\n');
+       if (S_ISDIR(p->fts_statp->st_mode))
+               indent = printf("%s", p->fts_name); 
+       else
+               indent = printf("    %s", p->fts_name);
+
+       if (indent > INDENTNAMELEN)
+               indent = MAXLINELEN;
+       else
+               indent += printf("%*s", INDENTNAMELEN - indent, "");
+
+       if (!S_ISREG(p->fts_statp->st_mode))
+               output(&indent, "type=%s", inotype(p->fts_statp->st_mode));
+       if (keys & (F_UID | F_UNAME) && p->fts_statp->st_uid != uid)
+               if (keys & F_UNAME && (pw = getpwuid(p->fts_statp->st_uid)))
+                       output(&indent, "uname=%s", pw->pw_name);
+               else /* if (keys & F_UID) */
+                       output(&indent, "uid=%u", p->fts_statp->st_uid);
+       if (keys & (F_GID | F_GNAME) && p->fts_statp->st_gid != gid)
+               if (keys & F_GNAME && (gr = getgrgid(p->fts_statp->st_gid)))
+                       output(&indent, "gid=%s", gr->gr_name);
+               else /* if (keys & F_GID) */
+                       output(&indent, "gid=%u", p->fts_statp->st_gid);
+       if (keys & F_MODE && (p->fts_statp->st_mode & MBITS) != mode)
+               output(&indent, "mode=%#o", p->fts_statp->st_mode & MBITS);
+       if (keys & F_NLINK && p->fts_statp->st_nlink != 1)
+               output(&indent, "nlink=%u", p->fts_statp->st_nlink);
+       if (keys & F_SIZE)
+               output(&indent, "size=%ld", p->fts_statp->st_size);
+       if (keys & F_TIME)
+               output(&indent, "time=%ld", p->fts_statp->st_mtime);
+       if (keys & F_CKSUM && S_ISREG(p->fts_statp->st_mode)) {
+               if ((fd = open(p->fts_accpath, O_RDONLY, 0)) < 0 ||
+                   crc(fd, &val, &len))
+                       err("%s: %s", p->fts_accpath, strerror(errno));
+               (void)close(fd);
+               output(&indent, "cksum=%lu", val);
        }
        }
-       (void)fts_close(t);
+       if (keys & F_SLINK &&
+           (p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE))
+               output(&indent, "link=%s", rlink(p->fts_accpath));
+       (void)putchar('\n');
 }
 
 #define        MAXGID  5000
 #define        MAXUID  5000
 #define        MAXMODE MBITS + 1
 
 }
 
 #define        MAXGID  5000
 #define        MAXUID  5000
 #define        MAXMODE MBITS + 1
 
-statdir(t, parent, puid, pgid, pmode, tabs)
+static int
+statd(t, parent, puid, pgid, pmode)
        FTS *t;
        FTSENT *parent;
        uid_t *puid;
        gid_t *pgid;
        mode_t *pmode;
        FTS *t;
        FTSENT *parent;
        uid_t *puid;
        gid_t *pgid;
        mode_t *pmode;
-       int *tabs;
 {
        register FTSENT *p;
 {
        register FTSENT *p;
-       register gid_t gid;
-       register uid_t uid;
-       register mode_t mode;
+       register gid_t sgid;
+       register uid_t suid;
+       register mode_t smode;
+       struct group *gr;
+       struct passwd *pw;
        gid_t savegid;
        uid_t saveuid;
        mode_t savemode;
        u_short maxgid, maxuid, maxmode, g[MAXGID], u[MAXUID], m[MAXMODE];
 
        gid_t savegid;
        uid_t saveuid;
        mode_t savemode;
        u_short maxgid, maxuid, maxmode, g[MAXGID], u[MAXUID], m[MAXMODE];
 
-       if (!(p = fts_children(t))) {
-               if (errno) {
-                       (void)fprintf(stderr, "mtree: %s: %s.\n",
-                           RP(parent), strerror(errno));
-                       exit(1);
-               }
-               return(1);
+       if ((p = fts_children(t, 0)) == NULL) {
+               if (errno)
+                       err("%s: %s", RP(parent), strerror(errno));
+               return (1);
        }
 
        bzero(g, sizeof(g));
        bzero(u, sizeof(u));
        bzero(m, sizeof(m));
 
        }
 
        bzero(g, sizeof(g));
        bzero(u, sizeof(u));
        bzero(m, sizeof(m));
 
-       *tabs = 1;
        maxuid = maxgid = maxmode = 0;
        for (; p; p = p->fts_link) {
        maxuid = maxgid = maxmode = 0;
        for (; p; p = p->fts_link) {
-               mode = p->fts_statb.st_mode & MBITS;
-               if (mode < MAXMODE && ++m[mode] > maxmode) {
-                       savemode = mode;
-                       maxmode = m[mode];
+               smode = p->fts_statp->st_mode & MBITS;
+               if (smode < MAXMODE && ++m[smode] > maxmode) {
+                       savemode = smode;
+                       maxmode = m[smode];
                }
                }
-               gid = p->fts_statb.st_gid;
-               if (gid < MAXGID && ++g[gid] > maxgid) {
-                       savegid = gid;
-                       maxgid = g[gid];
+               sgid = p->fts_statp->st_gid;
+               if (sgid < MAXGID && ++g[sgid] > maxgid) {
+                       savegid = sgid;
+                       maxgid = g[sgid];
                }
                }
-               uid = p->fts_statb.st_uid;
-               if (uid < MAXUID && ++u[uid] > maxuid) {
-                       saveuid = uid;
-                       maxuid = u[uid];
+               suid = p->fts_statp->st_uid;
+               if (suid < MAXUID && ++u[suid] > maxuid) {
+                       saveuid = suid;
+                       maxuid = u[suid];
                }
                }
-               if (p->fts_namelen > 7)
-                       *tabs = 2;
        }
        }
-       (void)printf("\n/set group=%u mode=%#o nlink=1 owner=%u type=file\n",
-           savegid, savemode, saveuid);
+       (void)printf("/set type=file");
+       if (keys & F_GID)
+               (void)printf(" gid=%u", savegid);
+       if (keys & F_GNAME)
+               if ((gr = getgrgid(savegid)) != NULL)
+                       (void)printf(" gname=%s", gr->gr_name);
+               else
+                       (void)printf(" gid=%u", savegid);
+       if (keys & F_UNAME)
+               if ((pw = getpwuid(saveuid)) != NULL)
+                       (void)printf(" uname=%s", pw->pw_name);
+               else
+                       (void)printf(" uid=%u", saveuid);
+       if (keys & F_UID)
+               (void)printf(" uid=%u", saveuid);
+       if (keys & F_MODE)
+               (void)printf(" mode=%#o", savemode);
+       if (keys & F_NLINK)
+               (void)printf(" nlink=1");
+       (void)printf("\n");
        *puid = saveuid;
        *pgid = savegid;
        *pmode = savemode;
        *puid = saveuid;
        *pgid = savegid;
        *pmode = savemode;
-       return(0);
+       return (0);
 }
 
 }
 
-dsort(p1, p2)
-       FTSENT **p1, **p2;
+static int
+dsort(a, b)
+       const FTSENT **a, **b;
 {
 {
-       register FTSENT *a, *b;
+       if (S_ISDIR((*a)->fts_statp->st_mode)) {
+               if (!S_ISDIR((*b)->fts_statp->st_mode))
+                       return (1);
+       } else if (S_ISDIR((*b)->fts_statp->st_mode))
+               return (-1);
+       return (strcmp((*a)->fts_name, (*b)->fts_name));
+}
 
 
-       a = *p1;
-       b = *p2;
+#if __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
 
 
-       if (S_ISDIR(a->fts_statb.st_mode)) {
-               if (!S_ISDIR(b->fts_statb.st_mode))
-                       return(1);
-       } else if (S_ISDIR(b->fts_statb.st_mode))
-               return(-1);
-       return(strcmp(a->fts_name, b->fts_name));
+void
+#if __STDC__
+output(int *offset, const char *fmt, ...)
+#else
+output(offset, fmt, va_alist)
+       int *offset;
+       char *fmt;
+        va_dcl
+#endif
+{
+       va_list ap;
+       int len;
+       char buf[1024];
+#if __STDC__
+       va_start(ap, fmt);
+#else
+       va_start(ap);
+#endif
+       len = vsnprintf(buf, sizeof(buf), fmt, ap);
+       va_end(ap);
+
+       if (*offset + len > MAXLINELEN - 3) {
+               (void)printf(" \\\n%*s", INDENTNAMELEN, "");
+               *offset = INDENTNAMELEN;
+       }
+       *offset += printf(" %s", buf) + 1;
 }
 }
diff --git a/usr.sbin/mtree/extern.h b/usr.sbin/mtree/extern.h
new file mode 100644 (file)
index 0000000..1593165
--- /dev/null
@@ -0,0 +1,44 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * 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.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ *
+ *     @(#)extern.h    5.2 (Berkeley) 4/17/92
+ */
+
+int     compare __P((char *, NODE *, FTSENT *));
+int     crc __P((int, u_long *, u_long *));
+void    cwalk __P((void));
+void    err __P((const char *, ...));
+char   *inotype __P((u_int));
+u_int   parsekey __P((char *, int *));
+char   *rlink __P((char *));
+NODE   *spec __P((void));
+int     verify __P((void));
diff --git a/usr.sbin/mtree/misc.c b/usr.sbin/mtree/misc.c
new file mode 100644 (file)
index 0000000..4546991
--- /dev/null
@@ -0,0 +1,125 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * 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.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ *
+ *     @(#)misc.c      5.2 (Berkeley) 4/17/92
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fts.h>
+#include <stdio.h>
+#include "mtree.h"
+#include "extern.h"
+
+extern int lineno;
+
+typedef struct _key {
+       char *name;                     /* key name */
+       u_int val;                      /* value */
+
+#define        NEEDVALUE       0x01
+       u_int flags;
+} KEY;
+
+/* NB: the following table must be sorted lexically. */
+static KEY keylist[] = {
+       "cksum",        F_CKSUM,        NEEDVALUE,
+       "gid",          F_GID,          NEEDVALUE,
+       "gname",        F_GNAME,        NEEDVALUE,
+       "ignore",       F_IGN,          0,
+       "link",         F_SLINK,        NEEDVALUE,
+       "mode",         F_MODE,         NEEDVALUE,
+       "nlink",        F_NLINK,        NEEDVALUE,
+       "size",         F_SIZE,         NEEDVALUE,
+       "time",         F_TIME,         NEEDVALUE,
+       "type",         F_TYPE,         NEEDVALUE,
+       "uid",          F_UID,          NEEDVALUE,
+       "uname",        F_UNAME,        NEEDVALUE,
+};
+
+u_int
+parsekey(name, needvaluep)
+       char *name;
+       int *needvaluep;
+{
+       KEY *k, tmp;
+       int keycompare __P((const void *, const void *));
+
+       tmp.name = name;
+       k = (KEY *)bsearch(&tmp, keylist, sizeof(keylist) / sizeof(KEY),
+           sizeof(KEY), keycompare);
+       if (k == NULL)
+               err("unknown keyword %s", name);
+
+       if (needvaluep)
+               *needvaluep = k->flags & NEEDVALUE ? 1 : 0;
+       return (k->val);
+}
+
+int
+keycompare(a, b)
+       const void *a, *b;
+{
+       return (strcmp(((KEY *)a)->name, ((KEY *)b)->name));
+}
+
+#if __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+void
+#if __STDC__
+err(const char *fmt, ...)
+#else
+err(fmt, va_alist)
+       char *fmt;
+        va_dcl
+#endif
+{
+       va_list ap;
+#if __STDC__
+       va_start(ap, fmt);
+#else
+       va_start(ap);
+#endif
+       (void)fprintf(stderr, "mtree: ");
+       (void)vfprintf(stderr, fmt, ap);
+       va_end(ap);
+       (void)fprintf(stderr, "\n");
+       if (lineno)
+               (void)fprintf(stderr,
+                   "mtree: failed at line %d of the specification\n", lineno);
+       exit(1);
+       /* NOTREACHED */
+}
diff --git a/usr.sbin/mtree/mtree.8 b/usr.sbin/mtree/mtree.8
new file mode 100644 (file)
index 0000000..b32a548
--- /dev/null
@@ -0,0 +1,249 @@
+.\" Copyright (c) 1989, 1990 The Regents of the University of California.
+.\" 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.
+.\" 3. All advertising materials mentioning features or use of this software
+.\"    must display the following acknowledgement:
+.\"    This product includes software developed by the University of
+.\"    California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+.\"
+.\"     @(#)mtree.8    5.11 (Berkeley) 12/11/91
+.\"
+.Dd December 11, 1991
+.Dt MTREE 8
+.Os
+.Sh NAME
+.Nm mtree
+.Nd map a directory hierarchy
+.Sh SYNOPSIS
+.Nm mtree
+.Op Fl cderux
+.Op Fl f Ar spec
+.Op Fl K Ar keywords
+.Op Fl k Ar keywords
+.Op Fl p Ar path
+.Op Fl s Ar seed
+.Sh DESCRIPTION
+The utility
+.Nm mtree
+compares the file hierarchy rooted in the current directory against a
+specification read from the standard input.
+Messages are written to the standard output for any files whose
+characteristics do not match the specification's, or which are
+missing from either the file hierarchy or the specification.
+.Pp
+The options are as follows:
+.Bl -tag -width flag
+.It Fl c
+Print a specification for the file hierarchy to the standard output.
+.It Fl d
+Ignore everything except directory type files.
+.It Fl e
+Don't complain about files that are in the file hierarchy, but not in the
+specification.
+.It Fl f
+Read the specification from
+.Ar file  ,
+instead of from the standard input.
+.It Fl K
+Add the specified (whitespace or comma separated) keywords to the current
+set of keywords.
+.It Fl k
+Use the ``type'' keyword plus the specified (whitespace or comma separated)
+keywords instead of the current set of keywords.
+.It Fl p
+Use the file hierarchy rooted in
+.Ar path  ,
+instead of the current directory.
+.It Fl r
+Remove any files in the file hierarchy that are not described in the
+specification.
+.It Fl s
+Display a single checksum to the standard error output that represents all
+of the files for which the keyword
+.Cm cksum
+was specified.
+The checksum is seeded with the specified value.
+.It Fl u
+Modify the owner, group, and permissions of existing files to match
+the specification and create any missing directories.
+User, group, and permissions must all be specified for missing directories
+to be created.
+.It Fl x
+Don't descend below mount points in the file hierarchy.
+.El
+.Pp
+Specifications are mostly composed of ``keywords'', i.e. strings that
+that specify values relating to files.
+No keywords have default values, and if a keyword has no value set, no
+checks based on it are performed.
+.Pp
+Currently supported keywords are as follows:
+.Bl -tag -width Cm
+.It Cm cksum
+The checksum of the file using the default algorithm specified by
+the
+.Xr cksum 1
+utility.
+.It Cm ignore
+Ignore any file hierarchy below this file.
+.It Cm gid
+The file group as a numeric value.
+.It Cm gname
+The file group as a symbolic name.
+.It Cm mode
+The current file's permissions as a numeric (octal) or symbolic
+value.
+.It Cm nlink
+The number of hard links the file is expected to have.
+.It Cm uid
+The file owner as a numeric value.
+.It Cm uname
+The file group as a symbolic name.
+.It Cm size
+The size, in bytes, of the file.
+.It Cm link
+The file the symbolic link is expected to reference.
+.It Cm time
+The last modification time of the file.
+.It Cm type
+The type of the file; may be set to any one of the following:
+.sp
+.Bl -tag -width Cm -compact
+.It Cm block
+block special device
+.It Cm char
+character special device
+.It Cm dir
+directory
+.It Cm fifo
+fifo
+.It Cm file
+regular file
+.It Cm link
+symbolic link
+.It Cm socket
+socket
+.El
+.El
+.Pp
+The default set of keywords are
+.Cm gid ,
+.Cm mode ,
+.Cm nlink ,
+.Cm size ,
+.Cm slink ,
+.Cm time ,
+and
+.Cm uid .
+.Pp
+There are four types of lines in a specification.
+.Pp
+The first type of line sets a global value for a keyword, and consists of
+the string ``/set'' followed by whitespace, followed by sets of keyword/value
+pairs, separated by whitespace.
+Keyword/value pairs consist of a keyword, followed by an equals sign
+(``=''), followed by a value, without whitespace characters.
+Once a keyword has been set, its value remains unchanged until either
+reset or unset.
+.Pp
+The second type of line unsets keywords and consists of the string
+``/unset'', followed by whitespace, followed by one or more keywords,
+separated by whitespace.
+.Pp
+The third type of line is a file specification and consists of a file
+name, followed by whitespace, followed by zero or more whitespace
+separated keyword/value pairs.
+The file name may be preceded by whitespace characters.
+The file name may contain any of the standard file name matching
+characters (``['', ``]'', ``?'' or ``*''), in which case files
+in the hierarchy will be associated with the first pattern that
+they match.
+.Pp
+Each of the keyword/value pairs consist of a keyword, followed by an
+equals sign (``=''), followed by the keyword's value, without
+whitespace characters.
+These values override, without changing, the global value of the
+corresponding keyword.
+.Pp
+All paths are relative.
+Specifying a directory will cause subsequent files to be searched
+for in that directory hierarchy.
+Which brings us to the last type of line in a specification: a line
+containing only the string
+.Dq Nm \&..
+causes the current directory
+path to ascend one level.
+.Pp
+Empty lines and lines whose first non-whitespace character is a hash
+mark (``#'') are ignored.
+.Pp
+The
+.Nm mtree
+utility exits with a status of 0 on success, 1 if any error occurred,
+and 2 if the file hierarchy did not match the specification.
+.Sh EXAMPLES
+To detect system binaries that have been ``trojan horsed'', it is recommended
+that
+.Nm mtree
+be run on the file systems, and a copy of the results stored on a different
+machine, or, at least, in encrypted form.
+The seed for the
+.Fl s
+option should not be an obvious value and the final checksum should not be
+stored on-line under any circumstances!
+Then, periodically,
+.Nm mtree
+should be run against the on-line specifications and the final checksum
+compared with the previous value.
+While it is possible for the bad guys to change the on-line specifications
+to conform to their modified binaries, it shouldn't be possible for them
+to make it produce the same final checksum value.
+If the final checksum value changes, the off-line copies of the specification
+can be used to detect which of the binaries have actually been modified.
+.Pp
+The
+.Fl d
+and
+.Fl u
+options can be used in combination to create directory hierarchies
+for distributions and other such things.
+.Sh FILES
+.Bl -tag -width /etc/mtree -compact
+.It Pa /etc/mtree
+system specification directory
+.El
+.Sh SEE ALSO
+.Xr chmod 1 ,
+.Xr chown 1 ,
+.Xr chgrp 1 ,
+.Xr cksum 1 ,
+.Xr stat 2 ,
+.Xr fts 3 ,
+.Sh HISTORY
+The
+.Nm mtree
+utility appeared in
+.Bx 4.3 Reno .
index a46e4fd..7dea6de 100644 (file)
@@ -38,31 +38,40 @@ char copyright[] =
 #endif /* not lint */
 
 #ifndef lint
 #endif /* not lint */
 
 #ifndef lint
-static char sccsid[] = "@(#)mtree.c    5.8 (Berkeley) 5/25/90";
+static char sccsid[] = "@(#)mtree.c    5.10 (Berkeley) 4/17/92";
 #endif /* not lint */
 
 #include <sys/param.h>
 #include <sys/stat.h>
 #include <errno.h>
 #endif /* not lint */
 
 #include <sys/param.h>
 #include <sys/stat.h>
 #include <errno.h>
+#include <unistd.h>
 #include <stdio.h>
 #include <fts.h>
 #include "mtree.h"
 #include <stdio.h>
 #include <fts.h>
 #include "mtree.h"
+#include "extern.h"
 
 
-NODE *root;
-int exitval;
-int cflag, dflag, eflag, rflag, uflag;
+int crc_total;
 
 
+int ftsoptions = FTS_PHYSICAL;
+int cflag, dflag, eflag, rflag, sflag, uflag;
+u_short keys;
+char fullpath[MAXPATHLEN];
+
+static void usage __P((void));
+
+int
 main(argc, argv)
        int argc;
 main(argc, argv)
        int argc;
-       char **argv;
+       char *argv[];
 {
 {
-       extern int ftsoptions, optind;
+       extern int optind;
        extern char *optarg;
        int ch;
        extern char *optarg;
        int ch;
-       char *dir;
+       char *dir, *p;
 
 
-       dir = (char *)NULL;
-       while ((ch = getopt(argc, argv, "cdef:p:rux")) != EOF)
+       dir = NULL;
+       keys = KEYDEFAULT;
+       while ((ch = getopt(argc, argv, "cdef:K:k:p:rs:ux")) != EOF)
                switch((char)ch) {
                case 'c':
                        cflag = 1;
                switch((char)ch) {
                case 'c':
                        cflag = 1;
@@ -74,11 +83,19 @@ main(argc, argv)
                        eflag = 1;
                        break;
                case 'f':
                        eflag = 1;
                        break;
                case 'f':
-                       if (!(freopen(optarg, "r", stdin))) {
-                               (void)fprintf(stderr,
-                                   "mtree: can't read %s.\n", optarg);
-                               exit(1);
-                       }
+                       if (!(freopen(optarg, "r", stdin)))
+                               err("%s: %s", optarg, strerror(errno));
+                       break;
+               case 'K':
+                       while ((p = strsep(&optarg, " \t,")) != NULL)
+                               if (*p != '\0')
+                                       keys |= parsekey(p, NULL);
+                       break;
+               case 'k':
+                       keys = F_TYPE;
+                       while ((p = strsep(&optarg, " \t,")) != NULL)
+                               if (*p != '\0')
+                                       keys |= parsekey(p, NULL);
                        break;
                case 'p':
                        dir = optarg;
                        break;
                case 'p':
                        dir = optarg;
@@ -86,6 +103,11 @@ main(argc, argv)
                case 'r':
                        rflag = 1;
                        break;
                case 'r':
                        rflag = 1;
                        break;
+               case 's':
+                       sflag = 1;
+                       crc_total = ~strtol(optarg, &p, 0);
+                       if (*p)
+                               err("illegal seed value -- %s", optarg);
                case 'u':
                        uflag = 1;
                        break;
                case 'u':
                        uflag = 1;
                        break;
@@ -97,28 +119,28 @@ main(argc, argv)
                        usage();
                }
        argc -= optind;
                        usage();
                }
        argc -= optind;
+       argv += optind;
+
        if (argc)
                usage();
 
        if (argc)
                usage();
 
-       if (!cflag)
-               spec();
+       if (dir && chdir(dir))
+               err("%s: %s", dir, strerror(errno));
 
 
-       if (dir && chdir(dir)) {
-               (void)fprintf(stderr,
-                   "mtree: %s: %s\n", dir, strerror(errno));
-               exit(1);
-       }
+       if ((cflag || sflag) && !getwd(fullpath))
+               err("%s", fullpath);
 
 
-       if (cflag)
+       if (cflag) {
                cwalk();
                cwalk();
-       else
-               verify();
-       exit(exitval);
+               exit(0);
+       }
+       exit(verify());
 }
 
 }
 
+static void
 usage()
 {
        (void)fprintf(stderr,
 usage()
 {
        (void)fprintf(stderr,
-           "usage: mtree [-cderux] [-p path] [-f spec]\n");
+"usage: mtree [-cderux] [-f spec] [-K key] [-k key] [-p path] [-s seed]\n");
        exit(1);
 }
        exit(1);
 }
index 9dd416e..3c98af2 100644 (file)
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- *     @(#)mtree.h     5.7 (Berkeley) 5/25/90
+ *     @(#)mtree.h     5.9 (Berkeley) 2/19/92
  */
 
 #include <string.h>
 #include <stdlib.h>
 
  */
 
 #include <string.h>
 #include <stdlib.h>
 
+#define        KEYDEFAULT \
+       (F_GID | F_MODE | F_NLINK | F_SIZE | F_SLINK | F_TIME | F_UID)
+
+#define        MISMATCHEXIT    2
+
 typedef struct _node {
        struct _node    *parent, *child;        /* up, down */
        struct _node    *prev, *next;           /* left, right */
 typedef struct _node {
        struct _node    *parent, *child;        /* up, down */
        struct _node    *prev, *next;           /* left, right */
@@ -43,37 +48,41 @@ typedef struct _node {
        time_t  st_mtime;                       /* last modification time */
        u_long  cksum;                          /* check sum */
        char    *slink;                         /* symbolic link reference */
        time_t  st_mtime;                       /* last modification time */
        u_long  cksum;                          /* check sum */
        char    *slink;                         /* symbolic link reference */
-       uid_t   st_uid;                         /* owner */
-       gid_t   st_gid;                         /* group */
+       uid_t   st_uid;                         /* uid */
+       gid_t   st_gid;                         /* gid */
 #define        MBITS   (S_ISUID|S_ISGID|S_ISTXT|S_IRWXU|S_IRWXG|S_IRWXO)
        mode_t  st_mode;                        /* mode */
        nlink_t st_nlink;                       /* link count */
 
 #define        MBITS   (S_ISUID|S_ISGID|S_ISTXT|S_IRWXU|S_IRWXG|S_IRWXO)
        mode_t  st_mode;                        /* mode */
        nlink_t st_nlink;                       /* link count */
 
-#define        F_BLOCK 0x001                           /* block special */
-#define        F_CHAR  0x002                           /* char special */
-#define        F_DIR   0x004                           /* directory */
-#define        F_FIFO  0x008                           /* fifo */
-#define        F_FILE  0x010                           /* regular file */
-#define        F_LINK  0x020                           /* symbolic link */
-#define        F_SOCK  0x040                           /* socket */
-       u_short type;                           /* file type */
-
 #define        F_CKSUM 0x0001                          /* check sum */
 #define        F_DONE  0x0002                          /* directory done */
 #define        F_CKSUM 0x0001                          /* check sum */
 #define        F_DONE  0x0002                          /* directory done */
-#define        F_GROUP 0x0004                          /* group */
-#define        F_IGN   0x0008                          /* ignore */
-#define        F_MAGIC 0x0010                          /* name has magic chars */
-#define        F_MODE  0x0020                          /* mode */
-#define        F_NLINK 0x0040                          /* number of links */
-#define        F_OWNER 0x0080                          /* owner */
+#define        F_GID   0x0004                          /* gid */
+#define        F_GNAME 0x0008                          /* group name */
+#define        F_IGN   0x0010                          /* ignore */
+#define        F_MAGIC 0x0020                          /* name has magic chars */
+#define        F_MODE  0x0040                          /* mode */
+#define        F_NLINK 0x0080                          /* number of links */
 #define        F_SIZE  0x0100                          /* size */
 #define        F_SLINK 0x0200                          /* link count */
 #define        F_TIME  0x0400                          /* modification time */
 #define        F_TYPE  0x0800                          /* file type */
 #define        F_SIZE  0x0100                          /* size */
 #define        F_SLINK 0x0200                          /* link count */
 #define        F_TIME  0x0400                          /* modification time */
 #define        F_TYPE  0x0800                          /* file type */
-#define        F_VISIT 0x1000                          /* file visited */
+#define        F_UID   0x1000                          /* uid */
+#define        F_UNAME 0x2000                          /* user name */
+#define        F_VISIT 0x4000                          /* file visited */
        u_short flags;                          /* items set */
 
        u_short flags;                          /* items set */
 
+#define        F_BLOCK 0x001                           /* block special */
+#define        F_CHAR  0x002                           /* char special */
+#define        F_DIR   0x004                           /* directory */
+#define        F_FIFO  0x008                           /* fifo */
+#define        F_FILE  0x010                           /* regular file */
+#define        F_LINK  0x020                           /* symbolic link */
+#define        F_SOCK  0x040                           /* socket */
+       u_char  type;                           /* file type */
+
        char    name[1];                        /* file name (must be last) */
 } NODE;
 
        char    name[1];                        /* file name (must be last) */
 } NODE;
 
-#define        RP(p)   (p->fts_path + 2)
+#define        RP(p)   \
+       ((p)->fts_path[0] == '.' && (p)->fts_path[1] == '/' ? \
+           (p)->fts_path + 2 : (p)->fts_path)
index 384d593..2fb3286 100644 (file)
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)spec.c     5.14 (Berkeley) 3/2/91";
+static char sccsid[] = "@(#)spec.c     5.17 (Berkeley) 4/17/92";
 #endif /* not lint */
 
 #include <sys/types.h>
 #endif /* not lint */
 
 #include <sys/types.h>
+#include <sys/stat.h>
+#include <fts.h>
 #include <pwd.h>
 #include <grp.h>
 #include <pwd.h>
 #include <grp.h>
-#include <stdio.h>
 #include <errno.h>
 #include <errno.h>
+#include <unistd.h>
+#include <stdio.h>
 #include <ctype.h>
 #include "mtree.h"
 #include <ctype.h>
 #include "mtree.h"
+#include "extern.h"
 
 
-extern NODE *root;                     /* root of the tree */
+int lineno;                            /* Current spec line number. */
 
 
-static int lineno;                     /* current spec line number */
+static void     set __P((char *, NODE *));
+static void     unset __P((char *, NODE *));
 
 
+NODE *
 spec()
 {
        register NODE *centry, *last;
        register char *p;
 spec()
 {
        register NODE *centry, *last;
        register char *p;
-       NODE ginfo, *emalloc();
+       NODE ginfo, *root;
+       int c_cur, c_next;
        char buf[2048];
 
        char buf[2048];
 
-       bzero((void *)&ginfo, sizeof(ginfo));
-       for (lineno = 1; fgets(buf, sizeof(buf), stdin); ++lineno) {
-               if (!(p = index(buf, '\n'))) {
-                       (void)fprintf(stderr,
-                           "mtree: line %d too long.\n", lineno);
-                       exit(1);
+       root = NULL;
+       bzero(&ginfo, sizeof(ginfo));
+       c_cur = c_next = 0;
+       for (lineno = 1; fgets(buf, sizeof(buf), stdin);
+           ++lineno, c_cur = c_next, c_next = 0) {
+               /* Skip empty lines. */
+               if (buf[0] == '\n')
+                       continue;
+
+               /* Find end of line. */
+               if ((p = index(buf, '\n')) == NULL)
+                       err("line %d too long", lineno);
+
+               /* See if next line is continuation line. */
+               if (p[-1] == '\\') {
+                       --p;
+                       c_next = 1;
                }
                }
+
+               /* Null-terminate the line. */
                *p = '\0';
                *p = '\0';
+
+               /* Skip leading whitespace. */
                for (p = buf; *p && isspace(*p); ++p);
                for (p = buf; *p && isspace(*p); ++p);
+
+               /* If nothing but whitespace or comment char, continue. */
                if (!*p || *p == '#')
                        continue;
 
                if (!*p || *p == '#')
                        continue;
 
-               /* grab file name, "$", "set", or "unset" */
-               if (!(p = strtok(p, "\n\t ")))
-                       specerr();
+#ifdef DEBUG
+               (void)fprintf(stderr, "line %d: {%s}\n", lineno, p);
+#endif
+               if (c_cur) {
+                       set(p, centry);
+                       continue;
+               }
+                       
+               /* Grab file name, "$", "set", or "unset". */
+               if ((p = strtok(p, "\n\t ")) == NULL)
+                       err("missing field");
 
                if (p[0] == '/')
                        switch(p[1]) {
                        case 's':
                                if (strcmp(p + 1, "set"))
                                        break;
 
                if (p[0] == '/')
                        switch(p[1]) {
                        case 's':
                                if (strcmp(p + 1, "set"))
                                        break;
-                               set(&ginfo);
+                               set(NULL, &ginfo);
                                continue;
                        case 'u':
                                if (strcmp(p + 1, "unset"))
                                        break;
                                continue;
                        case 'u':
                                if (strcmp(p + 1, "unset"))
                                        break;
-                               unset(&ginfo);
+                               unset(NULL, &ginfo);
                                continue;
                        }
 
                                continue;
                        }
 
-               if (index(p, '/')) {
-                       (void)fprintf(stderr,
-                           "mtree: file names may not contain slashes.\n");
-                       specerr();
-               }
+               if (index(p, '/'))
+                       err("slash character in file name");
 
                if (!strcmp(p, "..")) {
 
                if (!strcmp(p, "..")) {
-                       /* don't go up, if haven't gone down */
+                       /* Don't go up, if haven't gone down. */
                        if (!root)
                        if (!root)
-                               noparent();
+                               goto noparent;
                        if (last->type != F_DIR || last->flags & F_DONE) {
                                if (last == root)
                        if (last->type != F_DIR || last->flags & F_DONE) {
                                if (last == root)
-                                       noparent();
+                                       goto noparent;
                                last = last->parent;
                        }
                        last->flags |= F_DONE;
                        continue;
                                last = last->parent;
                        }
                        last->flags |= F_DONE;
                        continue;
+
+noparent:              err("no parent node");
                }
 
                }
 
-               centry = emalloc(sizeof(NODE) + strlen(p));
+               if ((centry = calloc(1, sizeof(NODE) + strlen(p))) == NULL)
+                       err("%s", strerror(errno));
                *centry = ginfo;
                (void)strcpy(centry->name, p);
 #define        MAGIC   "?*["
                if (strpbrk(p, MAGIC))
                        centry->flags |= F_MAGIC;
                *centry = ginfo;
                (void)strcpy(centry->name, p);
 #define        MAGIC   "?*["
                if (strpbrk(p, MAGIC))
                        centry->flags |= F_MAGIC;
-               set(centry);
+               set(NULL, centry);
 
                if (!root) {
                        last = root = centry;
 
                if (!root) {
                        last = root = centry;
@@ -123,58 +155,68 @@ spec()
                        last = last->next = centry;
                }
        }
                        last = last->next = centry;
                }
        }
+       return (root);
 }
 
 }
 
-set(ip)
+static void
+set(t, ip)
+       char *t;
        register NODE *ip;
 {
        register int type;
        register char *kw, *val;
        register NODE *ip;
 {
        register int type;
        register char *kw, *val;
-       gid_t getgroup();
-       uid_t getowner();
-       long atol(), strtol();
+       struct group *gr;
+       struct passwd *pw;
+       mode_t *m;
+       int value;
+       char *ep;
 
 
-       while (kw = strtok((char *)NULL, "= \t\n")) {
-               ip->flags |= type = key(kw);
-               val = strtok((char *)NULL, " \t\n");
-               if (!val)
-                       specerr();
+       for (; kw = strtok(t, "= \t\n"); t = NULL) {
+               ip->flags |= type = parsekey(kw, &value);
+               if (value && (val = strtok(NULL, " \t\n")) == NULL)
+                       err("missing value");
                switch(type) {
                case F_CKSUM:
                switch(type) {
                case F_CKSUM:
-                       ip->cksum = atol(val);
+                       ip->cksum = strtoul(val, &ep, 10);
+                       if (*ep)
+                               err("invalid checksum %s", val);
+                       break;
+               case F_GID:
+                       ip->st_gid = strtoul(val, &ep, 10);
+                       if (*ep)
+                               err("invalid gid %s", val);
                        break;
                        break;
-               case F_GROUP:
-                       ip->st_gid = getgroup(val);
+               case F_GNAME:
+                       if ((gr = getgrnam(val)) == NULL)
+                           err("unknown group %s", val);
+                       ip->st_gid = gr->gr_gid;
                        break;
                case F_IGN:
                        /* just set flag bit */
                        break;
                        break;
                case F_IGN:
                        /* just set flag bit */
                        break;
-               case F_MODE: {
-                       mode_t *m, *setmode();
-
-                       if (!(m = setmode(val))) {
-                               (void)fprintf(stderr,
-                                   "mtree: invalid file mode %s.\n", val);
-                               specerr();
-                       }
+               case F_MODE:
+                       if ((m = setmode(val)) == NULL)
+                               err("invalid file mode %s", val);
                        ip->st_mode = getmode(m, 0);
                        break;
                        ip->st_mode = getmode(m, 0);
                        break;
-               }
                case F_NLINK:
                case F_NLINK:
-                       ip->st_nlink = atoi(val);
-                       break;
-               case F_OWNER:
-                       ip->st_uid = getowner(val);
+                       ip->st_nlink = strtoul(val, &ep, 10);
+                       if (*ep)
+                               err("invalid link count %s", val);
                        break;
                case F_SIZE:
                        break;
                case F_SIZE:
-                       ip->st_size = atol(val);
+                       ip->st_size = strtoul(val, &ep, 10);
+                       if (*ep)
+                               err("invalid size %s", val);
                        break;
                case F_SLINK:
                        break;
                case F_SLINK:
-                       if (!(ip->slink = strdup(val)))
-                               nomem();
+                       if ((ip->slink = strdup(val)) == NULL)
+                               err("%s", strerror(errno));
                        break;
                case F_TIME:
                        break;
                case F_TIME:
-                       ip->st_mtime = atol(val);
+                       ip->st_mtime = strtoul(val, &ep, 10);
+                       if (*ep)
+                               err("invalid time %s", val);
                        break;
                case F_TYPE:
                        switch(*val) {
                        break;
                case F_TYPE:
                        switch(*val) {
@@ -205,139 +247,30 @@ set(ip)
                                        ip->type = F_SOCK;
                                break;
                        default:
                                        ip->type = F_SOCK;
                                break;
                        default:
-                               (void)fprintf(stderr,
-                                   "mtree: unknown file type %s.\n", val);
-                               specerr();
+                               err("unknown file type %s", val);
                        }
                        break;
                        }
                        break;
+               case F_UID:
+                       ip->st_uid = strtoul(val, &ep, 10);
+                       if (*ep)
+                               err("invalid uid %s", val);
+                       break;
+               case F_UNAME:
+                       if ((pw = getpwnam(val)) == NULL)
+                           err("unknown user %s", val);
+                       ip->st_uid = pw->pw_uid;
+                       break;
                }
        }
 }
 
                }
        }
 }
 
-unset(ip)
+static void
+unset(t, ip)
+       char *t;
        register NODE *ip;
 {
        register char *p;
 
        register NODE *ip;
 {
        register char *p;
 
-       while (p = strtok((char *)NULL, "\n\t "))
-               ip->flags &= ~key(p);
-}
-
-key(p)
-       char *p;
-{
-       switch(*p) {
-       case 'c':
-               if (!strcmp(p, "cksum"))
-                       return(F_CKSUM);
-               break;
-       case 'g':
-               if (!strcmp(p, "group"))
-                       return(F_GROUP);
-               break;
-       case 'i':
-               if (!strcmp(p, "ignore"))
-                       return(F_IGN);
-               break;
-       case 'l':
-               if (!strcmp(p, "link"))
-                       return(F_SLINK);
-               break;
-       case 'm':
-               if (!strcmp(p, "mode"))
-                       return(F_MODE);
-               break;
-       case 'n':
-               if (!strcmp(p, "nlink"))
-                       return(F_NLINK);
-               break;
-       case 'o':
-               if (!strcmp(p, "owner"))
-                       return(F_OWNER);
-               break;
-       case 's':
-               if (!strcmp(p, "size"))
-                       return(F_SIZE);
-               break;
-       case 't':
-               if (!strcmp(p, "type"))
-                       return(F_TYPE);
-               if (!strcmp(p, "time"))
-                       return(F_TIME);
-               break;
-       }
-       (void)fprintf(stderr, "mtree: unknown keyword %s.\n", p);
-       specerr();
-       /* NOTREACHED */
-}
-
-
-uid_t
-getowner(p)
-       register char *p;
-{
-       struct passwd *pw;
-       int val;
-
-       if (isdigit(*p)) {
-               if ((val = atoi(p)) >= 0)
-                       return((uid_t)val);
-               (void)fprintf(stderr, "mtree: illegal uid value %s.\n", p);
-       } else if (pw = getpwnam(p))
-               return(pw->pw_uid);
-       else
-               (void)fprintf(stderr, "mtree: unknown user %s.\n", p);
-       specerr();
-       /* NOTREACHED */
-}
-
-gid_t
-getgroup(p)
-       register char *p;
-{
-       struct group *gr;
-       int val;
-
-       if (isdigit(*p)) {
-               if ((val = atoi(p)) >= 0)
-                       return((gid_t)val);
-               (void)fprintf(stderr, "mtree: illegal gid value %s.\n", p);
-       } else if (gr = getgrnam(p))
-               return(gr->gr_gid);
-       else
-               (void)fprintf(stderr, "mtree: unknown group %s.\n", p);
-       specerr();
-       /* NOTREACHED */
-}
-
-noparent()
-{
-       (void)fprintf(stderr, "mtree: no parent node.\n");
-       specerr();
-}
-
-specerr()
-{
-       (void)fprintf(stderr,
-           "mtree: line %d of the specification is incorrect.\n", lineno);
-       exit(1);
-}
-
-NODE *
-emalloc(size)
-       int size;
-{
-       void *p;
-
-       /* NOSTRICT */
-       if (!(p = malloc((u_int)size)))
-               nomem();
-       bzero(p, size);
-       return((NODE *)p);
-}
-
-nomem()
-{
-       (void)fprintf(stderr, "mtree: %s.\n", strerror(ENOMEM));
-       exit(1);
+       while (p = strtok(t, "\n\t "))
+               ip->flags &= ~parsekey(p, NULL);
 }
 }
index bb767ea..d093126 100644 (file)
@@ -32,7 +32,7 @@
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)verify.c   5.9 (Berkeley) 3/12/91";
+static char sccsid[] = "@(#)verify.c   5.11 (Berkeley) 4/17/92";
 #endif /* not lint */
 
 #include <sys/param.h>
 #endif /* not lint */
 
 #include <sys/param.h>
@@ -40,57 +40,65 @@ static char sccsid[] = "@(#)verify.c        5.9 (Berkeley) 3/12/91";
 #include <dirent.h>
 #include <fts.h>
 #include <unistd.h>
 #include <dirent.h>
 #include <fts.h>
 #include <unistd.h>
+#include <fnmatch.h>
 #include <errno.h>
 #include <stdio.h>
 #include <errno.h>
 #include <stdio.h>
-#include <fnmatch.h>
 #include "mtree.h"
 #include "mtree.h"
+#include "extern.h"
 
 
-extern NODE *root;
+extern int crc_total, ftsoptions;
+extern int dflag, eflag, rflag, sflag, uflag;
+extern char fullpath[MAXPATHLEN];
 
 
+static NODE *root;
 static char path[MAXPATHLEN];
 
 static char path[MAXPATHLEN];
 
+static void    miss __P((NODE *, char *));
+static int     vwalk __P((void));
+
+int
 verify()
 {
 verify()
 {
-       vwalk();
+       int rval;
+
+       root = spec();
+       rval = vwalk();
        miss(root, path);
        miss(root, path);
+       return (rval);
 }
 
 }
 
+static int
 vwalk()
 {
 vwalk()
 {
-       extern int ftsoptions, dflag, eflag, rflag;
        register FTS *t;
        register FTSENT *p;
        register NODE *ep, *level;
        register FTS *t;
        register FTSENT *p;
        register NODE *ep, *level;
+       int ftsdepth, specdepth, rval;
        char *argv[2];
        char *argv[2];
-       int ftsdepth = 0, specdepth = 0;
 
        argv[0] = ".";
 
        argv[0] = ".";
-       argv[1] = (char *)NULL;
-       if (!(t = fts_open(argv, ftsoptions, (int (*)())NULL))) {
-               (void)fprintf(stderr,
-                   "mtree: fts_open: %s.\n", strerror(errno));
-               exit(1);
-       }
+       argv[1] = NULL;
+       if ((t = fts_open(argv, ftsoptions, NULL)) == NULL)
+               err("fts_open: %s", strerror(errno));
        level = root;
        level = root;
+       ftsdepth = specdepth = rval = 0;
        while (p = fts_read(t)) {
                switch(p->fts_info) {
                case FTS_D:
        while (p = fts_read(t)) {
                switch(p->fts_info) {
                case FTS_D:
-                       if (!strcmp(p->fts_name, "."))
-                               continue;
-                       ftsdepth++; 
+                       ++ftsdepth; 
                        break;
                case FTS_DP:
                        break;
                case FTS_DP:
-                       ftsdepth--
+                       --ftsdepth
                        if (specdepth > ftsdepth) {
                                for (level = level->parent; level->prev;
                                      level = level->prev);  
                        if (specdepth > ftsdepth) {
                                for (level = level->parent; level->prev;
                                      level = level->prev);  
-                               specdepth--;
+                               --specdepth;
                        }
                        continue;
                case FTS_DNR:
                case FTS_ERR:
                case FTS_NS:
                        }
                        continue;
                case FTS_DNR:
                case FTS_ERR:
                case FTS_NS:
-                       (void)fprintf(stderr, "mtree: %s: %s.\n",
+                       (void)fprintf(stderr, "mtree: %s: %s\n",
                            RP(p), strerror(errno));
                        continue;
                default:
                            RP(p), strerror(errno));
                        continue;
                default:
@@ -99,19 +107,18 @@ vwalk()
                }
 
                for (ep = level; ep; ep = ep->next)
                }
 
                for (ep = level; ep; ep = ep->next)
-                       if (ep->flags & F_MAGIC && !fnmatch(ep->name,
+                       if (ep->flags & F_MAGIC && fnmatch(ep->name,
                            p->fts_name, FNM_PATHNAME) ||
                            !strcmp(ep->name, p->fts_name)) {
                                ep->flags |= F_VISIT;
                            p->fts_name, FNM_PATHNAME) ||
                            !strcmp(ep->name, p->fts_name)) {
                                ep->flags |= F_VISIT;
-                               if (ep->flags & F_IGN) {
+                               if (compare(ep->name, ep, p))
+                                       rval = MISMATCHEXIT;
+                               if (ep->flags & F_IGN)
                                        (void)fts_set(t, p, FTS_SKIP);
                                        (void)fts_set(t, p, FTS_SKIP);
-                                       continue;
-                               }
-                               compare(ep->name, ep, p);
-                               if (ep->child && ep->type == F_DIR &&
+                               else if (ep->child && ep->type == F_DIR &&
                                    p->fts_info == FTS_D) {
                                        level = ep->child;
                                    p->fts_info == FTS_D) {
                                        level = ep->child;
-                                       specdepth++;
+                                       ++specdepth;
                                }
                                break;
                        }
                                }
                                break;
                        }
@@ -132,13 +139,17 @@ vwalk()
                (void)fts_set(t, p, FTS_SKIP);
        }
        (void)fts_close(t);
                (void)fts_set(t, p, FTS_SKIP);
        }
        (void)fts_close(t);
+       if (sflag)
+               (void)fprintf(stderr,
+                   "mtree: %s checksum: %lu\n", fullpath, crc_total);
+       return (rval);
 }
 
 }
 
+static void
 miss(p, tail)
        register NODE *p;
        register char *tail;
 {
 miss(p, tail)
        register NODE *p;
        register char *tail;
 {
-       extern int dflag, uflag;
        register int create;
        register char *tp;
 
        register int create;
        register char *tp;
 
@@ -155,9 +166,12 @@ miss(p, tail)
 
                create = 0;
                if (!(p->flags & F_VISIT) && uflag)
 
                create = 0;
                if (!(p->flags & F_VISIT) && uflag)
-#define        MINBITS (F_GROUP|F_MODE|F_OWNER)
-                       if ((p->flags & MINBITS) != MINBITS)
-                               (void)printf(" (not created -- group, mode or owner not specified)");
+                       if (!(p->flags & (F_UID | F_UNAME)))
+                           (void)printf(" (not created: user not specified)");
+                       else if (!(p->flags & (F_GID | F_GNAME)))
+                           (void)printf(" (not created: group not specified)");
+                       else if (!(p->flags & F_MODE))
+                           (void)printf(" (not created: mode not specified)");
                        else if (mkdir(path, S_IRWXU))
                                (void)printf(" (not created: %s)",
                                    strerror(errno));
                        else if (mkdir(path, S_IRWXU))
                                (void)printf(" (not created: %s)",
                                    strerror(errno));
@@ -177,7 +191,7 @@ miss(p, tail)
                if (!create)
                        continue;
                if (chown(path, p->st_uid, p->st_gid)) {
                if (!create)
                        continue;
                if (chown(path, p->st_uid, p->st_gid)) {
-                       (void)printf("%s: owner/group/mode not modified: %s\n",
+                       (void)printf("%s: user/group/mode not modified: %s\n",
                            path, strerror(errno));
                        continue;
                }
                            path, strerror(errno));
                        continue;
                }
index 130d6cf..5bfd908 100644 (file)
@@ -1,7 +1,9 @@
 #      @(#)Makefile    5.5 (Berkeley) 4/23/91
 
 PROG=  swapinfo
 #      @(#)Makefile    5.5 (Berkeley) 4/23/91
 
 PROG=  swapinfo
-SRCS=  swapinfo.c devname.c
+SRCS=  swapinfo.c devname.c getbsize.c
+.PATH:  ${.CURDIR}/../../bin/df
+
 DPADD= ${LIBMATH} ${LIBUTIL}
 LDADD= -lm -lutil
 BINGRP=        kmem
 DPADD= ${LIBMATH} ${LIBUTIL}
 LDADD= -lm -lutil
 BINGRP=        kmem
index 43cf774..8d2a8b7 100644 (file)
@@ -34,6 +34,7 @@ static struct nlist nl[] = {{"_swapmap"},  /* list of free swap areas */
 #define VM_DMMAX       4
                            {""}};
 
 #define VM_DMMAX       4
                            {""}};
 
+char       *getbsize __P((char *, int *, long *));
 
 main (argc, argv)
 int    argc;
 
 main (argc, argv)
 int    argc;
@@ -44,16 +45,17 @@ char        **argv;
                nswap, nswdev, dmmax;
        struct swdevt   *swdevt;
        struct rlist    head;
                nswap, nswdev, dmmax;
        struct swdevt   *swdevt;
        struct rlist    head;
+       static long blocksize;
+        static int headerlen;
+        static char *header;
 
        /* We are trying to be simple here: */
 
        if (argc > 1)
 
        /* We are trying to be simple here: */
 
        if (argc > 1)
-               if (strcmp (argv [1], "-k") == 0) {
-                       use_k = 2;
-               } else {
-                       fprintf (stderr, "Usage:  swapinfo [-k]\n");
-                       exit (1);
-               }
+       {
+               fprintf (stderr, "Usage:  swapinfo\n");
+               exit (1);
+       }
 
        /* Open up /dev/kmem for reading. */
        
 
        /* Open up /dev/kmem for reading. */
        
@@ -154,9 +156,9 @@ char        **argv;
                swapmap = head.rl_next;
        }
 
                swapmap = head.rl_next;
        }
 
+       header = getbsize("swapinfo", &headerlen, &blocksize);
        printf ("%-10s %10s %10s %10s %10s\n",
        printf ("%-10s %10s %10s %10s %10s\n",
-               "Device", use_k == 1 ? "512-blks" : "Kilobytes", 
-               "Used", "Available", "Capacity");
+               "Device", header, "Used", "Available", "Capacity");
        for (total_avail = total_partitions = i = 0; i < nswdev; i++) {
                printf ("/dev/%-5s %10d ",
                        devname (swdevt [i].sw_dev, S_IFBLK), 
        for (total_avail = total_partitions = i = 0; i < nswdev; i++) {
                printf ("/dev/%-5s %10d ",
                        devname (swdevt [i].sw_dev, S_IFBLK),