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

« back to all changes in this revision

Viewing changes to src/df.c

  • Committer: Colin Watson
  • Date: 2013-10-30 15:48:33 UTC
  • mfrom: (8.3.5 sid)
  • Revision ID: cjwatson@canonical.com-20131030154833-xdt6e1yfffqom1c4
merge from Debian 8.21-1

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/* df - summarize free disk space
2
 
   Copyright (C) 1991-2012 Free Software Foundation, Inc.
 
2
   Copyright (C) 1991-2013 Free Software Foundation, Inc.
3
3
 
4
4
   This program is free software: you can redistribute it and/or modify
5
5
   it under the terms of the GNU General Public License as published by
43
43
  proper_name ("David MacKenzie"), \
44
44
  proper_name ("Paul Eggert")
45
45
 
46
 
/* If true, show inode information. */
47
 
static bool inode_format;
 
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
};
48
54
 
49
55
/* If true, show even file systems with zero size or
50
 
   uninteresting types. */
 
56
   uninteresting types.  */
51
57
static bool show_all_fs;
52
58
 
53
59
/* If true, show only local file systems.  */
63
69
/* The units to use when printing sizes.  */
64
70
static uintmax_t output_block_size;
65
71
 
66
 
/* If true, use the POSIX output format.  */
67
 
static bool posix_format;
68
 
 
69
72
/* True if a file system has been processed for output.  */
70
73
static bool file_systems_processed;
71
74
 
78
81
/* Desired exit status.  */
79
82
static int exit_status;
80
83
 
81
 
/* A file system type to display. */
 
84
/* A file system type to display.  */
82
85
 
83
86
struct fs_type_list
84
87
{
104
107
 
105
108
static struct fs_type_list *fs_exclude_list;
106
109
 
107
 
/* Linked list of mounted file systems. */
 
110
/* Linked list of mounted file systems.  */
108
111
static struct mount_entry *mount_list;
109
112
 
110
113
/* If true, print file system type as well.  */
113
116
/* If true, print a grand total at the end.  */
114
117
static bool print_grand_total;
115
118
 
116
 
/* Grand total data. */
 
119
/* Grand total data.  */
117
120
static struct fs_usage grand_fsu;
118
121
 
119
122
/* Display modes.  */
120
 
enum { DEFAULT_MODE, INODES_MODE, HUMAN_MODE, POSIX_MODE, NMODES };
 
123
enum
 
124
{
 
125
  DEFAULT_MODE,
 
126
  INODES_MODE,
 
127
  HUMAN_MODE,
 
128
  POSIX_MODE,
 
129
  OUTPUT_MODE
 
130
};
121
131
static int header_mode = DEFAULT_MODE;
122
132
 
123
133
/* Displayable fields.  */
124
 
enum
125
 
{
126
 
  DEV_FIELD,   /* file system */
127
 
  TYPE_FIELD,  /* FS type */
128
 
  TOTAL_FIELD, /* blocks or inodes */
129
 
  USED_FIELD,  /* ditto */
130
 
  FREE_FIELD,  /* ditto */
131
 
  PCENT_FIELD, /* percent used */
132
 
  MNT_FIELD,   /* mount point */
133
 
  NFIELDS
134
 
};
135
 
 
136
 
/* Header strings for the above fields in each mode.
137
 
   NULL means to use the header for the default mode.  */
138
 
static const char *headers[NFIELDS][NMODES] = {
139
 
/*  DEFAULT_MODE        INODES_MODE     HUMAN_MODE      POSIX_MODE  */
140
 
  { N_("Filesystem"),   NULL,           NULL,           NULL },
141
 
  { N_("Type"),         NULL,           NULL,           NULL },
142
 
  { N_("blocks"),       N_("Inodes"),   N_("Size"),     NULL },
143
 
  { N_("Used"),         N_("IUsed"),    NULL,           NULL },
144
 
  { N_("Available"),    N_("IFree"),    N_("Avail"),    NULL },
145
 
  { N_("Use%"),         N_("IUse%"),    NULL,           N_("Capacity") },
146
 
  { N_("Mounted on"),   NULL,           NULL,           NULL }
147
 
};
148
 
 
149
 
/* Alignments for the 3 textual and 4 numeric fields.  */
150
 
static mbs_align_t alignments[NFIELDS] = {
151
 
  MBS_ALIGN_LEFT, MBS_ALIGN_LEFT,
152
 
  MBS_ALIGN_RIGHT, MBS_ALIGN_RIGHT, MBS_ALIGN_RIGHT, MBS_ALIGN_RIGHT,
153
 
  MBS_ALIGN_LEFT
154
 
};
155
 
 
156
 
/* Auto adjusted (up) widths used to align columns.  */
157
 
static size_t widths[NFIELDS] = { 14, 4, 5, 5, 5, 4, 0 };
 
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
};
158
226
 
