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