Back to index

nordugrid-arc-nox  1.1.0~rc6
fsusage.c
Go to the documentation of this file.
00001 /* fsusage.c -- return space usage of mounted file systems
00002 
00003    Copyright (C) 1991, 1992, 1996, 1998, 1999, 2002, 2003, 2004, 2005, 2006
00004    Free Software Foundation, Inc.
00005 
00006    This program is free software: you can redistribute it and/or modify
00007    it under the terms of the GNU General Public License as published by
00008    the Free Software Foundation; either version 3 of the License, or
00009    (at your option) any later version.
00010 
00011    This program is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014    GNU General Public License for more details.
00015 
00016    You should have received a copy of the GNU General Public License
00017    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
00018 
00019 #ifdef HAVE_CONFIG_H
00020 #include <config.h>
00021 #endif
00022 
00023 #include "fsusage.h"
00024 
00025 #include <limits.h>
00026 #include <sys/types.h>
00027 
00028 #if STAT_STATVFS            /* POSIX 1003.1-2001 (and later) with XSI */
00029 # include <sys/statvfs.h>
00030 #else
00031 /* Don't include backward-compatibility files unless they're needed.
00032    Eventually we'd like to remove all this cruft.  */
00033 # include <fcntl.h>
00034 # include <unistd.h>
00035 # include <sys/stat.h>
00036 # if HAVE_SYS_PARAM_H
00037 #  include <sys/param.h>
00038 # endif
00039 # if HAVE_SYS_MOUNT_H
00040 #  include <sys/mount.h>
00041 # endif
00042 # if HAVE_SYS_VFS_H
00043 #  include <sys/vfs.h>
00044 # endif
00045 # if HAVE_SYS_FS_S5PARAM_H  /* Fujitsu UXP/V */
00046 #  include <sys/fs/s5param.h>
00047 # endif
00048 # if defined HAVE_SYS_FILSYS_H && !defined _CRAY
00049 #  include <sys/filsys.h>   /* SVR2 */
00050 # endif
00051 # if HAVE_SYS_STATFS_H
00052 #  include <sys/statfs.h>
00053 # endif
00054 # if HAVE_DUSTAT_H          /* AIX PS/2 */
00055 #  include <sys/dustat.h>
00056 # endif
00057 #endif
00058 
00059 /* The results of open() in this file are not used with fchdir,
00060    therefore save some unnecessary work in fchdir.c.  */
00061 #undef open
00062 #undef close
00063 
00064 /* Many space usage primitives use all 1 bits to denote a value that is
00065    not applicable or unknown.  Propagate this information by returning
00066    a uintmax_t value that is all 1 bits if X is all 1 bits, even if X
00067    is unsigned and narrower than uintmax_t.  */
00068 #define PROPAGATE_ALL_ONES(x) \
00069   ((sizeof (x) < sizeof (uintmax_t) \
00070     && (~ (x) == (sizeof (x) < sizeof (int) \
00071                 ? - (1 << (sizeof (x) * CHAR_BIT)) \
00072                 : 0))) \
00073    ? UINTMAX_MAX : (uintmax_t) (x))
00074 
00075 /* Extract the top bit of X as an uintmax_t value.  */
00076 #define EXTRACT_TOP_BIT(x) ((x) \
00077                          & ((uintmax_t) 1 << (sizeof (x) * CHAR_BIT - 1)))
00078 
00079 /* If a value is negative, many space usage primitives store it into an
00080    integer variable by assignment, even if the variable's type is unsigned.
00081    So, if a space usage variable X's top bit is set, convert X to the
00082    uintmax_t value V such that (- (uintmax_t) V) is the negative of
00083    the original value.  If X's top bit is clear, just yield X.
00084    Use PROPAGATE_TOP_BIT if the original value might be negative;
00085    otherwise, use PROPAGATE_ALL_ONES.  */
00086 #define PROPAGATE_TOP_BIT(x) ((x) | ~ (EXTRACT_TOP_BIT (x) - 1))
00087 
00088 /* Fill in the fields of FSP with information about space usage for
00089    the file system on which FILE resides.
00090    DISK is the device on which FILE is mounted, for space-getting
00091    methods that need to know it.
00092    Return 0 if successful, -1 if not.  When returning -1, ensure that
00093    ERRNO is either a system error value, or zero if DISK is NULL
00094    on a system that requires a non-NULL value.  */
00095 int
00096 get_fs_usage (char const *file, char const *disk, struct fs_usage *fsp)
00097 {
00098 #if defined STAT_STATVFS           /* POSIX */
00099 
00100   struct statvfs fsd;
00101 
00102   if (statvfs (file, &fsd) < 0)
00103     return -1;
00104 
00105   /* f_frsize isn't guaranteed to be supported.  */
00106   fsp->fsu_blocksize = (fsd.f_frsize
00107                      ? PROPAGATE_ALL_ONES (fsd.f_frsize)
00108                      : PROPAGATE_ALL_ONES (fsd.f_bsize));
00109 
00110 #elif defined STAT_STATFS2_FS_DATA /* Ultrix */
00111 
00112   struct fs_data fsd;
00113 
00114   if (statfs (file, &fsd) != 1)
00115     return -1;
00116 
00117   fsp->fsu_blocksize = 1024;
00118   fsp->fsu_blocks = PROPAGATE_ALL_ONES (fsd.fd_req.btot);
00119   fsp->fsu_bfree = PROPAGATE_ALL_ONES (fsd.fd_req.bfree);
00120   fsp->fsu_bavail = PROPAGATE_TOP_BIT (fsd.fd_req.bfreen);
00121   fsp->fsu_bavail_top_bit_set = EXTRACT_TOP_BIT (fsd.fd_req.bfreen) != 0;
00122   fsp->fsu_files = PROPAGATE_ALL_ONES (fsd.fd_req.gtot);
00123   fsp->fsu_ffree = PROPAGATE_ALL_ONES (fsd.fd_req.gfree);
00124 
00125 #elif defined STAT_READ_FILSYS            /* SVR2 */
00126 # ifndef SUPERBOFF
00127 #  define SUPERBOFF (SUPERB * 512)
00128 # endif
00129   return -1;
00130 #if 0
00131   struct filsys fsd;
00132   int fd;
00133 
00134   if (! disk)
00135     {
00136       errno = 0;
00137       return -1;
00138     }
00139 
00140   fd = open (disk, O_RDONLY);
00141   if (fd < 0)
00142     return -1;
00143   lseek (fd, (off_t) SUPERBOFF, 0);
00144   if (full_read (fd, (char *) &fsd, sizeof fsd) != sizeof fsd)
00145     {
00146       close (fd);
00147       return -1;
00148     }
00149   close (fd);
00150 
00151   fsp->fsu_blocksize = (fsd.s_type == Fs2b ? 1024 : 512);
00152   fsp->fsu_blocks = PROPAGATE_ALL_ONES (fsd.s_fsize);
00153   fsp->fsu_bfree = PROPAGATE_ALL_ONES (fsd.s_tfree);
00154   fsp->fsu_bavail = PROPAGATE_TOP_BIT (fsd.s_tfree);
00155   fsp->fsu_bavail_top_bit_set = EXTRACT_TOP_BIT (fsd.s_tfree) != 0;
00156   fsp->fsu_files = (fsd.s_isize == -1
00157                   ? UINTMAX_MAX
00158                   : (fsd.s_isize - 2) * INOPB * (fsd.s_type == Fs2b ? 2 : 1));
00159   fsp->fsu_ffree = PROPAGATE_ALL_ONES (fsd.s_tinode);
00160 #endif
00161 #elif defined STAT_STATFS3_OSF1
00162 
00163   struct statfs fsd;
00164 
00165   if (statfs (file, &fsd, sizeof (struct statfs)) != 0)
00166     return -1;
00167 
00168   fsp->fsu_blocksize = PROPAGATE_ALL_ONES (fsd.f_fsize);
00169 
00170 #elif defined STAT_STATFS2_BSIZE   /* 4.3BSD, SunOS 4, HP-UX, AIX */
00171 
00172   struct statfs fsd;
00173 
00174   if (statfs (file, &fsd) < 0)
00175     return -1;
00176 
00177   fsp->fsu_blocksize = PROPAGATE_ALL_ONES (fsd.f_bsize);
00178 
00179 # ifdef STATFS_TRUNCATES_BLOCK_COUNTS
00180 
00181   /* In SunOS 4.1.2, 4.1.3, and 4.1.3_U1, the block counts in the
00182      struct statfs are truncated to 2GB.  These conditions detect that
00183      truncation, presumably without botching the 4.1.1 case, in which
00184      the values are not truncated.  The correct counts are stored in
00185      undocumented spare fields.  */
00186   if (fsd.f_blocks == 0x7fffffff / fsd.f_bsize && fsd.f_spare[0] > 0)
00187     {
00188       fsd.f_blocks = fsd.f_spare[0];
00189       fsd.f_bfree = fsd.f_spare[1];
00190       fsd.f_bavail = fsd.f_spare[2];
00191     }
00192 # endif /* STATFS_TRUNCATES_BLOCK_COUNTS */
00193 
00194 #elif defined STAT_STATFS2_FSIZE   /* 4.4BSD */
00195 
00196   struct statfs fsd;
00197 
00198   if (statfs (file, &fsd) < 0)
00199     return -1;
00200 
00201   fsp->fsu_blocksize = PROPAGATE_ALL_ONES (fsd.f_fsize);
00202 
00203 #elif defined STAT_STATFS4         /* SVR3, Dynix, Irix, AIX */
00204 
00205 # if !_AIX && !defined _SEQUENT_ && !defined DOLPHIN
00206 #  define f_bavail f_bfree
00207 # endif
00208 
00209   struct statfs fsd;
00210 
00211   if (statfs (file, &fsd, sizeof fsd, 0) < 0)
00212     return -1;
00213 
00214   /* Empirically, the block counts on most SVR3 and SVR3-derived
00215      systems seem to always be in terms of 512-byte blocks,
00216      no matter what value f_bsize has.  */
00217 # if _AIX || defined _CRAY
00218    fsp->fsu_blocksize = PROPAGATE_ALL_ONES (fsd.f_bsize);
00219 # else
00220    fsp->fsu_blocksize = 512;
00221 # endif
00222 
00223 #endif
00224 
00225 #if (defined STAT_STATVFS \
00226      || (!defined STAT_STATFS2_FS_DATA && !defined STAT_READ_FILSYS))
00227 
00228   fsp->fsu_blocks = PROPAGATE_ALL_ONES (fsd.f_blocks);
00229   fsp->fsu_bfree = PROPAGATE_ALL_ONES (fsd.f_bfree);
00230   fsp->fsu_bavail = PROPAGATE_TOP_BIT (fsd.f_bavail);
00231   fsp->fsu_bavail_top_bit_set = EXTRACT_TOP_BIT (fsd.f_bavail) != 0;
00232   fsp->fsu_files = PROPAGATE_ALL_ONES (fsd.f_files);
00233   fsp->fsu_ffree = PROPAGATE_ALL_ONES (fsd.f_ffree);
00234 
00235 #endif
00236 
00237   return 0;
00238 }
00239 
00240 #if defined _AIX && defined _I386
00241 /* AIX PS/2 does not supply statfs.  */
00242 
00243 int
00244 statfs (char *file, struct statfs *fsb)
00245 {
00246   struct stat stats;
00247   struct dustat fsd;
00248 
00249   if (stat (file, &stats) != 0)
00250     return -1;
00251   if (dustat (stats.st_dev, 0, &fsd, sizeof (fsd)))
00252     return -1;
00253   fsb->f_type   = 0;
00254   fsb->f_bsize  = fsd.du_bsize;
00255   fsb->f_blocks = fsd.du_fsize - fsd.du_isize;
00256   fsb->f_bfree  = fsd.du_tfree;
00257   fsb->f_bavail = fsd.du_tfree;
00258   fsb->f_files  = (fsd.du_isize - 2) * fsd.du_inopb;
00259   fsb->f_ffree  = fsd.du_tinode;
00260   fsb->f_fsid.val[0] = fsd.du_site;
00261   fsb->f_fsid.val[1] = fsd.du_pckno;
00262   return 0;
00263 }
00264 
00265 #endif /* _AIX && _I386 */