159
227
/* Storage for pointers for each string (cell of table).  */
160
228
static char ***table;
168
236
{
169
237
  NO_SYNC_OPTION = CHAR_MAX + 1,
170
238
  SYNC_OPTION,
 
239
  TOTAL_OPTION,
 
240
  OUTPUT_OPTION,
171
241
  MEGABYTES_OPTION  /* FIXME: remove long opt in Aug 2013 */
172
242
};
173
243
 
180
250
  {"si", no_argument, NULL, 'H'},
181
251
  {"local", no_argument, NULL, 'l'},
182
252
  {"megabytes", no_argument, NULL, MEGABYTES_OPTION}, /* obsolescent,  */
 
253
  {"output", optional_argument, NULL, OUTPUT_OPTION},
183
254
  {"portability", no_argument, NULL, 'P'},
184
255
  {"print-type", no_argument, NULL, 'T'},
185
256
  {"sync", no_argument, NULL, SYNC_OPTION},
186
257
  {"no-sync", no_argument, NULL, NO_SYNC_OPTION},
187
 
  {"total", no_argument, NULL, 'c'},
 
258
  {"total", no_argument, NULL, TOTAL_OPTION},
188
259
  {"type", required_argument, NULL, 't'},
189
260
  {"exclude-type", required_argument, NULL, 'x'},
190
261
  {GETOPT_HELP_OPTION_DECL},
217
288
{
218
289
  nrows++;
219
290
  table = xnrealloc (table, nrows, sizeof (char *));
220
 
  table[nrows-1] = xnmalloc (NFIELDS, sizeof (char *));
 
291
  table[nrows - 1] = xnmalloc (ncolumns, sizeof (char *));
221
292
}
222
293
 
223
294
/* Output each cell in the table, accounting for the
226
297
static void
227
298
print_table (void)
228
299
{
229
 
  size_t field, row;
 
300
  size_t row;
230
301
 
231
 
  for (row = 0; row < nrows; row ++)
 
302
  for (row = 0; row < nrows; row++)
232
303
    {
233
 
      for (field = 0; field < NFIELDS; field++)
 
304
      size_t col;
 
305
      for (col = 0; col < ncolumns; col++)
234
306
        {
235
 
          size_t width = widths[field];
236
 
          char *cell = table[row][field];
237
 
          if (!cell) /* Missing type column, or mount point etc. */
238
 
            continue;
 
307
          char *cell = table[row][col];
239
308
 
240
 
          /* Note the DEV_FIELD used to be displayed on it's own line
 
309
          /* Note the SOURCE_FIELD used to be displayed on it's own line
241
310
             if (!posix_format && mbswidth (cell) > 20), but that
242
 
             functionality is probably more problematic than helpful.  */
243
 
          if (field != 0)
 
311
             functionality was probably more problematic than helpful,
 
312
             hence changed in commit v8.10-40-g99679ff.  */
 
313
          if (col != 0)
244
314
            putchar (' ');
245
 
          if (field == MNT_FIELD) /* The last one.  */
