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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 23 /* 24 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 25 * Use is subject to license terms. 26 */ 27 28 #pragma ident "%Z%%M% %I% %E% SMI" 29 30 #include <fm/fmd_adm.h> 31 32 #include <strings.h> 33 #include <limits.h> 34 #include <stdlib.h> 35 #include <stdarg.h> 36 #include <stdio.h> 37 #include <errno.h> 38 #include <poll.h> 39 40 #define FMSTAT_EXIT_SUCCESS 0 41 #define FMSTAT_EXIT_ERROR 1 42 #define FMSTAT_EXIT_USAGE 2 43 44 static const struct stats { 45 fmd_stat_t module; 46 fmd_stat_t authority; 47 fmd_stat_t state; 48 fmd_stat_t loadtime; 49 fmd_stat_t snaptime; 50 fmd_stat_t received; 51 fmd_stat_t discarded; 52 fmd_stat_t retried; 53 fmd_stat_t replayed; 54 fmd_stat_t lost; 55 fmd_stat_t dispatched; 56 fmd_stat_t dequeued; 57 fmd_stat_t prdequeued; 58 fmd_stat_t accepted; 59 fmd_stat_t memtotal; 60 fmd_stat_t buftotal; 61 fmd_stat_t caseopen; 62 fmd_stat_t casesolved; 63 fmd_stat_t wcnt; 64 fmd_stat_t wtime; 65 fmd_stat_t wlentime; 66 fmd_stat_t wlastupdate; 67 fmd_stat_t dtime; 68 fmd_stat_t dlastupdate; 69 } stats_template = { 70 { "module", FMD_TYPE_STRING }, 71 { "authority", FMD_TYPE_STRING }, 72 { "state", FMD_TYPE_STRING }, 73 { "loadtime", FMD_TYPE_TIME }, 74 { "snaptime", FMD_TYPE_TIME }, 75 { "received", FMD_TYPE_UINT64 }, 76 { "discarded", FMD_TYPE_UINT64 }, 77 { "retried", FMD_TYPE_UINT64 }, 78 { "replayed", FMD_TYPE_UINT64 }, 79 { "lost", FMD_TYPE_UINT64 }, 80 { "dispatched", FMD_TYPE_UINT64 }, 81 { "dequeued", FMD_TYPE_UINT64 }, 82 { "prdequeued", FMD_TYPE_UINT64 }, 83 { "accepted", FMD_TYPE_UINT64 }, 84 { "memtotal", FMD_TYPE_SIZE }, 85 { "buftotal", FMD_TYPE_SIZE }, 86 { "caseopen", FMD_TYPE_UINT64 }, 87 { "casesolved", FMD_TYPE_UINT64 }, 88 { "wcnt", FMD_TYPE_UINT32 }, 89 { "wtime", FMD_TYPE_TIME }, 90 { "wlentime", FMD_TYPE_TIME }, 91 { "wlastupdate", FMD_TYPE_TIME }, 92 { "dtime", FMD_TYPE_TIME }, 93 { "dlastupdate", FMD_TYPE_TIME }, 94 }; 95 96 static const char *g_pname; 97 static fmd_adm_t *g_adm; 98 99 static struct modstats { 100 char *m_name; 101 struct modstats *m_next; 102 struct stats m_stbuf[2]; 103 int m_stidx; 104 int m_id; 105 struct stats *m_old; 106 struct stats *m_new; 107 double m_wait; 108 double m_svc; 109 double m_pct_b; 110 double m_pct_w; 111 } *g_mods; 112 113 static void 114 vwarn(const char *format, va_list ap) 115 { 116 int err = errno; 117 118 (void) fprintf(stderr, "%s: ", g_pname); 119 120 if (format != NULL) 121 (void) vfprintf(stderr, format, ap); 122 123 errno = err; /* restore errno for fmd_adm_errmsg() */ 124 125 if (format == NULL) 126 (void) fprintf(stderr, "%s\n", fmd_adm_errmsg(g_adm)); 127 else if (strchr(format, '\n') == NULL) 128 (void) fprintf(stderr, ": %s\n", fmd_adm_errmsg(g_adm)); 129 } 130 131 /*PRINTFLIKE1*/ 132 void 133 warn(const char *format, ...) 134 { 135 va_list ap; 136 137 va_start(ap, format); 138 vwarn(format, ap); 139 va_end(ap); 140 } 141 142 /*PRINTFLIKE1*/ 143 void 144 die(const char *format, ...) 145 { 146 va_list ap; 147 148 va_start(ap, format); 149 vwarn(format, ap); 150 va_end(ap); 151 152 fmd_adm_close(g_adm); 153 exit(FMSTAT_EXIT_ERROR); 154 } 155 156 static char * 157 time2str(char *buf, size_t len, uint64_t time) 158 { 159 static const struct unit { 160 const char *u_name; 161 hrtime_t u_mul; 162 } units[] = { 163 { "d", NANOSEC * (hrtime_t)(24 * 60 * 60) }, 164 { "h", NANOSEC * (hrtime_t)(60 * 60) }, 165 { "m", NANOSEC * (hrtime_t)60 }, 166 { "s", NANOSEC / SEC }, 167 { "ms", NANOSEC / MILLISEC }, 168 { "us", NANOSEC / MICROSEC }, 169 { "ns", NANOSEC / NANOSEC }, 170 }; 171 172 const struct unit *up; 173 174 for (up = units; time % up->u_mul != 0; up++) 175 continue; /* find largest unit of which 'time' is a multiple */ 176 177 (void) snprintf(buf, len, "%llu%s", time / up->u_mul, up->u_name); 178 return (buf); 179 } 180 181 static char * 182 size2str(char *buf, size_t len, uint64_t size) 183 { 184 static const char units[] = "bKMGTPE"; 185 const uint64_t scale = 1024; 186 const char *up = units; 187 uint64_t osize = 0; 188 189 /* 190 * Convert the input size to a round number of the appropriately 191 * scaled units (saved in 'size') and a remainder (saved in 'osize'). 192 */ 193 while (size >= scale && up < (units + sizeof (units) - 2)) { 194 up++; 195 osize = size; 196 size = (size + (scale / 2)) / scale; 197 } 198 199 /* 200 * Format the result using at most one decimal place and the unit 201 * depending upon the amount of remainder (same as df -h algorithm). 202 */ 203 if (osize != 0 && (osize / scale) < 10) 204 (void) snprintf(buf, len, "%.1f%c", (float)osize / scale, *up); 205 else if (size != 0) 206 (void) snprintf(buf, len, "%llu%c", size, *up); 207 else 208 (void) snprintf(buf, len, "0"); 209 210 return (buf); 211 } 212 213 static uint64_t 214 u64delta(uint64_t old, uint64_t new) 215 { 216 return (new >= old ? (new - old) : ((UINT64_MAX - old) + new + 1)); 217 } 218 219 static struct modstats * 220 modstat_create(const char *name, id_t id) 221 { 222 struct modstats *mp = malloc(sizeof (struct modstats)); 223 224 if (mp == NULL) 225 return (NULL); 226 227 bzero(mp, sizeof (struct modstats)); 228 229 if (name != NULL && (mp->m_name = strdup(name)) == NULL) { 230 free(mp); 231 return (NULL); 232 } 233 234 mp->m_id = id; 235 mp->m_next = g_mods; 236 g_mods = mp; 237 return (mp); 238 } 239 240 /* 241 * Given a statistics buffer containing event queue statistics, compute the 242 * common queue statistics for the given module and store the results in 'mp'. 243 * We set m_new and m_old for the caller, and store the compute values of 244 * m_svc, m_wait, m_pct_w, and m_pct_b there as well. The caller must not free 245 * 'ams' until after using the results as m_new may contain pointers to it. 246 */ 247 static void 248 modstat_compute(struct modstats *mp, fmd_adm_stats_t *ams) 249 { 250 static fmd_stat_t *t_beg = (fmd_stat_t *)(&stats_template + 0); 251 static fmd_stat_t *t_end = (fmd_stat_t *)(&stats_template + 1); 252 253 struct stats *old, *new; 254 fmd_stat_t *tsp, *nsp, *sp; 255 double elapsed, avg_w, avg_d; 256 uint64_t delta; 257 258 old = mp->m_old = &mp->m_stbuf[mp->m_stidx]; 259 mp->m_stidx = 1 - mp->m_stidx; 260 new = mp->m_new = &mp->m_stbuf[mp->m_stidx]; 261 262 /* 263 * The statistics can come in any order; we compare each one to the 264 * template of statistics of interest, find the matching ones, and copy 265 * their values into the appropriate slot of the 'new' stats. 266 */ 267 for (nsp = ams->ams_buf; nsp < ams->ams_buf + ams->ams_len; nsp++) { 268 for (tsp = t_beg; tsp < t_end; tsp++) { 269 const char *p = strrchr(nsp->fmds_name, '.'); 270 271 /* 272 * The fmd queue stats can either be named fmd.<name> 273 * or fmd.xprt.%u.<name> depending on whether we're 274 * looking at the module queue or the transport queue. 275 * So we match using the patterns fmd.* and *.<name> 276 * and store only the value of <name> in stats_template. 277 */ 278 if (p == NULL || strcmp(p + 1, tsp->fmds_name) != 0 || 279 strncmp(nsp->fmds_name, "fmd.", 4) != 0) 280 continue; /* continue until we match the stat */ 281 282 if (tsp->fmds_type != nsp->fmds_type) { 283 warn("%s has unexpected type (%u != %u)\n", 284 nsp->fmds_name, tsp->fmds_type, 285 nsp->fmds_type); 286 } else { 287 sp = (fmd_stat_t *)new + (tsp - t_beg); 288 sp->fmds_value = nsp->fmds_value; 289 } 290 } 291 } 292 293 /* 294 * Compute the elapsed time by taking the delta between 'snaptime', or 295 * or between snaptime and loadtime if there is no previous snapshot. 296 * If delta is zero, set it to 1sec so we don't divide by zero later. 297 */ 298 delta = u64delta(old->snaptime.fmds_value.ui64 ? 299 old->snaptime.fmds_value.ui64 : old->loadtime.fmds_value.ui64, 300 new->snaptime.fmds_value.ui64); 301 302 elapsed = delta ? (double)delta : (double)NANOSEC; 303 304 /* 305 * Compute average wait queue len by taking the delta in the wait queue 306 * len * time products (wlentime stat) and dividing by the elapsed time. 307 */ 308 delta = u64delta(old->wlentime.fmds_value.ui64, 309 new->wlentime.fmds_value.ui64); 310 311 if (delta != 0) 312 mp->m_wait = (double)delta / elapsed; 313 else 314 mp->m_wait = 0.0; 315 316 /* 317 * Compute average wait time by taking the delta in the wait queue time 318 * (wtime) and dividing by the delta in the number of dispatches. 319 */ 320 delta = u64delta(old->dispatched.fmds_value.ui64, 321 new->dispatched.fmds_value.ui64); 322 323 if (delta != 0) { 324 avg_w = (double)u64delta(old->wtime.fmds_value.ui64, 325 new->wtime.fmds_value.ui64) / (double)delta; 326 } else 327 avg_w = 0.0; 328 329 /* 330 * Compute average dispatch time by taking the delta in the dispatch 331 * time (dtime) and dividing by the delta in the number of dequeues. 332 */ 333 delta = u64delta(old->dequeued.fmds_value.ui64, 334 new->dequeued.fmds_value.ui64); 335 336 if (delta != 0) { 337 avg_d = (double)u64delta(old->dtime.fmds_value.ui64, 338 new->dtime.fmds_value.ui64) / (double)delta; 339 } else 340 avg_d = 0.0; 341 342 /* 343 * Finally compute the average overall service time by adding together 344 * the average wait and dispatch times and converting to milliseconds. 345 */ 346 mp->m_svc = ((avg_w + avg_d) * (double)MILLISEC) / (double)NANOSEC; 347 348 /* 349 * Compute the %wait and %busy times by taking the delta in wait and 350 * busy times, dividing by the elapsed time, and multiplying by 100. 351 */ 352 delta = u64delta(old->wtime.fmds_value.ui64, 353 new->wtime.fmds_value.ui64); 354 355 if (delta != 0) 356 mp->m_pct_w = ((double)delta / elapsed) * 100.0; 357 else 358 mp->m_pct_w = 0.0; 359 360 delta = u64delta(old->dtime.fmds_value.ui64, 361 new->dtime.fmds_value.ui64); 362 363 if (delta != 0) 364 mp->m_pct_b = ((double)delta / elapsed) * 100.0; 365 else 366 mp->m_pct_b = 0.0; 367 } 368 369 /*ARGSUSED*/ 370 static int 371 stat_one_xprt(id_t id, void *ignored) 372 { 373 fmd_adm_stats_t ams; 374 struct modstats *mp; 375 376 if (fmd_adm_xprt_stats(g_adm, id, &ams) != 0) { 377 warn("failed to retrieve statistics for transport %d", (int)id); 378 return (0); /* continue on to the next transport */ 379 } 380 381 for (mp = g_mods; mp != NULL; mp = mp->m_next) { 382 if (mp->m_id == id) 383 break; 384 } 385 386 if (mp == NULL && (mp = modstat_create(NULL, id)) == NULL) { 387 warn("failed to allocate memory for transport %d", (int)id); 388 (void) fmd_adm_stats_free(g_adm, &ams); 389 return (0); 390 } 391 392 modstat_compute(mp, &ams); 393 394 (void) printf("%3d %5s %7llu %7llu %7llu %7llu " 395 "%4.1f %6.1f %3.0f %3.0f %s\n", (int)id, 396 mp->m_new->state.fmds_value.str, 397 u64delta(mp->m_old->prdequeued.fmds_value.ui64, 398 mp->m_new->prdequeued.fmds_value.ui64), 399 u64delta(mp->m_old->received.fmds_value.ui64, 400 mp->m_new->received.fmds_value.ui64), 401 u64delta(mp->m_old->discarded.fmds_value.ui64, 402 mp->m_new->discarded.fmds_value.ui64), 403 u64delta(mp->m_old->lost.fmds_value.ui64, 404 mp->m_new->lost.fmds_value.ui64), 405 mp->m_wait, mp->m_svc, mp->m_pct_w, mp->m_pct_b, 406 mp->m_new->module.fmds_value.str); 407 408 (void) fmd_adm_stats_free(g_adm, &ams); 409 return (0); 410 } 411 412 static void 413 stat_xprt(void) 414 { 415 (void) printf("%3s %5s %7s %7s %7s %7s %4s %6s %3s %3s %s\n", 416 "id", "state", "ev_send", "ev_recv", "ev_drop", "ev_lost", 417 "wait", "svc_t", "%w", "%b", "module"); 418 419 if (fmd_adm_xprt_iter(g_adm, stat_one_xprt, NULL) != 0) 420 die("failed to retrieve list of transports"); 421 } 422 423 static int 424 stat_one_xprt_auth(id_t id, void *arg) 425 { 426 const char *module = arg; 427 fmd_adm_stats_t ams; 428 struct modstats *mp; 429 430 if (fmd_adm_xprt_stats(g_adm, id, &ams) != 0) { 431 warn("failed to retrieve statistics for transport %d", (int)id); 432 return (0); /* continue on to the next transport */ 433 } 434 435 for (mp = g_mods; mp != NULL; mp = mp->m_next) { 436 if (mp->m_id == id) 437 break; 438 } 439 440 if (mp == NULL && (mp = modstat_create(NULL, id)) == NULL) { 441 warn("failed to allocate memory for transport %d", (int)id); 442 (void) fmd_adm_stats_free(g_adm, &ams); 443 return (0); 444 } 445 446 modstat_compute(mp, &ams); 447 448 if (module == NULL || 449 strcmp(module, mp->m_new->module.fmds_value.str) == 0) { 450 (void) printf("%3d %5s %-18s %s\n", (int)id, 451 mp->m_new->state.fmds_value.str, 452 mp->m_new->module.fmds_value.str, 453 mp->m_new->authority.fmds_value.str ? 454 mp->m_new->authority.fmds_value.str : "-"); 455 } 456 457 (void) fmd_adm_stats_free(g_adm, &ams); 458 return (0); 459 } 460 461 static void 462 stat_xprt_auth(const char *module) 463 { 464 (void) printf("%3s %5s %-18s %s\n", 465 "id", "state", "module", "authority"); 466 467 if (fmd_adm_xprt_iter(g_adm, stat_one_xprt_auth, (void *)module) != 0) 468 die("failed to retrieve list of transports"); 469 } 470 471 /*ARGSUSED*/ 472 static int 473 stat_one_fmd(const fmd_adm_modinfo_t *ami, void *ignored) 474 { 475 char memsz[8], bufsz[8]; 476 fmd_adm_stats_t ams; 477 struct modstats *mp; 478 479 if (fmd_adm_module_stats(g_adm, ami->ami_name, &ams) != 0) { 480 warn("failed to retrieve statistics for %s", ami->ami_name); 481 return (0); /* continue on to the next module */ 482 } 483 484 for (mp = g_mods; mp != NULL; mp = mp->m_next) { 485 if (strcmp(mp->m_name, ami->ami_name) == 0) 486 break; 487 } 488 489 if (mp == NULL && (mp = modstat_create(ami->ami_name, 0)) == NULL) { 490 warn("failed to allocate memory for %s", ami->ami_name); 491 (void) fmd_adm_stats_free(g_adm, &ams); 492 return (0); 493 } 494 495 modstat_compute(mp, &ams); 496 497 (void) printf("%-18s %7llu %7llu %4.1f %6.1f %3.0f %3.0f " 498 "%5llu %5llu %6s %6s\n", ami->ami_name, 499 u64delta(mp->m_old->prdequeued.fmds_value.ui64, 500 mp->m_new->prdequeued.fmds_value.ui64), 501 u64delta(mp->m_old->accepted.fmds_value.ui64, 502 mp->m_new->accepted.fmds_value.ui64), 503 mp->m_wait, mp->m_svc, mp->m_pct_w, mp->m_pct_b, 504 mp->m_new->caseopen.fmds_value.ui64, 505 mp->m_new->casesolved.fmds_value.ui64, 506 size2str(memsz, sizeof (memsz), 507 mp->m_new->memtotal.fmds_value.ui64), 508 size2str(bufsz, sizeof (bufsz), 509 mp->m_new->buftotal.fmds_value.ui64)); 510 511 (void) fmd_adm_stats_free(g_adm, &ams); 512 return (0); 513 } 514 515 static void 516 stat_fmd(void) 517 { 518 (void) printf("%-18s %7s %7s %4s %6s %3s %3s %5s %5s %6s %6s\n", 519 "module", "ev_recv", "ev_acpt", "wait", "svc_t", "%w", "%b", 520 "open", "solve", "memsz", "bufsz"); 521 522 if (fmd_adm_module_iter(g_adm, stat_one_fmd, NULL) != 0) 523 die("failed to retrieve list of modules"); 524 } 525 526 static void 527 stat_mod(const char *name, int aflag, int zflag) 528 { 529 fmd_adm_stats_t ams; 530 fmd_stat_t *sp; 531 char buf[64]; 532 533 if (fmd_adm_stats_read(g_adm, name, &ams) != 0) { 534 die("failed to retrieve statistics for %s", 535 name ? name : "fmd(1M)"); 536 } 537 538 (void) printf("%20s %-16s %s\n", "NAME", "VALUE", "DESCRIPTION"); 539 540 for (sp = ams.ams_buf; sp < ams.ams_buf + ams.ams_len; sp++) { 541 if (aflag == 0 && strncmp(sp->fmds_name, "fmd.", 4) == 0) 542 continue; /* skip fmd-internal stats unless -a used */ 543 544 if (zflag) { 545 switch (sp->fmds_type) { 546 case FMD_TYPE_INT32: 547 case FMD_TYPE_UINT32: 548 if (sp->fmds_value.ui32 == 0) 549 continue; 550 break; 551 case FMD_TYPE_INT64: 552 case FMD_TYPE_UINT64: 553 case FMD_TYPE_TIME: 554 case FMD_TYPE_SIZE: 555 if (sp->fmds_value.ui64 == 0) 556 continue; 557 break; 558 case FMD_TYPE_STRING: 559 if (sp->fmds_value.str == NULL || 560 sp->fmds_value.str[0] == '\0') 561 continue; 562 break; 563 } 564 } 565 566 (void) printf("%20s ", sp->fmds_name); 567 568 switch (sp->fmds_type) { 569 case FMD_TYPE_BOOL: 570 (void) printf("%-16s", 571 sp->fmds_value.bool ? "true" : "false"); 572 break; 573 case FMD_TYPE_INT32: 574 (void) printf("%-16d", sp->fmds_value.i32); 575 break; 576 case FMD_TYPE_UINT32: 577 (void) printf("%-16u", sp->fmds_value.ui32); 578 break; 579 case FMD_TYPE_INT64: 580 (void) printf("%-16lld", sp->fmds_value.i64); 581 break; 582 case FMD_TYPE_UINT64: 583 (void) printf("%-16llu", sp->fmds_value.ui64); 584 break; 585 case FMD_TYPE_STRING: 586 (void) printf("%-16s", sp->fmds_value.str ? 587 sp->fmds_value.str : "<<null>>"); 588 break; 589 case FMD_TYPE_TIME: 590 (void) printf("%-16s", 591 time2str(buf, sizeof (buf), sp->fmds_value.ui64)); 592 break; 593 case FMD_TYPE_SIZE: 594 (void) printf("%-16s", 595 size2str(buf, sizeof (buf), sp->fmds_value.ui64)); 596 break; 597 default: 598 (void) snprintf(buf, sizeof (buf), 599 "<<type=%u>>\n", sp->fmds_type); 600 (void) printf("%-16s", buf); 601 } 602 603 (void) printf(" %s\n", sp->fmds_desc); 604 } 605 606 (void) fmd_adm_stats_free(g_adm, &ams); 607 } 608 609 /*ARGSUSED*/ 610 static int 611 stat_one_serd(const fmd_adm_serdinfo_t *asi, void *ignored) 612 { 613 char buf1[32], buf2[32], n[32]; 614 615 (void) snprintf(n, sizeof (n), ">%llu", asi->asi_n); 616 617 (void) printf("%-36s %3s %5s %3u %24s %s\n", 618 asi->asi_name, n, time2str(buf1, sizeof (buf1), asi->asi_t), 619 asi->asi_count, time2str(buf2, sizeof (buf2), asi->asi_delta), 620 (asi->asi_flags & FMD_ADM_SERD_FIRED) ? "fire" : "pend"); 621 622 return (0); 623 } 624 625 static void 626 stat_mod_serd(const char *name) 627 { 628 (void) printf("%-36s %3s %5s %3s %24s %4s\n", 629 "NAME", ">N", "T", "CNT", "DELTA", "STAT"); 630 631 if (fmd_adm_serd_iter(g_adm, name, stat_one_serd, NULL) != 0) 632 die("failed to retrieve serd engines for %s", name); 633 } 634 635 static int 636 getint(const char *name, const char *s) 637 { 638 long val; 639 char *p; 640 641 errno = 0; 642 val = strtol(s, &p, 10); 643 644 if (errno != 0 || p == s || *p != '\0' || val < 0 || val > INT_MAX) { 645 (void) fprintf(stderr, "%s: invalid %s argument -- %s\n", 646 g_pname, name, s); 647 exit(FMSTAT_EXIT_USAGE); 648 } 649 650 return ((int)val); 651 } 652 653 static uint32_t 654 getu32(const char *name, const char *s) 655 { 656 u_longlong_t val; 657 char *p; 658 659 errno = 0; 660 val = strtoull(s, &p, 0); 661 662 if (errno != 0 || p == s || *p != '\0' || val > UINT32_MAX) { 663 (void) fprintf(stderr, "%s: invalid %s argument -- %s\n", 664 g_pname, name, s); 665 exit(FMSTAT_EXIT_USAGE); 666 } 667 668 return ((uint32_t)val); 669 } 670 671 static int 672 usage(FILE *fp) 673 { 674 (void) fprintf(fp, "Usage: %s [-astTz] [-m module] " 675 "[-P prog] [interval [count]]\n\n", g_pname); 676 677 (void) fprintf(fp, 678 "\t-a show all statistics, including those kept by fmd\n" 679 "\t-m show module-specific statistics\n" 680 "\t-P connect to alternate fmd program\n" 681 "\t-s show module-specific serd engines\n" 682 "\t-t show transport-specific statistics\n" 683 "\t-T show transport modules and authorities\n" 684 "\t-z suppress zero-valued statistics\n"); 685 686 return (FMSTAT_EXIT_USAGE); 687 } 688 689 int 690 main(int argc, char *argv[]) 691 { 692 int opt_a = 0, opt_s = 0, opt_t = 0, opt_T = 0, opt_z = 0; 693 const char *opt_m = NULL; 694 int msec = 0, iter = 1; 695 696 uint32_t program; 697 char *p; 698 int c; 699 700 if ((p = strrchr(argv[0], '/')) == NULL) 701 g_pname = argv[0]; 702 else 703 g_pname = p + 1; 704 705 if ((p = getenv("FMD_PROGRAM")) != NULL) 706 program = getu32("$FMD_PROGRAM", p); 707 else 708 program = FMD_ADM_PROGRAM; 709 710 while ((c = getopt(argc, argv, "am:P:stTz")) != EOF) { 711 switch (c) { 712 case 'a': 713 opt_a++; 714 break; 715 case 'm': 716 opt_m = optarg; 717 break; 718 case 'P': 719 program = getu32("program", optarg); 720 break; 721 case 's': 722 opt_s++; 723 break; 724 case 't': 725 opt_t++; 726 break; 727 case 'T': 728 opt_T++; 729 break; 730 case 'z': 731 opt_z++; 732 break; 733 default: 734 return (usage(stderr)); 735 } 736 } 737 738 if (optind < argc) { 739 msec = getint("interval", argv[optind++]) * MILLISEC; 740 iter = -1; 741 } 742 743 if (optind < argc) 744 iter = getint("count", argv[optind++]); 745 746 if (optind < argc) 747 return (usage(stderr)); 748 749 if (opt_t != 0 && (opt_m != NULL || opt_s != 0)) { 750 (void) fprintf(stderr, 751 "%s: -t cannot be used with -m or -s\n", g_pname); 752 return (FMSTAT_EXIT_USAGE); 753 } 754 755 if (opt_t != 0 && opt_T != 0) { 756 (void) fprintf(stderr, 757 "%s: -t and -T are mutually exclusive options\n", g_pname); 758 return (FMSTAT_EXIT_USAGE); 759 } 760 761 if (opt_m == NULL && opt_s != 0) { 762 (void) fprintf(stderr, 763 "%s: -s requires -m <module>\n", g_pname); 764 return (FMSTAT_EXIT_USAGE); 765 } 766 767 if ((g_adm = fmd_adm_open(NULL, program, FMD_ADM_VERSION)) == NULL) 768 die(NULL); /* fmd_adm_errmsg() has enough info */ 769 770 while (iter < 0 || iter-- > 0) { 771 if (opt_s) 772 stat_mod_serd(opt_m); 773 else if (opt_T) 774 stat_xprt_auth(opt_m); 775 else if (opt_a || opt_m) 776 stat_mod(opt_m, opt_a, opt_z); 777 else if (opt_t) 778 stat_xprt(); 779 else 780 stat_fmd(); 781 782 if (iter != 0) { 783 (void) poll(NULL, 0, msec); 784 (void) putchar('\n'); 785 } 786 } 787 788 fmd_adm_close(g_adm); 789 return (FMSTAT_EXIT_SUCCESS); 790 } 791