1 /* stat.c -- display file or file system status
2 Copyright (C) 2001-2024 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>
60 #include "areadlink.h"
63 #include "file-type.h"
66 #include "mountlist.h"
67 #include "octhexdigits.h"
69 #include "stat-size.h"
70 #include "stat-time.h"
72 #include "find-mount-point.h"
73 #include "xvasprintf.h"
76 #if HAVE_STATX && defined STATX_INO
83 # define STRUCT_STATXFS_F_FSID_IS_INTEGER STRUCT_STATVFS_F_FSID_IS_INTEGER
84 # define HAVE_STRUCT_STATXFS_F_TYPE HAVE_STRUCT_STATVFS_F_TYPE
85 # if HAVE_STRUCT_STATVFS_F_NAMEMAX
86 # define SB_F_NAMEMAX(S) ((S)->f_namemax)
88 # if ! STAT_STATVFS && STAT_STATVFS64
89 # define STRUCT_STATVFS struct statvfs64
90 # define STATFS statvfs64
92 # define STRUCT_STATVFS struct statvfs
93 # define STATFS statvfs
95 # define STATFS_FRSIZE(S) ((S)->f_frsize)
97 # define HAVE_STRUCT_STATXFS_F_TYPE HAVE_STRUCT_STATFS_F_TYPE
98 # if HAVE_STRUCT_STATFS_F_NAMELEN
99 # define SB_F_NAMEMAX(S) ((S)->f_namelen)
100 # elif HAVE_STRUCT_STATFS_F_NAMEMAX
101 # define SB_F_NAMEMAX(S) ((S)->f_namemax)
103 # define STATFS statfs
104 # if HAVE_OS_H /* BeOS */
105 /* BeOS has a statvfs function, but it does not return sensible values
106 for f_files, f_ffree and f_favail, and lacks f_type, f_basetype and
107 f_fstypename. Use 'struct fs_info' instead. */
110 statfs (char const *filename
, struct fs_info
*buf
)
112 dev_t device
= dev_for_path (filename
);
115 errno
= (device
== B_ENTRY_NOT_FOUND
? ENOENT
116 : device
== B_BAD_VALUE
? EINVAL
117 : device
== B_NAME_TOO_LONG
? ENAMETOOLONG
118 : device
== B_NO_MEMORY
? ENOMEM
119 : device
== B_FILE_ERROR
? EIO
123 /* If successful, buf->dev will be == device. */
124 return fs_stat_dev (device
, buf
);
127 # define f_blocks total_blocks
128 # define f_bfree free_blocks
129 # define f_bavail free_blocks
130 # define f_bsize io_size
131 # define f_files total_nodes
132 # define f_ffree free_nodes
133 # define STRUCT_STATVFS struct fs_info
134 # define STRUCT_STATXFS_F_FSID_IS_INTEGER true
135 # define STATFS_FRSIZE(S) ((S)->block_size)
137 # define STRUCT_STATVFS struct statfs
138 # define STRUCT_STATXFS_F_FSID_IS_INTEGER STRUCT_STATFS_F_FSID_IS_INTEGER
139 # if HAVE_STRUCT_STATFS_F_FRSIZE
140 # define STATFS_FRSIZE(S) ((S)->f_frsize)
142 # define STATFS_FRSIZE(S) 0
148 # define OUT_NAMEMAX out_uint
150 /* Depending on whether statvfs or statfs is used,
151 neither f_namemax or f_namelen may be available. */
152 # define SB_F_NAMEMAX(S) "?"
153 # define OUT_NAMEMAX out_string
156 #if HAVE_STRUCT_STATVFS_F_BASETYPE
157 # define STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME f_basetype
159 # if HAVE_STRUCT_STATVFS_F_FSTYPENAME || HAVE_STRUCT_STATFS_F_FSTYPENAME
160 # define STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME f_fstypename
161 # elif HAVE_OS_H /* BeOS */
162 # define STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME fsh_name
168 # include <sys/nvpair.h>
171 static char const digits
[] = "0123456789";
173 /* Flags that are portable for use in printf, for at least one
174 conversion specifier; make_format removes non-portable flags as
175 needed for particular specifiers. The glibc 2.2 extension "I" is
176 listed here; it is removed by make_format because it has undefined
177 behavior elsewhere and because it is incompatible with
179 static char const printf_flags
[] = "'-+ #0I";
181 /* Formats for the --terse option. */
182 static char const fmt_terse_fs
[] = "%n %i %l %t %s %S %b %f %a %c %d\n";
183 static char const fmt_terse_regular
[] = "%n %s %b %f %u %g %D %i %h %t %T"
185 static char const fmt_terse_selinux
[] = "%n %s %b %f %u %g %D %i %h %t %T"
186 " %X %Y %Z %W %o %C\n";
188 #define PROGRAM_NAME "stat"
190 #define AUTHORS proper_name ("Michael Meskes")
194 PRINTF_OPTION
= CHAR_MAX
+ 1
204 static char const *const cached_args
[] =
206 "default", "never", "always", nullptr
209 static enum cached_mode
const cached_modes
[] =
211 cached_default
, cached_never
, cached_always
214 static struct option
const long_options
[] =
216 {"dereference", no_argument
, nullptr, 'L'},
217 {"file-system", no_argument
, nullptr, 'f'},
218 {"format", required_argument
, nullptr, 'c'},
219 {"printf", required_argument
, nullptr, PRINTF_OPTION
},
220 {"terse", no_argument
, nullptr, 't'},
221 {"cached", required_argument
, nullptr, 0},
222 {GETOPT_HELP_OPTION_DECL
},
223 {GETOPT_VERSION_OPTION_DECL
},
224 {nullptr, 0, nullptr, 0}
227 /* Whether to follow symbolic links; True for --dereference (-L). */
228 static bool follow_links
;
230 /* Whether to interpret backslash-escape sequences.
231 True for --printf=FMT, not for --format=FMT (-c). */
232 static bool interpret_backslash_escapes
;
234 /* The trailing delimiter string:
235 "" for --printf=FMT, "\n" for --format=FMT (-c). */
236 static char const *trailing_delim
= "";
238 /* The representation of the decimal point in the current locale. */
239 static char const *decimal_point
;
240 static size_t decimal_point_len
;
243 print_stat (char *pformat
, size_t prefix_len
, char mod
, char m
,
244 int fd
, char const *filename
, void const *data
);
246 /* Return the type of the specified file system.
247 Some systems have statfvs.f_basetype[FSTYPSZ] (AIX, HP-UX, and Solaris).
248 Others have statvfs.f_fstypename[_VFS_NAMELEN] (NetBSD 3.0).
249 Others have statfs.f_fstypename[MFSNAMELEN] (NetBSD 1.5.2).
250 Still others have neither and have to get by with f_type (GNU/Linux).
251 But f_type may only exist in statfs (Cygwin). */
254 human_fstype (STRUCT_STATVFS
const *statfsbuf
)
256 #ifdef STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME
257 return statfsbuf
->STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME
;
259 switch (statfsbuf
->f_type
)
261 # if defined __linux__ || defined __ANDROID__
263 /* Compare with what's in libc:
264 f=/a/libc/sysdeps/unix/sysv/linux/linux_fsinfo.h
265 sed -n '/ADFS_SUPER_MAGIC/,/SYSFS_MAGIC/p' $f \
266 | perl -n -e '/#define (.*?)_(?:SUPER_)MAGIC\s+0x(\S+)/' \
267 -e 'and print "case S_MAGIC_$1: /\* 0x" . uc($2) . " *\/\n"' \
269 perl -ne '/^\s+(case S_MAGIC_.*?): \/\* 0x(\S+) \*\//' \
270 -e 'and do { $v=uc$2; print "$1: /\* 0x$v *\/\n"}' stat.c \
272 diff -u sym_stat sym_libc
275 /* Also compare with the list in "man 2 statfs" using the
276 fs-magic-compare make target. */
278 /* IMPORTANT NOTE: Each of the following 'case S_MAGIC_...:'
279 statements must be followed by a hexadecimal constant in
280 a comment. The S_MAGIC_... name and constant are automatically
281 combined to produce the #define directives in fs.h. */
283 case S_MAGIC_AAFS
: /* 0x5A3C69F0 local */
285 case S_MAGIC_ACFS
: /* 0x61636673 remote */
287 case S_MAGIC_ADFS
: /* 0xADF5 local */
289 case S_MAGIC_AFFS
: /* 0xADFF local */
291 case S_MAGIC_AFS
: /* 0x5346414F remote */
293 case S_MAGIC_ANON_INODE_FS
: /* 0x09041934 local */
294 return "anon-inode FS";
295 case S_MAGIC_AUFS
: /* 0x61756673 remote */
296 /* FIXME: change syntax or add an optional attribute like "inotify:no".
297 The above is labeled as "remote" so that tail always uses polling,
298 but this isn't really a remote file system type. */
300 case S_MAGIC_AUTOFS
: /* 0x0187 local */
302 case S_MAGIC_BALLOON_KVM
: /* 0x13661366 local */
303 return "balloon-kvm-fs";
304 case S_MAGIC_BCACHEFS
: /* 0xCA451A4E local */
306 case S_MAGIC_BEFS
: /* 0x42465331 local */
308 case S_MAGIC_BDEVFS
: /* 0x62646576 local */
310 case S_MAGIC_BFS
: /* 0x1BADFACE local */
312 case S_MAGIC_BINDERFS
: /* 0x6C6F6F70 local */
314 case S_MAGIC_BPF_FS
: /* 0xCAFE4A11 local */
316 case S_MAGIC_BINFMTFS
: /* 0x42494E4D local */
317 return "binfmt_misc";
318 case S_MAGIC_BTRFS
: /* 0x9123683E local */
320 case S_MAGIC_BTRFS_TEST
: /* 0x73727279 local */
322 case S_MAGIC_CEPH
: /* 0x00C36400 remote */
324 case S_MAGIC_CGROUP
: /* 0x0027E0EB local */
326 case S_MAGIC_CGROUP2
: /* 0x63677270 local */
328 case S_MAGIC_CIFS
: /* 0xFF534D42 remote */
330 case S_MAGIC_CODA
: /* 0x73757245 remote */
332 case S_MAGIC_COH
: /* 0x012FF7B7 local */
334 case S_MAGIC_CONFIGFS
: /* 0x62656570 local */
336 case S_MAGIC_CRAMFS
: /* 0x28CD3D45 local */
338 case S_MAGIC_CRAMFS_WEND
: /* 0x453DCD28 local */
339 return "cramfs-wend";
340 case S_MAGIC_DAXFS
: /* 0x64646178 local */
342 case S_MAGIC_DEBUGFS
: /* 0x64626720 local */
344 case S_MAGIC_DEVFS
: /* 0x1373 local */
346 case S_MAGIC_DEVMEM
: /* 0x454D444D local */
348 case S_MAGIC_DEVPTS
: /* 0x1CD1 local */
350 case S_MAGIC_DMA_BUF
: /* 0x444D4142 local */
352 case S_MAGIC_ECRYPTFS
: /* 0xF15F local */
354 case S_MAGIC_EFIVARFS
: /* 0xDE5E81E4 local */
356 case S_MAGIC_EFS
: /* 0x00414A53 local */
358 case S_MAGIC_EROFS_V1
: /* 0xE0F5E1E2 local */
360 case S_MAGIC_EXFAT
: /* 0x2011BAB0 local */
362 case S_MAGIC_EXFS
: /* 0x45584653 local */
364 case S_MAGIC_EXOFS
: /* 0x5DF5 local */
366 case S_MAGIC_EXT
: /* 0x137D local */
368 case S_MAGIC_EXT2
: /* 0xEF53 local */
370 case S_MAGIC_EXT2_OLD
: /* 0xEF51 local */
372 case S_MAGIC_F2FS
: /* 0xF2F52010 local */
374 case S_MAGIC_FAT
: /* 0x4006 local */
376 case S_MAGIC_FHGFS
: /* 0x19830326 remote */
378 case S_MAGIC_FUSE
: /* 0x65735546 remote */
380 case S_MAGIC_FUSECTL
: /* 0x65735543 remote */
382 case S_MAGIC_FUTEXFS
: /* 0x0BAD1DEA local */
384 case S_MAGIC_GFS
: /* 0x01161970 remote */
386 case S_MAGIC_GPFS
: /* 0x47504653 remote */
388 case S_MAGIC_HFS
: /* 0x4244 local */
390 case S_MAGIC_HFS_PLUS
: /* 0x482B local */
392 case S_MAGIC_HFS_X
: /* 0x4858 local */
394 case S_MAGIC_HOSTFS
: /* 0x00C0FFEE local */
396 case S_MAGIC_HPFS
: /* 0xF995E849 local */
398 case S_MAGIC_HUGETLBFS
: /* 0x958458F6 local */
400 case S_MAGIC_MTD_INODE_FS
: /* 0x11307854 local */
402 case S_MAGIC_IBRIX
: /* 0x013111A8 remote */
404 case S_MAGIC_INOTIFYFS
: /* 0x2BAD1DEA local */
406 case S_MAGIC_ISOFS
: /* 0x9660 local */
408 case S_MAGIC_ISOFS_R_WIN
: /* 0x4004 local */
410 case S_MAGIC_ISOFS_WIN
: /* 0x4000 local */
412 case S_MAGIC_JFFS
: /* 0x07C0 local */
414 case S_MAGIC_JFFS2
: /* 0x72B6 local */
416 case S_MAGIC_JFS
: /* 0x3153464A local */
418 case S_MAGIC_KAFS
: /* 0x6B414653 remote */
420 case S_MAGIC_LOGFS
: /* 0xC97E8168 local */
422 case S_MAGIC_LUSTRE
: /* 0x0BD00BD0 remote */
424 case S_MAGIC_M1FS
: /* 0x5346314D local */
426 case S_MAGIC_MINIX
: /* 0x137F local */
428 case S_MAGIC_MINIX_30
: /* 0x138F local */
429 return "minix (30 char.)";
430 case S_MAGIC_MINIX_V2
: /* 0x2468 local */
432 case S_MAGIC_MINIX_V2_30
: /* 0x2478 local */
433 return "minix v2 (30 char.)";
434 case S_MAGIC_MINIX_V3
: /* 0x4D5A local */
436 case S_MAGIC_MQUEUE
: /* 0x19800202 local */
438 case S_MAGIC_MSDOS
: /* 0x4D44 local */
440 case S_MAGIC_NCP
: /* 0x564C remote */
442 case S_MAGIC_NFS
: /* 0x6969 remote */
444 case S_MAGIC_NFSD
: /* 0x6E667364 remote */
446 case S_MAGIC_NILFS
: /* 0x3434 local */
448 case S_MAGIC_NSFS
: /* 0x6E736673 local */
450 case S_MAGIC_NTFS
: /* 0x5346544E local */
452 case S_MAGIC_OPENPROM
: /* 0x9FA1 local */
454 case S_MAGIC_OCFS2
: /* 0x7461636F remote */
456 case S_MAGIC_OVERLAYFS
: /* 0x794C7630 remote */
457 /* This may overlay remote file systems.
458 Also there have been issues reported with inotify and overlayfs,
459 so mark as "remote" so that polling is used. */
461 case S_MAGIC_PANFS
: /* 0xAAD7AAEA remote */
463 case S_MAGIC_PID_FS
: /* 0x50494446 local */
465 case S_MAGIC_PIPEFS
: /* 0x50495045 remote */
466 /* FIXME: change syntax or add an optional attribute like "inotify:no".
467 pipefs and prlfs are labeled as "remote" so that tail always polls,
468 but these aren't really remote file system types. */
470 case S_MAGIC_PPC_CMM
: /* 0xC7571590 local */
472 case S_MAGIC_PRL_FS
: /* 0x7C7C6673 remote */
474 case S_MAGIC_PROC
: /* 0x9FA0 local */
476 case S_MAGIC_PSTOREFS
: /* 0x6165676C local */
478 case S_MAGIC_QNX4
: /* 0x002F local */
480 case S_MAGIC_QNX6
: /* 0x68191122 local */
482 case S_MAGIC_RAMFS
: /* 0x858458F6 local */
484 case S_MAGIC_RDTGROUP
: /* 0x07655821 local */
486 case S_MAGIC_REISERFS
: /* 0x52654973 local */
488 case S_MAGIC_ROMFS
: /* 0x7275 local */
490 case S_MAGIC_RPC_PIPEFS
: /* 0x67596969 local */
492 case S_MAGIC_SDCARDFS
: /* 0x5DCA2DF5 local */
494 case S_MAGIC_SECRETMEM
: /* 0x5345434D local */
496 case S_MAGIC_SECURITYFS
: /* 0x73636673 local */
498 case S_MAGIC_SELINUX
: /* 0xF97CFF8C local */
500 case S_MAGIC_SMACK
: /* 0x43415D53 local */
502 case S_MAGIC_SMB
: /* 0x517B remote */
504 case S_MAGIC_SMB2
: /* 0xFE534D42 remote */
506 case S_MAGIC_SNFS
: /* 0xBEEFDEAD remote */
508 case S_MAGIC_SOCKFS
: /* 0x534F434B local */
510 case S_MAGIC_SQUASHFS
: /* 0x73717368 local */
512 case S_MAGIC_SYSFS
: /* 0x62656572 local */
514 case S_MAGIC_SYSV2
: /* 0x012FF7B6 local */
516 case S_MAGIC_SYSV4
: /* 0x012FF7B5 local */
518 case S_MAGIC_TMPFS
: /* 0x01021994 local */
520 case S_MAGIC_TRACEFS
: /* 0x74726163 local */
522 case S_MAGIC_UBIFS
: /* 0x24051905 local */
524 case S_MAGIC_UDF
: /* 0x15013346 local */
526 case S_MAGIC_UFS
: /* 0x00011954 local */
528 case S_MAGIC_UFS_BYTESWAPPED
: /* 0x54190100 local */
530 case S_MAGIC_USBDEVFS
: /* 0x9FA2 local */
532 case S_MAGIC_V9FS
: /* 0x01021997 local */
534 case S_MAGIC_VBOXSF
: /* 0x786F4256 remote */
536 case S_MAGIC_VMHGFS
: /* 0xBACBACBC remote */
538 case S_MAGIC_VXFS
: /* 0xA501FCF5 remote */
539 /* Veritas File System can run in single instance or clustered mode,
540 so mark as remote to cater for the latter case. */
542 case S_MAGIC_VZFS
: /* 0x565A4653 local */
544 case S_MAGIC_WSLFS
: /* 0x53464846 local */
546 case S_MAGIC_XENFS
: /* 0xABBA1974 local */
548 case S_MAGIC_XENIX
: /* 0x012FF7B4 local */
550 case S_MAGIC_XFS
: /* 0x58465342 local */
552 case S_MAGIC_XIAFS
: /* 0x012FD16D local */
554 case S_MAGIC_Z3FOLD
: /* 0x0033 local */
556 case S_MAGIC_ZFS
: /* 0x2FC12FC1 local */
558 case S_MAGIC_ZONEFS
: /* 0x5A4F4653 local */
560 case S_MAGIC_ZSMALLOC
: /* 0x58295829 local */
622 unsigned long int type
= statfsbuf
->f_type
;
623 static char buf
[sizeof "UNKNOWN (0x%lx)" - 3
624 + (sizeof type
* CHAR_BIT
+ 3) / 4];
625 sprintf (buf
, "UNKNOWN (0x%lx)", type
);
634 human_access (struct stat
const *statbuf
)
636 static char modebuf
[12];
637 filemodestring (statbuf
, modebuf
);
644 human_time (struct timespec t
)
646 /* STR must be at least INT_BUFSIZE_BOUND (intmax_t) big, either
647 because localtime_rz fails, or because the time zone is truly
648 outlandish so that %z expands to a long string. */
649 static char str
[INT_BUFSIZE_BOUND (intmax_t)
650 + INT_STRLEN_BOUND (int) /* YYYY */
651 + 1 /* because YYYY might equal INT_MAX + 1900 */
652 + sizeof "-MM-DD HH:MM:SS.NNNNNNNNN +"];
653 static timezone_t tz
;
655 tz
= tzalloc (getenv ("TZ"));
658 if (localtime_rz (tz
, &t
.tv_sec
, &tm
))
659 nstrftime (str
, sizeof str
, "%Y-%m-%d %H:%M:%S.%N %z", &tm
, tz
, ns
);
662 char secbuf
[INT_BUFSIZE_BOUND (intmax_t)];
663 sprintf (str
, "%s.%09d", timetostr (t
.tv_sec
, secbuf
), ns
);
668 /* PFORMAT points to a '%' followed by a prefix of a format, all of
669 size PREFIX_LEN. The flags allowed for this format are
670 ALLOWED_FLAGS; remove other printf flags from the prefix, then
673 make_format (char *pformat
, size_t prefix_len
, char const *allowed_flags
,
676 char *dst
= pformat
+ 1;
678 char const *srclim
= pformat
+ prefix_len
;
679 for (src
= dst
; src
< srclim
&& strchr (printf_flags
, *src
); src
++)
680 if (strchr (allowed_flags
, *src
))
684 strcpy (dst
, suffix
);
688 out_string (char *pformat
, size_t prefix_len
, char const *arg
)
690 make_format (pformat
, prefix_len
, "-", "s");
691 printf (pformat
, arg
);
694 out_int (char *pformat
, size_t prefix_len
, intmax_t arg
)
696 make_format (pformat
, prefix_len
, "'-+ 0", "jd");
697 return printf (pformat
, arg
);
700 out_uint (char *pformat
, size_t prefix_len
, uintmax_t arg
)
702 make_format (pformat
, prefix_len
, "'-0", "ju");
703 return printf (pformat
, arg
);
706 out_uint_o (char *pformat
, size_t prefix_len
, uintmax_t arg
)
708 make_format (pformat
, prefix_len
, "-#0", "jo");
709 printf (pformat
, arg
);
712 out_uint_x (char *pformat
, size_t prefix_len
, uintmax_t arg
)
714 make_format (pformat
, prefix_len
, "-#0", "jx");
715 printf (pformat
, arg
);
718 out_minus_zero (char *pformat
, size_t prefix_len
)
720 make_format (pformat
, prefix_len
, "'-+ 0", ".0f");
721 return printf (pformat
, -0.25);
724 /* Output the number of seconds since the Epoch, using a format that
725 acts like printf's %f format. */
727 out_epoch_sec (char *pformat
, size_t prefix_len
,
730 char *dot
= memchr (pformat
, '.', prefix_len
);
731 size_t sec_prefix_len
= prefix_len
;
734 bool frac_left_adjust
= false;
738 sec_prefix_len
= dot
- pformat
;
739 pformat
[prefix_len
] = '\0';
741 if (ISDIGIT (dot
[1]))
743 long int lprec
= strtol (dot
+ 1, nullptr, 10);
744 precision
= (lprec
<= INT_MAX
? lprec
: INT_MAX
);
751 if (precision
&& ISDIGIT (dot
[-1]))
753 /* If a nontrivial width is given, subtract the width of the
754 decimal point and PRECISION digits that will be output
761 while (ISDIGIT (p
[-1]));
763 long int lwidth
= strtol (p
, nullptr, 10);
764 width
= (lwidth
<= INT_MAX
? lwidth
: INT_MAX
);
768 sec_prefix_len
= p
- pformat
;
769 int w_d
= (decimal_point_len
< width
770 ? width
- decimal_point_len
774 int w
= w_d
- precision
;
778 for (char const *src
= dst
; src
< p
; src
++)
781 frac_left_adjust
= true;
787 + (frac_left_adjust
? 0 : sprintf (dst
, "%d", w
)));
795 for (int i
= precision
; i
< 9; i
++)
797 int frac_sec
= arg
.tv_nsec
/ divisor
;
800 if (TYPE_SIGNED (time_t))
802 bool minus_zero
= false;
803 if (arg
.tv_sec
< 0 && arg
.tv_nsec
!= 0)
805 int frac_sec_modulus
= 1000000000 / divisor
;
806 frac_sec
= (frac_sec_modulus
- frac_sec
807 - (arg
.tv_nsec
% divisor
!= 0));
808 arg
.tv_sec
+= (frac_sec
!= 0);
809 minus_zero
= (arg
.tv_sec
== 0);
811 int_len
= (minus_zero
812 ? out_minus_zero (pformat
, sec_prefix_len
)
813 : out_int (pformat
, sec_prefix_len
, arg
.tv_sec
));
816 int_len
= out_uint (pformat
, sec_prefix_len
, arg
.tv_sec
);
820 int prec
= (precision
< 9 ? precision
: 9);
821 int trailing_prec
= precision
- prec
;
822 int ilen
= (int_len
< 0 ? 0 : int_len
);
823 int trailing_width
= (ilen
< width
&& decimal_point_len
< width
- ilen
824 ? width
- ilen
- decimal_point_len
- prec
826 printf ("%s%.*d%-*.*d", decimal_point
, prec
, frac_sec
,
827 trailing_width
, trailing_prec
, 0);
831 /* Print the context information of FILENAME, and return true iff the
832 context could not be obtained. */
835 out_file_context (char *pformat
, size_t prefix_len
, char const *filename
)
841 ? getfilecon (filename
, &scontext
)
842 : lgetfilecon (filename
, &scontext
)) < 0)
844 error (0, errno
, _("failed to get security context of %s"),
849 strcpy (pformat
+ prefix_len
, "s");
850 printf (pformat
, (scontext
? scontext
: "?"));
856 /* Print statfs info. Return zero upon success, nonzero upon failure. */
859 print_statfs (char *pformat
, size_t prefix_len
, MAYBE_UNUSED
char mod
, char m
,
860 int fd
, char const *filename
,
863 STRUCT_STATVFS
const *statfsbuf
= data
;
869 out_string (pformat
, prefix_len
, filename
);
874 #if STRUCT_STATXFS_F_FSID_IS_INTEGER
875 uintmax_t fsid
= statfsbuf
->f_fsid
;
877 typedef unsigned int fsid_word
;
878 static_assert (alignof (STRUCT_STATVFS
) % alignof (fsid_word
) == 0);
879 static_assert (offsetof (STRUCT_STATVFS
, f_fsid
) % alignof (fsid_word
)
881 static_assert (sizeof statfsbuf
->f_fsid
% alignof (fsid_word
) == 0);
882 fsid_word
const *p
= (fsid_word
*) &statfsbuf
->f_fsid
;
884 /* Assume a little-endian word order, as that is compatible
885 with glibc's statvfs implementation. */
887 int words
= sizeof statfsbuf
->f_fsid
/ sizeof *p
;
888 for (int i
= 0; i
< words
&& i
* sizeof *p
< sizeof fsid
; i
++)
890 uintmax_t u
= p
[words
- 1 - i
];
891 fsid
|= u
<< (i
* CHAR_BIT
* sizeof *p
);
894 out_uint_x (pformat
, prefix_len
, fsid
);
899 OUT_NAMEMAX (pformat
, prefix_len
, SB_F_NAMEMAX (statfsbuf
));
902 #if HAVE_STRUCT_STATXFS_F_TYPE
903 out_uint_x (pformat
, prefix_len
, statfsbuf
->f_type
);
909 out_string (pformat
, prefix_len
, human_fstype (statfsbuf
));
912 out_int (pformat
, prefix_len
, statfsbuf
->f_blocks
);
915 out_int (pformat
, prefix_len
, statfsbuf
->f_bfree
);
918 out_int (pformat
, prefix_len
, statfsbuf
->f_bavail
);
921 out_uint (pformat
, prefix_len
, statfsbuf
->f_bsize
);
925 uintmax_t frsize
= STATFS_FRSIZE (statfsbuf
);
927 frsize
= statfsbuf
->f_bsize
;
928 out_uint (pformat
, prefix_len
, frsize
);
932 out_uint (pformat
, prefix_len
, statfsbuf
->f_files
);
935 out_int (pformat
, prefix_len
, statfsbuf
->f_ffree
);
944 /* Return any bind mounted source for a path.
945 The caller should not free the returned buffer.
946 Return nullptr if no bind mount found. */
949 find_bind_mount (char const * name
)
951 char const * bind_mount
= nullptr;
953 static struct mount_entry
*mount_list
;
954 static bool tried_mount_list
= false;
955 if (!tried_mount_list
) /* attempt/warn once per process. */
957 if (!(mount_list
= read_file_system_list (false)))
958 error (0, errno
, "%s", _("cannot read table of mounted file systems"));
959 tried_mount_list
= true;
962 struct stat name_stats
;
963 if (stat (name
, &name_stats
) != 0)
966 struct mount_entry
*me
;
967 for (me
= mount_list
; me
; me
= me
->me_next
)
969 if (me
->me_dummy
&& me
->me_devname
[0] == '/'
970 && STREQ (me
->me_mountdir
, name
))
972 struct stat dev_stats
;
974 if (stat (me
->me_devname
, &dev_stats
) == 0
975 && psame_inode (&name_stats
, &dev_stats
))
977 bind_mount
= me
->me_devname
;
986 /* Print mount point. Return zero upon success, nonzero upon failure. */
989 out_mount_point (char const *filename
, char *pformat
, size_t prefix_len
,
990 const struct stat
*statp
)
993 char const *np
= "?", *bp
= nullptr;
997 /* Look for bind mounts first. Note we output the immediate alias,
998 rather than further resolving to a base device mount point. */
999 if (follow_links
|| !S_ISLNK (statp
->st_mode
))
1001 char *resolved
= canonicalize_file_name (filename
);
1004 error (0, errno
, _("failed to canonicalize %s"), quoteaf (filename
));
1005 goto print_mount_point
;
1007 bp
= find_bind_mount (resolved
);
1012 goto print_mount_point
;
1016 /* If there is no direct bind mount, then navigate
1017 back up the tree looking for a device change.
1018 Note we don't detect if any of the directory components
1019 are bind mounted to the same device, but that's OK
1020 since we've not directly queried them. */
1021 if ((mp
= find_mount_point (filename
, statp
)))
1023 /* This dir might be bind mounted to another device,
1024 so we resolve the bound source in that case also. */
1025 bp
= find_bind_mount (mp
);
1031 out_string (pformat
, prefix_len
, bp
? bp
: mp
? mp
: np
);
1036 /* Map a TS with negative TS.tv_nsec to {0,0}. */
1037 static inline struct timespec
1038 neg_to_zero (struct timespec ts
)
1040 if (0 <= ts
.tv_nsec
)
1042 struct timespec z
= {0};
1046 /* Set the quoting style default if the environment variable
1047 QUOTING_STYLE is set. */
1050 getenv_quoting_style (void)
1052 char const *q_style
= getenv ("QUOTING_STYLE");
1055 int i
= ARGMATCH (q_style
, quoting_style_args
, quoting_style_vals
);
1057 set_quoting_style (nullptr, quoting_style_vals
[i
]);
1060 set_quoting_style (nullptr, shell_escape_always_quoting_style
);
1061 error (0, 0, _("ignoring invalid value of environment "
1062 "variable QUOTING_STYLE: %s"), quote (q_style
));
1066 set_quoting_style (nullptr, shell_escape_always_quoting_style
);
1069 /* Equivalent to quotearg(), but explicit to avoid syntax checks. */
1070 #define quoteN(x) quotearg_style (get_quoting_style (nullptr), x)
1072 /* Output a single-character \ escape. */
1075 print_esc_char (char c
)
1079 case 'a': /* Alert. */
1082 case 'b': /* Backspace. */
1085 case 'e': /* Escape. */
1088 case 'f': /* Form feed. */
1091 case 'n': /* New line. */
1094 case 'r': /* Carriage return. */
1097 case 't': /* Horizontal tab. */
1100 case 'v': /* Vertical tab. */
1107 error (0, 0, _("warning: unrecognized escape '\\%c'"), c
);
1115 format_code_offset (char const *directive
)
1117 size_t len
= strspn (directive
+ 1, printf_flags
);
1118 char const *fmt_char
= directive
+ len
+ 1;
1119 fmt_char
+= strspn (fmt_char
, digits
);
1120 if (*fmt_char
== '.')
1121 fmt_char
+= 1 + strspn (fmt_char
+ 1, digits
);
1122 return fmt_char
- directive
;
1125 /* Print the information specified by the format string, FORMAT,
1126 calling PRINT_FUNC for each %-directive encountered.
1127 Return zero upon success, nonzero upon failure. */
1130 print_it (char const *format
, int fd
, char const *filename
,
1131 bool (*print_func
) (char *, size_t, char, char,
1132 int, char const *, void const *),
1137 /* Add 2 to accommodate our conversion of the stat '%s' format string
1138 to the longer printf '%llu' one. */
1141 MAX_ADDITIONAL_BYTES
=
1143 MAX (sizeof "jo", MAX (sizeof "ju", sizeof "jx")))
1146 size_t n_alloc
= strlen (format
) + MAX_ADDITIONAL_BYTES
+ 1;
1147 char *dest
= xmalloc (n_alloc
);
1149 for (b
= format
; *b
; b
++)
1155 size_t len
= format_code_offset (b
);
1156 char fmt_char
= *(b
+ len
);
1158 memcpy (dest
, b
, len
);
1169 dest
[len
] = fmt_char
;
1170 dest
[len
+ 1] = '\0';
1171 error (EXIT_FAILURE
, 0, _("%s: invalid directive"),
1178 mod_char
= fmt_char
;
1179 fmt_char
= *(b
+ 1);
1180 if (print_func
== print_stat
1181 && (fmt_char
== 'd' || fmt_char
== 'r'))
1187 fmt_char
= mod_char
;
1192 fail
|= print_func (dest
, len
, mod_char
, fmt_char
,
1193 fd
, filename
, data
);
1200 if ( ! interpret_backslash_escapes
)
1208 int esc_value
= fromoct (*b
);
1209 int esc_length
= 1; /* number of octal digits */
1210 for (++b
; esc_length
< 3 && isoct (*b
);
1213 esc_value
= esc_value
* 8 + fromoct (*b
);
1215 putchar (esc_value
);
1218 else if (*b
== 'x' && c_isxdigit (to_uchar (b
[1])))
1220 int esc_value
= fromhex (b
[1]); /* Value of \xhh escape. */
1221 /* A hexadecimal \xhh escape sequence must have
1222 1 or 2 hex. digits. */
1224 if (c_isxdigit (to_uchar (b
[1])))
1227 esc_value
= esc_value
* 16 + fromhex (*b
);
1229 putchar (esc_value
);
1231 else if (*b
== '\0')
1233 error (0, 0, _("warning: backslash at end of format"));
1235 /* Arrange to exit the loop. */
1240 print_esc_char (*b
);
1251 fputs (trailing_delim
, stdout
);
1256 /* Stat the file system and print what we find. */
1259 do_statfs (char const *filename
, char const *format
)
1261 STRUCT_STATVFS statfsbuf
;
1263 if (STREQ (filename
, "-"))
1265 error (0, 0, _("using %s to denote standard input does not work"
1266 " in file system mode"), quoteaf (filename
));
1270 if (STATFS (filename
, &statfsbuf
) != 0)
1272 error (0, errno
, _("cannot read file system information for %s"),
1273 quoteaf (filename
));
1277 bool fail
= print_it (format
, -1, filename
, print_statfs
, &statfsbuf
);
1283 struct timespec btime
;
1286 /* Ask statx to avoid syncing? */
1287 static bool dont_sync
;
1289 /* Ask statx to force sync? */
1290 static bool force_sync
;
1294 fmt_to_mask (char fmt
)
1309 return STATX_MODE
|STATX_TYPE
;
1321 return STATX_MODE
|STATX_INO
;
1328 return STATX_BLOCKS
;
1347 format_to_mask (char const *format
)
1349 unsigned int mask
= 0;
1352 for (b
= format
; *b
; b
++)
1357 b
+= format_code_offset (b
);
1360 mask
|= fmt_to_mask (*b
);
1365 /* statx the file and print what we find */
1368 do_stat (char const *filename
, char const *format
, char const *format2
)
1370 int fd
= STREQ (filename
, "-") ? 0 : AT_FDCWD
;
1373 struct statx stx
= {0};
1374 char const *pathname
= filename
;
1375 struct print_args pa
;
1377 pa
.btime
= (struct timespec
) {.tv_sec
= -1, .tv_nsec
= -1};
1382 flags
= AT_EMPTY_PATH
;
1384 else if (!follow_links
)
1386 flags
= AT_SYMLINK_NOFOLLOW
;
1390 flags
|= AT_STATX_DONT_SYNC
;
1391 else if (force_sync
)
1392 flags
|= AT_STATX_FORCE_SYNC
;
1395 flags
|= AT_NO_AUTOMOUNT
;
1397 fd
= statx (fd
, pathname
, flags
, format_to_mask (format
), &stx
);
1400 if (flags
& AT_EMPTY_PATH
)
1401 error (0, errno
, _("cannot stat standard input"));
1403 error (0, errno
, _("cannot statx %s"), quoteaf (filename
));
1407 if (S_ISBLK (stx
.stx_mode
) || S_ISCHR (stx
.stx_mode
))
1410 statx_to_stat (&stx
, &st
);
1411 if (stx
.stx_mask
& STATX_BTIME
)
1412 pa
.btime
= statx_timestamp_to_timespec (stx
.stx_btime
);
1414 bool fail
= print_it (format
, fd
, filename
, print_stat
, &pa
);
1418 #else /* USE_STATX */
1420 static struct timespec
1421 get_birthtime (int fd
, char const *filename
, struct stat
const *st
)
1423 struct timespec ts
= get_stat_birthtime (st
);
1430 ? getattrat (AT_FDCWD
, XATTR_VIEW_READWRITE
, filename
, &response
)
1431 : fgetattr (fd
, XATTR_VIEW_READWRITE
, &response
))
1436 if (nvlist_lookup_uint64_array (response
, A_CRTIME
, &val
, &n
) == 0
1438 && val
[0] <= TYPE_MAXIMUM (time_t)
1439 && val
[1] < 1000000000 * 2 /* for leap seconds */)
1442 ts
.tv_nsec
= val
[1];
1444 nvlist_free (response
);
1453 /* stat the file and print what we find */
1456 do_stat (char const *filename
, char const *format
,
1457 char const *format2
)
1459 int fd
= STREQ (filename
, "-") ? 0 : -1;
1460 struct stat statbuf
;
1461 struct print_args pa
;
1463 pa
.btime
= (struct timespec
) {.tv_sec
= -1, .tv_nsec
= -1};
1467 if (fstat (fd
, &statbuf
) != 0)
1469 error (0, errno
, _("cannot stat standard input"));
1473 /* We can't use the shorter
1474 (follow_links?stat:lstat) (filename, &statbug)
1475 since stat might be a function-like macro. */
1476 else if ((follow_links
1477 ? stat (filename
, &statbuf
)
1478 : lstat (filename
, &statbuf
)) != 0)
1480 error (0, errno
, _("cannot stat %s"), quoteaf (filename
));
1484 if (S_ISBLK (statbuf
.st_mode
) || S_ISCHR (statbuf
.st_mode
))
1487 bool fail
= print_it (format
, fd
, filename
, print_stat
, &pa
);
1490 #endif /* USE_STATX */
1492 /* POSIX requires 'ls' to print file sizes without a sign, even
1493 when negative. Be consistent with that. */
1496 unsigned_file_size (off_t size
)
1498 return size
+ (size
< 0) * ((uintmax_t) OFF_T_MAX
- OFF_T_MIN
+ 1);
1501 /* Print stat info. Return zero upon success, nonzero upon failure. */
1503 print_stat (char *pformat
, size_t prefix_len
, char mod
, char m
,
1504 int fd
, char const *filename
, void const *data
)
1506 struct print_args
*parg
= (struct print_args
*) data
;
1507 struct stat
*statbuf
= parg
->st
;
1508 struct timespec btime
= parg
->btime
;
1509 struct passwd
*pw_ent
;
1510 struct group
*gw_ent
;
1516 out_string (pformat
, prefix_len
, filename
);
1519 out_string (pformat
, prefix_len
, quoteN (filename
));
1520 if (S_ISLNK (statbuf
->st_mode
))
1522 char *linkname
= areadlink_with_size (filename
, statbuf
->st_size
);
1523 if (linkname
== nullptr)
1525 error (0, errno
, _("cannot read symbolic link %s"),
1526 quoteaf (filename
));
1530 out_string (pformat
, prefix_len
, quoteN (linkname
));
1536 out_uint (pformat
, prefix_len
, major (statbuf
->st_dev
));
1537 else if (mod
== 'L')
1538 out_uint (pformat
, prefix_len
, minor (statbuf
->st_dev
));
1540 out_uint (pformat
, prefix_len
, statbuf
->st_dev
);
1543 out_uint_x (pformat
, prefix_len
, statbuf
->st_dev
);
1546 out_uint (pformat
, prefix_len
, statbuf
->st_ino
);
1549 out_uint_o (pformat
, prefix_len
, statbuf
->st_mode
& CHMOD_MODE_BITS
);
1552 out_string (pformat
, prefix_len
, human_access (statbuf
));
1555 out_uint_x (pformat
, prefix_len
, statbuf
->st_mode
);
1558 out_string (pformat
, prefix_len
, file_type (statbuf
));
1561 out_uint (pformat
, prefix_len
, statbuf
->st_nlink
);
1564 out_uint (pformat
, prefix_len
, statbuf
->st_uid
);
1567 pw_ent
= getpwuid (statbuf
->st_uid
);
1568 out_string (pformat
, prefix_len
,
1569 pw_ent
? pw_ent
->pw_name
: "UNKNOWN");
1572 out_uint (pformat
, prefix_len
, statbuf
->st_gid
);
1575 gw_ent
= getgrgid (statbuf
->st_gid
);
1576 out_string (pformat
, prefix_len
,
1577 gw_ent
? gw_ent
->gr_name
: "UNKNOWN");
1580 fail
|= out_mount_point (filename
, pformat
, prefix_len
, statbuf
);
1583 out_uint (pformat
, prefix_len
, unsigned_file_size (statbuf
->st_size
));
1587 out_uint (pformat
, prefix_len
, major (statbuf
->st_rdev
));
1588 else if (mod
== 'L')
1589 out_uint (pformat
, prefix_len
, minor (statbuf
->st_rdev
));
1591 out_uint (pformat
, prefix_len
, statbuf
->st_rdev
);
1594 out_uint_x (pformat
, prefix_len
, statbuf
->st_rdev
);
1597 out_uint_x (pformat
, prefix_len
, major (statbuf
->st_rdev
));
1600 out_uint_x (pformat
, prefix_len
, minor (statbuf
->st_rdev
));
1603 out_uint (pformat
, prefix_len
, ST_NBLOCKSIZE
);
1606 out_uint (pformat
, prefix_len
, STP_NBLOCKS (statbuf
));
1609 out_uint (pformat
, prefix_len
, STP_BLKSIZE (statbuf
));
1614 btime
= get_birthtime (fd
, filename
, statbuf
);
1616 if (btime
.tv_nsec
< 0)
1617 out_string (pformat
, prefix_len
, "-");
1619 out_string (pformat
, prefix_len
, human_time (btime
));
1625 btime
= get_birthtime (fd
, filename
, statbuf
);
1627 out_epoch_sec (pformat
, prefix_len
, neg_to_zero (btime
));
1631 out_string (pformat
, prefix_len
, human_time (get_stat_atime (statbuf
)));
1634 out_epoch_sec (pformat
, prefix_len
, get_stat_atime (statbuf
));
1637 out_string (pformat
, prefix_len
, human_time (get_stat_mtime (statbuf
)));
1640 out_epoch_sec (pformat
, prefix_len
, get_stat_mtime (statbuf
));
1643 out_string (pformat
, prefix_len
, human_time (get_stat_ctime (statbuf
)));
1646 out_epoch_sec (pformat
, prefix_len
, get_stat_ctime (statbuf
));
1649 fail
|= out_file_context (pformat
, prefix_len
, filename
);
1652 fputc ('?', stdout
);
1658 /* Return an allocated format string in static storage that
1659 corresponds to whether FS and TERSE options were declared. */
1661 default_format (bool fs
, bool terse
, bool device
)
1667 format
= xstrdup (fmt_terse_fs
);
1670 /* TRANSLATORS: This string uses format specifiers from
1671 'stat --help' with --file-system, and NOT from printf. */
1672 format
= xstrdup (_(" File: \"%n\"\n"
1673 " ID: %-8i Namelen: %-7l Type: %T\n"
1674 "Block size: %-10s Fundamental block size: %S\n"
1675 "Blocks: Total: %-10b Free: %-10f Available: %a\n"
1676 "Inodes: Total: %-10c Free: %d\n"));
1683 if (0 < is_selinux_enabled ())
1684 format
= xstrdup (fmt_terse_selinux
);
1686 format
= xstrdup (fmt_terse_regular
);
1691 /* TRANSLATORS: This string uses format specifiers from
1692 'stat --help' without --file-system, and NOT from printf. */
1693 format
= xstrdup (_("\
1695 Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n\
1701 /* TRANSLATORS: This string uses format specifiers from
1702 'stat --help' without --file-system, and NOT from printf. */
1703 format
= xasprintf ("%s%s", format
, _("\
1704 " "Device: %Hd,%Ld\tInode: %-10i Links: %-5h Device type: %Hr,%Lr\n\
1709 /* TRANSLATORS: This string uses format specifiers from
1710 'stat --help' without --file-system, and NOT from printf. */
1711 format
= xasprintf ("%s%s", format
, _("\
1712 " "Device: %Hd,%Ld\tInode: %-10i Links: %h\n\
1718 /* TRANSLATORS: This string uses format specifiers from
1719 'stat --help' without --file-system, and NOT from printf. */
1720 format
= xasprintf ("%s%s", format
, _("\
1721 " "Access: (%04a/%10.10A) Uid: (%5u/%8U) Gid: (%5g/%8G)\n\
1725 if (0 < is_selinux_enabled ())
1728 /* TRANSLATORS: This string uses format specifiers from
1729 'stat --help' without --file-system, and NOT from printf. */
1730 format
= xasprintf ("%s%s", format
, _("Context: %C\n"));
1735 format
= xasprintf ("%s%s", format
,
1736 /* TRANSLATORS: This string uses format specifiers
1737 from 'stat --help' without --file-system, and
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 (see '#' 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
);