246
 
            fputs (cell, stdout);
247
 
          else
248
 
            {
249
 
              cell = ambsalign (cell, &width, alignments[field], 0);
250
 
              /* When ambsalign fails, output unaligned data.  */
251
 
              fputs (cell ? cell : table[row][field], stdout);
252
 
              free (cell);
253
 
            }
254
 
          IF_LINT (free (table[row][field]));
 
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]));
255
327
        }
256
328
      putchar ('\n');
257
329
      IF_LINT (free (table[row]));
260
332
  IF_LINT (free (table));
261
333
}
262
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
 
263
491
/* Obtain the appropriate header entries.  */
264
492
 
265
493
static void
266
494
get_header (void)
267
495
{
268
 
  size_t field;
 
496
  size_t col;
269
497
 
270
498
  alloc_table_row ();
271
499
 
272
 
  for (field = 0; field < NFIELDS; field++)
 
500
  for (col = 0; col < ncolumns; col++)
273
501
    {
274
 
      if (field == TYPE_FIELD && !print_type)
275
 
        {
276
 
          table[nrows-1][field] = NULL;
277
 
          continue;
278
 
        }
279
 
 
280
502
      char *cell = NULL;
281
 
      char const *header = _(headers[field][header_mode]);
282
 
      if (!header)
283
 
        header = _(headers[field][DEFAULT_MODE]);
 
503
      char const *header = _(columns[col]->caption);
284
504
 
285
 
      if (header_mode == DEFAULT_MODE && field == TOTAL_FIELD)
 
505
      if (columns[col]->field == SIZE_FIELD
 
506
          && (header_mode == DEFAULT_MODE
 
507
              || (header_mode == OUTPUT_MODE
 
508
                  && !(human_output_opts & human_autoscale))))
286
509
        {
287
510
          char buf[LONGEST_HUMAN_READABLE + 1];
288
511
 
315
538
 
316
539
          char *num = human_readable (output_block_size, buf, opts, 1, 1);
317
540
 
 
541
          /* Reset the header back to the default in OUTPUT_MODE.  */
 
542
          header = N_("blocks");
 
543
 
318
544
          /* TRANSLATORS: this is the "1K-blocks" header in "df" output.  */
319
545
          if (asprintf (&cell, _("%s-%s"), num, header) == -1)
320
546
            cell = NULL;
321
547
        }
322
 
      else if (header_mode == POSIX_MODE && field == TOTAL_FIELD)
 
548
      else if (header_mode == POSIX_MODE && columns[col]->field == SIZE_FIELD)
323
549
        {
324
550
          char buf[INT_BUFSIZE_BOUND (uintmax_t)];
325
551
          char *num = umaxtostr (output_block_size, buf);
336
562
 
337
563
      hide_problematic_chars (cell);
338
564
 
339
 
      table[nrows-1][field] = cell;
 
565
      table[nrows - 1][col] = cell;
340
566
 
341
 
      widths[field] = MAX (widths[field], mbswidth (cell, 0));
 
567
      columns[col]->width = MAX (columns[col]->width, mbswidth (cell, 0));
342
568
    }
343
569
}
344
570
 
372
598
  return false;
373
599
}
374
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
 
375
673
/* Return true if N is a known integer value.  On many file systems,
376
674
   UINTMAX_MAX represents an unknown value; on AIX, UINTMAX_MAX - 1
377
675
   represents unknown.  Use a rule that works on AIX file systems, and
409
707
#define LOG_EQ(a, b) (!(a) == !(b))
410
708
 
411
709
/* Add integral value while using uintmax_t for value part and separate
412
 
   negation flag. It adds value of SRC and SRC_NEG to DEST and DEST_NEG.
 
710
   negation flag.  It adds value of SRC and SRC_NEG to DEST and DEST_NEG.
413
711
   The result will be in DEST and DEST_NEG.  See df_readable to understand
414
712
   how the negation flag is used.  */
