Fix for bin/15510: df(1) does not lineup with large filesystems

Ian Dowse <[email protected]>
Newsgroups gmane.os.freebsd.devel.audit
Message-ID <[email protected]>
The patch below should address bin/15510. We keep track of the
maximum width required for every variable-width field instead of
just the first one.

Note that this retains the following historical formatting behaviour:
 - double space after the "Filesystem" column;
 - double space before the "Mounted on" column;
 - overlapping of the "Capacity" heading with the "iused" column
   when the "-i" option is specified.
These could easily be removed if desirable.

Ian

Index: df.c
===================================================================
RCS file: /dump/FreeBSD-CVS/src/bin/df/df.c,v
retrieving revision 1.36
diff -u -r1.36 df.c
--- df.c	22 Feb 2002 20:57:53 -0000	1.36
+++ df.c	23 Mar 2002 21:49:50 -0000
@@ -91,6 +91,16 @@
 #define TERA_SI_SZ (TERA_SZ(1000ULL))
 #define PETA_SI_SZ (PETA_SZ(1000ULL))
 
+/* Maximum widths of various fields. */
+struct maxwidths {
+	int mntfrom;
+	int total;
+	int used;
+	int avail;
+	int iused;
+	int ifree;
+};
+
 unsigned long long vals_si [] = {1, KILO_SI_SZ, MEGA_SI_SZ, GIGA_SI_SZ, TERA_SI_SZ, PETA_SI_SZ};
 unsigned long long vals_base2[] = {1, KILO_2_SZ, MEGA_2_SZ, GIGA_2_SZ, TERA_2_SZ, PETA_2_SZ};
 unsigned long long *valp;
@@ -102,28 +112,36 @@
 int	  bread(off_t, void *, int);
 int	  checkvfsname(const char *, char **);
 char	 *getmntpt(char *);
+int	  longwidth(long);
 char	 *makenetvfslist(void);
 char	**makevfslist(char *);
 void	  prthuman(struct statfs *, long);
 void	  prthumanval(double);
-void	  prtstat(struct statfs *, int);
+void	  prtstat(struct statfs *, struct maxwidths *);
 long	  regetmntinfo(struct statfs **, long, char **);
-int	  ufs_df(char *, int);
+int	  ufs_df(char *, struct maxwidths *);
 unit_t	  unit_adjust(double *);
+void	  update_maxwidths(struct maxwidths *, struct statfs *);
 void	  usage(void);
 
 int	aflag = 0, hflag, iflag, nflag;
 struct	ufs_args mdev;
 
+static __inline int imax(int a, int b)
+{
+	return (a > b ? a : b);
+}
+
 int
 main(int argc, char *argv[])
 {
 	struct stat stbuf;
 	struct statfs statfsbuf, *mntbuf;
+	struct maxwidths maxwidths;
 	const char *fstype;
 	char *mntpath, *mntpt, **vfslist;
 	long mntsize;
-	int ch, i, maxwidth, rv, width;
+	int ch, i, rv;
 
 	fstype = "ufs";
 
@@ -184,27 +202,21 @@
 	argv += optind;
 
 	mntsize = getmntinfo(&mntbuf, MNT_NOWAIT);
-	maxwidth = 0;
-	for (i = 0; i < mntsize; i++) {
-		width = strlen(mntbuf[i].f_mntfromname);
-		if (width > maxwidth)
-			maxwidth = width;
-	}
+	bzero(&maxwidths, sizeof(maxwidths));
+	for (i = 0; i < mntsize; i++)
+		update_maxwidths(&maxwidths, &mntbuf[i]);
 
 	rv = 0;
 	if (!*argv) {
 		mntsize = regetmntinfo(&mntbuf, mntsize, vfslist);
 		if (vfslist != NULL) {
-			maxwidth = 0;
-			for (i = 0; i < mntsize; i++) {
-				width = strlen(mntbuf[i].f_mntfromname);
-				if (width > maxwidth)
-					maxwidth = width;
-			}
+			bzero(&maxwidths, sizeof(maxwidths));
+			for (i = 0; i < mntsize; i++)
+				update_maxwidths(&maxwidths, &mntbuf[i]);
 		}
 		for (i = 0; i < mntsize; i++) {
 			if (aflag || (mntbuf[i].f_flags & MNT_IGNORE) == 0)
-				prtstat(&mntbuf[i], maxwidth);
+				prtstat(&mntbuf[i], &maxwidths);
 		}
 		exit(rv);
 	}
@@ -234,13 +246,13 @@
 				}
 				if (mount(fstype, mntpt, MNT_RDONLY,
 				    &mdev) != 0) {
-					rv = ufs_df(*argv, maxwidth) || rv;
+					rv = ufs_df(*argv, &maxwidths) || rv;
 					(void)rmdir(mntpt);
 					free(mntpath);
 					continue;
 				} else if (statfs(mntpt, &statfsbuf) == 0) {
 					statfsbuf.f_mntonname[0] = '\0';
-					prtstat(&statfsbuf, maxwidth);
+					prtstat(&statfsbuf, &maxwidths);
 				} else {
 					warn("%s", *argv);
 					rv = 1;
@@ -261,9 +273,11 @@
 			rv = 1;
 			continue;
 		}
