Blame sysdeps/common/fsusage.c

Packit d37888
/* fsusage.c -- return space usage of mounted filesystems
Packit d37888
   Copyright (C) 1991, 1992, 1996, 1998, 1999, 2002, 2003 Free Software
Packit d37888
   Foundation, Inc.
Packit d37888
Packit d37888
   This program is free software; you can redistribute it and/or modify
Packit d37888
   it under the terms of the GNU General Public License as published by
Packit d37888
   the Free Software Foundation; either version 2, or (at your option)
Packit d37888
   any later version.
Packit d37888
Packit d37888
   This program is distributed in the hope that it will be useful,
Packit d37888
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit d37888
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit d37888
   GNU General Public License for more details.
Packit d37888
Packit d37888
   You should have received a copy of the GNU General Public License
Packit d37888
   along with this program; if not, write to the Free Software Foundation,
Packit d37888
   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
Packit d37888
Packit d37888
#ifdef HAVE_CONFIG_H
Packit d37888
# include <config.h>
Packit d37888
#endif
Packit d37888
Packit d37888
#include <glibtop.h>
Packit d37888
#include <glibtop/fsusage.h>
Packit d37888
Packit d37888
#include <sys/types.h>
Packit d37888
#include <sys/stat.h>
Packit d37888
Packit d37888
#ifdef HAVE_LIMITS_H
Packit d37888
# include <limits.h>
Packit d37888
#endif
Packit d37888
#ifndef CHAR_BIT
Packit d37888
# define CHAR_BIT 8
Packit d37888
#endif
Packit d37888
Packit d37888
#ifdef HAVE_SYS_PARAM_H
Packit d37888
# include <sys/param.h>
Packit d37888
#endif
Packit d37888
Packit d37888
#ifdef HAVE_SYS_MOUNT_H
Packit d37888
# include <sys/mount.h>
Packit d37888
#endif
Packit d37888
Packit d37888
#ifdef HAVE_SYS_VFS_H
Packit d37888
# include <sys/vfs.h>
Packit d37888
#endif
Packit d37888
Packit d37888
#ifdef HAVE_SYS_FS_S5PARAM_H	/* Fujitsu UXP/V */
Packit d37888
# include <sys/fs/s5param.h>
Packit d37888
#endif
Packit d37888
Packit d37888
#if defined HAVE_SYS_FILSYS_H && !defined _CRAY
Packit d37888
# include <sys/filsys.h>	/* SVR2 */
Packit d37888
#endif
Packit d37888
Packit d37888
#ifdef HAVE_FCNTL_H
Packit d37888
# include <fcntl.h>
Packit d37888
#endif
Packit d37888
Packit d37888
#ifdef HAVE_SYS_STATFS_H
Packit d37888
# include <sys/statfs.h>
Packit d37888
#endif
Packit d37888
Packit d37888
#ifdef HAVE_DUSTAT_H		/* AIX PS/2 */
Packit d37888
# include <sys/dustat.h>
Packit d37888
#endif
Packit d37888
Packit d37888
#ifdef HAVE_SYS_STATVFS_H		/* SVR4 */
Packit d37888
# include <sys/statvfs.h>
Packit d37888
int statvfs (const char *path, struct statvfs *buf);
Packit d37888
#endif
Packit d37888
Packit d37888
/* Many space usage primitives use all 1 bits to denote a value that is
Packit d37888
   not applicable or unknown.  Propagate this information by returning
Packit d37888
   a guint64 value that is all 1 bits if X is all 1 bits, even if X
Packit d37888
   is unsigned and narrower than guint64.  */
Packit d37888
#define PROPAGATE_ALL_ONES(x) \
Packit d37888
  ((sizeof (x) < sizeof (guint64) \
Packit d37888
    && (~ (x) == (sizeof (x) < sizeof (int) \
Packit d37888
		  ? - (1 << (sizeof (x) * CHAR_BIT)) \
Packit d37888
		  : 0))) \
Packit d37888
   ? G_MAXUINT64 : (x))
Packit d37888
Packit d37888
/* Extract the top bit of X as an guint64 value.  */
Packit d37888
#define EXTRACT_TOP_BIT(x) ((x) \
Packit d37888
			    & ((guint64) 1 << (sizeof (x) * CHAR_BIT - 1)))