415
713
static void
451
749
          && strspn (s + len - 36, "-0123456789abcdefABCDEF") == 36);
452
750
}
453
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
 
454
811
/* Obtain a space listing for the disk device with absolute file name DISK.
455
812
   If MOUNT_POINT is non-NULL, it is the name of the root of the
456
813
   file system on DISK.
473
830
         const struct fs_usage *force_fsu,
474
831
         bool process_all)
475
832
{
476
 
  struct fs_usage fsu;
477
 
  char buf[LONGEST_HUMAN_READABLE + 2];
478
 
  uintmax_t input_units;
479
 
  uintmax_t output_units;
480
 
  uintmax_t total;
481
 
  uintmax_t available;
482
 
  bool negate_available;
483
 
  uintmax_t available_to_root;
484
 
  uintmax_t used;
485
 
  bool negate_used;
486
 
  double pct = -1;
487
 
  char* cell;
488
 
  size_t field;
489
 
 
490
833
  if (me_remote && show_local_fs)
491
834
    return;
492
835
 
503
846
  if (!stat_file)
504
847
    stat_file = mount_point ? mount_point : disk;
505
848
 
 
849
  struct fs_usage fsu;
506
850
  if (force_fsu)
507
851
    fsu = *force_fsu;
508
852
  else if (get_fs_usage (stat_file, disk, &fsu))
515
859
  if (fsu.fsu_blocks == 0 && !show_all_fs && !show_listed_fs)
516
860
    return;
517
861
 
518
 
  if (! file_systems_processed)
519
 
    {
520
 
      if (! force_fsu)
521
 
        file_systems_processed = true;
522
 
      get_header ();
523
 
    }
 
862
  if (! force_fsu)
 
863
    file_systems_processed = true;
524
864
 
525
865
  alloc_table_row ();
526
866
 
547
887
  if (! fstype)
548
888
    fstype = "-";               /* unknown */
549
889
 
550
 
  if (inode_format)
551
 
    {
552
 
      input_units = output_units = 1;
553
 
      total = fsu.fsu_files;
554
 
      available = fsu.fsu_ffree;
555
 
      negate_available = false;
556
 
      available_to_root = available;
557
 
 
558
 
      if (known_value (total))
559
 
        grand_fsu.fsu_files += total;
560
 
      if (known_value (available))
561
 
        grand_fsu.fsu_ffree += available;
562
 
    }
563
 
  else
564
 
    {
565
 
      input_units = fsu.fsu_blocksize;
566
 
      output_units = output_block_size;
567
 
      total = fsu.fsu_blocks;
568
 
      available = fsu.fsu_bavail;
569
 
      negate_available = (fsu.fsu_bavail_top_bit_set
570
 
                          && known_value (available));
571
 
      available_to_root = fsu.fsu_bfree;
572
 
 
573
 
      if (known_value (total))
574
 
        grand_fsu.fsu_blocks += input_units * total;
575
 
      if (known_value (available_to_root))
576
 
        grand_fsu.fsu_bfree  += input_units * available_to_root;
577
 
      if (known_value (available))
578
 
        add_uint_with_neg_flag (&grand_fsu.fsu_bavail,
579
 
                                &grand_fsu.fsu_bavail_top_bit_set,
580
 
                                input_units * available, negate_available);
581
 
    }
582
 
 
583
 
  used = UINTMAX_MAX;
584
 
  negate_used = false;
585
 
  if (known_value (total) && known_value (available_to_root))
586
 
    {
587
 
      used = total - available_to_root;
588
 
      negate_used = (total < available_to_root);
589
 
    }
590
 
 
591
 
  for (field = 0; field < NFIELDS; field++)
