*** empty log message ***
[coreutils.git] / src / du.c
blobd25cb119fb576afbe54c16afa7745eb3d590e8e5
1 /* du -- summarize disk usage
2 Copyright (C) 88, 89, 90, 91, 1995-2002 Free Software Foundation, Inc.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software Foundation,
16 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
18 /* Differences from the Unix du:
19 * Doesn't simply ignore the names of regular files given as arguments
20 when -a is given.
21 * Additional options:
22 -l Count the size of all files, even if they have appeared
23 already in another hard link.
24 -x Do not cross file-system boundaries during the recursion.
25 -c Write a grand total of all of the arguments after all
26 arguments have been processed. This can be used to find
27 out the disk usage of a directory, with some files excluded.
28 -h Print sizes in human readable format (1k 234M 2G, etc).
29 -H Similar, but use powers of 1000 not 1024.
30 -k Print sizes in kilobytes.
31 -m Print sizes in megabytes.
32 -b Print sizes in bytes.
33 -S Count the size of each directory separately, not including
34 the sizes of subdirectories.
35 -D Dereference only symbolic links given on the command line.
36 -L Dereference all symbolic links.
37 --exclude=PATTERN Exclude files that match PATTERN.
38 -X FILE Exclude files that match patterns taken from FILE.
40 By tege@sics.se, Torbjorn Granlund,
41 and djm@ai.mit.edu, David MacKenzie.
42 Variable blocks added by lm@sgi.com and eggert@twinsun.com.
45 #include <config.h>
46 #if HAVE_INTTYPES_H
47 # include <inttypes.h>
48 #endif
49 #include <stdio.h>
50 #include <getopt.h>
51 #include <sys/types.h>
52 #include <assert.h>
54 #include "system.h"
55 #include "error.h"
56 #include "exclude.h"
57 #include "hash.h"
58 #include "human.h"
59 #include "quote.h"
60 #include "same.h"
61 #include "save-cwd.h"
62 #include "savedir.h"
63 #include "xstrtol.h"
65 /* The official name of this program (e.g., no `g' prefix). */
66 #define PROGRAM_NAME "du"
68 #define AUTHORS \
69 "Torbjorn Granlund, David MacKenzie, Larry McVoy, and Paul Eggert"
71 /* Initial size of the hash table. */
72 #define INITIAL_TABLE_SIZE 103
74 /* Initial size to allocate for `path'. */
75 #define INITIAL_PATH_SIZE 100
77 /* Hash structure for inode and device numbers. The separate entry
78 structure makes it easier to rehash "in place". */
80 struct entry
82 ino_t st_ino;
83 dev_t st_dev;
86 /* A set of dev/ino pairs. */
87 static Hash_table *htab;
89 /* Structure for dynamically resizable strings. */
91 struct String
93 unsigned alloc; /* Size of allocation for the text. */
94 unsigned length; /* Length of the text currently. */
95 char *text; /* Pointer to the text. */
97 typedef struct String String;
99 int stat ();
100 int lstat ();
102 /* Name under which this program was invoked. */
103 char *program_name;
105 /* If nonzero, display counts for all files, not just directories. */
106 static int opt_all = 0;
108 /* If nonzero, count each hard link of files with multiple links. */
109 static int opt_count_all = 0;
111 /* If nonzero, do not cross file-system boundaries. */
112 static int opt_one_file_system = 0;
114 /* If nonzero, print a grand total at the end. */
115 static int print_totals = 0;
117 /* If nonzero, do not add sizes of subdirectories. */
118 static int opt_separate_dirs = 0;
120 /* If nonzero, dereference symlinks that are command line arguments. */
121 static int opt_dereference_arguments = 0;
123 /* Show the total for each directory (and file if --all) that is at
124 most MAX_DEPTH levels down from the root of the hierarchy. The root
125 is at level 0, so `du --max-depth=0' is equivalent to `du -s'. */
126 static int max_depth = INT_MAX;
128 /* If positive, the units to use when printing sizes;
129 if negative, the human-readable base. */
130 static int output_block_size;
132 /* Accumulated path for file or directory being processed. */
133 static String *path;
135 /* A pointer to either lstat or stat, depending on whether
136 dereferencing of all symbolic links is to be done. */
137 static int (*xstat) ();
139 /* The exit status to use if we don't get any fatal errors. */
140 static int exit_status;
142 /* File name patterns to exclude. */
143 static struct exclude *exclude;
145 /* Grand total size of all args, in units of ST_NBLOCKSIZE-byte blocks. */
146 static uintmax_t tot_size = 0;
148 /* For long options that have no equivalent short option, use a
149 non-character as a pseudo short option, starting with CHAR_MAX + 1. */
150 enum
152 EXCLUDE_OPTION = CHAR_MAX + 1,
153 MAX_DEPTH_OPTION
156 static struct option const long_options[] =
158 {"all", no_argument, NULL, 'a'},
159 {"block-size", required_argument, 0, 'B'},
160 {"bytes", no_argument, NULL, 'b'},
161 {"count-links", no_argument, NULL, 'l'},
162 {"dereference", no_argument, NULL, 'L'},
163 {"dereference-args", no_argument, NULL, 'D'},
164 {"exclude", required_argument, 0, EXCLUDE_OPTION},
165 {"exclude-from", required_argument, 0, 'X'},
166 {"human-readable", no_argument, NULL, 'h'},
167 {"si", no_argument, 0, 'H'},
168 {"kilobytes", no_argument, NULL, 'k'}, /* long form is obsolescent */
169 {"max-depth", required_argument, NULL, MAX_DEPTH_OPTION},
170 {"megabytes", no_argument, NULL, 'm'}, /* obsolescent */
171 {"one-file-system", no_argument, NULL, 'x'},
172 {"separate-dirs", no_argument, NULL, 'S'},
173 {"summarize", no_argument, NULL, 's'},
174 {"total", no_argument, NULL, 'c'},
175 {GETOPT_HELP_OPTION_DECL},
176 {GETOPT_VERSION_OPTION_DECL},
177 {NULL, 0, NULL, 0}
180 void
181 usage (int status)
183 if (status != 0)
184 fprintf (stderr, _("Try `%s --help' for more information.\n"),
185 program_name);
186 else
188 printf (_("Usage: %s [OPTION]... [FILE]...\n"), program_name);
189 fputs (_("\
190 Summarize disk usage of each FILE, recursively for directories.\n\
192 "), stdout);
193 fputs (_("\
194 Mandatory arguments to long options are mandatory for short options too.\n\
195 "), stdout);
196 fputs (_("\
197 -a, --all write counts for all files, not just directories\n\
198 -B, --block-size=SIZE use SIZE-byte blocks\n\
199 -b, --bytes print size in bytes\n\
200 -c, --total produce a grand total\n\
201 -D, --dereference-args dereference PATHs when symbolic link\n\
202 "), stdout);
203 fputs (_("\
204 -h, --human-readable print sizes in human readable format (e.g., 1K 234M 2G)\n\
205 -H, --si likewise, but use powers of 1000 not 1024\n\
206 -k like --block-size=1K\n\
207 -l, --count-links count sizes many times if hard linked\n\
208 "), stdout);
209 fputs (_("\
210 -L, --dereference dereference all symbolic links\n\
211 -S, --separate-dirs do not include size of subdirectories\n\
212 -s, --summarize display only a total for each argument\n\
213 "), stdout);
214 fputs (_("\
215 -x, --one-file-system skip directories on different filesystems\n\
216 -X FILE, --exclude-from=FILE Exclude files that match any pattern in FILE.\n\
217 --exclude=PATTERN Exclude files that match PATTERN.\n\
218 --max-depth=N print the total for a directory (or file, with --all)\n\
219 only if it is N or fewer levels below the command\n\
220 line argument; --max-depth=0 is the same as\n\
221 --summarize\n\
222 "), stdout);
223 fputs (HELP_OPTION_DESCRIPTION, stdout);
224 fputs (VERSION_OPTION_DESCRIPTION, stdout);
225 fputs (_("\n\
226 SIZE may be (or may be an integer optionally followed by) one of following:\n\
227 kB 1000, K 1024, MB 1,000,000, M 1,048,576, and so on for G, T, P, E, Z, Y.\n\
228 "), stdout);
229 printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
231 exit (status);
234 static unsigned int
235 entry_hash (void const *x, unsigned int table_size)
237 struct entry const *p = x;
239 /* Ignoring the device number here should be fine. */
240 /* The cast to uintmax_t prevents negative remainders
241 if st_ino is negative. */
242 return (uintmax_t) p->st_ino % table_size;
245 /* Compare two dev/ino pairs. Return true if they are the same. */
246 static bool
247 entry_compare (void const *x, void const *y)
249 struct entry const *a = x;
250 struct entry const *b = y;
251 return SAME_INODE (*a, *b) ? true : false;
254 /* Try to insert the INO/DEV pair into the global table, HTAB.
255 If the pair is successfully inserted, return zero.
256 Upon failed memory allocation exit nonzero.
257 If the pair is already in the table, return nonzero. */
258 static int
259 hash_ins (ino_t ino, dev_t dev)
261 struct entry *ent;
262 struct entry *ent_from_table;
264 ent = (struct entry *) xmalloc (sizeof *ent);
265 ent->st_ino = ino;
266 ent->st_dev = dev;
268 ent_from_table = hash_insert (htab, ent);
269 if (ent_from_table == NULL)
271 /* Insertion failed due to lack of memory. */
272 xalloc_die ();
275 if (ent_from_table == ent)
277 /* Insertion succeeded. */
278 return 0;
281 /* That pair is already in the table, so ENT was not inserted. Free it. */
282 free (ent);
284 return 1;
287 /* Initialize the hash table. */
288 static void
289 hash_init (void)
291 htab = hash_initialize (INITIAL_TABLE_SIZE, NULL,
292 entry_hash, entry_compare, free);
293 if (htab == NULL)
294 xalloc_die ();
297 /* Initialize string S1 to hold SIZE characters. */
299 static void
300 str_init (String **s1, unsigned int size)
302 String *s;
304 s = (String *) xmalloc (sizeof (struct String));
305 s->text = xmalloc (size + 1);
307 s->alloc = size;
308 *s1 = s;
311 static void
312 ensure_space (String *s, unsigned int size)
314 if (s->alloc < size)
316 s->text = xrealloc (s->text, size + 1);
317 s->alloc = size;
321 /* Assign the null-terminated C-string CSTR to S1. */
323 static void
324 str_copyc (String *s1, const char *cstr)
326 unsigned l = strlen (cstr);
327 ensure_space (s1, l);
328 strcpy (s1->text, cstr);
329 s1->length = l;
332 static void
333 str_concatc (String *s1, const char *cstr)
335 unsigned l1 = s1->length;
336 unsigned l2 = strlen (cstr);
337 unsigned l = l1 + l2;
339 ensure_space (s1, l);
340 strcpy (s1->text + l1, cstr);
341 s1->length = l;
344 /* Truncate the string S1 to have length LENGTH. */
346 static void
347 str_trunc (String *s1, unsigned int length)
349 if (s1->length > length)
351 s1->text[length] = 0;
352 s1->length = length;
356 /* Print N_BLOCKS followed by STRING on a line. NBLOCKS is the number of
357 ST_NBLOCKSIZE-byte blocks; convert it to OUTPUT_BLOCK_SIZE units before
358 printing. If OUTPUT_BLOCK_SIZE is negative, use a human readable
359 notation instead. */
361 static void
362 print_size (uintmax_t n_blocks, const char *string)
364 char buf[LONGEST_HUMAN_READABLE + 1];
365 printf ("%s\t%s\n",
366 human_readable_inexact (n_blocks, buf, ST_NBLOCKSIZE,
367 output_block_size, human_ceiling),
368 string);
369 fflush (stdout);
372 /* Restore the previous working directory or exit.
373 If CWD is null, simply call `chdir ("..")'. Otherwise,
374 use CWD and free it. CURR_DIR_NAME is the name of the current directory
375 and is used solely in failure diagnostics. */
377 static void
378 pop_dir (struct saved_cwd *cwd, const char *curr_dir_name)
380 if (cwd)
382 if (restore_cwd (cwd, "..", curr_dir_name))
383 exit (1);
384 free_cwd (cwd);
386 else if (chdir ("..") < 0)
388 error (1, errno, _("cannot change to `..' from directory %s"),
389 quote (curr_dir_name));
393 /* Print (if appropriate) the size (in units determined by `output_block_size')
394 of file or directory ENT. Return the size of ENT in units of 512-byte
395 blocks. TOP is one for external calls, zero for recursive calls.
396 LAST_DEV is the device that the parent directory of ENT is on.
397 DEPTH is the number of levels (in hierarchy) down from a command
398 line argument. Don't print if DEPTH > max_depth.
399 An important invariant is that when this function returns, the current
400 working directory is the same as when it was called. */
402 static uintmax_t
403 count_entry (const char *ent, int top, dev_t last_dev, int depth)
405 uintmax_t size;
406 struct stat stat_buf;
408 if (((top && opt_dereference_arguments)
409 ? stat (ent, &stat_buf)
410 : (*xstat) (ent, &stat_buf)) < 0)
412 error (0, errno, "%s", quote (path->text));
413 exit_status = 1;
414 return 0;
417 if (!opt_count_all
418 && stat_buf.st_nlink > 1
419 && hash_ins (stat_buf.st_ino, stat_buf.st_dev))
420 return 0; /* Have counted this already. */
422 size = ST_NBLOCKS (stat_buf);
423 tot_size += size;
425 if (S_ISDIR (stat_buf.st_mode))
427 unsigned pathlen;
428 dev_t dir_dev;
429 char *name_space;
430 char *namep;
431 struct saved_cwd *cwd;
432 struct saved_cwd cwd_buf;
433 struct stat e_buf;
435 dir_dev = stat_buf.st_dev;
437 /* Return `0' here, not SIZE, since the SIZE bytes
438 would reside in the new filesystem. */
439 if (opt_one_file_system && !top && last_dev != dir_dev)
440 return 0; /* Don't enter a new file system. */
442 #ifndef S_ISLNK
443 # define S_ISLNK(s) 0
444 #endif
445 /* If we're traversing more than one level, or if we're
446 dereferencing symlinks and we're about to chdir through a
447 symlink, remember the current directory so we can return to
448 it later. In other cases, chdir ("..") works fine.
449 Treat `.' and `..' like multi-level paths, since `chdir ("..")'
450 wont't restore the current working directory after a `chdir'
451 to one of those. */
452 if (strchr (ent, '/')
453 || DOT_OR_DOTDOT (ent)
454 || (xstat == stat
455 && lstat (ent, &e_buf) == 0
456 && S_ISLNK (e_buf.st_mode)))
458 if (save_cwd (&cwd_buf))
459 exit (1);
460 cwd = &cwd_buf;
462 else
463 cwd = NULL;
465 if (chdir (ent) < 0)
467 error (0, errno, _("cannot change to directory %s"),
468 quote (path->text));
469 if (cwd)
470 free_cwd (cwd);
471 exit_status = 1;
472 /* Do return SIZE, here, since even though we can't chdir into ENT,
473 we *can* count the blocks used by its directory entry. */
474 return opt_separate_dirs ? 0 : size;
477 name_space = savedir (".");
478 if (name_space == NULL)
480 error (0, errno, "%s", quote (path->text));
481 pop_dir (cwd, path->text);
482 exit_status = 1;
483 /* Do count the SIZE bytes. */
484 return opt_separate_dirs ? 0 : size;
487 /* Remember the current path. */
489 str_concatc (path, "/");
490 pathlen = path->length;
492 for (namep = name_space; *namep; namep += strlen (namep) + 1)
494 if (!excluded_filename (exclude, namep))
496 str_concatc (path, namep);
497 size += count_entry (namep, 0, dir_dev, depth + 1);
498 str_trunc (path, pathlen);
502 free (name_space);
503 pop_dir (cwd, path->text);
505 str_trunc (path, pathlen - 1); /* Remove the "/" we added. */
506 if (depth <= max_depth || top)
507 print_size (size, path->length > 0 ? path->text : "/");
508 return opt_separate_dirs ? 0 : size;
510 else if ((opt_all && depth <= max_depth) || top)
512 /* FIXME: make this an option. */
513 int print_only_dir_size = 0;
514 if (!print_only_dir_size)
515 print_size (size, path->length > 0 ? path->text : "/");
518 return size;
521 /* Recursively print the sizes of the directories (and, if selected, files)
522 named in FILES, the last entry of which is NULL. */
524 static void
525 du_files (char **files)
527 int i; /* Index in FILES. */
529 for (i = 0; files[i]; i++)
531 char *arg;
532 int s;
534 arg = files[i];
536 /* Delete final slash in the argument, unless the slash is alone. */
537 s = strlen (arg) - 1;
538 if (s != 0)
540 if (arg[s] == '/')
541 arg[s] = 0;
543 str_copyc (path, arg);
545 else if (arg[0] == '/')
546 str_trunc (path, 0); /* Null path for root directory. */
547 else
548 str_copyc (path, arg);
550 if (!print_totals)
551 hash_clear (htab);
553 count_entry (arg, 1, 0, 0);
556 if (print_totals)
557 print_size (tot_size, _("total"));
561 main (int argc, char **argv)
563 int c;
564 char *cwd_only[2];
565 int max_depth_specified = 0;
567 /* If nonzero, display only a total for each argument. */
568 int opt_summarize_only = 0;
570 cwd_only[0] = ".";
571 cwd_only[1] = NULL;
573 program_name = argv[0];
574 setlocale (LC_ALL, "");
575 bindtextdomain (PACKAGE, LOCALEDIR);
576 textdomain (PACKAGE);
578 atexit (close_stdout);
580 exclude = new_exclude ();
581 xstat = lstat;
583 human_block_size (getenv ("DU_BLOCK_SIZE"), 0, &output_block_size);
585 while ((c = getopt_long (argc, argv, "abchHklmsxB:DLSX:", long_options, NULL))
586 != -1)
588 long int tmp_long;
589 switch (c)
591 case 0: /* Long option. */
592 break;
594 case 'a':
595 opt_all = 1;
596 break;
598 case 'b':
599 output_block_size = 1;
600 break;
602 case 'c':
603 print_totals = 1;
604 break;
606 case 'h':
607 output_block_size = -1024;
608 break;
610 case 'H':
611 output_block_size = -1000;
612 break;
614 case 'k':
615 output_block_size = 1024;
616 break;
618 case MAX_DEPTH_OPTION: /* --max-depth=N */
619 if (xstrtol (optarg, NULL, 0, &tmp_long, NULL) != LONGINT_OK
620 || tmp_long < 0 || tmp_long > INT_MAX)
621 error (1, 0, _("invalid maximum depth %s"), quote (optarg));
623 max_depth_specified = 1;
624 max_depth = (int) tmp_long;
625 break;
627 case 'm': /* obsolescent */
628 output_block_size = 1024 * 1024;
629 break;
631 case 'l':
632 opt_count_all = 1;
633 break;
635 case 's':
636 opt_summarize_only = 1;
637 break;
639 case 'x':
640 opt_one_file_system = 1;
641 break;
643 case 'B':
644 human_block_size (optarg, 1, &output_block_size);
645 break;
647 case 'D':
648 opt_dereference_arguments = 1;
649 break;
651 case 'L':
652 xstat = stat;
653 break;
655 case 'S':
656 opt_separate_dirs = 1;
657 break;
659 case 'X':
660 if (add_exclude_file (add_exclude, exclude, optarg,
661 EXCLUDE_WILDCARDS, '\n'))
662 error (1, errno, "%s", quote (optarg));
663 break;
665 case EXCLUDE_OPTION:
666 add_exclude (exclude, optarg, EXCLUDE_WILDCARDS);
667 break;
669 case_GETOPT_HELP_CHAR;
671 case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
673 default:
674 usage (1);
678 if (opt_all && opt_summarize_only)
680 error (0, 0, _("cannot both summarize and show all entries"));
681 usage (1);
684 if (opt_summarize_only && max_depth_specified && max_depth == 0)
686 error (0, 0,
687 _("warning: summarizing is the same as using --max-depth=0"));
690 if (opt_summarize_only && max_depth_specified && max_depth != 0)
692 error (0, 0,
693 _("warning: summarizing conflicts with --max-depth=%d"),
694 max_depth);
695 usage (1);
698 if (opt_summarize_only)
699 max_depth = 0;
701 /* Initialize the hash structure for inode numbers. */
702 hash_init ();
704 str_init (&path, INITIAL_PATH_SIZE);
706 du_files (optind == argc ? cwd_only : argv + optind);
708 exit (exit_status);