Packit d37888
Packit d37888
/* If a value is negative, many space usage primitives store it into an
Packit d37888
   integer variable by assignment, even if the variable's type is unsigned.
Packit d37888
   So, if a space usage variable X's top bit is set, convert X to the
Packit d37888
   guint64 value V such that (- (guint64) V) is the negative of
Packit d37888
   the original value.  If X's top bit is clear, just yield X.
Packit d37888
   Use PROPAGATE_TOP_BIT if the original value might be negative;
Packit d37888
   otherwise, use PROPAGATE_ALL_ONES.  */
Packit d37888
#define PROPAGATE_TOP_BIT(x) ((x) | ~ (EXTRACT_TOP_BIT (x) - 1))
Packit d37888
Packit d37888
/* Fill in the fields of FSP with information about space usage for
Packit d37888
   the filesystem on which PATH resides.
Packit d37888
   DISK is the device on which PATH is mounted, for space-getting
Packit d37888
   methods that need to know it.
Packit d37888
   Return 0 if successful, -1 if not.  When returning -1, ensure that
Packit d37888
   ERRNO is either a system error value, or zero if DISK is NULL
Packit d37888
   on a system that requires a non-NULL value.  */
Packit d37888
Packit d37888
Packit d37888
static const unsigned long _glibtop_sysdeps_fsusage =
Packit d37888
(1L << GLIBTOP_FSUSAGE_BLOCKS) + (1L << GLIBTOP_FSUSAGE_BFREE)
Packit d37888
+ (1L << GLIBTOP_FSUSAGE_BAVAIL) + (1L << GLIBTOP_FSUSAGE_FILES)
Packit d37888
+ (1L << GLIBTOP_FSUSAGE_FFREE) + (1L << GLIBTOP_FSUSAGE_BLOCK_SIZE);
Packit d37888
Packit d37888
Packit d37888
/*
Packit d37888
 * _glibtop_get_fsusage_read_write
Packit d37888
 * New function to retrieve total read and write
Packit d37888
 *
Packit d37888
 * Each arch should have its own function()
Packit d37888
 * and the proper #define. This is more readable than one single
Packit d37888
 * function full of #something where everything is mixed.
Packit d37888
 * These functions are private.
Packit d37888
 *
Packit d37888
 * void  _glibtop_<arch>_get_fsusage_read_write(glibtop*server,
Packit d37888
 *                                              glibtop_fsusage *buf,
Packit d37888
 *                                              const char *path);
Packit d37888
 *
Packit d37888
 * TODO: split this file properly, is possible
Packit d37888
 */
Packit d37888
Packit d37888
#ifdef linux
Packit d37888
void
Packit d37888
_glibtop_linux_get_fsusage_read_write(glibtop *server,
Packit d37888
				      glibtop_fsusage *buf,
Packit d37888
				      const char *path);
Packit d37888
Packit d37888
static inline void
Packit d37888
_glibtop_get_fsusage_read_write(glibtop *server,
Packit d37888
				glibtop_fsusage *buf,
Packit d37888
				const char *path)
Packit d37888
{
Packit d37888
	_glibtop_linux_get_fsusage_read_write(server, buf, path);
Packit d37888
}
Packit d37888
Packit d37888
Packit d37888
#elif defined(__FreeBSD__)
Packit d37888
void
Packit d37888
_glibtop_freebsd_get_fsusage_read_write(glibtop *server,
Packit d37888
					glibtop_fsusage *buf,
Packit d37888
					const char *path);
Packit d37888
Packit d37888
#define _glibtop_get_fsusage_read_write(S, B, P) \
Packit d37888
	_glibtop_freebsd_get_fsusage_read_write(S, B, P)
Packit d37888
Packit d37888
#elif defined(__OpenBSD__)
Packit d37888
void
Packit d37888
_glibtop_openbsd_get_fsusage_read_write(glibtop *server,
Packit d37888
					glibtop_fsusage *buf,
Packit d37888
					const char *path);
Packit d37888
Packit d37888
#define _glibtop_get_fsusage_read_write(S, B, P) \
Packit d37888
	_glibtop_openbsd_get_fsusage_read_write(S, B, P)
Packit d37888
Packit d37888
#else /* default fallback */
Packit d37888
#warning glibtop_get_fsusage .read .write are not implemented.
Packit d37888
static inline void
Packit d37888
_glibtop_get_fsusage_read_write(glibtop *server,
Packit d37888
				glibtop_fsusage *buf,
Packit d37888
				const char *path)
Packit d37888
{
Packit d37888
  /* NOOP */
Packit d37888
}
Packit d37888
#endif /* default fallback */
Packit d37888
Packit d37888
/* end _glibtop_get_fsusage_read_write */
Packit d37888
Packit d37888
Packit d37888
Packit d37888
void
Packit d37888
glibtop_get_fsusage_s (glibtop *server, glibtop_fsusage *buf,
Packit d37888
		       const char *path)
