stat.c
时间:2006-07-31 来源:anima
/* stat.c -- display file or filesystem status
Copyright (C) 2001, 2002 Free Software Foundation.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Written by Michael Meskes. */
#include <config.h>
#include <stdio.h>
#include <sys/types.h>
#ifdef HAVE_SYS_SYSMACROS_H
# include <sys/sysmacros.h>
#endif
#include <pwd.h>
#include <grp.h>
#include <unistd.h>
#include <time.h>
#if HAVE_SYS_STATVFS_H
# include <sys/statvfs.h>
#endif
#if HAVE_SYS_VFS_H
# include <sys/vfs.h>
#endif
/* NetBSD 1.5.2 needs these, for the declaration of struct statfs. */
#if !HAVE_SYS_STATVFS_H && !HAVE_SYS_VFS_H
# if HAVE_SYS_MOUNT_H && HAVE_SYS_PARAM_H
# include <sys/param.h>
# include <sys/mount.h>
# endif
#endif
#include <string.h>
#include <ctype.h>
#include "system.h"
#include "closeout.h"
#include "error.h"
#include "filemode.h"
#include "fs.h"
#include "getopt.h"
#include "quote.h"
#include "quotearg.h"
#include "xreadlink.h"
#define NAMEMAX_FORMAT PRIuMAX
#if HAVE_STRUCT_STATVFS_F_BASETYPE
# define STRUCT_STATVFS struct statvfs
# define HAVE_STRUCT_STATXFS_F_TYPE HAVE_STRUCT_STATVFS
# if HAVE_STRUCT_STATVFS_F_NAMEMAX
# define SB_F_NAMEMAX(S) ((uintmax_t) ((S)->f_namemax))
# endif
#else
# define STRUCT_STATVFS struct statfs
# define HAVE_STRUCT_STATXFS_F_TYPE HAVE_STRUCT_STATFS
# if HAVE_STRUCT_STATFS_F_NAMELEN
# define SB_F_NAMEMAX(S) ((uintmax_t) ((S)->f_namelen))
# endif
#endif
#ifndef SB_F_NAMEMAX
/* NetBSD 1.5.2 has neither f_namemax nor f_namelen. */
# define SB_F_NAMEMAX(S) "*"
# undef NAMEMAX_FORMAT
# define NAMEMAX_FORMAT "s"
#endif
size_t nstrftime PARAMS ((char *, size_t, char const *,
struct tm const *, int, int));
#define PROGRAM_NAME "stat"
#define AUTHORS "Michael Meskes"
static struct option const long_options[] = {
{"link", no_argument, 0, 'l'}, /* deprecated. FIXME: remove in 2003 */
{"dereference", no_argument, 0, 'L'},
{"format", required_argument, 0, 'c'},
{"filesystem", no_argument, 0, 'f'},
{"terse", no_argument, 0, 't'},
{GETOPT_HELP_OPTION_DECL},
{GETOPT_VERSION_OPTION_DECL},
{NULL, 0, NULL, 0}
};
char *program_name;
static void
print_human_type (mode_t mode)
{
char const *type;
switch (mode & S_IFMT)
{
case S_IFDIR:
type = "Directory";
break;
case S_IFCHR:
type = "Character Device";
break;
case S_IFBLK:
type = "Block Device";
break;
case S_IFREG:
type = "Regular File";
break;
case S_IFLNK:
type = "Symbolic Link";
break;
case S_IFSOCK:
type = "Socket";
break;
case S_IFIFO:
type = "Fifo File";
break;
default:
type = "Unknown";
}
fputs (type, stdout);
}
/* Return the type of the specified file system.
Some systems have statfvs.f_basetype[FSTYPSZ]. (AIX, HP-UX, and Solaris)
Others have statfs.f_fstypename[MFSNAMELEN]. (NetBSD 1.5.2)
Still others have neither and have to get by with f_type (Linux). */
static char *
human_fstype (STRUCT_STATVFS const *statfsbuf)
{
#if HAVE_STRUCT_STATVFS_F_BASETYPE
return statfsbuf->f_basetype;
#else
# if HAVE_STRUCT_STATFS_F_FSTYPENAME
return statfsbuf->f_fstypename;
# else
char const *type;
switch (statfsbuf->f_type)
{
# if defined __linux__
case S_MAGIC_AFFS:
type = "affs";
break;
case S_MAGIC_EXT:
type = "ext";
break;
case S_MAGIC_EXT2_OLD:
type = "ext2";
break;
case S_MAGIC_EXT2:
type = "ext2/ext3";
break;
case S_MAGIC_HPFS:
type = "hpfs";
break;
case S_MAGIC_ISOFS:
type = "isofs";
break;
case S_MAGIC_ISOFS_WIN:
type = "isofs";
break;
case S_MAGIC_ISOFS_R_WIN:
type = "isofs";
break;
case S_MAGIC_MINIX:
type = "minix";
break;
case S_MAGIC_MINIX_30:
type = "minix (30 char.)";
break;
case S_MAGIC_MINIX_V2:
type = "minix v2";
break;
case S_MAGIC_MINIX_V2_30:
type = "minix v2 (30 char.)";
break;
case S_MAGIC_MSDOS:
type = "msdos";
break;
case S_MAGIC_FAT:
type = "fat";
break;
case S_MAGIC_NCP:
type = "novell";
break;
case S_MAGIC_NFS:
type = "nfs";
break;
case S_MAGIC_PROC:
type = "proc";
break;
case S_MAGIC_SMB:
type = "smb";
break;
case S_MAGIC_XENIX:
type = "xenix";
break;
case S_MAGIC_SYSV4:
type = "sysv4";
break;
case S_MAGIC_SYSV2:
type = "sysv2";
break;
case S_MAGIC_COH:
type = "coh";
break;
case S_MAGIC_UFS:
type = "ufs";
break;
case S_MAGIC_XIAFS:
type = "xia";
break;
case S_MAGIC_NTFS:
type = "ntfs";
break;
case S_MAGIC_TMPFS:
type = "tmpfs";
break;
case S_MAGIC_REISERFS:
type = "reiserfs";
break;
case S_MAGIC_CRAMFS:
type = "cramfs";
break;
case S_MAGIC_ROMFS:
type = "romfs";
break;
# elif __GNU__
case FSTYPE_UFS:
type = "ufs";
break;
case FSTYPE_NFS:
type = "nfs";
break;
case FSTYPE_GFS:
type = "gfs";
break;
case FSTYPE_LFS:
type = "lfs";
break;
case FSTYPE_SYSV:
type = "sysv";
break;
case FSTYPE_FTP:
type = "ftp";
break;
case FSTYPE_TAR:
type = "tar";
break;
case FSTYPE_AR:
type = "ar";
break;
case FSTYPE_CPIO:
type = "cpio";
break;
case FSTYPE_MSLOSS:
type = "msloss";
break;
case FSTYPE_CPM:
type = "cpm";
break;
case FSTYPE_HFS:
type = "hfs";
break;
case FSTYPE_DTFS:
type = "dtfs";
break;
case FSTYPE_GRFS:
type = "grfs";
break;
case FSTYPE_TERM:
type = "term";
break;
case FSTYPE_DEV:
type = "dev";
break;
case FSTYPE_PROC:
type = "proc";
break;
case FSTYPE_IFSOCK:
type = "ifsock";
break;
case FSTYPE_AFS:
type = "afs";
break;
case FSTYPE_DFS:
type = "dfs";
break;
case FSTYPE_PROC9:
type = "proc9";
break;
case FSTYPE_SOCKET:
type = "socket";
break;
case FSTYPE_MISC:
type = "misc";
break;
case FSTYPE_EXT2FS:
type = "ext2/ext3";
break;
case FSTYPE_HTTP:
type = "http";
break;
case FSTYPE_MEMFS:
type = "memfs";
break;
case FSTYPE_ISO9660:
type = "iso9660";
break;
# endif
default:
type = NULL;
break;
}
if (type)
return (char *) type;
{
static char buf[sizeof "UNKNOWN (0x%x)" - 2
+ 2 * sizeof (statfsbuf->f_type)];
sprintf (buf, "UNKNOWN (0x%x)", statfsbuf->f_type);
return buf;
}
# endif
#endif
}
static void
print_human_access (struct stat const *statbuf)
{
char modebuf[11];
mode_string (statbuf->st_mode, modebuf);
modebuf[10] = 0;
fputs (modebuf, stdout);
}
static void
print_human_time (time_t const *t)
{
char str[80];
#if 0 /* %c is too locale-dependent. */
if (strftime (str, 40, "%c", localtime (t)) > 0)
#else
if (nstrftime (str, sizeof str, "%Y-%m-%d %H:%M:%S.%N %z",
localtime (t), 0, 0) > 0)
#endif
fputs (str, stdout);
else
printf ("Cannot calculate human readable time, sorry");
}
/* print statfs info */
static void
print_statfs (char *pformat, char m, char const *filename,
void const *data)
{
STRUCT_STATVFS const *statfsbuf = data;
switch (m)
{
case 'n':
strcat (pformat, "s");
printf (pformat, filename);
break;
case 'i':
#if HAVE_STRUCT_STATXFS_F_FSID___VAL
strcat (pformat, "x %-8x");
printf (pformat, statfsbuf->f_fsid.__val[0], /* u_long */
statfsbuf->f_fsid.__val[1]);
#else
strcat (pformat, "Lx");
printf (pformat, statfsbuf->f_fsid);
#endif
break;
case 'l':
strcat (pformat, NAMEMAX_FORMAT);
printf (pformat, SB_F_NAMEMAX (statfsbuf));
break;
case 't':
#if HAVE_STRUCT_STATXFS_F_TYPE
strcat (pformat, "lx");
printf (pformat, (long int) (statfsbuf->f_type)); /* no equiv. */
#else
fputc ('*', stdout);
#endif
break;
case 'T':
strcat (pformat, "s");
printf (pformat, human_fstype (statfsbuf));
break;
case 'b':
strcat (pformat, PRIdMAX);
printf (pformat, (intmax_t) (statfsbuf->f_blocks));
break;
case 'f':
strcat (pformat, PRIdMAX);
printf (pformat, (intmax_t) (statfsbuf->f_bfree));
break;
case 'a':
strcat (pformat, PRIdMAX);
printf (pformat, (intmax_t) (statfsbuf->f_bavail));
break;
case 's':
strcat (pformat, "ld");
printf (pformat, (long int) (statfsbuf->f_bsize));
break;
case 'c':
strcat (pformat, PRIdMAX);
printf (pformat, (intmax_t) (statfsbuf->f_files));
break;
case 'd':
strcat (pformat, PRIdMAX);
printf (pformat, (intmax_t) (statfsbuf->f_ffree));
break;
default:
strcat (pformat, "c");
printf (pformat, m);
break;
}
}
/* print stat info */
static void
print_stat (char *pformat, char m, char const *filename, void const *data)
{
struct stat *statbuf = (struct stat *) data;
struct passwd *pw_ent;
struct group *gw_ent;
switch (m)
{
case 'n':
strcat (pformat, "s");
printf (pformat, filename);
break;
case 'N':
strcat (pformat, "s");
if ((statbuf->st_mode & S_IFMT) == S_IFLNK)
{
char *linkname = xreadlink (filename);
if (linkname == NULL)
{
error (0, errno, _("cannot read symbolic link %s"),
quote (filename));
return;
}
/*printf("\"%s\" -> \"%s\"", filename, linkname); */
printf (pformat, quote (filename));
printf (" -> ");
printf (pformat, quote (linkname));
}
else
{
printf (pformat, quote (filename));
}
break;
case 'd':
strcat (pformat, "d");
printf (pformat, (int) statbuf->st_dev);
break;
case 'D':
strcat (pformat, "x");
printf (pformat, (int) statbuf->st_dev);
break;
case 'i':
strcat (pformat, "d");
printf (pformat, (int) statbuf->st_ino);
break;
case 'a':
strcat (pformat, "o");
printf (pformat, statbuf->st_mode & 07777);
break;
case 'A':
print_human_access (statbuf);
break;
case 'f':
strcat (pformat, "x");
printf (pformat, statbuf->st_mode);
break;
case 'F':
print_human_type (statbuf->st_mode);
break;
case 'h':
strcat (pformat, "d");
printf (pformat, (int) statbuf->st_nlink);
break;
case 'u':
strcat (pformat, "d");
printf (pformat, statbuf->st_uid);
break;
case 'U':
strcat (pformat, "s");
setpwent ();
pw_ent = getpwuid (statbuf->st_uid);
printf (pformat, (pw_ent != 0L) ? pw_ent->pw_name : "UNKNOWN");
break;
case 'g':
strcat (pformat, "d");
printf (pformat, statbuf->st_gid);
break;
case 'G':
strcat (pformat, "s");
setgrent ();
gw_ent = getgrgid (statbuf->st_gid);
printf (pformat, (gw_ent != 0L) ? gw_ent->gr_name : "UNKNOWN");
break;
case 't':
strcat (pformat, "x");
printf (pformat, major (statbuf->st_rdev));
break;
case 'T':
strcat (pformat, "x");
printf (pformat, minor (statbuf->st_rdev));
break;
case 's':
strcat (pformat, PRIuMAX);
printf (pformat, (uintmax_t) (statbuf->st_size));
break;
case 'b':
strcat (pformat, "u");
printf (pformat, (unsigned int) statbuf->st_blocks);
break;
case 'o':
strcat (pformat, "d");
printf (pformat, (int) statbuf->st_blksize);
break;
case 'x':
print_human_time (&(statbuf->st_atime));
break;
case 'X':
strcat (pformat, "d");
printf (pformat, (int) statbuf->st_atime);
break;
case 'y':
print_human_time (&(statbuf->st_mtime));
break;
case 'Y':
strcat (pformat, "d");
printf (pformat, (int) statbuf->st_mtime);
break;
case 'z':
print_human_time (&(statbuf->st_ctime));
break;
case 'Z':
strcat (pformat, "d");
printf (pformat, (int) statbuf->st_ctime);
break;
default:
strcat (pformat, "c");
printf (pformat, m);
break;
}
}
static void
print_it (char const *masterformat, char const *filename,
void (*print_func) (char *, char, char const *, void const *),
void const *data)
{
char *b;
/* create a working copy of the format string */
char *format = xstrdup (masterformat);
char *dest = xmalloc (strlen (format) + 1);
b = format;
while (b)
{
char *p = strchr (b, '%');
if (p != NULL)
{
size_t len;
*p++ = '\0';
fputs (b, stdout);
len = strspn (p, "#-+.I 0123456789");
dest[0] = '%';
memcpy (dest + 1, p, len);
dest[1 + len] = 0;
p += len;
switch (*p)
{
case '\0':
case '%':
fputs ("%", stdout);
break;
default:
print_func (dest, *p, filename, data);
break;
}
b = p + 1;
}
else
{
fputs (b, stdout);
b = NULL;
}
}
free (format);
free (dest);
fputc ('\n', stdout);
}
/* stat the filesystem and print what we find */
static void
do_statfs (char const *filename, int terse, char const *format)
{
STRUCT_STATVFS statfsbuf;
int i = statfs (filename, &statfsbuf);
if (i == -1)
{
error (0, errno, _("cannot read file system information for %s"),
quote (filename));
return;
}
if (format == NULL)
{
format = (terse
? "%n %i %l %t %b %f %a %s %c %d"
: " File: \"%n\"\n"
" ID: %-8i Namelen: %-7l Type: %T\n"
"Blocks: Total: %-10b Free: %-10f Available: %-10a Size: %s\n"
"Inodes: Total: %-10c Free: %-10d");
}
print_it (format, filename, print_statfs, &statfsbuf);
}
/* stat the file and print what we find */
static void
do_stat (char const *filename, int follow_links, int terse,
char const *format)
{
struct stat statbuf;
int i = ((follow_links == 1)
? stat (filename, &statbuf)
: lstat (filename, &statbuf));
if (i == -1)
{
error (0, errno, _("cannot stat %s"), quote (filename));
return;
}
if (format == NULL)
{
if (terse != 0)
{
format = "%n %s %b %f %u %g %D %i %h %t %T %X %Y %Z %o";
}
else
{
/* tmp hack to match orignal output until conditional implemented */
i = statbuf.st_mode & S_IFMT;
if (i == S_IFCHR || i == S_IFBLK)
{
format =
" File: %N\n"
" Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n"
"Device: %Dh/%dd\tInode: %-10i Links: %-5h"
" Device type: %t,%T\n"
"Access: (%04a/%10.10A) Uid: (%5u/%8U) Gid: (%5g/%8G)\n"
"Access: %x\n" "Modify: %y\n" "Change: %z\n";
}
else
{
format =
" File: %N\n"
" Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n"
"Device: %Dh/%dd\tInode: %-10i Links: %-5h\n"
"Access: (%04a/%10.10A) Uid: (%5u/%8U) Gid: (%5g/%8G)\n"
"Access: %x\n" "Modify: %y\n" "Change: %z\n";
}
}
}
print_it (format, filename, print_stat, &statbuf);
}
void
usage (int status)
{
if (status != 0)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
program_name);
else
{
printf (_("Usage: %s [OPTION] FILE...\n"), program_name);
fputs (_("\
Display file or filesystem status.\n\
\n\
-f, --filesystem display filesystem status instead of file status\n\
-c --format=FORMAT use the specified FORMAT instead of the default\n\
-L, --dereference follow links\n\
-t, --terse print the information in terse form\n\
"), stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
fputs (_("\n\
The valid format sequences for files (without --filesystem):\n\
\n\
%A - Access rights in human readable form\n\
%a - Access rights in octal\n\
%b - Number of blocks allocated\n\
"), stdout);
fputs (_("\
%D - Device number in hex\n\
%d - Device number in decimal\n\
%F - File type\n\
%f - raw mode in hex\n\
%G - Group name of owner\n\
%g - Group ID of owner\n\
"), stdout);
fputs (_("\
%h - Number of hard links\n\
%i - Inode number\n\
%N - Quoted File name with dereference if symbolic link\n\
%n - File name\n\
%o - IO block size\n\
%s - Total size, in bytes\n\
%T - Minor device type in hex\n\
%t - Major device type in hex\n\
"), stdout);
fputs (_("\
%U - User name of owner\n\
%u - User ID of owner\n\
%X - Time of last access as seconds since Epoch\n\
%x - Time of last access\n\
%Y - Time of last modification as seconds since Epoch\n\
%y - Time of last modification\n\
%Z - Time of last change as seconds since Epoch\n\
%z - Time of last change\n\
\n\
"), stdout);
fputs (_("\
Valid format sequences for file systems:\n\
\n\
%a - Free blocks available to non-superuser\n\
%b - Total data blocks in file system\n\
%c - Total file nodes in file system\n\
%d - Free file nodes in file system\n\
%f - Free blocks in file system\n\
"), stdout);
fputs (_("\
%i - File System id in hex\n\
%l - Maximum length of filenames\n\
%n - File name\n\
%s - Optimal transfer block size\n\
%T - Type in human readable form\n\
%t - Type in hex\n\
"), stdout);
printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
}
exit (status);
}
int
main (int argc, char *argv[])
{
int c;
int i;
int follow_links = 0;
int fs = 0;
int terse = 0;
char *format = NULL;
program_name = argv[0];
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
atexit (close_stdout);
while ((c = getopt_long (argc, argv, "c:fLlt", long_options, NULL)) != -1)
{
switch (c)
{
case 'c':
format = optarg;
break;
case 'l': /* deprecated */
case 'L':
follow_links = 1;
break;
case 'f':
fs = 1;
break;
case 't':
terse = 1;
break;
case_GETOPT_HELP_CHAR;
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
default:
usage (EXIT_FAILURE);
}
}
if (argc == optind)
{
error (0, 0, _("too few arguments"));
usage (EXIT_FAILURE);
}
for (i = optind; i < argc; i++)
{
if (fs == 0)
do_stat (argv[i], follow_links, terse, format);
else
do_statfs (argv[i], terse, format);
}
exit (EXIT_SUCCESS);
}
Copyright (C) 2001, 2002 Free Software Foundation.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Written by Michael Meskes. */
#include <config.h>
#include <stdio.h>
#include <sys/types.h>
#ifdef HAVE_SYS_SYSMACROS_H
# include <sys/sysmacros.h>
#endif
#include <pwd.h>
#include <grp.h>
#include <unistd.h>
#include <time.h>
#if HAVE_SYS_STATVFS_H
# include <sys/statvfs.h>
#endif
#if HAVE_SYS_VFS_H
# include <sys/vfs.h>
#endif
/* NetBSD 1.5.2 needs these, for the declaration of struct statfs. */
#if !HAVE_SYS_STATVFS_H && !HAVE_SYS_VFS_H
# if HAVE_SYS_MOUNT_H && HAVE_SYS_PARAM_H
# include <sys/param.h>
# include <sys/mount.h>
# endif
#endif
#include <string.h>
#include <ctype.h>
#include "system.h"
#include "closeout.h"
#include "error.h"
#include "filemode.h"
#include "fs.h"
#include "getopt.h"
#include "quote.h"
#include "quotearg.h"
#include "xreadlink.h"
#define NAMEMAX_FORMAT PRIuMAX
#if HAVE_STRUCT_STATVFS_F_BASETYPE
# define STRUCT_STATVFS struct statvfs
# define HAVE_STRUCT_STATXFS_F_TYPE HAVE_STRUCT_STATVFS
# if HAVE_STRUCT_STATVFS_F_NAMEMAX
# define SB_F_NAMEMAX(S) ((uintmax_t) ((S)->f_namemax))
# endif
#else
# define STRUCT_STATVFS struct statfs
# define HAVE_STRUCT_STATXFS_F_TYPE HAVE_STRUCT_STATFS
# if HAVE_STRUCT_STATFS_F_NAMELEN
# define SB_F_NAMEMAX(S) ((uintmax_t) ((S)->f_namelen))
# endif
#endif
#ifndef SB_F_NAMEMAX
/* NetBSD 1.5.2 has neither f_namemax nor f_namelen. */
# define SB_F_NAMEMAX(S) "*"
# undef NAMEMAX_FORMAT
# define NAMEMAX_FORMAT "s"
#endif
size_t nstrftime PARAMS ((char *, size_t, char const *,
struct tm const *, int, int));
#define PROGRAM_NAME "stat"
#define AUTHORS "Michael Meskes"
static struct option const long_options[] = {
{"link", no_argument, 0, 'l'}, /* deprecated. FIXME: remove in 2003 */
{"dereference", no_argument, 0, 'L'},
{"format", required_argument, 0, 'c'},
{"filesystem", no_argument, 0, 'f'},
{"terse", no_argument, 0, 't'},
{GETOPT_HELP_OPTION_DECL},
{GETOPT_VERSION_OPTION_DECL},
{NULL, 0, NULL, 0}
};
char *program_name;
static void
print_human_type (mode_t mode)
{
char const *type;
switch (mode & S_IFMT)
{
case S_IFDIR:
type = "Directory";
break;
case S_IFCHR:
type = "Character Device";
break;
case S_IFBLK:
type = "Block Device";
break;
case S_IFREG:
type = "Regular File";
break;
case S_IFLNK:
type = "Symbolic Link";
break;
case S_IFSOCK:
type = "Socket";
break;
case S_IFIFO:
type = "Fifo File";
break;
default:
type = "Unknown";
}
fputs (type, stdout);
}
/* Return the type of the specified file system.
Some systems have statfvs.f_basetype[FSTYPSZ]. (AIX, HP-UX, and Solaris)
Others have statfs.f_fstypename[MFSNAMELEN]. (NetBSD 1.5.2)
Still others have neither and have to get by with f_type (Linux). */
static char *
human_fstype (STRUCT_STATVFS const *statfsbuf)
{
#if HAVE_STRUCT_STATVFS_F_BASETYPE
return statfsbuf->f_basetype;
#else
# if HAVE_STRUCT_STATFS_F_FSTYPENAME
return statfsbuf->f_fstypename;
# else
char const *type;
switch (statfsbuf->f_type)
{
# if defined __linux__
case S_MAGIC_AFFS:
type = "affs";
break;
case S_MAGIC_EXT:
type = "ext";
break;
case S_MAGIC_EXT2_OLD:
type = "ext2";
break;
case S_MAGIC_EXT2:
type = "ext2/ext3";
break;
case S_MAGIC_HPFS:
type = "hpfs";
break;
case S_MAGIC_ISOFS:
type = "isofs";
break;
case S_MAGIC_ISOFS_WIN:
type = "isofs";
break;
case S_MAGIC_ISOFS_R_WIN:
type = "isofs";
break;
case S_MAGIC_MINIX:
type = "minix";
break;
case S_MAGIC_MINIX_30:
type = "minix (30 char.)";
break;
case S_MAGIC_MINIX_V2:
type = "minix v2";
break;
case S_MAGIC_MINIX_V2_30:
type = "minix v2 (30 char.)";
break;
case S_MAGIC_MSDOS:
type = "msdos";
break;
case S_MAGIC_FAT:
type = "fat";
break;
case S_MAGIC_NCP:
type = "novell";
break;
case S_MAGIC_NFS:
type = "nfs";
break;
case S_MAGIC_PROC:
type = "proc";
break;
case S_MAGIC_SMB:
type = "smb";
break;
case S_MAGIC_XENIX:
type = "xenix";
break;
case S_MAGIC_SYSV4:
type = "sysv4";
break;
case S_MAGIC_SYSV2:
type = "sysv2";
break;
case S_MAGIC_COH:
type = "coh";
break;
case S_MAGIC_UFS:
type = "ufs";
break;
case S_MAGIC_XIAFS:
type = "xia";
break;
case S_MAGIC_NTFS:
type = "ntfs";
break;
case S_MAGIC_TMPFS:
type = "tmpfs";
break;
case S_MAGIC_REISERFS:
type = "reiserfs";
break;
case S_MAGIC_CRAMFS:
type = "cramfs";
break;
case S_MAGIC_ROMFS:
type = "romfs";
break;
# elif __GNU__
case FSTYPE_UFS:
type = "ufs";
break;
case FSTYPE_NFS:
type = "nfs";
break;
case FSTYPE_GFS:
type = "gfs";
break;
case FSTYPE_LFS:
type = "lfs";
break;
case FSTYPE_SYSV:
type = "sysv";
break;
case FSTYPE_FTP:
type = "ftp";
break;
case FSTYPE_TAR:
type = "tar";
break;
case FSTYPE_AR:
type = "ar";
break;
case FSTYPE_CPIO:
type = "cpio";
break;
case FSTYPE_MSLOSS:
type = "msloss";
break;
case FSTYPE_CPM:
type = "cpm";
break;
case FSTYPE_HFS:
type = "hfs";
break;
case FSTYPE_DTFS:
type = "dtfs";
break;
case FSTYPE_GRFS:
type = "grfs";
break;
case FSTYPE_TERM:
type = "term";
break;
case FSTYPE_DEV:
type = "dev";
break;
case FSTYPE_PROC:
type = "proc";
break;
case FSTYPE_IFSOCK:
type = "ifsock";
break;
case FSTYPE_AFS:
type = "afs";
break;
case FSTYPE_DFS:
type = "dfs";
break;
case FSTYPE_PROC9:
type = "proc9";
break;
case FSTYPE_SOCKET:
type = "socket";
break;
case FSTYPE_MISC:
type = "misc";
break;
case FSTYPE_EXT2FS:
type = "ext2/ext3";
break;
case FSTYPE_HTTP:
type = "http";
break;
case FSTYPE_MEMFS:
type = "memfs";
break;
case FSTYPE_ISO9660:
type = "iso9660";
break;
# endif
default:
type = NULL;
break;
}
if (type)
return (char *) type;
{
static char buf[sizeof "UNKNOWN (0x%x)" - 2
+ 2 * sizeof (statfsbuf->f_type)];
sprintf (buf, "UNKNOWN (0x%x)", statfsbuf->f_type);
return buf;
}
# endif
#endif
}
static void
print_human_access (struct stat const *statbuf)
{
char modebuf[11];
mode_string (statbuf->st_mode, modebuf);
modebuf[10] = 0;
fputs (modebuf, stdout);
}
static void
print_human_time (time_t const *t)
{
char str[80];
#if 0 /* %c is too locale-dependent. */
if (strftime (str, 40, "%c", localtime (t)) > 0)
#else
if (nstrftime (str, sizeof str, "%Y-%m-%d %H:%M:%S.%N %z",
localtime (t), 0, 0) > 0)
#endif
fputs (str, stdout);
else
printf ("Cannot calculate human readable time, sorry");
}
/* print statfs info */
static void
print_statfs (char *pformat, char m, char const *filename,
void const *data)
{
STRUCT_STATVFS const *statfsbuf = data;
switch (m)
{
case 'n':
strcat (pformat, "s");
printf (pformat, filename);
break;
case 'i':
#if HAVE_STRUCT_STATXFS_F_FSID___VAL
strcat (pformat, "x %-8x");
printf (pformat, statfsbuf->f_fsid.__val[0], /* u_long */
statfsbuf->f_fsid.__val[1]);
#else
strcat (pformat, "Lx");
printf (pformat, statfsbuf->f_fsid);
#endif
break;
case 'l':
strcat (pformat, NAMEMAX_FORMAT);
printf (pformat, SB_F_NAMEMAX (statfsbuf));
break;
case 't':
#if HAVE_STRUCT_STATXFS_F_TYPE
strcat (pformat, "lx");
printf (pformat, (long int) (statfsbuf->f_type)); /* no equiv. */
#else
fputc ('*', stdout);
#endif
break;
case 'T':
strcat (pformat, "s");
printf (pformat, human_fstype (statfsbuf));
break;
case 'b':
strcat (pformat, PRIdMAX);
printf (pformat, (intmax_t) (statfsbuf->f_blocks));
break;
case 'f':
strcat (pformat, PRIdMAX);
printf (pformat, (intmax_t) (statfsbuf->f_bfree));
break;
case 'a':
strcat (pformat, PRIdMAX);
printf (pformat, (intmax_t) (statfsbuf->f_bavail));
break;
case 's':
strcat (pformat, "ld");
printf (pformat, (long int) (statfsbuf->f_bsize));
break;
case 'c':
strcat (pformat, PRIdMAX);
printf (pformat, (intmax_t) (statfsbuf->f_files));
break;
case 'd':
strcat (pformat, PRIdMAX);
printf (pformat, (intmax_t) (statfsbuf->f_ffree));
break;
default:
strcat (pformat, "c");
printf (pformat, m);
break;
}
}
/* print stat info */
static void
print_stat (char *pformat, char m, char const *filename, void const *data)
{
struct stat *statbuf = (struct stat *) data;
struct passwd *pw_ent;
struct group *gw_ent;
switch (m)
{
case 'n':
strcat (pformat, "s");
printf (pformat, filename);
break;
case 'N':
strcat (pformat, "s");
if ((statbuf->st_mode & S_IFMT) == S_IFLNK)
{
char *linkname = xreadlink (filename);
if (linkname == NULL)
{
error (0, errno, _("cannot read symbolic link %s"),
quote (filename));
return;
}
/*printf("\"%s\" -> \"%s\"", filename, linkname); */
printf (pformat, quote (filename));
printf (" -> ");
printf (pformat, quote (linkname));
}
else
{
printf (pformat, quote (filename));
}
break;
case 'd':
strcat (pformat, "d");
printf (pformat, (int) statbuf->st_dev);
break;
case 'D':
strcat (pformat, "x");
printf (pformat, (int) statbuf->st_dev);
break;
case 'i':
strcat (pformat, "d");
printf (pformat, (int) statbuf->st_ino);
break;
case 'a':
strcat (pformat, "o");
printf (pformat, statbuf->st_mode & 07777);
break;
case 'A':
print_human_access (statbuf);
break;
case 'f':
strcat (pformat, "x");
printf (pformat, statbuf->st_mode);
break;
case 'F':
print_human_type (statbuf->st_mode);
break;
case 'h':
strcat (pformat, "d");
printf (pformat, (int) statbuf->st_nlink);
break;
case 'u':
strcat (pformat, "d");
printf (pformat, statbuf->st_uid);
break;
case 'U':
strcat (pformat, "s");
setpwent ();
pw_ent = getpwuid (statbuf->st_uid);
printf (pformat, (pw_ent != 0L) ? pw_ent->pw_name : "UNKNOWN");
break;
case 'g':
strcat (pformat, "d");
printf (pformat, statbuf->st_gid);
break;
case 'G':
strcat (pformat, "s");
setgrent ();
gw_ent = getgrgid (statbuf->st_gid);
printf (pformat, (gw_ent != 0L) ? gw_ent->gr_name : "UNKNOWN");
break;
case 't':
strcat (pformat, "x");
printf (pformat, major (statbuf->st_rdev));
break;
case 'T':
strcat (pformat, "x");
printf (pformat, minor (statbuf->st_rdev));
break;
case 's':
strcat (pformat, PRIuMAX);
printf (pformat, (uintmax_t) (statbuf->st_size));
break;
case 'b':
strcat (pformat, "u");
printf (pformat, (unsigned int) statbuf->st_blocks);
break;
case 'o':
strcat (pformat, "d");
printf (pformat, (int) statbuf->st_blksize);
break;
case 'x':
print_human_time (&(statbuf->st_atime));
break;
case 'X':
strcat (pformat, "d");
printf (pformat, (int) statbuf->st_atime);
break;
case 'y':
print_human_time (&(statbuf->st_mtime));
break;
case 'Y':
strcat (pformat, "d");
printf (pformat, (int) statbuf->st_mtime);
break;
case 'z':
print_human_time (&(statbuf->st_ctime));
break;
case 'Z':
strcat (pformat, "d");
printf (pformat, (int) statbuf->st_ctime);
break;
default:
strcat (pformat, "c");
printf (pformat, m);
break;
}
}
static void
print_it (char const *masterformat, char const *filename,
void (*print_func) (char *, char, char const *, void const *),
void const *data)
{
char *b;
/* create a working copy of the format string */
char *format = xstrdup (masterformat);
char *dest = xmalloc (strlen (format) + 1);
b = format;
while (b)
{
char *p = strchr (b, '%');
if (p != NULL)
{
size_t len;
*p++ = '\0';
fputs (b, stdout);
len = strspn (p, "#-+.I 0123456789");
dest[0] = '%';
memcpy (dest + 1, p, len);
dest[1 + len] = 0;
p += len;
switch (*p)
{
case '\0':
case '%':
fputs ("%", stdout);
break;
default:
print_func (dest, *p, filename, data);
break;
}
b = p + 1;
}
else
{
fputs (b, stdout);
b = NULL;
}
}
free (format);
free (dest);
fputc ('\n', stdout);
}
/* stat the filesystem and print what we find */
static void
do_statfs (char const *filename, int terse, char const *format)
{
STRUCT_STATVFS statfsbuf;
int i = statfs (filename, &statfsbuf);
if (i == -1)
{
error (0, errno, _("cannot read file system information for %s"),
quote (filename));
return;
}
if (format == NULL)
{
format = (terse
? "%n %i %l %t %b %f %a %s %c %d"
: " File: \"%n\"\n"
" ID: %-8i Namelen: %-7l Type: %T\n"
"Blocks: Total: %-10b Free: %-10f Available: %-10a Size: %s\n"
"Inodes: Total: %-10c Free: %-10d");
}
print_it (format, filename, print_statfs, &statfsbuf);
}
/* stat the file and print what we find */
static void
do_stat (char const *filename, int follow_links, int terse,
char const *format)
{
struct stat statbuf;
int i = ((follow_links == 1)
? stat (filename, &statbuf)
: lstat (filename, &statbuf));
if (i == -1)
{
error (0, errno, _("cannot stat %s"), quote (filename));
return;
}
if (format == NULL)
{
if (terse != 0)
{
format = "%n %s %b %f %u %g %D %i %h %t %T %X %Y %Z %o";
}
else
{
/* tmp hack to match orignal output until conditional implemented */
i = statbuf.st_mode & S_IFMT;
if (i == S_IFCHR || i == S_IFBLK)
{
format =
" File: %N\n"
" Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n"
"Device: %Dh/%dd\tInode: %-10i Links: %-5h"
" Device type: %t,%T\n"
"Access: (%04a/%10.10A) Uid: (%5u/%8U) Gid: (%5g/%8G)\n"
"Access: %x\n" "Modify: %y\n" "Change: %z\n";
}
else
{
format =
" File: %N\n"
" Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n"
"Device: %Dh/%dd\tInode: %-10i Links: %-5h\n"
"Access: (%04a/%10.10A) Uid: (%5u/%8U) Gid: (%5g/%8G)\n"
"Access: %x\n" "Modify: %y\n" "Change: %z\n";
}
}
}
print_it (format, filename, print_stat, &statbuf);
}
void
usage (int status)
{
if (status != 0)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
program_name);
else
{
printf (_("Usage: %s [OPTION] FILE...\n"), program_name);
fputs (_("\
Display file or filesystem status.\n\
\n\
-f, --filesystem display filesystem status instead of file status\n\
-c --format=FORMAT use the specified FORMAT instead of the default\n\
-L, --dereference follow links\n\
-t, --terse print the information in terse form\n\
"), stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
fputs (_("\n\
The valid format sequences for files (without --filesystem):\n\
\n\
%A - Access rights in human readable form\n\
%a - Access rights in octal\n\
%b - Number of blocks allocated\n\
"), stdout);
fputs (_("\
%D - Device number in hex\n\
%d - Device number in decimal\n\
%F - File type\n\
%f - raw mode in hex\n\
%G - Group name of owner\n\
%g - Group ID of owner\n\
"), stdout);
fputs (_("\
%h - Number of hard links\n\
%i - Inode number\n\
%N - Quoted File name with dereference if symbolic link\n\
%n - File name\n\
%o - IO block size\n\
%s - Total size, in bytes\n\
%T - Minor device type in hex\n\
%t - Major device type in hex\n\
"), stdout);
fputs (_("\
%U - User name of owner\n\
%u - User ID of owner\n\
%X - Time of last access as seconds since Epoch\n\
%x - Time of last access\n\
%Y - Time of last modification as seconds since Epoch\n\
%y - Time of last modification\n\
%Z - Time of last change as seconds since Epoch\n\
%z - Time of last change\n\
\n\
"), stdout);
fputs (_("\
Valid format sequences for file systems:\n\
\n\
%a - Free blocks available to non-superuser\n\
%b - Total data blocks in file system\n\
%c - Total file nodes in file system\n\
%d - Free file nodes in file system\n\
%f - Free blocks in file system\n\
"), stdout);
fputs (_("\
%i - File System id in hex\n\
%l - Maximum length of filenames\n\
%n - File name\n\
%s - Optimal transfer block size\n\
%T - Type in human readable form\n\
%t - Type in hex\n\
"), stdout);
printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
}
exit (status);
}
int
main (int argc, char *argv[])
{
int c;
int i;
int follow_links = 0;
int fs = 0;
int terse = 0;
char *format = NULL;
program_name = argv[0];
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
atexit (close_stdout);
while ((c = getopt_long (argc, argv, "c:fLlt", long_options, NULL)) != -1)
{
switch (c)
{
case 'c':
format = optarg;
break;
case 'l': /* deprecated */
case 'L':
follow_links = 1;
break;
case 'f':
fs = 1;
break;
case 't':
terse = 1;
break;
case_GETOPT_HELP_CHAR;
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
default:
usage (EXIT_FAILURE);
}
}
if (argc == optind)
{
error (0, 0, _("too few arguments"));
usage (EXIT_FAILURE);
}
for (i = optind; i < argc; i++)
{
if (fs == 0)
do_stat (argv[i], follow_links, terse, format);
else
do_statfs (argv[i], terse, format);
}
exit (EXIT_SUCCESS);
}
相关阅读 更多 +