1 /* stat.c -- display file or filesystem status
2 Copyright (C) 2001, 2002 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>
24 #ifdef HAVE_SYS_SYSMACROS_H
25 # include <sys/sysmacros.h>
31 #if HAVE_SYS_STATVFS_H
32 # include <sys/statvfs.h>
38 /* NetBSD 1.5.2 needs these, for the declaration of struct statfs. */
39 #if !HAVE_SYS_STATVFS_H && !HAVE_SYS_VFS_H
40 # if HAVE_SYS_MOUNT_H && HAVE_SYS_PARAM_H
41 # include <sys/param.h>
42 # include <sys/mount.h>
50 # include <inttypes.h>
55 # define PRIdMAX "lld"
63 # define PRIuMAX "llu"
78 #include "xreadlink.h"
80 #define NAMEMAX_FORMAT PRIuMAX
82 #if HAVE_STRUCT_STATVFS_F_BASETYPE
83 # define STRUCT_STATVFS struct statvfs
84 # define HAVE_STRUCT_STATXFS_F_TYPE HAVE_STRUCT_STATVFS
85 # if HAVE_STRUCT_STATVFS_F_NAMEMAX
86 # define SB_F_NAMEMAX(S) ((uintmax_t) ((S)->f_namemax))
89 # define STRUCT_STATVFS struct statfs
90 # define HAVE_STRUCT_STATXFS_F_TYPE HAVE_STRUCT_STATFS
91 # if HAVE_STRUCT_STATFS_F_NAMELEN
92 # define SB_F_NAMEMAX(S) ((uintmax_t) ((S)->f_namelen))
97 /* NetBSD 1.5.2 has neither f_namemax nor f_namelen. */
98 # define SB_F_NAMEMAX(S) "*"
99 # undef NAMEMAX_FORMAT
100 # define NAMEMAX_FORMAT "s"
103 size_t nstrftime
PARAMS ((char *, size_t, char const *,
104 struct tm
const *, int, int));
106 #define PROGRAM_NAME "stat"
108 #define AUTHORS "Michael Meskes"
110 static struct option
const long_options
[] = {
111 {"link", no_argument
, 0, 'l'}, /* deprecated. FIXME: remove in 2003 */
112 {"dereference", no_argument
, 0, 'L'},
113 {"format", required_argument
, 0, 'c'},
114 {"filesystem", no_argument
, 0, 'f'},
115 {"terse", no_argument
, 0, 't'},
116 {GETOPT_HELP_OPTION_DECL
},
117 {GETOPT_VERSION_OPTION_DECL
},
124 print_human_type (mode_t mode
)
127 switch (mode
& S_IFMT
)
133 type
= "Character Device";
136 type
= "Block Device";
139 type
= "Regular File";
142 type
= "Symbolic Link";
153 fputs (type
, stdout
);
156 /* Return the type of the specified file system.
157 Some systems have statfvs.f_basetype[FSTYPSZ]. (AIX, HP-UX, and Solaris)
158 Others have statfs.f_fstypename[MFSNAMELEN]. (NetBSD 1.5.2)
159 Still others have neither and have to get by with f_type (Linux). */
161 human_fstype (STRUCT_STATVFS
const *statfsbuf
)
163 #if HAVE_STRUCT_STATVFS_F_BASETYPE
164 return statfsbuf
->f_basetype
;
166 # if HAVE_STRUCT_STATFS_F_FSTYPENAME
167 return statfsbuf
->f_fstypename
;
171 switch (statfsbuf
->f_type
)
173 # if defined __linux__
180 case S_MAGIC_EXT2_OLD
:
192 case S_MAGIC_ISOFS_WIN
:
195 case S_MAGIC_ISOFS_R_WIN
:
201 case S_MAGIC_MINIX_30
:
202 type
= "minix (30 char.)";
204 case S_MAGIC_MINIX_V2
:
207 case S_MAGIC_MINIX_V2_30
:
208 type
= "minix v2 (30 char.)";
252 case S_MAGIC_REISERFS
:
350 return (char *) type
;
353 static char buf
[sizeof "UNKNOWN (0x%x)" - 2
354 + 2 * sizeof (statfsbuf
->f_type
)];
355 sprintf (buf
, "UNKNOWN (0x%x)", statfsbuf
->f_type
);
363 print_human_access (struct stat
const *statbuf
)
366 mode_string (statbuf
->st_mode
, modebuf
);
368 fputs (modebuf
, stdout
);
372 print_human_time (time_t const *t
)
376 #if 0 /* %c is too locale-dependent. */
377 if (strftime (str
, 40, "%c", localtime (t
)) > 0)
379 if (nstrftime (str
, sizeof str
, "%Y-%m-%d %H:%M:%S.%N %z",
380 localtime (t
), 0, 0) > 0)
384 printf ("Cannot calculate human readable time, sorry");
387 /* print statfs info */
389 print_statfs (char *pformat
, char m
, char const *filename
,
392 STRUCT_STATVFS
const *statfsbuf
= data
;
397 strcat (pformat
, "s");
398 printf (pformat
, filename
);
402 #if HAVE_STRUCT_STATXFS_F_FSID___VAL
403 strcat (pformat
, "x %-8x");
404 printf (pformat
, statfsbuf
->f_fsid
.__val
[0], /* u_long */
405 statfsbuf
->f_fsid
.__val
[1]);
407 strcat (pformat
, "Lx");
408 printf (pformat
, statfsbuf
->f_fsid
);
413 strcat (pformat
, NAMEMAX_FORMAT
);
414 printf (pformat
, SB_F_NAMEMAX (statfsbuf
));
417 #if HAVE_STRUCT_STATXFS_F_TYPE
418 strcat (pformat
, "lx");
419 printf (pformat
, (long int) (statfsbuf
->f_type
)); /* no equiv. */
425 strcat (pformat
, "s");
426 printf (pformat
, human_fstype (statfsbuf
));
429 strcat (pformat
, PRIdMAX
);
430 printf (pformat
, (intmax_t) (statfsbuf
->f_blocks
));
433 strcat (pformat
, PRIdMAX
);
434 printf (pformat
, (intmax_t) (statfsbuf
->f_bfree
));
437 strcat (pformat
, PRIdMAX
);
438 printf (pformat
, (intmax_t) (statfsbuf
->f_bavail
));
441 strcat (pformat
, "ld");
442 printf (pformat
, (long int) (statfsbuf
->f_bsize
));
445 strcat (pformat
, PRIdMAX
);
446 printf (pformat
, (intmax_t) (statfsbuf
->f_files
));
449 strcat (pformat
, PRIdMAX
);
450 printf (pformat
, (intmax_t) (statfsbuf
->f_ffree
));
454 strcat (pformat
, "c");
460 /* print stat info */
462 print_stat (char *pformat
, char m
, char const *filename
, void const *data
)
464 struct stat
*statbuf
= (struct stat
*) data
;
465 struct passwd
*pw_ent
;
466 struct group
*gw_ent
;
471 strcat (pformat
, "s");
472 printf (pformat
, filename
);
475 strcat (pformat
, "s");
476 if ((statbuf
->st_mode
& S_IFMT
) == S_IFLNK
)
478 char *linkname
= xreadlink (filename
);
479 if (linkname
== NULL
)
481 error (0, errno
, _("cannot read symbolic link %s"),
485 /*printf("\"%s\" -> \"%s\"", filename, linkname); */
486 printf (pformat
, quote (filename
));
488 printf (pformat
, quote (linkname
));
492 printf (pformat
, quote (filename
));
496 strcat (pformat
, "d");
497 printf (pformat
, (int) statbuf
->st_dev
);
500 strcat (pformat
, "x");
501 printf (pformat
, (int) statbuf
->st_dev
);
504 strcat (pformat
, "d");
505 printf (pformat
, (int) statbuf
->st_ino
);
508 strcat (pformat
, "o");
509 printf (pformat
, statbuf
->st_mode
& 07777);
512 print_human_access (statbuf
);
515 strcat (pformat
, "x");
516 printf (pformat
, statbuf
->st_mode
);
519 print_human_type (statbuf
->st_mode
);
522 strcat (pformat
, "d");
523 printf (pformat
, (int) statbuf
->st_nlink
);
526 strcat (pformat
, "d");
527 printf (pformat
, statbuf
->st_uid
);
530 strcat (pformat
, "s");
532 pw_ent
= getpwuid (statbuf
->st_uid
);
533 printf (pformat
, (pw_ent
!= 0L) ? pw_ent
->pw_name
: "UNKNOWN");
536 strcat (pformat
, "d");
537 printf (pformat
, statbuf
->st_gid
);
540 strcat (pformat
, "s");
542 gw_ent
= getgrgid (statbuf
->st_gid
);
543 printf (pformat
, (gw_ent
!= 0L) ? gw_ent
->gr_name
: "UNKNOWN");
546 strcat (pformat
, "x");
547 printf (pformat
, major (statbuf
->st_rdev
));
550 strcat (pformat
, "x");
551 printf (pformat
, minor (statbuf
->st_rdev
));
554 strcat (pformat
, PRIuMAX
);
555 printf (pformat
, (uintmax_t) (statbuf
->st_size
));
558 strcat (pformat
, "u");
559 printf (pformat
, (unsigned int) statbuf
->st_blocks
);
562 strcat (pformat
, "d");
563 printf (pformat
, (int) statbuf
->st_blksize
);
566 print_human_time (&(statbuf
->st_atime
));
569 strcat (pformat
, "d");
570 printf (pformat
, (int) statbuf
->st_atime
);
573 print_human_time (&(statbuf
->st_mtime
));
576 strcat (pformat
, "d");
577 printf (pformat
, (int) statbuf
->st_mtime
);
580 print_human_time (&(statbuf
->st_ctime
));
583 strcat (pformat
, "d");
584 printf (pformat
, (int) statbuf
->st_ctime
);
587 strcat (pformat
, "c");
594 print_it (char const *masterformat
, char const *filename
,
595 void (*print_func
) (char *, char, char const *, void const *),
600 /* create a working copy of the format string */
601 char *format
= xstrdup (masterformat
);
603 char *dest
= xmalloc (strlen (format
) + 1);
609 char *p
= strchr (b
, '%');
616 len
= strspn (p
, "#-+.I 0123456789");
618 memcpy (dest
+ 1, p
, len
);
629 print_func (dest
, *p
, filename
, data
);
642 fputc ('\n', stdout
);
645 /* stat the filesystem and print what we find */
647 do_statfs (char const *filename
, int terse
, char const *format
)
649 STRUCT_STATVFS statfsbuf
;
650 int i
= statfs (filename
, &statfsbuf
);
654 error (0, errno
, _("cannot read file system information for %s"),
662 ? "%n %i %l %t %b %f %a %s %c %d"
664 " ID: %-8i Namelen: %-7l Type: %T\n"
665 "Blocks: Total: %-10b Free: %-10f Available: %-10a Size: %s\n"
666 "Inodes: Total: %-10c Free: %-10d");
669 print_it (format
, filename
, print_statfs
, &statfsbuf
);
672 /* stat the file and print what we find */
674 do_stat (char const *filename
, int follow_links
, int terse
,
678 int i
= ((follow_links
== 1)
679 ? stat (filename
, &statbuf
)
680 : lstat (filename
, &statbuf
));
684 error (0, errno
, _("cannot stat %s"), quote (filename
));
692 format
= "%n %s %b %f %u %g %D %i %h %t %T %X %Y %Z %o";
696 /* tmp hack to match orignal output until conditional implemented */
697 i
= statbuf
.st_mode
& S_IFMT
;
698 if (i
== S_IFCHR
|| i
== S_IFBLK
)
702 " Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n"
703 "Device: %Dh/%dd\tInode: %-10i Links: %-5h"
704 " Device type: %t,%T\n"
705 "Access: (%04a/%10.10A) Uid: (%5u/%8U) Gid: (%5g/%8G)\n"
706 "Access: %x\n" "Modify: %y\n" "Change: %z\n";
712 " Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n"
713 "Device: %Dh/%dd\tInode: %-10i Links: %-5h\n"
714 "Access: (%04a/%10.10A) Uid: (%5u/%8U) Gid: (%5g/%8G)\n"
715 "Access: %x\n" "Modify: %y\n" "Change: %z\n";
719 print_it (format
, filename
, print_stat
, &statbuf
);
726 fprintf (stderr
, _("Try `%s --help' for more information.\n"),
730 printf (_("Usage: %s [OPTION] FILE...\n"), program_name
);
732 Display file or filesystem status.\n\
734 -f, --filesystem display filesystem status instead of file status\n\
735 -c --format=FORMAT use the specified FORMAT instead of the default\n\
736 -L, --dereference follow links\n\
737 -t, --terse print the information in terse form\n\
739 fputs (HELP_OPTION_DESCRIPTION
, stdout
);
740 fputs (VERSION_OPTION_DESCRIPTION
, stdout
);
743 The valid format sequences for files (without --filesystem):\n\
745 %A - Access rights in human readable form\n\
746 %a - Access rights in octal\n\
747 %b - Number of blocks allocated\n\
750 %D - Device number in hex\n\
751 %d - Device number in decimal\n\
753 %f - raw mode in hex\n\
754 %G - Group name of owner\n\
755 %g - Group ID of owner\n\
758 %h - Number of hard links\n\
760 %N - Quoted File name with dereference if symbolic link\n\
762 %o - IO block size\n\
763 %s - Total size, in bytes\n\
764 %T - Minor device type in hex\n\
765 %t - Major device type in hex\n\
768 %U - User name of owner\n\
769 %u - User ID of owner\n\
770 %X - Time of last access as seconds since Epoch\n\
771 %x - Time of last access\n\
772 %Y - Time of last modification as seconds since Epoch\n\
773 %y - Time of last modification\n\
774 %Z - Time of last change as seconds since Epoch\n\
775 %z - Time of last change\n\
780 Valid format sequences for file systems:\n\
782 %a - Free blocks available to non-superuser\n\
783 %b - Total data blocks in file system\n\
784 %c - Total file nodes in file system\n\
785 %d - Free file nodes in file system\n\
786 %f - Free blocks in file system\n\
789 %i - File System id in hex\n\
790 %l - Maximum length of filenames\n\
792 %s - Optimal transfer block size\n\
793 %T - Type in human readable form\n\
796 printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT
);
802 main (int argc
, char *argv
[])
806 int follow_links
= 0;
811 program_name
= argv
[0];
812 setlocale (LC_ALL
, "");
813 bindtextdomain (PACKAGE
, LOCALEDIR
);
814 textdomain (PACKAGE
);
816 atexit (close_stdout
);
818 while ((c
= getopt_long (argc
, argv
, "c:fLlt", long_options
, NULL
)) != -1)
825 case 'l': /* deprecated */
836 case_GETOPT_HELP_CHAR
;
838 case_GETOPT_VERSION_CHAR (PROGRAM_NAME
, AUTHORS
);
841 usage (EXIT_FAILURE
);
847 error (0, 0, _("too few arguments"));
848 usage (EXIT_FAILURE
);
851 for (i
= optind
; i
< argc
; i
++)
854 do_stat (argv
[i
], follow_links
, terse
, format
);
856 do_statfs (argv
[i
], terse
, format
);