Packit d37888
{
Packit d37888
#if defined STAT_STATFS3_OSF1
Packit d37888
  struct statfs fsd;
Packit d37888
#elif defined STAT_STATFS2_FS_DATA  /* Ultrix */
Packit d37888
  struct fs_data fsd;
Packit d37888
#elif defined STAT_STATFS2_BSIZE    /* 4.3BSD, SunOS 4, HP-UX, AIX */
Packit d37888
  struct statfs fsd;
Packit d37888
#elif defined STAT_STATVFS          /* SVR4 */
Packit d37888
  struct statvfs fsd;
Packit d37888
#elif defined STAT_STATFS2_FSIZE    /* 4.4BSD */
Packit d37888
  struct statfs fsd;
Packit d37888
#elif defined STAT_STATFS4         /* SVR3, Dynix, Irix, AIX */
Packit d37888
  struct stafs fsd;
Packit d37888
#endif
Packit d37888
Packit d37888
  glibtop_init_r (&server, 0, 0);
Packit d37888
Packit d37888
  memset (buf, 0, sizeof (glibtop_fsusage));
Packit d37888
Packit d37888
#ifdef STAT_STATFS3_OSF1
Packit d37888
Packit d37888
  if (statfs (path, &fsd, sizeof (struct statfs)) != 0)
Packit d37888
    return;
Packit d37888
Packit d37888
  buf->block_size = PROPAGATE_ALL_ONES (fsd.f_fsize);
Packit d37888
Packit d37888
#endif /* STAT_STATFS3_OSF1 */
Packit d37888
Packit d37888
#ifdef STAT_STATFS2_FS_DATA	/* Ultrix */
Packit d37888
Packit d37888
  if (statfs (path, &fsd) != 1)
Packit d37888
    return;
Packit d37888
Packit d37888
  buf->block_size = 1024;
Packit d37888
  buf->blocks = PROPAGATE_ALL_ONES (fsd.fd_req.btot);
Packit d37888
  buf->bfree = PROPAGATE_ALL_ONES (fsd.fd_req.bfree);
Packit d37888
  buf->bavail = PROPAGATE_TOP_BIT (fsd.fd_req.bfreen);
Packit d37888
  /* buf->bavail_top_bit_set = EXTRACT_TOP_BIT (fsd.fd_req.bfreen) != 0; */
Packit d37888
  buf->files = PROPAGATE_ALL_ONES (fsd.fd_req.gtot);
Packit d37888
  buf->ffree = PROPAGATE_ALL_ONES (fsd.fd_req.gfree);
Packit d37888
Packit d37888
#endif /* STAT_STATFS2_FS_DATA */
Packit d37888
Packit d37888
#ifdef STAT_STATFS2_BSIZE	/* 4.3BSD, SunOS 4, HP-UX, AIX */
Packit d37888
Packit d37888
  if (statfs (path, &fsd) < 0)
Packit d37888
    return;
Packit d37888
Packit d37888
  buf->block_size = PROPAGATE_ALL_ONES (fsd.f_bsize);
Packit d37888
Packit d37888
# ifdef STATFS_TRUNCATES_BLOCK_COUNTS
Packit d37888
Packit d37888
  /* In SunOS 4.1.2, 4.1.3, and 4.1.3_U1, the block counts in the
Packit d37888
     struct statfs are truncated to 2GB.  These conditions detect that
Packit d37888
     truncation, presumably without botching the 4.1.1 case, in which
Packit d37888
     the values are not truncated.  The correct counts are stored in
Packit d37888
     undocumented spare fields.  */
Packit d37888
  if (fsd.f_blocks == 0x7fffffff / fsd.f_bsize && fsd.f_spare[0] > 0)
Packit d37888
    {
Packit d37888
      fsd.f_blocks = fsd.f_spare[0];
Packit d37888
      fsd.f_bfree = fsd.f_spare[1];
Packit d37888
      fsd.f_bavail = fsd.f_spare[2];
Packit d37888
    }
Packit d37888
# endif /* STATFS_TRUNCATES_BLOCK_COUNTS */
Packit d37888
Packit d37888
#endif /* STAT_STATFS2_BSIZE */
Packit d37888
Packit d37888
#ifdef STAT_STATFS2_FSIZE	/* 4.4BSD */
Packit d37888
Packit d37888
  if (statfs (path, &fsd) < 0)
Packit d37888
    return;
Packit d37888
Packit d37888
  buf->block_size = PROPAGATE_ALL_ONES (fsd.f_fsize);
Packit d37888
Packit d37888
#endif /* STAT_STATFS2_FSIZE */
Packit d37888
Packit d37888
#ifdef STAT_STATFS4		/* SVR3, Dynix, Irix, AIX */
Packit d37888
Packit d37888
# if !_AIX && !defined _SEQUENT_ && !defined DOLPHIN
Packit d37888
#  define f_bavail f_bfree
Packit d37888
# endif
Packit d37888
Packit d37888
  if (statfs (path, &fsd, sizeof fsd, 0) < 0)
Packit d37888
    return;
Packit d37888
Packit d37888
  /* Empirically, the block counts on most SVR3 and SVR3-derived
Packit d37888
     systems seem to always be in terms of 512-byte blocks,
Packit d37888
     no matter what value f_bsize has.  */
Packit d37888
# if _AIX || defined _CRAY
Packit d37888
   buf->block_size = PROPAGATE_ALL_ONES (fsd.f_bsize);
Packit d37888
# else
Packit d37888
   buf->block_size = 512;
Packit d37888
# endif
Packit d37888
Packit d37888
#endif /* STAT_STATFS4 */
Packit d37888
Packit d37888
#ifdef STAT_STATVFS		/* SVR4 */
Packit d37888
   /* Linux, Solaris */
Packit d37888
Packit d37888
  if (statvfs (path, &fsd) < 0)
Packit d37888
    return;
Packit d37888
Packit d37888
#if (defined(sun) || defined(__sun)) && (defined(__SVR4) || defined(__svr4__)) \
Packit d37888
	|| defined(__FreeBSD__) || defined(__OpenBSD__)
Packit d37888
  /* Solaris but not SunOS and FreeBSD */
Packit d37888
  buf->block_size = fsd.f_frsize;
Packit d37888
#else
Packit d37888
  /* else, including Linux */
Packit d37888
  buf->block_size = fsd.f_bsize;
Packit d37888
#endif
Packit d37888
Packit d37888
#endif /* STAT_STATVFS */
Packit d37888
Packit d37888
#if !defined STAT_STATFS2_FS_DATA && !defined STAT_READ_FILSYS
Packit d37888
				/* !Ultrix && !SVR2 */
Packit d37888
  /* Linux */
Packit d37888
Packit d37888
  buf->blocks = fsd.f_blocks;
Packit d37888
  buf->bfree  = fsd.f_bfree;
Packit d37888
  buf->bavail = (fsd.f_bavail > fsd.f_bfree) ? 0 : fsd.f_bavail;
Packit d37888
  buf->files  = fsd.f_files;
Packit d37888
  buf->ffree  = fsd.f_ffree;
Packit d37888
Packit d37888
#endif /* not STAT_STATFS2_FS_DATA && not STAT_READ_FILSYS */
Packit d37888
Packit d37888
  buf->flags = _glibtop_sysdeps_fsusage;
Packit d37888
Packit d37888
  /* setting additional flags is delegated */
Packit d37888
  _glibtop_get_fsusage_read_write(server, buf, path);
Packit d37888
}
Packit d37888
Packit d37888
#if defined _AIX && defined _I386
Packit d37888
/* AIX PS/2 does not supply statfs.  */
Packit d37888
Packit d37888
static int
Packit d37888
statfs (const char *path, struct statfs *fsb)
Packit d37888
{
Packit d37888
  struct stat stats;
Packit d37888
  struct dustat fsd;
Packit d37888
Packit d37888
  if (stat (path, &stats))
Packit d37888
    return -1;
Packit d37888
  if (dustat (stats.st_dev, 0, &fsd, sizeof (fsd)))
Packit d37888
    return -1;
Packit d37888
  fsb->f_type   = 0;
Packit d37888
  fsb->f_bsize  = fsd.du_bsize;
Packit d37888
  fsb->f_blocks = fsd.du_fsize - fsd.du_isize;
Packit d37888
  fsb->f_bfree  = fsd.du_tfree;
Packit d37888
  fsb->f_bavail = fsd.du_tfree;
Packit d37888
  fsb->f_files  = (fsd.du_isize - 2) * fsd.du_inopb;
Packit d37888
  fsb->f_ffree  = fsd.du_tinode;
Packit d37888
  fsb->f_fsid.val[0] = fsd.du_site;
Packit d37888
  fsb->f_fsid.val[1] = fsd.du_pckno;
Packit d37888
  return 0;
Packit d37888
}
Packit d37888
Packit d37888
#endif /* _AIX && _I386 */