Index | Thread | Search

From:
Job Snijders <job@bsd.nl>
Subject:
make 'df -hi' more human readable
To:
tech@openbsd.org
Date:
Wed, 7 Jan 2026 11:41:15 +0000

Download raw body.

Thread
Before:

$ df -hi
Filesystem     Size    Used   Avail Capacity  iused    ifree %iused  Mounted on
/dev/sd0a      986M    159M    777M    17%     2179   153339    2%   /
/dev/sd0l      295G   47.6G    233G    17%    12019 19728651    1%   /home
/dev/sd0d     31.0G    1.9M   29.5G     1%       13  4224945    1%   /tmp
/dev/sd0f     29.1G    2.1G   25.5G     8%   212711  3727127    6%   /usr
/dev/sd0g      1.0G    347M    644M    36%     5801   149717    4%   /usr/X11R6
/dev/sd0h     19.4G    958M   17.5G     6%    31861  2611977    2%   /usr/local
/dev/sd0k      5.8G   18.2M    5.5G     1%     2405   801113    1%   /usr/obj
/dev/sd0j      5.8G    1.6G    4.0G    29%   122418   681100   16%   /usr/src
/dev/sd0e      197G    130G   56.9G    70%     1794 13158652    1%   /var
/dev/sd0m      2.8T   61.6G    2.6T     3%  8595400 803391798    2%   /var/www/htdocs/rpki
mfs:50241      3.7G    1.3G    2.3G    36%   589843  1526379   28%   /var/cache/rpki-client
mfs:65537      2.9G    464M    2.3G    17%       61   797505    1%   /var/www/htdocs/rpki/erik/snapshot

After:

$ ./obj/df -hi
Filesystem     Size    Used   Avail Capacity iused  ifree %iused  Mounted on
/dev/sd0a      986M    159M    777M    17%    2.2k   153k    2%   /
/dev/sd0l      295G   47.6G    233G    17%   12.0k  19.7M    1%   /home
/dev/sd0d     31.0G    1.9M   29.5G     1%      13   4.2M    1%   /tmp
/dev/sd0f     29.1G    2.1G   25.5G     8%    213k   3.7M    6%   /usr
/dev/sd0g      1.0G    347M    644M    36%    5.8k   150k    4%   /usr/X11R6
/dev/sd0h     19.4G    958M   17.5G     6%   31.9k   2.6M    2%   /usr/local
/dev/sd0k      5.8G   18.2M    5.5G     1%    2.4k   801k    1%   /usr/obj
/dev/sd0j      5.8G    1.6G    4.0G    29%    122k   681k   16%   /usr/src
/dev/sd0e      197G    130G   56.9G    70%    1.8k  13.2M    1%   /var
/dev/sd0m      2.8T   61.6G    2.6T     3%    8.6M   803M    2%   /var/www/htdocs/rpki
mfs:50241      3.7G    1.3G    2.3G    36%    590k   1.5M   28%   /var/cache/rpki-client
mfs:65537      2.9G    489M    2.3G    18%      57   798k    1%   /var/www/htdocs/rpki/erik/snapshot

OK?

Index: df.1
===================================================================
RCS file: /cvs/src/bin/df/df.1,v
diff -u -p -r1.49 df.1
--- df.1	31 Dec 2022 21:47:53 -0000	1.49
+++ df.1	7 Jan 2026 11:39:00 -0000
@@ -73,7 +73,9 @@ This option is incompatible with the
 .Fl P
 option.
 .It Fl i
-Include statistics on the number of free inodes.
+Include statistics on the number of free inodes, may be combined with the
+.Fl h
+flag to report using SI symbols.
 This option is incompatible with the
 .Fl P
 option.
Index: df.c
===================================================================
RCS file: /cvs/src/bin/df/df.c,v
diff -u -p -r1.62 df.c
--- df.c	12 Mar 2025 16:01:31 -0000	1.62
+++ df.c	7 Jan 2026 11:39:00 -0000
@@ -298,6 +298,60 @@ prthuman(struct statfs *sfsp, unsigned l
 }
 
 /*
+ * Human readable output using SI symbols and multiples of thousand.
+ */
+static const struct scale {
+	char symbol;
+	unsigned long long factor;
+} scale[] = {
+	{ ' ', 1LL },
+	{ 'k', 1000LL },					/* kilo */
+	{ 'M', 1000LL * 1000 },					/* mega */
+	{ 'G', 1000LL * 1000 * 1000 },				/* giga */
+	{ 'T', 1000LL * 1000 * 1000 * 1000 },			/* tera */
+	{ 'P', 1000LL * 1000 * 1000 * 1000 * 1000 },		/* peta */
+	{ 'E', 1000LL * 1000 * 1000 * 1000 * 1000 * 1000 }	/*  exa */
+};
+#define SCALE_LENGTH	(sizeof(scale) / sizeof(scale[0]))
+
+static void
+prtscaleddecimal(unsigned long long num)
+{
+	long long fract = 0;
+	unsigned long i;
+	int unit = 0;
+
+	if (num < 1000 || num / 1000 >= scale[SCALE_LENGTH - 1].factor) {
+		(void)printf(" %6llu", num);
+		return;
+	}
+
+	for (i = 0; i < SCALE_LENGTH; i++) {
+		if (num / 1000 < scale[i].factor) {
+			unit = i;
+			fract = (i == 0) ? 0 : num % scale[i].factor;
+			num /= scale[i].factor;
+			if (i > 0)
+				fract /= scale[i - 1].factor;
+			break;
+		}
+	}
+
+	fract = (10 * fract + 500) / 1000;
+	if (fract >= 10) {
+		num++;
+		fract = 0;
+	}
+
+	if (num >= 100) {
+		if (fract >= 5)
+			num++;
+		(void)printf(" %5llu%c", num, scale[unit].symbol);
+	} else
+		(void)printf(" %3llu.%1llu%c", num, fract, scale[unit].symbol);
+}
+
+/*
  * Convert statfs returned filesystem size into BLOCKSIZE units.
  * Attempts to avoid overflow for large filesystems.
  */
@@ -328,8 +382,16 @@ prtstat(struct statfs *sfsp, int maxwidt
 	if (iflag) {
 		inodes = sfsp->f_files;
 		used = inodes - sfsp->f_ffree;
-		(void)printf(" %8llu %8llu %4d%% ", used, sfsp->f_ffree,
-		   percent(used, inodes));
+
+		if (hflag) {
+			(void)printf(" ");
+			prtscaleddecimal(used);
+			prtscaleddecimal(sfsp->f_ffree);
+			(void)printf(" %4d%% ", percent(used, inodes));
+		} else {
+			(void)printf(" %8llu %8llu %4d%% ", used, sfsp->f_ffree,
+			   percent(used, inodes));
+		}
 	} else
 		(void)printf("  ");
 	(void)printf("  %s\n", sfsp->f_mntonname);
@@ -362,8 +424,12 @@ bsdprint(struct statfs *mntbuf, long mnt
 		(void)printf("%-*.*s %s      Used     Avail Capacity",
 			     maxwidth, maxwidth, "Filesystem", header);
 	}
-	if (iflag)
-		(void)printf("  iused    ifree %%iused");
+	if (iflag) {
+		if (hflag)
+			(void)printf(" iused  ifree %%iused");
+		else
+			(void)printf("  iused    ifree %%iused");
+	}
 	(void)printf("  Mounted on\n");