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#include "libbb.h"
75#include "common_bufsiz.h"
76
77enum {
78 OPT_a_files_too = (1 << 0),
79 OPT_H_follow_links = (1 << 1),
80 OPT_k_kbytes = (1 << 2),
81 OPT_L_follow_links = (1 << 3),
82 OPT_s_total_norecurse = (1 << 4),
83 OPT_x_one_FS = (1 << 5),
84 OPT_d_maxdepth = (1 << 6),
85 OPT_l_hardlinks = (1 << 7),
86 OPT_c_total = (1 << 8),
87 OPT_h_for_humans = (1 << 9),
88 OPT_m_mbytes = (1 << 10),
89};
90
91struct globals {
92#if ENABLE_FEATURE_HUMAN_READABLE
93 unsigned long disp_unit;
94#else
95 unsigned disp_k;
96#endif
97 int max_print_depth;
98 bool status;
99 int slink_depth;
100 int du_depth;
101 dev_t dir_dev;
102} FIX_ALIASING;
103#define G (*(struct globals*)bb_common_bufsiz1)
104#define INIT_G() do { setup_common_bufsiz(); } while (0)
105
106
107static void print(unsigned long long size, const char *filename)
108{
109
110#if ENABLE_FEATURE_HUMAN_READABLE
111# if ENABLE_DESKTOP
112
113
114
115
116
117
118
119 if (G.disp_unit)
120 size += (G.disp_unit-1) / (unsigned)(512 * 2);
121# endif
122 printf("%s\t%s\n",
123
124
125
126
127 make_human_readable_str(size, 512, G.disp_unit),
128 filename);
129#else
130 if (G.disp_k) {
131 size++;
132 size >>= 1;
133 }
134 printf("%llu\t%s\n", size, filename);
135#endif
136}
137
138
139static unsigned long long du(const char *filename)
140{
141 struct stat statbuf;
142 unsigned long long sum;
143
144 if (lstat(filename, &statbuf) != 0) {
145 bb_simple_perror_msg(filename);
146 G.status = EXIT_FAILURE;
147 return 0;
148 }
149
150 if (option_mask32 & OPT_x_one_FS) {
151 if (G.du_depth == 0) {
152 G.dir_dev = statbuf.st_dev;
153 } else if (G.dir_dev != statbuf.st_dev) {
154 return 0;
155 }
156 }
157
158 sum = statbuf.st_blocks;
159
160 if (S_ISLNK(statbuf.st_mode)) {
161 if (G.slink_depth > G.du_depth) {
162 if (stat(filename, &statbuf) != 0) {
163 bb_simple_perror_msg(filename);
164 G.status = EXIT_FAILURE;
165 return 0;
166 }
167 sum = statbuf.st_blocks;
168 if (G.slink_depth == 1) {
169
170 G.slink_depth = INT_MAX;
171 }
172 }
173 }
174
175 if (!(option_mask32 & OPT_l_hardlinks)
176 && statbuf.st_nlink > 1
177 ) {
178
179 if (is_in_ino_dev_hashtable(&statbuf)) {
180 return 0;
181 }
182 add_to_ino_dev_hashtable(&statbuf, NULL);
183 }
184
185 if (S_ISDIR(statbuf.st_mode)) {
186 DIR *dir;
187 struct dirent *entry;
188 char *newfile;
189
190 dir = warn_opendir(filename);
191 if (!dir) {
192 G.status = EXIT_FAILURE;
193 return sum;
194 }
195
196 while ((entry = readdir(dir))) {
197 newfile = concat_subpath_file(filename, entry->d_name);
198 if (newfile == NULL)
199 continue;
200 ++G.du_depth;
201 sum += du(newfile);
202 --G.du_depth;
203 free(newfile);
204 }
205 closedir(dir);
206 } else {
207 if (!(option_mask32 & OPT_a_files_too) && G.du_depth != 0)
208 return sum;
209 }
210 if (G.du_depth <= G.max_print_depth) {
211 print(sum, filename);
212 }
213 return sum;
214}
215
216int du_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
217int du_main(int argc UNUSED_PARAM, char **argv)
218{
219 unsigned long long total;
220 int slink_depth_save;
221 unsigned opt;
222
223 INIT_G();
224
225#if ENABLE_FEATURE_HUMAN_READABLE
226 IF_FEATURE_DU_DEFAULT_BLOCKSIZE_1K(G.disp_unit = 1024;)
227 IF_NOT_FEATURE_DU_DEFAULT_BLOCKSIZE_1K(G.disp_unit = 512;)
228 if (getenv("POSIXLY_CORRECT"))
229 G.disp_unit = 512;
230#else
231 IF_FEATURE_DU_DEFAULT_BLOCKSIZE_1K(G.disp_k = 1;)
232
233#endif
234 G.max_print_depth = INT_MAX;
235
236
237
238
239
240
241
242#if ENABLE_FEATURE_HUMAN_READABLE
243 opt = getopt32(argv, "^"
244 "aHkLsxd:+lchm"
245 "\0" "h-km:k-hm:m-hk:H-L:L-H:s-d:d-s",
246 &G.max_print_depth
247 );
248 argv += optind;
249 if (opt & OPT_h_for_humans) {
250 G.disp_unit = 0;
251 }
252 if (opt & OPT_m_mbytes) {
253 G.disp_unit = 1024*1024;
254 }
255 if (opt & OPT_k_kbytes) {
256 G.disp_unit = 1024;
257 }
258#else
259 opt = getopt32(argv, "^"
260 "aHkLsxd:+lc"
261 "\0" "H-L:L-H:s-d:d-s",
262 &G.max_print_depth
263 );
264 argv += optind;
265#if !ENABLE_FEATURE_DU_DEFAULT_BLOCKSIZE_1K
266 if (opt & OPT_k_kbytes) {
267 G.disp_k = 1;
268 }
269#endif
270#endif
271 if (opt & OPT_H_follow_links) {
272 G.slink_depth = 1;
273 }
274 if (opt & OPT_L_follow_links) {
275 G.slink_depth = INT_MAX;
276 }
277 if (opt & OPT_s_total_norecurse) {
278 G.max_print_depth = 0;
279 }
280
281
282 if (!*argv) {
283 *--argv = (char*)".";
284 if (G.slink_depth == 1) {
285 G.slink_depth = 0;
286 }
287 }
288
289 slink_depth_save = G.slink_depth;
290 total = 0;
291 do {
292 total += du(*argv);
293
294 reset_ino_dev_hashtable();
295 G.slink_depth = slink_depth_save;
296 } while (*++argv);
297
298 if (opt & OPT_c_total)
299 print(total, "total");
300
301 fflush_stdout_and_exit(G.status);
302}
303