build: ensure make-prime-list doesn't access out of bounds memory
[platform/upstream/coreutils.git] / src / df.c
1 /* df - summarize free disk space
2    Copyright (C) 1991-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 /* Written by David MacKenzie <djm@gnu.ai.mit.edu>.
18    --human-readable and --megabyte options added by lm@sgi.com.
19    --si and large file support added by eggert@twinsun.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 "system.h"
28 #include "canonicalize.h"
29 #include "error.h"
30 #include "fsusage.h"
31 #include "human.h"
32 #include "mbsalign.h"
33 #include "mbswidth.h"
34 #include "mountlist.h"
35 #include "quote.h"
36 #include "find-mount-point.h"
37
38 /* The official name of this program (e.g., no 'g' prefix).  */
39 #define PROGRAM_NAME "df"
40
41 #define AUTHORS \
42   proper_name_utf8 ("Torbjorn Granlund", "Torbj\303\266rn Granlund"), \
43   proper_name ("David MacKenzie"), \
44   proper_name ("Paul Eggert")
45
46 /* Filled with device numbers of examined file systems to avoid
47    duplicities in output.  */
48 struct devlist
49 {
50   dev_t dev_num;
51   struct mount_entry *me;
52   struct devlist *next;
53 };
54
55 /* If true, show even file systems with zero size or
56    uninteresting types.  */
57 static bool show_all_fs;
58
59 /* If true, show only local file systems.  */
60 static bool show_local_fs;
61
62 /* If true, output data for each file system corresponding to a
63    command line argument -- even if it's a dummy (automounter) entry.  */
64 static bool show_listed_fs;
65
66 /* Human-readable options for output.  */
67 static int human_output_opts;
68
69 /* The units to use when printing sizes.  */
70 static uintmax_t output_block_size;
71
72 /* True if a file system has been processed for output.  */
73 static bool file_systems_processed;
74
75 /* If true, invoke the 'sync' system call before getting any usage data.
76    Using this option can make df very slow, especially with many or very
77    busy disks.  Note that this may make a difference on some systems --
78    SunOS 4.1.3, for one.  It is *not* necessary on GNU/Linux.  */
79 static bool require_sync;
80
81 /* Desired exit status.  */
82 static int exit_status;
83
84 /* A file system type to display.  */
85
86 struct fs_type_list
87 {
88   char *fs_name;
89   struct fs_type_list *fs_next;
90 };
91
92 /* Linked list of file system types to display.
93    If 'fs_select_list' is NULL, list all types.
94    This table is generated dynamically from command-line options,
95    rather than hardcoding into the program what it thinks are the
96    valid file system types; let the user specify any file system type
97    they want to, and if there are any file systems of that type, they
98    will be shown.
99
100    Some file system types:
101    4.2 4.3 ufs nfs swap ignore io vm efs dbg */
102
103 static struct fs_type_list *fs_select_list;
104
105 /* Linked list of file system types to omit.
106    If the list is empty, don't exclude any types.  */
107
108 static struct fs_type_list *fs_exclude_list;
109
110 /* Linked list of mounted file systems.  */
111 static struct mount_entry *mount_list;
112
113 /* If true, print file system type as well.  */
114 static bool print_type;
115
116 /* If true, print a grand total at the end.  */
117 static bool print_grand_total;
118
119 /* Grand total data.  */
120 static struct fs_usage grand_fsu;
121
122 /* Display modes.  */
123 enum
124 {
125   DEFAULT_MODE,
126   INODES_MODE,
127   HUMAN_MODE,
128   POSIX_MODE,
129   OUTPUT_MODE
130 };
131 static int header_mode = DEFAULT_MODE;
132
133 /* Displayable fields.  */
134 typedef enum
135 {
136   SOURCE_FIELD, /* file system */
137   FSTYPE_FIELD, /* FS type */
138   SIZE_FIELD,   /* FS size */
139   USED_FIELD,   /* FS size used  */
140   AVAIL_FIELD,  /* FS size available */
141   PCENT_FIELD,  /* percent used */
142   ITOTAL_FIELD, /* inode total */
143   IUSED_FIELD,  /* inodes used */
144   IAVAIL_FIELD, /* inodes available */
145   IPCENT_FIELD, /* inodes used in percent */
146   TARGET_FIELD  /* mount point */
147 } display_field_t;
148
149 /* Flag if a field contains a block, an inode or another value.  */
150 typedef enum
151 {
152   BLOCK_FLD, /* Block values field */
153   INODE_FLD, /* Inode values field */
154   OTHER_FLD  /* Neutral field, e.g. target */
155 } field_type_t;
156
157 /* Attributes of a display field.  */
158 struct field_data_t
159 {
160   display_field_t field;
161   char const *arg;
162   field_type_t field_type;
163   const char *caption;/* NULL means to use the default header of this field.  */
164   size_t width;       /* Auto adjusted (up) widths used to align columns.  */
165   mbs_align_t align;  /* Alignment for this field.  */
166   bool used;
167 };
168
169 /* Header strings, minimum width and alignment for the above fields.  */
170 static struct field_data_t field_data[] = {
171   [SOURCE_FIELD] = { SOURCE_FIELD,
172     "source", OTHER_FLD, N_("Filesystem"), 14, MBS_ALIGN_LEFT,  false },
173
174   [FSTYPE_FIELD] = { FSTYPE_FIELD,
175     "fstype", OTHER_FLD, N_("Type"),        4, MBS_ALIGN_LEFT,  false },
176
177   [SIZE_FIELD] = { SIZE_FIELD,
178     "size",   BLOCK_FLD, N_("blocks"),      5, MBS_ALIGN_RIGHT, false },
179
180   [USED_FIELD] = { USED_FIELD,
181     "used",   BLOCK_FLD, N_("Used"),        5, MBS_ALIGN_RIGHT, false },
182
183   [AVAIL_FIELD] = { AVAIL_FIELD,
184     "avail",  BLOCK_FLD, N_("Available"),   5, MBS_ALIGN_RIGHT, false },
185
186   [PCENT_FIELD] = { PCENT_FIELD,
187     "pcent",  BLOCK_FLD, N_("Use%"),        4, MBS_ALIGN_RIGHT, false },
188
189   [ITOTAL_FIELD] = { ITOTAL_FIELD,
190     "itotal", INODE_FLD, N_("Inodes"),      5, MBS_ALIGN_RIGHT, false },
191
192   [IUSED_FIELD] = { IUSED_FIELD,
193     "iused",  INODE_FLD, N_("IUsed"),       5, MBS_ALIGN_RIGHT, false },
194
195   [IAVAIL_FIELD] = { IAVAIL_FIELD,
196     "iavail", INODE_FLD, N_("IFree"),       5, MBS_ALIGN_RIGHT, false },
197
198   [IPCENT_FIELD] = { IPCENT_FIELD,
199     "ipcent", INODE_FLD, N_("IUse%"),       4, MBS_ALIGN_RIGHT, false },
200
201   [TARGET_FIELD] = { TARGET_FIELD,
202     "target", OTHER_FLD, N_("Mounted on"),  0, MBS_ALIGN_LEFT,  false }
203 };
204
205 static char const *all_args_string =
206   "source,fstype,itotal,iused,iavail,ipcent,size,used,avail,pcent,target";
207
208 /* Storage for the definition of output columns.  */
209 static struct field_data_t **columns;
210
211 /* The current number of output columns.  */
212 static size_t ncolumns;
213
214 /* Field values.  */
215 struct field_values_t
216 {
217   uintmax_t input_units;
218   uintmax_t output_units;
219   uintmax_t total;
220   uintmax_t available;
221   bool negate_available;
222   uintmax_t available_to_root;
223   uintmax_t used;
224   bool negate_used;
225 };
226
227 /* Storage for pointers for each string (cell of table).  */
228 static char ***table;
229
230 /* The current number of processed rows (including header).  */
231 static size_t nrows;
232
233 /* For long options that have no equivalent short option, use a
234    non-character as a pseudo short option, starting with CHAR_MAX + 1.  */
235 enum
236 {
237   NO_SYNC_OPTION = CHAR_MAX + 1,
238   SYNC_OPTION,
239   TOTAL_OPTION,
240   OUTPUT_OPTION,
241   MEGABYTES_OPTION  /* FIXME: remove long opt in Aug 2013 */
242 };
243
244 static struct option const long_options[] =
245 {
246   {"all", no_argument, NULL, 'a'},
247   {"block-size", required_argument, NULL, 'B'},
248   {"inodes", no_argument, NULL, 'i'},
249   {"human-readable", no_argument, NULL, 'h'},
250   {"si", no_argument, NULL, 'H'},
251   {"local", no_argument, NULL, 'l'},
252   {"megabytes", no_argument, NULL, MEGABYTES_OPTION}, /* obsolescent,  */
253   {"output", optional_argument, NULL, OUTPUT_OPTION},
254   {"portability", no_argument, NULL, 'P'},
255   {"print-type", no_argument, NULL, 'T'},
256   {"sync", no_argument, NULL, SYNC_OPTION},
257   {"no-sync", no_argument, NULL, NO_SYNC_OPTION},
258   {"total", no_argument, NULL, TOTAL_OPTION},
259   {"type", required_argument, NULL, 't'},
260   {"exclude-type", required_argument, NULL, 'x'},
261   {GETOPT_HELP_OPTION_DECL},
262   {GETOPT_VERSION_OPTION_DECL},
263   {NULL, 0, NULL, 0}
264 };
265
266 /* Replace problematic chars with '?'.
267    Since only control characters are currently considered,
268    this should work in all encodings.  */
269
270 static char*
271 hide_problematic_chars (char *cell)
272 {
273   char *p = cell;
274   while (*p)
275     {
276       if (iscntrl (to_uchar (*p)))
277         *p = '?';
278       p++;
279     }
280   return cell;
281 }
282
283 /* Dynamically allocate a row of pointers in TABLE, which
284    can then be accessed with standard 2D array notation.  */
285
286 static void
287 alloc_table_row (void)
288 {
289   nrows++;
290   table = xnrealloc (table, nrows, sizeof (char *));
291   table[nrows - 1] = xnmalloc (ncolumns, sizeof (char *));
292 }
293
294 /* Output each cell in the table, accounting for the
295    alignment and max width of each column.  */
296
297 static void
298 print_table (void)
299 {
300   size_t row;
301
302   for (row = 0; row < nrows; row++)
303     {
304       size_t col;
305       for (col = 0; col < ncolumns; col++)
306         {
307           char *cell = table[row][col];
308
309           /* Note the SOURCE_FIELD used to be displayed on it's own line
310              if (!posix_format && mbswidth (cell) > 20), but that
311              functionality was probably more problematic than helpful,
312              hence changed in commit v8.10-40-g99679ff.  */
313           if (col != 0)
314             putchar (' ');
315
316           int flags = 0;
317           if (col == ncolumns - 1) /* The last one.  */
318             flags = MBA_NO_RIGHT_PAD;
319
320           size_t width = columns[col]->width;
321           cell = ambsalign (cell, &width, columns[col]->align, flags);
322           /* When ambsalign fails, output unaligned data.  */
323           fputs (cell ? cell : table[row][col], stdout);
324           free (cell);
325
326           IF_LINT (free (table[row][col]));
327         }
328       putchar ('\n');
329       IF_LINT (free (table[row]));
330     }
331
332   IF_LINT (free (table));
333 }
334
335 /* Dynamically allocate a struct field_t in COLUMNS, which
336    can then be accessed with standard array notation.  */
337
338 static void
339 alloc_field (int f, const char *c)
340 {
341   ncolumns++;
342   columns = xnrealloc (columns, ncolumns, sizeof (struct field_data_t *));
343   columns[ncolumns - 1] = &field_data[f];
344   if (c != NULL)
345     columns[ncolumns - 1]->caption = c;
346
347   if (field_data[f].used)
348     assert (!"field used");
349
350   /* Mark field as used.  */
351   field_data[f].used = true;
352 }
353
354
355 /* Given a string, ARG, containing a comma-separated list of arguments
356    to the --output option, add the appropriate fields to columns.  */
357 static void
358 decode_output_arg (char const *arg)
359 {
360   char *arg_writable = xstrdup (arg);
361   char *s = arg_writable;
362   do
363     {
364       /* find next comma */
365       char *comma = strchr (s, ',');
366
367       /* If we found a comma, put a NUL in its place and advance.  */
368       if (comma)
369         *comma++ = 0;
370
371       /* process S.  */
372       display_field_t field = -1;
373       for (unsigned int i = 0; i < ARRAY_CARDINALITY (field_data); i++)
374         {
375           if (STREQ (field_data[i].arg, s))
376             {
377               field = i;
378               break;
379             }
380         }
381       if (field == -1)
382         {
383           error (0, 0, _("option --output: field '%s' unknown"), s);
384           usage (EXIT_FAILURE);
385         }
386
387       if (field_data[field].used)
388         {
389           /* Prevent the fields from being used more than once.  */
390           error (0, 0, _("option --output: field '%s' used more than once"),
391                  field_data[field].arg);
392           usage (EXIT_FAILURE);
393         }
394
395       switch (field)
396         {
397         case SOURCE_FIELD:
398         case FSTYPE_FIELD:
399         case USED_FIELD:
400         case PCENT_FIELD:
401         case ITOTAL_FIELD:
402         case IUSED_FIELD:
403         case IAVAIL_FIELD:
404         case IPCENT_FIELD:
405         case TARGET_FIELD:
406           alloc_field (field, NULL);
407           break;
408
409         case SIZE_FIELD:
410           alloc_field (field, N_("Size"));
411           break;
412
413         case AVAIL_FIELD:
414           alloc_field (field, N_("Avail"));
415           break;
416
417         default:
418           assert (!"invalid field");
419         }
420       s = comma;
421     }
422   while (s);
423
424   free (arg_writable);
425 }
426
427 /* Get the appropriate columns for the mode.  */
428 static void
429 get_field_list (void)
430 {
431   switch (header_mode)
432     {
433     case DEFAULT_MODE:
434       alloc_field (SOURCE_FIELD, NULL);
435       if (print_type)
436         alloc_field (FSTYPE_FIELD, NULL);
437       alloc_field (SIZE_FIELD,   NULL);
438       alloc_field (USED_FIELD,   NULL);
439       alloc_field (AVAIL_FIELD,  NULL);
440       alloc_field (PCENT_FIELD,  NULL);
441       alloc_field (TARGET_FIELD, NULL);
442       break;
443
444     case HUMAN_MODE:
445       alloc_field (SOURCE_FIELD, NULL);
446       if (print_type)
447         alloc_field (FSTYPE_FIELD, NULL);
448
449       alloc_field (SIZE_FIELD,   N_("Size"));
450       alloc_field (USED_FIELD,   NULL);
451       alloc_field (AVAIL_FIELD,  N_("Avail"));
452       alloc_field (PCENT_FIELD,  NULL);
453       alloc_field (TARGET_FIELD, NULL);
454       break;
455
456     case INODES_MODE:
457       alloc_field (SOURCE_FIELD, NULL);
458       if (print_type)
459         alloc_field (FSTYPE_FIELD, NULL);
460       alloc_field (ITOTAL_FIELD,  NULL);
461       alloc_field (IUSED_FIELD,   NULL);
462       alloc_field (IAVAIL_FIELD,  NULL);
463       alloc_field (IPCENT_FIELD,  NULL);
464       alloc_field (TARGET_FIELD,  NULL);
465       break;
466
467     case POSIX_MODE:
468       alloc_field (SOURCE_FIELD, NULL);
469       if (print_type)
470         alloc_field (FSTYPE_FIELD, NULL);
471       alloc_field (SIZE_FIELD,   NULL);
472       alloc_field (USED_FIELD,   NULL);
473       alloc_field (AVAIL_FIELD,  NULL);
474       alloc_field (PCENT_FIELD,  N_("Capacity"));
475       alloc_field (TARGET_FIELD, NULL);
476       break;
477
478     case OUTPUT_MODE:
479       if (!ncolumns)
480         {
481           /* Add all fields if --output was given without a field list.  */
482           decode_output_arg (all_args_string);
483         }
484       break;
485
486     default:
487       assert (!"invalid header_mode");
488     }
489 }
490
491 /* Obtain the appropriate header entries.  */
492
493 static void
494 get_header (void)
495 {
496   size_t col;
497
498   alloc_table_row ();
499
500   for (col = 0; col < ncolumns; col++)
501     {
502       char *cell = NULL;
503       char const *header = _(columns[col]->caption);
504
505       if (columns[col]->field == SIZE_FIELD
506           && (header_mode == DEFAULT_MODE
507               || (header_mode == OUTPUT_MODE
508                   && !(human_output_opts & human_autoscale))))
509         {
510           char buf[LONGEST_HUMAN_READABLE + 1];
511
512           int opts = (human_suppress_point_zero
513                       | human_autoscale | human_SI
514                       | (human_output_opts
515                          & (human_group_digits | human_base_1024 | human_B)));
516
517           /* Prefer the base that makes the human-readable value more exact,
518              if there is a difference.  */
519
520           uintmax_t q1000 = output_block_size;
521           uintmax_t q1024 = output_block_size;
522           bool divisible_by_1000;
523           bool divisible_by_1024;
524
525           do
526             {
527               divisible_by_1000 = q1000 % 1000 == 0;  q1000 /= 1000;
528               divisible_by_1024 = q1024 % 1024 == 0;  q1024 /= 1024;
529             }
530           while (divisible_by_1000 & divisible_by_1024);
531
532           if (divisible_by_1000 < divisible_by_1024)
533             opts |= human_base_1024;
534           if (divisible_by_1024 < divisible_by_1000)
535             opts &= ~human_base_1024;
536           if (! (opts & human_base_1024))
537             opts |= human_B;
538
539           char *num = human_readable (output_block_size, buf, opts, 1, 1);
540
541           /* Reset the header back to the default in OUTPUT_MODE.  */
542           header = N_("blocks");
543
544           /* TRANSLATORS: this is the "1K-blocks" header in "df" output.  */
545           if (asprintf (&cell, _("%s-%s"), num, header) == -1)
546             cell = NULL;
547         }
548       else if (header_mode == POSIX_MODE && columns[col]->field == SIZE_FIELD)
549         {
550           char buf[INT_BUFSIZE_BOUND (uintmax_t)];
551           char *num = umaxtostr (output_block_size, buf);
552
553           /* TRANSLATORS: this is the "1024-blocks" header in "df -P".  */
554           if (asprintf (&cell, _("%s-%s"), num, header) == -1)
555             cell = NULL;
556         }
557       else
558         cell = strdup (header);
559
560       if (!cell)
561         xalloc_die ();
562
563       hide_problematic_chars (cell);
564
565       table[nrows - 1][col] = cell;
566
567       columns[col]->width = MAX (columns[col]->width, mbswidth (cell, 0));
568     }
569 }
570
571 /* Is FSTYPE a type of file system that should be listed?  */
572
573 static bool _GL_ATTRIBUTE_PURE
574 selected_fstype (const char *fstype)
575 {
576   const struct fs_type_list *fsp;
577
578   if (fs_select_list == NULL || fstype == NULL)
579     return true;
580   for (fsp = fs_select_list; fsp; fsp = fsp->fs_next)
581     if (STREQ (fstype, fsp->fs_name))
582       return true;
583   return false;
584 }
585
586 /* Is FSTYPE a type of file system that should be omitted?  */
587
588 static bool _GL_ATTRIBUTE_PURE
589 excluded_fstype (const char *fstype)
590 {
591   const struct fs_type_list *fsp;
592
593   if (fs_exclude_list == NULL || fstype == NULL)
594     return false;
595   for (fsp = fs_exclude_list; fsp; fsp = fsp->fs_next)
596     if (STREQ (fstype, fsp->fs_name))
597       return true;
598   return false;
599 }
600
601 /* Filter mount list by skipping duplicate entries.
602    In the case of duplicities - based on to the device number - the mount entry
603    with a '/' in its me_devname (i.e. not pseudo name like tmpfs) wins.
604    If both have a real devname (e.g. bind mounts), then that with the shorter
605    me_mountdir wins.  */
606
607 static void
608 filter_mount_list (void)
609 {
610   struct mount_entry *me;
611
612   /* Store of already-processed device numbers.  */
613   struct devlist *devlist_head = NULL;
614
615   /* Sort all 'wanted' entries into the list devlist_head.  */
616   for (me = mount_list; me; me = me->me_next)
617     {
618       struct stat buf;
619       struct devlist *devlist;
620
621       if (-1 == stat (me->me_mountdir, &buf))
622         {
623           ;  /* Stat failed - add ME to be able to complain about it later.  */
624         }
625       else
626         {
627           /* If the device name is a real path name ...  */
628           if (strchr (me->me_devname, '/'))
629             {
630               /* ... try to find its device number in the devlist.  */
631               for (devlist = devlist_head; devlist; devlist = devlist->next)
632                 if (devlist->dev_num == buf.st_dev)
633                   break;
634
635               if (devlist)
636                 {
637                   /* Let the shorter mountdir win.  */
638                   if (   !strchr (devlist->me->me_devname, '/')
639                       || ( strlen (devlist->me->me_mountdir)
640                          > strlen (me->me_mountdir)))
641                     {
642                        /* FIXME: free ME - the others are also not free()d.  */
643                       devlist->me = me;
644                     }
645                   continue; /* ... with the loop over the mount_list.  */
646                 }
647             }
648         }
649
650       /* Add the device number to the global list devlist.  */
651       devlist = xmalloc (sizeof *devlist);
652       devlist->me = me;
653       devlist->dev_num = buf.st_dev;
654       devlist->next = devlist_head;
655       devlist_head = devlist;
656     }
657
658   /* Finally rebuild the mount_list from the devlist.  */
659   mount_list = NULL;
660   while (devlist_head)
661     {
662       /* Add the mount entry.  */
663       me = devlist_head->me;
664       me->me_next = mount_list;
665       mount_list = me;
666       /* Free devlist entry and advance.  */
667       struct devlist *devlist = devlist_head->next;
668       free (devlist_head);
669       devlist_head = devlist;
670     }
671 }
672
673 /* Return true if N is a known integer value.  On many file systems,
674    UINTMAX_MAX represents an unknown value; on AIX, UINTMAX_MAX - 1
675    represents unknown.  Use a rule that works on AIX file systems, and
676    that almost-always works on other types.  */
677 static bool
678 known_value (uintmax_t n)
679 {
680   return n < UINTMAX_MAX - 1;
681 }
682
683 /* Like human_readable (N, BUF, human_output_opts, INPUT_UNITS, OUTPUT_UNITS),
684    except:
685
686     - If NEGATIVE, then N represents a negative number,
687       expressed in two's complement.
688     - Otherwise, return "-" if N is unknown.  */
689
690 static char const *
691 df_readable (bool negative, uintmax_t n, char *buf,
692              uintmax_t input_units, uintmax_t output_units)
693 {
694   if (! known_value (n) && !negative)
695     return "-";
696   else
697     {
698       char *p = human_readable (negative ? -n : n, buf + negative,
699                                 human_output_opts, input_units, output_units);
700       if (negative)
701         *--p = '-';
702       return p;
703     }
704 }
705
706 /* Logical equivalence */
707 #define LOG_EQ(a, b) (!(a) == !(b))
708
709 /* Add integral value while using uintmax_t for value part and separate
710    negation flag.  It adds value of SRC and SRC_NEG to DEST and DEST_NEG.
711    The result will be in DEST and DEST_NEG.  See df_readable to understand
712    how the negation flag is used.  */
713 static void
714 add_uint_with_neg_flag (uintmax_t *dest, bool *dest_neg,
715                         uintmax_t src, bool src_neg)
716 {
717   if (LOG_EQ (*dest_neg, src_neg))
718     {
719       *dest += src;
720       return;
721     }
722
723   if (*dest_neg)
724     *dest = -*dest;
725
726   if (src_neg)
727     src = -src;
728
729   if (src < *dest)
730     *dest -= src;
731   else
732     {
733       *dest = src - *dest;
734       *dest_neg = src_neg;
735     }
736
737   if (*dest_neg)
738     *dest = -*dest;
739 }
740
741 /* Return true if S ends in a string that may be a 36-byte UUID,
742    i.e., of the form HHHHHHHH-HHHH-HHHH-HHHH-HHHHHHHHHHHH, where
743    each H is an upper or lower case hexadecimal digit.  */
744 static bool _GL_ATTRIBUTE_PURE
745 has_uuid_suffix (char const *s)
746 {
747   size_t len = strlen (s);
748   return (36 < len
749           && strspn (s + len - 36, "-0123456789abcdefABCDEF") == 36);
750 }
751
752 /* Obtain the block values BV and inode values IV
753    from the file system usage FSU.  */
754 static void
755 get_field_values (struct field_values_t *bv,
756                   struct field_values_t *iv,
757                   const struct fs_usage *fsu)
758 {
759   /* Inode values.  */
760   iv->input_units = iv->output_units = 1;
761   iv->total = fsu->fsu_files;
762   iv->available = iv->available_to_root = fsu->fsu_ffree;
763   iv->negate_available = false;
764
765   iv->used = UINTMAX_MAX;
766   iv->negate_used = false;
767   if (known_value (iv->total) && known_value (iv->available_to_root))
768     {
769       iv->used = iv->total - iv->available_to_root;
770       iv->negate_used = (iv->total < iv->available_to_root);
771     }
772
773   /* Block values.  */
774   bv->input_units = fsu->fsu_blocksize;
775   bv->output_units = output_block_size;
776   bv->total = fsu->fsu_blocks;
777   bv->available = fsu->fsu_bavail;
778   bv->available_to_root = fsu->fsu_bfree;
779   bv->negate_available = (fsu->fsu_bavail_top_bit_set
780                          && known_value (fsu->fsu_bavail));
781
782   bv->used = UINTMAX_MAX;
783   bv->negate_used = false;
784   if (known_value (bv->total) && known_value (bv->available_to_root))
785     {
786       bv->used = bv->total - bv->available_to_root;
787       bv->negate_used = (bv->total < bv->available_to_root);
788     }
789 }
790
791 /* Add block and inode values to grand total.  */
792 static void
793 add_to_grand_total (struct field_values_t *bv, struct field_values_t *iv)
794 {
795   if (known_value (iv->total))
796     grand_fsu.fsu_files += iv->total;
797   if (known_value (iv->available))
798     grand_fsu.fsu_ffree += iv->available;
799
800   if (known_value (bv->total))
801     grand_fsu.fsu_blocks += bv->input_units * bv->total;
802   if (known_value (bv->available_to_root))
803     grand_fsu.fsu_bfree += bv->input_units * bv->available_to_root;
804   if (known_value (bv->available))
805     add_uint_with_neg_flag (&grand_fsu.fsu_bavail,
806                             &grand_fsu.fsu_bavail_top_bit_set,
807                             bv->input_units * bv->available,
808                             bv->negate_available);
809 }
810
811 /* Obtain a space listing for the disk device with absolute file name DISK.
812    If MOUNT_POINT is non-NULL, it is the name of the root of the
813    file system on DISK.
814    If STAT_FILE is non-null, it is the name of a file within the file
815    system that the user originally asked for; this provides better
816    diagnostics, and sometimes it provides better results on networked
817    file systems that give different free-space results depending on
818    where in the file system you probe.
819    If FSTYPE is non-NULL, it is the type of the file system on DISK.
820    If MOUNT_POINT is non-NULL, then DISK may be NULL -- certain systems may
821    not be able to produce statistics in this case.
822    ME_DUMMY and ME_REMOTE are the mount entry flags.
823    Caller must set PROCESS_ALL to true when iterating over all entries, as
824    when df is invoked with no non-option argument.  See below for details.  */
825
826 static void
827 get_dev (char const *disk, char const *mount_point,
828          char const *stat_file, char const *fstype,
829          bool me_dummy, bool me_remote,
830          const struct fs_usage *force_fsu,
831          bool process_all)
832 {
833   if (me_remote && show_local_fs)
834     return;
835
836   if (me_dummy && !show_all_fs && !show_listed_fs)
837     return;
838
839   if (!selected_fstype (fstype) || excluded_fstype (fstype))
840     return;
841
842   /* If MOUNT_POINT is NULL, then the file system is not mounted, and this
843      program reports on the file system that the special file is on.
844      It would be better to report on the unmounted file system,
845      but statfs doesn't do that on most systems.  */
846   if (!stat_file)
847     stat_file = mount_point ? mount_point : disk;
848
849   struct fs_usage fsu;
850   if (force_fsu)
851     fsu = *force_fsu;
852   else if (get_fs_usage (stat_file, disk, &fsu))
853     {
854       error (0, errno, "%s", quote (stat_file));
855       exit_status = EXIT_FAILURE;
856       return;
857     }
858
859   if (fsu.fsu_blocks == 0 && !show_all_fs && !show_listed_fs)
860     return;
861
862   if (! force_fsu)
863     file_systems_processed = true;
864
865   alloc_table_row ();
866
867   if (! disk)
868     disk = "-";                 /* unknown */
869
870   char *dev_name = xstrdup (disk);
871   char *resolved_dev;
872
873   /* On some systems, dev_name is a long-named symlink like
874      /dev/disk/by-uuid/828fc648-9f30-43d8-a0b1-f7196a2edb66 pointing to a
875      much shorter and more useful name like /dev/sda1.  It may also look
876      like /dev/mapper/luks-828fc648-9f30-43d8-a0b1-f7196a2edb66 and point to
877      /dev/dm-0.  When process_all is true and dev_name is a symlink whose
878      name ends with a UUID use the resolved name instead.  */
879   if (process_all
880       && has_uuid_suffix (dev_name)
881       && (resolved_dev = canonicalize_filename_mode (dev_name, CAN_EXISTING)))
882     {
883       free (dev_name);
884       dev_name = resolved_dev;
885     }
886
887   if (! fstype)
888     fstype = "-";               /* unknown */
889
890   struct field_values_t block_values;
891   struct field_values_t inode_values;
892   get_field_values (&block_values, &inode_values, &fsu);
893
894   /* Add to grand total unless processing grand total line.  */
895   if (print_grand_total && ! force_fsu)
896     add_to_grand_total (&block_values, &inode_values);
897
898   size_t col;
899   for (col = 0; col < ncolumns; col++)
900     {
901       char buf[LONGEST_HUMAN_READABLE + 2];
902       char *cell;
903
904       struct field_values_t *v;
905       switch (columns[col]->field_type)
906         {
907         case BLOCK_FLD:
908           v = &block_values;
909           break;
910         case INODE_FLD:
911           v = &inode_values;
912           break;
913         case OTHER_FLD:
914           v = NULL;
915           break;
916         default:
917           assert (!"bad field_type");
918         }
919
920       switch (columns[col]->field)
921         {
922         case SOURCE_FIELD:
923           cell = xstrdup (dev_name);
924           break;
925
926         case FSTYPE_FIELD:
927           cell = xstrdup (fstype);
928           break;
929
930         case SIZE_FIELD:
931         case ITOTAL_FIELD:
932           cell = xstrdup (df_readable (false, v->total, buf,
933                                        v->input_units, v->output_units));
934           break;
935
936         case USED_FIELD:
937         case IUSED_FIELD:
938           cell = xstrdup (df_readable (v->negate_used, v->used, buf,
939                                        v->input_units, v->output_units));
940           break;
941
942         case AVAIL_FIELD:
943         case IAVAIL_FIELD:
944           cell = xstrdup (df_readable (v->negate_available, v->available, buf,
945                                        v->input_units, v->output_units));
946           break;
947
948         case PCENT_FIELD:
949         case IPCENT_FIELD:
950           {
951             double pct = -1;
952             if (! known_value (v->used) || ! known_value (v->available))
953               ;
954             else if (!v->negate_used
955                      && v->used <= TYPE_MAXIMUM (uintmax_t) / 100
956                      && v->used + v->available != 0
957                      && (v->used + v->available < v->used)
958                      == v->negate_available)
959               {
960                 uintmax_t u100 = v->used * 100;
961                 uintmax_t nonroot_total = v->used + v->available;
962                 pct = u100 / nonroot_total + (u100 % nonroot_total != 0);
963               }
964             else
965               {
966                 /* The calculation cannot be done easily with integer
967                    arithmetic.  Fall back on floating point.  This can suffer
968                    from minor rounding errors, but doing it exactly requires
969                    multiple precision arithmetic, and it's not worth the
970                    aggravation.  */
971                 double u = v->negate_used ? - (double) - v->used : v->used;
972                 double a = v->negate_available
973                            ? - (double) - v->available : v->available;
974                 double nonroot_total = u + a;
975                 if (nonroot_total)
976                   {
977                     long int lipct = pct = u * 100 / nonroot_total;
978                     double ipct = lipct;
979
980                     /* Like 'pct = ceil (dpct);', but avoid ceil so that
981                        the math library needn't be linked.  */
982                     if (ipct - 1 < pct && pct <= ipct + 1)
983                       pct = ipct + (ipct < pct);
984                   }
985               }
986
987             if (0 <= pct)
988               {
989                 if (asprintf (&cell, "%.0f%%", pct) == -1)
990                   cell = NULL;
991               }
992             else
993               cell = strdup ("-");
994
995             if (!cell)
996               xalloc_die ();
997
998             break;
999           }
1000
1001         case TARGET_FIELD:
1002 #ifdef HIDE_AUTOMOUNT_PREFIX
1003           /* Don't print the first directory name in MOUNT_POINT if it's an
1004              artifact of an automounter.  This is a bit too aggressive to be
1005              the default.  */
1006           if (STRNCMP_LIT (mount_point, "/auto/") == 0)
1007             mount_point += 5;
1008           else if (STRNCMP_LIT (mount_point, "/tmp_mnt/") == 0)
1009             mount_point += 8;
1010 #endif
1011           cell = xstrdup (mount_point);
1012           break;
1013
1014         default:
1015           assert (!"unhandled field");
1016         }
1017
1018       if (!cell)
1019         assert (!"empty cell");
1020
1021       hide_problematic_chars (cell);
1022       columns[col]->width = MAX (columns[col]->width, mbswidth (cell, 0));
1023       table[nrows - 1][col] = cell;
1024     }
1025   free (dev_name);
1026 }
1027
1028 /* If DISK corresponds to a mount point, show its usage
1029    and return true.  Otherwise, return false.  */
1030 static bool
1031 get_disk (char const *disk)
1032 {
1033   struct mount_entry const *me;
1034   struct mount_entry const *best_match = NULL;
1035
1036   for (me = mount_list; me; me = me->me_next)
1037     if (STREQ (disk, me->me_devname))
1038       best_match = me;
1039
1040   if (best_match)
1041     {
1042       get_dev (best_match->me_devname, best_match->me_mountdir, NULL,
1043                best_match->me_type, best_match->me_dummy,
1044                best_match->me_remote, NULL, false);
1045       return true;
1046     }
1047
1048   return false;
1049 }
1050
1051 /* Figure out which device file or directory POINT is mounted on
1052    and show its disk usage.
1053    STATP must be the result of 'stat (POINT, STATP)'.  */
1054 static void
1055 get_point (const char *point, const struct stat *statp)
1056 {
1057   struct stat disk_stats;
1058   struct mount_entry *me;
1059   struct mount_entry const *best_match = NULL;
1060
1061   /* Calculate the real absolute file name for POINT, and use that to find
1062      the mount point.  This avoids statting unavailable mount points,
1063      which can hang df.  */
1064   char *resolved = canonicalize_file_name (point);
1065   if (resolved && resolved[0] == '/')
1066     {
1067       size_t resolved_len = strlen (resolved);
1068       size_t best_match_len = 0;
1069
1070       for (me = mount_list; me; me = me->me_next)
1071       if (!STREQ (me->me_type, "lofs")
1072           && (!best_match || best_match->me_dummy || !me->me_dummy))
1073         {
1074           size_t len = strlen (me->me_mountdir);
1075           if (best_match_len <= len && len <= resolved_len
1076               && (len == 1 /* root file system */
1077                   || ((len == resolved_len || resolved[len] == '/')
1078                       && STREQ_LEN (me->me_mountdir, resolved, len))))
1079             {
1080               best_match = me;
1081               best_match_len = len;
1082             }
1083         }
1084     }
1085   free (resolved);
1086   if (best_match
1087       && (stat (best_match->me_mountdir, &disk_stats) != 0
1088           || disk_stats.st_dev != statp->st_dev))
1089     best_match = NULL;
1090
1091   if (! best_match)
1092     for (me = mount_list; me; me = me->me_next)
1093       {
1094         if (me->me_dev == (dev_t) -1)
1095           {
1096             if (stat (me->me_mountdir, &disk_stats) == 0)
1097               me->me_dev = disk_stats.st_dev;
1098             else
1099               {
1100                 /* Report only I/O errors.  Other errors might be
1101                    caused by shadowed mount points, which means POINT
1102                    can't possibly be on this file system.  */
1103                 if (errno == EIO)
1104                   {
1105                     error (0, errno, "%s", quote (me->me_mountdir));
1106                     exit_status = EXIT_FAILURE;
1107                   }
1108
1109                 /* So we won't try and fail repeatedly.  */
1110                 me->me_dev = (dev_t) -2;
1111               }
1112           }
1113
1114         if (statp->st_dev == me->me_dev
1115             && !STREQ (me->me_type, "lofs")
1116             && (!best_match || best_match->me_dummy || !me->me_dummy))
1117           {
1118             /* Skip bogus mtab entries.  */
1119             if (stat (me->me_mountdir, &disk_stats) != 0
1120                 || disk_stats.st_dev != me->me_dev)
1121               me->me_dev = (dev_t) -2;
1122             else
1123               best_match = me;
1124           }
1125       }
1126
1127   if (best_match)
1128     get_dev (best_match->me_devname, best_match->me_mountdir, point,
1129              best_match->me_type, best_match->me_dummy, best_match->me_remote,
1130              NULL, false);
1131   else
1132     {
1133       /* We couldn't find the mount entry corresponding to POINT.  Go ahead and
1134          print as much info as we can; methods that require the device to be
1135          present will fail at a later point.  */
1136
1137       /* Find the actual mount point.  */
1138       char *mp = find_mount_point (point, statp);
1139       if (mp)
1140         {
1141           get_dev (NULL, mp, NULL, NULL, false, false, NULL, false);
1142           free (mp);
1143         }
1144     }
1145 }
1146
1147 /* Determine what kind of node NAME is and show the disk usage
1148    for it.  STATP is the results of 'stat' on NAME.  */
1149
1150 static void
1151 get_entry (char const *name, struct stat const *statp)
1152 {
1153   if ((S_ISBLK (statp->st_mode) || S_ISCHR (statp->st_mode))
1154       && get_disk (name))
1155     return;
1156
1157   get_point (name, statp);
1158 }
1159
1160 /* Show all mounted file systems, except perhaps those that are of
1161    an unselected type or are empty.  */
1162
1163 static void
1164 get_all_entries (void)
1165 {
1166   struct mount_entry *me;
1167
1168   if (!show_all_fs)
1169     filter_mount_list ();
1170
1171   for (me = mount_list; me; me = me->me_next)
1172     get_dev (me->me_devname, me->me_mountdir, NULL, me->me_type,
1173              me->me_dummy, me->me_remote, NULL, true);
1174 }
1175
1176 /* Add FSTYPE to the list of file system types to display.  */
1177
1178 static void
1179 add_fs_type (const char *fstype)
1180 {
1181   struct fs_type_list *fsp;
1182
1183   fsp = xmalloc (sizeof *fsp);
1184   fsp->fs_name = (char *) fstype;
1185   fsp->fs_next = fs_select_list;
1186   fs_select_list = fsp;
1187 }
1188
1189 /* Add FSTYPE to the list of file system types to be omitted.  */
1190
1191 static void
1192 add_excluded_fs_type (const char *fstype)
1193 {
1194   struct fs_type_list *fsp;
1195
1196   fsp = xmalloc (sizeof *fsp);
1197   fsp->fs_name = (char *) fstype;
1198   fsp->fs_next = fs_exclude_list;
1199   fs_exclude_list = fsp;
1200 }
1201
1202 void
1203 usage (int status)
1204 {
1205   if (status != EXIT_SUCCESS)
1206     emit_try_help ();
1207   else
1208     {
1209       printf (_("Usage: %s [OPTION]... [FILE]...\n"), program_name);
1210       fputs (_("\
1211 Show information about the file system on which each FILE resides,\n\
1212 or all file systems by default.\n\
1213 "), stdout);
1214
1215       emit_mandatory_arg_note ();
1216
1217       fputs (_("\
1218   -a, --all             include dummy file systems\n\
1219   -B, --block-size=SIZE  scale sizes by SIZE before printing them.  E.g.,\n\
1220                            '-BM' prints sizes in units of 1,048,576 bytes.\n\
1221                            See SIZE format below.\n\
1222       --total           produce a grand total\n\
1223   -h, --human-readable  print sizes in human readable format (e.g., 1K 234M 2G)\
1224 \n\
1225   -H, --si              likewise, but use powers of 1000 not 1024\n\
1226 "), stdout);
1227       fputs (_("\
1228   -i, --inodes          list inode information instead of block usage\n\
1229   -k                    like --block-size=1K\n\
1230   -l, --local           limit listing to local file systems\n\
1231       --no-sync         do not invoke sync before getting usage info (default)\
1232 \n\
1233 "), stdout);
1234       fputs (_("\
1235       --output[=FIELD_LIST]  use the output format defined by FIELD_LIST,\n\
1236                                or print all fields if FIELD_LIST is omitted.\n\
1237   -P, --portability     use the POSIX output format\n\
1238       --sync            invoke sync before getting usage info\n\
1239   -t, --type=TYPE       limit listing to file systems of type TYPE\n\
1240   -T, --print-type      print file system type\n\
1241   -x, --exclude-type=TYPE   limit listing to file systems not of type TYPE\n\
1242   -v                    (ignored)\n\
1243 "), stdout);
1244       fputs (HELP_OPTION_DESCRIPTION, stdout);
1245       fputs (VERSION_OPTION_DESCRIPTION, stdout);
1246       emit_blocksize_note ("DF");
1247       emit_size_note ();
1248       fputs (_("\n\
1249 FIELD_LIST is a comma-separated list of columns to be included.  Valid\n\
1250 field names are: 'source', 'fstype', 'itotal', 'iused', 'iavail', 'ipcent',\n\
1251 'size', 'used', 'avail', 'pcent' and 'target' (see info page).\n\
1252 "), stdout);
1253       emit_ancillary_info ();
1254     }
1255   exit (status);
1256 }
1257
1258 int
1259 main (int argc, char **argv)
1260 {
1261   struct stat *stats IF_LINT ( = 0);
1262
1263   initialize_main (&argc, &argv);
1264   set_program_name (argv[0]);
1265   setlocale (LC_ALL, "");
1266   bindtextdomain (PACKAGE, LOCALEDIR);
1267   textdomain (PACKAGE);
1268
1269   atexit (close_stdout);
1270
1271   fs_select_list = NULL;
1272   fs_exclude_list = NULL;
1273   show_all_fs = false;
1274   show_listed_fs = false;
1275   human_output_opts = -1;
1276   print_type = false;
1277   file_systems_processed = false;
1278   exit_status = EXIT_SUCCESS;
1279   print_grand_total = false;
1280   grand_fsu.fsu_blocksize = 1;
1281
1282   /* If true, use the POSIX output format.  */
1283   bool posix_format = false;
1284
1285   const char *msg_mut_excl = _("options %s and %s are mutually exclusive");
1286
1287   while (true)
1288     {
1289       int oi = -1;
1290       int c = getopt_long (argc, argv, "aB:iF:hHklmPTt:vx:", long_options,
1291                            &oi);
1292       if (c == -1)
1293         break;
1294
1295       switch (c)
1296         {
1297         case 'a':
1298           show_all_fs = true;
1299           break;
1300         case 'B':
1301           {
1302             enum strtol_error e = human_options (optarg, &human_output_opts,
1303                                                  &output_block_size);
1304             if (e != LONGINT_OK)
1305               xstrtol_fatal (e, oi, c, long_options, optarg);
1306           }
1307           break;
1308         case 'i':
1309           if (header_mode == OUTPUT_MODE)
1310             {
1311               error (0, 0, msg_mut_excl, "-i", "--output");
1312               usage (EXIT_FAILURE);
1313             }
1314           header_mode = INODES_MODE;
1315           break;
1316         case 'h':
1317           human_output_opts = human_autoscale | human_SI | human_base_1024;
1318           output_block_size = 1;
1319           break;
1320         case 'H':
1321           human_output_opts = human_autoscale | human_SI;
1322           output_block_size = 1;
1323           break;
1324         case 'k':
1325           human_output_opts = 0;
1326           output_block_size = 1024;
1327           break;
1328         case 'l':
1329           show_local_fs = true;
1330           break;
1331         case MEGABYTES_OPTION:
1332           /* Distinguish between the long and the short option.
1333              As we want to remove the long option soon,
1334              give a warning when the long form is used.  */
1335           error (0, 0, "%s%s", _("warning: "),
1336             _("long option '--megabytes' is deprecated"
1337               " and will soon be removed"));
1338         case 'm': /* obsolescent, exists for BSD compatibility */
1339           human_output_opts = 0;
1340           output_block_size = 1024 * 1024;
1341           break;
1342         case 'T':
1343           if (header_mode == OUTPUT_MODE)
1344             {
1345               error (0, 0, msg_mut_excl, "-T", "--output");
1346               usage (EXIT_FAILURE);
1347             }
1348           print_type = true;
1349           break;
1350         case 'P':
1351           if (header_mode == OUTPUT_MODE)
1352             {
1353               error (0, 0, msg_mut_excl, "-P", "--output");
1354               usage (EXIT_FAILURE);
1355             }
1356           posix_format = true;
1357           break;
1358         case SYNC_OPTION:
1359           require_sync = true;
1360           break;
1361         case NO_SYNC_OPTION:
1362           require_sync = false;
1363           break;
1364
1365         case 'F':
1366           /* Accept -F as a synonym for -t for compatibility with Solaris.  */
1367         case 't':
1368           add_fs_type (optarg);
1369           break;
1370
1371         case 'v':               /* For SysV compatibility.  */
1372           /* ignore */
1373           break;
1374         case 'x':
1375           add_excluded_fs_type (optarg);
1376           break;
1377
1378         case OUTPUT_OPTION:
1379           if (header_mode == INODES_MODE)
1380             {
1381               error (0, 0, msg_mut_excl, "-i", "--output");
1382               usage (EXIT_FAILURE);
1383             }
1384           if (posix_format && header_mode == DEFAULT_MODE)
1385             {
1386               error (0, 0, msg_mut_excl, "-P", "--output");
1387               usage (EXIT_FAILURE);
1388             }
1389           if (print_type)
1390             {
1391               error (0, 0, msg_mut_excl, "-T", "--output");
1392               usage (EXIT_FAILURE);
1393             }
1394           header_mode = OUTPUT_MODE;
1395           if (optarg)
1396             decode_output_arg (optarg);
1397           break;
1398
1399         case TOTAL_OPTION:
1400           print_grand_total = true;
1401           break;
1402
1403         case_GETOPT_HELP_CHAR;
1404         case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
1405
1406         default:
1407           usage (EXIT_FAILURE);
1408         }
1409     }
1410
1411   if (human_output_opts == -1)
1412     {
1413       if (posix_format)
1414         {
1415           human_output_opts = 0;
1416           output_block_size = (getenv ("POSIXLY_CORRECT") ? 512 : 1024);
1417         }
1418       else
1419         human_options (getenv ("DF_BLOCK_SIZE"),
1420                        &human_output_opts, &output_block_size);
1421     }
1422
1423   if (header_mode == INODES_MODE || header_mode == OUTPUT_MODE)
1424     ;
1425   else if (human_output_opts & human_autoscale)
1426     header_mode = HUMAN_MODE;
1427   else if (posix_format)
1428     header_mode = POSIX_MODE;
1429
1430   /* Fail if the same file system type was both selected and excluded.  */
1431   {
1432     bool match = false;
1433     struct fs_type_list *fs_incl;
1434     for (fs_incl = fs_select_list; fs_incl; fs_incl = fs_incl->fs_next)
1435       {
1436         struct fs_type_list *fs_excl;
1437         for (fs_excl = fs_exclude_list; fs_excl; fs_excl = fs_excl->fs_next)
1438           {
1439             if (STREQ (fs_incl->fs_name, fs_excl->fs_name))
1440               {
1441                 error (0, 0,
1442                        _("file system type %s both selected and excluded"),
1443                        quote (fs_incl->fs_name));
1444                 match = true;
1445                 break;
1446               }
1447           }
1448       }
1449     if (match)
1450       exit (EXIT_FAILURE);
1451   }
1452
1453   if (optind < argc)
1454     {
1455       int i;
1456
1457       /* Open each of the given entries to make sure any corresponding
1458          partition is automounted.  This must be done before reading the
1459          file system table.  */
1460       stats = xnmalloc (argc - optind, sizeof *stats);
1461       for (i = optind; i < argc; ++i)
1462         {
1463           /* Prefer to open with O_NOCTTY and use fstat, but fall back
1464              on using "stat", in case the file is unreadable.  */
1465           int fd = open (argv[i], O_RDONLY | O_NOCTTY);
1466           if ((fd < 0 || fstat (fd, &stats[i - optind]))
1467               && stat (argv[i], &stats[i - optind]))
1468             {
1469               error (0, errno, "%s", quote (argv[i]));
1470               exit_status = EXIT_FAILURE;
1471               argv[i] = NULL;
1472             }
1473           if (0 <= fd)
1474             close (fd);
1475         }
1476     }
1477
1478   mount_list =
1479     read_file_system_list ((fs_select_list != NULL
1480                             || fs_exclude_list != NULL
1481                             || print_type
1482                             || field_data[FSTYPE_FIELD].used
1483                             || show_local_fs));
1484
1485   if (mount_list == NULL)
1486     {
1487       /* Couldn't read the table of mounted file systems.
1488          Fail if df was invoked with no file name arguments,
1489          or when either of -a, -l, -t or -x is used with file name
1490          arguments.  Otherwise, merely give a warning and proceed.  */
1491       int status = 0;
1492       if ( ! (optind < argc)
1493            || (show_all_fs
1494                || show_local_fs
1495                || fs_select_list != NULL
1496                || fs_exclude_list != NULL))
1497         {
1498           status = EXIT_FAILURE;
1499         }
1500       const char *warning = (status == 0 ? _("Warning: ") : "");
1501       error (status, errno, "%s%s", warning,
1502              _("cannot read table of mounted file systems"));
1503     }
1504
1505   if (require_sync)
1506     sync ();
1507
1508   get_field_list ();
1509   get_header ();
1510
1511   if (optind < argc)
1512     {
1513       int i;
1514
1515       /* Display explicitly requested empty file systems.  */
1516       show_listed_fs = true;
1517
1518       for (i = optind; i < argc; ++i)
1519         if (argv[i])
1520           get_entry (argv[i], &stats[i - optind]);
1521     }
1522   else
1523     get_all_entries ();
1524
1525   if (file_systems_processed)
1526     {
1527       if (print_grand_total)
1528         get_dev ("total",
1529                  (field_data[SOURCE_FIELD].used ? "-" : "total"),
1530                  NULL, NULL, false, false, &grand_fsu, false);
1531
1532       print_table ();
1533     }
1534   else
1535     {
1536       /* Print the "no FS processed" diagnostic only if there was no preceding
1537          diagnostic, e.g., if all have been excluded.  */
1538       if (exit_status == EXIT_SUCCESS)
1539         error (EXIT_FAILURE, 0, _("no file systems processed"));
1540     }
1541
1542   IF_LINT (free (columns));
1543
1544   exit (exit_status);
1545 }