GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/iostat/iostat.c Lines: 0 166 0.0 %
Date: 2017-11-07 Branches: 0 142 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: iostat.c,v 1.39 2015/10/23 08:21:27 tedu Exp $	*/
2
/*	$NetBSD: iostat.c,v 1.10 1996/10/25 18:21:58 scottr Exp $	*/
3
4
/*
5
 * Copyright (c) 1996 John M. Vinopal
6
 * All rights reserved.
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions
10
 * are met:
11
 * 1. Redistributions of source code must retain the above copyright
12
 *    notice, this list of conditions and the following disclaimer.
13
 * 2. Redistributions in binary form must reproduce the above copyright
14
 *    notice, this list of conditions and the following disclaimer in the
15
 *    documentation and/or other materials provided with the distribution.
16
 * 3. All advertising materials mentioning features or use of this software
17
 *    must display the following acknowledgement:
18
 *      This product includes software developed for the NetBSD Project
19
 *      by John M. Vinopal.
20
 * 4. The name of the author may not be used to endorse or promote products
21
 *    derived from this software without specific prior written permission.
22
 *
23
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
30
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33
 * SUCH DAMAGE.
34
 */
35
36
/*-
37
 * Copyright (c) 1986, 1991, 1993
38
 *      The Regents of the University of California.  All rights reserved.
39
 *
40
 * Redistribution and use in source and binary forms, with or without
41
 * modification, are permitted provided that the following conditions
42
 * are met:
43
 * 1. Redistributions of source code must retain the above copyright
44
 *    notice, this list of conditions and the following disclaimer.
45
 * 2. Redistributions in binary form must reproduce the above copyright
46
 *    notice, this list of conditions and the following disclaimer in the
47
 *    documentation and/or other materials provided with the distribution.
48
 * 3. Neither the name of the University nor the names of its contributors
49
 *    may be used to endorse or promote products derived from this software
50
 *    without specific prior written permission.
51
 *
52
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
53
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
54
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
55
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
56
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
57
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
58
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
59
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
60
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
61
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
62
 * SUCH DAMAGE.
63
 */
