xref: /titanic_52/usr/src/cmd/avs/dsstat/dsstat.c (revision 2fb4439d628ad2df0775287be1abd1ed95e7d267)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <unistd.h>
30 #include <errno.h>
31 #include <inttypes.h>
32 #include <locale.h>
33 
34 #include <kstat.h>
35 
36 #include "dsstat.h"
37 #include "multi_stats.h"
38 
39 /* Globals */
40 int mode = 0;
41 int interval = 1;
42 int iterations = 1;
43 int zflag = 0;
44 int linesout = 0;
45 
46 short hflags = HEADERS_EXL;
47 short dflags = 0;
48 short rflags = 0;
49 vslist_t *vs_top = NULL;
50 
51 void
52 errout(char *msg)
53 {
54 
55 	(void) fprintf(stderr, msg);
56 }
57 
58 void
59 usage()
60 {
61 	errout(gettext(
62 	    "\ndsstat [-m <mode>[,<mode>]] [-f | -F] [-z] [-s <sets>] "
63 	    "[-r <flags>] \\\n[-d <flags>] [<interval> [<count>]]\n\n"));
64 }
65 
66 void
67 help()
68 {
69 	usage();
70 
71 	errout(gettext("\t"
72 	    "-d <flags> Specifies the statistics to be displayed\n\n"));
73 	errout(gettext("\t"
74 	    "   For 'cache' mode\n"));
75 	errout(gettext("\t"
76 	    "      Valid <flags> are 'rwfsdc', default <flags> are 'sf'\n"));
77 	errout(gettext("\t"
78 	    "      r=read, w=write, f=flags, s=summary,\n"));
79 	errout(gettext("\t"
80 	    "   only available for cache mode, need to combine with '-m'\n"));
81 	errout(gettext("\t"
82 	    "      d=destaged, c=write cancellations\n\n"));
83 	errout(gettext("\t"
84 	    "   For 'ii' mode;\n"));
85 	errout(gettext("\t"
86 	    "      Valid <flags> are 'rwtfps', default <flags> are 'sf'\n"));
87 	errout(gettext("\t"
88 	    "      r=read, w=write, t=timing, f=flags, p=percentages,\n"));
89 	errout(gettext("\t"
90 	    "      s=summary\n\n"));
91 	errout(gettext("\t"
92 	    "   For 'sndr' mode;\n"));
93 	errout(gettext("\t"
94 	    "      Valid <flags> are'rwtfpsq', default <flags> are 'spf'\n"));
95 	errout(gettext("\t"
96 	    "      r=read, w=write, t=timing, f=flags, p=percentages,\n"));
97 	errout(gettext("\t"
98 	    "      s=summary\n"));
99 	errout(gettext("\t"
100 	    "   only available for sndr mode, need to combine with '-m'\n"));
101 	errout(gettext("\t"
102 	    "      q=queue\n\n"));
103 	errout(gettext("\t"
104 	    "-f  prints field headers once for each iteration\n\n"));
105 	errout(gettext("\t"
106 	    "-F  prints field headers once, at the start of reporting\n\n"));
107 	errout(gettext("\t"
108 	    "-h  prints detailed usage message\n\n"));
109 	errout(gettext("\t"
110 	    "-m <mode>[,<mode>] where mode is, 'cache', 'ii', or 'sndr'\n\n"));
111 	errout(gettext("\t"
112 	    "   Multiple modes may be specified as a comma separated list,\n"));
113 	errout(gettext("\t"
114 	    "   or multiple -m switches may be used.\n\n"));
115 	errout(gettext("\t"
116 	    "-r <flags> specifies components to be reported\n\n"));
117 	errout(gettext("\t"
118 	    "   For 'cache' mode, this option is not used.\n\n"));
119 	errout(gettext("\t"
120 	    "   For 'ii' mode;\n"));
121 	errout(gettext("\t"
122 	    "      Valid <flags> are 'msbo', default <flags> are 'msbo'\n"));
123 	errout(gettext("\t"
124 	    "      m=master, s=shadow, b=bitmap, o=overflow\n\n"));
125 	errout(gettext("\t"
126 	    "   For 'sndr' mode;\n"));
127 	errout(gettext("\t"
128 	    "      Valid <flags> are 'nb', default <flags> are 'nb'\n"));
129 	errout(gettext("\t"
130 	    "      n=network, b=bitmap\n\n"));
131 	errout(gettext("\t"
132 	    "-s <sets> outputs specified sets\n"));
133 	errout(gettext("\t"
134 	    "    Where <sets> is a comma delimited list of set names\n\n"));
135 	errout(gettext("\t"
136 	    "-z  suppress reports with zero value (no activity)\n\n"));
137 	errout(gettext("\t"
138 	    "<interval> is the number of seconds between reports\n\n"));
139 	errout(gettext("\t"
140 	    "<count> is the number of reports to be generated\n\n"));
141 }
142 
143 void
144 fail(int err, char *msg)
145 {
146 	errout(gettext("\ndsstat: "));
147 	errout(msg);
148 
149 	usage();
150 
151 	errout(gettext("For detailed usage run \"dsstat -h\"\n"));
152 
153 	exit(err);
154 }
155 
156 int
157 set_mode(char *user_modes)
158 {
159 	char *m;
160 	int local_mode = 0;
161 
162 	for (m = strtok(user_modes, ","); m != NULL; m = strtok(NULL, ",")) {
163 		if (local_mode != 0) {
164 			local_mode |= MULTI;
165 		}
166 
167 		if (strncasecmp("sndr", m, strlen(m)) == 0) {
168 			local_mode |= SNDR;
169 			continue;
170 		}
171 
172 		if (strncasecmp("ii", m, strlen(m)) == 0) {
173 			local_mode |= IIMG;
174 			continue;
175 		}
176 
177 		if (strncasecmp("cache", m, strlen(m)) == 0) {
178 			local_mode |= SDBC;
179 			continue;
180 		}
181 
182 		fail(DSSTAT_EINVAL, gettext("Invalid mode specified"));
183 	}
184 
185 	return (local_mode);
186 }
187 
188 short
189 set_dflags(char *flags)
190 {
191 	int index;
192 	short user_dflags = 0;
193 
194 	for (index = 0; index < strlen(flags); index++) {
195 		switch (flags[index]) {
196 			case 'r':
197 				user_dflags |= READ;
198 				break;
199 			case 'w':
200 				user_dflags |= WRITE;
201 				break;
202 			case 't':
203 				user_dflags |= TIMING;
204 				break;
205 			case 'f':
206 				user_dflags |= FLAGS;
207 				break;
208 			case 'p':
209 				user_dflags |= PCTS;
210 				break;
211 			case 's':
212 				user_dflags |= SUMMARY;
213 				break;
214 			case 'd':
215 				user_dflags |= DESTAGED;
216 				break;
217 			case 'c':
218 				user_dflags |= WRCANCEL;
219 				break;
220 			case 'h':
221 				user_dflags |= RATIO;
222 				break;
223 			case 'q':
224 				user_dflags |= ASYNC_QUEUE;
225 				break;
226 			default:
227 				fail(DSSTAT_EINVAL,
228 				    gettext("Invalid display-flags set\n"));
229 		}
230 	}
231 
232 	return (user_dflags);
233 }
234 
235 short
236 set_rflags(char *flags)
237 {
238 	int index;
239 	short user_rflags = 0;
240 
241 	for (index = 0; index < strlen(flags); index++) {
242 		switch (flags[index]) {
243 			case 'm':
244 				user_rflags |= IIMG_MST;
245 				break;
246 			case 's':
247 				user_rflags |= IIMG_SHD;
248 				break;
249 			case 'b':
250 				user_rflags |= IIMG_BMP;
251 				user_rflags |= SNDR_BMP;
252 				break;
253 			case 'o':
254 				user_rflags |= IIMG_OVR;
255 				break;
256 			case 'n':
257 				user_rflags |= SNDR_NET;
258 				break;
259 			default:
260 				fail(DSSTAT_EINVAL,
261 				    gettext("Invalid report-flags set\n"));
262 		}
263 	}
264 
265 	return (user_rflags);
266 }
267 
268 void
269 set_vol_list(char *list)
270 {
271 	vslist_t *pre;
272 	vslist_t *newvol;
273 	vslist_t *vslist;
274 	char *volume;
275 
276 	for (volume = strtok(list, ","); volume != NULL;
277 	    volume = strtok(NULL, ",")) {
278 		int dup = 0;
279 		char *vh = NULL;
280 		char *vn = NULL;
281 
282 		/* get user-specified set information */
283 		if ((vn = strchr(volume, ':')) == NULL) {
284 			vn = volume;
285 		} else {
286 			*vn = '\0';
287 			vn++;
288 			vh = volume;
289 		}
290 
291 		/* check for duplicates */
292 		dup = 0;
293 
294 		for (vslist = vs_top; vslist != NULL; vslist = vslist->next) {
295 			if (vslist->volhost && vh) {
296 				if (strcmp(vslist->volhost, vh) == 0 &&
297 				    strcmp(vslist->volname, vn) == 0)
298 					dup = 1;
299 			} else {
300 				if (strcmp(vslist->volname, vn) == 0)
301 					dup = 1;
302 			}
303 
304 			pre = vslist;
305 		}
306 
307 		if (dup)
308 			continue;
309 
310 		/* initialize new vslist record */
311 		newvol = (vslist_t *)calloc(1, sizeof (vslist_t));
312 
313 		newvol->volname = (char *)calloc((strlen(vn) + 1),
314 		    sizeof (char));
315 		(void) strcpy(newvol->volname, vn);
316 
317 		if (vh == NULL)
318 			goto save;
319 
320 		newvol->volhost = (char *)calloc((strlen(vh) + 1),
321 		    sizeof (char));
322 		(void) strcpy(newvol->volhost, vh);
323 
324 save:
325 		/* save record */
326 		if (vs_top == NULL) {
327 			vslist = vs_top = newvol;
328 			vslist->next = NULL;
329 			continue;
330 		}
331 
332 		if (vslist == NULL) {
333 			vslist = pre->next = newvol;
334 			vslist->next = NULL;
335 			continue;
336 		}
337 	}
338 }
339 
340 int
341 main(int argc, char **argv)
342 {
343 	extern char *optarg;
344 	extern int optind;
345 
346 	int c;
347 	int error;
348 	short user_dflags = 0;
349 	short user_rflags = 0;
350 
351 	/* Parse command line */
352 	while ((c = getopt(argc, argv, "d:fFhm:r:s:z")) != EOF) {
353 		switch (c) {
354 			case 'd':	/* what to display */
355 				user_dflags = set_dflags(optarg);
356 				break;
357 			case 'f':
358 				hflags = HEADERS_ATT;
359 				break;
360 			case 'F':
361 				hflags = HEADERS_BOR;
362 				break;
363 			case 'h':		/* usage */
364 				help();
365 				exit(0);
366 				break;
367 			case 'm':		/* Mode */
368 				mode |= set_mode(optarg);
369 				break;
370 			case 'r':		/* what to report on */
371 				user_rflags = set_rflags(optarg);
372 				break;
373 			case 's':
374 				set_vol_list(optarg);
375 				break;
376 			case 'z':
377 				zflag = 1;
378 				break;
379 
380 			default:
381 				fail(DSSTAT_EINVAL,
382 				    "Invalid argument specified\n");
383 		}
384 	}
385 
386 	/* Parse additional arguments */
387 	if (optind < argc) {
388 		if ((interval = atoi(argv[optind])) <= 0) {
389 			fail(DSSTAT_EINVAL,
390 			    gettext("Invalid interval specified.\n"));
391 		} else {
392 			iterations = -1;
393 		}
394 
395 		optind++;
396 
397 		if (optind < argc) {
398 			if ((iterations = atoi(argv[optind])) <= 0) {
399 				fail(DSSTAT_EINVAL,
400 				    gettext("Invalid count specified.\n"));
401 			}
402 		}
403 
404 		optind++;
405 	}
406 
407 	if (optind < argc) {
408 		fail(DSSTAT_EINVAL,
409 		    gettext("Too many parameters specified.\n"));
410 	}
411 
412 	if (mode == 0)
413 		mode |= MULTI | IIMG | SNDR | SDBC;
414 
415 	/* Select statistics to gather */
416 	if (mode & SNDR) {
417 		if (! (mode & MULTI)) {
418 			if (user_rflags & IIMG_BMP)
419 				user_rflags ^= IIMG_BMP;
420 
421 			if ((user_dflags | SNDR_DIS_MASK) != SNDR_DIS_MASK) {
422 				fail(DSSTAT_EINVAL, gettext("Invalid "
423 				    "display-flags for RemoteMirror\n"));
424 			}
425 
426 			if ((user_rflags | SNDR_REP_MASK) != SNDR_REP_MASK) {
427 				fail(DSSTAT_EINVAL,
428 				    gettext("Invalid report-flags for "
429 				    "Remote Mirror\n"));
430 			}
431 		}
432 
433 		if ((mode & MULTI) && (user_dflags & ASYNC_QUEUE)) {
434 			fail(DSSTAT_EINVAL, gettext("Remote Mirror async. queue"
435 			    "statistics can not be displayed with mutiple "
436 			    "modes."));
437 		}
438 
439 		if (user_dflags)
440 			dflags = user_dflags;
441 		else
442 			dflags |= (SUMMARY | PCTS | FLAGS | RATIO);
443 
444 		if (user_rflags)
445 			rflags = user_rflags;
446 		else
447 			rflags |= (SNDR_NET | SNDR_BMP);
448 	}
449 
450 	if (mode & IIMG) {
451 		if (! (mode & MULTI)) {
452 			if (user_rflags & SNDR_BMP)
453 				user_rflags ^= SNDR_BMP;
454 
455 			if ((user_dflags | IIMG_DIS_MASK) != IIMG_DIS_MASK) {
456 				fail(DSSTAT_EINVAL,
457 				    gettext("Invalid display-flags for "
458 				    "Point-in-Time Copy\n"));
459 			}
460 
461 			if ((user_rflags | IIMG_REP_MASK) != IIMG_REP_MASK) {
462 				fail(DSSTAT_EINVAL,
463 				    gettext("Invalid report-flags for "
464 				    "Point-in-Time Copy\n"));
465 			}
466 		}
467 
468 		if (user_dflags)
469 			dflags = user_dflags;
470 		else
471 			dflags |= (SUMMARY | PCTS | FLAGS | RATIO);
472 
473 		if (user_rflags)
474 			rflags = user_rflags;
475 		else
476 			rflags |= (IIMG_MST | IIMG_SHD | IIMG_BMP | IIMG_OVR);
477 	}
478 
479 	if (mode & SDBC) {
480 		if (! (mode & MULTI)) {
481 			if ((user_dflags | CACHE_DIS_MASK) != CACHE_DIS_MASK) {
482 				fail(DSSTAT_EINVAL, gettext("Invalid "
483 				    "display-flags for CACHE\n"));
484 			}
485 
486 			if ((user_rflags | CACHE_REP_MASK) != CACHE_REP_MASK) {
487 				fail(DSSTAT_EINVAL, gettext("Invalid "
488 				    "report-flags for CACHE\n"));
489 			}
490 		} else {
491 		    if ((user_dflags & DESTAGED) || (user_dflags & WRCANCEL)) {
492 			if (user_dflags & DESTAGED)
493 			    fail(DSSTAT_EINVAL, gettext("Cache, destaged "
494 				"statistics can not be displayed with mutiple "
495 				"modes."));
496 			else
497 			    fail(DSSTAT_EINVAL, gettext("Cache, write "
498 				"cancellations "
499 				"statistics can not be displayed with mutiple "
500 				"modes."));
501 		    }
502 		}
503 
504 		if (user_dflags)
505 			dflags = user_dflags;
506 		else
507 			if (mode & MULTI)
508 				dflags |= (SUMMARY);
509 			else
510 				dflags |= (SUMMARY | FLAGS);
511 
512 		if (user_rflags)
513 			rflags = user_rflags;
514 		else
515 			rflags |= user_rflags;
516 	}
517 
518 	error = do_stats();
519 
520 	if (error == EAGAIN) {
521 		fail(DSSTAT_NOSTAT, gettext("No statistics available for the "
522 		    "specified mode(s).\n"));
523 	}
524 
525 	if (error == EINVAL) {
526 		fail(DSSTAT_EINVAL,
527 		    gettext("Invalid kstat format detected.\n"));
528 	}
529 
530 	if (error == ENOMEM) {
531 		fail(DSSTAT_ENOMEM,
532 		    gettext("Unable to open kstat device for reading.\n"));
533 	}
534 
535 	if (error == -1) {
536 		if (execv("/usr/sbin/dsstat", argv) != 0) {
537 			fail(DSSTAT_EMAP, gettext("Kstat is invalid.\n"));
538 		}
539 	}
540 
541 	if (error) {
542 		fail(DSSTAT_EUNKNWN, gettext("An unknown error occured.\n"));
543 	}
544 
545 	return (0);
546 }
547