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