(add_tabstop): Give correct size when reallocating tab_list buffer.
[platform/upstream/coreutils.git] / src / du.c
1 /* du -- summarize disk usage
2    Copyright (C) 1988, 1989, 1990, 1991, 1995 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 2, or (at your option)
7    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, write to the Free Software
16    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
17
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    -k           Print sizes in kilobytes instead of 512 byte blocks
29                 (the default required by POSIX).
30    -b           Print sizes in bytes.
31    -S           Count the size of each directory separately, not including
32                 the sizes of subdirectories.
33    -D           Dereference only symbolic links given on the command line.
34    -L           Dereference all symbolic links.
35
36    By tege@sics.se, Torbjorn Granlund,
37    and djm@ai.mit.edu, David MacKenzie.  */
38
39 #ifdef _AIX
40  #pragma alloca
41 #endif
42
43 #include <config.h>
44 #include <stdio.h>
45 #include <getopt.h>
46 #include <sys/types.h>
47
48 #include "system.h"
49 #include "version.h"
50 #include "safe-stat.h"
51 #include "safe-lstat.h"
52 #include "error.h"
53
54 /* Initial number of entries in each hash table entry's table of inodes.  */
55 #define INITIAL_HASH_MODULE 100
56
57 /* Initial number of entries in the inode hash table.  */
58 #define INITIAL_ENTRY_TAB_SIZE 70
59
60 /* Initial size to allocate for `path'.  */
61 #define INITIAL_PATH_SIZE 100
62
63 /* Hash structure for inode and device numbers.  The separate entry
64    structure makes it easier to rehash "in place".  */
65
66 struct entry
67 {
68   ino_t ino;
69   dev_t dev;
70   struct entry *coll_link;
71 };
72
73 /* Structure for a hash table for inode numbers. */
74
75 struct htab
76 {
77   unsigned modulus;             /* Size of the `hash' pointer vector.  */
78   struct entry *entry_tab;      /* Pointer to dynamically growing vector.  */
79   unsigned entry_tab_size;      /* Size of current `entry_tab' allocation.  */
80   unsigned first_free_entry;    /* Index in `entry_tab'.  */
81   struct entry *hash[1];        /* Vector of pointers in `entry_tab'.  */
82 };
83
84 struct saved_cwd
85   {
86     int desc;
87     char *name;
88   };
89
90
91 /* Structure for dynamically resizable strings. */
92
93 typedef struct
94 {
95   unsigned alloc;               /* Size of allocation for the text.  */
96   unsigned length;              /* Length of the text currently.  */
97   char *text;                   /* Pointer to the text.  */
98 } *string, stringstruct;
99
100 char *savedir ();
101 char *xgetcwd ();
102 char *xmalloc ();
103 char *xrealloc ();
104
105 static int hash_insert ();
106 static int hash_insert2 ();
107 static long count_entry ();
108 static void du_files ();
109 static void hash_init ();
110 static void hash_reset ();
111 static void str_concatc ();
112 static void str_copyc ();
113 static void str_init ();
114 static void str_trunc ();
115
116 /* Name under which this program was invoked.  */
117 char *program_name;
118
119 /* If nonzero, display only a total for each argument. */
120 static int opt_summarize_only = 0;
121
122 /* If nonzero, display counts for all files, not just directories. */
123 static int opt_all = 0;
124
125 /* If nonzero, count each hard link of files with multiple links. */
126 static int opt_count_all = 0;
127
128 /* If nonzero, do not cross file-system boundaries. */
129 static int opt_one_file_system = 0;
130
131 /* If nonzero, print a grand total at the end. */
132 static int opt_combined_arguments = 0;
133
134 /* If nonzero, do not add sizes of subdirectories. */
135 static int opt_separate_dirs = 0;
136
137 /* If nonzero, dereference symlinks that are command line arguments. */
138 static int opt_dereference_arguments = 0;
139
140 enum output_size
141 {
142   size_blocks,                  /* 512-byte blocks. */
143   size_kilobytes,               /* 1K blocks. */
144   size_bytes                    /* 1-byte blocks. */
145 };
146
147 /* The units to count in. */
148 static enum output_size output_size;
149
150 /* Accumulated path for file or directory being processed.  */
151 static string path;
152
153 /* Pointer to hash structure, used by the hash routines.  */
154 static struct htab *htab;
155
156 /* Globally used stat buffer.  */
157 static struct stat stat_buf;
158
159 /* A pointer to either lstat or stat, depending on whether
160    dereferencing of all symbolic links is to be done. */
161 static int (*xstat) ();
162
163 /* The exit status to use if we don't get any fatal errors. */
164 static int exit_status;
165
166 /* If non-zero, display usage information and exit.  */
167 static int show_help;
168
169 /* If non-zero, print the version on standard output and exit.  */
170 static int show_version;
171
172 /* Grand total size of all args. */
173 static long tot_size = 0L;
174
175 static struct option const long_options[] =
176 {
177   {"all", no_argument, &opt_all, 1},
178   {"bytes", no_argument, NULL, 'b'},
179   {"count-links", no_argument, &opt_count_all, 1},
180   {"dereference", no_argument, NULL, 'L'},
181   {"dereference-args", no_argument, &opt_dereference_arguments, 1},
182   {"kilobytes", no_argument, NULL, 'k'},
183   {"one-file-system", no_argument, &opt_one_file_system, 1},
184   {"separate-dirs", no_argument, &opt_separate_dirs, 1},
185   {"summarize", no_argument, &opt_summarize_only, 1},
186   {"total", no_argument, &opt_combined_arguments, 1},
187   {"help", no_argument, &show_help, 1},
188   {"version", no_argument, &show_version, 1},
189   {NULL, 0, NULL, 0}
190 };
191
192 static void
193 save_cwd (cwd)
194      struct saved_cwd *cwd;
195 {
196   static int have_working_fchdir = 1;
197
198   if (have_working_fchdir)
199     {
200 #ifdef HAVE_FCHDIR
201       cwd->desc = open (".", O_RDONLY);
202       if (cwd->desc < 0)
203         error (1, errno, "cannot open current directory");
204
205       /* On SunOS 4, fchdir returns EINVAL if accounting is enabled,
206          so we have to fall back to chdir.  */
207       if (fchdir (cwd->desc))
208         {
209           if (errno == EINVAL)
210             {
211               close (cwd->desc);
212               cwd->desc = -1;
213               have_working_fchdir = 0;
214             }
215           else
216             {
217               error (1, errno, "current directory");
218             }
219         }
220 #else
221 #define fchdir(x) (abort (), 0)
222       have_working_fchdir = 0;
223 #endif
224     }
225
226   if (!have_working_fchdir)
227     {
228       cwd->desc = -1;
229       cwd->name = xgetcwd ();
230       if (cwd->name == NULL)
231         error (1, errno, "cannot get current directory");
232     }
233   else
234     {
235       cwd->name = NULL;
236     }
237 }
238
239 static void
240 restore_cwd (cwd, dest, current)
241      const struct saved_cwd *cwd;
242      const char *dest;
243      const char *current;
244 {
245   if (cwd->desc >= 0)
246     {
247       if (fchdir (cwd->desc))
248         error (1, errno, "cannot return to %s%s%s", dest,
249                (current ? " from " : ""),
250                (current ? current : ""));
251     }
252   else if (chdir (cwd->name) < 0)
253     {
254       error (1, errno, "%s", cwd->name);
255     }
256 }
257
258 static void
259 usage (status, reason)
260      int status;
261      char *reason;
262 {
263   if (reason != NULL)
264     fprintf (status == 0 ? stdout : stderr, "%s: %s\n",
265              program_name, reason);
266
267   if (status != 0)
268     fprintf (stderr, "Try `%s --help' for more information.\n",
269              program_name);
270   else
271     {
272       printf ("Usage: %s [OPTION]... [PATH]...\n", program_name);
273       printf ("\
274 \n\
275   -a, --all                write counts for all files, not just directories\n\
276   -b, --bytes              print size in bytes\n\
277   -c, --total              produce a grand total\n\
278   -k, --kilobytes          use 1024 blocks, not 512 despite POSIXLY_CORRECT\n\
279   -l, --count-links        count sizes many times if hard linked\n\
280   -s, --summarize          display only a total for each argument\n\
281   -x, --one-file-system    skip directories on different filesystems\n\
282   -D, --dereference-args   dereference PATHs when symbolic link\n\
283   -L, --dereference        dereference all symbolic links\n\
284   -S, --separate-dirs      do not include size of subdirectories\n\
285       --help               display this help and exit\n\
286       --version            output version information and exit\n");
287     }
288   exit (status);
289 }
290 \f
291 void
292 main (argc, argv)
293      int argc;
294      char *argv[];
295 {
296   int c;
297   char *cwd_only[2];
298   
299   cwd_only[0] = ".";
300   cwd_only[1] = NULL;
301
302   program_name = argv[0];
303   xstat = safe_lstat;
304   output_size = getenv ("POSIXLY_CORRECT") ? size_blocks : size_kilobytes;
305
306   while ((c = getopt_long (argc, argv, "abcklsxDLS", long_options, (int *) 0))
307          != EOF)
308     {
309       switch (c)
310         {
311         case 0:                 /* Long option. */
312           break;
313
314         case 'a':
315           opt_all = 1;
316           break;
317
318         case 'b':
319           output_size = size_bytes;
320           break;
321
322         case 'c':
323           opt_combined_arguments = 1;
324           break;
325
326         case 'k':
327           output_size = size_kilobytes;
328           break;
329
330         case 'l':
331           opt_count_all = 1;
332           break;
333
334         case 's':
335           opt_summarize_only = 1;
336           break;
337
338         case 'x':
339           opt_one_file_system = 1;
340           break;
341
342         case 'D':
343           opt_dereference_arguments = 1;
344           break;
345
346         case 'L':
347           xstat = safe_stat;
348           break;
349
350         case 'S':
351           opt_separate_dirs = 1;
352           break;
353
354         default:
355           usage (2, (char *) 0);
356         }
357     }
358
359   if (show_version)
360     {
361       printf ("%s\n", version_string);
362       exit (0);
363     }
364
365   if (show_help)
366     usage (0, NULL);
367
368   if (opt_all && opt_summarize_only)
369     usage (2, "cannot both summarize and show all entries");
370
371   /* Initialize the hash structure for inode numbers.  */
372   hash_init (INITIAL_HASH_MODULE, INITIAL_ENTRY_TAB_SIZE);
373
374   str_init (&path, INITIAL_PATH_SIZE);
375
376   du_files (optind == argc ? cwd_only : argv + optind);
377
378   exit (exit_status);
379 }
380 \f
381 /* Recursively print the sizes of the directories (and, if selected, files)
382    named in FILES, the last entry of which is NULL.  */
383
384 static void
385 du_files (files)
386      char **files;
387 {
388   struct saved_cwd cwd;
389   ino_t initial_ino;            /* Initial directory's inode. */
390   dev_t initial_dev;            /* Initial directory's device. */
391   int i;                        /* Index in FILES. */
392
393   save_cwd (&cwd);
394
395   /* Remember the inode and device number of the current directory.  */
396   if (safe_stat (".", &stat_buf))
397     error (1, errno, "current directory");
398   initial_ino = stat_buf.st_ino;
399   initial_dev = stat_buf.st_dev;
400
401   for (i = 0; files[i]; i++)
402     {
403       char *arg;
404       int s;
405
406       arg = files[i];
407
408       /* Delete final slash in the argument, unless the slash is alone.  */
409       s = strlen (arg) - 1;
410       if (s != 0)
411         {
412           if (arg[s] == '/')
413             arg[s] = 0;
414
415           str_copyc (path, arg);
416         }
417       else if (arg[0] == '/')
418         str_trunc (path, 0);    /* Null path for root directory.  */
419       else
420         str_copyc (path, arg);
421
422       if (!opt_combined_arguments)
423         hash_reset ();
424
425       count_entry (arg, 1, 0);
426
427       /* chdir if `count_entry' has changed the working directory.  */
428       if (safe_stat (".", &stat_buf))
429         error (1, errno, ".");
430       if (stat_buf.st_ino != initial_ino || stat_buf.st_dev != initial_dev)
431         {
432           restore_cwd (&cwd, "starting directory", NULL);
433         }
434     }
435
436   if (opt_combined_arguments)
437     {
438       printf ("%ld\ttotal\n", output_size == size_bytes ? tot_size
439               : convert_blocks (tot_size, output_size == size_kilobytes));
440       fflush (stdout);
441     }
442
443   if (cwd.name != NULL)
444     free (cwd.name);
445 }
446 \f
447 /* Print (if appropriate) and return the size
448    (in units determined by `output_size') of file or directory ENT.
449    TOP is one for external calls, zero for recursive calls.
450    LAST_DEV is the device that the parent directory of ENT is on.  */
451
452 static long
453 count_entry (ent, top, last_dev)
454      char *ent;
455      int top;
456      dev_t last_dev;
457 {
458   long size;
459
460   if (((top && opt_dereference_arguments)
461        ? safe_stat (ent, &stat_buf)
462        : (*xstat) (ent, &stat_buf)) < 0)
463     {
464       error (0, errno, "%s", path->text);
465       exit_status = 1;
466       return 0;
467     }
468
469   if (!opt_count_all
470       && stat_buf.st_nlink > 1
471       && hash_insert (stat_buf.st_ino, stat_buf.st_dev))
472     return 0;                   /* Have counted this already.  */
473
474   if (output_size == size_bytes)
475     size = stat_buf.st_size;
476   else
477     size = ST_NBLOCKS (stat_buf);
478
479   tot_size += size;
480
481   if (S_ISDIR (stat_buf.st_mode))
482     {
483       unsigned pathlen;
484       dev_t dir_dev;
485       char *name_space;
486       char *namep;
487       struct saved_cwd cwd;
488       int through_symlink;
489       struct stat e_buf;
490
491       dir_dev = stat_buf.st_dev;
492
493       if (opt_one_file_system && !top && last_dev != dir_dev)
494         return 0;               /* Don't enter a new file system.  */
495
496 #ifndef S_ISDIR
497 # define S_ISDIR(s) 0
498 #endif
499       /* If we're dereferencing symlinks and we're about to chdir through
500          a symlink, remember the current directory so we can return to it
501          later.  In other cases, chdir ("..") works fine.  */
502       through_symlink = (xstat == safe_stat
503                          && safe_lstat (ent, &e_buf) == 0
504                          && S_ISLNK (e_buf.st_mode));
505       if (through_symlink)
506         save_cwd (&cwd);
507
508       if (chdir (ent) < 0)
509         {
510           error (0, errno, "cannot change to directory %s", path->text);
511           exit_status = 1;
512           return 0;
513         }
514
515       errno = 0;
516       name_space = savedir (".", stat_buf.st_size);
517       if (name_space == NULL)
518         {
519           if (errno)
520             {
521               error (0, errno, "%s", path->text);
522               if (through_symlink)
523                 {
524                   restore_cwd (&cwd, "..", path->text);
525                   if (cwd.name != NULL)
526                     free (cwd.name);
527                 }
528               else if (chdir ("..") < 0)
529                   error (1, errno, "cannot change to `..' from directory %s",
530                          path->text);
531               exit_status = 1;
532               return 0;
533             }
534           else
535             error (1, 0, "virtual memory exhausted");
536         }
537
538       /* Remember the current path.  */
539
540       str_concatc (path, "/");
541       pathlen = path->length;
542
543       namep = name_space;
544       while (*namep != 0)
545         {
546           str_concatc (path, namep);
547
548           size += count_entry (namep, 0, dir_dev);
549
550           str_trunc (path, pathlen);
551           namep += strlen (namep) + 1;
552         }
553       free (name_space);
554       if (through_symlink)
555         {
556           restore_cwd (&cwd, "..", path->text);
557           if (cwd.name != NULL)
558             free (cwd.name);
559         }
560       else if (chdir ("..") < 0)
561         error (1, errno, "cannot change to `..' from directory %s", path->text);
562
563       str_trunc (path, pathlen - 1); /* Remove the "/" we added.  */
564       if (!opt_summarize_only || top)
565         {
566           printf ("%ld\t%s\n", output_size == size_bytes ? size
567                   : convert_blocks (size, output_size == size_kilobytes),
568                   path->length > 0 ? path->text : "/");
569           fflush (stdout);
570         }
571       return opt_separate_dirs ? 0 : size;
572     }
573   else if (opt_all || top)
574     {
575       /* FIXME: make this an option.  */
576       int print_only_dir_size = 0;
577       if (!print_only_dir_size)
578         {
579           printf ("%ld\t%s\n", output_size == size_bytes ? size
580                   : convert_blocks (size, output_size == size_kilobytes),
581                   path->text);
582           fflush (stdout);
583         }
584     }
585
586   return size;
587 }
588 \f
589 /* Allocate space for the hash structures, and set the global
590    variable `htab' to point to it.  The initial hash module is specified in
591    MODULUS, and the number of entries are specified in ENTRY_TAB_SIZE.  (The
592    hash structure will be rebuilt when ENTRY_TAB_SIZE entries have been
593    inserted, and MODULUS and ENTRY_TAB_SIZE in the global `htab' will be
594    doubled.)  */
595
596 static void
597 hash_init (modulus, entry_tab_size)
598      unsigned modulus;
599      unsigned entry_tab_size;
600 {
601   struct htab *htab_r;
602
603   htab_r = (struct htab *)
604     xmalloc (sizeof (struct htab) + sizeof (struct entry *) * modulus);
605
606   htab_r->entry_tab = (struct entry *)
607     xmalloc (sizeof (struct entry) * entry_tab_size);
608
609   htab_r->modulus = modulus;
610   htab_r->entry_tab_size = entry_tab_size;
611   htab = htab_r;
612
613   hash_reset ();
614 }
615
616 /* Reset the hash structure in the global variable `htab' to
617    contain no entries.  */
618
619 static void
620 hash_reset ()
621 {
622   int i;
623   struct entry **p;
624
625   htab->first_free_entry = 0;
626
627   p = htab->hash;
628   for (i = htab->modulus; i > 0; i--)
629     *p++ = NULL;
630 }
631
632 /* Insert an item (inode INO and device DEV) in the hash
633    structure in the global variable `htab', if an entry with the same data
634    was not found already.  Return zero if the item was inserted and non-zero
635    if it wasn't.  */
636
637 static int
638 hash_insert (ino, dev)
639      ino_t ino;
640      dev_t dev;
641 {
642   struct htab *htab_r = htab;   /* Initially a copy of the global `htab'.  */
643
644   if (htab_r->first_free_entry >= htab_r->entry_tab_size)
645     {
646       int i;
647       struct entry *ep;
648       unsigned modulus;
649       unsigned entry_tab_size;
650
651       /* Increase the number of hash entries, and re-hash the data.
652          The method of shrimping and increasing is made to compactify
653          the heap.  If twice as much data would be allocated
654          straightforwardly, we would never re-use a byte of memory.  */
655
656       /* Let `htab' shrimp.  Keep only the header, not the pointer vector.  */
657
658       htab_r = (struct htab *)
659         xrealloc ((char *) htab_r, sizeof (struct htab));
660
661       modulus = 2 * htab_r->modulus;
662       entry_tab_size = 2 * htab_r->entry_tab_size;
663
664       /* Increase the number of possible entries.  */
665
666       htab_r->entry_tab = (struct entry *)
667         xrealloc ((char *) htab_r->entry_tab,
668                  sizeof (struct entry) * entry_tab_size);
669
670       /* Increase the size of htab again.  */
671
672       htab_r = (struct htab *)
673         xrealloc ((char *) htab_r,
674                  sizeof (struct htab) + sizeof (struct entry *) * modulus);
675
676       htab_r->modulus = modulus;
677       htab_r->entry_tab_size = entry_tab_size;
678       htab = htab_r;
679
680       i = htab_r->first_free_entry;
681
682       /* Make the increased hash table empty.  The entries are still
683          available in htab->entry_tab.  */
684
685       hash_reset ();
686
687       /* Go through the entries and install them in the pointer vector
688          htab->hash.  The items are actually inserted in htab->entry_tab at
689          the position where they already are.  The htab->coll_link need
690          however be updated.  Could be made a little more efficient.  */
691
692       for (ep = htab_r->entry_tab; i > 0; i--)
693         {
694           hash_insert2 (htab_r, ep->ino, ep->dev);
695           ep++;
696         }
697     }
698
699   return hash_insert2 (htab_r, ino, dev);
700 }
701
702 /* Insert INO and DEV in the hash structure HTAB, if not
703    already present.  Return zero if inserted and non-zero if it
704    already existed.  */
705
706 static int
707 hash_insert2 (htab, ino, dev)
708      struct htab *htab;
709      ino_t ino;
710      dev_t dev;
711 {
712   struct entry **hp, *ep2, *ep;
713   hp = &htab->hash[ino % htab->modulus];
714   ep2 = *hp;
715
716   /* Collision?  */
717
718   if (ep2 != NULL)
719     {
720       ep = ep2;
721
722       /* Search for an entry with the same data.  */
723
724       do
725         {
726           if (ep->ino == ino && ep->dev == dev)
727             return 1;           /* Found an entry with the same data.  */
728           ep = ep->coll_link;
729         }
730       while (ep != NULL);
731
732       /* Did not find it.  */
733
734     }
735
736   ep = *hp = &htab->entry_tab[htab->first_free_entry++];
737   ep->ino = ino;
738   ep->dev = dev;
739   ep->coll_link = ep2;          /* `ep2' is NULL if no collision.  */
740
741   return 0;
742 }
743 \f
744 /* Initialize the struct string S1 for holding SIZE characters.  */
745
746 static void
747 str_init (s1, size)
748      string *s1;
749      unsigned size;
750 {
751   string s;
752
753   s = (string) xmalloc (sizeof (stringstruct));
754   s->text = xmalloc (size + 1);
755
756   s->alloc = size;
757   *s1 = s;
758 }
759
760 static void
761 ensure_space (s, size)
762      string s;
763      unsigned size;
764 {
765   if (s->alloc < size)
766     {
767       s->text = xrealloc (s->text, size + 1);
768       s->alloc = size;
769     }
770 }
771
772 /* Assign the null-terminated C-string CSTR to S1.  */
773
774 static void
775 str_copyc (s1, cstr)
776      string s1;
777      char *cstr;
778 {
779   unsigned l = strlen (cstr);
780   ensure_space (s1, l);
781   strcpy (s1->text, cstr);
782   s1->length = l;
783 }
784
785 static void
786 str_concatc (s1, cstr)
787      string s1;
788      char *cstr;
789 {
790   unsigned l1 = s1->length;
791   unsigned l2 = strlen (cstr);
792   unsigned l = l1 + l2;
793
794   ensure_space (s1, l);
795   strcpy (s1->text + l1, cstr);
796   s1->length = l;
797 }
798
799 /* Truncate the string S1 to have length LENGTH.  */
800
801 static void
802 str_trunc (s1, length)
803      string s1;
804      unsigned length;
805 {
806   if (s1->length > length)
807     {
808       s1->text[length] = 0;
809       s1->length = length;
810     }
811 }