.
[coreutils.git] / src / stat.c
blobc9c71c55512687ca49dbd95891bb0d848e012d05
1 /* stat.c -- display file or file system status
2 Copyright (C) 2001, 2002, 2003, 2004, 2005 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 #include <stdio.h>
23 #include <sys/types.h>
24 #include <pwd.h>
25 #include <grp.h>
26 #if HAVE_SYS_STATVFS_H && HAVE_STRUCT_STATVFS_F_BASETYPE
27 # include <sys/statvfs.h>
28 #elif HAVE_SYS_VFS_H
29 # include <sys/vfs.h>
30 #elif HAVE_SYS_MOUNT_H && HAVE_SYS_PARAM_H
31 /* NOTE: freebsd5.0 needs sys/param.h and sys/mount.h for statfs.
32 It does have statvfs.h, but shouldn't use it, since it doesn't
33 HAVE_STRUCT_STATVFS_F_BASETYPE. So find a clean way to fix it. */
34 /* NetBSD 1.5.2 needs these, for the declaration of struct statfs. */
35 # include <sys/param.h>
36 # include <sys/mount.h>
37 # if HAVE_NETINET_IN_H && HAVE_NFS_NFS_CLNT_H && HAVE_NFS_VFS_H
38 /* Ultrix 4.4 needs these for the declaration of struct statfs. */
39 # include <netinet/in.h>
40 # include <nfs/nfs_clnt.h>
41 # include <nfs/vfs.h>
42 # endif
43 #endif
45 #include "system.h"
47 #include "error.h"
48 #include "filemode.h"
49 #include "file-type.h"
50 #include "fs.h"
51 #include "getopt.h"
52 #include "inttostr.h"
53 #include "quote.h"
54 #include "quotearg.h"
55 #include "stat-time.h"
56 #include "strftime.h"
57 #include "xreadlink.h"
59 #define NAMEMAX_FORMAT PRIuMAX
61 #if HAVE_STRUCT_STATVFS_F_BASETYPE
62 # define STRUCT_STATVFS struct statvfs
63 # define HAVE_STRUCT_STATXFS_F_TYPE HAVE_STRUCT_STATVFS_F_TYPE
64 # if HAVE_STRUCT_STATVFS_F_NAMEMAX
65 # define SB_F_NAMEMAX(S) ((uintmax_t) ((S)->f_namemax))
66 # endif
67 # if STAT_STATVFS
68 # define STATFS statvfs
69 # define STATFS_FRSIZE(S) ((S)->f_frsize)
70 # endif
71 #else
72 # define STRUCT_STATVFS struct statfs
73 # define HAVE_STRUCT_STATXFS_F_TYPE HAVE_STRUCT_STATFS_F_TYPE
74 # if HAVE_STRUCT_STATFS_F_NAMELEN
75 # define SB_F_NAMEMAX(S) ((uintmax_t) ((S)->f_namelen))
76 # endif
77 #endif
79 #ifndef STATFS
80 # define STATFS statfs
81 # define STATFS_FRSIZE(S) 0
82 #endif
84 #ifndef SB_F_NAMEMAX
85 /* NetBSD 1.5.2 has neither f_namemax nor f_namelen. */
86 # define SB_F_NAMEMAX(S) "*"
87 # undef NAMEMAX_FORMAT
88 # define NAMEMAX_FORMAT "s"
89 #endif
91 #if HAVE_STRUCT_STATVFS_F_BASETYPE
92 # define STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME f_basetype
93 #else
94 # if HAVE_STRUCT_STATFS_F_FSTYPENAME
95 # define STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME f_fstypename
96 # endif
97 #endif
99 #define PROGRAM_NAME "stat"
101 #define AUTHORS "Michael Meskes"
103 static struct option const long_options[] = {
104 {"link", no_argument, NULL, 'l'}, /* deprecated. FIXME: remove in 2003 */
105 {"dereference", no_argument, NULL, 'L'},
106 {"file-system", no_argument, NULL, 'f'},
107 {"filesystem", no_argument, NULL, 'f'}, /* obsolete and undocumented alias */
108 {"format", required_argument, NULL, 'c'},
109 {"terse", no_argument, NULL, 't'},
110 {GETOPT_HELP_OPTION_DECL},
111 {GETOPT_VERSION_OPTION_DECL},
112 {NULL, 0, NULL, 0}
115 char *program_name;
117 /* Return the type of the specified file system.
118 Some systems have statfvs.f_basetype[FSTYPSZ]. (AIX, HP-UX, and Solaris)
119 Others have statfs.f_fstypename[MFSNAMELEN]. (NetBSD 1.5.2)
120 Still others have neither and have to get by with f_type (Linux). */
121 static char const *
122 human_fstype (STRUCT_STATVFS const *statfsbuf)
124 #ifdef STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME
125 return statfsbuf->STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME;
126 #else
127 switch (statfsbuf->f_type)
129 # if defined __linux__
131 /* IMPORTANT NOTE: Each of the following `case S_MAGIC_...:'
132 statements must be followed by a hexadecimal constant in
133 a comment. The S_MAGIC_... name and constant are automatically
134 combined to produce the #define directives in fs.h. */
136 case S_MAGIC_AFFS: /* 0xADFF */
137 return "affs";
138 case S_MAGIC_DEVPTS: /* 0x1CD1 */
139 return "devpts";
140 case S_MAGIC_EXT: /* 0x137D */
141 return "ext";
142 case S_MAGIC_EXT2_OLD: /* 0xEF51 */
143 return "ext2";
144 case S_MAGIC_EXT2: /* 0xEF53 */
145 return "ext2/ext3";
146 case S_MAGIC_JFS: /* 0x3153464a */
147 return "jfs";
148 case S_MAGIC_XFS: /* 0x58465342 */
149 return "xfs";
150 case S_MAGIC_HPFS: /* 0xF995E849 */
151 return "hpfs";
152 case S_MAGIC_ISOFS: /* 0x9660 */
153 return "isofs";
154 case S_MAGIC_ISOFS_WIN: /* 0x4000 */
155 return "isofs";
156 case S_MAGIC_ISOFS_R_WIN: /* 0x4004 */
157 return "isofs";
158 case S_MAGIC_MINIX: /* 0x137F */
159 return "minix";
160 case S_MAGIC_MINIX_30: /* 0x138F */
161 return "minix (30 char.)";
162 case S_MAGIC_MINIX_V2: /* 0x2468 */
163 return "minix v2";
164 case S_MAGIC_MINIX_V2_30: /* 0x2478 */
165 return "minix v2 (30 char.)";
166 case S_MAGIC_MSDOS: /* 0x4d44 */
167 return "msdos";
168 case S_MAGIC_FAT: /* 0x4006 */
169 return "fat";
170 case S_MAGIC_NCP: /* 0x564c */
171 return "novell";
172 case S_MAGIC_NFS: /* 0x6969 */
173 return "nfs";
174 case S_MAGIC_PROC: /* 0x9fa0 */
175 return "proc";
176 case S_MAGIC_SMB: /* 0x517B */
177 return "smb";
178 case S_MAGIC_XENIX: /* 0x012FF7B4 */
179 return "xenix";
180 case S_MAGIC_SYSV4: /* 0x012FF7B5 */
181 return "sysv4";
182 case S_MAGIC_SYSV2: /* 0x012FF7B6 */
183 return "sysv2";
184 case S_MAGIC_COH: /* 0x012FF7B7 */
185 return "coh";
186 case S_MAGIC_UFS: /* 0x00011954 */
187 return "ufs";
188 case S_MAGIC_XIAFS: /* 0x012FD16D */
189 return "xia";
190 case S_MAGIC_NTFS: /* 0x5346544e */
191 return "ntfs";
192 case S_MAGIC_TMPFS: /* 0x1021994 */
193 return "tmpfs";
194 case S_MAGIC_REISERFS: /* 0x52654973 */
195 return "reiserfs";
196 case S_MAGIC_CRAMFS: /* 0x28cd3d45 */
197 return "cramfs";
198 case S_MAGIC_ROMFS: /* 0x7275 */
199 return "romfs";
200 case S_MAGIC_RAMFS: /* 0x858458f6 */
201 return "ramfs";
202 case S_MAGIC_SQUASHFS: /* 0x73717368 */
203 return "squashfs";
204 case S_MAGIC_SYSFS: /* 0x62656572 */
205 return "sysfs";
206 # elif __GNU__
207 case FSTYPE_UFS:
208 return "ufs";
209 case FSTYPE_NFS:
210 return "nfs";
211 case FSTYPE_GFS:
212 return "gfs";
213 case FSTYPE_LFS:
214 return "lfs";
215 case FSTYPE_SYSV:
216 return "sysv";
217 case FSTYPE_FTP:
218 return "ftp";
219 case FSTYPE_TAR:
220 return "tar";
221 case FSTYPE_AR:
222 return "ar";
223 case FSTYPE_CPIO:
224 return "cpio";
225 case FSTYPE_MSLOSS:
226 return "msloss";
227 case FSTYPE_CPM:
228 return "cpm";
229 case FSTYPE_HFS:
230 return "hfs";
231 case FSTYPE_DTFS:
232 return "dtfs";
233 case FSTYPE_GRFS:
234 return "grfs";
235 case FSTYPE_TERM:
236 return "term";
237 case FSTYPE_DEV:
238 return "dev";
239 case FSTYPE_PROC:
240 return "proc";
241 case FSTYPE_IFSOCK:
242 return "ifsock";
243 case FSTYPE_AFS:
244 return "afs";
245 case FSTYPE_DFS:
246 return "dfs";
247 case FSTYPE_PROC9:
248 return "proc9";
249 case FSTYPE_SOCKET:
250 return "socket";
251 case FSTYPE_MISC:
252 return "misc";
253 case FSTYPE_EXT2FS:
254 return "ext2/ext3";
255 case FSTYPE_HTTP:
256 return "http";
257 case FSTYPE_MEMFS:
258 return "memfs";
259 case FSTYPE_ISO9660:
260 return "iso9660";
261 # endif
262 default:
264 unsigned long int type = statfsbuf->f_type;
265 static char buf[sizeof "UNKNOWN (0x%lx)" - 3
266 + (sizeof type * CHAR_BIT + 3) / 4];
267 sprintf (buf, "UNKNOWN (0x%lx)", type);
268 return buf;
271 #endif
274 static char *
275 human_access (struct stat const *statbuf)
277 static char modebuf[11];
278 mode_string (statbuf->st_mode, modebuf);
279 modebuf[10] = 0;
280 return modebuf;
283 static char *
284 human_time (struct timespec t)
286 static char str[MAX (INT_BUFSIZE_BOUND (intmax_t),
287 (INT_STRLEN_BOUND (int) /* YYYY */
288 + 1 /* because YYYY might equal INT_MAX + 1900 */
289 + sizeof "-MM-DD HH:MM:SS.NNNNNNNNN +ZZZZ"))];
290 struct tm const *tm = localtime (&t.tv_sec);
291 if (tm == NULL)
292 return (TYPE_SIGNED (time_t)
293 ? imaxtostr (t.tv_sec, str)
294 : umaxtostr (t.tv_sec, str));
295 nstrftime (str, sizeof str, "%Y-%m-%d %H:%M:%S.%N %z", tm, 0, t.tv_nsec);
296 return str;
299 /* Like strcat, but don't return anything and do check that
300 DEST_BUFSIZE is at least a long as strlen (DEST) + strlen (SRC) + 1.
301 The signature is deliberately different from that of strncat. */
302 static void
303 xstrcat (char *dest, size_t dest_bufsize, char const *src)
305 size_t dest_len = strlen (dest);
306 size_t src_len = strlen (src);
307 if (dest_bufsize < dest_len + src_len + 1)
308 abort ();
309 memcpy (dest + dest_len, src, src_len + 1);
312 /* print statfs info */
313 static void
314 print_statfs (char *pformat, size_t buf_len, char m, char const *filename,
315 void const *data)
317 STRUCT_STATVFS const *statfsbuf = data;
319 switch (m)
321 case 'n':
322 xstrcat (pformat, buf_len, "s");
323 printf (pformat, filename);
324 break;
326 case 'i':
327 #if HAVE_STRUCT_STATXFS_F_FSID___VAL
328 xstrcat (pformat, buf_len, "x %-8x");
329 printf (pformat, statfsbuf->f_fsid.__val[0], /* u_long */
330 statfsbuf->f_fsid.__val[1]);
331 #else
332 xstrcat (pformat, buf_len, "Lx");
333 printf (pformat, statfsbuf->f_fsid);
334 #endif
335 break;
337 case 'l':
338 xstrcat (pformat, buf_len, NAMEMAX_FORMAT);
339 printf (pformat, SB_F_NAMEMAX (statfsbuf));
340 break;
341 case 't':
342 #if HAVE_STRUCT_STATXFS_F_TYPE
343 xstrcat (pformat, buf_len, "lx");
344 printf (pformat,
345 (unsigned long int) (statfsbuf->f_type)); /* no equiv. */
346 #else
347 fputc ('*', stdout);
348 #endif
349 break;
350 case 'T':
351 xstrcat (pformat, buf_len, "s");
352 printf (pformat, human_fstype (statfsbuf));
353 break;
354 case 'b':
355 xstrcat (pformat, buf_len, PRIdMAX);
356 printf (pformat, (intmax_t) (statfsbuf->f_blocks));
357 break;
358 case 'f':
359 xstrcat (pformat, buf_len, PRIdMAX);
360 printf (pformat, (intmax_t) (statfsbuf->f_bfree));
361 break;
362 case 'a':
363 xstrcat (pformat, buf_len, PRIdMAX);
364 printf (pformat, (intmax_t) (statfsbuf->f_bavail));
365 break;
366 case 's':
367 xstrcat (pformat, buf_len, "lu");
368 printf (pformat, (unsigned long int) (statfsbuf->f_bsize));
369 break;
370 case 'S':
372 unsigned long int frsize = STATFS_FRSIZE (statfsbuf);
373 if (! frsize)
374 frsize = statfsbuf->f_bsize;
375 xstrcat (pformat, buf_len, "lu");
376 printf (pformat, frsize);
378 break;
379 case 'c':
380 xstrcat (pformat, buf_len, PRIdMAX);
381 printf (pformat, (intmax_t) (statfsbuf->f_files));
382 break;
383 case 'd':
384 xstrcat (pformat, buf_len, PRIdMAX);
385 printf (pformat, (intmax_t) (statfsbuf->f_ffree));
386 break;
388 default:
389 xstrcat (pformat, buf_len, "c");
390 printf (pformat, m);
391 break;
395 /* print stat info */
396 static void
397 print_stat (char *pformat, size_t buf_len, char m,
398 char const *filename, void const *data)
400 struct stat *statbuf = (struct stat *) data;
401 struct passwd *pw_ent;
402 struct group *gw_ent;
404 switch (m)
406 case 'n':
407 xstrcat (pformat, buf_len, "s");
408 printf (pformat, filename);
409 break;
410 case 'N':
411 xstrcat (pformat, buf_len, "s");
412 if (S_ISLNK (statbuf->st_mode))
414 char *linkname = xreadlink (filename, statbuf->st_size);
415 if (linkname == NULL)
417 error (0, errno, _("cannot read symbolic link %s"),
418 quote (filename));
419 return;
421 /*printf("\"%s\" -> \"%s\"", filename, linkname); */
422 printf (pformat, quote (filename));
423 printf (" -> ");
424 printf (pformat, quote (linkname));
426 else
428 printf (pformat, quote (filename));
430 break;
431 case 'd':
432 xstrcat (pformat, buf_len, PRIuMAX);
433 printf (pformat, (uintmax_t) statbuf->st_dev);
434 break;
435 case 'D':
436 xstrcat (pformat, buf_len, PRIxMAX);
437 printf (pformat, (uintmax_t) statbuf->st_dev);
438 break;
439 case 'i':
440 xstrcat (pformat, buf_len, PRIuMAX);
441 printf (pformat, (uintmax_t) statbuf->st_ino);
442 break;
443 case 'a':
444 xstrcat (pformat, buf_len, "lo");
445 printf (pformat,
446 (unsigned long int) (statbuf->st_mode & CHMOD_MODE_BITS));
447 break;
448 case 'A':
449 xstrcat (pformat, buf_len, "s");
450 printf (pformat, human_access (statbuf));
451 break;
452 case 'f':
453 xstrcat (pformat, buf_len, "lx");
454 printf (pformat, (unsigned long int) statbuf->st_mode);
455 break;
456 case 'F':
457 xstrcat (pformat, buf_len, "s");
458 printf (pformat, file_type (statbuf));
459 break;
460 case 'h':
461 xstrcat (pformat, buf_len, "lu");
462 printf (pformat, (unsigned long int) statbuf->st_nlink);
463 break;
464 case 'u':
465 xstrcat (pformat, buf_len, "lu");
466 printf (pformat, (unsigned long int) statbuf->st_uid);
467 break;
468 case 'U':
469 xstrcat (pformat, buf_len, "s");
470 setpwent ();
471 pw_ent = getpwuid (statbuf->st_uid);
472 printf (pformat, (pw_ent != 0L) ? pw_ent->pw_name : "UNKNOWN");
473 break;
474 case 'g':
475 xstrcat (pformat, buf_len, "lu");
476 printf (pformat, (unsigned long int) statbuf->st_gid);
477 break;
478 case 'G':
479 xstrcat (pformat, buf_len, "s");
480 setgrent ();
481 gw_ent = getgrgid (statbuf->st_gid);
482 printf (pformat, (gw_ent != 0L) ? gw_ent->gr_name : "UNKNOWN");
483 break;
484 case 't':
485 xstrcat (pformat, buf_len, "lx");
486 printf (pformat, (unsigned long int) major (statbuf->st_rdev));
487 break;
488 case 'T':
489 xstrcat (pformat, buf_len, "lx");
490 printf (pformat, (unsigned long int) minor (statbuf->st_rdev));
491 break;
492 case 's':
493 xstrcat (pformat, buf_len, PRIuMAX);
494 printf (pformat, (uintmax_t) (statbuf->st_size));
495 break;
496 case 'B':
497 xstrcat (pformat, buf_len, "lu");
498 printf (pformat, (unsigned long int) ST_NBLOCKSIZE);
499 break;
500 case 'b':
501 xstrcat (pformat, buf_len, PRIuMAX);
502 printf (pformat, (uintmax_t) ST_NBLOCKS (*statbuf));
503 break;
504 case 'o':
505 xstrcat (pformat, buf_len, "lu");
506 printf (pformat, (unsigned long int) statbuf->st_blksize);
507 break;
508 case 'x':
509 xstrcat (pformat, buf_len, "s");
510 printf (pformat, human_time (get_stat_atime (statbuf)));
511 break;
512 case 'X':
513 xstrcat (pformat, buf_len, TYPE_SIGNED (time_t) ? "ld" : "lu");
514 printf (pformat, (unsigned long int) statbuf->st_atime);
515 break;
516 case 'y':
517 xstrcat (pformat, buf_len, "s");
518 printf (pformat, human_time (get_stat_mtime (statbuf)));
519 break;
520 case 'Y':
521 xstrcat (pformat, buf_len, TYPE_SIGNED (time_t) ? "ld" : "lu");
522 printf (pformat, (unsigned long int) statbuf->st_mtime);
523 break;
524 case 'z':
525 xstrcat (pformat, buf_len, "s");
526 printf (pformat, human_time (get_stat_ctime (statbuf)));
527 break;
528 case 'Z':
529 xstrcat (pformat, buf_len, TYPE_SIGNED (time_t) ? "ld" : "lu");
530 printf (pformat, (unsigned long int) statbuf->st_ctime);
531 break;
532 default:
533 xstrcat (pformat, buf_len, "c");
534 printf (pformat, m);
535 break;
539 static void
540 print_it (char const *masterformat, char const *filename,
541 void (*print_func) (char *, size_t, char, char const *, void const *),
542 void const *data)
544 char *b;
546 /* create a working copy of the format string */
547 char *format = xstrdup (masterformat);
549 /* Add 2 to accommodate our conversion of the stat `%s' format string
550 to the printf `%llu' one. */
551 size_t n_alloc = strlen (format) + 2 + 1;
552 char *dest = xmalloc (n_alloc);
554 b = format;
555 while (b)
557 char *p = strchr (b, '%');
558 if (p != NULL)
560 size_t len;
561 *p++ = '\0';
562 fputs (b, stdout);
564 len = strspn (p, "#-+.I 0123456789");
565 dest[0] = '%';
566 memcpy (dest + 1, p, len);
567 dest[1 + len] = 0;
568 p += len;
570 b = p + 1;
571 switch (*p)
573 case '\0':
574 b = NULL;
575 /* fall through */
576 case '%':
577 putchar ('%');
578 break;
579 default:
580 print_func (dest, n_alloc, *p, filename, data);
581 break;
584 else
586 fputs (b, stdout);
587 b = NULL;
590 free (format);
591 free (dest);
594 /* Stat the file system and print what we find. */
595 static bool
596 do_statfs (char const *filename, bool terse, char const *format)
598 STRUCT_STATVFS statfsbuf;
600 if (STATFS (filename, &statfsbuf) != 0)
602 error (0, errno, _("cannot read file system information for %s"),
603 quote (filename));
604 return false;
607 if (format == NULL)
609 format = (terse
610 ? "%n %i %l %t %s %S %b %f %a %c %d\n"
611 : " File: \"%n\"\n"
612 " ID: %-8i Namelen: %-7l Type: %T\n"
613 "Block size: %-10s Fundamental block size: %S\n"
614 "Blocks: Total: %-10b Free: %-10f Available: %a\n"
615 "Inodes: Total: %-10c Free: %d\n");
618 print_it (format, filename, print_statfs, &statfsbuf);
619 return true;
622 /* stat the file and print what we find */
623 static bool
624 do_stat (char const *filename, bool follow_links, bool terse,
625 char const *format)
627 struct stat statbuf;
629 if ((follow_links ? stat : lstat) (filename, &statbuf) != 0)
631 error (0, errno, _("cannot stat %s"), quote (filename));
632 return false;
635 if (format == NULL)
637 if (terse)
639 format = "%n %s %b %f %u %g %D %i %h %t %T %X %Y %Z %o\n";
641 else
643 /* Temporary hack to match original output until conditional
644 implemented. */
645 if (S_ISBLK (statbuf.st_mode) || S_ISCHR (statbuf.st_mode))
647 format =
648 " File: %N\n"
649 " Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n"
650 "Device: %Dh/%dd\tInode: %-10i Links: %-5h"
651 " Device type: %t,%T\n"
652 "Access: (%04a/%10.10A) Uid: (%5u/%8U) Gid: (%5g/%8G)\n"
653 "Access: %x\n" "Modify: %y\n" "Change: %z\n";
655 else
657 format =
658 " File: %N\n"
659 " Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n"
660 "Device: %Dh/%dd\tInode: %-10i Links: %h\n"
661 "Access: (%04a/%10.10A) Uid: (%5u/%8U) Gid: (%5g/%8G)\n"
662 "Access: %x\n" "Modify: %y\n" "Change: %z\n";
666 print_it (format, filename, print_stat, &statbuf);
667 return true;
670 void
671 usage (int status)
673 if (status != EXIT_SUCCESS)
674 fprintf (stderr, _("Try `%s --help' for more information.\n"),
675 program_name);
676 else
678 printf (_("Usage: %s [OPTION] FILE...\n"), program_name);
679 fputs (_("\
680 Display file or file system status.\n\
682 -f, --file-system display file system status instead of file status\n\
683 -c --format=FORMAT use the specified FORMAT instead of the default\n\
684 -L, --dereference follow links\n\
685 -t, --terse print the information in terse form\n\
686 "), stdout);
687 fputs (HELP_OPTION_DESCRIPTION, stdout);
688 fputs (VERSION_OPTION_DESCRIPTION, stdout);
690 fputs (_("\n\
691 The valid format sequences for files (without --file-system):\n\
693 %a Access rights in octal\n\
694 %A Access rights in human readable form\n\
695 %b Number of blocks allocated (see %B)\n\
696 %B The size in bytes of each block reported by %b\n\
697 "), stdout);
698 fputs (_("\
699 %d Device number in decimal\n\
700 %D Device number in hex\n\
701 %f Raw mode in hex\n\
702 %F File type\n\
703 %g Group ID of owner\n\
704 %G Group name of owner\n\
705 "), stdout);
706 fputs (_("\
707 %h Number of hard links\n\
708 %i Inode number\n\
709 %n File name\n\
710 %N Quoted file name with dereference if symbolic link\n\
711 %o I/O block size\n\
712 %s Total size, in bytes\n\
713 %t Major device type in hex\n\
714 %T Minor device type in hex\n\
715 "), stdout);
716 fputs (_("\
717 %u User ID of owner\n\
718 %U User name of owner\n\
719 %x Time of last access\n\
720 %X Time of last access as seconds since Epoch\n\
721 %y Time of last modification\n\
722 %Y Time of last modification as seconds since Epoch\n\
723 %z Time of last change\n\
724 %Z Time of last change as seconds since Epoch\n\
726 "), stdout);
728 fputs (_("\
729 Valid format sequences for file systems:\n\
731 %a Free blocks available to non-superuser\n\
732 %b Total data blocks in file system\n\
733 %c Total file nodes in file system\n\
734 %d Free file nodes in file system\n\
735 %f Free blocks in file system\n\
736 "), stdout);
737 fputs (_("\
738 %i File System ID in hex\n\
739 %l Maximum length of filenames\n\
740 %n File name\n\
741 %s Block size (for faster transfers)\n\
742 %S Fundamental block size (for block counts)\n\
743 %t Type in hex\n\
744 %T Type in human readable form\n\
745 "), stdout);
746 printf (USAGE_BUILTIN_WARNING, PROGRAM_NAME);
747 printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
749 exit (status);
753 main (int argc, char *argv[])
755 int c;
756 int i;
757 bool follow_links = false;
758 bool fs = false;
759 bool terse = false;
760 char *format = NULL;
761 bool ok = true;
763 initialize_main (&argc, &argv);
764 program_name = argv[0];
765 setlocale (LC_ALL, "");
766 bindtextdomain (PACKAGE, LOCALEDIR);
767 textdomain (PACKAGE);
769 atexit (close_stdout);
771 while ((c = getopt_long (argc, argv, "c:fLlt", long_options, NULL)) != -1)
773 switch (c)
775 case 'c':
776 format = optarg;
777 break;
779 case 'l': /* deprecated */
780 error (0, 0, _("Warning: `-l' is deprecated; use `-L' instead"));
781 /* fall through */
782 case 'L':
783 follow_links = true;
784 break;
786 case 'f':
787 fs = true;
788 break;
790 case 't':
791 terse = true;
792 break;
794 case_GETOPT_HELP_CHAR;
796 case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
798 default:
799 usage (EXIT_FAILURE);
803 if (argc == optind)
805 error (0, 0, _("missing operand"));
806 usage (EXIT_FAILURE);
809 for (i = optind; i < argc; i++)
810 ok &= (fs
811 ? do_statfs (argv[i], terse, format)
812 : do_stat (argv[i], follow_links, terse, format));
814 exit (ok ? EXIT_SUCCESS : EXIT_FAILURE);