source: MondoRescue/branches/2.2.8.selinux/mindi-busybox/coreutils/du.c@ 3528

Last change on this file since 3528 was 1765, checked in by Bruno Cornec, 16 years ago

Update to busybox 1.7.2

File size: 5.6 KB
Line 
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini du implementation for busybox
4 *
5 * Copyright (C) 1999,2000,2001 by Lineo, inc. and John Beppu
6 * Copyright (C) 1999,2000,2001 by John Beppu <beppu@codepoet.org>
7 * Copyright (C) 2002 Edward Betts <edward@debian.org>
8 *
9 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
10 */
11
12/* BB_AUDIT SUSv3 compliant (unless default blocksize set to 1k) */
13/* http://www.opengroup.org/onlinepubs/007904975/utilities/du.html */
14
15/* Mar 16, 2003 Manuel Novoa III (mjn3@codepoet.org)
16 *
17 * Mostly rewritten for SUSv3 compliance and to fix bugs/defects.
18 * 1) Added support for SUSv3 -a, -H, -L, gnu -c, and (busybox) -d options.
19 * The -d option allows setting of max depth (similar to gnu --max-depth).
20 * 2) Fixed incorrect size calculations for links and directories, especially
21 * when errors occurred. Calculates sizes should now match gnu du output.
22 * 3) Added error checking of output.
23 * 4) Fixed busybox bug #1284 involving long overflow with human_readable.
24 */
25
26#include "libbb.h"
27
28#if ENABLE_FEATURE_HUMAN_READABLE
29# if ENABLE_FEATURE_DU_DEFAULT_BLOCKSIZE_1K
30static unsigned long disp_hr = 1024;
31# else
32static unsigned long disp_hr = 512;
33# endif
34#elif ENABLE_FEATURE_DU_DEFAULT_BLOCKSIZE_1K
35static unsigned disp_k = 1;
36#else
37static unsigned disp_k; /* bss inits to 0 */
38#endif
39
40static int max_print_depth = INT_MAX;
41static nlink_t count_hardlinks = 1;
42
43static int status;
44static int print_files;
45static int slink_depth;
46static int du_depth;
47static int one_file_system;
48static dev_t dir_dev;
49
50
51static void print(long size, const char *const filename)
52{
53 /* TODO - May not want to defer error checking here. */
54#if ENABLE_FEATURE_HUMAN_READABLE
55 printf("%s\t%s\n", make_human_readable_str(size, 512, disp_hr),
56 filename);
57#else
58 if (disp_k) {
59 size++;
60 size >>= 1;
61 }
62 printf("%ld\t%s\n", size, filename);
63#endif
64}
65
66/* tiny recursive du */
67static long du(const char *const filename)
68{
69 struct stat statbuf;
70 long sum;
71
72 if (lstat(filename, &statbuf) != 0) {
73 bb_perror_msg("%s", filename);
74 status = EXIT_FAILURE;
75 return 0;
76 }
77
78 if (one_file_system) {
79 if (du_depth == 0) {
80 dir_dev = statbuf.st_dev;
81 } else if (dir_dev != statbuf.st_dev) {
82 return 0;
83 }
84 }
85
86 sum = statbuf.st_blocks;
87
88 if (S_ISLNK(statbuf.st_mode)) {
89 if (slink_depth > du_depth) { /* -H or -L */
90 if (stat(filename, &statbuf) != 0) {
91 bb_perror_msg("%s", filename);
92 status = EXIT_FAILURE;
93 return 0;
94 }
95 sum = statbuf.st_blocks;
96 if (slink_depth == 1) {
97 slink_depth = INT_MAX; /* Convert -H to -L. */
98 }
99 }
100 }
101
102 if (statbuf.st_nlink > count_hardlinks) {
103 /* Add files/directories with links only once */
104 if (is_in_ino_dev_hashtable(&statbuf)) {
105 return 0;
106 }
107 add_to_ino_dev_hashtable(&statbuf, NULL);
108 }
109
110 if (S_ISDIR(statbuf.st_mode)) {
111 DIR *dir;
112 struct dirent *entry;
113 char *newfile;
114
115 dir = warn_opendir(filename);
116 if (!dir) {
117 status = EXIT_FAILURE;
118 return sum;
119 }
120
121 newfile = last_char_is(filename, '/');
122 if (newfile)
123 *newfile = '\0';
124
125 while ((entry = readdir(dir))) {
126 char *name = entry->d_name;
127
128 newfile = concat_subpath_file(filename, name);
129 if (newfile == NULL)
130 continue;
131 ++du_depth;
132 sum += du(newfile);
133 --du_depth;
134 free(newfile);
135 }
136 closedir(dir);
137 } else if (du_depth > print_files) {
138 return sum;
139 }
140 if (du_depth <= max_print_depth) {
141 print(sum, filename);
142 }
143 return sum;
144}
145
146int du_main(int argc, char **argv);
147int du_main(int argc, char **argv)
148{
149 long total;
150 int slink_depth_save;
151 int print_final_total;
152 char *smax_print_depth;
153 unsigned opt;
154
155#if ENABLE_FEATURE_DU_DEFAULT_BLOCKSIZE_1K
156 if (getenv("POSIXLY_CORRECT")) { /* TODO - a new libbb function? */
157#if ENABLE_FEATURE_HUMAN_READABLE
158 disp_hr = 512;
159#else
160 disp_k = 0;
161#endif
162 }
163#endif
164
165 /* Note: SUSv3 specifies that -a and -s options cannot be used together
166 * in strictly conforming applications. However, it also says that some
167 * du implementations may produce output when -a and -s are used together.
168 * gnu du exits with an error code in this case. We choose to simply
169 * ignore -a. This is consistent with -s being equivalent to -d 0.
170 */
171#if ENABLE_FEATURE_HUMAN_READABLE
172 opt_complementary = "h-km:k-hm:m-hk:H-L:L-H:s-d:d-s";
173 opt = getopt32(argv, "aHkLsx" "d:" "lc" "hm", &smax_print_depth);
174 if (opt & (1 << 9)) {
175 /* -h opt */
176 disp_hr = 0;
177 }
178 if (opt & (1 << 10)) {
179 /* -m opt */
180 disp_hr = 1024*1024;
181 }
182 if (opt & (1 << 2)) {
183 /* -k opt */
184 disp_hr = 1024;
185 }
186#else
187 opt_complementary = "H-L:L-H:s-d:d-s";
188 opt = getopt32(argv, "aHkLsx" "d:" "lc", &smax_print_depth);
189#if !ENABLE_FEATURE_DU_DEFAULT_BLOCKSIZE_1K
190 if (opt & (1 << 2)) {
191 /* -k opt */
192 disp_k = 1;
193 }
194#endif
195#endif
196 if (opt & (1 << 0)) {
197 /* -a opt */
198 print_files = INT_MAX;
199 }
200 if (opt & (1 << 1)) {
201 /* -H opt */
202 slink_depth = 1;
203 }
204 if (opt & (1 << 3)) {
205 /* -L opt */
206 slink_depth = INT_MAX;
207 }
208 if (opt & (1 << 4)) {
209 /* -s opt */
210 max_print_depth = 0;
211 }
212 one_file_system = opt & (1 << 5); /* -x opt */
213 if (opt & (1 << 6)) {
214 /* -d opt */
215 max_print_depth = xatoi_u(smax_print_depth);
216 }
217 if (opt & (1 << 7)) {
218 /* -l opt */
219 count_hardlinks = MAXINT(nlink_t);
220 }
221 print_final_total = opt & (1 << 8); /* -c opt */
222
223 /* go through remaining args (if any) */
224 argv += optind;
225 if (optind >= argc) {
226 *--argv = (char*)".";
227 if (slink_depth == 1) {
228 slink_depth = 0;
229 }
230 }
231
232 slink_depth_save = slink_depth;
233 total = 0;
234 do {
235 total += du(*argv);
236 slink_depth = slink_depth_save;
237 } while (*++argv);
238 if (ENABLE_FEATURE_CLEAN_UP)
239 reset_ino_dev_hashtable();
240 if (print_final_total) {
241 print(total, "total");
242 }
243
244 fflush_stdout_and_exit(status);
245}
Note: See TracBrowser for help on using the repository browser.