git: a3b349e43987 - stable/13 - Import latest mtree from NetBSD
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Sat, 20 Dec 2025 01:11:19 UTC
The branch stable/13 has been updated by jlduran:
URL: https://cgit.FreeBSD.org/src/commit/?id=a3b349e439870eeb4f58c74b990f721d86a75e1d
commit a3b349e439870eeb4f58c74b990f721d86a75e1d
Author: Jose Luis Duran <jlduran@FreeBSD.org>
AuthorDate: 2025-12-13 14:28:16 +0000
Commit: Jose Luis Duran <jlduran@FreeBSD.org>
CommitDate: 2025-12-20 01:08:28 +0000
Import latest mtree from NetBSD
Merge commit 'f600477feb4ae61a75f61949eb600caff4aeea8c'
MFC after: 1 week
Discussed with: brooks
(cherry picked from commit 49b6dda4d71175ad615718401573be5fd024822b)
---
contrib/mtree/compare.c | 39 ++++++++-----
contrib/mtree/crc.c | 20 +++----
contrib/mtree/create.c | 144 ++++++++++++++++++++---------------------------
contrib/mtree/extern.h | 13 ++++-
contrib/mtree/misc.c | 10 ++--
contrib/mtree/mtree.8 | 139 +++++++++++++++++++++++++++++++++++----------
contrib/mtree/mtree.c | 8 +--
contrib/mtree/spec.c | 44 ++++++++++++---
contrib/mtree/specspec.c | 4 +-
contrib/mtree/verify.c | 17 ++++--
10 files changed, 271 insertions(+), 167 deletions(-)
diff --git a/contrib/mtree/compare.c b/contrib/mtree/compare.c
index e3639ceea08f..c4e5bfcac1d7 100644
--- a/contrib/mtree/compare.c
+++ b/contrib/mtree/compare.c
@@ -1,4 +1,4 @@
-/* $NetBSD: compare.c,v 1.58 2013/11/21 18:39:50 christos Exp $ */
+/* $NetBSD: compare.c,v 1.61 2024/12/05 17:17:43 christos Exp $ */
/*-
* Copyright (c) 1989, 1993
@@ -38,7 +38,7 @@
#if 0
static char sccsid[] = "@(#)compare.c 8.1 (Berkeley) 6/6/93";
#else
-__RCSID("$NetBSD: compare.c,v 1.58 2013/11/21 18:39:50 christos Exp $");
+__RCSID("$NetBSD: compare.c,v 1.61 2024/12/05 17:17:43 christos Exp $");
#endif
#endif /* not lint */
@@ -135,8 +135,9 @@ do { \
int
compare(NODE *s, FTSENT *p)
{
- u_int32_t len, val, flags;
+ uint32_t len, val, flags;
int fd, label;
+ bool was_unlinked;
const char *cp, *tab;
#if !defined(NO_MD5) || !defined(NO_RMD160) || !defined(NO_SHA1) || !defined(NO_SHA2)
char *digestbuf;
@@ -144,6 +145,7 @@ compare(NODE *s, FTSENT *p)
tab = NULL;
label = 0;
+ was_unlinked = false;
switch(s->type) {
case F_BLOCK:
if (!S_ISBLK(p->fts_statp->st_mode))
@@ -210,47 +212,53 @@ typeerr: LABEL;
s->st_mode | nodetoino(s->type),
s->st_rdev) == -1) ||
(lchown(p->fts_accpath, p->fts_statp->st_uid,
- p->fts_statp->st_gid) == -1) )
+ p->fts_statp->st_gid) == -1) ) {
printf(", not modified: %s%s\n",
strerror(errno),
flavor == F_FREEBSD9 ? "" : ")");
- else
+ } else {
printf(", modified%s\n",
flavor == F_FREEBSD9 ? "" : ")");
+ was_unlinked = true;
+ }
} else
printf(")\n");
tab = "\t";
}
/* Set the uid/gid first, then set the mode. */
- if (s->flags & (F_UID | F_UNAME) && s->st_uid != p->fts_statp->st_uid) {
+ if (s->flags & (F_UID | F_UNAME) &&
+ (was_unlinked || s->st_uid != p->fts_statp->st_uid)) {
LABEL;
printf(flavor == F_FREEBSD9 ?
"%suser expected %lu found %lu" : "%suser (%lu, %lu",
tab, (u_long)s->st_uid, (u_long)p->fts_statp->st_uid);
if (uflag) {
- if (lchown(p->fts_accpath, s->st_uid, -1))
+ if (lchown(p->fts_accpath, s->st_uid, (gid_t)-1))
printf(", not modified: %s%s\n",
strerror(errno),
flavor == F_FREEBSD9 ? "" : ")");
else
- printf(", modified%s\n",
+ printf(", modified%s%s\n",
+ was_unlinked ? " by unlink" : "",
flavor == F_FREEBSD9 ? "" : ")");
} else
printf(")\n");
tab = "\t";
}
- if (s->flags & (F_GID | F_GNAME) && s->st_gid != p->fts_statp->st_gid) {
+ if (s->flags & (F_GID | F_GNAME) &&
+ (was_unlinked || s->st_gid != p->fts_statp->st_gid)) {
LABEL;
printf(flavor == F_FREEBSD9 ?
"%sgid expected %lu found %lu" : "%sgid (%lu, %lu",
tab, (u_long)s->st_gid, (u_long)p->fts_statp->st_gid);
if (uflag) {
- if (lchown(p->fts_accpath, -1, s->st_gid))
+ if (lchown(p->fts_accpath, (uid_t)-1, s->st_gid))
printf(", not modified: %s%s\n",
strerror(errno),
flavor == F_FREEBSD9 ? "" : ")");
else
- printf(", modified%s\n",
+ printf(", modified%s%s\n",
+ was_unlinked ? " by unlink" : "",
flavor == F_FREEBSD9 ? "" : ")");
}
else
@@ -258,8 +266,8 @@ typeerr: LABEL;
tab = "\t";
}
if (s->flags & F_MODE &&
- s->st_mode != (p->fts_statp->st_mode & MBITS)) {
- if (lflag) {
+ (was_unlinked || s->st_mode != (p->fts_statp->st_mode & MBITS))) {
+ if (lflag && !was_unlinked) {
mode_t tmode, mode;
tmode = s->st_mode;
@@ -287,7 +295,8 @@ typeerr: LABEL;
strerror(errno),
flavor == F_FREEBSD9 ? "" : ")");
else
- printf(", modified%s\n",
+ printf(", modified%s%s\n",
+ was_unlinked ? " by unlink" : "",
flavor == F_FREEBSD9 ? "" : ")");
}
else
@@ -567,7 +576,7 @@ const char *
rlink(const char *name)
{
static char lbuf[MAXPATHLEN];
- int len;
+ ssize_t len;
if ((len = readlink(name, lbuf, sizeof(lbuf) - 1)) == -1)
mtree_err("%s: %s", name, strerror(errno));
diff --git a/contrib/mtree/crc.c b/contrib/mtree/crc.c
index 4eac66e5b995..69b30b206439 100644
--- a/contrib/mtree/crc.c
+++ b/contrib/mtree/crc.c
@@ -1,4 +1,4 @@
-/* $NetBSD: crc.c,v 1.9 2012/10/05 00:40:51 christos Exp $ */
+/* $NetBSD: crc.c,v 1.11 2024/12/05 17:17:43 christos Exp $ */
/*-
* Copyright (c) 1991, 1993
@@ -41,7 +41,7 @@
#if 0
static char sccsid[] = "@(#)crc.c 8.1 (Berkeley) 6/17/93";
#else
-__RCSID("$NetBSD: crc.c,v 1.9 2012/10/05 00:40:51 christos Exp $");
+__RCSID("$NetBSD: crc.c,v 1.11 2024/12/05 17:17:43 christos Exp $");
#endif
#endif /* not lint */
@@ -53,7 +53,7 @@ __RCSID("$NetBSD: crc.c,v 1.9 2012/10/05 00:40:51 christos Exp $");
#include "extern.h"
-static const u_int32_t crctab[] = {
+static const uint32_t crctab[] = {
0x0,
0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b,
0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6,
@@ -114,15 +114,15 @@ static const u_int32_t crctab[] = {
* locations to store the crc and the number of bytes read. It returns 0 on
* success and 1 on failure. Errno is set on failure.
*/
-u_int32_t crc_total = ~0; /* The crc over a number of files. */
+uint32_t crc_total = ~0u; /* The crc over a number of files. */
int
-crc(int fd, u_int32_t *cval, u_int32_t *clen)
+crc(int fd, uint32_t *cval, uint32_t *clen)
{
u_char *p;
- int nr;
- u_int32_t thecrc, len;
- u_int32_t crctot;
+ ssize_t nr;
+ uint32_t thecrc, len;
+ uint32_t crctot;
u_char buf[16 * 1024];
#define COMPUTE(var, ch) (var) = (var) << 8 ^ crctab[(var) >> 24 ^ (ch)]
@@ -132,12 +132,12 @@ crc(int fd, u_int32_t *cval, u_int32_t *clen)
crctot = ~crc_total;
while ((nr = read(fd, buf, sizeof(buf))) > 0)
if (sflag) {
- for (len += nr, p = buf; nr--; ++p) {
+ for (len += (uint32_t)nr, p = buf; nr--; ++p) {
COMPUTE(thecrc, *p);
COMPUTE(crctot, *p);
}
} else {
- for (len += nr, p = buf; nr--; ++p)
+ for (len += (uint32_t)nr, p = buf; nr--; ++p)
COMPUTE(thecrc, *p);
}
if (nr < 0)
diff --git a/contrib/mtree/create.c b/contrib/mtree/create.c
index 7a09a1cc3951..e23004851f39 100644
--- a/contrib/mtree/create.c
+++ b/contrib/mtree/create.c
@@ -1,4 +1,4 @@
-/* $NetBSD: create.c,v 1.73 2014/04/24 17:22:41 christos Exp $ */
+/* $NetBSD: create.c,v 1.79 2024/12/05 17:17:43 christos Exp $ */
/*-
* Copyright (c) 1989, 1993
@@ -38,7 +38,7 @@
#if 0
static char sccsid[] = "@(#)create.c 8.1 (Berkeley) 6/6/93";
#else
-__RCSID("$NetBSD: create.c,v 1.73 2014/04/24 17:22:41 christos Exp $");
+__RCSID("$NetBSD: create.c,v 1.79 2024/12/05 17:17:43 christos Exp $");
#endif
#endif /* not lint */
@@ -84,13 +84,6 @@ static uid_t uid;
static mode_t mode;
static u_long flags;
-#ifdef __FreeBSD__
-#define FTS_CONST const
-#else
-#define FTS_CONST
-#endif
-
-static int dcmp(const FTSENT *FTS_CONST *, const FTSENT *FTS_CONST *);
static void output(FILE *, int, int *, const char *, ...)
__printflike(4, 5);
static int statd(FILE *, FTS *, FTSENT *, uid_t *, gid_t *, mode_t *,
@@ -180,15 +173,59 @@ cwalk(FILE *fp)
mtree_err("%s checksum: %u", fullpath, crc_total);
}
+static void
+dosum(FILE *fp, int indent, FTSENT *p, int *offset, int flag,
+ char * (*func)(const char *, char *), const char *key)
+{
+ char *digestbuf;
+
+ if ((keys & flag) == 0)
+ return;
+
+ digestbuf = (*func)(p->fts_accpath, NULL);
+ if (digestbuf != NULL) {
+ output(fp, indent, offset, "%s=%s", key, digestbuf);
+ free(digestbuf);
+ return;
+ }
+
+ if (qflag) {
+ warn("%s: %s failed", p->fts_path, key);
+ return;
+ }
+
+ mtree_err("%s: %s failed: %s", p->fts_path, key, strerror(errno));
+}
+
+static char *
+crcFile(const char *fname, char *dummy __unused)
+{
+ char *ptr;
+ uint32_t val, len;
+ int fd, e;
+
+ if ((fd = open(fname, O_RDONLY)) == -1)
+ goto out;
+
+ e = crc(fd, &val, &len);
+ close(fd);
+ if (e)
+ goto out;
+
+ if (asprintf(&ptr, "%u", val) < 0)
+ goto out;
+
+ return ptr;
+out:
+ mtree_err("%s: %s", fname, strerror(errno));
+ return NULL;
+}
+
static void
statf(FILE *fp, int indent, FTSENT *p)
{
- u_int32_t len, val;
- int fd, offset;
+ int offset;
const char *name = NULL;
-#if !defined(NO_MD5) || !defined(NO_RMD160) || !defined(NO_SHA1) || !defined(NO_SHA2)
- char *digestbuf;
-#endif
offset = fprintf(fp, "%*s%s%s", indent, "",
S_ISDIR(p->fts_statp->st_mode) ? "" : " ", vispath(p->fts_name));
@@ -241,65 +278,25 @@ statf(FILE *fp, int indent, FTSENT *p)
output(fp, indent, &offset, "time=%jd.%09ld",
(intmax_t)p->fts_statp->st_mtime, (long)0);
#endif
- 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))
- mtree_err("%s: %s", p->fts_accpath, strerror(errno));
- close(fd);
- output(fp, indent, &offset, "cksum=%lu", (long)val);
- }
+ if (S_ISREG(p->fts_statp->st_mode)) {
+ dosum(fp, indent, p, &offset, F_CKSUM, crcFile, "cksum");
#ifndef NO_MD5
- if (keys & F_MD5 && S_ISREG(p->fts_statp->st_mode)) {
- if ((digestbuf = MD5File(p->fts_accpath, NULL)) == NULL)
- mtree_err("%s: MD5File failed: %s", p->fts_accpath,
- strerror(errno));
- output(fp, indent, &offset, "%s=%s", MD5KEY, digestbuf);
- free(digestbuf);
- }
+ dosum(fp, indent, p, &offset, F_MD5, MD5File, MD5KEY);
#endif /* ! NO_MD5 */
#ifndef NO_RMD160
- if (keys & F_RMD160 && S_ISREG(p->fts_statp->st_mode)) {
- if ((digestbuf = RMD160File(p->fts_accpath, NULL)) == NULL)
- mtree_err("%s: RMD160File failed: %s", p->fts_accpath,
- strerror(errno));
- output(fp, indent, &offset, "%s=%s", RMD160KEY, digestbuf);
- free(digestbuf);
- }
+ dosum(fp, indent, p, &offset, F_RMD160, RMD160File, RMD160KEY);
#endif /* ! NO_RMD160 */
#ifndef NO_SHA1
- if (keys & F_SHA1 && S_ISREG(p->fts_statp->st_mode)) {
- if ((digestbuf = SHA1File(p->fts_accpath, NULL)) == NULL)
- mtree_err("%s: SHA1File failed: %s", p->fts_accpath,
- strerror(errno));
- output(fp, indent, &offset, "%s=%s", SHA1KEY, digestbuf);
- free(digestbuf);
- }
+ dosum(fp, indent, p, &offset, F_SHA1, SHA1File, SHA1KEY);
#endif /* ! NO_SHA1 */
#ifndef NO_SHA2
- if (keys & F_SHA256 && S_ISREG(p->fts_statp->st_mode)) {
- if ((digestbuf = SHA256_File(p->fts_accpath, NULL)) == NULL)
- mtree_err("%s: SHA256_File failed: %s", p->fts_accpath,
- strerror(errno));
- output(fp, indent, &offset, "%s=%s", SHA256KEY, digestbuf);
- free(digestbuf);
- }
+ dosum(fp, indent, p, &offset, F_SHA256, SHA256_File, SHA256KEY);
#ifdef SHA384_BLOCK_LENGTH
- if (keys & F_SHA384 && S_ISREG(p->fts_statp->st_mode)) {
- if ((digestbuf = SHA384_File(p->fts_accpath, NULL)) == NULL)
- mtree_err("%s: SHA384_File failed: %s", p->fts_accpath,
- strerror(errno));
- output(fp, indent, &offset, "%s=%s", SHA384KEY, digestbuf);
- free(digestbuf);
- }
+ dosum(fp, indent, p, &offset, F_SHA384, SHA384_File, SHA384KEY);
#endif
- if (keys & F_SHA512 && S_ISREG(p->fts_statp->st_mode)) {
- if ((digestbuf = SHA512_File(p->fts_accpath, NULL)) == NULL)
- mtree_err("%s: SHA512_File failed: %s", p->fts_accpath,
- strerror(errno));
- output(fp, indent, &offset, "%s=%s", SHA512KEY, digestbuf);
- free(digestbuf);
- }
+ dosum(fp, indent, p, &offset, F_SHA512, SHA512_File, SHA512KEY);
#endif /* ! NO_SHA2 */
+ }
if (keys & F_SLINK &&
(p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE))
output(fp, indent, &offset, "link=%s",
@@ -440,27 +437,6 @@ statd(FILE *fp, FTS *t, FTSENT *parent, uid_t *puid, gid_t *pgid, mode_t *pmode,
return (0);
}
-/*
- * dcmp --
- * used as a comparison function passed to fts_open() to control
- * the order in which fts_read() returns results. We make
- * directories sort after non-directories, but otherwise sort in
- * strcmp() order.
- *
- * Keep this in sync with nodecmp() in spec.c.
- */
-static int
-dcmp(const FTSENT *FTS_CONST *a, const FTSENT *FTS_CONST *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));
-}
-
void
output(FILE *fp, int indent, int *offset, const char *fmt, ...)
{
diff --git a/contrib/mtree/extern.h b/contrib/mtree/extern.h
index 091cf8f84460..7b58dd4a4d20 100644
--- a/contrib/mtree/extern.h
+++ b/contrib/mtree/extern.h
@@ -1,4 +1,4 @@
-/* $NetBSD: extern.h,v 1.39 2014/04/24 17:22:41 christos Exp $ */
+/* $NetBSD: extern.h,v 1.41 2024/12/05 17:17:43 christos Exp $ */
/*-
* Copyright (c) 1991, 1993
@@ -49,6 +49,12 @@
#include <netdb.h>
#endif
+#if defined(__FreeBSD__) && !defined(HAVE_NBTOOL_CONFIG_H)
+#define FTS_CONST const
+#else
+#define FTS_CONST
+#endif
+
#ifndef MAXHOSTNAMELEN
#define MAXHOSTNAMELEN 256
#endif
@@ -62,8 +68,9 @@ enum flavor {
void addtag(slist_t *, char *);
int check_excludes(const char *, const char *);
int compare(NODE *, FTSENT *);
-int crc(int, u_int32_t *, u_int32_t *);
+int crc(int, uint32_t *, uint32_t *);
void cwalk(FILE *);
+int dcmp(const FTSENT *FTS_CONST *, const FTSENT *FTS_CONST *);
void dump_nodes(FILE *, const char *, NODE *, int);
void init_excludes(void);
int matchtags(NODE *);
@@ -83,7 +90,7 @@ extern int bflag, dflag, eflag, iflag, jflag, lflag, mflag,
extern int mtree_Mflag, mtree_Sflag, mtree_Wflag;
extern size_t mtree_lineno;
extern enum flavor flavor;
-extern u_int32_t crc_total;
+extern uint32_t crc_total;
extern int ftsoptions, keys;
extern char fullpath[];
extern slist_t includetags, excludetags;
diff --git a/contrib/mtree/misc.c b/contrib/mtree/misc.c
index b99f1ce1f708..b5bd9f4e06c6 100644
--- a/contrib/mtree/misc.c
+++ b/contrib/mtree/misc.c
@@ -1,4 +1,4 @@
-/* $NetBSD: misc.c,v 1.34 2012/12/20 19:09:25 christos Exp $ */
+/* $NetBSD: misc.c,v 1.35 2024/12/05 17:17:43 christos Exp $ */
/*-
* Copyright (c) 1991, 1993
@@ -37,7 +37,7 @@
#include <sys/cdefs.h>
#if defined(__RCSID) && !defined(lint)
-__RCSID("$NetBSD: misc.c,v 1.34 2012/12/20 19:09:25 christos Exp $");
+__RCSID("$NetBSD: misc.c,v 1.35 2024/12/05 17:17:43 christos Exp $");
#endif /* not lint */
#include <sys/types.h>
@@ -111,7 +111,7 @@ slist_t excludetags, includetags;
int keys = KEYDEFAULT;
-int keycompare(const void *, const void *);
+static int keycompare(const void *, const void *);
u_int
parsekey(const char *name, int *needvaluep)
@@ -153,7 +153,7 @@ parsetype(const char *name)
return (k->val);
}
-int
+static int
keycompare(const void *a, const void *b)
{
@@ -198,7 +198,7 @@ void
parsetags(slist_t *list, char *args)
{
char *p, *e;
- int len;
+ size_t len;
if (args == NULL) {
addtag(list, NULL);
diff --git a/contrib/mtree/mtree.8 b/contrib/mtree/mtree.8
index 53bb21f711bf..99e3199de943 100644
--- a/contrib/mtree/mtree.8
+++ b/contrib/mtree/mtree.8
@@ -1,4 +1,4 @@
-.\" $NetBSD: mtree.8,v 1.69 2013/02/03 19:16:06 christos Exp $
+.\" $NetBSD: mtree.8,v 1.78 2023/12/02 13:26:09 christos Exp $
.\"
.\" Copyright (c) 1989, 1990, 1993
.\" The Regents of the University of California. All rights reserved.
@@ -56,7 +56,7 @@
.\"
.\" @(#)mtree.8 8.2 (Berkeley) 12/11/93
.\"
-.Dd February 3, 2013
+.Dd December 2, 2023
.Dt MTREE 8
.Os
.Sh NAME
@@ -93,9 +93,11 @@ characteristics do not match the specification, or which are
missing from either the file hierarchy or the specification.
.Pp
The options are as follows:
-.Bl -tag -width Xxxexcludexfilexx
+.Bl -tag -width Fl
+.
.It Fl b
Suppress blank lines before entering and after exiting directories.
+.
.It Fl C
Convert a specification into
a format that's easier to parse with various tools.
@@ -105,8 +107,7 @@ from the file given by
In the output, each file or directory is represented using a single line
(which might be very long).
The full path name
-(beginning with
-.Dq \&./ )
+.Pq beginning with Ql \&./
is always printed as the first field;
.Fl K ,
.Fl k ,
@@ -120,19 +121,25 @@ can be used to control which files are printed;
and the
.Fl S
option can be used to sort the output.
+.
.It Fl c
Print a specification for the file hierarchy originating at
-the current working directory (or the directory provided by
-.Fl p Ar path )
+the current working directory
+.Po or the directory provided by
+.Fl p Ar path
+.Pc
to the standard output.
The output is in a style using relative path names.
+.
.It Fl D
As per
.Fl C ,
except that the path name is always printed as the last field instead of
the first.
+.
.It Fl d
Ignore everything except directory type files.
+.
.It Fl E Ar tags
Add the comma separated tags to the
.Dq exclusion
@@ -141,9 +148,11 @@ Non-directories with tags which are in the exclusion list are not printed with
.Fl C
and
.Fl D .
+.
.It Fl e
Don't complain about files that are in the file hierarchy, but not in the
specification.
+.
.It Fl F Ar flavor
Set the compatibility flavor of the
.Nm
@@ -151,22 +160,23 @@ utility.
The
.Ar flavor
can be one of
-.Sy mtree ,
-.Sy freebsd9 ,
+.Cm mtree ,
+.Cm freebsd9 ,
or
-.Sy netbsd6 .
+.Cm netbsd6 .
The default is
-.Sy mtree .
+.Cm mtree .
The
-.Sy freebsd9
+.Cm freebsd9
and
-.Sy netbsd6
-flavors attempt to preserve output compatiblity and command line option
+.Cm netbsd6
+flavors attempt to preserve output compatibility and command line option
backward compatibility with
.Fx 9.0
and
.Nx 6.0
respectively.
+.
.It Fl f Ar spec
Read the specification from
.Ar file ,
@@ -178,10 +188,18 @@ The specifications will be sorted like output generated using
.Fl c .
The output format in this case is somewhat reminiscent of
.Xr comm 1 ,
-having "in first spec only", "in second spec only", and "different"
-columns, prefixed by zero, one and two TAB characters respectively.
-Each entry in the "different" column occupies two lines, one from each
-specification.
+having
+.Dq in first spec only ,
+.Dq in second spec only ,
+and
+.Dq different
+columns, prefixed by zero, one and two
+.Tn TAB
+characters respectively.
+Each entry in the
+.Dq different
+column occupies two lines, one from each specification.
+.
.It Fl I Ar tags
Add the comma separated tags to the
.Dq inclusion
@@ -191,14 +209,22 @@ Non-directories with tags which are in the inclusion list are printed with
and
.Fl D .
If no inclusion list is provided, the default is to display all files.
+.
.It Fl i
-If specified, set the schg and/or sappnd flags.
+If specified, set the
+.Ql schg
+and/or
+.Ql sappnd
+flags.
+.
.It Fl j
Indent the output 4 spaces each time a directory level is descended when
creating a specification with the
.Fl c
option.
-This does not affect either the /set statements or the comment before each
+This does not affect either the
+.Ql /set
+statements or the comment before each
directory.
It does however affect the comment before the close of each directory.
This is the equivalent of the
@@ -207,26 +233,31 @@ option in the
.Fx
version of
.Nm .
+.
.It Fl K Ar keywords
Add the specified (whitespace or comma separated) keywords to the current
set of keywords.
If
.Ql all
is specified, add all of the other keywords.
+.
.It Fl k Ar keywords
Use the
.Sy type
keyword plus the specified (whitespace or comma separated)
-keywords instead of the current set of keywords.
+.Ar keywords
+instead of the current set of keywords.
If
.Ql all
is specified, use all of the other keywords.
If the
.Sy type
keyword is not desired, suppress it with
-.Fl R Ar type .
+.Fl R Cm type .
+.
.It Fl L
Follow all symbolic links in the file hierarchy.
+.
.It Fl l
Do
.Dq loose
@@ -235,7 +266,7 @@ will match less stringent ones.
For example, a file marked mode 0444
will pass a check for mode 0644.
.Dq Loose
-checks apply only to read, write and execute permissions -- in
+checks apply only to read, write and execute permissions \(em in
particular, if other bits like the sticky bit or suid/sgid bits are
set either in the specification or the file, exact checking will be
performed.
@@ -244,17 +275,25 @@ This option may not be set at the same time as the
or
.Fl u
option.
+.
.It Fl M
Permit merging of specification entries with different types,
with the last entry taking precedence.
+.
.It Fl m
-If the schg and/or sappnd flags are specified, reset these flags.
-Note that this is only possible with securelevel less than 1 (i.e.,
-in single user mode or while the system is running in insecure
-mode).
+If the
+.Ql schg
+and/or
+.Ql sappnd
+flags are specified, reset these flags.
+Note that this is only possible with securelevel less than 1
+.Po
+i.e., in single user mode or while the system is running in insecure mode
+.Pc .
See
.Xr init 8
for information on security levels.
+.
.It Fl n
Do not emit pathname comments when creating a specification.
Normally
@@ -262,6 +301,7 @@ a comment is emitted before each directory and before the close of that
directory when using the
.Fl c
option.
+.
.It Fl N Ar dbdir
Use the user database text file
.Pa master.passwd
@@ -274,31 +314,42 @@ rather than using the results from the system's
and
.Xr getgrnam 3
(and related) library calls.
+.
.It Fl O Ar onlypaths
Only include files included in this list of pathnames.
+.
.It Fl P
Don't follow symbolic links in the file hierarchy, instead consider
the symbolic link itself in any comparisons.
This is the default.
+.
.It Fl p Ar path
Use the file hierarchy rooted in
.Ar path ,
instead of the current directory.
+.
.It Fl q
Quiet mode.
Do not complain when a
.Dq missing
directory cannot be created because it already exists.
This occurs when the directory is a symbolic link.
+.
.It Fl R Ar keywords
Remove the specified (whitespace or comma separated) keywords from the current
set of keywords.
If
.Ql all
is specified, remove all of the other keywords.
+.
.It Fl r
Remove any files in the file hierarchy that are not described in the
specification.
+Repeating the flag more than once will attempt to reset all the
+file flags via
+.Xr lchflags 2
+before attempting to remove the file in case the file was immutable.
+.
.It Fl S
When reading a specification into an internal data structure,
sort the entries.
@@ -320,19 +371,23 @@ By default, if the
.Fl S
option is not used, entries within the same directory are collected
together (separated from entries for other directories), but not sorted.
+.
.It Fl s Ar seed
Display a single checksum to the standard error output that represents all
of the files for which the keyword
.Sy cksum
was specified.
The checksum is seeded with the specified value.
+.
.It Fl t
Modify the modified time of existing files, the device type of devices, and
symbolic link targets, to match the specification.
+.
.It Fl U
Same as
.Fl u
except that a mismatch is not considered to be an error if it was corrected.
+.
.It Fl u
Modify the owner, group, permissions, and flags of existing files,
the device type of devices, and symbolic link targets,
@@ -350,6 +405,7 @@ is given, these flags will be reset.
Exit with a status of 0 on success,
2 if the file hierarchy did not match the specification, and
1 if any other error occurred.
+.
.It Fl W
Don't attempt to set various file attributes such as the
ownership, mode, flags, or time
@@ -358,6 +414,7 @@ This option will be most useful when used in conjunction with
.Fl U
or
.Fl u .
+.
.It Fl X Ar exclude-file
The specified file contains
.Xr fnmatch 3
@@ -370,11 +427,14 @@ the starting directory); otherwise,
it will be matched against basenames only.
Comments are permitted in
the
-.Ar exclude-list
+.Ar exclude-file
file.
+.
.It Fl x
Don't descend below mount points in the file hierarchy.
+.
.El
+.
.Pp
Specifications are mostly composed of
.Dq keywords ,
@@ -384,7 +444,8 @@ 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 sha384digestxx
+.
+.Bl -tag -width Sy
.It Sy cksum
The checksum of the file using the default algorithm specified by
the
@@ -420,6 +481,7 @@ format.)
.It Ar number
Opaque number (as stored on the file system).
.El
+.
.Pp
The following values for
.Ar format
@@ -614,9 +676,24 @@ they match.
.Nm
uses
.Xr strsvis 3
-(in VIS_CSTYLE format) to encode path names containing
+(in
+.Dv VIS_OCTAL
+format) to encode path names containing
non-printable characters.
Whitespace characters are encoded as
+.Ql \e040
+(space),
+.Ql \e011
+(tab), and
+.Ql \e012
+(new line).
+When flavor
+.Sy netbsd6
+is selected,
+.Xr strsvis 3
+(in
+.Dv VIS_CSTYLE
+format) is used and whitespace characters are encoded as
.Ql \es
(space),
.Ql \et
@@ -678,7 +755,7 @@ The
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 FILES
-.Bl -tag -width /etc/mtree -compact
+.Bl -tag -width Pa -compact
.It Pa /etc/mtree
system specification directory
.El
diff --git a/contrib/mtree/mtree.c b/contrib/mtree/mtree.c
index 8b4cb9494d53..28f09fa32210 100644
--- a/contrib/mtree/mtree.c
+++ b/contrib/mtree/mtree.c
@@ -1,4 +1,4 @@
-/* $NetBSD: mtree.c,v 1.49 2014/04/24 17:22:41 christos Exp $ */
+/* $NetBSD: mtree.c,v 1.51 2024/12/05 17:17:15 christos Exp $ */
/*-
* Copyright (c) 1989, 1990, 1993
@@ -43,7 +43,7 @@ __COPYRIGHT("@(#) Copyright (c) 1989, 1990, 1993\
#if 0
static char sccsid[] = "@(#)mtree.c 8.1 (Berkeley) 6/6/93";
#else
-__RCSID("$NetBSD: mtree.c,v 1.49 2014/04/24 17:22:41 christos Exp $");
+__RCSID("$NetBSD: mtree.c,v 1.51 2024/12/05 17:17:15 christos Exp $");
#endif
#endif /* not lint */
@@ -195,7 +195,7 @@ main(int argc, char **argv)
qflag = 1;
break;
case 'r':
- rflag = 1;
+ rflag++;
break;
case 'R':
while ((p = strsep(&optarg, " \t,")) != NULL)
@@ -204,7 +204,7 @@ main(int argc, char **argv)
break;
case 's':
sflag = 1;
- crc_total = ~strtol(optarg, &p, 0);
+ crc_total = (uint32_t)~strtol(optarg, &p, 0);
if (*p)
mtree_err("illegal seed value -- %s", optarg);
break;
diff --git a/contrib/mtree/spec.c b/contrib/mtree/spec.c
index 6fbe6f534560..25bface34bd0 100644
--- a/contrib/mtree/spec.c
+++ b/contrib/mtree/spec.c
@@ -1,4 +1,4 @@
-/* $NetBSD: spec.c,v 1.89 2014/04/24 17:22:41 christos Exp $ */
+/* $NetBSD: spec.c,v 1.92 2024/12/05 17:17:43 christos Exp $ */
/*-
* Copyright (c) 1989, 1993
@@ -67,7 +67,7 @@
#if 0
static char sccsid[] = "@(#)spec.c 8.2 (Berkeley) 4/28/95";
#else
-__RCSID("$NetBSD: spec.c,v 1.89 2014/04/24 17:22:41 christos Exp $");
+__RCSID("$NetBSD: spec.c,v 1.92 2024/12/05 17:17:43 christos Exp $");
#endif
#endif /* not lint */
@@ -224,10 +224,14 @@ noparent: mtree_err("no parent node");
*/
if (strcmp(centry->name, ".") == 0 && centry->type == 0)
centry->type = F_DIR;
- if (strcmp(centry->name, ".") != 0 ||
- centry->type != F_DIR)
+ if (strcmp(centry->name, ".") != 0)
mtree_err(
- "root node must be the directory `.'");
+ "root node must be the directory `.',"
+ " found `%s'", centry->name);
+ if (centry->type != F_DIR)
+ mtree_err(
+ "root node must type %#x != %#x",
+ F_DIR, centry->type);
last = root = centry;
root->parent = root;
} else if (pathparent != NULL) {
@@ -539,7 +543,8 @@ replacenode(NODE *cur, NODE *new)
static void
set(char *t, NODE *ip)
{
*** 120 LINES SKIPPED ***