LCOV - code coverage report
Current view: top level - src - stat.c (source / functions) Hit Total Coverage
Test: coreutils.info Lines: 345 477 72.3 %
Date: 2018-01-30 Functions: 17 17 100.0 %

          Line data    Source code
       1             : /* stat.c -- display file or file system status
       2             :    Copyright (C) 2001-2008 Free Software Foundation, Inc.
       3             : 
       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 3 of the License, or
       7             :    (at your option) any later version.
       8             : 
       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.
      13             : 
      14             :    You should have received a copy of the GNU General Public License
      15             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      16             : 
      17             :    Written by Michael Meskes.  */
      18             : 
      19             : #include <config.h>
      20             : 
      21             : /* Keep this conditional in sync with the similar conditional in
      22             :    ../m4/stat-prog.m4.  */
      23             : #if (STAT_STATVFS \
      24             :      && (HAVE_STRUCT_STATVFS_F_BASETYPE || HAVE_STRUCT_STATVFS_F_FSTYPENAME \
      25             :          || (! HAVE_STRUCT_STATFS_F_FSTYPENAME && HAVE_STRUCT_STATVFS_F_TYPE)))
      26             : # define USE_STATVFS 1
      27             : #else
      28             : # define USE_STATVFS 0
      29             : #endif
      30             : 
      31             : #include <stddef.h>
      32             : #include <stdio.h>
      33             : #include <sys/types.h>
      34             : #include <pwd.h>
      35             : #include <grp.h>
      36             : #if USE_STATVFS
      37             : # include <sys/statvfs.h>
      38             : #elif HAVE_SYS_VFS_H
      39             : # include <sys/vfs.h>
      40             : #elif HAVE_SYS_MOUNT_H && HAVE_SYS_PARAM_H
      41             : /* NOTE: freebsd5.0 needs sys/param.h and sys/mount.h for statfs.
      42             :    It does have statvfs.h, but shouldn't use it, since it doesn't
      43             :    HAVE_STRUCT_STATVFS_F_BASETYPE.  So find a clean way to fix it.  */
      44             : /* NetBSD 1.5.2 needs these, for the declaration of struct statfs. */
      45             : # include <sys/param.h>
      46             : # include <sys/mount.h>
      47             : # if HAVE_NETINET_IN_H && HAVE_NFS_NFS_CLNT_H && HAVE_NFS_VFS_H
      48             : /* Ultrix 4.4 needs these for the declaration of struct statfs.  */
      49             : #  include <netinet/in.h>
      50             : #  include <nfs/nfs_clnt.h>
      51             : #  include <nfs/vfs.h>
      52             : # endif
      53             : #elif HAVE_OS_H /* BeOS */
      54             : # include <fs_info.h>
      55             : #endif
      56             : #include <selinux/selinux.h>
      57             : 
      58             : #include "system.h"
      59             : 
      60             : #include "error.h"
      61             : #include "filemode.h"
      62             : #include "file-type.h"
      63             : #include "fs.h"
      64             : #include "getopt.h"
      65             : #include "inttostr.h"
      66             : #include "quote.h"
      67             : #include "quotearg.h"
      68             : #include "stat-time.h"
      69             : #include "strftime.h"
      70             : #include "areadlink.h"
      71             : 
      72             : #define alignof(type) offsetof (struct { char c; type x; }, x)
      73             : 
      74             : #if USE_STATVFS
      75             : # define STRUCT_STATVFS struct statvfs
      76             : # define STRUCT_STATXFS_F_FSID_IS_INTEGER STRUCT_STATVFS_F_FSID_IS_INTEGER
      77             : # define HAVE_STRUCT_STATXFS_F_TYPE HAVE_STRUCT_STATVFS_F_TYPE
      78             : # if HAVE_STRUCT_STATVFS_F_NAMEMAX
      79             : #  define SB_F_NAMEMAX(S) ((S)->f_namemax)
      80             : # endif
      81             : # define STATFS statvfs
      82             : # define STATFS_FRSIZE(S) ((S)->f_frsize)
      83             : #else
      84             : # define HAVE_STRUCT_STATXFS_F_TYPE HAVE_STRUCT_STATFS_F_TYPE
      85             : # if HAVE_STRUCT_STATFS_F_NAMELEN
      86             : #  define SB_F_NAMEMAX(S) ((S)->f_namelen)
      87             : # endif
      88             : # define STATFS statfs
      89             : # if HAVE_OS_H /* BeOS */
      90             : /* BeOS has a statvfs function, but it does not return sensible values
      91             :    for f_files, f_ffree and f_favail, and lacks f_type, f_basetype and
      92             :    f_fstypename.  Use 'struct fs_info' instead.  */
      93             : static int
      94             : statfs (char const *filename, struct fs_info *buf)
      95             : {
      96             :   dev_t device = dev_for_path (filename);
      97             :   if (device < 0)
      98             :     {
      99             :       errno = (device == B_ENTRY_NOT_FOUND ? ENOENT
     100             :                : device == B_BAD_VALUE ? EINVAL
     101             :                : device == B_NAME_TOO_LONG ? ENAMETOOLONG
     102             :                : device == B_NO_MEMORY ? ENOMEM
     103             :                : device == B_FILE_ERROR ? EIO
     104             :                : 0);
     105             :       return -1;
     106             :     }
     107             :   /* If successful, buf->dev will be == device.  */
     108             :   return fs_stat_dev (device, buf);
     109             : }
     110             : #  define f_fsid dev
     111             : #  define f_blocks total_blocks
     112             : #  define f_bfree free_blocks
     113             : #  define f_bavail free_blocks
     114             : #  define f_bsize io_size
     115             : #  define f_files total_nodes
     116             : #  define f_ffree free_nodes
     117             : #  define STRUCT_STATVFS struct fs_info
     118             : #  define STRUCT_STATXFS_F_FSID_IS_INTEGER true
     119             : #  define STATFS_FRSIZE(S) ((S)->block_size)
     120             : # else
     121             : #  define STRUCT_STATVFS struct statfs
     122             : #  define STRUCT_STATXFS_F_FSID_IS_INTEGER STRUCT_STATFS_F_FSID_IS_INTEGER
     123             : #  define STATFS_FRSIZE(S) 0
     124             : # endif
     125             : #endif
     126             : 
     127             : #ifdef SB_F_NAMEMAX
     128             : # define OUT_NAMEMAX out_uint
     129             : #else
     130             : /* NetBSD 1.5.2 has neither f_namemax nor f_namelen.  */
     131             : # define SB_F_NAMEMAX(S) "*"
     132             : # define OUT_NAMEMAX out_string
     133             : #endif
     134             : 
     135             : #if HAVE_STRUCT_STATVFS_F_BASETYPE
     136             : # define STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME f_basetype
     137             : #else
     138             : # if HAVE_STRUCT_STATVFS_F_FSTYPENAME || HAVE_STRUCT_STATFS_F_FSTYPENAME
     139             : #  define STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME f_fstypename
     140             : # elif HAVE_OS_H /* BeOS */
     141             : #  define STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME fsh_name
     142             : # endif
     143             : #endif
     144             : 
     145             : /* FIXME: these are used by printf.c, too */
     146             : #define isodigit(c) ('0' <= (c) && (c) <= '7')
     147             : #define octtobin(c) ((c) - '0')
     148             : #define hextobin(c) ((c) >= 'a' && (c) <= 'f' ? (c) - 'a' + 10 : \
     149             :                      (c) >= 'A' && (c) <= 'F' ? (c) - 'A' + 10 : (c) - '0')
     150             : 
     151             : #define PROGRAM_NAME "stat"
     152             : 
     153             : #define AUTHORS "Michael Meskes"
     154             : 
     155             : enum
     156             : {
     157             :   PRINTF_OPTION = CHAR_MAX + 1
     158             : };
     159             : 
     160             : static struct option const long_options[] = {
     161             :   {"context", no_argument, 0, 'Z'},
     162             :   {"dereference", no_argument, NULL, 'L'},
     163             :   {"file-system", no_argument, NULL, 'f'},
     164             : 
     165             :   /* obsolete and undocumented alias: FIXME: remove in 2009 */
     166             :   {"filesystem", no_argument, NULL, 'f'},
     167             : 
     168             :   {"format", required_argument, NULL, 'c'},
     169             :   {"printf", required_argument, NULL, PRINTF_OPTION},
     170             :   {"terse", no_argument, NULL, 't'},
     171             :   {GETOPT_HELP_OPTION_DECL},
     172             :   {GETOPT_VERSION_OPTION_DECL},
     173             :   {NULL, 0, NULL, 0}
     174             : };
     175             : 
     176             : char *program_name;
     177             : 
     178             : /* Whether to follow symbolic links;  True for --dereference (-L).  */
     179             : static bool follow_links;
     180             : 
     181             : /* Whether to interpret backslash-escape sequences.
     182             :    True for --printf=FMT, not for --format=FMT (-c).  */
     183             : static bool interpret_backslash_escapes;
     184             : 
     185             : /* The trailing delimiter string:
     186             :    "" for --printf=FMT, "\n" for --format=FMT (-c).  */
     187             : static char const *trailing_delim = "";
     188             : 
     189             : /* Return the type of the specified file system.
     190             :    Some systems have statfvs.f_basetype[FSTYPSZ] (AIX, HP-UX, and Solaris).
     191             :    Others have statvfs.f_fstypename[_VFS_NAMELEN] (NetBSD 3.0).
     192             :    Others have statfs.f_fstypename[MFSNAMELEN] (NetBSD 1.5.2).
     193             :    Still others have neither and have to get by with f_type (Linux).
     194             :    But f_type may only exist in statfs (Cygwin).  */
     195             : static char const *
     196           6 : human_fstype (STRUCT_STATVFS const *statfsbuf)
     197             : {
     198             : #ifdef STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME
     199             :   return statfsbuf->STATXFS_FILE_SYSTEM_TYPE_MEMBER_NAME;
     200             : #else
     201           6 :   switch (statfsbuf->f_type)
     202             :     {
     203             : # if defined __linux__
     204             : 
     205             :       /* Compare with what's in libc:
     206             :          f=/a/libc/sysdeps/unix/sysv/linux/linux_fsinfo.h
     207             :          sed -n '/ADFS_SUPER_MAGIC/,/SYSFS_MAGIC/p' $f \
     208             :            | perl -n -e '/#define (.*?)_(?:SUPER_)MAGIC\s+0x(\S+)/' \
     209             :              -e 'and print "case S_MAGIC_$1: /\* 0x" . uc($2) . " *\/\n"' \
     210             :            | sort > sym_libc
     211             :          perl -ne '/^\s+(case S_MAGIC_.*?): \/\* 0x(\S+) \*\//' \
     212             :              -e 'and do { $v=uc$2; print "$1: /\* 0x$v *\/\n"}' stat.c \
     213             :            | sort > sym_stat
     214             :          diff -u sym_stat sym_libc
     215             :       */
     216             : 
     217             :       /* Also sync from the list in "man 2 statfs".  */
     218             : 
     219             :       /* IMPORTANT NOTE: Each of the following `case S_MAGIC_...:'
     220             :          statements must be followed by a hexadecimal constant in
     221             :          a comment.  The S_MAGIC_... name and constant are automatically
     222             :          combined to produce the #define directives in fs.h.  */
     223             : 
     224           0 :     case S_MAGIC_ADFS: /* 0xADF5 */
     225           0 :       return "adfs";
     226           0 :     case S_MAGIC_AFFS: /* 0xADFF */
     227           0 :       return "affs";
     228           0 :     case S_MAGIC_AUTOFS: /* 0x187 */
     229           0 :       return "autofs";
     230           0 :     case S_MAGIC_BEFS: /* 0x42465331 */
     231           0 :       return "befs";
     232           0 :     case S_MAGIC_BFS: /* 0x1BADFACE */
     233           0 :       return "bfs";
     234           0 :     case S_MAGIC_BINFMT_MISC: /* 0x42494e4d */
     235           0 :       return "binfmt_misc";
     236           0 :     case S_MAGIC_CODA: /* 0x73757245 */
     237           0 :       return "coda";
     238           0 :     case S_MAGIC_COH: /* 0x012FF7B7 */
     239           0 :       return "coh";
     240           0 :     case S_MAGIC_CRAMFS: /* 0x28CD3D45 */
     241           0 :       return "cramfs";
     242           0 :     case S_MAGIC_DEVFS: /* 0x1373 */
     243           0 :       return "devfs";
     244           0 :     case S_MAGIC_DEVPTS: /* 0x1CD1 */
     245           0 :       return "devpts";
     246           0 :     case S_MAGIC_EFS: /* 0x414A53 */
     247           0 :       return "efs";
     248           0 :     case S_MAGIC_EXT: /* 0x137D */
     249           0 :       return "ext";
     250           0 :     case S_MAGIC_EXT2: /* 0xEF53 */
     251           0 :       return "ext2/ext3";
     252           0 :     case S_MAGIC_EXT2_OLD: /* 0xEF51 */
     253           0 :       return "ext2";
     254           0 :     case S_MAGIC_FAT: /* 0x4006 */
     255           0 :       return "fat";
     256           0 :     case S_MAGIC_FUSECTL: /* 0x65735543 */
     257           0 :       return "fusectl";
     258           0 :     case S_MAGIC_HPFS: /* 0xF995E849 */
     259           0 :       return "hpfs";
     260           0 :     case S_MAGIC_HUGETLBFS: /* 0x958458f6 */
     261           0 :       return "hugetlbfs";
     262           0 :     case S_MAGIC_ISOFS: /* 0x9660 */
     263           0 :       return "isofs";
     264           0 :     case S_MAGIC_ISOFS_R_WIN: /* 0x4004 */
     265           0 :       return "isofs";
     266           0 :     case S_MAGIC_ISOFS_WIN: /* 0x4000 */
     267           0 :       return "isofs";
     268           0 :     case S_MAGIC_JFFS2: /* 0x72B6 */
     269           0 :       return "jffs2";
     270           0 :     case S_MAGIC_JFFS: /* 0x07C0 */
     271           0 :       return "jffs";
     272           0 :     case S_MAGIC_JFS: /* 0x3153464A */
     273           0 :       return "jfs";
     274           0 :     case S_MAGIC_MINIX: /* 0x137F */
     275           0 :       return "minix";
     276           0 :     case S_MAGIC_MINIX_30: /* 0x138F */
     277           0 :       return "minix (30 char.)";
     278           0 :     case S_MAGIC_MINIX_V2: /* 0x2468 */
     279           0 :       return "minix v2";
     280           0 :     case S_MAGIC_MINIX_V2_30: /* 0x2478 */
     281           0 :       return "minix v2 (30 char.)";
     282           0 :     case S_MAGIC_MSDOS: /* 0x4D44 */
     283           0 :       return "msdos";
     284           0 :     case S_MAGIC_NCP: /* 0x564C */
     285           0 :       return "novell";
     286           0 :     case S_MAGIC_NFS: /* 0x6969 */
     287           0 :       return "nfs";
     288           0 :     case S_MAGIC_NFSD: /* 0x6E667364 */
     289           0 :       return "nfsd";
     290           0 :     case S_MAGIC_NTFS: /* 0x5346544E */
     291           0 :       return "ntfs";
     292           0 :     case S_MAGIC_OPENPROM: /* 0x9fa1 */
     293           0 :       return "openprom";
     294           0 :     case S_MAGIC_PROC: /* 0x9FA0 */
     295           0 :       return "proc";
     296           0 :     case S_MAGIC_QNX4: /* 0x002F */
     297           0 :       return "qnx4";
     298           0 :     case S_MAGIC_RAMFS: /* 0x858458F6 */
     299           0 :       return "ramfs";
     300           0 :     case S_MAGIC_REISERFS: /* 0x52654973 */
     301           0 :       return "reiserfs";
     302           0 :     case S_MAGIC_ROMFS: /* 0x7275 */
     303           0 :       return "romfs";
     304           0 :     case S_MAGIC_SMB: /* 0x517B */
     305           0 :       return "smb";
     306           0 :     case S_MAGIC_SQUASHFS: /* 0x73717368 */
     307           0 :       return "squashfs";
     308           0 :     case S_MAGIC_SYSFS: /* 0x62656572 */
     309           0 :       return "sysfs";
     310           0 :     case S_MAGIC_SYSV2: /* 0x012FF7B6 */
     311           0 :       return "sysv2";
     312           0 :     case S_MAGIC_SYSV4: /* 0x012FF7B5 */
     313           0 :       return "sysv4";
     314           0 :     case S_MAGIC_TMPFS: /* 0x1021994 */
     315           0 :       return "tmpfs";
     316           0 :     case S_MAGIC_UDF: /* 0x15013346 */
     317           0 :       return "udf";
     318           0 :     case S_MAGIC_UFS: /* 0x00011954 */
     319           0 :       return "ufs";
     320           0 :     case S_MAGIC_UFS_BYTESWAPPED: /* 0x54190100 */
     321           0 :       return "ufs";
     322           0 :     case S_MAGIC_USBDEVFS: /* 0x9FA2 */
     323           0 :       return "usbdevfs";
     324           0 :     case S_MAGIC_VXFS: /* 0xA501FCF5 */
     325           0 :       return "vxfs";
     326           0 :     case S_MAGIC_XENIX: /* 0x012FF7B4 */
     327           0 :       return "xenix";
     328           0 :     case S_MAGIC_XFS: /* 0x58465342 */
     329           0 :       return "xfs";
     330           0 :     case S_MAGIC_XIAFS: /* 0x012FD16D */
     331           0 :       return "xia";
     332             : 
     333             : # elif __GNU__
     334             :     case FSTYPE_UFS:
     335             :       return "ufs";
     336             :     case FSTYPE_NFS:
     337             :       return "nfs";
     338             :     case FSTYPE_GFS:
     339             :       return "gfs";
     340             :     case FSTYPE_LFS:
     341             :       return "lfs";
     342             :     case FSTYPE_SYSV:
     343             :       return "sysv";
     344             :     case FSTYPE_FTP:
     345             :       return "ftp";
     346             :     case FSTYPE_TAR:
     347             :       return "tar";
     348             :     case FSTYPE_AR:
     349             :       return "ar";
     350             :     case FSTYPE_CPIO:
     351             :       return "cpio";
     352             :     case FSTYPE_MSLOSS:
     353             :       return "msloss";
     354             :     case FSTYPE_CPM:
     355             :       return "cpm";
     356             :     case FSTYPE_HFS:
     357             :       return "hfs";
     358             :     case FSTYPE_DTFS:
     359             :       return "dtfs";
     360             :     case FSTYPE_GRFS:
     361             :       return "grfs";
     362             :     case FSTYPE_TERM:
     363             :       return "term";
     364             :     case FSTYPE_DEV:
     365             :       return "dev";
     366             :     case FSTYPE_PROC:
     367             :       return "proc";
     368             :     case FSTYPE_IFSOCK:
     369             :       return "ifsock";
     370             :     case FSTYPE_AFS:
     371             :       return "afs";
     372             :     case FSTYPE_DFS:
     373             :       return "dfs";
     374             :     case FSTYPE_PROC9:
     375             :       return "proc9";
     376             :     case FSTYPE_SOCKET:
     377             :       return "socket";
     378             :     case FSTYPE_MISC:
     379             :       return "misc";
     380             :     case FSTYPE_EXT2FS:
     381             :       return "ext2/ext3";
     382             :     case FSTYPE_HTTP:
     383             :       return "http";
     384             :     case FSTYPE_MEMFS:
     385             :       return "memfs";
     386             :     case FSTYPE_ISO9660:
     387             :       return "iso9660";
     388             : # endif
     389           6 :     default:
     390             :       {
     391           6 :         unsigned long int type = statfsbuf->f_type;
     392             :         static char buf[sizeof "UNKNOWN (0x%lx)" - 3
     393             :                         + (sizeof type * CHAR_BIT + 3) / 4];
     394           6 :         sprintf (buf, "UNKNOWN (0x%lx)", type);
     395           6 :         return buf;
     396             :       }
     397             :     }
     398             : #endif
     399             : }
     400             : 
     401             : static char *
     402          36 : human_access (struct stat const *statbuf)
     403             : {
     404             :   static char modebuf[12];
     405          36 :   filemodestring (statbuf, modebuf);
     406          36 :   modebuf[10] = 0;
     407          36 :   return modebuf;
     408             : }
     409             : 
     410             : static char *
     411         108 : human_time (struct timespec t)
     412             : {
     413             :   static char str[MAX (INT_BUFSIZE_BOUND (intmax_t),
     414             :                        (INT_STRLEN_BOUND (int) /* YYYY */
     415             :                         + 1 /* because YYYY might equal INT_MAX + 1900 */
     416             :                         + sizeof "-MM-DD HH:MM:SS.NNNNNNNNN +ZZZZ"))];
     417         108 :   struct tm const *tm = localtime (&t.tv_sec);
     418         108 :   if (tm == NULL)
     419             :     return (TYPE_SIGNED (time_t)
     420             :             ? imaxtostr (t.tv_sec, str)
     421           5 :             : umaxtostr (t.tv_sec, str));
     422         103 :   nstrftime (str, sizeof str, "%Y-%m-%d %H:%M:%S.%N %z", tm, 0, t.tv_nsec);
     423         103 :   return str;
     424             : }
     425             : 
     426             : static void
     427         304 : out_string (char *pformat, size_t prefix_len, char const *arg)
     428             : {
     429         304 :   strcpy (pformat + prefix_len, "s");
     430         304 :   printf (pformat, arg);
     431         304 : }
     432             : static void
     433          33 : out_int (char *pformat, size_t prefix_len, intmax_t arg)
     434             : {
     435          33 :   strcpy (pformat + prefix_len, PRIdMAX);
     436          33 :   printf (pformat, arg);
     437          33 : }
     438             : static void
     439         315 : out_uint (char *pformat, size_t prefix_len, uintmax_t arg)
     440             : {
     441         315 :   strcpy (pformat + prefix_len, PRIuMAX);
     442         315 :   printf (pformat, arg);
     443         315 : }
     444             : static void
     445          36 : out_uint_o (char *pformat, size_t prefix_len, uintmax_t arg)
     446             : {
     447          36 :   strcpy (pformat + prefix_len, PRIoMAX);
     448          36 :   printf (pformat, arg);
     449          36 : }
     450             : static void
     451          46 : out_uint_x (char *pformat, size_t prefix_len, uintmax_t arg)
     452             : {
     453          46 :   strcpy (pformat + prefix_len, PRIxMAX);
     454          46 :   printf (pformat, arg);
     455          46 : }
     456             : 
     457             : /* Very specialized function (modifies FORMAT), just so as to avoid
     458             :    duplicating this code between both print_statfs and print_stat.  */
     459             : static void
     460           2 : out_file_context (char const *filename, char *pformat, size_t prefix_len)
     461             : {
     462             :   char *scontext;
     463           2 :   if ((follow_links
     464           2 :        ? getfilecon (filename, &scontext)
     465           2 :        : lgetfilecon (filename, &scontext)) < 0)
     466             :     {
     467           2 :       error (0, errno, _("failed to get security context of %s"),
     468             :              quote (filename));
     469           2 :       scontext = NULL;
     470             :     }
     471           2 :   strcpy (pformat + prefix_len, "s");
     472           2 :   printf (pformat, (scontext ? scontext : "?"));
     473           2 :   if (scontext)
     474           0 :     freecon (scontext);
     475           2 : }
     476             : 
     477             : /* print statfs info */
     478             : static void
     479          66 : print_statfs (char *pformat, size_t prefix_len, char m, char const *filename,
     480             :               void const *data)
     481             : {
     482          66 :   STRUCT_STATVFS const *statfsbuf = data;
     483             : 
     484          66 :   switch (m)
     485             :     {
     486           6 :     case 'n':
     487           6 :       out_string (pformat, prefix_len, filename);
     488           6 :       break;
     489             : 
     490           6 :     case 'i':
     491             :       {
     492             : #if STRUCT_STATXFS_F_FSID_IS_INTEGER
     493             :         uintmax_t fsid = statfsbuf->f_fsid;
     494             : #else
     495             :         typedef unsigned int fsid_word;
     496             :         verify (alignof (STRUCT_STATVFS) % alignof (fsid_word) == 0);
     497             :         verify (offsetof (STRUCT_STATVFS, f_fsid) % alignof (fsid_word) == 0);
     498             :         verify (sizeof statfsbuf->f_fsid % alignof (fsid_word) == 0);
     499           6 :         fsid_word const *p = (fsid_word *) &statfsbuf->f_fsid;
     500             : 
     501             :         /* Assume a little-endian word order, as that is compatible
     502             :            with glibc's statvfs implementation.  */
     503           6 :         uintmax_t fsid = 0;
     504           6 :         int words = sizeof statfsbuf->f_fsid / sizeof *p;
     505             :         int i;
     506          18 :         for (i = 0; i < words && i * sizeof *p < sizeof fsid; i++)
     507             :           {
     508          12 :             uintmax_t u = p[words - 1 - i];
     509          12 :             fsid |= u << (i * CHAR_BIT * sizeof *p);
     510             :           }
     511             : #endif
     512           6 :         out_uint_x (pformat, prefix_len, fsid);
     513             :       }
     514           6 :       break;
     515             : 
     516           6 :     case 'l':
     517           6 :       OUT_NAMEMAX (pformat, prefix_len, SB_F_NAMEMAX (statfsbuf));
     518           6 :       break;
     519           0 :     case 't':
     520             : #if HAVE_STRUCT_STATXFS_F_TYPE
     521           0 :       out_uint_x (pformat, prefix_len, statfsbuf->f_type);
     522             : #else
     523             :       fputc ('?', stdout);
     524             : #endif
     525           0 :       break;
     526           6 :     case 'T':
     527           6 :       out_string (pformat, prefix_len, human_fstype (statfsbuf));
     528           6 :       break;
     529           6 :     case 'b':
     530           6 :       out_int (pformat, prefix_len, statfsbuf->f_blocks);
     531           6 :       break;
     532           6 :     case 'f':
     533           6 :       out_int (pformat, prefix_len, statfsbuf->f_bfree);
     534           6 :       break;
     535           6 :     case 'a':
     536           6 :       out_int (pformat, prefix_len, statfsbuf->f_bavail);
     537           6 :       break;
     538           6 :     case 's':
     539           6 :       out_uint (pformat, prefix_len, statfsbuf->f_bsize);
     540           6 :       break;
     541           6 :     case 'S':
     542             :       {
     543           6 :         uintmax_t frsize = STATFS_FRSIZE (statfsbuf);
     544           6 :         if (! frsize)
     545           6 :           frsize = statfsbuf->f_bsize;
     546           6 :         out_uint (pformat, prefix_len, frsize);
     547             :       }
     548           6 :       break;
     549           6 :     case 'c':
     550           6 :       out_int (pformat, prefix_len, statfsbuf->f_files);
     551           6 :       break;
     552           6 :     case 'd':
     553           6 :       out_int (pformat, prefix_len, statfsbuf->f_ffree);
     554           6 :       break;
     555           0 :     case 'C':
     556           0 :       out_file_context (filename, pformat, prefix_len);
     557           0 :       break;
     558           0 :     default:
     559           0 :       fputc ('?', stdout);
     560           0 :       break;
     561             :     }
     562          66 : }
     563             : 
     564             : /* print stat info */
     565             : static void
     566         669 : print_stat (char *pformat, size_t prefix_len, char m,
     567             :             char const *filename, void const *data)
     568             : {
     569         669 :   struct stat *statbuf = (struct stat *) data;
     570             :   struct passwd *pw_ent;
     571             :   struct group *gw_ent;
     572             : 
     573         669 :   switch (m)
     574             :     {
     575           1 :     case 'n':
     576           1 :       out_string (pformat, prefix_len, filename);
     577           1 :       break;
     578          36 :     case 'N':
     579          36 :       out_string (pformat, prefix_len, quote (filename));
     580          36 :       if (S_ISLNK (statbuf->st_mode))
     581             :         {
     582           3 :           char *linkname = areadlink_with_size (filename, statbuf->st_size);
     583           3 :           if (linkname == NULL)
     584             :             {
     585           0 :               error (0, errno, _("cannot read symbolic link %s"),
     586             :                      quote (filename));
     587           0 :               return;
     588             :             }
     589           3 :           printf (" -> ");
     590           3 :           out_string (pformat, prefix_len, quote (linkname));
     591             :         }
     592          36 :       break;
     593          36 :     case 'd':
     594          36 :       out_uint (pformat, prefix_len, statbuf->st_dev);
     595          36 :       break;
     596          37 :     case 'D':
     597          37 :       out_uint_x (pformat, prefix_len, statbuf->st_dev);
     598          37 :       break;
     599          37 :     case 'i':
     600          37 :       out_uint (pformat, prefix_len, statbuf->st_ino);
     601          37 :       break;
     602          36 :     case 'a':
     603          36 :       out_uint_o (pformat, prefix_len, statbuf->st_mode & CHMOD_MODE_BITS);
     604          36 :       break;
     605          36 :     case 'A':
     606          36 :       out_string (pformat, prefix_len, human_access (statbuf));
     607          36 :       break;
     608           1 :     case 'f':
     609           1 :       out_uint_x (pformat, prefix_len, statbuf->st_mode);
     610           1 :       break;
     611          36 :     case 'F':
     612          36 :       out_string (pformat, prefix_len, file_type (statbuf));
     613          36 :       break;
     614          37 :     case 'h':
     615          37 :       out_uint (pformat, prefix_len, statbuf->st_nlink);
     616          37 :       break;
     617          37 :     case 'u':
     618          37 :       out_uint (pformat, prefix_len, statbuf->st_uid);
     619          37 :       break;
     620          36 :     case 'U':
     621          36 :       setpwent ();
     622          36 :       pw_ent = getpwuid (statbuf->st_uid);
     623          36 :       out_string (pformat, prefix_len,
     624             :                   pw_ent ? pw_ent->pw_name : "UNKNOWN");
     625          36 :       break;
     626          37 :     case 'g':
     627          37 :       out_uint (pformat, prefix_len, statbuf->st_gid);
     628          37 :       break;
     629          36 :     case 'G':
     630          36 :       setgrent ();
     631          36 :       gw_ent = getgrgid (statbuf->st_gid);
     632          36 :       out_string (pformat, prefix_len,
     633             :                   gw_ent ? gw_ent->gr_name : "UNKNOWN");
     634          36 :       break;
     635           1 :     case 't':
     636           1 :       out_uint_x (pformat, prefix_len, major (statbuf->st_rdev));
     637           1 :       break;
     638           1 :     case 'T':
     639           1 :       out_uint_x (pformat, prefix_len, minor (statbuf->st_rdev));
     640           1 :       break;
     641          37 :     case 's':
     642          37 :       out_uint (pformat, prefix_len, statbuf->st_size);
     643          37 :       break;
     644           2 :     case 'B':
     645           2 :       out_uint (pformat, prefix_len, ST_NBLOCKSIZE);
     646           2 :       break;
     647          37 :     case 'b':
     648          37 :       out_uint (pformat, prefix_len, ST_NBLOCKS (*statbuf));
     649          37 :       break;
     650          37 :     case 'o':
     651          37 :       out_uint (pformat, prefix_len, statbuf->st_blksize);
     652          37 :       break;
     653          36 :     case 'x':
     654          36 :       out_string (pformat, prefix_len, human_time (get_stat_atime (statbuf)));
     655          36 :       break;
     656           1 :     case 'X':
     657             :       if (TYPE_SIGNED (time_t))
     658           1 :         out_int (pformat, prefix_len, statbuf->st_atime);
     659             :       else
     660             :         out_uint (pformat, prefix_len, statbuf->st_atime);
     661           1 :       break;
     662          36 :     case 'y':
     663          36 :       out_string (pformat, prefix_len, human_time (get_stat_mtime (statbuf)));
     664          36 :       break;
     665           1 :     case 'Y':
     666             :       if (TYPE_SIGNED (time_t))
     667           1 :         out_int (pformat, prefix_len, statbuf->st_mtime);
     668             :       else
     669             :         out_uint (pformat, prefix_len, statbuf->st_mtime);
     670           1 :       break;
     671          36 :     case 'z':
     672          36 :       out_string (pformat, prefix_len, human_time (get_stat_ctime (statbuf)));
     673          36 :       break;
     674           1 :     case 'Z':
     675             :       if (TYPE_SIGNED (time_t))
     676           1 :         out_int (pformat, prefix_len, statbuf->st_ctime);
     677             :       else
     678             :         out_uint (pformat, prefix_len, statbuf->st_ctime);
     679           1 :       break;
     680           2 :     case 'C':
     681           2 :       out_file_context (filename, pformat, prefix_len);
     682           2 :       break;
     683           2 :     default:
     684           2 :       fputc ('?', stdout);
     685           2 :       break;
     686             :     }
     687             : }
     688             : 
     689             : /* Output a single-character \ escape.  */
     690             : 
     691             : static void
     692           8 : print_esc_char (char c)
     693             : {
     694           8 :   switch (c)
     695             :     {
     696           1 :     case 'a':                   /* Alert. */
     697           1 :       c ='\a';
     698           1 :       break;
     699           1 :     case 'b':                   /* Backspace. */
     700           1 :       c ='\b';
     701           1 :       break;
     702           1 :     case 'f':                   /* Form feed. */
     703           1 :       c ='\f';
     704           1 :       break;
     705           1 :     case 'n':                   /* New line. */
     706           1 :       c ='\n';
     707           1 :       break;
     708           1 :     case 'r':                   /* Carriage return. */
     709           1 :       c ='\r';
     710           1 :       break;
     711           1 :     case 't':                   /* Horizontal tab. */
     712           1 :       c ='\t';
     713           1 :       break;
     714           1 :     case 'v':                   /* Vertical tab. */
     715           1 :       c ='\v';
     716           1 :       break;
     717           0 :     case '"':
     718             :     case '\\':
     719           0 :       break;
     720           1 :     default:
     721           1 :       error (0, 0, _("warning: unrecognized escape `\\%c'"), c);
     722           1 :       break;
     723             :     }
     724           8 :   putchar (c);
     725           8 : }
     726             : 
     727             : static void
     728          69 : print_it (char const *format, char const *filename,
     729             :           void (*print_func) (char *, size_t, char, char const *, void const *),
     730             :           void const *data)
     731             : {
     732             :   /* Add 2 to accommodate our conversion of the stat `%s' format string
     733             :      to the longer printf `%llu' one.  */
     734             :   enum
     735             :     {
     736             :       MAX_ADDITIONAL_BYTES =
     737             :         (MAX (sizeof PRIdMAX,
     738             :               MAX (sizeof PRIoMAX, MAX (sizeof PRIuMAX, sizeof PRIxMAX)))
     739             :          - 1)
     740             :     };
     741          69 :   size_t n_alloc = strlen (format) + MAX_ADDITIONAL_BYTES + 1;
     742          69 :   char *dest = xmalloc (n_alloc);
     743             :   char const *b;
     744        6247 :   for (b = format; *b; b++)
     745             :     {
     746        6179 :       switch (*b)
     747             :         {
     748         737 :         case '%':
     749             :           {
     750         737 :             size_t len = strspn (b + 1, "#-+.I 0123456789");
     751         737 :             char const *fmt_char = b + len + 1;
     752         737 :             memcpy (dest, b, len + 1);
     753             : 
     754         737 :             b = fmt_char;
     755         737 :             switch (*fmt_char)
     756             :               {
     757           2 :               case '\0':
     758           2 :                 --b;
     759             :                 /* fall through */
     760           2 :               case '%':
     761           2 :                 if (0 < len)
     762             :                   {
     763           1 :                     dest[len + 1] = *fmt_char;
     764           1 :                     dest[len + 2] = '\0';
     765           1 :                     error (EXIT_FAILURE, 0, _("%s: invalid directive"),
     766             :                            quotearg_colon (dest));
     767             :                   }
     768           1 :                 putchar ('%');
     769           1 :                 break;
     770         735 :               default:
     771         735 :                 print_func (dest, len + 1, *fmt_char, filename, data);
     772         735 :                 break;
     773             :               }
     774         736 :             break;
     775             :           }
     776             : 
     777          20 :         case '\\':
     778          20 :           if ( ! interpret_backslash_escapes)
     779             :             {
     780           9 :               putchar ('\\');
     781           9 :               break;
     782             :             }
     783          11 :           ++b;
     784          11 :           if (isodigit (*b))
     785           1 :             {
     786           1 :               int esc_value = octtobin (*b);
     787           1 :               int esc_length = 1;       /* number of octal digits */
     788           2 :               for (++b; esc_length < 3 && isodigit (*b);
     789           0 :                    ++esc_length, ++b)
     790             :                 {
     791           0 :                   esc_value = esc_value * 8 + octtobin (*b);
     792             :                 }
     793           1 :               putchar (esc_value);
     794           1 :               --b;
     795             :             }
     796          10 :           else if (*b == 'x' && isxdigit (to_uchar (b[1])))
     797           0 :             {
     798           0 :               int esc_value = hextobin (b[1]);  /* Value of \xhh escape. */
     799             :               /* A hexadecimal \xhh escape sequence must have
     800             :                  1 or 2 hex. digits.  */
     801           0 :               ++b;
     802           0 :               if (isxdigit (to_uchar (b[1])))
     803             :                 {
     804           0 :                   ++b;
     805           0 :                   esc_value = esc_value * 16 + hextobin (*b);
     806             :                 }
     807           0 :               putchar (esc_value);
     808             :             }
     809          10 :           else if (*b == '\0')
     810             :             {
     811           2 :               error (0, 0, _("warning: backslash at end of format"));
     812           2 :               putchar ('\\');
     813             :               /* Arrange to exit the loop.  */
     814           2 :               --b;
     815             :             }
     816             :           else
     817             :             {
     818           8 :               print_esc_char (*b);
     819             :             }
     820          11 :           break;
     821             : 
     822        5422 :         default:
     823        5422 :           putchar (*b);
     824        5422 :           break;
     825             :         }
     826             :     }
     827          68 :   free (dest);
     828             : 
     829          68 :   fputs (trailing_delim, stdout);
     830          68 : }
     831             : 
     832             : /* Stat the file system and print what we find.  */
     833             : static bool
     834           9 : do_statfs (char const *filename, bool terse, char const *format)
     835             : {
     836             :   STRUCT_STATVFS statfsbuf;
     837             : 
     838           9 :   if (STATFS (filename, &statfsbuf) != 0)
     839             :     {
     840           2 :       error (0, errno, _("cannot read file system information for %s"),
     841             :              quote (filename));
     842           2 :       return false;
     843             :     }
     844             : 
     845           7 :   if (format == NULL)
     846             :     {
     847           6 :       format = (terse
     848             :                 ? "%n %i %l %t %s %S %b %f %a %c %d\n"
     849           6 :                 : "  File: \"%n\"\n"
     850             :                 "    ID: %-8i Namelen: %-7l Type: %T\n"
     851             :                 "Block size: %-10s Fundamental block size: %S\n"
     852             :                 "Blocks: Total: %-10b Free: %-10f Available: %a\n"
     853             :                 "Inodes: Total: %-10c Free: %d\n");
     854             :     }
     855             : 
     856           7 :   print_it (format, filename, print_statfs, &statfsbuf);
     857           7 :   return true;
     858             : }
     859             : 
     860             : /* stat the file and print what we find */
     861             : static bool
     862          83 : do_stat (char const *filename, bool terse, char const *format)
     863             : {
     864             :   struct stat statbuf;
     865             : 
     866          83 :   if ((follow_links ? stat : lstat) (filename, &statbuf) != 0)
     867             :     {
     868          21 :       error (0, errno, _("cannot stat %s"), quote (filename));
     869          21 :       return false;
     870             :     }
     871             : 
     872          62 :   if (format == NULL)
     873             :     {
     874          37 :       if (terse)
     875             :         {
     876           1 :           format = "%n %s %b %f %u %g %D %i %h %t %T %X %Y %Z %o\n";
     877             :         }
     878             :       else
     879             :         {
     880             :           /* Temporary hack to match original output until conditional
     881             :              implemented.  */
     882          36 :           if (S_ISBLK (statbuf.st_mode) || S_ISCHR (statbuf.st_mode))
     883             :             {
     884           0 :               format =
     885             :                 "  File: %N\n"
     886             :                 "  Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n"
     887             :                 "Device: %Dh/%dd\tInode: %-10i  Links: %-5h"
     888             :                 " Device type: %t,%T\n"
     889             :                 "Access: (%04a/%10.10A)  Uid: (%5u/%8U)   Gid: (%5g/%8G)\n"
     890             :                 "Access: %x\n" "Modify: %y\n" "Change: %z\n";
     891             :             }
     892             :           else
     893             :             {
     894          36 :               format =
     895             :                 "  File: %N\n"
     896             :                 "  Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n"
     897             :                 "Device: %Dh/%dd\tInode: %-10i  Links: %h\n"
     898             :                 "Access: (%04a/%10.10A)  Uid: (%5u/%8U)   Gid: (%5g/%8G)\n"
     899             :                 "Access: %x\n" "Modify: %y\n" "Change: %z\n";
     900             :             }
     901             :         }
     902             :     }
     903          62 :   print_it (format, filename, print_stat, &statbuf);
     904          61 :   return true;
     905             : }
     906             : 
     907             : void
     908          12 : usage (int status)
     909             : {
     910          12 :   if (status != EXIT_SUCCESS)
     911          11 :     fprintf (stderr, _("Try `%s --help' for more information.\n"),
     912             :              program_name);
     913             :   else
     914             :     {
     915           1 :       printf (_("Usage: %s [OPTION] FILE...\n"), program_name);
     916           1 :       fputs (_("\
     917             : Display file or file system status.\n\
     918             : \n\
     919             :   -L, --dereference     follow links\n\
     920             :   -f, --file-system     display file system status instead of file status\n\
     921             : "), stdout);
     922           1 :       fputs (_("\
     923             :   -c  --format=FORMAT   use the specified FORMAT instead of the default;\n\
     924             :                           output a newline after each use of FORMAT\n\
     925             :       --printf=FORMAT   like --format, but interpret backslash escapes,\n\
     926             :                           and do not output a mandatory trailing newline.\n\
     927             :                           If you want a newline, include \\n in FORMAT.\n\
     928             :   -t, --terse           print the information in terse form\n\
     929             : "), stdout);
     930           1 :       fputs (HELP_OPTION_DESCRIPTION, stdout);
     931           1 :       fputs (VERSION_OPTION_DESCRIPTION, stdout);
     932             : 
     933           1 :       fputs (_("\n\
     934             : The valid format sequences for files (without --file-system):\n\
     935             : \n\
     936             :   %a   Access rights in octal\n\
     937             :   %A   Access rights in human readable form\n\
     938             :   %b   Number of blocks allocated (see %B)\n\
     939             :   %B   The size in bytes of each block reported by %b\n\
     940             :   %C   SELinux security context string\n\
     941             : "), stdout);
     942           1 :       fputs (_("\
     943             :   %d   Device number in decimal\n\
     944             :   %D   Device number in hex\n\
     945             :   %f   Raw mode in hex\n\
     946             :   %F   File type\n\
     947             :   %g   Group ID of owner\n\
     948             :   %G   Group name of owner\n\
     949             : "), stdout);
     950           1 :       fputs (_("\
     951             :   %h   Number of hard links\n\
     952             :   %i   Inode number\n\
     953             :   %n   File name\n\
     954             :   %N   Quoted file name with dereference if symbolic link\n\
     955             :   %o   I/O block size\n\
     956             :   %s   Total size, in bytes\n\
     957             :   %t   Major device type in hex\n\
     958             :   %T   Minor device type in hex\n\
     959             : "), stdout);
     960           1 :       fputs (_("\
     961             :   %u   User ID of owner\n\
     962             :   %U   User name of owner\n\
     963             :   %x   Time of last access\n\
     964             :   %X   Time of last access as seconds since Epoch\n\
     965             :   %y   Time of last modification\n\
     966             :   %Y   Time of last modification as seconds since Epoch\n\
     967             :   %z   Time of last change\n\
     968             :   %Z   Time of last change as seconds since Epoch\n\
     969             : \n\
     970             : "), stdout);
     971             : 
     972           1 :       fputs (_("\
     973             : Valid format sequences for file systems:\n\
     974             : \n\
     975             :   %a   Free blocks available to non-superuser\n\
     976             :   %b   Total data blocks in file system\n\
     977             :   %c   Total file nodes in file system\n\
     978             :   %d   Free file nodes in file system\n\
     979             :   %f   Free blocks in file system\n\
     980             :   %C   SELinux security context string\n\
     981             : "), stdout);
     982           1 :       fputs (_("\
     983             :   %i   File System ID in hex\n\
     984             :   %l   Maximum length of filenames\n\
     985             :   %n   File name\n\
     986             :   %s   Block size (for faster transfers)\n\
     987             :   %S   Fundamental block size (for block counts)\n\
     988             :   %t   Type in hex\n\
     989             :   %T   Type in human readable form\n\
     990             : "), stdout);
     991           1 :       printf (USAGE_BUILTIN_WARNING, PROGRAM_NAME);
     992           1 :       emit_bug_reporting_address ();
     993             :     }
     994          12 :   exit (status);
     995             : }
     996             : 
     997             : int
     998          77 : main (int argc, char *argv[])
     999             : {
    1000             :   int c;
    1001             :   int i;
    1002          77 :   bool fs = false;
    1003          77 :   bool terse = false;
    1004          77 :   char *format = NULL;
    1005          77 :   bool ok = true;
    1006             : 
    1007             :   initialize_main (&argc, &argv);
    1008          77 :   program_name = argv[0];
    1009          77 :   setlocale (LC_ALL, "");
    1010             :   bindtextdomain (PACKAGE, LOCALEDIR);
    1011             :   textdomain (PACKAGE);
    1012             : 
    1013          77 :   atexit (close_stdout);
    1014             : 
    1015         193 :   while ((c = getopt_long (argc, argv, "c:fLtZ", long_options, NULL)) != -1)
    1016             :     {
    1017          50 :       switch (c)
    1018             :         {
    1019          12 :         case PRINTF_OPTION:
    1020          12 :           format = optarg;
    1021          12 :           interpret_backslash_escapes = true;
    1022          12 :           trailing_delim = "";
    1023          12 :           break;
    1024             : 
    1025          11 :         case 'c':
    1026          11 :           format = optarg;
    1027          11 :           interpret_backslash_escapes = false;
    1028          11 :           trailing_delim = "\n";
    1029          11 :           break;
    1030             : 
    1031           5 :         case 'L':
    1032           5 :           follow_links = true;
    1033           5 :           break;
    1034             : 
    1035           9 :         case 'f':
    1036           9 :           fs = true;
    1037           9 :           break;
    1038             : 
    1039           1 :         case 't':
    1040           1 :           terse = true;
    1041           1 :           break;
    1042             : 
    1043           1 :         case 'Z':  /* FIXME: remove in 2010, warn in mid 2008 */
    1044             :           /* Ignored, for compatibility with distributions
    1045             :              that implemented this before upstream.  */
    1046           1 :           break;
    1047             : 
    1048           1 :         case_GETOPT_HELP_CHAR;
    1049             : 
    1050           1 :         case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
    1051             : 
    1052           9 :         default:
    1053           9 :           usage (EXIT_FAILURE);
    1054             :         }
    1055             :     }
    1056             : 
    1057          66 :   if (argc == optind)
    1058             :     {
    1059           2 :       error (0, 0, _("missing operand"));
    1060           2 :       usage (EXIT_FAILURE);
    1061             :     }
    1062             : 
    1063         155 :   for (i = optind; i < argc; i++)
    1064          91 :     ok &= (fs
    1065           9 :            ? do_statfs (argv[i], terse, format)
    1066         101 :            : do_stat (argv[i], terse, format));
    1067             : 
    1068          63 :   exit (ok ? EXIT_SUCCESS : EXIT_FAILURE);
    1069             : }

Generated by: LCOV version 1.10