Home | History | Annotate | Download | only in dsstat
      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 2008 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 		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 		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