From e445f7e6c5539594600ace7a722dafa3b91a5374 Mon Sep 17 00:00:00 2001 From: Craig Small Date: Tue, 7 Jul 2015 22:42:06 +1000 Subject: [PATCH] library: Update diskstat API 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 --- Makefile.am | 3 + proc/diskstat.c | 327 ++++++++++++++++++++++++++++++ proc/diskstat.h | 70 +++++++ proc/libprocps.sym | 10 +- proc/sysinfo.c | 82 +------- proc/sysinfo.h | 27 --- vmstat.c | 480 ++++++++++++++++++++------------------------- 7 files changed, 618 insertions(+), 381 deletions(-) create mode 100644 proc/diskstat.c create mode 100644 proc/diskstat.h diff --git a/Makefile.am b/Makefile.am index 36ef0eb4..e9c437a7 100644 --- a/Makefile.am +++ b/Makefile.am @@ -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 index 00000000..77642863 --- /dev/null +++ b/proc/diskstat.c @@ -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 + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#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 index 00000000..adf9cfb4 --- /dev/null +++ b/proc/diskstat.h @@ -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 + * + * 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 + +__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 diff --git a/proc/libprocps.sym b/proc/libprocps.sym index fd2980c5..f40cb52a 100644 --- a/proc/libprocps.sym +++ b/proc/libprocps.sym @@ -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; diff --git a/proc/sysinfo.c b/proc/sysinfo.c index 13175bb8..c9dc9f3c 100644 --- a/proc/sysinfo.c +++ b/proc/sysinfo.c @@ -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 diff --git a/proc/sysinfo.h b/proc/sysinfo.h index d025415a..dbb8bef9 100644 --- a/proc/sysinfo.h +++ b/proc/sysinfo.h @@ -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; diff --git a/vmstat.c b/vmstat.c index 559582db..6bd124b5 100644 --- a/vmstat.c +++ b/vmstat.c @@ -53,6 +53,7 @@ #include #include #include +#include #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; ireads, 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) -- 2.40.0