]> granicus.if.org Git - procps-ng/commitdiff
library: Update diskstat API
authorCraig Small <csmall@enc.com.au>
Tue, 7 Jul 2015 12:42:06 +0000 (22:42 +1000)
committerCraig Small <csmall@enc.com.au>
Tue, 7 Jul 2015 12:42:06 +0000 (22:42 +1000)
The calls for reading diskstat have been moved out of
sysinfo and into new files diskstat.[ch] These new
library calls follow the standard pattern for the
new libprocps.

vmstat is updated to use the new API and also got
the weighted IO time added.

vmstat -p previously would only show partitions, not
disks. There does not appear to be any good reason to
artifically deny a user to use this command on a disk,
rather than a partition so this restriction was lifted.

I also realised using int for devid means you can send
the library negative numbers, the index uses unsigned int.
Other similiar calls will need to be fixed too.

Signed-off-by: Craig Small <csmall@enc.com.au>
Makefile.am
proc/diskstat.c [new file with mode: 0644]
proc/diskstat.h [new file with mode: 0644]
proc/libprocps.sym
proc/sysinfo.c
proc/sysinfo.h
vmstat.c

index 36ef0eb4aeaa4a721eaf84f1d02f5f03c0c97291..e9c437a77d20572aebfa7678178060bee991638c 100644 (file)
@@ -156,6 +156,8 @@ proc_libprocps_la_SOURCES = \
        proc/alloc.h \
        proc/devname.c \
        proc/devname.h \
+       proc/diskstat.c \
+       proc/diskstat.h \
        proc/escape.c \
        proc/escape.h \
        proc/procps-private.h \
@@ -185,6 +187,7 @@ proc_libprocps_la_includedir = $(includedir)/proc/
 proc_libprocps_la_include_HEADERS = \
        proc/alloc.h \
        proc/devname.h \
+       proc/diskstat.h \
        proc/escape.h \
        proc/procps.h \
        proc/pwcache.h \
diff --git a/proc/diskstat.c b/proc/diskstat.c
new file mode 100644 (file)
index 0000000..7764286
--- /dev/null
@@ -0,0 +1,327 @@
+/*
+ * 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;
+}
diff --git a/proc/diskstat.h b/proc/diskstat.h
new file mode 100644 (file)
index 0000000..adf9cfb
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * 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
+ */
+#ifndef PROC_DISKSTAT_H
+#define PROC_DISKSTAT_H
+
+#include <proc/procps.h>
+
+__BEGIN_DECLS
+
+enum procps_diskstat_devitem {
+    PROCPS_DISKSTAT_READS,
+    PROCPS_DISKSTAT_READS_MERGED,
+    PROCPS_DISKSTAT_READ_SECTORS,
+    PROCPS_DISKSTAT_READ_TIME,
+    PROCPS_DISKSTAT_WRITES,
+    PROCPS_DISKSTAT_WRITES_MERGED,
+    PROCPS_DISKSTAT_WRITE_SECTORS,
+    PROCPS_DISKSTAT_WRITE_TIME,
+    PROCPS_DISKSTAT_IO_INPROGRESS,
+    PROCPS_DISKSTAT_IO_TIME,
+    PROCPS_DISKSTAT_IO_WTIME
+};
+
+struct procps_diskstat;
+struct procps_diskstat_dev;
+
+int procps_diskstat_new (struct procps_diskstat **info);
+int procps_diskstat_read (struct procps_diskstat *info);
+
+int procps_diskstat_ref (struct procps_diskstat *info);
+int procps_diskstat_unref (struct procps_diskstat **info);
+
+int procps_diskstat_dev_count (const struct procps_diskstat *info);
+int procps_diskstat_dev_getbyname(
+        const struct procps_diskstat *info,
+        const char *name);
+
+unsigned long procps_diskstat_dev_get(
+        const struct procps_diskstat *info,
+        const enum procps_diskstat_devitem item,
+        const unsigned int devid);
+
+char* procps_diskstat_dev_getname(
+        const struct procps_diskstat *info,
+        const unsigned int devid);
+
+int procps_diskstat_dev_isdisk(
+        const struct procps_diskstat *info,
+        const unsigned int devid);
+__END_DECLS
+#endif
index fd2980c562bcbb445cd86dc70ac242d0906b5e78..f40cb52a2d33ac079f38e8df4e65734ea1d7b4a4 100644 (file)
@@ -12,7 +12,6 @@ global:
        get_ns_name;
        get_pid_digits;
        get_slabinfo;
-       getdiskstat;
        getslabinfo;
        look_up_our_self;
        lookup_wchan;
@@ -27,6 +26,15 @@ global:
        tty_to_dev;
        user_from_uid;
        procps_cpu_count;
+       procps_diskstat_dev_count;
+       procps_diskstat_dev_get;
+       procps_diskstat_dev_getbyname;
+       procps_diskstat_dev_getname;
+       procps_diskstat_dev_isdisk;
+       procps_diskstat_new;
+       procps_diskstat_read;
+       procps_diskstat_ref;
+       procps_diskstat_unref;
        procps_hertz_get;
        procps_linux_version;
        procps_loadavg;
index 13175bb8bcb1a65e0ccbfab5e4139404ea48845a..c9dc9f3cb87b12a3132c0ae586f335a236e7df22 100644 (file)
@@ -2,7 +2,7 @@
  * File for parsing top-level /proc entities.
  * Copyright (C) 1992-1998 by Michael K. Johnson, johnsonm@redhat.com
  * Copyright 1998-2003 Albert Cahalan
