diff options
Diffstat (limited to 'gl/fsusage.c')
-rw-r--r-- | gl/fsusage.c | 100 |
1 files changed, 82 insertions, 18 deletions
diff --git a/gl/fsusage.c b/gl/fsusage.c index 17102aad..0657555f 100644 --- a/gl/fsusage.c +++ b/gl/fsusage.c @@ -1,6 +1,6 @@ /* fsusage.c -- return space usage of mounted file systems - Copyright (C) 1991-1992, 1996, 1998-1999, 2002-2006, 2009-2010 Free Software + Copyright (C) 1991-1992, 1996, 1998-1999, 2002-2006, 2009-2013 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify @@ -23,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. @@ -31,15 +31,15 @@ # 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_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 @@ -84,6 +84,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 @@ -94,11 +123,36 @@ int get_fs_usage (char const *file, char const *disk, struct fs_usage *fsp) { -#if defined STAT_STATVFS /* POSIX, except glibc/Linux */ +#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. */ @@ -165,8 +219,17 @@ 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 /* glibc/Linux, 4.3BSD, SunOS 4, \ - MacOS X < 10.4, FreeBSD < 5.0, \ +#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; @@ -223,8 +286,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); |