doc: od --strings: clarify operation
[coreutils.git] / src / stat.c
blobecb9696ca15926d21529dfa61ab23cc2c2e5e305
1 /* stat.c -- display file or file system status
2 Copyright (C) 2001-2023 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <https://www.gnu.org/licenses/>.
17 Written by Michael Meskes. */
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 <sys/types.h>
34 #include <pwd.h>
35 #include <grp.h>
36 #if USE_STATVFS
37 # include <sys/statvfs.h>
38 #elif HAVE_SYS_VFS_H
39 # include <sys/vfs.h>
40 #elif HAVE_SYS_MOUNT_H && HAVE_SYS_PARAM_H
41 /* NOTE: freebsd5.0 needs sys/param.h and sys/mount.h for statfs.
42 It does have statvfs.h, but shouldn't use it, since it doesn't
43 HAVE_STRUCT_STATVFS_F_BASETYPE. So find a clean way to fix it. */
44 /* NetBSD 1.5.2 needs these, for the declaration of struct statfs. */
45 # include <sys/param.h>
46 # include <sys/mount.h>
47 # if HAVE_NFS_NFS_CLNT_H && HAVE_NFS_VFS_H
48 /* Ultrix 4.4 needs these for the declaration of struct statfs. */
49 # include <netinet/in.h>
50 # include <nfs/nfs_clnt.h>
51 # include <nfs/vfs.h>
52 # endif
53 #elif HAVE_OS_H /* BeOS */
54 # include <fs_info.h>
55 #endif
56 #include <selinux/selinux.h>
58 #include "system.h"
60 #include "areadlink.h"
61 #include "argmatch.h"
62 #include "die.h"
63 #include "error.h"
64 #include "file-type.h"
65 #include "filemode.h"
66 #include "fs.h"
67 #include "getopt.h"
68 #include "mountlist.h"
69 #include "quote.h"
70 #include "stat-size.h"
71 #include "stat-time.h"
72 #include "strftime.h"
73 #include "find-mount-point.h"
74 #include "xvasprintf.h"
75 #include "statx.h"
77 #if HAVE_STATX && defined STATX_INO
78 # define USE_STATX 1
79 #else
80 # define USE_STATX 0
81 #endif
83 #if USE_STATVFS
84 # define STRUCT_STATXFS_F_FSID_IS_INTEGER STRUCT_STATVFS_F_FSID_IS_INTEGER
85 # define HAVE_STRUCT_STATXFS_F_TYPE HAVE_STRUCT_STATVFS_F_TYPE
86 # if HAVE_STRUCT_STATVFS_F_NAMEMAX
87 # define SB_F_NAMEMAX(S) ((S)->f_namemax)
88 # endif
89 # if ! STAT_STATVFS && STAT_STATVFS64
90 # define STRUCT_STATVFS struct statvfs64
91 # define STATFS statvfs64
92 # else
93 # define STRUCT_STATVFS struct statvfs
94 # define STATFS statvfs
95 # endif
96 # define STATFS_FRSIZE(S) ((S)->f_frsize)
97 #else
98 # define HAVE_STRUCT_STATXFS_F_TYPE HAVE_STRUCT_STATFS_F_TYPE
99 # if HAVE_STRUCT_STATFS_F_NAMELEN
100 # define SB_F_NAMEMAX(S) ((S)->f_namelen)
101 # elif HAVE_STRUCT_STATFS_F_NAMEMAX
102 # define SB_F_NAMEMAX(S) ((S)->f_namemax)
103 # endif
104 # define STATFS statfs
105 # if HAVE_OS_H /* BeOS */
106 /* BeOS has a statvfs function, but it does not return sensible values
107 for f_files, f_ffree and f_favail, and lacks f_type, f_basetype and
108 f_fstypename. Use 'struct fs_info' instead. */
109 NODISCARD
110 static int
111 statfs (char const *filename, struct fs_info *buf)
113 dev_t device = dev_for_path (filename);
114 if (device < 0)
116 errno = (device == B_ENTRY_NOT_FOUND ? ENOENT
117 : device == B_BAD_VALUE ? EINVAL
118 : device == B_NAME_TOO_LONG ? ENAMETOOLONG
119 : device == B_NO_MEMORY ? ENOMEM
120 : device == B_FILE_ERROR ? EIO
121 : 0);
122 return -1;
124 /* If successful, buf->dev will be == device. */
125 return fs_stat_dev (device, buf);
127 # define f_fsid dev
128 # define f_blocks total_blocks
129 # define f_bfree free_blocks
130 # define f_bavail free_blocks
131 # define f_bsize io_size
132 # define f_files total_nodes
133 # define f_ffree free_nodes
134 # define STRUCT_STATVFS struct fs_info
135 # define STRUCT_STATXFS_F_FSID_IS_INTEGER true
136 # define STATFS_FRSIZE(S) ((S)->block_size)
137 # else
138 # define STRUCT_STATVFS struct statfs
139 # define STRUCT_STATXFS_F_FSID_IS_INTEGER STRUCT_STATFS_F_FSID_IS_INTEGER
140 # if HAVE_STRUCT_STATFS_F_FRSIZE
141 # define STATFS_FRSIZE(S) ((S)->f_frsize)
142 # else
143 # define STATFS_FRSIZE(S) 0
144 # endif
145 # endif
146 #endif
148 #ifdef SB_F_NAMEMAX
149 # define OUT_NAMEMAX out_uint
150 #else
151 /* Depending on whether statvfs or statfs is used,
152 neither f_namemax or f_namelen may be available. */
153 # define SB_F_NAMEMAX(S) "?"
154 # define OUT_NAMEMAX out_string
155 #endif
157 #if HAVE_STRUCT_STATVFS_F_BASETYPE
158 # define STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME f_basetype
159 #else
160 # if HAVE_STRUCT_STATVFS_F_FSTYPENAME || HAVE_STRUCT_STATFS_F_FSTYPENAME
161 # define STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME f_fstypename
162 # elif HAVE_OS_H /* BeOS */
163 # define STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME fsh_name
164 # endif
165 #endif
167 #if HAVE_GETATTRAT
168 # include <attr.h>
169 # include <sys/nvpair.h>
170 #endif
172 /* FIXME: these are used by printf.c, too */
173 #define isodigit(c) ('0' <= (c) && (c) <= '7')
174 #define octtobin(c) ((c) - '0')
175 #define hextobin(c) ((c) >= 'a' && (c) <= 'f' ? (c) - 'a' + 10 : \
176 (c) >= 'A' && (c) <= 'F' ? (c) - 'A' + 10 : (c) - '0')
178 static char const digits[] = "0123456789";
180 /* Flags that are portable for use in printf, for at least one
181 conversion specifier; make_format removes unportable flags as
182 needed for particular specifiers. The glibc 2.2 extension "I" is
183 listed here; it is removed by make_format because it has undefined
184 behavior elsewhere and because it is incompatible with
185 out_epoch_sec. */
186 static char const printf_flags[] = "'-+ #0I";
188 /* Formats for the --terse option. */
189 static char const fmt_terse_fs[] = "%n %i %l %t %s %S %b %f %a %c %d\n";
190 static char const fmt_terse_regular[] = "%n %s %b %f %u %g %D %i %h %t %T"
191 " %X %Y %Z %W %o\n";
192 static char const fmt_terse_selinux[] = "%n %s %b %f %u %g %D %i %h %t %T"
193 " %X %Y %Z %W %o %C\n";
195 #define PROGRAM_NAME "stat"
197 #define AUTHORS proper_name ("Michael Meskes")
199 enum
201 PRINTF_OPTION = CHAR_MAX + 1
204 enum cached_mode
206 cached_default,
207 cached_never,
208 cached_always
211 static char const *const cached_args[] =
213 "default", "never", "always", NULL
216 static enum cached_mode const cached_modes[] =
218 cached_default, cached_never, cached_always
221 static struct option const long_options[] =
223 {"dereference", no_argument, NULL, 'L'},
224 {"file-system", no_argument, NULL, 'f'},
225 {"format", required_argument, NULL, 'c'},
226 {"printf", required_argument, NULL, PRINTF_OPTION},
227 {"terse", no_argument, NULL, 't'},
228 {"cached", required_argument, NULL, 0},
229 {GETOPT_HELP_OPTION_DECL},
230 {GETOPT_VERSION_OPTION_DECL},
231 {NULL, 0, NULL, 0}
234 /* Whether to follow symbolic links; True for --dereference (-L). */
235 static bool follow_links;
237 /* Whether to interpret backslash-escape sequences.
238 True for --printf=FMT, not for --format=FMT (-c). */
239 static bool interpret_backslash_escapes;
241 /* The trailing delimiter string:
242 "" for --printf=FMT, "\n" for --format=FMT (-c). */
243 static char const *trailing_delim = "";
245 /* The representation of the decimal point in the current locale. */
246 static char const *decimal_point;
247 static size_t decimal_point_len;
249 static bool
250 print_stat (char *pformat, size_t prefix_len, char mod, char m,
251 int fd, char const *filename, void const *data);
253 /* Return the type of the specified file system.
254 Some systems have statfvs.f_basetype[FSTYPSZ] (AIX, HP-UX, and Solaris).
255 Others have statvfs.f_fstypename[_VFS_NAMELEN] (NetBSD 3.0).
256 Others have statfs.f_fstypename[MFSNAMELEN] (NetBSD 1.5.2).
257 Still others have neither and have to get by with f_type (GNU/Linux).
258 But f_type may only exist in statfs (Cygwin). */
259 NODISCARD
260 static char const *
261 human_fstype (STRUCT_STATVFS const *statfsbuf)
263 #ifdef STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME
264 return statfsbuf->STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME;
265 #else
266 switch (statfsbuf->f_type)
268 # if defined __linux__ || defined __ANDROID__
270 /* Compare with what's in libc:
271 f=/a/libc/sysdeps/unix/sysv/linux/linux_fsinfo.h
272 sed -n '/ADFS_SUPER_MAGIC/,/SYSFS_MAGIC/p' $f \
273 | perl -n -e '/#define (.*?)_(?:SUPER_)MAGIC\s+0x(\S+)/' \
274 -e 'and print "case S_MAGIC_$1: /\* 0x" . uc($2) . " *\/\n"' \
275 | sort > sym_libc
276 perl -ne '/^\s+(case S_MAGIC_.*?): \/\* 0x(\S+) \*\//' \
277 -e 'and do { $v=uc$2; print "$1: /\* 0x$v *\/\n"}' stat.c \
278 | sort > sym_stat
279 diff -u sym_stat sym_libc
282 /* Also compare with the list in "man 2 statfs" using the
283 fs-magic-compare make target. */
285 /* IMPORTANT NOTE: Each of the following 'case S_MAGIC_...:'
286 statements must be followed by a hexadecimal constant in
287 a comment. The S_MAGIC_... name and constant are automatically
288 combined to produce the #define directives in fs.h. */
290 case S_MAGIC_AAFS: /* 0x5A3C69F0 local */
291 return "aafs";
292 case S_MAGIC_ACFS: /* 0x61636673 remote */
293 return "acfs";
294 case S_MAGIC_ADFS: /* 0xADF5 local */
295 return "adfs";
296 case S_MAGIC_AFFS: /* 0xADFF local */
297 return "affs";
298 case S_MAGIC_AFS: /* 0x5346414F remote */
299 return "afs";
300 case S_MAGIC_ANON_INODE_FS: /* 0x09041934 local */
301 return "anon-inode FS";
302 case S_MAGIC_AUFS: /* 0x61756673 remote */
303 /* FIXME: change syntax or add an optional attribute like "inotify:no".
304 The above is labeled as "remote" so that tail always uses polling,
305 but this isn't really a remote file system type. */
306 return "aufs";
307 case S_MAGIC_AUTOFS: /* 0x0187 local */
308 return "autofs";
309 case S_MAGIC_BALLOON_KVM: /* 0x13661366 local */
310 return "balloon-kvm-fs";
311 case S_MAGIC_BEFS: /* 0x42465331 local */
312 return "befs";
313 case S_MAGIC_BDEVFS: /* 0x62646576 local */
314 return "bdevfs";
315 case S_MAGIC_BFS: /* 0x1BADFACE local */
316 return "bfs";
317 case S_MAGIC_BINDERFS: /* 0x6C6F6F70 local */
318 return "binderfs";
319 case S_MAGIC_BPF_FS: /* 0xCAFE4A11 local */
320 return "bpf_fs";
321 case S_MAGIC_BINFMTFS: /* 0x42494E4D local */
322 return "binfmt_misc";
323 case S_MAGIC_BTRFS: /* 0x9123683E local */
324 return "btrfs";
325 case S_MAGIC_BTRFS_TEST: /* 0x73727279 local */
326 return "btrfs_test";
327 case S_MAGIC_CEPH: /* 0x00C36400 remote */
328 return "ceph";
329 case S_MAGIC_CGROUP: /* 0x0027E0EB local */
330 return "cgroupfs";
331 case S_MAGIC_CGROUP2: /* 0x63677270 local */
332 return "cgroup2fs";
333 case S_MAGIC_CIFS: /* 0xFF534D42 remote */
334 return "cifs";
335 case S_MAGIC_CODA: /* 0x73757245 remote */
336 return "coda";
337 case S_MAGIC_COH: /* 0x012FF7B7 local */
338 return "coh";
339 case S_MAGIC_CONFIGFS: /* 0x62656570 local */
340 return "configfs";
341 case S_MAGIC_CRAMFS: /* 0x28CD3D45 local */
342 return "cramfs";
343 case S_MAGIC_CRAMFS_WEND: /* 0x453DCD28 local */
344 return "cramfs-wend";
345 case S_MAGIC_DAXFS: /* 0x64646178 local */
346 return "daxfs";
347 case S_MAGIC_DEBUGFS: /* 0x64626720 local */
348 return "debugfs";
349 case S_MAGIC_DEVFS: /* 0x1373 local */
350 return "devfs";
351 case S_MAGIC_DEVMEM: /* 0x454D444D local */
352 return "devmem";
353 case S_MAGIC_DEVPTS: /* 0x1CD1 local */
354 return "devpts";
355 case S_MAGIC_DMA_BUF: /* 0x444D4142 local */
356 return "dma-buf-fs";
357 case S_MAGIC_ECRYPTFS: /* 0xF15F local */
358 return "ecryptfs";
359 case S_MAGIC_EFIVARFS: /* 0xDE5E81E4 local */
360 return "efivarfs";
361 case S_MAGIC_EFS: /* 0x00414A53 local */
362 return "efs";
363 case S_MAGIC_EROFS_V1: /* 0xE0F5E1E2 local */
364 return "erofs";
365 case S_MAGIC_EXFAT: /* 0x2011BAB0 local */
366 return "exfat";
367 case S_MAGIC_EXFS: /* 0x45584653 local */
368 return "exfs";
369 case S_MAGIC_EXOFS: /* 0x5DF5 local */
370 return "exofs";
371 case S_MAGIC_EXT: /* 0x137D local */
372 return "ext";
373 case S_MAGIC_EXT2: /* 0xEF53 local */
374 return "ext2/ext3";
375 case S_MAGIC_EXT2_OLD: /* 0xEF51 local */
376 return "ext2";
377 case S_MAGIC_F2FS: /* 0xF2F52010 local */
378 return "f2fs";
379 case S_MAGIC_FAT: /* 0x4006 local */
380 return "fat";
381 case S_MAGIC_FHGFS: /* 0x19830326 remote */
382 return "fhgfs";
383 case S_MAGIC_FUSEBLK: /* 0x65735546 remote */
384 return "fuseblk";
385 case S_MAGIC_FUSECTL: /* 0x65735543 remote */
386 return "fusectl";
387 case S_MAGIC_FUTEXFS: /* 0x0BAD1DEA local */
388 return "futexfs";
389 case S_MAGIC_GFS: /* 0x01161970 remote */
390 return "gfs/gfs2";
391 case S_MAGIC_GPFS: /* 0x47504653 remote */
392 return "gpfs";
393 case S_MAGIC_HFS: /* 0x4244 local */
394 return "hfs";
395 case S_MAGIC_HFS_PLUS: /* 0x482B local */
396 return "hfs+";
397 case S_MAGIC_HFS_X: /* 0x4858 local */
398 return "hfsx";
399 case S_MAGIC_HOSTFS: /* 0x00C0FFEE local */
400 return "hostfs";
401 case S_MAGIC_HPFS: /* 0xF995E849 local */
402 return "hpfs";
403 case S_MAGIC_HUGETLBFS: /* 0x958458F6 local */
404 return "hugetlbfs";
405 case S_MAGIC_MTD_INODE_FS: /* 0x11307854 local */
406 return "inodefs";
407 case S_MAGIC_IBRIX: /* 0x013111A8 remote */
408 return "ibrix";
409 case S_MAGIC_INOTIFYFS: /* 0x2BAD1DEA local */
410 return "inotifyfs";
411 case S_MAGIC_ISOFS: /* 0x9660 local */
412 return "isofs";
413 case S_MAGIC_ISOFS_R_WIN: /* 0x4004 local */
414 return "isofs";
415 case S_MAGIC_ISOFS_WIN: /* 0x4000 local */
416 return "isofs";
417 case S_MAGIC_JFFS: /* 0x07C0 local */
418 return "jffs";
419 case S_MAGIC_JFFS2: /* 0x72B6 local */
420 return "jffs2";
421 case S_MAGIC_JFS: /* 0x3153464A local */
422 return "jfs";
423 case S_MAGIC_KAFS: /* 0x6B414653 remote */
424 return "k-afs";
425 case S_MAGIC_LOGFS: /* 0xC97E8168 local */
426 return "logfs";
427 case S_MAGIC_LUSTRE: /* 0x0BD00BD0 remote */
428 return "lustre";
429 case S_MAGIC_M1FS: /* 0x5346314D local */
430 return "m1fs";
431 case S_MAGIC_MINIX: /* 0x137F local */
432 return "minix";
433 case S_MAGIC_MINIX_30: /* 0x138F local */
434 return "minix (30 char.)";
435 case S_MAGIC_MINIX_V2: /* 0x2468 local */
436 return "minix v2";
437 case S_MAGIC_MINIX_V2_30: /* 0x2478 local */
438 return "minix v2 (30 char.)";
439 case S_MAGIC_MINIX_V3: /* 0x4D5A local */
440 return "minix3";
441 case S_MAGIC_MQUEUE: /* 0x19800202 local */
442 return "mqueue";
443 case S_MAGIC_MSDOS: /* 0x4D44 local */
444 return "msdos";
445 case S_MAGIC_NCP: /* 0x564C remote */
446 return "novell";
447 case S_MAGIC_NFS: /* 0x6969 remote */
448 return "nfs";
449 case S_MAGIC_NFSD: /* 0x6E667364 remote */
450 return "nfsd";
451 case S_MAGIC_NILFS: /* 0x3434 local */
452 return "nilfs";
453 case S_MAGIC_NSFS: /* 0x6E736673 local */
454 return "nsfs";
455 case S_MAGIC_NTFS: /* 0x5346544E local */
456 return "ntfs";
457 case S_MAGIC_OPENPROM: /* 0x9FA1 local */
458 return "openprom";
459 case S_MAGIC_OCFS2: /* 0x7461636F remote */
460 return "ocfs2";
461 case S_MAGIC_OVERLAYFS: /* 0x794C7630 remote */
462 /* This may overlay remote file systems.
463 Also there have been issues reported with inotify and overlayfs,
464 so mark as "remote" so that polling is used. */
465 return "overlayfs";
466 case S_MAGIC_PANFS: /* 0xAAD7AAEA remote */
467 return "panfs";
468 case S_MAGIC_PIPEFS: /* 0x50495045 remote */
469 /* FIXME: change syntax or add an optional attribute like "inotify:no".
470 pipefs and prlfs are labeled as "remote" so that tail always polls,
471 but these aren't really remote file system types. */
472 return "pipefs";
473 case S_MAGIC_PPC_CMM: /* 0xC7571590 local */
474 return "ppc-cmm-fs";
475 case S_MAGIC_PRL_FS: /* 0x7C7C6673 remote */
476 return "prl_fs";
477 case S_MAGIC_PROC: /* 0x9FA0 local */
478 return "proc";
479 case S_MAGIC_PSTOREFS: /* 0x6165676C local */
480 return "pstorefs";
481 case S_MAGIC_QNX4: /* 0x002F local */
482 return "qnx4";
483 case S_MAGIC_QNX6: /* 0x68191122 local */
484 return "qnx6";
485 case S_MAGIC_RAMFS: /* 0x858458F6 local */
486 return "ramfs";
487 case S_MAGIC_RDTGROUP: /* 0x07655821 local */
488 return "rdt";
489 case S_MAGIC_REISERFS: /* 0x52654973 local */
490 return "reiserfs";
491 case S_MAGIC_ROMFS: /* 0x7275 local */
492 return "romfs";
493 case S_MAGIC_RPC_PIPEFS: /* 0x67596969 local */
494 return "rpc_pipefs";
495 case S_MAGIC_SDCARDFS: /* 0x5DCA2DF5 local */
496 return "sdcardfs";
497 case S_MAGIC_SECRETMEM: /* 0x5345434D local */
498 return "secretmem";
499 case S_MAGIC_SECURITYFS: /* 0x73636673 local */
500 return "securityfs";
501 case S_MAGIC_SELINUX: /* 0xF97CFF8C local */
502 return "selinux";
503 case S_MAGIC_SMACK: /* 0x43415D53 local */
504 return "smackfs";
505 case S_MAGIC_SMB: /* 0x517B remote */
506 return "smb";
507 case S_MAGIC_SMB2: /* 0xFE534D42 remote */
508 return "smb2";
509 case S_MAGIC_SNFS: /* 0xBEEFDEAD remote */
510 return "snfs";
511 case S_MAGIC_SOCKFS: /* 0x534F434B local */
512 return "sockfs";
513 case S_MAGIC_SQUASHFS: /* 0x73717368 local */
514 return "squashfs";
515 case S_MAGIC_SYSFS: /* 0x62656572 local */
516 return "sysfs";
517 case S_MAGIC_SYSV2: /* 0x012FF7B6 local */
518 return "sysv2";
519 case S_MAGIC_SYSV4: /* 0x012FF7B5 local */
520 return "sysv4";
521 case S_MAGIC_TMPFS: /* 0x01021994 local */
522 return "tmpfs";
523 case S_MAGIC_TRACEFS: /* 0x74726163 local */
524 return "tracefs";
525 case S_MAGIC_UBIFS: /* 0x24051905 local */
526 return "ubifs";
527 case S_MAGIC_UDF: /* 0x15013346 local */
528 return "udf";
529 case S_MAGIC_UFS: /* 0x00011954 local */
530 return "ufs";
531 case S_MAGIC_UFS_BYTESWAPPED: /* 0x54190100 local */
532 return "ufs";
533 case S_MAGIC_USBDEVFS: /* 0x9FA2 local */
534 return "usbdevfs";
535 case S_MAGIC_V9FS: /* 0x01021997 local */
536 return "v9fs";
537 case S_MAGIC_VBOXSF: /* 0x786F4256 remote */
538 return "vboxsf";
539 case S_MAGIC_VMHGFS: /* 0xBACBACBC remote */
540 return "vmhgfs";
541 case S_MAGIC_VXFS: /* 0xA501FCF5 remote */
542 /* Veritas File System can run in single instance or clustered mode,
543 so mark as remote to cater for the latter case. */
544 return "vxfs";
545 case S_MAGIC_VZFS: /* 0x565A4653 local */
546 return "vzfs";
547 case S_MAGIC_WSLFS: /* 0x53464846 local */
548 return "wslfs";
549 case S_MAGIC_XENFS: /* 0xABBA1974 local */
550 return "xenfs";
551 case S_MAGIC_XENIX: /* 0x012FF7B4 local */
552 return "xenix";
553 case S_MAGIC_XFS: /* 0x58465342 local */
554 return "xfs";
555 case S_MAGIC_XIAFS: /* 0x012FD16D local */
556 return "xia";
557 case S_MAGIC_Z3FOLD: /* 0x0033 local */
558 return "z3fold";
559 case S_MAGIC_ZFS: /* 0x2FC12FC1 local */
560 return "zfs";
561 case S_MAGIC_ZONEFS: /* 0x5A4F4653 local */
562 return "zonefs";
563 case S_MAGIC_ZSMALLOC: /* 0x58295829 local */
564 return "zsmallocfs";
567 # elif __GNU__
568 case FSTYPE_UFS:
569 return "ufs";
570 case FSTYPE_NFS:
571 return "nfs";
572 case FSTYPE_GFS:
573 return "gfs";
574 case FSTYPE_LFS:
575 return "lfs";
576 case FSTYPE_SYSV:
577 return "sysv";
578 case FSTYPE_FTP:
579 return "ftp";
580 case FSTYPE_TAR:
581 return "tar";
582 case FSTYPE_AR:
583 return "ar";
584 case FSTYPE_CPIO:
585 return "cpio";
586 case FSTYPE_MSLOSS:
587 return "msloss";
588 case FSTYPE_CPM:
589 return "cpm";
590 case FSTYPE_HFS:
591 return "hfs";
592 case FSTYPE_DTFS:
593 return "dtfs";
594 case FSTYPE_GRFS:
595 return "grfs";
596 case FSTYPE_TERM:
597 return "term";
598 case FSTYPE_DEV:
599 return "dev";
600 case FSTYPE_PROC:
601 return "proc";
602 case FSTYPE_IFSOCK:
603 return "ifsock";
604 case FSTYPE_AFS:
605 return "afs";
606 case FSTYPE_DFS:
607 return "dfs";
608 case FSTYPE_PROC9:
609 return "proc9";
610 case FSTYPE_SOCKET:
611 return "socket";
612 case FSTYPE_MISC:
613 return "misc";
614 case FSTYPE_EXT2FS:
615 return "ext2/ext3";
616 case FSTYPE_HTTP:
617 return "http";
618 case FSTYPE_MEMFS:
619 return "memfs";
620 case FSTYPE_ISO9660:
621 return "iso9660";
622 # endif
623 default:
625 unsigned long int type = statfsbuf->f_type;
626 static char buf[sizeof "UNKNOWN (0x%lx)" - 3
627 + (sizeof type * CHAR_BIT + 3) / 4];
628 sprintf (buf, "UNKNOWN (0x%lx)", type);
629 return buf;
632 #endif
635 NODISCARD
636 static char *
637 human_access (struct stat const *statbuf)
639 static char modebuf[12];
640 filemodestring (statbuf, modebuf);
641 modebuf[10] = 0;
642 return modebuf;
645 NODISCARD
646 static char *
647 human_time (struct timespec t)
649 /* STR must be at least INT_BUFSIZE_BOUND (intmax_t) big, either
650 because localtime_rz fails, or because the time zone is truly
651 outlandish so that %z expands to a long string. */
652 static char str[INT_BUFSIZE_BOUND (intmax_t)
653 + INT_STRLEN_BOUND (int) /* YYYY */
654 + 1 /* because YYYY might equal INT_MAX + 1900 */
655 + sizeof "-MM-DD HH:MM:SS.NNNNNNNNN +"];
656 static timezone_t tz;
657 if (!tz)
658 tz = tzalloc (getenv ("TZ"));
659 struct tm tm;
660 int ns = t.tv_nsec;
661 if (localtime_rz (tz, &t.tv_sec, &tm))
662 nstrftime (str, sizeof str, "%Y-%m-%d %H:%M:%S.%N %z", &tm, tz, ns);
663 else
665 char secbuf[INT_BUFSIZE_BOUND (intmax_t)];
666 sprintf (str, "%s.%09d", timetostr (t.tv_sec, secbuf), ns);
668 return str;
671 /* PFORMAT points to a '%' followed by a prefix of a format, all of
672 size PREFIX_LEN. The flags allowed for this format are
673 ALLOWED_FLAGS; remove other printf flags from the prefix, then
674 append SUFFIX. */
675 static void
676 make_format (char *pformat, size_t prefix_len, char const *allowed_flags,
677 char const *suffix)
679 char *dst = pformat + 1;
680 char const *src;
681 char const *srclim = pformat + prefix_len;
682 for (src = dst; src < srclim && strchr (printf_flags, *src); src++)
683 if (strchr (allowed_flags, *src))
684 *dst++ = *src;
685 while (src < srclim)
686 *dst++ = *src++;
687 strcpy (dst, suffix);
690 static void
691 out_string (char *pformat, size_t prefix_len, char const *arg)
693 make_format (pformat, prefix_len, "-", "s");
694 printf (pformat, arg);
696 static int
697 out_int (char *pformat, size_t prefix_len, intmax_t arg)
699 make_format (pformat, prefix_len, "'-+ 0", PRIdMAX);
700 return printf (pformat, arg);
702 static int
703 out_uint (char *pformat, size_t prefix_len, uintmax_t arg)
705 make_format (pformat, prefix_len, "'-0", PRIuMAX);
706 return printf (pformat, arg);
708 static void
709 out_uint_o (char *pformat, size_t prefix_len, uintmax_t arg)
711 make_format (pformat, prefix_len, "-#0", PRIoMAX);
712 printf (pformat, arg);
714 static void
715 out_uint_x (char *pformat, size_t prefix_len, uintmax_t arg)
717 make_format (pformat, prefix_len, "-#0", PRIxMAX);
718 printf (pformat, arg);
720 static int
721 out_minus_zero (char *pformat, size_t prefix_len)
723 make_format (pformat, prefix_len, "'-+ 0", ".0f");
724 return printf (pformat, -0.25);
727 /* Output the number of seconds since the Epoch, using a format that
728 acts like printf's %f format. */
729 static void
730 out_epoch_sec (char *pformat, size_t prefix_len,
731 struct timespec arg)
733 char *dot = memchr (pformat, '.', prefix_len);
734 size_t sec_prefix_len = prefix_len;
735 int width = 0;
736 int precision = 0;
737 bool frac_left_adjust = false;
739 if (dot)
741 sec_prefix_len = dot - pformat;
742 pformat[prefix_len] = '\0';
744 if (ISDIGIT (dot[1]))
746 long int lprec = strtol (dot + 1, NULL, 10);
747 precision = (lprec <= INT_MAX ? lprec : INT_MAX);
749 else
751 precision = 9;
754 if (precision && ISDIGIT (dot[-1]))
756 /* If a nontrivial width is given, subtract the width of the
757 decimal point and PRECISION digits that will be output
758 later. */
759 char *p = dot;
760 *dot = '\0';
763 --p;
764 while (ISDIGIT (p[-1]));
766 long int lwidth = strtol (p, NULL, 10);
767 width = (lwidth <= INT_MAX ? lwidth : INT_MAX);
768 if (1 < width)
770 p += (*p == '0');
771 sec_prefix_len = p - pformat;
772 int w_d = (decimal_point_len < width
773 ? width - decimal_point_len
774 : 0);
775 if (1 < w_d)
777 int w = w_d - precision;
778 if (1 < w)
780 char *dst = pformat;
781 for (char const *src = dst; src < p; src++)
783 if (*src == '-')
784 frac_left_adjust = true;
785 else
786 *dst++ = *src;
788 sec_prefix_len =
789 (dst - pformat
790 + (frac_left_adjust ? 0 : sprintf (dst, "%d", w)));
797 int divisor = 1;
798 for (int i = precision; i < 9; i++)
799 divisor *= 10;
800 int frac_sec = arg.tv_nsec / divisor;
801 int int_len;
803 if (TYPE_SIGNED (time_t))
805 bool minus_zero = false;
806 if (arg.tv_sec < 0 && arg.tv_nsec != 0)
808 int frac_sec_modulus = 1000000000 / divisor;
809 frac_sec = (frac_sec_modulus - frac_sec
810 - (arg.tv_nsec % divisor != 0));
811 arg.tv_sec += (frac_sec != 0);
812 minus_zero = (arg.tv_sec == 0);
814 int_len = (minus_zero
815 ? out_minus_zero (pformat, sec_prefix_len)
816 : out_int (pformat, sec_prefix_len, arg.tv_sec));
818 else
819 int_len = out_uint (pformat, sec_prefix_len, arg.tv_sec);
821 if (precision)
823 int prec = (precision < 9 ? precision : 9);
824 int trailing_prec = precision - prec;
825 int ilen = (int_len < 0 ? 0 : int_len);
826 int trailing_width = (ilen < width && decimal_point_len < width - ilen
827 ? width - ilen - decimal_point_len - prec
828 : 0);
829 printf ("%s%.*d%-*.*d", decimal_point, prec, frac_sec,
830 trailing_width, trailing_prec, 0);
834 /* Print the context information of FILENAME, and return true iff the
835 context could not be obtained. */
836 NODISCARD
837 static bool
838 out_file_context (char *pformat, size_t prefix_len, char const *filename)
840 char *scontext;
841 bool fail = false;
843 if ((follow_links
844 ? getfilecon (filename, &scontext)
845 : lgetfilecon (filename, &scontext)) < 0)
847 error (0, errno, _("failed to get security context of %s"),
848 quoteaf (filename));
849 scontext = NULL;
850 fail = true;
852 strcpy (pformat + prefix_len, "s");
853 printf (pformat, (scontext ? scontext : "?"));
854 if (scontext)
855 freecon (scontext);
856 return fail;
859 /* Print statfs info. Return zero upon success, nonzero upon failure. */
860 NODISCARD
861 static bool
862 print_statfs (char *pformat, size_t prefix_len, MAYBE_UNUSED char mod, char m,
863 int fd, char const *filename,
864 void const *data)
866 STRUCT_STATVFS const *statfsbuf = data;
867 bool fail = false;
869 switch (m)
871 case 'n':
872 out_string (pformat, prefix_len, filename);
873 break;
875 case 'i':
877 #if STRUCT_STATXFS_F_FSID_IS_INTEGER
878 uintmax_t fsid = statfsbuf->f_fsid;
879 #else
880 typedef unsigned int fsid_word;
881 static_assert (alignof (STRUCT_STATVFS) % alignof (fsid_word) == 0);
882 static_assert (offsetof (STRUCT_STATVFS, f_fsid) % alignof (fsid_word)
883 == 0);
884 static_assert (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 if (! force_sync)
1398 flags |= AT_NO_AUTOMOUNT;
1400 fd = statx (fd, pathname, flags, format_to_mask (format), &stx);
1401 if (fd < 0)
1403 if (flags & AT_EMPTY_PATH)
1404 error (0, errno, _("cannot stat standard input"));
1405 else
1406 error (0, errno, _("cannot statx %s"), quoteaf (filename));
1407 return false;
1410 if (S_ISBLK (stx.stx_mode) || S_ISCHR (stx.stx_mode))
1411 format = format2;
1413 statx_to_stat (&stx, &st);
1414 if (stx.stx_mask & STATX_BTIME)
1415 pa.btime = statx_timestamp_to_timespec (stx.stx_btime);
1417 bool fail = print_it (format, fd, filename, print_stat, &pa);
1418 return ! fail;
1421 #else /* USE_STATX */
1423 static struct timespec
1424 get_birthtime (int fd, char const *filename, struct stat const *st)
1426 struct timespec ts = get_stat_birthtime (st);
1428 # if HAVE_GETATTRAT
1429 if (ts.tv_nsec < 0)
1431 nvlist_t *response;
1432 if ((fd < 0
1433 ? getattrat (AT_FDCWD, XATTR_VIEW_READWRITE, filename, &response)
1434 : fgetattr (fd, XATTR_VIEW_READWRITE, &response))
1435 == 0)
1437 uint64_t *val;
1438 uint_t n;
1439 if (nvlist_lookup_uint64_array (response, A_CRTIME, &val, &n) == 0
1440 && 2 <= n
1441 && val[0] <= TYPE_MAXIMUM (time_t)
1442 && val[1] < 1000000000 * 2 /* for leap seconds */)
1444 ts.tv_sec = val[0];
1445 ts.tv_nsec = val[1];
1447 nvlist_free (response);
1450 # endif
1452 return ts;
1456 /* stat the file and print what we find */
1457 NODISCARD
1458 static bool
1459 do_stat (char const *filename, char const *format,
1460 char const *format2)
1462 int fd = STREQ (filename, "-") ? 0 : -1;
1463 struct stat statbuf;
1464 struct print_args pa;
1465 pa.st = &statbuf;
1466 pa.btime = (struct timespec) {-1, -1};
1468 if (0 <= fd)
1470 if (fstat (fd, &statbuf) != 0)
1472 error (0, errno, _("cannot stat standard input"));
1473 return false;
1476 /* We can't use the shorter
1477 (follow_links?stat:lstat) (filename, &statbug)
1478 since stat might be a function-like macro. */
1479 else if ((follow_links
1480 ? stat (filename, &statbuf)
1481 : lstat (filename, &statbuf)) != 0)
1483 error (0, errno, _("cannot stat %s"), quoteaf (filename));
1484 return false;
1487 if (S_ISBLK (statbuf.st_mode) || S_ISCHR (statbuf.st_mode))
1488 format = format2;
1490 bool fail = print_it (format, fd, filename, print_stat, &pa);
1491 return ! fail;
1493 #endif /* USE_STATX */
1495 /* POSIX requires 'ls' to print file sizes without a sign, even
1496 when negative. Be consistent with that. */
1498 static uintmax_t
1499 unsigned_file_size (off_t size)
1501 return size + (size < 0) * ((uintmax_t) OFF_T_MAX - OFF_T_MIN + 1);
1504 /* Print stat info. Return zero upon success, nonzero upon failure. */
1505 static bool
1506 print_stat (char *pformat, size_t prefix_len, char mod, char m,
1507 int fd, char const *filename, void const *data)
1509 struct print_args *parg = (struct print_args *) data;
1510 struct stat *statbuf = parg->st;
1511 struct timespec btime = parg->btime;
1512 struct passwd *pw_ent;
1513 struct group *gw_ent;
1514 bool fail = false;
1516 switch (m)
1518 case 'n':
1519 out_string (pformat, prefix_len, filename);
1520 break;
1521 case 'N':
1522 out_string (pformat, prefix_len, quoteN (filename));
1523 if (S_ISLNK (statbuf->st_mode))
1525 char *linkname = areadlink_with_size (filename, statbuf->st_size);
1526 if (linkname == NULL)
1528 error (0, errno, _("cannot read symbolic link %s"),
1529 quoteaf (filename));
1530 return true;
1532 printf (" -> ");
1533 out_string (pformat, prefix_len, quoteN (linkname));
1534 free (linkname);
1536 break;
1537 case 'd':
1538 if (mod == 'H')
1539 out_uint (pformat, prefix_len, major (statbuf->st_dev));
1540 else if (mod == 'L')
1541 out_uint (pformat, prefix_len, minor (statbuf->st_dev));
1542 else
1543 out_uint (pformat, prefix_len, statbuf->st_dev);
1544 break;
1545 case 'D':
1546 out_uint_x (pformat, prefix_len, statbuf->st_dev);
1547 break;
1548 case 'i':
1549 out_uint (pformat, prefix_len, statbuf->st_ino);
1550 break;
1551 case 'a':
1552 out_uint_o (pformat, prefix_len, statbuf->st_mode & CHMOD_MODE_BITS);
1553 break;
1554 case 'A':
1555 out_string (pformat, prefix_len, human_access (statbuf));
1556 break;
1557 case 'f':
1558 out_uint_x (pformat, prefix_len, statbuf->st_mode);
1559 break;
1560 case 'F':
1561 out_string (pformat, prefix_len, file_type (statbuf));
1562 break;
1563 case 'h':
1564 out_uint (pformat, prefix_len, statbuf->st_nlink);
1565 break;
1566 case 'u':
1567 out_uint (pformat, prefix_len, statbuf->st_uid);
1568 break;
1569 case 'U':
1570 pw_ent = getpwuid (statbuf->st_uid);
1571 out_string (pformat, prefix_len,
1572 pw_ent ? pw_ent->pw_name : "UNKNOWN");
1573 break;
1574 case 'g':
1575 out_uint (pformat, prefix_len, statbuf->st_gid);
1576 break;
1577 case 'G':
1578 gw_ent = getgrgid (statbuf->st_gid);
1579 out_string (pformat, prefix_len,
1580 gw_ent ? gw_ent->gr_name : "UNKNOWN");
1581 break;
1582 case 'm':
1583 fail |= out_mount_point (filename, pformat, prefix_len, statbuf);
1584 break;
1585 case 's':
1586 out_uint (pformat, prefix_len, unsigned_file_size (statbuf->st_size));
1587 break;
1588 case 'r':
1589 if (mod == 'H')
1590 out_uint (pformat, prefix_len, major (statbuf->st_rdev));
1591 else if (mod == 'L')
1592 out_uint (pformat, prefix_len, minor (statbuf->st_rdev));
1593 else
1594 out_uint (pformat, prefix_len, statbuf->st_rdev);
1595 break;
1596 case 'R':
1597 out_uint_x (pformat, prefix_len, statbuf->st_rdev);
1598 break;
1599 case 't':
1600 out_uint_x (pformat, prefix_len, major (statbuf->st_rdev));
1601 break;
1602 case 'T':
1603 out_uint_x (pformat, prefix_len, minor (statbuf->st_rdev));
1604 break;
1605 case 'B':
1606 out_uint (pformat, prefix_len, ST_NBLOCKSIZE);
1607 break;
1608 case 'b':
1609 out_uint (pformat, prefix_len, ST_NBLOCKS (*statbuf));
1610 break;
1611 case 'o':
1612 out_uint (pformat, prefix_len, ST_BLKSIZE (*statbuf));
1613 break;
1614 case 'w':
1616 #if ! USE_STATX
1617 btime = get_birthtime (fd, filename, statbuf);
1618 #endif
1619 if (btime.tv_nsec < 0)
1620 out_string (pformat, prefix_len, "-");
1621 else
1622 out_string (pformat, prefix_len, human_time (btime));
1624 break;
1625 case 'W':
1627 #if ! USE_STATX
1628 btime = get_birthtime (fd, filename, statbuf);
1629 #endif
1630 out_epoch_sec (pformat, prefix_len, neg_to_zero (btime));
1632 break;
1633 case 'x':
1634 out_string (pformat, prefix_len, human_time (get_stat_atime (statbuf)));
1635 break;
1636 case 'X':
1637 out_epoch_sec (pformat, prefix_len, get_stat_atime (statbuf));
1638 break;
1639 case 'y':
1640 out_string (pformat, prefix_len, human_time (get_stat_mtime (statbuf)));
1641 break;
1642 case 'Y':
1643 out_epoch_sec (pformat, prefix_len, get_stat_mtime (statbuf));
1644 break;
1645 case 'z':
1646 out_string (pformat, prefix_len, human_time (get_stat_ctime (statbuf)));
1647 break;
1648 case 'Z':
1649 out_epoch_sec (pformat, prefix_len, get_stat_ctime (statbuf));
1650 break;
1651 case 'C':
1652 fail |= out_file_context (pformat, prefix_len, filename);
1653 break;
1654 default:
1655 fputc ('?', stdout);
1656 break;
1658 return fail;
1661 /* Return an allocated format string in static storage that
1662 corresponds to whether FS and TERSE options were declared. */
1663 static char *
1664 default_format (bool fs, bool terse, bool device)
1666 char *format;
1667 if (fs)
1669 if (terse)
1670 format = xstrdup (fmt_terse_fs);
1671 else
1673 /* TRANSLATORS: This string uses format specifiers from
1674 'stat --help' with --file-system, and NOT from printf. */
1675 format = xstrdup (_(" File: \"%n\"\n"
1676 " ID: %-8i Namelen: %-7l Type: %T\n"
1677 "Block size: %-10s Fundamental block size: %S\n"
1678 "Blocks: Total: %-10b Free: %-10f Available: %a\n"
1679 "Inodes: Total: %-10c Free: %d\n"));
1682 else /* ! fs */
1684 if (terse)
1686 if (0 < is_selinux_enabled ())
1687 format = xstrdup (fmt_terse_selinux);
1688 else
1689 format = xstrdup (fmt_terse_regular);
1691 else
1693 char *temp;
1694 /* TRANSLATORS: This string uses format specifiers from
1695 'stat --help' without --file-system, and NOT from printf. */
1696 format = xstrdup (_("\
1697 File: %N\n\
1698 Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n\
1699 "));
1701 temp = format;
1702 if (device)
1704 /* TRANSLATORS: This string uses format specifiers from
1705 'stat --help' without --file-system, and NOT from printf. */
1706 format = xasprintf ("%s%s", format, _("\
1707 " "Device: %Hd,%Ld\tInode: %-10i Links: %-5h Device type: %Hr,%Lr\n\
1708 "));
1710 else
1712 /* TRANSLATORS: This string uses format specifiers from
1713 'stat --help' without --file-system, and NOT from printf. */
1714 format = xasprintf ("%s%s", format, _("\
1715 " "Device: %Hd,%Ld\tInode: %-10i Links: %h\n\
1716 "));
1718 free (temp);
1720 temp = format;
1721 /* TRANSLATORS: This string uses format specifiers from
1722 'stat --help' without --file-system, and NOT from printf. */
1723 format = xasprintf ("%s%s", format, _("\
1724 " "Access: (%04a/%10.10A) Uid: (%5u/%8U) Gid: (%5g/%8G)\n\
1725 "));
1726 free (temp);
1728 if (0 < is_selinux_enabled ())
1730 temp = format;
1731 /* TRANSLATORS: This string uses format specifiers from
1732 'stat --help' without --file-system, and NOT from printf. */
1733 format = xasprintf ("%s%s", format, _("Context: %C\n"));
1734 free (temp);
1737 temp = format;
1738 /* TRANSLATORS: This string uses format specifiers from
1739 'stat --help' without --file-system, and NOT from printf. */
1740 format = xasprintf ("%s%s", format,
1741 _("Access: %x\n"
1742 "Modify: %y\n"
1743 "Change: %z\n"
1744 " Birth: %w\n"));
1745 free (temp);
1748 return format;
1751 void
1752 usage (int status)
1754 if (status != EXIT_SUCCESS)
1755 emit_try_help ();
1756 else
1758 printf (_("Usage: %s [OPTION]... FILE...\n"), program_name);
1759 fputs (_("\
1760 Display file or file system status.\n\
1761 "), stdout);
1763 emit_mandatory_arg_note ();
1765 fputs (_("\
1766 -L, --dereference follow links\n\
1767 -f, --file-system display file system status instead of file status\n\
1768 "), stdout);
1769 fputs (_("\
1770 --cached=MODE specify how to use cached attributes;\n\
1771 useful on remote file systems. See MODE below\n\
1772 "), stdout);
1773 fputs (_("\
1774 -c --format=FORMAT use the specified FORMAT instead of the default;\n\
1775 output a newline after each use of FORMAT\n\
1776 --printf=FORMAT like --format, but interpret backslash escapes,\n\
1777 and do not output a mandatory trailing newline;\n\
1778 if you want a newline, include \\n in FORMAT\n\
1779 -t, --terse print the information in terse form\n\
1780 "), stdout);
1781 fputs (HELP_OPTION_DESCRIPTION, stdout);
1782 fputs (VERSION_OPTION_DESCRIPTION, stdout);
1784 fputs (_("\n\
1785 The MODE argument of --cached can be: always, never, or default.\n\
1786 'always' will use cached attributes if available, while\n\
1787 'never' will try to synchronize with the latest attributes, and\n\
1788 'default' will leave it up to the underlying file system.\n\
1789 "), stdout);
1791 fputs (_("\n\
1792 The valid format sequences for files (without --file-system):\n\
1794 %a permission bits in octal (note '#' and '0' printf flags)\n\
1795 %A permission bits and file type in human readable form\n\
1796 %b number of blocks allocated (see %B)\n\
1797 %B the size in bytes of each block reported by %b\n\
1798 %C SELinux security context string\n\
1799 "), stdout);
1800 fputs (_("\
1801 %d device number in decimal (st_dev)\n\
1802 %D device number in hex (st_dev)\n\
1803 %Hd major device number in decimal\n\
1804 %Ld minor device number in decimal\n\
1805 %f raw mode in hex\n\
1806 %F file type\n\
1807 %g group ID of owner\n\
1808 %G group name of owner\n\
1809 "), stdout);
1810 fputs (_("\
1811 %h number of hard links\n\
1812 %i inode number\n\
1813 %m mount point\n\
1814 %n file name\n\
1815 %N quoted file name with dereference if symbolic link\n\
1816 %o optimal I/O transfer size hint\n\
1817 %s total size, in bytes\n\
1818 %r device type in decimal (st_rdev)\n\
1819 %R device type in hex (st_rdev)\n\
1820 %Hr major device type in decimal, for character/block device special files\n\
1821 %Lr minor device type in decimal, for character/block device special files\n\
1822 %t major device type in hex, for character/block device special files\n\
1823 %T minor device type in hex, for character/block device special files\n\
1824 "), stdout);
1825 fputs (_("\
1826 %u user ID of owner\n\
1827 %U user name of owner\n\
1828 %w time of file birth, human-readable; - if unknown\n\
1829 %W time of file birth, seconds since Epoch; 0 if unknown\n\
1830 %x time of last access, human-readable\n\
1831 %X time of last access, seconds since Epoch\n\
1832 %y time of last data modification, human-readable\n\
1833 %Y time of last data modification, seconds since Epoch\n\
1834 %z time of last status change, human-readable\n\
1835 %Z time of last status change, seconds since Epoch\n\
1837 "), stdout);
1839 fputs (_("\
1840 Valid format sequences for file systems:\n\
1842 %a free blocks available to non-superuser\n\
1843 %b total data blocks in file system\n\
1844 %c total file nodes in file system\n\
1845 %d free file nodes in file system\n\
1846 %f free blocks in file system\n\
1847 "), stdout);
1848 fputs (_("\
1849 %i file system ID in hex\n\
1850 %l maximum length of filenames\n\
1851 %n file name\n\
1852 %s block size (for faster transfers)\n\
1853 %S fundamental block size (for block counts)\n\
1854 %t file system type in hex\n\
1855 %T file system type in human readable form\n\
1856 "), stdout);
1858 printf (_("\n\
1859 --terse is equivalent to the following FORMAT:\n\
1862 #if HAVE_SELINUX_SELINUX_H
1863 fmt_terse_selinux
1864 #else
1865 fmt_terse_regular
1866 #endif
1869 printf (_("\
1870 --terse --file-system is equivalent to the following FORMAT:\n\
1872 "), fmt_terse_fs);
1874 printf (USAGE_BUILTIN_WARNING, PROGRAM_NAME);
1875 emit_ancillary_info (PROGRAM_NAME);
1877 exit (status);
1881 main (int argc, char *argv[])
1883 int c;
1884 bool fs = false;
1885 bool terse = false;
1886 char *format = NULL;
1887 char *format2;
1888 bool ok = true;
1890 initialize_main (&argc, &argv);
1891 set_program_name (argv[0]);
1892 setlocale (LC_ALL, "");
1893 bindtextdomain (PACKAGE, LOCALEDIR);
1894 textdomain (PACKAGE);
1896 struct lconv const *locale = localeconv ();
1897 decimal_point = (locale->decimal_point[0] ? locale->decimal_point : ".");
1898 decimal_point_len = strlen (decimal_point);
1900 atexit (close_stdout);
1902 while ((c = getopt_long (argc, argv, "c:fLt", long_options, NULL)) != -1)
1904 switch (c)
1906 case PRINTF_OPTION:
1907 format = optarg;
1908 interpret_backslash_escapes = true;
1909 trailing_delim = "";
1910 break;
1912 case 'c':
1913 format = optarg;
1914 interpret_backslash_escapes = false;
1915 trailing_delim = "\n";
1916 break;
1918 case 'L':
1919 follow_links = true;
1920 break;
1922 case 'f':
1923 fs = true;
1924 break;
1926 case 't':
1927 terse = true;
1928 break;
1930 case 0:
1931 switch (XARGMATCH ("--cached", optarg, cached_args, cached_modes))
1933 case cached_never:
1934 force_sync = true;
1935 dont_sync = false;
1936 break;
1937 case cached_always:
1938 force_sync = false;
1939 dont_sync = true;
1940 break;
1941 case cached_default:
1942 force_sync = false;
1943 dont_sync = false;
1945 break;
1947 case_GETOPT_HELP_CHAR;
1949 case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
1951 default:
1952 usage (EXIT_FAILURE);
1956 if (argc == optind)
1958 error (0, 0, _("missing operand"));
1959 usage (EXIT_FAILURE);
1962 if (format)
1964 if (strstr (format, "%N"))
1965 getenv_quoting_style ();
1966 format2 = format;
1968 else
1970 format = default_format (fs, terse, /* device= */ false);
1971 format2 = default_format (fs, terse, /* device= */ true);
1974 for (int i = optind; i < argc; i++)
1975 ok &= (fs
1976 ? do_statfs (argv[i], format)
1977 : do_stat (argv[i], format, format2));
1979 main_exit (ok ? EXIT_SUCCESS : EXIT_FAILURE);