tests: remove a non portable localtime test
[coreutils.git] / src / stat.c
blobe11e4318f8572c8032c804b3decf84db44e4499f
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. */
19 #include <config.h>
21 /* Keep this conditional in sync with the similar conditional in
22 ../m4/stat-prog.m4. */
23 #if ((STAT_STATVFS || STAT_STATVFS64) \
24 && (HAVE_STRUCT_STATVFS_F_BASETYPE || HAVE_STRUCT_STATVFS_F_FSTYPENAME \
25 || (! HAVE_STRUCT_STATFS_F_FSTYPENAME && HAVE_STRUCT_STATVFS_F_TYPE)))
26 # define USE_STATVFS 1
27 #else
28 # define USE_STATVFS 0
29 #endif
31 #include <stddef.h>
32 #include <stdio.h>
33 #include <stdalign.h>
34 #include <sys/types.h>
35 #include <pwd.h>
36 #include <grp.h>
37 #if USE_STATVFS
38 # include <sys/statvfs.h>
39 #elif HAVE_SYS_VFS_H
40 # include <sys/vfs.h>
41 #elif HAVE_SYS_MOUNT_H && HAVE_SYS_PARAM_H
42 /* NOTE: freebsd5.0 needs sys/param.h and sys/mount.h for statfs.
43 It does have statvfs.h, but shouldn't use it, since it doesn't
44 HAVE_STRUCT_STATVFS_F_BASETYPE. So find a clean way to fix it. */
45 /* NetBSD 1.5.2 needs these, for the declaration of struct statfs. */
46 # include <sys/param.h>
47 # include <sys/mount.h>
48 # if HAVE_NFS_NFS_CLNT_H && HAVE_NFS_VFS_H
49 /* Ultrix 4.4 needs these for the declaration of struct statfs. */
50 # include <netinet/in.h>
51 # include <nfs/nfs_clnt.h>
52 # include <nfs/vfs.h>
53 # endif
54 #elif HAVE_OS_H /* BeOS */
55 # include <fs_info.h>
56 #endif
57 #include <selinux/selinux.h>
59 #include "system.h"
61 #include "areadlink.h"
62 #include "error.h"
63 #include "file-type.h"
64 #include "filemode.h"
65 #include "fs.h"
66 #include "getopt.h"
67 #include "mountlist.h"
68 #include "quote.h"
69 #include "stat-size.h"
70 #include "stat-time.h"
71 #include "strftime.h"
72 #include "find-mount-point.h"
73 #include "xvasprintf.h"
75 #if USE_STATVFS
76 # define STRUCT_STATXFS_F_FSID_IS_INTEGER STRUCT_STATVFS_F_FSID_IS_INTEGER
77 # define HAVE_STRUCT_STATXFS_F_TYPE HAVE_STRUCT_STATVFS_F_TYPE
78 # if HAVE_STRUCT_STATVFS_F_NAMEMAX
79 # define SB_F_NAMEMAX(S) ((S)->f_namemax)
80 # endif
81 # if ! STAT_STATVFS && STAT_STATVFS64
82 # define STRUCT_STATVFS struct statvfs64
83 # define STATFS statvfs64
84 # else
85 # define STRUCT_STATVFS struct statvfs
86 # define STATFS statvfs
87 # endif
88 # define STATFS_FRSIZE(S) ((S)->f_frsize)
89 #else
90 # define HAVE_STRUCT_STATXFS_F_TYPE HAVE_STRUCT_STATFS_F_TYPE
91 # if HAVE_STRUCT_STATFS_F_NAMELEN
92 # define SB_F_NAMEMAX(S) ((S)->f_namelen)
93 # endif
94 # define STATFS statfs
95 # if HAVE_OS_H /* BeOS */
96 /* BeOS has a statvfs function, but it does not return sensible values
97 for f_files, f_ffree and f_favail, and lacks f_type, f_basetype and
98 f_fstypename. Use 'struct fs_info' instead. */
99 static int ATTRIBUTE_WARN_UNUSED_RESULT
100 statfs (char const *filename, struct fs_info *buf)
102 dev_t device = dev_for_path (filename);
103 if (device < 0)
105 errno = (device == B_ENTRY_NOT_FOUND ? ENOENT
106 : device == B_BAD_VALUE ? EINVAL
107 : device == B_NAME_TOO_LONG ? ENAMETOOLONG
108 : device == B_NO_MEMORY ? ENOMEM
109 : device == B_FILE_ERROR ? EIO
110 : 0);
111 return -1;
113 /* If successful, buf->dev will be == device. */
114 return fs_stat_dev (device, buf);
116 # define f_fsid dev
117 # define f_blocks total_blocks
118 # define f_bfree free_blocks
119 # define f_bavail free_blocks
120 # define f_bsize io_size
121 # define f_files total_nodes
122 # define f_ffree free_nodes
123 # define STRUCT_STATVFS struct fs_info
124 # define STRUCT_STATXFS_F_FSID_IS_INTEGER true
125 # define STATFS_FRSIZE(S) ((S)->block_size)
126 # else
127 # define STRUCT_STATVFS struct statfs
128 # define STRUCT_STATXFS_F_FSID_IS_INTEGER STRUCT_STATFS_F_FSID_IS_INTEGER
129 # if HAVE_STRUCT_STATFS_F_FRSIZE
130 # define STATFS_FRSIZE(S) ((S)->f_frsize)
131 # else
132 # define STATFS_FRSIZE(S) 0
133 # endif
134 # endif
135 #endif
137 #ifdef SB_F_NAMEMAX
138 # define OUT_NAMEMAX out_uint
139 #else
140 /* NetBSD 1.5.2 has neither f_namemax nor f_namelen. */
141 # define SB_F_NAMEMAX(S) "*"
142 # define OUT_NAMEMAX out_string
143 #endif
145 #if HAVE_STRUCT_STATVFS_F_BASETYPE
146 # define STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME f_basetype
147 #else
148 # if HAVE_STRUCT_STATVFS_F_FSTYPENAME || HAVE_STRUCT_STATFS_F_FSTYPENAME
149 # define STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME f_fstypename
150 # elif HAVE_OS_H /* BeOS */
151 # define STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME fsh_name
152 # endif
153 #endif
155 #if HAVE_GETATTRAT
156 # include <attr.h>
157 # include <sys/nvpair.h>
158 #endif
160 /* FIXME: these are used by printf.c, too */
161 #define isodigit(c) ('0' <= (c) && (c) <= '7')
162 #define octtobin(c) ((c) - '0')
163 #define hextobin(c) ((c) >= 'a' && (c) <= 'f' ? (c) - 'a' + 10 : \
164 (c) >= 'A' && (c) <= 'F' ? (c) - 'A' + 10 : (c) - '0')
166 static char const digits[] = "0123456789";
168 /* Flags that are portable for use in printf, for at least one
169 conversion specifier; make_format removes unportable flags as
170 needed for particular specifiers. The glibc 2.2 extension "I" is
171 listed here; it is removed by make_format because it has undefined
172 behavior elsewhere and because it is incompatible with
173 out_epoch_sec. */
174 static char const printf_flags[] = "'-+ #0I";
176 #define PROGRAM_NAME "stat"
178 #define AUTHORS proper_name ("Michael Meskes")
180 enum
182 PRINTF_OPTION = CHAR_MAX + 1
185 static struct option const long_options[] =
187 {"dereference", no_argument, NULL, 'L'},
188 {"file-system", no_argument, NULL, 'f'},
189 {"format", required_argument, NULL, 'c'},
190 {"printf", required_argument, NULL, PRINTF_OPTION},
191 {"terse", no_argument, NULL, 't'},
192 {GETOPT_HELP_OPTION_DECL},
193 {GETOPT_VERSION_OPTION_DECL},
194 {NULL, 0, NULL, 0}
197 /* Whether to follow symbolic links; True for --dereference (-L). */
198 static bool follow_links;
200 /* Whether to interpret backslash-escape sequences.
201 True for --printf=FMT, not for --format=FMT (-c). */
202 static bool interpret_backslash_escapes;
204 /* The trailing delimiter string:
205 "" for --printf=FMT, "\n" for --format=FMT (-c). */
206 static char const *trailing_delim = "";
208 /* The representation of the decimal point in the current locale. */
209 static char const *decimal_point;
210 static size_t decimal_point_len;
212 /* Return the type of the specified file system.
213 Some systems have statfvs.f_basetype[FSTYPSZ] (AIX, HP-UX, and Solaris).
214 Others have statvfs.f_fstypename[_VFS_NAMELEN] (NetBSD 3.0).
215 Others have statfs.f_fstypename[MFSNAMELEN] (NetBSD 1.5.2).
216 Still others have neither and have to get by with f_type (GNU/Linux).
217 But f_type may only exist in statfs (Cygwin). */
218 static char const * ATTRIBUTE_WARN_UNUSED_RESULT
219 human_fstype (STRUCT_STATVFS const *statfsbuf)
221 #ifdef STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME
222 return statfsbuf->STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME;
223 #else
224 switch (statfsbuf->f_type)
226 # if defined __linux__
228 /* Compare with what's in libc:
229 f=/a/libc/sysdeps/unix/sysv/linux/linux_fsinfo.h
230 sed -n '/ADFS_SUPER_MAGIC/,/SYSFS_MAGIC/p' $f \
231 | perl -n -e '/#define (.*?)_(?:SUPER_)MAGIC\s+0x(\S+)/' \
232 -e 'and print "case S_MAGIC_$1: /\* 0x" . uc($2) . " *\/\n"' \
233 | sort > sym_libc
234 perl -ne '/^\s+(case S_MAGIC_.*?): \/\* 0x(\S+) \*\//' \
235 -e 'and do { $v=uc$2; print "$1: /\* 0x$v *\/\n"}' stat.c \
236 | sort > sym_stat
237 diff -u sym_stat sym_libc
240 /* Also compare with the list in "man 2 statfs" using the
241 fs-magic-compare make target. */
243 /* IMPORTANT NOTE: Each of the following 'case S_MAGIC_...:'
244 statements must be followed by a hexadecimal constant in
245 a comment. The S_MAGIC_... name and constant are automatically
246 combined to produce the #define directives in fs.h. */
248 case S_MAGIC_ACFS: /* 0x61636673 remote */
249 return "acfs";
250 case S_MAGIC_ADFS: /* 0xADF5 local */
251 return "adfs";
252 case S_MAGIC_AFFS: /* 0xADFF local */
253 return "affs";
254 case S_MAGIC_AFS: /* 0x5346414F remote */
255 return "afs";
256 case S_MAGIC_ANON_INODE_FS: /* 0x09041934 local */
257 return "anon-inode FS";
258 case S_MAGIC_AUFS: /* 0x61756673 remote */
259 /* FIXME: change syntax or add an optional attribute like "inotify:no".
260 The above is labeled as "remote" so that tail always uses polling,
261 but this isn't really a remote file system type. */
262 return "aufs";
263 case S_MAGIC_AUTOFS: /* 0x0187 local */
264 return "autofs";
265 case S_MAGIC_BEFS: /* 0x42465331 local */
266 return "befs";
267 case S_MAGIC_BDEVFS: /* 0x62646576 local */
268 return "bdevfs";
269 case S_MAGIC_BFS: /* 0x1BADFACE local */
270 return "bfs";
271 case S_MAGIC_BPF_FS: /* 0xCAFE4A11 local */
272 return "bpf_fs";
273 case S_MAGIC_BINFMTFS: /* 0x42494E4D local */
274 return "binfmt_misc";
275 case S_MAGIC_BTRFS: /* 0x9123683E local */
276 return "btrfs";
277 case S_MAGIC_BTRFS_TEST: /* 0x73727279 local */
278 return "btrfs_test";
279 case S_MAGIC_CEPH: /* 0x00C36400 remote */
280 return "ceph";
281 case S_MAGIC_CGROUP: /* 0x0027E0EB local */
282 return "cgroupfs";
283 case S_MAGIC_CIFS: /* 0xFF534D42 remote */
284 return "cifs";
285 case S_MAGIC_CODA: /* 0x73757245 remote */
286 return "coda";
287 case S_MAGIC_COH: /* 0x012FF7B7 local */
288 return "coh";
289 case S_MAGIC_CONFIGFS: /* 0x62656570 local */
290 return "configfs";
291 case S_MAGIC_CRAMFS: /* 0x28CD3D45 local */
292 return "cramfs";
293 case S_MAGIC_CRAMFS_WEND: /* 0x453DCD28 local */
294 return "cramfs-wend";
295 case S_MAGIC_DEBUGFS: /* 0x64626720 local */
296 return "debugfs";
297 case S_MAGIC_DEVFS: /* 0x1373 local */
298 return "devfs";
299 case S_MAGIC_DEVPTS: /* 0x1CD1 local */
300 return "devpts";
301 case S_MAGIC_ECRYPTFS: /* 0xF15F local */
302 return "ecryptfs";
303 case S_MAGIC_EFIVARFS: /* 0xDE5E81E4 local */
304 return "efivarfs";
305 case S_MAGIC_EFS: /* 0x00414A53 local */
306 return "efs";
307 case S_MAGIC_EXOFS: /* 0x5DF5 local */
308 return "exofs";
309 case S_MAGIC_EXT: /* 0x137D local */
310 return "ext";
311 case S_MAGIC_EXT2: /* 0xEF53 local */
312 return "ext2/ext3";
313 case S_MAGIC_EXT2_OLD: /* 0xEF51 local */
314 return "ext2";
315 case S_MAGIC_F2FS: /* 0xF2F52010 local */
316 return "f2fs";
317 case S_MAGIC_FAT: /* 0x4006 local */
318 return "fat";
319 case S_MAGIC_FHGFS: /* 0x19830326 remote */
320 return "fhgfs";
321 case S_MAGIC_FUSEBLK: /* 0x65735546 remote */
322 return "fuseblk";
323 case S_MAGIC_FUSECTL: /* 0x65735543 remote */
324 return "fusectl";
325 case S_MAGIC_FUTEXFS: /* 0x0BAD1DEA local */
326 return "futexfs";
327 case S_MAGIC_GFS: /* 0x01161970 remote */
328 return "gfs/gfs2";
329 case S_MAGIC_GPFS: /* 0x47504653 remote */
330 return "gpfs";
331 case S_MAGIC_HFS: /* 0x4244 local */
332 return "hfs";
333 case S_MAGIC_HFS_PLUS: /* 0x482B local */
334 return "hfs+";
335 case S_MAGIC_HFS_X: /* 0x4858 local */
336 return "hfsx";
337 case S_MAGIC_HOSTFS: /* 0x00C0FFEE local */
338 return "hostfs";
339 case S_MAGIC_HPFS: /* 0xF995E849 local */
340 return "hpfs";
341 case S_MAGIC_HUGETLBFS: /* 0x958458F6 local */
342 return "hugetlbfs";
343 case S_MAGIC_MTD_INODE_FS: /* 0x11307854 local */
344 return "inodefs";
345 case S_MAGIC_IBRIX: /* 0x013111A8 remote */
346 return "ibrix";
347 case S_MAGIC_INOTIFYFS: /* 0x2BAD1DEA local */
348 return "inotifyfs";
349 case S_MAGIC_ISOFS: /* 0x9660 local */
350 return "isofs";
351 case S_MAGIC_ISOFS_R_WIN: /* 0x4004 local */
352 return "isofs";
353 case S_MAGIC_ISOFS_WIN: /* 0x4000 local */
354 return "isofs";
355 case S_MAGIC_JFFS: /* 0x07C0 local */
356 return "jffs";
357 case S_MAGIC_JFFS2: /* 0x72B6 local */
358 return "jffs2";
359 case S_MAGIC_JFS: /* 0x3153464A local */
360 return "jfs";
361 case S_MAGIC_KAFS: /* 0x6B414653 remote */
362 return "k-afs";
363 case S_MAGIC_LOGFS: /* 0xC97E8168 local */
364 return "logfs";
365 case S_MAGIC_LUSTRE: /* 0x0BD00BD0 remote */
366 return "lustre";
367 case S_MAGIC_MINIX: /* 0x137F local */
368 return "minix";
369 case S_MAGIC_MINIX_30: /* 0x138F local */
370 return "minix (30 char.)";
371 case S_MAGIC_MINIX_V2: /* 0x2468 local */
372 return "minix v2";
373 case S_MAGIC_MINIX_V2_30: /* 0x2478 local */
374 return "minix v2 (30 char.)";
375 case S_MAGIC_MINIX_V3: /* 0x4D5A local */
376 return "minix3";
377 case S_MAGIC_MQUEUE: /* 0x19800202 local */
378 return "mqueue";
379 case S_MAGIC_MSDOS: /* 0x4D44 local */
380 return "msdos";
381 case S_MAGIC_NCP: /* 0x564C remote */
382 return "novell";
383 case S_MAGIC_NFS: /* 0x6969 remote */
384 return "nfs";
385 case S_MAGIC_NFSD: /* 0x6E667364 remote */
386 return "nfsd";
387 case S_MAGIC_NILFS: /* 0x3434 local */
388 return "nilfs";
389 case S_MAGIC_NSFS: /* 0x6E736673 local */
390 return "nsfs";
391 case S_MAGIC_NTFS: /* 0x5346544E local */
392 return "ntfs";
393 case S_MAGIC_OPENPROM: /* 0x9FA1 local */
394 return "openprom";
395 case S_MAGIC_OCFS2: /* 0x7461636F remote */
396 return "ocfs2";
397 case S_MAGIC_OVERLAYFS: /* 0x794C7630 remote */
398 /* This may overlay remote file systems.
399 Also there have been issues reported with inotify and overlayfs,
400 so mark as "remote" so that polling is used. */
401 return "overlayfs";
402 case S_MAGIC_PANFS: /* 0xAAD7AAEA remote */
403 return "panfs";
404 case S_MAGIC_PIPEFS: /* 0x50495045 remote */
405 /* FIXME: change syntax or add an optional attribute like "inotify:no".
406 The above is labeled as "remote" so that tail always uses polling,
407 but this isn't really a remote file system type. */
408 return "pipefs";
409 case S_MAGIC_PROC: /* 0x9FA0 local */
410 return "proc";
411 case S_MAGIC_PSTOREFS: /* 0x6165676C local */
412 return "pstorefs";
413 case S_MAGIC_QNX4: /* 0x002F local */
414 return "qnx4";
415 case S_MAGIC_QNX6: /* 0x68191122 local */
416 return "qnx6";
417 case S_MAGIC_RAMFS: /* 0x858458F6 local */
418 return "ramfs";
419 case S_MAGIC_REISERFS: /* 0x52654973 local */
420 return "reiserfs";
421 case S_MAGIC_ROMFS: /* 0x7275 local */
422 return "romfs";
423 case S_MAGIC_RPC_PIPEFS: /* 0x67596969 local */
424 return "rpc_pipefs";
425 case S_MAGIC_SECURITYFS: /* 0x73636673 local */
426 return "securityfs";
427 case S_MAGIC_SELINUX: /* 0xF97CFF8C local */
428 return "selinux";
429 case S_MAGIC_SMACK: /* 0x43415D53 local */
430 return "smackfs";
431 case S_MAGIC_SMB: /* 0x517B remote */
432 return "smb";
433 case S_MAGIC_SNFS: /* 0xBEEFDEAD remote */
434 return "snfs";
435 case S_MAGIC_SOCKFS: /* 0x534F434B local */
436 return "sockfs";
437 case S_MAGIC_SQUASHFS: /* 0x73717368 local */
438 return "squashfs";
439 case S_MAGIC_SYSFS: /* 0x62656572 local */
440 return "sysfs";
441 case S_MAGIC_SYSV2: /* 0x012FF7B6 local */
442 return "sysv2";
443 case S_MAGIC_SYSV4: /* 0x012FF7B5 local */
444 return "sysv4";
445 case S_MAGIC_TMPFS: /* 0x01021994 local */
446 return "tmpfs";
447 case S_MAGIC_TRACEFS: /* 0x74726163 local */
448 return "tracefs";
449 case S_MAGIC_UBIFS: /* 0x24051905 local */
450 return "ubifs";
451 case S_MAGIC_UDF: /* 0x15013346 local */
452 return "udf";
453 case S_MAGIC_UFS: /* 0x00011954 local */
454 return "ufs";
455 case S_MAGIC_UFS_BYTESWAPPED: /* 0x54190100 local */
456 return "ufs";
457 case S_MAGIC_USBDEVFS: /* 0x9FA2 local */
458 return "usbdevfs";
459 case S_MAGIC_V9FS: /* 0x01021997 local */
460 return "v9fs";
461 case S_MAGIC_VMHGFS: /* 0xBACBACBC remote */
462 return "vmhgfs";
463 case S_MAGIC_VXFS: /* 0xA501FCF5 remote */
464 /* Veritas File System can run in single instance or clustered mode,
465 so mark as remote to cater for the latter case. */
466 return "vxfs";
467 case S_MAGIC_VZFS: /* 0x565A4653 local */
468 return "vzfs";
469 case S_MAGIC_XENFS: /* 0xABBA1974 local */
470 return "xenfs";
471 case S_MAGIC_XENIX: /* 0x012FF7B4 local */
472 return "xenix";
473 case S_MAGIC_XFS: /* 0x58465342 local */
474 return "xfs";
475 case S_MAGIC_XIAFS: /* 0x012FD16D local */
476 return "xia";
477 case S_MAGIC_ZFS: /* 0x2FC12FC1 local */
478 return "zfs";
480 # elif __GNU__
481 case FSTYPE_UFS:
482 return "ufs";
483 case FSTYPE_NFS:
484 return "nfs";
485 case FSTYPE_GFS:
486 return "gfs";
487 case FSTYPE_LFS:
488 return "lfs";
489 case FSTYPE_SYSV:
490 return "sysv";
491 case FSTYPE_FTP:
492 return "ftp";
493 case FSTYPE_TAR:
494 return "tar";
495 case FSTYPE_AR:
496 return "ar";
497 case FSTYPE_CPIO:
498 return "cpio";
499 case FSTYPE_MSLOSS:
500 return "msloss";
501 case FSTYPE_CPM:
502 return "cpm";
503 case FSTYPE_HFS:
504 return "hfs";
505 case FSTYPE_DTFS:
506 return "dtfs";
507 case FSTYPE_GRFS:
508 return "grfs";
509 case FSTYPE_TERM:
510 return "term";
511 case FSTYPE_DEV:
512 return "dev";
513 case FSTYPE_PROC:
514 return "proc";
515 case FSTYPE_IFSOCK:
516 return "ifsock";
517 case FSTYPE_AFS:
518 return "afs";
519 case FSTYPE_DFS:
520 return "dfs";
521 case FSTYPE_PROC9:
522 return "proc9";
523 case FSTYPE_SOCKET:
524 return "socket";
525 case FSTYPE_MISC:
526 return "misc";
527 case FSTYPE_EXT2FS:
528 return "ext2/ext3";
529 case FSTYPE_HTTP:
530 return "http";
531 case FSTYPE_MEMFS:
532 return "memfs";
533 case FSTYPE_ISO9660:
534 return "iso9660";
535 # endif
536 default:
538 unsigned long int type = statfsbuf->f_type;
539 static char buf[sizeof "UNKNOWN (0x%lx)" - 3
540 + (sizeof type * CHAR_BIT + 3) / 4];
541 sprintf (buf, "UNKNOWN (0x%lx)", type);
542 return buf;
545 #endif
548 static char * ATTRIBUTE_WARN_UNUSED_RESULT
549 human_access (struct stat const *statbuf)
551 static char modebuf[12];
552 filemodestring (statbuf, modebuf);
553 modebuf[10] = 0;
554 return modebuf;
557 static char * ATTRIBUTE_WARN_UNUSED_RESULT
558 human_time (struct timespec t)
560 static char str[MAX (INT_BUFSIZE_BOUND (intmax_t),
561 (INT_STRLEN_BOUND (int) /* YYYY */
562 + 1 /* because YYYY might equal INT_MAX + 1900 */
563 + sizeof "-MM-DD HH:MM:SS.NNNNNNNNN +ZZZZ"))];
564 static timezone_t tz;
565 if (!tz)
566 tz = tzalloc (getenv ("TZ"));
567 struct tm const *tm = localtime (&t.tv_sec);
568 if (tm == NULL)
569 return timetostr (t.tv_sec, str);
570 nstrftime (str, sizeof str, "%Y-%m-%d %H:%M:%S.%N %z", tm, tz, t.tv_nsec);
571 return str;
574 /* PFORMAT points to a '%' followed by a prefix of a format, all of
575 size PREFIX_LEN. The flags allowed for this format are
576 ALLOWED_FLAGS; remove other printf flags from the prefix, then
577 append SUFFIX. */
578 static void
579 make_format (char *pformat, size_t prefix_len, char const *allowed_flags,
580 char const *suffix)
582 char *dst = pformat + 1;
583 char const *src;
584 char const *srclim = pformat + prefix_len;
585 for (src = dst; src < srclim && strchr (printf_flags, *src); src++)
586 if (strchr (allowed_flags, *src))
587 *dst++ = *src;
588 while (src < srclim)
589 *dst++ = *src++;
590 strcpy (dst, suffix);
593 static void
594 out_string (char *pformat, size_t prefix_len, char const *arg)
596 make_format (pformat, prefix_len, "-", "s");
597 printf (pformat, arg);
599 static int
600 out_int (char *pformat, size_t prefix_len, intmax_t arg)
602 make_format (pformat, prefix_len, "'-+ 0", PRIdMAX);
603 return printf (pformat, arg);
605 static int
606 out_uint (char *pformat, size_t prefix_len, uintmax_t arg)
608 make_format (pformat, prefix_len, "'-0", PRIuMAX);
609 return printf (pformat, arg);
611 static void
612 out_uint_o (char *pformat, size_t prefix_len, uintmax_t arg)
614 make_format (pformat, prefix_len, "-#0", PRIoMAX);
615 printf (pformat, arg);
617 static void
618 out_uint_x (char *pformat, size_t prefix_len, uintmax_t arg)
620 make_format (pformat, prefix_len, "-#0", PRIxMAX);
621 printf (pformat, arg);
623 static int
624 out_minus_zero (char *pformat, size_t prefix_len)
626 make_format (pformat, prefix_len, "'-+ 0", ".0f");
627 return printf (pformat, -0.25);
630 /* Output the number of seconds since the Epoch, using a format that
631 acts like printf's %f format. */
632 static void
633 out_epoch_sec (char *pformat, size_t prefix_len,
634 struct stat const *statbuf _GL_UNUSED,
635 struct timespec arg)
637 char *dot = memchr (pformat, '.', prefix_len);
638 size_t sec_prefix_len = prefix_len;
639 int width = 0;
640 int precision = 0;
641 bool frac_left_adjust = false;
643 if (dot)
645 sec_prefix_len = dot - pformat;
646 pformat[prefix_len] = '\0';
648 if (ISDIGIT (dot[1]))
650 long int lprec = strtol (dot + 1, NULL, 10);
651 precision = (lprec <= INT_MAX ? lprec : INT_MAX);
653 else
655 precision = 9;
658 if (precision && ISDIGIT (dot[-1]))
660 /* If a nontrivial width is given, subtract the width of the
661 decimal point and PRECISION digits that will be output
662 later. */
663 char *p = dot;
664 *dot = '\0';
667 --p;
668 while (ISDIGIT (p[-1]));
670 long int lwidth = strtol (p, NULL, 10);
671 width = (lwidth <= INT_MAX ? lwidth : INT_MAX);
672 if (1 < width)
674 p += (*p == '0');
675 sec_prefix_len = p - pformat;
676 int w_d = (decimal_point_len < width
677 ? width - decimal_point_len
678 : 0);
679 if (1 < w_d)
681 int w = w_d - precision;
682 if (1 < w)
684 char *dst = pformat;
685 for (char const *src = dst; src < p; src++)
687 if (*src == '-')
688 frac_left_adjust = true;
689 else
690 *dst++ = *src;
692 sec_prefix_len =
693 (dst - pformat
694 + (frac_left_adjust ? 0 : sprintf (dst, "%d", w)));
701 int divisor = 1;
702 for (int i = precision; i < 9; i++)
703 divisor *= 10;
704 int frac_sec = arg.tv_nsec / divisor;
705 int int_len;
707 if (TYPE_SIGNED (time_t))
709 bool minus_zero = false;
710 if (arg.tv_sec < 0 && arg.tv_nsec != 0)
712 int frac_sec_modulus = 1000000000 / divisor;
713 frac_sec = (frac_sec_modulus - frac_sec
714 - (arg.tv_nsec % divisor != 0));
715 arg.tv_sec += (frac_sec != 0);
716 minus_zero = (arg.tv_sec == 0);
718 int_len = (minus_zero
719 ? out_minus_zero (pformat, sec_prefix_len)
720 : out_int (pformat, sec_prefix_len, arg.tv_sec));
722 else
723 int_len = out_uint (pformat, sec_prefix_len, arg.tv_sec);
725 if (precision)
727 int prec = (precision < 9 ? precision : 9);
728 int trailing_prec = precision - prec;
729 int ilen = (int_len < 0 ? 0 : int_len);
730 int trailing_width = (ilen < width && decimal_point_len < width - ilen
731 ? width - ilen - decimal_point_len - prec
732 : 0);
733 printf ("%s%.*d%-*.*d", decimal_point, prec, frac_sec,
734 trailing_width, trailing_prec, 0);
738 /* Print the context information of FILENAME, and return true iff the
739 context could not be obtained. */
740 static bool ATTRIBUTE_WARN_UNUSED_RESULT
741 out_file_context (char *pformat, size_t prefix_len, char const *filename)
743 char *scontext;
744 bool fail = false;
746 if ((follow_links
747 ? getfilecon (filename, &scontext)
748 : lgetfilecon (filename, &scontext)) < 0)
750 error (0, errno, _("failed to get security context of %s"),
751 quoteaf (filename));
752 scontext = NULL;
753 fail = true;
755 strcpy (pformat + prefix_len, "s");
756 printf (pformat, (scontext ? scontext : "?"));
757 if (scontext)
758 freecon (scontext);
759 return fail;
762 /* Print statfs info. Return zero upon success, nonzero upon failure. */
763 static bool ATTRIBUTE_WARN_UNUSED_RESULT
764 print_statfs (char *pformat, size_t prefix_len, unsigned int m,
765 int fd, char const *filename,
766 void const *data)
768 STRUCT_STATVFS const *statfsbuf = data;
769 bool fail = false;
771 switch (m)
773 case 'n':
774 out_string (pformat, prefix_len, filename);
775 break;
777 case 'i':
779 #if STRUCT_STATXFS_F_FSID_IS_INTEGER
780 uintmax_t fsid = statfsbuf->f_fsid;
781 #else
782 typedef unsigned int fsid_word;
783 verify (alignof (STRUCT_STATVFS) % alignof (fsid_word) == 0);
784 verify (offsetof (STRUCT_STATVFS, f_fsid) % alignof (fsid_word) == 0);
785 verify (sizeof statfsbuf->f_fsid % alignof (fsid_word) == 0);
786 fsid_word const *p = (fsid_word *) &statfsbuf->f_fsid;
788 /* Assume a little-endian word order, as that is compatible
789 with glibc's statvfs implementation. */
790 uintmax_t fsid = 0;
791 int words = sizeof statfsbuf->f_fsid / sizeof *p;
792 int i;
793 for (i = 0; i < words && i * sizeof *p < sizeof fsid; i++)
795 uintmax_t u = p[words - 1 - i];
796 fsid |= u << (i * CHAR_BIT * sizeof *p);
798 #endif
799 out_uint_x (pformat, prefix_len, fsid);
801 break;
803 case 'l':
804 OUT_NAMEMAX (pformat, prefix_len, SB_F_NAMEMAX (statfsbuf));
805 break;
806 case 't':
807 #if HAVE_STRUCT_STATXFS_F_TYPE
808 out_uint_x (pformat, prefix_len, statfsbuf->f_type);
809 #else
810 fputc ('?', stdout);
811 #endif
812 break;
813 case 'T':
814 out_string (pformat, prefix_len, human_fstype (statfsbuf));
815 break;
816 case 'b':
817 out_int (pformat, prefix_len, statfsbuf->f_blocks);
818 break;
819 case 'f':
820 out_int (pformat, prefix_len, statfsbuf->f_bfree);
821 break;
822 case 'a':
823 out_int (pformat, prefix_len, statfsbuf->f_bavail);
824 break;
825 case 's':
826 out_uint (pformat, prefix_len, statfsbuf->f_bsize);
827 break;
828 case 'S':
830 uintmax_t frsize = STATFS_FRSIZE (statfsbuf);
831 if (! frsize)
832 frsize = statfsbuf->f_bsize;
833 out_uint (pformat, prefix_len, frsize);
835 break;
836 case 'c':
837 out_uint (pformat, prefix_len, statfsbuf->f_files);
838 break;
839 case 'd':
840 out_int (pformat, prefix_len, statfsbuf->f_ffree);
841 break;
842 default:
843 fputc ('?', stdout);
844 break;
846 return fail;
849 /* Return any bind mounted source for a path.
850 The caller should not free the returned buffer.
851 Return NULL if no bind mount found. */
852 static char const * ATTRIBUTE_WARN_UNUSED_RESULT
853 find_bind_mount (char const * name)
855 char const * bind_mount = NULL;
857 static struct mount_entry *mount_list;
858 static bool tried_mount_list = false;
859 if (!tried_mount_list) /* attempt/warn once per process. */
861 if (!(mount_list = read_file_system_list (false)))
862 error (0, errno, "%s", _("cannot read table of mounted file systems"));
863 tried_mount_list = true;
866 struct stat name_stats;
867 if (stat (name, &name_stats) != 0)
868 return NULL;
870 struct mount_entry *me;
871 for (me = mount_list; me; me = me->me_next)
873 if (me->me_dummy && me->me_devname[0] == '/'
874 && STREQ (me->me_mountdir, name))
876 struct stat dev_stats;
878 if (stat (me->me_devname, &dev_stats) == 0
879 && SAME_INODE (name_stats, dev_stats))
881 bind_mount = me->me_devname;
882 break;
887 return bind_mount;
890 /* Print mount point. Return zero upon success, nonzero upon failure. */
891 static bool ATTRIBUTE_WARN_UNUSED_RESULT
892 out_mount_point (char const *filename, char *pformat, size_t prefix_len,
893 const struct stat *statp)
896 char const *np = "?", *bp = NULL;
897 char *mp = NULL;
898 bool fail = true;
900 /* Look for bind mounts first. Note we output the immediate alias,
901 rather than further resolving to a base device mount point. */
902 if (follow_links || !S_ISLNK (statp->st_mode))
904 char *resolved = canonicalize_file_name (filename);
905 if (!resolved)
907 error (0, errno, _("failed to canonicalize %s"), quoteaf (filename));
908 goto print_mount_point;
910 bp = find_bind_mount (resolved);
911 free (resolved);
912 if (bp)
914 fail = false;
915 goto print_mount_point;
919 /* If there is no direct bind mount, then navigate
920 back up the tree looking for a device change.
921 Note we don't detect if any of the directory components
922 are bind mounted to the same device, but that's OK
923 since we've not directly queried them. */
924 if ((mp = find_mount_point (filename, statp)))
926 /* This dir might be bind mounted to another device,
927 so we resolve the bound source in that case also. */
928 bp = find_bind_mount (mp);
929 fail = false;
932 print_mount_point:
934 out_string (pformat, prefix_len, bp ? bp : mp ? mp : np);
935 free (mp);
936 return fail;
939 static struct timespec
940 get_birthtime (int fd, char const *filename, struct stat const *st)
942 struct timespec ts = get_stat_birthtime (st);
944 #if HAVE_GETATTRAT
945 if (ts.tv_nsec < 0)
947 nvlist_t *response;
948 if ((fd < 0
949 ? getattrat (AT_FDCWD, XATTR_VIEW_READWRITE, filename, &response)
950 : fgetattr (fd, XATTR_VIEW_READWRITE, &response))
951 == 0)
953 uint64_t *val;
954 uint_t n;
955 if (nvlist_lookup_uint64_array (response, A_CRTIME, &val, &n) == 0
956 && 2 <= n
957 && val[0] <= TYPE_MAXIMUM (time_t)
958 && val[1] < 1000000000 * 2 /* for leap seconds */)
960 ts.tv_sec = val[0];
961 ts.tv_nsec = val[1];
963 nvlist_free (response);
966 #endif
968 return ts;
971 /* Map a TS with negative TS.tv_nsec to {0,0}. */
972 static inline struct timespec
973 neg_to_zero (struct timespec ts)
975 if (0 <= ts.tv_nsec)
976 return ts;
977 struct timespec z = {0, 0};
978 return z;
981 /* Print stat info. Return zero upon success, nonzero upon failure. */
982 static bool
983 print_stat (char *pformat, size_t prefix_len, unsigned int m,
984 int fd, char const *filename, void const *data)
986 struct stat *statbuf = (struct stat *) data;
987 struct passwd *pw_ent;
988 struct group *gw_ent;
989 bool fail = false;
991 switch (m)
993 case 'n':
994 out_string (pformat, prefix_len, filename);
995 break;
996 case 'N':
997 out_string (pformat, prefix_len, quoteaf (filename));
998 if (S_ISLNK (statbuf->st_mode))
1000 char *linkname = areadlink_with_size (filename, statbuf->st_size);
1001 if (linkname == NULL)
1003 error (0, errno, _("cannot read symbolic link %s"),
1004 quoteaf (filename));
1005 return true;
1007 printf (" -> ");
1008 out_string (pformat, prefix_len, quoteaf (linkname));
1009 free (linkname);
1011 break;
1012 case 'd':
1013 out_uint (pformat, prefix_len, statbuf->st_dev);
1014 break;
1015 case 'D':
1016 out_uint_x (pformat, prefix_len, statbuf->st_dev);
1017 break;
1018 case 'i':
1019 out_uint (pformat, prefix_len, statbuf->st_ino);
1020 break;
1021 case 'a':
1022 out_uint_o (pformat, prefix_len, statbuf->st_mode & CHMOD_MODE_BITS);
1023 break;
1024 case 'A':
1025 out_string (pformat, prefix_len, human_access (statbuf));
1026 break;
1027 case 'f':
1028 out_uint_x (pformat, prefix_len, statbuf->st_mode);
1029 break;
1030 case 'F':
1031 out_string (pformat, prefix_len, file_type (statbuf));
1032 break;
1033 case 'h':
1034 out_uint (pformat, prefix_len, statbuf->st_nlink);
1035 break;
1036 case 'u':
1037 out_uint (pformat, prefix_len, statbuf->st_uid);
1038 break;
1039 case 'U':
1040 pw_ent = getpwuid (statbuf->st_uid);
1041 out_string (pformat, prefix_len,
1042 pw_ent ? pw_ent->pw_name : "UNKNOWN");
1043 break;
1044 case 'g':
1045 out_uint (pformat, prefix_len, statbuf->st_gid);
1046 break;
1047 case 'G':
1048 gw_ent = getgrgid (statbuf->st_gid);
1049 out_string (pformat, prefix_len,
1050 gw_ent ? gw_ent->gr_name : "UNKNOWN");
1051 break;
1052 case 't':
1053 out_uint_x (pformat, prefix_len, major (statbuf->st_rdev));
1054 break;
1055 case 'm':
1056 fail |= out_mount_point (filename, pformat, prefix_len, statbuf);
1057 break;
1058 case 'T':
1059 out_uint_x (pformat, prefix_len, minor (statbuf->st_rdev));
1060 break;
1061 case 's':
1062 out_int (pformat, prefix_len, statbuf->st_size);
1063 break;
1064 case 'B':
1065 out_uint (pformat, prefix_len, ST_NBLOCKSIZE);
1066 break;
1067 case 'b':
1068 out_uint (pformat, prefix_len, ST_NBLOCKS (*statbuf));
1069 break;
1070 case 'o':
1071 out_uint (pformat, prefix_len, ST_BLKSIZE (*statbuf));
1072 break;
1073 case 'w':
1075 struct timespec t = get_birthtime (fd, filename, statbuf);
1076 if (t.tv_nsec < 0)
1077 out_string (pformat, prefix_len, "-");
1078 else
1079 out_string (pformat, prefix_len, human_time (t));
1081 break;
1082 case 'W':
1083 out_epoch_sec (pformat, prefix_len, statbuf,
1084 neg_to_zero (get_birthtime (fd, filename, statbuf)));
1085 break;
1086 case 'x':
1087 out_string (pformat, prefix_len, human_time (get_stat_atime (statbuf)));
1088 break;
1089 case 'X':
1090 out_epoch_sec (pformat, prefix_len, statbuf, get_stat_atime (statbuf));
1091 break;
1092 case 'y':
1093 out_string (pformat, prefix_len, human_time (get_stat_mtime (statbuf)));
1094 break;
1095 case 'Y':
1096 out_epoch_sec (pformat, prefix_len, statbuf, get_stat_mtime (statbuf));
1097 break;
1098 case 'z':
1099 out_string (pformat, prefix_len, human_time (get_stat_ctime (statbuf)));
1100 break;
1101 case 'Z':
1102 out_epoch_sec (pformat, prefix_len, statbuf, get_stat_ctime (statbuf));
1103 break;
1104 case 'C':
1105 fail |= out_file_context (pformat, prefix_len, filename);
1106 break;
1107 default:
1108 fputc ('?', stdout);
1109 break;
1111 return fail;
1114 /* Output a single-character \ escape. */
1116 static void
1117 print_esc_char (char c)
1119 switch (c)
1121 case 'a': /* Alert. */
1122 c ='\a';
1123 break;
1124 case 'b': /* Backspace. */
1125 c ='\b';
1126 break;
1127 case 'e': /* Escape. */
1128 c ='\x1B';
1129 break;
1130 case 'f': /* Form feed. */
1131 c ='\f';
1132 break;
1133 case 'n': /* New line. */
1134 c ='\n';
1135 break;
1136 case 'r': /* Carriage return. */
1137 c ='\r';
1138 break;
1139 case 't': /* Horizontal tab. */
1140 c ='\t';
1141 break;
1142 case 'v': /* Vertical tab. */
1143 c ='\v';
1144 break;
1145 case '"':
1146 case '\\':
1147 break;
1148 default:
1149 error (0, 0, _("warning: unrecognized escape '\\%c'"), c);
1150 break;
1152 putchar (c);
1155 /* Print the information specified by the format string, FORMAT,
1156 calling PRINT_FUNC for each %-directive encountered.
1157 Return zero upon success, nonzero upon failure. */
1158 static bool ATTRIBUTE_WARN_UNUSED_RESULT
1159 print_it (char const *format, int fd, char const *filename,
1160 bool (*print_func) (char *, size_t, unsigned int,
1161 int, char const *, void const *),
1162 void const *data)
1164 bool fail = false;
1166 /* Add 2 to accommodate our conversion of the stat '%s' format string
1167 to the longer printf '%llu' one. */
1168 enum
1170 MAX_ADDITIONAL_BYTES =
1171 (MAX (sizeof PRIdMAX,
1172 MAX (sizeof PRIoMAX, MAX (sizeof PRIuMAX, sizeof PRIxMAX)))
1173 - 1)
1175 size_t n_alloc = strlen (format) + MAX_ADDITIONAL_BYTES + 1;
1176 char *dest = xmalloc (n_alloc);
1177 char const *b;
1178 for (b = format; *b; b++)
1180 switch (*b)
1182 case '%':
1184 size_t len = strspn (b + 1, printf_flags);
1185 char const *fmt_char = b + len + 1;
1186 fmt_char += strspn (fmt_char, digits);
1187 if (*fmt_char == '.')
1188 fmt_char += 1 + strspn (fmt_char + 1, digits);
1189 len = fmt_char - (b + 1);
1190 unsigned int fmt_code = *fmt_char;
1191 memcpy (dest, b, len + 1);
1193 b = fmt_char;
1194 switch (fmt_code)
1196 case '\0':
1197 --b;
1198 /* fall through */
1199 case '%':
1200 if (0 < len)
1202 dest[len + 1] = *fmt_char;
1203 dest[len + 2] = '\0';
1204 error (EXIT_FAILURE, 0, _("%s: invalid directive"),
1205 quote (dest));
1207 putchar ('%');
1208 break;
1209 default:
1210 fail |= print_func (dest, len + 1, fmt_code,
1211 fd, filename, data);
1212 break;
1214 break;
1217 case '\\':
1218 if ( ! interpret_backslash_escapes)
1220 putchar ('\\');
1221 break;
1223 ++b;
1224 if (isodigit (*b))
1226 int esc_value = octtobin (*b);
1227 int esc_length = 1; /* number of octal digits */
1228 for (++b; esc_length < 3 && isodigit (*b);
1229 ++esc_length, ++b)
1231 esc_value = esc_value * 8 + octtobin (*b);
1233 putchar (esc_value);
1234 --b;
1236 else if (*b == 'x' && isxdigit (to_uchar (b[1])))
1238 int esc_value = hextobin (b[1]); /* Value of \xhh escape. */
1239 /* A hexadecimal \xhh escape sequence must have
1240 1 or 2 hex. digits. */
1241 ++b;
1242 if (isxdigit (to_uchar (b[1])))
1244 ++b;
1245 esc_value = esc_value * 16 + hextobin (*b);
1247 putchar (esc_value);
1249 else if (*b == '\0')
1251 error (0, 0, _("warning: backslash at end of format"));
1252 putchar ('\\');
1253 /* Arrange to exit the loop. */
1254 --b;
1256 else
1258 print_esc_char (*b);
1260 break;
1262 default:
1263 putchar (*b);
1264 break;
1267 free (dest);
1269 fputs (trailing_delim, stdout);
1271 return fail;
1274 /* Stat the file system and print what we find. */
1275 static bool ATTRIBUTE_WARN_UNUSED_RESULT
1276 do_statfs (char const *filename, char const *format)
1278 STRUCT_STATVFS statfsbuf;
1280 if (STREQ (filename, "-"))
1282 error (0, 0, _("using %s to denote standard input does not work"
1283 " in file system mode"), quoteaf (filename));
1284 return false;
1287 if (STATFS (filename, &statfsbuf) != 0)
1289 error (0, errno, _("cannot read file system information for %s"),
1290 quoteaf (filename));
1291 return false;
1294 bool fail = print_it (format, -1, filename, print_statfs, &statfsbuf);
1295 return ! fail;
1298 /* stat the file and print what we find */
1299 static bool ATTRIBUTE_WARN_UNUSED_RESULT
1300 do_stat (char const *filename, char const *format,
1301 char const *format2)
1303 int fd = STREQ (filename, "-") ? 0 : -1;
1304 struct stat statbuf;
1306 if (0 <= fd)
1308 if (fstat (fd, &statbuf) != 0)
1310 error (0, errno, _("cannot stat standard input"));
1311 return false;
1314 /* We can't use the shorter
1315 (follow_links?stat:lstat) (filename, &statbug)
1316 since stat might be a function-like macro. */
1317 else if ((follow_links
1318 ? stat (filename, &statbuf)
1319 : lstat (filename, &statbuf)) != 0)
1321 error (0, errno, _("cannot stat %s"), quoteaf (filename));
1322 return false;
1325 if (S_ISBLK (statbuf.st_mode) || S_ISCHR (statbuf.st_mode))
1326 format = format2;
1328 bool fail = print_it (format, fd, filename, print_stat, &statbuf);
1329 return ! fail;
1332 /* Return an allocated format string in static storage that
1333 corresponds to whether FS and TERSE options were declared. */
1334 static char *
1335 default_format (bool fs, bool terse, bool device)
1337 char *format;
1338 if (fs)
1340 if (terse)
1341 format = xstrdup ("%n %i %l %t %s %S %b %f %a %c %d\n");
1342 else
1344 /* TRANSLATORS: This string uses format specifiers from
1345 'stat --help' with --file-system, and NOT from printf. */
1346 format = xstrdup (_(" File: \"%n\"\n"
1347 " ID: %-8i Namelen: %-7l Type: %T\n"
1348 "Block size: %-10s Fundamental block size: %S\n"
1349 "Blocks: Total: %-10b Free: %-10f Available: %a\n"
1350 "Inodes: Total: %-10c Free: %d\n"));
1353 else /* ! fs */
1355 if (terse)
1357 if (0 < is_selinux_enabled ())
1358 format = xstrdup ("%n %s %b %f %u %g %D %i %h %t %T"
1359 " %X %Y %Z %W %o %C\n");
1360 else
1361 format = xstrdup ("%n %s %b %f %u %g %D %i %h %t %T"
1362 " %X %Y %Z %W %o\n");
1364 else
1366 char *temp;
1367 /* TRANSLATORS: This string uses format specifiers from
1368 'stat --help' without --file-system, and NOT from printf. */
1369 format = xstrdup (_("\
1370 File: %N\n\
1371 Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n\
1372 "));
1374 temp = format;
1375 if (device)
1377 /* TRANSLATORS: This string uses format specifiers from
1378 'stat --help' without --file-system, and NOT from printf. */
1379 format = xasprintf ("%s%s", format, _("\
1380 " "Device: %Dh/%dd\tInode: %-10i Links: %-5h Device type: %t,%T\n\
1381 "));
1383 else
1385 /* TRANSLATORS: This string uses format specifiers from
1386 'stat --help' without --file-system, and NOT from printf. */
1387 format = xasprintf ("%s%s", format, _("\
1388 " "Device: %Dh/%dd\tInode: %-10i Links: %h\n\
1389 "));
1391 free (temp);
1393 temp = format;
1394 /* TRANSLATORS: This string uses format specifiers from
1395 'stat --help' without --file-system, and NOT from printf. */
1396 format = xasprintf ("%s%s", format, _("\
1397 " "Access: (%04a/%10.10A) Uid: (%5u/%8U) Gid: (%5g/%8G)\n\
1398 "));
1399 free (temp);
1401 if (0 < is_selinux_enabled ())
1403 temp = format;
1404 /* TRANSLATORS: This string uses format specifiers from
1405 'stat --help' without --file-system, and NOT from printf. */
1406 format = xasprintf ("%s%s", format, _("Context: %C\n"));
1407 free (temp);
1410 temp = format;
1411 /* TRANSLATORS: This string uses format specifiers from
1412 'stat --help' without --file-system, and NOT from printf. */
1413 format = xasprintf ("%s%s", format,
1414 _("Access: %x\n"
1415 "Modify: %y\n"
1416 "Change: %z\n"
1417 " Birth: %w\n"));
1418 free (temp);
1421 return format;
1424 void
1425 usage (int status)
1427 if (status != EXIT_SUCCESS)
1428 emit_try_help ();
1429 else
1431 printf (_("Usage: %s [OPTION]... FILE...\n"), program_name);
1432 fputs (_("\
1433 Display file or file system status.\n\
1434 "), stdout);
1436 emit_mandatory_arg_note ();
1438 fputs (_("\
1439 -L, --dereference follow links\n\
1440 -f, --file-system display file system status instead of file status\n\
1441 "), stdout);
1442 fputs (_("\
1443 -c --format=FORMAT use the specified FORMAT instead of the default;\n\
1444 output a newline after each use of FORMAT\n\
1445 --printf=FORMAT like --format, but interpret backslash escapes,\n\
1446 and do not output a mandatory trailing newline;\n\
1447 if you want a newline, include \\n in FORMAT\n\
1448 -t, --terse print the information in terse form\n\
1449 "), stdout);
1450 fputs (HELP_OPTION_DESCRIPTION, stdout);
1451 fputs (VERSION_OPTION_DESCRIPTION, stdout);
1453 fputs (_("\n\
1454 The valid format sequences for files (without --file-system):\n\
1456 %a access rights in octal (note '#' and '0' printf flags)\n\
1457 %A access rights in human readable form\n\
1458 %b number of blocks allocated (see %B)\n\
1459 %B the size in bytes of each block reported by %b\n\
1460 %C SELinux security context string\n\
1461 "), stdout);
1462 fputs (_("\
1463 %d device number in decimal\n\
1464 %D device number in hex\n\
1465 %f raw mode in hex\n\
1466 %F file type\n\
1467 %g group ID of owner\n\
1468 %G group name of owner\n\
1469 "), stdout);
1470 fputs (_("\
1471 %h number of hard links\n\
1472 %i inode number\n\
1473 %m mount point\n\
1474 %n file name\n\
1475 %N quoted file name with dereference if symbolic link\n\
1476 %o optimal I/O transfer size hint\n\
1477 %s total size, in bytes\n\
1478 %t major device type in hex, for character/block device special files\n\
1479 %T minor device type in hex, for character/block device special files\n\
1480 "), stdout);
1481 fputs (_("\
1482 %u user ID of owner\n\
1483 %U user name of owner\n\
1484 %w time of file birth, human-readable; - if unknown\n\
1485 %W time of file birth, seconds since Epoch; 0 if unknown\n\
1486 %x time of last access, human-readable\n\
1487 %X time of last access, seconds since Epoch\n\
1488 %y time of last data modification, human-readable\n\
1489 %Y time of last data modification, seconds since Epoch\n\
1490 %z time of last status change, human-readable\n\
1491 %Z time of last status change, seconds since Epoch\n\
1493 "), stdout);
1495 fputs (_("\
1496 Valid format sequences for file systems:\n\
1498 %a free blocks available to non-superuser\n\
1499 %b total data blocks in file system\n\
1500 %c total file nodes in file system\n\
1501 %d free file nodes in file system\n\
1502 %f free blocks in file system\n\
1503 "), stdout);
1504 fputs (_("\
1505 %i file system ID in hex\n\
1506 %l maximum length of filenames\n\
1507 %n file name\n\
1508 %s block size (for faster transfers)\n\
1509 %S fundamental block size (for block counts)\n\
1510 %t file system type in hex\n\
1511 %T file system type in human readable form\n\
1512 "), stdout);
1513 printf (USAGE_BUILTIN_WARNING, PROGRAM_NAME);
1514 emit_ancillary_info (PROGRAM_NAME);
1516 exit (status);
1520 main (int argc, char *argv[])
1522 int c;
1523 int i;
1524 bool fs = false;
1525 bool terse = false;
1526 char *format = NULL;
1527 char *format2;
1528 bool ok = true;
1530 initialize_main (&argc, &argv);
1531 set_program_name (argv[0]);
1532 setlocale (LC_ALL, "");
1533 bindtextdomain (PACKAGE, LOCALEDIR);
1534 textdomain (PACKAGE);
1536 struct lconv const *locale = localeconv ();
1537 decimal_point = (locale->decimal_point[0] ? locale->decimal_point : ".");
1538 decimal_point_len = strlen (decimal_point);
1540 atexit (close_stdout);
1542 while ((c = getopt_long (argc, argv, "c:fLt", long_options, NULL)) != -1)
1544 switch (c)
1546 case PRINTF_OPTION:
1547 format = optarg;
1548 interpret_backslash_escapes = true;
1549 trailing_delim = "";
1550 break;
1552 case 'c':
1553 format = optarg;
1554 interpret_backslash_escapes = false;
1555 trailing_delim = "\n";
1556 break;
1558 case 'L':
1559 follow_links = true;
1560 break;
1562 case 'f':
1563 fs = true;
1564 break;
1566 case 't':
1567 terse = true;
1568 break;
1570 case_GETOPT_HELP_CHAR;
1572 case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
1574 default:
1575 usage (EXIT_FAILURE);
1579 if (argc == optind)
1581 error (0, 0, _("missing operand"));
1582 usage (EXIT_FAILURE);
1585 if (format)
1586 format2 = format;
1587 else
1589 format = default_format (fs, terse, false);
1590 format2 = default_format (fs, terse, true);
1593 for (i = optind; i < argc; i++)
1594 ok &= (fs
1595 ? do_statfs (argv[i], format)
1596 : do_stat (argv[i], format, format2));
1598 return ok ? EXIT_SUCCESS : EXIT_FAILURE;