X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;f=lib%2Ffsusage.c;h=0657555f44d17805e7c90d8e4d6d5ae41296522a;hb=5191b3546cfb6c163228c23f214e325ddf60d46f;hp=099b0aabcbba5fedbaf8a57e99739026673a9b9f;hpb=1602f0afed21be664fcf5c42d59db07cc22c56d6;p=gnulib.git diff --git a/lib/fsusage.c b/lib/fsusage.c index 099b0aabc..0657555f4 100644 --- a/lib/fsusage.c +++ b/lib/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-2012 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 @@ -31,15 +31,15 @@ # include # include # include -# if HAVE_SYS_PARAM_H -# include -# endif -# if HAVE_SYS_MOUNT_H -# include -# endif -# if HAVE_SYS_VFS_H -# include -# endif +#if HAVE_SYS_PARAM_H +# include +#endif +#if HAVE_SYS_MOUNT_H +# include +#endif +#if HAVE_SYS_VFS_H +# include +#endif # if HAVE_SYS_FS_S5PARAM_H /* Fujitsu UXP/V */ # include # 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 /* for strverscmp */ +# include +# include +# 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,19 +123,32 @@ int get_fs_usage (char const *file, char const *disk, struct fs_usage *fsp) { -#if defined STAT_STATVFS /* POSIX, except glibc/Linux */ - - struct statvfs fsd; +#ifdef STAT_STATVFS /* POSIX, except pre-2.6.36 glibc/Linux */ - if (statvfs (file, &fsd) < 0) - return -1; + 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; + } - /* 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)); +#endif -#elif defined STAT_STATVFS64 /* AIX */ +#if defined STAT_STATVFS64 /* AIX */ struct statvfs64 fsd; @@ -177,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; @@ -235,8 +286,9 @@ get_fs_usage (char const *file, char const *disk, struct fs_usage *fsp) #endif -#if (defined STAT_STATVFS || defined STAT_STATVFS64 \ - || (!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);