Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 23 Mar 2002 22:29:15 +0000
From:      Ian Dowse <iedowse@maths.tcd.ie>
To:        freebsd-audit@freebsd.org
Subject:   Fix for bin/15510: df(1) does not lineup with large filesystems
Message-ID:   <200203232229.aa87310@salmon.maths.tcd.ie>

next in thread | raw e-mail | index | archive | help

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 majordomo@FreeBSD.org
with "unsubscribe freebsd-audit" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi? <200203232229.aa87310>