~ubuntu-branches/ubuntu/utopic/coreutils/utopic-proposed

« back to all changes in this revision

Viewing changes to src/du.c

  • Committer: Package Import Robot
  • Author(s): Colin Watson
  • Date: 2012-11-28 03:03:42 UTC
  • mfrom: (8.3.4 sid)
  • Revision ID: package-import@ubuntu.com-20121128030342-21zanj8354gas5gr
Tags: 8.20-3ubuntu1
* Resynchronise with Debian.  Remaining changes:
  - Make 'uname -i -p' return the real processor/hardware, instead of
    unknown.
  - Build-depend on gettext:any instead of on gettext, so that apt-get can
    properly resolve build-dependencies on the tool when cross-building.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/* du -- summarize disk usage
2
 
   Copyright (C) 1988-1991, 1995-2011 Free Software Foundation, Inc.
 
2
   Copyright (C) 1988-2012 Free Software Foundation, Inc.
3
3
 
4
4
   This program is free software: you can redistribute it and/or modify
5
5
   it under the terms of the GNU General Public License as published by
35
35
#include "exclude.h"
36
36
#include "fprintftime.h"
37
37
#include "human.h"
 
38
#include "mountlist.h"
38
39
#include "quote.h"
39
40
#include "quotearg.h"
40
41
#include "stat-size.h"
45
46
 
46
47
extern bool fts_debug;
47
48
 
48
 
/* The official name of this program (e.g., no `g' prefix).  */
 
49
/* The official name of this program (e.g., no 'g' prefix).  */
49
50
#define PROGRAM_NAME "du"
50
51
 
51
52
#define AUTHORS \
60
61
# define FTS_CROSS_CHECK(Fts)
61
62
#endif
62
63
 
63
 
/* A set of dev/ino pairs.  */
64
 
static struct di_set *di_set;
 
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;
65
70
 
66
71
/* Keep track of the preceding "level" (depth in hierarchy)
67
72
   from one call of process_file to the next.  */
99
104
static inline void
100
105
duinfo_add (struct duinfo *a, struct duinfo const *b)
101
106
{
102
 
  a->size += b->size;
 
107
  uintmax_t sum = a->size + b->size;
 
108
  a->size = a->size <= sum ? sum : UINTMAX_MAX;
103
109
  if (timespec_cmp (a->tmax, b->tmax) < 0)
104
110
    a->tmax = b->tmax;
105
111
}
138
144
 
139
145
/* Show the total for each directory (and file if --all) that is at
140
146
   most MAX_DEPTH levels down from the root of the hierarchy.  The root
141
 
   is at level 0, so `du --max-depth=0' is equivalent to `du -s'.  */
 
147
   is at level 0, so 'du --max-depth=0' is equivalent to 'du -s'.  */
142
148
static size_t max_depth = SIZE_MAX;
143
149
 
144
150
/* Human-readable options for output.  */
229
235
};
230
236
ARGMATCH_VERIFY (time_args, time_types);
231
237
 
232
 
/* `full-iso' uses full ISO-style dates and times.  `long-iso' uses longer
233
 
   ISO-style time stamps, though shorter than `full-iso'.  `iso' uses shorter
 
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
234
240
   ISO-style time stamps.  */
