xref: /netbsd-src/usr.bin/vmstat/drvstats.c (revision 1d6b489c6ecbe44de5cd5944470e3e2e40e4879d)
1*1d6b489cSrillig /*	$NetBSD: drvstats.c,v 1.14 2021/11/27 22:16:42 rillig Exp $	*/
27d866d26Sblymn 
37d866d26Sblymn /*
47d866d26Sblymn  * Copyright (c) 1996 John M. Vinopal
57d866d26Sblymn  * All rights reserved.
67d866d26Sblymn  *
77d866d26Sblymn  * Redistribution and use in source and binary forms, with or without
87d866d26Sblymn  * modification, are permitted provided that the following conditions
97d866d26Sblymn  * are met:
107d866d26Sblymn  * 1. Redistributions of source code must retain the above copyright
117d866d26Sblymn  *    notice, this list of conditions and the following disclaimer.
127d866d26Sblymn  * 2. Redistributions in binary form must reproduce the above copyright
137d866d26Sblymn  *    notice, this list of conditions and the following disclaimer in the
147d866d26Sblymn  *    documentation and/or other materials provided with the distribution.
157d866d26Sblymn  * 3. All advertising materials mentioning features or use of this software
167d866d26Sblymn  *    must display the following acknowledgement:
177d866d26Sblymn  *      This product includes software developed for the NetBSD Project
187d866d26Sblymn  *      by John M. Vinopal.
197d866d26Sblymn  * 4. The name of the author may not be used to endorse or promote products
207d866d26Sblymn  *    derived from this software without specific prior written permission.
217d866d26Sblymn  *
227d866d26Sblymn  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
237d866d26Sblymn  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
247d866d26Sblymn  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
257d866d26Sblymn  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
267d866d26Sblymn  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
277d866d26Sblymn  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
287d866d26Sblymn  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
297d866d26Sblymn  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
307d866d26Sblymn  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
317d866d26Sblymn  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
327d866d26Sblymn  * SUCH DAMAGE.
337d866d26Sblymn  */
347d866d26Sblymn 
357d866d26Sblymn #include <sys/param.h>
367d866d26Sblymn #include <sys/sched.h>
377d866d26Sblymn #include <sys/sysctl.h>
387d866d26Sblymn #include <sys/time.h>
397d866d26Sblymn #include <sys/iostat.h>
407d866d26Sblymn 
417d866d26Sblymn #include <err.h>
427d866d26Sblymn #include <fcntl.h>
437d866d26Sblymn #include <limits.h>
447d866d26Sblymn #include <stdio.h>
457d866d26Sblymn #include <stdlib.h>
467d866d26Sblymn #include <string.h>
477d866d26Sblymn #include <unistd.h>
487d866d26Sblymn #include "drvstats.h"
497d866d26Sblymn 
507d866d26Sblymn /* Structures to hold the statistics. */
517d866d26Sblymn struct _drive	cur, last;
527d866d26Sblymn 
537d866d26Sblymn extern int	hz;
547d866d26Sblymn 
557d866d26Sblymn /* sysctl hw.drivestats buffer. */
567d866d26Sblymn static struct io_sysctl	*drives = NULL;
577d866d26Sblymn 
587d866d26Sblymn /* Backward compatibility references. */
593ceb6c1cSchristos size_t		ndrive = 0;
607d866d26Sblymn int		*drv_select;
617d866d26Sblymn char		**dr_name;
627d866d26Sblymn 
637d866d26Sblymn /* Missing from <sys/time.h> */
647d866d26Sblymn #define	timerset(tvp, uvp) do {						\
657d866d26Sblymn 	((uvp)->tv_sec = (tvp)->tv_sec);				\
667d866d26Sblymn 	((uvp)->tv_usec = (tvp)->tv_usec);				\
67*1d6b489cSrillig } while (0)
687d866d26Sblymn 
697d866d26Sblymn /*
707d866d26Sblymn  * Take the delta between the present values and the last recorded
717d866d26Sblymn  * values, storing the present values in the 'last' structure, and
727d866d26Sblymn  * the delta values in the 'cur' structure.
737d866d26Sblymn  */
747d866d26Sblymn void
drvswap(void)757d866d26Sblymn drvswap(void)
767d866d26Sblymn {
777d866d26Sblymn 	u_int64_t tmp;
78c493aef5Slukem 	size_t	i;
797d866d26Sblymn 
807d866d26Sblymn #define	SWAP(fld) do {							\
817d866d26Sblymn 	tmp = cur.fld;							\
827d866d26Sblymn 	cur.fld -= last.fld;						\
837d866d26Sblymn 	last.fld = tmp;							\
84*1d6b489cSrillig } while (0)
857d866d26Sblymn 
86ba576b71Smlelstv #define DELTA(x) do {							\
87ba576b71Smlelstv 		timerclear(&tmp_timer);					\
88ba576b71Smlelstv 		timerset(&(cur.x), &tmp_timer);				\
89ba576b71Smlelstv 		timersub(&tmp_timer, &(last.x), &(cur.x));		\
90ba576b71Smlelstv 		timerclear(&(last.x));					\
91ba576b71Smlelstv 		timerset(&tmp_timer, &(last.x));			\
92*1d6b489cSrillig } while (0)
93ba576b71Smlelstv 
947d866d26Sblymn 	for (i = 0; i < ndrive; i++) {
957d866d26Sblymn 		struct timeval	tmp_timer;
967d866d26Sblymn 
977d866d26Sblymn 		if (!cur.select[i])
987d866d26Sblymn 			continue;
997d866d26Sblymn 
100245a1a45Smlelstv 		/*
101245a1a45Smlelstv 		 * When a drive is replaced with one of the same
102245a1a45Smlelstv 		 * name, the previous statistics are invalid. Try
103245a1a45Smlelstv 		 * to detect this by validating counters and timestamp
104245a1a45Smlelstv 		 */
105245a1a45Smlelstv 		if ((cur.rxfer[i] == 0 && cur.wxfer[i] == 0)
106245a1a45Smlelstv 		    || cur.rxfer[i] - last.rxfer[i] > INT64_MAX
107245a1a45Smlelstv 		    || cur.wxfer[i] - last.wxfer[i] > INT64_MAX
108245a1a45Smlelstv 		    || cur.seek[i] - last.seek[i] > INT64_MAX
109245a1a45Smlelstv 		    || (cur.timestamp[i].tv_sec == 0 &&
110245a1a45Smlelstv 		        cur.timestamp[i].tv_usec == 0)) {
111245a1a45Smlelstv 
112245a1a45Smlelstv 			last.rxfer[i] = cur.rxfer[i];
113245a1a45Smlelstv 			last.wxfer[i] = cur.wxfer[i];
114245a1a45Smlelstv 			last.seek[i] = cur.seek[i];
115245a1a45Smlelstv 			last.rbytes[i] = cur.rbytes[i];
116245a1a45Smlelstv 			last.wbytes[i] = cur.wbytes[i];
117245a1a45Smlelstv 
118245a1a45Smlelstv 			timerclear(&last.wait[i]);
119245a1a45Smlelstv 			timerclear(&last.time[i]);
120245a1a45Smlelstv 			timerclear(&last.waitsum[i]);
121245a1a45Smlelstv 			timerclear(&last.busysum[i]);
122245a1a45Smlelstv 			timerclear(&last.timestamp[i]);
123245a1a45Smlelstv 		}
124245a1a45Smlelstv 
1257d866d26Sblymn 		/* Delta Values. */
1267d866d26Sblymn 		SWAP(rxfer[i]);
1277d866d26Sblymn 		SWAP(wxfer[i]);
1287d866d26Sblymn 		SWAP(seek[i]);
1297d866d26Sblymn 		SWAP(rbytes[i]);
1307d866d26Sblymn 		SWAP(wbytes[i]);
1317d866d26Sblymn 
132ba576b71Smlelstv 		DELTA(wait[i]);
133ba576b71Smlelstv 		DELTA(time[i]);
134ba576b71Smlelstv 		DELTA(waitsum[i]);
135ba576b71Smlelstv 		DELTA(busysum[i]);
136245a1a45Smlelstv 		DELTA(timestamp[i]);
1377d866d26Sblymn 	}
1387d866d26Sblymn }
1397d866d26Sblymn 
1407d866d26Sblymn void
tkswap(void)1417d866d26Sblymn tkswap(void)
1427d866d26Sblymn {
1437d866d26Sblymn 	u_int64_t tmp;
1447d866d26Sblymn 
1457d866d26Sblymn 	SWAP(tk_nin);
1467d866d26Sblymn 	SWAP(tk_nout);
1477d866d26Sblymn }
1487d866d26Sblymn 
1497d866d26Sblymn void
cpuswap(void)1507d866d26Sblymn cpuswap(void)
1517d866d26Sblymn {
1527d866d26Sblymn 	double etime;
1537d866d26Sblymn 	u_int64_t tmp;
1547d866d26Sblymn 	int	i, state;
1557d866d26Sblymn 
1567d866d26Sblymn 	for (i = 0; i < CPUSTATES; i++)
1577d866d26Sblymn 		SWAP(cp_time[i]);
1587d866d26Sblymn 
1597d866d26Sblymn 	etime = 0;
1607d866d26Sblymn 	for (state = 0; state < CPUSTATES; ++state) {
1617d866d26Sblymn 		etime += cur.cp_time[state];
1627d866d26Sblymn 	}
1637d866d26Sblymn 	if (etime == 0)
1647d866d26Sblymn 		etime = 1;
1657d866d26Sblymn 	etime /= hz;
1667d866d26Sblymn 	etime /= cur.cp_ncpu;
1677d866d26Sblymn 
1687d866d26Sblymn 	cur.cp_etime = etime;
1697d866d26Sblymn }
170ba576b71Smlelstv #undef DELTA
1717d866d26Sblymn #undef SWAP
1727d866d26Sblymn 
1737d866d26Sblymn /*
1747d866d26Sblymn  * Read the drive statistics for each drive in the drive list.
1757d866d26Sblymn  * Also collect statistics for tty i/o and CPU ticks.
1767d866d26Sblymn  */
1777d866d26Sblymn void
drvreadstats(void)1787d866d26Sblymn drvreadstats(void)
1797d866d26Sblymn {
180245a1a45Smlelstv 	size_t		size, i, j, count;
1817d866d26Sblymn 	int		mib[3];
1827d866d26Sblymn 
1837d866d26Sblymn 	mib[0] = CTL_HW;
1847d866d26Sblymn 	mib[1] = HW_IOSTATS;
1857d866d26Sblymn 	mib[2] = sizeof(struct io_sysctl);
1867d866d26Sblymn 
1877d866d26Sblymn 	size = ndrive * sizeof(struct io_sysctl);
1887d866d26Sblymn 	if (sysctl(mib, 3, drives, &size, NULL, 0) < 0)
1897d866d26Sblymn 		err(1, "sysctl hw.iostats failed");
190245a1a45Smlelstv 	/* recalculate array length */
191245a1a45Smlelstv 	count = size / sizeof(struct io_sysctl);
192ba576b71Smlelstv 
193245a1a45Smlelstv #define COPYF(x,k,l) cur.x[k] = drives[l].x
194245a1a45Smlelstv #define COPYT(x,k,l) do {						\
195245a1a45Smlelstv 		cur.x[k].tv_sec = drives[l].x##_sec;			\
196245a1a45Smlelstv 		cur.x[k].tv_usec = drives[l].x##_usec;			\
197*1d6b489cSrillig } while (0)
198ba576b71Smlelstv 
199245a1a45Smlelstv 	for (i = 0, j = 0; i < ndrive && j < count; i++) {
200ba576b71Smlelstv 
201245a1a45Smlelstv 		/*
202245a1a45Smlelstv 		 * skip removed entries
203245a1a45Smlelstv 		 *
204245a1a45Smlelstv 		 * we cannot detect entries replaced with
205245a1a45Smlelstv 		 * devices of the same name (e.g. unplug/replug).
206245a1a45Smlelstv 		 */
207245a1a45Smlelstv 		if (strcmp(cur.name[i], drives[j].name)) {
208245a1a45Smlelstv 			cur.select[i] = 0;
209245a1a45Smlelstv 			continue;
2107d866d26Sblymn 		}
2117d866d26Sblymn 
212245a1a45Smlelstv 		COPYF(rxfer, i, j);
213245a1a45Smlelstv 		COPYF(wxfer, i, j);
214245a1a45Smlelstv 		COPYF(seek, i, j);
215245a1a45Smlelstv 		COPYF(rbytes, i, j);
216245a1a45Smlelstv 		COPYF(wbytes, i, j);
217245a1a45Smlelstv 
218245a1a45Smlelstv 		COPYT(wait, i, j);
219245a1a45Smlelstv 		COPYT(time, i, j);
220245a1a45Smlelstv 		COPYT(waitsum, i, j);
221245a1a45Smlelstv 		COPYT(busysum, i, j);
222245a1a45Smlelstv 		COPYT(timestamp, i, j);
223245a1a45Smlelstv 
224245a1a45Smlelstv 		++j;
225245a1a45Smlelstv 	}
226245a1a45Smlelstv 
227245a1a45Smlelstv 	/* shrink table to new size */
228245a1a45Smlelstv 	ndrive = j;
229245a1a45Smlelstv 
2307d866d26Sblymn 	mib[0] = CTL_KERN;
2317d866d26Sblymn 	mib[1] = KERN_TKSTAT;
2327d866d26Sblymn 	mib[2] = KERN_TKSTAT_NIN;
2337d866d26Sblymn 	size = sizeof(cur.tk_nin);
2347d866d26Sblymn 	if (sysctl(mib, 3, &cur.tk_nin, &size, NULL, 0) < 0)
2357d866d26Sblymn 		cur.tk_nin = 0;
2367d866d26Sblymn 
2377d866d26Sblymn 	mib[2] = KERN_TKSTAT_NOUT;
2387d866d26Sblymn 	size = sizeof(cur.tk_nout);
2397d866d26Sblymn 	if (sysctl(mib, 3, &cur.tk_nout, &size, NULL, 0) < 0)
2407d866d26Sblymn 		cur.tk_nout = 0;
2417d866d26Sblymn 
2427d866d26Sblymn 	size = sizeof(cur.cp_time);
2433ceb6c1cSchristos 	(void)memset(cur.cp_time, 0, size);
2447d866d26Sblymn 	mib[0] = CTL_KERN;
2457d866d26Sblymn 	mib[1] = KERN_CP_TIME;
2467d866d26Sblymn 	if (sysctl(mib, 2, cur.cp_time, &size, NULL, 0) < 0)
2473ceb6c1cSchristos 		(void)memset(cur.cp_time, 0, sizeof(cur.cp_time));
2487d866d26Sblymn }
249ba576b71Smlelstv #undef COPYT
250ba576b71Smlelstv #undef COPYF
2517d866d26Sblymn 
2527d866d26Sblymn /*
2537d866d26Sblymn  * Read collect statistics for tty i/o.
2547d866d26Sblymn  */
2557d866d26Sblymn 
2567d866d26Sblymn void
tkreadstats(void)2577d866d26Sblymn tkreadstats(void)
2587d866d26Sblymn {
2597d866d26Sblymn 	size_t		size;
2607d866d26Sblymn 	int		mib[3];
2617d866d26Sblymn 
2627d866d26Sblymn 	mib[0] = CTL_KERN;
2637d866d26Sblymn 	mib[1] = KERN_TKSTAT;
2647d866d26Sblymn 	mib[2] = KERN_TKSTAT_NIN;
2657d866d26Sblymn 	size = sizeof(cur.tk_nin);
2667d866d26Sblymn 	if (sysctl(mib, 3, &cur.tk_nin, &size, NULL, 0) < 0)
2677d866d26Sblymn 		cur.tk_nin = 0;
2687d866d26Sblymn 
2697d866d26Sblymn 	mib[2] = KERN_TKSTAT_NOUT;
2707d866d26Sblymn 	size = sizeof(cur.tk_nout);
2717d866d26Sblymn 	if (sysctl(mib, 3, &cur.tk_nout, &size, NULL, 0) < 0)
2727d866d26Sblymn 		cur.tk_nout = 0;
2737d866d26Sblymn }
2747d866d26Sblymn 
2757d866d26Sblymn /*
2767d866d26Sblymn  * Read collect statistics for CPU ticks.
2777d866d26Sblymn  */
2787d866d26Sblymn 
2797d866d26Sblymn void
cpureadstats(void)2807d866d26Sblymn cpureadstats(void)
2817d866d26Sblymn {
2827d866d26Sblymn 	size_t		size;
2837d866d26Sblymn 	int		mib[2];
2847d866d26Sblymn 
2857d866d26Sblymn 	size = sizeof(cur.cp_time);
2863ceb6c1cSchristos 	(void)memset(cur.cp_time, 0, size);
2877d866d26Sblymn 	mib[0] = CTL_KERN;
2887d866d26Sblymn 	mib[1] = KERN_CP_TIME;
2897d866d26Sblymn 	if (sysctl(mib, 2, cur.cp_time, &size, NULL, 0) < 0)
2903ceb6c1cSchristos 		(void)memset(cur.cp_time, 0, sizeof(cur.cp_time));
2917d866d26Sblymn }
2927d866d26Sblymn 
2937d866d26Sblymn /*
2947d866d26Sblymn  * Perform all of the initialization and memory allocation needed to
2957d866d26Sblymn  * track drive statistics.
2967d866d26Sblymn  */
2977d866d26Sblymn int
drvinit(int selected)2987d866d26Sblymn drvinit(int selected)
2997d866d26Sblymn {
3007d866d26Sblymn 	struct clockinfo clockinfo;
301c493aef5Slukem 	size_t		size, i;
3027d866d26Sblymn 	static int	once = 0;
303c493aef5Slukem 	int		mib[3];
3047d866d26Sblymn 
3057d866d26Sblymn 	if (once)
3067d866d26Sblymn 		return (1);
3077d866d26Sblymn 
3087d866d26Sblymn 	mib[0] = CTL_HW;
3097d866d26Sblymn 	mib[1] = HW_NCPU;
3107d866d26Sblymn 	size = sizeof(cur.cp_ncpu);
3117d866d26Sblymn 	if (sysctl(mib, 2, &cur.cp_ncpu, &size, NULL, 0) == -1)
3127d866d26Sblymn 		err(1, "sysctl hw.ncpu failed");
3137d866d26Sblymn 
3147d866d26Sblymn 	mib[0] = CTL_KERN;
3157d866d26Sblymn 	mib[1] = KERN_CLOCKRATE;
3167d866d26Sblymn 	size = sizeof(clockinfo);
3177d866d26Sblymn 	if (sysctl(mib, 2, &clockinfo, &size, NULL, 0) == -1)
3187d866d26Sblymn 		err(1, "sysctl kern.clockrate failed");
3197d866d26Sblymn 	hz = clockinfo.stathz;
3207d866d26Sblymn 	if (!hz)
3217d866d26Sblymn 		hz = clockinfo.hz;
3227d866d26Sblymn 
3237d866d26Sblymn 	mib[0] = CTL_HW;
3247d866d26Sblymn 	mib[1] = HW_IOSTATS;
3257d866d26Sblymn 	mib[2] = sizeof(struct io_sysctl);
3267d866d26Sblymn 	if (sysctl(mib, 3, NULL, &size, NULL, 0) == -1)
3277d866d26Sblymn 		err(1, "sysctl hw.drivestats failed");
3287d866d26Sblymn 	ndrive = size / sizeof(struct io_sysctl);
3297d866d26Sblymn 
3307d866d26Sblymn 	if (size == 0) {
3317d866d26Sblymn 		warnx("No drives attached.");
3327d866d26Sblymn 	} else {
3337d866d26Sblymn 		drives = (struct io_sysctl *)malloc(size);
3347d866d26Sblymn 		if (drives == NULL)
3357d866d26Sblymn 			errx(1, "Memory allocation failure.");
3367d866d26Sblymn 	}
3377d866d26Sblymn 
3387d866d26Sblymn 	/* Allocate space for the statistics. */
3397d866d26Sblymn 	cur.time = calloc(ndrive, sizeof(struct timeval));
340ba576b71Smlelstv 	cur.wait = calloc(ndrive, sizeof(struct timeval));
341ba576b71Smlelstv 	cur.waitsum = calloc(ndrive, sizeof(struct timeval));
342ba576b71Smlelstv 	cur.busysum = calloc(ndrive, sizeof(struct timeval));
343245a1a45Smlelstv 	cur.timestamp = calloc(ndrive, sizeof(struct timeval));
3447d866d26Sblymn 	cur.rxfer = calloc(ndrive, sizeof(u_int64_t));
3457d866d26Sblymn 	cur.wxfer = calloc(ndrive, sizeof(u_int64_t));
3467d866d26Sblymn 	cur.seek = calloc(ndrive, sizeof(u_int64_t));
3477d866d26Sblymn 	cur.rbytes = calloc(ndrive, sizeof(u_int64_t));
3487d866d26Sblymn 	cur.wbytes = calloc(ndrive, sizeof(u_int64_t));
349feecb28eShe 	cur.scale = calloc(ndrive, sizeof(int));
3507d866d26Sblymn 	last.time = calloc(ndrive, sizeof(struct timeval));
351ba576b71Smlelstv 	last.wait = calloc(ndrive, sizeof(struct timeval));
352ba576b71Smlelstv 	last.waitsum = calloc(ndrive, sizeof(struct timeval));
353ba576b71Smlelstv 	last.busysum = calloc(ndrive, sizeof(struct timeval));
354245a1a45Smlelstv 	last.timestamp = calloc(ndrive, sizeof(struct timeval));
3557d866d26Sblymn 	last.rxfer = calloc(ndrive, sizeof(u_int64_t));
3567d866d26Sblymn 	last.wxfer = calloc(ndrive, sizeof(u_int64_t));
3577d866d26Sblymn 	last.seek = calloc(ndrive, sizeof(u_int64_t));
3587d866d26Sblymn 	last.rbytes = calloc(ndrive, sizeof(u_int64_t));
3597d866d26Sblymn 	last.wbytes = calloc(ndrive, sizeof(u_int64_t));
3607d866d26Sblymn 	cur.select = calloc(ndrive, sizeof(int));
3617d866d26Sblymn 	cur.name = calloc(ndrive, sizeof(char *));
3627d866d26Sblymn 
363ba576b71Smlelstv 	if (cur.time == NULL || cur.wait == NULL ||
364ba576b71Smlelstv 	    cur.waitsum == NULL || cur.busysum == NULL ||
365245a1a45Smlelstv 	    cur.timestamp == NULL ||
366ba576b71Smlelstv 	    cur.rxfer == NULL || cur.wxfer == NULL ||
367ba576b71Smlelstv 	    cur.seek == NULL || cur.rbytes == NULL ||
368ba576b71Smlelstv 	    cur.wbytes == NULL ||
369ba576b71Smlelstv 	    last.time == NULL || last.wait == NULL ||
370ba576b71Smlelstv 	    last.waitsum == NULL || last.busysum == NULL ||
371245a1a45Smlelstv 	    last.timestamp == NULL ||
372ba576b71Smlelstv 	    last.rxfer == NULL || last.wxfer == NULL ||
373ba576b71Smlelstv 	    last.seek == NULL || last.rbytes == NULL ||
374ba576b71Smlelstv 	    last.wbytes == NULL ||
3757d866d26Sblymn 	    cur.select == NULL || cur.name == NULL)
3767d866d26Sblymn 		errx(1, "Memory allocation failure.");
3777d866d26Sblymn 
3787d866d26Sblymn 	/* Set up the compatibility interfaces. */
3797d866d26Sblymn 	drv_select = cur.select;
3807d866d26Sblymn 	dr_name = cur.name;
3817d866d26Sblymn 
38232cded6cSdholland 	/* Read the drive names and set initial selection. */
3837d866d26Sblymn 	mib[0] = CTL_HW;		/* Should be still set from */
3847d866d26Sblymn 	mib[1] = HW_IOSTATS;		/* ... above, but be safe... */
3857d866d26Sblymn 	mib[2] = sizeof(struct io_sysctl);
3867d866d26Sblymn 	if (sysctl(mib, 3, drives, &size, NULL, 0) == -1)
3877d866d26Sblymn 		err(1, "sysctl hw.iostats failed");
388245a1a45Smlelstv 	/* Recalculate array length */
389245a1a45Smlelstv 	ndrive = size / sizeof(struct io_sysctl);
3907d866d26Sblymn 	for (i = 0; i < ndrive; i++) {
391245a1a45Smlelstv 		cur.name[i] = strndup(drives[i].name, sizeof(drives[i].name));
392245a1a45Smlelstv 		if (cur.name[i] == NULL)
393245a1a45Smlelstv 			errx(1, "Memory allocation failure");
3947d866d26Sblymn 		cur.select[i] = selected;
3957d866d26Sblymn 	}
3967d866d26Sblymn 
3977d866d26Sblymn 	/* Never do this initialization again. */
3987d866d26Sblymn 	once = 1;
3997d866d26Sblymn 	return (1);
4007d866d26Sblymn }
401