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