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}