bracket bug address with <> and append a period
[platform/upstream/coreutils.git] / src / df.c
1 /* df - summarize free disk space
2    Copyright (C) 91, 95, 1996 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 Foundation,
16    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
17
18 /* Written by David MacKenzie <djm@gnu.ai.mit.edu>.
19    --human-readable and --megabyte options added by lm@sgi.com.  */
20
21 #include <config.h>
22 #include <stdio.h>
23 #include <sys/types.h>
24 #include <getopt.h>
25 #include <assert.h>
26
27 #include "mountlist.h"
28 #include "fsusage.h"
29 #include "system.h"
30 #include "save-cwd.h"
31 #include "error.h"
32
33 char *dirname ();
34 void strip_trailing_slashes ();
35 char *xmalloc ();
36 char *xstrdup ();
37 char *xgetcwd ();
38
39 /* The maximum length of a human-readable string.  Be pessimistic
40    and assume `int' is 64-bits wide.  Converting 2^63 - 1 gives the
41    14-character string, 8796093022208G.  The number being converted
42    is the number of 1024-byte blocks, so we divide by 1024 * 1024.  */
43 #define LONGEST_HUMAN_READABLE_1K_BYTE_BLOCKS 14
44
45 /* Name this program was run with. */
46 char *program_name;
47
48 /* If nonzero, show inode information. */
49 static int inode_format;
50
51 /* If nonzero, show even filesystems with zero size or
52    uninteresting types. */
53 static int show_all_fs;
54
55 /* If nonzero, output data for each filesystem corresponding to a
56    command line argument -- even if it's a dummy (automounter) entry.  */
57 static int show_listed_fs;
58
59 /* If nonzero, use variable sized printouts instead of 512-byte blocks. */
60 static int human_blocks;
61
62 /* If nonzero, use 1K blocks instead of 512-byte blocks. */
63 static int kilobyte_blocks;
64
65 /* If nonzero, use 1M blocks instead of 512-byte blocks. */
66 static int megabyte_blocks;
67
68 /* If nonzero, use the POSIX output format.  */
69 static int posix_format;
70
71 /* If nonzero, invoke the `sync' system call before getting any usage data.
72    Using this option can make df very slow, especially with many or very
73    busy disks.  Note that this may make a difference on some systems --
74    SunOs4.1.3, for one.  It is *not* necessary on Linux.  */
75 static int require_sync = 0;
76
77 /* Nonzero if errors have occurred. */
78 static int exit_status;
79
80 /* A filesystem type to display. */
81
82 struct fs_type_list
83 {
84   char *fs_name;
85   struct fs_type_list *fs_next;
86 };
87
88 /* Linked list of filesystem types to display.
89    If `fs_select_list' is NULL, list all types.
90    This table is generated dynamically from command-line options,
91    rather than hardcoding into the program what it thinks are the
92    valid filesystem types; let the user specify any filesystem type
93    they want to, and if there are any filesystems of that type, they
94    will be shown.
95
96    Some filesystem types:
97    4.2 4.3 ufs nfs swap ignore io vm efs dbg */
98
99 static struct fs_type_list *fs_select_list;
100
101 /* Linked list of filesystem types to omit.
102    If the list is empty, don't exclude any types.  */
103
104 static struct fs_type_list *fs_exclude_list;
105
106 /* Linked list of mounted filesystems. */
107 static struct mount_entry *mount_list;
108
109 /* If nonzero, display usage information and exit.  */
110 static int show_help;
111
112 /* If nonzero, print the version on standard output and exit.  */
113 static int show_version;
114
115 /* If nonzero, print filesystem type as well.  */
116 static int print_type;
117
118 static struct option const long_options[] =
119 {
120   {"all", no_argument, &show_all_fs, 1},
121   {"inodes", no_argument, &inode_format, 1},
122   {"human-readable", no_argument, 0, 'h'},
123   {"kilobytes", no_argument, 0, 'k'},
124   {"megabytes", no_argument, 0, 'm'},
125   {"portability", no_argument, &posix_format, 1},
126   {"print-type", no_argument, &print_type, 1},
127   {"sync", no_argument, 0, 129},
128   {"no-sync", no_argument, 0, 130},
129   {"type", required_argument, 0, 't'},
130   {"exclude-type", required_argument, 0, 'x'},
131   {"help", no_argument, &show_help, 1},
132   {"version", no_argument, &show_version, 1},
133   {NULL, 0, NULL, 0}
134 };
135
136 static void
137 print_header (void)
138 {
139   printf ("Filesystem ");
140
141   if (print_type)
142     printf ("   Type");
143   else
144     printf ("       ");
145
146   if (inode_format)
147     printf ("   Inodes   IUsed   IFree  %%IUsed");
148   else
149     if (megabyte_blocks)
150       printf (" MB-blocks    Used Available Capacity");
151     else if (human_blocks)
152       printf ("    Size  Used  Avail  Capacity");
153     else
154       printf (" %s  Used Available Capacity",
155             kilobyte_blocks ? "1024-blocks" : " 512-blocks");
156   printf (" Mounted on\n");
157 }
158
159 /* Convert N_1K_BYTE_BLOCKS to a more readable string than %d would.
160    Most people visually process strings of 3-4 digits effectively,
161    but longer strings of digits are more prone to misinterpretation.
162    Hence, converting to an abbreviated form usually improves readability.
163    Use a suffix indicating multiples of 1024 (M) and 1024*1024 (G).
164    For example, 8500 would be converted to 8.3M, 133456345 to 127G,
165    and so on.  Numbers smaller than 1024 get the `K' suffix.  */
166
167 static char *
168 human_readable_1k_blocks (int n_1k_byte_blocks, char *buf, int buf_len)
169 {
170   const char *suffix;
171   double amt;
172   char *p;
173
174   assert (buf_len > LONGEST_HUMAN_READABLE_1K_BYTE_BLOCKS);
175
176   p = buf;
177   amt = n_1k_byte_blocks;
178
179   if (amt >= 1024 * 1024)
180     {
181       amt /= (1024 * 1024);
182       suffix = "G";
183     }
184   else if (amt >= 1024)
185     {
186       amt /= 1024;
187       suffix = "M";
188     }
189   else
190     {
191       suffix = "K";
192     }
193
194   if (amt >= 10)
195     {
196       sprintf (p, "%4.0f%s", amt, suffix);
197     }
198   else if (amt == 0)
199     {
200       strcpy (p, "0");
201     }
202   else
203     {
204       sprintf (p, "%4.1f%s", amt, suffix);
205     }
206   return (p);
207 }
208
209 /* If FSTYPE is a type of filesystem that should be listed,
210    return nonzero, else zero. */
211
212 static int
213 selected_fstype (const char *fstype)
214 {
215   const struct fs_type_list *fsp;
216
217   if (fs_select_list == NULL || fstype == NULL)
218     return 1;
219   for (fsp = fs_select_list; fsp; fsp = fsp->fs_next)
220     if (STREQ (fstype, fsp->fs_name))
221       return 1;
222   return 0;
223 }
224
225 /* If FSTYPE is a type of filesystem that should be omitted,
226    return nonzero, else zero. */
227
228 static int
229 excluded_fstype (const char *fstype)
230 {
231   const struct fs_type_list *fsp;
232
233   if (fs_exclude_list == NULL || fstype == NULL)
234     return 0;
235   for (fsp = fs_exclude_list; fsp; fsp = fsp->fs_next)
236     if (STREQ (fstype, fsp->fs_name))
237       return 1;
238   return 0;
239 }
240
241 /* Display a space listing for the disk device with absolute path DISK.
242    If MOUNT_POINT is non-NULL, it is the path of the root of the
243    filesystem on DISK.
244    If FSTYPE is non-NULL, it is the type of the filesystem on DISK.
245    If MOUNT_POINT is non-NULL, then DISK may be NULL -- certain systems may
246    not be able to produce statistics in this case.  */
247
248 static void
249 show_dev (const char *disk, const char *mount_point, const char *fstype)
250 {
251   struct fs_usage fsu;
252   long blocks_used;
253   long blocks_percent_used;
254   long inodes_used;
255   long inodes_percent_used;
256   const char *stat_file;
257
258   if (!selected_fstype (fstype) || excluded_fstype (fstype))
259     return;
260
261   /* If MOUNT_POINT is NULL, then the filesystem is not mounted, and this
262      program reports on the filesystem that the special file is on.
263      It would be better to report on the unmounted filesystem,
264      but statfs doesn't do that on most systems.  */
265   stat_file = mount_point ? mount_point : disk;
266
267   if (get_fs_usage (stat_file, disk, &fsu))
268     {
269       error (0, errno, "%s", stat_file);
270       exit_status = 1;
271       return;
272     }
273
274   if (megabyte_blocks)
275     {
276       fsu.fsu_blocks /= 2*1024;
277       fsu.fsu_bfree /= 2*1024;
278       fsu.fsu_bavail /= 2*1024;
279     }
280   else if (kilobyte_blocks)
281     {
282       fsu.fsu_blocks /= 2;
283       fsu.fsu_bfree /= 2;
284       fsu.fsu_bavail /= 2;
285     }
286
287   if (fsu.fsu_blocks == 0)
288     {
289       if (!show_all_fs && !show_listed_fs)
290         return;
291       blocks_used = fsu.fsu_bavail = blocks_percent_used = 0;
292     }
293   else
294     {
295       blocks_used = fsu.fsu_blocks - fsu.fsu_bfree;
296       blocks_percent_used = (long)
297         (blocks_used * 100.0 / (blocks_used + fsu.fsu_bavail) + 0.5);
298     }
299
300   if (fsu.fsu_files == 0)
301     {
302       inodes_used = fsu.fsu_ffree = inodes_percent_used = 0;
303     }
304   else
305     {
306       inodes_used = fsu.fsu_files - fsu.fsu_ffree;
307       inodes_percent_used = (long)
308         (inodes_used * 100.0 / fsu.fsu_files + 0.5);
309     }
310
311   if (! disk)
312     disk = "-";                 /* unknown */
313
314   printf ((print_type ? "%-13s" : "%-20s"), disk);
315   if ((int) strlen (disk) > (print_type ? 13 : 20) && !posix_format)
316     printf ((print_type ? "\n%13s" : "\n%20s"), "");
317
318   if (! fstype)
319     fstype = "-";               /* unknown */
320   if (print_type)
321     printf (" %-5s ", fstype);
322
323   if (inode_format)
324     printf (" %7ld %7ld %7ld %5ld%%",
325             fsu.fsu_files, inodes_used, fsu.fsu_ffree, inodes_percent_used);
326   else if (human_blocks)
327     {
328       char buf[3][LONGEST_HUMAN_READABLE_1K_BYTE_BLOCKS + 1];
329       printf (" %4s %4s  %5s  %5ld%% ",
330               human_readable_1k_blocks (fsu.fsu_blocks, buf[0],
331                                     LONGEST_HUMAN_READABLE_1K_BYTE_BLOCKS + 1),
332               human_readable_1k_blocks (blocks_used, buf[1],
333                                     LONGEST_HUMAN_READABLE_1K_BYTE_BLOCKS + 1),
334               human_readable_1k_blocks (fsu.fsu_bavail, buf[2],
335                                     LONGEST_HUMAN_READABLE_1K_BYTE_BLOCKS + 1),
336               blocks_percent_used);
337     }
338   else
339     printf (" %7ld %7ld  %7ld  %5ld%% ",
340             fsu.fsu_blocks, blocks_used, fsu.fsu_bavail, blocks_percent_used);
341
342   if (mount_point)
343     {
344 #ifdef HIDE_AUTOMOUNT_PREFIX
345       /* Don't print the first directory name in MOUNT_POINT if it's an
346          artifact of an automounter.  This is a bit too aggressive to be
347          the default.  */
348       if (strncmp ("/auto/", mount_point, 6) == 0)
349         mount_point += 5;
350       else if (strncmp ("/tmp_mnt/", mount_point, 9) == 0)
351         mount_point += 8;
352 #endif
353       printf ("  %s", mount_point);
354     }
355   putchar ('\n');
356 }
357
358 /* Identify the directory, if any, that device
359    DISK is mounted on, and show its disk usage.  */
360
361 static void
362 show_disk (const char *disk)
363 {
364   struct mount_entry *me;
365
366   for (me = mount_list; me; me = me->me_next)
367     if (STREQ (disk, me->me_devname))
368       {
369         show_dev (me->me_devname, me->me_mountdir, me->me_type);
370         return;
371       }
372   /* No filesystem is mounted on DISK. */
373   show_dev (disk, (char *) NULL, (char *) NULL);
374 }
375
376 /* Return the root mountpoint of the filesystem on which FILE exists, in
377    malloced storage.  FILE_STAT should be the result of stating FILE.  */
378 static char *
379 find_mount_point (const char *file, const struct stat *file_stat)
380 {
381   struct saved_cwd cwd;
382   struct stat last_stat;
383   char *mp = 0;                 /* The malloced mount point path.  */
384
385   if (save_cwd (&cwd))
386     return NULL;
387
388   if (S_ISDIR (file_stat->st_mode))
389     /* FILE is a directory, so just chdir there directly.  */
390     {
391       last_stat = *file_stat;
392       if (chdir (file) < 0)
393         return NULL;
394     }
395   else
396     /* FILE is some other kind of file, we need to use its directory.  */
397     {
398       int rv;
399       char *tmp = xstrdup (file);
400       char *dir;
401
402       strip_trailing_slashes (tmp);
403       dir = dirname (tmp);
404       free (tmp);
405       rv = chdir (dir);
406       free (dir);
407
408       if (rv < 0)
409         return NULL;
410
411       if (stat (".", &last_stat) < 0)
412         goto done;
413     }
414
415   /* Now walk up FILE's parents until we find another filesystem or /,
416      chdiring as we go.  LAST_STAT holds stat information for the last place
417      we visited.  */
418   for (;;)
419     {
420       struct stat st;
421       if (stat ("..", &st) < 0)
422         goto done;
423       if (st.st_dev != last_stat.st_dev || st.st_ino == last_stat.st_ino)
424         /* cwd is the mount point.  */
425         break;
426       if (chdir ("..") < 0)
427         goto done;
428       last_stat = st;
429     }
430
431   /* Finally reached a mount point, see what it's called.  */
432   mp = xgetcwd ();
433
434 done:
435   /* Restore the original cwd.  */
436   {
437     int save_errno = errno;
438     if (restore_cwd (&cwd, 0, mp))
439       exit (1);                 /* We're scrod.  */
440     free_cwd (&cwd);
441     errno = save_errno;
442   }
443
444   return mp;
445 }
446
447 /* Figure out which device file or directory POINT is mounted on
448    and show its disk usage.
449    STATP is the results of `stat' on POINT.  */
450 static void
451 show_point (const char *point, const struct stat *statp)
452 {
453   struct stat disk_stats;
454   struct mount_entry *me;
455
456   for (me = mount_list; me; me = me->me_next)
457     {
458       if (me->me_dev == (dev_t) -1)
459         {
460           if (stat (me->me_mountdir, &disk_stats) == 0)
461             me->me_dev = disk_stats.st_dev;
462           else
463             {
464               error (0, errno, "%s", me->me_mountdir);
465               exit_status = 1;
466               /* So we won't try and fail repeatedly. */
467               me->me_dev = (dev_t) -2;
468             }
469         }
470
471       if (statp->st_dev == me->me_dev)
472         {
473           /* Skip bogus mtab entries.  */
474           if (stat (me->me_mountdir, &disk_stats) != 0 ||
475               disk_stats.st_dev != me->me_dev)
476             continue;
477           show_dev (me->me_devname, me->me_mountdir, me->me_type);
478           return;
479         }
480     }
481
482   /* We couldn't find the mount entry corresponding to POINT.  Go ahead and
483      print as much info as we can; methods that require the device to be
484      present will fail at a later point.  */
485   {
486     /* Find the actual mount point.  */
487     char *mp = find_mount_point (point, statp);
488     if (mp)
489       {
490         show_dev (0, mp, 0);
491         free (mp);
492       }
493     else
494       error (0, errno, "%s", point);
495   }
496 }
497
498 /* Determine what kind of node PATH is and show the disk usage
499    for it.  STATP is the results of `stat' on PATH.  */
500
501 static void
502 show_entry (const char *path, const struct stat *statp)
503 {
504   if (S_ISBLK (statp->st_mode) || S_ISCHR (statp->st_mode))
505     show_disk (path);
506   else
507     show_point (path, statp);
508 }
509
510 /* Show all mounted filesystems, except perhaps those that are of
511    an unselected type or are empty. */
512
513 static void
514 show_all_entries (void)
515 {
516   struct mount_entry *me;
517
518   for (me = mount_list; me; me = me->me_next)
519     show_dev (me->me_devname, me->me_mountdir, me->me_type);
520 }
521
522 /* Add FSTYPE to the list of filesystem types to display. */
523
524 static void
525 add_fs_type (const char *fstype)
526 {
527   struct fs_type_list *fsp;
528
529   fsp = (struct fs_type_list *) xmalloc (sizeof (struct fs_type_list));
530   fsp->fs_name = (char *) fstype;
531   fsp->fs_next = fs_select_list;
532   fs_select_list = fsp;
533 }
534
535 /* Add FSTYPE to the list of filesystem types to be omitted. */
536
537 static void
538 add_excluded_fs_type (const char *fstype)
539 {
540   struct fs_type_list *fsp;
541
542   fsp = (struct fs_type_list *) xmalloc (sizeof (struct fs_type_list));
543   fsp->fs_name = (char *) fstype;
544   fsp->fs_next = fs_exclude_list;
545   fs_exclude_list = fsp;
546 }
547
548 static void
549 usage (int status)
550 {
551   if (status != 0)
552     fprintf (stderr, _("Try `%s --help' for more information.\n"),
553              program_name);
554   else
555     {
556       printf (_("Usage: %s [OPTION]... [FILE]...\n"), program_name);
557       printf (_("\
558 Show information about the filesystem on which each FILE resides,\n\
559 or all filesystems by default.\n\
560 \n\
561   -a, --all             include filesystems having 0 blocks\n\
562   -h, --human-readable  print sizes in human readable format (e.g., 1K 234M 2G)\n\
563   -i, --inodes          list inode information instead of block usage\n\
564   -k, --kilobytes       use 1024-byte blocks, not 512 despite POSIXLY_CORRECT\n\
565   -m, --megabytes       use 1024K-byte blocks, not 512 despite POSIXLY_CORRECT\n\
566       --no-sync         do not invoke sync before getting usage info (default)\n\
567   -P, --portability     use the POSIX output format\n\
568       --sync            invoke sync before getting usage info\n\
569   -t, --type=TYPE       limit listing to filesystems of type TYPE\n\
570   -T, --print-type      print filesystem type\n\
571   -x, --exclude-type=TYPE   limit listing to filesystems not of type TYPE\n\
572   -v                    (ignored)\n\
573       --help            display this help and exit\n\
574       --version         output version information and exit\n\
575 "));
576       puts (_("\nReport bugs to <fileutils-bugs@gnu.ai.mit.edu>."));
577     }
578   exit (status);
579 }
580
581 int
582 main (int argc, char **argv)
583 {
584   int i;
585   struct stat *stats;
586
587   program_name = argv[0];
588   setlocale (LC_ALL, "");
589   bindtextdomain (PACKAGE, LOCALEDIR);
590   textdomain (PACKAGE);
591
592   fs_select_list = NULL;
593   fs_exclude_list = NULL;
594   inode_format = 0;
595   show_all_fs = 0;
596   show_listed_fs = 0;
597
598   if (getenv ("POSIXLY_CORRECT"))
599     kilobyte_blocks = 0;
600   else
601     {
602       char *bs;
603       kilobyte_blocks = 1;
604       if ((bs = getenv ("BLOCKSIZE"))
605           && strncmp (bs, "HUMAN", sizeof ("HUMAN") - 1) == 0)
606         human_blocks = 1;
607     }
608
609   print_type = 0;
610   posix_format = 0;
611   exit_status = 0;
612
613   while ((i = getopt_long (argc, argv, "aiF:hkmPTt:vx:", long_options, NULL))
614          != -1)
615     {
616       switch (i)
617         {
618         case 0:                 /* Long option. */
619           break;
620         case 'a':
621           show_all_fs = 1;
622           break;
623         case 'i':
624           inode_format = 1;
625           break;
626         case 'h':
627           human_blocks = 1;
628           kilobyte_blocks = 1;
629           megabyte_blocks = 0;
630           break;
631         case 'k':
632           human_blocks = 0;
633           kilobyte_blocks = 1;
634           megabyte_blocks = 0;
635           break;
636         case 'm':
637           human_blocks = 0;
638           kilobyte_blocks = 0;
639           megabyte_blocks = 1;
640           break;
641         case 'T':
642           print_type = 1;
643           break;
644         case 'P':
645           posix_format = 1;
646           break;
647         case 129:
648           require_sync = 1;
649           break;
650         case 130:
651           require_sync = 0;
652           break;
653
654         case 'F':
655           /* Accept -F as a synonym for -t for compatibility with Solaris.  */
656         case 't':
657           add_fs_type (optarg);
658           break;
659
660         case 'v':               /* For SysV compatibility. */
661           /* ignore */
662           break;
663         case 'x':
664           add_excluded_fs_type (optarg);
665           break;
666         default:
667           usage (1);
668         }
669     }
670
671   if (show_version)
672     {
673       printf ("df (%s) %s\n", GNU_PACKAGE, VERSION);
674       exit (0);
675     }
676
677   if (show_help)
678     usage (0);
679
680   if (posix_format && megabyte_blocks)
681     error (1, 0, _("the option for counting 1MB blocks may not be used\n\
682 with the portable output format"));
683
684   if (posix_format && human_blocks)
685     error (1, 0,
686            _("the option for printing with adaptive units may not be used\n\
687 with the portable output format"));
688
689   /* Fail if the same file system type was both selected and excluded.  */
690   {
691     int match = 0;
692     struct fs_type_list *i;
693     for (i = fs_select_list; i; i = i->fs_next)
694       {
695         struct fs_type_list *j;
696         for (j = fs_exclude_list; j; j = j->fs_next)
697           {
698             if (STREQ (i->fs_name, j->fs_name))
699               {
700                 error (0, 0,
701                        _("file system type `%s' both selected and excluded"),
702                        i->fs_name);
703                 match = 1;
704                 break;
705               }
706           }
707       }
708     if (match)
709       exit (1);
710   }
711
712   if (optind == argc)
713     {
714 #ifdef lint
715       /* Suppress `used before initialized' warning.  */
716       stats = NULL;
717 #endif
718     }
719   else
720     {
721       /* stat all the given entries to make sure they get automounted,
722          if necessary, before reading the filesystem table.  */
723       stats = (struct stat *)
724         xmalloc ((argc - optind) * sizeof (struct stat));
725       for (i = optind; i < argc; ++i)
726         if (stat (argv[i], &stats[i - optind]))
727           {
728             error (0, errno, "%s", argv[i]);
729             exit_status = 1;
730             argv[i] = NULL;
731           }
732     }
733
734   mount_list =
735     read_filesystem_list ((fs_select_list != NULL
736                            || fs_exclude_list != NULL
737                            || print_type),
738                           show_all_fs);
739
740   if (require_sync)
741     sync ();
742
743   if (optind == argc)
744     {
745       if (mount_list == NULL)
746         error (1, errno, _("cannot read table of mounted filesystems"));
747       print_header ();
748       show_all_entries ();
749     }
750   else
751     {
752       /* Display explicitly requested empty filesystems. */
753       show_listed_fs = 1;
754
755       print_header ();
756       for (i = optind; i < argc; ++i)
757         if (argv[i])
758           show_entry (argv[i], &stats[i - optind]);
759     }
760
761   exit (exit_status);
762 }
763