64
65
#include <sys/limits.h>
66
#include <sys/time.h>
67
#include <sys/sched.h>
68
69
#include <err.h>
70
#include <ctype.h>
71
#include <signal.h>
72
#include <stdio.h>
73
#include <stdlib.h>
74
#include <string.h>
75
#include <unistd.h>
76
#include <kvm.h>
77
78
#include "dkstats.h"
79
80
/* Defined in dkstats.c */
81
extern struct _disk cur, last;
82
extern int	dk_ndrive;
83
84
/* Namelist and memory files. */
85
kvm_t *kd;
86
char	*nlistf, *memf;
87
88
int		hz, reps, interval;
89
static int	todo = 0;
90
91
volatile sig_atomic_t wantheader;
92
93
#define ISSET(x, a)	((x) & (a))
94
#define SHOW_CPU	0x0001
95
#define SHOW_TTY	0x0002
96
#define SHOW_STATS_1	0x0004
97
#define SHOW_STATS_2	0x0008
98
#define SHOW_TOTALS	0x0080
99
100
static void cpustats(void);
101
static void disk_stats(double);
102
static void disk_stats2(double);
103
static void sigheader(int);
104
static void header(void);
105
static void usage(void);
106
static void display(void);
107
static void selectdrives(char **);
108
109
void dkswap(void);
110
void dkreadstats(void);
111
int dkinit(int);
112
113
int
114
main(int argc, char *argv[])
115
{
116
	const char *errstr;
117
	int ch, hdrcnt;
118
	struct timespec	ts;
119
120
	while ((ch = getopt(argc, argv, "Cc:dDIM:N:Tw:")) != -1)
121
		switch(ch) {
122
		case 'c':
123
			reps = strtonum(optarg, 1, INT_MAX, &errstr);
124
			if (errstr)
125
				errx(1, "repetition count is %s", errstr);
126
			break;
127
		case 'C':
128
			todo |= SHOW_CPU;
129
			break;
130
		case 'd':
131
			todo |= SHOW_STATS_1;
132
			break;
133
		case 'D':
134
			todo |= SHOW_STATS_2;
135
			break;
136
		case 'I':
137
			todo |= SHOW_TOTALS;
138
			break;
139
		case 'M':
140
			memf = optarg;
141
			break;
142
		case 'N':
143
			nlistf = optarg;
144
			break;
145
		case 'T':
146
			todo |= SHOW_TTY;
147
			break;
148
		case 'w':
149
			interval = strtonum(optarg, 1, INT_MAX, &errstr);
150
			if (errstr)
151
				errx(1, "interval is %s", errstr);
152
			break;
153
		case '?':
154
		default:
155
			usage();
156
		}
157
	argc -= optind;
158
	argv += optind;
159
160
	if (!ISSET(todo, SHOW_CPU | SHOW_TTY | SHOW_STATS_1 | SHOW_STATS_2))
161
		todo |= SHOW_CPU | SHOW_TTY | SHOW_STATS_1;
162
163
	dkinit(0);
164
	dkreadstats();
165
	selectdrives(argv);
166
167
	ts.tv_sec = interval;
168
	ts.tv_nsec = 0;
169
170
	/* print a new header on sigcont */
171
	signal(SIGCONT, sigheader);
172
173
	for (hdrcnt = 1;;) {
174
		if (!--hdrcnt || wantheader) {
175
			header();
176
			hdrcnt = 20;
177
			wantheader = 0;
178
		}
179
180
		if (!ISSET(todo, SHOW_TOTALS))
181
			dkswap();
182
		display();
183
184
		if (reps >= 0 && --reps <= 0)
185
			break;
186
		nanosleep(&ts, NULL);
187
		dkreadstats();
188
		if (last.dk_ndrive != cur.dk_ndrive)
189
			wantheader = 1;
190
	}
191
	exit(0);
192
}
193
194
/*ARGSUSED*/
195
static void
196
sigheader(int signo)
197
{
198
	wantheader = 1;
199
}
200
201
static void
202
header(void)
203
{
204
	int i;
205
	static int printedheader = 0;
206
207
	if (printedheader && !isatty(STDOUT_FILENO))
208
		return;
209
210
	/* Main Headers. */
211
	if (ISSET(todo, SHOW_TTY)) {
212
		if (ISSET(todo, SHOW_TOTALS))
213
			printf("            tty");
214
		else
215
			printf("      tty");
216
	}
217
218
	if (ISSET(todo, SHOW_STATS_1))
219
		for (i = 0; i < dk_ndrive; i++)
220
			if (cur.dk_select[i]) {
221
				if (ISSET(todo, SHOW_TOTALS))
222
					printf(" %18.18s ", cur.dk_name[i]);
223
				else
224
					printf(" %16.16s ", cur.dk_name[i]);
225
			}
226
	if (ISSET(todo, SHOW_STATS_2))
227
		for (i = 0; i < dk_ndrive; i++)
228
			if (cur.dk_select[i])
229
				printf(" %16.16s ", cur.dk_name[i]);
230
231
	if (ISSET(todo, SHOW_CPU))
232
		printf("            cpu");
233
	printf("\n");
234
235
	/* Sub-Headers. */
236
	if (ISSET(todo, SHOW_TTY)) {
237
		if (ISSET(todo, SHOW_TOTALS))
238
			printf("   tin     tout");
239
		else
240
			printf(" tin tout");
241
	}
242
243
	if (ISSET(todo, SHOW_STATS_1))
244
		for (i = 0; i < dk_ndrive; i++)
245
			if (cur.dk_select[i]) {
246
				if (ISSET(todo, SHOW_TOTALS))
247
					printf("  KB/t   xfr     MB ");
248
				else
249
					printf("  KB/t  t/s  MB/s ");
250
			}
251
	if (ISSET(todo, SHOW_STATS_2))
252
		for (i = 0; i < dk_ndrive; i++)
253
			if (cur.dk_select[i])
254
				printf("     KB  xfr time ");
255
256
	if (ISSET(todo, SHOW_CPU))
257
		printf(" us ni sy in id");
258
	printf("\n");
259
}
260
261
static void
262
disk_stats(double etime)
263
{
264
	int dn;
265
	double atime, mbps;
266
267
	for (dn = 0; dn < dk_ndrive; ++dn) {
268
		if (!cur.dk_select[dn])
269
			continue;
270
271
		/* average Kbytes per transfer. */
272
		if (cur.dk_rxfer[dn] + cur.dk_wxfer[dn])
273
			mbps = ((cur.dk_rbytes[dn] + cur.dk_wbytes[dn]) /
274
			    (1024.0)) / (cur.dk_rxfer[dn] + cur.dk_wxfer[dn]);
275
		else
276
			mbps = 0.0;
277
278
		printf(" %5.2f", mbps);
279
280
		/* average transfers per second. */
281
		if (ISSET(todo, SHOW_TOTALS))
282
			printf(" %5.0f", (cur.dk_rxfer[dn] + cur.dk_wxfer[dn]) / etime);
283
		else
284
			printf(" %4.0f", (cur.dk_rxfer[dn] + cur.dk_wxfer[dn]) / etime);
285
286
		/* time busy in disk activity */
287
		atime = (double)cur.dk_time[dn].tv_sec +
288
			((double)cur.dk_time[dn].tv_usec / (double)1000000);
289
290
		/* Megabytes per second. */
291
		if (atime != 0.0)
292
			mbps = (cur.dk_rbytes[dn] + cur.dk_wbytes[dn]) /
293
			    (double)(1024 * 1024);
294
		else
295
			mbps = 0;
296
		if (ISSET(todo, SHOW_TOTALS))
297
			printf(" %6.2f ", mbps / etime);
298
		else
299
			printf(" %5.2f ", mbps / etime);
300
	}
301
}
302
303
static void
304
disk_stats2(double etime)
305
{
306
	int dn;
307
	double atime;
308
309
	for (dn = 0; dn < dk_ndrive; ++dn) {
310
		if (!cur.dk_select[dn])
311
			continue;
312
313
		/* average kbytes per second. */
314
		printf(" %6.0f",
315
		    (cur.dk_rbytes[dn] + cur.dk_wbytes[dn]) / (1024.0) / etime);
316
317
		/* average transfers per second. */
318
		printf(" %4.0f", (cur.dk_rxfer[dn] + cur.dk_wxfer[dn]) / etime);
319
320
		/* average time busy in disk activity. */
321
		atime = (double)cur.dk_time[dn].tv_sec +
322
		    ((double)cur.dk_time[dn].tv_usec / (double)1000000);
323
		printf(" %4.2f ", atime / etime);
324
	}
325
}
326
327
static void
328
cpustats(void)
329
{
330
	int state;
331
	double t = 0;
332
333
	for (state = 0; state < CPUSTATES; ++state)
334
		t += cur.cp_time[state];
335
	if (!t)
336
		t = 1.0;
337
	/* States are generally never 100% and can use %3.0f. */
338
	for (state = 0; state < CPUSTATES; ++state)
339
		printf("%3.0f", 100. * cur.cp_time[state] / t);
340
}
341
342
static void
343
usage(void)
344
{
345
	fprintf(stderr,
346
"usage: iostat [-CDdIT] [-c count] [-M core] [-N system] [-w wait] [drives]\n");
347
	exit(1);
348
}
349
350
static void
351
display(void)
352
{
353
	int	i;
354
	double	etime;
355
356
	/* Sum up the elapsed ticks. */
357
	etime = 0.0;
358
	for (i = 0; i < CPUSTATES; i++)
359
		etime += cur.cp_time[i];
360
	if (etime == 0.0)
361
		etime = 1.0;
362
	/* Convert to seconds. */
363
	etime /= (float)hz;
364
365
	/* If we're showing totals only, then don't divide by the
366
	 * system time.
367
	 */
368
	if (ISSET(todo, SHOW_TOTALS))
369
		etime = 1.0;
370
371
	if (ISSET(todo, SHOW_TTY)) {
372
		if (ISSET(todo, SHOW_TOTALS))
373
			printf("%6.0f %8.0f", cur.tk_nin / etime,
374
			    cur.tk_nout / etime);
375
		else
376
			printf("%4.0f %4.0f", cur.tk_nin / etime,
377
			    cur.tk_nout / etime);
378
	}
379
380
	if (ISSET(todo, SHOW_STATS_1))
381
		disk_stats(etime);
382
383
	if (ISSET(todo, SHOW_STATS_2))
384
		disk_stats2(etime);
385
386
	if (ISSET(todo, SHOW_CPU))
387
		cpustats();
388
389
	printf("\n");
390
	fflush(stdout);
391
}
392
393
static void
394
selectdrives(char *argv[])
395
{
396
	const char *errstr;
397
	int	i, ndrives;
398
399
	/*
400
	 * Choose drives to be displayed.  Priority goes to (in order) drives
401
	 * supplied as arguments and default drives.  If everything isn't
402
	 * filled in and there are drives not taken care of, display the first
403
	 * few that fit.
404
	 *
405
	 * The backward compatibility syntax is:
406
	 *	iostat [ drives ] [ interval [ count ] ]
407
	 */
408
	for (ndrives = 0; *argv; ++argv) {
409
		if (isdigit((unsigned char)**argv))
410
			break;
411
		for (i = 0; i < dk_ndrive; i++) {
412
			if (strcmp(cur.dk_name[i], *argv))
413
				continue;
414
			cur.dk_select[i] = 1;
415
			++ndrives;
416
			break;
417
		}
418
		if (i == dk_ndrive)
419
			errx(1, "invalid interval or drive name: %s", *argv);
420
	}
421
	if (*argv) {
422
		interval = strtonum(*argv, 1, INT_MAX, &errstr);
423
		if (errstr)
424
			errx(1, "interval is %s", errstr);
425
		if (*++argv) {
426
			reps = strtonum(*argv, 1, INT_MAX, &errstr);
427
			if (errstr)
428
				errx(1, "repetition count is %s", errstr);
429
			++argv;
430
		}
431
	}
432
	if (*argv)
433
		errx(1, "too many arguments");
434
435
	if (interval) {
436
		if (!reps)
437
			reps = -1;
438
	} else
439
		if (reps)
440
			interval = 1;
441
442
	/* Pick up to 4 drives if none specified. */
443
	if (ndrives == 0)
444
		for (i = 0; i < dk_ndrive && ndrives < 4; i++) {
445
			if (cur.dk_select[i])
446
				continue;
447
			cur.dk_select[i] = 1;
448
			++ndrives;
449
		}
450
}