xref: /illumos-gate/usr/src/cmd/rpcsvc/rstat_proc.c (revision 2a8bcb4e)
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
5*d62bc4baSyz  * Common Development and Distribution License (the "License").
6*d62bc4baSyz  * 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  */
217c478bd9Sstevel@tonic-gate /*
22*d62bc4baSyz  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate /*
277c478bd9Sstevel@tonic-gate  * rstat service:  built with rstat.x
287c478bd9Sstevel@tonic-gate  */
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate #include <stdio.h>
317c478bd9Sstevel@tonic-gate #include <stdlib.h>
327c478bd9Sstevel@tonic-gate #include <stdarg.h>
337c478bd9Sstevel@tonic-gate #include <string.h>
347c478bd9Sstevel@tonic-gate #include <signal.h>
357c478bd9Sstevel@tonic-gate #include <utmpx.h>
367c478bd9Sstevel@tonic-gate #include <nlist.h>
377c478bd9Sstevel@tonic-gate #include <fcntl.h>
387c478bd9Sstevel@tonic-gate #include <syslog.h>
397c478bd9Sstevel@tonic-gate #include <kstat.h>
407c478bd9Sstevel@tonic-gate 
417c478bd9Sstevel@tonic-gate #include <rpc/rpc.h>
427c478bd9Sstevel@tonic-gate 
437c478bd9Sstevel@tonic-gate #include <sys/socket.h>
447c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h>
457c478bd9Sstevel@tonic-gate #include <sys/sysinfo.h>
467c478bd9Sstevel@tonic-gate #include <sys/systm.h>
477c478bd9Sstevel@tonic-gate #include <errno.h>
487c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
497c478bd9Sstevel@tonic-gate #include <sys/tihdr.h>
507c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate #include <net/if.h>
537c478bd9Sstevel@tonic-gate #include <inet/mib2.h>
547c478bd9Sstevel@tonic-gate 
557c478bd9Sstevel@tonic-gate #include "rstat.h"
567c478bd9Sstevel@tonic-gate #include "rstat_v2.h"
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate typedef struct {
597c478bd9Sstevel@tonic-gate 	kstat_t	sys;
607c478bd9Sstevel@tonic-gate 	kstat_t	vm;
617c478bd9Sstevel@tonic-gate } _cpu_stats_t;
627c478bd9Sstevel@tonic-gate 
637c478bd9Sstevel@tonic-gate /*
647c478bd9Sstevel@tonic-gate  *	system and cpu stats
657c478bd9Sstevel@tonic-gate  */
667c478bd9Sstevel@tonic-gate static	kstat_ctl_t	*kc;		/* libkstat cookie */
677c478bd9Sstevel@tonic-gate static	int	ncpus;
687c478bd9Sstevel@tonic-gate static	_cpu_stats_t	*cpu_stats_list = NULL;
697c478bd9Sstevel@tonic-gate static	kstat_t	*system_misc_ksp;
707c478bd9Sstevel@tonic-gate static	kstat_named_t *boot_time_knp;
717c478bd9Sstevel@tonic-gate static	kstat_named_t *avenrun_1min_knp, *avenrun_5min_knp, *avenrun_15min_knp;
727c478bd9Sstevel@tonic-gate static	int	hz;
737c478bd9Sstevel@tonic-gate static	struct	timeval btm;		/* boottime */
747c478bd9Sstevel@tonic-gate 
757c478bd9Sstevel@tonic-gate /*
767c478bd9Sstevel@tonic-gate  *	network interface stats
777c478bd9Sstevel@tonic-gate  */
787c478bd9Sstevel@tonic-gate 
797c478bd9Sstevel@tonic-gate typedef struct mib_item_s {
807c478bd9Sstevel@tonic-gate 	struct mib_item_s	*next_item;
817c478bd9Sstevel@tonic-gate 	long			group;
827c478bd9Sstevel@tonic-gate 	long			mib_id;
837c478bd9Sstevel@tonic-gate 	long			length;
847c478bd9Sstevel@tonic-gate 	char			*valp;
857c478bd9Sstevel@tonic-gate } mib_item_t;
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate mib_item_t	*netstat_item;
887c478bd9Sstevel@tonic-gate 
897c478bd9Sstevel@tonic-gate /*
907c478bd9Sstevel@tonic-gate  * disk stats
917c478bd9Sstevel@tonic-gate  */
927c478bd9Sstevel@tonic-gate 
937c478bd9Sstevel@tonic-gate struct diskinfo {
947c478bd9Sstevel@tonic-gate 	struct diskinfo *next;
957c478bd9Sstevel@tonic-gate 	kstat_t *ks;
967c478bd9Sstevel@tonic-gate 	kstat_io_t kios;
977c478bd9Sstevel@tonic-gate };
987c478bd9Sstevel@tonic-gate 
997c478bd9Sstevel@tonic-gate #define	NULLDISK (struct diskinfo *)0
1007c478bd9Sstevel@tonic-gate static	struct diskinfo zerodisk = { NULL, NULL };
1017c478bd9Sstevel@tonic-gate static	struct diskinfo *firstdisk = NULLDISK;
1027c478bd9Sstevel@tonic-gate static	struct diskinfo *lastdisk = NULLDISK;
1037c478bd9Sstevel@tonic-gate static	struct diskinfo *snip = NULLDISK;
1047c478bd9Sstevel@tonic-gate static	int ndisks;
1057c478bd9Sstevel@tonic-gate 
1067c478bd9Sstevel@tonic-gate /*
1077c478bd9Sstevel@tonic-gate  * net stats
1087c478bd9Sstevel@tonic-gate  */
1097c478bd9Sstevel@tonic-gate 
1107c478bd9Sstevel@tonic-gate struct netinfo {
1117c478bd9Sstevel@tonic-gate 	struct netinfo *next;
1127c478bd9Sstevel@tonic-gate 	kstat_t	*ks;
1137c478bd9Sstevel@tonic-gate 	kstat_named_t *ipackets;
1147c478bd9Sstevel@tonic-gate 	kstat_named_t *opackets;
1157c478bd9Sstevel@tonic-gate 	kstat_named_t *ierrors;
1167c478bd9Sstevel@tonic-gate 	kstat_named_t *oerrors;
1177c478bd9Sstevel@tonic-gate 	kstat_named_t *collisions;
1187c478bd9Sstevel@tonic-gate };
1197c478bd9Sstevel@tonic-gate 
1207c478bd9Sstevel@tonic-gate #define	NULLNET (struct netinfo *)0
1217c478bd9Sstevel@tonic-gate static	struct netinfo zeronet = { NULL, NULL, NULL, NULL, NULL, NULL, NULL };
1227c478bd9Sstevel@tonic-gate static	struct netinfo *firstnet = NULLNET;
1237c478bd9Sstevel@tonic-gate static	struct netinfo *lastnet = NULLNET;
1247c478bd9Sstevel@tonic-gate static	struct netinfo *netsnip = NULLNET;
1257c478bd9Sstevel@tonic-gate static	int nnets;
1267c478bd9Sstevel@tonic-gate 
1277c478bd9Sstevel@tonic-gate /*
1287c478bd9Sstevel@tonic-gate  *  Define EXIT_WHEN_IDLE if you are able to have this program invoked
1297c478bd9Sstevel@tonic-gate  *  automatically on demand (as from inetd).  When defined, the service
1307c478bd9Sstevel@tonic-gate  *  will terminated after being idle for 120 seconds.
1317c478bd9Sstevel@tonic-gate  */
1327c478bd9Sstevel@tonic-gate 
1337c478bd9Sstevel@tonic-gate #define	EXIT_WHEN_IDLE	1
1347c478bd9Sstevel@tonic-gate 
1357c478bd9Sstevel@tonic-gate int sincelastreq = 0;		/* number of alarms since last request */
1367c478bd9Sstevel@tonic-gate #ifdef EXIT_WHEN_IDLE
1377c478bd9Sstevel@tonic-gate #define	CLOSEDOWN 120		/* how long to wait before exiting */
1387c478bd9Sstevel@tonic-gate #endif /* def EXIT_WHEN_IDLE */
1397c478bd9Sstevel@tonic-gate 
1407c478bd9Sstevel@tonic-gate statstime stats_s3;
1417c478bd9Sstevel@tonic-gate statsvar stats_s4;
1427c478bd9Sstevel@tonic-gate /* V2 support for backwards compatibility to pre-5.0 systems */
1437c478bd9Sstevel@tonic-gate statsswtch stats_s2;
1447c478bd9Sstevel@tonic-gate 
14549e7ca49Speteh static int stat_is_init = 0;
1467c478bd9Sstevel@tonic-gate 
1477c478bd9Sstevel@tonic-gate static	void	fail(int, char *, ...);
1487c478bd9Sstevel@tonic-gate static	void	safe_zalloc(void **, int, int);
1497c478bd9Sstevel@tonic-gate static	kid_t	safe_kstat_read(kstat_ctl_t *, kstat_t *, void *);
1507c478bd9Sstevel@tonic-gate static	kstat_t	*safe_kstat_lookup(kstat_ctl_t *, char *, int, char *);
1517c478bd9Sstevel@tonic-gate static	void	*safe_kstat_data_lookup(kstat_t *, char *);
1527c478bd9Sstevel@tonic-gate static	void	system_stat_init(void);
1537c478bd9Sstevel@tonic-gate static	int	system_stat_load(void);
1547c478bd9Sstevel@tonic-gate static	void	init_disks(void);
1557c478bd9Sstevel@tonic-gate static	int	diskinfo_load(void);
1567c478bd9Sstevel@tonic-gate static	void	init_net(void);
1577c478bd9Sstevel@tonic-gate static	int	netinfo_load(void);
1587c478bd9Sstevel@tonic-gate 
1597c478bd9Sstevel@tonic-gate static	void	updatestat(int);
1607c478bd9Sstevel@tonic-gate 
1617c478bd9Sstevel@tonic-gate static	mib_item_t	*mibget(int sd);
1627c478bd9Sstevel@tonic-gate static	int	mibopen(void);
1637c478bd9Sstevel@tonic-gate static  char	*octetstr(char *buf, Octet_t *op, int code);
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate static	void	kstat_copy(kstat_t *, kstat_t *, int);
1667c478bd9Sstevel@tonic-gate 
1677c478bd9Sstevel@tonic-gate static	char	*cmdname = "rpc.rstatd";
1687c478bd9Sstevel@tonic-gate 
1697c478bd9Sstevel@tonic-gate #define	CPU_STAT(ksp, name)	(((kstat_named_t *)safe_kstat_data_lookup( \
1707c478bd9Sstevel@tonic-gate 				    (ksp), (name)))->value.ui64)
1717c478bd9Sstevel@tonic-gate static	_cpu_stats_t	cpu_stats_all = { 0 };
1727c478bd9Sstevel@tonic-gate 
1737c478bd9Sstevel@tonic-gate static void
stat_init(void)1747c478bd9Sstevel@tonic-gate stat_init(void)
1757c478bd9Sstevel@tonic-gate {
1767c478bd9Sstevel@tonic-gate 	struct utmpx *utmpx, utmpx_id;
1777c478bd9Sstevel@tonic-gate 
1787c478bd9Sstevel@tonic-gate 	stat_is_init = 1;
1797c478bd9Sstevel@tonic-gate 
1807c478bd9Sstevel@tonic-gate 	if ((kc = kstat_open()) == NULL)
1817c478bd9Sstevel@tonic-gate 		fail(1, "kstat_open(): can't open /dev/kstat");
1827c478bd9Sstevel@tonic-gate 
1837c478bd9Sstevel@tonic-gate 	/*
1847c478bd9Sstevel@tonic-gate 	 * Preallocate minimal set of drive entries.
1857c478bd9Sstevel@tonic-gate 	 */
1867c478bd9Sstevel@tonic-gate 
1877c478bd9Sstevel@tonic-gate 	if (stats_s4.dk_xfer.dk_xfer_val == NULL) {
1887c478bd9Sstevel@tonic-gate 		stats_s4.dk_xfer.dk_xfer_len = RSTAT_DK_NDRIVE;
1897c478bd9Sstevel@tonic-gate 		stats_s4.dk_xfer.dk_xfer_val =
1907c478bd9Sstevel@tonic-gate 		    (int *)calloc(RSTAT_DK_NDRIVE, sizeof (int));
1917c478bd9Sstevel@tonic-gate 	}
1927c478bd9Sstevel@tonic-gate 
1937c478bd9Sstevel@tonic-gate 	system_stat_init();
1947c478bd9Sstevel@tonic-gate 	init_disks();
1957c478bd9Sstevel@tonic-gate 	init_net();
1967c478bd9Sstevel@tonic-gate 
1977c478bd9Sstevel@tonic-gate 	/*
1987c478bd9Sstevel@tonic-gate 	 * To get the boot time, use utmpx, which is per-zone, but fall back
1997c478bd9Sstevel@tonic-gate 	 * to the system-wide kstat if utmpx is hosed for any reason.
2007c478bd9Sstevel@tonic-gate 	 */
2017c478bd9Sstevel@tonic-gate 	utmpx_id.ut_type = BOOT_TIME;
2027c478bd9Sstevel@tonic-gate 	if ((utmpx = getutxid(&utmpx_id)) != NULL)
2037c478bd9Sstevel@tonic-gate 		btm = utmpx->ut_tv;
2047c478bd9Sstevel@tonic-gate 	else {
2057c478bd9Sstevel@tonic-gate 		btm.tv_sec = boot_time_knp->value.ul;
2067c478bd9Sstevel@tonic-gate 		btm.tv_usec = 0; /* don't bother with usecs for boot time */
2077c478bd9Sstevel@tonic-gate 	}
2087c478bd9Sstevel@tonic-gate 	endutxent();
2097c478bd9Sstevel@tonic-gate 	stats_s4.boottime.tv_sec =
2107c478bd9Sstevel@tonic-gate 		stats_s2.boottime.tv_sec =
2117c478bd9Sstevel@tonic-gate 		stats_s3.boottime.tv_sec = btm.tv_sec;
2127c478bd9Sstevel@tonic-gate 	stats_s4.boottime.tv_usec =
2137c478bd9Sstevel@tonic-gate 		stats_s2.boottime.tv_usec =
2147c478bd9Sstevel@tonic-gate 		stats_s3.boottime.tv_usec = btm.tv_usec;
2157c478bd9Sstevel@tonic-gate 
2167c478bd9Sstevel@tonic-gate 	updatestat(0);
2177c478bd9Sstevel@tonic-gate 	alarm(1);
2187c478bd9Sstevel@tonic-gate 	signal(SIGALRM, updatestat);
2197c478bd9Sstevel@tonic-gate 	sleep(2);		/* allow for one wake-up */
2207c478bd9Sstevel@tonic-gate }
2217c478bd9Sstevel@tonic-gate 
2227c478bd9Sstevel@tonic-gate statsvar *
rstatproc_stats_4_svc(argp,svcrq)2237c478bd9Sstevel@tonic-gate rstatproc_stats_4_svc(argp, svcrq)
2247c478bd9Sstevel@tonic-gate void *argp;
2257c478bd9Sstevel@tonic-gate struct svc_req *svcrq;
2267c478bd9Sstevel@tonic-gate {
2277c478bd9Sstevel@tonic-gate 	if (! stat_is_init)
2287c478bd9Sstevel@tonic-gate 		stat_init();
2297c478bd9Sstevel@tonic-gate #ifdef EXIT_WHEN_IDLE
2307c478bd9Sstevel@tonic-gate 	sincelastreq = 0;
2317c478bd9Sstevel@tonic-gate #endif
2327c478bd9Sstevel@tonic-gate 	return (&stats_s4);
2337c478bd9Sstevel@tonic-gate }
2347c478bd9Sstevel@tonic-gate 
2357c478bd9Sstevel@tonic-gate statstime *
rstatproc_stats_3_svc(argp,svcrq)2367c478bd9Sstevel@tonic-gate rstatproc_stats_3_svc(argp, svcrq)
2377c478bd9Sstevel@tonic-gate void *argp;
2387c478bd9Sstevel@tonic-gate struct svc_req *svcrq;
2397c478bd9Sstevel@tonic-gate {
2407c478bd9Sstevel@tonic-gate 	if (! stat_is_init)
2417c478bd9Sstevel@tonic-gate 		stat_init();
2427c478bd9Sstevel@tonic-gate #ifdef EXIT_WHEN_IDLE
2437c478bd9Sstevel@tonic-gate 	sincelastreq = 0;
2447c478bd9Sstevel@tonic-gate #endif
2457c478bd9Sstevel@tonic-gate 	return (&stats_s3);
2467c478bd9Sstevel@tonic-gate }
2477c478bd9Sstevel@tonic-gate 
2487c478bd9Sstevel@tonic-gate statsswtch *
rstatproc_stats_2_svc(argp,svcrq)2497c478bd9Sstevel@tonic-gate rstatproc_stats_2_svc(argp, svcrq)
2507c478bd9Sstevel@tonic-gate void *argp;
2517c478bd9Sstevel@tonic-gate struct svc_req *svcrq;
2527c478bd9Sstevel@tonic-gate {
2537c478bd9Sstevel@tonic-gate 	if (! stat_is_init)
2547c478bd9Sstevel@tonic-gate 		stat_init();
2557c478bd9Sstevel@tonic-gate #ifdef EXIT_WHEN_IDLE
2567c478bd9Sstevel@tonic-gate 	sincelastreq = 0;
2577c478bd9Sstevel@tonic-gate #endif
2587c478bd9Sstevel@tonic-gate 	return (&stats_s2);
2597c478bd9Sstevel@tonic-gate }
2607c478bd9Sstevel@tonic-gate 
2617c478bd9Sstevel@tonic-gate 
2627c478bd9Sstevel@tonic-gate uint_t *
rstatproc_havedisk_4_svc(argp,svcrq)2637c478bd9Sstevel@tonic-gate rstatproc_havedisk_4_svc(argp, svcrq)
2647c478bd9Sstevel@tonic-gate void *argp;
2657c478bd9Sstevel@tonic-gate struct svc_req *svcrq;
2667c478bd9Sstevel@tonic-gate {
2677c478bd9Sstevel@tonic-gate 	return (rstatproc_havedisk_3_svc(argp, svcrq));
2687c478bd9Sstevel@tonic-gate }
2697c478bd9Sstevel@tonic-gate 
2707c478bd9Sstevel@tonic-gate uint_t *
rstatproc_havedisk_3_svc(argp,svcrq)2717c478bd9Sstevel@tonic-gate rstatproc_havedisk_3_svc(argp, svcrq)
2727c478bd9Sstevel@tonic-gate void *argp;
2737c478bd9Sstevel@tonic-gate struct svc_req *svcrq;
2747c478bd9Sstevel@tonic-gate {
2757c478bd9Sstevel@tonic-gate 	static uint_t have;
2767c478bd9Sstevel@tonic-gate 
2777c478bd9Sstevel@tonic-gate 	if (! stat_is_init)
2787c478bd9Sstevel@tonic-gate 		stat_init();
2797c478bd9Sstevel@tonic-gate #ifdef EXIT_WHEN_IDLE
2807c478bd9Sstevel@tonic-gate 	sincelastreq = 0;
2817c478bd9Sstevel@tonic-gate #endif
2827c478bd9Sstevel@tonic-gate 	have = (ndisks != 0);
2837c478bd9Sstevel@tonic-gate 	return (&have);
2847c478bd9Sstevel@tonic-gate }
2857c478bd9Sstevel@tonic-gate 
2867c478bd9Sstevel@tonic-gate uint_t *
rstatproc_havedisk_2_svc(argp,svcrq)2877c478bd9Sstevel@tonic-gate rstatproc_havedisk_2_svc(argp, svcrq)
2887c478bd9Sstevel@tonic-gate void *argp;
2897c478bd9Sstevel@tonic-gate struct svc_req *svcrq;
2907c478bd9Sstevel@tonic-gate {
2917c478bd9Sstevel@tonic-gate 	return (rstatproc_havedisk_3_svc(argp, svcrq));
2927c478bd9Sstevel@tonic-gate }
2937c478bd9Sstevel@tonic-gate 
2947c478bd9Sstevel@tonic-gate void
updatestat(int ignored)2957c478bd9Sstevel@tonic-gate updatestat(int ignored)
2967c478bd9Sstevel@tonic-gate {
2977c478bd9Sstevel@tonic-gate extern int _rpcpmstart;		 /* Started by a port monitor ? */
2987c478bd9Sstevel@tonic-gate extern int _rpcsvcdirty;	 /* Still serving ? */
2997c478bd9Sstevel@tonic-gate 
3007c478bd9Sstevel@tonic-gate #ifdef DEBUG
3017c478bd9Sstevel@tonic-gate 	fprintf(stderr, "entering updatestat\n");
3027c478bd9Sstevel@tonic-gate #endif
3037c478bd9Sstevel@tonic-gate #ifdef EXIT_WHEN_IDLE
3047c478bd9Sstevel@tonic-gate 	if (_rpcpmstart && sincelastreq >= CLOSEDOWN && !_rpcsvcdirty) {
3057c478bd9Sstevel@tonic-gate #ifdef DEBUG
3067c478bd9Sstevel@tonic-gate 		fprintf(stderr, "about to closedown\n");
3077c478bd9Sstevel@tonic-gate #endif
3087c478bd9Sstevel@tonic-gate 		exit(0);
3097c478bd9Sstevel@tonic-gate 	}
3107c478bd9Sstevel@tonic-gate 	sincelastreq++;
3117c478bd9Sstevel@tonic-gate #endif /* def EXIT_WHEN_IDLE */
3127c478bd9Sstevel@tonic-gate 
3137c478bd9Sstevel@tonic-gate 	(void) alarm(0);
3147c478bd9Sstevel@tonic-gate #ifdef DEBUG
3157c478bd9Sstevel@tonic-gate 	fprintf(stderr, "boottime: %d %d\n", stats_s3.boottime.tv_sec,
3167c478bd9Sstevel@tonic-gate 		stats_s3.boottime.tv_usec);
3177c478bd9Sstevel@tonic-gate #endif
3187c478bd9Sstevel@tonic-gate 	while (system_stat_load() || diskinfo_load() || netinfo_load()) {
3197c478bd9Sstevel@tonic-gate 		(void) kstat_chain_update(kc);
3207c478bd9Sstevel@tonic-gate 		system_stat_init();
3217c478bd9Sstevel@tonic-gate 		init_disks();
3227c478bd9Sstevel@tonic-gate 		init_net();
3237c478bd9Sstevel@tonic-gate 	}
3247c478bd9Sstevel@tonic-gate 	stats_s4.cp_time.cp_time_len = CPU_STATES;
3257c478bd9Sstevel@tonic-gate 	if (stats_s4.cp_time.cp_time_val == NULL)
3267c478bd9Sstevel@tonic-gate 		stats_s4.cp_time.cp_time_val =
3277c478bd9Sstevel@tonic-gate 		malloc(stats_s4.cp_time.cp_time_len * sizeof (int));
3287c478bd9Sstevel@tonic-gate 	stats_s2.cp_time[RSTAT_CPU_USER] =
3297c478bd9Sstevel@tonic-gate 	stats_s3.cp_time[RSTAT_CPU_USER] =
3307c478bd9Sstevel@tonic-gate 	stats_s4.cp_time.cp_time_val[RSTAT_CPU_USER] =
3317c478bd9Sstevel@tonic-gate 		CPU_STAT(&cpu_stats_all.sys, "cpu_ticks_user");
3327c478bd9Sstevel@tonic-gate 	stats_s2.cp_time[RSTAT_CPU_NICE] =
3337c478bd9Sstevel@tonic-gate 	stats_s3.cp_time[RSTAT_CPU_NICE] =
3347c478bd9Sstevel@tonic-gate 	stats_s4.cp_time.cp_time_val[RSTAT_CPU_NICE] =
3357c478bd9Sstevel@tonic-gate 		CPU_STAT(&cpu_stats_all.sys, "cpu_ticks_wait");
3367c478bd9Sstevel@tonic-gate 	stats_s2.cp_time[RSTAT_CPU_SYS] =
3377c478bd9Sstevel@tonic-gate 	stats_s3.cp_time[RSTAT_CPU_SYS] =
3387c478bd9Sstevel@tonic-gate 	stats_s4.cp_time.cp_time_val[RSTAT_CPU_SYS] =
3397c478bd9Sstevel@tonic-gate 		CPU_STAT(&cpu_stats_all.sys, "cpu_ticks_kernel");
3407c478bd9Sstevel@tonic-gate 	stats_s2.cp_time[RSTAT_CPU_IDLE] =
3417c478bd9Sstevel@tonic-gate 	stats_s3.cp_time[RSTAT_CPU_IDLE] =
3427c478bd9Sstevel@tonic-gate 	stats_s4.cp_time.cp_time_val[RSTAT_CPU_IDLE] =
3437c478bd9Sstevel@tonic-gate 		CPU_STAT(&cpu_stats_all.sys, "cpu_ticks_idle");
3447c478bd9Sstevel@tonic-gate 
3457c478bd9Sstevel@tonic-gate #ifdef DEBUG
3467c478bd9Sstevel@tonic-gate 	fprintf(stderr, "cpu: %d %d %d %d\n",
3477c478bd9Sstevel@tonic-gate 		CPU_STAT(&cpu_stats_all.sys, "cpu_ticks_user"),
3487c478bd9Sstevel@tonic-gate 		CPU_STAT(&cpu_stats_all.sys, "cpu_ticks_wait"),
3497c478bd9Sstevel@tonic-gate 		CPU_STAT(&cpu_stats_all.sys, "cpu_ticks_kernel"),
3507c478bd9Sstevel@tonic-gate 		CPU_STAT(&cpu_stats_all.sys, "cpu_ticks_idle"));
3517c478bd9Sstevel@tonic-gate 	fprintf(stderr, "cp_time: %d %d %d %d\n",
3527c478bd9Sstevel@tonic-gate 		stats_s3.cp_time[RSTAT_CPU_USER],
3537c478bd9Sstevel@tonic-gate 		stats_s3.cp_time[RSTAT_CPU_NICE],
3547c478bd9Sstevel@tonic-gate 		stats_s3.cp_time[RSTAT_CPU_SYS],
3557c478bd9Sstevel@tonic-gate 		stats_s3.cp_time[RSTAT_CPU_IDLE]);
3567c478bd9Sstevel@tonic-gate #endif
3577c478bd9Sstevel@tonic-gate 
3587c478bd9Sstevel@tonic-gate 	/* current time */
3597c478bd9Sstevel@tonic-gate 	gettimeofday((struct timeval *)&stats_s3.curtime, NULL);
3607c478bd9Sstevel@tonic-gate 	stats_s4.curtime = stats_s3.curtime;
3617c478bd9Sstevel@tonic-gate 
3627c478bd9Sstevel@tonic-gate 	stats_s2.v_pgpgin =
3637c478bd9Sstevel@tonic-gate 	stats_s3.v_pgpgin =
3647c478bd9Sstevel@tonic-gate 	stats_s4.v_pgpgin = CPU_STAT(&cpu_stats_all.vm, "pgpgin");
3657c478bd9Sstevel@tonic-gate 	stats_s2.v_pgpgout =
3667c478bd9Sstevel@tonic-gate 	stats_s3.v_pgpgout =
3677c478bd9Sstevel@tonic-gate 	stats_s4.v_pgpgout = CPU_STAT(&cpu_stats_all.vm, "pgpgout");
3687c478bd9Sstevel@tonic-gate 	stats_s2.v_pswpin =
3697c478bd9Sstevel@tonic-gate 	stats_s3.v_pswpin =
3707c478bd9Sstevel@tonic-gate 	stats_s4.v_pswpin = CPU_STAT(&cpu_stats_all.vm, "pgswapin");
3717c478bd9Sstevel@tonic-gate 	stats_s2.v_pswpout =
3727c478bd9Sstevel@tonic-gate 	stats_s3.v_pswpout =
3737c478bd9Sstevel@tonic-gate 	stats_s4.v_pswpout = CPU_STAT(&cpu_stats_all.vm, "pgswapout");
3747c478bd9Sstevel@tonic-gate 	stats_s3.v_intr = CPU_STAT(&cpu_stats_all.sys, "intr");
3757c478bd9Sstevel@tonic-gate 	stats_s3.v_intr -= hz*(stats_s3.curtime.tv_sec - btm.tv_sec) +
3767c478bd9Sstevel@tonic-gate 		hz*(stats_s3.curtime.tv_usec - btm.tv_usec)/1000000;
3777c478bd9Sstevel@tonic-gate 	stats_s2.v_intr =
3787c478bd9Sstevel@tonic-gate 	stats_s4.v_intr = stats_s3.v_intr;
3797c478bd9Sstevel@tonic-gate 	/* swtch not in V1 */
3807c478bd9Sstevel@tonic-gate 	stats_s2.v_swtch =
3817c478bd9Sstevel@tonic-gate 	stats_s3.v_swtch =
3827c478bd9Sstevel@tonic-gate 	stats_s4.v_swtch = CPU_STAT(&cpu_stats_all.sys, "pswitch");
3837c478bd9Sstevel@tonic-gate 
3847c478bd9Sstevel@tonic-gate #ifdef DEBUG
3857c478bd9Sstevel@tonic-gate 	fprintf(stderr,
3867c478bd9Sstevel@tonic-gate 		"pgin: %d pgout: %d swpin: %d swpout: %d intr: %d swtch: %d\n",
3877c478bd9Sstevel@tonic-gate 		stats_s3.v_pgpgin,
3887c478bd9Sstevel@tonic-gate 		stats_s3.v_pgpgout,
3897c478bd9Sstevel@tonic-gate 		stats_s3.v_pswpin,
3907c478bd9Sstevel@tonic-gate 		stats_s3.v_pswpout,
3917c478bd9Sstevel@tonic-gate 		stats_s3.v_intr,
3927c478bd9Sstevel@tonic-gate 		stats_s3.v_swtch);
3937c478bd9Sstevel@tonic-gate #endif
3947c478bd9Sstevel@tonic-gate 	/*
3957c478bd9Sstevel@tonic-gate 	 * V2 and V3 of rstat are limited to RSTAT_DK_NDRIVE drives
3967c478bd9Sstevel@tonic-gate 	 */
3977c478bd9Sstevel@tonic-gate 	memcpy(stats_s3.dk_xfer, stats_s4.dk_xfer.dk_xfer_val,
3987c478bd9Sstevel@tonic-gate 		RSTAT_DK_NDRIVE * sizeof (int));
3997c478bd9Sstevel@tonic-gate 	memcpy(stats_s2.dk_xfer, stats_s4.dk_xfer.dk_xfer_val,
4007c478bd9Sstevel@tonic-gate 		RSTAT_DK_NDRIVE * sizeof (int));
4017c478bd9Sstevel@tonic-gate #ifdef DEBUG
4027c478bd9Sstevel@tonic-gate 	fprintf(stderr, "dk_xfer: %d %d %d %d\n",
4037c478bd9Sstevel@tonic-gate 		stats_s4.dk_xfer.dk_xfer_val[0],
4047c478bd9Sstevel@tonic-gate 		stats_s4.dk_xfer.dk_xfer_val[1],
4057c478bd9Sstevel@tonic-gate 		stats_s4.dk_xfer.dk_xfer_val[2],
4067c478bd9Sstevel@tonic-gate 		stats_s4.dk_xfer.dk_xfer_val[3]);
4077c478bd9Sstevel@tonic-gate #endif
4087c478bd9Sstevel@tonic-gate 
4097c478bd9Sstevel@tonic-gate 	stats_s2.if_ipackets =
4107c478bd9Sstevel@tonic-gate 	stats_s3.if_ipackets = stats_s4.if_ipackets;
4117c478bd9Sstevel@tonic-gate 	/* no s2 opackets */
4127c478bd9Sstevel@tonic-gate 	stats_s3.if_opackets = stats_s4.if_opackets;
4137c478bd9Sstevel@tonic-gate 	stats_s2.if_ierrors =
4147c478bd9Sstevel@tonic-gate 	stats_s3.if_ierrors = stats_s4.if_ierrors;
4157c478bd9Sstevel@tonic-gate 	stats_s2.if_oerrors =
4167c478bd9Sstevel@tonic-gate 	stats_s3.if_oerrors = stats_s4.if_oerrors;
4177c478bd9Sstevel@tonic-gate 	stats_s2.if_collisions =
4187c478bd9Sstevel@tonic-gate 	stats_s3.if_collisions = stats_s4.if_collisions;
4197c478bd9Sstevel@tonic-gate 
4207c478bd9Sstevel@tonic-gate 	stats_s2.avenrun[0] =
4217c478bd9Sstevel@tonic-gate 	stats_s3.avenrun[0] =
4227c478bd9Sstevel@tonic-gate 	stats_s4.avenrun[0] = avenrun_1min_knp->value.ul;
4237c478bd9Sstevel@tonic-gate 	stats_s2.avenrun[1] =
4247c478bd9Sstevel@tonic-gate 	stats_s3.avenrun[1] =
4257c478bd9Sstevel@tonic-gate 	stats_s4.avenrun[1] = avenrun_5min_knp->value.ul;
4267c478bd9Sstevel@tonic-gate 	stats_s2.avenrun[2] =
4277c478bd9Sstevel@tonic-gate 	stats_s3.avenrun[2] =
4287c478bd9Sstevel@tonic-gate 	stats_s4.avenrun[2] = avenrun_15min_knp->value.ul;
4297c478bd9Sstevel@tonic-gate #ifdef DEBUG
4307c478bd9Sstevel@tonic-gate 	fprintf(stderr, "avenrun: %d %d %d\n", stats_s3.avenrun[0],
4317c478bd9Sstevel@tonic-gate 		stats_s3.avenrun[1], stats_s3.avenrun[2]);
4327c478bd9Sstevel@tonic-gate #endif
4337c478bd9Sstevel@tonic-gate 	signal(SIGALRM, updatestat);
4347c478bd9Sstevel@tonic-gate 	alarm(1);
4357c478bd9Sstevel@tonic-gate }
4367c478bd9Sstevel@tonic-gate 
4377c478bd9Sstevel@tonic-gate /* --------------------------------- MIBGET -------------------------------- */
4387c478bd9Sstevel@tonic-gate 
4397c478bd9Sstevel@tonic-gate static mib_item_t *
mibget(int sd)4407c478bd9Sstevel@tonic-gate mibget(int sd)
4417c478bd9Sstevel@tonic-gate {
4427c478bd9Sstevel@tonic-gate 	int			flags;
4437c478bd9Sstevel@tonic-gate 	int			j, getcode;
4447c478bd9Sstevel@tonic-gate 	struct strbuf		ctlbuf, databuf;
4457c478bd9Sstevel@tonic-gate 	char			buf[512];
4467c478bd9Sstevel@tonic-gate 	struct T_optmgmt_req	*tor = (struct T_optmgmt_req *)buf;
4477c478bd9Sstevel@tonic-gate 	struct T_optmgmt_ack	*toa = (struct T_optmgmt_ack *)buf;
4487c478bd9Sstevel@tonic-gate 	struct T_error_ack	*tea = (struct T_error_ack *)buf;
4497c478bd9Sstevel@tonic-gate 	struct opthdr		*req;
4507c478bd9Sstevel@tonic-gate 	mib_item_t		*first_item = NULL;
4517c478bd9Sstevel@tonic-gate 	mib_item_t		*last_item  = NULL;
4527c478bd9Sstevel@tonic-gate 	mib_item_t		*temp;
4537c478bd9Sstevel@tonic-gate 
4547c478bd9Sstevel@tonic-gate 	tor->PRIM_type = T_SVR4_OPTMGMT_REQ;
4557c478bd9Sstevel@tonic-gate 	tor->OPT_offset = sizeof (struct T_optmgmt_req);
4567c478bd9Sstevel@tonic-gate 	tor->OPT_length = sizeof (struct opthdr);
4577c478bd9Sstevel@tonic-gate 	tor->MGMT_flags = T_CURRENT;
4587c478bd9Sstevel@tonic-gate 	req = (struct opthdr *)&tor[1];
4597c478bd9Sstevel@tonic-gate 	req->level = MIB2_IP;		/* any MIB2_xxx value ok here */
4607c478bd9Sstevel@tonic-gate 	req->name  = 0;
4617c478bd9Sstevel@tonic-gate 	req->len   = 0;
4627c478bd9Sstevel@tonic-gate 
4637c478bd9Sstevel@tonic-gate 	ctlbuf.buf = buf;
4647c478bd9Sstevel@tonic-gate 	ctlbuf.len = tor->OPT_length + tor->OPT_offset;
4657c478bd9Sstevel@tonic-gate 	flags = 0;
4667c478bd9Sstevel@tonic-gate 	if (putmsg(sd, &ctlbuf, NULL, flags) == -1) {
4677c478bd9Sstevel@tonic-gate 		perror("mibget: putmsg(ctl) failed");
4687c478bd9Sstevel@tonic-gate 		goto error_exit;
4697c478bd9Sstevel@tonic-gate 	}
4707c478bd9Sstevel@tonic-gate 	/*
4717c478bd9Sstevel@tonic-gate 	 * each reply consists of a ctl part for one fixed structure
4727c478bd9Sstevel@tonic-gate 	 * or table, as defined in mib2.h.  The format is a T_OPTMGMT_ACK,
4737c478bd9Sstevel@tonic-gate 	 * containing an opthdr structure.  level/name identify the entry,
4747c478bd9Sstevel@tonic-gate 	 * len is the size of the data part of the message.
4757c478bd9Sstevel@tonic-gate 	 */
4767c478bd9Sstevel@tonic-gate 	req = (struct opthdr *)&toa[1];
4777c478bd9Sstevel@tonic-gate 	ctlbuf.maxlen = sizeof (buf);
4787c478bd9Sstevel@tonic-gate 	/*CSTYLED*/
4797c478bd9Sstevel@tonic-gate 	for (j = 1; ; j++) {
4807c478bd9Sstevel@tonic-gate 		flags = 0;
4817c478bd9Sstevel@tonic-gate 		getcode = getmsg(sd, &ctlbuf, NULL, &flags);
4827c478bd9Sstevel@tonic-gate 		if (getcode == -1) {
4837c478bd9Sstevel@tonic-gate #ifdef DEBUG_MIB
4847c478bd9Sstevel@tonic-gate 			perror("mibget getmsg(ctl) failed");
4857c478bd9Sstevel@tonic-gate 			fprintf(stderr, "#   level   name    len\n");
4867c478bd9Sstevel@tonic-gate 			i = 0;
4877c478bd9Sstevel@tonic-gate 			for (last_item = first_item; last_item;
4887c478bd9Sstevel@tonic-gate 				last_item = last_item->next_item)
4897c478bd9Sstevel@tonic-gate 				fprintf(stderr, "%d  %4d   %5d   %d\n", ++i,
4907c478bd9Sstevel@tonic-gate 					last_item->group,
4917c478bd9Sstevel@tonic-gate 					last_item->mib_id,
4927c478bd9Sstevel@tonic-gate 					last_item->length);
4937c478bd9Sstevel@tonic-gate #endif /* DEBUG_MIB */
4947c478bd9Sstevel@tonic-gate 			goto error_exit;
4957c478bd9Sstevel@tonic-gate 		}
4967c478bd9Sstevel@tonic-gate 		if (getcode == 0 &&
4977c478bd9Sstevel@tonic-gate 			(ctlbuf.len >= sizeof (struct T_optmgmt_ack)) &&
4987c478bd9Sstevel@tonic-gate 			(toa->PRIM_type == T_OPTMGMT_ACK) &&
4997c478bd9Sstevel@tonic-gate 			(toa->MGMT_flags == T_SUCCESS) &&
5007c478bd9Sstevel@tonic-gate 			req->len == 0) {
5017c478bd9Sstevel@tonic-gate #ifdef DEBUG_MIB
5027c478bd9Sstevel@tonic-gate 			fprintf(stderr,
5037c478bd9Sstevel@tonic-gate 		"mibget getmsg() %d returned EOD (level %d, name %d)\n",
5047c478bd9Sstevel@tonic-gate 				j, req->level, req->name);
5057c478bd9Sstevel@tonic-gate #endif /* DEBUG_MIB */
5067c478bd9Sstevel@tonic-gate 			return (first_item);		/* this is EOD msg */
5077c478bd9Sstevel@tonic-gate 		}
5087c478bd9Sstevel@tonic-gate 
5097c478bd9Sstevel@tonic-gate 		if (ctlbuf.len >= sizeof (struct T_error_ack) &&
5107c478bd9Sstevel@tonic-gate 			(tea->PRIM_type == T_ERROR_ACK)) {
5117c478bd9Sstevel@tonic-gate #ifdef DEBUG_MIB
5127c478bd9Sstevel@tonic-gate 			fprintf(stderr,
5137c478bd9Sstevel@tonic-gate 	"mibget %d gives T_ERROR_ACK: TLI_error = 0x%x, UNIX_error = 0x%x\n",
5147c478bd9Sstevel@tonic-gate 				j, getcode, tea->TLI_error, tea->UNIX_error);
5157c478bd9Sstevel@tonic-gate #endif /* DEBUG_MIB */
5167c478bd9Sstevel@tonic-gate 			errno = (tea->TLI_error == TSYSERR)
5177c478bd9Sstevel@tonic-gate 				? tea->UNIX_error : EPROTO;
5187c478bd9Sstevel@tonic-gate 			goto error_exit;
5197c478bd9Sstevel@tonic-gate 		}
5207c478bd9Sstevel@tonic-gate 
5217c478bd9Sstevel@tonic-gate 		if (getcode != MOREDATA ||
5227c478bd9Sstevel@tonic-gate 			(ctlbuf.len < sizeof (struct T_optmgmt_ack)) ||
5237c478bd9Sstevel@tonic-gate 			(toa->PRIM_type != T_OPTMGMT_ACK) ||
5247c478bd9Sstevel@tonic-gate 			(toa->MGMT_flags != T_SUCCESS)) {
5257c478bd9Sstevel@tonic-gate #ifdef DEBUG_MIB
5267c478bd9Sstevel@tonic-gate 			fprintf(stderr,
5277c478bd9Sstevel@tonic-gate 	"mibget getmsg(ctl) %d returned %d, ctlbuf.len = %d, PRIM_type = %d\n",
5287c478bd9Sstevel@tonic-gate 				j, getcode, ctlbuf.len, toa->PRIM_type);
5297c478bd9Sstevel@tonic-gate 			if (toa->PRIM_type == T_OPTMGMT_ACK)
5307c478bd9Sstevel@tonic-gate 				fprintf(stderr,
5317c478bd9Sstevel@tonic-gate 	"T_OPTMGMT_ACK: MGMT_flags = 0x%x, req->len = %d\n",
5327c478bd9Sstevel@tonic-gate 					toa->MGMT_flags, req->len);
5337c478bd9Sstevel@tonic-gate #endif /* DEBUG_MIB */
5347c478bd9Sstevel@tonic-gate 			errno = ENOMSG;
5357c478bd9Sstevel@tonic-gate 			goto error_exit;
5367c478bd9Sstevel@tonic-gate 		}
5377c478bd9Sstevel@tonic-gate 
5387c478bd9Sstevel@tonic-gate 		temp = malloc(sizeof (mib_item_t));
5397c478bd9Sstevel@tonic-gate 		if (!temp) {
5407c478bd9Sstevel@tonic-gate 			perror("mibget malloc failed");
5417c478bd9Sstevel@tonic-gate 			goto error_exit;
5427c478bd9Sstevel@tonic-gate 		}
5437c478bd9Sstevel@tonic-gate 		if (last_item)
5447c478bd9Sstevel@tonic-gate 			last_item->next_item = temp;
5457c478bd9Sstevel@tonic-gate 		else
5467c478bd9Sstevel@tonic-gate 			first_item = temp;
5477c478bd9Sstevel@tonic-gate 		last_item = temp;
5487c478bd9Sstevel@tonic-gate 		last_item->next_item = NULL;
5497c478bd9Sstevel@tonic-gate 		last_item->group = req->level;
5507c478bd9Sstevel@tonic-gate 		last_item->mib_id = req->name;
5517c478bd9Sstevel@tonic-gate 		last_item->length = req->len;
5527c478bd9Sstevel@tonic-gate 		last_item->valp = malloc(req->len);
5537c478bd9Sstevel@tonic-gate #ifdef DEBUG_MIB
5547c478bd9Sstevel@tonic-gate 		fprintf(stderr,
5557c478bd9Sstevel@tonic-gate 			"msg %d:  group = %4d   mib_id = %5d   length = %d\n",
5567c478bd9Sstevel@tonic-gate 			j, last_item->group, last_item->mib_id,
5577c478bd9Sstevel@tonic-gate 			last_item->length);
5587c478bd9Sstevel@tonic-gate #endif /* DEBUG_MIB */
5597c478bd9Sstevel@tonic-gate 		databuf.maxlen = last_item->length;
5607c478bd9Sstevel@tonic-gate 		databuf.buf    = last_item->valp;
5617c478bd9Sstevel@tonic-gate 		databuf.len    = 0;
5627c478bd9Sstevel@tonic-gate 		flags = 0;
5637c478bd9Sstevel@tonic-gate 		getcode = getmsg(sd, NULL, &databuf, &flags);
5647c478bd9Sstevel@tonic-gate 		if (getcode == -1) {
5657c478bd9Sstevel@tonic-gate 			perror("mibget getmsg(data) failed");
5667c478bd9Sstevel@tonic-gate 			goto error_exit;
5677c478bd9Sstevel@tonic-gate 		} else if (getcode != 0) {
5687c478bd9Sstevel@tonic-gate 			fprintf(stderr,
5697c478bd9Sstevel@tonic-gate "mibget getmsg(data) returned %d, databuf.maxlen = %d, databuf.len = %d\n",
5707c478bd9Sstevel@tonic-gate 				getcode, databuf.maxlen, databuf.len);
5717c478bd9Sstevel@tonic-gate 			goto error_exit;
5727c478bd9Sstevel@tonic-gate 		}
5737c478bd9Sstevel@tonic-gate 	}
5747c478bd9Sstevel@tonic-gate 
5757c478bd9Sstevel@tonic-gate error_exit:
5767c478bd9Sstevel@tonic-gate 	while (first_item) {
5777c478bd9Sstevel@tonic-gate 		last_item = first_item;
5787c478bd9Sstevel@tonic-gate 		first_item = first_item->next_item;
5797c478bd9Sstevel@tonic-gate 		if (last_item->valp) {
5807c478bd9Sstevel@tonic-gate 			free(last_item->valp);
5817c478bd9Sstevel@tonic-gate 		}
5827c478bd9Sstevel@tonic-gate 		free(last_item);
5837c478bd9Sstevel@tonic-gate 	}
5847c478bd9Sstevel@tonic-gate 	return (first_item);
5857c478bd9Sstevel@tonic-gate }
5867c478bd9Sstevel@tonic-gate 
5877c478bd9Sstevel@tonic-gate static int
mibopen(void)5887c478bd9Sstevel@tonic-gate mibopen(void)
5897c478bd9Sstevel@tonic-gate {
5907c478bd9Sstevel@tonic-gate 	int	sd;
5917c478bd9Sstevel@tonic-gate 
5927c478bd9Sstevel@tonic-gate 	/* gives us ip w/ arp on top */
5937c478bd9Sstevel@tonic-gate 	sd = open("/dev/arp", O_RDWR);
5947c478bd9Sstevel@tonic-gate 	if (sd == -1) {
5957c478bd9Sstevel@tonic-gate 		perror("arp open");
5967c478bd9Sstevel@tonic-gate 		close(sd);
5977c478bd9Sstevel@tonic-gate 		return (-1);
5987c478bd9Sstevel@tonic-gate 	}
5997c478bd9Sstevel@tonic-gate 	if (ioctl(sd, I_PUSH, "tcp") == -1) {
6007c478bd9Sstevel@tonic-gate 		perror("tcp I_PUSH");
6017c478bd9Sstevel@tonic-gate 		close(sd);
6027c478bd9Sstevel@tonic-gate 		return (-1);
6037c478bd9Sstevel@tonic-gate 	}
6047c478bd9Sstevel@tonic-gate 	if (ioctl(sd, I_PUSH, "udp") == -1) {
6057c478bd9Sstevel@tonic-gate 		perror("udp I_PUSH");
6067c478bd9Sstevel@tonic-gate 		close(sd);
6077c478bd9Sstevel@tonic-gate 		return (-1);
6087c478bd9Sstevel@tonic-gate 	}
6097c478bd9Sstevel@tonic-gate 	return (sd);
6107c478bd9Sstevel@tonic-gate }
6117c478bd9Sstevel@tonic-gate 
6127c478bd9Sstevel@tonic-gate static char *
octetstr(char * buf,Octet_t * op,int code)6137c478bd9Sstevel@tonic-gate octetstr(char *buf, Octet_t *op, int code)
6147c478bd9Sstevel@tonic-gate {
6157c478bd9Sstevel@tonic-gate 	int	i;
6167c478bd9Sstevel@tonic-gate 	char	*cp;
6177c478bd9Sstevel@tonic-gate 
6187c478bd9Sstevel@tonic-gate 	cp = buf;
6197c478bd9Sstevel@tonic-gate 	if (op)
6207c478bd9Sstevel@tonic-gate 		for (i = 0; i < op->o_length; i++)
6217c478bd9Sstevel@tonic-gate 			switch (code) {
6227c478bd9Sstevel@tonic-gate 			case 'd':
6237c478bd9Sstevel@tonic-gate 				sprintf(cp, "%d.", 0xff & op->o_bytes[i]);
6247c478bd9Sstevel@tonic-gate 				cp = strchr(cp, '\0');
6257c478bd9Sstevel@tonic-gate 				break;
6267c478bd9Sstevel@tonic-gate 			case 'a':
6277c478bd9Sstevel@tonic-gate 				*cp++ = op->o_bytes[i];
6287c478bd9Sstevel@tonic-gate 				break;
6297c478bd9Sstevel@tonic-gate 			case 'h':
6307c478bd9Sstevel@tonic-gate 			default:
6317c478bd9Sstevel@tonic-gate 				sprintf(cp, "%02x:", 0xff & op->o_bytes[i]);
6327c478bd9Sstevel@tonic-gate 				cp += 3;
6337c478bd9Sstevel@tonic-gate 				break;
6347c478bd9Sstevel@tonic-gate 			}
6357c478bd9Sstevel@tonic-gate 	if (code != 'a' && cp != buf)
6367c478bd9Sstevel@tonic-gate 		cp--;
6377c478bd9Sstevel@tonic-gate 	*cp = '\0';
6387c478bd9Sstevel@tonic-gate 	return (buf);
6397c478bd9Sstevel@tonic-gate }
6407c478bd9Sstevel@tonic-gate 
6417c478bd9Sstevel@tonic-gate static void
fail(int do_perror,char * message,...)6427c478bd9Sstevel@tonic-gate fail(int do_perror, char *message, ...)
6437c478bd9Sstevel@tonic-gate {
6447c478bd9Sstevel@tonic-gate 	va_list args;
6457c478bd9Sstevel@tonic-gate 
6467c478bd9Sstevel@tonic-gate 	va_start(args, message);
6477c478bd9Sstevel@tonic-gate 	fprintf(stderr, "%s: ", cmdname);
6487c478bd9Sstevel@tonic-gate 	vfprintf(stderr, message, args);
6497c478bd9Sstevel@tonic-gate 	va_end(args);
6507c478bd9Sstevel@tonic-gate 	if (do_perror)
6517c478bd9Sstevel@tonic-gate 		fprintf(stderr, ": %s", strerror(errno));
6527c478bd9Sstevel@tonic-gate 	fprintf(stderr, "\n");
6537c478bd9Sstevel@tonic-gate 	exit(2);
6547c478bd9Sstevel@tonic-gate }
6557c478bd9Sstevel@tonic-gate 
6567c478bd9Sstevel@tonic-gate static void
safe_zalloc(void ** ptr,int size,int free_first)6577c478bd9Sstevel@tonic-gate safe_zalloc(void **ptr, int size, int free_first)
6587c478bd9Sstevel@tonic-gate {
6597c478bd9Sstevel@tonic-gate 	if (free_first && *ptr != NULL)
6607c478bd9Sstevel@tonic-gate 		free(*ptr);
6617c478bd9Sstevel@tonic-gate 	if ((*ptr = malloc(size)) == NULL)
6627c478bd9Sstevel@tonic-gate 		fail(1, "malloc failed");
6637c478bd9Sstevel@tonic-gate 	memset(*ptr, 0, size);
6647c478bd9Sstevel@tonic-gate }
6657c478bd9Sstevel@tonic-gate 
6667c478bd9Sstevel@tonic-gate kid_t
safe_kstat_read(kstat_ctl_t * kctl,kstat_t * ksp,void * data)6677c478bd9Sstevel@tonic-gate safe_kstat_read(kstat_ctl_t *kctl, kstat_t *ksp, void *data)
6687c478bd9Sstevel@tonic-gate {
6697c478bd9Sstevel@tonic-gate 	kid_t kstat_chain_id = kstat_read(kctl, ksp, data);
6707c478bd9Sstevel@tonic-gate 
6717c478bd9Sstevel@tonic-gate 	if (kstat_chain_id == -1)
6727c478bd9Sstevel@tonic-gate 		fail(1, "kstat_read(%x, '%s') failed", kctl, ksp->ks_name);
6737c478bd9Sstevel@tonic-gate 	return (kstat_chain_id);
6747c478bd9Sstevel@tonic-gate }
6757c478bd9Sstevel@tonic-gate 
6767c478bd9Sstevel@tonic-gate kstat_t *
safe_kstat_lookup(kstat_ctl_t * kctl,char * ks_module,int ks_instance,char * ks_name)6777c478bd9Sstevel@tonic-gate safe_kstat_lookup(kstat_ctl_t *kctl, char *ks_module, int ks_instance,
6787c478bd9Sstevel@tonic-gate 	char *ks_name)
6797c478bd9Sstevel@tonic-gate {
6807c478bd9Sstevel@tonic-gate 	kstat_t *ksp = kstat_lookup(kctl, ks_module, ks_instance, ks_name);
6817c478bd9Sstevel@tonic-gate 
6827c478bd9Sstevel@tonic-gate 	if (ksp == NULL)
6837c478bd9Sstevel@tonic-gate 		fail(0, "kstat_lookup('%s', %d, '%s') failed",
6847c478bd9Sstevel@tonic-gate 			ks_module == NULL ? "" : ks_module,
6857c478bd9Sstevel@tonic-gate 			ks_instance,
6867c478bd9Sstevel@tonic-gate 			ks_name == NULL ? "" : ks_name);
6877c478bd9Sstevel@tonic-gate 	return (ksp);
6887c478bd9Sstevel@tonic-gate }
6897c478bd9Sstevel@tonic-gate 
6907c478bd9Sstevel@tonic-gate void *
safe_kstat_data_lookup(kstat_t * ksp,char * name)6917c478bd9Sstevel@tonic-gate safe_kstat_data_lookup(kstat_t *ksp, char *name)
6927c478bd9Sstevel@tonic-gate {
6937c478bd9Sstevel@tonic-gate 	void *fp = kstat_data_lookup(ksp, name);
6947c478bd9Sstevel@tonic-gate 
6957c478bd9Sstevel@tonic-gate 	if (fp == NULL) {
6967c478bd9Sstevel@tonic-gate 		fail(0, "kstat_data_lookup('%s', '%s') failed",
6977c478bd9Sstevel@tonic-gate 			ksp->ks_name, name);
6987c478bd9Sstevel@tonic-gate 	}
6997c478bd9Sstevel@tonic-gate 	return (fp);
7007c478bd9Sstevel@tonic-gate }
7017c478bd9Sstevel@tonic-gate 
7027c478bd9Sstevel@tonic-gate /*
7037c478bd9Sstevel@tonic-gate  * Get various KIDs for subsequent system_stat_load operations.
7047c478bd9Sstevel@tonic-gate  */
7057c478bd9Sstevel@tonic-gate 
7067c478bd9Sstevel@tonic-gate static void
system_stat_init(void)7077c478bd9Sstevel@tonic-gate system_stat_init(void)
7087c478bd9Sstevel@tonic-gate {
7097c478bd9Sstevel@tonic-gate 	kstat_t *ksp;
7107c478bd9Sstevel@tonic-gate 	int i, nvmks;
7117c478bd9Sstevel@tonic-gate 
7127c478bd9Sstevel@tonic-gate 	/*
7137c478bd9Sstevel@tonic-gate 	 * Global statistics
7147c478bd9Sstevel@tonic-gate 	 */
7157c478bd9Sstevel@tonic-gate 
7167c478bd9Sstevel@tonic-gate 	system_misc_ksp	= safe_kstat_lookup(kc, "unix", 0, "system_misc");
7177c478bd9Sstevel@tonic-gate 
7187c478bd9Sstevel@tonic-gate 	safe_kstat_read(kc, system_misc_ksp, NULL);
7197c478bd9Sstevel@tonic-gate 	boot_time_knp = safe_kstat_data_lookup(system_misc_ksp, "boot_time");
7207c478bd9Sstevel@tonic-gate 	avenrun_1min_knp = safe_kstat_data_lookup(system_misc_ksp,
7217c478bd9Sstevel@tonic-gate 		"avenrun_1min");
7227c478bd9Sstevel@tonic-gate 	avenrun_5min_knp = safe_kstat_data_lookup(system_misc_ksp,
7237c478bd9Sstevel@tonic-gate 		"avenrun_5min");
7247c478bd9Sstevel@tonic-gate 	avenrun_15min_knp = safe_kstat_data_lookup(system_misc_ksp,
7257c478bd9Sstevel@tonic-gate 		"avenrun_15min");
7267c478bd9Sstevel@tonic-gate 
7277c478bd9Sstevel@tonic-gate 	/*
7287c478bd9Sstevel@tonic-gate 	 * Per-CPU statistics
7297c478bd9Sstevel@tonic-gate 	 */
7307c478bd9Sstevel@tonic-gate 
7317c478bd9Sstevel@tonic-gate 	ncpus = 0;
7327c478bd9Sstevel@tonic-gate 	for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next)
7337c478bd9Sstevel@tonic-gate 		if (strcmp(ksp->ks_module, "cpu") == 0 &&
7347c478bd9Sstevel@tonic-gate 		    strcmp(ksp->ks_name, "sys") == 0)
7357c478bd9Sstevel@tonic-gate 			ncpus++;
7367c478bd9Sstevel@tonic-gate 
7377c478bd9Sstevel@tonic-gate 	safe_zalloc((void **)&cpu_stats_list, ncpus * sizeof (*cpu_stats_list),
7387c478bd9Sstevel@tonic-gate 	    1);
7397c478bd9Sstevel@tonic-gate 
7407c478bd9Sstevel@tonic-gate 	ncpus = 0;
7417c478bd9Sstevel@tonic-gate 	for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next)
7427c478bd9Sstevel@tonic-gate 		if (strcmp(ksp->ks_module, "cpu") == 0 &&
7437c478bd9Sstevel@tonic-gate 		    strcmp(ksp->ks_name, "sys") == 0 &&
7447c478bd9Sstevel@tonic-gate 		    kstat_read(kc, ksp, NULL) != -1) {
7457c478bd9Sstevel@tonic-gate 			kstat_copy(ksp, &cpu_stats_list[ncpus].sys,
7467c478bd9Sstevel@tonic-gate 			    1);
7477c478bd9Sstevel@tonic-gate 			if ((ksp = kstat_lookup(kc, "cpu", ksp->ks_instance,
7487c478bd9Sstevel@tonic-gate 			    "vm")) != NULL && kstat_read(kc, ksp, NULL) != -1)
7497c478bd9Sstevel@tonic-gate 				kstat_copy(ksp, &cpu_stats_list[ncpus].vm, 1);
7507c478bd9Sstevel@tonic-gate 			else
7517c478bd9Sstevel@tonic-gate 				fail(0, "couldn't find per-CPU VM statistics");
7527c478bd9Sstevel@tonic-gate 			ncpus++;
7537c478bd9Sstevel@tonic-gate 		    }
7547c478bd9Sstevel@tonic-gate 
7557c478bd9Sstevel@tonic-gate 	if (ncpus == 0)
7567c478bd9Sstevel@tonic-gate 		fail(0, "couldn't find per-CPU statistics");
7577c478bd9Sstevel@tonic-gate }
7587c478bd9Sstevel@tonic-gate 
7597c478bd9Sstevel@tonic-gate /*
7607c478bd9Sstevel@tonic-gate  * load statistics, summing across CPUs where needed
7617c478bd9Sstevel@tonic-gate  */
7627c478bd9Sstevel@tonic-gate 
7637c478bd9Sstevel@tonic-gate static int
system_stat_load(void)7647c478bd9Sstevel@tonic-gate system_stat_load(void)
7657c478bd9Sstevel@tonic-gate {
7667c478bd9Sstevel@tonic-gate 	int i, j;
7677c478bd9Sstevel@tonic-gate 	_cpu_stats_t cs;
7687c478bd9Sstevel@tonic-gate 	ulong_t *np, *tp;
7697c478bd9Sstevel@tonic-gate 
7707c478bd9Sstevel@tonic-gate 	/*
7717c478bd9Sstevel@tonic-gate 	 * Global statistics
7727c478bd9Sstevel@tonic-gate 	 */
7737c478bd9Sstevel@tonic-gate 
7747c478bd9Sstevel@tonic-gate 	safe_kstat_read(kc, system_misc_ksp, NULL);
7757c478bd9Sstevel@tonic-gate 
7767c478bd9Sstevel@tonic-gate 	/*
7777c478bd9Sstevel@tonic-gate 	 * Per-CPU statistics.
7787c478bd9Sstevel@tonic-gate 	 */
7797c478bd9Sstevel@tonic-gate 
7807c478bd9Sstevel@tonic-gate 	for (i = 0; i < ncpus; i++) {
7817c478bd9Sstevel@tonic-gate 		if (kstat_read(kc, &cpu_stats_list[i].sys, NULL) == -1 ||
7827c478bd9Sstevel@tonic-gate 		    kstat_read(kc, &cpu_stats_list[i].vm, NULL) == -1)
7837c478bd9Sstevel@tonic-gate 			return (1);
7847c478bd9Sstevel@tonic-gate 		if (i == 0) {
7857c478bd9Sstevel@tonic-gate 			kstat_copy(&cpu_stats_list[0].sys, &cpu_stats_all.sys,
7867c478bd9Sstevel@tonic-gate 			    1);
7877c478bd9Sstevel@tonic-gate 			kstat_copy(&cpu_stats_list[0].vm, &cpu_stats_all.vm, 1);
7887c478bd9Sstevel@tonic-gate 		} else {
7897c478bd9Sstevel@tonic-gate 			kstat_named_t *nkp;
7907c478bd9Sstevel@tonic-gate 			kstat_named_t *tkp;
7917c478bd9Sstevel@tonic-gate 
7927c478bd9Sstevel@tonic-gate 			/*
7937c478bd9Sstevel@tonic-gate 			 * Other CPUs' statistics are accumulated in
7947c478bd9Sstevel@tonic-gate 			 * cpu_stats_all, initialized at the first iteration of
7957c478bd9Sstevel@tonic-gate 			 * the loop.
7967c478bd9Sstevel@tonic-gate 			 */
7977c478bd9Sstevel@tonic-gate 			nkp = (kstat_named_t *)cpu_stats_all.sys.ks_data;
7987c478bd9Sstevel@tonic-gate 			tkp = (kstat_named_t *)cpu_stats_list[i].sys.ks_data;
7997c478bd9Sstevel@tonic-gate 			for (j = 0; j < cpu_stats_list[i].sys.ks_ndata; j++)
8007c478bd9Sstevel@tonic-gate 				(nkp++)->value.ui64 += (tkp++)->value.ui64;
8017c478bd9Sstevel@tonic-gate 			nkp = (kstat_named_t *)cpu_stats_all.vm.ks_data;
8027c478bd9Sstevel@tonic-gate 			tkp = (kstat_named_t *)cpu_stats_list[i].vm.ks_data;
8037c478bd9Sstevel@tonic-gate 			for (j = 0; j < cpu_stats_list[i].vm.ks_ndata; j++)
8047c478bd9Sstevel@tonic-gate 				(nkp++)->value.ui64 += (tkp++)->value.ui64;
8057c478bd9Sstevel@tonic-gate 		}
8067c478bd9Sstevel@tonic-gate 	}
8077c478bd9Sstevel@tonic-gate 	return (0);
8087c478bd9Sstevel@tonic-gate }
8097c478bd9Sstevel@tonic-gate 
8107c478bd9Sstevel@tonic-gate static int
kscmp(kstat_t * ks1,kstat_t * ks2)8117c478bd9Sstevel@tonic-gate kscmp(kstat_t *ks1, kstat_t *ks2)
8127c478bd9Sstevel@tonic-gate {
8137c478bd9Sstevel@tonic-gate 	int cmp;
8147c478bd9Sstevel@tonic-gate 
8157c478bd9Sstevel@tonic-gate 	cmp = strcmp(ks1->ks_module, ks2->ks_module);
8167c478bd9Sstevel@tonic-gate 	if (cmp != 0)
8177c478bd9Sstevel@tonic-gate 		return (cmp);
8187c478bd9Sstevel@tonic-gate 	cmp = ks1->ks_instance - ks2->ks_instance;
8197c478bd9Sstevel@tonic-gate 	if (cmp != 0)
8207c478bd9Sstevel@tonic-gate 		return (cmp);
8217c478bd9Sstevel@tonic-gate 	return (strcmp(ks1->ks_name, ks2->ks_name));
8227c478bd9Sstevel@tonic-gate }
8237c478bd9Sstevel@tonic-gate 
8247c478bd9Sstevel@tonic-gate static void
init_disks(void)8257c478bd9Sstevel@tonic-gate init_disks(void)
8267c478bd9Sstevel@tonic-gate {
8277c478bd9Sstevel@tonic-gate 	struct diskinfo *disk, *prevdisk, *comp;
8287c478bd9Sstevel@tonic-gate 	kstat_t *ksp;
8297c478bd9Sstevel@tonic-gate 
8307c478bd9Sstevel@tonic-gate 	ndisks = 0;
8317c478bd9Sstevel@tonic-gate 	disk = &zerodisk;
8327c478bd9Sstevel@tonic-gate 
8337c478bd9Sstevel@tonic-gate 	/*
8347c478bd9Sstevel@tonic-gate 	 * Patch the snip in the diskinfo list (see below)
8357c478bd9Sstevel@tonic-gate 	 */
8367c478bd9Sstevel@tonic-gate 	if (snip)
8377c478bd9Sstevel@tonic-gate 		lastdisk->next = snip;
8387c478bd9Sstevel@tonic-gate 
8397c478bd9Sstevel@tonic-gate 	for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
8407c478bd9Sstevel@tonic-gate 
8417c478bd9Sstevel@tonic-gate 		if (ksp->ks_type != KSTAT_TYPE_IO ||
8427c478bd9Sstevel@tonic-gate 		    strcmp(ksp->ks_class, "disk") != 0)
8437c478bd9Sstevel@tonic-gate 			continue;
8447c478bd9Sstevel@tonic-gate 		prevdisk = disk;
8457c478bd9Sstevel@tonic-gate 		if (disk->next)
8467c478bd9Sstevel@tonic-gate 			disk = disk->next;
8477c478bd9Sstevel@tonic-gate 		else {
8487c478bd9Sstevel@tonic-gate 			safe_zalloc((void **)&disk->next,
8497c478bd9Sstevel@tonic-gate 			    sizeof (struct diskinfo), 0);
8507c478bd9Sstevel@tonic-gate 			disk = disk->next;
8517c478bd9Sstevel@tonic-gate 			disk->next = NULLDISK;
8527c478bd9Sstevel@tonic-gate 		}
8537c478bd9Sstevel@tonic-gate 		disk->ks = ksp;
8547c478bd9Sstevel@tonic-gate 		memset((void *)&disk->kios, 0, sizeof (kstat_io_t));
8557c478bd9Sstevel@tonic-gate 		disk->kios.wlastupdate = disk->ks->ks_crtime;
8567c478bd9Sstevel@tonic-gate 		disk->kios.rlastupdate = disk->ks->ks_crtime;
8577c478bd9Sstevel@tonic-gate 
8587c478bd9Sstevel@tonic-gate 		/*
8597c478bd9Sstevel@tonic-gate 		 * Insertion sort on (ks_module, ks_instance, ks_name)
8607c478bd9Sstevel@tonic-gate 		 */
8617c478bd9Sstevel@tonic-gate 		comp = &zerodisk;
8627c478bd9Sstevel@tonic-gate 		while (kscmp(disk->ks, comp->next->ks) > 0)
8637c478bd9Sstevel@tonic-gate 			comp = comp->next;
8647c478bd9Sstevel@tonic-gate 		if (prevdisk != comp) {
8657c478bd9Sstevel@tonic-gate 			prevdisk->next = disk->next;
8667c478bd9Sstevel@tonic-gate 			disk->next = comp->next;
8677c478bd9Sstevel@tonic-gate 			comp->next = disk;
8687c478bd9Sstevel@tonic-gate 			disk = prevdisk;
8697c478bd9Sstevel@tonic-gate 		}
8707c478bd9Sstevel@tonic-gate 		ndisks++;
8717c478bd9Sstevel@tonic-gate 	}
8727c478bd9Sstevel@tonic-gate 	/*
8737c478bd9Sstevel@tonic-gate 	 * Put a snip in the linked list of diskinfos.  The idea:
8747c478bd9Sstevel@tonic-gate 	 * If there was a state change such that now there are fewer
8757c478bd9Sstevel@tonic-gate 	 * disks, we snip the list and retain the tail, rather than
8767c478bd9Sstevel@tonic-gate 	 * freeing it.  At the next state change, we clip the tail back on.
8777c478bd9Sstevel@tonic-gate 	 * This prevents a lot of malloc/free activity, and it's simpler.
8787c478bd9Sstevel@tonic-gate 	 */
8797c478bd9Sstevel@tonic-gate 	lastdisk = disk;
8807c478bd9Sstevel@tonic-gate 	snip = disk->next;
8817c478bd9Sstevel@tonic-gate 	disk->next = NULLDISK;
8827c478bd9Sstevel@tonic-gate 
8837c478bd9Sstevel@tonic-gate 	firstdisk = zerodisk.next;
8847c478bd9Sstevel@tonic-gate 
8857c478bd9Sstevel@tonic-gate 	if (ndisks > stats_s4.dk_xfer.dk_xfer_len) {
8867c478bd9Sstevel@tonic-gate 		stats_s4.dk_xfer.dk_xfer_len = ndisks;
8877c478bd9Sstevel@tonic-gate 		safe_zalloc((void **)&stats_s4.dk_xfer.dk_xfer_val,
8887c478bd9Sstevel@tonic-gate 			ndisks * sizeof (int), 1);
8897c478bd9Sstevel@tonic-gate 	}
8907c478bd9Sstevel@tonic-gate }
8917c478bd9Sstevel@tonic-gate 
8927c478bd9Sstevel@tonic-gate static int
diskinfo_load(void)8937c478bd9Sstevel@tonic-gate diskinfo_load(void)
8947c478bd9Sstevel@tonic-gate {
8957c478bd9Sstevel@tonic-gate 	struct diskinfo *disk;
8967c478bd9Sstevel@tonic-gate 	int i;
8977c478bd9Sstevel@tonic-gate 
8987c478bd9Sstevel@tonic-gate 	for (disk = firstdisk, i = 0; disk; disk = disk->next, i++) {
8997c478bd9Sstevel@tonic-gate 		if (kstat_read(kc, disk->ks, (void *)&disk->kios) == -1)
9007c478bd9Sstevel@tonic-gate 			return (1);
9017c478bd9Sstevel@tonic-gate 		stats_s4.dk_xfer.dk_xfer_val[i] = disk->kios.reads +
9027c478bd9Sstevel@tonic-gate 			disk->kios.writes;
9037c478bd9Sstevel@tonic-gate 	}
9047c478bd9Sstevel@tonic-gate 	return (0);
9057c478bd9Sstevel@tonic-gate }
9067c478bd9Sstevel@tonic-gate 
9077c478bd9Sstevel@tonic-gate static void
init_net(void)9087c478bd9Sstevel@tonic-gate init_net(void)
9097c478bd9Sstevel@tonic-gate {
9107c478bd9Sstevel@tonic-gate 	static int sd;
9117c478bd9Sstevel@tonic-gate 	mib_item_t *item;
9127c478bd9Sstevel@tonic-gate 	mib2_ipAddrEntry_t *ap;
9137c478bd9Sstevel@tonic-gate 	char namebuf[KSTAT_STRLEN];
9147c478bd9Sstevel@tonic-gate 	struct netinfo *net, *prevnet, *comp;
9157c478bd9Sstevel@tonic-gate 	kstat_t *ksp;
9167c478bd9Sstevel@tonic-gate 
9177c478bd9Sstevel@tonic-gate 	if (sd) {
9187c478bd9Sstevel@tonic-gate 		close(sd);
9197c478bd9Sstevel@tonic-gate 	}
9207c478bd9Sstevel@tonic-gate 	while (netstat_item) {
9217c478bd9Sstevel@tonic-gate 		item = netstat_item;
9227c478bd9Sstevel@tonic-gate 		netstat_item = netstat_item->next_item;
9237c478bd9Sstevel@tonic-gate 		if (item->valp) {
9247c478bd9Sstevel@tonic-gate 			free(item->valp);
9257c478bd9Sstevel@tonic-gate 		}
9267c478bd9Sstevel@tonic-gate 		free(item);
9277c478bd9Sstevel@tonic-gate 	}
9287c478bd9Sstevel@tonic-gate 	sd = mibopen();
9297c478bd9Sstevel@tonic-gate 	if (sd == -1) {
9307c478bd9Sstevel@tonic-gate #ifdef DEBUG
9317c478bd9Sstevel@tonic-gate 		fprintf(stderr, "mibopen() failed\n");
9327c478bd9Sstevel@tonic-gate #endif
9337c478bd9Sstevel@tonic-gate 		sd = 0;
9347c478bd9Sstevel@tonic-gate 	} else {
9357c478bd9Sstevel@tonic-gate 		if ((netstat_item = mibget(sd)) == NULL) {
9367c478bd9Sstevel@tonic-gate #ifdef DEBUG
9377c478bd9Sstevel@tonic-gate 			fprintf(stderr, "mibget() failed\n");
9387c478bd9Sstevel@tonic-gate #endif
9397c478bd9Sstevel@tonic-gate 			close(sd);
9407c478bd9Sstevel@tonic-gate 			sd = 0;
9417c478bd9Sstevel@tonic-gate 		}
9427c478bd9Sstevel@tonic-gate 	}
9437c478bd9Sstevel@tonic-gate #ifdef DEBUG
9447c478bd9Sstevel@tonic-gate 	fprintf(stderr, "mibget returned item: %x\n", netstat_item);
9457c478bd9Sstevel@tonic-gate #endif
9467c478bd9Sstevel@tonic-gate 
9477c478bd9Sstevel@tonic-gate 	nnets = 0;
9487c478bd9Sstevel@tonic-gate 	net = &zeronet;
9497c478bd9Sstevel@tonic-gate 
9507c478bd9Sstevel@tonic-gate 	if (netsnip)
9517c478bd9Sstevel@tonic-gate 		lastnet->next = netsnip;
9527c478bd9Sstevel@tonic-gate 
9537c478bd9Sstevel@tonic-gate 	for (item = netstat_item; item; item = item->next_item) {
9547c478bd9Sstevel@tonic-gate #ifdef DEBUG_MIB
9557c478bd9Sstevel@tonic-gate 		fprintf(stderr, "\n--- Item %x ---\n", item);
9567c478bd9Sstevel@tonic-gate 		fprintf(stderr,
9577c478bd9Sstevel@tonic-gate 		"Group = %d, mib_id = %d, length = %d, valp = 0x%x\n",
9587c478bd9Sstevel@tonic-gate 		item->group, item->mib_id, item->length,
9597c478bd9Sstevel@tonic-gate 		item->valp);
9607c478bd9Sstevel@tonic-gate #endif
9617c478bd9Sstevel@tonic-gate 		if (item->group != MIB2_IP || item->mib_id != MIB2_IP_20)
9627c478bd9Sstevel@tonic-gate 			continue;
9637c478bd9Sstevel@tonic-gate 		ap = (mib2_ipAddrEntry_t *)item->valp;
9647c478bd9Sstevel@tonic-gate 		for (; (char *)ap < item->valp + item->length; ap++) {
9657c478bd9Sstevel@tonic-gate 
9667c478bd9Sstevel@tonic-gate 			octetstr(namebuf, &ap->ipAdEntIfIndex, 'a');
9677c478bd9Sstevel@tonic-gate #ifdef DEBUG
9687c478bd9Sstevel@tonic-gate 			fprintf(stderr, "%s ", namebuf);
9697c478bd9Sstevel@tonic-gate #endif
9707c478bd9Sstevel@tonic-gate 			if (strlen(namebuf) == 0)
9717c478bd9Sstevel@tonic-gate 				continue;
9727c478bd9Sstevel@tonic-gate 			/*
9737c478bd9Sstevel@tonic-gate 			 * We found a device of interest.
9747c478bd9Sstevel@tonic-gate 			 * Now, let's see if there's a kstat for it.
975*d62bc4baSyz 			 * First we try to query the "link" kstats in case
976*d62bc4baSyz 			 * the link is renamed. If that fails, fallback
977*d62bc4baSyz 			 * to legacy ktats for those non-GLDv3 links.
9787c478bd9Sstevel@tonic-gate 			 */
979*d62bc4baSyz 			if (((ksp = kstat_lookup(kc, "link", 0, namebuf))
980*d62bc4baSyz 			    == NULL) && ((ksp = kstat_lookup(kc, NULL, -1,
981*d62bc4baSyz 			    namebuf)) == NULL)) {
9827c478bd9Sstevel@tonic-gate 				continue;
983*d62bc4baSyz 			}
9847c478bd9Sstevel@tonic-gate 			if (ksp->ks_type != KSTAT_TYPE_NAMED)
9857c478bd9Sstevel@tonic-gate 				continue;
9867c478bd9Sstevel@tonic-gate 			if (kstat_read(kc, ksp, NULL) == -1)
9877c478bd9Sstevel@tonic-gate 				continue;
9887c478bd9Sstevel@tonic-gate 			prevnet = net;
9897c478bd9Sstevel@tonic-gate 			if (net->next)
9907c478bd9Sstevel@tonic-gate 				net = net->next;
9917c478bd9Sstevel@tonic-gate 			else {
9927c478bd9Sstevel@tonic-gate 				safe_zalloc((void **)&net->next,
9937c478bd9Sstevel@tonic-gate 					sizeof (struct netinfo), 0);
9947c478bd9Sstevel@tonic-gate 				net = net->next;
9957c478bd9Sstevel@tonic-gate 				net->next = NULLNET;
9967c478bd9Sstevel@tonic-gate 			}
9977c478bd9Sstevel@tonic-gate 			net->ks = ksp;
9987c478bd9Sstevel@tonic-gate 			net->ipackets	= kstat_data_lookup(net->ks,
9997c478bd9Sstevel@tonic-gate 				"ipackets");
10007c478bd9Sstevel@tonic-gate 			net->opackets	= kstat_data_lookup(net->ks,
10017c478bd9Sstevel@tonic-gate 				"opackets");
10027c478bd9Sstevel@tonic-gate 			net->ierrors	= kstat_data_lookup(net->ks,
10037c478bd9Sstevel@tonic-gate 				"ierrors");
10047c478bd9Sstevel@tonic-gate 			net->oerrors	= kstat_data_lookup(net->ks,
10057c478bd9Sstevel@tonic-gate 				"oerrors");
10067c478bd9Sstevel@tonic-gate 			net->collisions	= kstat_data_lookup(net->ks,
10077c478bd9Sstevel@tonic-gate 				"collisions");
10087c478bd9Sstevel@tonic-gate 			/*
10097c478bd9Sstevel@tonic-gate 			 * Insertion sort on the name
10107c478bd9Sstevel@tonic-gate 			 */
10117c478bd9Sstevel@tonic-gate 			comp = &zeronet;
10127c478bd9Sstevel@tonic-gate 			while (strcmp(net->ks->ks_name,
10137c478bd9Sstevel@tonic-gate 			    comp->next->ks->ks_name) > 0)
10147c478bd9Sstevel@tonic-gate 				comp = comp->next;
10157c478bd9Sstevel@tonic-gate 			if (prevnet != comp) {
10167c478bd9Sstevel@tonic-gate 				prevnet->next = net->next;
10177c478bd9Sstevel@tonic-gate 				net->next = comp->next;
10187c478bd9Sstevel@tonic-gate 				comp->next = net;
10197c478bd9Sstevel@tonic-gate 				net = prevnet;
10207c478bd9Sstevel@tonic-gate 			}
10217c478bd9Sstevel@tonic-gate 			nnets++;
10227c478bd9Sstevel@tonic-gate 		}
10237c478bd9Sstevel@tonic-gate #ifdef DEBUG
10247c478bd9Sstevel@tonic-gate 		fprintf(stderr, "\n");
10257c478bd9Sstevel@tonic-gate #endif
10267c478bd9Sstevel@tonic-gate 	}
10277c478bd9Sstevel@tonic-gate 	/*
10287c478bd9Sstevel@tonic-gate 	 * Put a snip in the linked list of netinfos.  The idea:
10297c478bd9Sstevel@tonic-gate 	 * If there was a state change such that now there are fewer
10307c478bd9Sstevel@tonic-gate 	 * nets, we snip the list and retain the tail, rather than
10317c478bd9Sstevel@tonic-gate 	 * freeing it.  At the next state change, we clip the tail back on.
10327c478bd9Sstevel@tonic-gate 	 * This prevents a lot of malloc/free activity, and it's simpler.
10337c478bd9Sstevel@tonic-gate 	 */
10347c478bd9Sstevel@tonic-gate 	lastnet = net;
10357c478bd9Sstevel@tonic-gate 	netsnip = net->next;
10367c478bd9Sstevel@tonic-gate 	net->next = NULLNET;
10377c478bd9Sstevel@tonic-gate 
10387c478bd9Sstevel@tonic-gate 	firstnet = zeronet.next;
10397c478bd9Sstevel@tonic-gate }
10407c478bd9Sstevel@tonic-gate 
10417c478bd9Sstevel@tonic-gate static int
netinfo_load(void)10427c478bd9Sstevel@tonic-gate netinfo_load(void)
10437c478bd9Sstevel@tonic-gate {
10447c478bd9Sstevel@tonic-gate 	struct netinfo *net;
10457c478bd9Sstevel@tonic-gate 
10467c478bd9Sstevel@tonic-gate 	if (netstat_item == NULL) {
10477c478bd9Sstevel@tonic-gate #ifdef DEBUG
10487c478bd9Sstevel@tonic-gate 		fprintf(stderr, "No net stats\n");
10497c478bd9Sstevel@tonic-gate #endif
10507c478bd9Sstevel@tonic-gate 		return (0);
10517c478bd9Sstevel@tonic-gate 	}
10527c478bd9Sstevel@tonic-gate 
10537c478bd9Sstevel@tonic-gate 	stats_s4.if_ipackets =
10547c478bd9Sstevel@tonic-gate 	stats_s4.if_opackets =
10557c478bd9Sstevel@tonic-gate 	stats_s4.if_ierrors =
10567c478bd9Sstevel@tonic-gate 	stats_s4.if_oerrors =
10577c478bd9Sstevel@tonic-gate 	stats_s4.if_collisions = 0;
10587c478bd9Sstevel@tonic-gate 
10597c478bd9Sstevel@tonic-gate 	for (net = firstnet; net; net = net->next) {
10607c478bd9Sstevel@tonic-gate 		if (kstat_read(kc, net->ks, NULL) == -1)
10617c478bd9Sstevel@tonic-gate 			return (1);
10627c478bd9Sstevel@tonic-gate 		if (net->ipackets)
10637c478bd9Sstevel@tonic-gate 			stats_s4.if_ipackets	+= net->ipackets->value.ul;
10647c478bd9Sstevel@tonic-gate 		if (net->opackets)
10657c478bd9Sstevel@tonic-gate 			stats_s4.if_opackets	+= net->opackets->value.ul;
10667c478bd9Sstevel@tonic-gate 		if (net->ierrors)
10677c478bd9Sstevel@tonic-gate 			stats_s4.if_ierrors	+= net->ierrors->value.ul;
10687c478bd9Sstevel@tonic-gate 		if (net->oerrors)
10697c478bd9Sstevel@tonic-gate 			stats_s4.if_oerrors	+= net->oerrors->value.ul;
10707c478bd9Sstevel@tonic-gate 		if (net->collisions)
10717c478bd9Sstevel@tonic-gate 			stats_s4.if_collisions	+= net->collisions->value.ul;
10727c478bd9Sstevel@tonic-gate 	}
10737c478bd9Sstevel@tonic-gate #ifdef DEBUG
10747c478bd9Sstevel@tonic-gate 	fprintf(stderr,
10757c478bd9Sstevel@tonic-gate 	    "ipackets: %d opackets: %d ierrors: %d oerrors: %d colls: %d\n",
10767c478bd9Sstevel@tonic-gate 		stats_s4.if_ipackets,
10777c478bd9Sstevel@tonic-gate 		stats_s4.if_opackets,
10787c478bd9Sstevel@tonic-gate 		stats_s4.if_ierrors,
10797c478bd9Sstevel@tonic-gate 		stats_s4.if_oerrors,
10807c478bd9Sstevel@tonic-gate 		stats_s4.if_collisions);
10817c478bd9Sstevel@tonic-gate #endif
10827c478bd9Sstevel@tonic-gate 	return (0);
10837c478bd9Sstevel@tonic-gate }
10847c478bd9Sstevel@tonic-gate 
10857c478bd9Sstevel@tonic-gate static void
kstat_copy(kstat_t * src,kstat_t * dst,int fr)10867c478bd9Sstevel@tonic-gate kstat_copy(kstat_t *src, kstat_t *dst, int fr)
10877c478bd9Sstevel@tonic-gate {
10887c478bd9Sstevel@tonic-gate 	if (fr)
10897c478bd9Sstevel@tonic-gate 		free(dst->ks_data);
10907c478bd9Sstevel@tonic-gate 	*dst = *src;
10917c478bd9Sstevel@tonic-gate 	if (src->ks_data != NULL) {
10927c478bd9Sstevel@tonic-gate 		safe_zalloc(&dst->ks_data, src->ks_data_size, 0);
10937c478bd9Sstevel@tonic-gate 		(void) memcpy(dst->ks_data, src->ks_data, src->ks_data_size);
10947c478bd9Sstevel@tonic-gate 	} else {
10957c478bd9Sstevel@tonic-gate 		dst->ks_data = NULL;
10967c478bd9Sstevel@tonic-gate 		dst->ks_data_size = 0;
10977c478bd9Sstevel@tonic-gate 	}
10987c478bd9Sstevel@tonic-gate }
1099