1 /* stat.c -- display file or file system status
2 Copyright (C) 2001-2010 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. */
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
33 #include <sys/types.h>
37 # include <sys/statvfs.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>
53 #elif HAVE_OS_H /* BeOS */
56 #include <selinux/selinux.h>
61 #include "areadlink.h"
63 #include "file-type.h"
67 #include "mountlist.h"
70 #include "stat-time.h"
72 #include "find-mount-point.h"
73 #include "xvasprintf.h"
76 # define STRUCT_STATVFS struct statvfs
77 # define STRUCT_STATXFS_F_FSID_IS_INTEGER STRUCT_STATVFS_F_FSID_IS_INTEGER
78 # define HAVE_STRUCT_STATXFS_F_TYPE HAVE_STRUCT_STATVFS_F_TYPE
79 # if HAVE_STRUCT_STATVFS_F_NAMEMAX
80 # define SB_F_NAMEMAX(S) ((S)->f_namemax)
82 # define STATFS statvfs
83 # define STATFS_FRSIZE(S) ((S)->f_frsize)
85 # define HAVE_STRUCT_STATXFS_F_TYPE HAVE_STRUCT_STATFS_F_TYPE
86 # if HAVE_STRUCT_STATFS_F_NAMELEN
87 # define SB_F_NAMEMAX(S) ((S)->f_namelen)
89 # define STATFS statfs
90 # if HAVE_OS_H /* BeOS */
91 /* BeOS has a statvfs function, but it does not return sensible values
92 for f_files, f_ffree and f_favail, and lacks f_type, f_basetype and
93 f_fstypename. Use 'struct fs_info' instead. */
94 static int ATTRIBUTE_WARN_UNUSED_RESULT
95 statfs (char const *filename
, struct fs_info
*buf
)
97 dev_t device
= dev_for_path (filename
);
100 errno
= (device
== B_ENTRY_NOT_FOUND
? ENOENT
101 : device
== B_BAD_VALUE
? EINVAL
102 : device
== B_NAME_TOO_LONG
? ENAMETOOLONG
103 : device
== B_NO_MEMORY
? ENOMEM
104 : device
== B_FILE_ERROR
? EIO
108 /* If successful, buf->dev will be == device. */
109 return fs_stat_dev (device
, buf
);
112 # define f_blocks total_blocks
113 # define f_bfree free_blocks
114 # define f_bavail free_blocks
115 # define f_bsize io_size
116 # define f_files total_nodes
117 # define f_ffree free_nodes
118 # define STRUCT_STATVFS struct fs_info
119 # define STRUCT_STATXFS_F_FSID_IS_INTEGER true
120 # define STATFS_FRSIZE(S) ((S)->block_size)
122 # define STRUCT_STATVFS struct statfs
123 # define STRUCT_STATXFS_F_FSID_IS_INTEGER STRUCT_STATFS_F_FSID_IS_INTEGER
124 # define STATFS_FRSIZE(S) 0
129 # define OUT_NAMEMAX out_uint
131 /* NetBSD 1.5.2 has neither f_namemax nor f_namelen. */
132 # define SB_F_NAMEMAX(S) "*"
133 # define OUT_NAMEMAX out_string
136 #if HAVE_STRUCT_STATVFS_F_BASETYPE
137 # define STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME f_basetype
139 # if HAVE_STRUCT_STATVFS_F_FSTYPENAME || HAVE_STRUCT_STATFS_F_FSTYPENAME
140 # define STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME f_fstypename
141 # elif HAVE_OS_H /* BeOS */
142 # define STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME fsh_name
146 /* FIXME: these are used by printf.c, too */
147 #define isodigit(c) ('0' <= (c) && (c) <= '7')
148 #define octtobin(c) ((c) - '0')
149 #define hextobin(c) ((c) >= 'a' && (c) <= 'f' ? (c) - 'a' + 10 : \
150 (c) >= 'A' && (c) <= 'F' ? (c) - 'A' + 10 : (c) - '0')
152 #define PROGRAM_NAME "stat"
154 #define AUTHORS proper_name ("Michael Meskes")
158 PRINTF_OPTION
= CHAR_MAX
+ 1
161 static struct option
const long_options
[] =
163 {"context", no_argument
, 0, 'Z'},
164 {"dereference", no_argument
, NULL
, 'L'},
165 {"file-system", no_argument
, NULL
, 'f'},
166 {"format", required_argument
, NULL
, 'c'},
167 {"printf", required_argument
, NULL
, PRINTF_OPTION
},
168 {"terse", no_argument
, NULL
, 't'},
169 {GETOPT_HELP_OPTION_DECL
},
170 {GETOPT_VERSION_OPTION_DECL
},
174 /* Whether to follow symbolic links; True for --dereference (-L). */
175 static bool follow_links
;
177 /* Whether to interpret backslash-escape sequences.
178 True for --printf=FMT, not for --format=FMT (-c). */
179 static bool interpret_backslash_escapes
;
181 /* The trailing delimiter string:
182 "" for --printf=FMT, "\n" for --format=FMT (-c). */
183 static char const *trailing_delim
= "";
185 /* Return the type of the specified file system.
186 Some systems have statfvs.f_basetype[FSTYPSZ] (AIX, HP-UX, and Solaris).
187 Others have statvfs.f_fstypename[_VFS_NAMELEN] (NetBSD 3.0).
188 Others have statfs.f_fstypename[MFSNAMELEN] (NetBSD 1.5.2).
189 Still others have neither and have to get by with f_type (GNU/Linux).
190 But f_type may only exist in statfs (Cygwin). */
191 static char const * ATTRIBUTE_WARN_UNUSED_RESULT
192 human_fstype (STRUCT_STATVFS
const *statfsbuf
)
194 #ifdef STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME
195 return statfsbuf
->STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME
;
197 switch (statfsbuf
->f_type
)
199 # if defined __linux__
201 /* Compare with what's in libc:
202 f=/a/libc/sysdeps/unix/sysv/linux/linux_fsinfo.h
203 sed -n '/ADFS_SUPER_MAGIC/,/SYSFS_MAGIC/p' $f \
204 | perl -n -e '/#define (.*?)_(?:SUPER_)MAGIC\s+0x(\S+)/' \
205 -e 'and print "case S_MAGIC_$1: /\* 0x" . uc($2) . " *\/\n"' \
207 perl -ne '/^\s+(case S_MAGIC_.*?): \/\* 0x(\S+) \*\//' \
208 -e 'and do { $v=uc$2; print "$1: /\* 0x$v *\/\n"}' stat.c \
210 diff -u sym_stat sym_libc
213 /* Also compare with the list in "man 2 statfs" using the
214 fs-magic-compare make target. */
216 /* IMPORTANT NOTE: Each of the following `case S_MAGIC_...:'
217 statements must be followed by a hexadecimal constant in
218 a comment. The S_MAGIC_... name and constant are automatically
219 combined to produce the #define directives in fs.h. */
221 case S_MAGIC_ADFS
: /* 0xADF5 */
223 case S_MAGIC_AFFS
: /* 0xADFF */
225 case S_MAGIC_AFS
: /* 0x5346414F */
227 case S_MAGIC_ANON_INODE_FS
: /* 0x09041934 */
228 return "anon-inode FS";
229 case S_MAGIC_AUTOFS
: /* 0x0187 */
231 case S_MAGIC_BEFS
: /* 0x42465331 */
233 case S_MAGIC_BFS
: /* 0x1BADFACE */
235 case S_MAGIC_BINFMT_MISC
: /* 0x42494E4D */
236 return "binfmt_misc";
237 case S_MAGIC_BTRFS
: /* 0x9123683E */
239 case S_MAGIC_CGROUP
: /* 0x0027E0EB */
241 case S_MAGIC_CIFS
: /* 0xFF534D42 */
243 case S_MAGIC_CODA
: /* 0x73757245 */
245 case S_MAGIC_COH
: /* 0x012FF7B7 */
247 case S_MAGIC_CRAMFS
: /* 0x28CD3D45 */
249 case S_MAGIC_CRAMFS_WEND
: /* 0x453DCD28 */
250 return "cramfs-wend";
251 case S_MAGIC_DEBUGFS
: /* 0x64626720 */
253 case S_MAGIC_DEVFS
: /* 0x1373 */
255 case S_MAGIC_DEVPTS
: /* 0x1CD1 */
257 case S_MAGIC_EFS
: /* 0x00414A53 */
259 case S_MAGIC_EXT
: /* 0x137D */
261 case S_MAGIC_EXT2
: /* 0xEF53 */
263 case S_MAGIC_EXT2_OLD
: /* 0xEF51 */
265 case S_MAGIC_FAT
: /* 0x4006 */
267 case S_MAGIC_FUSEBLK
: /* 0x65735546 */
269 case S_MAGIC_FUSECTL
: /* 0x65735543 */
271 case S_MAGIC_FUTEXFS
: /* 0x0BAD1DEA */
273 case S_MAGIC_GFS
: /* 0x1161970 */
275 case S_MAGIC_HFS
: /* 0x4244 */
277 case S_MAGIC_HPFS
: /* 0xF995E849 */
279 case S_MAGIC_HUGETLBFS
: /* 0x958458F6 */
281 case S_MAGIC_INOTIFYFS
: /* 0x2BAD1DEA */
283 case S_MAGIC_ISOFS
: /* 0x9660 */
285 case S_MAGIC_ISOFS_R_WIN
: /* 0x4004 */
287 case S_MAGIC_ISOFS_WIN
: /* 0x4000 */
289 case S_MAGIC_JFFS
: /* 0x07C0 */
291 case S_MAGIC_JFFS2
: /* 0x72B6 */
293 case S_MAGIC_JFS
: /* 0x3153464A */
295 case S_MAGIC_KAFS
: /* 0x6B414653 */
297 case S_MAGIC_LUSTRE
: /* 0x0BD00BD0 */
299 case S_MAGIC_MINIX
: /* 0x137F */
301 case S_MAGIC_MINIX_30
: /* 0x138F */
302 return "minix (30 char.)";
303 case S_MAGIC_MINIX_V2
: /* 0x2468 */
305 case S_MAGIC_MINIX_V2_30
: /* 0x2478 */
306 return "minix v2 (30 char.)";
307 case S_MAGIC_MINIX_V3
: /* 0x4D5A */
309 case S_MAGIC_MSDOS
: /* 0x4D44 */
311 case S_MAGIC_NCP
: /* 0x564C */
313 case S_MAGIC_NFS
: /* 0x6969 */
315 case S_MAGIC_NFSD
: /* 0x6E667364 */
317 case S_MAGIC_NILFS
: /* 0x3434 */
319 case S_MAGIC_NTFS
: /* 0x5346544E */
321 case S_MAGIC_OPENPROM
: /* 0x9FA1 */
323 case S_MAGIC_OCFS2
: /* 0x7461636f */
325 case S_MAGIC_PROC
: /* 0x9FA0 */
327 case S_MAGIC_QNX4
: /* 0x002F */
329 case S_MAGIC_RAMFS
: /* 0x858458F6 */
331 case S_MAGIC_REISERFS
: /* 0x52654973 */
333 case S_MAGIC_ROMFS
: /* 0x7275 */
335 case S_MAGIC_RPC_PIPEFS
: /* 0x67596969 */
337 case S_MAGIC_SECURITYFS
: /* 0x73636673 */
339 case S_MAGIC_SELINUX
: /* 0xF97CFF8C */
341 case S_MAGIC_SMB
: /* 0x517B */
343 case S_MAGIC_SOCKFS
: /* 0x534F434B */
345 case S_MAGIC_SQUASHFS
: /* 0x73717368 */
347 case S_MAGIC_SYSFS
: /* 0x62656572 */
349 case S_MAGIC_SYSV2
: /* 0x012FF7B6 */
351 case S_MAGIC_SYSV4
: /* 0x012FF7B5 */
353 case S_MAGIC_TMPFS
: /* 0x01021994 */
355 case S_MAGIC_UDF
: /* 0x15013346 */
357 case S_MAGIC_UFS
: /* 0x00011954 */
359 case S_MAGIC_UFS_BYTESWAPPED
: /* 0x54190100 */
361 case S_MAGIC_USBDEVFS
: /* 0x9FA2 */
363 case S_MAGIC_VXFS
: /* 0xA501FCF5 */
365 case S_MAGIC_XENFS
: /* 0xABBA1974 */
367 case S_MAGIC_XENIX
: /* 0x012FF7B4 */
369 case S_MAGIC_XFS
: /* 0x58465342 */
371 case S_MAGIC_XIAFS
: /* 0x012FD16D */
432 unsigned long int type
= statfsbuf
->f_type
;
433 static char buf
[sizeof "UNKNOWN (0x%lx)" - 3
434 + (sizeof type
* CHAR_BIT
+ 3) / 4];
435 sprintf (buf
, "UNKNOWN (0x%lx)", type
);
442 static char * ATTRIBUTE_WARN_UNUSED_RESULT
443 human_access (struct stat
const *statbuf
)
445 static char modebuf
[12];
446 filemodestring (statbuf
, modebuf
);
451 static char * ATTRIBUTE_WARN_UNUSED_RESULT
452 human_time (struct timespec t
)
454 static char str
[MAX (INT_BUFSIZE_BOUND (intmax_t),
455 (INT_STRLEN_BOUND (int) /* YYYY */
456 + 1 /* because YYYY might equal INT_MAX + 1900 */
457 + sizeof "-MM-DD HH:MM:SS.NNNNNNNNN +ZZZZ"))];
458 struct tm
const *tm
= localtime (&t
.tv_sec
);
460 return timetostr (t
.tv_sec
, str
);
461 nstrftime (str
, sizeof str
, "%Y-%m-%d %H:%M:%S.%N %z", tm
, 0, t
.tv_nsec
);
465 static char * ATTRIBUTE_WARN_UNUSED_RESULT
466 epoch_time (struct timespec t
)
468 static char str
[INT_STRLEN_BOUND (time_t) + sizeof ".NNNNNNNNN"];
469 /* Note that time_t can technically be a floating point value, such
470 that casting to [u]intmax_t could lose a fractional value or
471 suffer from overflow. However, most porting targets have an
472 integral time_t; also, we know of no file systems that store
473 valid time values outside the bounds of intmax_t even if that
474 value were represented as a floating point. Besides, the cost of
475 converting to struct tm just to use nstrftime (str, len, "%s.%N",
476 tm, 0, t.tv_nsec) is pointless, since nstrftime would have to
477 convert back to seconds as time_t. */
478 if (TYPE_SIGNED (time_t))
479 sprintf (str
, "%" PRIdMAX
".%09ld", (intmax_t) t
.tv_sec
, t
.tv_nsec
);
481 sprintf (str
, "%" PRIuMAX
".%09ld", (uintmax_t) t
.tv_sec
, t
.tv_nsec
);
486 out_string (char *pformat
, size_t prefix_len
, char const *arg
)
488 strcpy (pformat
+ prefix_len
, "s");
489 printf (pformat
, arg
);
492 out_int (char *pformat
, size_t prefix_len
, intmax_t arg
)
494 strcpy (pformat
+ prefix_len
, PRIdMAX
);
495 printf (pformat
, arg
);
498 out_uint (char *pformat
, size_t prefix_len
, uintmax_t arg
)
500 strcpy (pformat
+ prefix_len
, PRIuMAX
);
501 printf (pformat
, arg
);
504 out_uint_o (char *pformat
, size_t prefix_len
, uintmax_t arg
)
506 strcpy (pformat
+ prefix_len
, PRIoMAX
);
507 printf (pformat
, arg
);
510 out_uint_x (char *pformat
, size_t prefix_len
, uintmax_t arg
)
512 strcpy (pformat
+ prefix_len
, PRIxMAX
);
513 printf (pformat
, arg
);
516 /* Print the context information of FILENAME, and return true iff the
517 context could not be obtained. */
518 static bool ATTRIBUTE_WARN_UNUSED_RESULT
519 out_file_context (char *pformat
, size_t prefix_len
, char const *filename
)
525 ? getfilecon (filename
, &scontext
)
526 : lgetfilecon (filename
, &scontext
)) < 0)
528 error (0, errno
, _("failed to get security context of %s"),
533 strcpy (pformat
+ prefix_len
, "s");
534 printf (pformat
, (scontext
? scontext
: "?"));
540 /* Print statfs info. Return zero upon success, nonzero upon failure. */
541 static bool ATTRIBUTE_WARN_UNUSED_RESULT
542 print_statfs (char *pformat
, size_t prefix_len
, char m
, char const *filename
,
545 STRUCT_STATVFS
const *statfsbuf
= data
;
551 out_string (pformat
, prefix_len
, filename
);
556 #if STRUCT_STATXFS_F_FSID_IS_INTEGER
557 uintmax_t fsid
= statfsbuf
->f_fsid
;
559 typedef unsigned int fsid_word
;
560 verify (alignof (STRUCT_STATVFS
) % alignof (fsid_word
) == 0);
561 verify (offsetof (STRUCT_STATVFS
, f_fsid
) % alignof (fsid_word
) == 0);
562 verify (sizeof statfsbuf
->f_fsid
% alignof (fsid_word
) == 0);
563 fsid_word
const *p
= (fsid_word
*) &statfsbuf
->f_fsid
;
565 /* Assume a little-endian word order, as that is compatible
566 with glibc's statvfs implementation. */
568 int words
= sizeof statfsbuf
->f_fsid
/ sizeof *p
;
570 for (i
= 0; i
< words
&& i
* sizeof *p
< sizeof fsid
; i
++)
572 uintmax_t u
= p
[words
- 1 - i
];
573 fsid
|= u
<< (i
* CHAR_BIT
* sizeof *p
);
576 out_uint_x (pformat
, prefix_len
, fsid
);
581 OUT_NAMEMAX (pformat
, prefix_len
, SB_F_NAMEMAX (statfsbuf
));
584 #if HAVE_STRUCT_STATXFS_F_TYPE
585 out_uint_x (pformat
, prefix_len
, statfsbuf
->f_type
);
591 out_string (pformat
, prefix_len
, human_fstype (statfsbuf
));
594 out_int (pformat
, prefix_len
, statfsbuf
->f_blocks
);
597 out_int (pformat
, prefix_len
, statfsbuf
->f_bfree
);
600 out_int (pformat
, prefix_len
, statfsbuf
->f_bavail
);
603 out_uint (pformat
, prefix_len
, statfsbuf
->f_bsize
);
607 uintmax_t frsize
= STATFS_FRSIZE (statfsbuf
);
609 frsize
= statfsbuf
->f_bsize
;
610 out_uint (pformat
, prefix_len
, frsize
);
614 out_uint (pformat
, prefix_len
, statfsbuf
->f_files
);
617 out_int (pformat
, prefix_len
, statfsbuf
->f_ffree
);
626 /* Return any bind mounted source for a path.
627 The caller should not free the returned buffer.
628 Return NULL if no bind mount found. */
629 static char const * ATTRIBUTE_WARN_UNUSED_RESULT
630 find_bind_mount (char const * name
)
632 char const * bind_mount
= NULL
;
634 static struct mount_entry
*mount_list
;
635 static bool tried_mount_list
= false;
636 if (!tried_mount_list
) /* attempt/warn once per process. */
638 if (!(mount_list
= read_file_system_list (false)))
639 error (0, errno
, "%s", _("cannot read table of mounted file systems"));
640 tried_mount_list
= true;
643 struct mount_entry
*me
;
644 for (me
= mount_list
; me
; me
= me
->me_next
)
646 if (me
->me_dummy
&& me
->me_devname
[0] == '/'
647 && STREQ (me
->me_mountdir
, name
))
649 struct stat name_stats
;
650 struct stat dev_stats
;
652 if (stat (name
, &name_stats
) == 0
653 && stat (me
->me_devname
, &dev_stats
) == 0
654 && SAME_INODE (name_stats
, dev_stats
))
656 bind_mount
= me
->me_devname
;
665 /* Print mount point. Return zero upon success, nonzero upon failure. */
666 static bool ATTRIBUTE_WARN_UNUSED_RESULT
667 out_mount_point (char const *filename
, char *pformat
, size_t prefix_len
,
668 const struct stat
*statp
)
671 char const *np
= "?", *bp
= NULL
;
675 /* Look for bind mounts first. Note we output the immediate alias,
676 rather than further resolving to a base device mount point. */
677 if (follow_links
|| !S_ISLNK (statp
->st_mode
))
679 char *resolved
= canonicalize_file_name (filename
);
682 error (0, errno
, _("failed to canonicalize %s"), quote (filename
));
683 goto print_mount_point
;
685 bp
= find_bind_mount (resolved
);
690 goto print_mount_point
;
694 /* If there is no direct bind mount, then navigate
695 back up the tree looking for a device change.
696 Note we don't detect if any of the directory components
697 are bind mounted to the same device, but that's OK
698 since we've not directly queried them. */
699 if ((mp
= find_mount_point (filename
, statp
)))
701 /* This dir might be bind mounted to another device,
702 so we resolve the bound source in that case also. */
703 bp
= find_bind_mount (mp
);
709 out_string (pformat
, prefix_len
, bp
? bp
: mp
? mp
: np
);
714 /* Print stat info. Return zero upon success, nonzero upon failure. */
716 print_stat (char *pformat
, size_t prefix_len
, char m
,
717 char const *filename
, void const *data
)
719 struct stat
*statbuf
= (struct stat
*) data
;
720 struct passwd
*pw_ent
;
721 struct group
*gw_ent
;
727 out_string (pformat
, prefix_len
, filename
);
730 out_string (pformat
, prefix_len
, quote (filename
));
731 if (S_ISLNK (statbuf
->st_mode
))
733 char *linkname
= areadlink_with_size (filename
, statbuf
->st_size
);
734 if (linkname
== NULL
)
736 error (0, errno
, _("cannot read symbolic link %s"),
741 out_string (pformat
, prefix_len
, quote (linkname
));
746 out_uint (pformat
, prefix_len
, statbuf
->st_dev
);
749 out_uint_x (pformat
, prefix_len
, statbuf
->st_dev
);
752 out_uint (pformat
, prefix_len
, statbuf
->st_ino
);
755 out_uint_o (pformat
, prefix_len
, statbuf
->st_mode
& CHMOD_MODE_BITS
);
758 out_string (pformat
, prefix_len
, human_access (statbuf
));
761 out_uint_x (pformat
, prefix_len
, statbuf
->st_mode
);
764 out_string (pformat
, prefix_len
, file_type (statbuf
));
767 out_uint (pformat
, prefix_len
, statbuf
->st_nlink
);
770 out_uint (pformat
, prefix_len
, statbuf
->st_uid
);
774 pw_ent
= getpwuid (statbuf
->st_uid
);
775 out_string (pformat
, prefix_len
,
776 pw_ent
? pw_ent
->pw_name
: "UNKNOWN");
779 out_uint (pformat
, prefix_len
, statbuf
->st_gid
);
783 gw_ent
= getgrgid (statbuf
->st_gid
);
784 out_string (pformat
, prefix_len
,
785 gw_ent
? gw_ent
->gr_name
: "UNKNOWN");
788 out_uint_x (pformat
, prefix_len
, major (statbuf
->st_rdev
));
791 fail
|= out_mount_point (filename
, pformat
, prefix_len
, statbuf
);
794 out_uint_x (pformat
, prefix_len
, minor (statbuf
->st_rdev
));
797 out_uint (pformat
, prefix_len
, statbuf
->st_size
);
800 out_uint (pformat
, prefix_len
, ST_NBLOCKSIZE
);
803 out_uint (pformat
, prefix_len
, ST_NBLOCKS (*statbuf
));
806 out_uint (pformat
, prefix_len
, statbuf
->st_blksize
);
810 struct timespec t
= get_stat_birthtime (statbuf
);
812 out_string (pformat
, prefix_len
, "-");
814 out_string (pformat
, prefix_len
, human_time (t
));
819 struct timespec t
= get_stat_birthtime (statbuf
);
821 out_string (pformat
, prefix_len
, "-");
823 out_string (pformat
, prefix_len
, epoch_time (t
));
827 out_string (pformat
, prefix_len
, human_time (get_stat_atime (statbuf
)));
830 out_string (pformat
, prefix_len
, epoch_time (get_stat_atime (statbuf
)));
833 out_string (pformat
, prefix_len
, human_time (get_stat_mtime (statbuf
)));
836 out_string (pformat
, prefix_len
, epoch_time (get_stat_mtime (statbuf
)));
839 out_string (pformat
, prefix_len
, human_time (get_stat_ctime (statbuf
)));
842 out_string (pformat
, prefix_len
, epoch_time (get_stat_ctime (statbuf
)));
845 fail
|= out_file_context (pformat
, prefix_len
, filename
);
854 /* Output a single-character \ escape. */
857 print_esc_char (char c
)
861 case 'a': /* Alert. */
864 case 'b': /* Backspace. */
867 case 'e': /* Escape. */
870 case 'f': /* Form feed. */
873 case 'n': /* New line. */
876 case 'r': /* Carriage return. */
879 case 't': /* Horizontal tab. */
882 case 'v': /* Vertical tab. */
889 error (0, 0, _("warning: unrecognized escape `\\%c'"), c
);
895 /* Print the information specified by the format string, FORMAT,
896 calling PRINT_FUNC for each %-directive encountered.
897 Return zero upon success, nonzero upon failure. */
898 static bool ATTRIBUTE_WARN_UNUSED_RESULT
899 print_it (char const *format
, char const *filename
,
900 bool (*print_func
) (char *, size_t, char, char const *, void const *),
905 /* Add 2 to accommodate our conversion of the stat `%s' format string
906 to the longer printf `%llu' one. */
909 MAX_ADDITIONAL_BYTES
=
910 (MAX (sizeof PRIdMAX
,
911 MAX (sizeof PRIoMAX
, MAX (sizeof PRIuMAX
, sizeof PRIxMAX
)))
914 size_t n_alloc
= strlen (format
) + MAX_ADDITIONAL_BYTES
+ 1;
915 char *dest
= xmalloc (n_alloc
);
917 for (b
= format
; *b
; b
++)
923 size_t len
= strspn (b
+ 1, "#-+.I 0123456789");
924 char const *fmt_char
= b
+ len
+ 1;
925 memcpy (dest
, b
, len
+ 1);
936 dest
[len
+ 1] = *fmt_char
;
937 dest
[len
+ 2] = '\0';
938 error (EXIT_FAILURE
, 0, _("%s: invalid directive"),
939 quotearg_colon (dest
));
944 fail
|= print_func (dest
, len
+ 1, *fmt_char
, filename
, data
);
951 if ( ! interpret_backslash_escapes
)
959 int esc_value
= octtobin (*b
);
960 int esc_length
= 1; /* number of octal digits */
961 for (++b
; esc_length
< 3 && isodigit (*b
);
964 esc_value
= esc_value
* 8 + octtobin (*b
);
969 else if (*b
== 'x' && isxdigit (to_uchar (b
[1])))
971 int esc_value
= hextobin (b
[1]); /* Value of \xhh escape. */
972 /* A hexadecimal \xhh escape sequence must have
973 1 or 2 hex. digits. */
975 if (isxdigit (to_uchar (b
[1])))
978 esc_value
= esc_value
* 16 + hextobin (*b
);
984 error (0, 0, _("warning: backslash at end of format"));
986 /* Arrange to exit the loop. */
1002 fputs (trailing_delim
, stdout
);
1007 /* Stat the file system and print what we find. */
1008 static bool ATTRIBUTE_WARN_UNUSED_RESULT
1009 do_statfs (char const *filename
, bool terse
, char const *format
)
1011 STRUCT_STATVFS statfsbuf
;
1013 if (STREQ (filename
, "-"))
1015 error (0, 0, _("using %s to denote standard input does not work"
1016 " in file system mode"), quote (filename
));
1020 if (STATFS (filename
, &statfsbuf
) != 0)
1022 error (0, errno
, _("cannot read file system information for %s"),
1027 bool fail
= print_it (format
, filename
, print_statfs
, &statfsbuf
);
1031 /* stat the file and print what we find */
1032 static bool ATTRIBUTE_WARN_UNUSED_RESULT
1033 do_stat (char const *filename
, bool terse
, char const *format
,
1034 char const *format2
)
1036 struct stat statbuf
;
1038 if (STREQ (filename
, "-"))
1040 if (fstat (STDIN_FILENO
, &statbuf
) != 0)
1042 error (0, errno
, _("cannot stat standard input"));
1046 /* We can't use the shorter
1047 (follow_links?stat:lstat) (filename, &statbug)
1048 since stat might be a function-like macro. */
1049 else if ((follow_links
1050 ? stat (filename
, &statbuf
)
1051 : lstat (filename
, &statbuf
)) != 0)
1053 error (0, errno
, _("cannot stat %s"), quote (filename
));
1057 if (S_ISBLK (statbuf
.st_mode
) || S_ISCHR (statbuf
.st_mode
))
1060 bool fail
= print_it (format
, filename
, print_stat
, &statbuf
);
1064 /* Return an allocated format string in static storage that
1065 corresponds to whether FS and TERSE options were declared. */
1067 default_format (bool fs
, bool terse
, bool device
)
1073 format
= xstrdup ("%n %i %l %t %s %S %b %f %a %c %d\n");
1076 /* TRANSLATORS: This string uses format specifiers from
1077 'stat --help' with --file-system, and NOT from printf. */
1078 format
= xstrdup (_("\
1080 ID: %-8i Namelen: %-7l Type: %T\n\
1081 Block size: %-10s Fundamental block size: %S\n\
1082 Blocks: Total: %-10b Free: %-10f Available: %a\n\
1083 Inodes: Total: %-10c Free: %d\n\
1091 if (0 < is_selinux_enabled ())
1092 format
= xstrdup ("%n %s %b %f %u %g %D %i %h %t %T"
1093 " %X %Y %Z %W %o %C\n");
1095 format
= xstrdup ("%n %s %b %f %u %g %D %i %h %t %T"
1096 " %X %Y %Z %W %o\n");
1101 /* TRANSLATORS: This string uses format specifiers from
1102 'stat --help' without --file-system, and NOT from printf. */
1103 format
= xstrdup (_("\
1105 Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n\
1111 /* TRANSLATORS: This string uses format specifiers from
1112 'stat --help' without --file-system, and NOT from printf. */
1113 format
= xasprintf ("%s%s", format
, _("\
1114 Device: %Dh/%dd\tInode: %-10i Links: %-5h Device type: %t,%T\n\
1119 /* TRANSLATORS: This string uses format specifiers from
1120 'stat --help' without --file-system, and NOT from printf. */
1121 format
= xasprintf ("%s%s", format
, _("\
1122 Device: %Dh/%dd\tInode: %-10i Links: %h\n\
1128 /* TRANSLATORS: This string uses format specifiers from
1129 'stat --help' without --file-system, and NOT from printf. */
1130 format
= xasprintf ("%s%s", format
, _("\
1131 Access: (%04a/%10.10A) Uid: (%5u/%8U) Gid: (%5g/%8G)\n\
1135 if (0 < is_selinux_enabled ())
1138 /* TRANSLATORS: This string uses format specifiers from
1139 'stat --help' without --file-system, and NOT from printf. */
1140 format
= xasprintf ("%s%s", format
, _("\
1147 /* TRANSLATORS: This string uses format specifiers from
1148 'stat --help' without --file-system, and NOT from printf. */
1149 format
= xasprintf ("%s%s", format
, _("\
1164 if (status
!= EXIT_SUCCESS
)
1165 fprintf (stderr
, _("Try `%s --help' for more information.\n"),
1169 printf (_("Usage: %s [OPTION]... FILE...\n"), program_name
);
1171 Display file or file system status.\n\
1173 -L, --dereference follow links\n\
1174 -f, --file-system display file system status instead of file status\n\
1177 -c --format=FORMAT use the specified FORMAT instead of the default;\n\
1178 output a newline after each use of FORMAT\n\
1179 --printf=FORMAT like --format, but interpret backslash escapes,\n\
1180 and do not output a mandatory trailing newline.\n\
1181 If you want a newline, include \\n in FORMAT\n\
1182 -t, --terse print the information in terse form\n\
1184 fputs (HELP_OPTION_DESCRIPTION
, stdout
);
1185 fputs (VERSION_OPTION_DESCRIPTION
, stdout
);
1188 The valid format sequences for files (without --file-system):\n\
1190 %a Access rights in octal\n\
1191 %A Access rights in human readable form\n\
1192 %b Number of blocks allocated (see %B)\n\
1193 %B The size in bytes of each block reported by %b\n\
1194 %C SELinux security context string\n\
1197 %d Device number in decimal\n\
1198 %D Device number in hex\n\
1199 %f Raw mode in hex\n\
1201 %g Group ID of owner\n\
1202 %G Group name of owner\n\
1205 %h Number of hard links\n\
1209 %N Quoted file name with dereference if symbolic link\n\
1210 %o I/O block size\n\
1211 %s Total size, in bytes\n\
1212 %t Major device type in hex\n\
1213 %T Minor device type in hex\n\
1216 %u User ID of owner\n\
1217 %U User name of owner\n\
1218 %w Time of file birth, or - if unknown\n\
1219 %W Time of file birth as seconds since Epoch, or - if unknown\n\
1220 %x Time of last access\n\
1221 %X Time of last access as seconds since Epoch\n\
1222 %y Time of last modification\n\
1223 %Y Time of last modification as seconds since Epoch\n\
1224 %z Time of last change\n\
1225 %Z Time of last change as seconds since Epoch\n\
1230 Valid format sequences for file systems:\n\
1232 %a Free blocks available to non-superuser\n\
1233 %b Total data blocks in file system\n\
1234 %c Total file nodes in file system\n\
1235 %d Free file nodes in file system\n\
1236 %f Free blocks in file system\n\
1239 %i File System ID in hex\n\
1240 %l Maximum length of filenames\n\
1242 %s Block size (for faster transfers)\n\
1243 %S Fundamental block size (for block counts)\n\
1245 %T Type in human readable form\n\
1247 printf (USAGE_BUILTIN_WARNING
, PROGRAM_NAME
);
1248 emit_ancillary_info ();
1254 main (int argc
, char *argv
[])
1260 char *format
= NULL
;
1264 initialize_main (&argc
, &argv
);
1265 set_program_name (argv
[0]);
1266 setlocale (LC_ALL
, "");
1267 bindtextdomain (PACKAGE
, LOCALEDIR
);
1268 textdomain (PACKAGE
);
1270 atexit (close_stdout
);
1272 while ((c
= getopt_long (argc
, argv
, "c:fLt", long_options
, NULL
)) != -1)
1278 interpret_backslash_escapes
= true;
1279 trailing_delim
= "";
1284 interpret_backslash_escapes
= false;
1285 trailing_delim
= "\n";
1289 follow_links
= true;
1300 case_GETOPT_HELP_CHAR
;
1302 case_GETOPT_VERSION_CHAR (PROGRAM_NAME
, AUTHORS
);
1305 usage (EXIT_FAILURE
);
1311 error (0, 0, _("missing operand"));
1312 usage (EXIT_FAILURE
);
1319 format
= default_format (fs
, terse
, false);
1320 format2
= default_format (fs
, terse
, true);
1323 for (i
= optind
; i
< argc
; i
++)
1325 ? do_statfs (argv
[i
], terse
, format
)
1326 : do_stat (argv
[i
], terse
, format
, format2
));
1328 exit (ok
? EXIT_SUCCESS
: EXIT_FAILURE
);