git: 741b90dc69ee - stable/12 - bin/df: allow -t option to be used together with -l

From: Stefan Eßer <se_at_FreeBSD.org>
Date: Mon, 18 Apr 2022 11:12:46 UTC
The branch stable/12 has been updated by se:

URL: https://cgit.FreeBSD.org/src/commit/?id=741b90dc69ee9e9f3bbd2b0548ea214030c4ea34

commit 741b90dc69ee9e9f3bbd2b0548ea214030c4ea34
Author:     Stefan Eßer <se@FreeBSD.org>
AuthorDate: 2022-02-10 20:09:34 +0000
Commit:     Stefan Eßer <se@FreeBSD.org>
CommitDate: 2022-04-18 11:04:04 +0000

    bin/df: allow -t option to be used together with -l
    
    The df command provides a -l option to exclude all non-local file
    systems and a -t option with a (positive or negative) list of file
    system types to display.
    
    This commit adds support for a combination of -l and -t. If both are
    specified, the parameter list of the -t option is applied on top of
    the selection of öocal file systems (independently of the order of
    the -l and -t options).
    
    E.g., "df -t noprocfs,sysfs -l" will select all local file systems
    except those of type procfs and sysfs.
    
    (cherry picked from commit f0fd4a32c4f7ab5eb008ab08a1a13cb20d4b30d2)
    (cherry picked from commit c888fc2d97ee3e25269ca8218f80769bca930705)
---
 bin/df/Makefile |   7 +---
 bin/df/df.1     |  16 +++++++--
 bin/df/df.c     | 109 +++++++++++++++++++++++++++++++++++++++++++++-----------
 3 files changed, 103 insertions(+), 29 deletions(-)

diff --git a/bin/df/Makefile b/bin/df/Makefile
index 6d36a370b02c..52eab0abfc1a 100644
--- a/bin/df/Makefile
+++ b/bin/df/Makefile
@@ -2,16 +2,11 @@
 # $FreeBSD$
 
 PACKAGE=runtime
-MOUNT=	${SRCTOP}/sbin/mount
-.PATH: ${MOUNT}
 
 PROG=	df
-SRCS=	df.c vfslist.c
-
-CFLAGS+= -I${MOUNT}
+SRCS=	df.c
 
 CFLAGS+= -DMOUNT_CHAR_DEVS
-SRCS+=	getmntopts.c
 
 LIBADD=	xo util
 
diff --git a/bin/df/df.1 b/bin/df/df.1
index e618077cbf06..047fc0f61ea2 100644
--- a/bin/df/df.1
+++ b/bin/df/df.1
@@ -116,7 +116,11 @@ option and any
 .Ev BLOCKSIZE
 specification from the environment.
 .It Fl l
-Only display information about locally-mounted file systems.
+Select locally-mounted file system for display.
+If used in combination with the
+.Fl t Ar type
+option, file system types will be added or excluded acccording to the
+parameters of that option.
 .It Fl m
 Use 1048576 byte (1 Mebibyte) blocks rather than the default.
 This overrides any
@@ -141,14 +145,20 @@ option.
 The
 .Fl k
 option overrides this option.
-.It Fl t
-Only print out statistics for file systems of the specified types.
+.It Fl t Ar type
+Select file systems to display.
 More than one type may be specified in a comma separated list.
 The list of file system types can be prefixed with
 .Dq no
 to specify the file system types for which action should
 .Em not
 be taken.
+If used in combination with the
+.Fl l
+option, the parameters of this option will modify the list of
+locally-mounted file systems selected by the
+.Fl l
+option.
 For example, the
 .Nm
 command:
diff --git a/bin/df/df.c b/bin/df/df.c
index 4de8c639bc75..12b6eee0e2cf 100644
--- a/bin/df/df.c
+++ b/bin/df/df.c
@@ -70,8 +70,6 @@ __FBSDID("$FreeBSD$");
 #include <unistd.h>
 #include <libxo/xo.h>
 
-#include "extern.h"
-
 #define UNITS_SI	1
 #define UNITS_2		2
 
@@ -88,13 +86,16 @@ struct maxwidths {
 
 static void	  addstat(struct statfs *, struct statfs *);
 static char	 *getmntpt(const char *);
+static const char **makevfslist(char *fslist, int *skip);
+static int	  checkvfsname(const char *vfsname, const char **vfslist, int skip);
+static int	  checkvfsselected(char *);
 static int	  int64width(int64_t);
 static char	 *makenetvfslist(void);
 static void	  prthuman(const struct statfs *, int64_t);
 static void	  prthumanval(const char *, int64_t);
 static intmax_t	  fsbtoblk(int64_t, uint64_t, u_long);
 static void	  prtstat(struct statfs *, struct maxwidths *);
-static size_t	  regetmntinfo(struct statfs **, long, const char **);
+static size_t	  regetmntinfo(struct statfs **, long);
 static void	  update_maxwidths(struct maxwidths *, const struct statfs *);
 static void	  usage(void);
 
@@ -104,11 +105,13 @@ imax(int a, int b)
 	return (a > b ? a : b);
 }
 
-static int	aflag = 0, cflag, hflag, iflag, kflag, lflag = 0, nflag, Tflag;
-static int	thousands;
+static int	  aflag = 0, cflag, hflag, iflag, kflag, lflag = 0, nflag, Tflag;
+static int	  thousands;
 #ifdef MOUNT_CHAR_DEVS
 static struct	ufs_args mdev;
 #endif
