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 }