592
 
    {
593
 
      switch (field)
594
 
        {
595
 
        case DEV_FIELD:
596
 
          cell = dev_name;
597
 
          break;
598
 
 
599
 
        case TYPE_FIELD:
600
 
          cell = print_type ? xstrdup (fstype) : NULL;
601
 
          break;
602
 
 
603
 
        case TOTAL_FIELD:
604
 
          cell = xstrdup (df_readable (false, total, buf,
605
 
                                       input_units, output_units));
606
 
          break;
 
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
 
607
936
        case USED_FIELD:
608
 
          cell = xstrdup (df_readable (negate_used, used, buf,
609
 
                                       input_units, output_units));
 
937
        case IUSED_FIELD:
 
938
          cell = xstrdup (df_readable (v->negate_used, v->used, buf,
 
939
                                       v->input_units, v->output_units));
610
940
          break;
611
 
        case FREE_FIELD:
612
 
          cell = xstrdup (df_readable (negate_available, available, buf,
613
 
                                       input_units, output_units));
 
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));
614
946
          break;
615
947
 
616
948
        case PCENT_FIELD:
617
 
          if (! known_value (used) || ! known_value (available))
618
 
            ;
619
 
          else if (!negate_used
620
 
                   && used <= TYPE_MAXIMUM (uintmax_t) / 100
621
 
                   && used + available != 0
622
 
                   && (used + available < used) == negate_available)
623
 
            {
624
 
              uintmax_t u100 = used * 100;
625
 
              uintmax_t nonroot_total = used + available;
626
 
              pct = u100 / nonroot_total + (u100 % nonroot_total != 0);
627
 
            }
628
 
          else
629
 
            {
630
 
              /* The calculation cannot be done easily with integer
631
 
                 arithmetic.  Fall back on floating point.  This can suffer
632
 
                 from minor rounding errors, but doing it exactly requires
633
 
                 multiple precision arithmetic, and it's not worth the
634
 
                 aggravation.  */
635
 
              double u = negate_used ? - (double) - used : used;
636
 
              double a = negate_available ? - (double) - available : available;
637
 
              double nonroot_total = u + a;
638
 
              if (nonroot_total)
639
 
                {
640
 
                  long int lipct = pct = u * 100 / nonroot_total;
641
 
                  double ipct = lipct;
642
 
 
643
 
                  /* Like 'pct = ceil (dpct);', but avoid ceil so that
644
 
                     the math library needn't be linked.  */
645
 
                  if (ipct - 1 < pct && pct <= ipct + 1)
646
 
                    pct = ipct + (ipct < pct);
647
 
                }
648
 
            }
649
 
 
650
 
          if (0 <= pct)
651
 
            {
652
 
              if (asprintf (&cell, "%.0f%%", pct) == -1)
653
 
                cell = NULL;
654
 
            }
655
 
          else
656
 
            cell = strdup ("-");
657
 
 
658
 
          if (!cell)
659
 
            xalloc_die ();
660
 
 
661
 
          break;
662
 
 
663
 
        case MNT_FIELD:
664
 
          if (mount_point)
665
 
            {
 
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:
666
1002
#ifdef HIDE_AUTOMOUNT_PREFIX
667
 
              /* Don't print the first directory name in MOUNT_POINT if it's an
668
 
                 artifact of an automounter.  This is a bit too aggressive to be
669
 
                 the default.  */
670
 
              if (STRNCMP_LIT (mount_point, "/auto/") == 0)
671
 
                mount_point += 5;
672
 
              else if (STRNCMP_LIT (mount_point, "/tmp_mnt/") == 0)
673
 
                mount_point += 8;
 
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;
674
1010
#endif
675
 
              cell = xstrdup (mount_point);
676
 
            }
677
 
          else
678
 
            cell = NULL;
 
1011
          cell = xstrdup (mount_point);
679
1012
          break;
680
1013
 
681
1014
        default:
682
1015
          assert (!"unhandled field");
683
1016
        }
684
1017
 
685
 
      if (cell)
686
 
        {
687
 
          hide_problematic_chars (cell);
688
 
          widths[field] = MAX (widths[field], mbswidth (cell, 0));
689
 
        }
