summaryrefslogtreecommitdiff
path: root/lib/fsusage.c
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2016-01-20 10:55:18 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2016-01-20 10:55:18 +0000
commit70e9163c9c18e995515598085cb824e554eb7ae7 (patch)
treea42dc8b2a6c031354bf31472de888bfc8a060132 /lib/fsusage.c
parentcbf5993c43f49281173f185863577d86bfac6eae (diff)
downloadcoreutils-tarball-70e9163c9c18e995515598085cb824e554eb7ae7.tar.gz
Diffstat (limited to 'lib/fsusage.c')
-rw-r--r--lib/fsusage.c148
1 files changed, 105 insertions, 43 deletions
diff --git a/lib/fsusage.c b/lib/fsusage.c
index 337bf53..a230538 100644
--- a/lib/fsusage.c
+++ b/lib/fsusage.c
@@ -1,12 +1,12 @@
/* fsusage.c -- return space usage of mounted file systems
- Copyright (C) 1991, 1992, 1996, 1998, 1999, 2002, 2003, 2004, 2005, 2006
- Free Software Foundation, Inc.
+ Copyright (C) 1991-1992, 1996, 1998-1999, 2002-2006, 2009-2016 Free Software
+ Foundation, Inc.
- This program is free software; you can redistribute it and/or modify
+ 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.
+ the Free Software Foundation; either version 3 of the License, 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
@@ -14,8 +14,7 @@
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include <config.h>
@@ -24,7 +23,7 @@
#include <limits.h>
#include <sys/types.h>
-#if STAT_STATVFS /* POSIX 1003.1-2001 (and later) with XSI */
+#if STAT_STATVFS || STAT_STATVFS64 /* POSIX 1003.1-2001 (and later) with XSI */
# include <sys/statvfs.h>
#else
/* Don't include backward-compatibility files unless they're needed.
@@ -32,35 +31,30 @@
# include <fcntl.h>
# include <unistd.h>
# include <sys/stat.h>
-# if HAVE_SYS_PARAM_H
-# include <sys/param.h>
-# endif
-# if HAVE_SYS_MOUNT_H
-# include <sys/mount.h>
-# endif
-# if HAVE_SYS_VFS_H
-# include <sys/vfs.h>
-# endif
-# if HAVE_SYS_FS_S5PARAM_H /* Fujitsu UXP/V */
+#if HAVE_SYS_PARAM_H
+# include <sys/param.h>
+#endif
+#if HAVE_SYS_MOUNT_H
+# include <sys/mount.h>
+#endif
+#if HAVE_SYS_VFS_H
+# include <sys/vfs.h>
+#endif
+# if HAVE_SYS_FS_S5PARAM_H /* Fujitsu UXP/V */
# include <sys/fs/s5param.h>
# endif
# if defined HAVE_SYS_FILSYS_H && !defined _CRAY
-# include <sys/filsys.h> /* SVR2 */
+# include <sys/filsys.h> /* SVR2 */
# endif
# if HAVE_SYS_STATFS_H
# include <sys/statfs.h>
# endif
-# if HAVE_DUSTAT_H /* AIX PS/2 */
+# if HAVE_DUSTAT_H /* AIX PS/2 */
# include <sys/dustat.h>
# endif
# include "full-read.h"
#endif
-/* The results of open() in this file are not used with fchdir,
- therefore save some unnecessary work in fchdir.c. */
-#undef open
-#undef close
-
/* Many space usage primitives use all 1 bits to denote a value that is
not applicable or unknown. Propagate this information by returning
a uintmax_t value that is all 1 bits if X is all 1 bits, even if X
@@ -68,13 +62,13 @@
#define PROPAGATE_ALL_ONES(x) \
((sizeof (x) < sizeof (uintmax_t) \
&& (~ (x) == (sizeof (x) < sizeof (int) \
- ? - (1 << (sizeof (x) * CHAR_BIT)) \
- : 0))) \
+ ? - (1 << (sizeof (x) * CHAR_BIT)) \
+ : 0))) \
? UINTMAX_MAX : (uintmax_t) (x))
/* Extract the top bit of X as an uintmax_t value. */
#define EXTRACT_TOP_BIT(x) ((x) \
- & ((uintmax_t) 1 << (sizeof (x) * CHAR_BIT - 1)))
+ & ((uintmax_t) 1 << (sizeof (x) * CHAR_BIT - 1)))
/* If a value is negative, many space usage primitives store it into an
integer variable by assignment, even if the variable's type is unsigned.
@@ -85,6 +79,35 @@
otherwise, use PROPAGATE_ALL_ONES. */
#define PROPAGATE_TOP_BIT(x) ((x) | ~ (EXTRACT_TOP_BIT (x) - 1))
+#ifdef STAT_STATVFS
+/* Return true if statvfs works. This is false for statvfs on systems
+ with GNU libc on Linux kernels before 2.6.36, which stats all
+ preceding entries in /proc/mounts; that makes df hang if even one
+ of the corresponding file systems is hard-mounted but not available. */
+# if ! (__linux__ && (__GLIBC__ || __UCLIBC__))
+/* The FRSIZE fallback is not required in this case. */
+# undef STAT_STATFS2_FRSIZE
+static int statvfs_works (void) { return 1; }
+# else
+# include <string.h> /* for strverscmp */
+# include <sys/utsname.h>
+# include <sys/statfs.h>
+# define STAT_STATFS2_BSIZE 1
+
+static int
+statvfs_works (void)
+{
+ static int statvfs_works_cache = -1;
+ struct utsname name;
+ if (statvfs_works_cache < 0)
+ statvfs_works_cache = (uname (&name) == 0
+ && 0 <= strverscmp (name.release, "2.6.36"));
+ return statvfs_works_cache;
+}
+# endif
+#endif
+
+
/* Fill in the fields of FSP with information about space usage for
the file system on which FILE resides.
DISK is the device on which FILE is mounted, for space-getting
@@ -95,19 +118,44 @@
int
get_fs_usage (char const *file, char const *disk, struct fs_usage *fsp)
{
-#if defined STAT_STATVFS /* POSIX */
+#ifdef STAT_STATVFS /* POSIX, except pre-2.6.36 glibc/Linux */
+
+ if (statvfs_works ())
+ {
+ struct statvfs vfsd;
+
+ if (statvfs (file, &vfsd) < 0)
+ return -1;
+
+ /* f_frsize isn't guaranteed to be supported. */
+ fsp->fsu_blocksize = (vfsd.f_frsize
+ ? PROPAGATE_ALL_ONES (vfsd.f_frsize)
+ : PROPAGATE_ALL_ONES (vfsd.f_bsize));
+
+ fsp->fsu_blocks = PROPAGATE_ALL_ONES (vfsd.f_blocks);
+ fsp->fsu_bfree = PROPAGATE_ALL_ONES (vfsd.f_bfree);
+ fsp->fsu_bavail = PROPAGATE_TOP_BIT (vfsd.f_bavail);
+ fsp->fsu_bavail_top_bit_set = EXTRACT_TOP_BIT (vfsd.f_bavail) != 0;
+ fsp->fsu_files = PROPAGATE_ALL_ONES (vfsd.f_files);
+ fsp->fsu_ffree = PROPAGATE_ALL_ONES (vfsd.f_ffree);
+ return 0;
+ }
+
+#endif
+
+#if defined STAT_STATVFS64 /* AIX */
- struct statvfs fsd;
+ struct statvfs64 fsd;
- if (statvfs (file, &fsd) < 0)
+ if (statvfs64 (file, &fsd) < 0)
return -1;
/* f_frsize isn't guaranteed to be supported. */
fsp->fsu_blocksize = (fsd.f_frsize
- ? PROPAGATE_ALL_ONES (fsd.f_frsize)
- : PROPAGATE_ALL_ONES (fsd.f_bsize));
+ ? PROPAGATE_ALL_ONES (fsd.f_frsize)
+ : PROPAGATE_ALL_ONES (fsd.f_bsize));
-#elif defined STAT_STATFS2_FS_DATA /* Ultrix */
+#elif defined STAT_STATFS2_FS_DATA /* Ultrix */
struct fs_data fsd;
@@ -122,7 +170,7 @@ get_fs_usage (char const *file, char const *disk, struct fs_usage *fsp)
fsp->fsu_files = PROPAGATE_ALL_ONES (fsd.fd_req.gtot);
fsp->fsu_ffree = PROPAGATE_ALL_ONES (fsd.fd_req.gfree);
-#elif defined STAT_READ_FILSYS /* SVR2 */
+#elif defined STAT_READ_FILSYS /* SVR2 */
# ifndef SUPERBOFF
# define SUPERBOFF (SUPERB * 512)
# endif
@@ -153,11 +201,11 @@ get_fs_usage (char const *file, char const *disk, struct fs_usage *fsp)
fsp->fsu_bavail = PROPAGATE_TOP_BIT (fsd.s_tfree);
fsp->fsu_bavail_top_bit_set = EXTRACT_TOP_BIT (fsd.s_tfree) != 0;
fsp->fsu_files = (fsd.s_isize == -1
- ? UINTMAX_MAX
- : (fsd.s_isize - 2) * INOPB * (fsd.s_type == Fs2b ? 2 : 1));
+ ? UINTMAX_MAX
+ : (fsd.s_isize - 2) * INOPB * (fsd.s_type == Fs2b ? 2 : 1));
fsp->fsu_ffree = PROPAGATE_ALL_ONES (fsd.s_tinode);
-#elif defined STAT_STATFS3_OSF1
+#elif defined STAT_STATFS3_OSF1 /* OSF/1 */
struct statfs fsd;
@@ -166,7 +214,18 @@ get_fs_usage (char const *file, char const *disk, struct fs_usage *fsp)
fsp->fsu_blocksize = PROPAGATE_ALL_ONES (fsd.f_fsize);
-#elif defined STAT_STATFS2_BSIZE /* 4.3BSD, SunOS 4, HP-UX, AIX */
+#elif defined STAT_STATFS2_FRSIZE /* 2.6 < glibc/Linux < 2.6.36 */
+
+ struct statfs fsd;
+
+ if (statfs (file, &fsd) < 0)
+ return -1;
+
+ fsp->fsu_blocksize = PROPAGATE_ALL_ONES (fsd.f_frsize);
+
+#elif defined STAT_STATFS2_BSIZE /* glibc/Linux < 2.6, 4.3BSD, SunOS 4, \
+ Mac OS X < 10.4, FreeBSD < 5.0, \
+ NetBSD < 3.0, OpenBSD < 4.4 */
struct statfs fsd;
@@ -190,7 +249,7 @@ get_fs_usage (char const *file, char const *disk, struct fs_usage *fsp)
}
# endif /* STATFS_TRUNCATES_BLOCK_COUNTS */
-#elif defined STAT_STATFS2_FSIZE /* 4.4BSD */
+#elif defined STAT_STATFS2_FSIZE /* 4.4BSD and older NetBSD */
struct statfs fsd;
@@ -199,7 +258,8 @@ get_fs_usage (char const *file, char const *disk, struct fs_usage *fsp)
fsp->fsu_blocksize = PROPAGATE_ALL_ONES (fsd.f_fsize);
-#elif defined STAT_STATFS4 /* SVR3, Dynix, Irix, AIX */
+#elif defined STAT_STATFS4 /* SVR3, Dynix, old Irix, old AIX, \
+ Dolphin */
# if !_AIX && !defined _SEQUENT_ && !defined DOLPHIN
# define f_bavail f_bfree
@@ -221,8 +281,9 @@ get_fs_usage (char const *file, char const *disk, struct fs_usage *fsp)
#endif
-#if (defined STAT_STATVFS \
- || (!defined STAT_STATFS2_FS_DATA && !defined STAT_READ_FILSYS))
+#if (defined STAT_STATVFS64 || defined STAT_STATFS3_OSF1 \
+ || defined STAT_STATFS2_FRSIZE || defined STAT_STATFS2_BSIZE \
+ || defined STAT_STATFS2_FSIZE || defined STAT_STATFS4)
fsp->fsu_blocks = PROPAGATE_ALL_ONES (fsd.f_blocks);
fsp->fsu_bfree = PROPAGATE_ALL_ONES (fsd.f_bfree);
@@ -233,6 +294,7 @@ get_fs_usage (char const *file, char const *disk, struct fs_usage *fsp)
#endif
+ (void) disk; /* avoid argument-unused warning */
return 0;
}