Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 30 Nov 1999 00:30:45 -0700
From:      Warner Losh <imp@village.org>
To:        matt@csis.gvsu.edu, freebsd-hackers@FreeBSD.ORG
Subject:   Re: Human readable df 
Message-ID:  <199911300730.AAA00409@harmony.village.org>
In-Reply-To: Your message of "Mon, 29 Nov 1999 23:57:48 MST." <199911300657.XAA99880@harmony.village.org> 
References:  <199911300657.XAA99880@harmony.village.org>  <19991129230436.A6501@badmofo> 

next in thread | previous in thread | raw e-mail | index | archive | help
Here's a slightly better patch.  It tries harder to fill up the 5
digit field with as many sig figs as possible (always up to 3).  It
uses better constants for things than the magic numbers of the first
patch.  I've not tried to patch the man page yet.  Also patched where
the gross use of "BKMGTP"[unit], the disorder in the prototypes.  I
also fixed it so that disk larger then 1000Pbytes are displayed in
petabytes rather than bytes like the old code.

I think this looks a little better than the orignial patch singe it
now gives the same resolution of data for each file system.

I experimented with setting the throttle from 1000.00 the previous
unit to 2000.00 the previous unit to give it a more multi-meter look
and to give higher resolution around 1 which would give you a more
linear amount of data (taken as the log of the rounding error), but
that didn't look as good, so I left it on the cutting room floor.

I also experimented with a format that looked like
/dev/da0s1e  192.M  167.M  9.22M    95%     /usr

but that too didn't look good to my eye, even though it was more
pedantically correct from a sigfig point of view (since 200M means
there is one sig fig, while 200.M means two, at least in the sig fig
system I learned in high school).

Here's the output

Filesystem    Size   Used    Avail Capacity Mounted on
/dev/da0s1a  62.0M  31.0M  26.1M    54%     /
/dev/da0s1e   192M   167M  9.22M    95%     /usr
/dev/da0s1d  61.4M  11.3M  45.2M    20%     /var
/dev/da0s1f   288M   247M  18.4M    93%     /usr/local
/dev/da0s1g  2.17G  1.88G   122M    94%     /home
procfs       4.00K  4.00K     0B   100%     /proc
/dev/sd1a     990M   376M   534M    41%     /jaz
/dev/da2s4c  1.94G  1.72G  68.0M    96%     /hawk
/dev/da3s4a  3.93G  1.95G  1.67G    54%     /u

Warner

P.S. I thought of doing a -H as well that used real SI units rather
than the traditional CS si-ish units, but thought better of it.  I
also didn't use the new ki, Mi, et al either since that would just
make the display look wrong to my eye (I was also unsure of their
exact spelling :-).

Index: df.c
===================================================================
RCS file: /home/imp/FreeBSD/CVS/src/bin/df/df.c,v
retrieving revision 1.22
diff -u -r1.22 df.c
--- df.c	1999/11/01 04:57:43	1.22
+++ df.c	1999/11/30 07:19:07
@@ -59,21 +59,28 @@
 #include <err.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <math.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 
-int	  checkvfsname __P((const char *, char **));
-char	**makevfslist __P((char *));
-long	  regetmntinfo __P((struct statfs **, long, char **));
+typedef enum { NONE = 0, KILO, MEGA, GIGA, TERA, PETA /* , EXA */ } unit_t;
+const char *unit_string = "BKMGTP";
+
 int	  bread __P((off_t, void *, int));
+int	  checkvfsname __P((const char *, char **));
 char	 *getmntpt __P((char *));
+char	**makevfslist __P((char *));
+void	  prthuman __P((struct statfs *, long));
+void	  prthumanval __P((double));
 void	  prtstat __P((struct statfs *, int));
+long	  regetmntinfo __P((struct statfs **, long, char **));
 int	  ufs_df __P((char *, int));
+unit_t	  unit_adjust __P((double *));
 void	  usage __P((void));
 
-int	aflag = 0, iflag, nflag;
+int	aflag = 0, iflag, nflag, hflag;
 struct	ufs_args mdev;
 
 int
@@ -88,11 +95,14 @@
 	char *mntpt, *mntpath, **vfslist;
 
 	vfslist = NULL;
