1 /* stat.c -- display file or file system status
2 Copyright (C) 2001-2023 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <https://www.gnu.org/licenses/>.
17 Written by Michael Meskes. */
21 /* Keep this conditional in sync with the similar conditional in
22 ../m4/stat-prog.m4. */
23 #if ((STAT_STATVFS || STAT_STATVFS64) \
24 && (HAVE_STRUCT_STATVFS_F_BASETYPE || HAVE_STRUCT_STATVFS_F_FSTYPENAME \
25 || (! HAVE_STRUCT_STATFS_F_FSTYPENAME && HAVE_STRUCT_STATVFS_F_TYPE)))
26 # define USE_STATVFS 1
28 # define USE_STATVFS 0
32 #include <sys/types.h>
36 # include <sys/statvfs.h>
39 #elif HAVE_SYS_MOUNT_H && HAVE_SYS_PARAM_H
40 /* NOTE: freebsd5.0 needs sys/param.h and sys/mount.h for statfs.
41 It does have statvfs.h, but shouldn't use it, since it doesn't
42 HAVE_STRUCT_STATVFS_F_BASETYPE. So find a clean way to fix it. */
43 /* NetBSD 1.5.2 needs these, for the declaration of struct statfs. */
44 # include <sys/param.h>
45 # include <sys/mount.h>
46 # if HAVE_NFS_NFS_CLNT_H && HAVE_NFS_VFS_H
47 /* Ultrix 4.4 needs these for the declaration of struct statfs. */
48 # include <netinet/in.h>
49 # include <nfs/nfs_clnt.h>
52 #elif HAVE_OS_H /* BeOS */
55 #include <selinux/selinux.h>
59 #include "areadlink.h"
62 #include "file-type.h"
66 #include "mountlist.h"
68 #include "stat-size.h"
69 #include "stat-time.h"
71 #include "find-mount-point.h"
72 #include "xvasprintf.h"
75 #if HAVE_STATX && defined STATX_INO
82 # define STRUCT_STATXFS_F_FSID_IS_INTEGER STRUCT_STATVFS_F_FSID_IS_INTEGER
83 # define HAVE_STRUCT_STATXFS_F_TYPE HAVE_STRUCT_STATVFS_F_TYPE
84 # if HAVE_STRUCT_STATVFS_F_NAMEMAX
85 # define SB_F_NAMEMAX(S) ((S)->f_namemax)
87 # if ! STAT_STATVFS && STAT_STATVFS64
88 # define STRUCT_STATVFS struct statvfs64
89 # define STATFS statvfs64
91 # define STRUCT_STATVFS struct statvfs
92 # define STATFS statvfs
94 # define STATFS_FRSIZE(S) ((S)->f_frsize)
96 # define HAVE_STRUCT_STATXFS_F_TYPE HAVE_STRUCT_STATFS_F_TYPE
97 # if HAVE_STRUCT_STATFS_F_NAMELEN
98 # define SB_F_NAMEMAX(S) ((S)->f_namelen)
99 # elif HAVE_STRUCT_STATFS_F_NAMEMAX
100 # define SB_F_NAMEMAX(S) ((S)->f_namemax)
102 # define STATFS statfs
103 # if HAVE_OS_H /* BeOS */
104 /* BeOS has a statvfs function, but it does not return sensible values
105 for f_files, f_ffree and f_favail, and lacks f_type, f_basetype and
106 f_fstypename. Use 'struct fs_info' instead. */
109 statfs (char const *filename
, struct fs_info
*buf
)
111 dev_t device
= dev_for_path (filename
);
114 errno
= (device
== B_ENTRY_NOT_FOUND
? ENOENT
115 : device
== B_BAD_VALUE
? EINVAL
116 : device
== B_NAME_TOO_LONG
? ENAMETOOLONG
117 : device
== B_NO_MEMORY
? ENOMEM
118 : device
== B_FILE_ERROR
? EIO
122 /* If successful, buf->dev will be == device. */
123 return fs_stat_dev (device
, buf
);
126 # define f_blocks total_blocks
127 # define f_bfree free_blocks
128 # define f_bavail free_blocks
129 # define f_bsize io_size
130 # define f_files total_nodes
131 # define f_ffree free_nodes
132 # define STRUCT_STATVFS struct fs_info
133 # define STRUCT_STATXFS_F_FSID_IS_INTEGER true
134 # define STATFS_FRSIZE(S) ((S)->block_size)
136 # define STRUCT_STATVFS struct statfs
137 # define STRUCT_STATXFS_F_FSID_IS_INTEGER STRUCT_STATFS_F_FSID_IS_INTEGER
138 # if HAVE_STRUCT_STATFS_F_FRSIZE
139 # define STATFS_FRSIZE(S) ((S)->f_frsize)
141 # define STATFS_FRSIZE(S) 0
147 # define OUT_NAMEMAX out_uint
149 /* Depending on whether statvfs or statfs is used,
150 neither f_namemax or f_namelen may be available. */
151 # define SB_F_NAMEMAX(S) "?"
152 # define OUT_NAMEMAX out_string
155 #if HAVE_STRUCT_STATVFS_F_BASETYPE
156 # define STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME f_basetype
158 # if HAVE_STRUCT_STATVFS_F_FSTYPENAME || HAVE_STRUCT_STATFS_F_FSTYPENAME
159 # define STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME f_fstypename
160 # elif HAVE_OS_H /* BeOS */
161 # define STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME fsh_name
167 # include <sys/nvpair.h>
170 /* FIXME: these are used by printf.c, too */
171 #define isodigit(c) ('0' <= (c) && (c) <= '7')
172 #define octtobin(c) ((c) - '0')
173 #define hextobin(c) ((c) >= 'a' && (c) <= 'f' ? (c) - 'a' + 10 : \
174 (c) >= 'A' && (c) <= 'F' ? (c) - 'A' + 10 : (c) - '0')
176 static char const digits
[] = "0123456789";
178 /* Flags that are portable for use in printf, for at least one
179 conversion specifier; make_format removes non-portable flags as
180 needed for particular specifiers. The glibc 2.2 extension "I" is
181 listed here; it is removed by make_format because it has undefined
182 behavior elsewhere and because it is incompatible with
184 static char const printf_flags
[] = "'-+ #0I";
186 /* Formats for the --terse option. */
187 static char const fmt_terse_fs
[] = "%n %i %l %t %s %S %b %f %a %c %d\n";
188 static char const fmt_terse_regular
[] = "%n %s %b %f %u %g %D %i %h %t %T"
190 static char const fmt_terse_selinux
[] = "%n %s %b %f %u %g %D %i %h %t %T"
191 " %X %Y %Z %W %o %C\n";
193 #define PROGRAM_NAME "stat"
195 #define AUTHORS proper_name ("Michael Meskes")
199 PRINTF_OPTION
= CHAR_MAX
+ 1
209 static char const *const cached_args
[] =
211 "default", "never", "always", nullptr
214 static enum cached_mode
const cached_modes
[] =
216 cached_default
, cached_never
, cached_always
219 static struct option
const long_options
[] =
221 {"dereference", no_argument
, nullptr, 'L'},
222 {"file-system", no_argument
, nullptr, 'f'},
223 {"format", required_argument
, nullptr, 'c'},
224 {"printf", required_argument
, nullptr, PRINTF_OPTION
},
225 {"terse", no_argument
, nullptr, 't'},
226 {"cached", required_argument
, nullptr, 0},
227 {GETOPT_HELP_OPTION_DECL
},
228 {GETOPT_VERSION_OPTION_DECL
},
229 {nullptr, 0, nullptr, 0}
232 /* Whether to follow symbolic links; True for --dereference (-L). */
233 static bool follow_links
;
235 /* Whether to interpret backslash-escape sequences.
236 True for --printf=FMT, not for --format=FMT (-c). */
237 static bool interpret_backslash_escapes
;
239 /* The trailing delimiter string:
240 "" for --printf=FMT, "\n" for --format=FMT (-c). */
241 static char const *trailing_delim
= "";
243 /* The representation of the decimal point in the current locale. */
244 static char const *decimal_point
;
245 static size_t decimal_point_len
;
248 print_stat (char *pformat
, size_t prefix_len
, char mod
, char m
,
249 int fd
, char const *filename
, void const *data
);
251 /* Return the type of the specified file system.
252 Some systems have statfvs.f_basetype[FSTYPSZ] (AIX, HP-UX, and Solaris).
253 Others have statvfs.f_fstypename[_VFS_NAMELEN] (NetBSD 3.0).
254 Others have statfs.f_fstypename[MFSNAMELEN] (NetBSD 1.5.2).
255 Still others have neither and have to get by with f_type (GNU/Linux).
256 But f_type may only exist in statfs (Cygwin). */
259 human_fstype (STRUCT_STATVFS
const *statfsbuf
)
261 #ifdef STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME
262 return statfsbuf
->STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME
;
264 switch (statfsbuf
->f_type
)
266 # if defined __linux__ || defined __ANDROID__
268 /* Compare with what's in libc:
269 f=/a/libc/sysdeps/unix/sysv/linux/linux_fsinfo.h
270 sed -n '/ADFS_SUPER_MAGIC/,/SYSFS_MAGIC/p' $f \
271 | perl -n -e '/#define (.*?)_(?:SUPER_)MAGIC\s+0x(\S+)/' \
272 -e 'and print "case S_MAGIC_$1: /\* 0x" . uc($2) . " *\/\n"' \
274 perl -ne '/^\s+(case S_MAGIC_.*?): \/\* 0x(\S+) \*\//' \
275 -e 'and do { $v=uc$2; print "$1: /\* 0x$v *\/\n"}' stat.c \
277 diff -u sym_stat sym_libc
280 /* Also compare with the list in "man 2 statfs" using the
281 fs-magic-compare make target. */
283 /* IMPORTANT NOTE: Each of the following 'case S_MAGIC_...:'
284 statements must be followed by a hexadecimal constant in
285 a comment. The S_MAGIC_... name and constant are automatically
286 combined to produce the #define directives in fs.h. */
288 case S_MAGIC_AAFS
: /* 0x5A3C69F0 local */
290 case S_MAGIC_ACFS
: /* 0x61636673 remote */
292 case S_MAGIC_ADFS
: /* 0xADF5 local */
294 case S_MAGIC_AFFS
: /* 0xADFF local */
296 case S_MAGIC_AFS
: /* 0x5346414F remote */
298 case S_MAGIC_ANON_INODE_FS
: /* 0x09041934 local */
299 return "anon-inode FS";
300 case S_MAGIC_AUFS
: /* 0x61756673 remote */
301 /* FIXME: change syntax or add an optional attribute like "inotify:no".
302 The above is labeled as "remote" so that tail always uses polling,
303 but this isn't really a remote file system type. */
305 case S_MAGIC_AUTOFS
: /* 0x0187 local */
307 case S_MAGIC_BALLOON_KVM
: /* 0x13661366 local */
308 return "balloon-kvm-fs";
309 case S_MAGIC_BEFS
: /* 0x42465331 local */
311 case S_MAGIC_BDEVFS
: /* 0x62646576 local */
313 case S_MAGIC_BFS
: /* 0x1BADFACE local */
315 case S_MAGIC_BINDERFS
: /* 0x6C6F6F70 local */
317 case S_MAGIC_BPF_FS
: /* 0xCAFE4A11 local */
319 case S_MAGIC_BINFMTFS
: /* 0x42494E4D local */
320 return "binfmt_misc";
321 case S_MAGIC_BTRFS
: /* 0x9123683E local */
323 case S_MAGIC_BTRFS_TEST
: /* 0x73727279 local */
325 case S_MAGIC_CEPH
: /* 0x00C36400 remote */
327 case S_MAGIC_CGROUP
: /* 0x0027E0EB local */
329 case S_MAGIC_CGROUP2
: /* 0x63677270 local */
331 case S_MAGIC_CIFS
: /* 0xFF534D42 remote */
333 case S_MAGIC_CODA
: /* 0x73757245 remote */
335 case S_MAGIC_COH
: /* 0x012FF7B7 local */
337 case S_MAGIC_CONFIGFS
: /* 0x62656570 local */
339 case S_MAGIC_CRAMFS
: /* 0x28CD3D45 local */
341 case S_MAGIC_CRAMFS_WEND
: /* 0x453DCD28 local */
342 return "cramfs-wend";
343 case S_MAGIC_DAXFS
: /* 0x64646178 local */
345 case S_MAGIC_DEBUGFS
: /* 0x64626720 local */
347 case S_MAGIC_DEVFS
: /* 0x1373 local */
349 case S_MAGIC_DEVMEM
: /* 0x454D444D local */
351 case S_MAGIC_DEVPTS
: /* 0x1CD1 local */
353 case S_MAGIC_DMA_BUF
: /* 0x444D4142 local */
355 case S_MAGIC_ECRYPTFS
: /* 0xF15F local */
357 case S_MAGIC_EFIVARFS
: /* 0xDE5E81E4 local */
359 case S_MAGIC_EFS
: /* 0x00414A53 local */
361 case S_MAGIC_EROFS_V1
: /* 0xE0F5E1E2 local */
363 case S_MAGIC_EXFAT
: /* 0x2011BAB0 local */
365 case S_MAGIC_EXFS
: /* 0x45584653 local */
367 case S_MAGIC_EXOFS
: /* 0x5DF5 local */
369 case S_MAGIC_EXT
: /* 0x137D local */
371 case S_MAGIC_EXT2
: /* 0xEF53 local */
373 case S_MAGIC_EXT2_OLD
: /* 0xEF51 local */
375 case S_MAGIC_F2FS
: /* 0xF2F52010 local */
377 case S_MAGIC_FAT
: /* 0x4006 local */
379 case S_MAGIC_FHGFS
: /* 0x19830326 remote */
381 case S_MAGIC_FUSEBLK
: /* 0x65735546 remote */
383 case S_MAGIC_FUSECTL
: /* 0x65735543 remote */
385 case S_MAGIC_FUTEXFS
: /* 0x0BAD1DEA local */
387 case S_MAGIC_GFS
: /* 0x01161970 remote */
389 case S_MAGIC_GPFS
: /* 0x47504653 remote */
391 case S_MAGIC_HFS
: /* 0x4244 local */
393 case S_MAGIC_HFS_PLUS
: /* 0x482B local */
395 case S_MAGIC_HFS_X
: /* 0x4858 local */
397 case S_MAGIC_HOSTFS
: /* 0x00C0FFEE local */
399 case S_MAGIC_HPFS
: /* 0xF995E849 local */
401 case S_MAGIC_HUGETLBFS
: /* 0x958458F6 local */
403 case S_MAGIC_MTD_INODE_FS
: /* 0x11307854 local */
405 case S_MAGIC_IBRIX
: /* 0x013111A8 remote */
407 case S_MAGIC_INOTIFYFS
: /* 0x2BAD1DEA local */
409 case S_MAGIC_ISOFS
: /* 0x9660 local */
411 case S_MAGIC_ISOFS_R_WIN
: /* 0x4004 local */
413 case S_MAGIC_ISOFS_WIN
: /* 0x4000 local */
415 case S_MAGIC_JFFS
: /* 0x07C0 local */
417 case S_MAGIC_JFFS2
: /* 0x72B6 local */
419 case S_MAGIC_JFS
: /* 0x3153464A local */
421 case S_MAGIC_KAFS
: /* 0x6B414653 remote */
423 case S_MAGIC_LOGFS
: /* 0xC97E8168 local */
425 case S_MAGIC_LUSTRE
: /* 0x0BD00BD0 remote */
427 case S_MAGIC_M1FS
: /* 0x5346314D local */
429 case S_MAGIC_MINIX
: /* 0x137F local */
431 case S_MAGIC_MINIX_30
: /* 0x138F local */
432 return "minix (30 char.)";
433 case S_MAGIC_MINIX_V2
: /* 0x2468 local */
435 case S_MAGIC_MINIX_V2_30
: /* 0x2478 local */
436 return "minix v2 (30 char.)";
437 case S_MAGIC_MINIX_V3
: /* 0x4D5A local */
439 case S_MAGIC_MQUEUE
: /* 0x19800202 local */
441 case S_MAGIC_MSDOS
: /* 0x4D44 local */
443 case S_MAGIC_NCP
: /* 0x564C remote */
445 case S_MAGIC_NFS
: /* 0x6969 remote */
447 case S_MAGIC_NFSD
: /* 0x6E667364 remote */
449 case S_MAGIC_NILFS
: /* 0x3434 local */
451 case S_MAGIC_NSFS
: /* 0x6E736673 local */
453 case S_MAGIC_NTFS
: /* 0x5346544E local */
455 case S_MAGIC_OPENPROM
: /* 0x9FA1 local */
457 case S_MAGIC_OCFS2
: /* 0x7461636F remote */
459 case S_MAGIC_OVERLAYFS
: /* 0x794C7630 remote */
460 /* This may overlay remote file systems.
461 Also there have been issues reported with inotify and overlayfs,
462 so mark as "remote" so that polling is used. */
464 case S_MAGIC_PANFS
: /* 0xAAD7AAEA remote */
466 case S_MAGIC_PIPEFS
: /* 0x50495045 remote */
467 /* FIXME: change syntax or add an optional attribute like "inotify:no".
468 pipefs and prlfs are labeled as "remote" so that tail always polls,
469 but these aren't really remote file system types. */
471 case S_MAGIC_PPC_CMM
: /* 0xC7571590 local */
473 case S_MAGIC_PRL_FS
: /* 0x7C7C6673 remote */
475 case S_MAGIC_PROC
: /* 0x9FA0 local */
477 case S_MAGIC_PSTOREFS
: /* 0x6165676C local */
479 case S_MAGIC_QNX4
: /* 0x002F local */
481 case S_MAGIC_QNX6
: /* 0x68191122 local */
483 case S_MAGIC_RAMFS
: /* 0x858458F6 local */
485 case S_MAGIC_RDTGROUP
: /* 0x07655821 local */
487 case S_MAGIC_REISERFS
: /* 0x52654973 local */
489 case S_MAGIC_ROMFS
: /* 0x7275 local */
491 case S_MAGIC_RPC_PIPEFS
: /* 0x67596969 local */
493 case S_MAGIC_SDCARDFS
: /* 0x5DCA2DF5 local */
495 case S_MAGIC_SECRETMEM
: /* 0x5345434D local */
497 case S_MAGIC_SECURITYFS
: /* 0x73636673 local */
499 case S_MAGIC_SELINUX
: /* 0xF97CFF8C local */
501 case S_MAGIC_SMACK
: /* 0x43415D53 local */
503 case S_MAGIC_SMB
: /* 0x517B remote */
505 case S_MAGIC_SMB2
: /* 0xFE534D42 remote */
507 case S_MAGIC_SNFS
: /* 0xBEEFDEAD remote */
509 case S_MAGIC_SOCKFS
: /* 0x534F434B local */
511 case S_MAGIC_SQUASHFS
: /* 0x73717368 local */
513 case S_MAGIC_SYSFS
: /* 0x62656572 local */
515 case S_MAGIC_SYSV2
: /* 0x012FF7B6 local */
517 case S_MAGIC_SYSV4
: /* 0x012FF7B5 local */
519 case S_MAGIC_TMPFS
: /* 0x01021994 local */
521 case S_MAGIC_TRACEFS
: /* 0x74726163 local */
523 case S_MAGIC_UBIFS
: /* 0x24051905 local */
525 case S_MAGIC_UDF
: /* 0x15013346 local */
527 case S_MAGIC_UFS
: /* 0x00011954 local */
529 case S_MAGIC_UFS_BYTESWAPPED
: /* 0x54190100 local */
531 case S_MAGIC_USBDEVFS
: /* 0x9FA2 local */
533 case S_MAGIC_V9FS
: /* 0x01021997 local */
535 case S_MAGIC_VBOXSF
: /* 0x786F4256 remote */
537 case S_MAGIC_VMHGFS
: /* 0xBACBACBC remote */
539 case S_MAGIC_VXFS
: /* 0xA501FCF5 remote */
540 /* Veritas File System can run in single instance or clustered mode,
541 so mark as remote to cater for the latter case. */
543 case S_MAGIC_VZFS
: /* 0x565A4653 local */
545 case S_MAGIC_WSLFS
: /* 0x53464846 local */
547 case S_MAGIC_XENFS
: /* 0xABBA1974 local */
549 case S_MAGIC_XENIX
: /* 0x012FF7B4 local */
551 case S_MAGIC_XFS
: /* 0x58465342 local */
553 case S_MAGIC_XIAFS
: /* 0x012FD16D local */
555 case S_MAGIC_Z3FOLD
: /* 0x0033 local */
557 case S_MAGIC_ZFS
: /* 0x2FC12FC1 local */
559 case S_MAGIC_ZONEFS
: /* 0x5A4F4653 local */
561 case S_MAGIC_ZSMALLOC
: /* 0x58295829 local */
623 unsigned long int type
= statfsbuf
->f_type
;
624 static char buf
[sizeof "UNKNOWN (0x%lx)" - 3
625 + (sizeof type
* CHAR_BIT
+ 3) / 4];
626 sprintf (buf
, "UNKNOWN (0x%lx)", type
);
635 human_access (struct stat
const *statbuf
)
637 static char modebuf
[12];
638 filemodestring (statbuf
, modebuf
);
645 human_time (struct timespec t
)
647 /* STR must be at least INT_BUFSIZE_BOUND (intmax_t) big, either
648 because localtime_rz fails, or because the time zone is truly
649 outlandish so that %z expands to a long string. */
650 static char str
[INT_BUFSIZE_BOUND (intmax_t)
651 + INT_STRLEN_BOUND (int) /* YYYY */
652 + 1 /* because YYYY might equal INT_MAX + 1900 */
653 + sizeof "-MM-DD HH:MM:SS.NNNNNNNNN +"];
654 static timezone_t tz
;
656 tz
= tzalloc (getenv ("TZ"));
659 if (localtime_rz (tz
, &t
.tv_sec
, &tm
))
660 nstrftime (str
, sizeof str
, "%Y-%m-%d %H:%M:%S.%N %z", &tm
, tz
, ns
);
663 char secbuf
[INT_BUFSIZE_BOUND (intmax_t)];
664 sprintf (str
, "%s.%09d", timetostr (t
.tv_sec
, secbuf
), ns
);
669 /* PFORMAT points to a '%' followed by a prefix of a format, all of
670 size PREFIX_LEN. The flags allowed for this format are
671 ALLOWED_FLAGS; remove other printf flags from the prefix, then
674 make_format (char *pformat
, size_t prefix_len
, char const *allowed_flags
,
677 char *dst
= pformat
+ 1;
679 char const *srclim
= pformat
+ prefix_len
;
680 for (src
= dst
; src
< srclim
&& strchr (printf_flags
, *src
); src
++)
681 if (strchr (allowed_flags
, *src
))
685 strcpy (dst
, suffix
);
689 out_string (char *pformat
, size_t prefix_len
, char const *arg
)
691 make_format (pformat
, prefix_len
, "-", "s");
692 printf (pformat
, arg
);
695 out_int (char *pformat
, size_t prefix_len
, intmax_t arg
)
697 make_format (pformat
, prefix_len
, "'-+ 0", "jd");
698 return printf (pformat
, arg
);
701 out_uint (char *pformat
, size_t prefix_len
, uintmax_t arg
)
703 make_format (pformat
, prefix_len
, "'-0", "ju");
704 return printf (pformat
, arg
);
707 out_uint_o (char *pformat
, size_t prefix_len
, uintmax_t arg
)
709 make_format (pformat
, prefix_len
, "-#0", "jo");
710 printf (pformat
, arg
);
713 out_uint_x (char *pformat
, size_t prefix_len
, uintmax_t arg
)
715 make_format (pformat
, prefix_len
, "-#0", "jx");
716 printf (pformat
, arg
);
719 out_minus_zero (char *pformat
, size_t prefix_len
)
721 make_format (pformat
, prefix_len
, "'-+ 0", ".0f");
722 return printf (pformat
, -0.25);
725 /* Output the number of seconds since the Epoch, using a format that
726 acts like printf's %f format. */
728 out_epoch_sec (char *pformat
, size_t prefix_len
,
731 char *dot
= memchr (pformat
, '.', prefix_len
);
732 size_t sec_prefix_len
= prefix_len
;
735 bool frac_left_adjust
= false;
739 sec_prefix_len
= dot
- pformat
;
740 pformat
[prefix_len
] = '\0';
742 if (ISDIGIT (dot
[1]))
744 long int lprec
= strtol (dot
+ 1, nullptr, 10);
745 precision
= (lprec
<= INT_MAX
? lprec
: INT_MAX
);
752 if (precision
&& ISDIGIT (dot
[-1]))
754 /* If a nontrivial width is given, subtract the width of the
755 decimal point and PRECISION digits that will be output
762 while (ISDIGIT (p
[-1]));
764 long int lwidth
= strtol (p
, nullptr, 10);
765 width
= (lwidth
<= INT_MAX
? lwidth
: INT_MAX
);
769 sec_prefix_len
= p
- pformat
;
770 int w_d
= (decimal_point_len
< width
771 ? width
- decimal_point_len
775 int w
= w_d
- precision
;
779 for (char const *src
= dst
; src
< p
; src
++)
782 frac_left_adjust
= true;
788 + (frac_left_adjust
? 0 : sprintf (dst
, "%d", w
)));
796 for (int i
= precision
; i
< 9; i
++)
798 int frac_sec
= arg
.tv_nsec
/ divisor
;
801 if (TYPE_SIGNED (time_t))
803 bool minus_zero
= false;
804 if (arg
.tv_sec
< 0 && arg
.tv_nsec
!= 0)
806 int frac_sec_modulus
= 1000000000 / divisor
;
807 frac_sec
= (frac_sec_modulus
- frac_sec
808 - (arg
.tv_nsec
% divisor
!= 0));
809 arg
.tv_sec
+= (frac_sec
!= 0);
810 minus_zero
= (arg
.tv_sec
== 0);
812 int_len
= (minus_zero
813 ? out_minus_zero (pformat
, sec_prefix_len
)
814 : out_int (pformat
, sec_prefix_len
, arg
.tv_sec
));
817 int_len
= out_uint (pformat
, sec_prefix_len
, arg
.tv_sec
);
821 int prec
= (precision
< 9 ? precision
: 9);
822 int trailing_prec
= precision
- prec
;
823 int ilen
= (int_len
< 0 ? 0 : int_len
);
824 int trailing_width
= (ilen
< width
&& decimal_point_len
< width
- ilen
825 ? width
- ilen
- decimal_point_len
- prec
827 printf ("%s%.*d%-*.*d", decimal_point
, prec
, frac_sec
,
828 trailing_width
, trailing_prec
, 0);
832 /* Print the context information of FILENAME, and return true iff the
833 context could not be obtained. */
836 out_file_context (char *pformat
, size_t prefix_len
, char const *filename
)
842 ? getfilecon (filename
, &scontext
)
843 : lgetfilecon (filename
, &scontext
)) < 0)
845 error (0, errno
, _("failed to get security context of %s"),
850 strcpy (pformat
+ prefix_len
, "s");
851 printf (pformat
, (scontext
? scontext
: "?"));
857 /* Print statfs info. Return zero upon success, nonzero upon failure. */
860 print_statfs (char *pformat
, size_t prefix_len
, MAYBE_UNUSED
char mod
, char m
,
861 int fd
, char const *filename
,
864 STRUCT_STATVFS
const *statfsbuf
= data
;
870 out_string (pformat
, prefix_len
, filename
);
875 #if STRUCT_STATXFS_F_FSID_IS_INTEGER
876 uintmax_t fsid
= statfsbuf
->f_fsid
;
878 typedef unsigned int fsid_word
;
879 static_assert (alignof (STRUCT_STATVFS
) % alignof (fsid_word
) == 0);
880 static_assert (offsetof (STRUCT_STATVFS
, f_fsid
) % alignof (fsid_word
)
882 static_assert (sizeof statfsbuf
->f_fsid
% alignof (fsid_word
) == 0);
883 fsid_word
const *p
= (fsid_word
*) &statfsbuf
->f_fsid
;
885 /* Assume a little-endian word order, as that is compatible
886 with glibc's statvfs implementation. */
888 int words
= sizeof statfsbuf
->f_fsid
/ sizeof *p
;
889 for (int i
= 0; i
< words
&& i
* sizeof *p
< sizeof fsid
; i
++)
891 uintmax_t u
= p
[words
- 1 - i
];
892 fsid
|= u
<< (i
* CHAR_BIT
* sizeof *p
);
895 out_uint_x (pformat
, prefix_len
, fsid
);
900 OUT_NAMEMAX (pformat
, prefix_len
, SB_F_NAMEMAX (statfsbuf
));
903 #if HAVE_STRUCT_STATXFS_F_TYPE
904 out_uint_x (pformat
, prefix_len
, statfsbuf
->f_type
);
910 out_string (pformat
, prefix_len
, human_fstype (statfsbuf
));
913 out_int (pformat
, prefix_len
, statfsbuf
->f_blocks
);
916 out_int (pformat
, prefix_len
, statfsbuf
->f_bfree
);
919 out_int (pformat
, prefix_len
, statfsbuf
->f_bavail
);
922 out_uint (pformat
, prefix_len
, statfsbuf
->f_bsize
);
926 uintmax_t frsize
= STATFS_FRSIZE (statfsbuf
);
928 frsize
= statfsbuf
->f_bsize
;
929 out_uint (pformat
, prefix_len
, frsize
);
933 out_uint (pformat
, prefix_len
, statfsbuf
->f_files
);
936 out_int (pformat
, prefix_len
, statfsbuf
->f_ffree
);
945 /* Return any bind mounted source for a path.
946 The caller should not free the returned buffer.
947 Return nullptr if no bind mount found. */
950 find_bind_mount (char const * name
)
952 char const * bind_mount
= nullptr;
954 static struct mount_entry
*mount_list
;
955 static bool tried_mount_list
= false;
956 if (!tried_mount_list
) /* attempt/warn once per process. */
958 if (!(mount_list
= read_file_system_list (false)))
959 error (0, errno
, "%s", _("cannot read table of mounted file systems"));
960 tried_mount_list
= true;
963 struct stat name_stats
;
964 if (stat (name
, &name_stats
) != 0)
967 struct mount_entry
*me
;
968 for (me
= mount_list
; me
; me
= me
->me_next
)
970 if (me
->me_dummy
&& me
->me_devname
[0] == '/'
971 && STREQ (me
->me_mountdir
, name
))
973 struct stat dev_stats
;
975 if (stat (me
->me_devname
, &dev_stats
) == 0
976 && psame_inode (&name_stats
, &dev_stats
))
978 bind_mount
= me
->me_devname
;
987 /* Print mount point. Return zero upon success, nonzero upon failure. */
990 out_mount_point (char const *filename
, char *pformat
, size_t prefix_len
,
991 const struct stat
*statp
)
994 char const *np
= "?", *bp
= nullptr;
998 /* Look for bind mounts first. Note we output the immediate alias,
999 rather than further resolving to a base device mount point. */
1000 if (follow_links
|| !S_ISLNK (statp
->st_mode
))
1002 char *resolved
= canonicalize_file_name (filename
);
1005 error (0, errno
, _("failed to canonicalize %s"), quoteaf (filename
));
1006 goto print_mount_point
;
1008 bp
= find_bind_mount (resolved
);
1013 goto print_mount_point
;
1017 /* If there is no direct bind mount, then navigate
1018 back up the tree looking for a device change.
1019 Note we don't detect if any of the directory components
1020 are bind mounted to the same device, but that's OK
1021 since we've not directly queried them. */
1022 if ((mp
= find_mount_point (filename
, statp
)))
1024 /* This dir might be bind mounted to another device,
1025 so we resolve the bound source in that case also. */
1026 bp
= find_bind_mount (mp
);
1032 out_string (pformat
, prefix_len
, bp
? bp
: mp
? mp
: np
);
1037 /* Map a TS with negative TS.tv_nsec to {0,0}. */
1038 static inline struct timespec
1039 neg_to_zero (struct timespec ts
)
1041 if (0 <= ts
.tv_nsec
)
1043 struct timespec z
= {0};
1047 /* Set the quoting style default if the environment variable
1048 QUOTING_STYLE is set. */
1051 getenv_quoting_style (void)
1053 char const *q_style
= getenv ("QUOTING_STYLE");
1056 int i
= ARGMATCH (q_style
, quoting_style_args
, quoting_style_vals
);
1058 set_quoting_style (nullptr, quoting_style_vals
[i
]);
1061 set_quoting_style (nullptr, shell_escape_always_quoting_style
);
1062 error (0, 0, _("ignoring invalid value of environment "
1063 "variable QUOTING_STYLE: %s"), quote (q_style
));
1067 set_quoting_style (nullptr, shell_escape_always_quoting_style
);
1070 /* Equivalent to quotearg(), but explicit to avoid syntax checks. */
1071 #define quoteN(x) quotearg_style (get_quoting_style (nullptr), x)
1073 /* Output a single-character \ escape. */
1076 print_esc_char (char c
)
1080 case 'a': /* Alert. */
1083 case 'b': /* Backspace. */
1086 case 'e': /* Escape. */
1089 case 'f': /* Form feed. */
1092 case 'n': /* New line. */
1095 case 'r': /* Carriage return. */
1098 case 't': /* Horizontal tab. */
1101 case 'v': /* Vertical tab. */
1108 error (0, 0, _("warning: unrecognized escape '\\%c'"), c
);
1116 format_code_offset (char const *directive
)
1118 size_t len
= strspn (directive
+ 1, printf_flags
);
1119 char const *fmt_char
= directive
+ len
+ 1;
1120 fmt_char
+= strspn (fmt_char
, digits
);
1121 if (*fmt_char
== '.')
1122 fmt_char
+= 1 + strspn (fmt_char
+ 1, digits
);
1123 return fmt_char
- directive
;
1126 /* Print the information specified by the format string, FORMAT,
1127 calling PRINT_FUNC for each %-directive encountered.
1128 Return zero upon success, nonzero upon failure. */
1131 print_it (char const *format
, int fd
, char const *filename
,
1132 bool (*print_func
) (char *, size_t, char, char,
1133 int, char const *, void const *),
1138 /* Add 2 to accommodate our conversion of the stat '%s' format string
1139 to the longer printf '%llu' one. */
1142 MAX_ADDITIONAL_BYTES
=
1144 MAX (sizeof "jo", MAX (sizeof "ju", sizeof "jx")))
1147 size_t n_alloc
= strlen (format
) + MAX_ADDITIONAL_BYTES
+ 1;
1148 char *dest
= xmalloc (n_alloc
);
1150 for (b
= format
; *b
; b
++)
1156 size_t len
= format_code_offset (b
);
1157 char fmt_char
= *(b
+ len
);
1159 memcpy (dest
, b
, len
);
1170 dest
[len
] = fmt_char
;
1171 dest
[len
+ 1] = '\0';
1172 error (EXIT_FAILURE
, 0, _("%s: invalid directive"),
1179 mod_char
= fmt_char
;
1180 fmt_char
= *(b
+ 1);
1181 if (print_func
== print_stat
1182 && (fmt_char
== 'd' || fmt_char
== 'r'))
1188 fmt_char
= mod_char
;
1193 fail
|= print_func (dest
, len
, mod_char
, fmt_char
,
1194 fd
, filename
, data
);
1201 if ( ! interpret_backslash_escapes
)
1209 int esc_value
= octtobin (*b
);
1210 int esc_length
= 1; /* number of octal digits */
1211 for (++b
; esc_length
< 3 && isodigit (*b
);
1214 esc_value
= esc_value
* 8 + octtobin (*b
);
1216 putchar (esc_value
);
1219 else if (*b
== 'x' && c_isxdigit (to_uchar (b
[1])))
1221 int esc_value
= hextobin (b
[1]); /* Value of \xhh escape. */
1222 /* A hexadecimal \xhh escape sequence must have
1223 1 or 2 hex. digits. */
1225 if (c_isxdigit (to_uchar (b
[1])))
1228 esc_value
= esc_value
* 16 + hextobin (*b
);
1230 putchar (esc_value
);
1232 else if (*b
== '\0')
1234 error (0, 0, _("warning: backslash at end of format"));
1236 /* Arrange to exit the loop. */
1241 print_esc_char (*b
);
1252 fputs (trailing_delim
, stdout
);
1257 /* Stat the file system and print what we find. */
1260 do_statfs (char const *filename
, char const *format
)
1262 STRUCT_STATVFS statfsbuf
;
1264 if (STREQ (filename
, "-"))
1266 error (0, 0, _("using %s to denote standard input does not work"
1267 " in file system mode"), quoteaf (filename
));
1271 if (STATFS (filename
, &statfsbuf
) != 0)
1273 error (0, errno
, _("cannot read file system information for %s"),
1274 quoteaf (filename
));
1278 bool fail
= print_it (format
, -1, filename
, print_statfs
, &statfsbuf
);
1284 struct timespec btime
;
1287 /* Ask statx to avoid syncing? */
1288 static bool dont_sync
;
1290 /* Ask statx to force sync? */
1291 static bool force_sync
;
1295 fmt_to_mask (char fmt
)
1310 return STATX_MODE
|STATX_TYPE
;
1322 return STATX_MODE
|STATX_INO
;
1329 return STATX_BLOCKS
;
1348 format_to_mask (char const *format
)
1350 unsigned int mask
= 0;
1353 for (b
= format
; *b
; b
++)
1358 b
+= format_code_offset (b
);
1361 mask
|= fmt_to_mask (*b
);
1366 /* statx the file and print what we find */
1369 do_stat (char const *filename
, char const *format
, char const *format2
)
1371 int fd
= STREQ (filename
, "-") ? 0 : AT_FDCWD
;
1374 struct statx stx
= {0};
1375 char const *pathname
= filename
;
1376 struct print_args pa
;
1378 pa
.btime
= (struct timespec
) {.tv_sec
= -1, .tv_nsec
= -1};
1383 flags
= AT_EMPTY_PATH
;
1385 else if (!follow_links
)
1387 flags
= AT_SYMLINK_NOFOLLOW
;
1391 flags
|= AT_STATX_DONT_SYNC
;
1392 else if (force_sync
)
1393 flags
|= AT_STATX_FORCE_SYNC
;
1396 flags
|= AT_NO_AUTOMOUNT
;
1398 fd
= statx (fd
, pathname
, flags
, format_to_mask (format
), &stx
);
1401 if (flags
& AT_EMPTY_PATH
)
1402 error (0, errno
, _("cannot stat standard input"));
1404 error (0, errno
, _("cannot statx %s"), quoteaf (filename
));
1408 if (S_ISBLK (stx
.stx_mode
) || S_ISCHR (stx
.stx_mode
))
1411 statx_to_stat (&stx
, &st
);
1412 if (stx
.stx_mask
& STATX_BTIME
)
1413 pa
.btime
= statx_timestamp_to_timespec (stx
.stx_btime
);
1415 bool fail
= print_it (format
, fd
, filename
, print_stat
, &pa
);
1419 #else /* USE_STATX */
1421 static struct timespec
1422 get_birthtime (int fd
, char const *filename
, struct stat
const *st
)
1424 struct timespec ts
= get_stat_birthtime (st
);
1431 ? getattrat (AT_FDCWD
, XATTR_VIEW_READWRITE
, filename
, &response
)
1432 : fgetattr (fd
, XATTR_VIEW_READWRITE
, &response
))
1437 if (nvlist_lookup_uint64_array (response
, A_CRTIME
, &val
, &n
) == 0
1439 && val
[0] <= TYPE_MAXIMUM (time_t)
1440 && val
[1] < 1000000000 * 2 /* for leap seconds */)
1443 ts
.tv_nsec
= val
[1];
1445 nvlist_free (response
);
1454 /* stat the file and print what we find */
1457 do_stat (char const *filename
, char const *format
,
1458 char const *format2
)
1460 int fd
= STREQ (filename
, "-") ? 0 : -1;
1461 struct stat statbuf
;
1462 struct print_args pa
;
1464 pa
.btime
= (struct timespec
) {.tv_sec
= -1, .tv_nsec
= -1};
1468 if (fstat (fd
, &statbuf
) != 0)
1470 error (0, errno
, _("cannot stat standard input"));
1474 /* We can't use the shorter
1475 (follow_links?stat:lstat) (filename, &statbug)
1476 since stat might be a function-like macro. */
1477 else if ((follow_links
1478 ? stat (filename
, &statbuf
)
1479 : lstat (filename
, &statbuf
)) != 0)
1481 error (0, errno
, _("cannot stat %s"), quoteaf (filename
));
1485 if (S_ISBLK (statbuf
.st_mode
) || S_ISCHR (statbuf
.st_mode
))
1488 bool fail
= print_it (format
, fd
, filename
, print_stat
, &pa
);
1491 #endif /* USE_STATX */
1493 /* POSIX requires 'ls' to print file sizes without a sign, even
1494 when negative. Be consistent with that. */
1497 unsigned_file_size (off_t size
)
1499 return size
+ (size
< 0) * ((uintmax_t) OFF_T_MAX
- OFF_T_MIN
+ 1);
1502 /* Print stat info. Return zero upon success, nonzero upon failure. */
1504 print_stat (char *pformat
, size_t prefix_len
, char mod
, char m
,
1505 int fd
, char const *filename
, void const *data
)
1507 struct print_args
*parg
= (struct print_args
*) data
;
1508 struct stat
*statbuf
= parg
->st
;
1509 struct timespec btime
= parg
->btime
;
1510 struct passwd
*pw_ent
;
1511 struct group
*gw_ent
;
1517 out_string (pformat
, prefix_len
, filename
);
1520 out_string (pformat
, prefix_len
, quoteN (filename
));
1521 if (S_ISLNK (statbuf
->st_mode
))
1523 char *linkname
= areadlink_with_size (filename
, statbuf
->st_size
);
1524 if (linkname
== nullptr)
1526 error (0, errno
, _("cannot read symbolic link %s"),
1527 quoteaf (filename
));
1531 out_string (pformat
, prefix_len
, quoteN (linkname
));
1537 out_uint (pformat
, prefix_len
, major (statbuf
->st_dev
));
1538 else if (mod
== 'L')
1539 out_uint (pformat
, prefix_len
, minor (statbuf
->st_dev
));
1541 out_uint (pformat
, prefix_len
, statbuf
->st_dev
);
1544 out_uint_x (pformat
, prefix_len
, statbuf
->st_dev
);
1547 out_uint (pformat
, prefix_len
, statbuf
->st_ino
);
1550 out_uint_o (pformat
, prefix_len
, statbuf
->st_mode
& CHMOD_MODE_BITS
);
1553 out_string (pformat
, prefix_len
, human_access (statbuf
));
1556 out_uint_x (pformat
, prefix_len
, statbuf
->st_mode
);
1559 out_string (pformat
, prefix_len
, file_type (statbuf
));
1562 out_uint (pformat
, prefix_len
, statbuf
->st_nlink
);
1565 out_uint (pformat
, prefix_len
, statbuf
->st_uid
);
1568 pw_ent
= getpwuid (statbuf
->st_uid
);
1569 out_string (pformat
, prefix_len
,
1570 pw_ent
? pw_ent
->pw_name
: "UNKNOWN");
1573 out_uint (pformat
, prefix_len
, statbuf
->st_gid
);
1576 gw_ent
= getgrgid (statbuf
->st_gid
);
1577 out_string (pformat
, prefix_len
,
1578 gw_ent
? gw_ent
->gr_name
: "UNKNOWN");
1581 fail
|= out_mount_point (filename
, pformat
, prefix_len
, statbuf
);
1584 out_uint (pformat
, prefix_len
, unsigned_file_size (statbuf
->st_size
));
1588 out_uint (pformat
, prefix_len
, major (statbuf
->st_rdev
));
1589 else if (mod
== 'L')
1590 out_uint (pformat
, prefix_len
, minor (statbuf
->st_rdev
));
1592 out_uint (pformat
, prefix_len
, statbuf
->st_rdev
);
1595 out_uint_x (pformat
, prefix_len
, statbuf
->st_rdev
);
1598 out_uint_x (pformat
, prefix_len
, major (statbuf
->st_rdev
));
1601 out_uint_x (pformat
, prefix_len
, minor (statbuf
->st_rdev
));
1604 out_uint (pformat
, prefix_len
, ST_NBLOCKSIZE
);
1607 out_uint (pformat
, prefix_len
, STP_NBLOCKS (statbuf
));
1610 out_uint (pformat
, prefix_len
, STP_BLKSIZE (statbuf
));
1615 btime
= get_birthtime (fd
, filename
, statbuf
);
1617 if (btime
.tv_nsec
< 0)
1618 out_string (pformat
, prefix_len
, "-");
1620 out_string (pformat
, prefix_len
, human_time (btime
));
1626 btime
= get_birthtime (fd
, filename
, statbuf
);
1628 out_epoch_sec (pformat
, prefix_len
, neg_to_zero (btime
));
1632 out_string (pformat
, prefix_len
, human_time (get_stat_atime (statbuf
)));
1635 out_epoch_sec (pformat
, prefix_len
, get_stat_atime (statbuf
));
1638 out_string (pformat
, prefix_len
, human_time (get_stat_mtime (statbuf
)));
1641 out_epoch_sec (pformat
, prefix_len
, get_stat_mtime (statbuf
));
1644 out_string (pformat
, prefix_len
, human_time (get_stat_ctime (statbuf
)));
1647 out_epoch_sec (pformat
, prefix_len
, get_stat_ctime (statbuf
));
1650 fail
|= out_file_context (pformat
, prefix_len
, filename
);
1653 fputc ('?', stdout
);
1659 /* Return an allocated format string in static storage that
1660 corresponds to whether FS and TERSE options were declared. */
1662 default_format (bool fs
, bool terse
, bool device
)
1668 format
= xstrdup (fmt_terse_fs
);
1671 /* TRANSLATORS: This string uses format specifiers from
1672 'stat --help' with --file-system, and NOT from printf. */
1673 format
= xstrdup (_(" File: \"%n\"\n"
1674 " ID: %-8i Namelen: %-7l Type: %T\n"
1675 "Block size: %-10s Fundamental block size: %S\n"
1676 "Blocks: Total: %-10b Free: %-10f Available: %a\n"
1677 "Inodes: Total: %-10c Free: %d\n"));
1684 if (0 < is_selinux_enabled ())
1685 format
= xstrdup (fmt_terse_selinux
);
1687 format
= xstrdup (fmt_terse_regular
);
1692 /* TRANSLATORS: This string uses format specifiers from
1693 'stat --help' without --file-system, and NOT from printf. */
1694 format
= xstrdup (_("\
1696 Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n\
1702 /* TRANSLATORS: This string uses format specifiers from
1703 'stat --help' without --file-system, and NOT from printf. */
1704 format
= xasprintf ("%s%s", format
, _("\
1705 " "Device: %Hd,%Ld\tInode: %-10i Links: %-5h Device type: %Hr,%Lr\n\
1710 /* TRANSLATORS: This string uses format specifiers from
1711 'stat --help' without --file-system, and NOT from printf. */
1712 format
= xasprintf ("%s%s", format
, _("\
1713 " "Device: %Hd,%Ld\tInode: %-10i Links: %h\n\
1719 /* TRANSLATORS: This string uses format specifiers from
1720 'stat --help' without --file-system, and NOT from printf. */
1721 format
= xasprintf ("%s%s", format
, _("\
1722 " "Access: (%04a/%10.10A) Uid: (%5u/%8U) Gid: (%5g/%8G)\n\
1726 if (0 < is_selinux_enabled ())
1729 /* TRANSLATORS: This string uses format specifiers from
1730 'stat --help' without --file-system, and NOT from printf. */
1731 format
= xasprintf ("%s%s", format
, _("Context: %C\n"));
1736 /* TRANSLATORS: This string uses format specifiers from
1737 'stat --help' without --file-system, and NOT from printf. */
1738 format
= xasprintf ("%s%s", format
,
1752 if (status
!= EXIT_SUCCESS
)
1756 printf (_("Usage: %s [OPTION]... FILE...\n"), program_name
);
1758 Display file or file system status.\n\
1761 emit_mandatory_arg_note ();
1764 -L, --dereference follow links\n\
1765 -f, --file-system display file system status instead of file status\n\
1768 --cached=MODE specify how to use cached attributes;\n\
1769 useful on remote file systems. See MODE below\n\
1772 -c --format=FORMAT use the specified FORMAT instead of the default;\n\
1773 output a newline after each use of FORMAT\n\
1774 --printf=FORMAT like --format, but interpret backslash escapes,\n\
1775 and do not output a mandatory trailing newline;\n\
1776 if you want a newline, include \\n in FORMAT\n\
1777 -t, --terse print the information in terse form\n\
1779 fputs (HELP_OPTION_DESCRIPTION
, stdout
);
1780 fputs (VERSION_OPTION_DESCRIPTION
, stdout
);
1783 The MODE argument of --cached can be: always, never, or default.\n\
1784 'always' will use cached attributes if available, while\n\
1785 'never' will try to synchronize with the latest attributes, and\n\
1786 'default' will leave it up to the underlying file system.\n\
1790 The valid format sequences for files (without --file-system):\n\
1792 %a permission bits in octal (note '#' and '0' printf flags)\n\
1793 %A permission bits and file type in human readable form\n\
1794 %b number of blocks allocated (see %B)\n\
1795 %B the size in bytes of each block reported by %b\n\
1796 %C SELinux security context string\n\
1799 %d device number in decimal (st_dev)\n\
1800 %D device number in hex (st_dev)\n\
1801 %Hd major device number in decimal\n\
1802 %Ld minor device number in decimal\n\
1803 %f raw mode in hex\n\
1805 %g group ID of owner\n\
1806 %G group name of owner\n\
1809 %h number of hard links\n\
1813 %N quoted file name with dereference if symbolic link\n\
1814 %o optimal I/O transfer size hint\n\
1815 %s total size, in bytes\n\
1816 %r device type in decimal (st_rdev)\n\
1817 %R device type in hex (st_rdev)\n\
1818 %Hr major device type in decimal, for character/block device special files\n\
1819 %Lr minor device type in decimal, for character/block device special files\n\
1820 %t major device type in hex, for character/block device special files\n\
1821 %T minor device type in hex, for character/block device special files\n\
1824 %u user ID of owner\n\
1825 %U user name of owner\n\
1826 %w time of file birth, human-readable; - if unknown\n\
1827 %W time of file birth, seconds since Epoch; 0 if unknown\n\
1828 %x time of last access, human-readable\n\
1829 %X time of last access, seconds since Epoch\n\
1830 %y time of last data modification, human-readable\n\
1831 %Y time of last data modification, seconds since Epoch\n\
1832 %z time of last status change, human-readable\n\
1833 %Z time of last status change, seconds since Epoch\n\
1838 Valid format sequences for file systems:\n\
1840 %a free blocks available to non-superuser\n\
1841 %b total data blocks in file system\n\
1842 %c total file nodes in file system\n\
1843 %d free file nodes in file system\n\
1844 %f free blocks in file system\n\
1847 %i file system ID in hex\n\
1848 %l maximum length of filenames\n\
1850 %s block size (for faster transfers)\n\
1851 %S fundamental block size (for block counts)\n\
1852 %t file system type in hex\n\
1853 %T file system type in human readable form\n\
1857 --terse is equivalent to the following FORMAT:\n\
1860 #if HAVE_SELINUX_SELINUX_H
1868 --terse --file-system is equivalent to the following FORMAT:\n\
1872 printf (USAGE_BUILTIN_WARNING
, PROGRAM_NAME
);
1873 emit_ancillary_info (PROGRAM_NAME
);
1879 main (int argc
, char *argv
[])
1884 char *format
= nullptr;
1888 initialize_main (&argc
, &argv
);
1889 set_program_name (argv
[0]);
1890 setlocale (LC_ALL
, "");
1891 bindtextdomain (PACKAGE
, LOCALEDIR
);
1892 textdomain (PACKAGE
);
1894 struct lconv
const *locale
= localeconv ();
1895 decimal_point
= (locale
->decimal_point
[0] ? locale
->decimal_point
: ".");
1896 decimal_point_len
= strlen (decimal_point
);
1898 atexit (close_stdout
);
1900 while ((c
= getopt_long (argc
, argv
, "c:fLt", long_options
, nullptr)) != -1)
1906 interpret_backslash_escapes
= true;
1907 trailing_delim
= "";
1912 interpret_backslash_escapes
= false;
1913 trailing_delim
= "\n";
1917 follow_links
= true;
1929 switch (XARGMATCH ("--cached", optarg
, cached_args
, cached_modes
))
1939 case cached_default
:
1945 case_GETOPT_HELP_CHAR
;
1947 case_GETOPT_VERSION_CHAR (PROGRAM_NAME
, AUTHORS
);
1950 usage (EXIT_FAILURE
);
1956 error (0, 0, _("missing operand"));
1957 usage (EXIT_FAILURE
);
1962 if (strstr (format
, "%N"))
1963 getenv_quoting_style ();
1968 format
= default_format (fs
, terse
, /* device= */ false);
1969 format2
= default_format (fs
, terse
, /* device= */ true);
1972 for (int i
= optind
; i
< argc
; i
++)
1974 ? do_statfs (argv
[i
], format
)
1975 : do_stat (argv
[i
], format
, format2
));
1977 main_exit (ok
? EXIT_SUCCESS
: EXIT_FAILURE
);