du: add -t SIZE, --threshold=SIZE option
[platform/upstream/coreutils.git] / src / du.c
1 /* du -- summarize disk usage
2    Copyright (C) 1988-2013 Free Software Foundation, Inc.
3
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 3 of the License, or
7    (at your option) any later version.
8
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.
13
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
16
17 /* Differences from the Unix du:
18    * Doesn't simply ignore the names of regular files given as arguments
19      when -a is given.
20
21    By tege@sics.se, Torbjorn Granlund,
22    and djm@ai.mit.edu, David MacKenzie.
23    Variable blocks added by lm@sgi.com and eggert@twinsun.com.
24    Rewritten to use nftw, then to use fts by Jim Meyering.  */
25
26 #include <config.h>
27 #include <getopt.h>
28 #include <sys/types.h>
29 #include <assert.h>
30 #include "system.h"
31 #include "argmatch.h"
32 #include "argv-iter.h"
33 #include "di-set.h"
34 #include "error.h"
35 #include "exclude.h"
36 #include "fprintftime.h"
37 #include "human.h"
38 #include "mountlist.h"
39 #include "quote.h"
40 #include "quotearg.h"
41 #include "stat-size.h"
42 #include "stat-time.h"
43 #include "stdio--.h"
44 #include "xfts.h"
45 #include "xstrtol.h"
46
47 extern bool fts_debug;
48
49 /* The official name of this program (e.g., no 'g' prefix).  */
50 #define PROGRAM_NAME "du"
51
52 #define AUTHORS \
53   proper_name_utf8 ("Torbjorn Granlund", "Torbj\303\266rn Granlund"), \
54   proper_name ("David MacKenzie"), \
55   proper_name ("Paul Eggert"), \
56   proper_name ("Jim Meyering")
57
58 #if DU_DEBUG
59 # define FTS_CROSS_CHECK(Fts) fts_cross_check (Fts)
60 #else
61 # define FTS_CROSS_CHECK(Fts)
62 #endif
63
64 /* A set of dev/ino pairs to help identify files and directories
65    whose sizes have already been counted.  */
66 static struct di_set *di_files;
67
68 /* A set containing a dev/ino pair for each local mount point directory.  */
69 static struct di_set *di_mnt;
70
71 /* Keep track of the preceding "level" (depth in hierarchy)
72    from one call of process_file to the next.  */
73 static size_t prev_level;
74
75 /* Define a class for collecting directory information. */
76 struct duinfo
77 {
78   /* Size of files in directory.  */
79   uintmax_t size;
80
81   /* Latest time stamp found.  If tmax.tv_sec == TYPE_MINIMUM (time_t)
82      && tmax.tv_nsec < 0, no time stamp has been found.  */
83   struct timespec tmax;
84 };
85
86 /* Initialize directory data.  */
87 static inline void
88 duinfo_init (struct duinfo *a)
89 {
90   a->size = 0;
91   a->tmax.tv_sec = TYPE_MINIMUM (time_t);
92   a->tmax.tv_nsec = -1;
93 }
94
95 /* Set directory data.  */
96 static inline void
97 duinfo_set (struct duinfo *a, uintmax_t size, struct timespec tmax)
98 {
99   a->size = size;
100   a->tmax = tmax;
101 }
102
103 /* Accumulate directory data.  */
104 static inline void
105 duinfo_add (struct duinfo *a, struct duinfo const *b)
106 {
107   uintmax_t sum = a->size + b->size;
108   a->size = a->size <= sum ? sum : UINTMAX_MAX;
109   if (timespec_cmp (a->tmax, b->tmax) < 0)
110     a->tmax = b->tmax;
111 }
112
113 /* A structure for per-directory level information.  */
114 struct dulevel
115 {
116   /* Entries in this directory.  */
117   struct duinfo ent;
118
119   /* Total for subdirectories.  */
120   struct duinfo subdir;
121 };
122
123 /* If true, display counts for all files, not just directories.  */
124 static bool opt_all = false;
125
126 /* If true, rather than using the disk usage of each file,
127    use the apparent size (a la stat.st_size).  */
128 static bool apparent_size = false;
129
130 /* If true, count each hard link of files with multiple links.  */
131 static bool opt_count_all = false;
132
133 /* If true, hash all files to look for hard links.  */
134 static bool hash_all;
135
136 /* If true, output the NUL byte instead of a newline at the end of each line. */
137 static bool opt_nul_terminate_output = false;
138
139 /* If true, print a grand total at the end.  */
140 static bool print_grand_total = false;
141
142 /* If nonzero, do not add sizes of subdirectories.  */
143 static bool opt_separate_dirs = false;
144
145 /* Show the total for each directory (and file if --all) that is at
146    most MAX_DEPTH levels down from the root of the hierarchy.  The root
147    is at level 0, so 'du --max-depth=0' is equivalent to 'du -s'.  */
148 static size_t max_depth = SIZE_MAX;
149
150 /* Only output entries with at least this SIZE if positive,
151    or at most if negative.  See --threshold option.  */
152 static intmax_t opt_threshold = 0;
153
154 /* Human-readable options for output.  */
155 static int human_output_opts;
156
157 /* If true, print most recently modified date, using the specified format.  */
158 static bool opt_time = false;
159
160 /* Type of time to display. controlled by --time.  */
161
162 enum time_type
163   {
164     time_mtime,                 /* default */
165     time_ctime,
166     time_atime
167   };
168
169 static enum time_type time_type = time_mtime;
170
171 /* User specified date / time style */
172 static char const *time_style = NULL;
173
174 /* Format used to display date / time. Controlled by --time-style */
175 static char const *time_format = NULL;
176
177 /* The units to use when printing sizes.  */
178 static uintmax_t output_block_size;
179
180 /* File name patterns to exclude.  */
181 static struct exclude *exclude;
182
183 /* Grand total size of all args, in bytes. Also latest modified date. */
184 static struct duinfo tot_dui;
185
186 #define IS_DIR_TYPE(Type)       \
187   ((Type) == FTS_DP             \
188    || (Type) == FTS_DNR)
189
190 /* For long options that have no equivalent short option, use a
191    non-character as a pseudo short option, starting with CHAR_MAX + 1.  */
192 enum
193 {
194   APPARENT_SIZE_OPTION = CHAR_MAX + 1,
195   EXCLUDE_OPTION,
196   FILES0_FROM_OPTION,
197   HUMAN_SI_OPTION,
198   FTS_DEBUG,
199   TIME_OPTION,
200   TIME_STYLE_OPTION
201 };
202
203 static struct option const long_options[] =
204 {
205   {"all", no_argument, NULL, 'a'},
206   {"apparent-size", no_argument, NULL, APPARENT_SIZE_OPTION},
207   {"block-size", required_argument, NULL, 'B'},
208   {"bytes", no_argument, NULL, 'b'},
209   {"count-links", no_argument, NULL, 'l'},
210   /* {"-debug", no_argument, NULL, FTS_DEBUG}, */
211   {"dereference", no_argument, NULL, 'L'},
212   {"dereference-args", no_argument, NULL, 'D'},
213   {"exclude", required_argument, NULL, EXCLUDE_OPTION},
214   {"exclude-from", required_argument, NULL, 'X'},
215   {"files0-from", required_argument, NULL, FILES0_FROM_OPTION},
216   {"human-readable", no_argument, NULL, 'h'},
217   {"si", no_argument, NULL, HUMAN_SI_OPTION},
218   {"max-depth", required_argument, NULL, 'd'},
219   {"null", no_argument, NULL, '0'},
220   {"no-dereference", no_argument, NULL, 'P'},
221   {"one-file-system", no_argument, NULL, 'x'},
222   {"separate-dirs", no_argument, NULL, 'S'},
223   {"summarize", no_argument, NULL, 's'},
224   {"total", no_argument, NULL, 'c'},
225   {"threshold", required_argument, NULL, 't'},
226   {"time", optional_argument, NULL, TIME_OPTION},
227   {"time-style", required_argument, NULL, TIME_STYLE_OPTION},
228   {GETOPT_HELP_OPTION_DECL},
229   {GETOPT_VERSION_OPTION_DECL},
230   {NULL, 0, NULL, 0}
231 };
232
233 static char const *const time_args[] =
234 {
235   "atime", "access", "use", "ctime", "status", NULL
236 };
237 static enum time_type const time_types[] =
238 {
239   time_atime, time_atime, time_atime, time_ctime, time_ctime
240 };
241 ARGMATCH_VERIFY (time_args, time_types);
242
243 /* 'full-iso' uses full ISO-style dates and times.  'long-iso' uses longer
244    ISO-style time stamps, though shorter than 'full-iso'.  'iso' uses shorter
245    ISO-style time stamps.  */
246 enum time_style
247   {
248     full_iso_time_style,       /* --time-style=full-iso */
249     long_iso_time_style,       /* --time-style=long-iso */
250     iso_time_style             /* --time-style=iso */
251   };
252
253 static char const *const time_style_args[] =
254 {
255   "full-iso", "long-iso", "iso", NULL
256 };
257 static enum time_style const time_style_types[] =
258 {
259   full_iso_time_style, long_iso_time_style, iso_time_style
260 };
261 ARGMATCH_VERIFY (time_style_args, time_style_types);
262
263 void
264 usage (int status)
265 {
266   if (status != EXIT_SUCCESS)
267     emit_try_help ();
268   else
269     {
270       printf (_("\
271 Usage: %s [OPTION]... [FILE]...\n\
272   or:  %s [OPTION]... --files0-from=F\n\
273 "), program_name, program_name);
274       fputs (_("\
275 Summarize disk usage of each FILE, recursively for directories.\n\
276 \n\
277 "), stdout);
278       fputs (_("\
279 Mandatory arguments to long options are mandatory for short options too.\n\
280 "), stdout);
281       fputs (_("\
282   -a, --all             write counts for all files, not just directories\n\
283       --apparent-size   print apparent sizes, rather than disk usage; although\
284 \n\
285                           the apparent size is usually smaller, it may be\n\
286                           larger due to holes in ('sparse') files, internal\n\
287                           fragmentation, indirect blocks, and the like\n\
288 "), stdout);
289       fputs (_("\
290   -B, --block-size=SIZE  scale sizes by SIZE before printing them.  E.g.,\n\
291                            '-BM' prints sizes in units of 1,048,576 bytes.\n\
292                            See SIZE format below.\n\
293   -b, --bytes           equivalent to '--apparent-size --block-size=1'\n\
294   -c, --total           produce a grand total\n\
295   -D, --dereference-args  dereference only symlinks that are listed on the\n\
296                           command line\n\
297 "), stdout);
298       fputs (_("\
299       --files0-from=F   summarize disk usage of the NUL-terminated file\n\
300                           names specified in file F;\n\
301                           If F is - then read names from standard input\n\
302   -H                    equivalent to --dereference-args (-D)\n\
303   -h, --human-readable  print sizes in human readable format (e.g., 1K 234M 2G)\
304 \n\
305       --si              like -h, but use powers of 1000 not 1024\n\
306 "), stdout);
307       fputs (_("\
308   -k                    like --block-size=1K\n\
309   -l, --count-links     count sizes many times if hard linked\n\
310   -m                    like --block-size=1M\n\
311 "), stdout);
312       fputs (_("\
313   -L, --dereference     dereference all symbolic links\n\
314   -P, --no-dereference  don't follow any symbolic links (this is the default)\n\
315   -0, --null            end each output line with 0 byte rather than newline\n\
316   -S, --separate-dirs   do not include size of subdirectories\n\
317   -s, --summarize       display only a total for each argument\n\
318 "), stdout);
319       fputs (_("\
320   -x, --one-file-system    skip directories on different file systems\n\
321   -X, --exclude-from=FILE  exclude files that match any pattern in FILE\n\
322       --exclude=PATTERN    exclude files that match PATTERN\n\
323   -d, --max-depth=N     print the total for a directory (or file, with --all)\n\
324                           only if it is N or fewer levels below the command\n\
325                           line argument;  --max-depth=0 is the same as\n\
326                           --summarize\n\
327   -t, --threshold=SIZE  exclude entries smaller than SIZE if positive,\n\
328                           or entries greater than SIZE if negative\n\
329 "), stdout);
330       fputs (_("\
331       --time            show time of the last modification of any file in the\n\
332                           directory, or any of its subdirectories\n\
333       --time=WORD       show time as WORD instead of modification time:\n\
334                           atime, access, use, ctime or status\n\
335       --time-style=STYLE  show times using style STYLE:\n\
336                           full-iso, long-iso, iso, +FORMAT\n\
337                           FORMAT is interpreted like 'date'\n\
338 "), stdout);
339       fputs (HELP_OPTION_DESCRIPTION, stdout);
340       fputs (VERSION_OPTION_DESCRIPTION, stdout);
341       emit_blocksize_note ("DU");
342       emit_size_note ();
343       emit_ancillary_info ();
344     }
345   exit (status);
346 }
347
348 /* Try to insert the INO/DEV pair into DI_SET.
349    Return true if the pair is successfully inserted,
350    false if the pair was already there.  */
351 static bool
352 hash_ins (struct di_set *di_set, ino_t ino, dev_t dev)
353 {
354   int inserted = di_set_insert (di_set, dev, ino);
355   if (inserted < 0)
356     xalloc_die ();
357   return inserted;
358 }
359
360 /* FIXME: this code is nearly identical to code in date.c  */
361 /* Display the date and time in WHEN according to the format specified
362    in FORMAT.  */
363
364 static void
365 show_date (const char *format, struct timespec when)
366 {
367   struct tm *tm = localtime (&when.tv_sec);
368   if (! tm)
369     {
370       char buf[INT_BUFSIZE_BOUND (intmax_t)];
371       char *when_str = timetostr (when.tv_sec, buf);
372       error (0, 0, _("time %s is out of range"), when_str);
373       fputs (when_str, stdout);
374       return;
375     }
376
377   fprintftime (stdout, format, tm, 0, when.tv_nsec);
378 }
379
380 /* Print N_BYTES.  Convert it to a readable value before printing.  */
381
382 static void
383 print_only_size (uintmax_t n_bytes)
384 {
385   char buf[LONGEST_HUMAN_READABLE + 1];
386   fputs ((n_bytes == UINTMAX_MAX
387           ? _("Infinity")
388           : human_readable (n_bytes, buf, human_output_opts,
389                             1, output_block_size)),
390          stdout);
391 }
392
393 /* Print size (and optionally time) indicated by *PDUI, followed by STRING.  */
394
395 static void
396 print_size (const struct duinfo *pdui, const char *string)
397 {
398   print_only_size (pdui->size);
399   if (opt_time)
400     {
401       putchar ('\t');
402       show_date (time_format, pdui->tmax);
403     }
404   printf ("\t%s%c", string, opt_nul_terminate_output ? '\0' : '\n');
405   fflush (stdout);
406 }
407
408 /* This function is called once for every file system object that fts
409    encounters.  fts does a depth-first traversal.  This function knows
410    that and accumulates per-directory totals based on changes in
411    the depth of the current entry.  It returns true on success.  */
412
413 static bool
414 process_file (FTS *fts, FTSENT *ent)
415 {
416   bool ok = true;
417   struct duinfo dui;
418   struct duinfo dui_to_print;
419   size_t level;
420   static size_t n_alloc;
421   /* First element of the structure contains:
422      The sum of the st_size values of all entries in the single directory
423      at the corresponding level.  Although this does include the st_size
424      corresponding to each subdirectory, it does not include the size of
425      any file in a subdirectory. Also corresponding last modified date.
426      Second element of the structure contains:
427      The sum of the sizes of all entries in the hierarchy at or below the
428      directory at the specified level.  */
429   static struct dulevel *dulvl;
430
431   const char *file = ent->fts_path;
432   const struct stat *sb = ent->fts_statp;
433   int info = ent->fts_info;
434
435   if (info == FTS_DNR)
436     {
437       /* An error occurred, but the size is known, so count it.  */
438       error (0, ent->fts_errno, _("cannot read directory %s"), quote (file));
439       ok = false;
440     }
441   else if (info != FTS_DP)
442     {
443       bool excluded = excluded_file_name (exclude, file);
444       if (! excluded)
445         {
446           /* Make the stat buffer *SB valid, or fail noisily.  */
447
448           if (info == FTS_NSOK)
449             {
450               fts_set (fts, ent, FTS_AGAIN);
451               FTSENT const *e = fts_read (fts);
452               assert (e == ent);
453               info = ent->fts_info;
454             }
455
456           if (info == FTS_NS || info == FTS_SLNONE)
457             {
458               error (0, ent->fts_errno, _("cannot access %s"), quote (file));
459               return false;
460             }
461
462           /* The --one-file-system (-x) option cannot exclude anything
463              specified on the command-line.  By definition, it can exclude
464              a file or directory only when its device number is different
465              from that of its just-processed parent directory, and du does
466              not process the parent of a command-line argument.  */
467           if (fts->fts_options & FTS_XDEV
468               && FTS_ROOTLEVEL < ent->fts_level
469               && fts->fts_dev != sb->st_dev)
470             excluded = true;
471         }
472
473       if (excluded
474           || (! opt_count_all
475               && (hash_all || (! S_ISDIR (sb->st_mode) && 1 < sb->st_nlink))
476               && ! hash_ins (di_files, sb->st_ino, sb->st_dev)))
477         {
478           /* If ignoring a directory in preorder, skip its children.
479              Ignore the next fts_read output too, as it's a postorder
480              visit to the same directory.  */
481           if (info == FTS_D)
482             {
483               fts_set (fts, ent, FTS_SKIP);
484               FTSENT const *e = fts_read (fts);
485               assert (e == ent);
486             }
487
488           return true;
489         }
490
491       switch (info)
492         {
493         case FTS_D:
494           return true;
495
496         case FTS_ERR:
497           /* An error occurred, but the size is known, so count it.  */
498           error (0, ent->fts_errno, "%s", quote (file));
499           ok = false;
500           break;
501
502         case FTS_DC:
503           if (cycle_warning_required (fts, ent))
504             {
505               /* If this is a mount point, then diagnose it and avoid
506                  the cycle.  */
507               if (di_set_lookup (di_mnt, sb->st_dev, sb->st_ino))
508                 error (0, 0, _("mount point %s already traversed"),
509                        quote (file));
510               else
511                 emit_cycle_warning (file);
512               return false;
513             }
514           return true;
515         }
516     }
517
518   duinfo_set (&dui,
519               (apparent_size
520                ? MAX (0, sb->st_size)
521                : (uintmax_t) ST_NBLOCKS (*sb) * ST_NBLOCKSIZE),
522               (time_type == time_mtime ? get_stat_mtime (sb)
523                : time_type == time_atime ? get_stat_atime (sb)
524                : get_stat_ctime (sb)));
525
526   level = ent->fts_level;
527   dui_to_print = dui;
528
529   if (n_alloc == 0)
530     {
531       n_alloc = level + 10;
532       dulvl = xcalloc (n_alloc, sizeof *dulvl);
533     }
534   else
535     {
536       if (level == prev_level)
537         {
538           /* This is usually the most common case.  Do nothing.  */
539         }
540       else if (level > prev_level)
541         {
542           /* Descending the hierarchy.
543              Clear the accumulators for *all* levels between prev_level
544              and the current one.  The depth may change dramatically,
545              e.g., from 1 to 10.  */
546           size_t i;
547
548           if (n_alloc <= level)
549             {
550               dulvl = xnrealloc (dulvl, level, 2 * sizeof *dulvl);
551               n_alloc = level * 2;
552             }
553
554           for (i = prev_level + 1; i <= level; i++)
555             {
556               duinfo_init (&dulvl[i].ent);
557               duinfo_init (&dulvl[i].subdir);
558             }
559         }
560       else /* level < prev_level */
561         {
562           /* Ascending the hierarchy.
563              Process a directory only after all entries in that
564              directory have been processed.  When the depth decreases,
565              propagate sums from the children (prev_level) to the parent.
566              Here, the current level is always one smaller than the
567              previous one.  */
568           assert (level == prev_level - 1);
569           duinfo_add (&dui_to_print, &dulvl[prev_level].ent);
570           if (!opt_separate_dirs)
571             duinfo_add (&dui_to_print, &dulvl[prev_level].subdir);
572           duinfo_add (&dulvl[level].subdir, &dulvl[prev_level].ent);
573           duinfo_add (&dulvl[level].subdir, &dulvl[prev_level].subdir);
574         }
575     }
576
577   prev_level = level;
578
579   /* Let the size of a directory entry contribute to the total for the
580      containing directory, unless --separate-dirs (-S) is specified.  */
581   if (! (opt_separate_dirs && IS_DIR_TYPE (info)))
582     duinfo_add (&dulvl[level].ent, &dui);
583
584   /* Even if this directory is unreadable or we can't chdir into it,
585      do let its size contribute to the total. */
586   duinfo_add (&tot_dui, &dui);
587
588   if ((IS_DIR_TYPE (info) && level <= max_depth)
589       || (opt_all && level <= max_depth)
590       || level == 0)
591     {
592       /* Print or elide this entry according to the --threshold option.  */
593       if (opt_threshold < 0
594           ? dui_to_print.size <= -opt_threshold
595           : dui_to_print.size >= opt_threshold)
596         print_size (&dui_to_print, file);
597     }
598
599   return ok;
600 }
601
602 /* Recursively print the sizes of the directories (and, if selected, files)
603    named in FILES, the last entry of which is NULL.
604    BIT_FLAGS controls how fts works.
605    Return true if successful.  */
606
607 static bool
608 du_files (char **files, int bit_flags)
609 {
610   bool ok = true;
611
612   if (*files)
613     {
614       FTS *fts = xfts_open (files, bit_flags, NULL);
615
616       while (1)
617         {
618           FTSENT *ent;
619
620           ent = fts_read (fts);
621           if (ent == NULL)
622             {
623               if (errno != 0)
624                 {
625                   error (0, errno, _("fts_read failed: %s"),
626                          quotearg_colon (fts->fts_path));
627                   ok = false;
628                 }
629
630               /* When exiting this loop early, be careful to reset the
631                  global, prev_level, used in process_file.  Otherwise, its
632                  (level == prev_level - 1) assertion could fail.  */
633               prev_level = 0;
634               break;
635             }
636           FTS_CROSS_CHECK (fts);
637
638           ok &= process_file (fts, ent);
639         }
640
641       if (fts_close (fts) != 0)
642         {
643           error (0, errno, _("fts_close failed"));
644           ok = false;
645         }
646     }
647
648   return ok;
649 }
650
651 /* Fill the di_mnt set with local mount point dev/ino pairs.  */
652
653 static void
654 fill_mount_table (void)
655 {
656   struct mount_entry *mnt_ent = read_file_system_list (false);
657   while (mnt_ent)
658     {
659       struct mount_entry *mnt_free;
660       if (!mnt_ent->me_remote && !mnt_ent->me_dummy)
661         {
662           struct stat buf;
663           if (!stat (mnt_ent->me_mountdir, &buf))
664             hash_ins (di_mnt, buf.st_ino, buf.st_dev);
665           else
666             {
667               /* Ignore stat failure.  False positives are too common.
668                  E.g., "Permission denied" on /run/user/<name>/gvfs.  */
669             }
670         }
671
672       mnt_free = mnt_ent;
673       mnt_ent = mnt_ent->me_next;
674
675       free (mnt_free->me_devname);
676       free (mnt_free->me_mountdir);
677       if (mnt_free->me_type_malloced)
678         free (mnt_free->me_type);
679       free (mnt_free);
680     }
681 }
682
683 int
684 main (int argc, char **argv)
685 {
686   char *cwd_only[2];
687   bool max_depth_specified = false;
688   bool ok = true;
689   char *files_from = NULL;
690
691   /* Bit flags that control how fts works.  */
692   int bit_flags = FTS_NOSTAT;
693
694   /* Select one of the three FTS_ options that control if/when
695      to follow a symlink.  */
696   int symlink_deref_bits = FTS_PHYSICAL;
697
698   /* If true, display only a total for each argument. */
699   bool opt_summarize_only = false;
700
701   cwd_only[0] = bad_cast (".");
702   cwd_only[1] = NULL;
703
704   initialize_main (&argc, &argv);
705   set_program_name (argv[0]);
706   setlocale (LC_ALL, "");
707   bindtextdomain (PACKAGE, LOCALEDIR);
708   textdomain (PACKAGE);
709
710   atexit (close_stdout);
711
712   exclude = new_exclude ();
713
714   human_options (getenv ("DU_BLOCK_SIZE"),
715                  &human_output_opts, &output_block_size);
716
717   while (true)
718     {
719       int oi = -1;
720       int c = getopt_long (argc, argv, "0abd:chHklmst:xB:DLPSX:",
721                            long_options, &oi);
722       if (c == -1)
723         break;
724
725       switch (c)
726         {
727 #if DU_DEBUG
728         case FTS_DEBUG:
729           fts_debug = true;
730           break;
731 #endif
732
733         case '0':
734           opt_nul_terminate_output = true;
735           break;
736
737         case 'a':
738           opt_all = true;
739           break;
740
741         case APPARENT_SIZE_OPTION:
742           apparent_size = true;
743           break;
744
745         case 'b':
746           apparent_size = true;
747           human_output_opts = 0;
748           output_block_size = 1;
749           break;
750
751         case 'c':
752           print_grand_total = true;
753           break;
754
755         case 'h':
756           human_output_opts = human_autoscale | human_SI | human_base_1024;
757           output_block_size = 1;
758           break;
759
760         case HUMAN_SI_OPTION:
761           human_output_opts = human_autoscale | human_SI;
762           output_block_size = 1;
763           break;
764
765         case 'k':
766           human_output_opts = 0;
767           output_block_size = 1024;
768           break;
769
770         case 'd':               /* --max-depth=N */
771           {
772             unsigned long int tmp_ulong;
773             if (xstrtoul (optarg, NULL, 0, &tmp_ulong, NULL) == LONGINT_OK
774                 && tmp_ulong <= SIZE_MAX)
775               {
776                 max_depth_specified = true;
777                 max_depth = tmp_ulong;
778               }
779             else
780               {
781                 error (0, 0, _("invalid maximum depth %s"),
782                        quote (optarg));
783                 ok = false;
784               }
785           }
786           break;
787
788         case 'm':
789           human_output_opts = 0;
790           output_block_size = 1024 * 1024;
791           break;
792
793         case 'l':
794           opt_count_all = true;
795           break;
796
797         case 's':
798           opt_summarize_only = true;
799           break;
800
801         case 't':
802           {
803             enum strtol_error e;
804             e = xstrtoimax (optarg, NULL, 0, &opt_threshold, "kKmMGTPEZY0");
805             if (e != LONGINT_OK)
806               xstrtol_fatal (e, oi, c, long_options, optarg);
807             if (opt_threshold == 0 && *optarg == '-')
808               {
809                 /* Do not allow -0, as this wouldn't make sense anyway.  */
810                 error (EXIT_FAILURE, 0, _("invalid --threshold argument '-0'"));
811               }
812           }
813           break;
814
815         case 'x':
816           bit_flags |= FTS_XDEV;
817           break;
818
819         case 'B':
820           {
821             enum strtol_error e = human_options (optarg, &human_output_opts,
822                                                  &output_block_size);
823             if (e != LONGINT_OK)
824               xstrtol_fatal (e, oi, c, long_options, optarg);
825           }
826           break;
827
828         case 'H':  /* NOTE: before 2008-12, -H was equivalent to --si.  */
829         case 'D':
830           symlink_deref_bits = FTS_COMFOLLOW | FTS_PHYSICAL;
831           break;
832
833         case 'L': /* --dereference */
834           symlink_deref_bits = FTS_LOGICAL;
835           break;
836
837         case 'P': /* --no-dereference */
838           symlink_deref_bits = FTS_PHYSICAL;
839           break;
840
841         case 'S':
842           opt_separate_dirs = true;
843           break;
844
845         case 'X':
846           if (add_exclude_file (add_exclude, exclude, optarg,
847                                 EXCLUDE_WILDCARDS, '\n'))
848             {
849               error (0, errno, "%s", quotearg_colon (optarg));
850               ok = false;
851             }
852           break;
853
854         case FILES0_FROM_OPTION:
855           files_from = optarg;
856           break;
857
858         case EXCLUDE_OPTION:
859           add_exclude (exclude, optarg, EXCLUDE_WILDCARDS);
860           break;
861
862         case TIME_OPTION:
863           opt_time = true;
864           time_type =
865             (optarg
866              ? XARGMATCH ("--time", optarg, time_args, time_types)
867              : time_mtime);
868           break;
869
870         case TIME_STYLE_OPTION:
871           time_style = optarg;
872           break;
873
874         case_GETOPT_HELP_CHAR;
875
876         case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
877
878         default:
879           ok = false;
880         }
881     }
882
883   if (!ok)
884     usage (EXIT_FAILURE);
885
886   if (opt_all && opt_summarize_only)
887     {
888       error (0, 0, _("cannot both summarize and show all entries"));
889       usage (EXIT_FAILURE);
890     }
891
892   if (opt_summarize_only && max_depth_specified && max_depth == 0)
893     {
894       error (0, 0,
895              _("warning: summarizing is the same as using --max-depth=0"));
896     }
897
898   if (opt_summarize_only && max_depth_specified && max_depth != 0)
899     {
900       unsigned long int d = max_depth;
901       error (0, 0, _("warning: summarizing conflicts with --max-depth=%lu"), d);
902       usage (EXIT_FAILURE);
903     }
904
905   if (opt_summarize_only)
906     max_depth = 0;
907
908   /* Process time style if printing last times.  */
909   if (opt_time)
910     {
911       if (! time_style)
912         {
913           time_style = getenv ("TIME_STYLE");
914
915           /* Ignore TIMESTYLE="locale", for compatibility with ls.  */
916           if (! time_style || STREQ (time_style, "locale"))
917             time_style = "long-iso";
918           else if (*time_style == '+')
919             {
920               /* Ignore anything after a newline, for compatibility
921                  with ls.  */
922               char *p = strchr (time_style, '\n');
923               if (p)
924                 *p = '\0';
925             }
926           else
927             {
928               /* Ignore "posix-" prefix, for compatibility with ls.  */
929               static char const posix_prefix[] = "posix-";
930               while (strncmp (time_style, posix_prefix, sizeof posix_prefix - 1)
931                      == 0)
932                 time_style += sizeof posix_prefix - 1;
933             }
934         }
935
936       if (*time_style == '+')
937         time_format = time_style + 1;
938       else
939         {
940           switch (XARGMATCH ("time style", time_style,
941                              time_style_args, time_style_types))
942             {
943             case full_iso_time_style:
944               time_format = "%Y-%m-%d %H:%M:%S.%N %z";
945               break;
946
947             case long_iso_time_style:
948               time_format = "%Y-%m-%d %H:%M";
949               break;
950
951             case iso_time_style:
952               time_format = "%Y-%m-%d";
953               break;
954             }
955         }
956     }
957
958   struct argv_iterator *ai;
959   if (files_from)
960     {
961       /* When using --files0-from=F, you may not specify any files
962          on the command-line.  */
963       if (optind < argc)
964         {
965           error (0, 0, _("extra operand %s"), quote (argv[optind]));
966           fprintf (stderr, "%s\n",
967                    _("file operands cannot be combined with --files0-from"));
968           usage (EXIT_FAILURE);
969         }
970
971       if (! (STREQ (files_from, "-") || freopen (files_from, "r", stdin)))
972         error (EXIT_FAILURE, errno, _("cannot open %s for reading"),
973                quote (files_from));
974
975       ai = argv_iter_init_stream (stdin);
976
977       /* It's not easy here to count the arguments, so assume the
978          worst.  */
979       hash_all = true;
980     }
981   else
982     {
983       char **files = (optind < argc ? argv + optind : cwd_only);
984       ai = argv_iter_init_argv (files);
985
986       /* Hash all dev,ino pairs if there are multiple arguments, or if
987          following non-command-line symlinks, because in either case a
988          file with just one hard link might be seen more than once.  */
989       hash_all = (optind + 1 < argc || symlink_deref_bits == FTS_LOGICAL);
990     }
991
992   if (!ai)
993     xalloc_die ();
994
995   /* Initialize the set of dev,inode pairs.  */
996
997   di_mnt = di_set_alloc ();
998   if (!di_mnt)
999     xalloc_die ();
1000
1001   fill_mount_table ();
1002
1003   di_files = di_set_alloc ();
1004   if (!di_files)
1005     xalloc_die ();
1006
1007   /* If not hashing everything, process_file won't find cycles on its
1008      own, so ask fts_read to check for them accurately.  */
1009   if (opt_count_all || ! hash_all)
1010     bit_flags |= FTS_TIGHT_CYCLE_CHECK;
1011
1012   bit_flags |= symlink_deref_bits;
1013   static char *temp_argv[] = { NULL, NULL };
1014
1015   while (true)
1016     {
1017       bool skip_file = false;
1018       enum argv_iter_err ai_err;
1019       char *file_name = argv_iter (ai, &ai_err);
1020       if (!file_name)
1021         {
1022           switch (ai_err)
1023             {
1024             case AI_ERR_EOF:
1025               goto argv_iter_done;
1026             case AI_ERR_READ:
1027               error (0, errno, _("%s: read error"),
1028                      quotearg_colon (files_from));
1029               ok = false;
1030               goto argv_iter_done;
1031             case AI_ERR_MEM:
1032               xalloc_die ();
1033             default:
1034               assert (!"unexpected error code from argv_iter");
1035             }
1036         }
1037       if (files_from && STREQ (files_from, "-") && STREQ (file_name, "-"))
1038         {
1039           /* Give a better diagnostic in an unusual case:
1040              printf - | du --files0-from=- */
1041           error (0, 0, _("when reading file names from stdin, "
1042                          "no file name of %s allowed"),
1043                  quote (file_name));
1044           skip_file = true;
1045         }
1046
1047       /* Report and skip any empty file names before invoking fts.
1048          This works around a glitch in fts, which fails immediately
1049          (without looking at the other file names) when given an empty
1050          file name.  */
1051       if (!file_name[0])
1052         {
1053           /* Diagnose a zero-length file name.  When it's one
1054              among many, knowing the record number may help.
1055              FIXME: currently print the record number only with
1056              --files0-from=FILE.  Maybe do it for argv, too?  */
1057           if (files_from == NULL)
1058             error (0, 0, "%s", _("invalid zero-length file name"));
1059           else
1060             {
1061               /* Using the standard 'filename:line-number:' prefix here is
1062                  not totally appropriate, since NUL is the separator, not NL,
1063                  but it might be better than nothing.  */
1064               unsigned long int file_number = argv_iter_n_args (ai);
1065               error (0, 0, "%s:%lu: %s", quotearg_colon (files_from),
1066                      file_number, _("invalid zero-length file name"));
1067             }
1068           skip_file = true;
1069         }
1070
1071       if (skip_file)
1072         ok = false;
1073       else
1074         {
1075           temp_argv[0] = file_name;
1076           ok &= du_files (temp_argv, bit_flags);
1077         }
1078     }
1079  argv_iter_done:
1080
1081   argv_iter_free (ai);
1082   di_set_free (di_files);
1083   di_set_free (di_mnt);
1084
1085   if (files_from && (ferror (stdin) || fclose (stdin) != 0) && ok)
1086     error (EXIT_FAILURE, 0, _("error reading %s"), quote (files_from));
1087
1088   if (print_grand_total)
1089     print_size (&tot_dui, _("total"));
1090
1091   exit (ok ? EXIT_SUCCESS : EXIT_FAILURE);
1092 }