master xplshn/aruu / cmd / posix / df.c
  1/* See LICENSE file for copyright and license details. */
  2
  3
  4#include <sys/statvfs.h>
  5
  6#include <mntent.h>
  7#include <stdio.h>
  8#include <stdlib.h>
  9#include <string.h>
 10
 11#include "util.h"
 12
 13static long blksize = 512;
 14static int aflag = 0;
 15static int hflag = 0;
 16static int kflag = 0;
 17
 18#define CALC_POWER(n, power, base, i) do { \
 19	while (n > power) {                \
 20		power = power * base;      \
 21		i++;                       \
 22	}                                  \
 23} while(0)
 24
 25static void
 26print_human(
 27	const char         *fsname,
 28	unsigned long long total,
 29	unsigned long long used,
 30	unsigned long long avail,
 31	int                capacity,
 32	const char         *dir)
 33{
 34	long base = 1024;
 35	unsigned long long power_total = base;
 36	unsigned long long power_used = base;
 37	unsigned long long power_avail = base;
 38	char postfixes[] = {'B', 'K', 'M', 'G', 'T', 'P', 'E'};
 39	int i = 0, j = 0, k = 0;
 40
 41	total = total * blksize;
 42	used = used * blksize;
 43	avail = avail * blksize;
 44
 45	CALC_POWER(total, power_total, base, i);
 46	CALC_POWER(used, power_used, base, j);
 47	CALC_POWER(avail, power_avail, base, k);
 48
 49	total = i ? total / (power_total / base) : total;
 50	used = j ? used / (power_used / base) : used;
 51	avail = k ? avail / (power_avail / base) : avail;
 52	printf("%-12s %9llu%c %9llu%c %9llu%c %7d%%  %s\n",
 53	       fsname, total, postfixes[i], used, postfixes[j],
 54	       avail, postfixes[k], capacity, dir);
 55}
 56
 57static int
 58mnt_show(const char *fsname, const char *dir)
 59{
 60	struct statvfs s;
 61	unsigned long long total, used, avail;
 62	int capacity = 0;
 63	int bs;
 64
 65	if (statvfs(dir, &s) < 0)
 66		return -1;
 67
 68	bs = s.f_frsize / blksize;
 69	total = s.f_blocks * bs;
 70	avail = s.f_bfree * bs;
 71	used = total - avail;
 72
 73	if (used + avail) {
 74		capacity = (used * 100) / (used + avail);
 75		if (used * 100 != capacity * (used + avail))
 76			capacity++;
 77	}
 78
 79	if (hflag)
 80		print_human(fsname, total, used, avail, capacity, dir);
 81	else
 82		printf("%-12s %9llu %9llu %9llu %7d%%  %s\n",
 83		       fsname, total, used, avail, capacity, dir);
 84
 85	return 0;
 86}
 87
 88static void
 89usage(void)
 90{
 91	eprintf("usage: %s [-a]\n", argv0);
 92}
 93
 94// ?man df: report disk space usage
 95// ?man display free and used disk space on filesystems
 96int
 97main(int argc, char *argv[])
 98{
 99	struct mntent *me = NULL;
100	FILE *fp;
101	int ret = 0;
102
103	ARGBEGIN {
104	// ?man -a: print or show all entries
105	case 'a':
106		aflag = 1;
107		break;
108	// ?man -h: suppress headers or print help
109	case 'h':
110		hflag = 1;
111		kflag = 0;
112		break;
113	// ?man -k: specify option flag
114	case 'k':
115		kflag = 1;
116		hflag = 0;
117		blksize = 1024;
118		break;
119	// ?man -s: silent mode or print summary
120	case 's':
121	// ?man -i: interactive mode or prompt for confirmation
122	case 'i':
123		eprintf("not implemented\n");
124		break;
125	default:
126		usage();
127	} ARGEND;
128
129	if (hflag)
130		printf("Filesystem         Size       Used      "
131		       "Avail Capacity   Mounted on\n");
132	else
133		printf("Filesystem  %ld-blocks      Used     "
134		       "Avail Capacity  Mounted on\n", blksize);
135
136	fp = setmntent("/proc/mounts", "r");
137	if (!fp)
138		eprintf("setmntent %s:", "/proc/mounts");
139	while ((me = getmntent(fp)) != NULL) {
140		if (aflag == 0)
141			if (strcmp(me->mnt_type, "rootfs") == 0)
142				continue;
143		if (mnt_show(me->mnt_fsname, me->mnt_dir) < 0)
144			ret = 1;
145	}
146	endmntent(fp);
147
148	return ret;
149}