+static int	  skipvfs_l, skipvfs_t;
+static const char **vfslist_l, **vfslist_t;
 
 static const struct option long_options[] =
 {
@@ -132,7 +135,6 @@ main(int argc, char *argv[])
 	char errmsg[255] = {0};
 #endif
 	char *mntpt;
-	const char **vfslist;
 	int i, mntsize;
 	int ch, rv;
 #ifdef MOUNT_CHAR_DEVS
@@ -144,7 +146,6 @@ main(int argc, char *argv[])
 	memset(&totalbuf, 0, sizeof(totalbuf));
 	totalbuf.f_bsize = DEV_BSIZE;
 	strlcpy(totalbuf.f_mntfromname, "total", MNAMELEN);
-	vfslist = NULL;
 
 	argc = xo_parse_args(argc, argv);
 	if (argc < 0)
@@ -195,9 +196,7 @@ main(int argc, char *argv[])
 			/* Ignore duplicate -l */
 			if (lflag)
 				break;
-			if (vfslist != NULL)
-				xo_errx(1, "-l and -t are mutually exclusive.");
-			vfslist = makevfslist(makenetvfslist());
+			vfslist_l = makevfslist(makenetvfslist(), &skipvfs_l);
 			lflag = 1;
 			break;
 		case 'm':
@@ -208,11 +207,9 @@ main(int argc, char *argv[])
 			nflag = 1;
 			break;
 		case 't':
-			if (lflag)
-				xo_errx(1, "-l and -t are mutually exclusive.");
-			if (vfslist != NULL)
+			if (vfslist_t != NULL)
 				xo_errx(1, "only one -t option may be specified");
-			vfslist = makevfslist(optarg);
+			vfslist_t = makevfslist(optarg, &skipvfs_t);
 			break;
 		case 'T':
 			Tflag = 1;
@@ -231,7 +228,7 @@ main(int argc, char *argv[])
 	if (!*argv) {
 		/* everything (modulo -t) */
 		mntsize = getmntinfo(&mntbuf, MNT_NOWAIT);
-		mntsize = regetmntinfo(&mntbuf, mntsize, vfslist);
+		mntsize = regetmntinfo(&mntbuf, mntsize);
 	} else {
 		/* just the filesystems specified on the command line */
 		mntbuf = malloc(argc * sizeof(*mntbuf));
@@ -330,7 +327,7 @@ main(int argc, char *argv[])
 		 * list a mount point that does not match the other args
 		 * we've been given (-l, -t, etc.).
 		 */
-		if (checkvfsname(statfsbuf.f_fstypename, vfslist)) {
+		if (checkvfsselected(statfsbuf.f_fstypename) != 0) {
 			rv = 1;
 			continue;
 		}
@@ -378,23 +375,95 @@ getmntpt(const char *name)
 	return (NULL);
 }
 
+static const char **
+makevfslist(char *fslist, int *skip)
+{
+	const char **av;
+	int i;
+	char *nextcp;
+
+	if (fslist == NULL)
+		return (NULL);
+	*skip = 0;
+	if (fslist[0] == 'n' && fslist[1] == 'o') {
+		fslist += 2;
+		*skip = 1;
+	}
+	for (i = 0, nextcp = fslist; *nextcp; nextcp++)
+		if (*nextcp == ',')
+			i++;
+	if ((av = malloc((size_t)(i + 2) * sizeof(char *))) == NULL) {
+		warnx("malloc failed");
+		return (NULL);
+	}
+	nextcp = fslist;
+	i = 0;
+	av[i++] = nextcp;
+	while ((nextcp = strchr(nextcp, ',')) != NULL) {
+		*nextcp++ = '\0';
+		av[i++] = nextcp;
+	}
+	av[i++] = NULL;
+	return (av);
+}
+
+static int
+checkvfsname(const char *vfsname, const char **vfslist, int skip)
+{
+
+	if (vfslist == NULL)
+		return (0);
+	while (*vfslist != NULL) {
+		if (strcmp(vfsname, *vfslist) == 0)
+			return (skip);
+		++vfslist;
+	}
+	return (!skip);
+}
+
+/*
+ * Without -l and -t option, all file system types are enabled.
+ * The -l option selects the local file systems, if present.
+ * A -t option modifies the selection by adding or removing further
+ * file system types, based on the argument that is passed.
+ */
+static int
+checkvfsselected(char *fstypename)
+{
+	int result;
+
+	if (vfslist_t) {
+		/* if -t option used then select passed types */
+		result = checkvfsname(fstypename, vfslist_t, skipvfs_t);
+		if (vfslist_l) {
+			/* if -l option then adjust selection */
+			if (checkvfsname(fstypename, vfslist_l, skipvfs_l) == skipvfs_t)
+				result = skipvfs_t;
+		}
+	} else {
+		/* no -t option then -l decides */
+		result = checkvfsname(fstypename, vfslist_l, skipvfs_l);
+	}
+	return (result);
+}
+
 /*
  * Make a pass over the file system info in ``mntbuf'' filtering out
- * file system types not in vfslist and possibly re-stating to get
+ * file system types not in vfslist_{l,t} and possibly re-stating to get
  * current (not cached) info.  Returns the new count of valid statfs bufs.
  */
 static size_t
-regetmntinfo(struct statfs **mntbufp, long mntsize, const char **vfslist)
+regetmntinfo(struct statfs **mntbufp, long mntsize)
 {
 	int error, i, j;
 	struct statfs *mntbuf;
 
-	if (vfslist == NULL)
+	if (vfslist_l == NULL && vfslist_t == NULL)
 		return (nflag ? mntsize : getmntinfo(mntbufp, MNT_WAIT));
 
 	mntbuf = *mntbufp;
 	for (j = 0, i = 0; i < mntsize; i++) {
-		if (checkvfsname(mntbuf[i].f_fstypename, vfslist))
+		if (checkvfsselected(mntbuf[i].f_fstypename) != 0)
 			continue;
 		/*
 		 * XXX statfs(2) can fail for various reasons. It may be