139230Sgibbs/* 282168Sken * Copyright (c) 1997, 1998, 2000, 2001 Kenneth D. Merry 339230Sgibbs * All rights reserved. 439230Sgibbs * 539230Sgibbs * Redistribution and use in source and binary forms, with or without 639230Sgibbs * modification, are permitted provided that the following conditions 739230Sgibbs * are met: 839230Sgibbs * 1. Redistributions of source code must retain the above copyright 939230Sgibbs * notice, this list of conditions and the following disclaimer. 1039230Sgibbs * 2. Redistributions in binary form must reproduce the above copyright 1139230Sgibbs * notice, this list of conditions and the following disclaimer in the 1239230Sgibbs * documentation and/or other materials provided with the distribution. 1339230Sgibbs * 3. The name of the author may not be used to endorse or promote products 1439230Sgibbs * derived from this software without specific prior written permission. 1539230Sgibbs * 1639230Sgibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1739230Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1839230Sgibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1939230Sgibbs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2039230Sgibbs * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2139230Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2239230Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2339230Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2439230Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2539230Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2639230Sgibbs * SUCH DAMAGE. 2756561Scharnier * 2856561Scharnier * $FreeBSD$ 2939230Sgibbs */ 3039230Sgibbs/* 3139230Sgibbs * Parts of this program are derived from the original FreeBSD iostat 3239230Sgibbs * program: 3339230Sgibbs */ 341553Srgrimes/*- 351553Srgrimes * Copyright (c) 1986, 1991, 1993 361553Srgrimes * The Regents of the University of California. All rights reserved. 371553Srgrimes * 381553Srgrimes * Redistribution and use in source and binary forms, with or without 391553Srgrimes * modification, are permitted provided that the following conditions 401553Srgrimes * are met: 411553Srgrimes * 1. Redistributions of source code must retain the above copyright 421553Srgrimes * notice, this list of conditions and the following disclaimer. 431553Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 441553Srgrimes * notice, this list of conditions and the following disclaimer in the 451553Srgrimes * documentation and/or other materials provided with the distribution. 461553Srgrimes * 4. Neither the name of the University nor the names of its contributors 471553Srgrimes * may be used to endorse or promote products derived from this software 481553Srgrimes * without specific prior written permission. 491553Srgrimes * 501553Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 511553Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 521553Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 531553Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 541553Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 551553Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 561553Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 571553Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 581553Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 591553Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 601553Srgrimes * SUCH DAMAGE. 611553Srgrimes */ 6239230Sgibbs/* 6339230Sgibbs * Ideas for the new iostat statistics output modes taken from the NetBSD 6439230Sgibbs * version of iostat: 6539230Sgibbs */ 6639230Sgibbs/* 6739230Sgibbs * Copyright (c) 1996 John M. Vinopal 6839230Sgibbs * All rights reserved. 6939230Sgibbs * 7039230Sgibbs * Redistribution and use in source and binary forms, with or without 7139230Sgibbs * modification, are permitted provided that the following conditions 7239230Sgibbs * are met: 7339230Sgibbs * 1. Redistributions of source code must retain the above copyright 7439230Sgibbs * notice, this list of conditions and the following disclaimer. 7539230Sgibbs * 2. Redistributions in binary form must reproduce the above copyright 7639230Sgibbs * notice, this list of conditions and the following disclaimer in the 7739230Sgibbs * documentation and/or other materials provided with the distribution. 7839230Sgibbs * 3. All advertising materials mentioning features or use of this software 7939230Sgibbs * must display the following acknowledgement: 8039230Sgibbs * This product includes software developed for the NetBSD Project 8139230Sgibbs * by John M. Vinopal. 8239230Sgibbs * 4. The name of the author may not be used to endorse or promote products 8339230Sgibbs * derived from this software without specific prior written permission. 8439230Sgibbs * 8539230Sgibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 8639230Sgibbs * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 8739230Sgibbs * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 8839230Sgibbs * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 8939230Sgibbs * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 9039230Sgibbs * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 9139230Sgibbs * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 9239230Sgibbs * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 9339230Sgibbs * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 9439230Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 9539230Sgibbs * SUCH DAMAGE. 9639230Sgibbs */ 971553Srgrimes 981553Srgrimes 991553Srgrimes#include <sys/param.h> 10039230Sgibbs#include <sys/errno.h> 101111008Sphk#include <sys/resource.h> 10281134Stmm#include <sys/sysctl.h> 1031553Srgrimes 104228661Sdim#include <ctype.h> 105228661Sdim#include <devstat.h> 1061553Srgrimes#include <err.h> 1071553Srgrimes#include <fcntl.h> 108228661Sdim#include <inttypes.h> 1091553Srgrimes#include <kvm.h> 110228661Sdim#include <limits.h> 111228661Sdim#include <math.h> 112102067Sbde#include <nlist.h> 113293696Sasomers#include <signal.h> 1141553Srgrimes#include <stdio.h> 1151553Srgrimes#include <stdlib.h> 1161553Srgrimes#include <string.h> 117175562Skeramida#include <termios.h> 1181553Srgrimes#include <unistd.h> 1191553Srgrimes 120296995Sasomersstatic struct nlist namelist[] = { 12139230Sgibbs#define X_TK_NIN 0 122296995Sasomers { .n_name = "_tk_nin", 123296995Sasomers .n_type = 0, .n_other = 0, .n_desc = 0, .n_value = 0 }, 12439230Sgibbs#define X_TK_NOUT 1 125296995Sasomers { .n_name = "_tk_nout", 126296995Sasomers .n_type = 0, .n_other = 0, .n_desc = 0, .n_value = 0 }, 127181881Sjhb#define X_BOOTTIME 2 128296995Sasomers { .n_name = "_boottime", 129296995Sasomers .n_type = 0, .n_other = 0, .n_desc = 0, .n_value = 0 }, 130181881Sjhb#define X_END 2 131296995Sasomers { .n_name = NULL, 132296995Sasomers .n_type = 0, .n_other = 0, .n_desc = 0, .n_value = 0 }, 1331553Srgrimes}; 1341553Srgrimes 135175562Skeramida#define IOSTAT_DEFAULT_ROWS 20 /* Traditional default `wrows' */ 136175562Skeramida 137296995Sasomersstatic struct statinfo cur, last; 138296995Sasomersstatic int num_devices; 139296995Sasomersstatic struct device_selection *dev_select; 140296995Sasomersstatic int maxshowdevs; 141296995Sasomersstatic volatile sig_atomic_t headercount; 142296995Sasomersstatic volatile sig_atomic_t wresized; /* Tty resized, when non-zero. */ 143296995Sasomersstatic volatile sig_atomic_t alarm_rang; 144296995Sasomersstatic volatile sig_atomic_t return_requested; 145296995Sasomersstatic unsigned short wrows; /* Current number of tty rows. */ 146296995Sasomersstatic int dflag = 0, Iflag = 0, Cflag = 0, Tflag = 0, oflag = 0, Kflag = 0; 147296995Sasomersstatic int xflag = 0, zflag = 0; 1481553Srgrimes 14939230Sgibbs/* local function declarations */ 15039230Sgibbsstatic void usage(void); 15183965Sguidostatic void needhdr(int signo); 152175562Skeramidastatic void needresize(int signo); 153293696Sasomersstatic void needreturn(int signo); 154293696Sasomersstatic void alarm_clock(int signo); 155175562Skeramidastatic void doresize(void); 15683965Sguidostatic void phdr(void); 15782168Skenstatic void devstats(int perf_select, long double etime, int havelast); 15839230Sgibbsstatic void cpustats(void); 15982168Skenstatic int readvar(kvm_t *kd, const char *name, int nlid, void *ptr, 16082168Sken size_t len); 1611553Srgrimes 16239230Sgibbsstatic void 16339230Sgibbsusage(void) 16439230Sgibbs{ 16539230Sgibbs /* 16639230Sgibbs * We also support the following 'traditional' syntax: 16739230Sgibbs * iostat [drives] [wait [count]] 16839230Sgibbs * This isn't mentioned in the man page, or the usage statement, 16939230Sgibbs * but it is supported. 17039230Sgibbs */ 171157800Smaxim fprintf(stderr, "usage: iostat [-CdhIKoTxz?] [-c count] [-M core]" 17256561Scharnier " [-n devs] [-N system]\n" 17356561Scharnier "\t [-t type,if,pass] [-w wait] [drives]\n"); 17439230Sgibbs} 1751553Srgrimes 1761553Srgrimesint 17739230Sgibbsmain(int argc, char **argv) 1781553Srgrimes{ 179157802Smaxim int c, i; 18039230Sgibbs int tflag = 0, hflag = 0, cflag = 0, wflag = 0, nflag = 0; 18139230Sgibbs int count = 0, waittime = 0; 18239230Sgibbs char *memf = NULL, *nlistf = NULL; 18339230Sgibbs struct devstat_match *matches; 184293696Sasomers struct itimerval alarmspec; 18539230Sgibbs int num_matches = 0; 186157801Smaxim char errbuf[_POSIX2_LINE_MAX]; 18781134Stmm kvm_t *kd = NULL; 18839498Sken long generation; 18939230Sgibbs int num_devices_specified; 19039498Sken int num_selected, num_selections; 19139498Sken long select_generation; 19239230Sgibbs char **specified_devices; 19339230Sgibbs devstat_select_mode select_mode; 194208389Ssbruno float f; 19582168Sken int havelast = 0; 1961553Srgrimes 19739230Sgibbs matches = NULL; 19839230Sgibbs maxshowdevs = 3; 19939230Sgibbs 200157800Smaxim while ((c = getopt(argc, argv, "c:CdhIKM:n:N:ot:Tw:xz?")) != -1) { 20139230Sgibbs switch(c) { 20239230Sgibbs case 'c': 20339230Sgibbs cflag++; 20439230Sgibbs count = atoi(optarg); 20539230Sgibbs if (count < 1) 20639230Sgibbs errx(1, "count %d is < 1", count); 20739230Sgibbs break; 20839230Sgibbs case 'C': 20939230Sgibbs Cflag++; 21039230Sgibbs break; 21139230Sgibbs case 'd': 21239230Sgibbs dflag++; 21339230Sgibbs break; 21439230Sgibbs case 'h': 21539230Sgibbs hflag++; 21639230Sgibbs break; 21739387Sken case 'I': 21839387Sken Iflag++; 21939387Sken break; 22039371Sdillon case 'K': 22139371Sdillon Kflag++; 22239371Sdillon break; 22339230Sgibbs case 'M': 22439230Sgibbs memf = optarg; 22539230Sgibbs break; 22639230Sgibbs case 'n': 22739230Sgibbs nflag++; 22839230Sgibbs maxshowdevs = atoi(optarg); 22939230Sgibbs if (maxshowdevs < 0) 23056483Scharnier errx(1, "number of devices %d is < 0", 23139230Sgibbs maxshowdevs); 23239230Sgibbs break; 23339230Sgibbs case 'N': 23439230Sgibbs nlistf = optarg; 23539230Sgibbs break; 23639230Sgibbs case 'o': 23739230Sgibbs oflag++; 23839230Sgibbs break; 23939230Sgibbs case 't': 24039230Sgibbs tflag++; 241157801Smaxim if (devstat_buildmatch(optarg, &matches, 24281134Stmm &num_matches) != 0) 24339230Sgibbs errx(1, "%s", devstat_errbuf); 24439230Sgibbs break; 24539230Sgibbs case 'T': 24639230Sgibbs Tflag++; 24739230Sgibbs break; 24839230Sgibbs case 'w': 24939230Sgibbs wflag++; 250208389Ssbruno f = atof(optarg); 251208389Ssbruno waittime = f * 1000; 25239230Sgibbs if (waittime < 1) 253208389Ssbruno errx(1, "wait time is < 1ms"); 25439230Sgibbs break; 255157800Smaxim case 'x': 256157800Smaxim xflag++; 257157800Smaxim break; 258157800Smaxim case 'z': 259157800Smaxim zflag++; 260157800Smaxim break; 26139230Sgibbs default: 26239230Sgibbs usage(); 26356561Scharnier exit(1); 26439230Sgibbs break; 2651553Srgrimes } 26639230Sgibbs } 26739230Sgibbs 2681553Srgrimes argc -= optind; 2691553Srgrimes argv += optind; 2701553Srgrimes 27182168Sken if (nlistf != NULL || memf != NULL) { 27281134Stmm kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf); 273157801Smaxim 27482168Sken if (kd == NULL) 27581134Stmm errx(1, "kvm_openfiles: %s", errbuf); 276157801Smaxim 27781134Stmm if (kvm_nlist(kd, namelist) == -1) 27881134Stmm errx(1, "kvm_nlist: %s", kvm_geterr(kd)); 27981134Stmm } 28081134Stmm 28139230Sgibbs /* 28239230Sgibbs * Make sure that the userland devstat version matches the kernel 283157801Smaxim * devstat version. If not, exit and print a message informing 28439230Sgibbs * the user of his mistake. 28539230Sgibbs */ 28681134Stmm if (devstat_checkversion(kd) < 0) 28739230Sgibbs errx(1, "%s", devstat_errbuf); 2881553Srgrimes 28939230Sgibbs /* 29082168Sken * Make sure Tflag and/or Cflag are set if dflag == 0. If dflag is 29182168Sken * greater than 0, they may be 0 or non-zero. 29282168Sken */ 293157800Smaxim if (dflag == 0 && xflag == 0) { 29482168Sken Cflag = 1; 29582168Sken Tflag = 1; 29682168Sken } 29782168Sken 298171709Smaxim /* find out how many devices we have */ 299171709Smaxim if ((num_devices = devstat_getnumdevs(kd)) < 0) 300171709Smaxim err(1, "can't get number of devices"); 301171709Smaxim 30282168Sken /* 30339230Sgibbs * Figure out how many devices we should display. 30439230Sgibbs */ 30539230Sgibbs if (nflag == 0) { 306171709Smaxim if (xflag > 0) 307171709Smaxim maxshowdevs = num_devices; 308171709Smaxim else if (oflag > 0) { 30939230Sgibbs if ((dflag > 0) && (Cflag == 0) && (Tflag == 0)) 31039230Sgibbs maxshowdevs = 5; 31139230Sgibbs else if ((dflag > 0) && (Tflag > 0) && (Cflag == 0)) 31239230Sgibbs maxshowdevs = 5; 31339230Sgibbs else 31439230Sgibbs maxshowdevs = 4; 31539230Sgibbs } else { 31639230Sgibbs if ((dflag > 0) && (Cflag == 0)) 317157801Smaxim maxshowdevs = 4; 31839230Sgibbs else 31939230Sgibbs maxshowdevs = 3; 32039230Sgibbs } 3211553Srgrimes } 3221553Srgrimes 323192570Sdelphij cur.dinfo = (struct devinfo *)calloc(1, sizeof(struct devinfo)); 32482168Sken if (cur.dinfo == NULL) 325192570Sdelphij err(1, "calloc failed"); 32682168Sken 327192570Sdelphij last.dinfo = (struct devinfo *)calloc(1, sizeof(struct devinfo)); 32882168Sken if (last.dinfo == NULL) 329192570Sdelphij err(1, "calloc failed"); 33082168Sken 3311553Srgrimes /* 33239230Sgibbs * Grab all the devices. We don't look to see if the list has 33339230Sgibbs * changed here, since it almost certainly has. We only look for 33439230Sgibbs * errors. 3351553Srgrimes */ 33681134Stmm if (devstat_getdevs(kd, &cur) == -1) 33739230Sgibbs errx(1, "%s", devstat_errbuf); 33839230Sgibbs 33939230Sgibbs num_devices = cur.dinfo->numdevs; 34039230Sgibbs generation = cur.dinfo->generation; 34139230Sgibbs 34239230Sgibbs /* 34339230Sgibbs * If the user specified any devices on the command line, see if 34439230Sgibbs * they are in the list of devices we have now. 34539230Sgibbs */ 34682168Sken specified_devices = (char **)malloc(sizeof(char *)); 34782168Sken if (specified_devices == NULL) 34882168Sken err(1, "malloc failed"); 34982168Sken 35039230Sgibbs for (num_devices_specified = 0; *argv; ++argv) { 3511553Srgrimes if (isdigit(**argv)) 3521553Srgrimes break; 35339230Sgibbs num_devices_specified++; 35439230Sgibbs specified_devices = (char **)realloc(specified_devices, 35539230Sgibbs sizeof(char *) * 35639230Sgibbs num_devices_specified); 35782168Sken if (specified_devices == NULL) 35882168Sken err(1, "realloc failed"); 35982168Sken 36039230Sgibbs specified_devices[num_devices_specified - 1] = *argv; 36139230Sgibbs 3621553Srgrimes } 36339371Sdillon if (nflag == 0 && maxshowdevs < num_devices_specified) 36439371Sdillon maxshowdevs = num_devices_specified; 36539230Sgibbs 36639230Sgibbs dev_select = NULL; 36739230Sgibbs 36839230Sgibbs if ((num_devices_specified == 0) && (num_matches == 0)) 36939230Sgibbs select_mode = DS_SELECT_ADD; 37039230Sgibbs else 37139230Sgibbs select_mode = DS_SELECT_ONLY; 37239230Sgibbs 37339230Sgibbs /* 37439230Sgibbs * At this point, selectdevs will almost surely indicate that the 37539230Sgibbs * device list has changed, so we don't look for return values of 0 37639230Sgibbs * or 1. If we get back -1, though, there is an error. 37739230Sgibbs */ 37881134Stmm if (devstat_selectdevs(&dev_select, &num_selected, 37981134Stmm &num_selections, &select_generation, generation, 38081134Stmm cur.dinfo->devices, num_devices, matches, 38181134Stmm num_matches, specified_devices, 38281134Stmm num_devices_specified, select_mode, maxshowdevs, 38381134Stmm hflag) == -1) 38439230Sgibbs errx(1, "%s", devstat_errbuf); 38539230Sgibbs 38639230Sgibbs /* 38739230Sgibbs * Look for the traditional wait time and count arguments. 38839230Sgibbs */ 3891553Srgrimes if (*argv) { 390208389Ssbruno f = atof(*argv); 391208389Ssbruno waittime = f * 1000; 3921553Srgrimes 39339230Sgibbs /* Let the user know he goofed, but keep going anyway */ 394157801Smaxim if (wflag != 0) 39539230Sgibbs warnx("discarding previous wait interval, using" 396208389Ssbruno " %g instead", waittime / 1000.0); 39739230Sgibbs wflag++; 3981553Srgrimes 39939230Sgibbs if (*++argv) { 40039230Sgibbs count = atoi(*argv); 40139230Sgibbs if (cflag != 0) 40239230Sgibbs warnx("discarding previous count, using %d" 40339230Sgibbs " instead", count); 40439230Sgibbs cflag++; 40539230Sgibbs } else 40639230Sgibbs count = -1; 4071553Srgrimes } 4081553Srgrimes 40939230Sgibbs /* 41039230Sgibbs * If the user specified a count, but not an interval, we default 41139230Sgibbs * to an interval of 1 second. 41239230Sgibbs */ 41339230Sgibbs if ((wflag == 0) && (cflag > 0)) 414208389Ssbruno waittime = 1 * 1000; 41539230Sgibbs 41639230Sgibbs /* 41739230Sgibbs * If the user specified a wait time, but not a count, we want to 41839230Sgibbs * go on ad infinitum. This can be redundant if the user uses the 41939230Sgibbs * traditional method of specifying the wait, since in that case we 42039230Sgibbs * already set count = -1 above. Oh well. 42139230Sgibbs */ 42239230Sgibbs if ((wflag > 0) && (cflag == 0)) 42339230Sgibbs count = -1; 42439230Sgibbs 425181878Sjhb bzero(cur.cp_time, sizeof(cur.cp_time)); 42682168Sken cur.tk_nout = 0; 42782168Sken cur.tk_nin = 0; 42882168Sken 42939230Sgibbs /* 430157801Smaxim * Set the snap time to the system boot time (ie: zero), so the 431112288Sphk * stats are calculated since system boot. 43282168Sken */ 433112288Sphk cur.snap_time = 0; 43482168Sken 43582168Sken /* 43639230Sgibbs * If the user stops the program (control-Z) and then resumes it, 43739230Sgibbs * print out the header again. 43839230Sgibbs */ 43983965Sguido (void)signal(SIGCONT, needhdr); 4401553Srgrimes 441175562Skeramida /* 442175562Skeramida * If our standard output is a tty, then install a SIGWINCH handler 443175562Skeramida * and set wresized so that our first iteration through the main 444175562Skeramida * iostat loop will peek at the terminal's current rows to find out 445175562Skeramida * how many lines can fit in a screenful of output. 446175562Skeramida */ 447175562Skeramida if (isatty(fileno(stdout)) != 0) { 448175562Skeramida wresized = 1; 449175562Skeramida (void)signal(SIGWINCH, needresize); 450175562Skeramida } else { 451175562Skeramida wresized = 0; 452175562Skeramida wrows = IOSTAT_DEFAULT_ROWS; 453175562Skeramida } 454175562Skeramida 455293696Sasomers /* 456293696Sasomers * Register a SIGINT handler so that we can print out final statistics 457293696Sasomers * when we get that signal 458293696Sasomers */ 459293696Sasomers (void)signal(SIGINT, needreturn); 460293696Sasomers 461293696Sasomers /* 462293696Sasomers * Register a SIGALRM handler to implement sleeps if the user uses the 463293696Sasomers * -c or -w options 464293696Sasomers */ 465293696Sasomers (void)signal(SIGALRM, alarm_clock); 466293696Sasomers alarmspec.it_interval.tv_sec = waittime / 1000; 467293696Sasomers alarmspec.it_interval.tv_usec = 1000 * (waittime % 1000); 468293696Sasomers alarmspec.it_value.tv_sec = waittime / 1000; 469293696Sasomers alarmspec.it_value.tv_usec = 1000 * (waittime % 1000); 470293696Sasomers setitimer(ITIMER_REAL, &alarmspec, NULL); 471293696Sasomers 47239230Sgibbs for (headercount = 1;;) { 47339230Sgibbs struct devinfo *tmp_dinfo; 47439230Sgibbs long tmp; 47582168Sken long double etime; 476293696Sasomers sigset_t sigmask, oldsigmask; 47739230Sgibbs 47882168Sken if (Tflag > 0) { 47982168Sken if ((readvar(kd, "kern.tty_nin", X_TK_NIN, &cur.tk_nin, 48082168Sken sizeof(cur.tk_nin)) != 0) 48182168Sken || (readvar(kd, "kern.tty_nout", X_TK_NOUT, 48282168Sken &cur.tk_nout, sizeof(cur.tk_nout))!= 0)) { 48382168Sken Tflag = 0; 48482168Sken warnx("disabling TTY statistics"); 48582168Sken } 48682168Sken } 48782168Sken 48882168Sken if (Cflag > 0) { 489181881Sjhb if (kd == NULL) { 490181881Sjhb if (readvar(kd, "kern.cp_time", 0, 491181881Sjhb &cur.cp_time, sizeof(cur.cp_time)) != 0) 492181881Sjhb Cflag = 0; 493181881Sjhb } else { 494181881Sjhb if (kvm_getcptime(kd, cur.cp_time) < 0) { 495181881Sjhb warnx("kvm_getcptime: %s", 496181881Sjhb kvm_geterr(kd)); 497181881Sjhb Cflag = 0; 498181881Sjhb } 499181881Sjhb } 500181881Sjhb if (Cflag == 0) 50182168Sken warnx("disabling CPU time statistics"); 50282168Sken } 50382168Sken 50439230Sgibbs if (!--headercount) { 50583965Sguido phdr(); 506175562Skeramida if (wresized != 0) 507175562Skeramida doresize(); 508175562Skeramida headercount = wrows; 5091553Srgrimes } 51039230Sgibbs 51139230Sgibbs tmp_dinfo = last.dinfo; 51239230Sgibbs last.dinfo = cur.dinfo; 51339230Sgibbs cur.dinfo = tmp_dinfo; 51439230Sgibbs 515112288Sphk last.snap_time = cur.snap_time; 51639230Sgibbs 51739230Sgibbs /* 51839230Sgibbs * Here what we want to do is refresh our device stats. 51981134Stmm * devstat_getdevs() returns 1 when the device list has changed. 52039230Sgibbs * If the device list has changed, we want to go through 52139230Sgibbs * the selection process again, in case a device that we 52239230Sgibbs * were previously displaying has gone away. 52339230Sgibbs */ 52481134Stmm switch (devstat_getdevs(kd, &cur)) { 52539230Sgibbs case -1: 52639230Sgibbs errx(1, "%s", devstat_errbuf); 52739230Sgibbs break; 52839230Sgibbs case 1: { 52939230Sgibbs int retval; 53039230Sgibbs 53139230Sgibbs num_devices = cur.dinfo->numdevs; 53239230Sgibbs generation = cur.dinfo->generation; 53381134Stmm retval = devstat_selectdevs(&dev_select, &num_selected, 53481134Stmm &num_selections, 53581134Stmm &select_generation, 53681134Stmm generation, 53781134Stmm cur.dinfo->devices, 53881134Stmm num_devices, matches, 53981134Stmm num_matches, 54081134Stmm specified_devices, 54181134Stmm num_devices_specified, 54281134Stmm select_mode, maxshowdevs, 54381134Stmm hflag); 54439230Sgibbs switch(retval) { 54539230Sgibbs case -1: 54639230Sgibbs errx(1, "%s", devstat_errbuf); 54739230Sgibbs break; 54839230Sgibbs case 1: 54983965Sguido phdr(); 550175562Skeramida if (wresized != 0) 551175562Skeramida doresize(); 552175562Skeramida headercount = wrows; 55339230Sgibbs break; 55439230Sgibbs default: 55539230Sgibbs break; 55639230Sgibbs } 55739230Sgibbs break; 5581553Srgrimes } 55939230Sgibbs default: 56039230Sgibbs break; 56139230Sgibbs } 56239230Sgibbs 56339230Sgibbs /* 56439230Sgibbs * We only want to re-select devices if we're in 'top' 56539230Sgibbs * mode. This is the only mode where the devices selected 56639230Sgibbs * could actually change. 56739230Sgibbs */ 56839230Sgibbs if (hflag > 0) { 56939230Sgibbs int retval; 57081134Stmm retval = devstat_selectdevs(&dev_select, &num_selected, 57181134Stmm &num_selections, 57281134Stmm &select_generation, 57381134Stmm generation, 57481134Stmm cur.dinfo->devices, 57581134Stmm num_devices, matches, 57681134Stmm num_matches, 57781134Stmm specified_devices, 57881134Stmm num_devices_specified, 57981134Stmm select_mode, maxshowdevs, 58081134Stmm hflag); 58139230Sgibbs switch(retval) { 58239230Sgibbs case -1: 58339230Sgibbs errx(1,"%s", devstat_errbuf); 58439230Sgibbs break; 58539230Sgibbs case 1: 58683965Sguido phdr(); 587175562Skeramida if (wresized != 0) 588175562Skeramida doresize(); 589175562Skeramida headercount = wrows; 59039230Sgibbs break; 59139230Sgibbs default: 59239230Sgibbs break; 59339230Sgibbs } 59439230Sgibbs } 59539230Sgibbs 59682168Sken if (Tflag > 0) { 59782168Sken tmp = cur.tk_nin; 59882168Sken cur.tk_nin -= last.tk_nin; 59982168Sken last.tk_nin = tmp; 60082168Sken tmp = cur.tk_nout; 60182168Sken cur.tk_nout -= last.tk_nout; 60282168Sken last.tk_nout = tmp; 60382168Sken } 60439230Sgibbs 605112288Sphk etime = cur.snap_time - last.snap_time; 60639230Sgibbs 60782168Sken if (etime == 0.0) 60882168Sken etime = 1.0; 60939230Sgibbs 6101553Srgrimes for (i = 0; i < CPUSTATES; i++) { 61182168Sken tmp = cur.cp_time[i]; 61282168Sken cur.cp_time[i] -= last.cp_time[i]; 61382168Sken last.cp_time[i] = tmp; 6141553Srgrimes } 61582168Sken 616157800Smaxim if (xflag == 0 && Tflag > 0) 617196254Skeramida printf("%4.0Lf %5.0Lf", cur.tk_nin / etime, 618157800Smaxim cur.tk_nout / etime); 61982168Sken 62081134Stmm devstats(hflag, etime, havelast); 62182168Sken 622157800Smaxim if (xflag == 0) { 623157800Smaxim if (Cflag > 0) 624157800Smaxim cpustats(); 62582168Sken 626157800Smaxim printf("\n"); 627157800Smaxim } 62839230Sgibbs fflush(stdout); 6291553Srgrimes 630293696Sasomers if ((count >= 0 && --count <= 0) || return_requested) 6311553Srgrimes break; 63239230Sgibbs 633293696Sasomers /* 634293696Sasomers * Use sigsuspend to safely sleep until either signal is 635293696Sasomers * received 636293696Sasomers */ 637293696Sasomers alarm_rang = 0; 638293696Sasomers sigemptyset(&sigmask); 639293696Sasomers sigaddset(&sigmask, SIGINT); 640293696Sasomers sigaddset(&sigmask, SIGALRM); 641293696Sasomers sigprocmask(SIG_BLOCK, &sigmask, &oldsigmask); 642293696Sasomers while (! (alarm_rang || return_requested) ) { 643293696Sasomers sigsuspend(&oldsigmask); 644293696Sasomers } 645293696Sasomers sigprocmask(SIG_UNBLOCK, &sigmask, NULL); 646293696Sasomers 64781134Stmm havelast = 1; 6481553Srgrimes } 64939230Sgibbs 6501553Srgrimes exit(0); 6511553Srgrimes} 6521553Srgrimes 65383965Sguido/* 65483965Sguido * Force a header to be prepended to the next output. 65583965Sguido */ 65683965Sguidovoid 657296995Sasomersneedhdr(int signo __unused) 6581553Srgrimes{ 659157801Smaxim 660157801Smaxim headercount = 1; 66182723Skris} 66282723Skris 663175562Skeramida/* 664175562Skeramida * When the terminal is resized, force an update of the maximum number of rows 665175562Skeramida * printed between each header repetition. Then force a new header to be 666175562Skeramida * prepended to the next output. 667175562Skeramida */ 668175562Skeramidavoid 669296995Sasomersneedresize(int signo __unused) 670175562Skeramida{ 671175562Skeramida 672175562Skeramida wresized = 1; 673175562Skeramida headercount = 1; 674175562Skeramida} 675175562Skeramida 676175562Skeramida/* 677293696Sasomers * Record the alarm so the main loop can break its sleep 678293696Sasomers */ 679293696Sasomersvoid 680296995Sasomersalarm_clock(int signo __unused) 681293696Sasomers{ 682293696Sasomers alarm_rang = 1; 683293696Sasomers} 684293696Sasomers 685293696Sasomers/* 686293696Sasomers * Request that the main loop exit soon 687293696Sasomers */ 688293696Sasomersvoid 689296995Sasomersneedreturn(int signo __unused) 690293696Sasomers{ 691293696Sasomers return_requested = 1; 692293696Sasomers} 693293696Sasomers 694293696Sasomers/* 695175562Skeramida * Update the global `wrows' count of terminal rows. 696175562Skeramida */ 697175562Skeramidavoid 698175562Skeramidadoresize(void) 699175562Skeramida{ 700175562Skeramida int status; 701175562Skeramida struct winsize w; 702175562Skeramida 703175562Skeramida for (;;) { 704175562Skeramida status = ioctl(fileno(stdout), TIOCGWINSZ, &w); 705175562Skeramida if (status == -1 && errno == EINTR) 706175562Skeramida continue; 707175562Skeramida else if (status == -1) 708175562Skeramida err(1, "ioctl"); 709175562Skeramida if (w.ws_row > 3) 710175562Skeramida wrows = w.ws_row - 3; 711175562Skeramida else 712175562Skeramida wrows = IOSTAT_DEFAULT_ROWS; 713175562Skeramida break; 714175562Skeramida } 715175562Skeramida 716175562Skeramida /* 717175562Skeramida * Inhibit doresize() calls until we are rescheduled by SIGWINCH. 718175562Skeramida */ 719175562Skeramida wresized = 0; 720175562Skeramida} 721175562Skeramida 72282723Skrisstatic void 72383965Sguidophdr(void) 72482723Skris{ 725157802Smaxim int i, printed; 726182927Sadrian char devbuf[256]; 727157801Smaxim 728157800Smaxim /* 729157800Smaxim * If xflag is set, we need a per-loop header, not a page header, so 730157800Smaxim * just return. We'll print the header in devstats(). 731157800Smaxim */ 732157800Smaxim if (xflag > 0) 733157800Smaxim return; 7341553Srgrimes 73582168Sken if (Tflag > 0) 736196254Skeramida (void)printf(" tty"); 73739230Sgibbs for (i = 0, printed=0;(i < num_devices) && (printed < maxshowdevs);i++){ 73839230Sgibbs int di; 73939230Sgibbs if ((dev_select[i].selected != 0) 74039230Sgibbs && (dev_select[i].selected <= maxshowdevs)) { 74139230Sgibbs di = dev_select[i].position; 742182927Sadrian snprintf(devbuf, sizeof(devbuf), "%s%d", 74339230Sgibbs cur.dinfo->devices[di].device_name, 74439230Sgibbs cur.dinfo->devices[di].unit_number); 745182927Sadrian if (oflag > 0) 746182927Sadrian (void)printf("%13.6s ", devbuf); 74739230Sgibbs else 748182927Sadrian printf("%16.6s ", devbuf); 74939230Sgibbs printed++; 75039230Sgibbs } 75139230Sgibbs } 75282168Sken if (Cflag > 0) 75339230Sgibbs (void)printf(" cpu\n"); 75439230Sgibbs else 75539230Sgibbs (void)printf("\n"); 75639230Sgibbs 75782168Sken if (Tflag > 0) 758196254Skeramida (void)printf(" tin tout"); 75939230Sgibbs 76039230Sgibbs for (i=0, printed = 0;(i < num_devices) && (printed < maxshowdevs);i++){ 76139230Sgibbs if ((dev_select[i].selected != 0) 76239230Sgibbs && (dev_select[i].selected <= maxshowdevs)) { 76339371Sdillon if (oflag > 0) { 76439230Sgibbs if (Iflag == 0) 76539230Sgibbs (void)printf(" sps tps msps "); 76639230Sgibbs else 76739230Sgibbs (void)printf(" blk xfr msps "); 76839371Sdillon } else { 76939230Sgibbs if (Iflag == 0) 77039230Sgibbs printf(" KB/t tps MB/s "); 77139230Sgibbs else 77239230Sgibbs printf(" KB/t xfrs MB "); 77339371Sdillon } 77439230Sgibbs printed++; 77539230Sgibbs } 77639230Sgibbs } 77782168Sken if (Cflag > 0) 77839230Sgibbs (void)printf(" us ni sy in id\n"); 77939230Sgibbs else 78039230Sgibbs printf("\n"); 78183965Sguido 7821553Srgrimes} 7831553Srgrimes 78439230Sgibbsstatic void 78582168Skendevstats(int perf_select, long double etime, int havelast) 7861553Srgrimes{ 787157802Smaxim int dn; 788157800Smaxim long double transfers_per_second, transfers_per_second_read, transfers_per_second_write; 789157800Smaxim long double kb_per_transfer, mb_per_second, mb_per_second_read, mb_per_second_write; 79039230Sgibbs u_int64_t total_bytes, total_transfers, total_blocks; 791169496Smaxim u_int64_t total_bytes_read, total_transfers_read; 792169496Smaxim u_int64_t total_bytes_write, total_transfers_write; 793244271Strociny long double busy_pct, busy_time; 794157800Smaxim u_int64_t queue_len; 79539230Sgibbs long double total_mb; 796244271Strociny long double blocks_per_second, ms_per_transaction, total_duration; 797157800Smaxim int firstline = 1; 798296995Sasomers char *devicename; 799157800Smaxim 800157800Smaxim if (xflag > 0) { 801157800Smaxim printf(" extended device statistics "); 802157800Smaxim if (Tflag > 0) 803196254Skeramida printf(" tty "); 804157800Smaxim if (Cflag > 0) 805157800Smaxim printf(" cpu "); 806157800Smaxim printf("\n"); 807244271Strociny if (Iflag == 0) { 808244271Strociny printf("device r/s w/s kr/s kw/s qlen " 809244271Strociny "svc_t %%b "); 810244271Strociny } else { 811244271Strociny printf("device r/i w/i kr/i" 812244271Strociny " kw/i qlen tsvc_t/i sb/i "); 813244271Strociny } 814157800Smaxim if (Tflag > 0) 815196254Skeramida printf("tin tout "); 816157800Smaxim if (Cflag > 0) 817157800Smaxim printf("us ni sy in id "); 818157800Smaxim printf("\n"); 819157800Smaxim } 820157801Smaxim 82139230Sgibbs for (dn = 0; dn < num_devices; dn++) { 82239230Sgibbs int di; 82339230Sgibbs 82439230Sgibbs if (((perf_select == 0) && (dev_select[dn].selected == 0)) 82539230Sgibbs || (dev_select[dn].selected > maxshowdevs)) 8261553Srgrimes continue; 8271553Srgrimes 82839230Sgibbs di = dev_select[dn].position; 8291553Srgrimes 83081134Stmm if (devstat_compute_statistics(&cur.dinfo->devices[di], 83182168Sken havelast ? &last.dinfo->devices[di] : NULL, etime, 83281134Stmm DSM_TOTAL_BYTES, &total_bytes, 833169496Smaxim DSM_TOTAL_BYTES_READ, &total_bytes_read, 834169496Smaxim DSM_TOTAL_BYTES_WRITE, &total_bytes_write, 83581134Stmm DSM_TOTAL_TRANSFERS, &total_transfers, 836169496Smaxim DSM_TOTAL_TRANSFERS_READ, &total_transfers_read, 837169496Smaxim DSM_TOTAL_TRANSFERS_WRITE, &total_transfers_write, 83881134Stmm DSM_TOTAL_BLOCKS, &total_blocks, 83981134Stmm DSM_KB_PER_TRANSFER, &kb_per_transfer, 84081134Stmm DSM_TRANSFERS_PER_SECOND, &transfers_per_second, 841157800Smaxim DSM_TRANSFERS_PER_SECOND_READ, &transfers_per_second_read, 842157800Smaxim DSM_TRANSFERS_PER_SECOND_WRITE, &transfers_per_second_write, 843157801Smaxim DSM_MB_PER_SECOND, &mb_per_second, 844157801Smaxim DSM_MB_PER_SECOND_READ, &mb_per_second_read, 845157801Smaxim DSM_MB_PER_SECOND_WRITE, &mb_per_second_write, 84681134Stmm DSM_BLOCKS_PER_SECOND, &blocks_per_second, 84781134Stmm DSM_MS_PER_TRANSACTION, &ms_per_transaction, 848157800Smaxim DSM_BUSY_PCT, &busy_pct, 849157800Smaxim DSM_QUEUE_LENGTH, &queue_len, 850244271Strociny DSM_TOTAL_DURATION, &total_duration, 851244271Strociny DSM_TOTAL_BUSY_TIME, &busy_time, 85281134Stmm DSM_NONE) != 0) 85339230Sgibbs errx(1, "%s", devstat_errbuf); 85439230Sgibbs 85539230Sgibbs if (perf_select != 0) { 85639230Sgibbs dev_select[dn].bytes = total_bytes; 85739230Sgibbs if ((dev_select[dn].selected == 0) 85839230Sgibbs || (dev_select[dn].selected > maxshowdevs)) 85939230Sgibbs continue; 86039230Sgibbs } 86139230Sgibbs 862157800Smaxim if (Kflag > 0 || xflag > 0) { 86339371Sdillon int block_size = cur.dinfo->devices[di].block_size; 86439387Sken total_blocks = total_blocks * (block_size ? 86539387Sken block_size : 512) / 1024; 86639371Sdillon } 86739371Sdillon 868157800Smaxim if (xflag > 0) { 869296995Sasomers if (asprintf(&devicename, "%s%d", 870157800Smaxim cur.dinfo->devices[di].device_name, 871175252Smaxim cur.dinfo->devices[di].unit_number) == -1) 872175252Smaxim err(1, "asprintf"); 873157800Smaxim /* 874157800Smaxim * If zflag is set, skip any devices with zero I/O. 875157800Smaxim */ 876157800Smaxim if (zflag == 0 || transfers_per_second_read > 0.05 || 877157800Smaxim transfers_per_second_write > 0.05 || 878157800Smaxim mb_per_second_read > ((long double).0005)/1024 || 879157800Smaxim mb_per_second_write > ((long double).0005)/1024 || 880157800Smaxim busy_pct > 0.5) { 881169496Smaxim if (Iflag == 0) 882228661Sdim printf("%-8.8s %5.1Lf %5.1Lf %7.1Lf %7.1Lf %4" PRIu64 " %5.1Lf %3.0Lf ", 883296995Sasomers devicename, 884296995Sasomers transfers_per_second_read, 885169496Smaxim transfers_per_second_write, 886169496Smaxim mb_per_second_read * 1024, 887169506Smaxim mb_per_second_write * 1024, 888169506Smaxim queue_len, 889169496Smaxim ms_per_transaction, busy_pct); 890169496Smaxim else 891244271Strociny printf("%-8.8s %11.1Lf %11.1Lf " 892244271Strociny "%12.1Lf %12.1Lf %4" PRIu64 893244271Strociny " %10.1Lf %9.1Lf ", 894296995Sasomers devicename, 895169506Smaxim (long double)total_transfers_read, 896169496Smaxim (long double)total_transfers_write, 897169506Smaxim (long double) 898169506Smaxim total_bytes_read / 1024, 899169506Smaxim (long double) 900169506Smaxim total_bytes_write / 1024, 901169506Smaxim queue_len, 902244271Strociny total_duration, busy_time); 903157800Smaxim if (firstline) { 904157800Smaxim /* 905157800Smaxim * If this is the first device 906157800Smaxim * we're printing, also print 907157800Smaxim * CPU or TTY stats if requested. 908157800Smaxim */ 909157800Smaxim firstline = 0; 910157800Smaxim if (Tflag > 0) 911157800Smaxim printf("%4.0Lf%5.0Lf", 912157800Smaxim cur.tk_nin / etime, 913157800Smaxim cur.tk_nout / etime); 914157800Smaxim if (Cflag > 0) 915157800Smaxim cpustats(); 916157800Smaxim } 917157800Smaxim printf("\n"); 918157800Smaxim } 919296995Sasomers free(devicename); 920157800Smaxim } else if (oflag > 0) { 92139371Sdillon int msdig = (ms_per_transaction < 100.0) ? 1 : 0; 92239230Sgibbs 92339230Sgibbs if (Iflag == 0) 92439371Sdillon printf("%4.0Lf%4.0Lf%5.*Lf ", 92539230Sgibbs blocks_per_second, 92639230Sgibbs transfers_per_second, 92739371Sdillon msdig, 92839230Sgibbs ms_per_transaction); 929157801Smaxim else 930228661Sdim printf("%4.1" PRIu64 "%4.1" PRIu64 "%5.*Lf ", 93139230Sgibbs total_blocks, 93239230Sgibbs total_transfers, 93339371Sdillon msdig, 93439230Sgibbs ms_per_transaction); 93539230Sgibbs } else { 93639230Sgibbs if (Iflag == 0) 937157801Smaxim printf(" %5.2Lf %3.0Lf %5.2Lf ", 93839230Sgibbs kb_per_transfer, 93939230Sgibbs transfers_per_second, 94039230Sgibbs mb_per_second); 94139230Sgibbs else { 94239230Sgibbs total_mb = total_bytes; 94339230Sgibbs total_mb /= 1024 * 1024; 94439230Sgibbs 945228661Sdim printf(" %5.2Lf %3.1" PRIu64 " %5.2Lf ", 94639230Sgibbs kb_per_transfer, 94739230Sgibbs total_transfers, 94839230Sgibbs total_mb); 94939230Sgibbs } 95039230Sgibbs } 9511553Srgrimes } 952157800Smaxim if (xflag > 0 && zflag > 0 && firstline == 1 && 953157800Smaxim (Tflag > 0 || Cflag > 0)) { 954157800Smaxim /* 955157800Smaxim * If zflag is set and we did not print any device 956157800Smaxim * lines I/O because they were all zero, 957157800Smaxim * print TTY/CPU stats. 958157800Smaxim */ 959157800Smaxim printf("%52s",""); 960157800Smaxim if (Tflag > 0) 961196254Skeramida printf("%4.0Lf %5.0Lf", cur.tk_nin / etime, 962157800Smaxim cur.tk_nout / etime); 963157800Smaxim if (Cflag > 0) 964157800Smaxim cpustats(); 965157800Smaxim printf("\n"); 966157800Smaxim } 9671553Srgrimes} 9681553Srgrimes 96939230Sgibbsstatic void 97039230Sgibbscpustats(void) 9711553Srgrimes{ 972157802Smaxim int state; 973296995Sasomers double cptime; 9741553Srgrimes 975296995Sasomers cptime = 0.0; 97639230Sgibbs 9771553Srgrimes for (state = 0; state < CPUSTATES; ++state) 978296995Sasomers cptime += cur.cp_time[state]; 9791553Srgrimes for (state = 0; state < CPUSTATES; ++state) 980102068Sbde printf(" %2.0f", 981296995Sasomers rint(100. * cur.cp_time[state] / (cptime ? cptime : 1))); 9821553Srgrimes} 98381134Stmm 98482168Skenstatic int 98582168Skenreadvar(kvm_t *kd, const char *name, int nlid, void *ptr, size_t len) 98681134Stmm{ 98782168Sken if (kd != NULL) { 98882168Sken ssize_t nbytes; 98982168Sken 990166541Sjhb nbytes = kvm_read(kd, namelist[nlid].n_value, ptr, len); 99182168Sken 992166541Sjhb if (nbytes < 0) { 993166541Sjhb warnx("kvm_read(%s): %s", namelist[nlid].n_name, 994166541Sjhb kvm_geterr(kd)); 99582168Sken return (1); 996296995Sasomers } else if ((size_t)nbytes != len) { 997166541Sjhb warnx("kvm_read(%s): expected %zu bytes, got %zd bytes", 998166541Sjhb namelist[nlid].n_name, len, nbytes); 99982168Sken return (1); 100082168Sken } 100182168Sken } else { 100282168Sken size_t nlen = len; 1003157801Smaxim 100482168Sken if (sysctlbyname(name, ptr, &nlen, NULL, 0) == -1) { 100582168Sken warn("sysctl(%s...) failed", name); 100682168Sken return (1); 100782168Sken } 100882168Sken if (nlen != len) { 100982168Sken warnx("sysctl(%s...): expected %lu, got %lu", name, 101082168Sken (unsigned long)len, (unsigned long)nlen); 101182168Sken return (1); 101282168Sken } 101382168Sken } 101482168Sken return (0); 101581134Stmm} 1016