Import latest mtree from NetBSD

Merge commit 'f600477feb4ae61a75f61949eb600caff4aeea8c'

MFC after:	1 week
Discussed with:	brooks
This commit is contained in:
Jose Luis Duran
2025-12-13 14:28:16 +00:00
10 changed files with 271 additions and 167 deletions
+24 -15
View File
@@ -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 * Copyright (c) 1989, 1993
@@ -38,7 +38,7 @@
#if 0 #if 0
static char sccsid[] = "@(#)compare.c 8.1 (Berkeley) 6/6/93"; static char sccsid[] = "@(#)compare.c 8.1 (Berkeley) 6/6/93";
#else #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
#endif /* not lint */ #endif /* not lint */
@@ -135,8 +135,9 @@ do { \
int int
compare(NODE *s, FTSENT *p) compare(NODE *s, FTSENT *p)
{ {
u_int32_t len, val, flags; uint32_t len, val, flags;
int fd, label; int fd, label;
bool was_unlinked;
const char *cp, *tab; const char *cp, *tab;
#if !defined(NO_MD5) || !defined(NO_RMD160) || !defined(NO_SHA1) || !defined(NO_SHA2) #if !defined(NO_MD5) || !defined(NO_RMD160) || !defined(NO_SHA1) || !defined(NO_SHA2)
char *digestbuf; char *digestbuf;
@@ -144,6 +145,7 @@ compare(NODE *s, FTSENT *p)
tab = NULL; tab = NULL;
label = 0; label = 0;
was_unlinked = false;
switch(s->type) { switch(s->type) {
case F_BLOCK: case F_BLOCK:
if (!S_ISBLK(p->fts_statp->st_mode)) if (!S_ISBLK(p->fts_statp->st_mode))
@@ -210,47 +212,53 @@ typeerr: LABEL;
s->st_mode | nodetoino(s->type), s->st_mode | nodetoino(s->type),
s->st_rdev) == -1) || s->st_rdev) == -1) ||
(lchown(p->fts_accpath, p->fts_statp->st_uid, (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", printf(", not modified: %s%s\n",
strerror(errno), strerror(errno),
flavor == F_FREEBSD9 ? "" : ")"); flavor == F_FREEBSD9 ? "" : ")");
else } else {
printf(", modified%s\n", printf(", modified%s\n",
flavor == F_FREEBSD9 ? "" : ")"); flavor == F_FREEBSD9 ? "" : ")");
was_unlinked = true;
}
} else } else
printf(")\n"); printf(")\n");
tab = "\t"; tab = "\t";
} }
/* Set the uid/gid first, then set the mode. */ /* 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; LABEL;
printf(flavor == F_FREEBSD9 ? printf(flavor == F_FREEBSD9 ?
"%suser expected %lu found %lu" : "%suser (%lu, %lu", "%suser expected %lu found %lu" : "%suser (%lu, %lu",
tab, (u_long)s->st_uid, (u_long)p->fts_statp->st_uid); tab, (u_long)s->st_uid, (u_long)p->fts_statp->st_uid);
if (uflag) { 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", printf(", not modified: %s%s\n",
strerror(errno), strerror(errno),
flavor == F_FREEBSD9 ? "" : ")"); flavor == F_FREEBSD9 ? "" : ")");
else else
printf(", modified%s\n", printf(", modified%s%s\n",
was_unlinked ? " by unlink" : "",
flavor == F_FREEBSD9 ? "" : ")"); flavor == F_FREEBSD9 ? "" : ")");
} else } else
printf(")\n"); printf(")\n");
tab = "\t"; 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; LABEL;
printf(flavor == F_FREEBSD9 ? printf(flavor == F_FREEBSD9 ?
"%sgid expected %lu found %lu" : "%sgid (%lu, %lu", "%sgid expected %lu found %lu" : "%sgid (%lu, %lu",
tab, (u_long)s->st_gid, (u_long)p->fts_statp->st_gid); tab, (u_long)s->st_gid, (u_long)p->fts_statp->st_gid);
if (uflag) { 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", printf(", not modified: %s%s\n",
strerror(errno), strerror(errno),
flavor == F_FREEBSD9 ? "" : ")"); flavor == F_FREEBSD9 ? "" : ")");
else else
printf(", modified%s\n", printf(", modified%s%s\n",
was_unlinked ? " by unlink" : "",
flavor == F_FREEBSD9 ? "" : ")"); flavor == F_FREEBSD9 ? "" : ")");
} }
else else
@@ -258,8 +266,8 @@ typeerr: LABEL;
tab = "\t"; tab = "\t";
} }
if (s->flags & F_MODE && if (s->flags & F_MODE &&
s->st_mode != (p->fts_statp->st_mode & MBITS)) { (was_unlinked || s->st_mode != (p->fts_statp->st_mode & MBITS))) {
if (lflag) { if (lflag && !was_unlinked) {
mode_t tmode, mode; mode_t tmode, mode;
tmode = s->st_mode; tmode = s->st_mode;
@@ -287,7 +295,8 @@ typeerr: LABEL;
strerror(errno), strerror(errno),
flavor == F_FREEBSD9 ? "" : ")"); flavor == F_FREEBSD9 ? "" : ")");
else else
printf(", modified%s\n", printf(", modified%s%s\n",
was_unlinked ? " by unlink" : "",
flavor == F_FREEBSD9 ? "" : ")"); flavor == F_FREEBSD9 ? "" : ")");
} }
else else
@@ -567,7 +576,7 @@ const char *
rlink(const char *name) rlink(const char *name)
{ {
static char lbuf[MAXPATHLEN]; static char lbuf[MAXPATHLEN];
int len; ssize_t len;
if ((len = readlink(name, lbuf, sizeof(lbuf) - 1)) == -1) if ((len = readlink(name, lbuf, sizeof(lbuf) - 1)) == -1)
mtree_err("%s: %s", name, strerror(errno)); mtree_err("%s: %s", name, strerror(errno));
+10 -10
View File
@@ -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 * Copyright (c) 1991, 1993
@@ -41,7 +41,7 @@
#if 0 #if 0
static char sccsid[] = "@(#)crc.c 8.1 (Berkeley) 6/17/93"; static char sccsid[] = "@(#)crc.c 8.1 (Berkeley) 6/17/93";
#else #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
#endif /* not lint */ #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" #include "extern.h"
static const u_int32_t crctab[] = { static const uint32_t crctab[] = {
0x0, 0x0,
0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b,
0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 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 * 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. * 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 int
crc(int fd, u_int32_t *cval, u_int32_t *clen) crc(int fd, uint32_t *cval, uint32_t *clen)
{ {
u_char *p; u_char *p;
int nr; ssize_t nr;
u_int32_t thecrc, len; uint32_t thecrc, len;
u_int32_t crctot; uint32_t crctot;
u_char buf[16 * 1024]; u_char buf[16 * 1024];
#define COMPUTE(var, ch) (var) = (var) << 8 ^ crctab[(var) >> 24 ^ (ch)] #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; crctot = ~crc_total;
while ((nr = read(fd, buf, sizeof(buf))) > 0) while ((nr = read(fd, buf, sizeof(buf))) > 0)
if (sflag) { if (sflag) {
for (len += nr, p = buf; nr--; ++p) { for (len += (uint32_t)nr, p = buf; nr--; ++p) {
COMPUTE(thecrc, *p); COMPUTE(thecrc, *p);
COMPUTE(crctot, *p); COMPUTE(crctot, *p);
} }
} else { } else {
for (len += nr, p = buf; nr--; ++p) for (len += (uint32_t)nr, p = buf; nr--; ++p)
COMPUTE(thecrc, *p); COMPUTE(thecrc, *p);
} }
if (nr < 0) if (nr < 0)
+60 -84
View File
@@ -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 * Copyright (c) 1989, 1993
@@ -38,7 +38,7 @@
#if 0 #if 0
static char sccsid[] = "@(#)create.c 8.1 (Berkeley) 6/6/93"; static char sccsid[] = "@(#)create.c 8.1 (Berkeley) 6/6/93";
#else #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
#endif /* not lint */ #endif /* not lint */
@@ -84,13 +84,6 @@ static uid_t uid;
static mode_t mode; static mode_t mode;
static u_long flags; 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 *, ...) static void output(FILE *, int, int *, const char *, ...)
__printflike(4, 5); __printflike(4, 5);
static int statd(FILE *, FTS *, FTSENT *, uid_t *, gid_t *, mode_t *, 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); 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 static void
statf(FILE *fp, int indent, FTSENT *p) statf(FILE *fp, int indent, FTSENT *p)
{ {
u_int32_t len, val; int offset;
int fd, offset;
const char *name = NULL; 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, "", offset = fprintf(fp, "%*s%s%s", indent, "",
S_ISDIR(p->fts_statp->st_mode) ? "" : " ", vispath(p->fts_name)); 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", output(fp, indent, &offset, "time=%jd.%09ld",
(intmax_t)p->fts_statp->st_mtime, (long)0); (intmax_t)p->fts_statp->st_mtime, (long)0);
#endif #endif
if (keys & F_CKSUM && S_ISREG(p->fts_statp->st_mode)) { if (S_ISREG(p->fts_statp->st_mode)) {
if ((fd = open(p->fts_accpath, O_RDONLY, 0)) < 0 || dosum(fp, indent, p, &offset, F_CKSUM, crcFile, "cksum");
crc(fd, &val, &len))
mtree_err("%s: %s", p->fts_accpath, strerror(errno));
close(fd);
output(fp, indent, &offset, "cksum=%lu", (long)val);
}
#ifndef NO_MD5 #ifndef NO_MD5
if (keys & F_MD5 && S_ISREG(p->fts_statp->st_mode)) { dosum(fp, indent, p, &offset, F_MD5, MD5File, MD5KEY);
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);
}
#endif /* ! NO_MD5 */ #endif /* ! NO_MD5 */
#ifndef NO_RMD160 #ifndef NO_RMD160
if (keys & F_RMD160 && S_ISREG(p->fts_statp->st_mode)) { dosum(fp, indent, p, &offset, F_RMD160, RMD160File, RMD160KEY);
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);
}
#endif /* ! NO_RMD160 */ #endif /* ! NO_RMD160 */
#ifndef NO_SHA1 #ifndef NO_SHA1
if (keys & F_SHA1 && S_ISREG(p->fts_statp->st_mode)) { dosum(fp, indent, p, &offset, F_SHA1, SHA1File, SHA1KEY);
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);
}
#endif /* ! NO_SHA1 */ #endif /* ! NO_SHA1 */
#ifndef NO_SHA2 #ifndef NO_SHA2
if (keys & F_SHA256 && S_ISREG(p->fts_statp->st_mode)) { dosum(fp, indent, p, &offset, F_SHA256, SHA256_File, SHA256KEY);
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);
}
#ifdef SHA384_BLOCK_LENGTH #ifdef SHA384_BLOCK_LENGTH
if (keys & F_SHA384 && S_ISREG(p->fts_statp->st_mode)) { dosum(fp, indent, p, &offset, F_SHA384, SHA384_File, SHA384KEY);
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);
}
#endif #endif
if (keys & F_SHA512 && S_ISREG(p->fts_statp->st_mode)) { dosum(fp, indent, p, &offset, F_SHA512, SHA512_File, SHA512KEY);
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);
}
#endif /* ! NO_SHA2 */ #endif /* ! NO_SHA2 */
}
if (keys & F_SLINK && if (keys & F_SLINK &&
(p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE)) (p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE))
output(fp, indent, &offset, "link=%s", 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); 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 void
output(FILE *fp, int indent, int *offset, const char *fmt, ...) output(FILE *fp, int indent, int *offset, const char *fmt, ...)
{ {
+10 -3
View File
@@ -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 * Copyright (c) 1991, 1993
@@ -49,6 +49,12 @@
#include <netdb.h> #include <netdb.h>
#endif #endif
#if defined(__FreeBSD__) && !defined(HAVE_NBTOOL_CONFIG_H)
#define FTS_CONST const
#else
#define FTS_CONST
#endif
#ifndef MAXHOSTNAMELEN #ifndef MAXHOSTNAMELEN
#define MAXHOSTNAMELEN 256 #define MAXHOSTNAMELEN 256
#endif #endif
@@ -62,8 +68,9 @@ enum flavor {
void addtag(slist_t *, char *); void addtag(slist_t *, char *);
int check_excludes(const char *, const char *); int check_excludes(const char *, const char *);
int compare(NODE *, FTSENT *); int compare(NODE *, FTSENT *);
int crc(int, u_int32_t *, u_int32_t *); int crc(int, uint32_t *, uint32_t *);
void cwalk(FILE *); void cwalk(FILE *);
int dcmp(const FTSENT *FTS_CONST *, const FTSENT *FTS_CONST *);
void dump_nodes(FILE *, const char *, NODE *, int); void dump_nodes(FILE *, const char *, NODE *, int);
void init_excludes(void); void init_excludes(void);
int matchtags(NODE *); 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 int mtree_Mflag, mtree_Sflag, mtree_Wflag;
extern size_t mtree_lineno; extern size_t mtree_lineno;
extern enum flavor flavor; extern enum flavor flavor;
extern u_int32_t crc_total; extern uint32_t crc_total;
extern int ftsoptions, keys; extern int ftsoptions, keys;
extern char fullpath[]; extern char fullpath[];
extern slist_t includetags, excludetags; extern slist_t includetags, excludetags;
+5 -5
View File
@@ -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 * Copyright (c) 1991, 1993
@@ -37,7 +37,7 @@
#include <sys/cdefs.h> #include <sys/cdefs.h>
#if defined(__RCSID) && !defined(lint) #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 */ #endif /* not lint */
#include <sys/types.h> #include <sys/types.h>
@@ -111,7 +111,7 @@ slist_t excludetags, includetags;
int keys = KEYDEFAULT; int keys = KEYDEFAULT;
int keycompare(const void *, const void *); static int keycompare(const void *, const void *);
u_int u_int
parsekey(const char *name, int *needvaluep) parsekey(const char *name, int *needvaluep)
@@ -153,7 +153,7 @@ parsetype(const char *name)
return (k->val); return (k->val);
} }
int static int
keycompare(const void *a, const void *b) keycompare(const void *a, const void *b)
{ {
@@ -198,7 +198,7 @@ void
parsetags(slist_t *list, char *args) parsetags(slist_t *list, char *args)
{ {
char *p, *e; char *p, *e;
int len; size_t len;
if (args == NULL) { if (args == NULL) {
addtag(list, NULL); addtag(list, NULL);
+108 -31
View File
@@ -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 .\" Copyright (c) 1989, 1990, 1993
.\" The Regents of the University of California. All rights reserved. .\" The Regents of the University of California. All rights reserved.
@@ -56,7 +56,7 @@
.\" .\"
.\" @(#)mtree.8 8.2 (Berkeley) 12/11/93 .\" @(#)mtree.8 8.2 (Berkeley) 12/11/93
.\" .\"
.Dd February 3, 2013 .Dd December 2, 2023
.Dt MTREE 8 .Dt MTREE 8
.Os .Os
.Sh NAME .Sh NAME
@@ -93,9 +93,11 @@ characteristics do not match the specification, or which are
missing from either the file hierarchy or the specification. missing from either the file hierarchy or the specification.
.Pp .Pp
The options are as follows: The options are as follows:
.Bl -tag -width Xxxexcludexfilexx .Bl -tag -width Fl
.
.It Fl b .It Fl b
Suppress blank lines before entering and after exiting directories. Suppress blank lines before entering and after exiting directories.
.
.It Fl C .It Fl C
Convert a specification into Convert a specification into
a format that's easier to parse with various tools. 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 In the output, each file or directory is represented using a single line
(which might be very long). (which might be very long).
The full path name The full path name
(beginning with .Pq beginning with Ql \&./
.Dq \&./ )
is always printed as the first field; is always printed as the first field;
.Fl K , .Fl K ,
.Fl k , .Fl k ,
@@ -120,19 +121,25 @@ can be used to control which files are printed;
and the and the
.Fl S .Fl S
option can be used to sort the output. option can be used to sort the output.
.
.It Fl c .It Fl c
Print a specification for the file hierarchy originating at Print a specification for the file hierarchy originating at
the current working directory (or the directory provided by the current working directory
.Fl p Ar path ) .Po or the directory provided by
.Fl p Ar path
.Pc
to the standard output. to the standard output.
The output is in a style using relative path names. The output is in a style using relative path names.
.
.It Fl D .It Fl D
As per As per
.Fl C , .Fl C ,
except that the path name is always printed as the last field instead of except that the path name is always printed as the last field instead of
the first. the first.
.
.It Fl d .It Fl d
Ignore everything except directory type files. Ignore everything except directory type files.
.
.It Fl E Ar tags .It Fl E Ar tags
Add the comma separated tags to the Add the comma separated tags to the
.Dq exclusion .Dq exclusion
@@ -141,9 +148,11 @@ Non-directories with tags which are in the exclusion list are not printed with
.Fl C .Fl C
and and
.Fl D . .Fl D .
.
.It Fl e .It Fl e
Don't complain about files that are in the file hierarchy, but not in the Don't complain about files that are in the file hierarchy, but not in the
specification. specification.
.
.It Fl F Ar flavor .It Fl F Ar flavor
Set the compatibility flavor of the Set the compatibility flavor of the
.Nm .Nm
@@ -151,22 +160,23 @@ utility.
The The
.Ar flavor .Ar flavor
can be one of can be one of
.Sy mtree , .Cm mtree ,
.Sy freebsd9 , .Cm freebsd9 ,
or or
.Sy netbsd6 . .Cm netbsd6 .
The default is The default is
.Sy mtree . .Cm mtree .
The The
.Sy freebsd9 .Cm freebsd9
and and
.Sy netbsd6 .Cm netbsd6
flavors attempt to preserve output compatiblity and command line option flavors attempt to preserve output compatibility and command line option
backward compatibility with backward compatibility with
.Fx 9.0 .Fx 9.0
and and
.Nx 6.0 .Nx 6.0
respectively. respectively.
.
.It Fl f Ar spec .It Fl f Ar spec
Read the specification from Read the specification from
.Ar file , .Ar file ,
@@ -178,10 +188,18 @@ The specifications will be sorted like output generated using
.Fl c . .Fl c .
The output format in this case is somewhat reminiscent of The output format in this case is somewhat reminiscent of
.Xr comm 1 , .Xr comm 1 ,
having "in first spec only", "in second spec only", and "different" having
columns, prefixed by zero, one and two TAB characters respectively. .Dq in first spec only ,
Each entry in the "different" column occupies two lines, one from each .Dq in second spec only ,
specification. 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 .It Fl I Ar tags
Add the comma separated tags to the Add the comma separated tags to the
.Dq inclusion .Dq inclusion
@@ -191,14 +209,22 @@ Non-directories with tags which are in the inclusion list are printed with
and and
.Fl D . .Fl D .
If no inclusion list is provided, the default is to display all files. If no inclusion list is provided, the default is to display all files.
.
.It Fl i .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 .It Fl j
Indent the output 4 spaces each time a directory level is descended when Indent the output 4 spaces each time a directory level is descended when
creating a specification with the creating a specification with the
.Fl c .Fl c
option. 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. directory.
It does however affect the comment before the close of each directory. It does however affect the comment before the close of each directory.
This is the equivalent of the This is the equivalent of the
@@ -207,26 +233,31 @@ option in the
.Fx .Fx
version of version of
.Nm . .Nm .
.
.It Fl K Ar keywords .It Fl K Ar keywords
Add the specified (whitespace or comma separated) keywords to the current Add the specified (whitespace or comma separated) keywords to the current
set of keywords. set of keywords.
If If
.Ql all .Ql all
is specified, add all of the other keywords. is specified, add all of the other keywords.
.
.It Fl k Ar keywords .It Fl k Ar keywords
Use the Use the
.Sy type .Sy type
keyword plus the specified (whitespace or comma separated) 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 If
.Ql all .Ql all
is specified, use all of the other keywords. is specified, use all of the other keywords.
If the If the
.Sy type .Sy type
keyword is not desired, suppress it with keyword is not desired, suppress it with
.Fl R Ar type . .Fl R Cm type .
.
.It Fl L .It Fl L
Follow all symbolic links in the file hierarchy. Follow all symbolic links in the file hierarchy.
.
.It Fl l .It Fl l
Do Do
.Dq loose .Dq loose
@@ -235,7 +266,7 @@ will match less stringent ones.
For example, a file marked mode 0444 For example, a file marked mode 0444
will pass a check for mode 0644. will pass a check for mode 0644.
.Dq Loose .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 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 set either in the specification or the file, exact checking will be
performed. performed.
@@ -244,17 +275,25 @@ This option may not be set at the same time as the
or or
.Fl u .Fl u
option. option.
.
.It Fl M .It Fl M
Permit merging of specification entries with different types, Permit merging of specification entries with different types,
with the last entry taking precedence. with the last entry taking precedence.
.
.It Fl m .It Fl m
If the schg and/or sappnd flags are specified, reset these flags. If the
Note that this is only possible with securelevel less than 1 (i.e., .Ql schg
in single user mode or while the system is running in insecure and/or
mode). .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 See
.Xr init 8 .Xr init 8
for information on security levels. for information on security levels.
.
.It Fl n .It Fl n
Do not emit pathname comments when creating a specification. Do not emit pathname comments when creating a specification.
Normally Normally
@@ -262,6 +301,7 @@ a comment is emitted before each directory and before the close of that
directory when using the directory when using the
.Fl c .Fl c
option. option.
.
.It Fl N Ar dbdir .It Fl N Ar dbdir
Use the user database text file Use the user database text file
.Pa master.passwd .Pa master.passwd
@@ -274,31 +314,42 @@ rather than using the results from the system's
and and
.Xr getgrnam 3 .Xr getgrnam 3
(and related) library calls. (and related) library calls.
.
.It Fl O Ar onlypaths .It Fl O Ar onlypaths
Only include files included in this list of pathnames. Only include files included in this list of pathnames.
.
.It Fl P .It Fl P
Don't follow symbolic links in the file hierarchy, instead consider Don't follow symbolic links in the file hierarchy, instead consider
the symbolic link itself in any comparisons. the symbolic link itself in any comparisons.
This is the default. This is the default.
.
.It Fl p Ar path .It Fl p Ar path
Use the file hierarchy rooted in Use the file hierarchy rooted in
.Ar path , .Ar path ,
instead of the current directory. instead of the current directory.
.
.It Fl q .It Fl q
Quiet mode. Quiet mode.
Do not complain when a Do not complain when a
.Dq missing .Dq missing
directory cannot be created because it already exists. directory cannot be created because it already exists.
This occurs when the directory is a symbolic link. This occurs when the directory is a symbolic link.
.
.It Fl R Ar keywords .It Fl R Ar keywords
Remove the specified (whitespace or comma separated) keywords from the current Remove the specified (whitespace or comma separated) keywords from the current
set of keywords. set of keywords.
If If
.Ql all .Ql all
is specified, remove all of the other keywords. is specified, remove all of the other keywords.
.
.It Fl r .It Fl r
Remove any files in the file hierarchy that are not described in the Remove any files in the file hierarchy that are not described in the
specification. 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 .It Fl S
When reading a specification into an internal data structure, When reading a specification into an internal data structure,
sort the entries. sort the entries.
@@ -320,19 +371,23 @@ By default, if the
.Fl S .Fl S
option is not used, entries within the same directory are collected option is not used, entries within the same directory are collected
together (separated from entries for other directories), but not sorted. together (separated from entries for other directories), but not sorted.
.
.It Fl s Ar seed .It Fl s Ar seed
Display a single checksum to the standard error output that represents all Display a single checksum to the standard error output that represents all
of the files for which the keyword of the files for which the keyword
.Sy cksum .Sy cksum
was specified. was specified.
The checksum is seeded with the specified value. The checksum is seeded with the specified value.
.
.It Fl t .It Fl t
Modify the modified time of existing files, the device type of devices, and Modify the modified time of existing files, the device type of devices, and
symbolic link targets, to match the specification. symbolic link targets, to match the specification.
.
.It Fl U .It Fl U
Same as Same as
.Fl u .Fl u
except that a mismatch is not considered to be an error if it was corrected. except that a mismatch is not considered to be an error if it was corrected.
.
.It Fl u .It Fl u
Modify the owner, group, permissions, and flags of existing files, Modify the owner, group, permissions, and flags of existing files,
the device type of devices, and symbolic link targets, 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, Exit with a status of 0 on success,
2 if the file hierarchy did not match the specification, and 2 if the file hierarchy did not match the specification, and
1 if any other error occurred. 1 if any other error occurred.
.
.It Fl W .It Fl W
Don't attempt to set various file attributes such as the Don't attempt to set various file attributes such as the
ownership, mode, flags, or time ownership, mode, flags, or time
@@ -358,6 +414,7 @@ This option will be most useful when used in conjunction with
.Fl U .Fl U
or or
.Fl u . .Fl u .
.
.It Fl X Ar exclude-file .It Fl X Ar exclude-file
The specified file contains The specified file contains
.Xr fnmatch 3 .Xr fnmatch 3
@@ -370,11 +427,14 @@ the starting directory); otherwise,
it will be matched against basenames only. it will be matched against basenames only.
Comments are permitted in Comments are permitted in
the the
.Ar exclude-list .Ar exclude-file
file. file.
.
.It Fl x .It Fl x
Don't descend below mount points in the file hierarchy. Don't descend below mount points in the file hierarchy.
.
.El .El
.
.Pp .Pp
Specifications are mostly composed of Specifications are mostly composed of
.Dq keywords , .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. checks based on it are performed.
.Pp .Pp
Currently supported keywords are as follows: Currently supported keywords are as follows:
.Bl -tag -width sha384digestxx .
.Bl -tag -width Sy
.It Sy cksum .It Sy cksum
The checksum of the file using the default algorithm specified by The checksum of the file using the default algorithm specified by
the the
@@ -420,6 +481,7 @@ format.)
.It Ar number .It Ar number
Opaque number (as stored on the file system). Opaque number (as stored on the file system).
.El .El
.
.Pp .Pp
The following values for The following values for
.Ar format .Ar format
@@ -614,9 +676,24 @@ they match.
.Nm .Nm
uses uses
.Xr strsvis 3 .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. non-printable characters.
Whitespace characters are encoded as 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 .Ql \es
(space), (space),
.Ql \et .Ql \et
@@ -678,7 +755,7 @@ The
utility exits with a status of 0 on success, 1 if any error occurred, 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. and 2 if the file hierarchy did not match the specification.
.Sh FILES .Sh FILES
.Bl -tag -width /etc/mtree -compact .Bl -tag -width Pa -compact
.It Pa /etc/mtree .It Pa /etc/mtree
system specification directory system specification directory
.El .El
+4 -4
View File
@@ -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 * Copyright (c) 1989, 1990, 1993
@@ -43,7 +43,7 @@ __COPYRIGHT("@(#) Copyright (c) 1989, 1990, 1993\
#if 0 #if 0
static char sccsid[] = "@(#)mtree.c 8.1 (Berkeley) 6/6/93"; static char sccsid[] = "@(#)mtree.c 8.1 (Berkeley) 6/6/93";
#else #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
#endif /* not lint */ #endif /* not lint */
@@ -195,7 +195,7 @@ main(int argc, char **argv)
qflag = 1; qflag = 1;
break; break;
case 'r': case 'r':
rflag = 1; rflag++;
break; break;
case 'R': case 'R':
while ((p = strsep(&optarg, " \t,")) != NULL) while ((p = strsep(&optarg, " \t,")) != NULL)
@@ -204,7 +204,7 @@ main(int argc, char **argv)
break; break;
case 's': case 's':
sflag = 1; sflag = 1;
crc_total = ~strtol(optarg, &p, 0); crc_total = (uint32_t)~strtol(optarg, &p, 0);
if (*p) if (*p)
mtree_err("illegal seed value -- %s", optarg); mtree_err("illegal seed value -- %s", optarg);
break; break;
+36 -8
View File
@@ -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 * Copyright (c) 1989, 1993
@@ -67,7 +67,7 @@
#if 0 #if 0
static char sccsid[] = "@(#)spec.c 8.2 (Berkeley) 4/28/95"; static char sccsid[] = "@(#)spec.c 8.2 (Berkeley) 4/28/95";
#else #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
#endif /* not lint */ #endif /* not lint */
@@ -224,10 +224,14 @@ noparent: mtree_err("no parent node");
*/ */
if (strcmp(centry->name, ".") == 0 && centry->type == 0) if (strcmp(centry->name, ".") == 0 && centry->type == 0)
centry->type = F_DIR; centry->type = F_DIR;
if (strcmp(centry->name, ".") != 0 || if (strcmp(centry->name, ".") != 0)
centry->type != F_DIR)
mtree_err( 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; last = root = centry;
root->parent = root; root->parent = root;
} else if (pathparent != NULL) { } else if (pathparent != NULL) {
@@ -539,7 +543,8 @@ replacenode(NODE *cur, NODE *new)
static void static void
set(char *t, NODE *ip) set(char *t, NODE *ip)
{ {
int type, value, len; int type, value;
size_t len;
gid_t gid; gid_t gid;
uid_t uid; uid_t uid;
char *kw, *val, *md, *ep; char *kw, *val, *md, *ep;
@@ -838,7 +843,7 @@ addchild(NODE *pathparent, NODE *centry)
* directories sort after non-directories, but otherwise sort in * directories sort after non-directories, but otherwise sort in
* strcmp() order. * strcmp() order.
* *
* Keep this in sync with dcmp() in create.c. * Keep this in sync with dcmp() below.
*/ */
static int static int
nodecmp(const NODE *a, const NODE *b) nodecmp(const NODE *a, const NODE *b)
@@ -847,7 +852,30 @@ nodecmp(const NODE *a, const NODE *b)
if ((a->type & F_DIR) != 0) { if ((a->type & F_DIR) != 0) {
if ((b->type & F_DIR) == 0) if ((b->type & F_DIR) == 0)
return 1; return 1;
} else if ((b->type & F_DIR) != 0) } else if ((b->type & F_DIR) != 0) {
return -1; return -1;
}
return strcmp(a->name, b->name); return strcmp(a->name, b->name);
} }
/*
* 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() above.
*/
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);
}
+2 -2
View File
@@ -1,4 +1,4 @@
/* $NetBSD: specspec.c,v 1.2 2012/10/05 01:27:29 christos Exp $ */ /* $NetBSD: specspec.c,v 1.5 2023/12/02 13:24:00 christos Exp $ */
/*- /*-
* Copyright (c) 2003 Poul-Henning Kamp * Copyright (c) 2003 Poul-Henning Kamp
@@ -31,7 +31,7 @@
#endif #endif
#include <sys/cdefs.h> #include <sys/cdefs.h>
__RCSID("$NetBSD: specspec.c,v 1.2 2012/10/05 01:27:29 christos Exp $"); __RCSID("$NetBSD: specspec.c,v 1.5 2023/12/02 13:24:00 christos Exp $");
#include <err.h> #include <err.h>
#include <grp.h> #include <grp.h>
+12 -5
View File
@@ -1,4 +1,4 @@
/* $NetBSD: verify.c,v 1.44 2013/02/03 19:15:17 christos Exp $ */ /* $NetBSD: verify.c,v 1.50 2024/12/11 14:52:26 christos Exp $ */
/*- /*-
* Copyright (c) 1990, 1993 * Copyright (c) 1990, 1993
@@ -38,7 +38,7 @@
#if 0 #if 0
static char sccsid[] = "@(#)verify.c 8.1 (Berkeley) 6/6/93"; static char sccsid[] = "@(#)verify.c 8.1 (Berkeley) 6/6/93";
#else #else
__RCSID("$NetBSD: verify.c,v 1.44 2013/02/03 19:15:17 christos Exp $"); __RCSID("$NetBSD: verify.c,v 1.50 2024/12/11 14:52:26 christos Exp $");
#endif #endif
#endif /* not lint */ #endif /* not lint */
@@ -86,7 +86,7 @@ vwalk(void)
argv[0] = dot; argv[0] = dot;
argv[1] = NULL; argv[1] = NULL;
if ((t = fts_open(argv, ftsoptions, NULL)) == NULL) if ((t = fts_open(argv, ftsoptions, dcmp)) == NULL)
mtree_err("fts_open: %s", strerror(errno)); mtree_err("fts_open: %s", strerror(errno));
level = root; level = root;
specdepth = rval = 0; specdepth = rval = 0;
@@ -147,8 +147,15 @@ vwalk(void)
continue; continue;
extra: extra:
if (!eflag && !(dflag && p->fts_info == FTS_SL)) { if (!eflag && !(dflag && p->fts_info == FTS_SL)) {
printf("extra: %s", RP(p)); printf(flavor == F_FREEBSD9 ? "%s extra" : "extra: %s",
RP(p));
if (rflag) { if (rflag) {
#if HAVE_STRUCT_STAT_ST_FLAGS
if (rflag > 1 &&
lchflags(p->fts_accpath, 0) == -1)
printf(" (chflags %s)",
strerror(errno));
#endif
if ((S_ISDIR(p->fts_statp->st_mode) if ((S_ISDIR(p->fts_statp->st_mode)
? rmdir : unlink)(p->fts_accpath)) { ? rmdir : unlink)(p->fts_accpath)) {
printf(", not removed: %s", printf(", not removed: %s",
@@ -174,7 +181,7 @@ miss(NODE *p, char *tail)
int create; int create;
char *tp; char *tp;
const char *type; const char *type;
u_int32_t flags; u_long flags;
for (; p; p = p->next) { for (; p; p = p->next) {
if (p->flags & F_OPT && !(p->flags & F_VISIT)) if (p->flags & F_OPT && !(p->flags & F_VISIT))