-		if (argc == 1)
-			maxwidth = strlen(statfsbuf.f_mntfromname) + 1;
-		prtstat(&statfsbuf, maxwidth);
+		if (argc == 1) {
+			bzero(&maxwidths, sizeof(maxwidths));
+			update_maxwidths(&maxwidths, &statfsbuf);
+		}
+		prtstat(&statfsbuf, &maxwidths);
 	}
 	return (rv);
 }
@@ -372,54 +386,107 @@
  * Print out status about a filesystem.
  */
 void
-prtstat(struct statfs *sfsp, int maxwidth)
+prtstat(struct statfs *sfsp, struct maxwidths *mwp)
 {
 	static long blocksize;
 	static int headerlen, timesthrough;
 	static const char *header;
 	long used, availblks, inodes;
 
-	if (maxwidth < 11)
-		maxwidth = 11;
 	if (++timesthrough == 1) {
+		mwp->mntfrom = imax(mwp->mntfrom, strlen("Filesystem"));
 		if (hflag) {
 			header = "  Size";
-			headerlen = strlen(header);
-			(void)printf("%-*.*s %-s   Used  Avail Capacity",
-				maxwidth, maxwidth, "Filesystem", header);
+			mwp->total = mwp->used = mwp->avail = strlen(header);
 		} else {
 			header = getbsize(&headerlen, &blocksize);
-			(void)printf("%-*.*s %-s     Used    Avail Capacity",
-				maxwidth, maxwidth, "Filesystem", header);
+			mwp->total = imax(mwp->total, headerlen);
+		}
+		mwp->used = imax(mwp->used, strlen("Used"));
+		mwp->avail = imax(mwp->avail, strlen("Avail"));
+
+		(void)printf("%-*s %-*s %*s %*s Capacity", mwp->mntfrom,
+		    "Filesystem", mwp->total, header, mwp->used, "Used",
+		    mwp->avail, "Avail");
+		if (iflag) {
+			mwp->iused = imax(mwp->iused, strlen("  iused"));
+			mwp->ifree = imax(mwp->ifree, strlen("ifree"));
+			(void)printf(" %*s %*s %%iused", mwp->iused - 2,
+			    "iused", mwp->ifree, "ifree");
 		}
-		if (iflag)
-			(void)printf(" iused   ifree  %%iused");
 		(void)printf("  Mounted on\n");
 	}
-	(void)printf("%-*.*s", maxwidth, maxwidth, sfsp->f_mntfromname);
+	(void)printf("%-*s", mwp->mntfrom, sfsp->f_mntfromname);
 	used = sfsp->f_blocks - sfsp->f_bfree;
 	availblks = sfsp->f_bavail + used;
 	if (hflag) {
 		prthuman(sfsp, used);
 	} else {
-		(void)printf(" %*ld %8ld %8ld", headerlen,
+		(void)printf(" %*ld %*ld %*ld", mwp->total,
 	            fsbtoblk(sfsp->f_blocks, sfsp->f_bsize, blocksize),
-	            fsbtoblk(used, sfsp->f_bsize, blocksize),
-	            fsbtoblk(sfsp->f_bavail, sfsp->f_bsize, blocksize));
+		    mwp->used, fsbtoblk(used, sfsp->f_bsize, blocksize),
+	            mwp->avail, fsbtoblk(sfsp->f_bavail, sfsp->f_bsize,
+		    blocksize));
 	}
 	(void)printf(" %5.0f%%",
 	    availblks == 0 ? 100.0 : (double)used / (double)availblks * 100.0);
 	if (iflag) {
 		inodes = sfsp->f_files;
 		used = inodes - sfsp->f_ffree;
-		(void)printf(" %7ld %7ld %5.0f%% ", used, sfsp->f_ffree,
-		   inodes == 0 ? 100.0 : (double)used / (double)inodes * 100.0);
+		(void)printf(" %*ld %*ld %4.0f%% ", mwp->iused, used,
+		    mwp->ifree, sfsp->f_ffree, inodes == 0 ? 100.0 :
+		    (double)used / (double)inodes * 100.0);
 	} else
 		(void)printf("  ");
 	(void)printf("  %s\n", sfsp->f_mntonname);
 }
 
 /*
+ * Update the maximum field-width information in `mwp' based on
+ * the filesystem specified by `sfsp'.
+ */
+void
+update_maxwidths(struct maxwidths *mwp, struct statfs *sfsp)
+{
+	static long blocksize;
+	int dummy;
+
+	if (blocksize == 0)
+		getbsize(&dummy, &blocksize);
+
+	mwp->mntfrom = imax(mwp->mntfrom, strlen(sfsp->f_mntfromname));
+	mwp->total = imax(mwp->total, longwidth(fsbtoblk(sfsp->f_blocks,
+	    sfsp->f_bsize, blocksize)));
+	mwp->used = imax(mwp->used, longwidth(fsbtoblk(sfsp->f_blocks -
+	    sfsp->f_bfree, sfsp->f_bsize, blocksize)));
+	mwp->avail = imax(mwp->avail, longwidth(fsbtoblk(sfsp->f_bavail,
+	    sfsp->f_bsize, blocksize)));
+	mwp->iused = imax(mwp->iused, longwidth(sfsp->f_files -
+	    sfsp->f_ffree));
+	mwp->ifree = imax(mwp->ifree, longwidth(sfsp->f_ffree));
+}
+
+/* Return the width in characters of the specified long. */
+int
+longwidth(long val)
+{
+	int len;
+
+	len = 0;
+	/* Negative or zero values require one extra digit. */
+	if (val <= 0) {
+		val = -val;
+		len++;
+	}
+	while (val > 0) {
+		len++;
+		val /= 10;
+	}
+
+	return (len);
+}
+
+/*
  * This code constitutes the pre-system call Berkeley df code for extracting
  * information from filesystem superblocks.
  */
@@ -433,7 +500,7 @@
 int	rfd;
 
 int
-ufs_df(char *file, int maxwidth)
+ufs_df(char *file, struct maxwidths *mwp)
 {
 	struct statfs statfsbuf;
 	struct statfs *sfsp;
@@ -469,7 +536,7 @@
 		mntpt = "";
 	memmove(&sfsp->f_mntonname[0], mntpt, (size_t)MNAMELEN);
 	memmove(&sfsp->f_mntfromname[0], file, (size_t)MNAMELEN);
-	prtstat(sfsp, maxwidth);
+	prtstat(sfsp, mwp);
 	(void)close(rfd);
 	return (0);
 }

To Unsubscribe: send mail to [email protected]
with "unsubscribe freebsd-audit" in the body of the message
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.