xref: /illumos-gate/usr/src/cmd/fm/fmstat/common/fmstat.c (revision bbf21555)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
526fd7700SKrishnendu Sadhukhan - Sun Microsystems  * Common Development and Distribution License (the "License").
626fd7700SKrishnendu Sadhukhan - Sun Microsystems  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
21d9638e54Smws 
227c478bd9Sstevel@tonic-gate /*
2326fd7700SKrishnendu Sadhukhan - Sun Microsystems  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
27f1c3c469SJohn Levon /*
28f1c3c469SJohn Levon  * Copyright (c) 2018, Joyent, Inc.
29f1c3c469SJohn Levon  */
30f1c3c469SJohn Levon 
317c478bd9Sstevel@tonic-gate #include <fm/fmd_adm.h>
327c478bd9Sstevel@tonic-gate 
337c478bd9Sstevel@tonic-gate #include <strings.h>
347c478bd9Sstevel@tonic-gate #include <limits.h>
357c478bd9Sstevel@tonic-gate #include <stdlib.h>
367c478bd9Sstevel@tonic-gate #include <stdarg.h>
377c478bd9Sstevel@tonic-gate #include <stdio.h>
387c478bd9Sstevel@tonic-gate #include <errno.h>
397c478bd9Sstevel@tonic-gate #include <poll.h>
4026fd7700SKrishnendu Sadhukhan - Sun Microsystems #include <locale.h>
4126fd7700SKrishnendu Sadhukhan - Sun Microsystems 
4226fd7700SKrishnendu Sadhukhan - Sun Microsystems #include "statcommon.h"
437c478bd9Sstevel@tonic-gate 
447c478bd9Sstevel@tonic-gate #define	FMSTAT_EXIT_SUCCESS	0
457c478bd9Sstevel@tonic-gate #define	FMSTAT_EXIT_ERROR	1
467c478bd9Sstevel@tonic-gate #define	FMSTAT_EXIT_USAGE	2
477c478bd9Sstevel@tonic-gate 
487c478bd9Sstevel@tonic-gate static const struct stats {
49d9638e54Smws 	fmd_stat_t module;
50d9638e54Smws 	fmd_stat_t authority;
51d9638e54Smws 	fmd_stat_t state;
527c478bd9Sstevel@tonic-gate 	fmd_stat_t loadtime;
537c478bd9Sstevel@tonic-gate 	fmd_stat_t snaptime;
54d9638e54Smws 	fmd_stat_t received;
55d9638e54Smws 	fmd_stat_t discarded;
56d9638e54Smws 	fmd_stat_t retried;
57d9638e54Smws 	fmd_stat_t replayed;
58d9638e54Smws 	fmd_stat_t lost;
597c478bd9Sstevel@tonic-gate 	fmd_stat_t dispatched;
607c478bd9Sstevel@tonic-gate 	fmd_stat_t dequeued;
617c478bd9Sstevel@tonic-gate 	fmd_stat_t prdequeued;
627c478bd9Sstevel@tonic-gate 	fmd_stat_t accepted;
637c478bd9Sstevel@tonic-gate 	fmd_stat_t memtotal;
647c478bd9Sstevel@tonic-gate 	fmd_stat_t buftotal;
657c478bd9Sstevel@tonic-gate 	fmd_stat_t caseopen;
667c478bd9Sstevel@tonic-gate 	fmd_stat_t casesolved;
677c478bd9Sstevel@tonic-gate 	fmd_stat_t wcnt;
687c478bd9Sstevel@tonic-gate 	fmd_stat_t wtime;
697c478bd9Sstevel@tonic-gate 	fmd_stat_t wlentime;
707c478bd9Sstevel@tonic-gate 	fmd_stat_t wlastupdate;
717c478bd9Sstevel@tonic-gate 	fmd_stat_t dtime;
727c478bd9Sstevel@tonic-gate 	fmd_stat_t dlastupdate;
737c478bd9Sstevel@tonic-gate } stats_template = {
74d9638e54Smws 	{ "module", FMD_TYPE_STRING },
75d9638e54Smws 	{ "authority", FMD_TYPE_STRING },
76d9638e54Smws 	{ "state", FMD_TYPE_STRING },
77d9638e54Smws 	{ "loadtime", FMD_TYPE_TIME },
78d9638e54Smws 	{ "snaptime", FMD_TYPE_TIME },
79d9638e54Smws 	{ "received", FMD_TYPE_UINT64 },
80d9638e54Smws 	{ "discarded", FMD_TYPE_UINT64 },
81d9638e54Smws 	{ "retried", FMD_TYPE_UINT64 },
82d9638e54Smws 	{ "replayed", FMD_TYPE_UINT64 },
83d9638e54Smws 	{ "lost", FMD_TYPE_UINT64 },
84d9638e54Smws 	{ "dispatched", FMD_TYPE_UINT64 },
85d9638e54Smws 	{ "dequeued", FMD_TYPE_UINT64 },
86d9638e54Smws 	{ "prdequeued", FMD_TYPE_UINT64 },
87d9638e54Smws 	{ "accepted", FMD_TYPE_UINT64 },
88d9638e54Smws 	{ "memtotal", FMD_TYPE_SIZE },
89d9638e54Smws 	{ "buftotal", FMD_TYPE_SIZE },
90d9638e54Smws 	{ "caseopen", FMD_TYPE_UINT64 },
91d9638e54Smws 	{ "casesolved", FMD_TYPE_UINT64 },
92d9638e54Smws 	{ "wcnt", FMD_TYPE_UINT32 },
93d9638e54Smws 	{ "wtime", FMD_TYPE_TIME },
94d9638e54Smws 	{ "wlentime", FMD_TYPE_TIME },
95d9638e54Smws 	{ "wlastupdate", FMD_TYPE_TIME },
96d9638e54Smws 	{ "dtime", FMD_TYPE_TIME },
97d9638e54Smws 	{ "dlastupdate", FMD_TYPE_TIME },
987c478bd9Sstevel@tonic-gate };
997c478bd9Sstevel@tonic-gate 
1007c478bd9Sstevel@tonic-gate static const char *g_pname;
1017c478bd9Sstevel@tonic-gate static fmd_adm_t *g_adm;
1027c478bd9Sstevel@tonic-gate 
1037c478bd9Sstevel@tonic-gate static struct modstats {
1047c478bd9Sstevel@tonic-gate 	char *m_name;
1057c478bd9Sstevel@tonic-gate 	struct modstats *m_next;
1067c478bd9Sstevel@tonic-gate 	struct stats m_stbuf[2];
1077c478bd9Sstevel@tonic-gate 	int m_stidx;
108d9638e54Smws 	int m_id;
109d9638e54Smws 	struct stats *m_old;
110d9638e54Smws 	struct stats *m_new;
111d9638e54Smws 	double m_wait;
112d9638e54Smws 	double m_svc;
113d9638e54Smws 	double m_pct_b;
114d9638e54Smws 	double m_pct_w;
1157c478bd9Sstevel@tonic-gate } *g_mods;
1167c478bd9Sstevel@tonic-gate 
11726fd7700SKrishnendu Sadhukhan - Sun Microsystems static uint_t timestamp_fmt = NODATE;
11826fd7700SKrishnendu Sadhukhan - Sun Microsystems 
11926fd7700SKrishnendu Sadhukhan - Sun Microsystems #if !defined(TEXT_DOMAIN)		/* Should be defined by cc -D */
12026fd7700SKrishnendu Sadhukhan - Sun Microsystems #define	TEXT_DOMAIN "SYS_TEST"		/* Use this only if it isn't */
12126fd7700SKrishnendu Sadhukhan - Sun Microsystems #endif
12226fd7700SKrishnendu Sadhukhan - Sun Microsystems 
1237c478bd9Sstevel@tonic-gate static void
vwarn(const char * format,va_list ap)1247c478bd9Sstevel@tonic-gate vwarn(const char *format, va_list ap)
1257c478bd9Sstevel@tonic-gate {
1267c478bd9Sstevel@tonic-gate 	int err = errno;
1277c478bd9Sstevel@tonic-gate 
1287c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "%s: ", g_pname);
1297c478bd9Sstevel@tonic-gate 
1307c478bd9Sstevel@tonic-gate 	if (format != NULL)
1317c478bd9Sstevel@tonic-gate 		(void) vfprintf(stderr, format, ap);
1327c478bd9Sstevel@tonic-gate 
1337c478bd9Sstevel@tonic-gate 	errno = err; /* restore errno for fmd_adm_errmsg() */
1347c478bd9Sstevel@tonic-gate 
1357c478bd9Sstevel@tonic-gate 	if (format == NULL)
1367c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "%s\n", fmd_adm_errmsg(g_adm));
1377c478bd9Sstevel@tonic-gate 	else if (strchr(format, '\n') == NULL)
1387c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, ": %s\n", fmd_adm_errmsg(g_adm));
1397c478bd9Sstevel@tonic-gate }
1407c478bd9Sstevel@tonic-gate 
1417c478bd9Sstevel@tonic-gate /*PRINTFLIKE1*/
1427c478bd9Sstevel@tonic-gate void
warn(const char * format,...)1437c478bd9Sstevel@tonic-gate warn(const char *format, ...)
1447c478bd9Sstevel@tonic-gate {
1457c478bd9Sstevel@tonic-gate 	va_list ap;
1467c478bd9Sstevel@tonic-gate 
1477c478bd9Sstevel@tonic-gate 	va_start(ap, format);
1487c478bd9Sstevel@tonic-gate 	vwarn(format, ap);
1497c478bd9Sstevel@tonic-gate 	va_end(ap);
1507c478bd9Sstevel@tonic-gate }
1517c478bd9Sstevel@tonic-gate 
1527c478bd9Sstevel@tonic-gate /*PRINTFLIKE1*/
1537c478bd9Sstevel@tonic-gate void
die(const char * format,...)1547c478bd9Sstevel@tonic-gate die(const char *format, ...)
1557c478bd9Sstevel@tonic-gate {
1567c478bd9Sstevel@tonic-gate 	va_list ap;
1577c478bd9Sstevel@tonic-gate 
1587c478bd9Sstevel@tonic-gate 	va_start(ap, format);
1597c478bd9Sstevel@tonic-gate 	vwarn(format, ap);
1607c478bd9Sstevel@tonic-gate 	va_end(ap);
1617c478bd9Sstevel@tonic-gate 
1627c478bd9Sstevel@tonic-gate 	fmd_adm_close(g_adm);
1637c478bd9Sstevel@tonic-gate 	exit(FMSTAT_EXIT_ERROR);
1647c478bd9Sstevel@tonic-gate }
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate static char *
time2str(char * buf,size_t len,uint64_t time)1677c478bd9Sstevel@tonic-gate time2str(char *buf, size_t len, uint64_t time)
1687c478bd9Sstevel@tonic-gate {
1697c478bd9Sstevel@tonic-gate 	static const struct unit {
1707c478bd9Sstevel@tonic-gate 		const char *u_name;
1717c478bd9Sstevel@tonic-gate 		hrtime_t u_mul;
1727c478bd9Sstevel@tonic-gate 	} units[] = {
1737c478bd9Sstevel@tonic-gate 		{ "d",	NANOSEC * (hrtime_t)(24 * 60 * 60) },
1747c478bd9Sstevel@tonic-gate 		{ "h",	NANOSEC * (hrtime_t)(60 * 60) },
1757c478bd9Sstevel@tonic-gate 		{ "m",	NANOSEC * (hrtime_t)60 },
1767c478bd9Sstevel@tonic-gate 		{ "s",	NANOSEC / SEC },
1777c478bd9Sstevel@tonic-gate 		{ "ms",	NANOSEC / MILLISEC },
1787c478bd9Sstevel@tonic-gate 		{ "us",	NANOSEC / MICROSEC },
1797c478bd9Sstevel@tonic-gate 		{ "ns",	NANOSEC / NANOSEC },
1807c478bd9Sstevel@tonic-gate 	};
1817c478bd9Sstevel@tonic-gate 
1827c478bd9Sstevel@tonic-gate 	const struct unit *up;
1837c478bd9Sstevel@tonic-gate 
1847c478bd9Sstevel@tonic-gate 	for (up = units; time % up->u_mul != 0; up++)
1857c478bd9Sstevel@tonic-gate 		continue; /* find largest unit of which 'time' is a multiple */
1867c478bd9Sstevel@tonic-gate 
1877c478bd9Sstevel@tonic-gate 	(void) snprintf(buf, len, "%llu%s", time / up->u_mul, up->u_name);
1887c478bd9Sstevel@tonic-gate 	return (buf);
1897c478bd9Sstevel@tonic-gate }
1907c478bd9Sstevel@tonic-gate 
1917c478bd9Sstevel@tonic-gate static char *
size2str(char * buf,size_t len,uint64_t size)1927c478bd9Sstevel@tonic-gate size2str(char *buf, size_t len, uint64_t size)
1937c478bd9Sstevel@tonic-gate {
1947c478bd9Sstevel@tonic-gate 	static const char units[] = "bKMGTPE";
1957c478bd9Sstevel@tonic-gate 	const uint64_t scale = 1024;
1967c478bd9Sstevel@tonic-gate 	const char *up = units;
1977c478bd9Sstevel@tonic-gate 	uint64_t osize = 0;
1987c478bd9Sstevel@tonic-gate 
1997c478bd9Sstevel@tonic-gate 	/*
2007c478bd9Sstevel@tonic-gate 	 * Convert the input size to a round number of the appropriately
2017c478bd9Sstevel@tonic-gate 	 * scaled units (saved in 'size') and a remainder (saved in 'osize').
2027c478bd9Sstevel@tonic-gate 	 */
2037c478bd9Sstevel@tonic-gate 	while (size >= scale && up < (units + sizeof (units) - 2)) {
2047c478bd9Sstevel@tonic-gate 		up++;
2057c478bd9Sstevel@tonic-gate 		osize = size;
2067c478bd9Sstevel@tonic-gate 		size = (size + (scale / 2)) / scale;
2077c478bd9Sstevel@tonic-gate 	}
2087c478bd9Sstevel@tonic-gate 
2097c478bd9Sstevel@tonic-gate 	/*
2107c478bd9Sstevel@tonic-gate 	 * Format the result using at most one decimal place and the unit
2117c478bd9Sstevel@tonic-gate 	 * depending upon the amount of remainder (same as df -h algorithm).
2127c478bd9Sstevel@tonic-gate 	 */
2137c478bd9Sstevel@tonic-gate 	if (osize != 0 && (osize / scale) < 10)
2147c478bd9Sstevel@tonic-gate 		(void) snprintf(buf, len, "%.1f%c", (float)osize / scale, *up);
2157c478bd9Sstevel@tonic-gate 	else if (size != 0)
2167c478bd9Sstevel@tonic-gate 		(void) snprintf(buf, len, "%llu%c", size, *up);
2177c478bd9Sstevel@tonic-gate 	else
2187c478bd9Sstevel@tonic-gate 		(void) snprintf(buf, len, "0");
2197c478bd9Sstevel@tonic-gate 
2207c478bd9Sstevel@tonic-gate 	return (buf);
2217c478bd9Sstevel@tonic-gate }
2227c478bd9Sstevel@tonic-gate 
2237c478bd9Sstevel@tonic-gate static uint64_t
u64delta(uint64_t old,uint64_t new)2247c478bd9Sstevel@tonic-gate u64delta(uint64_t old, uint64_t new)
2257c478bd9Sstevel@tonic-gate {
2267c478bd9Sstevel@tonic-gate 	return (new >= old ? (new - old) : ((UINT64_MAX - old) + new + 1));
2277c478bd9Sstevel@tonic-gate }
2287c478bd9Sstevel@tonic-gate 
229d9638e54Smws static struct modstats *
modstat_create(const char * name,id_t id)230d9638e54Smws modstat_create(const char *name, id_t id)
2317c478bd9Sstevel@tonic-gate {
232d9638e54Smws 	struct modstats *mp = malloc(sizeof (struct modstats));
2337c478bd9Sstevel@tonic-gate 
234d9638e54Smws 	if (mp == NULL)
235d9638e54Smws 		return (NULL);
2367c478bd9Sstevel@tonic-gate 
237d9638e54Smws 	bzero(mp, sizeof (struct modstats));
2387c478bd9Sstevel@tonic-gate 
239d9638e54Smws 	if (name != NULL && (mp->m_name = strdup(name)) == NULL) {
240d9638e54Smws 		free(mp);
241d9638e54Smws 		return (NULL);
2427c478bd9Sstevel@tonic-gate 	}
2437c478bd9Sstevel@tonic-gate 
244d9638e54Smws 	mp->m_id = id;
245d9638e54Smws 	mp->m_next = g_mods;
246d9638e54Smws 	g_mods = mp;
247d9638e54Smws 	return (mp);
248d9638e54Smws }
2497c478bd9Sstevel@tonic-gate 
250d9638e54Smws /*
251d9638e54Smws  * Given a statistics buffer containing event queue statistics, compute the
252d9638e54Smws  * common queue statistics for the given module and store the results in 'mp'.
253d9638e54Smws  * We set m_new and m_old for the caller, and store the compute values of
254d9638e54Smws  * m_svc, m_wait, m_pct_w, and m_pct_b there as well.  The caller must not free
255d9638e54Smws  * 'ams' until after using the results as m_new may contain pointers to it.
256d9638e54Smws  */
257d9638e54Smws static void
modstat_compute(struct modstats * mp,fmd_adm_stats_t * ams)258d9638e54Smws modstat_compute(struct modstats *mp, fmd_adm_stats_t *ams)
259d9638e54Smws {
260d9638e54Smws 	static fmd_stat_t *t_beg = (fmd_stat_t *)(&stats_template + 0);
261d9638e54Smws 	static fmd_stat_t *t_end = (fmd_stat_t *)(&stats_template + 1);
2627c478bd9Sstevel@tonic-gate 
263d9638e54Smws 	struct stats *old, *new;
264d9638e54Smws 	fmd_stat_t *tsp, *nsp, *sp;
265d9638e54Smws 	double elapsed, avg_w, avg_d;
266d9638e54Smws 	uint64_t delta;
2677c478bd9Sstevel@tonic-gate 
268d9638e54Smws 	old = mp->m_old = &mp->m_stbuf[mp->m_stidx];
2697c478bd9Sstevel@tonic-gate 	mp->m_stidx = 1 - mp->m_stidx;
270d9638e54Smws 	new = mp->m_new = &mp->m_stbuf[mp->m_stidx];
2717c478bd9Sstevel@tonic-gate 
2727c478bd9Sstevel@tonic-gate 	/*
2737c478bd9Sstevel@tonic-gate 	 * The statistics can come in any order; we compare each one to the
2747c478bd9Sstevel@tonic-gate 	 * template of statistics of interest, find the matching ones, and copy
2757c478bd9Sstevel@tonic-gate 	 * their values into the appropriate slot of the 'new' stats.
2767c478bd9Sstevel@tonic-gate 	 */
277d9638e54Smws 	for (nsp = ams->ams_buf; nsp < ams->ams_buf + ams->ams_len; nsp++) {
2787c478bd9Sstevel@tonic-gate 		for (tsp = t_beg; tsp < t_end; tsp++) {
279d9638e54Smws 			const char *p = strrchr(nsp->fmds_name, '.');
280d9638e54Smws 
281d9638e54Smws 			/*
282d9638e54Smws 			 * The fmd queue stats can either be named fmd.<name>
283d9638e54Smws 			 * or fmd.xprt.%u.<name> depending on whether we're
284d9638e54Smws 			 * looking at the module queue or the transport queue.
285d9638e54Smws 			 * So we match using the patterns fmd.* and *.<name>
286d9638e54Smws 			 * and store only the value of <name> in stats_template.
287d9638e54Smws 			 */
288d9638e54Smws 			if (p == NULL || strcmp(p + 1, tsp->fmds_name) != 0 ||
289d9638e54Smws 			    strncmp(nsp->fmds_name, "fmd.", 4) != 0)
290d9638e54Smws 				continue; /* continue until we match the stat */
2917c478bd9Sstevel@tonic-gate 
2927c478bd9Sstevel@tonic-gate 			if (tsp->fmds_type != nsp->fmds_type) {
2937c478bd9Sstevel@tonic-gate 				warn("%s has unexpected type (%u != %u)\n",
294d9638e54Smws 				    nsp->fmds_name, tsp->fmds_type,
2957c478bd9Sstevel@tonic-gate 				    nsp->fmds_type);
2967c478bd9Sstevel@tonic-gate 			} else {
2977c478bd9Sstevel@tonic-gate 				sp = (fmd_stat_t *)new + (tsp - t_beg);
2987c478bd9Sstevel@tonic-gate 				sp->fmds_value = nsp->fmds_value;
2997c478bd9Sstevel@tonic-gate 			}
3007c478bd9Sstevel@tonic-gate 		}
3017c478bd9Sstevel@tonic-gate 	}
3027c478bd9Sstevel@tonic-gate 
3037c478bd9Sstevel@tonic-gate 	/*
3047c478bd9Sstevel@tonic-gate 	 * Compute the elapsed time by taking the delta between 'snaptime', or
3057c478bd9Sstevel@tonic-gate 	 * or between snaptime and loadtime if there is no previous snapshot.
3067c478bd9Sstevel@tonic-gate 	 * If delta is zero, set it to 1sec so we don't divide by zero later.
3077c478bd9Sstevel@tonic-gate 	 */
3087c478bd9Sstevel@tonic-gate 	delta = u64delta(old->snaptime.fmds_value.ui64 ?
3097c478bd9Sstevel@tonic-gate 	    old->snaptime.fmds_value.ui64 : old->loadtime.fmds_value.ui64,
3107c478bd9Sstevel@tonic-gate 	    new->snaptime.fmds_value.ui64);
3117c478bd9Sstevel@tonic-gate 
3127c478bd9Sstevel@tonic-gate 	elapsed = delta ? (double)delta : (double)NANOSEC;
3137c478bd9Sstevel@tonic-gate 
3147c478bd9Sstevel@tonic-gate 	/*
3157c478bd9Sstevel@tonic-gate 	 * Compute average wait queue len by taking the delta in the wait queue
3167c478bd9Sstevel@tonic-gate 	 * len * time products (wlentime stat) and dividing by the elapsed time.
3177c478bd9Sstevel@tonic-gate 	 */
3187c478bd9Sstevel@tonic-gate 	delta = u64delta(old->wlentime.fmds_value.ui64,
3197c478bd9Sstevel@tonic-gate 	    new->wlentime.fmds_value.ui64);
3207c478bd9Sstevel@tonic-gate 
3217c478bd9Sstevel@tonic-gate 	if (delta != 0)
322d9638e54Smws 		mp->m_wait = (double)delta / elapsed;
3237c478bd9Sstevel@tonic-gate 	else
324d9638e54Smws 		mp->m_wait = 0.0;
3257c478bd9Sstevel@tonic-gate 
3267c478bd9Sstevel@tonic-gate 	/*
3277c478bd9Sstevel@tonic-gate 	 * Compute average wait time by taking the delta in the wait queue time
3287c478bd9Sstevel@tonic-gate 	 * (wtime) and dividing by the delta in the number of dispatches.
3297c478bd9Sstevel@tonic-gate 	 */
3307c478bd9Sstevel@tonic-gate 	delta = u64delta(old->dispatched.fmds_value.ui64,
3317c478bd9Sstevel@tonic-gate 	    new->dispatched.fmds_value.ui64);
3327c478bd9Sstevel@tonic-gate 
3337c478bd9Sstevel@tonic-gate 	if (delta != 0) {
3347c478bd9Sstevel@tonic-gate 		avg_w = (double)u64delta(old->wtime.fmds_value.ui64,
3357c478bd9Sstevel@tonic-gate 		    new->wtime.fmds_value.ui64) / (double)delta;
3367c478bd9Sstevel@tonic-gate 	} else
3377c478bd9Sstevel@tonic-gate 		avg_w = 0.0;
3387c478bd9Sstevel@tonic-gate 
3397c478bd9Sstevel@tonic-gate 	/*
3407c478bd9Sstevel@tonic-gate 	 * Compute average dispatch time by taking the delta in the dispatch
3417c478bd9Sstevel@tonic-gate 	 * time (dtime) and dividing by the delta in the number of dequeues.
3427c478bd9Sstevel@tonic-gate 	 */
3437c478bd9Sstevel@tonic-gate 	delta = u64delta(old->dequeued.fmds_value.ui64,
3447c478bd9Sstevel@tonic-gate 	    new->dequeued.fmds_value.ui64);
3457c478bd9Sstevel@tonic-gate 
3467c478bd9Sstevel@tonic-gate 	if (delta != 0) {
3477c478bd9Sstevel@tonic-gate 		avg_d = (double)u64delta(old->dtime.fmds_value.ui64,
3487c478bd9Sstevel@tonic-gate 		    new->dtime.fmds_value.ui64) / (double)delta;
3497c478bd9Sstevel@tonic-gate 	} else
3507c478bd9Sstevel@tonic-gate 		avg_d = 0.0;
3517c478bd9Sstevel@tonic-gate 
3527c478bd9Sstevel@tonic-gate 	/*
3537c478bd9Sstevel@tonic-gate 	 * Finally compute the average overall service time by adding together
3547c478bd9Sstevel@tonic-gate 	 * the average wait and dispatch times and converting to milliseconds.
3557c478bd9Sstevel@tonic-gate 	 */
356d9638e54Smws 	mp->m_svc = ((avg_w + avg_d) * (double)MILLISEC) / (double)NANOSEC;
3577c478bd9Sstevel@tonic-gate 
3587c478bd9Sstevel@tonic-gate 	/*
3597c478bd9Sstevel@tonic-gate 	 * Compute the %wait and %busy times by taking the delta in wait and
3607c478bd9Sstevel@tonic-gate 	 * busy times, dividing by the elapsed time, and multiplying by 100.
3617c478bd9Sstevel@tonic-gate 	 */
3627c478bd9Sstevel@tonic-gate 	delta = u64delta(old->wtime.fmds_value.ui64,
3637c478bd9Sstevel@tonic-gate 	    new->wtime.fmds_value.ui64);
3647c478bd9Sstevel@tonic-gate 
3657c478bd9Sstevel@tonic-gate 	if (delta != 0)
366d9638e54Smws 		mp->m_pct_w = ((double)delta / elapsed) * 100.0;
3677c478bd9Sstevel@tonic-gate 	else
368d9638e54Smws 		mp->m_pct_w = 0.0;
3697c478bd9Sstevel@tonic-gate 
3707c478bd9Sstevel@tonic-gate 	delta = u64delta(old->dtime.fmds_value.ui64,
3717c478bd9Sstevel@tonic-gate 	    new->dtime.fmds_value.ui64);
3727c478bd9Sstevel@tonic-gate 
3737c478bd9Sstevel@tonic-gate 	if (delta != 0)
374d9638e54Smws 		mp->m_pct_b = ((double)delta / elapsed) * 100.0;
3757c478bd9Sstevel@tonic-gate 	else
376d9638e54Smws 		mp->m_pct_b = 0.0;
377d9638e54Smws }
378d9638e54Smws 
379d9638e54Smws /*ARGSUSED*/
380f1c3c469SJohn Levon static void
stat_one_xprt(id_t id,void * ignored)381d9638e54Smws stat_one_xprt(id_t id, void *ignored)
382d9638e54Smws {
383d9638e54Smws 	fmd_adm_stats_t ams;
384d9638e54Smws 	struct modstats *mp;
385d9638e54Smws 
386d9638e54Smws 	if (fmd_adm_xprt_stats(g_adm, id, &ams) != 0) {
387d9638e54Smws 		warn("failed to retrieve statistics for transport %d", (int)id);
388f1c3c469SJohn Levon 		return;
389d9638e54Smws 	}
390d9638e54Smws 
391d9638e54Smws 	for (mp = g_mods; mp != NULL; mp = mp->m_next) {
392d9638e54Smws 		if (mp->m_id == id)
393d9638e54Smws 			break;
394d9638e54Smws 	}
395d9638e54Smws 
396d9638e54Smws 	if (mp == NULL && (mp = modstat_create(NULL, id)) == NULL) {
397d9638e54Smws 		warn("failed to allocate memory for transport %d", (int)id);
398d9638e54Smws 		(void) fmd_adm_stats_free(g_adm, &ams);
399f1c3c469SJohn Levon 		return;
400d9638e54Smws 	}
401d9638e54Smws 
402d9638e54Smws 	modstat_compute(mp, &ams);
403d9638e54Smws 
404d9638e54Smws 	(void) printf("%3d %5s %7llu %7llu %7llu %7llu "
405d9638e54Smws 	    "%4.1f %6.1f %3.0f %3.0f %s\n", (int)id,
406d9638e54Smws 	    mp->m_new->state.fmds_value.str,
407d9638e54Smws 	    u64delta(mp->m_old->prdequeued.fmds_value.ui64,
408d9638e54Smws 	    mp->m_new->prdequeued.fmds_value.ui64),
409d9638e54Smws 	    u64delta(mp->m_old->received.fmds_value.ui64,
410d9638e54Smws 	    mp->m_new->received.fmds_value.ui64),
411d9638e54Smws 	    u64delta(mp->m_old->discarded.fmds_value.ui64,
412d9638e54Smws 	    mp->m_new->discarded.fmds_value.ui64),
413d9638e54Smws 	    u64delta(mp->m_old->lost.fmds_value.ui64,
414d9638e54Smws 	    mp->m_new->lost.fmds_value.ui64),
415d9638e54Smws 	    mp->m_wait, mp->m_svc, mp->m_pct_w, mp->m_pct_b,
416d9638e54Smws 	    mp->m_new->module.fmds_value.str);
417d9638e54Smws 
418d9638e54Smws 	(void) fmd_adm_stats_free(g_adm, &ams);
419d9638e54Smws }
420d9638e54Smws 
421d9638e54Smws static void
stat_xprt(void)422d9638e54Smws stat_xprt(void)
423d9638e54Smws {
424d9638e54Smws 	(void) printf("%3s %5s %7s %7s %7s %7s %4s %6s %3s %3s %s\n",
425d9638e54Smws 	    "id", "state", "ev_send", "ev_recv", "ev_drop", "ev_lost",
426d9638e54Smws 	    "wait", "svc_t", "%w", "%b", "module");
427d9638e54Smws 
428d9638e54Smws 	if (fmd_adm_xprt_iter(g_adm, stat_one_xprt, NULL) != 0)
429d9638e54Smws 		die("failed to retrieve list of transports");
430d9638e54Smws }
431d9638e54Smws 
432f1c3c469SJohn Levon static void
stat_one_xprt_auth(id_t id,void * arg)433d9638e54Smws stat_one_xprt_auth(id_t id, void *arg)
434d9638e54Smws {
435d9638e54Smws 	const char *module = arg;
436d9638e54Smws 	fmd_adm_stats_t ams;
437d9638e54Smws 	struct modstats *mp;
438d9638e54Smws 
439d9638e54Smws 	if (fmd_adm_xprt_stats(g_adm, id, &ams) != 0) {
440d9638e54Smws 		warn("failed to retrieve statistics for transport %d", (int)id);
441f1c3c469SJohn Levon 		return;
442d9638e54Smws 	}
443d9638e54Smws 
444d9638e54Smws 	for (mp = g_mods; mp != NULL; mp = mp->m_next) {
445d9638e54Smws 		if (mp->m_id == id)
446d9638e54Smws 			break;
447d9638e54Smws 	}
448d9638e54Smws 
449d9638e54Smws 	if (mp == NULL && (mp = modstat_create(NULL, id)) == NULL) {
450d9638e54Smws 		warn("failed to allocate memory for transport %d", (int)id);
451d9638e54Smws 		(void) fmd_adm_stats_free(g_adm, &ams);
452f1c3c469SJohn Levon 		return;
453d9638e54Smws 	}
454d9638e54Smws 
455d9638e54Smws 	modstat_compute(mp, &ams);
456d9638e54Smws 
457d9638e54Smws 	if (module == NULL ||
458d9638e54Smws 	    strcmp(module, mp->m_new->module.fmds_value.str) == 0) {
459d9638e54Smws 		(void) printf("%3d %5s %-18s  %s\n", (int)id,
460d9638e54Smws 		    mp->m_new->state.fmds_value.str,
461d9638e54Smws 		    mp->m_new->module.fmds_value.str,
462d9638e54Smws 		    mp->m_new->authority.fmds_value.str ?
463d9638e54Smws 		    mp->m_new->authority.fmds_value.str : "-");
464d9638e54Smws 	}
465d9638e54Smws 
466d9638e54Smws 	(void) fmd_adm_stats_free(g_adm, &ams);
467d9638e54Smws }
468d9638e54Smws 
469d9638e54Smws static void
stat_xprt_auth(const char * module)470d9638e54Smws stat_xprt_auth(const char *module)
471d9638e54Smws {
472d9638e54Smws 	(void) printf("%3s %5s %-18s  %s\n",
473d9638e54Smws 	    "id", "state", "module", "authority");
474d9638e54Smws 
475d9638e54Smws 	if (fmd_adm_xprt_iter(g_adm, stat_one_xprt_auth, (void *)module) != 0)
476d9638e54Smws 		die("failed to retrieve list of transports");
477d9638e54Smws }
478d9638e54Smws 
479d9638e54Smws /*ARGSUSED*/
480d9638e54Smws static int
stat_one_fmd(const fmd_adm_modinfo_t * ami,void * ignored)481d9638e54Smws stat_one_fmd(const fmd_adm_modinfo_t *ami, void *ignored)
482d9638e54Smws {
483d9638e54Smws 	char memsz[8], bufsz[8];
484d9638e54Smws 	fmd_adm_stats_t ams;
485d9638e54Smws 	struct modstats *mp;
486d9638e54Smws 
487d9638e54Smws 	if (fmd_adm_module_stats(g_adm, ami->ami_name, &ams) != 0) {
488d9638e54Smws 		warn("failed to retrieve statistics for %s", ami->ami_name);
489d9638e54Smws 		return (0); /* continue on to the next module */
490d9638e54Smws 	}
491d9638e54Smws 
492d9638e54Smws 	for (mp = g_mods; mp != NULL; mp = mp->m_next) {
493d9638e54Smws 		if (strcmp(mp->m_name, ami->ami_name) == 0)
494d9638e54Smws 			break;
495d9638e54Smws 	}
496d9638e54Smws 
497d9638e54Smws 	if (mp == NULL && (mp = modstat_create(ami->ami_name, 0)) == NULL) {
498d9638e54Smws 		warn("failed to allocate memory for %s", ami->ami_name);
499d9638e54Smws 		(void) fmd_adm_stats_free(g_adm, &ams);
500d9638e54Smws 		return (0);
501d9638e54Smws 	}
502d9638e54Smws 
503d9638e54Smws 	modstat_compute(mp, &ams);
5047c478bd9Sstevel@tonic-gate 
5057c478bd9Sstevel@tonic-gate 	(void) printf("%-18s %7llu %7llu %4.1f %6.1f %3.0f %3.0f "
5067c478bd9Sstevel@tonic-gate 	    "%5llu %5llu %6s %6s\n", ami->ami_name,
507d9638e54Smws 	    u64delta(mp->m_old->prdequeued.fmds_value.ui64,
508d9638e54Smws 	    mp->m_new->prdequeued.fmds_value.ui64),
509d9638e54Smws 	    u64delta(mp->m_old->accepted.fmds_value.ui64,
510d9638e54Smws 	    mp->m_new->accepted.fmds_value.ui64),
511d9638e54Smws 	    mp->m_wait, mp->m_svc, mp->m_pct_w, mp->m_pct_b,
512d9638e54Smws 	    mp->m_new->caseopen.fmds_value.ui64,
513d9638e54Smws 	    mp->m_new->casesolved.fmds_value.ui64,
514d9638e54Smws 	    size2str(memsz, sizeof (memsz),
515d9638e54Smws 	    mp->m_new->memtotal.fmds_value.ui64),
516d9638e54Smws 	    size2str(bufsz, sizeof (bufsz),
517d9638e54Smws 	    mp->m_new->buftotal.fmds_value.ui64));
5187c478bd9Sstevel@tonic-gate 
5197c478bd9Sstevel@tonic-gate 	(void) fmd_adm_stats_free(g_adm, &ams);
5207c478bd9Sstevel@tonic-gate 	return (0);
5217c478bd9Sstevel@tonic-gate }
5227c478bd9Sstevel@tonic-gate 
5237c478bd9Sstevel@tonic-gate static void
stat_fmd(void)5247c478bd9Sstevel@tonic-gate stat_fmd(void)
5257c478bd9Sstevel@tonic-gate {
5267c478bd9Sstevel@tonic-gate 	(void) printf("%-18s %7s %7s %4s %6s %3s %3s %5s %5s %6s %6s\n",
5277c478bd9Sstevel@tonic-gate 	    "module", "ev_recv", "ev_acpt", "wait", "svc_t", "%w", "%b",
5287c478bd9Sstevel@tonic-gate 	    "open", "solve", "memsz", "bufsz");
5297c478bd9Sstevel@tonic-gate 
5307c478bd9Sstevel@tonic-gate 	if (fmd_adm_module_iter(g_adm, stat_one_fmd, NULL) != 0)
5317c478bd9Sstevel@tonic-gate 		die("failed to retrieve list of modules");
5327c478bd9Sstevel@tonic-gate }
5337c478bd9Sstevel@tonic-gate 
5347c478bd9Sstevel@tonic-gate static void
stat_mod(const char * name,int aflag,int zflag)5357c478bd9Sstevel@tonic-gate stat_mod(const char *name, int aflag, int zflag)
5367c478bd9Sstevel@tonic-gate {
5377c478bd9Sstevel@tonic-gate 	fmd_adm_stats_t ams;
5387c478bd9Sstevel@tonic-gate 	fmd_stat_t *sp;
5397c478bd9Sstevel@tonic-gate 	char buf[64];
5407c478bd9Sstevel@tonic-gate 
5417c478bd9Sstevel@tonic-gate 	if (fmd_adm_stats_read(g_adm, name, &ams) != 0) {
5427c478bd9Sstevel@tonic-gate 		die("failed to retrieve statistics for %s",
543*bbf21555SRichard Lowe 		    name ? name : "fmd(8)");
5447c478bd9Sstevel@tonic-gate 	}
5457c478bd9Sstevel@tonic-gate 
5467c478bd9Sstevel@tonic-gate 	(void) printf("%20s %-16s %s\n", "NAME", "VALUE", "DESCRIPTION");
5477c478bd9Sstevel@tonic-gate 
5487c478bd9Sstevel@tonic-gate 	for (sp = ams.ams_buf; sp < ams.ams_buf + ams.ams_len; sp++) {
5497c478bd9Sstevel@tonic-gate 		if (aflag == 0 && strncmp(sp->fmds_name, "fmd.", 4) == 0)
5507c478bd9Sstevel@tonic-gate 			continue; /* skip fmd-internal stats unless -a used */
5517c478bd9Sstevel@tonic-gate 
5527c478bd9Sstevel@tonic-gate 		if (zflag) {
5537c478bd9Sstevel@tonic-gate 			switch (sp->fmds_type) {
5547c478bd9Sstevel@tonic-gate 			case FMD_TYPE_INT32:
5557c478bd9Sstevel@tonic-gate 			case FMD_TYPE_UINT32:
5567c478bd9Sstevel@tonic-gate 				if (sp->fmds_value.ui32 == 0)
5577c478bd9Sstevel@tonic-gate 					continue;
5587c478bd9Sstevel@tonic-gate 				break;
5597c478bd9Sstevel@tonic-gate 			case FMD_TYPE_INT64:
5607c478bd9Sstevel@tonic-gate 			case FMD_TYPE_UINT64:
5617c478bd9Sstevel@tonic-gate 			case FMD_TYPE_TIME:
5627c478bd9Sstevel@tonic-gate 			case FMD_TYPE_SIZE:
5637c478bd9Sstevel@tonic-gate 				if (sp->fmds_value.ui64 == 0)
5647c478bd9Sstevel@tonic-gate 					continue;
5657c478bd9Sstevel@tonic-gate 				break;
5667c478bd9Sstevel@tonic-gate 			case FMD_TYPE_STRING:
5677c478bd9Sstevel@tonic-gate 				if (sp->fmds_value.str == NULL ||
5687c478bd9Sstevel@tonic-gate 				    sp->fmds_value.str[0] == '\0')
5697c478bd9Sstevel@tonic-gate 					continue;
5707c478bd9Sstevel@tonic-gate 				break;
5717c478bd9Sstevel@tonic-gate 			}
5727c478bd9Sstevel@tonic-gate 		}
5737c478bd9Sstevel@tonic-gate 
5747c478bd9Sstevel@tonic-gate 		(void) printf("%20s ", sp->fmds_name);
5757c478bd9Sstevel@tonic-gate 
5767c478bd9Sstevel@tonic-gate 		switch (sp->fmds_type) {
5777c478bd9Sstevel@tonic-gate 		case FMD_TYPE_BOOL:
5787c478bd9Sstevel@tonic-gate 			(void) printf("%-16s",
5797c478bd9Sstevel@tonic-gate 			    sp->fmds_value.bool ? "true" : "false");
5807c478bd9Sstevel@tonic-gate 			break;
5817c478bd9Sstevel@tonic-gate 		case FMD_TYPE_INT32:
5827c478bd9Sstevel@tonic-gate 			(void) printf("%-16d", sp->fmds_value.i32);
5837c478bd9Sstevel@tonic-gate 			break;
5847c478bd9Sstevel@tonic-gate 		case FMD_TYPE_UINT32:
5857c478bd9Sstevel@tonic-gate 			(void) printf("%-16u", sp->fmds_value.ui32);
5867c478bd9Sstevel@tonic-gate 			break;
5877c478bd9Sstevel@tonic-gate 		case FMD_TYPE_INT64:
5887c478bd9Sstevel@tonic-gate 			(void) printf("%-16lld", sp->fmds_value.i64);
5897c478bd9Sstevel@tonic-gate 			break;
5907c478bd9Sstevel@tonic-gate 		case FMD_TYPE_UINT64:
5917c478bd9Sstevel@tonic-gate 			(void) printf("%-16llu", sp->fmds_value.ui64);
5927c478bd9Sstevel@tonic-gate 			break;
5937c478bd9Sstevel@tonic-gate 		case FMD_TYPE_STRING:
5947c478bd9Sstevel@tonic-gate 			(void) printf("%-16s", sp->fmds_value.str ?
5957c478bd9Sstevel@tonic-gate 			    sp->fmds_value.str : "<<null>>");
5967c478bd9Sstevel@tonic-gate 			break;
5977c478bd9Sstevel@tonic-gate 		case FMD_TYPE_TIME:
5987c478bd9Sstevel@tonic-gate 			(void) printf("%-16s",
5997c478bd9Sstevel@tonic-gate 			    time2str(buf, sizeof (buf), sp->fmds_value.ui64));
6007c478bd9Sstevel@tonic-gate 			break;
6017c478bd9Sstevel@tonic-gate 		case FMD_TYPE_SIZE:
6027c478bd9Sstevel@tonic-gate 			(void) printf("%-16s",
6037c478bd9Sstevel@tonic-gate 			    size2str(buf, sizeof (buf), sp->fmds_value.ui64));
6047c478bd9Sstevel@tonic-gate 			break;
6057c478bd9Sstevel@tonic-gate 		default:
6067c478bd9Sstevel@tonic-gate 			(void) snprintf(buf, sizeof (buf),
6077c478bd9Sstevel@tonic-gate 			    "<<type=%u>>\n", sp->fmds_type);
6087c478bd9Sstevel@tonic-gate 			(void) printf("%-16s", buf);
6097c478bd9Sstevel@tonic-gate 		}
6107c478bd9Sstevel@tonic-gate 
6117c478bd9Sstevel@tonic-gate 		(void) printf(" %s\n", sp->fmds_desc);
6127c478bd9Sstevel@tonic-gate 	}
6137c478bd9Sstevel@tonic-gate 
6147c478bd9Sstevel@tonic-gate 	(void) fmd_adm_stats_free(g_adm, &ams);
6157c478bd9Sstevel@tonic-gate }
6167c478bd9Sstevel@tonic-gate 
6177c478bd9Sstevel@tonic-gate /*ARGSUSED*/
6187c478bd9Sstevel@tonic-gate static int
stat_one_serd(const fmd_adm_serdinfo_t * asi,void * ignored)6197c478bd9Sstevel@tonic-gate stat_one_serd(const fmd_adm_serdinfo_t *asi, void *ignored)
6207c478bd9Sstevel@tonic-gate {
6217c478bd9Sstevel@tonic-gate 	char buf1[32], buf2[32], n[32];
6227c478bd9Sstevel@tonic-gate 
6237c478bd9Sstevel@tonic-gate 	(void) snprintf(n, sizeof (n), ">%llu", asi->asi_n);
6247c478bd9Sstevel@tonic-gate 
6257c478bd9Sstevel@tonic-gate 	(void) printf("%-36s %3s %5s %3u %24s %s\n",
6267c478bd9Sstevel@tonic-gate 	    asi->asi_name, n, time2str(buf1, sizeof (buf1), asi->asi_t),
6277c478bd9Sstevel@tonic-gate 	    asi->asi_count, time2str(buf2, sizeof (buf2), asi->asi_delta),
6287c478bd9Sstevel@tonic-gate 	    (asi->asi_flags & FMD_ADM_SERD_FIRED) ? "fire" : "pend");
6297c478bd9Sstevel@tonic-gate 
6307c478bd9Sstevel@tonic-gate 	return (0);
6317c478bd9Sstevel@tonic-gate }
6327c478bd9Sstevel@tonic-gate 
6337c478bd9Sstevel@tonic-gate static void
stat_mod_serd(const char * name)6347c478bd9Sstevel@tonic-gate stat_mod_serd(const char *name)
6357c478bd9Sstevel@tonic-gate {
6367c478bd9Sstevel@tonic-gate 	(void) printf("%-36s %3s %5s %3s %24s %4s\n",
6377c478bd9Sstevel@tonic-gate 	    "NAME", ">N", "T", "CNT", "DELTA", "STAT");
6387c478bd9Sstevel@tonic-gate 
6397c478bd9Sstevel@tonic-gate 	if (fmd_adm_serd_iter(g_adm, name, stat_one_serd, NULL) != 0)
6407c478bd9Sstevel@tonic-gate 		die("failed to retrieve serd engines for %s", name);
6417c478bd9Sstevel@tonic-gate }
6427c478bd9Sstevel@tonic-gate 
6437c478bd9Sstevel@tonic-gate static int
getint(const char * name,const char * s)6447c478bd9Sstevel@tonic-gate getint(const char *name, const char *s)
6457c478bd9Sstevel@tonic-gate {
6467c478bd9Sstevel@tonic-gate 	long val;
6477c478bd9Sstevel@tonic-gate 	char *p;
6487c478bd9Sstevel@tonic-gate 
6497c478bd9Sstevel@tonic-gate 	errno = 0;
6507c478bd9Sstevel@tonic-gate 	val = strtol(s, &p, 10);
6517c478bd9Sstevel@tonic-gate 
6527c478bd9Sstevel@tonic-gate 	if (errno != 0 || p == s || *p != '\0' || val < 0 || val > INT_MAX) {
6537c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "%s: invalid %s argument -- %s\n",
6547c478bd9Sstevel@tonic-gate 		    g_pname, name, s);
6557c478bd9Sstevel@tonic-gate 		exit(FMSTAT_EXIT_USAGE);
6567c478bd9Sstevel@tonic-gate 	}
6577c478bd9Sstevel@tonic-gate 
6587c478bd9Sstevel@tonic-gate 	return ((int)val);
6597c478bd9Sstevel@tonic-gate }
6607c478bd9Sstevel@tonic-gate 
6617c478bd9Sstevel@tonic-gate static uint32_t
getu32(const char * name,const char * s)6627c478bd9Sstevel@tonic-gate getu32(const char *name, const char *s)
6637c478bd9Sstevel@tonic-gate {
6647c478bd9Sstevel@tonic-gate 	u_longlong_t val;
6657c478bd9Sstevel@tonic-gate 	char *p;
6667c478bd9Sstevel@tonic-gate 
6677c478bd9Sstevel@tonic-gate 	errno = 0;
6687c478bd9Sstevel@tonic-gate 	val = strtoull(s, &p, 0);
6697c478bd9Sstevel@tonic-gate 
6707c478bd9Sstevel@tonic-gate 	if (errno != 0 || p == s || *p != '\0' || val > UINT32_MAX) {
6717c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "%s: invalid %s argument -- %s\n",
6727c478bd9Sstevel@tonic-gate 		    g_pname, name, s);
6737c478bd9Sstevel@tonic-gate 		exit(FMSTAT_EXIT_USAGE);
6747c478bd9Sstevel@tonic-gate 	}
6757c478bd9Sstevel@tonic-gate 
6767c478bd9Sstevel@tonic-gate 	return ((uint32_t)val);
6777c478bd9Sstevel@tonic-gate }
6787c478bd9Sstevel@tonic-gate 
6797c478bd9Sstevel@tonic-gate static int
usage(FILE * fp)6807c478bd9Sstevel@tonic-gate usage(FILE *fp)
6817c478bd9Sstevel@tonic-gate {
682d9638e54Smws 	(void) fprintf(fp, "Usage: %s [-astTz] [-m module] "
68326fd7700SKrishnendu Sadhukhan - Sun Microsystems 	    "[-P prog] [-d d|u] [interval [count]]\n\n", g_pname);
6847c478bd9Sstevel@tonic-gate 
6857c478bd9Sstevel@tonic-gate 	(void) fprintf(fp,
6867c478bd9Sstevel@tonic-gate 	    "\t-a show all statistics, including those kept by fmd\n"
68726fd7700SKrishnendu Sadhukhan - Sun Microsystems 	    "\t-d display a timestamp in date (d) or unix time_t (u)\n"
6887c478bd9Sstevel@tonic-gate 	    "\t-m show module-specific statistics\n"
6897c478bd9Sstevel@tonic-gate 	    "\t-P connect to alternate fmd program\n"
6907c478bd9Sstevel@tonic-gate 	    "\t-s show module-specific serd engines\n"
691d9638e54Smws 	    "\t-t show transport-specific statistics\n"
692d9638e54Smws 	    "\t-T show transport modules and authorities\n"
6937c478bd9Sstevel@tonic-gate 	    "\t-z suppress zero-valued statistics\n");
6947c478bd9Sstevel@tonic-gate 
6957c478bd9Sstevel@tonic-gate 	return (FMSTAT_EXIT_USAGE);
6967c478bd9Sstevel@tonic-gate }
6977c478bd9Sstevel@tonic-gate 
6987c478bd9Sstevel@tonic-gate int
main(int argc,char * argv[])6997c478bd9Sstevel@tonic-gate main(int argc, char *argv[])
7007c478bd9Sstevel@tonic-gate {
701d9638e54Smws 	int opt_a = 0, opt_s = 0, opt_t = 0, opt_T = 0, opt_z = 0;
7027c478bd9Sstevel@tonic-gate 	const char *opt_m = NULL;
7037c478bd9Sstevel@tonic-gate 	int msec = 0, iter = 1;
7047c478bd9Sstevel@tonic-gate 
7057c478bd9Sstevel@tonic-gate 	uint32_t program;
7067c478bd9Sstevel@tonic-gate 	char *p;
7077c478bd9Sstevel@tonic-gate 	int c;
7087c478bd9Sstevel@tonic-gate 
7097c478bd9Sstevel@tonic-gate 	if ((p = strrchr(argv[0], '/')) == NULL)
7107c478bd9Sstevel@tonic-gate 		g_pname = argv[0];
7117c478bd9Sstevel@tonic-gate 	else
7127c478bd9Sstevel@tonic-gate 		g_pname = p + 1;
7137c478bd9Sstevel@tonic-gate 
7147c478bd9Sstevel@tonic-gate 	if ((p = getenv("FMD_PROGRAM")) != NULL)
7157c478bd9Sstevel@tonic-gate 		program = getu32("$FMD_PROGRAM", p);
7167c478bd9Sstevel@tonic-gate 	else
7177c478bd9Sstevel@tonic-gate 		program = FMD_ADM_PROGRAM;
7187c478bd9Sstevel@tonic-gate 
71926fd7700SKrishnendu Sadhukhan - Sun Microsystems 	(void) setlocale(LC_ALL, "");
72026fd7700SKrishnendu Sadhukhan - Sun Microsystems 	(void) textdomain(TEXT_DOMAIN);
72126fd7700SKrishnendu Sadhukhan - Sun Microsystems 
72226fd7700SKrishnendu Sadhukhan - Sun Microsystems 	while ((c = getopt(argc, argv, "ad:m:P:stTz")) != EOF) {
7237c478bd9Sstevel@tonic-gate 		switch (c) {
7247c478bd9Sstevel@tonic-gate 		case 'a':
7257c478bd9Sstevel@tonic-gate 			opt_a++;
7267c478bd9Sstevel@tonic-gate 			break;
72726fd7700SKrishnendu Sadhukhan - Sun Microsystems 		case 'd':
72826fd7700SKrishnendu Sadhukhan - Sun Microsystems 			if (optarg) {
72926fd7700SKrishnendu Sadhukhan - Sun Microsystems 				if (*optarg == 'u')
73026fd7700SKrishnendu Sadhukhan - Sun Microsystems 					timestamp_fmt = UDATE;
73126fd7700SKrishnendu Sadhukhan - Sun Microsystems 				else if (*optarg == 'd')
73226fd7700SKrishnendu Sadhukhan - Sun Microsystems 					timestamp_fmt = DDATE;
73326fd7700SKrishnendu Sadhukhan - Sun Microsystems 				else
73426fd7700SKrishnendu Sadhukhan - Sun Microsystems 					return (usage(stderr));
73526fd7700SKrishnendu Sadhukhan - Sun Microsystems 			} else {
73626fd7700SKrishnendu Sadhukhan - Sun Microsystems 				return (usage(stderr));
73726fd7700SKrishnendu Sadhukhan - Sun Microsystems 			}
73826fd7700SKrishnendu Sadhukhan - Sun Microsystems 			break;
7397c478bd9Sstevel@tonic-gate 		case 'm':
7407c478bd9Sstevel@tonic-gate 			opt_m = optarg;
7417c478bd9Sstevel@tonic-gate 			break;
7427c478bd9Sstevel@tonic-gate 		case 'P':
7437c478bd9Sstevel@tonic-gate 			program = getu32("program", optarg);
7447c478bd9Sstevel@tonic-gate 			break;
7457c478bd9Sstevel@tonic-gate 		case 's':
7467c478bd9Sstevel@tonic-gate 			opt_s++;
7477c478bd9Sstevel@tonic-gate 			break;
748d9638e54Smws 		case 't':
749d9638e54Smws 			opt_t++;
750d9638e54Smws 			break;
751d9638e54Smws 		case 'T':
752d9638e54Smws 			opt_T++;
753d9638e54Smws 			break;
7547c478bd9Sstevel@tonic-gate 		case 'z':
7557c478bd9Sstevel@tonic-gate 			opt_z++;
7567c478bd9Sstevel@tonic-gate 			break;
7577c478bd9Sstevel@tonic-gate 		default:
7587c478bd9Sstevel@tonic-gate 			return (usage(stderr));
7597c478bd9Sstevel@tonic-gate 		}
7607c478bd9Sstevel@tonic-gate 	}
7617c478bd9Sstevel@tonic-gate 
7627c478bd9Sstevel@tonic-gate 	if (optind < argc) {
7637c478bd9Sstevel@tonic-gate 		msec = getint("interval", argv[optind++]) * MILLISEC;
7647c478bd9Sstevel@tonic-gate 		iter = -1;
7657c478bd9Sstevel@tonic-gate 	}
7667c478bd9Sstevel@tonic-gate 
7677c478bd9Sstevel@tonic-gate 	if (optind < argc)
7687c478bd9Sstevel@tonic-gate 		iter = getint("count", argv[optind++]);
7697c478bd9Sstevel@tonic-gate 
7707c478bd9Sstevel@tonic-gate 	if (optind < argc)
7717c478bd9Sstevel@tonic-gate 		return (usage(stderr));
7727c478bd9Sstevel@tonic-gate 
773d9638e54Smws 	if (opt_t != 0 && (opt_m != NULL || opt_s != 0)) {
774d9638e54Smws 		(void) fprintf(stderr,
775d9638e54Smws 		    "%s: -t cannot be used with -m or -s\n", g_pname);
776d9638e54Smws 		return (FMSTAT_EXIT_USAGE);
777d9638e54Smws 	}
778d9638e54Smws 
779d9638e54Smws 	if (opt_t != 0 && opt_T != 0) {
780d9638e54Smws 		(void) fprintf(stderr,
781d9638e54Smws 		    "%s: -t and -T are mutually exclusive options\n", g_pname);
782d9638e54Smws 		return (FMSTAT_EXIT_USAGE);
783d9638e54Smws 	}
784d9638e54Smws 
7857c478bd9Sstevel@tonic-gate 	if (opt_m == NULL && opt_s != 0) {
7867c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr,
7877c478bd9Sstevel@tonic-gate 		    "%s: -s requires -m <module>\n", g_pname);
7887c478bd9Sstevel@tonic-gate 		return (FMSTAT_EXIT_USAGE);
7897c478bd9Sstevel@tonic-gate 	}
7907c478bd9Sstevel@tonic-gate 
7917c478bd9Sstevel@tonic-gate 	if ((g_adm = fmd_adm_open(NULL, program, FMD_ADM_VERSION)) == NULL)
7927c478bd9Sstevel@tonic-gate 		die(NULL); /* fmd_adm_errmsg() has enough info */
7937c478bd9Sstevel@tonic-gate 
7947c478bd9Sstevel@tonic-gate 	while (iter < 0 || iter-- > 0) {
79526fd7700SKrishnendu Sadhukhan - Sun Microsystems 		if (timestamp_fmt != NODATE)
79626fd7700SKrishnendu Sadhukhan - Sun Microsystems 			print_timestamp(timestamp_fmt);
7977c478bd9Sstevel@tonic-gate 		if (opt_s)
7987c478bd9Sstevel@tonic-gate 			stat_mod_serd(opt_m);
799d9638e54Smws 		else if (opt_T)
800d9638e54Smws 			stat_xprt_auth(opt_m);
8017c478bd9Sstevel@tonic-gate 		else if (opt_a || opt_m)
8027c478bd9Sstevel@tonic-gate 			stat_mod(opt_m, opt_a, opt_z);
803d9638e54Smws 		else if (opt_t)
804d9638e54Smws 			stat_xprt();
8057c478bd9Sstevel@tonic-gate 		else
8067c478bd9Sstevel@tonic-gate 			stat_fmd();
8077c478bd9Sstevel@tonic-gate 
8087c478bd9Sstevel@tonic-gate 		if (iter != 0) {
8097c478bd9Sstevel@tonic-gate 			(void) poll(NULL, 0, msec);
8107c478bd9Sstevel@tonic-gate 			(void) putchar('\n');
8117c478bd9Sstevel@tonic-gate 		}
8127c478bd9Sstevel@tonic-gate 	}
8137c478bd9Sstevel@tonic-gate 
8147c478bd9Sstevel@tonic-gate 	fmd_adm_close(g_adm);
8157c478bd9Sstevel@tonic-gate 	return (FMSTAT_EXIT_SUCCESS);
8167c478bd9Sstevel@tonic-gate }
817