1/*
2 * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
3 * Use is subject to license terms.
4 */
5
6/*
7 * BSD 3 Clause License
8 *
9 * Copyright (c) 2007, The Storage Networking Industry Association.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 	- Redistributions of source code must retain the above copyright
15 *	  notice, this list of conditions and the following disclaimer.
16 *
17 * 	- Redistributions in binary form must reproduce the above copyright
18 *	  notice, this list of conditions and the following disclaimer in
19 *	  the documentation and/or other materials provided with the
20 *	  distribution.
21 *
22 *	- Neither the name of The Storage Networking Industry Association (SNIA)
23 *	  nor the names of its contributors may be used to endorse or promote
24 *	  products derived from this software without specific prior written
25 *	  permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
28 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
31 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 * POSSIBILITY OF SUCH DAMAGE.
38 */
39#include <stdio.h>
40#include <stdlib.h>
41#include <stdarg.h>
42#include <ctype.h>
43#include <unistd.h>
44#include <memory.h>
45#include <string.h>
46#include <fcntl.h>
47#include <errno.h>
48#include <signal.h>
49#include <values.h>
50#include <poll.h>
51#include <locale.h>
52#include <libndmp.h>
53
54#define	MAX_DEV_STAT	16
55#define	REPRINT	19
56#define	VAL(v)		(new->ns_##v)
57#define	DELTA(v)	(new->ns_##v - (old ? old->ns_##v : 0))
58#define	ADJ(n)		((adj <= 0) ? n : (adj >= n) ? 1 : n - adj)
59#define	adjprintf(fmt, n, val)	adj -= (n + 1) - printf(fmt, ADJ(n), val)
60#if !defined(TEXT_DOMAIN)
61#define	TEXT_DOMAIN	"SYS_TEST"
62#endif
63
64static int adj;		/* number of excess columns */
65static long iter = 0;
66static int blksize = 1024;
67static int poll_interval = 1;
68static ndmp_stat_t *nstat;
69static int lines = 1;
70
71static void dostats(ndmp_stat_t *, ndmp_stat_t *);
72static void printhdr(int);
73static void usage(void);
74
75int
76main(int argc, char **argv)
77{
78	ndmp_stat_t *old = NULL;
79
80	(void) setlocale(LC_ALL, "");
81	(void) textdomain(TEXT_DOMAIN);
82
83	argc--, argv++;
84
85	if (argc > 0) {
86		long interval;
87		char *endptr;
88
89		errno = 0;
90		interval = strtol(argv[0], &endptr, 10);
91
92		if (errno > 0 || *endptr != '\0' || interval <= 0 ||
93		    interval > MAXLONG) {
94			usage();
95			return (1);
96		}
97		poll_interval = 1000 * interval;
98		if (poll_interval <= 0) {
99			usage();
100			return (1);
101		}
102		iter = MAXLONG;
103		if (argc > 1) {
104			iter = strtol(argv[1], NULL, 10);
105			if (errno > 0 || *endptr != '\0' || iter <= 0) {
106				usage();
107				return (1);
108			}
109		}
110		if (argc > 2) {
111			usage();
112			return (1);
113		}
114	}
115
116	if (ndmp_door_status()) {
117		(void) fprintf(stdout,
118		    gettext(" Error: ndmpd service not running.\n"));
119		return (1);
120	}
121
122	(void) sigset(SIGCONT, printhdr);
123
124	printhdr(0);
125
126	if ((nstat = malloc(sizeof (ndmp_stat_t))) == NULL) {
127		(void) fprintf(stdout, gettext("Out of memory"));
128		return (1);
129	}
130
131
132	if (ndmp_get_stats(nstat) != 0) {
133		free(nstat);
134		return (1);
135	}
136
137	dostats(old, nstat);
138	while (--iter > 0) {
139		(void) poll(NULL, 0, poll_interval);
140
141		free(old);
142		old = nstat;
143		if ((nstat = malloc(sizeof (ndmp_stat_t))) == NULL) {
144			(void) fprintf(stdout, gettext("Out of memory"));
145			free(old);
146			return (1);
147		}
148		if (ndmp_get_stats(nstat) != 0) {
149			free(old);
150			free(nstat);
151			return (1);
152		}
153		dostats(old, nstat);
154	}
155
156	return (0);
157}
158
159/* ARGSUSED */
160static void
161printhdr(int sig)
162{
163	(void) printf(" wthr  ops    file      disk      tape      ");
164	(void) printf("bytes   perf     prcnt\n");
165
166	(void) printf(" r w  bk rs  rd   wr   rd   wr   rd   wr   rd   ");
167	(void) printf("wr  bk rs  dsk tpe idl\n");
168
169	lines = REPRINT;
170}
171
172static void
173dostats(ndmp_stat_t *old, ndmp_stat_t *new)
174{
175	long long dskop = 0;
176	long long tpop = 0;
177	long dpcnt, tpcnt;
178	long ipcnt;
179	int totl;
180	long rbytes;
181	long wbytes;
182
183	adj = 0;
184
185	if (--lines == 0)
186		printhdr(0);
187
188	if (!old) {
189		(void) printf(" 0 0  0  0    0    0    0    ");
190		(void) printf("0    0    0    0    0   0  0    0   0 100\n");
191		return;
192	}
193
194	adjprintf(" %*u", 1, VAL(trun));
195	adjprintf(" %*u", 1, VAL(twait));
196	adjprintf(" %*u", 2, VAL(nbk));
197	adjprintf(" %*u", 2, VAL(nrs));
198	adjprintf(" %*u", 4, DELTA(rfile));
199	adjprintf(" %*u", 4, DELTA(wfile));
200	adjprintf(" %*u", 4, (unsigned)(DELTA(rdisk) / blksize));
201	adjprintf(" %*u", 4, (unsigned)(DELTA(wdisk) / blksize));
202	adjprintf(" %*u", 4, (unsigned)(DELTA(rtape) / blksize));
203	adjprintf(" %*u", 4, (unsigned)(DELTA(wtape) / blksize));
204
205	/* Get the average throughput */
206	rbytes = (DELTA(wtape) + DELTA(rdisk)) / 2;
207	wbytes = (DELTA(rtape) + DELTA(wdisk)) / 2;
208	rbytes /= blksize;
209	wbytes /= blksize;
210
211	adjprintf(" %*lu", 4, rbytes);
212	adjprintf(" %*lu", 4, wbytes);
213
214	adjprintf(" %*lu", 3, rbytes / poll_interval);
215	adjprintf(" %*lu", 2, wbytes / poll_interval);
216
217	dskop += DELTA(rdisk);
218	dskop += DELTA(wdisk);
219	tpop += DELTA(rtape);
220	tpop += DELTA(wtape);
221	totl = (dskop + tpop) ? (dskop + tpop) : 1;
222
223	dpcnt = (dskop * 100) / totl;
224	tpcnt = (tpop * 100) / totl;
225	ipcnt = 100 - dpcnt - tpcnt;
226
227	adjprintf(" %*lu", 4, dpcnt);
228	adjprintf(" %*lu", 3, tpcnt);
229	adjprintf(" %*lu\n", 3, ipcnt);
230	(void) fflush(stdout);
231}
232
233static void
234usage(void)
235{
236	(void) fprintf(stderr, "Usage: ndmpstat [interval [count]]\n");
237}
238