2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
26 * Copyright (c) 1997, 1998, 2000, 2001 Kenneth D. Merry
27 * All rights reserved.
29 * Redistribution and use in source and binary forms, with or without
30 * modification, are permitted provided that the following conditions
32 * 1. Redistributions of source code must retain the above copyright
33 * notice, this list of conditions and the following disclaimer.
34 * 2. Redistributions in binary form must reproduce the above copyright
35 * notice, this list of conditions and the following disclaimer in the
36 * documentation and/or other materials provided with the distribution.
37 * 3. The name of the author may not be used to endorse or promote products
38 * derived from this software without specific prior written permission.
40 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
41 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
43 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
44 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
45 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
46 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
48 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
49 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
52 * $FreeBSD: src/usr.sbin/iostat/iostat.c,v 1.22 2001/09/01 07:40:19 kris Exp $
55 * Parts of this program are derived from the original FreeBSD iostat
59 * Copyright (c) 1986, 1991, 1993
60 * The Regents of the University of California. All rights reserved.
62 * Redistribution and use in source and binary forms, with or without
63 * modification, are permitted provided that the following conditions
65 * 1. Redistributions of source code must retain the above copyright
66 * notice, this list of conditions and the following disclaimer.
67 * 2. Redistributions in binary form must reproduce the above copyright
68 * notice, this list of conditions and the following disclaimer in the
69 * documentation and/or other materials provided with the distribution.
70 * 3. All advertising materials mentioning features or use of this software
71 * must display the following acknowledgement:
72 * This product includes software developed by the University of
73 * California, Berkeley and its contributors.
74 * 4. Neither the name of the University nor the names of its contributors
75 * may be used to endorse or promote products derived from this software
76 * without specific prior written permission.
78 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
79 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
80 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
81 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
82 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
83 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
84 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
85 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
86 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
87 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
91 * Ideas for the new iostat statistics output modes taken from the NetBSD
95 * Copyright (c) 1996 John M. Vinopal
96 * All rights reserved.
98 * Redistribution and use in source and binary forms, with or without
99 * modification, are permitted provided that the following conditions
101 * 1. Redistributions of source code must retain the above copyright
102 * notice, this list of conditions and the following disclaimer.
103 * 2. Redistributions in binary form must reproduce the above copyright
104 * notice, this list of conditions and the following disclaimer in the
105 * documentation and/or other materials provided with the distribution.
106 * 3. All advertising materials mentioning features or use of this software
107 * must display the following acknowledgement:
108 * This product includes software developed for the NetBSD Project
109 * by John M. Vinopal.
110 * 4. The name of the author may not be used to endorse or promote products
111 * derived from this software without specific prior written permission.
113 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
114 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
115 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
116 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
117 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
118 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
119 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
120 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
121 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
122 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
126 #define IOKIT 1 /* to get io_name_t in device_types.h */
128 #include <sys/param.h>
129 #include <sys/sysctl.h>
131 #include <CoreFoundation/CoreFoundation.h>
132 #include <IOKit/IOKitLib.h>
133 #include <IOKit/storage/IOBlockStorageDriver.h>
134 #include <IOKit/storage/IOMedia.h>
135 #include <IOKit/IOBSD.h>
144 #define MAXDRIVES 16 /* most drives we will record */
145 #define MAXDRIVENAME 31 /* largest drive name we allow */
148 io_registry_entry_t driver
;
149 char name
[MAXDRIVENAME
+ 1];
151 u_int64_t total_bytes
;
152 u_int64_t total_transfers
;
153 u_int64_t total_time
;
156 static struct drivestats drivestat
[MAXDRIVES
];
158 static struct timeval cur_time
, last_time
;
163 host_cpu_load_info_data_t load
;
166 static struct statinfo cur
, last
;
168 static mach_port_t host_priv_port
;
169 static mach_port_t masterPort
;
171 static int num_devices
;
172 static int maxshowdevs
;
173 static int dflag
= 0, Iflag
= 0, Cflag
= 0, Tflag
= 0, oflag
= 0, Kflag
= 0;
174 static volatile sig_atomic_t phdr_flag
= 0;
176 /* local function declarations */
177 static void usage(void);
178 static void phdr(int signo
);
179 static void do_phdr();
180 static void devstats(int perf_select
, long double etime
, int havelast
);
181 static void cpustats(void);
182 static int readvar(const char *name
, void *ptr
, size_t len
);
184 static int record_all_devices(void);
185 static int record_one_device(char *name
);
186 static int record_device(io_registry_entry_t drive
);
188 static long double compute_etime(struct timeval cur_time
,
189 struct timeval prev_time
);
195 * We also support the following 'traditional' syntax:
196 * iostat [drives] [wait [count]]
197 * This isn't mentioned in the man page, or the usage statement,
198 * but it is supported.
200 fprintf(stderr
, "usage: iostat [-CdIKoT?] [-c count] [-n devs]\n"
201 "\t [-w wait] [drives]\n");
205 main(int argc
, char **argv
)
208 int hflag
= 0, cflag
= 0, wflag
= 0, nflag
= 0;
209 int count
= 0, waittime
= 0;
211 int num_devices_specified
;
216 while ((c
= getopt(argc
, argv
, "c:CdIKM:n:oTw:?")) != -1) {
220 count
= atoi(optarg
);
222 errx(1, "count %d is < 1", count
);
238 maxshowdevs
= atoi(optarg
);
240 errx(1, "number of devices %d is < 0",
251 waittime
= atoi(optarg
);
253 errx(1, "wait time is < 1");
266 * Get the Mach private port.
268 host_priv_port
= mach_host_self();
271 * Get the I/O Kit communication handle.
273 IOMasterPort(bootstrap_port
, &masterPort
);
276 * Make sure Tflag and/or Cflag are set if dflag == 0. If dflag is
277 * greater than 0, they may be 0 or non-zero.
285 * Figure out how many devices we should display if not given
290 if ((dflag
> 0) && (Cflag
== 0) && (Tflag
== 0))
292 else if ((dflag
> 0) && (Tflag
> 0) && (Cflag
== 0))
297 if ((dflag
> 0) && (Cflag
== 0))
305 * If the user specified any devices on the command line, record
306 * them for monitoring.
308 for (num_devices_specified
= 0; *argv
; ++argv
) {
311 if (record_one_device(*argv
))
312 errx(1, "can't record '%s' for monitoring");
313 num_devices_specified
++;
315 if (nflag
== 0 && maxshowdevs
< num_devices_specified
)
316 maxshowdevs
= num_devices_specified
;
318 /* if no devices were specified, pick them ourselves */
319 if ((num_devices_specified
== 0) && record_all_devices())
320 err(1, "can't find any devices to display");
323 * Look for the traditional wait time and count arguments.
326 waittime
= atoi(*argv
);
328 /* Let the user know he goofed, but keep going anyway */
330 warnx("discarding previous wait interval, using"
331 " %d instead", waittime
);
337 warnx("discarding previous count, using %d"
345 * If the user specified a count, but not an interval, we default
346 * to an interval of 1 second.
348 if ((wflag
== 0) && (cflag
> 0))
352 * If the user specified a wait time, but not a count, we want to
353 * go on ad infinitum. This can be redundant if the user uses the
354 * traditional method of specifying the wait, since in that case we
355 * already set count = -1 above. Oh well.
357 if ((wflag
> 0) && (cflag
== 0))
364 * Set the busy time to the system boot time, so the stats are
365 * calculated since system boot.
367 if (readvar("kern.boottime", &cur_time
, sizeof(cur_time
)) != 0)
371 * If the user stops the program (control-Z) and then resumes it,
372 * print out the header again.
374 (void)signal(SIGCONT
, phdr
);
376 for (headercount
= 1;;) {
381 if ((readvar("kern.tty_nin", &cur
.tk_nin
,
382 sizeof(cur
.tk_nin
)) != 0)
383 || (readvar("kern.tty_nout",
384 &cur
.tk_nout
, sizeof(cur
.tk_nout
))!= 0)) {
386 warnx("disabling TTY statistics");
395 if (!--headercount
) {
400 last_time
= cur_time
;
401 gettimeofday(&cur_time
, NULL
);
405 cur
.tk_nin
-= last
.tk_nin
;
408 cur
.tk_nout
-= last
.tk_nout
;
412 etime
= compute_etime(cur_time
, last_time
);
418 printf("%4.0Lf%5.0Lf", cur
.tk_nin
/ etime
,
419 cur
.tk_nout
/ etime
);
421 devstats(hflag
, etime
, havelast
);
429 if (count
>= 0 && --count
<= 0)
452 (void)printf(" tty");
454 for (i
= 0; (i
< num_devices
); i
++){
456 (void)printf("%12.6s ", drivestat
[i
].name
);
458 printf("%15.6s ", drivestat
[i
].name
);
462 (void)printf(" cpu\n");
467 (void)printf(" tin tout");
469 for (i
=0; i
< num_devices
; i
++){
472 (void)printf(" sps tps msps ");
474 (void)printf(" blk xfr msps ");
477 printf(" KB/t tps MB/s ");
479 printf(" KB/t xfrs MB ");
484 (void)printf(" us sy id\n");
490 devstats(int perf_select
, long double etime
, int havelast
)
493 CFDictionaryRef properties
;
494 CFDictionaryRef statistics
;
495 long double transfers_per_second
;
496 long double kb_per_transfer
, mb_per_second
;
498 u_int64_t total_bytes
, total_transfers
, total_blocks
, total_time
;
499 u_int64_t interval_bytes
, interval_transfers
, interval_blocks
;
500 u_int64_t interval_time
;
501 long double interval_mb
;
502 long double blocks_per_second
, ms_per_transaction
;
503 kern_return_t status
;
506 for (i
= 0; i
< num_devices
; i
++) {
509 * If the drive goes away, we may not get any properties
510 * for it. So take some defaults.
516 /* get drive properties */
517 status
= IORegistryEntryCreateCFProperties(drivestat
[i
].driver
,
518 (CFMutableDictionaryRef
*)&properties
,
521 if (status
!= KERN_SUCCESS
)
522 err(1, "device has no properties");
524 /* get statistics from properties */
525 statistics
= (CFDictionaryRef
)CFDictionaryGetValue(properties
,
526 CFSTR(kIOBlockStorageDriverStatisticsKey
));
532 if ((number
= (CFNumberRef
)CFDictionaryGetValue(statistics
,
533 CFSTR(kIOBlockStorageDriverStatisticsBytesReadKey
)))) {
534 CFNumberGetValue(number
, kCFNumberSInt64Type
, &value
);
535 total_bytes
+= value
;
537 if ((number
= (CFNumberRef
)CFDictionaryGetValue(statistics
,
538 CFSTR(kIOBlockStorageDriverStatisticsBytesWrittenKey
)))) {
539 CFNumberGetValue(number
, kCFNumberSInt64Type
, &value
);
540 total_bytes
+= value
;
546 if ((number
= (CFNumberRef
)CFDictionaryGetValue(statistics
,
547 CFSTR(kIOBlockStorageDriverStatisticsReadsKey
)))) {
548 CFNumberGetValue(number
, kCFNumberSInt64Type
, &value
);
549 total_transfers
+= value
;
551 if ((number
= (CFNumberRef
)CFDictionaryGetValue(statistics
,
552 CFSTR(kIOBlockStorageDriverStatisticsWritesKey
)))) {
553 CFNumberGetValue(number
, kCFNumberSInt64Type
, &value
);
554 total_transfers
+= value
;
560 if ((number
= (CFNumberRef
)CFDictionaryGetValue(statistics
,
561 CFSTR(kIOBlockStorageDriverStatisticsLatentReadTimeKey
)))) {
562 CFNumberGetValue(number
, kCFNumberSInt64Type
, &value
);
565 if ((number
= (CFNumberRef
)CFDictionaryGetValue(statistics
,
566 CFSTR(kIOBlockStorageDriverStatisticsLatentWriteTimeKey
)))) {
567 CFNumberGetValue(number
, kCFNumberSInt64Type
, &value
);
572 CFRelease(properties
);
575 * Compute delta values and stats.
577 interval_bytes
= total_bytes
- drivestat
[i
].total_bytes
;
578 interval_transfers
= total_transfers
579 - drivestat
[i
].total_transfers
;
580 interval_time
= total_time
- drivestat
[i
].total_time
;
582 /* update running totals, only once for -I */
583 if ((Iflag
== 0) || (drivestat
[i
].total_bytes
== 0)) {
584 drivestat
[i
].total_bytes
= total_bytes
;
585 drivestat
[i
].total_transfers
= total_transfers
;
586 drivestat
[i
].total_time
= total_time
;
589 interval_blocks
= interval_bytes
/ drivestat
[i
].blocksize
;
590 total_blocks
= total_bytes
/ drivestat
[i
].blocksize
;
592 blocks_per_second
= interval_blocks
/ etime
;
593 transfers_per_second
= interval_transfers
/ etime
;
594 mb_per_second
= (interval_bytes
/ etime
) / (1024 * 1024);
596 kb_per_transfer
= (interval_transfers
> 0) ?
597 ((long double)interval_bytes
/ interval_transfers
)
600 /* times are in nanoseconds, convert to milliseconds */
601 ms_per_transaction
= (interval_transfers
> 0) ?
602 ((long double)interval_time
/ interval_transfers
)
606 total_blocks
= total_blocks
* drivestat
[i
].blocksize
610 int msdig
= (ms_per_transaction
< 100.0) ? 1 : 0;
613 printf("%4.0Lf%4.0Lf%5.*Lf ",
615 transfers_per_second
,
619 printf("%4.1qu%4.1qu%5.*Lf ",
626 printf(" %5.2Lf %3.0Lf %5.2Lf ",
628 transfers_per_second
,
631 interval_mb
= interval_bytes
;
632 interval_mb
/= 1024 * 1024;
634 printf(" %5.2Lf %3.1qu %5.2Lf ",
646 mach_msg_type_number_t count
;
647 kern_return_t status
;
651 * Get CPU usage counters.
653 count
= HOST_CPU_LOAD_INFO_COUNT
;
654 status
= host_statistics(host_priv_port
, HOST_CPU_LOAD_INFO
,
655 (host_info_t
)&cur
.load
, &count
);
656 if (status
!= KERN_SUCCESS
)
657 errx(1, "couldn't fetch CPU stats");
660 * Make 'cur' fields relative, update 'last' fields to current values,
661 * calculate total elapsed time.
664 cur
.load
.cpu_ticks
[CPU_STATE_USER
]
665 -= last
.load
.cpu_ticks
[CPU_STATE_USER
];
666 last
.load
.cpu_ticks
[CPU_STATE_USER
]
667 += cur
.load
.cpu_ticks
[CPU_STATE_USER
];
668 time
+= cur
.load
.cpu_ticks
[CPU_STATE_USER
];
669 cur
.load
.cpu_ticks
[CPU_STATE_SYSTEM
]
670 -= last
.load
.cpu_ticks
[CPU_STATE_SYSTEM
];
671 last
.load
.cpu_ticks
[CPU_STATE_SYSTEM
]
672 += cur
.load
.cpu_ticks
[CPU_STATE_SYSTEM
];
673 time
+= cur
.load
.cpu_ticks
[CPU_STATE_SYSTEM
];
674 cur
.load
.cpu_ticks
[CPU_STATE_IDLE
]
675 -= last
.load
.cpu_ticks
[CPU_STATE_IDLE
];
676 last
.load
.cpu_ticks
[CPU_STATE_IDLE
]
677 += cur
.load
.cpu_ticks
[CPU_STATE_IDLE
];
678 time
+= cur
.load
.cpu_ticks
[CPU_STATE_IDLE
];
684 rint(100. * cur
.load
.cpu_ticks
[CPU_STATE_USER
]
685 / (time
? time
: 1)));
687 rint(100. * cur
.load
.cpu_ticks
[CPU_STATE_SYSTEM
]
688 / (time
? time
: 1)));
690 rint(100. * cur
.load
.cpu_ticks
[CPU_STATE_IDLE
]
691 / (time
? time
: 1)));
695 readvar(const char *name
, void *ptr
, size_t len
)
702 if (sysctlbyname(name
, ptr
, &nlen
, NULL
, 0) == -1) {
703 if (errno
!= ENOENT
) {
704 warn("sysctl(%s) failed", name
);
708 * XXX fallback code to deal with systems where
709 * sysctlbyname can't find "old" OIDs, should be removed.
711 if (!strcmp(name
, "kern.boottime")) {
713 oid
[1] = KERN_BOOTTIME
;
716 warn("sysctl(%s) failed", name
);
721 if (sysctl(oid
, oidlen
, ptr
, &nlen
, NULL
, 0) == -1) {
722 warn("sysctl(%s) failed", name
);
727 warnx("sysctl(%s): expected %lu, got %lu", name
,
728 (unsigned long)len
, (unsigned long)nlen
);
735 compute_etime(struct timeval cur_time
, struct timeval prev_time
)
737 struct timeval busy_time
;
741 timersub(&cur_time
, &prev_time
, &busy_time
);
743 busy_usec
= busy_time
.tv_sec
;
744 busy_usec
*= 1000000;
745 busy_usec
+= busy_time
.tv_usec
;
753 * Record all "whole" IOMedia objects as being interesting.
756 record_all_devices(void)
758 io_iterator_t drivelist
;
759 io_registry_entry_t drive
;
760 CFMutableDictionaryRef match
;
762 kern_return_t status
;
765 * Get an iterator for IOMedia objects.
767 match
= IOServiceMatching("IOMedia");
768 CFDictionaryAddValue(match
, CFSTR(kIOMediaWholeKey
), kCFBooleanTrue
);
769 status
= IOServiceGetMatchingServices(masterPort
, match
, &drivelist
);
770 if (status
!= KERN_SUCCESS
)
771 errx(1, "couldn't match whole IOMedia devices");
774 * Scan all of the IOMedia objects, and for each
775 * object that has a parent IOBlockStorageDriver, save
776 * the object's name and the parent (from which we can
779 * XXX What about RAID devices?
783 while ((drive
= IOIteratorNext(drivelist
))
784 && (ndrives
< maxshowdevs
)) {
785 if (!record_device(drive
)) {
789 IOObjectRelease(drive
);
791 IOObjectRelease(drivelist
);
797 * Try to record the named device as interesting. It
798 * must be an IOMedia device.
801 record_one_device(char *name
)
803 io_iterator_t drivelist
;
804 io_registry_entry_t drive
;
805 kern_return_t status
;
810 status
= IOServiceGetMatchingServices(masterPort
,
811 IOBSDNameMatching(masterPort
, kNilOptions
, name
),
813 if (status
!= KERN_SUCCESS
)
814 errx(1, "couldn't match '%s'", name
);
817 * Get the first match (should only be one)
819 if ((drive
= IOIteratorNext(drivelist
)) == NULL
)
820 errx(1, "'%s' not found", name
);
821 if (!IOObjectConformsTo(drive
, "IOMedia"))
822 errx(1, "'%s' is not a storage device", name
);
827 if (record_device(drive
))
828 errx(1, "could not record '%s' for monitoring", name
);
830 IOObjectRelease(drive
);
831 IOObjectRelease(drivelist
);
837 * Determine whether an IORegistryEntry refers to a valid
838 * I/O device, and if so, record it.
841 record_device(io_registry_entry_t drive
)
843 io_registry_entry_t parent
;
844 CFDictionaryRef properties
;
847 kern_return_t status
;
849 /* get drive's parent */
850 status
= IORegistryEntryGetParentEntry(drive
,
851 kIOServicePlane
, &parent
);
852 if (status
!= KERN_SUCCESS
)
853 errx(1, "device has no parent");
854 if (IOObjectConformsTo(parent
, "IOBlockStorageDriver")) {
855 drivestat
[num_devices
].driver
= parent
;
857 /* get drive properties */
858 status
= IORegistryEntryCreateCFProperties(drive
,
859 (CFMutableDictionaryRef
*)&properties
,
862 if (status
!= KERN_SUCCESS
)
863 errx(1, "device has no properties");
865 /* get name from properties */
866 name
= (CFStringRef
)CFDictionaryGetValue(properties
,
867 CFSTR(kIOBSDNameKey
));
868 CFStringGetCString(name
, drivestat
[num_devices
].name
,
869 MAXDRIVENAME
, CFStringGetSystemEncoding());
871 /* get blocksize from properties */
872 number
= (CFNumberRef
)CFDictionaryGetValue(properties
,
873 CFSTR(kIOMediaPreferredBlockSizeKey
));
874 CFNumberGetValue(number
, kCFNumberSInt64Type
,
875 &drivestat
[num_devices
].blocksize
);
877 /* clean up, return success */
878 CFRelease(properties
);
883 /* failed, don't keep parent */
884 IOObjectRelease(parent
);