--- /dev/null
+/*
+ * diskstat - Disk statistics - part of procps
+ *
+ * Copyright (C) 2003 Fabian Frederick
+ * Copyright (C) 2003 Albert Cahalan
+ * Copyright (C) 2015 Craig Small <csmall@enc.com.au>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <errno.h>
+
+#include <proc/diskstat.h>
+#include "procps-private.h"
+
+#define DISKSTAT_LINE_LEN 1024
+#define DISKSTAT_NAME_LEN 15
+#define DISKSTAT_FILE "/proc/diskstats"
+#define SYSBLOCK_DIR "/sys/block"
+
+struct procps_diskstat_dev {
+ char name[DISKSTAT_NAME_LEN];
+ int is_disk;
+ unsigned long reads;
+ unsigned long reads_merged;
+ unsigned long read_sectors;
+ unsigned long read_time;
+ unsigned long writes;
+ unsigned long writes_merged;
+ unsigned long write_sectors;
+ unsigned long write_time;
+ unsigned long io_inprogress;
+ unsigned long io_time;
+ unsigned long io_wtime;
+};
+
+struct procps_diskstat {
+ int refcount;
+ FILE *diskstat_fp;
+ struct procps_diskstat_dev *devs;
+ int devs_alloc;
+ int devs_used;
+};
+
+/*
+ * scan_for_disks:
+ *
+ * All disks start off as partitions. This function
+ * scans /sys/block and changes all devices found there
+ * into disks. If /sys/block cannot have the directory
+ * read, all devices are disks
+ */
+static int scan_for_disks(struct procps_diskstat *info)
+{
+ DIR *dirp;
+ struct dirent *dent;
+ int myerrno, i;
+
+ if ((dirp = opendir(SYSBLOCK_DIR)) == NULL) {
+ myerrno = errno;
+ if (myerrno != ENOENT && myerrno != EACCES)
+ return -myerrno;
+ /* Cannot open the dir or perm denied, make all devs disks */
+ for (i=0 ; i < info->devs_used; i++)
+ info->devs[i].is_disk = 1;
+ return 0;
+ }
+
+ while((dent = readdir(dirp)) != NULL) {
+ for (i=0; i < info->devs_used; i++)
+ if (strcmp(dent->d_name, info->devs[i].name) == 0) {
+ info->devs[i].is_disk = 1;
+ break;
+ }
+ }
+ return 0;
+}
+
+static void diskstat_clear(struct procps_diskstat *info)
+{
+ if (info == NULL)
+ return;
+ if (info->devs != NULL && info->devs_alloc > 0) {
+ memset(info->devs, 0, sizeof(struct procps_diskstat_dev)*info->devs_alloc);
+ info->devs_used = 0;
+ }
+}
+
+static int diskdata_alloc(
+ struct procps_diskstat *info)
+{
+ struct procps_diskstat_dev *new_disks;
+ int new_count;
+
+ if (info == NULL)
+ return -EINVAL;
+
+ if (info->devs_used < info->devs_alloc)
+ return 0;
+
+ /* Increment the allocated number of slabs */
+ new_count = info->devs_alloc * 5/4+30;
+
+ if ((new_disks = realloc(info->devs,
+ sizeof(struct procps_diskstat_dev)*new_count)) == NULL)
+ return -ENOMEM;
+ info->devs = new_disks;
+ info->devs_alloc = new_count;
+ return 0;
+}
+
+static int get_disk(
+ struct procps_diskstat *info,
+ struct procps_diskstat_dev **node)
+{
+ int retval;
+
+ if (!info)
+ return -EINVAL;
+
+ if (info->devs_used == info->devs_alloc) {
+ if ((retval = diskdata_alloc(info)) < 0)
+ return retval;
+ }
+ *node = &(info->devs[info->devs_used++]);
+ return 0;
+}
+
+/*
+ * procps_diskstat_new:
+ *
+ * Create a new container to hold the diskstat information
+ *
+ * The initial refcount is 1, and needs to be decremented
+ * to release the resources of the structure.
+ *
+ * Returns: a new procps_diskstat container
+ */
+PROCPS_EXPORT int procps_diskstat_new (
+ struct procps_diskstat **info)
+{
+ struct procps_diskstat *ds;
+ ds = calloc(1, sizeof(struct procps_diskstat));
+ if (!ds)
+ return -ENOMEM;
+
+ ds->refcount = 1;
+ ds->diskstat_fp = NULL;
+ *info = ds;
+ return 0;
+}
+
+/*
+ * procps_diskstat_read:
+ *
+ * @info: info structure created at procps_diskstat_new
+ *
+ * Read the data out of /proc/diskstats putting the information
+ * into the supplied info structure
+ *
+ * Returns: 0 on success, negative on error
+ */
+PROCPS_EXPORT int procps_diskstat_read (
+ struct procps_diskstat *info)
+{
+ int retval, is_disk;
+ char buf[DISKSTAT_LINE_LEN];
+ char devname[DISKSTAT_NAME_LEN];
+ struct procps_diskstat_dev *disk;
+
+ /* clear/zero structures */
+ diskstat_clear(info);
+
+ if (NULL == info->diskstat_fp &&
+ NULL == (info->diskstat_fp = fopen(DISKSTAT_FILE, "r")))
+ return -errno;
+
+ if (fseek(info->diskstat_fp, 0L, SEEK_SET) == -1)
+ return -errno;
+
+ while (fgets(buf, DISKSTAT_LINE_LEN, info->diskstat_fp)) {
+ if (sscanf(buf,
+ "%*d %*d %" STRINGIFY(DISKSTAT_NAME_LEN) "s",
+ devname) < 1) {
+ if (errno != 0)
+ return -errno;
+ return -EINVAL;
+ }
+ if ((retval = get_disk(info, &disk)) < 0)
+ return retval;
+ if (sscanf(buf, " %*d %*d %*s %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu",
+ &disk->reads, &disk->reads_merged, &disk->read_sectors,
+ &disk->read_time,
+ &disk->writes, &disk->writes_merged, &disk->write_sectors,
+ &disk->write_time,
+ &disk->io_inprogress, &disk->io_time, &disk->io_wtime) != 11) {
+ if (errno != 0)
+ return -errno;
+ return -EINVAL;
+ }
+ disk->is_disk = 0; /* default to no until we scan */
+ strcpy(disk->name, devname);
+ }
+ if ((retval = scan_for_disks(info)) < 0)
+ return retval;
+ return 0;
+}
+
+/*
+ * procps_diskstat_dev_count:
+ *
+ * @info: structure that has been read
+ *
+ * Returns: number of devices (disk+partitions)
+ */
+PROCPS_EXPORT int procps_diskstat_dev_count (
+ const struct procps_diskstat *info)
+{
+ if (!info)
+ return -EINVAL;
+ return info->devs_used;
+}
+
+
+/*
+ * procps_diskstat_dev_getbyname
+ *
+ * @info: diskstat data already read
+ * @name: name of partition
+ *
+ * Find the device index by the name
+ *
+ * Returns: devid if found
+ * -1 if not found
+ */
+PROCPS_EXPORT int procps_diskstat_dev_getbyname(
+ const struct procps_diskstat *info,
+ const char *name)
+{
+ int i;
+
+ if (info == NULL || info->devs_used == 0)
+ return -1;
+ for (i=0; i < info->devs_used; i++)
+ if (strcmp(info->devs[i].name, name) == 0)
+ return i;
+ return -1;
+}
+
+
+PROCPS_EXPORT unsigned long procps_diskstat_dev_get(
+ const struct procps_diskstat *info,
+ const enum procps_diskstat_devitem item,
+ const unsigned int devid)
+{
+ if (info == NULL)
+ return 0;
+ if (devid > info->devs_used)
+ return 0;
+ switch(item) {
+ case PROCPS_DISKSTAT_READS:
+ return info->devs[devid].reads;
+ case PROCPS_DISKSTAT_READS_MERGED:
+ return info->devs[devid].reads_merged;
+ case PROCPS_DISKSTAT_READ_SECTORS:
+ return info->devs[devid].read_sectors;
+ case PROCPS_DISKSTAT_READ_TIME:
+ return info->devs[devid].read_time;
+ case PROCPS_DISKSTAT_WRITES:
+ return info->devs[devid].writes;
+ case PROCPS_DISKSTAT_WRITES_MERGED:
+ return info->devs[devid].writes_merged;
+ case PROCPS_DISKSTAT_WRITE_SECTORS:
+ return info->devs[devid].write_sectors;
+ case PROCPS_DISKSTAT_WRITE_TIME:
+ return info->devs[devid].write_time;
+ case PROCPS_DISKSTAT_IO_INPROGRESS:
+ return info->devs[devid].io_inprogress;
+ case PROCPS_DISKSTAT_IO_TIME:
+ return info->devs[devid].io_time;
+ case PROCPS_DISKSTAT_IO_WTIME:
+ return info->devs[devid].io_wtime;
+ default:
+ return 0;
+ }
+}
+
+PROCPS_EXPORT char* procps_diskstat_dev_getname(
+ const struct procps_diskstat *info,
+ const unsigned int devid)
+{
+ if (info == NULL)
+ return 0;
+ if (devid > info->devs_used)
+ return 0;
+ return info->devs[devid].name;
+}
+
+PROCPS_EXPORT int procps_diskstat_dev_isdisk(
+ const struct procps_diskstat *info,
+ const unsigned int devid)
+{
+ if (info == NULL || devid > info->devs_used)
+ return -EINVAL;
+
+ return info->devs[devid].is_disk;
+}
#include <proc/vmstat.h>
#include <proc/readstat.h>
#include <proc/meminfo.h>
+#include <proc/diskstat.h>
#define UNIT_B 1
#define UNIT_k 1000
static unsigned sleep_time = 1;
static int infinite_updates = 0;
-static unsigned long num_updates;
+static unsigned long num_updates =1;
/* window height */
static unsigned int height;
static unsigned int moreheaders = TRUE;
printf("\n");
}
-///////////////////////////////////////////////////////////////////////
-// based on Fabian Frederick's /proc/diskstats parser
-
-static unsigned int getpartitions_num(struct disk_stat *disks, int ndisks)
-{
- unsigned int i;
- int partitions=0;
-
- for (i=0; i<ndisks; i++) {
- partitions+=disks[i].partitions;
- }
- return partitions;
-}
static unsigned long unitConvert(unsigned long size)
{
static int diskpartition_format(const char *partition_name)
{
- FILE *fDiskstat;
- struct disk_stat *disks;
- struct partition_stat *partitions, *current_partition = NULL;
- unsigned long ndisks, j, k, npartitions;
- const char format[] = "%20u %10llu %10u %10llu\n";
-
- fDiskstat = fopen("/proc/diskstats", "rb");
- if (!fDiskstat)
- xerrx(EXIT_FAILURE,
- _("your kernel does not support diskstat. (2.5.70 or above required)"));
-
- fclose(fDiskstat);
- ndisks = getdiskstat(&disks, &partitions);
- npartitions = getpartitions_num(disks, ndisks);
- for (k = 0; k < npartitions; k++) {
- if (!strcmp(partition_name, partitions[k].partition_name)) {
- current_partition = &(partitions[k]);
- }
- }
- if (!current_partition) {
- free(disks);
- free(partitions);
- return -1;
- }
- diskpartition_header(partition_name);
- printf(format,
- current_partition->reads, current_partition->reads_sectors,
- current_partition->writes, current_partition->requested_writes);
- fflush(stdout);
- free(disks);
- free(partitions);
- for (j = 1; infinite_updates || j < num_updates; j++) {
- if (moreheaders && ((j % height) == 0))
- diskpartition_header(partition_name);
- sleep(sleep_time);
- ndisks = getdiskstat(&disks, &partitions);
- npartitions = getpartitions_num(disks, ndisks);
- current_partition = NULL;
- for (k = 0; k < npartitions; k++) {
- if (!strcmp
- (partition_name, partitions[k].partition_name)) {
- current_partition = &(partitions[k]);
- }
- }
- if (!current_partition) {
- free(disks);
- free(partitions);
- return -1;
- }
- printf(format,
- current_partition->reads,
- current_partition->reads_sectors,
- current_partition->writes,
- current_partition->requested_writes);
- fflush(stdout);
- free(disks);
- free(partitions);
- }
- return 0;
+#define PARTGET(x) procps_diskstat_dev_get(disk_stat, (x), partid)
+ struct procps_diskstat *disk_stat;
+ const char format[] = "%20u %10llu %10u %10llu\n";
+ int i, partid;
+
+ if (procps_diskstat_new(&disk_stat) < 0)
+ xerr(EXIT_FAILURE,
+ _("Unable to create diskstat structure"));
+
+ if (procps_diskstat_read(disk_stat) < 0)
+ xerr(EXIT_FAILURE,
+ _("Unable to read diskstat"));
+ if ((partid = procps_diskstat_dev_getbyname(disk_stat, partition_name))
+ < 0)
+ xerrx(EXIT_FAILURE, _("Partition %s not found"), partition_name);
+
+ diskpartition_header(partition_name);
+ for (i=0; infinite_updates || i < num_updates ; i++) {
+ if (procps_diskstat_read(disk_stat) < 0)
+ xerr(EXIT_FAILURE,
+ _("Unable to read diskstat"));
+ if ((partid = procps_diskstat_dev_getbyname(disk_stat, partition_name))
+ < 0)
+ xerrx(EXIT_FAILURE,
+ _("Partition %s not found"), partition_name);
+
+ printf(format,
+ PARTGET(PROCPS_DISKSTAT_READS),
+ PARTGET(PROCPS_DISKSTAT_READ_SECTORS),
+ PARTGET(PROCPS_DISKSTAT_WRITES),
+ PARTGET(PROCPS_DISKSTAT_WRITE_SECTORS)
+ );
+
+ if (infinite_updates || i+1 < num_updates)
+ sleep(sleep_time);
+ }
+ return 0;
}
static void diskheader(void)
{
- struct tm *tm_ptr;
- time_t the_time;
- char timebuf[32];
-
- /* Translation Hint: Translating folloging header & fields
- * that follow (marked with max x chars) might not work,
- * unless manual page is translated as well. */
- const char *header =
- _("disk- ------------reads------------ ------------writes----------- -----IO------");
- const char *wide_header =
- _("disk- -------------------reads------------------- -------------------writes------------------ ------IO-------");
- const char *timestamp_header = _(" -----timestamp-----");
-
- const char format[] =
- "%5s %6s %6s %7s %7s %6s %6s %7s %7s %6s %6s";
- const char wide_format[] =
- "%5s %9s %9s %11s %11s %9s %9s %11s %11s %7s %7s";
-
- printf("%s", w_option ? wide_header : header);
-
- if (t_option) {
- printf("%s", timestamp_header);
- }
-
- printf("\n");
-
- printf(w_option ? wide_format : format,
- " ",
- /* Translation Hint: max 6 chars */
- _("total"),
- /* Translation Hint: max 6 chars */
- _("merged"),
- /* Translation Hint: max 7 chars */
- _("sectors"),
- /* Translation Hint: max 7 chars */
- _("ms"),
- /* Translation Hint: max 6 chars */
- _("total"),
- /* Translation Hint: max 6 chars */
- _("merged"),
- /* Translation Hint: max 7 chars */
- _("sectors"),
- /* Translation Hint: max 7 chars */
- _("ms"),
- /* Translation Hint: max 6 chars */
- _("cur"),
- /* Translation Hint: max 6 chars */
- _("sec"));
+ struct tm *tm_ptr;
+ time_t the_time;
+ char timebuf[32];
+
+ /* Translation Hint: Translating folloging header & fields
+ * that follow (marked with max x chars) might not work,
+ * unless manual page is translated as well. */
+ const char *header =
+ _("disk- ------------reads------------ ------------writes----------- -----IO------");
+ const char *wide_header =
+ _("disk- -------------------reads------------------- -------------------writes------------------ ------IO-------");
+ const char *timestamp_header = _(" -----timestamp-----");
+
+ const char format[] =
+ "%5s %6s %6s %7s %7s %6s %6s %7s %7s %6s %6s";
+ const char wide_format[] =
+ "%5s %9s %9s %11s %11s %9s %9s %11s %11s %7s %7s";
+
+ printf("%s", w_option ? wide_header : header);
+
+ if (t_option) {
+ printf("%s", timestamp_header);
+ }
- if (t_option) {
- (void) time( &the_time );
- tm_ptr = localtime( &the_time );
- if (strftime(timebuf, sizeof(timebuf), "%Z", tm_ptr)) {
- timebuf[strlen(timestamp_header) - 1] = '\0';
- } else {
- timebuf[0] = '\0';
- }
- printf(" %*s", (int)(strlen(timestamp_header) - 1), timebuf);
- }
+ printf("\n");
+
+ printf(w_option ? wide_format : format,
+ " ",
+ /* Translation Hint: max 6 chars */
+ _("total"),
+ /* Translation Hint: max 6 chars */
+ _("merged"),
+ /* Translation Hint: max 7 chars */
+ _("sectors"),
+ /* Translation Hint: max 7 chars */
+ _("ms"),
+ /* Translation Hint: max 6 chars */
+ _("total"),
+ /* Translation Hint: max 6 chars */
+ _("merged"),
+ /* Translation Hint: max 7 chars */
+ _("sectors"),
+ /* Translation Hint: max 7 chars */
+ _("ms"),
+ /* Translation Hint: max 6 chars */
+ _("cur"),
+ /* Translation Hint: max 6 chars */
+ _("sec"));
+
+ if (t_option) {
+ (void) time( &the_time );
+ tm_ptr = localtime( &the_time );
+ if (strftime(timebuf, sizeof(timebuf), "%Z", tm_ptr)) {
+ timebuf[strlen(timestamp_header) - 1] = '\0';
+ } else {
+ timebuf[0] = '\0';
+ }
+ printf(" %*s", (int)(strlen(timestamp_header) - 1), timebuf);
+ }
- printf("\n");
+ printf("\n");
}
static void diskformat(void)
{
- const char format[] =
- "%-5s %6u %6u %7llu %7u %6u %6u %7llu %7u %6u %6u";
- const char wide_format[] =
- "%-5s %9u %9u %11llu %11u %9u %9u %11llu %11u %7u %7u";
-
- FILE *fDiskstat;
- struct disk_stat *disks;
- struct partition_stat *partitions;
- unsigned long ndisks, i, j, k;
- struct tm *tm_ptr;
- time_t the_time;
- char timebuf[32];
-
-
- if ((fDiskstat = fopen("/proc/diskstats", "rb"))) {
- fclose(fDiskstat);
- ndisks = getdiskstat(&disks, &partitions);
-
- if (t_option) {
- (void) time( &the_time );
- tm_ptr = localtime( &the_time );
- strftime(timebuf, sizeof(timebuf), "%Y-%m-%d %H:%M:%S", tm_ptr);
- }
-
- if (!moreheaders)
- diskheader();
- for (k = 0; k < ndisks; k++) {
- if (moreheaders && ((k % height) == 0))
- diskheader();
- printf(w_option ? wide_format : format,
- disks[k].disk_name,
- disks[k].reads,
- disks[k].merged_reads,
- disks[k].reads_sectors,
- disks[k].milli_reading,
- disks[k].writes,
- disks[k].merged_writes,
- disks[k].written_sectors,
- disks[k].milli_writing,
- disks[k].inprogress_IO ? disks[k].inprogress_IO / 1000 : 0,
- disks[k].milli_spent_IO ? disks[k].
- milli_spent_IO / 1000 : 0);
-
- if (t_option) {
- printf(" %s", timebuf);
- }
-
- printf("\n");
- fflush(stdout);
- }
- free(disks);
- free(partitions);
-
- for (j = 1; infinite_updates || j < num_updates; j++) {
- sleep(sleep_time);
- ndisks = getdiskstat(&disks, &partitions);
-
- if (t_option) {
- (void) time( &the_time );
- tm_ptr = localtime( &the_time );
- strftime(timebuf, sizeof(timebuf), "%Y-%m-%d %H:%M:%S", tm_ptr);
- }
-
- for (i = 0; i < ndisks; i++, k++) {
- if (moreheaders && ((k % height) == 0))
- diskheader();
- printf(w_option ? wide_format : format,
- disks[i].disk_name,
- disks[i].reads,
- disks[i].merged_reads,
- disks[i].reads_sectors,
- disks[i].milli_reading,
- disks[i].writes,
- disks[i].merged_writes,
- disks[i].written_sectors,
- disks[i].milli_writing,
- disks[i].inprogress_IO ? disks[i].inprogress_IO / 1000 : 0,
- disks[i].milli_spent_IO ? disks[i].
- milli_spent_IO / 1000 : 0);
-
- if (t_option) {
- printf(" %s", timebuf);
- }
-
- printf("\n");
- fflush(stdout);
- }
- free(disks);
- free(partitions);
- }
- } else
- xerrx(EXIT_FAILURE,
- _("your kernel does not support diskstat (2.5.70 or above required)"));
+#define DSTAT(x) procps_diskstat_dev_get(disk_stat, (x), diskid)
+ struct procps_diskstat *disk_stat;
+ int i,diskid, disk_count;
+ time_t the_time;
+ struct tm *tm_ptr;
+ char timebuf[32];
+ const char format[] = "%-5s %6u %6u %7llu %7u %6u %6u %7llu %7u %6u %6u";
+ const char wide_format[] = "%-5s %9u %9u %11llu %11u %9u %9u %11llu %11u %7u %7u";
+
+ if (procps_diskstat_new(&disk_stat) < 0)
+ xerr(EXIT_FAILURE,
+ _("Unable to create diskstat structure"));
+
+ if (!moreheaders)
+ diskheader();
+ for (i=0; infinite_updates || i < num_updates ; i++) {
+ if (procps_diskstat_read(disk_stat) < 0)
+ xerr(EXIT_FAILURE,
+ _("Unable to read diskstat data"));
+
+ if (t_option) {
+ (void) time( &the_time );
+ tm_ptr = localtime( &the_time );
+ strftime(timebuf, sizeof(timebuf), "%Y-%m-%d %H:%M:%S", tm_ptr);
+ }
+ disk_count = procps_diskstat_dev_count(disk_stat);
+ for (diskid = 0; diskid < disk_count; diskid++) {
+ if (procps_diskstat_dev_isdisk(disk_stat, diskid) != 1)
+ continue; /* not a disk */
+ if (moreheaders && ((diskid % height) == 0))
+ diskheader();
+ printf(w_option ? wide_format : format,
+ procps_diskstat_dev_getname(disk_stat, diskid),
+ DSTAT(PROCPS_DISKSTAT_READS),
+ DSTAT(PROCPS_DISKSTAT_READS_MERGED),
+ DSTAT(PROCPS_DISKSTAT_READ_SECTORS),
+ DSTAT(PROCPS_DISKSTAT_READ_TIME),
+ DSTAT(PROCPS_DISKSTAT_WRITES),
+ DSTAT(PROCPS_DISKSTAT_WRITES_MERGED),
+ DSTAT(PROCPS_DISKSTAT_WRITE_SECTORS),
+ DSTAT(PROCPS_DISKSTAT_WRITE_TIME),
+ DSTAT(PROCPS_DISKSTAT_IO_INPROGRESS) / 1000,
+ DSTAT(PROCPS_DISKSTAT_IO_TIME) / 1000);
+ if (t_option)
+ printf(" %s\n", timebuf);
+ else
+ printf("\n");
+ fflush(stdout);
+ }
+ if (infinite_updates || i+1 < num_updates)
+ sleep(sleep_time);
+ }
+#undef DSTAT
}
static void slabheader(void)
static void disksum_format(void)
{
-
- FILE *fDiskstat;
- struct disk_stat *disks;
- struct partition_stat *partitions;
- int ndisks, i;
- unsigned long reads, merged_reads, read_sectors, milli_reading, writes,
- merged_writes, written_sectors, milli_writing, inprogress_IO,
- milli_spent_IO, weighted_milli_spent_IO;
-
- reads = merged_reads = read_sectors = milli_reading = writes =
- merged_writes = written_sectors = milli_writing = inprogress_IO =
- milli_spent_IO = weighted_milli_spent_IO = 0;
-
- if ((fDiskstat = fopen("/proc/diskstats", "rb"))) {
- fclose(fDiskstat);
- ndisks = getdiskstat(&disks, &partitions);
- printf(_("%13d disks \n"), ndisks);
- printf(_("%13d partitions \n"),
- getpartitions_num(disks, ndisks));
-
- for (i = 0; i < ndisks; i++) {
- reads += disks[i].reads;
- merged_reads += disks[i].merged_reads;
- read_sectors += disks[i].reads_sectors;
- milli_reading += disks[i].milli_reading;
- writes += disks[i].writes;
- merged_writes += disks[i].merged_writes;
- written_sectors += disks[i].written_sectors;
- milli_writing += disks[i].milli_writing;
- inprogress_IO += disks[i].inprogress_IO ? disks[i].inprogress_IO / 1000 : 0;
- milli_spent_IO += disks[i].milli_spent_IO ? disks[i].milli_spent_IO / 1000 : 0;
- }
-
- printf(_("%13lu total reads\n"), reads);
- printf(_("%13lu merged reads\n"), merged_reads);
- printf(_("%13lu read sectors\n"), read_sectors);
- printf(_("%13lu milli reading\n"), milli_reading);
- printf(_("%13lu writes\n"), writes);
- printf(_("%13lu merged writes\n"), merged_writes);
- printf(_("%13lu written sectors\n"), written_sectors);
- printf(_("%13lu milli writing\n"), milli_writing);
- printf(_("%13lu inprogress IO\n"), inprogress_IO);
- printf(_("%13lu milli spent IO\n"), milli_spent_IO);
-
- free(disks);
- free(partitions);
- }
+#define DSTAT(x) procps_diskstat_dev_get(disk_stat, (x), devid)
+ struct procps_diskstat *disk_stat;
+
+ if (procps_diskstat_new(&disk_stat) < 0)
+ xerr(EXIT_FAILURE,
+ _("Unable to create diskstat structure"));
+
+ if (procps_diskstat_read(disk_stat) < 0)
+ xerr(EXIT_FAILURE,
+ _("Unable to read diskstat"));
+
+ int devid, dev_count, disk_count, part_count ;
+ unsigned long reads, merged_reads, read_sectors, milli_reading, writes,
+ merged_writes, written_sectors, milli_writing, inprogress_IO,
+ milli_spent_IO, weighted_milli_spent_IO;
+
+ reads = merged_reads = read_sectors = milli_reading = writes =
+ merged_writes = written_sectors = milli_writing = inprogress_IO =
+ milli_spent_IO = weighted_milli_spent_IO = 0;
+ disk_count = part_count = 0;
+
+ if ((dev_count = procps_diskstat_dev_count(disk_stat)) < 0)
+ xerr(EXIT_FAILURE,
+ _("Unable to count diskstat devices"));
+
+ for (devid=0; devid < dev_count; devid++) {
+ if (procps_diskstat_dev_isdisk(disk_stat, devid) != 1) {
+ part_count++;
+ continue; /* not a disk */
+ }
+ disk_count++;
+ reads += DSTAT(PROCPS_DISKSTAT_READS);
+ merged_reads += DSTAT(PROCPS_DISKSTAT_READS_MERGED);
+ read_sectors += DSTAT(PROCPS_DISKSTAT_READ_SECTORS);
+ milli_reading += DSTAT(PROCPS_DISKSTAT_READ_TIME);
+ writes += DSTAT(PROCPS_DISKSTAT_WRITES);
+ merged_writes += DSTAT(PROCPS_DISKSTAT_WRITES_MERGED);
+ written_sectors += DSTAT(PROCPS_DISKSTAT_WRITE_SECTORS);
+ milli_writing += DSTAT(PROCPS_DISKSTAT_WRITE_TIME);
+ inprogress_IO += DSTAT(PROCPS_DISKSTAT_IO_INPROGRESS) / 1000;
+ milli_spent_IO += DSTAT(PROCPS_DISKSTAT_IO_TIME) / 1000;
+ weighted_milli_spent_IO += DSTAT(PROCPS_DISKSTAT_IO_TIME) / 1000;
+ }
+ printf(_("%13d disks\n"), disk_count);
+ printf(_("%13d partitions\n"), part_count);
+ printf(_("%13lu reads\n"), reads);
+ printf(_("%13lu merged reads\n"), merged_reads);
+ printf(_("%13lu read sectors\n"), read_sectors);
+ printf(_("%13lu milli reading\n"), milli_reading);
+ printf(_("%13lu writes\n"), writes);
+ printf(_("%13lu merged writes\n"), merged_writes);
+ printf(_("%13lu written sectors\n"), written_sectors);
+ printf(_("%13lu milli writing\n"), milli_writing);
+ printf(_("%13lu inprogress IO\n"), inprogress_IO);
+ printf(_("%13lu milli spent IO\n"), milli_spent_IO);
+ printf(_("%13lu milli weighted IO\n"), weighted_milli_spent_IO);
+#undef DSTAT
}
static void sum_format(void)