dd: synchronize output after write errors
[coreutils.git] / src / stat.c
blobe58be55e9c022d1ae33070583d22caf210720dff
1 /* stat.c -- display file or file system status
2 Copyright (C) 2001-2022 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. */
19 #include <config.h>
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
27 #else
28 # define USE_STATVFS 0
29 #endif
31 #include <stddef.h>
32 #include <stdio.h>
33 #include <stdalign.h>
34 #include <sys/types.h>
35 #include <pwd.h>
36 #include <grp.h>
37 #if USE_STATVFS
38 # include <sys/statvfs.h>
39 #elif HAVE_SYS_VFS_H
40 # include <sys/vfs.h>
41 #elif HAVE_SYS_MOUNT_H && HAVE_SYS_PARAM_H
42 /* NOTE: freebsd5.0 needs sys/param.h and sys/mount.h for statfs.
43 It does have statvfs.h, but shouldn't use it, since it doesn't
44 HAVE_STRUCT_STATVFS_F_BASETYPE. So find a clean way to fix it. */
45 /* NetBSD 1.5.2 needs these, for the declaration of struct statfs. */
46 # include <sys/param.h>
47 # include <sys/mount.h>
48 # if HAVE_NFS_NFS_CLNT_H && HAVE_NFS_VFS_H
49 /* Ultrix 4.4 needs these for the declaration of struct statfs. */
50 # include <netinet/in.h>
51 # include <nfs/nfs_clnt.h>
52 # include <nfs/vfs.h>
53 # endif
54 #elif HAVE_OS_H /* BeOS */
55 # include <fs_info.h>
56 #endif
57 #include <selinux/selinux.h>
59 #include "system.h"
61 #include "areadlink.h"
62 #include "argmatch.h"
63 #include "die.h"
64 #include "error.h"
65 #include "file-type.h"
66 #include "filemode.h"
67 #include "fs.h"
68 #include "getopt.h"
69 #include "mountlist.h"
70 #include "quote.h"
71 #include "stat-size.h"
72 #include "stat-time.h"
73 #include "strftime.h"
74 #include "find-mount-point.h"
75 #include "xvasprintf.h"
76 #include "statx.h"
78 #if HAVE_STATX && defined STATX_INO
79 # define USE_STATX 1
80 #else
81 # define USE_STATX 0
82 #endif
84 #if USE_STATVFS
85 # define STRUCT_STATXFS_F_FSID_IS_INTEGER STRUCT_STATVFS_F_FSID_IS_INTEGER
86 # define HAVE_STRUCT_STATXFS_F_TYPE HAVE_STRUCT_STATVFS_F_TYPE
87 # if HAVE_STRUCT_STATVFS_F_NAMEMAX
88 # define SB_F_NAMEMAX(S) ((S)->f_namemax)
89 # endif
90 # if ! STAT_STATVFS && STAT_STATVFS64
91 # define STRUCT_STATVFS struct statvfs64
92 # define STATFS statvfs64
93 # else
94 # define STRUCT_STATVFS struct statvfs
95 # define STATFS statvfs
96 # endif
97 # define STATFS_FRSIZE(S) ((S)->f_frsize)
98 #else
99 # define HAVE_STRUCT_STATXFS_F_TYPE HAVE_STRUCT_STATFS_F_TYPE
100 # if HAVE_STRUCT_STATFS_F_NAMELEN
101 # define SB_F_NAMEMAX(S) ((S)->f_namelen)
102 # elif HAVE_STRUCT_STATFS_F_NAMEMAX
103 # define SB_F_NAMEMAX(S) ((S)->f_namemax)
104 # endif
105 # define STATFS statfs
106 # if HAVE_OS_H /* BeOS */
107 /* BeOS has a statvfs function, but it does not return sensible values
108 for f_files, f_ffree and f_favail, and lacks f_type, f_basetype and
109 f_fstypename. Use 'struct fs_info' instead. */
110 NODISCARD
111 static int
112 statfs (char const *filename, struct fs_info *buf)
114 dev_t device = dev_for_path (filename);
115 if (device < 0)
117 errno = (device == B_ENTRY_NOT_FOUND ? ENOENT
118 : device == B_BAD_VALUE ? EINVAL
119 : device == B_NAME_TOO_LONG ? ENAMETOOLONG
120 : device == B_NO_MEMORY ? ENOMEM
121 : device == B_FILE_ERROR ? EIO
122 : 0);
123 return -1;
125 /* If successful, buf->dev will be == device. */
126 return fs_stat_dev (device, buf);
128 # define f_fsid dev
129 # define f_blocks total_blocks
130 # define f_bfree free_blocks
131 # define f_bavail free_blocks
132 # define f_bsize io_size
133 # define f_files total_nodes
134 # define f_ffree free_nodes
135 # define STRUCT_STATVFS struct fs_info
136 # define STRUCT_STATXFS_F_FSID_IS_INTEGER true
137 # define STATFS_FRSIZE(S) ((S)->block_size)
138 # else
139 # define STRUCT_STATVFS struct statfs
140 # define STRUCT_STATXFS_F_FSID_IS_INTEGER STRUCT_STATFS_F_FSID_IS_INTEGER
141 # if HAVE_STRUCT_STATFS_F_FRSIZE
142 # define STATFS_FRSIZE(S) ((S)->f_frsize)
143 # else
144 # define STATFS_FRSIZE(S) 0
145 # endif
146 # endif
147 #endif
149 #ifdef SB_F_NAMEMAX
150 # define OUT_NAMEMAX out_uint
151 #else
152 /* Depending on whether statvfs or statfs is used,
153 neither f_namemax or f_namelen may be available. */
154 # define SB_F_NAMEMAX(S) "?"
155 # define OUT_NAMEMAX out_string
156 #endif
158 #if HAVE_STRUCT_STATVFS_F_BASETYPE
159 # define STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME f_basetype
160 #else
161 # if HAVE_STRUCT_STATVFS_F_FSTYPENAME || HAVE_STRUCT_STATFS_F_FSTYPENAME
162 # define STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME f_fstypename
163 # elif HAVE_OS_H /* BeOS */
164 # define STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME fsh_name
165 # endif
166 #endif
168 #if HAVE_GETATTRAT
169 # include <attr.h>
170 # include <sys/nvpair.h>
171 #endif
173 /* FIXME: these are used by printf.c, too */
174 #define isodigit(c) ('0' <= (c) && (c) <= '7')
175 #define octtobin(c) ((c) - '0')
176 #define hextobin(c) ((c) >= 'a' && (c) <= 'f' ? (c) - 'a' + 10 : \
177 (c) >= 'A' && (c) <= 'F' ? (c) - 'A' + 10 : (c) - '0')
179 static char const digits[] = "0123456789";
181 /* Flags that are portable for use in printf, for at least one
182 conversion specifier; make_format removes unportable flags as
183 needed for particular specifiers. The glibc 2.2 extension "I" is
184 listed here; it is removed by make_format because it has undefined
185 behavior elsewhere and because it is incompatible with
186 out_epoch_sec. */
187 static char const printf_flags[] = "'-+ #0I";
189 /* Formats for the --terse option. */
190 static char const fmt_terse_fs[] = "%n %i %l %t %s %S %b %f %a %c %d\n";
191 static char const fmt_terse_regular[] = "%n %s %b %f %u %g %D %i %h %t %T"
192 " %X %Y %Z %W %o\n";
193 static char const fmt_terse_selinux[] = "%n %s %b %f %u %g %D %i %h %t %T"
194 " %X %Y %Z %W %o %C\n";
196 #define PROGRAM_NAME "stat"
198 #define AUTHORS proper_name ("Michael Meskes")
200 enum
202 PRINTF_OPTION = CHAR_MAX + 1
205 enum cached_mode
207 cached_default,
208 cached_never,
209 cached_always
212 static char const *const cached_args[] =
214 "default", "never", "always", NULL
217 static enum cached_mode const cached_modes[] =
219 cached_default, cached_never, cached_always
222 static struct option const long_options[] =
224 {"dereference", no_argument, NULL, 'L'},
225 {"file-system", no_argument, NULL, 'f'},
226 {"format", required_argument, NULL, 'c'},
227 {"printf", required_argument, NULL, PRINTF_OPTION},
228 {"terse", no_argument, NULL, 't'},
229 {"cached", required_argument, NULL, 0},
230 {GETOPT_HELP_OPTION_DECL},
231 {GETOPT_VERSION_OPTION_DECL},
232 {NULL, 0, NULL, 0}
235 /* Whether to follow symbolic links; True for --dereference (-L). */
236 static bool follow_links;
238 /* Whether to interpret backslash-escape sequences.
239 True for --printf=FMT, not for --format=FMT (-c). */
240 static bool interpret_backslash_escapes;
242 /* The trailing delimiter string:
243 "" for --printf=FMT, "\n" for --format=FMT (-c). */
244 static char const *trailing_delim = "";
246 /* The representation of the decimal point in the current locale. */
247 static char const *decimal_point;
248 static size_t decimal_point_len;
250 static bool
251 print_stat (char *pformat, size_t prefix_len, char mod, char m,
252 int fd, char const *filename, void const *data);
254 /* Return the type of the specified file system.
255 Some systems have statfvs.f_basetype[FSTYPSZ] (AIX, HP-UX, and Solaris).
256 Others have statvfs.f_fstypename[_VFS_NAMELEN] (NetBSD 3.0).
257 Others have statfs.f_fstypename[MFSNAMELEN] (NetBSD 1.5.2).
258 Still others have neither and have to get by with f_type (GNU/Linux).
259 But f_type may only exist in statfs (Cygwin). */
260 NODISCARD
261 static char const *
262 human_fstype (STRUCT_STATVFS const *statfsbuf)
264 #ifdef STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME
265 return statfsbuf->STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME;
266 #else
267 switch (statfsbuf->f_type)
269 # if defined __linux__ || defined __ANDROID__
271 /* Compare with what's in libc:
272 f=/a/libc/sysdeps/unix/sysv/linux/linux_fsinfo.h
273 sed -n '/ADFS_SUPER_MAGIC/,/SYSFS_MAGIC/p' $f \
274 | perl -n -e '/#define (.*?)_(?:SUPER_)MAGIC\s+0x(\S+)/' \
275 -e 'and print "case S_MAGIC_$1: /\* 0x" . uc($2) . " *\/\n"' \
276 | sort > sym_libc
277 perl -ne '/^\s+(case S_MAGIC_.*?): \/\* 0x(\S+) \*\//' \
278 -e 'and do { $v=uc$2; print "$1: /\* 0x$v *\/\n"}' stat.c \
279 | sort > sym_stat
280 diff -u sym_stat sym_libc
283 /* Also compare with the list in "man 2 statfs" using the
284 fs-magic-compare make target. */
286 /* IMPORTANT NOTE: Each of the following 'case S_MAGIC_...:'
287 statements must be followed by a hexadecimal constant in
288 a comment. The S_MAGIC_... name and constant are automatically
289 combined to produce the #define directives in fs.h. */
291 case S_MAGIC_AAFS: /* 0x5A3C69F0 local */
292 return "aafs";
293 case S_MAGIC_ACFS: /* 0x61636673 remote */
294 return "acfs";
295 case S_MAGIC_ADFS: /* 0xADF5 local */
296 return "adfs";
297 case S_MAGIC_AFFS: /* 0xADFF local */
298 return "affs";
299 case S_MAGIC_AFS: /* 0x5346414F remote */
300 return "afs";
301 case S_MAGIC_ANON_INODE_FS: /* 0x09041934 local */
302 return "anon-inode FS";
303 case S_MAGIC_AUFS: /* 0x61756673 remote */
304 /* FIXME: change syntax or add an optional attribute like "inotify:no".
305 The above is labeled as "remote" so that tail always uses polling,
306 but this isn't really a remote file system type. */
307 return "aufs";
308 case S_MAGIC_AUTOFS: /* 0x0187 local */
309 return "autofs";
310 case S_MAGIC_BALLOON_KVM: /* 0x13661366 local */
311 return "balloon-kvm-fs";
312 case S_MAGIC_BEFS: /* 0x42465331 local */
313 return "befs";
314 case S_MAGIC_BDEVFS: /* 0x62646576 local */
315 return "bdevfs";
316 case S_MAGIC_BFS: /* 0x1BADFACE local */
317 return "bfs";
318 case S_MAGIC_BINDERFS: /* 0x6C6F6F70 local */
319 return "binderfs";
320 case S_MAGIC_BPF_FS: /* 0xCAFE4A11 local */
321 return "bpf_fs";
322 case S_MAGIC_BINFMTFS: /* 0x42494E4D local */
323 return "binfmt_misc";
324 case S_MAGIC_BTRFS: /* 0x9123683E local */
325 return "btrfs";
326 case S_MAGIC_BTRFS_TEST: /* 0x73727279 local */
327 return "btrfs_test";
328 case S_MAGIC_CEPH: /* 0x00C36400 remote */
329 return "ceph";
330 case S_MAGIC_CGROUP: /* 0x0027E0EB local */
331 return "cgroupfs";
332 case S_MAGIC_CGROUP2: /* 0x63677270 local */
333 return "cgroup2fs";
334 case S_MAGIC_CIFS: /* 0xFF534D42 remote */
335 return "cifs";
336 case S_MAGIC_CODA: /* 0x73757245 remote */
337 return "coda";
338 case S_MAGIC_COH: /* 0x012FF7B7 local */
339 return "coh";
340 case S_MAGIC_CONFIGFS: /* 0x62656570 local */
341 return "configfs";
342 case S_MAGIC_CRAMFS: /* 0x28CD3D45 local */
343 return "cramfs";
344 case S_MAGIC_CRAMFS_WEND: /* 0x453DCD28 local */
345 return "cramfs-wend";
346 case S_MAGIC_DAXFS: /* 0x64646178 local */
347 return "daxfs";
348 case S_MAGIC_DEBUGFS: /* 0x64626720 local */
349 return "debugfs";
350 case S_MAGIC_DEVFS: /* 0x1373 local */
351 return "devfs";
352 case S_MAGIC_DEVMEM: /* 0x454D444D local */
353 return "devmem";
354 case S_MAGIC_DEVPTS: /* 0x1CD1 local */
355 return "devpts";
356 case S_MAGIC_DMA_BUF: /* 0x444D4142 local */
357 return "dma-buf-fs";
358 case S_MAGIC_ECRYPTFS: /* 0xF15F local */
359 return "ecryptfs";
360 case S_MAGIC_EFIVARFS: /* 0xDE5E81E4 local */
361 return "efivarfs";
362 case S_MAGIC_EFS: /* 0x00414A53 local */
363 return "efs";
364 case S_MAGIC_EROFS_V1: /* 0xE0F5E1E2 local */
365 return "erofs";
366 case S_MAGIC_EXFAT: /* 0x2011BAB0 local */
367 return "exfat";
368 case S_MAGIC_EXFS: /* 0x45584653 local */
369 return "exfs";
370 case S_MAGIC_EXOFS: /* 0x5DF5 local */
371 return "exofs";
372 case S_MAGIC_EXT: /* 0x137D local */
373 return "ext";
374 case S_MAGIC_EXT2: /* 0xEF53 local */
375 return "ext2/ext3";
376 case S_MAGIC_EXT2_OLD: /* 0xEF51 local */
377 return "ext2";
378 case S_MAGIC_F2FS: /* 0xF2F52010 local */
379 return "f2fs";
380 case S_MAGIC_FAT: /* 0x4006 local */
381 return "fat";
382 case S_MAGIC_FHGFS: /* 0x19830326 remote */
383 return "fhgfs";
384 case S_MAGIC_FUSEBLK: /* 0x65735546 remote */
385 return "fuseblk";
386 case S_MAGIC_FUSECTL: /* 0x65735543 remote */
387 return "fusectl";
388 case S_MAGIC_FUTEXFS: /* 0x0BAD1DEA local */
389 return "futexfs";
390 case S_MAGIC_GFS: /* 0x01161970 remote */
391 return "gfs/gfs2";
392 case S_MAGIC_GPFS: /* 0x47504653 remote */
393 return "gpfs";
394 case S_MAGIC_HFS: /* 0x4244 local */
395 return "hfs";
396 case S_MAGIC_HFS_PLUS: /* 0x482B local */
397 return "hfs+";
398 case S_MAGIC_HFS_X: /* 0x4858 local */
399 return "hfsx";
400 case S_MAGIC_HOSTFS: /* 0x00C0FFEE local */
401 return "hostfs";
402 case S_MAGIC_HPFS: /* 0xF995E849 local */
403 return "hpfs";
404 case S_MAGIC_HUGETLBFS: /* 0x958458F6 local */
405 return "hugetlbfs";
406 case S_MAGIC_MTD_INODE_FS: /* 0x11307854 local */
407 return "inodefs";
408 case S_MAGIC_IBRIX: /* 0x013111A8 remote */
409 return "ibrix";
410 case S_MAGIC_INOTIFYFS: /* 0x2BAD1DEA local */
411 return "inotifyfs";
412 case S_MAGIC_ISOFS: /* 0x9660 local */
413 return "isofs";
414 case S_MAGIC_ISOFS_R_WIN: /* 0x4004 local */
415 return "isofs";
416 case S_MAGIC_ISOFS_WIN: /* 0x4000 local */
417 return "isofs";
418 case S_MAGIC_JFFS: /* 0x07C0 local */
419 return "jffs";
420 case S_MAGIC_JFFS2: /* 0x72B6 local */
421 return "jffs2";
422 case S_MAGIC_JFS: /* 0x3153464A local */
423 return "jfs";
424 case S_MAGIC_KAFS: /* 0x6B414653 remote */
425 return "k-afs";
426 case S_MAGIC_LOGFS: /* 0xC97E8168 local */
427 return "logfs";
428 case S_MAGIC_LUSTRE: /* 0x0BD00BD0 remote */
429 return "lustre";
430 case S_MAGIC_M1FS: /* 0x5346314D local */
431 return "m1fs";
432 case S_MAGIC_MINIX: /* 0x137F local */
433 return "minix";
434 case S_MAGIC_MINIX_30: /* 0x138F local */
435 return "minix (30 char.)";
436 case S_MAGIC_MINIX_V2: /* 0x2468 local */
437 return "minix v2";
438 case S_MAGIC_MINIX_V2_30: /* 0x2478 local */
439 return "minix v2 (30 char.)";
440 case S_MAGIC_MINIX_V3: /* 0x4D5A local */
441 return "minix3";
442 case S_MAGIC_MQUEUE: /* 0x19800202 local */
443 return "mqueue";
444 case S_MAGIC_MSDOS: /* 0x4D44 local */
445 return "msdos";
446 case S_MAGIC_NCP: /* 0x564C remote */
447 return "novell";
448 case S_MAGIC_NFS: /* 0x6969 remote */
449 return "nfs";
450 case S_MAGIC_NFSD: /* 0x6E667364 remote */
451 return "nfsd";
452 case S_MAGIC_NILFS: /* 0x3434 local */
453 return "nilfs";
454 case S_MAGIC_NSFS: /* 0x6E736673 local */
455 return "nsfs";
456 case S_MAGIC_NTFS: /* 0x5346544E local */
457 return "ntfs";
458 case S_MAGIC_OPENPROM: /* 0x9FA1 local */
459 return "openprom";
460 case S_MAGIC_OCFS2: /* 0x7461636F remote */
461 return "ocfs2";
462 case S_MAGIC_OVERLAYFS: /* 0x794C7630 remote */
463 /* This may overlay remote file systems.
464 Also there have been issues reported with inotify and overlayfs,
465 so mark as "remote" so that polling is used. */
466 return "overlayfs";
467 case S_MAGIC_PANFS: /* 0xAAD7AAEA remote */
468 return "panfs";
469 case S_MAGIC_PIPEFS: /* 0x50495045 remote */
470 /* FIXME: change syntax or add an optional attribute like "inotify:no".
471 pipefs and prlfs are labeled as "remote" so that tail always polls,
472 but these aren't really remote file system types. */
473 return "pipefs";
474 case S_MAGIC_PPC_CMM: /* 0xC7571590 local */
475 return "ppc-cmm-fs";
476 case S_MAGIC_PRL_FS: /* 0x7C7C6673 remote */
477 return "prl_fs";
478 case S_MAGIC_PROC: /* 0x9FA0 local */
479 return "proc";
480 case S_MAGIC_PSTOREFS: /* 0x6165676C local */
481 return "pstorefs";
482 case S_MAGIC_QNX4: /* 0x002F local */
483 return "qnx4";
484 case S_MAGIC_QNX6: /* 0x68191122 local */
485 return "qnx6";
486 case S_MAGIC_RAMFS: /* 0x858458F6 local */
487 return "ramfs";
488 case S_MAGIC_RDTGROUP: /* 0x07655821 local */
489 return "rdt";
490 case S_MAGIC_REISERFS: /* 0x52654973 local */
491 return "reiserfs";
492 case S_MAGIC_ROMFS: /* 0x7275 local */
493 return "romfs";
494 case S_MAGIC_RPC_PIPEFS: /* 0x67596969 local */
495 return "rpc_pipefs";
496 case S_MAGIC_SDCARDFS: /* 0x5DCA2DF5 local */
497 return "sdcardfs";
498 case S_MAGIC_SECRETMEM: /* 0x5345434D local */
499 return "secretmem";
500 case S_MAGIC_SECURITYFS: /* 0x73636673 local */
501 return "securityfs";
502 case S_MAGIC_SELINUX: /* 0xF97CFF8C local */
503 return "selinux";
504 case S_MAGIC_SMACK: /* 0x43415D53 local */
505 return "smackfs";
506 case S_MAGIC_SMB: /* 0x517B remote */
507 return "smb";
508 case S_MAGIC_SMB2: /* 0xFE534D42 remote */
509 return "smb2";
510 case S_MAGIC_SNFS: /* 0xBEEFDEAD remote */
511 return "snfs";
512 case S_MAGIC_SOCKFS: /* 0x534F434B local */
513 return "sockfs";
514 case S_MAGIC_SQUASHFS: /* 0x73717368 local */
515 return "squashfs";
516 case S_MAGIC_SYSFS: /* 0x62656572 local */
517 return "sysfs";
518 case S_MAGIC_SYSV2: /* 0x012FF7B6 local */
519 return "sysv2";
520 case S_MAGIC_SYSV4: /* 0x012FF7B5 local */
521 return "sysv4";
522 case S_MAGIC_TMPFS: /* 0x01021994 local */
523 return "tmpfs";
524 case S_MAGIC_TRACEFS: /* 0x74726163 local */
525 return "tracefs";
526 case S_MAGIC_UBIFS: /* 0x24051905 local */
527 return "ubifs";
528 case S_MAGIC_UDF: /* 0x15013346 local */
529 return "udf";
530 case S_MAGIC_UFS: /* 0x00011954 local */
531 return "ufs";
532 case S_MAGIC_UFS_BYTESWAPPED: /* 0x54190100 local */
533 return "ufs";
534 case S_MAGIC_USBDEVFS: /* 0x9FA2 local */
535 return "usbdevfs";
536 case S_MAGIC_V9FS: /* 0x01021997 local */
537 return "v9fs";
538 case S_MAGIC_VBOXSF: /* 0x786F4256 remote */
539 return "vboxsf";
540 case S_MAGIC_VMHGFS: /* 0xBACBACBC remote */
541 return "vmhgfs";
542 case S_MAGIC_VXFS: /* 0xA501FCF5 remote */
543 /* Veritas File System can run in single instance or clustered mode,
544 so mark as remote to cater for the latter case. */
545 return "vxfs";
546 case S_MAGIC_VZFS: /* 0x565A4653 local */
547 return "vzfs";
548 case S_MAGIC_WSLFS: /* 0x53464846 local */
549 return "wslfs";
550 case S_MAGIC_XENFS: /* 0xABBA1974 local */
551 return "xenfs";
552 case S_MAGIC_XENIX: /* 0x012FF7B4 local */
553 return "xenix";
554 case S_MAGIC_XFS: /* 0x58465342 local */
555 return "xfs";
556 case S_MAGIC_XIAFS: /* 0x012FD16D local */
557 return "xia";
558 case S_MAGIC_Z3FOLD: /* 0x0033 local */
559 return "z3fold";
560 case S_MAGIC_ZFS: /* 0x2FC12FC1 local */
561 return "zfs";
562 case S_MAGIC_ZONEFS: /* 0x5A4F4653 local */
563 return "zonefs";
564 case S_MAGIC_ZSMALLOC: /* 0x58295829 local */
565 return "zsmallocfs";
568 # elif __GNU__
569 case FSTYPE_UFS:
570 return "ufs";
571 case FSTYPE_NFS:
572 return "nfs";
573 case FSTYPE_GFS:
574 return "gfs";
575 case FSTYPE_LFS:
576 return "lfs";
577 case FSTYPE_SYSV:
578 return "sysv";
579 case FSTYPE_FTP:
580 return "ftp";
581 case FSTYPE_TAR:
582 return "tar";
583 case FSTYPE_AR:
584 return "ar";
585 case FSTYPE_CPIO:
586 return "cpio";
587 case FSTYPE_MSLOSS:
588 return "msloss";
589 case FSTYPE_CPM:
590 return "cpm";
591 case FSTYPE_HFS:
592 return "hfs";
593 case FSTYPE_DTFS:
594 return "dtfs";
595 case FSTYPE_GRFS:
596 return "grfs";
597 case FSTYPE_TERM:
598 return "term";
599 case FSTYPE_DEV:
600 return "dev";
601 case FSTYPE_PROC:
602 return "proc";
603 case FSTYPE_IFSOCK:
604 return "ifsock";
605 case FSTYPE_AFS:
606 return "afs";
607 case FSTYPE_DFS:
608 return "dfs";
609 case FSTYPE_PROC9:
610 return "proc9";
611 case FSTYPE_SOCKET:
612 return "socket";
613 case FSTYPE_MISC:
614 return "misc";
615 case FSTYPE_EXT2FS:
616 return "ext2/ext3";
617 case FSTYPE_HTTP:
618 return "http";
619 case FSTYPE_MEMFS:
620 return "memfs";
621 case FSTYPE_ISO9660:
622 return "iso9660";
623 # endif
624 default:
626 unsigned long int type = statfsbuf->f_type;
627 static char buf[sizeof "UNKNOWN (0x%lx)" - 3
628 + (sizeof type * CHAR_BIT + 3) / 4];
629 sprintf (buf, "UNKNOWN (0x%lx)", type);
630 return buf;
633 #endif
636 NODISCARD
637 static char *
638 human_access (struct stat const *statbuf)
640 static char modebuf[12];
641 filemodestring (statbuf, modebuf);
642 modebuf[10] = 0;
643 return modebuf;
646 NODISCARD
647 static char *
648 human_time (struct timespec t)
650 /* STR must be at least INT_BUFSIZE_BOUND (intmax_t) big, either
651 because localtime_rz fails, or because the time zone is truly
652 outlandish so that %z expands to a long string. */
653 static char str[INT_BUFSIZE_BOUND (intmax_t)
654 + INT_STRLEN_BOUND (int) /* YYYY */
655 + 1 /* because YYYY might equal INT_MAX + 1900 */
656 + sizeof "-MM-DD HH:MM:SS.NNNNNNNNN +"];
657 static timezone_t tz;
658 if (!tz)
659 tz = tzalloc (getenv ("TZ"));
660 struct tm tm;
661 int ns = t.tv_nsec;
662 if (localtime_rz (tz, &t.tv_sec, &tm))
663 nstrftime (str, sizeof str, "%Y-%m-%d %H:%M:%S.%N %z", &tm, tz, ns);
664 else
666 char secbuf[INT_BUFSIZE_BOUND (intmax_t)];
667 sprintf (str, "%s.%09d", timetostr (t.tv_sec, secbuf), ns);
669 return str;
672 /* PFORMAT points to a '%' followed by a prefix of a format, all of
673 size PREFIX_LEN. The flags allowed for this format are
674 ALLOWED_FLAGS; remove other printf flags from the prefix, then
675 append SUFFIX. */
676 static void
677 make_format (char *pformat, size_t prefix_len, char const *allowed_flags,
678 char const *suffix)
680 char *dst = pformat + 1;
681 char const *src;
682 char const *srclim = pformat + prefix_len;
683 for (src = dst; src < srclim && strchr (printf_flags, *src); src++)
684 if (strchr (allowed_flags, *src))
685 *dst++ = *src;
686 while (src < srclim)
687 *dst++ = *src++;
688 strcpy (dst, suffix);
691 static void
692 out_string (char *pformat, size_t prefix_len, char const *arg)
694 make_format (pformat, prefix_len, "-", "s");
695 printf (pformat, arg);
697 static int
698 out_int (char *pformat, size_t prefix_len, intmax_t arg)
700 make_format (pformat, prefix_len, "'-+ 0", PRIdMAX);
701 return printf (pformat, arg);
703 static int
704 out_uint (char *pformat, size_t prefix_len, uintmax_t arg)
706 make_format (pformat, prefix_len, "'-0", PRIuMAX);
707 return printf (pformat, arg);
709 static void
710 out_uint_o (char *pformat, size_t prefix_len, uintmax_t arg)
712 make_format (pformat, prefix_len, "-#0", PRIoMAX);
713 printf (pformat, arg);
715 static void
716 out_uint_x (char *pformat, size_t prefix_len, uintmax_t arg)
718 make_format (pformat, prefix_len, "-#0", PRIxMAX);
719 printf (pformat, arg);
721 static int
722 out_minus_zero (char *pformat, size_t prefix_len)
724 make_format (pformat, prefix_len, "'-+ 0", ".0f");
725 return printf (pformat, -0.25);
728 /* Output the number of seconds since the Epoch, using a format that
729 acts like printf's %f format. */
730 static void
731 out_epoch_sec (char *pformat, size_t prefix_len,
732 struct timespec arg)
734 char *dot = memchr (pformat, '.', prefix_len);
735 size_t sec_prefix_len = prefix_len;
736 int width = 0;
737 int precision = 0;
738 bool frac_left_adjust = false;
740 if (dot)
742 sec_prefix_len = dot - pformat;
743 pformat[prefix_len] = '\0';
745 if (ISDIGIT (dot[1]))
747 long int lprec = strtol (dot + 1, NULL, 10);
748 precision = (lprec <= INT_MAX ? lprec : INT_MAX);
750 else
752 precision = 9;
755 if (precision && ISDIGIT (dot[-1]))
757 /* If a nontrivial width is given, subtract the width of the
758 decimal point and PRECISION digits that will be output
759 later. */
760 char *p = dot;
761 *dot = '\0';
764 --p;
765 while (ISDIGIT (p[-1]));
767 long int lwidth = strtol (p, NULL, 10);
768 width = (lwidth <= INT_MAX ? lwidth : INT_MAX);
769 if (1 < width)
771 p += (*p == '0');
772 sec_prefix_len = p - pformat;
773 int w_d = (decimal_point_len < width
774 ? width - decimal_point_len
775 : 0);
776 if (1 < w_d)
778 int w = w_d - precision;
779 if (1 < w)
781 char *dst = pformat;
782 for (char const *src = dst; src < p; src++)
784 if (*src == '-')
785 frac_left_adjust = true;
786 else
787 *dst++ = *src;
789 sec_prefix_len =
790 (dst - pformat
791 + (frac_left_adjust ? 0 : sprintf (dst, "%d", w)));
798 int divisor = 1;
799 for (int i = precision; i < 9; i++)
800 divisor *= 10;
801 int frac_sec = arg.tv_nsec / divisor;
802 int int_len;
804 if (TYPE_SIGNED (time_t))
806 bool minus_zero = false;
807 if (arg.tv_sec < 0 && arg.tv_nsec != 0)
809 int frac_sec_modulus = 1000000000 / divisor;
810 frac_sec = (frac_sec_modulus - frac_sec
811 - (arg.tv_nsec % divisor != 0));
812 arg.tv_sec += (frac_sec != 0);
813 minus_zero = (arg.tv_sec == 0);
815 int_len = (minus_zero
816 ? out_minus_zero (pformat, sec_prefix_len)
817 : out_int (pformat, sec_prefix_len, arg.tv_sec));
819 else
820 int_len = out_uint (pformat, sec_prefix_len, arg.tv_sec);
822 if (precision)
824 int prec = (precision < 9 ? precision : 9);
825 int trailing_prec = precision - prec;
826 int ilen = (int_len < 0 ? 0 : int_len);
827 int trailing_width = (ilen < width && decimal_point_len < width - ilen
828 ? width - ilen - decimal_point_len - prec
829 : 0);
830 printf ("%s%.*d%-*.*d", decimal_point, prec, frac_sec,
831 trailing_width, trailing_prec, 0);
835 /* Print the context information of FILENAME, and return true iff the
836 context could not be obtained. */
837 NODISCARD
838 static bool
839 out_file_context (char *pformat, size_t prefix_len, char const *filename)
841 char *scontext;
842 bool fail = false;
844 if ((follow_links
845 ? getfilecon (filename, &scontext)
846 : lgetfilecon (filename, &scontext)) < 0)
848 error (0, errno, _("failed to get security context of %s"),
849 quoteaf (filename));
850 scontext = NULL;
851 fail = true;
853 strcpy (pformat + prefix_len, "s");
854 printf (pformat, (scontext ? scontext : "?"));
855 if (scontext)
856 freecon (scontext);
857 return fail;
860 /* Print statfs info. Return zero upon success, nonzero upon failure. */
861 NODISCARD
862 static bool
863 print_statfs (char *pformat, size_t prefix_len, MAYBE_UNUSED char mod, char m,
864 int fd, char const *filename,
865 void const *data)
867 STRUCT_STATVFS const *statfsbuf = data;
868 bool fail = false;
870 switch (m)
872 case 'n':
873 out_string (pformat, prefix_len, filename);
874 break;
876 case 'i':
878 #if STRUCT_STATXFS_F_FSID_IS_INTEGER
879 uintmax_t fsid = statfsbuf->f_fsid;
880 #else
881 typedef unsigned int fsid_word;
882 verify (alignof (STRUCT_STATVFS) % alignof (fsid_word) == 0);
883 verify (offsetof (STRUCT_STATVFS, f_fsid) % alignof (fsid_word) == 0);
884 verify (sizeof statfsbuf->f_fsid % alignof (fsid_word) == 0);
885 fsid_word const *p = (fsid_word *) &statfsbuf->f_fsid;
887 /* Assume a little-endian word order, as that is compatible
888 with glibc's statvfs implementation. */
889 uintmax_t fsid = 0;
890 int words = sizeof statfsbuf->f_fsid / sizeof *p;
891 for (int i = 0; i < words && i * sizeof *p < sizeof fsid; i++)
893 uintmax_t u = p[words - 1 - i];
894 fsid |= u << (i * CHAR_BIT * sizeof *p);
896 #endif
897 out_uint_x (pformat, prefix_len, fsid);
899 break;
901 case 'l':
902 OUT_NAMEMAX (pformat, prefix_len, SB_F_NAMEMAX (statfsbuf));
903 break;
904 case 't':
905 #if HAVE_STRUCT_STATXFS_F_TYPE
906 out_uint_x (pformat, prefix_len, statfsbuf->f_type);
907 #else
908 fputc ('?', stdout);
909 #endif
910 break;
911 case 'T':
912 out_string (pformat, prefix_len, human_fstype (statfsbuf));
913 break;
914 case 'b':
915 out_int (pformat, prefix_len, statfsbuf->f_blocks);
916 break;
917 case 'f':
918 out_int (pformat, prefix_len, statfsbuf->f_bfree);
919 break;
920 case 'a':
921 out_int (pformat, prefix_len, statfsbuf->f_bavail);
922 break;
923 case 's':
924 out_uint (pformat, prefix_len, statfsbuf->f_bsize);
925 break;
926 case 'S':
928 uintmax_t frsize = STATFS_FRSIZE (statfsbuf);
929 if (! frsize)
930 frsize = statfsbuf->f_bsize;
931 out_uint (pformat, prefix_len, frsize);
933 break;
934 case 'c':
935 out_uint (pformat, prefix_len, statfsbuf->f_files);
936 break;
937 case 'd':
938 out_int (pformat, prefix_len, statfsbuf->f_ffree);
939 break;
940 default:
941 fputc ('?', stdout);
942 break;
944 return fail;
947 /* Return any bind mounted source for a path.
948 The caller should not free the returned buffer.
949 Return NULL if no bind mount found. */
950 NODISCARD
951 static char const *
952 find_bind_mount (char const * name)
954 char const * bind_mount = NULL;
956 static struct mount_entry *mount_list;
957 static bool tried_mount_list = false;
958 if (!tried_mount_list) /* attempt/warn once per process. */
960 if (!(mount_list = read_file_system_list (false)))
961 error (0, errno, "%s", _("cannot read table of mounted file systems"));
962 tried_mount_list = true;
965 struct stat name_stats;
966 if (stat (name, &name_stats) != 0)
967 return NULL;
969 struct mount_entry *me;
970 for (me = mount_list; me; me = me->me_next)
972 if (me->me_dummy && me->me_devname[0] == '/'
973 && STREQ (me->me_mountdir, name))
975 struct stat dev_stats;
977 if (stat (me->me_devname, &dev_stats) == 0
978 && SAME_INODE (name_stats, dev_stats))
980 bind_mount = me->me_devname;
981 break;
986 return bind_mount;
989 /* Print mount point. Return zero upon success, nonzero upon failure. */
990 NODISCARD
991 static bool
992 out_mount_point (char const *filename, char *pformat, size_t prefix_len,
993 const struct stat *statp)
996 char const *np = "?", *bp = NULL;
997 char *mp = NULL;
998 bool fail = true;
1000 /* Look for bind mounts first. Note we output the immediate alias,
1001 rather than further resolving to a base device mount point. */
1002 if (follow_links || !S_ISLNK (statp->st_mode))
1004 char *resolved = canonicalize_file_name (filename);
1005 if (!resolved)
1007 error (0, errno, _("failed to canonicalize %s"), quoteaf (filename));
1008 goto print_mount_point;
1010 bp = find_bind_mount (resolved);
1011 free (resolved);
1012 if (bp)
1014 fail = false;
1015 goto print_mount_point;
1019 /* If there is no direct bind mount, then navigate
1020 back up the tree looking for a device change.
1021 Note we don't detect if any of the directory components
1022 are bind mounted to the same device, but that's OK
1023 since we've not directly queried them. */
1024 if ((mp = find_mount_point (filename, statp)))
1026 /* This dir might be bind mounted to another device,
1027 so we resolve the bound source in that case also. */
1028 bp = find_bind_mount (mp);
1029 fail = false;
1032 print_mount_point:
1034 out_string (pformat, prefix_len, bp ? bp : mp ? mp : np);
1035 free (mp);
1036 return fail;
1039 /* Map a TS with negative TS.tv_nsec to {0,0}. */
1040 static inline struct timespec
1041 neg_to_zero (struct timespec ts)
1043 if (0 <= ts.tv_nsec)
1044 return ts;
1045 struct timespec z = {0, 0};
1046 return z;
1049 /* Set the quoting style default if the environment variable
1050 QUOTING_STYLE is set. */
1052 static void
1053 getenv_quoting_style (void)
1055 char const *q_style = getenv ("QUOTING_STYLE");
1056 if (q_style)
1058 int i = ARGMATCH (q_style, quoting_style_args, quoting_style_vals);
1059 if (0 <= i)
1060 set_quoting_style (NULL, quoting_style_vals[i]);
1061 else
1063 set_quoting_style (NULL, shell_escape_always_quoting_style);
1064 error (0, 0, _("ignoring invalid value of environment "
1065 "variable QUOTING_STYLE: %s"), quote (q_style));
1068 else
1069 set_quoting_style (NULL, shell_escape_always_quoting_style);
1072 /* Equivalent to quotearg(), but explicit to avoid syntax checks. */
1073 #define quoteN(x) quotearg_style (get_quoting_style (NULL), x)
1075 /* Output a single-character \ escape. */
1077 static void
1078 print_esc_char (char c)
1080 switch (c)
1082 case 'a': /* Alert. */
1083 c ='\a';
1084 break;
1085 case 'b': /* Backspace. */
1086 c ='\b';
1087 break;
1088 case 'e': /* Escape. */
1089 c ='\x1B';
1090 break;
1091 case 'f': /* Form feed. */
1092 c ='\f';
1093 break;
1094 case 'n': /* New line. */
1095 c ='\n';
1096 break;
1097 case 'r': /* Carriage return. */
1098 c ='\r';
1099 break;
1100 case 't': /* Horizontal tab. */
1101 c ='\t';
1102 break;
1103 case 'v': /* Vertical tab. */
1104 c ='\v';
1105 break;
1106 case '"':
1107 case '\\':
1108 break;
1109 default:
1110 error (0, 0, _("warning: unrecognized escape '\\%c'"), c);
1111 break;
1113 putchar (c);
1116 ATTRIBUTE_PURE
1117 static size_t
1118 format_code_offset (char const *directive)
1120 size_t len = strspn (directive + 1, printf_flags);
1121 char const *fmt_char = directive + len + 1;
1122 fmt_char += strspn (fmt_char, digits);
1123 if (*fmt_char == '.')
1124 fmt_char += 1 + strspn (fmt_char + 1, digits);
1125 return fmt_char - directive;
1128 /* Print the information specified by the format string, FORMAT,
1129 calling PRINT_FUNC for each %-directive encountered.
1130 Return zero upon success, nonzero upon failure. */
1131 NODISCARD
1132 static bool
1133 print_it (char const *format, int fd, char const *filename,
1134 bool (*print_func) (char *, size_t, char, char,
1135 int, char const *, void const *),
1136 void const *data)
1138 bool fail = false;
1140 /* Add 2 to accommodate our conversion of the stat '%s' format string
1141 to the longer printf '%llu' one. */
1142 enum
1144 MAX_ADDITIONAL_BYTES =
1145 (MAX (sizeof PRIdMAX,
1146 MAX (sizeof PRIoMAX, MAX (sizeof PRIuMAX, sizeof PRIxMAX)))
1147 - 1)
1149 size_t n_alloc = strlen (format) + MAX_ADDITIONAL_BYTES + 1;
1150 char *dest = xmalloc (n_alloc);
1151 char const *b;
1152 for (b = format; *b; b++)
1154 switch (*b)
1156 case '%':
1158 size_t len = format_code_offset (b);
1159 char fmt_char = *(b + len);
1160 char mod_char = 0;
1161 memcpy (dest, b, len);
1162 b += len;
1164 switch (fmt_char)
1166 case '\0':
1167 --b;
1168 FALLTHROUGH;
1169 case '%':
1170 if (1 < len)
1172 dest[len] = fmt_char;
1173 dest[len + 1] = '\0';
1174 die (EXIT_FAILURE, 0, _("%s: invalid directive"),
1175 quote (dest));
1177 putchar ('%');
1178 break;
1179 case 'H':
1180 case 'L':
1181 mod_char = fmt_char;
1182 fmt_char = *(b + 1);
1183 if (print_func == print_stat
1184 && (fmt_char == 'd' || fmt_char == 'r'))
1186 b++;
1188 else
1190 fmt_char = mod_char;
1191 mod_char = 0;
1193 FALLTHROUGH;
1194 default:
1195 fail |= print_func (dest, len, mod_char, fmt_char,
1196 fd, filename, data);
1197 break;
1199 break;
1202 case '\\':
1203 if ( ! interpret_backslash_escapes)
1205 putchar ('\\');
1206 break;
1208 ++b;
1209 if (isodigit (*b))
1211 int esc_value = octtobin (*b);
1212 int esc_length = 1; /* number of octal digits */
1213 for (++b; esc_length < 3 && isodigit (*b);
1214 ++esc_length, ++b)
1216 esc_value = esc_value * 8 + octtobin (*b);
1218 putchar (esc_value);
1219 --b;
1221 else if (*b == 'x' && isxdigit (to_uchar (b[1])))
1223 int esc_value = hextobin (b[1]); /* Value of \xhh escape. */
1224 /* A hexadecimal \xhh escape sequence must have
1225 1 or 2 hex. digits. */
1226 ++b;
1227 if (isxdigit (to_uchar (b[1])))
1229 ++b;
1230 esc_value = esc_value * 16 + hextobin (*b);
1232 putchar (esc_value);
1234 else if (*b == '\0')
1236 error (0, 0, _("warning: backslash at end of format"));
1237 putchar ('\\');
1238 /* Arrange to exit the loop. */
1239 --b;
1241 else
1243 print_esc_char (*b);
1245 break;
1247 default:
1248 putchar (*b);
1249 break;
1252 free (dest);
1254 fputs (trailing_delim, stdout);
1256 return fail;
1259 /* Stat the file system and print what we find. */
1260 NODISCARD
1261 static bool
1262 do_statfs (char const *filename, char const *format)
1264 STRUCT_STATVFS statfsbuf;
1266 if (STREQ (filename, "-"))
1268 error (0, 0, _("using %s to denote standard input does not work"
1269 " in file system mode"), quoteaf (filename));
1270 return false;
1273 if (STATFS (filename, &statfsbuf) != 0)
1275 error (0, errno, _("cannot read file system information for %s"),
1276 quoteaf (filename));
1277 return false;
1280 bool fail = print_it (format, -1, filename, print_statfs, &statfsbuf);
1281 return ! fail;
1284 struct print_args {
1285 struct stat *st;
1286 struct timespec btime;
1289 /* Ask statx to avoid syncing? */
1290 static bool dont_sync;
1292 /* Ask statx to force sync? */
1293 static bool force_sync;
1295 #if USE_STATX
1296 static unsigned int
1297 fmt_to_mask (char fmt)
1299 switch (fmt)
1301 case 'N':
1302 return STATX_MODE;
1303 case 'd':
1304 case 'D':
1305 return STATX_MODE;
1306 case 'i':
1307 return STATX_INO;
1308 case 'a':
1309 case 'A':
1310 return STATX_MODE;
1311 case 'f':
1312 return STATX_MODE|STATX_TYPE;
1313 case 'F':
1314 return STATX_TYPE;
1315 case 'h':
1316 return STATX_NLINK;
1317 case 'u':
1318 case 'U':
1319 return STATX_UID;
1320 case 'g':
1321 case 'G':
1322 return STATX_GID;
1323 case 'm':
1324 return STATX_MODE|STATX_INO;
1325 case 's':
1326 return STATX_SIZE;
1327 case 't':
1328 case 'T':
1329 return STATX_MODE;
1330 case 'b':
1331 return STATX_BLOCKS;
1332 case 'w':
1333 case 'W':
1334 return STATX_BTIME;
1335 case 'x':
1336 case 'X':
1337 return STATX_ATIME;
1338 case 'y':
1339 case 'Y':
1340 return STATX_MTIME;
1341 case 'z':
1342 case 'Z':
1343 return STATX_CTIME;
1345 return 0;
1348 ATTRIBUTE_PURE
1349 static unsigned int
1350 format_to_mask (char const *format)
1352 unsigned int mask = 0;
1353 char const *b;
1355 for (b = format; *b; b++)
1357 if (*b != '%')
1358 continue;
1360 b += format_code_offset (b);
1361 if (*b == '\0')
1362 break;
1363 mask |= fmt_to_mask (*b);
1365 return mask;
1368 /* statx the file and print what we find */
1369 NODISCARD
1370 static bool
1371 do_stat (char const *filename, char const *format, char const *format2)
1373 int fd = STREQ (filename, "-") ? 0 : AT_FDCWD;
1374 int flags = 0;
1375 struct stat st;
1376 struct statx stx = { 0, };
1377 char const *pathname = filename;
1378 struct print_args pa;
1379 pa.st = &st;
1380 pa.btime = (struct timespec) {-1, -1};
1382 if (AT_FDCWD != fd)
1384 pathname = "";
1385 flags = AT_EMPTY_PATH;
1387 else if (!follow_links)
1389 flags = AT_SYMLINK_NOFOLLOW;
1392 if (dont_sync)
1393 flags |= AT_STATX_DONT_SYNC;
1394 else if (force_sync)
1395 flags |= AT_STATX_FORCE_SYNC;
1397 fd = statx (fd, pathname, flags, format_to_mask (format), &stx);
1398 if (fd < 0)
1400 if (flags & AT_EMPTY_PATH)
1401 error (0, errno, _("cannot stat standard input"));
1402 else
1403 error (0, errno, _("cannot statx %s"), quoteaf (filename));
1404 return false;
1407 if (S_ISBLK (stx.stx_mode) || S_ISCHR (stx.stx_mode))
1408 format = format2;
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);
1415 return ! fail;
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);
1425 # if HAVE_GETATTRAT
1426 if (ts.tv_nsec < 0)
1428 nvlist_t *response;
1429 if ((fd < 0
1430 ? getattrat (AT_FDCWD, XATTR_VIEW_READWRITE, filename, &response)
1431 : fgetattr (fd, XATTR_VIEW_READWRITE, &response))
1432 == 0)
1434 uint64_t *val;
1435 uint_t n;
1436 if (nvlist_lookup_uint64_array (response, A_CRTIME, &val, &n) == 0
1437 && 2 <= n
1438 && val[0] <= TYPE_MAXIMUM (time_t)
1439 && val[1] < 1000000000 * 2 /* for leap seconds */)
1441 ts.tv_sec = val[0];
1442 ts.tv_nsec = val[1];
1444 nvlist_free (response);
1447 # endif
1449 return ts;
1453 /* stat the file and print what we find */
1454 NODISCARD
1455 static bool
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;
1462 pa.st = &statbuf;
1463 pa.btime = (struct timespec) {-1, -1};
1465 if (0 <= fd)
1467 if (fstat (fd, &statbuf) != 0)
1469 error (0, errno, _("cannot stat standard input"));
1470 return false;
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));
1481 return false;
1484 if (S_ISBLK (statbuf.st_mode) || S_ISCHR (statbuf.st_mode))
1485 format = format2;
1487 bool fail = print_it (format, fd, filename, print_stat, &pa);
1488 return ! fail;
1490 #endif /* USE_STATX */
1493 /* Print stat info. Return zero upon success, nonzero upon failure. */
1494 static bool
1495 print_stat (char *pformat, size_t prefix_len, char mod, char m,
1496 int fd, char const *filename, void const *data)
1498 struct print_args *parg = (struct print_args *) data;
1499 struct stat *statbuf = parg->st;
1500 struct timespec btime = parg->btime;
1501 struct passwd *pw_ent;
1502 struct group *gw_ent;
1503 bool fail = false;
1505 switch (m)
1507 case 'n':
1508 out_string (pformat, prefix_len, filename);
1509 break;
1510 case 'N':
1511 out_string (pformat, prefix_len, quoteN (filename));
1512 if (S_ISLNK (statbuf->st_mode))
1514 char *linkname = areadlink_with_size (filename, statbuf->st_size);
1515 if (linkname == NULL)
1517 error (0, errno, _("cannot read symbolic link %s"),
1518 quoteaf (filename));
1519 return true;
1521 printf (" -> ");
1522 out_string (pformat, prefix_len, quoteN (linkname));
1523 free (linkname);
1525 break;
1526 case 'd':
1527 if (mod == 'H')
1528 out_uint (pformat, prefix_len, major (statbuf->st_dev));
1529 else if (mod == 'L')
1530 out_uint (pformat, prefix_len, minor (statbuf->st_dev));
1531 else
1532 out_uint (pformat, prefix_len, statbuf->st_dev);
1533 break;
1534 case 'D':
1535 out_uint_x (pformat, prefix_len, statbuf->st_dev);
1536 break;
1537 case 'i':
1538 out_uint (pformat, prefix_len, statbuf->st_ino);
1539 break;
1540 case 'a':
1541 out_uint_o (pformat, prefix_len, statbuf->st_mode & CHMOD_MODE_BITS);
1542 break;
1543 case 'A':
1544 out_string (pformat, prefix_len, human_access (statbuf));
1545 break;
1546 case 'f':
1547 out_uint_x (pformat, prefix_len, statbuf->st_mode);
1548 break;
1549 case 'F':
1550 out_string (pformat, prefix_len, file_type (statbuf));
1551 break;
1552 case 'h':
1553 out_uint (pformat, prefix_len, statbuf->st_nlink);
1554 break;
1555 case 'u':
1556 out_uint (pformat, prefix_len, statbuf->st_uid);
1557 break;
1558 case 'U':
1559 pw_ent = getpwuid (statbuf->st_uid);
1560 out_string (pformat, prefix_len,
1561 pw_ent ? pw_ent->pw_name : "UNKNOWN");
1562 break;
1563 case 'g':
1564 out_uint (pformat, prefix_len, statbuf->st_gid);
1565 break;
1566 case 'G':
1567 gw_ent = getgrgid (statbuf->st_gid);
1568 out_string (pformat, prefix_len,
1569 gw_ent ? gw_ent->gr_name : "UNKNOWN");
1570 break;
1571 case 'm':
1572 fail |= out_mount_point (filename, pformat, prefix_len, statbuf);
1573 break;
1574 case 's':
1575 out_int (pformat, prefix_len, statbuf->st_size);
1576 break;
1577 case 'r':
1578 if (mod == 'H')
1579 out_uint (pformat, prefix_len, major (statbuf->st_rdev));
1580 else if (mod == 'L')
1581 out_uint (pformat, prefix_len, minor (statbuf->st_rdev));
1582 else
1583 out_uint (pformat, prefix_len, statbuf->st_rdev);
1584 break;
1585 case 'R':
1586 out_uint_x (pformat, prefix_len, statbuf->st_rdev);
1587 break;
1588 case 't':
1589 out_uint_x (pformat, prefix_len, major (statbuf->st_rdev));
1590 break;
1591 case 'T':
1592 out_uint_x (pformat, prefix_len, minor (statbuf->st_rdev));
1593 break;
1594 case 'B':
1595 out_uint (pformat, prefix_len, ST_NBLOCKSIZE);
1596 break;
1597 case 'b':
1598 out_uint (pformat, prefix_len, ST_NBLOCKS (*statbuf));
1599 break;
1600 case 'o':
1601 out_uint (pformat, prefix_len, ST_BLKSIZE (*statbuf));
1602 break;
1603 case 'w':
1605 #if ! USE_STATX
1606 btime = get_birthtime (fd, filename, statbuf);
1607 #endif
1608 if (btime.tv_nsec < 0)
1609 out_string (pformat, prefix_len, "-");
1610 else
1611 out_string (pformat, prefix_len, human_time (btime));
1613 break;
1614 case 'W':
1616 #if ! USE_STATX
1617 btime = get_birthtime (fd, filename, statbuf);
1618 #endif
1619 out_epoch_sec (pformat, prefix_len, neg_to_zero (btime));
1621 break;
1622 case 'x':
1623 out_string (pformat, prefix_len, human_time (get_stat_atime (statbuf)));
1624 break;
1625 case 'X':
1626 out_epoch_sec (pformat, prefix_len, get_stat_atime (statbuf));
1627 break;
1628 case 'y':
1629 out_string (pformat, prefix_len, human_time (get_stat_mtime (statbuf)));
1630 break;
1631 case 'Y':
1632 out_epoch_sec (pformat, prefix_len, get_stat_mtime (statbuf));
1633 break;
1634 case 'z':
1635 out_string (pformat, prefix_len, human_time (get_stat_ctime (statbuf)));
1636 break;
1637 case 'Z':
1638 out_epoch_sec (pformat, prefix_len, get_stat_ctime (statbuf));
1639 break;
1640 case 'C':
1641 fail |= out_file_context (pformat, prefix_len, filename);
1642 break;
1643 default:
1644 fputc ('?', stdout);
1645 break;
1647 return fail;
1650 /* Return an allocated format string in static storage that
1651 corresponds to whether FS and TERSE options were declared. */
1652 static char *
1653 default_format (bool fs, bool terse, bool device)
1655 char *format;
1656 if (fs)
1658 if (terse)
1659 format = xstrdup (fmt_terse_fs);
1660 else
1662 /* TRANSLATORS: This string uses format specifiers from
1663 'stat --help' with --file-system, and NOT from printf. */
1664 format = xstrdup (_(" File: \"%n\"\n"
1665 " ID: %-8i Namelen: %-7l Type: %T\n"
1666 "Block size: %-10s Fundamental block size: %S\n"
1667 "Blocks: Total: %-10b Free: %-10f Available: %a\n"
1668 "Inodes: Total: %-10c Free: %d\n"));
1671 else /* ! fs */
1673 if (terse)
1675 if (0 < is_selinux_enabled ())
1676 format = xstrdup (fmt_terse_selinux);
1677 else
1678 format = xstrdup (fmt_terse_regular);
1680 else
1682 char *temp;
1683 /* TRANSLATORS: This string uses format specifiers from
1684 'stat --help' without --file-system, and NOT from printf. */
1685 format = xstrdup (_("\
1686 File: %N\n\
1687 Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n\
1688 "));
1690 temp = format;
1691 if (device)
1693 /* TRANSLATORS: This string uses format specifiers from
1694 'stat --help' without --file-system, and NOT from printf. */
1695 format = xasprintf ("%s%s", format, _("\
1696 " "Device: %Hd,%Ld\tInode: %-10i Links: %-5h Device type: %Hr,%Lr\n\
1697 "));
1699 else
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: %h\n\
1705 "));
1707 free (temp);
1709 temp = format;
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 " "Access: (%04a/%10.10A) Uid: (%5u/%8U) Gid: (%5g/%8G)\n\
1714 "));
1715 free (temp);
1717 if (0 < is_selinux_enabled ())
1719 temp = format;
1720 /* TRANSLATORS: This string uses format specifiers from
1721 'stat --help' without --file-system, and NOT from printf. */
1722 format = xasprintf ("%s%s", format, _("Context: %C\n"));
1723 free (temp);
1726 temp = format;
1727 /* TRANSLATORS: This string uses format specifiers from
1728 'stat --help' without --file-system, and NOT from printf. */
1729 format = xasprintf ("%s%s", format,
1730 _("Access: %x\n"
1731 "Modify: %y\n"
1732 "Change: %z\n"
1733 " Birth: %w\n"));
1734 free (temp);
1737 return format;
1740 void
1741 usage (int status)
1743 if (status != EXIT_SUCCESS)
1744 emit_try_help ();
1745 else
1747 printf (_("Usage: %s [OPTION]... FILE...\n"), program_name);
1748 fputs (_("\
1749 Display file or file system status.\n\
1750 "), stdout);
1752 emit_mandatory_arg_note ();
1754 fputs (_("\
1755 -L, --dereference follow links\n\
1756 -f, --file-system display file system status instead of file status\n\
1757 "), stdout);
1758 fputs (_("\
1759 --cached=MODE specify how to use cached attributes;\n\
1760 useful on remote file systems. See MODE below\n\
1761 "), stdout);
1762 fputs (_("\
1763 -c --format=FORMAT use the specified FORMAT instead of the default;\n\
1764 output a newline after each use of FORMAT\n\
1765 --printf=FORMAT like --format, but interpret backslash escapes,\n\
1766 and do not output a mandatory trailing newline;\n\
1767 if you want a newline, include \\n in FORMAT\n\
1768 -t, --terse print the information in terse form\n\
1769 "), stdout);
1770 fputs (HELP_OPTION_DESCRIPTION, stdout);
1771 fputs (VERSION_OPTION_DESCRIPTION, stdout);
1773 fputs (_("\n\
1774 The MODE argument of --cached can be: always, never, or default.\n\
1775 'always' will use cached attributes if available, while\n\
1776 'never' will try to synchronize with the latest attributes, and\n\
1777 'default' will leave it up to the underlying file system.\n\
1778 "), stdout);
1780 fputs (_("\n\
1781 The valid format sequences for files (without --file-system):\n\
1783 %a permission bits in octal (note '#' and '0' printf flags)\n\
1784 %A permission bits and file type in human readable form\n\
1785 %b number of blocks allocated (see %B)\n\
1786 %B the size in bytes of each block reported by %b\n\
1787 %C SELinux security context string\n\
1788 "), stdout);
1789 fputs (_("\
1790 %d device number in decimal (st_dev)\n\
1791 %D device number in hex (st_dev)\n\
1792 %Hd major device number in decimal\n\
1793 %Ld minor device number in decimal\n\
1794 %f raw mode in hex\n\
1795 %F file type\n\
1796 %g group ID of owner\n\
1797 %G group name of owner\n\
1798 "), stdout);
1799 fputs (_("\
1800 %h number of hard links\n\
1801 %i inode number\n\
1802 %m mount point\n\
1803 %n file name\n\
1804 %N quoted file name with dereference if symbolic link\n\
1805 %o optimal I/O transfer size hint\n\
1806 %s total size, in bytes\n\
1807 %r device type in decimal (st_rdev)\n\
1808 %R device type in hex (st_rdev)\n\
1809 %Hr major device type in decimal, for character/block device special files\n\
1810 %Lr minor device type in decimal, for character/block device special files\n\
1811 %t major device type in hex, for character/block device special files\n\
1812 %T minor device type in hex, for character/block device special files\n\
1813 "), stdout);
1814 fputs (_("\
1815 %u user ID of owner\n\
1816 %U user name of owner\n\
1817 %w time of file birth, human-readable; - if unknown\n\
1818 %W time of file birth, seconds since Epoch; 0 if unknown\n\
1819 %x time of last access, human-readable\n\
1820 %X time of last access, seconds since Epoch\n\
1821 %y time of last data modification, human-readable\n\
1822 %Y time of last data modification, seconds since Epoch\n\
1823 %z time of last status change, human-readable\n\
1824 %Z time of last status change, seconds since Epoch\n\
1826 "), stdout);
1828 fputs (_("\
1829 Valid format sequences for file systems:\n\
1831 %a free blocks available to non-superuser\n\
1832 %b total data blocks in file system\n\
1833 %c total file nodes in file system\n\
1834 %d free file nodes in file system\n\
1835 %f free blocks in file system\n\
1836 "), stdout);
1837 fputs (_("\
1838 %i file system ID in hex\n\
1839 %l maximum length of filenames\n\
1840 %n file name\n\
1841 %s block size (for faster transfers)\n\
1842 %S fundamental block size (for block counts)\n\
1843 %t file system type in hex\n\
1844 %T file system type in human readable form\n\
1845 "), stdout);
1847 printf (_("\n\
1848 --terse is equivalent to the following FORMAT:\n\
1851 #if HAVE_SELINUX_SELINUX_H
1852 fmt_terse_selinux
1853 #else
1854 fmt_terse_regular
1855 #endif
1858 printf (_("\
1859 --terse --file-system is equivalent to the following FORMAT:\n\
1861 "), fmt_terse_fs);
1863 printf (USAGE_BUILTIN_WARNING, PROGRAM_NAME);
1864 emit_ancillary_info (PROGRAM_NAME);
1866 exit (status);
1870 main (int argc, char *argv[])
1872 int c;
1873 bool fs = false;
1874 bool terse = false;
1875 char *format = NULL;
1876 char *format2;
1877 bool ok = true;
1879 initialize_main (&argc, &argv);
1880 set_program_name (argv[0]);
1881 setlocale (LC_ALL, "");
1882 bindtextdomain (PACKAGE, LOCALEDIR);
1883 textdomain (PACKAGE);
1885 struct lconv const *locale = localeconv ();
1886 decimal_point = (locale->decimal_point[0] ? locale->decimal_point : ".");
1887 decimal_point_len = strlen (decimal_point);
1889 atexit (close_stdout);
1891 while ((c = getopt_long (argc, argv, "c:fLt", long_options, NULL)) != -1)
1893 switch (c)
1895 case PRINTF_OPTION:
1896 format = optarg;
1897 interpret_backslash_escapes = true;
1898 trailing_delim = "";
1899 break;
1901 case 'c':
1902 format = optarg;
1903 interpret_backslash_escapes = false;
1904 trailing_delim = "\n";
1905 break;
1907 case 'L':
1908 follow_links = true;
1909 break;
1911 case 'f':
1912 fs = true;
1913 break;
1915 case 't':
1916 terse = true;
1917 break;
1919 case 0:
1920 switch (XARGMATCH ("--cached", optarg, cached_args, cached_modes))
1922 case cached_never:
1923 force_sync = true;
1924 dont_sync = false;
1925 break;
1926 case cached_always:
1927 force_sync = false;
1928 dont_sync = true;
1929 break;
1930 case cached_default:
1931 force_sync = false;
1932 dont_sync = false;
1934 break;
1936 case_GETOPT_HELP_CHAR;
1938 case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
1940 default:
1941 usage (EXIT_FAILURE);
1945 if (argc == optind)
1947 error (0, 0, _("missing operand"));
1948 usage (EXIT_FAILURE);
1951 if (format)
1953 if (strstr (format, "%N"))
1954 getenv_quoting_style ();
1955 format2 = format;
1957 else
1959 format = default_format (fs, terse, /* device= */ false);
1960 format2 = default_format (fs, terse, /* device= */ true);
1963 for (int i = optind; i < argc; i++)
1964 ok &= (fs
1965 ? do_statfs (argv[i], format)
1966 : do_stat (argv[i], format, format2));
1968 return ok ? EXIT_SUCCESS : EXIT_FAILURE;