/* df - summarize free disk space This is the df utility
Copyright (C) 1991-2018 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */ The GNUv3 license
/* Written by David MacKenzie <djm@gnu.ai.mit.edu>.
--human-readable option added by lm@sgi.com.
--si and large file support added by eggert@twinsun.com. */
#include <config.h> Provides system specific information
#include <stdio.h> Provides standard I/O capability
#include <sys/types.h> Provides system data types
#include <getopt.h> ...!includes auto-comment...
#include <assert.h> ...!includes auto-comment...
#include <wchar.h> ...!includes auto-comment...
#include <wctype.h> ...!includes auto-comment...
#include "system.h" ...!includes auto-comment...
#include "canonicalize.h" ...!includes auto-comment...
#include "die.h" ...!includes auto-comment...
#include "error.h" ...!includes auto-comment...
#include "fsusage.h" ...!includes auto-comment...
#include "human.h" ...!includes auto-comment...
#include "mbsalign.h" ...!includes auto-comment...
#include "mbswidth.h" ...!includes auto-comment...
#include "mountlist.h" ...!includes auto-comment...
#include "quote.h" ...!includes auto-comment...
#include "find-mount-point.h" ...!includes auto-comment...
#include "hash.h" ...!includes auto-comment...
/* The official name of this program (e.g., no 'g' prefix). */
#define PROGRAM_NAME "df" Line 43
#define AUTHORS \ Line 45
proper_name ("Torbjorn Granlund"), \ Line 46
proper_name ("David MacKenzie"), \ Line 47
proper_name ("Paul Eggert") Line 48
struct devlist Line 50
{
dev_t dev_num; Line 52
struct mount_entry *me; Line 53
struct devlist *next; Line 54
}; Block 1
/* Filled with device numbers of examined file systems to avoid
duplicates in output. */
static Hash_table *devlist_table; Line 59
/* If true, show even file systems with zero size or
uninteresting types. */
static bool show_all_fs; Line 63
/* If true, show only local file systems. */
static bool show_local_fs; Line 66
/* If true, output data for each file system corresponding to a
command line argument -- even if it's a dummy (automounter) entry. */
static bool show_listed_fs; Line 70
/* Human-readable options for output. */
static int human_output_opts; Line 73
/* The units to use when printing sizes. */
static uintmax_t output_block_size; Line 76
/* True if a file system has been processed for output. */
static bool file_systems_processed; Line 79
/* If true, invoke the 'sync' system call before getting any usage data.
Using this option can make df very slow, especially with many or very
busy disks. Note that this may make a difference on some systems --
SunOS 4.1.3, for one. It is *not* necessary on GNU/Linux. */
static bool require_sync; Line 85
/* Desired exit status. */
static int exit_status; Line 88
/* A file system type to display. */
struct fs_type_list Line 92
{
char *fs_name; Line 94
struct fs_type_list *fs_next; Line 95
}; Block 2
/* Linked list of file system types to display.
If 'fs_select_list' is NULL, list all types.
This table is generated dynamically from command-line options,
rather than hardcoding into the program what it thinks are the
valid file system types; let the user specify any file system type
they want to, and if there are any file systems of that type, they
will be shown.
Some file system types:
4.2 4.3 ufs nfs swap ignore io vm efs dbg */
static struct fs_type_list *fs_select_list; Line 109
/* Linked list of file system types to omit.
If the list is empty, don't exclude any types. */
static struct fs_type_list *fs_exclude_list; Line 114
/* Linked list of mounted file systems. */
static struct mount_entry *mount_list; Line 117
/* If true, print file system type as well. */
static bool print_type; Line 120
/* If true, print a grand total at the end. */
static bool print_grand_total; Line 123
/* Grand total data. */
static struct fs_usage grand_fsu; Line 126
/* Display modes. */
enum Line 129
{
DEFAULT_MODE, Line 131
INODES_MODE, Line 132
HUMAN_MODE, Line 133
POSIX_MODE, Line 134
OUTPUT_MODE Line 135
}; Block 3
static int header_mode = DEFAULT_MODE; Line 137
/* Displayable fields. */
typedef enum Line 140
{
SOURCE_FIELD, /* file system */ Line 142
FSTYPE_FIELD, /* FS type */ Line 143
SIZE_FIELD, /* FS size */ Line 144
USED_FIELD, /* FS size used */ Line 145
AVAIL_FIELD, /* FS size available */ Line 146
PCENT_FIELD, /* percent used */ Line 147
ITOTAL_FIELD, /* inode total */ Line 148
IUSED_FIELD, /* inodes used */ Line 149
IAVAIL_FIELD, /* inodes available */ Line 150
IPCENT_FIELD, /* inodes used in percent */ Line 151
TARGET_FIELD, /* mount point */ Line 152
FILE_FIELD, /* specified file name */ Line 153
INVALID_FIELD /* validation marker */ Line 154
} display_field_t; Line 155Block 4
/* Flag if a field contains a block, an inode or another value. */
typedef enum Line 158
{
BLOCK_FLD, /* Block values field */ Line 160
INODE_FLD, /* Inode values field */ Line 161
OTHER_FLD /* Neutral field, e.g. target */ Line 162
} field_type_t; Line 163Block 5
/* Attributes of a display field. */
struct field_data_t Line 166
{
display_field_t field; Line 168
char const *arg; Line 169
field_type_t field_type; Line 170
const char *caption;/* NULL means to use the default header of this field. */Line 171
size_t width; /* Auto adjusted (up) widths used to align columns. */ Line 172
mbs_align_t align; /* Alignment for this field. */ Line 173
bool used; Line 174
}; Block 6
/* Header strings, minimum width and alignment for the above fields. */
static struct field_data_t field_data[] = { Line 178
[SOURCE_FIELD] = { SOURCE_FIELD, Line 179
"source", OTHER_FLD, N_("Filesystem"), 14, MBS_ALIGN_LEFT, false }, Line 180
[FSTYPE_FIELD] = { FSTYPE_FIELD, Line 182
"fstype", OTHER_FLD, N_("Type"), 4, MBS_ALIGN_LEFT, false }, Line 183
[SIZE_FIELD] = { SIZE_FIELD, Line 185
"size", BLOCK_FLD, N_("blocks"), 5, MBS_ALIGN_RIGHT, false }, Line 186
[USED_FIELD] = { USED_FIELD, Line 188
"used", BLOCK_FLD, N_("Used"), 5, MBS_ALIGN_RIGHT, false }, Line 189
[AVAIL_FIELD] = { AVAIL_FIELD, Line 191
"avail", BLOCK_FLD, N_("Available"), 5, MBS_ALIGN_RIGHT, false }, Line 192
[PCENT_FIELD] = { PCENT_FIELD, Line 194
"pcent", BLOCK_FLD, N_("Use%"), 4, MBS_ALIGN_RIGHT, false }, Line 195
[ITOTAL_FIELD] = { ITOTAL_FIELD, Line 197
"itotal", INODE_FLD, N_("Inodes"), 5, MBS_ALIGN_RIGHT, false }, Line 198
[IUSED_FIELD] = { IUSED_FIELD, Line 200
"iused", INODE_FLD, N_("IUsed"), 5, MBS_ALIGN_RIGHT, false }, Line 201
[IAVAIL_FIELD] = { IAVAIL_FIELD, Line 203
"iavail", INODE_FLD, N_("IFree"), 5, MBS_ALIGN_RIGHT, false }, Line 204
[IPCENT_FIELD] = { IPCENT_FIELD, Line 206
"ipcent", INODE_FLD, N_("IUse%"), 4, MBS_ALIGN_RIGHT, false }, Line 207
[TARGET_FIELD] = { TARGET_FIELD, Line 209
"target", OTHER_FLD, N_("Mounted on"), 0, MBS_ALIGN_LEFT, false }, Line 210
[FILE_FIELD] = { FILE_FIELD, Line 212
"file", OTHER_FLD, N_("File"), 0, MBS_ALIGN_LEFT, false } Line 213
}; Block 7
static char const *all_args_string = Line 216
"source,fstype,itotal,iused,iavail,ipcent,size," Line 217
"used,avail,pcent,file,target"; Line 218
/* Storage for the definition of output columns. */
static struct field_data_t **columns; Line 221
/* The current number of output columns. */
static size_t ncolumns; Line 224
/* Field values. */
struct field_values_t Line 227
{
uintmax_t input_units; Line 229
uintmax_t output_units; Line 230
uintmax_t total; Line 231
uintmax_t available; Line 232
bool negate_available; Line 233
uintmax_t available_to_root; Line 234
uintmax_t used; Line 235
bool negate_used; Line 236
}; Block 8
/* Storage for pointers for each string (cell of table). */
static char ***table; Line 240
/* The current number of processed rows (including header). */
static size_t nrows; Line 243
/* For long options that have no equivalent short option, use a
non-character as a pseudo short option, starting with CHAR_MAX + 1. */
enum Line 247
{
NO_SYNC_OPTION = CHAR_MAX + 1, Line 249
SYNC_OPTION, Line 250
TOTAL_OPTION, Line 251
OUTPUT_OPTION Line 252
}; Block 9
static struct option const long_options[] = Line 255
{
{"all", no_argument, NULL, 'a'}, Line 257
{"block-size", required_argument, NULL, 'B'}, Line 258
{"inodes", no_argument, NULL, 'i'}, Line 259
{"human-readable", no_argument, NULL, 'h'}, Line 260
{"si", no_argument, NULL, 'H'}, Line 261
{"local", no_argument, NULL, 'l'}, Line 262
{"output", optional_argument, NULL, OUTPUT_OPTION}, Line 263
{"portability", no_argument, NULL, 'P'}, Line 264
{"print-type", no_argument, NULL, 'T'}, Line 265
{"sync", no_argument, NULL, SYNC_OPTION}, Line 266
{"no-sync", no_argument, NULL, NO_SYNC_OPTION}, Line 267
{"total", no_argument, NULL, TOTAL_OPTION}, Line 268
{"type", required_argument, NULL, 't'}, Line 269
{"exclude-type", required_argument, NULL, 'x'}, Line 270
{GETOPT_HELP_OPTION_DECL}, Line 271
{GETOPT_VERSION_OPTION_DECL}, Line 272
{NULL, 0, NULL, 0} Line 273
}; Block 10
/* Replace problematic chars with '?'. */
static void Line 278
hide_problematic_chars (char *cell) Line 279
{
char *srcend = cell + strlen (cell); Line 281
char *dst = cell; Line 282
mbstate_t mbstate = { 0, }; Line 283
size_t n; Line 284
for (char *src = cell; src != srcend; src += n) Line 286
{
wchar_t wc; Line 288
size_t srcbytes = srcend - src; Line 289
n = mbrtowc (&wc, src, srcbytes, &mbstate); Line 290
bool ok = n <= srcbytes; Line 291
if (ok) Line 293
ok = !iswcntrl (wc); Line 294
else Line 295
n = 1; Line 296
if (ok) Line 298
{
memmove (dst, src, n); Line 300
dst += n; Line 301
}
else Line 303
{
*dst++ = '?'; Line 305
memset (&mbstate, 0, sizeof mbstate); Line 306
}
}
*dst = '\0'; Line 310
} Block 11
/* Dynamically allocate a row of pointers in TABLE, which
can then be accessed with standard 2D array notation. */
static void Line 316
alloc_table_row (void) Line 317
{
nrows++; Line 319
table = xnrealloc (table, nrows, sizeof (char **)); Line 320
table[nrows - 1] = xnmalloc (ncolumns, sizeof (char *)); Line 321
} Block 12
/* Output each cell in the table, accounting for the
alignment and max width of each column. */
static void Line 327
print_table (void) Line 328
{
size_t row; Line 330
for (row = 0; row < nrows; row++) Line 332
{
size_t col; Line 334
for (col = 0; col < ncolumns; col++) Line 335
{
char *cell = table[row][col]; Line 337
/* Note the SOURCE_FIELD used to be displayed on it's own line
if (!posix_format && mbswidth (cell) > 20), but that
functionality was probably more problematic than helpful,
hence changed in commit v8.10-40-g99679ff. */
if (col != 0) Line 343
putchar (' '); Line 344
int flags = 0; Line 346
if (col == ncolumns - 1) /* The last one. */ Line 347
flags = MBA_NO_RIGHT_PAD; Line 348
size_t width = columns[col]->width; Line 350
cell = ambsalign (cell, &width, columns[col]->align, flags); Line 351
/* When ambsalign fails, output unaligned data. */
fputs (cell ? cell : table[row][col], stdout); Line 353
free (cell); Line 354
IF_LINT (free (table[row][col])); Line 356
}
putchar ('\n'); Line 358
IF_LINT (free (table[row])); Line 359
}
IF_LINT (free (table)); Line 362
} Block 13
/* Dynamically allocate a struct field_t in COLUMNS, which
can then be accessed with standard array notation. */
static void Line 368
alloc_field (int f, const char *c) Line 369
{
ncolumns++; Line 371
columns = xnrealloc (columns, ncolumns, sizeof (struct field_data_t *)); Line 372
columns[ncolumns - 1] = &field_data[f]; Line 373
if (c != NULL) Line 374
columns[ncolumns - 1]->caption = c; Line 375
if (field_data[f].used) Line 377
assert (!"field used"); Line 378
/* Mark field as used. */
field_data[f].used = true; Line 381
} Block 14
/* Given a string, ARG, containing a comma-separated list of arguments
to the --output option, add the appropriate fields to columns. */
static void Line 387
decode_output_arg (char const *arg) Line 388
{
char *arg_writable = xstrdup (arg); Line 390
char *s = arg_writable; Line 391
do
{
/* find next comma */
char *comma = strchr (s, ','); Line 395
/* If we found a comma, put a NUL in its place and advance. */
if (comma) Line 398
*comma++ = 0; Line 399
/* process S. */
display_field_t field = INVALID_FIELD; Line 402
for (unsigned int i = 0; i < ARRAY_CARDINALITY (field_data); i++) Line 403
{
if (STREQ (field_data[i].arg, s)) Line 405
{
field = i; Line 407
break; Line 408
}
}
if (field == INVALID_FIELD) Line 411
{
error (0, 0, _("option --output: field %s unknown"), quote (s)); Line 413
usage (EXIT_FAILURE); Line 414
}
if (field_data[field].used) Line 417
{
/* Prevent the fields from being used more than once. */
error (0, 0, _("option --output: field %s used more than once"), Line 420
quote (field_data[field].arg)); Line 421
usage (EXIT_FAILURE); Line 422
}
switch (field) Line 425
{
case SOURCE_FIELD: Line 427
case FSTYPE_FIELD: Line 428
case USED_FIELD: Line 429
case PCENT_FIELD: Line 430
case ITOTAL_FIELD: Line 431
case IUSED_FIELD: Line 432
case IAVAIL_FIELD: Line 433
case IPCENT_FIELD: Line 434
case TARGET_FIELD: Line 435
case FILE_FIELD: Line 436
alloc_field (field, NULL); Line 437
break; Line 438
case SIZE_FIELD: Line 440
alloc_field (field, N_("Size")); Line 441
break; Line 442
case AVAIL_FIELD: Line 444
alloc_field (field, N_("Avail")); Line 445
break; Line 446
default: Line 448
assert (!"invalid field"); Line 449
}
s = comma; Line 451
}
while (s); Line 453
free (arg_writable); Line 455
} Block 15
/* Get the appropriate columns for the mode. */
static void Line 459
get_field_list (void) Line 460
{
switch (header_mode) Line 462
{
case DEFAULT_MODE: Line 464
alloc_field (SOURCE_FIELD, NULL); Line 465
if (print_type) Line 466
alloc_field (FSTYPE_FIELD, NULL); Line 467
alloc_field (SIZE_FIELD, NULL); Line 468
alloc_field (USED_FIELD, NULL); Line 469
alloc_field (AVAIL_FIELD, NULL); Line 470
alloc_field (PCENT_FIELD, NULL); Line 471
alloc_field (TARGET_FIELD, NULL); Line 472
break; Line 473
case HUMAN_MODE: Line 475
alloc_field (SOURCE_FIELD, NULL); Line 476
if (print_type) Line 477
alloc_field (FSTYPE_FIELD, NULL); Line 478
alloc_field (SIZE_FIELD, N_("Size")); Line 480
alloc_field (USED_FIELD, NULL); Line 481
alloc_field (AVAIL_FIELD, N_("Avail")); Line 482
alloc_field (PCENT_FIELD, NULL); Line 483
alloc_field (TARGET_FIELD, NULL); Line 484
break; Line 485
case INODES_MODE: Line 487
alloc_field (SOURCE_FIELD, NULL); Line 488
if (print_type) Line 489
alloc_field (FSTYPE_FIELD, NULL); Line 490
alloc_field (ITOTAL_FIELD, NULL); Line 491
alloc_field (IUSED_FIELD, NULL); Line 492
alloc_field (IAVAIL_FIELD, NULL); Line 493
alloc_field (IPCENT_FIELD, NULL); Line 494
alloc_field (TARGET_FIELD, NULL); Line 495
break; Line 496
case POSIX_MODE: Line 498
alloc_field (SOURCE_FIELD, NULL); Line 499
if (print_type) Line 500
alloc_field (FSTYPE_FIELD, NULL); Line 501
alloc_field (SIZE_FIELD, NULL); Line 502
alloc_field (USED_FIELD, NULL); Line 503
alloc_field (AVAIL_FIELD, NULL); Line 504
alloc_field (PCENT_FIELD, N_("Capacity")); Line 505
alloc_field (TARGET_FIELD, NULL); Line 506
break; Line 507
case OUTPUT_MODE: Line 509
if (!ncolumns) Line 510
{
/* Add all fields if --output was given without a field list. */
decode_output_arg (all_args_string); Line 513
}
break; Line 515
default: Line 517
assert (!"invalid header_mode"); Line 518
}
} Block 16
/* Obtain the appropriate header entries. */
static void Line 524
get_header (void) Line 525
{
size_t col; Line 527
alloc_table_row (); Line 529
for (col = 0; col < ncolumns; col++) Line 531
{
char *cell = NULL; Line 533
char const *header = _(columns[col]->caption); Line 534
if (columns[col]->field == SIZE_FIELD Line 536
&& (header_mode == DEFAULT_MODE Line 537
|| (header_mode == OUTPUT_MODE Line 538
&& !(human_output_opts & human_autoscale)))) Line 539
{
char buf[LONGEST_HUMAN_READABLE + 1]; Line 541
int opts = (human_suppress_point_zero Line 543
| human_autoscale | human_SI Line 544
| (human_output_opts Line 545
& (human_group_digits | human_base_1024 | human_B))); Line 546
/* Prefer the base that makes the human-readable value more exact,
if there is a difference. */
uintmax_t q1000 = output_block_size; Line 551
uintmax_t q1024 = output_block_size; Line 552
bool divisible_by_1000; Line 553
bool divisible_by_1024; Line 554
do
{
divisible_by_1000 = q1000 % 1000 == 0; q1000 /= 1000; Line 558
divisible_by_1024 = q1024 % 1024 == 0; q1024 /= 1024; Line 559
}
while (divisible_by_1000 & divisible_by_1024); Line 561
if (divisible_by_1000 < divisible_by_1024) Line 563
opts |= human_base_1024; Line 564
if (divisible_by_1024 < divisible_by_1000) Line 565
opts &= ~human_base_1024; Line 566
if (! (opts & human_base_1024)) Line 567
opts |= human_B; Line 568
char *num = human_readable (output_block_size, buf, opts, 1, 1); Line 570
/* Reset the header back to the default in OUTPUT_MODE. */
header = _("blocks"); Line 573
/* TRANSLATORS: this is the "1K-blocks" header in "df" output. */
if (asprintf (&cell, _("%s-%s"), num, header) == -1) Line 576
cell = NULL; Line 577
}
else if (header_mode == POSIX_MODE && columns[col]->field == SIZE_FIELD) Line 579
{
char buf[INT_BUFSIZE_BOUND (uintmax_t)]; Line 581
char *num = umaxtostr (output_block_size, buf); Line 582
/* TRANSLATORS: this is the "1024-blocks" header in "df -P". */
if (asprintf (&cell, _("%s-%s"), num, header) == -1) Line 585
cell = NULL; Line 586
}
else Line 588
cell = strdup (header); Line 589
if (!cell) Line 591
xalloc_die (); ...!common auto-comment...
hide_problematic_chars (cell); Line 594
table[nrows - 1][col] = cell; Line 596
size_t cell_width = mbswidth (cell, 0); Line 598
columns[col]->width = MAX (columns[col]->width, cell_width); Line 599
}
} Block 17
/* Is FSTYPE a type of file system that should be listed? */
static bool _GL_ATTRIBUTE_PURE Line 605
selected_fstype (const char *fstype) Line 606
{
const struct fs_type_list *fsp; Line 608
if (fs_select_list == NULL || fstype == NULL) Line 610
return true; Line 611
for (fsp = fs_select_list; fsp; fsp = fsp->fs_next) Line 612
if (STREQ (fstype, fsp->fs_name)) Line 613
return true; Line 614
return false; Line 615
} Block 18
/* Is FSTYPE a type of file system that should be omitted? */
static bool _GL_ATTRIBUTE_PURE Line 620
excluded_fstype (const char *fstype) Line 621
{
const struct fs_type_list *fsp; Line 623
if (fs_exclude_list == NULL || fstype == NULL) Line 625
return false; Line 626
for (fsp = fs_exclude_list; fsp; fsp = fsp->fs_next) Line 627
if (STREQ (fstype, fsp->fs_name)) Line 628
return true; Line 629
return false; Line 630
} Block 19
static size_t Line 633
devlist_hash (void const *x, size_t table_size) Line 634
{
struct devlist const *p = x; Line 636
return (uintmax_t) p->dev_num % table_size; Line 637
} Block 20
static bool Line 640
devlist_compare (void const *x, void const *y) Line 641
{
struct devlist const *a = x; Line 643
struct devlist const *b = y; Line 644
return a->dev_num == b->dev_num; Line 645
} Block 21
static struct devlist * Line 648
devlist_for_dev (dev_t dev) Line 649
{
if (devlist_table == NULL) Line 651
return NULL; Line 652
struct devlist dev_entry; Line 653
dev_entry.dev_num = dev; Line 654
return hash_lookup (devlist_table, &dev_entry); Line 655
} Block 22
static void Line 658
devlist_free (void *p) Line 659
{
free (p); Line 661
} Block 23
/* Filter mount list by skipping duplicate entries.
In the case of duplicates - based on the device number - the mount entry
with a '/' in its me_devname (i.e., not pseudo name like tmpfs) wins.
If both have a real devname (e.g. bind mounts), then that with the shorter
me_mountdir wins. With DEVICES_ONLY == true (set with df -a), only update
the global devlist_table, rather than filtering the global mount_list. */
static void Line 671
filter_mount_list (bool devices_only) Line 672
{
struct mount_entry *me; Line 674
/* Temporary list to keep entries ordered. */
struct devlist *device_list = NULL; Line 677
int mount_list_size = 0; Line 678
for (me = mount_list; me; me = me->me_next) Line 680
mount_list_size++; Line 681
devlist_table = hash_initialize (mount_list_size, NULL, Line 683
devlist_hash, Line 684
devlist_compare, Line 685
devlist_free); Line 686
if (devlist_table == NULL) Line 687
xalloc_die (); ...!common auto-comment...
/* Sort all 'wanted' entries into the list device_list. */
for (me = mount_list; me;) Line 691
{
struct stat buf; Line 693
struct mount_entry *discard_me = NULL; Line 694
/* Avoid stating remote file systems as that may hang.
On Linux we probably have me_dev populated from /proc/self/mountinfo,
however we still stat() in case another device was mounted later. */
if ((me->me_remote && show_local_fs) Line 699
|| (me->me_dummy && !show_all_fs && !show_listed_fs) Line 700
|| (!selected_fstype (me->me_type) || excluded_fstype (me->me_type)) Line 701
|| -1 == stat (me->me_mountdir, &buf)) Line 702...!syscalls auto-comment...
{
/* If remote, and showing just local, or FS type is excluded,
add ME for filtering later.
If stat failed; add ME to be able to complain about it later. */
buf.st_dev = me->me_dev; Line 707
}
else Line 709
{
/* If we've already seen this device... */
struct devlist *seen_dev = devlist_for_dev (buf.st_dev); Line 712
if (seen_dev) Line 714
{
bool target_nearer_root = strlen (seen_dev->me->me_mountdir) Line 716
> strlen (me->me_mountdir); Line 717
/* With bind mounts, prefer items nearer the root of the source */
bool source_below_root = seen_dev->me->me_mntroot != NULL Line 719
&& me->me_mntroot != NULL Line 720
&& (strlen (seen_dev->me->me_mntroot) Line 721
< strlen (me->me_mntroot)); Line 722
if (! print_grand_total Line 723
&& me->me_remote && seen_dev->me->me_remote Line 724
&& ! STREQ (seen_dev->me->me_devname, me->me_devname)) Line 725
{
/* Don't discard remote entries with different locations,
as these are more likely to be explicitly mounted.
However avoid this when producing a total to give
a more accurate value in that case. */
}
else if ((strchr (me->me_devname, '/') Line 732
/* let "real" devices with '/' in the name win. */
&& ! strchr (seen_dev->me->me_devname, '/')) Line 734
/* let points towards the root of the device win. */
|| (target_nearer_root && ! source_below_root) Line 736
/* let an entry overmounted on a new device win... */
|| (! STREQ (seen_dev->me->me_devname, me->me_devname) Line 738
/* ... but only when matching an existing mnt point,
to avoid problematic replacement when given
inaccurate mount lists, seen with some chroot
environments for example. */
&& STREQ (me->me_mountdir, Line 743
seen_dev->me->me_mountdir))) Line 744
{
/* Discard mount entry for existing device. */
discard_me = seen_dev->me; Line 747
seen_dev->me = me; Line 748
}
else Line 750
{
/* Discard mount entry currently being processed. */
discard_me = me; Line 753
}
}
}
if (discard_me) Line 759
{
me = me->me_next; Line 761
if (! devices_only) Line 762
free_mount_entry (discard_me); Line 763
}
else Line 765
{
/* Add the device number to the device_table. */
struct devlist *devlist = xmalloc (sizeof *devlist); Line 768
devlist->me = me; Line 769
devlist->dev_num = buf.st_dev; Line 770
devlist->next = device_list; Line 771
device_list = devlist; Line 772
if (hash_insert (devlist_table, devlist) == NULL) Line 773
xalloc_die (); ...!common auto-comment...
me = me->me_next; Line 776
}
}
/* Finally rebuild the mount_list from the devlist. */
if (! devices_only) { Line 781
mount_list = NULL; Line 782
while (device_list) Line 783
{
/* Add the mount entry. */
me = device_list->me; Line 786
me->me_next = mount_list; Line 787
mount_list = me; Line 788
device_list = device_list->next; Line 789
}
hash_free (devlist_table); Line 792
devlist_table = NULL; Line 793
}
} Block 24
/* Search a mount entry list for device id DEV.
Return the corresponding mount entry if found or NULL if not. */
static struct mount_entry const * _GL_ATTRIBUTE_PURE Line 801
me_for_dev (dev_t dev) Line 802
{
struct devlist *dl = devlist_for_dev (dev); Line 804
if (dl) Line 805
return dl->me; Line 806
return NULL; Line 808
} Block 25
/* Return true if N is a known integer value. On many file systems,
UINTMAX_MAX represents an unknown value; on AIX, UINTMAX_MAX - 1
represents unknown. Use a rule that works on AIX file systems, and
that almost-always works on other types. */
static bool Line 815
known_value (uintmax_t n) Line 816
{
return n < UINTMAX_MAX - 1; Line 818
} Block 26
/* Like human_readable (N, BUF, human_output_opts, INPUT_UNITS, OUTPUT_UNITS),
except:
- If NEGATIVE, then N represents a negative number,
expressed in two's complement.
- Otherwise, return "-" if N is unknown. */
static char const * Line 828
df_readable (bool negative, uintmax_t n, char *buf, Line 829
uintmax_t input_units, uintmax_t output_units) Line 830
{
if (! known_value (n) && !negative) Line 832
return "-"; Line 833
else Line 834
{
char *p = human_readable (negative ? -n : n, buf + negative, Line 836
human_output_opts, input_units, output_units); Line 837
if (negative) Line 838
*--p = '-'; Line 839
return p; Line 840
}
} Block 27
/* Logical equivalence */
#define LOG_EQ(a, b) (!(a) == !(b)) Line 845
/* Add integral value while using uintmax_t for value part and separate
negation flag. It adds value of SRC and SRC_NEG to DEST and DEST_NEG.
The result will be in DEST and DEST_NEG. See df_readable to understand
how the negation flag is used. */
static void Line 851
add_uint_with_neg_flag (uintmax_t *dest, bool *dest_neg, Line 852
uintmax_t src, bool src_neg) Line 853
{
if (LOG_EQ (*dest_neg, src_neg)) Line 855
{
*dest += src; Line 857
return; Line 858
}
if (*dest_neg) Line 861
*dest = -*dest; Line 862
if (src_neg) Line 864
src = -src; Line 865
if (src < *dest) Line 867
*dest -= src; Line 868
else Line 869
{
*dest = src - *dest; Line 871
*dest_neg = src_neg; Line 872
}
if (*dest_neg) Line 875
*dest = -*dest; Line 876
} Block 28
/* Return true if S ends in a string that may be a 36-byte UUID,
i.e., of the form HHHHHHHH-HHHH-HHHH-HHHH-HHHHHHHHHHHH, where
each H is an upper or lower case hexadecimal digit. */
static bool _GL_ATTRIBUTE_PURE Line 882
has_uuid_suffix (char const *s) Line 883
{
size_t len = strlen (s); Line 885
return (36 < len Line 886
&& strspn (s + len - 36, "-0123456789abcdefABCDEF") == 36); Line 887
} Block 29
/* Obtain the block values BV and inode values IV
from the file system usage FSU. */
static void Line 892
get_field_values (struct field_values_t *bv, Line 893
struct field_values_t *iv, Line 894
const struct fs_usage *fsu) Line 895
{
/* Inode values. */
iv->input_units = iv->output_units = 1; Line 898
iv->total = fsu->fsu_files; Line 899
iv->available = iv->available_to_root = fsu->fsu_ffree; Line 900
iv->negate_available = false; Line 901
iv->used = UINTMAX_MAX; Line 903
iv->negate_used = false; Line 904
if (known_value (iv->total) && known_value (iv->available_to_root)) Line 905
{
iv->used = iv->total - iv->available_to_root; Line 907
iv->negate_used = (iv->total < iv->available_to_root); Line 908
}
/* Block values. */
bv->input_units = fsu->fsu_blocksize; Line 912
bv->output_units = output_block_size; Line 913
bv->total = fsu->fsu_blocks; Line 914
bv->available = fsu->fsu_bavail; Line 915
bv->available_to_root = fsu->fsu_bfree; Line 916
bv->negate_available = (fsu->fsu_bavail_top_bit_set Line 917
&& known_value (fsu->fsu_bavail)); Line 918
bv->used = UINTMAX_MAX; Line 920
bv->negate_used = false; Line 921
if (known_value (bv->total) && known_value (bv->available_to_root)) Line 922
{
bv->used = bv->total - bv->available_to_root; Line 924
bv->negate_used = (bv->total < bv->available_to_root); Line 925
}
}
/* Add block and inode values to grand total. */
static void Line 930
add_to_grand_total (struct field_values_t *bv, struct field_values_t *iv) Line 931
{
if (known_value (iv->total)) Line 933
grand_fsu.fsu_files += iv->total; Line 934
if (known_value (iv->available)) Line 935
grand_fsu.fsu_ffree += iv->available; Line 936
if (known_value (bv->total)) Line 938
grand_fsu.fsu_blocks += bv->input_units * bv->total; Line 939
if (known_value (bv->available_to_root)) Line 940
grand_fsu.fsu_bfree += bv->input_units * bv->available_to_root; Line 941
if (known_value (bv->available)) Line 942
add_uint_with_neg_flag (&grand_fsu.fsu_bavail, Line 943
&grand_fsu.fsu_bavail_top_bit_set, Line 944
bv->input_units * bv->available, Line 945
bv->negate_available); Line 946
} Block 31
/* Obtain a space listing for the disk device with absolute file name DISK.
If MOUNT_POINT is non-NULL, it is the name of the root of the
file system on DISK.
If STAT_FILE is non-null, it is the name of a file within the file
system that the user originally asked for; this provides better
diagnostics, and sometimes it provides better results on networked
file systems that give different free-space results depending on
where in the file system you probe.
If FSTYPE is non-NULL, it is the type of the file system on DISK.
If MOUNT_POINT is non-NULL, then DISK may be NULL -- certain systems may
not be able to produce statistics in this case.
ME_DUMMY and ME_REMOTE are the mount entry flags.
Caller must set PROCESS_ALL to true when iterating over all entries, as
when df is invoked with no non-option argument. See below for details. */
static void Line 964
get_dev (char const *disk, char const *mount_point, char const* file, Line 965
char const *stat_file, char const *fstype, Line 966
bool me_dummy, bool me_remote, Line 967
const struct fs_usage *force_fsu, Line 968
bool process_all) Line 969
{
if (me_remote && show_local_fs) Line 971
return; Line 972
if (me_dummy && !show_all_fs && !show_listed_fs) Line 974
return; Line 975
if (!selected_fstype (fstype) || excluded_fstype (fstype)) Line 977
return; Line 978
/* Ignore relative MOUNT_POINTs, which are present for example
in /proc/mounts on Linux with network namespaces. */
if (!force_fsu && mount_point && ! IS_ABSOLUTE_FILE_NAME (mount_point)) Line 982
return; Line 983
/* If MOUNT_POINT is NULL, then the file system is not mounted, and this
program reports on the file system that the special file is on.
It would be better to report on the unmounted file system,
but statfs doesn't do that on most systems. */
if (!stat_file) Line 989
stat_file = mount_point ? mount_point : disk; Line 990
struct fs_usage fsu; Line 992
if (force_fsu) Line 993
fsu = *force_fsu; Line 994
else if (get_fs_usage (stat_file, disk, &fsu)) Line 995
{
/* If we can't access a system provided entry due
to it not being present (now), or due to permissions,
just output placeholder values rather than failing. */
if (process_all && (errno == EACCES || errno == ENOENT)) Line 1000
{
if (! show_all_fs) Line 1002
return; Line 1003
fstype = "-"; Line 1005
fsu.fsu_bavail_top_bit_set = false; Line 1006
fsu.fsu_blocksize = fsu.fsu_blocks = fsu.fsu_bfree = Line 1007
fsu.fsu_bavail = fsu.fsu_files = fsu.fsu_ffree = UINTMAX_MAX; Line 1008
}
else Line 1010
{
error (0, errno, "%s", quotef (stat_file)); Line 1012
exit_status = EXIT_FAILURE; Line 1013
return; Line 1014
}
}
else if (process_all && show_all_fs) Line 1017
{
/* Ensure we don't output incorrect stats for over-mounted directories.
Discard stats when the device name doesn't match. Though don't
discard when used and current mount entries are both remote due
to the possibility of aliased host names or exports. */
struct stat sb; Line 1023
if (stat (stat_file, &sb) == 0) Line 1024...!syscalls auto-comment...
{
struct mount_entry const * dev_me = me_for_dev (sb.st_dev); Line 1026
if (dev_me && ! STREQ (dev_me->me_devname, disk) Line 1027
&& (! dev_me->me_remote || ! me_remote)) Line 1028
{
fstype = "-"; Line 1030
fsu.fsu_bavail_top_bit_set = false; Line 1031
fsu.fsu_blocksize = fsu.fsu_blocks = fsu.fsu_bfree = Line 1032
fsu.fsu_bavail = fsu.fsu_files = fsu.fsu_ffree = UINTMAX_MAX; Line 1033
}
}
}
if (fsu.fsu_blocks == 0 && !show_all_fs && !show_listed_fs) Line 1038
return; Line 1039
if (! force_fsu) Line 1041
file_systems_processed = true; Line 1042
alloc_table_row (); Line 1044
if (! disk) Line 1046
disk = "-"; /* unknown */ Line 1047
if (! file) Line 1049
file = "-"; /* unspecified */ Line 1050
char *dev_name = xstrdup (disk); Line 1052
char *resolved_dev; Line 1053
/* On some systems, dev_name is a long-named symlink like
/dev/disk/by-uuid/828fc648-9f30-43d8-a0b1-f7196a2edb66 pointing to a
much shorter and more useful name like /dev/sda1. It may also look
like /dev/mapper/luks-828fc648-9f30-43d8-a0b1-f7196a2edb66 and point to
/dev/dm-0. When process_all is true and dev_name is a symlink whose
name ends with a UUID use the resolved name instead. */
if (process_all Line 1061
&& has_uuid_suffix (dev_name) Line 1062
&& (resolved_dev = canonicalize_filename_mode (dev_name, CAN_EXISTING))) Line 1063
{
free (dev_name); Line 1065
dev_name = resolved_dev; Line 1066
}
if (! fstype) Line 1069
fstype = "-"; /* unknown */ Line 1070
struct field_values_t block_values; Line 1072
struct field_values_t inode_values; Line 1073
get_field_values (&block_values, &inode_values, &fsu); Line 1074
/* Add to grand total unless processing grand total line. */
if (print_grand_total && ! force_fsu) Line 1077
add_to_grand_total (&block_values, &inode_values); Line 1078
size_t col; Line 1080
for (col = 0; col < ncolumns; col++) Line 1081
{
char buf[LONGEST_HUMAN_READABLE + 2]; Line 1083
char *cell; Line 1084
struct field_values_t *v; Line 1086
switch (columns[col]->field_type) Line 1087
{
case BLOCK_FLD: Line 1089
v = &block_values; Line 1090
break; Line 1091
case INODE_FLD: Line 1092
v = &inode_values; Line 1093
break; Line 1094
case OTHER_FLD: Line 1095
v = NULL; Line 1096
break; Line 1097
default: Line 1098
v = NULL; /* Avoid warnings where assert() is not __noreturn__. */ Line 1099
assert (!"bad field_type"); Line 1100
}
switch (columns[col]->field) Line 1103
{
case SOURCE_FIELD: Line 1105
cell = xstrdup (dev_name); Line 1106
break; Line 1107
case FSTYPE_FIELD: Line 1109
cell = xstrdup (fstype); Line 1110
break; Line 1111
case SIZE_FIELD: Line 1113
case ITOTAL_FIELD: Line 1114
cell = xstrdup (df_readable (false, v->total, buf, Line 1115
v->input_units, v->output_units)); Line 1116
break; Line 1117
case USED_FIELD: Line 1119
case IUSED_FIELD: Line 1120
cell = xstrdup (df_readable (v->negate_used, v->used, buf, Line 1121
v->input_units, v->output_units)); Line 1122
break; Line 1123
case AVAIL_FIELD: Line 1125
case IAVAIL_FIELD: Line 1126
cell = xstrdup (df_readable (v->negate_available, v->available, buf, Line 1127
v->input_units, v->output_units)); Line 1128
break; Line 1129
case PCENT_FIELD: Line 1131
case IPCENT_FIELD: Line 1132
{
double pct = -1; Line 1134
if (! known_value (v->used) || ! known_value (v->available)) Line 1135
;
else if (!v->negate_used Line 1137
&& v->used <= TYPE_MAXIMUM (uintmax_t) / 100 Line 1138
&& v->used + v->available != 0 Line 1139
&& (v->used + v->available < v->used) Line 1140
== v->negate_available) Line 1141
{
uintmax_t u100 = v->used * 100; Line 1143
uintmax_t nonroot_total = v->used + v->available; Line 1144
pct = u100 / nonroot_total + (u100 % nonroot_total != 0); Line 1145
}
else Line 1147
{
/* The calculation cannot be done easily with integer
arithmetic. Fall back on floating point. This can suffer
from minor rounding errors, but doing it exactly requires
multiple precision arithmetic, and it's not worth the
aggravation. */
double u = v->negate_used ? - (double) - v->used : v->used; Line 1154
double a = v->negate_available Line 1155
? - (double) - v->available : v->available; Line 1156
double nonroot_total = u + a; Line 1157
if (nonroot_total) Line 1158
{
long int lipct = pct = u * 100 / nonroot_total; Line 1160
double ipct = lipct; Line 1161
/* Like 'pct = ceil (dpct);', but avoid ceil so that
the math library needn't be linked. */
if (ipct - 1 < pct && pct <= ipct + 1) Line 1165
pct = ipct + (ipct < pct); Line 1166
}
}
if (0 <= pct) Line 1170
{
if (asprintf (&cell, "%.0f%%", pct) == -1) Line 1172
cell = NULL; Line 1173
}
else Line 1175
cell = strdup ("-"); Line 1176
if (!cell) Line 1178
xalloc_die (); ...!common auto-comment...
break; Line 1181
}
case FILE_FIELD: Line 1184
cell = xstrdup (file); Line 1185
break; Line 1186
case TARGET_FIELD: Line 1188
#ifdef HIDE_AUTOMOUNT_PREFIX Line 1189
/* Don't print the first directory name in MOUNT_POINT if it's an
artifact of an automounter. This is a bit too aggressive to be
the default. */
if (STRNCMP_LIT (mount_point, "/auto/") == 0) Line 1193
mount_point += 5; Line 1194
else if (STRNCMP_LIT (mount_point, "/tmp_mnt/") == 0) Line 1195
mount_point += 8; Line 1196
#endif Line 1197
cell = xstrdup (mount_point); Line 1198
break; Line 1199
default: Line 1201
assert (!"unhandled field"); Line 1202
}
if (!cell) Line 1205
assert (!"empty cell"); Line 1206
hide_problematic_chars (cell); Line 1208
size_t cell_width = mbswidth (cell, 0); Line 1209
columns[col]->width = MAX (columns[col]->width, cell_width); Line 1210
table[nrows - 1][col] = cell; Line 1211
}
free (dev_name); Line 1213
} Block 32
/* Scan the mount list returning the _last_ device found for MOUNT.
NULL is returned if MOUNT not found. The result is malloced. */
static char * Line 1218
last_device_for_mount (char const* mount) Line 1219
{
struct mount_entry const *me; Line 1221
struct mount_entry const *le = NULL; Line 1222
for (me = mount_list; me; me = me->me_next) Line 1224
{
if (STREQ (me->me_mountdir, mount)) Line 1226
le = me; Line 1227
}
if (le) Line 1230
{
char *devname = le->me_devname; Line 1232
char *canon_dev = canonicalize_file_name (devname); Line 1233
if (canon_dev && IS_ABSOLUTE_FILE_NAME (canon_dev)) Line 1234
return canon_dev; Line 1235
free (canon_dev); Line 1236
return xstrdup (le->me_devname); Line 1237
}
else Line 1239
return NULL; Line 1240
} Block 33
/* If DISK corresponds to a mount point, show its usage
and return true. Otherwise, return false. */
static bool Line 1245
get_disk (char const *disk) Line 1246
{
struct mount_entry const *me; Line 1248
struct mount_entry const *best_match = NULL; Line 1249
bool best_match_accessible = false; Line 1250
bool eclipsed_device = false; Line 1251
char const *file = disk; Line 1252
char *resolved = canonicalize_file_name (disk); Line 1254
if (resolved && IS_ABSOLUTE_FILE_NAME (resolved)) Line 1255
disk = resolved; Line 1256
size_t best_match_len = SIZE_MAX; Line 1258
for (me = mount_list; me; me = me->me_next) Line 1259
{
/* TODO: Should cache canon_dev in the mount_entry struct. */
char *devname = me->me_devname; Line 1262
char *canon_dev = canonicalize_file_name (me->me_devname); Line 1263
if (canon_dev && IS_ABSOLUTE_FILE_NAME (canon_dev)) Line 1264
devname = canon_dev; Line 1265
if (STREQ (disk, devname)) Line 1267
{
char *last_device = last_device_for_mount (me->me_mountdir); Line 1269
eclipsed_device = last_device && ! STREQ (last_device, devname); Line 1270
size_t len = strlen (me->me_mountdir); Line 1271
if (! eclipsed_device Line 1273
&& (! best_match_accessible || len < best_match_len)) Line 1274
{
struct stat disk_stats; Line 1276
bool this_match_accessible = false; Line 1277
if (stat (me->me_mountdir, &disk_stats) == 0) Line 1279...!syscalls auto-comment...
best_match_accessible = this_match_accessible = true; Line 1280
if (this_match_accessible Line 1282
|| (! best_match_accessible && len < best_match_len)) Line 1283
{
best_match = me; Line 1285
if (len == 1) /* Traditional root. */ Line 1286
{
free (last_device); Line 1288
free (canon_dev); Line 1289
break; Line 1290
}
else Line 1292
best_match_len = len; Line 1293
}
}
free (last_device); Line 1297
}
free (canon_dev); Line 1300
}
free (resolved); Line 1303
if (best_match) Line 1305
{
get_dev (best_match->me_devname, best_match->me_mountdir, file, NULL, Line 1307
best_match->me_type, best_match->me_dummy, Line 1308
best_match->me_remote, NULL, false); Line 1309
return true; Line 1310
}
else if (eclipsed_device) Line 1312
{
error (0, 0, _("cannot access %s: over-mounted by another device"), Line 1314
quoteaf (file)); Line 1315
exit_status = EXIT_FAILURE; Line 1316
return true; Line 1317
}
return false; Line 1320
} Block 34
/* Figure out which device file or directory POINT is mounted on
and show its disk usage.
STATP must be the result of 'stat (POINT, STATP)'. */
static void Line 1326
get_point (const char *point, const struct stat *statp) Line 1327
{
struct stat disk_stats; Line 1329
struct mount_entry *me; Line 1330
struct mount_entry const *best_match = NULL; Line 1331
/* Calculate the real absolute file name for POINT, and use that to find
the mount point. This avoids statting unavailable mount points,
which can hang df. */
char *resolved = canonicalize_file_name (point); Line 1336
if (resolved && resolved[0] == '/') Line 1337
{
size_t resolved_len = strlen (resolved); Line 1339
size_t best_match_len = 0; Line 1340
for (me = mount_list; me; me = me->me_next) Line 1342
{
if (!STREQ (me->me_type, "lofs") Line 1344
&& (!best_match || best_match->me_dummy || !me->me_dummy)) Line 1345
{
size_t len = strlen (me->me_mountdir); Line 1347
if (best_match_len <= len && len <= resolved_len Line 1348
&& (len == 1 /* root file system */ Line 1349
|| ((len == resolved_len || resolved[len] == '/') Line 1350
&& STREQ_LEN (me->me_mountdir, resolved, len)))) Line 1351
{
best_match = me; Line 1353
best_match_len = len; Line 1354
}
}
}
}
free (resolved); Line 1359
if (best_match Line 1360
&& (stat (best_match->me_mountdir, &disk_stats) != 0 Line 1361...!syscalls auto-comment...
|| disk_stats.st_dev != statp->st_dev)) Line 1362
best_match = NULL; Line 1363
if (! best_match) Line 1365
for (me = mount_list; me; me = me->me_next) Line 1366
{
if (me->me_dev == (dev_t) -1) Line 1368
{
if (stat (me->me_mountdir, &disk_stats) == 0) Line 1370...!syscalls auto-comment...
me->me_dev = disk_stats.st_dev; Line 1371
else Line 1372
{
/* Report only I/O errors. Other errors might be
caused by shadowed mount points, which means POINT
can't possibly be on this file system. */
if (errno == EIO) Line 1377
{
error (0, errno, "%s", quotef (me->me_mountdir)); Line 1379
exit_status = EXIT_FAILURE; Line 1380
}
/* So we won't try and fail repeatedly. */
me->me_dev = (dev_t) -2; Line 1384
}
}
if (statp->st_dev == me->me_dev Line 1388
&& !STREQ (me->me_type, "lofs") Line 1389
&& (!best_match || best_match->me_dummy || !me->me_dummy)) Line 1390
{
/* Skip bogus mtab entries. */
if (stat (me->me_mountdir, &disk_stats) != 0 Line 1393...!syscalls auto-comment...
|| disk_stats.st_dev != me->me_dev) Line 1394
me->me_dev = (dev_t) -2; Line 1395
else Line 1396
best_match = me; Line 1397
}
}
if (best_match) Line 1401
get_dev (best_match->me_devname, best_match->me_mountdir, point, point, Line 1402
best_match->me_type, best_match->me_dummy, best_match->me_remote, Line 1403
NULL, false); Line 1404
else Line 1405
{
/* We couldn't find the mount entry corresponding to POINT. Go ahead and
print as much info as we can; methods that require the device to be
present will fail at a later point. */
/* Find the actual mount point. */
char *mp = find_mount_point (point, statp); Line 1412
if (mp) Line 1413
{
get_dev (NULL, mp, point, NULL, NULL, false, false, NULL, false); Line 1415
free (mp); Line 1416
}
}
} Block 35
/* Determine what kind of node NAME is and show the disk usage
for it. STATP is the results of 'stat' on NAME. */
static void Line 1424
get_entry (char const *name, struct stat const *statp) Line 1425
{
if ((S_ISBLK (statp->st_mode) || S_ISCHR (statp->st_mode)) Line 1427
&& get_disk (name)) Line 1428
return; Line 1429
get_point (name, statp); Line 1431
} Block 36
/* Show all mounted file systems, except perhaps those that are of
an unselected type or are empty. */
static void Line 1437
get_all_entries (void) Line 1438
{
struct mount_entry *me; Line 1440
filter_mount_list (show_all_fs); Line 1442
for (me = mount_list; me; me = me->me_next) Line 1444
get_dev (me->me_devname, me->me_mountdir, NULL, NULL, me->me_type, Line 1445
me->me_dummy, me->me_remote, NULL, true); Line 1446
} Block 37
/* Add FSTYPE to the list of file system types to display. */
static void Line 1451
add_fs_type (const char *fstype) Line 1452
{
struct fs_type_list *fsp; Line 1454
fsp = xmalloc (sizeof *fsp); Line 1456
fsp->fs_name = (char *) fstype; Line 1457
fsp->fs_next = fs_select_list; Line 1458
fs_select_list = fsp; Line 1459
} Block 38
/* Add FSTYPE to the list of file system types to be omitted. */
static void Line 1464
add_excluded_fs_type (const char *fstype) Line 1465
{
struct fs_type_list *fsp; Line 1467
fsp = xmalloc (sizeof *fsp); Line 1469
fsp->fs_name = (char *) fstype; Line 1470
fsp->fs_next = fs_exclude_list; Line 1471
fs_exclude_list = fsp; Line 1472
} Block 39
void Line 1475
usage (int status) Line 1476
{
if (status != EXIT_SUCCESS) Line 1478
emit_try_help (); ...!common auto-comment...
else Line 1480
{
printf (_("Usage: %s [OPTION]... [FILE]...\n"), program_name); Line 1482
fputs (_("\ Line 1483
Show information about the file system on which each FILE resides,\n\ Line 1484
or all file systems by default.\n\ Line 1485
"), stdout); Line 1486
emit_mandatory_arg_note (); ...!common auto-comment...
/* TRANSLATORS: The thousands and decimal separators are best
adjusted to an appropriate default for your locale. */
fputs (_("\ Line 1492
-a, --all include pseudo, duplicate, inaccessible file systems\n\ Line 1493
-B, --block-size=SIZE scale sizes by SIZE before printing them; e.g.,\n\ Line 1494
'-BM' prints sizes in units of 1,048,576 bytes;\n\ Line 1495
see SIZE format below\n\ Line 1496
-h, --human-readable print sizes in powers of 1024 (e.g., 1023M)\n\ Line 1497
-H, --si print sizes in powers of 1000 (e.g., 1.1G)\n\ Line 1498
"), stdout); Line 1499
fputs (_("\ Line 1500
-i, --inodes list inode information instead of block usage\n\ Line 1501
-k like --block-size=1K\n\ Line 1502
-l, --local limit listing to local file systems\n\ Line 1503
--no-sync do not invoke sync before getting usage info (default)\ Line 1504
\n\
"), stdout); Line 1506
fputs (_("\ Line 1507
--output[=FIELD_LIST] use the output format defined by FIELD_LIST,\n\ Line 1508
or print all fields if FIELD_LIST is omitted.\n\ Line 1509
-P, --portability use the POSIX output format\n\ Line 1510
--sync invoke sync before getting usage info\n\ Line 1511
"), stdout); Line 1512
fputs (_("\ Line 1513
--total elide all entries insignificant to available space,\n\ Line 1514
and produce a grand total\n\ Line 1515
"), stdout); Line 1516
fputs (_("\ Line 1517
-t, --type=TYPE limit listing to file systems of type TYPE\n\ Line 1518
-T, --print-type print file system type\n\ Line 1519
-x, --exclude-type=TYPE limit listing to file systems not of type TYPE\n\ Line 1520
-v (ignored)\n\ Line 1521
"), stdout); Line 1522
fputs (HELP_OPTION_DESCRIPTION, stdout); Line 1523
fputs (VERSION_OPTION_DESCRIPTION, stdout); Line 1524
emit_blocksize_note ("DF"); Line 1525
emit_size_note (); Line 1526
fputs (_("\n\ Line 1527
FIELD_LIST is a comma-separated list of columns to be included. Valid\n\ Line 1528
field names are: 'source', 'fstype', 'itotal', 'iused', 'iavail', 'ipcent',\n\ Line 1529
'size', 'used', 'avail', 'pcent', 'file' and 'target' (see info page).\n\ Line 1530
"), stdout); Line 1531
emit_ancillary_info (PROGRAM_NAME); Line 1532
}
exit (status); Line 1534
} Block 40
int
main (int argc, char **argv) Line 1538
{
struct stat *stats IF_LINT ( = 0); Line 1540
initialize_main (&argc, &argv); VMS-specific entry point handling wildcard expansion
set_program_name (argv[0]); Retains program name and discards path
setlocale (LC_ALL, ""); Sets up internationalization (i18n)
bindtextdomain (PACKAGE, LOCALEDIR); Assigns i18n directorySets text domain for _() [gettext()] function
textdomain (PACKAGE); Sets text domain for _() [gettext()] function
atexit (close_stdout); Close stdout on exit (see gnulib)
fs_select_list = NULL; Line 1550
fs_exclude_list = NULL; Line 1551
show_all_fs = false; Line 1552
show_listed_fs = false; Line 1553
human_output_opts = -1; Line 1554
print_type = false; Line 1555
file_systems_processed = false; Line 1556
exit_status = EXIT_SUCCESS; Line 1557
print_grand_total = false; Line 1558
grand_fsu.fsu_blocksize = 1; Line 1559
/* If true, use the POSIX output format. */
bool posix_format = false; Line 1562
const char *msg_mut_excl = _("options %s and %s are mutually exclusive"); Line 1564
while (true) Line 1566
{
int oi = -1; Line 1568
int c = getopt_long (argc, argv, "aB:iF:hHklmPTt:vx:", long_options, Line 1569
&oi); Line 1570
if (c == -1) Line 1571
break; Line 1572
switch (c) Line 1574
{
case 'a': Line 1576
show_all_fs = true; Line 1577
break; Line 1578
case 'B': Line 1579
{
enum strtol_error e = human_options (optarg, &human_output_opts, Line 1581
&output_block_size); Line 1582
if (e != LONGINT_OK) Line 1583
xstrtol_fatal (e, oi, c, long_options, optarg); Line 1584
}
break; Line 1586
case 'i': Line 1587
if (header_mode == OUTPUT_MODE) Line 1588
{
error (0, 0, msg_mut_excl, "-i", "--output"); Line 1590
usage (EXIT_FAILURE); Line 1591
}
header_mode = INODES_MODE; Line 1593
break; Line 1594
case 'h': Line 1595
human_output_opts = human_autoscale | human_SI | human_base_1024; Line 1596
output_block_size = 1; Line 1597
break; Line 1598
case 'H': Line 1599
human_output_opts = human_autoscale | human_SI; Line 1600
output_block_size = 1; Line 1601
break; Line 1602
case 'k': Line 1603
human_output_opts = 0; Line 1604
output_block_size = 1024; Line 1605
break; Line 1606
case 'l': Line 1607
show_local_fs = true; Line 1608
break; Line 1609
case 'm': /* obsolescent, exists for BSD compatibility */ Line 1610
human_output_opts = 0; Line 1611
output_block_size = 1024 * 1024; Line 1612
break; Line 1613
case 'T': Line 1614
if (header_mode == OUTPUT_MODE) Line 1615
{
error (0, 0, msg_mut_excl, "-T", "--output"); Line 1617
usage (EXIT_FAILURE); Line 1618
}
print_type = true; Line 1620
break; Line 1621
case 'P': Line 1622
if (header_mode == OUTPUT_MODE) Line 1623
{
error (0, 0, msg_mut_excl, "-P", "--output"); Line 1625
usage (EXIT_FAILURE); Line 1626
}
posix_format = true; Line 1628
break; Line 1629
case SYNC_OPTION: Line 1630
require_sync = true; Line 1631
break; Line 1632
case NO_SYNC_OPTION: Line 1633
require_sync = false; Line 1634
break; Line 1635
case 'F': Line 1637
/* Accept -F as a synonym for -t for compatibility with Solaris. */
case 't': Line 1639
add_fs_type (optarg); Line 1640
break; Line 1641
case 'v': /* For SysV compatibility. */ Line 1643
/* ignore */
break; Line 1645
case 'x': Line 1646
add_excluded_fs_type (optarg); Line 1647
break; Line 1648
case OUTPUT_OPTION: Line 1650
if (header_mode == INODES_MODE) Line 1651
{
error (0, 0, msg_mut_excl, "-i", "--output"); Line 1653
usage (EXIT_FAILURE); Line 1654
}
if (posix_format && header_mode == DEFAULT_MODE) Line 1656
{
error (0, 0, msg_mut_excl, "-P", "--output"); Line 1658
usage (EXIT_FAILURE); Line 1659
}
if (print_type) Line 1661
{
error (0, 0, msg_mut_excl, "-T", "--output"); Line 1663
usage (EXIT_FAILURE); Line 1664
}
header_mode = OUTPUT_MODE; Line 1666
if (optarg) Line 1667
decode_output_arg (optarg); Line 1668
break; Line 1669
case TOTAL_OPTION: Line 1671
print_grand_total = true; Line 1672
break; Line 1673
case_GETOPT_HELP_CHAR; Line 1675
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); Line 1676
default: Line 1678
usage (EXIT_FAILURE); Line 1679
}
}
if (human_output_opts == -1) Line 1683
{
if (posix_format) Line 1685
{
human_output_opts = 0; Line 1687
output_block_size = (getenv ("POSIXLY_CORRECT") ? 512 : 1024); Line 1688
}
else Line 1690
human_options (getenv ("DF_BLOCK_SIZE"), Line 1691
&human_output_opts, &output_block_size); Line 1692
}
if (header_mode == INODES_MODE || header_mode == OUTPUT_MODE) Line 1695
;
else if (human_output_opts & human_autoscale) Line 1697
header_mode = HUMAN_MODE; Line 1698
else if (posix_format) Line 1699
header_mode = POSIX_MODE; Line 1700
/* Fail if the same file system type was both selected and excluded. */
{
bool match = false; Line 1704
struct fs_type_list *fs_incl; Line 1705
for (fs_incl = fs_select_list; fs_incl; fs_incl = fs_incl->fs_next) Line 1706
{
struct fs_type_list *fs_excl; Line 1708
for (fs_excl = fs_exclude_list; fs_excl; fs_excl = fs_excl->fs_next) Line 1709
{
if (STREQ (fs_incl->fs_name, fs_excl->fs_name)) Line 1711
{
error (0, 0, Line 1713
_("file system type %s both selected and excluded"), Line 1714
quote (fs_incl->fs_name)); Line 1715
match = true; Line 1716
break; Line 1717
}
}
}
if (match) Line 1721
return EXIT_FAILURE; Line 1722
}
assume (0 < optind); Line 1725
if (optind < argc) Line 1727
{
/* stat each of the given entries to make sure any corresponding
partition is automounted. This must be done before reading the
file system table. */
stats = xnmalloc (argc - optind, sizeof *stats); Line 1732
for (int i = optind; i < argc; ++i) Line 1733
{
if (stat (argv[i], &stats[i - optind])) Line 1735...!syscalls auto-comment...
{
error (0, errno, "%s", quotef (argv[i])); Line 1737
exit_status = EXIT_FAILURE; Line 1738
argv[i] = NULL; Line 1739
}
else if (! S_ISFIFO (stats[i - optind].st_mode)) Line 1741
{
/* open() is needed to automount in some cases. */
int fd = open (argv[i], O_RDONLY | O_NOCTTY); Line 1744...!syscalls auto-comment...
if (0 <= fd) Line 1745
close (fd); Line 1746...!syscalls auto-comment...
}
}
}
mount_list = Line 1751
read_file_system_list ((fs_select_list != NULL Line 1752
|| fs_exclude_list != NULL Line 1753
|| print_type Line 1754
|| field_data[FSTYPE_FIELD].used Line 1755
|| show_local_fs)); Line 1756
if (mount_list == NULL) Line 1758
{
/* Couldn't read the table of mounted file systems.
Fail if df was invoked with no file name arguments,
or when either of -a, -l, -t or -x is used with file name
arguments. Otherwise, merely give a warning and proceed. */
int status = 0; Line 1764
if ( ! (optind < argc) Line 1765
|| (show_all_fs Line 1766
|| show_local_fs Line 1767
|| fs_select_list != NULL Line 1768
|| fs_exclude_list != NULL)) Line 1769
{
status = EXIT_FAILURE; Line 1771
}
const char *warning = (status == 0 ? _("Warning: ") : ""); Line 1773
error (status, errno, "%s%s", warning, Line 1774
_("cannot read table of mounted file systems")); Line 1775
}
if (require_sync) Line 1778
sync (); Line 1779...!syscalls auto-comment...
get_field_list (); Line 1781
get_header (); Line 1782
if (optind < argc) Line 1784
{
/* Display explicitly requested empty file systems. */
show_listed_fs = true; Line 1787
for (int i = optind; i < argc; ++i) Line 1789
if (argv[i]) Line 1790
get_entry (argv[i], &stats[i - optind]); Line 1791
IF_LINT (free (stats)); Line 1793
}
else Line 1795
get_all_entries (); Line 1796
if (file_systems_processed) Line 1798
{
if (print_grand_total) Line 1800
get_dev ("total", Line 1801
(field_data[SOURCE_FIELD].used ? "-" : "total"), Line 1802
NULL, NULL, NULL, false, false, &grand_fsu, false); Line 1803
print_table (); Line 1805
}
else Line 1807
{
/* Print the "no FS processed" diagnostic only if there was no preceding
diagnostic, e.g., if all have been excluded. */
if (exit_status == EXIT_SUCCESS) Line 1811
die (EXIT_FAILURE, 0, _("no file systems processed")); Line 1812
}
IF_LINT (free (columns)); Line 1815
return exit_status; Line 1817
} Block 41