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 
15 static int getdrivestat(io_registry_entry_t d, DriveStats *stat);
16 static int fillstat(io_registry_entry_t d, DriveStats *stat);
17 
18 int
v3readdrivestat(DriveStats a[],int n)19 v3readdrivestat(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 
48 static int
getdrivestat(io_registry_entry_t d,DriveStats * stat)49 getdrivestat(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 
87 static 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 
101 static int
fillstat(io_registry_entry_t d,DriveStats * stat)102 fillstat(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 }
132