Blame sysdeps/linux/fsusage.c

Packit d37888
#include <config.h>
Packit d37888
#include <glibtop.h>
Packit d37888
#include <glibtop/fsusage.h>
Packit d37888
#include <glibtop/error.h>
Packit d37888
Packit d37888
#include "glibtop_private.h"
Packit d37888
Packit d37888
#include <glib.h>
Packit d37888
Packit d37888
#include <unistd.h>
Packit d37888
#include <sys/types.h>
Packit d37888
#include <sys/stat.h>
Packit d37888
#include <linux/kdev_t.h>
Packit d37888
#include <sys/statvfs.h>
Packit d37888
#include <stdio.h>
Packit d37888
#include <string.h>
Packit d37888
#include <stdlib.h>
Packit d37888
#include <errno.h>
Packit d37888
#include <mntent.h>
Packit d37888
Packit d37888
Packit d37888
/*
Packit d37888
 * Linux 2.6.x
Packit d37888
 * linux/Documentation/iostats.txt
Packit d37888
 */
Packit d37888
Packit d37888
Packit d37888
Packit d37888
Packit d37888
static gboolean
Packit d37888
get_device(glibtop* server, const char *mountpoint,
Packit d37888
	   char* device, size_t device_size)
Packit d37888
{
Packit d37888
	const struct mntent *mnt;
Packit d37888
	FILE *fp;
Packit d37888
	gboolean found = FALSE;
Packit d37888
Packit d37888
	if (!(fp = setmntent(MOUNTED, "r"))) {
Packit d37888
		glibtop_warn_io_r(server, "Could not open %s", MOUNTED);
Packit d37888
		goto out;
Packit d37888
	}
Packit d37888
Packit d37888
	while ((mnt = getmntent(fp)))
Packit d37888
	{
Packit d37888
		/* There can be multiple root mount entries, skip the unuseful one */
Packit d37888
		if (!strcmp(mnt->mnt_fsname, "rootfs"))
Packit d37888
			continue;
Packit d37888
Packit d37888
		if (!strcmp(mountpoint, mnt->mnt_dir)) {
Packit d37888
			if (!strncmp(mnt->mnt_fsname, "/dev/", 5)) {
Packit d37888
				g_strlcpy(device, mnt->mnt_fsname + 5, device_size);
Packit d37888
				found = TRUE;
Packit d37888
			}
Packit d37888
			break;
Packit d37888
		}
Packit d37888
	}
Packit d37888
Packit d37888
	endmntent(fp);
Packit d37888
out:
Packit d37888
	return found;
Packit d37888
}
Packit d37888
Packit d37888
Packit d37888
/*
Packit d37888
  TRUE if device is like "hda3" and then set prefix to "hda".
Packit d37888
 */
Packit d37888
static gboolean
Packit d37888
is_partition(const char* device, char* prefix, size_t prefix_size)
Packit d37888
{
Packit d37888
	g_strlcpy(prefix, device, prefix_size);
Packit d37888
Packit d37888
	for ( ; *prefix; prefix++) {
Packit d37888
		if (isdigit(*prefix)) {
Packit d37888
			*prefix = '\0';
Packit d37888
			return TRUE;
Packit d37888
		}
Packit d37888
	}
Packit d37888
Packit d37888
	return FALSE;
Packit d37888
}
Packit d37888
Packit d37888
Packit d37888
/*
Packit d37888
  Bug #539360.
Packit d37888
  /sys/.../stat format is partially defined in
Packit d37888
  linux/Documentation/block/stat.txt (looks outdated).  Before linux
Packit d37888
  2.5.25, /sys/block/%s/stat and /sys/block/%s/%s/stat were not the
Packit d37888
  same, but the following commit changed the latter to have the same
Packit d37888
  format and broke compatibility.
Packit d37888
Packit d37888
  Commit 34e8beac92c27d292938065f8375842d2840767c
Packit d37888
  Author: Jerome Marchand <jmarchan@redhat.com>
Packit d37888
  Date:   Fri Feb 8 11:04:55 2008 +0100
Packit d37888
Packit d37888
    Enhanced partition statistics: sysfs
Packit d37888
Packit d37888
    Reports enhanced partition statistics in sysfs.
Packit d37888
Packit d37888
    Signed-off-by: Jerome Marchand <jmarchan@redhat.com>
Packit d37888
Packit d37888
    fs/partitions/check.c |   22 +++++++++++++++++++---
Packit d37888
    1 files changed, 19 insertions(+), 3 deletions(-)
Packit d37888
Packit d37888
 */
