Back to index

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