Blame sysdeps/common/fsusage.c

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