// https://github.com/lufia/iostat/blob/9f7362b77ad333b26c01c99de52a11bdb650ded2/iostat_darwin.c #include #include #include "iostat_darwin.h" #define IOKIT 1 /* to get io_name_t in device_types.h */ #include #include #include #include #include static int getdrivestat(io_registry_entry_t d, DriveStats *stat); static int fillstat(io_registry_entry_t d, DriveStats *stat); int gopsutil_v3_readdrivestat(DriveStats a[], int n) { mach_port_t port; CFMutableDictionaryRef match; io_iterator_t drives; io_registry_entry_t d; kern_return_t status; int na, rv; IOMainPort(bootstrap_port, &port); match = IOServiceMatching("IOMedia"); CFDictionaryAddValue(match, CFSTR(kIOMediaWholeKey), kCFBooleanTrue); status = IOServiceGetMatchingServices(port, match, &drives); if(status != KERN_SUCCESS) return -1; na = 0; while(na < n && (d=IOIteratorNext(drives)) > 0){ rv = getdrivestat(d, &a[na]); if(rv < 0) return -1; if(rv > 0) na++; IOObjectRelease(d); } IOObjectRelease(drives); return na; } static int getdrivestat(io_registry_entry_t d, DriveStats *stat) { io_registry_entry_t parent; kern_return_t status; CFDictionaryRef props; CFStringRef name; CFNumberRef num; int rv; memset(stat, 0, sizeof *stat); status = IORegistryEntryGetParentEntry(d, kIOServicePlane, &parent); if(status != KERN_SUCCESS) return -1; if(!IOObjectConformsTo(parent, "IOBlockStorageDriver")){ IOObjectRelease(parent); return 0; } status = IORegistryEntryCreateCFProperties(d, (CFMutableDictionaryRef *)&props, kCFAllocatorDefault, kNilOptions); if(status != KERN_SUCCESS){ IOObjectRelease(parent); return -1; } name = (CFStringRef)CFDictionaryGetValue(props, CFSTR(kIOBSDNameKey)); CFStringGetCString(name, stat->name, NAMELEN, CFStringGetSystemEncoding()); num = (CFNumberRef)CFDictionaryGetValue(props, CFSTR(kIOMediaSizeKey)); CFNumberGetValue(num, kCFNumberSInt64Type, &stat->size); num = (CFNumberRef)CFDictionaryGetValue(props, CFSTR(kIOMediaPreferredBlockSizeKey)); CFNumberGetValue(num, kCFNumberSInt64Type, &stat->blocksize); CFRelease(props); rv = fillstat(parent, stat); IOObjectRelease(parent); if(rv < 0) return -1; return 1; } static struct { char *key; size_t off; } statstab[] = { {kIOBlockStorageDriverStatisticsBytesReadKey, offsetof(DriveStats, read)}, {kIOBlockStorageDriverStatisticsBytesWrittenKey, offsetof(DriveStats, written)}, {kIOBlockStorageDriverStatisticsReadsKey, offsetof(DriveStats, nread)}, {kIOBlockStorageDriverStatisticsWritesKey, offsetof(DriveStats, nwrite)}, {kIOBlockStorageDriverStatisticsTotalReadTimeKey, offsetof(DriveStats, readtime)}, {kIOBlockStorageDriverStatisticsTotalWriteTimeKey, offsetof(DriveStats, writetime)}, {kIOBlockStorageDriverStatisticsLatentReadTimeKey, offsetof(DriveStats, readlat)}, {kIOBlockStorageDriverStatisticsLatentWriteTimeKey, offsetof(DriveStats, writelat)}, }; static int fillstat(io_registry_entry_t d, DriveStats *stat) { CFDictionaryRef props, v; CFNumberRef num; kern_return_t status; typeof(statstab[0]) *bp, *ep; status = IORegistryEntryCreateCFProperties(d, (CFMutableDictionaryRef *)&props, kCFAllocatorDefault, kNilOptions); if(status != KERN_SUCCESS) return -1; v = (CFDictionaryRef)CFDictionaryGetValue(props, CFSTR(kIOBlockStorageDriverStatisticsKey)); if(v == NULL){ CFRelease(props); return -1; } ep = &statstab[sizeof(statstab)/sizeof(statstab[0])]; for(bp = &statstab[0]; bp < ep; bp++){ CFStringRef s; s = CFStringCreateWithCString(kCFAllocatorDefault, bp->key, CFStringGetSystemEncoding()); num = (CFNumberRef)CFDictionaryGetValue(v, s); if(num) CFNumberGetValue(num, kCFNumberSInt64Type, ((char*)stat)+bp->off); CFRelease(s); } CFRelease(props); return 0; }