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