tail: with -f, use polling when a file is on an FS of unknown type
[coreutils.git] / src / stat.c
blob0a454cd084e210b352f18f1724aeeb6bf781af79
1 /* stat.c -- display file or file system status
2 Copyright (C) 2001-2011 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 "quotearg.h"
70 #include "stat-size.h"
71 #include "stat-time.h"
72 #include "strftime.h"
73 #include "find-mount-point.h"
74 #include "xvasprintf.h"
76 #if USE_STATVFS
77 # define STRUCT_STATVFS struct statvfs
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)
82 # endif
83 # if ! STAT_STATVFS && STAT_STATVFS64
84 # define STATFS statvfs64
85 # else
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 # define STATFS_FRSIZE(S) 0
130 # endif
131 #endif
133 #ifdef SB_F_NAMEMAX
134 # define OUT_NAMEMAX out_uint
135 #else
136 /* NetBSD 1.5.2 has neither f_namemax nor f_namelen. */
137 # define SB_F_NAMEMAX(S) "*"
138 # define OUT_NAMEMAX out_string
139 #endif
141 #if HAVE_STRUCT_STATVFS_F_BASETYPE
142 # define STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME f_basetype
143 #else
144 # if HAVE_STRUCT_STATVFS_F_FSTYPENAME || HAVE_STRUCT_STATFS_F_FSTYPENAME
145 # define STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME f_fstypename
146 # elif HAVE_OS_H /* BeOS */
147 # define STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME fsh_name
148 # endif
149 #endif
151 /* FIXME: these are used by printf.c, too */
152 #define isodigit(c) ('0' <= (c) && (c) <= '7')
153 #define octtobin(c) ((c) - '0')
154 #define hextobin(c) ((c) >= 'a' && (c) <= 'f' ? (c) - 'a' + 10 : \
155 (c) >= 'A' && (c) <= 'F' ? (c) - 'A' + 10 : (c) - '0')
157 static char const digits[] = "0123456789";
159 /* Flags that are portable for use in printf, for at least one
160 conversion specifier; make_format removes unportable flags as
161 needed for particular specifiers. The glibc 2.2 extension "I" is
162 listed here; it is removed by make_format because it has undefined
163 behavior elsewhere and because it is incompatible with
164 out_epoch_sec. */
165 static char const printf_flags[] = "'-+ #0I";
167 #define PROGRAM_NAME "stat"
169 #define AUTHORS proper_name ("Michael Meskes")
171 enum
173 PRINTF_OPTION = CHAR_MAX + 1
176 static struct option const long_options[] =
178 {"context", no_argument, 0, 'Z'},
179 {"dereference", no_argument, NULL, 'L'},
180 {"file-system", no_argument, NULL, 'f'},
181 {"format", required_argument, NULL, 'c'},
182 {"printf", required_argument, NULL, PRINTF_OPTION},
183 {"terse", no_argument, NULL, 't'},
184 {GETOPT_HELP_OPTION_DECL},
185 {GETOPT_VERSION_OPTION_DECL},
186 {NULL, 0, NULL, 0}
189 /* Whether to follow symbolic links; True for --dereference (-L). */
190 static bool follow_links;
192 /* Whether to interpret backslash-escape sequences.
193 True for --printf=FMT, not for --format=FMT (-c). */
194 static bool interpret_backslash_escapes;
196 /* The trailing delimiter string:
197 "" for --printf=FMT, "\n" for --format=FMT (-c). */
198 static char const *trailing_delim = "";
200 /* The representation of the decimal point in the current locale. */
201 static char const *decimal_point;
202 static size_t decimal_point_len;
204 /* Return the type of the specified file system.
205 Some systems have statfvs.f_basetype[FSTYPSZ] (AIX, HP-UX, and Solaris).
206 Others have statvfs.f_fstypename[_VFS_NAMELEN] (NetBSD 3.0).
207 Others have statfs.f_fstypename[MFSNAMELEN] (NetBSD 1.5.2).
208 Still others have neither and have to get by with f_type (GNU/Linux).
209 But f_type may only exist in statfs (Cygwin). */
210 static char const * ATTRIBUTE_WARN_UNUSED_RESULT
211 human_fstype (STRUCT_STATVFS const *statfsbuf)
213 #ifdef STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME
214 return statfsbuf->STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME;
215 #else
216 switch (statfsbuf->f_type)
218 # if defined __linux__
220 /* Compare with what's in libc:
221 f=/a/libc/sysdeps/unix/sysv/linux/linux_fsinfo.h
222 sed -n '/ADFS_SUPER_MAGIC/,/SYSFS_MAGIC/p' $f \
223 | perl -n -e '/#define (.*?)_(?:SUPER_)MAGIC\s+0x(\S+)/' \
224 -e 'and print "case S_MAGIC_$1: /\* 0x" . uc($2) . " *\/\n"' \
225 | sort > sym_libc
226 perl -ne '/^\s+(case S_MAGIC_.*?): \/\* 0x(\S+) \*\//' \
227 -e 'and do { $v=uc$2; print "$1: /\* 0x$v *\/\n"}' stat.c \
228 | sort > sym_stat
229 diff -u sym_stat sym_libc
232 /* Also compare with the list in "man 2 statfs" using the
233 fs-magic-compare make target. */
235 /* IMPORTANT NOTE: Each of the following `case S_MAGIC_...:'
236 statements must be followed by a hexadecimal constant in
237 a comment. The S_MAGIC_... name and constant are automatically
238 combined to produce the #define directives in fs.h. */
240 case S_MAGIC_ADFS: /* 0xADF5 local */
241 return "adfs";
242 case S_MAGIC_AFFS: /* 0xADFF local */
243 return "affs";
244 case S_MAGIC_AFS: /* 0x5346414F remote */
245 return "afs";
246 case S_MAGIC_ANON_INODE_FS: /* 0x09041934 local */
247 return "anon-inode FS";
248 case S_MAGIC_AUTOFS: /* 0x0187 local */
249 return "autofs";
250 case S_MAGIC_BEFS: /* 0x42465331 local */
251 return "befs";
252 case S_MAGIC_BFS: /* 0x1BADFACE local */
253 return "bfs";
254 case S_MAGIC_BINFMT_MISC: /* 0x42494E4D local */
255 return "binfmt_misc";
256 case S_MAGIC_BTRFS: /* 0x9123683E local */
257 return "btrfs";
258 case S_MAGIC_CGROUP: /* 0x0027E0EB local */
259 return "cgroupfs";
260 case S_MAGIC_CIFS: /* 0xFF534D42 remote */
261 return "cifs";
262 case S_MAGIC_CODA: /* 0x73757245 remote */
263 return "coda";
264 case S_MAGIC_COH: /* 0x012FF7B7 local */
265 return "coh";
266 case S_MAGIC_CRAMFS: /* 0x28CD3D45 local */
267 return "cramfs";
268 case S_MAGIC_CRAMFS_WEND: /* 0x453DCD28 local */
269 return "cramfs-wend";
270 case S_MAGIC_DEBUGFS: /* 0x64626720 local */
271 return "debugfs";
272 case S_MAGIC_DEVFS: /* 0x1373 local */
273 return "devfs";
274 case S_MAGIC_DEVPTS: /* 0x1CD1 local */
275 return "devpts";
276 case S_MAGIC_ECRYPTFS: /* 0xF15F local */
277 return "ecryptfs";
278 case S_MAGIC_EFS: /* 0x00414A53 local */
279 return "efs";
280 case S_MAGIC_EXT: /* 0x137D local */
281 return "ext";
282 case S_MAGIC_EXT2: /* 0xEF53 local */
283 return "ext2/ext3";
284 case S_MAGIC_EXT2_OLD: /* 0xEF51 local */
285 return "ext2";
286 case S_MAGIC_FAT: /* 0x4006 local */
287 return "fat";
288 case S_MAGIC_FHGFS: /* 0x19830326 remote */
289 return "fhgfs";
290 case S_MAGIC_FUSEBLK: /* 0x65735546 remote */
291 return "fuseblk";
292 case S_MAGIC_FUSECTL: /* 0x65735543 remote */
293 return "fusectl";
294 case S_MAGIC_FUTEXFS: /* 0x0BAD1DEA local */
295 return "futexfs";
296 case S_MAGIC_GFS: /* 0x1161970 remote */
297 return "gfs/gfs2";
298 case S_MAGIC_GPFS: /* 0x47504653 remote */
299 return "gpfs";
300 case S_MAGIC_HFS: /* 0x4244 local */
301 return "hfs";
302 case S_MAGIC_HPFS: /* 0xF995E849 local */
303 return "hpfs";
304 case S_MAGIC_HUGETLBFS: /* 0x958458F6 local */
305 return "hugetlbfs";
306 case S_MAGIC_INOTIFYFS: /* 0x2BAD1DEA local */
307 return "inotifyfs";
308 case S_MAGIC_ISOFS: /* 0x9660 local */
309 return "isofs";
310 case S_MAGIC_ISOFS_R_WIN: /* 0x4004 local */
311 return "isofs";
312 case S_MAGIC_ISOFS_WIN: /* 0x4000 local */
313 return "isofs";
314 case S_MAGIC_JFFS: /* 0x07C0 local */
315 return "jffs";
316 case S_MAGIC_JFFS2: /* 0x72B6 local */
317 return "jffs2";
318 case S_MAGIC_JFS: /* 0x3153464A local */
319 return "jfs";
320 case S_MAGIC_KAFS: /* 0x6B414653 remote */
321 return "k-afs";
322 case S_MAGIC_LUSTRE: /* 0x0BD00BD0 remote */
323 return "lustre";
324 case S_MAGIC_MINIX: /* 0x137F local */
325 return "minix";
326 case S_MAGIC_MINIX_30: /* 0x138F local */
327 return "minix (30 char.)";
328 case S_MAGIC_MINIX_V2: /* 0x2468 local */
329 return "minix v2";
330 case S_MAGIC_MINIX_V2_30: /* 0x2478 local */
331 return "minix v2 (30 char.)";
332 case S_MAGIC_MINIX_V3: /* 0x4D5A local */
333 return "minix3";
334 case S_MAGIC_MQUEUE: /* 0x19800202 local */
335 return "mqueue";
336 case S_MAGIC_MSDOS: /* 0x4D44 local */
337 return "msdos";
338 case S_MAGIC_NCP: /* 0x564C remote */
339 return "novell";
340 case S_MAGIC_NFS: /* 0x6969 remote */
341 return "nfs";
342 case S_MAGIC_NFSD: /* 0x6E667364 remote */
343 return "nfsd";
344 case S_MAGIC_NILFS: /* 0x3434 local */
345 return "nilfs";
346 case S_MAGIC_NTFS: /* 0x5346544E local */
347 return "ntfs";
348 case S_MAGIC_OPENPROM: /* 0x9FA1 local */
349 return "openprom";
350 case S_MAGIC_OCFS2: /* 0x7461636f remote */
351 return "ocfs2";
352 case S_MAGIC_PROC: /* 0x9FA0 local */
353 return "proc";
354 case S_MAGIC_PSTOREFS: /* 0x6165676C local */
355 return "pstorefs";
356 case S_MAGIC_QNX4: /* 0x002F local */
357 return "qnx4";
358 case S_MAGIC_RAMFS: /* 0x858458F6 local */
359 return "ramfs";
360 case S_MAGIC_REISERFS: /* 0x52654973 local */
361 return "reiserfs";
362 case S_MAGIC_ROMFS: /* 0x7275 local */
363 return "romfs";
364 case S_MAGIC_RPC_PIPEFS: /* 0x67596969 local */
365 return "rpc_pipefs";
366 case S_MAGIC_SECURITYFS: /* 0x73636673 local */
367 return "securityfs";
368 case S_MAGIC_SELINUX: /* 0xF97CFF8C local */
369 return "selinux";
370 case S_MAGIC_SMB: /* 0x517B remote */
371 return "smb";
372 case S_MAGIC_SOCKFS: /* 0x534F434B local */
373 return "sockfs";
374 case S_MAGIC_SQUASHFS: /* 0x73717368 local */
375 return "squashfs";
376 case S_MAGIC_SYSFS: /* 0x62656572 local */
377 return "sysfs";
378 case S_MAGIC_SYSV2: /* 0x012FF7B6 local */
379 return "sysv2";
380 case S_MAGIC_SYSV4: /* 0x012FF7B5 local */
381 return "sysv4";
382 case S_MAGIC_TMPFS: /* 0x01021994 local */
383 return "tmpfs";
384 case S_MAGIC_UDF: /* 0x15013346 local */
385 return "udf";
386 case S_MAGIC_UFS: /* 0x00011954 local */
387 return "ufs";
388 case S_MAGIC_UFS_BYTESWAPPED: /* 0x54190100 local */
389 return "ufs";
390 case S_MAGIC_USBDEVFS: /* 0x9FA2 local */
391 return "usbdevfs";
392 case S_MAGIC_V9FS: /* 0x01021997 local */
393 return "v9fs";
394 case S_MAGIC_VXFS: /* 0xA501FCF5 local */
395 return "vxfs";
396 case S_MAGIC_XENFS: /* 0xABBA1974 local */
397 return "xenfs";
398 case S_MAGIC_XENIX: /* 0x012FF7B4 local */
399 return "xenix";
400 case S_MAGIC_XFS: /* 0x58465342 local */
401 return "xfs";
402 case S_MAGIC_XIAFS: /* 0x012FD16D local */
403 return "xia";
405 # elif __GNU__
406 case FSTYPE_UFS:
407 return "ufs";
408 case FSTYPE_NFS:
409 return "nfs";
410 case FSTYPE_GFS:
411 return "gfs";
412 case FSTYPE_LFS:
413 return "lfs";
414 case FSTYPE_SYSV:
415 return "sysv";
416 case FSTYPE_FTP:
417 return "ftp";
418 case FSTYPE_TAR:
419 return "tar";
420 case FSTYPE_AR:
421 return "ar";
422 case FSTYPE_CPIO:
423 return "cpio";
424 case FSTYPE_MSLOSS:
425 return "msloss";
426 case FSTYPE_CPM:
427 return "cpm";
428 case FSTYPE_HFS:
429 return "hfs";
430 case FSTYPE_DTFS:
431 return "dtfs";
432 case FSTYPE_GRFS:
433 return "grfs";
434 case FSTYPE_TERM:
435 return "term";
436 case FSTYPE_DEV:
437 return "dev";
438 case FSTYPE_PROC:
439 return "proc";
440 case FSTYPE_IFSOCK:
441 return "ifsock";
442 case FSTYPE_AFS:
443 return "afs";
444 case FSTYPE_DFS:
445 return "dfs";
446 case FSTYPE_PROC9:
447 return "proc9";
448 case FSTYPE_SOCKET:
449 return "socket";
450 case FSTYPE_MISC:
451 return "misc";
452 case FSTYPE_EXT2FS:
453 return "ext2/ext3";
454 case FSTYPE_HTTP:
455 return "http";
456 case FSTYPE_MEMFS:
457 return "memfs";
458 case FSTYPE_ISO9660:
459 return "iso9660";
460 # endif
461 default:
463 unsigned long int type = statfsbuf->f_type;
464 static char buf[sizeof "UNKNOWN (0x%lx)" - 3
465 + (sizeof type * CHAR_BIT + 3) / 4];
466 sprintf (buf, "UNKNOWN (0x%lx)", type);
467 return buf;
470 #endif
473 static char * ATTRIBUTE_WARN_UNUSED_RESULT
474 human_access (struct stat const *statbuf)
476 static char modebuf[12];
477 filemodestring (statbuf, modebuf);
478 modebuf[10] = 0;
479 return modebuf;
482 static char * ATTRIBUTE_WARN_UNUSED_RESULT
483 human_time (struct timespec t)
485 static char str[MAX (INT_BUFSIZE_BOUND (intmax_t),
486 (INT_STRLEN_BOUND (int) /* YYYY */
487 + 1 /* because YYYY might equal INT_MAX + 1900 */
488 + sizeof "-MM-DD HH:MM:SS.NNNNNNNNN +ZZZZ"))];
489 struct tm const *tm = localtime (&t.tv_sec);
490 if (tm == NULL)
491 return timetostr (t.tv_sec, str);
492 nstrftime (str, sizeof str, "%Y-%m-%d %H:%M:%S.%N %z", tm, 0, t.tv_nsec);
493 return str;
496 /* PFORMAT points to a '%' followed by a prefix of a format, all of
497 size PREFIX_LEN. The flags allowed for this format are
498 ALLOWED_FLAGS; remove other printf flags from the prefix, then
499 append SUFFIX. */
500 static void
501 make_format (char *pformat, size_t prefix_len, char const *allowed_flags,
502 char const *suffix)
504 char *dst = pformat + 1;
505 char const *src;
506 char const *srclim = pformat + prefix_len;
507 for (src = dst; src < srclim && strchr (printf_flags, *src); src++)
508 if (strchr (allowed_flags, *src))
509 *dst++ = *src;
510 while (src < srclim)
511 *dst++ = *src++;
512 strcpy (dst, suffix);
515 static void
516 out_string (char *pformat, size_t prefix_len, char const *arg)
518 make_format (pformat, prefix_len, "-", "s");
519 printf (pformat, arg);
521 static int
522 out_int (char *pformat, size_t prefix_len, intmax_t arg)
524 make_format (pformat, prefix_len, "'-+ 0", PRIdMAX);
525 return printf (pformat, arg);
527 static int
528 out_uint (char *pformat, size_t prefix_len, uintmax_t arg)
530 make_format (pformat, prefix_len, "'-0", PRIuMAX);
531 return printf (pformat, arg);
533 static void
534 out_uint_o (char *pformat, size_t prefix_len, uintmax_t arg)
536 make_format (pformat, prefix_len, "-#0", PRIoMAX);
537 printf (pformat, arg);
539 static void
540 out_uint_x (char *pformat, size_t prefix_len, uintmax_t arg)
542 make_format (pformat, prefix_len, "-#0", PRIxMAX);
543 printf (pformat, arg);
545 static int
546 out_minus_zero (char *pformat, size_t prefix_len)
548 make_format (pformat, prefix_len, "'-+ 0", ".0f");
549 return printf (pformat, -0.25);
552 /* Output the number of seconds since the Epoch, using a format that
553 acts like printf's %f format. */
554 static void
555 out_epoch_sec (char *pformat, size_t prefix_len,
556 struct stat const *statbuf ATTRIBUTE_UNUSED,
557 struct timespec arg)
559 char *dot = memchr (pformat, '.', prefix_len);
560 size_t sec_prefix_len = prefix_len;
561 int width = 0;
562 int precision = 0;
563 bool frac_left_adjust = false;
565 if (dot)
567 sec_prefix_len = dot - pformat;
568 pformat[prefix_len] = '\0';
570 if (ISDIGIT (dot[1]))
572 long int lprec = strtol (dot + 1, NULL, 10);
573 precision = (lprec <= INT_MAX ? lprec : INT_MAX);
575 else
577 precision = 9;
580 if (precision && ISDIGIT (dot[-1]))
582 /* If a nontrivial width is given, subtract the width of the
583 decimal point and PRECISION digits that will be output
584 later. */
585 char *p = dot;
586 *dot = '\0';
589 --p;
590 while (ISDIGIT (p[-1]));
592 long int lwidth = strtol (p, NULL, 10);
593 width = (lwidth <= INT_MAX ? lwidth : INT_MAX);
594 if (1 < width)
596 p += (*p == '0');
597 sec_prefix_len = p - pformat;
598 int w_d = (decimal_point_len < width
599 ? width - decimal_point_len
600 : 0);
601 if (1 < w_d)
603 int w = w_d - precision;
604 if (1 < w)
606 char *dst = pformat;
607 for (char const *src = dst; src < p; src++)
609 if (*src == '-')
610 frac_left_adjust = true;
611 else
612 *dst++ = *src;
614 sec_prefix_len =
615 (dst - pformat
616 + (frac_left_adjust ? 0 : sprintf (dst, "%d", w)));
623 int divisor = 1;
624 for (int i = precision; i < 9; i++)
625 divisor *= 10;
626 int frac_sec = arg.tv_nsec / divisor;
627 int int_len;
629 if (TYPE_SIGNED (time_t))
631 bool minus_zero = false;
632 if (arg.tv_sec < 0 && arg.tv_nsec != 0)
634 int frac_sec_modulus = 1000000000 / divisor;
635 frac_sec = (frac_sec_modulus - frac_sec
636 - (arg.tv_nsec % divisor != 0));
637 arg.tv_sec += (frac_sec != 0);
638 minus_zero = (arg.tv_sec == 0);
640 int_len = (minus_zero
641 ? out_minus_zero (pformat, sec_prefix_len)
642 : out_int (pformat, sec_prefix_len, arg.tv_sec));
644 else
645 int_len = out_uint (pformat, sec_prefix_len, arg.tv_sec);
647 if (precision)
649 int prec = (precision < 9 ? precision : 9);
650 int trailing_prec = precision - prec;
651 int ilen = (int_len < 0 ? 0 : int_len);
652 int trailing_width = (ilen < width && decimal_point_len < width - ilen
653 ? width - ilen - decimal_point_len - prec
654 : 0);
655 printf ("%s%.*d%-*.*d", decimal_point, prec, frac_sec,
656 trailing_width, trailing_prec, 0);
660 /* Print the context information of FILENAME, and return true iff the
661 context could not be obtained. */
662 static bool ATTRIBUTE_WARN_UNUSED_RESULT
663 out_file_context (char *pformat, size_t prefix_len, char const *filename)
665 char *scontext;
666 bool fail = false;
668 if ((follow_links
669 ? getfilecon (filename, &scontext)
670 : lgetfilecon (filename, &scontext)) < 0)
672 error (0, errno, _("failed to get security context of %s"),
673 quote (filename));
674 scontext = NULL;
675 fail = true;
677 strcpy (pformat + prefix_len, "s");
678 printf (pformat, (scontext ? scontext : "?"));
679 if (scontext)
680 freecon (scontext);
681 return fail;
684 /* Print statfs info. Return zero upon success, nonzero upon failure. */
685 static bool ATTRIBUTE_WARN_UNUSED_RESULT
686 print_statfs (char *pformat, size_t prefix_len, unsigned int m,
687 char const *filename,
688 void const *data)
690 STRUCT_STATVFS const *statfsbuf = data;
691 bool fail = false;
693 switch (m)
695 case 'n':
696 out_string (pformat, prefix_len, filename);
697 break;
699 case 'i':
701 #if STRUCT_STATXFS_F_FSID_IS_INTEGER
702 uintmax_t fsid = statfsbuf->f_fsid;
703 #else
704 typedef unsigned int fsid_word;
705 verify (alignof (STRUCT_STATVFS) % alignof (fsid_word) == 0);
706 verify (offsetof (STRUCT_STATVFS, f_fsid) % alignof (fsid_word) == 0);
707 verify (sizeof statfsbuf->f_fsid % alignof (fsid_word) == 0);
708 fsid_word const *p = (fsid_word *) &statfsbuf->f_fsid;
710 /* Assume a little-endian word order, as that is compatible
711 with glibc's statvfs implementation. */
712 uintmax_t fsid = 0;
713 int words = sizeof statfsbuf->f_fsid / sizeof *p;
714 int i;
715 for (i = 0; i < words && i * sizeof *p < sizeof fsid; i++)
717 uintmax_t u = p[words - 1 - i];
718 fsid |= u << (i * CHAR_BIT * sizeof *p);
720 #endif
721 out_uint_x (pformat, prefix_len, fsid);
723 break;
725 case 'l':
726 OUT_NAMEMAX (pformat, prefix_len, SB_F_NAMEMAX (statfsbuf));
727 break;
728 case 't':
729 #if HAVE_STRUCT_STATXFS_F_TYPE
730 out_uint_x (pformat, prefix_len, statfsbuf->f_type);
731 #else
732 fputc ('?', stdout);
733 #endif
734 break;
735 case 'T':
736 out_string (pformat, prefix_len, human_fstype (statfsbuf));
737 break;
738 case 'b':
739 out_int (pformat, prefix_len, statfsbuf->f_blocks);
740 break;
741 case 'f':
742 out_int (pformat, prefix_len, statfsbuf->f_bfree);
743 break;
744 case 'a':
745 out_int (pformat, prefix_len, statfsbuf->f_bavail);
746 break;
747 case 's':
748 out_uint (pformat, prefix_len, statfsbuf->f_bsize);
749 break;
750 case 'S':
752 uintmax_t frsize = STATFS_FRSIZE (statfsbuf);
753 if (! frsize)
754 frsize = statfsbuf->f_bsize;
755 out_uint (pformat, prefix_len, frsize);
757 break;
758 case 'c':
759 out_uint (pformat, prefix_len, statfsbuf->f_files);
760 break;
761 case 'd':
762 out_int (pformat, prefix_len, statfsbuf->f_ffree);
763 break;
764 default:
765 fputc ('?', stdout);
766 break;
768 return fail;
771 /* Return any bind mounted source for a path.
772 The caller should not free the returned buffer.
773 Return NULL if no bind mount found. */
774 static char const * ATTRIBUTE_WARN_UNUSED_RESULT
775 find_bind_mount (char const * name)
777 char const * bind_mount = NULL;
779 static struct mount_entry *mount_list;
780 static bool tried_mount_list = false;
781 if (!tried_mount_list) /* attempt/warn once per process. */
783 if (!(mount_list = read_file_system_list (false)))
784 error (0, errno, "%s", _("cannot read table of mounted file systems"));
785 tried_mount_list = true;
788 struct mount_entry *me;
789 for (me = mount_list; me; me = me->me_next)
791 if (me->me_dummy && me->me_devname[0] == '/'
792 && STREQ (me->me_mountdir, name))
794 struct stat name_stats;
795 struct stat dev_stats;
797 if (stat (name, &name_stats) == 0
798 && stat (me->me_devname, &dev_stats) == 0
799 && SAME_INODE (name_stats, dev_stats))
801 bind_mount = me->me_devname;
802 break;
807 return bind_mount;
810 /* Print mount point. Return zero upon success, nonzero upon failure. */
811 static bool ATTRIBUTE_WARN_UNUSED_RESULT
812 out_mount_point (char const *filename, char *pformat, size_t prefix_len,
813 const struct stat *statp)
816 char const *np = "?", *bp = NULL;
817 char *mp = NULL;
818 bool fail = true;
820 /* Look for bind mounts first. Note we output the immediate alias,
821 rather than further resolving to a base device mount point. */
822 if (follow_links || !S_ISLNK (statp->st_mode))
824 char *resolved = canonicalize_file_name (filename);
825 if (!resolved)
827 error (0, errno, _("failed to canonicalize %s"), quote (filename));
828 goto print_mount_point;
830 bp = find_bind_mount (resolved);
831 free (resolved);
832 if (bp)
834 fail = false;
835 goto print_mount_point;
839 /* If there is no direct bind mount, then navigate
840 back up the tree looking for a device change.
841 Note we don't detect if any of the directory components
842 are bind mounted to the same device, but that's OK
843 since we've not directly queried them. */
844 if ((mp = find_mount_point (filename, statp)))
846 /* This dir might be bind mounted to another device,
847 so we resolve the bound source in that case also. */
848 bp = find_bind_mount (mp);
849 fail = false;
852 print_mount_point:
854 out_string (pformat, prefix_len, bp ? bp : mp ? mp : np);
855 free (mp);
856 return fail;
859 /* Map a TS with negative TS.tv_nsec to {0,0}. */
860 static inline struct timespec
861 neg_to_zero (struct timespec ts)
863 if (0 <= ts.tv_nsec)
864 return ts;
865 struct timespec z = {0, 0};
866 return z;
869 /* Print stat info. Return zero upon success, nonzero upon failure. */
870 static bool
871 print_stat (char *pformat, size_t prefix_len, unsigned int m,
872 char const *filename, void const *data)
874 struct stat *statbuf = (struct stat *) data;
875 struct passwd *pw_ent;
876 struct group *gw_ent;
877 bool fail = false;
879 switch (m)
881 case 'n':
882 out_string (pformat, prefix_len, filename);
883 break;
884 case 'N':
885 out_string (pformat, prefix_len, quote (filename));
886 if (S_ISLNK (statbuf->st_mode))
888 char *linkname = areadlink_with_size (filename, statbuf->st_size);
889 if (linkname == NULL)
891 error (0, errno, _("cannot read symbolic link %s"),
892 quote (filename));
893 return true;
895 printf (" -> ");
896 out_string (pformat, prefix_len, quote (linkname));
897 free (linkname);
899 break;
900 case 'd':
901 out_uint (pformat, prefix_len, statbuf->st_dev);
902 break;
903 case 'D':
904 out_uint_x (pformat, prefix_len, statbuf->st_dev);
905 break;
906 case 'i':
907 out_uint (pformat, prefix_len, statbuf->st_ino);
908 break;
909 case 'a':
910 out_uint_o (pformat, prefix_len, statbuf->st_mode & CHMOD_MODE_BITS);
911 break;
912 case 'A':
913 out_string (pformat, prefix_len, human_access (statbuf));
914 break;
915 case 'f':
916 out_uint_x (pformat, prefix_len, statbuf->st_mode);
917 break;
918 case 'F':
919 out_string (pformat, prefix_len, file_type (statbuf));
920 break;
921 case 'h':
922 out_uint (pformat, prefix_len, statbuf->st_nlink);
923 break;
924 case 'u':
925 out_uint (pformat, prefix_len, statbuf->st_uid);
926 break;
927 case 'U':
928 setpwent ();
929 pw_ent = getpwuid (statbuf->st_uid);
930 out_string (pformat, prefix_len,
931 pw_ent ? pw_ent->pw_name : "UNKNOWN");
932 break;
933 case 'g':
934 out_uint (pformat, prefix_len, statbuf->st_gid);
935 break;
936 case 'G':
937 setgrent ();
938 gw_ent = getgrgid (statbuf->st_gid);
939 out_string (pformat, prefix_len,
940 gw_ent ? gw_ent->gr_name : "UNKNOWN");
941 break;
942 case 't':
943 out_uint_x (pformat, prefix_len, major (statbuf->st_rdev));
944 break;
945 case 'm':
946 fail |= out_mount_point (filename, pformat, prefix_len, statbuf);
947 break;
948 case 'T':
949 out_uint_x (pformat, prefix_len, minor (statbuf->st_rdev));
950 break;
951 case 's':
952 out_uint (pformat, prefix_len, statbuf->st_size);
953 break;
954 case 'B':
955 out_uint (pformat, prefix_len, ST_NBLOCKSIZE);
956 break;
957 case 'b':
958 out_uint (pformat, prefix_len, ST_NBLOCKS (*statbuf));
959 break;
960 case 'o':
961 out_uint (pformat, prefix_len, ST_BLKSIZE (*statbuf));
962 break;
963 case 'w':
965 struct timespec t = get_stat_birthtime (statbuf);
966 if (t.tv_nsec < 0)
967 out_string (pformat, prefix_len, "-");
968 else
969 out_string (pformat, prefix_len, human_time (t));
971 break;
972 case 'W':
973 out_epoch_sec (pformat, prefix_len, statbuf,
974 neg_to_zero (get_stat_birthtime (statbuf)));
975 break;
976 case 'x':
977 out_string (pformat, prefix_len, human_time (get_stat_atime (statbuf)));
978 break;
979 case 'X':
980 out_epoch_sec (pformat, prefix_len, statbuf, get_stat_atime (statbuf));
981 break;
982 case 'y':
983 out_string (pformat, prefix_len, human_time (get_stat_mtime (statbuf)));
984 break;
985 case 'Y':
986 out_epoch_sec (pformat, prefix_len, statbuf, get_stat_mtime (statbuf));
987 break;
988 case 'z':
989 out_string (pformat, prefix_len, human_time (get_stat_ctime (statbuf)));
990 break;
991 case 'Z':
992 out_epoch_sec (pformat, prefix_len, statbuf, get_stat_ctime (statbuf));
993 break;
994 case 'C':
995 fail |= out_file_context (pformat, prefix_len, filename);
996 break;
997 default:
998 fputc ('?', stdout);
999 break;
1001 return fail;
1004 /* Output a single-character \ escape. */
1006 static void
1007 print_esc_char (char c)
1009 switch (c)
1011 case 'a': /* Alert. */
1012 c ='\a';
1013 break;
1014 case 'b': /* Backspace. */
1015 c ='\b';
1016 break;
1017 case 'e': /* Escape. */
1018 c ='\x1B';
1019 break;
1020 case 'f': /* Form feed. */
1021 c ='\f';
1022 break;
1023 case 'n': /* New line. */
1024 c ='\n';
1025 break;
1026 case 'r': /* Carriage return. */
1027 c ='\r';
1028 break;
1029 case 't': /* Horizontal tab. */
1030 c ='\t';
1031 break;
1032 case 'v': /* Vertical tab. */
1033 c ='\v';
1034 break;
1035 case '"':
1036 case '\\':
1037 break;
1038 default:
1039 error (0, 0, _("warning: unrecognized escape `\\%c'"), c);
1040 break;
1042 putchar (c);
1045 /* Print the information specified by the format string, FORMAT,
1046 calling PRINT_FUNC for each %-directive encountered.
1047 Return zero upon success, nonzero upon failure. */
1048 static bool ATTRIBUTE_WARN_UNUSED_RESULT
1049 print_it (char const *format, char const *filename,
1050 bool (*print_func) (char *, size_t, unsigned int,
1051 char const *, void const *),
1052 void const *data)
1054 bool fail = false;
1056 /* Add 2 to accommodate our conversion of the stat `%s' format string
1057 to the longer printf `%llu' one. */
1058 enum
1060 MAX_ADDITIONAL_BYTES =
1061 (MAX (sizeof PRIdMAX,
1062 MAX (sizeof PRIoMAX, MAX (sizeof PRIuMAX, sizeof PRIxMAX)))
1063 - 1)
1065 size_t n_alloc = strlen (format) + MAX_ADDITIONAL_BYTES + 1;
1066 char *dest = xmalloc (n_alloc);
1067 char const *b;
1068 for (b = format; *b; b++)
1070 switch (*b)
1072 case '%':
1074 size_t len = strspn (b + 1, printf_flags);
1075 char const *fmt_char = b + len + 1;
1076 fmt_char += strspn (fmt_char, digits);
1077 if (*fmt_char == '.')
1078 fmt_char += 1 + strspn (fmt_char + 1, digits);
1079 len = fmt_char - (b + 1);
1080 unsigned int fmt_code = *fmt_char;
1081 memcpy (dest, b, len + 1);
1083 b = fmt_char;
1084 switch (fmt_code)
1086 case '\0':
1087 --b;
1088 /* fall through */
1089 case '%':
1090 if (0 < len)
1092 dest[len + 1] = *fmt_char;
1093 dest[len + 2] = '\0';
1094 error (EXIT_FAILURE, 0, _("%s: invalid directive"),
1095 quotearg_colon (dest));
1097 putchar ('%');
1098 break;
1099 default:
1100 fail |= print_func (dest, len + 1, fmt_code, filename, data);
1101 break;
1103 break;
1106 case '\\':
1107 if ( ! interpret_backslash_escapes)
1109 putchar ('\\');
1110 break;
1112 ++b;
1113 if (isodigit (*b))
1115 int esc_value = octtobin (*b);
1116 int esc_length = 1; /* number of octal digits */
1117 for (++b; esc_length < 3 && isodigit (*b);
1118 ++esc_length, ++b)
1120 esc_value = esc_value * 8 + octtobin (*b);
1122 putchar (esc_value);
1123 --b;
1125 else if (*b == 'x' && isxdigit (to_uchar (b[1])))
1127 int esc_value = hextobin (b[1]); /* Value of \xhh escape. */
1128 /* A hexadecimal \xhh escape sequence must have
1129 1 or 2 hex. digits. */
1130 ++b;
1131 if (isxdigit (to_uchar (b[1])))
1133 ++b;
1134 esc_value = esc_value * 16 + hextobin (*b);
1136 putchar (esc_value);
1138 else if (*b == '\0')
1140 error (0, 0, _("warning: backslash at end of format"));
1141 putchar ('\\');
1142 /* Arrange to exit the loop. */
1143 --b;
1145 else
1147 print_esc_char (*b);
1149 break;
1151 default:
1152 putchar (*b);
1153 break;
1156 free (dest);
1158 fputs (trailing_delim, stdout);
1160 return fail;
1163 /* Stat the file system and print what we find. */
1164 static bool ATTRIBUTE_WARN_UNUSED_RESULT
1165 do_statfs (char const *filename, char const *format)
1167 STRUCT_STATVFS statfsbuf;
1169 if (STREQ (filename, "-"))
1171 error (0, 0, _("using %s to denote standard input does not work"
1172 " in file system mode"), quote (filename));
1173 return false;
1176 if (STATFS (filename, &statfsbuf) != 0)
1178 error (0, errno, _("cannot read file system information for %s"),
1179 quote (filename));
1180 return false;
1183 bool fail = print_it (format, filename, print_statfs, &statfsbuf);
1184 return ! fail;
1187 /* stat the file and print what we find */
1188 static bool ATTRIBUTE_WARN_UNUSED_RESULT
1189 do_stat (char const *filename, char const *format,
1190 char const *format2)
1192 struct stat statbuf;
1194 if (STREQ (filename, "-"))
1196 if (fstat (STDIN_FILENO, &statbuf) != 0)
1198 error (0, errno, _("cannot stat standard input"));
1199 return false;
1202 /* We can't use the shorter
1203 (follow_links?stat:lstat) (filename, &statbug)
1204 since stat might be a function-like macro. */
1205 else if ((follow_links
1206 ? stat (filename, &statbuf)
1207 : lstat (filename, &statbuf)) != 0)
1209 error (0, errno, _("cannot stat %s"), quote (filename));
1210 return false;
1213 if (S_ISBLK (statbuf.st_mode) || S_ISCHR (statbuf.st_mode))
1214 format = format2;
1216 bool fail = print_it (format, filename, print_stat, &statbuf);
1217 return ! fail;
1220 /* Return an allocated format string in static storage that
1221 corresponds to whether FS and TERSE options were declared. */
1222 static char *
1223 default_format (bool fs, bool terse, bool device)
1225 char *format;
1226 if (fs)
1228 if (terse)
1229 format = xstrdup ("%n %i %l %t %s %S %b %f %a %c %d\n");
1230 else
1232 /* TRANSLATORS: This string uses format specifiers from
1233 'stat --help' with --file-system, and NOT from printf. */
1234 format = xstrdup (_("\
1235 File: \"%n\"\n\
1236 ID: %-8i Namelen: %-7l Type: %T\n\
1237 Block size: %-10s Fundamental block size: %S\n\
1238 Blocks: Total: %-10b Free: %-10f Available: %a\n\
1239 Inodes: Total: %-10c Free: %d\n\
1240 "));
1243 else /* ! fs */
1245 if (terse)
1247 if (0 < is_selinux_enabled ())
1248 format = xstrdup ("%n %s %b %f %u %g %D %i %h %t %T"
1249 " %X %Y %Z %W %o %C\n");
1250 else
1251 format = xstrdup ("%n %s %b %f %u %g %D %i %h %t %T"
1252 " %X %Y %Z %W %o\n");
1254 else
1256 char *temp;
1257 /* TRANSLATORS: This string uses format specifiers from
1258 'stat --help' without --file-system, and NOT from printf. */
1259 format = xstrdup (_("\
1260 File: %N\n\
1261 Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n\
1262 "));
1264 temp = format;
1265 if (device)
1267 /* TRANSLATORS: This string uses format specifiers from
1268 'stat --help' without --file-system, and NOT from printf. */
1269 format = xasprintf ("%s%s", format, _("\
1270 Device: %Dh/%dd\tInode: %-10i Links: %-5h Device type: %t,%T\n\
1271 "));
1273 else
1275 /* TRANSLATORS: This string uses format specifiers from
1276 'stat --help' without --file-system, and NOT from printf. */
1277 format = xasprintf ("%s%s", format, _("\
1278 Device: %Dh/%dd\tInode: %-10i Links: %h\n\
1279 "));
1281 free (temp);
1283 temp = format;
1284 /* TRANSLATORS: This string uses format specifiers from
1285 'stat --help' without --file-system, and NOT from printf. */
1286 format = xasprintf ("%s%s", format, _("\
1287 Access: (%04a/%10.10A) Uid: (%5u/%8U) Gid: (%5g/%8G)\n\
1288 "));
1289 free (temp);
1291 if (0 < is_selinux_enabled ())
1293 temp = format;
1294 /* TRANSLATORS: This string uses format specifiers from
1295 'stat --help' without --file-system, and NOT from printf. */
1296 format = xasprintf ("%s%s", format, _("\
1297 Context: %C\n\
1298 "));
1299 free (temp);
1302 temp = format;
1303 /* TRANSLATORS: This string uses format specifiers from
1304 'stat --help' without --file-system, and NOT from printf. */
1305 format = xasprintf ("%s%s", format, _("\
1306 Access: %x\n\
1307 Modify: %y\n\
1308 Change: %z\n\
1309 Birth: %w\n\
1310 "));
1311 free (temp);
1314 return format;
1317 void
1318 usage (int status)
1320 if (status != EXIT_SUCCESS)
1321 fprintf (stderr, _("Try `%s --help' for more information.\n"),
1322 program_name);
1323 else
1325 printf (_("Usage: %s [OPTION]... FILE...\n"), program_name);
1326 fputs (_("\
1327 Display file or file system status.\n\
1329 -L, --dereference follow links\n\
1330 -f, --file-system display file system status instead of file status\n\
1331 "), stdout);
1332 fputs (_("\
1333 -c --format=FORMAT use the specified FORMAT instead of the default;\n\
1334 output a newline after each use of FORMAT\n\
1335 --printf=FORMAT like --format, but interpret backslash escapes,\n\
1336 and do not output a mandatory trailing newline.\n\
1337 If you want a newline, include \\n in FORMAT\n\
1338 -t, --terse print the information in terse form\n\
1339 "), stdout);
1340 fputs (HELP_OPTION_DESCRIPTION, stdout);
1341 fputs (VERSION_OPTION_DESCRIPTION, stdout);
1343 fputs (_("\n\
1344 The valid format sequences for files (without --file-system):\n\
1346 %a Access rights in octal\n\
1347 %A Access rights in human readable form\n\
1348 %b Number of blocks allocated (see %B)\n\
1349 %B The size in bytes of each block reported by %b\n\
1350 %C SELinux security context string\n\
1351 "), stdout);
1352 fputs (_("\
1353 %d Device number in decimal\n\
1354 %D Device number in hex\n\
1355 %f Raw mode in hex\n\
1356 %F File type\n\
1357 %g Group ID of owner\n\
1358 %G Group name of owner\n\
1359 "), stdout);
1360 fputs (_("\
1361 %h Number of hard links\n\
1362 %i Inode number\n\
1363 %m Mount point\n\
1364 %n File name\n\
1365 %N Quoted file name with dereference if symbolic link\n\
1366 %o I/O block size\n\
1367 %s Total size, in bytes\n\
1368 %t Major device type in hex\n\
1369 %T Minor device type in hex\n\
1370 "), stdout);
1371 fputs (_("\
1372 %u User ID of owner\n\
1373 %U User name of owner\n\
1374 %w Time of file birth, human-readable; - if unknown\n\
1375 %W Time of file birth, seconds since Epoch; 0 if unknown\n\
1376 %x Time of last access, human-readable\n\
1377 %X Time of last access, seconds since Epoch\n\
1378 %y Time of last modification, human-readable\n\
1379 %Y Time of last modification, seconds since Epoch\n\
1380 %z Time of last change, human-readable\n\
1381 %Z Time of last change, seconds since Epoch\n\
1383 "), stdout);
1385 fputs (_("\
1386 Valid format sequences for file systems:\n\
1388 %a Free blocks available to non-superuser\n\
1389 %b Total data blocks in file system\n\
1390 %c Total file nodes in file system\n\
1391 %d Free file nodes in file system\n\
1392 %f Free blocks in file system\n\
1393 "), stdout);
1394 fputs (_("\
1395 %i File System ID in hex\n\
1396 %l Maximum length of filenames\n\
1397 %n File name\n\
1398 %s Block size (for faster transfers)\n\
1399 %S Fundamental block size (for block counts)\n\
1400 %t Type in hex\n\
1401 %T Type in human readable form\n\
1402 "), stdout);
1403 printf (USAGE_BUILTIN_WARNING, PROGRAM_NAME);
1404 emit_ancillary_info ();
1406 exit (status);
1410 main (int argc, char *argv[])
1412 int c;
1413 int i;
1414 bool fs = false;
1415 bool terse = false;
1416 char *format = NULL;
1417 char *format2;
1418 bool ok = true;
1420 initialize_main (&argc, &argv);
1421 set_program_name (argv[0]);
1422 setlocale (LC_ALL, "");
1423 bindtextdomain (PACKAGE, LOCALEDIR);
1424 textdomain (PACKAGE);
1426 struct lconv const *locale = localeconv ();
1427 decimal_point = (locale->decimal_point[0] ? locale->decimal_point : ".");
1428 decimal_point_len = strlen (decimal_point);
1430 atexit (close_stdout);
1432 while ((c = getopt_long (argc, argv, "c:fLt", long_options, NULL)) != -1)
1434 switch (c)
1436 case PRINTF_OPTION:
1437 format = optarg;
1438 interpret_backslash_escapes = true;
1439 trailing_delim = "";
1440 break;
1442 case 'c':
1443 format = optarg;
1444 interpret_backslash_escapes = false;
1445 trailing_delim = "\n";
1446 break;
1448 case 'L':
1449 follow_links = true;
1450 break;
1452 case 'f':
1453 fs = true;
1454 break;
1456 case 't':
1457 terse = true;
1458 break;
1460 case_GETOPT_HELP_CHAR;
1462 case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
1464 default:
1465 usage (EXIT_FAILURE);
1469 if (argc == optind)
1471 error (0, 0, _("missing operand"));
1472 usage (EXIT_FAILURE);
1475 if (format)
1476 format2 = format;
1477 else
1479 format = default_format (fs, terse, false);
1480 format2 = default_format (fs, terse, true);
1483 for (i = optind; i < argc; i++)
1484 ok &= (fs
1485 ? do_statfs (argv[i], format)
1486 : do_stat (argv[i], format, format2));
1488 exit (ok ? EXIT_SUCCESS : EXIT_FAILURE);