690
 
      table[nrows-1][field] = cell;
 
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;
691
1024
    }
 
1025
  free (dev_name);
692
1026
}
693
1027
 
694
1028
/* If DISK corresponds to a mount point, show its usage
772
1106
                    exit_status = EXIT_FAILURE;
773
1107
                  }
774
1108
 
775
 
                /* So we won't try and fail repeatedly. */
 
1109
                /* So we won't try and fail repeatedly.  */
776
1110
                me->me_dev = (dev_t) -2;
777
1111
              }
778
1112
          }
824
1158
}
825
1159
 
826
1160
/* Show all mounted file systems, except perhaps those that are of
827
 
   an unselected type or are empty. */
 
1161
   an unselected type or are empty.  */
828
1162
 
829
1163
static void
830
1164
get_all_entries (void)
831
1165
{
832
1166
  struct mount_entry *me;
833
1167
 
 
1168
  if (!show_all_fs)
 
1169
    filter_mount_list ();
 
1170
 
834
1171
  for (me = mount_list; me; me = me->me_next)
835
1172
    get_dev (me->me_devname, me->me_mountdir, NULL, me->me_type,
836
1173
             me->me_dummy, me->me_remote, NULL, true);
837
1174
}
838
1175
 
839
 
/* Add FSTYPE to the list of file system types to display. */
 
1176
/* Add FSTYPE to the list of file system types to display.  */
840
1177
 
841
1178
static void
842
1179
add_fs_type (const char *fstype)
849
1186
  fs_select_list = fsp;
850
1187
}
851
1188
 
852
 
/* Add FSTYPE to the list of file system types to be omitted. */
 
1189
/* Add FSTYPE to the list of file system types to be omitted.  */
853
1190
 
