NetBSD Problem Report #59838
From www@netbsd.org Mon Dec 15 05:15:37 2025
Return-Path: <www@netbsd.org>
Received: from mail.netbsd.org (mail.netbsd.org [199.233.217.200])
(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)
key-exchange X25519 server-signature RSA-PSS (2048 bits)
client-signature RSA-PSS (2048 bits))
(Client CN "mail.NetBSD.org", Issuer "mail.NetBSD.org CA" (not verified))
by mollari.NetBSD.org (Postfix) with ESMTPS id 46D9C1A9239
for <gnats-bugs@gnats.NetBSD.org>; Mon, 15 Dec 2025 05:15:37 +0000 (UTC)
Message-Id: <20251215051535.DFDD71A923A@mollari.NetBSD.org>
Date: Mon, 15 Dec 2025 05:15:35 +0000 (UTC)
From: jlduran@gmail.com
Reply-To: jlduran@gmail.com
To: gnats-bugs@NetBSD.org
Subject: mtree: Fix parsing 'K', 'k', with 'R' flags
X-Send-Pr-Version: www-1.0
>Number: 59838
>Category: bin
>Synopsis: mtree: Fix parsing 'K', 'k', with 'R' flags
>Confidential: no
>Severity: non-critical
>Priority: medium
>Responsible: bin-bug-people
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Mon Dec 15 05:20:00 +0000 2025
>Last-Modified: Thu Jan 08 06:15:00 +0000 2026
>Originator: Jose Luis Duran
>Release: trunk
>Organization:
FreeBSD
>Environment:
>Description:
It was reported on
https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=219467
that an mtree command with -k and -R flags do not work as expected.
In mtree, the -k flag uses the type keyword plus the specified keywords. If the type keyword is not desired, it can be suppressed with -R type.
But issuing:
# mtree -cn -R type -k flags -p /usr/bin/ -x | grep type=
Doesn't seem to work as expected.
>How-To-Repeat:
# mtree -cn -R type -k flags -p /usr/bin/ -x | grep type=
>Fix:
A very straightforward solution is offered:
Move the parsing of the keywords for the 'K', 'k', and 'R' flags outside the getopt loop, so that the order of the flags does not matter.
Also, check for the presence of the F_TYPE flag before printing the type keyword.
---
contrib/mtree/create.c | 3 ++-
contrib/mtree/mtree.c | 30 +++++++++++++++++++++---------
2 files changed, 23 insertions(+), 10 deletions(-)
diff --git a/contrib/mtree/create.c b/contrib/mtree/create.c
index e23004851f39..245b9efa1c35 100644
--- a/contrib/mtree/create.c
+++ b/contrib/mtree/create.c
@@ -236,7 +236,8 @@ statf(FILE *fp, int indent, FTSENT *p)
offset += fprintf(fp, "%*s",
(INDENTNAMELEN + indent) - offset, "");
- if (!S_ISREG(p->fts_statp->st_mode) && (flavor == F_NETBSD6 || !dflag))
+ if (keys & F_TYPE && !S_ISREG(p->fts_statp->st_mode) &&
+ (flavor == F_NETBSD6 || !dflag))
output(fp, indent, &offset, "type=%s",
inotype(p->fts_statp->st_mode));
if (keys & (F_UID | F_UNAME) && p->fts_statp->st_uid != uid) {
diff --git a/contrib/mtree/mtree.c b/contrib/mtree/mtree.c
index 28f09fa32210..198db961e305 100644
--- a/contrib/mtree/mtree.c
+++ b/contrib/mtree/mtree.c
@@ -80,12 +80,14 @@ main(int argc, char **argv)
int ch, status;
unsigned int i;
int cflag, Cflag, Dflag, Uflag, wflag;
+ char *koptarg, *Koptarg, *Roptarg;
char *dir, *p;
FILE *spec1, *spec2;
setprogname(argv[0]);
cflag = Cflag = Dflag = Uflag = wflag = 0;
+ koptarg = Koptarg = Roptarg = NULL;
dir = NULL;
init_excludes();
spec1 = stdin;
@@ -150,14 +152,10 @@ main(int argc, char **argv)
break;
case 'k':
keys = F_TYPE;
- while ((p = strsep(&optarg, " \t,")) != NULL)
- if (*p != '\0')
- keys |= parsekey(p, NULL);
+ koptarg = optarg;
break;
case 'K':
- while ((p = strsep(&optarg, " \t,")) != NULL)
- if (*p != '\0')
- keys |= parsekey(p, NULL);
+ Koptarg = optarg;
break;
case 'l':
lflag = 1;
@@ -198,9 +196,7 @@ main(int argc, char **argv)
rflag++;
break;
case 'R':
- while ((p = strsep(&optarg, " \t,")) != NULL)
- if (*p != '\0')
- keys &= ~parsekey(p, NULL);
+ Roptarg = optarg;
break;
case 's':
sflag = 1;
@@ -243,6 +239,22 @@ main(int argc, char **argv)
if (argc)
usage();
+ if (koptarg != NULL) {
+ while ((p = strsep(&koptarg, " \t,")) != NULL)
+ if (*p != '\0')
+ keys |= parsekey(p, NULL);
+ }
+ if (Koptarg != NULL) {
+ while ((p = strsep(&Koptarg, " \t,")) != NULL)
+ if (*p != '\0')
+ keys |= parsekey(p, NULL);
+ }
+ if (Roptarg != NULL) {
+ while ((p = strsep(&Roptarg, " \t,")) != NULL)
+ if (*p != '\0')
+ keys &= ~parsekey(p, NULL);
+ }
+
switch (flavor) {
case F_FREEBSD9:
if (cflag && iflag) {
>Audit-Trail:
From: "Christos Zoulas" <christos@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc:
Subject: PR/59838 CVS commit: src/usr.sbin/mtree
Date: Thu, 18 Dec 2025 13:16:48 -0500
Module Name: src
Committed By: christos
Date: Thu Dec 18 18:16:48 UTC 2025
Modified Files:
src/usr.sbin/mtree: create.c
Log Message:
PR/59838: Jose Louis Duran: Check for F_TYPE before printing the type
To generate a diff of this commit:
cvs rdiff -u -r1.79 -r1.80 src/usr.sbin/mtree/create.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
From: "Christos Zoulas" <christos@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc:
Subject: PR/59838 CVS commit: src/usr.sbin/mtree
Date: Thu, 18 Dec 2025 13:17:26 -0500
Module Name: src
Committed By: christos
Date: Thu Dec 18 18:17:26 UTC 2025
Modified Files:
src/usr.sbin/mtree: mtree.c
Log Message:
PR/59838: Jose Louis Duran: Save the R mask and apply it at the end so the
order of -k -K -R does not matter.
To generate a diff of this commit:
cvs rdiff -u -r1.51 -r1.52 src/usr.sbin/mtree/mtree.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
From: Jose Luis Duran <jlduran@gmail.com>
To: gnats-bugs@netbsd.org
Cc:
Subject: Re: PR/59838 CVS commit: src/usr.sbin/mtree
Date: Thu, 18 Dec 2025 18:26:14 -0300
> Log Message:
> PR/59838: Jose Louis Duran: Save the R mask and apply it at the end so the
> order of -k -K -R does not matter.
Thank you, beautiful implementation!
I also had to:
--- a/usr.sbin/mtree/mtree.c
+++ b/usr.sbin/mtree/mtree.c
@@ -72,6 +72,7 @@ static struct {
{F_NETBSD6, "netbsd6"},
};
+static int parsekeys(char **);
__dead static void usage(void);
int
And I have a question, if this is also needed?:
--- a/usr.sbin/mtree/create.c
+++ b/usr.sbin/mtree/create.c
@@ -402,10 +402,13 @@ statd(FILE *fp, FTS *t, FTSENT *parent, uid_t
*puid, gid_t *pgid, mode_t *pmode,
((keys & F_FLAGS) && (*pflags != saveflags)) ||
first) {
first = 0;
- if (flavor != F_NETBSD6 && dflag)
- fprintf(fp, "/set type=dir");
- else
- fprintf(fp, "/set type=file");
+ fprintf(fp, "/set");
+ if (keys & F_TYPE) {
+ if (flavor != F_NETBSD6 && dflag)
+ fprintf(fp, " type=dir");
+ else
+ fprintf(fp, " type=file");
+ }
if (keys & (F_UID | F_UNAME)) {
if (keys & F_UNAME &&
(name = user_from_uid(saveuid, 1)) != NULL)
I'm worried that: `mtree -cn -k flags -R flags,type -p /usr/bin/ -x`
would result in a bad specification.
Thank you!
From: Jose Luis Duran <jlduran@gmail.com>
To: gnats-bugs@netbsd.org
Cc:
Subject: Re: PR/59838 CVS commit: src/usr.sbin/mtree
Date: Fri, 19 Dec 2025 11:12:40 -0300
> I also had to:
>
> --- a/usr.sbin/mtree/mtree.c
> +++ b/usr.sbin/mtree/mtree.c
> @@ -72,6 +72,7 @@ static struct {
> {F_NETBSD6, "netbsd6"},
> };
>
> +static int parsekeys(char **);
> __dead static void usage(void);
>
> int
It is not needed, the function prototype is there, I just didn't see it.
> And I have a question, if this is also needed?:
>
> --- a/usr.sbin/mtree/create.c
> +++ b/usr.sbin/mtree/create.c
> @@ -402,10 +402,13 @@ statd(FILE *fp, FTS *t, FTSENT *parent, uid_t
> *puid, gid_t *pgid, mode_t *pmode,
> ((keys & F_FLAGS) && (*pflags != saveflags)) ||
> first) {
> first = 0;
> - if (flavor != F_NETBSD6 && dflag)
> - fprintf(fp, "/set type=dir");
> - else
> - fprintf(fp, "/set type=file");
> + fprintf(fp, "/set");
> + if (keys & F_TYPE) {
> + if (flavor != F_NETBSD6 && dflag)
> + fprintf(fp, " type=dir");
> + else
> + fprintf(fp, " type=file");
> + }
> if (keys & (F_UID | F_UNAME)) {
> if (keys & F_UNAME &&
> (name = user_from_uid(saveuid, 1)) != NULL)
>
> I'm worried that: `mtree -cn -k flags -R flags,type -p /usr/bin/ -x`
> would result in a bad specification.
I believe it should also check for the presence of F_TYPE before
printing "/set":
--- a/usr.sbin/mtree/create.c
+++ b/usr.sbin/mtree/create.c
@@ -396,16 +396,20 @@ statd(FILE *fp, FTS *t, FTSENT *parent, uid_t
*puid, gid_t *pgid, mode_t *pmode,
* output a new one. So first we check to see if anything changed.
* Note that we always output a /set record for the first directory.
*/
- if (((keys & (F_UNAME | F_UID)) && (*puid != saveuid)) ||
+ if ((keys & F_TYPE) ||
+ ((keys & (F_UNAME | F_UID)) && (*puid != saveuid)) ||
((keys & (F_GNAME | F_GID)) && (*pgid != savegid)) ||
- ((keys & F_MODE) && (*pmode != savemode)) ||
+ ((keys & F_MODE) && (*pmode != savemode)) ||
((keys & F_FLAGS) && (*pflags != saveflags)) ||
first) {
first = 0;
- if (flavor != F_NETBSD6 && dflag)
- fprintf(fp, "/set type=dir");
- else
- fprintf(fp, "/set type=file");
+ fprintf(fp, "/set");
+ if (keys & F_TYPE) {
+ if (flavor != F_NETBSD6 && dflag)
+ fprintf(fp, " type=dir");
+ else
+ fprintf(fp, " type=file");
+ }
if (keys & (F_UID | F_UNAME)) {
if (keys & F_UNAME &&
(name = user_from_uid(saveuid, 1)) != NULL)
Thank you!
--
Jose Luis Duran
From: Christos Zoulas <christos@zoulas.com>
To: gnats-bugs@netbsd.org
Cc: gnats-admin@netbsd.org,
netbsd-bugs@netbsd.org,
jlduran@gmail.com
Subject: Re: PR/59838 CVS commit: src/usr.sbin/mtree
Date: Fri, 19 Dec 2025 09:22:13 -0500
--Apple-Mail=_18CAC5AA-D2D7-4EAB-94BC-CBDF68E67A1E
Content-Transfer-Encoding: quoted-printable
Content-Type: text/plain;
charset=utf-8
> On Dec 19, 2025, at 9:15=E2=80=AFAM, Jose Luis Duran via gnats =
<gnats-admin@netbsd.org> wrote:
>=20
> The following reply was made to PR bin/59838; it has been noted by =
GNATS.
>=20
[stuff deleted]
> I believe it should also check for the presence of F_TYPE before
> printing "/set":
>=20
> --- a/usr.sbin/mtree/create.c
> +++ b/usr.sbin/mtree/create.c
> @@ -396,16 +396,20 @@ statd(FILE *fp, FTS *t, FTSENT *parent, uid_t
> *puid, gid_t *pgid, mode_t *pmode,
> * output a new one. So first we check to see if anything =
changed.
> * Note that we always output a /set record for the first =
directory.
> */
> - if (((keys & (F_UNAME | F_UID)) && (*puid !=3D saveuid)) ||
> + if ((keys & F_TYPE) ||
> + ((keys & (F_UNAME | F_UID)) && (*puid !=3D saveuid)) ||
> ((keys & (F_GNAME | F_GID)) && (*pgid !=3D savegid)) ||
> - ((keys & F_MODE) && (*pmode !=3D savemode)) ||
> + ((keys & F_MODE) && (*pmode !=3D savemode)) ||
> ((keys & F_FLAGS) && (*pflags !=3D saveflags)) ||
> first) {
> first =3D 0;
> - if (flavor !=3D F_NETBSD6 && dflag)
> - fprintf(fp, "/set type=3Ddir");
> - else
> - fprintf(fp, "/set type=3Dfile");
> + fprintf(fp, "/set");
> + if (keys & F_TYPE) {
> + if (flavor !=3D F_NETBSD6 && dflag)
> + fprintf(fp, " type=3Ddir");
> + else
> + fprintf(fp, " type=3Dfile");
> + }
> if (keys & (F_UID | F_UNAME)) {
> if (keys & F_UNAME &&
> (name =3D user_from_uid(saveuid, 1)) !=3D =
NULL)
>=20
We do we need to check F_TYPE twice? It is in the outer if...
christos
--Apple-Mail=_18CAC5AA-D2D7-4EAB-94BC-CBDF68E67A1E
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
filename=signature.asc
Content-Type: application/pgp-signature;
name=signature.asc
Content-Description: Message signed with OpenPGP
-----BEGIN PGP SIGNATURE-----
Comment: GPGTools - http://gpgtools.org
iF0EARECAB0WIQS+BJlbqPkO0MDBdsRxESqxbLM7OgUCaUVflQAKCRBxESqxbLM7
OtaqAJ4x8GwpuM9jKMnL0DIKHfS0oOv25ACdGZvRn7fDPcwBeI8IvHQYpHroBoI=
=sihb
-----END PGP SIGNATURE-----
--Apple-Mail=_18CAC5AA-D2D7-4EAB-94BC-CBDF68E67A1E--
From: Jose Luis Duran <jlduran@gmail.com>
To: Christos Zoulas <christos@zoulas.com>
Cc: gnats-bugs@netbsd.org, gnats-admin@netbsd.org, netbsd-bugs@netbsd.org
Subject: Re: PR/59838 CVS commit: src/usr.sbin/mtree
Date: Fri, 19 Dec 2025 11:34:45 -0300
On Fri, Dec 19, 2025 at 11:22=E2=80=AFAM Christos Zoulas <christos@zoulas.c=
om> wrote:
>
>
>
> > On Dec 19, 2025, at 9:15=E2=80=AFAM, Jose Luis Duran via gnats <gnats-a=
dmin@netbsd.org> wrote:
> >
> > The following reply was made to PR bin/59838; it has been noted by GNAT=
S.
> >
>
> [stuff deleted]
>
> > I believe it should also check for the presence of F_TYPE before
> > printing "/set":
> >
> > --- a/usr.sbin/mtree/create.c
> > +++ b/usr.sbin/mtree/create.c
> > @@ -396,16 +396,20 @@ statd(FILE *fp, FTS *t, FTSENT *parent, uid_t
> > *puid, gid_t *pgid, mode_t *pmode,
> > * output a new one. So first we check to see if anything chan=
ged.
> > * Note that we always output a /set record for the first direc=
tory.
> > */
> > - if (((keys & (F_UNAME | F_UID)) && (*puid !=3D saveuid)) ||
> > + if ((keys & F_TYPE) ||
> > + ((keys & (F_UNAME | F_UID)) && (*puid !=3D saveuid)) ||
> > ((keys & (F_GNAME | F_GID)) && (*pgid !=3D savegid)) ||
> > - ((keys & F_MODE) && (*pmode !=3D savemode)) ||
> > + ((keys & F_MODE) && (*pmode !=3D savemode)) ||
> > ((keys & F_FLAGS) && (*pflags !=3D saveflags)) ||
> > first) {
> > first =3D 0;
> > - if (flavor !=3D F_NETBSD6 && dflag)
> > - fprintf(fp, "/set type=3Ddir");
> > - else
> > - fprintf(fp, "/set type=3Dfile");
> > + fprintf(fp, "/set");
> > + if (keys & F_TYPE) {
> > + if (flavor !=3D F_NETBSD6 && dflag)
> > + fprintf(fp, " type=3Ddir");
> > + else
> > + fprintf(fp, " type=3Dfile");
> > + }
> > if (keys & (F_UID | F_UNAME)) {
> > if (keys & F_UNAME &&
> > (name =3D user_from_uid(saveuid, 1)) !=3D N=
ULL)
> >
>
> We do we need to check F_TYPE twice? It is in the outer if...
The outer check is for the case where "/set" should not be printed at
all, without any key/value pair, for example:
$ mtree -cn -k flags -R flags,type -p /usr/bin/ -x
In that corner case, no "/set" line should be printed.
The inner check is to print "type=3D<dir/file>" conditionally, for example:
$ mtree -cn -k uid -R type -p /usr/bin/ -x
In this case, "/set uid=3D0" should be printed, notice that type is
indeed excluded from the line.
> christos
>
From: Jose Luis Duran <jlduran@gmail.com>
To: gnats-bugs@netbsd.org
Cc: gnats-admin@netbsd.org, netbsd-bugs@netbsd.org
Subject: Re: PR/59838 CVS commit: src/usr.sbin/mtree
Date: Fri, 19 Dec 2025 11:46:29 -0300
> > We do we need to check F_TYPE twice? It is in the outer if...
>
> The outer check is for the case where "/set" should not be printed at
> all, without any key/value pair, for example:
> $ mtree -cn -k flags -R flags,type -p /usr/bin/ -x
> In that corner case, no "/set" line should be printed.
Forgot to mention my doubt:
Reading the comment: "Note that we always output a /set record for the
first directory.", my fear is that it could produce an invalid
specification, because there would be no "/set" record, or, in the
previous case, just an empty "/set" record with no key/value pairs.
From: jlduran@gmail.com
To: gnats-bugs@NetBSD.org
Cc:
Subject: mtree: Partially revert PR/59838 mtree's type keyword is mandatory
Date: Thu, 8 Jan 2026 06:11:05 +0000 (UTC)
>Submitter-Id: net
>Originator: Jose Luis Duran
>Organization: FreeBSD
>Confidential: no
>Synopsis: mtree: Partially revert PR/59838 mtree's type keyword is mandatory
>Severity: non-critical
>Priority: low
>Category: bin
>Class: doc-bug
>Release: trunk
>Environment:
>Description:
It was reported on the FreeBSD current mailing list that the "type" keyword has been historically mandatory, and should not be removed by the -R flag.
Partially revert PR/59838 (create.c,v 1.80) and fix the manual page to clarify this intention, effectively also reverting mtree.8,v 1.44.
>How-To-Repeat:
$ mtree -c -R all | mtree -C
"-R all" should *not* remove the "type" keyword.
>Fix:
diff --git usr.sbin/mtree/create.c usr.sbin/mtree/create.c
index 1a4f006bcfea..3ad592ba1173 100644
--- usr.sbin/mtree/create.c
+++ usr.sbin/mtree/create.c
@@ -236,8 +236,7 @@ statf(FILE *fp, int indent, FTSENT *p)
offset += fprintf(fp, "%*s",
(INDENTNAMELEN + indent) - offset, "");
- if (keys & F_TYPE &&
- !S_ISREG(p->fts_statp->st_mode) && (flavor == F_NETBSD6 || !dflag))
+ if (!S_ISREG(p->fts_statp->st_mode) && (flavor == F_NETBSD6 || !dflag))
output(fp, indent, &offset, "type=%s",
inotype(p->fts_statp->st_mode));
if (keys & (F_UID | F_UNAME) && p->fts_statp->st_uid != uid) {
diff --git usr.sbin/mtree/mtree.8 usr.sbin/mtree/mtree.8
index 99e3199de943..a975403a6d20 100644
--- usr.sbin/mtree/mtree.8
+++ usr.sbin/mtree/mtree.8
@@ -56,7 +56,7 @@
.\"
.\" @(#)mtree.8 8.2 (Berkeley) 12/11/93
.\"
-.Dd December 2, 2023
+.Dd January 8, 2026
.Dt MTREE 8
.Os
.Sh NAME
@@ -242,18 +242,14 @@ If
is specified, add all of the other keywords.
.
.It Fl k Ar keywords
-Use the
+Use the mandatory
.Sy type
keyword plus the specified (whitespace or comma separated)
.Ar keywords
-instead of the current set of keywords.
+to replace 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 Cm type .
+is specified, use all of the available keywords.
.
.It Fl L
Follow all symbolic links in the file hierarchy.
@@ -338,9 +334,13 @@ 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.
+The
+.Sy type
+keyword is mandatory and is always retained.
If
.Ql all
-is specified, remove all of the other keywords.
+is specified, remove all keywords except
+.Sy type .
.
.It Fl r
Remove any files in the file hierarchy that are not described in the
(Contact us)
$NetBSD: query-full-pr,v 1.47 2022/09/11 19:34:41 kim Exp $
$NetBSD: gnats_config.sh,v 1.9 2014/08/02 14:16:04 spz Exp $
Copyright © 1994-2026
The NetBSD Foundation, Inc. ALL RIGHTS RESERVED.