1 /* stat.c -- display file or filesystem status
2 Copyright (C) 2001, 2002, 2003, 2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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"
56 #include "xreadlink.h"
58 #define NAMEMAX_FORMAT PRIuMAX
60 #if HAVE_STRUCT_STATVFS_F_BASETYPE
61 # define STRUCT_STATVFS struct statvfs
62 # define HAVE_STRUCT_STATXFS_F_TYPE HAVE_STRUCT_STATVFS
63 # if HAVE_STRUCT_STATVFS_F_NAMEMAX
64 # define SB_F_NAMEMAX(S) ((uintmax_t) ((S)->f_namemax))
67 # define STRUCT_STATVFS struct statfs
68 # define HAVE_STRUCT_STATXFS_F_TYPE HAVE_STRUCT_STATFS
69 # if HAVE_STRUCT_STATFS_F_NAMELEN
70 # define SB_F_NAMEMAX(S) ((uintmax_t) ((S)->f_namelen))
75 /* NetBSD 1.5.2 has neither f_namemax nor f_namelen. */
76 # define SB_F_NAMEMAX(S) "*"
77 # undef NAMEMAX_FORMAT
78 # define NAMEMAX_FORMAT "s"
81 #if HAVE_STRUCT_STATVFS_F_BASETYPE
82 # define STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME f_basetype
84 # if HAVE_STRUCT_STATFS_F_FSTYPENAME
85 # define STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME f_fstypename
89 #define PROGRAM_NAME "stat"
91 #define AUTHORS "Michael Meskes"
93 static struct option
const long_options
[] = {
94 {"link", no_argument
, 0, 'l'}, /* deprecated. FIXME: remove in 2003 */
95 {"dereference", no_argument
, 0, 'L'},
96 {"format", required_argument
, 0, 'c'},
97 {"filesystem", no_argument
, 0, 'f'},
98 {"terse", no_argument
, 0, 't'},
99 {GETOPT_HELP_OPTION_DECL
},
100 {GETOPT_VERSION_OPTION_DECL
},
104 /* Nonzero means we should exit with EXIT_FAILURE upon completion. */
109 /* Return the type of the specified file system.
110 Some systems have statfvs.f_basetype[FSTYPSZ]. (AIX, HP-UX, and Solaris)
111 Others have statfs.f_fstypename[MFSNAMELEN]. (NetBSD 1.5.2)
112 Still others have neither and have to get by with f_type (Linux). */
114 human_fstype (STRUCT_STATVFS
const *statfsbuf
)
116 #ifdef STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME
117 /* Cast away the `const' attribute. */
118 return (char *) statfsbuf
->STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME
;
121 switch (statfsbuf
->f_type
)
123 # if defined __linux__
125 /* IMPORTANT NOTE: Each of the following `case S_MAGIC_...:'
126 statements must be followed by a hexadecimal constant in
127 a comment. The S_MAGIC_... name and constant are automatically
128 combined to produce the #define directives in fs.h. */
130 case S_MAGIC_AFFS
: /* 0xADFF */
133 case S_MAGIC_DEVPTS
: /* 0x1CD1 */
136 case S_MAGIC_EXT
: /* 0x137D */
139 case S_MAGIC_EXT2_OLD
: /* 0xEF51 */
142 case S_MAGIC_EXT2
: /* 0xEF53 */
145 case S_MAGIC_HPFS
: /* 0xF995E849 */
148 case S_MAGIC_ISOFS
: /* 0x9660 */
151 case S_MAGIC_ISOFS_WIN
: /* 0x4000 */
154 case S_MAGIC_ISOFS_R_WIN
: /* 0x4004 */
157 case S_MAGIC_MINIX
: /* 0x137F */
160 case S_MAGIC_MINIX_30
: /* 0x138F */
161 type
= "minix (30 char.)";
163 case S_MAGIC_MINIX_V2
: /* 0x2468 */
166 case S_MAGIC_MINIX_V2_30
: /* 0x2478 */
167 type
= "minix v2 (30 char.)";
169 case S_MAGIC_MSDOS
: /* 0x4d44 */
172 case S_MAGIC_FAT
: /* 0x4006 */
175 case S_MAGIC_NCP
: /* 0x564c */
178 case S_MAGIC_NFS
: /* 0x6969 */
181 case S_MAGIC_PROC
: /* 0x9fa0 */
184 case S_MAGIC_SMB
: /* 0x517B */
187 case S_MAGIC_XENIX
: /* 0x012FF7B4 */
190 case S_MAGIC_SYSV4
: /* 0x012FF7B5 */
193 case S_MAGIC_SYSV2
: /* 0x012FF7B6 */
196 case S_MAGIC_COH
: /* 0x012FF7B7 */
199 case S_MAGIC_UFS
: /* 0x00011954 */
202 case S_MAGIC_XIAFS
: /* 0x012FD16D */
205 case S_MAGIC_NTFS
: /* 0x5346544e */
208 case S_MAGIC_TMPFS
: /* 0x1021994 */
211 case S_MAGIC_REISERFS
: /* 0x52654973 */
214 case S_MAGIC_CRAMFS
: /* 0x28cd3d45 */
217 case S_MAGIC_ROMFS
: /* 0x7275 */
309 return (char *) type
;
312 static char buf
[sizeof "UNKNOWN (0x%lx)" - 3
313 + 2 * sizeof (statfsbuf
->f_type
)];
314 sprintf (buf
, "UNKNOWN (0x%lx)", (unsigned long) statfsbuf
->f_type
);
321 human_access (struct stat
const *statbuf
)
323 static char modebuf
[11];
324 mode_string (statbuf
->st_mode
, modebuf
);
330 human_time (time_t t
, int t_ns
)
332 static char str
[MAX (INT_BUFSIZE_BOUND (intmax_t),
333 (INT_STRLEN_BOUND (int) /* YYYY */
334 + 1 /* because YYYY might equal INT_MAX + 1900 */
335 + sizeof "-MM-DD HH:MM:SS.NNNNNNNNN +ZZZZ"))];
336 struct tm
const *tm
= localtime (&t
);
338 return (TYPE_SIGNED (time_t)
340 : umaxtostr (t
, str
));
341 nstrftime (str
, sizeof str
, "%Y-%m-%d %H:%M:%S.%N %z", tm
, 0, t_ns
);
345 /* print statfs info */
347 print_statfs (char *pformat
, char m
, char const *filename
,
350 STRUCT_STATVFS
const *statfsbuf
= data
;
355 strcat (pformat
, "s");
356 printf (pformat
, filename
);
360 #if HAVE_STRUCT_STATXFS_F_FSID___VAL
361 strcat (pformat
, "x %-8x");
362 printf (pformat
, statfsbuf
->f_fsid
.__val
[0], /* u_long */
363 statfsbuf
->f_fsid
.__val
[1]);
365 strcat (pformat
, "Lx");
366 printf (pformat
, statfsbuf
->f_fsid
);
371 strcat (pformat
, NAMEMAX_FORMAT
);
372 printf (pformat
, SB_F_NAMEMAX (statfsbuf
));
375 #if HAVE_STRUCT_STATXFS_F_TYPE
376 strcat (pformat
, "lx");
377 printf (pformat
, (long int) (statfsbuf
->f_type
)); /* no equiv. */
383 strcat (pformat
, "s");
384 printf (pformat
, human_fstype (statfsbuf
));
387 strcat (pformat
, PRIdMAX
);
388 printf (pformat
, (intmax_t) (statfsbuf
->f_blocks
));
391 strcat (pformat
, PRIdMAX
);
392 printf (pformat
, (intmax_t) (statfsbuf
->f_bfree
));
395 strcat (pformat
, PRIdMAX
);
396 printf (pformat
, (intmax_t) (statfsbuf
->f_bavail
));
399 strcat (pformat
, "ld");
400 printf (pformat
, (long int) (statfsbuf
->f_bsize
));
403 strcat (pformat
, PRIdMAX
);
404 printf (pformat
, (intmax_t) (statfsbuf
->f_files
));
407 strcat (pformat
, PRIdMAX
);
408 printf (pformat
, (intmax_t) (statfsbuf
->f_ffree
));
412 strcat (pformat
, "c");
418 /* print stat info */
420 print_stat (char *pformat
, char m
, char const *filename
, void const *data
)
422 struct stat
*statbuf
= (struct stat
*) data
;
423 struct passwd
*pw_ent
;
424 struct group
*gw_ent
;
429 strcat (pformat
, "s");
430 printf (pformat
, filename
);
433 strcat (pformat
, "s");
434 if (S_ISLNK (statbuf
->st_mode
))
436 char *linkname
= xreadlink (filename
);
437 if (linkname
== NULL
)
439 error (0, errno
, _("cannot read symbolic link %s"),
443 /*printf("\"%s\" -> \"%s\"", filename, linkname); */
444 printf (pformat
, quote (filename
));
446 printf (pformat
, quote (linkname
));
450 printf (pformat
, quote (filename
));
454 strcat (pformat
, "d");
455 printf (pformat
, (int) statbuf
->st_dev
);
458 strcat (pformat
, "x");
459 printf (pformat
, (int) statbuf
->st_dev
);
462 strcat (pformat
, "d");
463 printf (pformat
, (int) statbuf
->st_ino
);
466 strcat (pformat
, "o");
467 printf (pformat
, statbuf
->st_mode
& 07777);
470 strcat (pformat
, "s");
471 printf (pformat
, human_access (statbuf
));
474 strcat (pformat
, "x");
475 printf (pformat
, statbuf
->st_mode
);
478 strcat (pformat
, "s");
479 printf (pformat
, file_type (statbuf
));
482 strcat (pformat
, "d");
483 printf (pformat
, (int) statbuf
->st_nlink
);
486 strcat (pformat
, "d");
487 printf (pformat
, statbuf
->st_uid
);
490 strcat (pformat
, "s");
492 pw_ent
= getpwuid (statbuf
->st_uid
);
493 printf (pformat
, (pw_ent
!= 0L) ? pw_ent
->pw_name
: "UNKNOWN");
496 strcat (pformat
, "d");
497 printf (pformat
, statbuf
->st_gid
);
500 strcat (pformat
, "s");
502 gw_ent
= getgrgid (statbuf
->st_gid
);
503 printf (pformat
, (gw_ent
!= 0L) ? gw_ent
->gr_name
: "UNKNOWN");
506 strcat (pformat
, "x");
507 printf (pformat
, major (statbuf
->st_rdev
));
510 strcat (pformat
, "x");
511 printf (pformat
, minor (statbuf
->st_rdev
));
514 strcat (pformat
, PRIuMAX
);
515 printf (pformat
, (uintmax_t) (statbuf
->st_size
));
518 strcat (pformat
, "u");
519 printf (pformat
, (unsigned int) ST_NBLOCKSIZE
);
522 strcat (pformat
, "u");
523 printf (pformat
, (unsigned int) ST_NBLOCKS (*statbuf
));
526 strcat (pformat
, "d");
527 printf (pformat
, (int) statbuf
->st_blksize
);
530 strcat (pformat
, "s");
531 printf (pformat
, human_time (statbuf
->st_atime
,
532 TIMESPEC_NS (statbuf
->st_atim
)));
535 strcat (pformat
, "d");
536 printf (pformat
, (int) statbuf
->st_atime
);
539 strcat (pformat
, "s");
540 printf (pformat
, human_time (statbuf
->st_mtime
,
541 TIMESPEC_NS (statbuf
->st_mtim
)));
544 strcat (pformat
, "d");
545 printf (pformat
, (int) statbuf
->st_mtime
);
548 strcat (pformat
, "s");
549 printf (pformat
, human_time (statbuf
->st_ctime
,
550 TIMESPEC_NS (statbuf
->st_ctim
)));
553 strcat (pformat
, "d");
554 printf (pformat
, (int) statbuf
->st_ctime
);
557 strcat (pformat
, "c");
564 print_it (char const *masterformat
, char const *filename
,
565 void (*print_func
) (char *, char, char const *, void const *),
570 /* create a working copy of the format string */
571 char *format
= xstrdup (masterformat
);
573 char *dest
= xmalloc (strlen (format
) + 1);
578 char *p
= strchr (b
, '%');
585 len
= strspn (p
, "#-+.I 0123456789");
587 memcpy (dest
+ 1, p
, len
);
601 print_func (dest
, *p
, filename
, data
);
613 fputc ('\n', stdout
);
616 /* stat the filesystem and print what we find */
618 do_statfs (char const *filename
, int terse
, char const *format
)
620 STRUCT_STATVFS statfsbuf
;
621 int i
= statfs (filename
, &statfsbuf
);
625 error (0, errno
, _("cannot read file system information for %s"),
633 ? "%n %i %l %t %b %f %a %s %c %d"
635 " ID: %-8i Namelen: %-7l Type: %T\n"
636 "Blocks: Total: %-10b Free: %-10f Available: %-10a Size: %s\n"
637 "Inodes: Total: %-10c Free: %-10d");
640 print_it (format
, filename
, print_statfs
, &statfsbuf
);
643 /* stat the file and print what we find */
645 do_stat (char const *filename
, int follow_links
, int terse
,
649 int i
= ((follow_links
== 1)
650 ? stat (filename
, &statbuf
)
651 : lstat (filename
, &statbuf
));
655 error (0, errno
, _("cannot stat %s"), quote (filename
));
663 format
= "%n %s %b %f %u %g %D %i %h %t %T %X %Y %Z %o";
667 /* tmp hack to match orignal output until conditional implemented */
668 i
= statbuf
.st_mode
& S_IFMT
;
669 if (i
== S_IFCHR
|| i
== S_IFBLK
)
673 " Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n"
674 "Device: %Dh/%dd\tInode: %-10i Links: %-5h"
675 " Device type: %t,%T\n"
676 "Access: (%04a/%10.10A) Uid: (%5u/%8U) Gid: (%5g/%8G)\n"
677 "Access: %x\n" "Modify: %y\n" "Change: %z";
683 " Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n"
684 "Device: %Dh/%dd\tInode: %-10i Links: %h\n"
685 "Access: (%04a/%10.10A) Uid: (%5u/%8U) Gid: (%5g/%8G)\n"
686 "Access: %x\n" "Modify: %y\n" "Change: %z";
690 print_it (format
, filename
, print_stat
, &statbuf
);
696 if (status
!= EXIT_SUCCESS
)
697 fprintf (stderr
, _("Try `%s --help' for more information.\n"),
701 printf (_("Usage: %s [OPTION] FILE...\n"), program_name
);
703 Display file or filesystem status.\n\
705 -f, --filesystem display filesystem status instead of file status\n\
706 -c --format=FORMAT use the specified FORMAT instead of the default\n\
707 -L, --dereference follow links\n\
708 -t, --terse print the information in terse form\n\
710 fputs (HELP_OPTION_DESCRIPTION
, stdout
);
711 fputs (VERSION_OPTION_DESCRIPTION
, stdout
);
714 The valid format sequences for files (without --filesystem):\n\
716 %A Access rights in human readable form\n\
717 %a Access rights in octal\n\
718 %B The size in bytes of each block reported by `%b'\n\
719 %b Number of blocks allocated (see %B)\n\
722 %D Device number in hex\n\
723 %d Device number in decimal\n\
725 %f Raw mode in hex\n\
726 %G Group name of owner\n\
727 %g Group ID of owner\n\
730 %h Number of hard links\n\
732 %N Quoted File name with dereference if symbolic link\n\
735 %s Total size, in bytes\n\
736 %T Minor device type in hex\n\
737 %t Major device type in hex\n\
740 %U User name of owner\n\
741 %u User ID of owner\n\
742 %X Time of last access as seconds since Epoch\n\
743 %x Time of last access\n\
744 %Y Time of last modification as seconds since Epoch\n\
745 %y Time of last modification\n\
746 %Z Time of last change as seconds since Epoch\n\
747 %z Time of last change\n\
752 Valid format sequences for file systems:\n\
754 %a Free blocks available to non-superuser\n\
755 %b Total data blocks in file system\n\
756 %c Total file nodes in file system\n\
757 %d Free file nodes in file system\n\
758 %f Free blocks in file system\n\
761 %i File System id in hex\n\
762 %l Maximum length of filenames\n\
764 %s Optimal transfer block size\n\
765 %T Type in human readable form\n\
768 printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT
);
774 main (int argc
, char *argv
[])
778 int follow_links
= 0;
783 initialize_main (&argc
, &argv
);
784 program_name
= argv
[0];
785 setlocale (LC_ALL
, "");
786 bindtextdomain (PACKAGE
, LOCALEDIR
);
787 textdomain (PACKAGE
);
789 atexit (close_stdout
);
791 while ((c
= getopt_long (argc
, argv
, "c:fLlt", long_options
, NULL
)) != -1)
799 case 'l': /* deprecated */
800 error (0, 0, _("Warning: `-l' is deprecated; use `-L' instead"));
814 case_GETOPT_HELP_CHAR
;
816 case_GETOPT_VERSION_CHAR (PROGRAM_NAME
, AUTHORS
);
819 usage (EXIT_FAILURE
);
825 error (0, 0, _("too few arguments"));
826 usage (EXIT_FAILURE
);
829 for (i
= optind
; i
< argc
; i
++)
832 do_stat (argv
[i
], follow_links
, terse
, format
);
834 do_statfs (argv
[i
], terse
, format
);
837 exit (G_fail
? EXIT_FAILURE
: EXIT_SUCCESS
);