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
errout(char * msg)52 errout(char *msg)
53 {
54
55 (void) fprintf(stderr, msg);
56 }
57
58 void
usage()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
help()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
fail(int err,char * msg)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
set_mode(char * user_modes)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
set_dflags(char * flags)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
set_rflags(char * flags)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
set_vol_list(char * list)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
main(int argc,char ** argv)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