- * June 2003, Fabian Frederick, disk and slab info
+ * June 2003, Fabian Frederick, slab info
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -154,86 +154,6 @@ static void crash(const char *filename) {
     exit(EXIT_FAILURE);
 }
 
-
-/////////////////////////////////////////////////////////////////////////////
-static int is_disk(char *dev)
-{
-  char syspath[32];
-  char *slash;
-
-  while ((slash = strchr(dev, '/')))
-    *slash = '!';
-  snprintf(syspath, sizeof(syspath), "/sys/block/%s", dev);
-  return !(access(syspath, F_OK));
-}
-
-/////////////////////////////////////////////////////////////////////////////
-
-unsigned int getdiskstat(struct disk_stat **disks, struct partition_stat **partitions){
-  FILE* fd;
-  int cDisk = 0;
-  int cPartition = 0;
-  int fields;
-  unsigned dummy;
-  char devname[32];
-
-  *disks = NULL;
-  *partitions = NULL;
-  buff[BUFFSIZE-1] = 0;
-  fd = fopen("/proc/diskstats", "rb");
-  if(!fd) crash("/proc/diskstats");
-
-  for (;;) {
-    if (!fgets(buff,BUFFSIZE-1,fd)){
-      fclose(fd);
-      break;
-    }
-    fields = sscanf(buff, " %*d %*d %15s %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %u", devname, &dummy);
-    if (fields == 2 && is_disk(devname)){
-      (*disks) = xrealloc(*disks, (cDisk+1)*sizeof(struct disk_stat));
-      sscanf(buff,  "   %*d    %*d %15s %u %u %llu %u %u %u %llu %u %u %u %u",
-        //&disk_major,
-        //&disk_minor,
-        (*disks)[cDisk].disk_name,
-        &(*disks)[cDisk].reads,
-        &(*disks)[cDisk].merged_reads,
-        &(*disks)[cDisk].reads_sectors,
-        &(*disks)[cDisk].milli_reading,
-        &(*disks)[cDisk].writes,
-        &(*disks)[cDisk].merged_writes,
-        &(*disks)[cDisk].written_sectors,
-        &(*disks)[cDisk].milli_writing,
-        &(*disks)[cDisk].inprogress_IO,
-        &(*disks)[cDisk].milli_spent_IO,
-        &(*disks)[cDisk].weighted_milli_spent_IO
-      );
-        (*disks)[cDisk].partitions=0;
-      cDisk++;
-    }else{
-      (*partitions) = xrealloc(*partitions, (cPartition+1)*sizeof(struct partition_stat));
-      fflush(stdout);
-      sscanf(buff,  (fields == 2)
-          ? "   %*d    %*d %15s %u %*u %llu %*u %u %*u %llu %*u %*u %*u %*u"
-          : "   %*d    %*d %15s %u %llu %u %llu",
-        //&part_major,
-        //&part_minor,
-        (*partitions)[cPartition].partition_name,
-        &(*partitions)[cPartition].reads,
-        &(*partitions)[cPartition].reads_sectors,
-        &(*partitions)[cPartition].writes,
-        &(*partitions)[cPartition].requested_writes
-      );
-
-      if (cDisk > 0) {
-        (*partitions)[cPartition++].parent_disk = cDisk-1;
-        (*disks)[cDisk-1].partitions++;
-      }
-    }
-  }
-
-  return cDisk;
-}
-
 /////////////////////////////////////////////////////////////////////////////
 // based on Fabian Frederick's /proc/slabinfo parser
 
index d025415a6d5ba633e9ffd758c2e58da62377b92c..dbb8bef932602d3acabc5c8311932f1f1ac68d36 100644 (file)
@@ -15,33 +15,6 @@ int procps_loadavg(double *av1, double *av5, double *av15);
 #define BUFFSIZE (64*1024)
 typedef unsigned long long jiff;
 
-typedef struct disk_stat{
-       unsigned long long reads_sectors;
-       unsigned long long written_sectors;
-       char               disk_name [16];
-       unsigned           inprogress_IO;
-       unsigned           merged_reads;
-       unsigned           merged_writes;
-       unsigned           milli_reading;
-       unsigned           milli_spent_IO;
-       unsigned           milli_writing;
-       unsigned           partitions;
-       unsigned           reads;
-       unsigned           weighted_milli_spent_IO;
-       unsigned           writes;
-}disk_stat;
-
-typedef struct partition_stat{
-       char partition_name [16];
-       unsigned long long reads_sectors;
-       unsigned           parent_disk;  // index into a struct disk_stat array
-       unsigned           reads;
-       unsigned           writes;
-       unsigned long long requested_writes;
-}partition_stat;
-
-extern unsigned int getdiskstat (struct disk_stat**,struct partition_stat**);
-
 typedef struct slab_cache{
        char name[48];
        unsigned active_objs;
index 559582dbbb82c55a107c3bab54da603be9f45e86..6bd124b5edf63d3f95cba4ee7cc00ee019b636bb 100644 (file)
--- a/vmstat.c
+++ b/vmstat.c
@@ -53,6 +53,7 @@
 #include <proc/vmstat.h>
 #include <proc/readstat.h>
 #include <proc/meminfo.h>
+#include <proc/diskstat.h>
 
 #define UNIT_B        1
 #define UNIT_k        1000
@@ -83,7 +84,7 @@ static int t_option;
 
 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;
@@ -199,19 +200,6 @@ static void new_header(void)
        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)
 {
@@ -444,227 +432,165 @@ static void diskpartition_header(const char *partition_name)
 
 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)
@@ -730,53 +656,63 @@ static void slabformat(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)