-	while ((ch = getopt(argc, argv, "aiknt:")) != -1)
+	while ((ch = getopt(argc, argv, "ahiknt:")) != -1)
 		switch (ch) {
 		case 'a':
 			aflag = 1;
 			break;
+		case 'h':
+			hflag = 1;
+			break;
 		case 'i':
 			iflag = 1;
 			break;
@@ -272,20 +282,26 @@
 	if (maxwidth < 11)
 		maxwidth = 11;
 	if (++timesthrough == 1) {
-		header = getbsize(&headerlen, &blocksize);
-		(void)printf("%-*.*s %s     Used    Avail Capacity",
+		if(hflag)
+			header = "  Size";
+		else
+			header = getbsize(&headerlen, &blocksize);
+			(void)printf("%-*.*s %s   Used    Avail Capacity",
 		    maxwidth, maxwidth, "Filesystem", header);
 		if (iflag)
 			(void)printf(" iused   ifree  %%iused");
-		(void)printf("  Mounted on\n");
+		(void)printf(" Mounted on\n");
 	}
 	(void)printf("%-*.*s", maxwidth, maxwidth, sfsp->f_mntfromname);
 	used = sfsp->f_blocks - sfsp->f_bfree;
 	availblks = sfsp->f_bavail + used;
-	(void)printf(" %*ld %8ld %8ld", headerlen,
-	    fsbtoblk(sfsp->f_blocks, sfsp->f_bsize, blocksize),
-	    fsbtoblk(used, sfsp->f_bsize, blocksize),
-	    fsbtoblk(sfsp->f_bavail, sfsp->f_bsize, blocksize));
+	if(hflag)
+		prthuman(sfsp, used);
+	else 
+		(void)printf(" %*ld %8ld %8ld", headerlen,
+	   	 fsbtoblk(sfsp->f_blocks, sfsp->f_bsize, blocksize),
+	   	 fsbtoblk(used, sfsp->f_bsize, blocksize),
+	   	 fsbtoblk(sfsp->f_bavail, sfsp->f_bsize, blocksize));
 	(void)printf(" %5.0f%%",
 	    availblks == 0 ? 100.0 : (double)used / (double)availblks * 100.0);
 	if (iflag) {
@@ -295,7 +311,74 @@
 		   inodes == 0 ? 100.0 : (double)used / (double)inodes * 100.0);
 	} else
 		(void)printf("  ");
-	(void)printf("  %s\n", sfsp->f_mntonname);
+	(void)printf("   %s\n", sfsp->f_mntonname);
+}
+
+/*
+ * "human-readable" output: use 3 digits max.--put unit suffixes at
+ * the end.  Makes output compact and easy-to-read esp. on huge disks.
+ */
+
+unit_t
+unit_adjust(val)
+	double *val;
+{
+#define K(a) ((a) * (1ULL<< 10))
+#define M(a) ((a) * (1ULL<< 20))
+#define G(a) ((a) * (1ULL<< 30))
+#define T(a) ((a) * (1ULL<< 40))
+#define P(a) ((a) * (1ULL<< 50))
+	double abval;
+	unit_t unit;
+
+	abval = fabs(*val);
+	if (abval < K(1))
+		unit = NONE;
+	else if (abval < K(1000.0)) {
+		unit = KILO;
+		*val /= K(1);
+	} else if (abval < M(1000.0)) {
+		unit = MEGA;
+		*val /= M(1);
+	} else if (abval < G(1000.0)) {
+		unit = GIGA;
+		*val /= G(1.0);
+	} else if (abval < T(1000.0)) {
+		unit = TERA;
+		*val /= T(1.0);
+	} else {
+		unit = PETA;
+		*val /= P(1.0);
+	}
+	return (unit);
+}
+
+void
+prthumanval(bytes)
+	double bytes;
+{
+	unit_t unit;
+
+	unit = unit_adjust(&bytes);
+
+	if (bytes == 0)
+		(void)printf("     0B");
+	else if (bytes > 100)
+		(void)printf(" %5.0f%c", bytes, unit_string[unit]);
+	else if (bytes > 10)
+		(void)printf(" %5.1f%c", bytes, unit_string[unit]);
+	else
+		(void)printf(" %5.2f%c", bytes, unit_string[unit]);
+}
+
+void
+prthuman(sfsp, used)
+	struct statfs *sfsp;
+	long used;
+{
+	prthumanval((double)(sfsp->f_blocks) * (double)(sfsp->f_bsize));
+	prthumanval((double)(used) * (double)(sfsp->f_bsize));
+	prthumanval((double)(sfsp->f_bavail) * (double)(sfsp->f_bsize));
 }
 
 /*


To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-hackers" in the body of the message




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