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