235
241
enum time_style
236
242
  {
253
259
usage (int status)
254
260
{
255
261
  if (status != EXIT_SUCCESS)
256
 
    fprintf (stderr, _("Try `%s --help' for more information.\n"),
257
 
             program_name);
 
262
    emit_try_help ();
258
263
  else
259
264
    {
260
265
      printf (_("\
273
278
      --apparent-size   print apparent sizes, rather than disk usage; although\
274
279
\n\
275
280
                          the apparent size is usually smaller, it may be\n\
276
 
                          larger due to holes in (`sparse') files, internal\n\
 
281
                          larger due to holes in ('sparse') files, internal\n\
277
282
                          fragmentation, indirect blocks, and the like\n\
278
283
"), stdout);
279
284
      fputs (_("\
280
285
  -B, --block-size=SIZE  scale sizes by SIZE before printing them.  E.g.,\n\
281
 
                           `-BM' prints sizes in units of 1,048,576 bytes.\n\
 
286
                           '-BM' prints sizes in units of 1,048,576 bytes.\n\
282
287
                           See SIZE format below.\n\
283
 
  -b, --bytes           equivalent to `--apparent-size --block-size=1'\n\
 
288
  -b, --bytes           equivalent to '--apparent-size --block-size=1'\n\
284
289
  -c, --total           produce a grand total\n\
285
290
  -D, --dereference-args  dereference only symlinks that are listed on the\n\
286
291
                          command line\n\
322
327
                          atime, access, use, ctime or status\n\
323
328
      --time-style=STYLE  show times using style STYLE:\n\
324
329
                          full-iso, long-iso, iso, +FORMAT\n\
325
 
                          FORMAT is interpreted like `date'\n\
 
330
                          FORMAT is interpreted like 'date'\n\
326
331
"), stdout);
327
332
      fputs (HELP_OPTION_DESCRIPTION, stdout);
328
333
      fputs (VERSION_OPTION_DESCRIPTION, stdout);
333
338
  exit (status);
334
339
}
335
340
 
336
 
/* Try to insert the INO/DEV pair into the global table, HTAB.
 
341
/* Try to insert the INO/DEV pair into DI_SET.
337
342
   Return true if the pair is successfully inserted,
338
 
   false if the pair is already in the table.  */
 
343
   false if the pair was already there.  */
339
344
static bool
340
 
hash_ins (ino_t ino, dev_t dev)
 
345
hash_ins (struct di_set *di_set, ino_t ino, dev_t dev)
341
346
{
342
347
  int inserted = di_set_insert (di_set, dev, ino);
343
348
  if (inserted < 0)
371
376
print_only_size (uintmax_t n_bytes)
372
377
{
373
378
  char buf[LONGEST_HUMAN_READABLE + 1];
374
 
  fputs (human_readable (n_bytes, buf, human_output_opts,
375
 
                         1, output_block_size), stdout);
 
379
  fputs ((n_bytes == UINTMAX_MAX
 
380
          ? _("Infinity")
 
381
          : human_readable (n_bytes, buf, human_output_opts,
 
382
                            1, output_block_size)),
 
383
         stdout);
376
384
}
377
385
 
378
386
/* Print size (and optionally time) indicated by *PDUI, followed by STRING.  */
443
451
              error (0, ent->fts_errno, _("cannot access %s"), quote (file));
444
452
              return false;
445
453
            }
 
454
 
 
455
          /* The --one-file-system (-x) option cannot exclude anything
 
456
             specified on the command-line.  By definition, it can exclude
 
457
             a file or directory only when its device number is different
 
458
             from that of its just-processed parent directory, and du does
 
459
             not process the parent of a command-line argument.  */
 
460
          if (fts->fts_options & FTS_XDEV
 
461
              && FTS_ROOTLEVEL < ent->fts_level
 
462
              && fts->fts_dev != sb->st_dev)
 
463
            excluded = true;
446
464
        }
447
465
 
448
466
      if (excluded
449
467
          || (! opt_count_all
450
468
              && (hash_all || (! S_ISDIR (sb->st_mode) && 1 < sb->st_nlink))
451
 
              && ! hash_ins (sb->st_ino, sb->st_dev)))
 
469
              && ! hash_ins (di_files, sb->st_ino, sb->st_dev)))
452
470
        {
453
471
          /* If ignoring a directory in preorder, skip its children.
454
472
             Ignore the next fts_read output too, as it's a postorder
477
495
        case FTS_DC:
478
496
          if (cycle_warning_required (fts, ent))
479
497
            {
480
 
              emit_cycle_warning (file);
 
498
              /* If this is a mount point, then diagnose it and avoid
 
499
                 the cycle.  */
 
500
              if (di_set_lookup (di_mnt, sb->st_dev, sb->st_ino))
 
501
                error (0, 0, _("mount point %s already traversed"),
 
502
                       quote (file));
 
503
              else
 
504
                emit_cycle_warning (file);
481
505
              return false;
482
506
            }
483
507
          return true;
486
510
 
487
511
  duinfo_set (&dui,
488
512
              (apparent_size
489
 
               ? sb->st_size
 
513
               ? MAX (0, sb->st_size)
490
514
               : (uintmax_t) ST_NBLOCKS (*sb) * ST_NBLOCKSIZE),
491
515
              (time_type == time_mtime ? get_stat_mtime (sb)
492
516
               : time_type == time_atime ? get_stat_atime (sb)
610
634
  return ok;
611
635
}
612
636
 
 
637
/* Fill the di_mnt set with local mount point dev/ino pairs.  */
 
638
 
 
639
static void
 
640
fill_mount_table (void)
 
641
{
 
642
  struct mount_entry *mnt_ent = read_file_system_list (false);
 
643
  while (mnt_ent)
 
644
    {
 
645
      struct mount_entry *mnt_free;
 
646
      if (!mnt_ent->me_remote && !mnt_ent->me_dummy)
 
647
        {
 
648
          struct stat buf;
 
649
          if (!stat (mnt_ent->me_mountdir, &buf))
 
650
            hash_ins (di_mnt, buf.st_ino, buf.st_dev);
 
651
          else
 
652
            {
 
653
              /* Ignore stat failure.  False positives are too common.
 
654
                 E.g., "Permission denied" on /run/user/<name>/gvfs.  */
 
655
            }
 
656
        }
 
657
 
 
658
      mnt_free = mnt_ent;
 
659
      mnt_ent = mnt_ent->me_next;
 
660
 
 
661
      free (mnt_free->me_devname);
 
662
      free (mnt_free->me_mountdir);
 
663
      if (mnt_free->me_type_malloced)
 
664
        free (mnt_free->me_type);
 
665
      free (mnt_free);
 
666
    }
 
667
}
 
668
 
613
669
int
614
670
main (int argc, char **argv)
615
671
{
909
965
    xalloc_die ();
910
966
 
911
967
  /* Initialize the set of dev,inode pairs.  */
912
 
  di_set = di_set_alloc ();
913
 
  if (!di_set)
 
968
 
 
969
  di_mnt = di_set_alloc ();
 
970
  if (!di_mnt)
 
971
    xalloc_die ();
 
972
 
 
973
  fill_mount_table ();
 
974
 
 
975
  di_files = di_set_alloc ();
 
976
  if (!di_files)
914
977
    xalloc_die ();
915
978
 
916
979
  /* If not hashing everything, process_file won't find cycles on its
967
1030
            error (0, 0, "%s", _("invalid zero-length file name"));
968
1031
          else
969
1032
            {
970
 
              /* Using the standard `filename:line-number:' prefix here is
 
1033
              /* Using the standard 'filename:line-number:' prefix here is
971
1034
                 not totally appropriate, since NUL is the separator, not NL,
972
1035
                 but it might be better than nothing.  */
973
1036
              unsigned long int file_number = argv_iter_n_args (ai);
988
1051
 argv_iter_done:
989
1052
 
990
1053
  argv_iter_free (ai);
991
 
  di_set_free (di_set);
 
1054
  di_set_free (di_files);
 
1055
  di_set_free (di_mnt);
992
1056
 
993
1057
  if (files_from && (ferror (stdin) || fclose (stdin) != 0) && ok)
994
1058
    error (EXIT_FAILURE, 0, _("error reading %s"), quote (files_from));