854
1191
static void
855
1192
add_excluded_fs_type (const char *fstype)
873
1210
      fputs (_("\
874
1211
Show information about the file system on which each FILE resides,\n\
875
1212
or all file systems by default.\n\
876
 
\n\
877
 
"), stdout);
878
 
      fputs (_("\
879
 
Mandatory arguments to long options are mandatory for short options too.\n\
880
 
"), stdout);
 
1213
"), stdout);
 
1214
 
 
1215
      emit_mandatory_arg_note ();
 
1216
 
881
1217
      fputs (_("\
882
1218
  -a, --all             include dummy file systems\n\
883
1219
  -B, --block-size=SIZE  scale sizes by SIZE before printing them.  E.g.,\n\
896
1232
\n\
897
1233
"), stdout);
898
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\
899
1237
  -P, --portability     use the POSIX output format\n\
900
1238
      --sync            invoke sync before getting usage info\n\
901
1239
  -t, --type=TYPE       limit listing to file systems of type TYPE\n\
907
1245
      fputs (VERSION_OPTION_DESCRIPTION, stdout);
908
1246
      emit_blocksize_note ("DF");
909
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);
910
1253
      emit_ancillary_info ();
911
1254
    }
912
1255
  exit (status);
927
1270
 
928
1271
  fs_select_list = NULL;
929
1272
  fs_exclude_list = NULL;
930
 
  inode_format = false;
931
1273
  show_all_fs = false;
932
1274
  show_listed_fs = false;
933
1275
  human_output_opts = -1;
934
1276
  print_type = false;
935
1277
  file_systems_processed = false;
936
 
  posix_format = false;
937
1278
  exit_status = EXIT_SUCCESS;
938
1279
  print_grand_total = false;
939
1280
  grand_fsu.fsu_blocksize = 1;
940
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
 
941
1287
  while (true)
942
1288
    {
943
1289
      int oi = -1;
960
1306
          }
961
1307
          break;
962
1308
        case 'i':
963
 
          inode_format = true;
 
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;
964
1315
          break;
965
1316
        case 'h':
966
1317
          human_output_opts = human_autoscale | human_SI | human_base_1024;
989
1340
          output_block_size = 1024 * 1024;
990
1341
          break;
991
1342
        case 'T':
 
1343
          if (header_mode == OUTPUT_MODE)
 
1344
            {
 
1345
              error (0, 0, msg_mut_excl, "-T", "--output");
 
1346
              usage (EXIT_FAILURE);
 
1347
            }
992
1348
          print_type = true;
993
1349
          break;
994
1350
        case 'P':
 
1351
          if (header_mode == OUTPUT_MODE)
 
1352
            {
 
1353
              error (0, 0, msg_mut_excl, "-P", "--output");
 
1354
              usage (EXIT_FAILURE);
 
1355
            }
995
1356
          posix_format = true;
996
1357
          break;
997
1358
        case SYNC_OPTION:
1007
1368
          add_fs_type (optarg);
1008
1369
          break;
1009
1370
 
1010
 
        case 'v':               /* For SysV compatibility. */
 
1371
        case 'v':               /* For SysV compatibility.  */
1011
1372
          /* ignore */
1012
1373
          break;
1013
1374
        case 'x':
1014
1375
          add_excluded_fs_type (optarg);
1015
1376
          break;
1016
1377
 
1017
 
        case 'c':
 
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:
1018
1400
          print_grand_total = true;
1019
1401
          break;
1020
1402
 
1038
1420
                       &human_output_opts, &output_block_size);
1039
1421
    }
1040
1422
 
1041
 
  if (inode_format)
1042
 
    header_mode = INODES_MODE;
 
1423
  if (header_mode == INODES_MODE || header_mode == OUTPUT_MODE)
 
1424
    ;
1043
1425
  else if (human_output_opts & human_autoscale)
1044
1426
    header_mode = HUMAN_MODE;
1045
1427
  else if (posix_format)
1097
1479
    read_file_system_list ((fs_select_list != NULL
1098
1480
                            || fs_exclude_list != NULL
1099
1481
                            || print_type
 
1482
                            || field_data[FSTYPE_FIELD].used
1100
1483
                            || show_local_fs));
1101
1484
 
1102
1485
  if (mount_list == NULL)
1104
1487
      /* Couldn't read the table of mounted file systems.
1105
1488
         Fail if df was invoked with no file name arguments,
1106
1489
         or when either of -a, -l, -t or -x is used with file name
1107
 
         arguments. Otherwise, merely give a warning and proceed.  */
 
1490
         arguments.  Otherwise, merely give a warning and proceed.  */
1108
1491
      int status = 0;
1109
1492
      if ( ! (optind < argc)
1110
1493
           || (show_all_fs
1122
1505
  if (require_sync)
1123
1506
    sync ();
1124
1507
 
 
1508
  get_field_list ();
 
1509
  get_header ();
 
1510
 
1125
1511
  if (optind < argc)
1126
1512
    {
1127
1513
      int i;
1128
1514
 
1129
 
      /* Display explicitly requested empty file systems. */
 
1515
      /* Display explicitly requested empty file systems.  */
1130
1516
      show_listed_fs = true;
1131
1517
 
1132
1518
      for (i = optind; i < argc; ++i)
1136
1522
  else
1137
1523
    get_all_entries ();
1138
1524
 
1139
 
  if (print_grand_total && file_systems_processed)
1140
 
    {
1141
 
      if (inode_format)
1142
 
        grand_fsu.fsu_blocks = 1;
1143
 
      get_dev ("total", NULL, NULL, NULL, false, false, &grand_fsu, false);
1144
 
    }
1145
 
 
1146
 
  print_table ();
1147
 
 
1148
 
  /* Print the "no FS processed" diagnostic only if there was no preceding
1149
 
     diagnostic, e.g., if all have been excluded.  */
1150
 
  if (exit_status == EXIT_SUCCESS && ! file_systems_processed)
1151
 
    error (EXIT_FAILURE, 0, _("no file systems processed"));
 
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));
1152
1543
 
1153
1544
  exit (exit_status);
1154
1545
}