1// https://github.com/lufia/iostat/blob/9f7362b77ad333b26c01c99de52a11bdb650ded2/iostat_darwin.c
2#include <stdint.h>
3#include <CoreFoundation/CoreFoundation.h>
4#include "iostat_darwin.h"
5
6#define IOKIT 1 /* to get io_name_t in device_types.h */
7
8#include <IOKit/IOKitLib.h>
9#include <IOKit/storage/IOBlockStorageDriver.h>
10#include <IOKit/storage/IOMedia.h>
11#include <IOKit/IOBSD.h>
12
13#include <mach/mach_host.h>
14
15static int getdrivestat(io_registry_entry_t d, DriveStats *stat);
16static int fillstat(io_registry_entry_t d, DriveStats *stat);
17
18int
19readdrivestat(DriveStats a[], int n)
20{
21 mach_port_t port;
22 CFMutableDictionaryRef match;
23 io_iterator_t drives;
24 io_registry_entry_t d;
25 kern_return_t status;
26 int na, rv;
27
28 IOMasterPort(bootstrap_port, &port);
29 match = IOServiceMatching("IOMedia");
30 CFDictionaryAddValue(match, CFSTR(kIOMediaWholeKey), kCFBooleanTrue);
31 status = IOServiceGetMatchingServices(port, match, &drives);
32 if(status != KERN_SUCCESS)
33 return -1;
34
35 na = 0;
36 while(na < n && (d=IOIteratorNext(drives)) > 0){
37 rv = getdrivestat(d, &a[na]);
38 if(rv < 0)
39 return -1;
40 if(rv > 0)
41 na++;
42 IOObjectRelease(d);
43 }
44 IOObjectRelease(drives);
45 return na;
46}
47
48static int
49getdrivestat(io_registry_entry_t d, DriveStats *stat)
50{
51 io_registry_entry_t parent;
52 kern_return_t status;
53 CFDictionaryRef props;
54 CFStringRef name;
55 CFNumberRef num;
56 int rv;
57
58 memset(stat, 0, sizeof *stat);
59 status = IORegistryEntryGetParentEntry(d, kIOServicePlane, &parent);
60 if(status != KERN_SUCCESS)
61 return -1;
62 if(!IOObjectConformsTo(parent, "IOBlockStorageDriver")){
63 IOObjectRelease(parent);
64 return 0;
65 }
66
67 status = IORegistryEntryCreateCFProperties(d, (CFMutableDictionaryRef *)&props, kCFAllocatorDefault, kNilOptions);
68 if(status != KERN_SUCCESS){
69 IOObjectRelease(parent);
70 return -1;
71 }
72 name = (CFStringRef)CFDictionaryGetValue(props, CFSTR(kIOBSDNameKey));
73 CFStringGetCString(name, stat->name, NAMELEN, CFStringGetSystemEncoding());
74 num = (CFNumberRef)CFDictionaryGetValue(props, CFSTR(kIOMediaSizeKey));
75 CFNumberGetValue(num, kCFNumberSInt64Type, &stat->size);
76 num = (CFNumberRef)CFDictionaryGetValue(props, CFSTR(kIOMediaPreferredBlockSizeKey));
77 CFNumberGetValue(num, kCFNumberSInt64Type, &stat->blocksize);
78 CFRelease(props);
79
80 rv = fillstat(parent, stat);
81 IOObjectRelease(parent);
82 if(rv < 0)
83 return -1;
84 return 1;
85}
86
87static struct {
88 char *key;
89 size_t off;
90} statstab[] = {
91 {kIOBlockStorageDriverStatisticsBytesReadKey, offsetof(DriveStats, read)},
92 {kIOBlockStorageDriverStatisticsBytesWrittenKey, offsetof(DriveStats, written)},
93 {kIOBlockStorageDriverStatisticsReadsKey, offsetof(DriveStats, nread)},
94 {kIOBlockStorageDriverStatisticsWritesKey, offsetof(DriveStats, nwrite)},
95 {kIOBlockStorageDriverStatisticsTotalReadTimeKey, offsetof(DriveStats, readtime)},
96 {kIOBlockStorageDriverStatisticsTotalWriteTimeKey, offsetof(DriveStats, writetime)},
97 {kIOBlockStorageDriverStatisticsLatentReadTimeKey, offsetof(DriveStats, readlat)},
98 {kIOBlockStorageDriverStatisticsLatentWriteTimeKey, offsetof(DriveStats, writelat)},
99};
100
101static int
102fillstat(io_registry_entry_t d, DriveStats *stat)
103{
104 CFDictionaryRef props, v;
105 CFNumberRef num;
106 kern_return_t status;
107 typeof(statstab[0]) *bp, *ep;
108
109 status = IORegistryEntryCreateCFProperties(d, (CFMutableDictionaryRef *)&props, kCFAllocatorDefault, kNilOptions);
110 if(status != KERN_SUCCESS)
111 return -1;
112 v = (CFDictionaryRef)CFDictionaryGetValue(props, CFSTR(kIOBlockStorageDriverStatisticsKey));
113 if(v == NULL){
114 CFRelease(props);
115 return -1;
116 }
117
118 ep = &statstab[sizeof(statstab)/sizeof(statstab[0])];
119 for(bp = &statstab[0]; bp < ep; bp++){
120 CFStringRef s;
121
122 s = CFStringCreateWithCString(kCFAllocatorDefault, bp->key, CFStringGetSystemEncoding());
123 num = (CFNumberRef)CFDictionaryGetValue(v, s);
124 if(num)
125 CFNumberGetValue(num, kCFNumberSInt64Type, ((char*)stat)+bp->off);
126 CFRelease(s);
127 }
128
129 CFRelease(props);
130 return 0;
131}
View as plain text