*** empty log message ***
[coreutils.git] / src / stat.c
blob6de5e15c3d34bf9277c3578ab1fe2d4539424d75
1 /* stat.c -- display file or file system status
2 Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation.
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 2, or (at your option)
7 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, write to the Free Software Foundation,
16 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 Written by Michael Meskes. */
20 #include <config.h>
22 /* Keep this conditional in sync with the similar conditional in
23 ../m4/stat-prog.m4. */
24 #if (STAT_STATVFS \
25 && (HAVE_STRUCT_STATVFS_F_BASETYPE || HAVE_STRUCT_STATVFS_F_FSTYPENAME \
26 || (! HAVE_STRUCT_STATFS_F_FSTYPENAME && HAVE_STRUCT_STATVFS_F_TYPE)))
27 # define USE_STATVFS 1
28 #else
29 # define USE_STATVFS 0
30 #endif
32 #include <stddef.h>
33 #include <stdio.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_NETINET_IN_H && 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
58 #include "system.h"
60 #include "error.h"
61 #include "filemode.h"
62 #include "file-type.h"
63 #include "fs.h"
64 #include "getopt.h"
65 #include "inttostr.h"
66 #include "quote.h"
67 #include "quotearg.h"
68 #include "stat-time.h"
69 #include "strftime.h"
70 #include "xreadlink.h"
72 #define alignof(type) offsetof (struct { char c; type x; }, x)
74 #if USE_STATVFS
75 # define STRUCT_STATVFS struct 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 # define STATFS statvfs
82 # define STATFS_FRSIZE(S) ((S)->f_frsize)
83 #else
84 # define HAVE_STRUCT_STATXFS_F_TYPE HAVE_STRUCT_STATFS_F_TYPE
85 # if HAVE_STRUCT_STATFS_F_NAMELEN
86 # define SB_F_NAMEMAX(S) ((S)->f_namelen)
87 # endif
88 # define STATFS statfs
89 # if HAVE_OS_H /* BeOS */
90 /* BeOS has a statvfs function, but it does not return sensible values
91 for f_files, f_ffree and f_favail, and lacks f_type, f_basetype and
92 f_fstypename. Use 'struct fs_info' instead. */
93 static int
94 statfs (char const *filename, struct fs_info *buf)
96 dev_t device = dev_for_path (filename);
97 if (device < 0)
99 errno = (device == B_ENTRY_NOT_FOUND ? ENOENT
100 : device == B_BAD_VALUE ? EINVAL
101 : device == B_NAME_TOO_LONG ? ENAMETOOLONG
102 : device == B_NO_MEMORY ? ENOMEM
103 : device == B_FILE_ERROR ? EIO
104 : 0);
105 return -1;
107 /* If successful, buf->dev will be == device. */
108 return fs_stat_dev (device, buf);
110 # define f_fsid dev
111 # define f_blocks total_blocks
112 # define f_bfree free_blocks
113 # define f_bavail free_blocks
114 # define f_bsize io_size
115 # define f_files total_nodes
116 # define f_ffree free_nodes
117 # define STRUCT_STATVFS struct fs_info
118 # define STRUCT_STATXFS_F_FSID_IS_INTEGER true
119 # define STATFS_FRSIZE(S) ((S)->block_size)
120 # else
121 # define STRUCT_STATVFS struct statfs
122 # define STRUCT_STATXFS_F_FSID_IS_INTEGER STRUCT_STATFS_F_FSID_IS_INTEGER
123 # define STATFS_FRSIZE(S) 0
124 # endif
125 #endif
127 #ifdef SB_F_NAMEMAX
128 # define OUT_NAMEMAX out_uint
129 #else
130 /* NetBSD 1.5.2 has neither f_namemax nor f_namelen. */
131 # define SB_F_NAMEMAX(S) "*"
132 # define OUT_NAMEMAX out_string
133 #endif
135 #if HAVE_STRUCT_STATVFS_F_BASETYPE
136 # define STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME f_basetype
137 #else
138 # if HAVE_STRUCT_STATVFS_F_FSTYPENAME || HAVE_STRUCT_STATFS_F_FSTYPENAME
139 # define STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME f_fstypename
140 # elif HAVE_OS_H /* BeOS */
141 # define STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME fsh_name
142 # endif
143 #endif
145 /* FIXME: these are used by printf.c, too */
146 #define isodigit(c) ('0' <= (c) && (c) <= '7')
147 #define octtobin(c) ((c) - '0')
148 #define hextobin(c) ((c) >= 'a' && (c) <= 'f' ? (c) - 'a' + 10 : \
149 (c) >= 'A' && (c) <= 'F' ? (c) - 'A' + 10 : (c) - '0')
151 #define PROGRAM_NAME "stat"
153 #define AUTHORS "Michael Meskes"
155 enum
157 PRINTF_OPTION = CHAR_MAX + 1,
160 static struct option const long_options[] = {
161 {"dereference", no_argument, NULL, 'L'},
162 {"file-system", no_argument, NULL, 'f'},
163 {"filesystem", no_argument, NULL, 'f'}, /* obsolete and undocumented alias */
164 {"format", required_argument, NULL, 'c'},
165 {"printf", required_argument, NULL, PRINTF_OPTION},
166 {"terse", no_argument, NULL, 't'},
167 {GETOPT_HELP_OPTION_DECL},
168 {GETOPT_VERSION_OPTION_DECL},
169 {NULL, 0, NULL, 0}
172 char *program_name;
174 /* Whether to interpret backslash-escape sequences.
175 True for --printf=FMT, not for --format=FMT (-c). */
176 static bool interpret_backslash_escapes;
178 /* The trailing delimiter string:
179 "" for --printf=FMT, "\n" for --format=FMT (-c). */
180 static char const *trailing_delim = "";
182 /* Return the type of the specified file system.
183 Some systems have statfvs.f_basetype[FSTYPSZ] (AIX, HP-UX, and Solaris).
184 Others have statvfs.f_fstypename[_VFS_NAMELEN] (NetBSD 3.0).
185 Others have statfs.f_fstypename[MFSNAMELEN] (NetBSD 1.5.2).
186 Still others have neither and have to get by with f_type (Linux).
187 But f_type may only exist in statfs (Cygwin). */
188 static char const *
189 human_fstype (STRUCT_STATVFS const *statfsbuf)
191 #ifdef STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME
192 return statfsbuf->STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME;
193 #else
194 switch (statfsbuf->f_type)
196 # if defined __linux__
198 /* IMPORTANT NOTE: Each of the following `case S_MAGIC_...:'
199 statements must be followed by a hexadecimal constant in
200 a comment. The S_MAGIC_... name and constant are automatically
201 combined to produce the #define directives in fs.h. */
203 case S_MAGIC_AFFS: /* 0xADFF */
204 return "affs";
205 case S_MAGIC_DEVPTS: /* 0x1CD1 */
206 return "devpts";
207 case S_MAGIC_EXT: /* 0x137D */
208 return "ext";
209 case S_MAGIC_EXT2_OLD: /* 0xEF51 */
210 return "ext2";
211 case S_MAGIC_EXT2: /* 0xEF53 */
212 return "ext2/ext3";
213 case S_MAGIC_JFS: /* 0x3153464a */
214 return "jfs";
215 case S_MAGIC_XFS: /* 0x58465342 */
216 return "xfs";
217 case S_MAGIC_HPFS: /* 0xF995E849 */
218 return "hpfs";
219 case S_MAGIC_ISOFS: /* 0x9660 */
220 return "isofs";
221 case S_MAGIC_ISOFS_WIN: /* 0x4000 */
222 return "isofs";
223 case S_MAGIC_ISOFS_R_WIN: /* 0x4004 */
224 return "isofs";
225 case S_MAGIC_MINIX: /* 0x137F */
226 return "minix";
227 case S_MAGIC_MINIX_30: /* 0x138F */
228 return "minix (30 char.)";
229 case S_MAGIC_MINIX_V2: /* 0x2468 */
230 return "minix v2";
231 case S_MAGIC_MINIX_V2_30: /* 0x2478 */
232 return "minix v2 (30 char.)";
233 case S_MAGIC_MSDOS: /* 0x4d44 */
234 return "msdos";
235 case S_MAGIC_FAT: /* 0x4006 */
236 return "fat";
237 case S_MAGIC_NCP: /* 0x564c */
238 return "novell";
239 case S_MAGIC_NFS: /* 0x6969 */
240 return "nfs";
241 case S_MAGIC_PROC: /* 0x9fa0 */
242 return "proc";
243 case S_MAGIC_SMB: /* 0x517B */
244 return "smb";
245 case S_MAGIC_XENIX: /* 0x012FF7B4 */
246 return "xenix";
247 case S_MAGIC_SYSV4: /* 0x012FF7B5 */
248 return "sysv4";
249 case S_MAGIC_SYSV2: /* 0x012FF7B6 */
250 return "sysv2";
251 case S_MAGIC_COH: /* 0x012FF7B7 */
252 return "coh";
253 case S_MAGIC_UFS: /* 0x00011954 */
254 return "ufs";
255 case S_MAGIC_XIAFS: /* 0x012FD16D */
256 return "xia";
257 case S_MAGIC_NTFS: /* 0x5346544e */
258 return "ntfs";
259 case S_MAGIC_TMPFS: /* 0x1021994 */
260 return "tmpfs";
261 case S_MAGIC_REISERFS: /* 0x52654973 */
262 return "reiserfs";
263 case S_MAGIC_CRAMFS: /* 0x28cd3d45 */
264 return "cramfs";
265 case S_MAGIC_ROMFS: /* 0x7275 */
266 return "romfs";
267 case S_MAGIC_RAMFS: /* 0x858458f6 */
268 return "ramfs";
269 case S_MAGIC_SQUASHFS: /* 0x73717368 */
270 return "squashfs";
271 case S_MAGIC_SYSFS: /* 0x62656572 */
272 return "sysfs";
273 # elif __GNU__
274 case FSTYPE_UFS:
275 return "ufs";
276 case FSTYPE_NFS:
277 return "nfs";
278 case FSTYPE_GFS:
279 return "gfs";
280 case FSTYPE_LFS:
281 return "lfs";
282 case FSTYPE_SYSV:
283 return "sysv";
284 case FSTYPE_FTP:
285 return "ftp";
286 case FSTYPE_TAR:
287 return "tar";
288 case FSTYPE_AR:
289 return "ar";
290 case FSTYPE_CPIO:
291 return "cpio";
292 case FSTYPE_MSLOSS:
293 return "msloss";
294 case FSTYPE_CPM:
295 return "cpm";
296 case FSTYPE_HFS:
297 return "hfs";
298 case FSTYPE_DTFS:
299 return "dtfs";
300 case FSTYPE_GRFS:
301 return "grfs";
302 case FSTYPE_TERM:
303 return "term";
304 case FSTYPE_DEV:
305 return "dev";
306 case FSTYPE_PROC:
307 return "proc";
308 case FSTYPE_IFSOCK:
309 return "ifsock";
310 case FSTYPE_AFS:
311 return "afs";
312 case FSTYPE_DFS:
313 return "dfs";
314 case FSTYPE_PROC9:
315 return "proc9";
316 case FSTYPE_SOCKET:
317 return "socket";
318 case FSTYPE_MISC:
319 return "misc";
320 case FSTYPE_EXT2FS:
321 return "ext2/ext3";
322 case FSTYPE_HTTP:
323 return "http";
324 case FSTYPE_MEMFS:
325 return "memfs";
326 case FSTYPE_ISO9660:
327 return "iso9660";
328 # endif
329 default:
331 unsigned long int type = statfsbuf->f_type;
332 static char buf[sizeof "UNKNOWN (0x%lx)" - 3
333 + (sizeof type * CHAR_BIT + 3) / 4];
334 sprintf (buf, "UNKNOWN (0x%lx)", type);
335 return buf;
338 #endif
341 static char *
342 human_access (struct stat const *statbuf)
344 static char modebuf[12];
345 filemodestring (statbuf, modebuf);
346 modebuf[10] = 0;
347 return modebuf;
350 static char *
351 human_time (struct timespec t)
353 static char str[MAX (INT_BUFSIZE_BOUND (intmax_t),
354 (INT_STRLEN_BOUND (int) /* YYYY */
355 + 1 /* because YYYY might equal INT_MAX + 1900 */
356 + sizeof "-MM-DD HH:MM:SS.NNNNNNNNN +ZZZZ"))];
357 struct tm const *tm = localtime (&t.tv_sec);
358 if (tm == NULL)
359 return (TYPE_SIGNED (time_t)
360 ? imaxtostr (t.tv_sec, str)
361 : umaxtostr (t.tv_sec, str));
362 nstrftime (str, sizeof str, "%Y-%m-%d %H:%M:%S.%N %z", tm, 0, t.tv_nsec);
363 return str;
366 static void
367 out_string (char *pformat, size_t prefix_len, char const *arg)
369 strcpy (pformat + prefix_len, "s");
370 printf (pformat, arg);
372 static void
373 out_int (char *pformat, size_t prefix_len, intmax_t arg)
375 strcpy (pformat + prefix_len, PRIdMAX);
376 printf (pformat, arg);
378 static void
379 out_uint (char *pformat, size_t prefix_len, uintmax_t arg)
381 strcpy (pformat + prefix_len, PRIuMAX);
382 printf (pformat, arg);
384 static void
385 out_uint_o (char *pformat, size_t prefix_len, uintmax_t arg)
387 strcpy (pformat + prefix_len, PRIoMAX);
388 printf (pformat, arg);
390 static void
391 out_uint_x (char *pformat, size_t prefix_len, uintmax_t arg)
393 strcpy (pformat + prefix_len, PRIxMAX);
394 printf (pformat, arg);
397 /* print statfs info */
398 static void
399 print_statfs (char *pformat, size_t prefix_len, char m, char const *filename,
400 void const *data)
402 STRUCT_STATVFS const *statfsbuf = data;
404 switch (m)
406 case 'n':
407 out_string (pformat, prefix_len, filename);
408 break;
410 case 'i':
412 #if STRUCT_STATXFS_F_FSID_IS_INTEGER
413 uintmax_t fsid = statfsbuf->f_fsid;
414 #else
415 typedef unsigned int fsid_word;
416 verify (alignof (STRUCT_STATVFS) % alignof (fsid_word) == 0);
417 verify (offsetof (STRUCT_STATVFS, f_fsid) % alignof (fsid_word) == 0);
418 verify (sizeof statfsbuf->f_fsid % alignof (fsid_word) == 0);
419 fsid_word const *p = (fsid_word *) &statfsbuf->f_fsid;
421 /* Assume a little-endian word order, as that is compatible
422 with glibc's statvfs implementation. */
423 uintmax_t fsid = 0;
424 int words = sizeof statfsbuf->f_fsid / sizeof *p;
425 int i;
426 for (i = 0; i < words && i * sizeof *p < sizeof fsid; i++)
428 uintmax_t u = p[words - 1 - i];
429 fsid |= u << (i * CHAR_BIT * sizeof *p);
431 #endif
432 out_uint_x (pformat, prefix_len, fsid);
434 break;
436 case 'l':
437 OUT_NAMEMAX (pformat, prefix_len, SB_F_NAMEMAX (statfsbuf));
438 break;
439 case 't':
440 #if HAVE_STRUCT_STATXFS_F_TYPE
441 out_uint_x (pformat, prefix_len, statfsbuf->f_type);
442 #else
443 fputc ('?', stdout);
444 #endif
445 break;
446 case 'T':
447 out_string (pformat, prefix_len, human_fstype (statfsbuf));
448 break;
449 case 'b':
450 out_int (pformat, prefix_len, statfsbuf->f_blocks);
451 break;
452 case 'f':
453 out_int (pformat, prefix_len, statfsbuf->f_bfree);
454 break;
455 case 'a':
456 out_int (pformat, prefix_len, statfsbuf->f_bavail);
457 break;
458 case 's':
459 out_uint (pformat, prefix_len, statfsbuf->f_bsize);
460 break;
461 case 'S':
463 uintmax_t frsize = STATFS_FRSIZE (statfsbuf);
464 if (! frsize)
465 frsize = statfsbuf->f_bsize;
466 out_uint (pformat, prefix_len, frsize);
468 break;
469 case 'c':
470 out_int (pformat, prefix_len, statfsbuf->f_files);
471 break;
472 case 'd':
473 out_int (pformat, prefix_len, statfsbuf->f_ffree);
474 break;
476 default:
477 fputc ('?', stdout);
478 break;
482 /* print stat info */
483 static void
484 print_stat (char *pformat, size_t prefix_len, char m,
485 char const *filename, void const *data)
487 struct stat *statbuf = (struct stat *) data;
488 struct passwd *pw_ent;
489 struct group *gw_ent;
491 switch (m)
493 case 'n':
494 out_string (pformat, prefix_len, filename);
495 break;
496 case 'N':
497 out_string (pformat, prefix_len, quote (filename));
498 if (S_ISLNK (statbuf->st_mode))
500 char *linkname = xreadlink (filename, statbuf->st_size);
501 if (linkname == NULL)
503 error (0, errno, _("cannot read symbolic link %s"),
504 quote (filename));
505 return;
507 printf (" -> ");
508 out_string (pformat, prefix_len, quote (linkname));
510 break;
511 case 'd':
512 out_uint (pformat, prefix_len, statbuf->st_dev);
513 break;
514 case 'D':
515 out_uint_x (pformat, prefix_len, statbuf->st_dev);
516 break;
517 case 'i':
518 out_uint (pformat, prefix_len, statbuf->st_ino);
519 break;
520 case 'a':
521 out_uint_o (pformat, prefix_len, statbuf->st_mode & CHMOD_MODE_BITS);
522 break;
523 case 'A':
524 out_string (pformat, prefix_len, human_access (statbuf));
525 break;
526 case 'f':
527 out_uint_x (pformat, prefix_len, statbuf->st_mode);
528 break;
529 case 'F':
530 out_string (pformat, prefix_len, file_type (statbuf));
531 break;
532 case 'h':
533 out_uint (pformat, prefix_len, statbuf->st_nlink);
534 break;
535 case 'u':
536 out_uint (pformat, prefix_len, statbuf->st_uid);
537 break;
538 case 'U':
539 setpwent ();
540 pw_ent = getpwuid (statbuf->st_uid);
541 out_string (pformat, prefix_len,
542 pw_ent ? pw_ent->pw_name : "UNKNOWN");
543 break;
544 case 'g':
545 out_uint (pformat, prefix_len, statbuf->st_gid);
546 break;
547 case 'G':
548 setgrent ();
549 gw_ent = getgrgid (statbuf->st_gid);
550 out_string (pformat, prefix_len,
551 gw_ent ? gw_ent->gr_name : "UNKNOWN");
552 break;
553 case 't':
554 out_uint_x (pformat, prefix_len, major (statbuf->st_rdev));
555 break;
556 case 'T':
557 out_uint_x (pformat, prefix_len, minor (statbuf->st_rdev));
558 break;
559 case 's':
560 out_uint (pformat, prefix_len, statbuf->st_size);
561 break;
562 case 'B':
563 out_uint (pformat, prefix_len, ST_NBLOCKSIZE);
564 break;
565 case 'b':
566 out_uint (pformat, prefix_len, ST_NBLOCKS (*statbuf));
567 break;
568 case 'o':
569 out_uint (pformat, prefix_len, statbuf->st_blksize);
570 break;
571 case 'x':
572 out_string (pformat, prefix_len, human_time (get_stat_atime (statbuf)));
573 break;
574 case 'X':
575 if (TYPE_SIGNED (time_t))
576 out_int (pformat, prefix_len, statbuf->st_atime);
577 else
578 out_uint (pformat, prefix_len, statbuf->st_atime);
579 break;
580 case 'y':
581 out_string (pformat, prefix_len, human_time (get_stat_mtime (statbuf)));
582 break;
583 case 'Y':
584 if (TYPE_SIGNED (time_t))
585 out_int (pformat, prefix_len, statbuf->st_mtime);
586 else
587 out_uint (pformat, prefix_len, statbuf->st_mtime);
588 break;
589 case 'z':
590 out_string (pformat, prefix_len, human_time (get_stat_ctime (statbuf)));
591 break;
592 case 'Z':
593 if (TYPE_SIGNED (time_t))
594 out_int (pformat, prefix_len, statbuf->st_ctime);
595 else
596 out_uint (pformat, prefix_len, statbuf->st_ctime);
597 break;
598 default:
599 fputc ('?', stdout);
600 break;
604 /* Output a single-character \ escape. */
606 static void
607 print_esc_char (char c)
609 switch (c)
611 case 'a': /* Alert. */
612 c ='\a';
613 break;
614 case 'b': /* Backspace. */
615 c ='\b';
616 break;
617 case 'f': /* Form feed. */
618 c ='\f';
619 break;
620 case 'n': /* New line. */
621 c ='\n';
622 break;
623 case 'r': /* Carriage return. */
624 c ='\r';
625 break;
626 case 't': /* Horizontal tab. */
627 c ='\t';
628 break;
629 case 'v': /* Vertical tab. */
630 c ='\v';
631 break;
632 case '"':
633 case '\\':
634 break;
635 default:
636 error (0, 0, _("warning: unrecognized escape `\\%c'"), c);
637 break;
639 putchar (c);
642 static void
643 print_it (char const *format, char const *filename,
644 void (*print_func) (char *, size_t, char, char const *, void const *),
645 void const *data)
647 /* Add 2 to accommodate our conversion of the stat `%s' format string
648 to the longer printf `%llu' one. */
649 enum
651 MAX_ADDITIONAL_BYTES =
652 (MAX (sizeof PRIdMAX,
653 MAX (sizeof PRIoMAX, MAX (sizeof PRIuMAX, sizeof PRIxMAX)))
654 - 1)
656 size_t n_alloc = strlen (format) + MAX_ADDITIONAL_BYTES + 1;
657 char *dest = xmalloc (n_alloc);
658 char const *b;
659 for (b = format; *b; b++)
661 switch (*b)
663 case '%':
665 size_t len = strspn (b + 1, "#-+.I 0123456789");
666 char const *fmt_char = b + len + 1;
667 memcpy (dest, b, len + 1);
669 b = fmt_char;
670 switch (*fmt_char)
672 case '\0':
673 --b;
674 /* fall through */
675 case '%':
676 if (0 < len)
678 dest[len + 1] = *fmt_char;
679 dest[len + 2] = '\0';
680 error (EXIT_FAILURE, 0, _("%s: invalid directive"),
681 quotearg_colon (dest));
683 putchar ('%');
684 break;
685 default:
686 print_func (dest, len + 1, *fmt_char, filename, data);
687 break;
689 break;
692 case '\\':
693 if ( ! interpret_backslash_escapes)
695 putchar ('\\');
696 break;
698 ++b;
699 if (isodigit (*b))
701 int esc_value = octtobin (*b);
702 int esc_length = 1; /* number of octal digits */
703 for (++b; esc_length < 3 && isodigit (*b);
704 ++esc_length, ++b)
706 esc_value = esc_value * 8 + octtobin (*b);
708 putchar (esc_value);
709 --b;
711 else if (*b == 'x' && isxdigit (to_uchar (b[1])))
713 int esc_value = hextobin (b[1]); /* Value of \xhh escape. */
714 /* A hexadecimal \xhh escape sequence must have
715 1 or 2 hex. digits. */
716 ++b;
717 if (isxdigit (to_uchar (b[1])))
719 ++b;
720 esc_value = esc_value * 16 + hextobin (*b);
722 putchar (esc_value);
724 else if (*b == '\0')
726 error (0, 0, _("warning: backslash at end of format"));
727 putchar ('\\');
728 /* Arrange to exit the loop. */
729 --b;
731 else
733 print_esc_char (*b);
735 break;
737 default:
738 putchar (*b);
739 break;
742 free (dest);
744 fputs (trailing_delim, stdout);
747 /* Stat the file system and print what we find. */
748 static bool
749 do_statfs (char const *filename, bool terse, char const *format)
751 STRUCT_STATVFS statfsbuf;
753 if (STATFS (filename, &statfsbuf) != 0)
755 error (0, errno, _("cannot read file system information for %s"),
756 quote (filename));
757 return false;
760 if (format == NULL)
762 format = (terse
763 ? "%n %i %l %t %s %S %b %f %a %c %d\n"
764 : " File: \"%n\"\n"
765 " ID: %-8i Namelen: %-7l Type: %T\n"
766 "Block size: %-10s Fundamental block size: %S\n"
767 "Blocks: Total: %-10b Free: %-10f Available: %a\n"
768 "Inodes: Total: %-10c Free: %d\n");
771 print_it (format, filename, print_statfs, &statfsbuf);
772 return true;
775 /* stat the file and print what we find */
776 static bool
777 do_stat (char const *filename, bool follow_links, bool terse,
778 char const *format)
780 struct stat statbuf;
782 if ((follow_links ? stat : lstat) (filename, &statbuf) != 0)
784 error (0, errno, _("cannot stat %s"), quote (filename));
785 return false;
788 if (format == NULL)
790 if (terse)
792 format = "%n %s %b %f %u %g %D %i %h %t %T %X %Y %Z %o\n";
794 else
796 /* Temporary hack to match original output until conditional
797 implemented. */
798 if (S_ISBLK (statbuf.st_mode) || S_ISCHR (statbuf.st_mode))
800 format =
801 " File: %N\n"
802 " Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n"
803 "Device: %Dh/%dd\tInode: %-10i Links: %-5h"
804 " Device type: %t,%T\n"
805 "Access: (%04a/%10.10A) Uid: (%5u/%8U) Gid: (%5g/%8G)\n"
806 "Access: %x\n" "Modify: %y\n" "Change: %z\n";
808 else
810 format =
811 " File: %N\n"
812 " Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n"
813 "Device: %Dh/%dd\tInode: %-10i Links: %h\n"
814 "Access: (%04a/%10.10A) Uid: (%5u/%8U) Gid: (%5g/%8G)\n"
815 "Access: %x\n" "Modify: %y\n" "Change: %z\n";
819 print_it (format, filename, print_stat, &statbuf);
820 return true;
823 void
824 usage (int status)
826 if (status != EXIT_SUCCESS)
827 fprintf (stderr, _("Try `%s --help' for more information.\n"),
828 program_name);
829 else
831 printf (_("Usage: %s [OPTION] FILE...\n"), program_name);
832 fputs (_("\
833 Display file or file system status.\n\
835 -L, --dereference follow links\n\
836 -f, --file-system display file system status instead of file status\n\
837 "), stdout);
838 fputs (_("\
839 -c --format=FORMAT use the specified FORMAT instead of the default;\n\
840 output a newline after each use of FORMAT\n\
841 --printf=FORMAT like --format, but interpret backslash escapes,\n\
842 and do not output a mandatory trailing newline.\n\
843 If you want a newline, include \\n in FORMAT.\n\
844 -t, --terse print the information in terse form\n\
845 "), stdout);
846 fputs (HELP_OPTION_DESCRIPTION, stdout);
847 fputs (VERSION_OPTION_DESCRIPTION, stdout);
849 fputs (_("\n\
850 The valid format sequences for files (without --file-system):\n\
852 %a Access rights in octal\n\
853 %A Access rights in human readable form\n\
854 %b Number of blocks allocated (see %B)\n\
855 %B The size in bytes of each block reported by %b\n\
856 "), stdout);
857 fputs (_("\
858 %d Device number in decimal\n\
859 %D Device number in hex\n\
860 %f Raw mode in hex\n\
861 %F File type\n\
862 %g Group ID of owner\n\
863 %G Group name of owner\n\
864 "), stdout);
865 fputs (_("\
866 %h Number of hard links\n\
867 %i Inode number\n\
868 %n File name\n\
869 %N Quoted file name with dereference if symbolic link\n\
870 %o I/O block size\n\
871 %s Total size, in bytes\n\
872 %t Major device type in hex\n\
873 %T Minor device type in hex\n\
874 "), stdout);
875 fputs (_("\
876 %u User ID of owner\n\
877 %U User name of owner\n\
878 %x Time of last access\n\
879 %X Time of last access as seconds since Epoch\n\
880 %y Time of last modification\n\
881 %Y Time of last modification as seconds since Epoch\n\
882 %z Time of last change\n\
883 %Z Time of last change as seconds since Epoch\n\
885 "), stdout);
887 fputs (_("\
888 Valid format sequences for file systems:\n\
890 %a Free blocks available to non-superuser\n\
891 %b Total data blocks in file system\n\
892 %c Total file nodes in file system\n\
893 %d Free file nodes in file system\n\
894 %f Free blocks in file system\n\
895 "), stdout);
896 fputs (_("\
897 %i File System ID in hex\n\
898 %l Maximum length of filenames\n\
899 %n File name\n\
900 %s Block size (for faster transfers)\n\
901 %S Fundamental block size (for block counts)\n\
902 %t Type in hex\n\
903 %T Type in human readable form\n\
904 "), stdout);
905 printf (USAGE_BUILTIN_WARNING, PROGRAM_NAME);
906 printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
908 exit (status);
912 main (int argc, char *argv[])
914 int c;
915 int i;
916 bool follow_links = false;
917 bool fs = false;
918 bool terse = false;
919 char *format = NULL;
920 bool ok = true;
922 initialize_main (&argc, &argv);
923 program_name = argv[0];
924 setlocale (LC_ALL, "");
925 bindtextdomain (PACKAGE, LOCALEDIR);
926 textdomain (PACKAGE);
928 atexit (close_stdout);
930 while ((c = getopt_long (argc, argv, "c:fLt", long_options, NULL)) != -1)
932 switch (c)
934 case PRINTF_OPTION:
935 format = optarg;
936 interpret_backslash_escapes = true;
937 trailing_delim = "";
938 break;
940 case 'c':
941 format = optarg;
942 interpret_backslash_escapes = false;
943 trailing_delim = "\n";
944 break;
946 case 'L':
947 follow_links = true;
948 break;
950 case 'f':
951 fs = true;
952 break;
954 case 't':
955 terse = true;
956 break;
958 case_GETOPT_HELP_CHAR;
960 case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
962 default:
963 usage (EXIT_FAILURE);
967 if (argc == optind)
969 error (0, 0, _("missing operand"));
970 usage (EXIT_FAILURE);
973 for (i = optind; i < argc; i++)
974 ok &= (fs
975 ? do_statfs (argv[i], terse, format)
976 : do_stat (argv[i], follow_links, terse, format));
978 exit (ok ? EXIT_SUCCESS : EXIT_FAILURE);