1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80#include <mntent.h>
81#include <sys/statvfs.h>
82#include "libbb.h"
83#include "unicode.h"
84
85#if !ENABLE_FEATURE_HUMAN_READABLE
86static unsigned long kscale(unsigned long b, unsigned long bs)
87{
88 return (b * (unsigned long long) bs + 1024/2) / 1024;
89}
90#endif
91
92int df_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
93int df_main(int argc UNUSED_PARAM, char **argv)
94{
95 unsigned long df_disp_hr = 1024;
96 int status = EXIT_SUCCESS;
97 unsigned opt;
98 FILE *mount_table;
99 struct mntent *mount_entry;
100 struct statvfs s;
101 enum {
102 OPT_KILO = (1 << 0),
103 OPT_POSIX = (1 << 1),
104 OPT_FSTYPE = (1 << 2),
105 OPT_t = (1 << 3),
106 OPT_ALL = (1 << 4) * ENABLE_FEATURE_DF_FANCY,
107 OPT_INODE = (1 << 5) * ENABLE_FEATURE_DF_FANCY,
108 OPT_BSIZE = (1 << 6) * ENABLE_FEATURE_DF_FANCY,
109 OPT_HUMAN = (1 << (4 + 3*ENABLE_FEATURE_DF_FANCY)) * ENABLE_FEATURE_HUMAN_READABLE,
110 OPT_MEGA = (1 << (5 + 3*ENABLE_FEATURE_DF_FANCY)) * ENABLE_FEATURE_HUMAN_READABLE,
111 };
112 const char *disp_units_hdr = NULL;
113 char *chp, *opt_t;
114
115 init_unicode();
116
117
118
119
120
121 if (getenv("POSIXLY_CORRECT"))
122 df_disp_hr = 512;
123
124 opt = getopt32(argv, "^"
125 "kPTt:"
126 IF_FEATURE_DF_FANCY("aiB:")
127 IF_FEATURE_HUMAN_READABLE("hm")
128 "\0"
129#if ENABLE_FEATURE_HUMAN_READABLE && ENABLE_FEATURE_DF_FANCY
130 "k-mB:m-Bk:B-km"
131#elif ENABLE_FEATURE_HUMAN_READABLE
132 "k-m:m-k"
133#endif
134 , &opt_t
135 IF_FEATURE_DF_FANCY(, &chp)
136 );
137 if (opt & OPT_MEGA)
138 df_disp_hr = 1024*1024;
139
140 if (opt & OPT_BSIZE) {
141
142 int i;
143 for (i = 0; kmg_i_suffixes[i].suffix[0]; i++) {
144 if (strcmp(kmg_i_suffixes[i].suffix, chp) == 0) {
145 df_disp_hr = kmg_i_suffixes[i].mult;
146 goto got_it;
147 }
148 }
149
150 df_disp_hr = xatoul_range_sfx(chp, 1, ULONG_MAX, kmg_i_suffixes);
151 got_it: ;
152 }
153
154 if (opt & OPT_HUMAN) {
155 df_disp_hr = 0;
156 disp_units_hdr = " Size";
157 }
158 if (opt & OPT_INODE)
159 disp_units_hdr = " Inodes";
160
161 if (disp_units_hdr == NULL) {
162#if ENABLE_FEATURE_HUMAN_READABLE
163 disp_units_hdr = xasprintf("%s-blocks",
164
165
166 make_human_readable_str(df_disp_hr, 0, !!(opt & OPT_POSIX))
167 );
168#else
169 disp_units_hdr = xasprintf("%lu-blocks", df_disp_hr);
170#endif
171 }
172
173 printf("Filesystem %s%-15sUsed Available %s Mounted on\n",
174 (opt & OPT_FSTYPE) ? "Type " : "",
175 disp_units_hdr,
176 (opt & OPT_POSIX) ? "Capacity" : "Use%");
177
178 mount_table = NULL;
179 argv += optind;
180 if (!argv[0]) {
181 mount_table = setmntent(bb_path_mtab_file, "r");
182 if (!mount_table)
183 bb_simple_perror_msg_and_die(bb_path_mtab_file);
184 }
185
186 while (1) {
187 const char *device;
188 const char *mount_point;
189 const char *fs_type;
190
191 if (mount_table) {
192 mount_entry = getmntent(mount_table);
193 if (!mount_entry) {
194 endmntent(mount_table);
195 break;
196 }
197 } else {
198 mount_point = *argv++;
199 if (!mount_point)
200 break;
201 mount_entry = find_mount_point(mount_point, 1);
202 if (!mount_entry) {
203 bb_error_msg("%s: can't find mount point", mount_point);
204 set_error:
205 status = EXIT_FAILURE;
206 continue;
207 }
208 }
209
210 device = mount_entry->mnt_fsname;
211
212
213 if (ENABLE_FEATURE_SKIP_ROOTFS && strcmp(device, "rootfs") == 0)
214 continue;
215
216 mount_point = mount_entry->mnt_dir;
217 fs_type = mount_entry->mnt_type;
218
219 if (opt & OPT_t) {
220 if (strcmp(fs_type, opt_t) != 0)
221 continue;
222 }
223
224 if (statvfs(mount_point, &s) != 0) {
225 bb_simple_perror_msg(mount_point);
226 goto set_error;
227 }
228
229
230
231 if (s.f_frsize == 0)
232 s.f_frsize = s.f_bsize;
233
234 if ((s.f_blocks > 0) || !mount_table || (opt & OPT_ALL)) {
235 unsigned long long blocks_used;
236 unsigned long long blocks_total;
237 unsigned blocks_percent_used;
238
239 if (opt & OPT_INODE) {
240 s.f_blocks = s.f_files;
241 s.f_bavail = s.f_bfree = s.f_ffree;
242 s.f_frsize = 1;
243 if (df_disp_hr)
244 df_disp_hr = 1;
245 }
246 blocks_used = s.f_blocks - s.f_bfree;
247 blocks_total = blocks_used + s.f_bavail;
248 blocks_percent_used = blocks_total;
249 if (blocks_total != 0) {
250
251 unsigned u;
252 while (blocks_total >= INT_MAX / 101) {
253 blocks_total >>= 1;
254 blocks_used >>= 1;
255 }
256 u = (unsigned)blocks_used * 100u + (unsigned)blocks_total / 2;
257 blocks_percent_used = u / (unsigned)blocks_total;
258 }
259
260#ifdef WHY_WE_DO_IT_FOR_DEV_ROOT_ONLY
261 if (strcmp(device, "/dev/root") == 0) {
262
263
264 device = find_block_device("/");
265 if (!device) {
266 goto set_error;
267 }
268 }
269#endif
270
271#if ENABLE_UNICODE_SUPPORT
272 {
273 uni_stat_t uni_stat;
274 char *uni_dev = unicode_conv_to_printable(&uni_stat, device);
275 if (uni_stat.unicode_width > 20 && !(opt & OPT_POSIX)) {
276 printf("%s\n%20s", uni_dev, "");
277 } else {
278 printf("%s%*s", uni_dev, 20 - (int)uni_stat.unicode_width, "");
279 }
280 free(uni_dev);
281 if (opt & OPT_FSTYPE) {
282 char *uni_type = unicode_conv_to_printable(&uni_stat, fs_type);
283 if (uni_stat.unicode_width > 10 && !(opt & OPT_POSIX))
284 printf(" %s\n%31s", uni_type, "");
285 else
286 printf(" %s%*s", uni_type, 10 - (int)uni_stat.unicode_width, "");
287 free(uni_type);
288 }
289 }
290#else
291 if (printf("\n%-20s" + 1, device) > 20 && !(opt & OPT_POSIX))
292 printf("\n%-20s", "");
293 if (opt & OPT_FSTYPE) {
294 if (printf(" %-10s", fs_type) > 11 && !(opt & OPT_POSIX))
295 printf("\n%-30s", "");
296 }
297#endif
298
299#if ENABLE_FEATURE_HUMAN_READABLE
300 printf(" %9s ",
301
302
303 make_human_readable_str(s.f_blocks, s.f_frsize, df_disp_hr));
304
305 printf(" %9s " + 1,
306
307
308 make_human_readable_str((s.f_blocks - s.f_bfree),
309 s.f_frsize, df_disp_hr));
310
311 printf("%9s %3u%% %s\n",
312
313
314 make_human_readable_str(s.f_bavail, s.f_frsize, df_disp_hr),
315 blocks_percent_used, mount_point);
316#else
317 printf(" %9lu %9lu %9lu %3u%% %s\n",
318 kscale(s.f_blocks, s.f_frsize),
319 kscale(s.f_blocks - s.f_bfree, s.f_frsize),
320 kscale(s.f_bavail, s.f_frsize),
321 blocks_percent_used, mount_point);
322#endif
323 }
324 }
325
326 return status;
327}
328