1 /* stat.c -- display file or file system status
2 Copyright (C) 2001-2016 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 <http://www.gnu.org/licenses/>.
17 Written by Michael Meskes. */
21 /* Keep this conditional in sync with the similar conditional in
22 ../m4/stat-prog.m4. */
23 #if ((STAT_STATVFS || STAT_STATVFS64) \
24 && (HAVE_STRUCT_STATVFS_F_BASETYPE || HAVE_STRUCT_STATVFS_F_FSTYPENAME \
25 || (! HAVE_STRUCT_STATFS_F_FSTYPENAME && HAVE_STRUCT_STATVFS_F_TYPE)))
26 # define USE_STATVFS 1
28 # define USE_STATVFS 0
34 #include <sys/types.h>
38 # include <sys/statvfs.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>
54 #elif HAVE_OS_H /* BeOS */
57 #include <selinux/selinux.h>
61 #include "areadlink.h"
65 #include "file-type.h"
69 #include "mountlist.h"
71 #include "stat-size.h"
72 #include "stat-time.h"
74 #include "find-mount-point.h"
75 #include "xvasprintf.h"
78 # define STRUCT_STATXFS_F_FSID_IS_INTEGER STRUCT_STATVFS_F_FSID_IS_INTEGER
79 # define HAVE_STRUCT_STATXFS_F_TYPE HAVE_STRUCT_STATVFS_F_TYPE
80 # if HAVE_STRUCT_STATVFS_F_NAMEMAX
81 # define SB_F_NAMEMAX(S) ((S)->f_namemax)
83 # if ! STAT_STATVFS && STAT_STATVFS64
84 # define STRUCT_STATVFS struct statvfs64
85 # define STATFS statvfs64
87 # define STRUCT_STATVFS struct statvfs
88 # define STATFS statvfs
90 # define STATFS_FRSIZE(S) ((S)->f_frsize)
92 # define HAVE_STRUCT_STATXFS_F_TYPE HAVE_STRUCT_STATFS_F_TYPE
93 # if HAVE_STRUCT_STATFS_F_NAMELEN
94 # define SB_F_NAMEMAX(S) ((S)->f_namelen)
96 # define STATFS statfs
97 # if HAVE_OS_H /* BeOS */
98 /* BeOS has a statvfs function, but it does not return sensible values
99 for f_files, f_ffree and f_favail, and lacks f_type, f_basetype and
100 f_fstypename. Use 'struct fs_info' instead. */
101 static int ATTRIBUTE_WARN_UNUSED_RESULT
102 statfs (char const *filename
, struct fs_info
*buf
)
104 dev_t device
= dev_for_path (filename
);
107 errno
= (device
== B_ENTRY_NOT_FOUND
? ENOENT
108 : device
== B_BAD_VALUE
? EINVAL
109 : device
== B_NAME_TOO_LONG
? ENAMETOOLONG
110 : device
== B_NO_MEMORY
? ENOMEM
111 : device
== B_FILE_ERROR
? EIO
115 /* If successful, buf->dev will be == device. */
116 return fs_stat_dev (device
, buf
);
119 # define f_blocks total_blocks
120 # define f_bfree free_blocks
121 # define f_bavail free_blocks
122 # define f_bsize io_size
123 # define f_files total_nodes
124 # define f_ffree free_nodes
125 # define STRUCT_STATVFS struct fs_info
126 # define STRUCT_STATXFS_F_FSID_IS_INTEGER true
127 # define STATFS_FRSIZE(S) ((S)->block_size)
129 # define STRUCT_STATVFS struct statfs
130 # define STRUCT_STATXFS_F_FSID_IS_INTEGER STRUCT_STATFS_F_FSID_IS_INTEGER
131 # if HAVE_STRUCT_STATFS_F_FRSIZE
132 # define STATFS_FRSIZE(S) ((S)->f_frsize)
134 # define STATFS_FRSIZE(S) 0
140 # define OUT_NAMEMAX out_uint
142 /* NetBSD 1.5.2 has neither f_namemax nor f_namelen. */
143 # define SB_F_NAMEMAX(S) "*"
144 # define OUT_NAMEMAX out_string
147 #if HAVE_STRUCT_STATVFS_F_BASETYPE
148 # define STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME f_basetype
150 # if HAVE_STRUCT_STATVFS_F_FSTYPENAME || HAVE_STRUCT_STATFS_F_FSTYPENAME
151 # define STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME f_fstypename
152 # elif HAVE_OS_H /* BeOS */
153 # define STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME fsh_name
159 # include <sys/nvpair.h>
162 /* FIXME: these are used by printf.c, too */
163 #define isodigit(c) ('0' <= (c) && (c) <= '7')
164 #define octtobin(c) ((c) - '0')
165 #define hextobin(c) ((c) >= 'a' && (c) <= 'f' ? (c) - 'a' + 10 : \
166 (c) >= 'A' && (c) <= 'F' ? (c) - 'A' + 10 : (c) - '0')
168 static char const digits
[] = "0123456789";
170 /* Flags that are portable for use in printf, for at least one
171 conversion specifier; make_format removes unportable flags as
172 needed for particular specifiers. The glibc 2.2 extension "I" is
173 listed here; it is removed by make_format because it has undefined
174 behavior elsewhere and because it is incompatible with
176 static char const printf_flags
[] = "'-+ #0I";
178 #define PROGRAM_NAME "stat"
180 #define AUTHORS proper_name ("Michael Meskes")
184 PRINTF_OPTION
= CHAR_MAX
+ 1
187 static struct option
const long_options
[] =
189 {"dereference", no_argument
, NULL
, 'L'},
190 {"file-system", no_argument
, NULL
, 'f'},
191 {"format", required_argument
, NULL
, 'c'},
192 {"printf", required_argument
, NULL
, PRINTF_OPTION
},
193 {"terse", no_argument
, NULL
, 't'},
194 {GETOPT_HELP_OPTION_DECL
},
195 {GETOPT_VERSION_OPTION_DECL
},
199 /* Whether to follow symbolic links; True for --dereference (-L). */
200 static bool follow_links
;
202 /* Whether to interpret backslash-escape sequences.
203 True for --printf=FMT, not for --format=FMT (-c). */
204 static bool interpret_backslash_escapes
;
206 /* The trailing delimiter string:
207 "" for --printf=FMT, "\n" for --format=FMT (-c). */
208 static char const *trailing_delim
= "";
210 /* The representation of the decimal point in the current locale. */
211 static char const *decimal_point
;
212 static size_t decimal_point_len
;
214 /* Return the type of the specified file system.
215 Some systems have statfvs.f_basetype[FSTYPSZ] (AIX, HP-UX, and Solaris).
216 Others have statvfs.f_fstypename[_VFS_NAMELEN] (NetBSD 3.0).
217 Others have statfs.f_fstypename[MFSNAMELEN] (NetBSD 1.5.2).
218 Still others have neither and have to get by with f_type (GNU/Linux).
219 But f_type may only exist in statfs (Cygwin). */
220 static char const * ATTRIBUTE_WARN_UNUSED_RESULT
221 human_fstype (STRUCT_STATVFS
const *statfsbuf
)
223 #ifdef STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME
224 return statfsbuf
->STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME
;
226 switch (statfsbuf
->f_type
)
228 # if defined __linux__
230 /* Compare with what's in libc:
231 f=/a/libc/sysdeps/unix/sysv/linux/linux_fsinfo.h
232 sed -n '/ADFS_SUPER_MAGIC/,/SYSFS_MAGIC/p' $f \
233 | perl -n -e '/#define (.*?)_(?:SUPER_)MAGIC\s+0x(\S+)/' \
234 -e 'and print "case S_MAGIC_$1: /\* 0x" . uc($2) . " *\/\n"' \
236 perl -ne '/^\s+(case S_MAGIC_.*?): \/\* 0x(\S+) \*\//' \
237 -e 'and do { $v=uc$2; print "$1: /\* 0x$v *\/\n"}' stat.c \
239 diff -u sym_stat sym_libc
242 /* Also compare with the list in "man 2 statfs" using the
243 fs-magic-compare make target. */
245 /* IMPORTANT NOTE: Each of the following 'case S_MAGIC_...:'
246 statements must be followed by a hexadecimal constant in
247 a comment. The S_MAGIC_... name and constant are automatically
248 combined to produce the #define directives in fs.h. */
250 case S_MAGIC_ACFS
: /* 0x61636673 remote */
252 case S_MAGIC_ADFS
: /* 0xADF5 local */
254 case S_MAGIC_AFFS
: /* 0xADFF local */
256 case S_MAGIC_AFS
: /* 0x5346414F remote */
258 case S_MAGIC_ANON_INODE_FS
: /* 0x09041934 local */
259 return "anon-inode FS";
260 case S_MAGIC_AUFS
: /* 0x61756673 remote */
261 /* FIXME: change syntax or add an optional attribute like "inotify:no".
262 The above is labeled as "remote" so that tail always uses polling,
263 but this isn't really a remote file system type. */
265 case S_MAGIC_AUTOFS
: /* 0x0187 local */
267 case S_MAGIC_BALLOON_KVM
: /* 0x13661366 local */
268 return "balloon-kvm-fs";
269 case S_MAGIC_BEFS
: /* 0x42465331 local */
271 case S_MAGIC_BDEVFS
: /* 0x62646576 local */
273 case S_MAGIC_BFS
: /* 0x1BADFACE local */
275 case S_MAGIC_BPF_FS
: /* 0xCAFE4A11 local */
277 case S_MAGIC_BINFMTFS
: /* 0x42494E4D local */
278 return "binfmt_misc";
279 case S_MAGIC_BTRFS
: /* 0x9123683E local */
281 case S_MAGIC_BTRFS_TEST
: /* 0x73727279 local */
283 case S_MAGIC_CEPH
: /* 0x00C36400 remote */
285 case S_MAGIC_CGROUP
: /* 0x0027E0EB local */
287 case S_MAGIC_CGROUP2
: /* 0x63677270 local */
289 case S_MAGIC_CIFS
: /* 0xFF534D42 remote */
291 case S_MAGIC_CODA
: /* 0x73757245 remote */
293 case S_MAGIC_COH
: /* 0x012FF7B7 local */
295 case S_MAGIC_CONFIGFS
: /* 0x62656570 local */
297 case S_MAGIC_CRAMFS
: /* 0x28CD3D45 local */
299 case S_MAGIC_CRAMFS_WEND
: /* 0x453DCD28 local */
300 return "cramfs-wend";
301 case S_MAGIC_DAXFS
: /* 0x64646178 local */
303 case S_MAGIC_DEBUGFS
: /* 0x64626720 local */
305 case S_MAGIC_DEVFS
: /* 0x1373 local */
307 case S_MAGIC_DEVPTS
: /* 0x1CD1 local */
309 case S_MAGIC_ECRYPTFS
: /* 0xF15F local */
311 case S_MAGIC_EFIVARFS
: /* 0xDE5E81E4 local */
313 case S_MAGIC_EFS
: /* 0x00414A53 local */
315 case S_MAGIC_EXOFS
: /* 0x5DF5 local */
317 case S_MAGIC_EXT
: /* 0x137D local */
319 case S_MAGIC_EXT2
: /* 0xEF53 local */
321 case S_MAGIC_EXT2_OLD
: /* 0xEF51 local */
323 case S_MAGIC_F2FS
: /* 0xF2F52010 local */
325 case S_MAGIC_FAT
: /* 0x4006 local */
327 case S_MAGIC_FHGFS
: /* 0x19830326 remote */
329 case S_MAGIC_FUSEBLK
: /* 0x65735546 remote */
331 case S_MAGIC_FUSECTL
: /* 0x65735543 remote */
333 case S_MAGIC_FUTEXFS
: /* 0x0BAD1DEA local */
335 case S_MAGIC_GFS
: /* 0x01161970 remote */
337 case S_MAGIC_GPFS
: /* 0x47504653 remote */
339 case S_MAGIC_HFS
: /* 0x4244 local */
341 case S_MAGIC_HFS_PLUS
: /* 0x482B local */
343 case S_MAGIC_HFS_X
: /* 0x4858 local */
345 case S_MAGIC_HOSTFS
: /* 0x00C0FFEE local */
347 case S_MAGIC_HPFS
: /* 0xF995E849 local */
349 case S_MAGIC_HUGETLBFS
: /* 0x958458F6 local */
351 case S_MAGIC_MTD_INODE_FS
: /* 0x11307854 local */
353 case S_MAGIC_IBRIX
: /* 0x013111A8 remote */
355 case S_MAGIC_INOTIFYFS
: /* 0x2BAD1DEA local */
357 case S_MAGIC_ISOFS
: /* 0x9660 local */
359 case S_MAGIC_ISOFS_R_WIN
: /* 0x4004 local */
361 case S_MAGIC_ISOFS_WIN
: /* 0x4000 local */
363 case S_MAGIC_JFFS
: /* 0x07C0 local */
365 case S_MAGIC_JFFS2
: /* 0x72B6 local */
367 case S_MAGIC_JFS
: /* 0x3153464A local */
369 case S_MAGIC_KAFS
: /* 0x6B414653 remote */
371 case S_MAGIC_LOGFS
: /* 0xC97E8168 local */
373 case S_MAGIC_LUSTRE
: /* 0x0BD00BD0 remote */
375 case S_MAGIC_M1FS
: /* 0x5346314D local */
377 case S_MAGIC_MINIX
: /* 0x137F local */
379 case S_MAGIC_MINIX_30
: /* 0x138F local */
380 return "minix (30 char.)";
381 case S_MAGIC_MINIX_V2
: /* 0x2468 local */
383 case S_MAGIC_MINIX_V2_30
: /* 0x2478 local */
384 return "minix v2 (30 char.)";
385 case S_MAGIC_MINIX_V3
: /* 0x4D5A local */
387 case S_MAGIC_MQUEUE
: /* 0x19800202 local */
389 case S_MAGIC_MSDOS
: /* 0x4D44 local */
391 case S_MAGIC_NCP
: /* 0x564C remote */
393 case S_MAGIC_NFS
: /* 0x6969 remote */
395 case S_MAGIC_NFSD
: /* 0x6E667364 remote */
397 case S_MAGIC_NILFS
: /* 0x3434 local */
399 case S_MAGIC_NSFS
: /* 0x6E736673 local */
401 case S_MAGIC_NTFS
: /* 0x5346544E local */
403 case S_MAGIC_OPENPROM
: /* 0x9FA1 local */
405 case S_MAGIC_OCFS2
: /* 0x7461636F remote */
407 case S_MAGIC_OVERLAYFS
: /* 0x794C7630 remote */
408 /* This may overlay remote file systems.
409 Also there have been issues reported with inotify and overlayfs,
410 so mark as "remote" so that polling is used. */
412 case S_MAGIC_PANFS
: /* 0xAAD7AAEA remote */
414 case S_MAGIC_PIPEFS
: /* 0x50495045 remote */
415 /* FIXME: change syntax or add an optional attribute like "inotify:no".
416 pipefs and prlfs are labeled as "remote" so that tail always polls,
417 but these aren't really remote file system types. */
419 case S_MAGIC_PRL_FS
: /* 0x7C7C6673 remote */
421 case S_MAGIC_PROC
: /* 0x9FA0 local */
423 case S_MAGIC_PSTOREFS
: /* 0x6165676C local */
425 case S_MAGIC_QNX4
: /* 0x002F local */
427 case S_MAGIC_QNX6
: /* 0x68191122 local */
429 case S_MAGIC_RAMFS
: /* 0x858458F6 local */
431 case S_MAGIC_REISERFS
: /* 0x52654973 local */
433 case S_MAGIC_ROMFS
: /* 0x7275 local */
435 case S_MAGIC_RPC_PIPEFS
: /* 0x67596969 local */
437 case S_MAGIC_SECURITYFS
: /* 0x73636673 local */
439 case S_MAGIC_SELINUX
: /* 0xF97CFF8C local */
441 case S_MAGIC_SMACK
: /* 0x43415D53 local */
443 case S_MAGIC_SMB
: /* 0x517B remote */
445 case S_MAGIC_SMB2
: /* 0xFE534D42 remote */
447 case S_MAGIC_SNFS
: /* 0xBEEFDEAD remote */
449 case S_MAGIC_SOCKFS
: /* 0x534F434B local */
451 case S_MAGIC_SQUASHFS
: /* 0x73717368 local */
453 case S_MAGIC_SYSFS
: /* 0x62656572 local */
455 case S_MAGIC_SYSV2
: /* 0x012FF7B6 local */
457 case S_MAGIC_SYSV4
: /* 0x012FF7B5 local */
459 case S_MAGIC_TMPFS
: /* 0x01021994 local */
461 case S_MAGIC_TRACEFS
: /* 0x74726163 local */
463 case S_MAGIC_UBIFS
: /* 0x24051905 local */
465 case S_MAGIC_UDF
: /* 0x15013346 local */
467 case S_MAGIC_UFS
: /* 0x00011954 local */
469 case S_MAGIC_UFS_BYTESWAPPED
: /* 0x54190100 local */
471 case S_MAGIC_USBDEVFS
: /* 0x9FA2 local */
473 case S_MAGIC_V9FS
: /* 0x01021997 local */
475 case S_MAGIC_VMHGFS
: /* 0xBACBACBC remote */
477 case S_MAGIC_VXFS
: /* 0xA501FCF5 remote */
478 /* Veritas File System can run in single instance or clustered mode,
479 so mark as remote to cater for the latter case. */
481 case S_MAGIC_VZFS
: /* 0x565A4653 local */
483 case S_MAGIC_WSLFS
: /* 0x53464846 local */
485 case S_MAGIC_XENFS
: /* 0xABBA1974 local */
487 case S_MAGIC_XENIX
: /* 0x012FF7B4 local */
489 case S_MAGIC_XFS
: /* 0x58465342 local */
491 case S_MAGIC_XIAFS
: /* 0x012FD16D local */
493 case S_MAGIC_ZFS
: /* 0x2FC12FC1 local */
495 case S_MAGIC_ZSMALLOC
: /* 0x58295829 local */
557 unsigned long int type
= statfsbuf
->f_type
;
558 static char buf
[sizeof "UNKNOWN (0x%lx)" - 3
559 + (sizeof type
* CHAR_BIT
+ 3) / 4];
560 sprintf (buf
, "UNKNOWN (0x%lx)", type
);
567 static char * ATTRIBUTE_WARN_UNUSED_RESULT
568 human_access (struct stat
const *statbuf
)
570 static char modebuf
[12];
571 filemodestring (statbuf
, modebuf
);
576 static char * ATTRIBUTE_WARN_UNUSED_RESULT
577 human_time (struct timespec t
)
579 /* STR must be at least this big, either because localtime_rz fails,
580 or because the time zone is truly outlandish so that %z expands
582 enum { intmax_bufsize
= INT_BUFSIZE_BOUND (intmax_t) };
584 static char str
[intmax_bufsize
585 + INT_STRLEN_BOUND (int) /* YYYY */
586 + 1 /* because YYYY might equal INT_MAX + 1900 */
587 + sizeof "-MM-DD HH:MM:SS.NNNNNNNNN +"];
588 static timezone_t tz
;
590 tz
= tzalloc (getenv ("TZ"));
593 if (localtime_rz (tz
, &t
.tv_sec
, &tm
))
594 nstrftime (str
, sizeof str
, "%Y-%m-%d %H:%M:%S.%N %z", &tm
, tz
, ns
);
597 char secbuf
[INT_BUFSIZE_BOUND (intmax_t)];
598 sprintf (str
, "%s.%09d", timetostr (t
.tv_sec
, secbuf
), ns
);
603 /* PFORMAT points to a '%' followed by a prefix of a format, all of
604 size PREFIX_LEN. The flags allowed for this format are
605 ALLOWED_FLAGS; remove other printf flags from the prefix, then
608 make_format (char *pformat
, size_t prefix_len
, char const *allowed_flags
,
611 char *dst
= pformat
+ 1;
613 char const *srclim
= pformat
+ prefix_len
;
614 for (src
= dst
; src
< srclim
&& strchr (printf_flags
, *src
); src
++)
615 if (strchr (allowed_flags
, *src
))
619 strcpy (dst
, suffix
);
623 out_string (char *pformat
, size_t prefix_len
, char const *arg
)
625 make_format (pformat
, prefix_len
, "-", "s");
626 printf (pformat
, arg
);
629 out_int (char *pformat
, size_t prefix_len
, intmax_t arg
)
631 make_format (pformat
, prefix_len
, "'-+ 0", PRIdMAX
);
632 return printf (pformat
, arg
);
635 out_uint (char *pformat
, size_t prefix_len
, uintmax_t arg
)
637 make_format (pformat
, prefix_len
, "'-0", PRIuMAX
);
638 return printf (pformat
, arg
);
641 out_uint_o (char *pformat
, size_t prefix_len
, uintmax_t arg
)
643 make_format (pformat
, prefix_len
, "-#0", PRIoMAX
);
644 printf (pformat
, arg
);
647 out_uint_x (char *pformat
, size_t prefix_len
, uintmax_t arg
)
649 make_format (pformat
, prefix_len
, "-#0", PRIxMAX
);
650 printf (pformat
, arg
);
653 out_minus_zero (char *pformat
, size_t prefix_len
)
655 make_format (pformat
, prefix_len
, "'-+ 0", ".0f");
656 return printf (pformat
, -0.25);
659 /* Output the number of seconds since the Epoch, using a format that
660 acts like printf's %f format. */
662 out_epoch_sec (char *pformat
, size_t prefix_len
,
663 struct stat
const *statbuf _GL_UNUSED
,
666 char *dot
= memchr (pformat
, '.', prefix_len
);
667 size_t sec_prefix_len
= prefix_len
;
670 bool frac_left_adjust
= false;
674 sec_prefix_len
= dot
- pformat
;
675 pformat
[prefix_len
] = '\0';
677 if (ISDIGIT (dot
[1]))
679 long int lprec
= strtol (dot
+ 1, NULL
, 10);
680 precision
= (lprec
<= INT_MAX
? lprec
: INT_MAX
);
687 if (precision
&& ISDIGIT (dot
[-1]))
689 /* If a nontrivial width is given, subtract the width of the
690 decimal point and PRECISION digits that will be output
697 while (ISDIGIT (p
[-1]));
699 long int lwidth
= strtol (p
, NULL
, 10);
700 width
= (lwidth
<= INT_MAX
? lwidth
: INT_MAX
);
704 sec_prefix_len
= p
- pformat
;
705 int w_d
= (decimal_point_len
< width
706 ? width
- decimal_point_len
710 int w
= w_d
- precision
;
714 for (char const *src
= dst
; src
< p
; src
++)
717 frac_left_adjust
= true;
723 + (frac_left_adjust
? 0 : sprintf (dst
, "%d", w
)));
731 for (int i
= precision
; i
< 9; i
++)
733 int frac_sec
= arg
.tv_nsec
/ divisor
;
736 if (TYPE_SIGNED (time_t))
738 bool minus_zero
= false;
739 if (arg
.tv_sec
< 0 && arg
.tv_nsec
!= 0)
741 int frac_sec_modulus
= 1000000000 / divisor
;
742 frac_sec
= (frac_sec_modulus
- frac_sec
743 - (arg
.tv_nsec
% divisor
!= 0));
744 arg
.tv_sec
+= (frac_sec
!= 0);
745 minus_zero
= (arg
.tv_sec
== 0);
747 int_len
= (minus_zero
748 ? out_minus_zero (pformat
, sec_prefix_len
)
749 : out_int (pformat
, sec_prefix_len
, arg
.tv_sec
));
752 int_len
= out_uint (pformat
, sec_prefix_len
, arg
.tv_sec
);
756 int prec
= (precision
< 9 ? precision
: 9);
757 int trailing_prec
= precision
- prec
;
758 int ilen
= (int_len
< 0 ? 0 : int_len
);
759 int trailing_width
= (ilen
< width
&& decimal_point_len
< width
- ilen
760 ? width
- ilen
- decimal_point_len
- prec
762 printf ("%s%.*d%-*.*d", decimal_point
, prec
, frac_sec
,
763 trailing_width
, trailing_prec
, 0);
767 /* Print the context information of FILENAME, and return true iff the
768 context could not be obtained. */
769 static bool ATTRIBUTE_WARN_UNUSED_RESULT
770 out_file_context (char *pformat
, size_t prefix_len
, char const *filename
)
776 ? getfilecon (filename
, &scontext
)
777 : lgetfilecon (filename
, &scontext
)) < 0)
779 error (0, errno
, _("failed to get security context of %s"),
784 strcpy (pformat
+ prefix_len
, "s");
785 printf (pformat
, (scontext
? scontext
: "?"));
791 /* Print statfs info. Return zero upon success, nonzero upon failure. */
792 static bool ATTRIBUTE_WARN_UNUSED_RESULT
793 print_statfs (char *pformat
, size_t prefix_len
, unsigned int m
,
794 int fd
, char const *filename
,
797 STRUCT_STATVFS
const *statfsbuf
= data
;
803 out_string (pformat
, prefix_len
, filename
);
808 #if STRUCT_STATXFS_F_FSID_IS_INTEGER
809 uintmax_t fsid
= statfsbuf
->f_fsid
;
811 typedef unsigned int fsid_word
;
812 verify (alignof (STRUCT_STATVFS
) % alignof (fsid_word
) == 0);
813 verify (offsetof (STRUCT_STATVFS
, f_fsid
) % alignof (fsid_word
) == 0);
814 verify (sizeof statfsbuf
->f_fsid
% alignof (fsid_word
) == 0);
815 fsid_word
const *p
= (fsid_word
*) &statfsbuf
->f_fsid
;
817 /* Assume a little-endian word order, as that is compatible
818 with glibc's statvfs implementation. */
820 int words
= sizeof statfsbuf
->f_fsid
/ sizeof *p
;
822 for (i
= 0; i
< words
&& i
* sizeof *p
< sizeof fsid
; i
++)
824 uintmax_t u
= p
[words
- 1 - i
];
825 fsid
|= u
<< (i
* CHAR_BIT
* sizeof *p
);
828 out_uint_x (pformat
, prefix_len
, fsid
);
833 OUT_NAMEMAX (pformat
, prefix_len
, SB_F_NAMEMAX (statfsbuf
));
836 #if HAVE_STRUCT_STATXFS_F_TYPE
837 out_uint_x (pformat
, prefix_len
, statfsbuf
->f_type
);
843 out_string (pformat
, prefix_len
, human_fstype (statfsbuf
));
846 out_int (pformat
, prefix_len
, statfsbuf
->f_blocks
);
849 out_int (pformat
, prefix_len
, statfsbuf
->f_bfree
);
852 out_int (pformat
, prefix_len
, statfsbuf
->f_bavail
);
855 out_uint (pformat
, prefix_len
, statfsbuf
->f_bsize
);
859 uintmax_t frsize
= STATFS_FRSIZE (statfsbuf
);
861 frsize
= statfsbuf
->f_bsize
;
862 out_uint (pformat
, prefix_len
, frsize
);
866 out_uint (pformat
, prefix_len
, statfsbuf
->f_files
);
869 out_int (pformat
, prefix_len
, statfsbuf
->f_ffree
);
878 /* Return any bind mounted source for a path.
879 The caller should not free the returned buffer.
880 Return NULL if no bind mount found. */
881 static char const * ATTRIBUTE_WARN_UNUSED_RESULT
882 find_bind_mount (char const * name
)
884 char const * bind_mount
= NULL
;
886 static struct mount_entry
*mount_list
;
887 static bool tried_mount_list
= false;
888 if (!tried_mount_list
) /* attempt/warn once per process. */
890 if (!(mount_list
= read_file_system_list (false)))
891 error (0, errno
, "%s", _("cannot read table of mounted file systems"));
892 tried_mount_list
= true;
895 struct stat name_stats
;
896 if (stat (name
, &name_stats
) != 0)
899 struct mount_entry
*me
;
900 for (me
= mount_list
; me
; me
= me
->me_next
)
902 if (me
->me_dummy
&& me
->me_devname
[0] == '/'
903 && STREQ (me
->me_mountdir
, name
))
905 struct stat dev_stats
;
907 if (stat (me
->me_devname
, &dev_stats
) == 0
908 && SAME_INODE (name_stats
, dev_stats
))
910 bind_mount
= me
->me_devname
;
919 /* Print mount point. Return zero upon success, nonzero upon failure. */
920 static bool ATTRIBUTE_WARN_UNUSED_RESULT
921 out_mount_point (char const *filename
, char *pformat
, size_t prefix_len
,
922 const struct stat
*statp
)
925 char const *np
= "?", *bp
= NULL
;
929 /* Look for bind mounts first. Note we output the immediate alias,
930 rather than further resolving to a base device mount point. */
931 if (follow_links
|| !S_ISLNK (statp
->st_mode
))
933 char *resolved
= canonicalize_file_name (filename
);
936 error (0, errno
, _("failed to canonicalize %s"), quoteaf (filename
));
937 goto print_mount_point
;
939 bp
= find_bind_mount (resolved
);
944 goto print_mount_point
;
948 /* If there is no direct bind mount, then navigate
949 back up the tree looking for a device change.
950 Note we don't detect if any of the directory components
951 are bind mounted to the same device, but that's OK
952 since we've not directly queried them. */
953 if ((mp
= find_mount_point (filename
, statp
)))
955 /* This dir might be bind mounted to another device,
956 so we resolve the bound source in that case also. */
957 bp
= find_bind_mount (mp
);
963 out_string (pformat
, prefix_len
, bp
? bp
: mp
? mp
: np
);
968 static struct timespec
969 get_birthtime (int fd
, char const *filename
, struct stat
const *st
)
971 struct timespec ts
= get_stat_birthtime (st
);
978 ? getattrat (AT_FDCWD
, XATTR_VIEW_READWRITE
, filename
, &response
)
979 : fgetattr (fd
, XATTR_VIEW_READWRITE
, &response
))
984 if (nvlist_lookup_uint64_array (response
, A_CRTIME
, &val
, &n
) == 0
986 && val
[0] <= TYPE_MAXIMUM (time_t)
987 && val
[1] < 1000000000 * 2 /* for leap seconds */)
992 nvlist_free (response
);
1000 /* Map a TS with negative TS.tv_nsec to {0,0}. */
1001 static inline struct timespec
1002 neg_to_zero (struct timespec ts
)
1004 if (0 <= ts
.tv_nsec
)
1006 struct timespec z
= {0, 0};
1010 /* Set the quoting style default if the environment variable
1011 QUOTING_STYLE is set. */
1014 getenv_quoting_style (void)
1016 char const *q_style
= getenv ("QUOTING_STYLE");
1019 int i
= ARGMATCH (q_style
, quoting_style_args
, quoting_style_vals
);
1021 set_quoting_style (NULL
, quoting_style_vals
[i
]);
1024 set_quoting_style (NULL
, shell_escape_always_quoting_style
);
1025 error (0, 0, _("ignoring invalid value of environment "
1026 "variable QUOTING_STYLE: %s"), quote (q_style
));
1030 set_quoting_style (NULL
, shell_escape_always_quoting_style
);
1033 /* Equivalent to quotearg(), but explicit to avoid syntax checks. */
1034 #define quoteN(x) quotearg_style (get_quoting_style (NULL), x)
1036 /* Print stat info. Return zero upon success, nonzero upon failure. */
1038 print_stat (char *pformat
, size_t prefix_len
, unsigned int m
,
1039 int fd
, char const *filename
, void const *data
)
1041 struct stat
*statbuf
= (struct stat
*) data
;
1042 struct passwd
*pw_ent
;
1043 struct group
*gw_ent
;
1049 out_string (pformat
, prefix_len
, filename
);
1052 out_string (pformat
, prefix_len
, quoteN (filename
));
1053 if (S_ISLNK (statbuf
->st_mode
))
1055 char *linkname
= areadlink_with_size (filename
, statbuf
->st_size
);
1056 if (linkname
== NULL
)
1058 error (0, errno
, _("cannot read symbolic link %s"),
1059 quoteaf (filename
));
1063 out_string (pformat
, prefix_len
, quoteN (linkname
));
1068 out_uint (pformat
, prefix_len
, statbuf
->st_dev
);
1071 out_uint_x (pformat
, prefix_len
, statbuf
->st_dev
);
1074 out_uint (pformat
, prefix_len
, statbuf
->st_ino
);
1077 out_uint_o (pformat
, prefix_len
, statbuf
->st_mode
& CHMOD_MODE_BITS
);
1080 out_string (pformat
, prefix_len
, human_access (statbuf
));
1083 out_uint_x (pformat
, prefix_len
, statbuf
->st_mode
);
1086 out_string (pformat
, prefix_len
, file_type (statbuf
));
1089 out_uint (pformat
, prefix_len
, statbuf
->st_nlink
);
1092 out_uint (pformat
, prefix_len
, statbuf
->st_uid
);
1095 pw_ent
= getpwuid (statbuf
->st_uid
);
1096 out_string (pformat
, prefix_len
,
1097 pw_ent
? pw_ent
->pw_name
: "UNKNOWN");
1100 out_uint (pformat
, prefix_len
, statbuf
->st_gid
);
1103 gw_ent
= getgrgid (statbuf
->st_gid
);
1104 out_string (pformat
, prefix_len
,
1105 gw_ent
? gw_ent
->gr_name
: "UNKNOWN");
1108 out_uint_x (pformat
, prefix_len
, major (statbuf
->st_rdev
));
1111 fail
|= out_mount_point (filename
, pformat
, prefix_len
, statbuf
);
1114 out_uint_x (pformat
, prefix_len
, minor (statbuf
->st_rdev
));
1117 out_int (pformat
, prefix_len
, statbuf
->st_size
);
1120 out_uint (pformat
, prefix_len
, ST_NBLOCKSIZE
);
1123 out_uint (pformat
, prefix_len
, ST_NBLOCKS (*statbuf
));
1126 out_uint (pformat
, prefix_len
, ST_BLKSIZE (*statbuf
));
1130 struct timespec t
= get_birthtime (fd
, filename
, statbuf
);
1132 out_string (pformat
, prefix_len
, "-");
1134 out_string (pformat
, prefix_len
, human_time (t
));
1138 out_epoch_sec (pformat
, prefix_len
, statbuf
,
1139 neg_to_zero (get_birthtime (fd
, filename
, statbuf
)));
1142 out_string (pformat
, prefix_len
, human_time (get_stat_atime (statbuf
)));
1145 out_epoch_sec (pformat
, prefix_len
, statbuf
, get_stat_atime (statbuf
));
1148 out_string (pformat
, prefix_len
, human_time (get_stat_mtime (statbuf
)));
1151 out_epoch_sec (pformat
, prefix_len
, statbuf
, get_stat_mtime (statbuf
));
1154 out_string (pformat
, prefix_len
, human_time (get_stat_ctime (statbuf
)));
1157 out_epoch_sec (pformat
, prefix_len
, statbuf
, get_stat_ctime (statbuf
));
1160 fail
|= out_file_context (pformat
, prefix_len
, filename
);
1163 fputc ('?', stdout
);
1169 /* Output a single-character \ escape. */
1172 print_esc_char (char c
)
1176 case 'a': /* Alert. */
1179 case 'b': /* Backspace. */
1182 case 'e': /* Escape. */
1185 case 'f': /* Form feed. */
1188 case 'n': /* New line. */
1191 case 'r': /* Carriage return. */
1194 case 't': /* Horizontal tab. */
1197 case 'v': /* Vertical tab. */
1204 error (0, 0, _("warning: unrecognized escape '\\%c'"), c
);
1210 /* Print the information specified by the format string, FORMAT,
1211 calling PRINT_FUNC for each %-directive encountered.
1212 Return zero upon success, nonzero upon failure. */
1213 static bool ATTRIBUTE_WARN_UNUSED_RESULT
1214 print_it (char const *format
, int fd
, char const *filename
,
1215 bool (*print_func
) (char *, size_t, unsigned int,
1216 int, char const *, void const *),
1221 /* Add 2 to accommodate our conversion of the stat '%s' format string
1222 to the longer printf '%llu' one. */
1225 MAX_ADDITIONAL_BYTES
=
1226 (MAX (sizeof PRIdMAX
,
1227 MAX (sizeof PRIoMAX
, MAX (sizeof PRIuMAX
, sizeof PRIxMAX
)))
1230 size_t n_alloc
= strlen (format
) + MAX_ADDITIONAL_BYTES
+ 1;
1231 char *dest
= xmalloc (n_alloc
);
1233 for (b
= format
; *b
; b
++)
1239 size_t len
= strspn (b
+ 1, printf_flags
);
1240 char const *fmt_char
= b
+ len
+ 1;
1241 fmt_char
+= strspn (fmt_char
, digits
);
1242 if (*fmt_char
== '.')
1243 fmt_char
+= 1 + strspn (fmt_char
+ 1, digits
);
1244 len
= fmt_char
- (b
+ 1);
1245 unsigned int fmt_code
= *fmt_char
;
1246 memcpy (dest
, b
, len
+ 1);
1257 dest
[len
+ 1] = *fmt_char
;
1258 dest
[len
+ 2] = '\0';
1259 die (EXIT_FAILURE
, 0, _("%s: invalid directive"),
1265 fail
|= print_func (dest
, len
+ 1, fmt_code
,
1266 fd
, filename
, data
);
1273 if ( ! interpret_backslash_escapes
)
1281 int esc_value
= octtobin (*b
);
1282 int esc_length
= 1; /* number of octal digits */
1283 for (++b
; esc_length
< 3 && isodigit (*b
);
1286 esc_value
= esc_value
* 8 + octtobin (*b
);
1288 putchar (esc_value
);
1291 else if (*b
== 'x' && isxdigit (to_uchar (b
[1])))
1293 int esc_value
= hextobin (b
[1]); /* Value of \xhh escape. */
1294 /* A hexadecimal \xhh escape sequence must have
1295 1 or 2 hex. digits. */
1297 if (isxdigit (to_uchar (b
[1])))
1300 esc_value
= esc_value
* 16 + hextobin (*b
);
1302 putchar (esc_value
);
1304 else if (*b
== '\0')
1306 error (0, 0, _("warning: backslash at end of format"));
1308 /* Arrange to exit the loop. */
1313 print_esc_char (*b
);
1324 fputs (trailing_delim
, stdout
);
1329 /* Stat the file system and print what we find. */
1330 static bool ATTRIBUTE_WARN_UNUSED_RESULT
1331 do_statfs (char const *filename
, char const *format
)
1333 STRUCT_STATVFS statfsbuf
;
1335 if (STREQ (filename
, "-"))
1337 error (0, 0, _("using %s to denote standard input does not work"
1338 " in file system mode"), quoteaf (filename
));
1342 if (STATFS (filename
, &statfsbuf
) != 0)
1344 error (0, errno
, _("cannot read file system information for %s"),
1345 quoteaf (filename
));
1349 bool fail
= print_it (format
, -1, filename
, print_statfs
, &statfsbuf
);
1353 /* stat the file and print what we find */
1354 static bool ATTRIBUTE_WARN_UNUSED_RESULT
1355 do_stat (char const *filename
, char const *format
,
1356 char const *format2
)
1358 int fd
= STREQ (filename
, "-") ? 0 : -1;
1359 struct stat statbuf
;
1363 if (fstat (fd
, &statbuf
) != 0)
1365 error (0, errno
, _("cannot stat standard input"));
1369 /* We can't use the shorter
1370 (follow_links?stat:lstat) (filename, &statbug)
1371 since stat might be a function-like macro. */
1372 else if ((follow_links
1373 ? stat (filename
, &statbuf
)
1374 : lstat (filename
, &statbuf
)) != 0)
1376 error (0, errno
, _("cannot stat %s"), quoteaf (filename
));
1380 if (S_ISBLK (statbuf
.st_mode
) || S_ISCHR (statbuf
.st_mode
))
1383 bool fail
= print_it (format
, fd
, filename
, print_stat
, &statbuf
);
1387 /* Return an allocated format string in static storage that
1388 corresponds to whether FS and TERSE options were declared. */
1390 default_format (bool fs
, bool terse
, bool device
)
1396 format
= xstrdup ("%n %i %l %t %s %S %b %f %a %c %d\n");
1399 /* TRANSLATORS: This string uses format specifiers from
1400 'stat --help' with --file-system, and NOT from printf. */
1401 format
= xstrdup (_(" File: \"%n\"\n"
1402 " ID: %-8i Namelen: %-7l Type: %T\n"
1403 "Block size: %-10s Fundamental block size: %S\n"
1404 "Blocks: Total: %-10b Free: %-10f Available: %a\n"
1405 "Inodes: Total: %-10c Free: %d\n"));
1412 if (0 < is_selinux_enabled ())
1413 format
= xstrdup ("%n %s %b %f %u %g %D %i %h %t %T"
1414 " %X %Y %Z %W %o %C\n");
1416 format
= xstrdup ("%n %s %b %f %u %g %D %i %h %t %T"
1417 " %X %Y %Z %W %o\n");
1422 /* TRANSLATORS: This string uses format specifiers from
1423 'stat --help' without --file-system, and NOT from printf. */
1424 format
= xstrdup (_("\
1426 Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n\
1432 /* TRANSLATORS: This string uses format specifiers from
1433 'stat --help' without --file-system, and NOT from printf. */
1434 format
= xasprintf ("%s%s", format
, _("\
1435 " "Device: %Dh/%dd\tInode: %-10i Links: %-5h Device type: %t,%T\n\
1440 /* TRANSLATORS: This string uses format specifiers from
1441 'stat --help' without --file-system, and NOT from printf. */
1442 format
= xasprintf ("%s%s", format
, _("\
1443 " "Device: %Dh/%dd\tInode: %-10i Links: %h\n\
1449 /* TRANSLATORS: This string uses format specifiers from
1450 'stat --help' without --file-system, and NOT from printf. */
1451 format
= xasprintf ("%s%s", format
, _("\
1452 " "Access: (%04a/%10.10A) Uid: (%5u/%8U) Gid: (%5g/%8G)\n\
1456 if (0 < is_selinux_enabled ())
1459 /* TRANSLATORS: This string uses format specifiers from
1460 'stat --help' without --file-system, and NOT from printf. */
1461 format
= xasprintf ("%s%s", format
, _("Context: %C\n"));
1466 /* TRANSLATORS: This string uses format specifiers from
1467 'stat --help' without --file-system, and NOT from printf. */
1468 format
= xasprintf ("%s%s", format
,
1482 if (status
!= EXIT_SUCCESS
)
1486 printf (_("Usage: %s [OPTION]... FILE...\n"), program_name
);
1488 Display file or file system status.\n\
1491 emit_mandatory_arg_note ();
1494 -L, --dereference follow links\n\
1495 -f, --file-system display file system status instead of file status\n\
1498 -c --format=FORMAT use the specified FORMAT instead of the default;\n\
1499 output a newline after each use of FORMAT\n\
1500 --printf=FORMAT like --format, but interpret backslash escapes,\n\
1501 and do not output a mandatory trailing newline;\n\
1502 if you want a newline, include \\n in FORMAT\n\
1503 -t, --terse print the information in terse form\n\
1505 fputs (HELP_OPTION_DESCRIPTION
, stdout
);
1506 fputs (VERSION_OPTION_DESCRIPTION
, stdout
);
1509 The valid format sequences for files (without --file-system):\n\
1511 %a access rights in octal (note '#' and '0' printf flags)\n\
1512 %A access rights in human readable form\n\
1513 %b number of blocks allocated (see %B)\n\
1514 %B the size in bytes of each block reported by %b\n\
1515 %C SELinux security context string\n\
1518 %d device number in decimal\n\
1519 %D device number in hex\n\
1520 %f raw mode in hex\n\
1522 %g group ID of owner\n\
1523 %G group name of owner\n\
1526 %h number of hard links\n\
1530 %N quoted file name with dereference if symbolic link\n\
1531 %o optimal I/O transfer size hint\n\
1532 %s total size, in bytes\n\
1533 %t major device type in hex, for character/block device special files\n\
1534 %T minor device type in hex, for character/block device special files\n\
1537 %u user ID of owner\n\
1538 %U user name of owner\n\
1539 %w time of file birth, human-readable; - if unknown\n\
1540 %W time of file birth, seconds since Epoch; 0 if unknown\n\
1541 %x time of last access, human-readable\n\
1542 %X time of last access, seconds since Epoch\n\
1543 %y time of last data modification, human-readable\n\
1544 %Y time of last data modification, seconds since Epoch\n\
1545 %z time of last status change, human-readable\n\
1546 %Z time of last status change, seconds since Epoch\n\
1551 Valid format sequences for file systems:\n\
1553 %a free blocks available to non-superuser\n\
1554 %b total data blocks in file system\n\
1555 %c total file nodes in file system\n\
1556 %d free file nodes in file system\n\
1557 %f free blocks in file system\n\
1560 %i file system ID in hex\n\
1561 %l maximum length of filenames\n\
1563 %s block size (for faster transfers)\n\
1564 %S fundamental block size (for block counts)\n\
1565 %t file system type in hex\n\
1566 %T file system type in human readable form\n\
1568 printf (USAGE_BUILTIN_WARNING
, PROGRAM_NAME
);
1569 emit_ancillary_info (PROGRAM_NAME
);
1575 main (int argc
, char *argv
[])
1581 char *format
= NULL
;
1585 initialize_main (&argc
, &argv
);
1586 set_program_name (argv
[0]);
1587 setlocale (LC_ALL
, "");
1588 bindtextdomain (PACKAGE
, LOCALEDIR
);
1589 textdomain (PACKAGE
);
1591 struct lconv
const *locale
= localeconv ();
1592 decimal_point
= (locale
->decimal_point
[0] ? locale
->decimal_point
: ".");
1593 decimal_point_len
= strlen (decimal_point
);
1595 atexit (close_stdout
);
1597 while ((c
= getopt_long (argc
, argv
, "c:fLt", long_options
, NULL
)) != -1)
1603 interpret_backslash_escapes
= true;
1604 trailing_delim
= "";
1609 interpret_backslash_escapes
= false;
1610 trailing_delim
= "\n";
1614 follow_links
= true;
1625 case_GETOPT_HELP_CHAR
;
1627 case_GETOPT_VERSION_CHAR (PROGRAM_NAME
, AUTHORS
);
1630 usage (EXIT_FAILURE
);
1636 error (0, 0, _("missing operand"));
1637 usage (EXIT_FAILURE
);
1642 if (strstr (format
, "%N"))
1643 getenv_quoting_style ();
1648 format
= default_format (fs
, terse
, /* device= */ false);
1649 format2
= default_format (fs
, terse
, /* device= */ true);
1652 for (i
= optind
; i
< argc
; i
++)
1654 ? do_statfs (argv
[i
], format
)
1655 : do_stat (argv
[i
], format
, format2
));
1657 return ok
? EXIT_SUCCESS
: EXIT_FAILURE
;