Packit d37888
Packit d37888
static void
Packit d37888
get_sys_path(glibtop* server, const char *device, char **stat_path, const char **parse_format)
Packit d37888
{
Packit d37888
	const char* linux_2_6_25_format = "%*llu %*llu %llu %*llu"
Packit d37888
					  "%*llu %*llu %llu %*llu";
Packit d37888
Packit d37888
	char prefix[32];
Packit d37888
Packit d37888
	if (is_partition(device, prefix, sizeof prefix)) {
Packit d37888
Packit d37888
		*stat_path = g_strdup_printf("/sys/block/%s/%s/stat",
Packit d37888
					     prefix, device);
Packit d37888
		if (server->os_version_code < LINUX_VERSION_CODE(2, 6, 25))
Packit d37888
			*parse_format = "%*llu %llu %*llu %llu";
Packit d37888
		else
Packit d37888
			*parse_format = linux_2_6_25_format;
Packit d37888
	}
Packit d37888
	else
Packit d37888
	{
Packit d37888
		*stat_path = g_strdup_printf("/sys/block/%s/stat", device);
Packit d37888
		if (server->os_version_code < LINUX_VERSION_CODE(2, 6, 25))
Packit d37888
			*parse_format = "%*llu %*llu %llu %*llu %*llu %*llu %llu";
Packit d37888
		else
Packit d37888
			*parse_format = linux_2_6_25_format;
Packit d37888
	}
Packit d37888
}
Packit d37888
Packit d37888
Packit d37888
Packit d37888
static void linux_2_6_0(glibtop *server, glibtop_fsusage *buf, const char *path)
Packit d37888
{
Packit d37888
	char *filename = NULL;
Packit d37888
	const char *format;
Packit d37888
	int ret;
Packit d37888
	char buffer[BUFSIZ];
Packit d37888
	char device[64];
Packit d37888
Packit d37888
	if (!get_device(server, path, device, sizeof device))
Packit d37888
		goto out;
Packit d37888
Packit d37888
	get_sys_path(server, device, &filename, &format);
Packit d37888
Packit d37888
	ret = try_file_to_buffer(buffer, sizeof buffer, "%s", filename);
Packit d37888
Packit d37888
	if (ret < 0) goto out;
Packit d37888
Packit d37888
	if (sscanf(buffer, format, &buf->read, &buf->write) != 2) {
Packit d37888
		glibtop_warn_io_r(server, "Could not parse %s", filename);
Packit d37888
		goto out;
Packit d37888
	}
Packit d37888
Packit d37888
	buf->flags |= (1 << GLIBTOP_FSUSAGE_READ) | (1 << GLIBTOP_FSUSAGE_WRITE);
Packit d37888
 out:
Packit d37888
	g_free(filename);
Packit d37888
}
Packit d37888
Packit d37888
Packit d37888
static void linux_2_4_0(glibtop *server, glibtop_fsusage *buf, const char *path)
Packit d37888
{
Packit d37888
}
Packit d37888
Packit d37888
Packit d37888
static void
Packit d37888
get_fsusage_read_write(glibtop *server, glibtop_fsusage *buf, const char *path)
Packit d37888
{
Packit d37888
  if(server->os_version_code >= LINUX_VERSION_CODE(2, 6, 0))
Packit d37888
    {
Packit d37888
      linux_2_6_0(server, buf, path);
Packit d37888
    }
Packit d37888
  else if(server->os_version_code >= LINUX_VERSION_CODE(2, 4, 0))
Packit d37888
    {
Packit d37888
      linux_2_4_0(server, buf, path);
Packit d37888
    }
Packit d37888
}
Packit d37888
Packit d37888
Packit d37888
/* the following comes from sysdeps/common/mountlist.c if copyright matters...
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
void
Packit d37888
glibtop_get_fsusage_s(glibtop *server, glibtop_fsusage *buf, const char *path)
Packit d37888
{
Packit d37888
  struct statvfs fsd;
Packit d37888
Packit d37888
  memset(buf, 0, sizeof(glibtop_fsusage));
Packit d37888
Packit d37888
  if (statvfs(path, &fsd) < 0) {
Packit d37888
    glibtop_warn_r(server, "statvfs '%s' failed: %s", path, strerror (errno));
Packit d37888
    return;
Packit d37888
  }
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
  buf->block_size = fsd.f_bsize;
Packit d37888
  buf->flags = _glibtop_sysdeps_fsusage;
Packit d37888
Packit d37888
  /* setting additional flags is delegated */
Packit d37888
  get_fsusage_read_write(server, buf, path);
Packit d37888
}