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)
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. */
23 #include <sys/types.h>
26 #if HAVE_SYS_STATVFS_H && HAVE_STRUCT_STATVFS_F_BASETYPE
27 # include <sys/statvfs.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>
49 #include "file-type.h"
55 #include "stat-time.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))
68 # define STATFS statvfs
69 # define STATFS_FRSIZE(S) ((S)->f_frsize)
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))
80 # define STATFS statfs
81 # define STATFS_FRSIZE(S) 0
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"
91 #if HAVE_STRUCT_STATVFS_F_BASETYPE
92 # define STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME f_basetype
94 # if HAVE_STRUCT_STATFS_F_FSTYPENAME
95 # define STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME f_fstypename
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
},
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). */
122 human_fstype (STRUCT_STATVFS
const *statfsbuf
)
124 #ifdef STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME
125 return statfsbuf
->STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME
;
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 */
138 case S_MAGIC_DEVPTS
: /* 0x1CD1 */
140 case S_MAGIC_EXT
: /* 0x137D */
142 case S_MAGIC_EXT2_OLD
: /* 0xEF51 */
144 case S_MAGIC_EXT2
: /* 0xEF53 */
146 case S_MAGIC_JFS
: /* 0x3153464a */
148 case S_MAGIC_XFS
: /* 0x58465342 */
150 case S_MAGIC_HPFS
: /* 0xF995E849 */
152 case S_MAGIC_ISOFS
: /* 0x9660 */
154 case S_MAGIC_ISOFS_WIN
: /* 0x4000 */
156 case S_MAGIC_ISOFS_R_WIN
: /* 0x4004 */
158 case S_MAGIC_MINIX
: /* 0x137F */
160 case S_MAGIC_MINIX_30
: /* 0x138F */
161 return "minix (30 char.)";
162 case S_MAGIC_MINIX_V2
: /* 0x2468 */
164 case S_MAGIC_MINIX_V2_30
: /* 0x2478 */
165 return "minix v2 (30 char.)";
166 case S_MAGIC_MSDOS
: /* 0x4d44 */
168 case S_MAGIC_FAT
: /* 0x4006 */
170 case S_MAGIC_NCP
: /* 0x564c */
172 case S_MAGIC_NFS
: /* 0x6969 */
174 case S_MAGIC_PROC
: /* 0x9fa0 */
176 case S_MAGIC_SMB
: /* 0x517B */
178 case S_MAGIC_XENIX
: /* 0x012FF7B4 */
180 case S_MAGIC_SYSV4
: /* 0x012FF7B5 */
182 case S_MAGIC_SYSV2
: /* 0x012FF7B6 */
184 case S_MAGIC_COH
: /* 0x012FF7B7 */
186 case S_MAGIC_UFS
: /* 0x00011954 */
188 case S_MAGIC_XIAFS
: /* 0x012FD16D */
190 case S_MAGIC_NTFS
: /* 0x5346544e */
192 case S_MAGIC_TMPFS
: /* 0x1021994 */
194 case S_MAGIC_REISERFS
: /* 0x52654973 */
196 case S_MAGIC_CRAMFS
: /* 0x28cd3d45 */
198 case S_MAGIC_ROMFS
: /* 0x7275 */
200 case S_MAGIC_RAMFS
: /* 0x858458f6 */
202 case S_MAGIC_SQUASHFS
: /* 0x73717368 */
204 case S_MAGIC_SYSFS
: /* 0x62656572 */
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
);
275 human_access (struct stat
const *statbuf
)
277 static char modebuf
[11];
278 mode_string (statbuf
->st_mode
, modebuf
);
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
);
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
);
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. */
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)
309 memcpy (dest
+ dest_len
, src
, src_len
+ 1);
312 /* print statfs info */
314 print_statfs (char *pformat
, size_t buf_len
, char m
, char const *filename
,
317 STRUCT_STATVFS
const *statfsbuf
= data
;
322 xstrcat (pformat
, buf_len
, "s");
323 printf (pformat
, filename
);
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]);
332 xstrcat (pformat
, buf_len
, "Lx");
333 printf (pformat
, statfsbuf
->f_fsid
);
338 xstrcat (pformat
, buf_len
, NAMEMAX_FORMAT
);
339 printf (pformat
, SB_F_NAMEMAX (statfsbuf
));
342 #if HAVE_STRUCT_STATXFS_F_TYPE
343 xstrcat (pformat
, buf_len
, "lx");
345 (unsigned long int) (statfsbuf
->f_type
)); /* no equiv. */
351 xstrcat (pformat
, buf_len
, "s");
352 printf (pformat
, human_fstype (statfsbuf
));
355 xstrcat (pformat
, buf_len
, PRIdMAX
);
356 printf (pformat
, (intmax_t) (statfsbuf
->f_blocks
));
359 xstrcat (pformat
, buf_len
, PRIdMAX
);
360 printf (pformat
, (intmax_t) (statfsbuf
->f_bfree
));
363 xstrcat (pformat
, buf_len
, PRIdMAX
);
364 printf (pformat
, (intmax_t) (statfsbuf
->f_bavail
));
367 xstrcat (pformat
, buf_len
, "lu");
368 printf (pformat
, (unsigned long int) (statfsbuf
->f_bsize
));
372 unsigned long int frsize
= STATFS_FRSIZE (statfsbuf
);
374 frsize
= statfsbuf
->f_bsize
;
375 xstrcat (pformat
, buf_len
, "lu");
376 printf (pformat
, frsize
);
380 xstrcat (pformat
, buf_len
, PRIdMAX
);
381 printf (pformat
, (intmax_t) (statfsbuf
->f_files
));
384 xstrcat (pformat
, buf_len
, PRIdMAX
);
385 printf (pformat
, (intmax_t) (statfsbuf
->f_ffree
));
389 xstrcat (pformat
, buf_len
, "c");
395 /* print stat info */
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
;
407 xstrcat (pformat
, buf_len
, "s");
408 printf (pformat
, filename
);
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"),
421 /*printf("\"%s\" -> \"%s\"", filename, linkname); */
422 printf (pformat
, quote (filename
));
424 printf (pformat
, quote (linkname
));
428 printf (pformat
, quote (filename
));
432 xstrcat (pformat
, buf_len
, PRIuMAX
);
433 printf (pformat
, (uintmax_t) statbuf
->st_dev
);
436 xstrcat (pformat
, buf_len
, PRIxMAX
);
437 printf (pformat
, (uintmax_t) statbuf
->st_dev
);
440 xstrcat (pformat
, buf_len
, PRIuMAX
);
441 printf (pformat
, (uintmax_t) statbuf
->st_ino
);
444 xstrcat (pformat
, buf_len
, "lo");
446 (unsigned long int) (statbuf
->st_mode
& CHMOD_MODE_BITS
));
449 xstrcat (pformat
, buf_len
, "s");
450 printf (pformat
, human_access (statbuf
));
453 xstrcat (pformat
, buf_len
, "lx");
454 printf (pformat
, (unsigned long int) statbuf
->st_mode
);
457 xstrcat (pformat
, buf_len
, "s");
458 printf (pformat
, file_type (statbuf
));
461 xstrcat (pformat
, buf_len
, "lu");
462 printf (pformat
, (unsigned long int) statbuf
->st_nlink
);
465 xstrcat (pformat
, buf_len
, "lu");
466 printf (pformat
, (unsigned long int) statbuf
->st_uid
);
469 xstrcat (pformat
, buf_len
, "s");
471 pw_ent
= getpwuid (statbuf
->st_uid
);
472 printf (pformat
, (pw_ent
!= 0L) ? pw_ent
->pw_name
: "UNKNOWN");
475 xstrcat (pformat
, buf_len
, "lu");
476 printf (pformat
, (unsigned long int) statbuf
->st_gid
);
479 xstrcat (pformat
, buf_len
, "s");
481 gw_ent
= getgrgid (statbuf
->st_gid
);
482 printf (pformat
, (gw_ent
!= 0L) ? gw_ent
->gr_name
: "UNKNOWN");
485 xstrcat (pformat
, buf_len
, "lx");
486 printf (pformat
, (unsigned long int) major (statbuf
->st_rdev
));
489 xstrcat (pformat
, buf_len
, "lx");
490 printf (pformat
, (unsigned long int) minor (statbuf
->st_rdev
));
493 xstrcat (pformat
, buf_len
, PRIuMAX
);
494 printf (pformat
, (uintmax_t) (statbuf
->st_size
));
497 xstrcat (pformat
, buf_len
, "lu");
498 printf (pformat
, (unsigned long int) ST_NBLOCKSIZE
);
501 xstrcat (pformat
, buf_len
, PRIuMAX
);
502 printf (pformat
, (uintmax_t) ST_NBLOCKS (*statbuf
));
505 xstrcat (pformat
, buf_len
, "lu");
506 printf (pformat
, (unsigned long int) statbuf
->st_blksize
);
509 xstrcat (pformat
, buf_len
, "s");
510 printf (pformat
, human_time (get_stat_atime (statbuf
)));
513 xstrcat (pformat
, buf_len
, TYPE_SIGNED (time_t) ? "ld" : "lu");
514 printf (pformat
, (unsigned long int) statbuf
->st_atime
);
517 xstrcat (pformat
, buf_len
, "s");
518 printf (pformat
, human_time (get_stat_mtime (statbuf
)));
521 xstrcat (pformat
, buf_len
, TYPE_SIGNED (time_t) ? "ld" : "lu");
522 printf (pformat
, (unsigned long int) statbuf
->st_mtime
);
525 xstrcat (pformat
, buf_len
, "s");
526 printf (pformat
, human_time (get_stat_ctime (statbuf
)));
529 xstrcat (pformat
, buf_len
, TYPE_SIGNED (time_t) ? "ld" : "lu");
530 printf (pformat
, (unsigned long int) statbuf
->st_ctime
);
533 xstrcat (pformat
, buf_len
, "c");
540 print_it (char const *masterformat
, char const *filename
,
541 void (*print_func
) (char *, size_t, char, char const *, void const *),
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
);
557 char *p
= strchr (b
, '%');
564 len
= strspn (p
, "#-+.I 0123456789");
566 memcpy (dest
+ 1, p
, len
);
580 print_func (dest
, n_alloc
, *p
, filename
, data
);
594 /* Stat the file system and print what we find. */
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"),
610 ? "%n %i %l %t %s %S %b %f %a %c %d\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
);
622 /* stat the file and print what we find */
624 do_stat (char const *filename
, bool follow_links
, bool terse
,
629 if ((follow_links
? stat
: lstat
) (filename
, &statbuf
) != 0)
631 error (0, errno
, _("cannot stat %s"), quote (filename
));
639 format
= "%n %s %b %f %u %g %D %i %h %t %T %X %Y %Z %o\n";
643 /* Temporary hack to match original output until conditional
645 if (S_ISBLK (statbuf
.st_mode
) || S_ISCHR (statbuf
.st_mode
))
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";
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
);
673 if (status
!= EXIT_SUCCESS
)
674 fprintf (stderr
, _("Try `%s --help' for more information.\n"),
678 printf (_("Usage: %s [OPTION] FILE...\n"), program_name
);
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\
687 fputs (HELP_OPTION_DESCRIPTION
, stdout
);
688 fputs (VERSION_OPTION_DESCRIPTION
, stdout
);
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\
699 %d Device number in decimal\n\
700 %D Device number in hex\n\
701 %f Raw mode in hex\n\
703 %g Group ID of owner\n\
704 %G Group name of owner\n\
707 %h Number of hard links\n\
710 %N Quoted file name with dereference if symbolic link\n\
712 %s Total size, in bytes\n\
713 %t Major device type in hex\n\
714 %T Minor device type in hex\n\
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\
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\
738 %i File System ID in hex\n\
739 %l Maximum length of filenames\n\
741 %s Block size (for faster transfers)\n\
742 %S Fundamental block size (for block counts)\n\
744 %T Type in human readable form\n\
746 printf (USAGE_BUILTIN_WARNING
, PROGRAM_NAME
);
747 printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT
);
753 main (int argc
, char *argv
[])
757 bool follow_links
= false;
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)
779 case 'l': /* deprecated */
780 error (0, 0, _("Warning: `-l' is deprecated; use `-L' instead"));
794 case_GETOPT_HELP_CHAR
;
796 case_GETOPT_VERSION_CHAR (PROGRAM_NAME
, AUTHORS
);
799 usage (EXIT_FAILURE
);
805 error (0, 0, _("missing operand"));
806 usage (EXIT_FAILURE
);
809 for (i
= optind
; i
< argc
; i
++)
811 ? do_statfs (argv
[i
], terse
, format
)
812 : do_stat (argv
[i
], follow_links
, terse
, format
));
814 exit (ok
? EXIT_SUCCESS
: EXIT_FAILURE
);