xref: /onnv-gate/usr/src/cmd/rpcsvc/rstat_proc.c (revision 5895:f251acdd9bdc)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*5895Syz147064  * Common Development and Distribution License (the "License").
6*5895Syz147064  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*5895Syz147064  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
270Sstevel@tonic-gate 
280Sstevel@tonic-gate /*
290Sstevel@tonic-gate  * rstat service:  built with rstat.x
300Sstevel@tonic-gate  */
310Sstevel@tonic-gate 
320Sstevel@tonic-gate #include <stdio.h>
330Sstevel@tonic-gate #include <stdlib.h>
340Sstevel@tonic-gate #include <stdarg.h>
350Sstevel@tonic-gate #include <string.h>
360Sstevel@tonic-gate #include <signal.h>
370Sstevel@tonic-gate #include <utmpx.h>
380Sstevel@tonic-gate #include <nlist.h>
390Sstevel@tonic-gate #include <fcntl.h>
400Sstevel@tonic-gate #include <syslog.h>
410Sstevel@tonic-gate #include <kstat.h>
420Sstevel@tonic-gate 
430Sstevel@tonic-gate #include <rpc/rpc.h>
440Sstevel@tonic-gate 
450Sstevel@tonic-gate #include <sys/socket.h>
460Sstevel@tonic-gate #include <sys/cpuvar.h>
470Sstevel@tonic-gate #include <sys/sysinfo.h>
480Sstevel@tonic-gate #include <sys/systm.h>
490Sstevel@tonic-gate #include <errno.h>
500Sstevel@tonic-gate #include <sys/stropts.h>
510Sstevel@tonic-gate #include <sys/tihdr.h>
520Sstevel@tonic-gate #include <sys/sysmacros.h>
530Sstevel@tonic-gate 
540Sstevel@tonic-gate #include <net/if.h>
550Sstevel@tonic-gate #include <inet/mib2.h>
560Sstevel@tonic-gate 
570Sstevel@tonic-gate #include "rstat.h"
580Sstevel@tonic-gate #include "rstat_v2.h"
590Sstevel@tonic-gate 
600Sstevel@tonic-gate typedef struct {
610Sstevel@tonic-gate 	kstat_t	sys;
620Sstevel@tonic-gate 	kstat_t	vm;
630Sstevel@tonic-gate } _cpu_stats_t;
640Sstevel@tonic-gate 
650Sstevel@tonic-gate /*
660Sstevel@tonic-gate  *	system and cpu stats
670Sstevel@tonic-gate  */
680Sstevel@tonic-gate static	kstat_ctl_t	*kc;		/* libkstat cookie */
690Sstevel@tonic-gate static	int	ncpus;
700Sstevel@tonic-gate static	_cpu_stats_t	*cpu_stats_list = NULL;
710Sstevel@tonic-gate static	kstat_t	*system_misc_ksp;
720Sstevel@tonic-gate static	kstat_named_t *boot_time_knp;
730Sstevel@tonic-gate static	kstat_named_t *avenrun_1min_knp, *avenrun_5min_knp, *avenrun_15min_knp;
740Sstevel@tonic-gate static	int	hz;
750Sstevel@tonic-gate static	struct	timeval btm;		/* boottime */
760Sstevel@tonic-gate 
770Sstevel@tonic-gate /*
780Sstevel@tonic-gate  *	network interface stats
790Sstevel@tonic-gate  */
800Sstevel@tonic-gate 
810Sstevel@tonic-gate typedef struct mib_item_s {
820Sstevel@tonic-gate 	struct mib_item_s	*next_item;
830Sstevel@tonic-gate 	long			group;
840Sstevel@tonic-gate 	long			mib_id;
850Sstevel@tonic-gate 	long			length;
860Sstevel@tonic-gate 	char			*valp;
870Sstevel@tonic-gate } mib_item_t;
880Sstevel@tonic-gate 
890Sstevel@tonic-gate mib_item_t	*netstat_item;
900Sstevel@tonic-gate 
910Sstevel@tonic-gate /*
920Sstevel@tonic-gate  * disk stats
930Sstevel@tonic-gate  */
940Sstevel@tonic-gate 
950Sstevel@tonic-gate struct diskinfo {
960Sstevel@tonic-gate 	struct diskinfo *next;
970Sstevel@tonic-gate 	kstat_t *ks;
980Sstevel@tonic-gate 	kstat_io_t kios;
990Sstevel@tonic-gate };
1000Sstevel@tonic-gate 
1010Sstevel@tonic-gate #define	NULLDISK (struct diskinfo *)0
1020Sstevel@tonic-gate static	struct diskinfo zerodisk = { NULL, NULL };
1030Sstevel@tonic-gate static	struct diskinfo *firstdisk = NULLDISK;
1040Sstevel@tonic-gate static	struct diskinfo *lastdisk = NULLDISK;
1050Sstevel@tonic-gate static	struct diskinfo *snip = NULLDISK;
1060Sstevel@tonic-gate static	int ndisks;
1070Sstevel@tonic-gate 
1080Sstevel@tonic-gate /*
1090Sstevel@tonic-gate  * net stats
1100Sstevel@tonic-gate  */
1110Sstevel@tonic-gate 
1120Sstevel@tonic-gate struct netinfo {
1130Sstevel@tonic-gate 	struct netinfo *next;
1140Sstevel@tonic-gate 	kstat_t	*ks;
1150Sstevel@tonic-gate 	kstat_named_t *ipackets;
1160Sstevel@tonic-gate 	kstat_named_t *opackets;
1170Sstevel@tonic-gate 	kstat_named_t *ierrors;
1180Sstevel@tonic-gate 	kstat_named_t *oerrors;
1190Sstevel@tonic-gate 	kstat_named_t *collisions;
1200Sstevel@tonic-gate };
1210Sstevel@tonic-gate 
1220Sstevel@tonic-gate #define	NULLNET (struct netinfo *)0
1230Sstevel@tonic-gate static	struct netinfo zeronet = { NULL, NULL, NULL, NULL, NULL, NULL, NULL };
1240Sstevel@tonic-gate static	struct netinfo *firstnet = NULLNET;
1250Sstevel@tonic-gate static	struct netinfo *lastnet = NULLNET;
1260Sstevel@tonic-gate static	struct netinfo *netsnip = NULLNET;
1270Sstevel@tonic-gate static	int nnets;
1280Sstevel@tonic-gate 
1290Sstevel@tonic-gate /*
1300Sstevel@tonic-gate  *  Define EXIT_WHEN_IDLE if you are able to have this program invoked
1310Sstevel@tonic-gate  *  automatically on demand (as from inetd).  When defined, the service
1320Sstevel@tonic-gate  *  will terminated after being idle for 120 seconds.
1330Sstevel@tonic-gate  */
1340Sstevel@tonic-gate 
1350Sstevel@tonic-gate #define	EXIT_WHEN_IDLE	1
1360Sstevel@tonic-gate 
1370Sstevel@tonic-gate int sincelastreq = 0;		/* number of alarms since last request */
1380Sstevel@tonic-gate #ifdef EXIT_WHEN_IDLE
1390Sstevel@tonic-gate #define	CLOSEDOWN 120		/* how long to wait before exiting */
1400Sstevel@tonic-gate #endif /* def EXIT_WHEN_IDLE */
1410Sstevel@tonic-gate 
1420Sstevel@tonic-gate statstime stats_s3;
1430Sstevel@tonic-gate statsvar stats_s4;
1440Sstevel@tonic-gate /* V2 support for backwards compatibility to pre-5.0 systems */
1450Sstevel@tonic-gate statsswtch stats_s2;
1460Sstevel@tonic-gate 
147631Speteh static int stat_is_init = 0;
1480Sstevel@tonic-gate 
1490Sstevel@tonic-gate static	void	fail(int, char *, ...);
1500Sstevel@tonic-gate static	void	safe_zalloc(void **, int, int);
1510Sstevel@tonic-gate static	kid_t	safe_kstat_read(kstat_ctl_t *, kstat_t *, void *);
1520Sstevel@tonic-gate static	kstat_t	*safe_kstat_lookup(kstat_ctl_t *, char *, int, char *);
1530Sstevel@tonic-gate static	void	*safe_kstat_data_lookup(kstat_t *, char *);
1540Sstevel@tonic-gate static	void	system_stat_init(void);
1550Sstevel@tonic-gate static	int	system_stat_load(void);
1560Sstevel@tonic-gate static	void	init_disks(void);
1570Sstevel@tonic-gate static	int	diskinfo_load(void);
1580Sstevel@tonic-gate static	void	init_net(void);
1590Sstevel@tonic-gate static	int	netinfo_load(void);
1600Sstevel@tonic-gate 
1610Sstevel@tonic-gate static	void	updatestat(int);
1620Sstevel@tonic-gate 
1630Sstevel@tonic-gate static	mib_item_t	*mibget(int sd);
1640Sstevel@tonic-gate static	int	mibopen(void);
1650Sstevel@tonic-gate static  char	*octetstr(char *buf, Octet_t *op, int code);
1660Sstevel@tonic-gate 
1670Sstevel@tonic-gate static	void	kstat_copy(kstat_t *, kstat_t *, int);
1680Sstevel@tonic-gate 
1690Sstevel@tonic-gate static	char	*cmdname = "rpc.rstatd";
1700Sstevel@tonic-gate 
1710Sstevel@tonic-gate #define	CPU_STAT(ksp, name)	(((kstat_named_t *)safe_kstat_data_lookup( \
1720Sstevel@tonic-gate 				    (ksp), (name)))->value.ui64)
1730Sstevel@tonic-gate static	_cpu_stats_t	cpu_stats_all = { 0 };
1740Sstevel@tonic-gate 
1750Sstevel@tonic-gate static void
stat_init(void)1760Sstevel@tonic-gate stat_init(void)
1770Sstevel@tonic-gate {
1780Sstevel@tonic-gate 	struct utmpx *utmpx, utmpx_id;
1790Sstevel@tonic-gate 
1800Sstevel@tonic-gate 	stat_is_init = 1;
1810Sstevel@tonic-gate 
1820Sstevel@tonic-gate 	if ((kc = kstat_open()) == NULL)
1830Sstevel@tonic-gate 		fail(1, "kstat_open(): can't open /dev/kstat");
1840Sstevel@tonic-gate 
1850Sstevel@tonic-gate 	/*
1860Sstevel@tonic-gate 	 * Preallocate minimal set of drive entries.
1870Sstevel@tonic-gate 	 */
1880Sstevel@tonic-gate 
1890Sstevel@tonic-gate 	if (stats_s4.dk_xfer.dk_xfer_val == NULL) {
1900Sstevel@tonic-gate 		stats_s4.dk_xfer.dk_xfer_len = RSTAT_DK_NDRIVE;
1910Sstevel@tonic-gate 		stats_s4.dk_xfer.dk_xfer_val =
1920Sstevel@tonic-gate 		    (int *)calloc(RSTAT_DK_NDRIVE, sizeof (int));
1930Sstevel@tonic-gate 	}
1940Sstevel@tonic-gate 
1950Sstevel@tonic-gate 	system_stat_init();
1960Sstevel@tonic-gate 	init_disks();
1970Sstevel@tonic-gate 	init_net();
1980Sstevel@tonic-gate 
1990Sstevel@tonic-gate 	/*
2000Sstevel@tonic-gate 	 * To get the boot time, use utmpx, which is per-zone, but fall back
2010Sstevel@tonic-gate 	 * to the system-wide kstat if utmpx is hosed for any reason.
2020Sstevel@tonic-gate 	 */
2030Sstevel@tonic-gate 	utmpx_id.ut_type = BOOT_TIME;
2040Sstevel@tonic-gate 	if ((utmpx = getutxid(&utmpx_id)) != NULL)
2050Sstevel@tonic-gate 		btm = utmpx->ut_tv;
2060Sstevel@tonic-gate 	else {
2070Sstevel@tonic-gate 		btm.tv_sec = boot_time_knp->value.ul;
2080Sstevel@tonic-gate 		btm.tv_usec = 0; /* don't bother with usecs for boot time */
2090Sstevel@tonic-gate 	}
2100Sstevel@tonic-gate 	endutxent();
2110Sstevel@tonic-gate 	stats_s4.boottime.tv_sec =
2120Sstevel@tonic-gate 		stats_s2.boottime.tv_sec =
2130Sstevel@tonic-gate 		stats_s3.boottime.tv_sec = btm.tv_sec;
2140Sstevel@tonic-gate 	stats_s4.boottime.tv_usec =
2150Sstevel@tonic-gate 		stats_s2.boottime.tv_usec =
2160Sstevel@tonic-gate 		stats_s3.boottime.tv_usec = btm.tv_usec;
2170Sstevel@tonic-gate 
2180Sstevel@tonic-gate 	updatestat(0);
2190Sstevel@tonic-gate 	alarm(1);
2200Sstevel@tonic-gate 	signal(SIGALRM, updatestat);
2210Sstevel@tonic-gate 	sleep(2);		/* allow for one wake-up */
2220Sstevel@tonic-gate }
2230Sstevel@tonic-gate 
2240Sstevel@tonic-gate statsvar *
rstatproc_stats_4_svc(argp,svcrq)2250Sstevel@tonic-gate rstatproc_stats_4_svc(argp, svcrq)
2260Sstevel@tonic-gate void *argp;
2270Sstevel@tonic-gate struct svc_req *svcrq;
2280Sstevel@tonic-gate {
2290Sstevel@tonic-gate 	if (! stat_is_init)
2300Sstevel@tonic-gate 		stat_init();
2310Sstevel@tonic-gate #ifdef EXIT_WHEN_IDLE
2320Sstevel@tonic-gate 	sincelastreq = 0;
2330Sstevel@tonic-gate #endif
2340Sstevel@tonic-gate 	return (&stats_s4);
2350Sstevel@tonic-gate }
2360Sstevel@tonic-gate 
2370Sstevel@tonic-gate statstime *
rstatproc_stats_3_svc(argp,svcrq)2380Sstevel@tonic-gate rstatproc_stats_3_svc(argp, svcrq)
2390Sstevel@tonic-gate void *argp;
2400Sstevel@tonic-gate struct svc_req *svcrq;
2410Sstevel@tonic-gate {
2420Sstevel@tonic-gate 	if (! stat_is_init)
2430Sstevel@tonic-gate 		stat_init();
2440Sstevel@tonic-gate #ifdef EXIT_WHEN_IDLE
2450Sstevel@tonic-gate 	sincelastreq = 0;
2460Sstevel@tonic-gate #endif
2470Sstevel@tonic-gate 	return (&stats_s3);
2480Sstevel@tonic-gate }
2490Sstevel@tonic-gate 
2500Sstevel@tonic-gate statsswtch *
rstatproc_stats_2_svc(argp,svcrq)2510Sstevel@tonic-gate rstatproc_stats_2_svc(argp, svcrq)
2520Sstevel@tonic-gate void *argp;
2530Sstevel@tonic-gate struct svc_req *svcrq;
2540Sstevel@tonic-gate {
2550Sstevel@tonic-gate 	if (! stat_is_init)
2560Sstevel@tonic-gate 		stat_init();
2570Sstevel@tonic-gate #ifdef EXIT_WHEN_IDLE
2580Sstevel@tonic-gate 	sincelastreq = 0;
2590Sstevel@tonic-gate #endif
2600Sstevel@tonic-gate 	return (&stats_s2);
2610Sstevel@tonic-gate }
2620Sstevel@tonic-gate 
2630Sstevel@tonic-gate 
2640Sstevel@tonic-gate uint_t *
rstatproc_havedisk_4_svc(argp,svcrq)2650Sstevel@tonic-gate rstatproc_havedisk_4_svc(argp, svcrq)
2660Sstevel@tonic-gate void *argp;
2670Sstevel@tonic-gate struct svc_req *svcrq;
2680Sstevel@tonic-gate {
2690Sstevel@tonic-gate 	return (rstatproc_havedisk_3_svc(argp, svcrq));
2700Sstevel@tonic-gate }
2710Sstevel@tonic-gate 
2720Sstevel@tonic-gate uint_t *
rstatproc_havedisk_3_svc(argp,svcrq)2730Sstevel@tonic-gate rstatproc_havedisk_3_svc(argp, svcrq)
2740Sstevel@tonic-gate void *argp;
2750Sstevel@tonic-gate struct svc_req *svcrq;
2760Sstevel@tonic-gate {
2770Sstevel@tonic-gate 	static uint_t have;
2780Sstevel@tonic-gate 
2790Sstevel@tonic-gate 	if (! stat_is_init)
2800Sstevel@tonic-gate 		stat_init();
2810Sstevel@tonic-gate #ifdef EXIT_WHEN_IDLE
2820Sstevel@tonic-gate 	sincelastreq = 0;
2830Sstevel@tonic-gate #endif
2840Sstevel@tonic-gate 	have = (ndisks != 0);
2850Sstevel@tonic-gate 	return (&have);
2860Sstevel@tonic-gate }
2870Sstevel@tonic-gate 
2880Sstevel@tonic-gate uint_t *
rstatproc_havedisk_2_svc(argp,svcrq)2890Sstevel@tonic-gate rstatproc_havedisk_2_svc(argp, svcrq)
2900Sstevel@tonic-gate void *argp;
2910Sstevel@tonic-gate struct svc_req *svcrq;
2920Sstevel@tonic-gate {
2930Sstevel@tonic-gate 	return (rstatproc_havedisk_3_svc(argp, svcrq));
2940Sstevel@tonic-gate }
2950Sstevel@tonic-gate 
2960Sstevel@tonic-gate void
updatestat(int ignored)2970Sstevel@tonic-gate updatestat(int ignored)
2980Sstevel@tonic-gate {
2990Sstevel@tonic-gate extern int _rpcpmstart;		 /* Started by a port monitor ? */
3000Sstevel@tonic-gate extern int _rpcsvcdirty;	 /* Still serving ? */
3010Sstevel@tonic-gate 
3020Sstevel@tonic-gate #ifdef DEBUG
3030Sstevel@tonic-gate 	fprintf(stderr, "entering updatestat\n");
3040Sstevel@tonic-gate #endif
3050Sstevel@tonic-gate #ifdef EXIT_WHEN_IDLE
3060Sstevel@tonic-gate 	if (_rpcpmstart && sincelastreq >= CLOSEDOWN && !_rpcsvcdirty) {
3070Sstevel@tonic-gate #ifdef DEBUG
3080Sstevel@tonic-gate 		fprintf(stderr, "about to closedown\n");
3090Sstevel@tonic-gate #endif
3100Sstevel@tonic-gate 		exit(0);
3110Sstevel@tonic-gate 	}
3120Sstevel@tonic-gate 	sincelastreq++;
3130Sstevel@tonic-gate #endif /* def EXIT_WHEN_IDLE */
3140Sstevel@tonic-gate 
3150Sstevel@tonic-gate 	(void) alarm(0);
3160Sstevel@tonic-gate #ifdef DEBUG
3170Sstevel@tonic-gate 	fprintf(stderr, "boottime: %d %d\n", stats_s3.boottime.tv_sec,
3180Sstevel@tonic-gate 		stats_s3.boottime.tv_usec);
3190Sstevel@tonic-gate #endif
3200Sstevel@tonic-gate 	while (system_stat_load() || diskinfo_load() || netinfo_load()) {
3210Sstevel@tonic-gate 		(void) kstat_chain_update(kc);
3220Sstevel@tonic-gate 		system_stat_init();
3230Sstevel@tonic-gate 		init_disks();
3240Sstevel@tonic-gate 		init_net();
3250Sstevel@tonic-gate 	}
3260Sstevel@tonic-gate 	stats_s4.cp_time.cp_time_len = CPU_STATES;
3270Sstevel@tonic-gate 	if (stats_s4.cp_time.cp_time_val == NULL)
3280Sstevel@tonic-gate 		stats_s4.cp_time.cp_time_val =
3290Sstevel@tonic-gate 		malloc(stats_s4.cp_time.cp_time_len * sizeof (int));
3300Sstevel@tonic-gate 	stats_s2.cp_time[RSTAT_CPU_USER] =
3310Sstevel@tonic-gate 	stats_s3.cp_time[RSTAT_CPU_USER] =
3320Sstevel@tonic-gate 	stats_s4.cp_time.cp_time_val[RSTAT_CPU_USER] =
3330Sstevel@tonic-gate 		CPU_STAT(&cpu_stats_all.sys, "cpu_ticks_user");
3340Sstevel@tonic-gate 	stats_s2.cp_time[RSTAT_CPU_NICE] =
3350Sstevel@tonic-gate 	stats_s3.cp_time[RSTAT_CPU_NICE] =
3360Sstevel@tonic-gate 	stats_s4.cp_time.cp_time_val[RSTAT_CPU_NICE] =
3370Sstevel@tonic-gate 		CPU_STAT(&cpu_stats_all.sys, "cpu_ticks_wait");
3380Sstevel@tonic-gate 	stats_s2.cp_time[RSTAT_CPU_SYS] =
3390Sstevel@tonic-gate 	stats_s3.cp_time[RSTAT_CPU_SYS] =
3400Sstevel@tonic-gate 	stats_s4.cp_time.cp_time_val[RSTAT_CPU_SYS] =
3410Sstevel@tonic-gate 		CPU_STAT(&cpu_stats_all.sys, "cpu_ticks_kernel");
3420Sstevel@tonic-gate 	stats_s2.cp_time[RSTAT_CPU_IDLE] =
3430Sstevel@tonic-gate 	stats_s3.cp_time[RSTAT_CPU_IDLE] =
3440Sstevel@tonic-gate 	stats_s4.cp_time.cp_time_val[RSTAT_CPU_IDLE] =
3450Sstevel@tonic-gate 		CPU_STAT(&cpu_stats_all.sys, "cpu_ticks_idle");
3460Sstevel@tonic-gate 
3470Sstevel@tonic-gate #ifdef DEBUG
3480Sstevel@tonic-gate 	fprintf(stderr, "cpu: %d %d %d %d\n",
3490Sstevel@tonic-gate 		CPU_STAT(&cpu_stats_all.sys, "cpu_ticks_user"),
3500Sstevel@tonic-gate 		CPU_STAT(&cpu_stats_all.sys, "cpu_ticks_wait"),
3510Sstevel@tonic-gate 		CPU_STAT(&cpu_stats_all.sys, "cpu_ticks_kernel"),
3520Sstevel@tonic-gate 		CPU_STAT(&cpu_stats_all.sys, "cpu_ticks_idle"));
3530Sstevel@tonic-gate 	fprintf(stderr, "cp_time: %d %d %d %d\n",
3540Sstevel@tonic-gate 		stats_s3.cp_time[RSTAT_CPU_USER],
3550Sstevel@tonic-gate 		stats_s3.cp_time[RSTAT_CPU_NICE],
3560Sstevel@tonic-gate 		stats_s3.cp_time[RSTAT_CPU_SYS],
3570Sstevel@tonic-gate 		stats_s3.cp_time[RSTAT_CPU_IDLE]);
3580Sstevel@tonic-gate #endif
3590Sstevel@tonic-gate 
3600Sstevel@tonic-gate 	/* current time */
3610Sstevel@tonic-gate 	gettimeofday((struct timeval *)&stats_s3.curtime, NULL);
3620Sstevel@tonic-gate 	stats_s4.curtime = stats_s3.curtime;
3630Sstevel@tonic-gate 
3640Sstevel@tonic-gate 	stats_s2.v_pgpgin =
3650Sstevel@tonic-gate 	stats_s3.v_pgpgin =
3660Sstevel@tonic-gate 	stats_s4.v_pgpgin = CPU_STAT(&cpu_stats_all.vm, "pgpgin");
3670Sstevel@tonic-gate 	stats_s2.v_pgpgout =
3680Sstevel@tonic-gate 	stats_s3.v_pgpgout =
3690Sstevel@tonic-gate 	stats_s4.v_pgpgout = CPU_STAT(&cpu_stats_all.vm, "pgpgout");
3700Sstevel@tonic-gate 	stats_s2.v_pswpin =
3710Sstevel@tonic-gate 	stats_s3.v_pswpin =
3720Sstevel@tonic-gate 	stats_s4.v_pswpin = CPU_STAT(&cpu_stats_all.vm, "pgswapin");
3730Sstevel@tonic-gate 	stats_s2.v_pswpout =
3740Sstevel@tonic-gate 	stats_s3.v_pswpout =
3750Sstevel@tonic-gate 	stats_s4.v_pswpout = CPU_STAT(&cpu_stats_all.vm, "pgswapout");
3760Sstevel@tonic-gate 	stats_s3.v_intr = CPU_STAT(&cpu_stats_all.sys, "intr");
3770Sstevel@tonic-gate 	stats_s3.v_intr -= hz*(stats_s3.curtime.tv_sec - btm.tv_sec) +
3780Sstevel@tonic-gate 		hz*(stats_s3.curtime.tv_usec - btm.tv_usec)/1000000;
3790Sstevel@tonic-gate 	stats_s2.v_intr =
3800Sstevel@tonic-gate 	stats_s4.v_intr = stats_s3.v_intr;
3810Sstevel@tonic-gate 	/* swtch not in V1 */
3820Sstevel@tonic-gate 	stats_s2.v_swtch =
3830Sstevel@tonic-gate 	stats_s3.v_swtch =
3840Sstevel@tonic-gate 	stats_s4.v_swtch = CPU_STAT(&cpu_stats_all.sys, "pswitch");
3850Sstevel@tonic-gate 
3860Sstevel@tonic-gate #ifdef DEBUG
3870Sstevel@tonic-gate 	fprintf(stderr,
3880Sstevel@tonic-gate 		"pgin: %d pgout: %d swpin: %d swpout: %d intr: %d swtch: %d\n",
3890Sstevel@tonic-gate 		stats_s3.v_pgpgin,
3900Sstevel@tonic-gate 		stats_s3.v_pgpgout,
3910Sstevel@tonic-gate 		stats_s3.v_pswpin,
3920Sstevel@tonic-gate 		stats_s3.v_pswpout,
3930Sstevel@tonic-gate 		stats_s3.v_intr,
3940Sstevel@tonic-gate 		stats_s3.v_swtch);
3950Sstevel@tonic-gate #endif
3960Sstevel@tonic-gate 	/*
3970Sstevel@tonic-gate 	 * V2 and V3 of rstat are limited to RSTAT_DK_NDRIVE drives
3980Sstevel@tonic-gate 	 */
3990Sstevel@tonic-gate 	memcpy(stats_s3.dk_xfer, stats_s4.dk_xfer.dk_xfer_val,
4000Sstevel@tonic-gate 		RSTAT_DK_NDRIVE * sizeof (int));
4010Sstevel@tonic-gate 	memcpy(stats_s2.dk_xfer, stats_s4.dk_xfer.dk_xfer_val,
4020Sstevel@tonic-gate 		RSTAT_DK_NDRIVE * sizeof (int));
4030Sstevel@tonic-gate #ifdef DEBUG
4040Sstevel@tonic-gate 	fprintf(stderr, "dk_xfer: %d %d %d %d\n",
4050Sstevel@tonic-gate 		stats_s4.dk_xfer.dk_xfer_val[0],
4060Sstevel@tonic-gate 		stats_s4.dk_xfer.dk_xfer_val[1],
4070Sstevel@tonic-gate 		stats_s4.dk_xfer.dk_xfer_val[2],
4080Sstevel@tonic-gate 		stats_s4.dk_xfer.dk_xfer_val[3]);
4090Sstevel@tonic-gate #endif
4100Sstevel@tonic-gate 
4110Sstevel@tonic-gate 	stats_s2.if_ipackets =
4120Sstevel@tonic-gate 	stats_s3.if_ipackets = stats_s4.if_ipackets;
4130Sstevel@tonic-gate 	/* no s2 opackets */
4140Sstevel@tonic-gate 	stats_s3.if_opackets = stats_s4.if_opackets;
4150Sstevel@tonic-gate 	stats_s2.if_ierrors =
4160Sstevel@tonic-gate 	stats_s3.if_ierrors = stats_s4.if_ierrors;
4170Sstevel@tonic-gate 	stats_s2.if_oerrors =
4180Sstevel@tonic-gate 	stats_s3.if_oerrors = stats_s4.if_oerrors;
4190Sstevel@tonic-gate 	stats_s2.if_collisions =
4200Sstevel@tonic-gate 	stats_s3.if_collisions = stats_s4.if_collisions;
4210Sstevel@tonic-gate 
4220Sstevel@tonic-gate 	stats_s2.avenrun[0] =
4230Sstevel@tonic-gate 	stats_s3.avenrun[0] =
4240Sstevel@tonic-gate 	stats_s4.avenrun[0] = avenrun_1min_knp->value.ul;
4250Sstevel@tonic-gate 	stats_s2.avenrun[1] =
4260Sstevel@tonic-gate 	stats_s3.avenrun[1] =
4270Sstevel@tonic-gate 	stats_s4.avenrun[1] = avenrun_5min_knp->value.ul;
4280Sstevel@tonic-gate 	stats_s2.avenrun[2] =
4290Sstevel@tonic-gate 	stats_s3.avenrun[2] =
4300Sstevel@tonic-gate 	stats_s4.avenrun[2] = avenrun_15min_knp->value.ul;
4310Sstevel@tonic-gate #ifdef DEBUG
4320Sstevel@tonic-gate 	fprintf(stderr, "avenrun: %d %d %d\n", stats_s3.avenrun[0],
4330Sstevel@tonic-gate 		stats_s3.avenrun[1], stats_s3.avenrun[2]);
4340Sstevel@tonic-gate #endif
4350Sstevel@tonic-gate 	signal(SIGALRM, updatestat);
4360Sstevel@tonic-gate 	alarm(1);
4370Sstevel@tonic-gate }
4380Sstevel@tonic-gate 
4390Sstevel@tonic-gate /* --------------------------------- MIBGET -------------------------------- */
4400Sstevel@tonic-gate 
4410Sstevel@tonic-gate static mib_item_t *
mibget(int sd)4420Sstevel@tonic-gate mibget(int sd)
4430Sstevel@tonic-gate {
4440Sstevel@tonic-gate 	int			flags;
4450Sstevel@tonic-gate 	int			j, getcode;
4460Sstevel@tonic-gate 	struct strbuf		ctlbuf, databuf;
4470Sstevel@tonic-gate 	char			buf[512];
4480Sstevel@tonic-gate 	struct T_optmgmt_req	*tor = (struct T_optmgmt_req *)buf;
4490Sstevel@tonic-gate 	struct T_optmgmt_ack	*toa = (struct T_optmgmt_ack *)buf;
4500Sstevel@tonic-gate 	struct T_error_ack	*tea = (struct T_error_ack *)buf;
4510Sstevel@tonic-gate 	struct opthdr		*req;
4520Sstevel@tonic-gate 	mib_item_t		*first_item = NULL;
4530Sstevel@tonic-gate 	mib_item_t		*last_item  = NULL;
4540Sstevel@tonic-gate 	mib_item_t		*temp;
4550Sstevel@tonic-gate 
4560Sstevel@tonic-gate 	tor->PRIM_type = T_SVR4_OPTMGMT_REQ;
4570Sstevel@tonic-gate 	tor->OPT_offset = sizeof (struct T_optmgmt_req);
4580Sstevel@tonic-gate 	tor->OPT_length = sizeof (struct opthdr);
4590Sstevel@tonic-gate 	tor->MGMT_flags = T_CURRENT;
4600Sstevel@tonic-gate 	req = (struct opthdr *)&tor[1];
4610Sstevel@tonic-gate 	req->level = MIB2_IP;		/* any MIB2_xxx value ok here */
4620Sstevel@tonic-gate 	req->name  = 0;
4630Sstevel@tonic-gate 	req->len   = 0;
4640Sstevel@tonic-gate 
4650Sstevel@tonic-gate 	ctlbuf.buf = buf;
4660Sstevel@tonic-gate 	ctlbuf.len = tor->OPT_length + tor->OPT_offset;
4670Sstevel@tonic-gate 	flags = 0;
4680Sstevel@tonic-gate 	if (putmsg(sd, &ctlbuf, NULL, flags) == -1) {
4690Sstevel@tonic-gate 		perror("mibget: putmsg(ctl) failed");
4700Sstevel@tonic-gate 		goto error_exit;
4710Sstevel@tonic-gate 	}
4720Sstevel@tonic-gate 	/*
4730Sstevel@tonic-gate 	 * each reply consists of a ctl part for one fixed structure
4740Sstevel@tonic-gate 	 * or table, as defined in mib2.h.  The format is a T_OPTMGMT_ACK,
4750Sstevel@tonic-gate 	 * containing an opthdr structure.  level/name identify the entry,
4760Sstevel@tonic-gate 	 * len is the size of the data part of the message.
4770Sstevel@tonic-gate 	 */
4780Sstevel@tonic-gate 	req = (struct opthdr *)&toa[1];
4790Sstevel@tonic-gate 	ctlbuf.maxlen = sizeof (buf);
4800Sstevel@tonic-gate 	/*CSTYLED*/
4810Sstevel@tonic-gate 	for (j = 1; ; j++) {
4820Sstevel@tonic-gate 		flags = 0;
4830Sstevel@tonic-gate 		getcode = getmsg(sd, &ctlbuf, NULL, &flags);
4840Sstevel@tonic-gate 		if (getcode == -1) {
4850Sstevel@tonic-gate #ifdef DEBUG_MIB
4860Sstevel@tonic-gate 			perror("mibget getmsg(ctl) failed");
4870Sstevel@tonic-gate 			fprintf(stderr, "#   level   name    len\n");
4880Sstevel@tonic-gate 			i = 0;
4890Sstevel@tonic-gate 			for (last_item = first_item; last_item;
4900Sstevel@tonic-gate 				last_item = last_item->next_item)
4910Sstevel@tonic-gate 				fprintf(stderr, "%d  %4d   %5d   %d\n", ++i,
4920Sstevel@tonic-gate 					last_item->group,
4930Sstevel@tonic-gate 					last_item->mib_id,
4940Sstevel@tonic-gate 					last_item->length);
4950Sstevel@tonic-gate #endif /* DEBUG_MIB */
4960Sstevel@tonic-gate 			goto error_exit;
4970Sstevel@tonic-gate 		}
4980Sstevel@tonic-gate 		if (getcode == 0 &&
4990Sstevel@tonic-gate 			(ctlbuf.len >= sizeof (struct T_optmgmt_ack)) &&
5000Sstevel@tonic-gate 			(toa->PRIM_type == T_OPTMGMT_ACK) &&
5010Sstevel@tonic-gate 			(toa->MGMT_flags == T_SUCCESS) &&
5020Sstevel@tonic-gate 			req->len == 0) {
5030Sstevel@tonic-gate #ifdef DEBUG_MIB
5040Sstevel@tonic-gate 			fprintf(stderr,
5050Sstevel@tonic-gate 		"mibget getmsg() %d returned EOD (level %d, name %d)\n",
5060Sstevel@tonic-gate 				j, req->level, req->name);
5070Sstevel@tonic-gate #endif /* DEBUG_MIB */
5080Sstevel@tonic-gate 			return (first_item);		/* this is EOD msg */
5090Sstevel@tonic-gate 		}
5100Sstevel@tonic-gate 
5110Sstevel@tonic-gate 		if (ctlbuf.len >= sizeof (struct T_error_ack) &&
5120Sstevel@tonic-gate 			(tea->PRIM_type == T_ERROR_ACK)) {
5130Sstevel@tonic-gate #ifdef DEBUG_MIB
5140Sstevel@tonic-gate 			fprintf(stderr,
5150Sstevel@tonic-gate 	"mibget %d gives T_ERROR_ACK: TLI_error = 0x%x, UNIX_error = 0x%x\n",
5160Sstevel@tonic-gate 				j, getcode, tea->TLI_error, tea->UNIX_error);
5170Sstevel@tonic-gate #endif /* DEBUG_MIB */
5180Sstevel@tonic-gate 			errno = (tea->TLI_error == TSYSERR)
5190Sstevel@tonic-gate 				? tea->UNIX_error : EPROTO;
5200Sstevel@tonic-gate 			goto error_exit;
5210Sstevel@tonic-gate 		}
5220Sstevel@tonic-gate 
5230Sstevel@tonic-gate 		if (getcode != MOREDATA ||
5240Sstevel@tonic-gate 			(ctlbuf.len < sizeof (struct T_optmgmt_ack)) ||
5250Sstevel@tonic-gate 			(toa->PRIM_type != T_OPTMGMT_ACK) ||
5260Sstevel@tonic-gate 			(toa->MGMT_flags != T_SUCCESS)) {
5270Sstevel@tonic-gate #ifdef DEBUG_MIB
5280Sstevel@tonic-gate 			fprintf(stderr,
5290Sstevel@tonic-gate 	"mibget getmsg(ctl) %d returned %d, ctlbuf.len = %d, PRIM_type = %d\n",
5300Sstevel@tonic-gate 				j, getcode, ctlbuf.len, toa->PRIM_type);
5310Sstevel@tonic-gate 			if (toa->PRIM_type == T_OPTMGMT_ACK)
5320Sstevel@tonic-gate 				fprintf(stderr,
5330Sstevel@tonic-gate 	"T_OPTMGMT_ACK: MGMT_flags = 0x%x, req->len = %d\n",
5340Sstevel@tonic-gate 					toa->MGMT_flags, req->len);
5350Sstevel@tonic-gate #endif /* DEBUG_MIB */
5360Sstevel@tonic-gate 			errno = ENOMSG;
5370Sstevel@tonic-gate 			goto error_exit;
5380Sstevel@tonic-gate 		}
5390Sstevel@tonic-gate 
5400Sstevel@tonic-gate 		temp = malloc(sizeof (mib_item_t));
5410Sstevel@tonic-gate 		if (!temp) {
5420Sstevel@tonic-gate 			perror("mibget malloc failed");
5430Sstevel@tonic-gate 			goto error_exit;
5440Sstevel@tonic-gate 		}
5450Sstevel@tonic-gate 		if (last_item)
5460Sstevel@tonic-gate 			last_item->next_item = temp;
5470Sstevel@tonic-gate 		else
5480Sstevel@tonic-gate 			first_item = temp;
5490Sstevel@tonic-gate 		last_item = temp;
5500Sstevel@tonic-gate 		last_item->next_item = NULL;
5510Sstevel@tonic-gate 		last_item->group = req->level;
5520Sstevel@tonic-gate 		last_item->mib_id = req->name;
5530Sstevel@tonic-gate 		last_item->length = req->len;
5540Sstevel@tonic-gate 		last_item->valp = malloc(req->len);
5550Sstevel@tonic-gate #ifdef DEBUG_MIB
5560Sstevel@tonic-gate 		fprintf(stderr,
5570Sstevel@tonic-gate 			"msg %d:  group = %4d   mib_id = %5d   length = %d\n",
5580Sstevel@tonic-gate 			j, last_item->group, last_item->mib_id,
5590Sstevel@tonic-gate 			last_item->length);
5600Sstevel@tonic-gate #endif /* DEBUG_MIB */
5610Sstevel@tonic-gate 		databuf.maxlen = last_item->length;
5620Sstevel@tonic-gate 		databuf.buf    = last_item->valp;
5630Sstevel@tonic-gate 		databuf.len    = 0;
5640Sstevel@tonic-gate 		flags = 0;
5650Sstevel@tonic-gate 		getcode = getmsg(sd, NULL, &databuf, &flags);
5660Sstevel@tonic-gate 		if (getcode == -1) {
5670Sstevel@tonic-gate 			perror("mibget getmsg(data) failed");
5680Sstevel@tonic-gate 			goto error_exit;
5690Sstevel@tonic-gate 		} else if (getcode != 0) {
5700Sstevel@tonic-gate 			fprintf(stderr,
5710Sstevel@tonic-gate "mibget getmsg(data) returned %d, databuf.maxlen = %d, databuf.len = %d\n",
5720Sstevel@tonic-gate 				getcode, databuf.maxlen, databuf.len);
5730Sstevel@tonic-gate 			goto error_exit;
5740Sstevel@tonic-gate 		}
5750Sstevel@tonic-gate 	}
5760Sstevel@tonic-gate 
5770Sstevel@tonic-gate error_exit:
5780Sstevel@tonic-gate 	while (first_item) {
5790Sstevel@tonic-gate 		last_item = first_item;
5800Sstevel@tonic-gate 		first_item = first_item->next_item;
5810Sstevel@tonic-gate 		if (last_item->valp) {
5820Sstevel@tonic-gate 			free(last_item->valp);
5830Sstevel@tonic-gate 		}
5840Sstevel@tonic-gate 		free(last_item);
5850Sstevel@tonic-gate 	}
5860Sstevel@tonic-gate 	return (first_item);
5870Sstevel@tonic-gate }
5880Sstevel@tonic-gate 
5890Sstevel@tonic-gate static int
mibopen(void)5900Sstevel@tonic-gate mibopen(void)
5910Sstevel@tonic-gate {
5920Sstevel@tonic-gate 	int	sd;
5930Sstevel@tonic-gate 
5940Sstevel@tonic-gate 	/* gives us ip w/ arp on top */
5950Sstevel@tonic-gate 	sd = open("/dev/arp", O_RDWR);
5960Sstevel@tonic-gate 	if (sd == -1) {
5970Sstevel@tonic-gate 		perror("arp open");
5980Sstevel@tonic-gate 		close(sd);
5990Sstevel@tonic-gate 		return (-1);
6000Sstevel@tonic-gate 	}
6010Sstevel@tonic-gate 	if (ioctl(sd, I_PUSH, "tcp") == -1) {
6020Sstevel@tonic-gate 		perror("tcp I_PUSH");
6030Sstevel@tonic-gate 		close(sd);
6040Sstevel@tonic-gate 		return (-1);
6050Sstevel@tonic-gate 	}
6060Sstevel@tonic-gate 	if (ioctl(sd, I_PUSH, "udp") == -1) {
6070Sstevel@tonic-gate 		perror("udp I_PUSH");
6080Sstevel@tonic-gate 		close(sd);
6090Sstevel@tonic-gate 		return (-1);
6100Sstevel@tonic-gate 	}
6110Sstevel@tonic-gate 	return (sd);
6120Sstevel@tonic-gate }
6130Sstevel@tonic-gate 
6140Sstevel@tonic-gate static char *
octetstr(char * buf,Octet_t * op,int code)6150Sstevel@tonic-gate octetstr(char *buf, Octet_t *op, int code)
6160Sstevel@tonic-gate {
6170Sstevel@tonic-gate 	int	i;
6180Sstevel@tonic-gate 	char	*cp;
6190Sstevel@tonic-gate 
6200Sstevel@tonic-gate 	cp = buf;
6210Sstevel@tonic-gate 	if (op)
6220Sstevel@tonic-gate 		for (i = 0; i < op->o_length; i++)
6230Sstevel@tonic-gate 			switch (code) {
6240Sstevel@tonic-gate 			case 'd':
6250Sstevel@tonic-gate 				sprintf(cp, "%d.", 0xff & op->o_bytes[i]);
6260Sstevel@tonic-gate 				cp = strchr(cp, '\0');
6270Sstevel@tonic-gate 				break;
6280Sstevel@tonic-gate 			case 'a':
6290Sstevel@tonic-gate 				*cp++ = op->o_bytes[i];
6300Sstevel@tonic-gate 				break;
6310Sstevel@tonic-gate 			case 'h':
6320Sstevel@tonic-gate 			default:
6330Sstevel@tonic-gate 				sprintf(cp, "%02x:", 0xff & op->o_bytes[i]);
6340Sstevel@tonic-gate 				cp += 3;
6350Sstevel@tonic-gate 				break;
6360Sstevel@tonic-gate 			}
6370Sstevel@tonic-gate 	if (code != 'a' && cp != buf)
6380Sstevel@tonic-gate 		cp--;
6390Sstevel@tonic-gate 	*cp = '\0';
6400Sstevel@tonic-gate 	return (buf);
6410Sstevel@tonic-gate }
6420Sstevel@tonic-gate 
6430Sstevel@tonic-gate static void
fail(int do_perror,char * message,...)6440Sstevel@tonic-gate fail(int do_perror, char *message, ...)
6450Sstevel@tonic-gate {
6460Sstevel@tonic-gate 	va_list args;
6470Sstevel@tonic-gate 
6480Sstevel@tonic-gate 	va_start(args, message);
6490Sstevel@tonic-gate 	fprintf(stderr, "%s: ", cmdname);
6500Sstevel@tonic-gate 	vfprintf(stderr, message, args);
6510Sstevel@tonic-gate 	va_end(args);
6520Sstevel@tonic-gate 	if (do_perror)
6530Sstevel@tonic-gate 		fprintf(stderr, ": %s", strerror(errno));
6540Sstevel@tonic-gate 	fprintf(stderr, "\n");
6550Sstevel@tonic-gate 	exit(2);
6560Sstevel@tonic-gate }
6570Sstevel@tonic-gate 
6580Sstevel@tonic-gate static void
safe_zalloc(void ** ptr,int size,int free_first)6590Sstevel@tonic-gate safe_zalloc(void **ptr, int size, int free_first)
6600Sstevel@tonic-gate {
6610Sstevel@tonic-gate 	if (free_first && *ptr != NULL)
6620Sstevel@tonic-gate 		free(*ptr);
6630Sstevel@tonic-gate 	if ((*ptr = malloc(size)) == NULL)
6640Sstevel@tonic-gate 		fail(1, "malloc failed");
6650Sstevel@tonic-gate 	memset(*ptr, 0, size);
6660Sstevel@tonic-gate }
6670Sstevel@tonic-gate 
6680Sstevel@tonic-gate kid_t
safe_kstat_read(kstat_ctl_t * kctl,kstat_t * ksp,void * data)6690Sstevel@tonic-gate safe_kstat_read(kstat_ctl_t *kctl, kstat_t *ksp, void *data)
6700Sstevel@tonic-gate {
6710Sstevel@tonic-gate 	kid_t kstat_chain_id = kstat_read(kctl, ksp, data);
6720Sstevel@tonic-gate 
6730Sstevel@tonic-gate 	if (kstat_chain_id == -1)
6740Sstevel@tonic-gate 		fail(1, "kstat_read(%x, '%s') failed", kctl, ksp->ks_name);
6750Sstevel@tonic-gate 	return (kstat_chain_id);
6760Sstevel@tonic-gate }
6770Sstevel@tonic-gate 
6780Sstevel@tonic-gate kstat_t *
safe_kstat_lookup(kstat_ctl_t * kctl,char * ks_module,int ks_instance,char * ks_name)6790Sstevel@tonic-gate safe_kstat_lookup(kstat_ctl_t *kctl, char *ks_module, int ks_instance,
6800Sstevel@tonic-gate 	char *ks_name)
6810Sstevel@tonic-gate {
6820Sstevel@tonic-gate 	kstat_t *ksp = kstat_lookup(kctl, ks_module, ks_instance, ks_name);
6830Sstevel@tonic-gate 
6840Sstevel@tonic-gate 	if (ksp == NULL)
6850Sstevel@tonic-gate 		fail(0, "kstat_lookup('%s', %d, '%s') failed",
6860Sstevel@tonic-gate 			ks_module == NULL ? "" : ks_module,
6870Sstevel@tonic-gate 			ks_instance,
6880Sstevel@tonic-gate 			ks_name == NULL ? "" : ks_name);
6890Sstevel@tonic-gate 	return (ksp);
6900Sstevel@tonic-gate }
6910Sstevel@tonic-gate 
6920Sstevel@tonic-gate void *
safe_kstat_data_lookup(kstat_t * ksp,char * name)6930Sstevel@tonic-gate safe_kstat_data_lookup(kstat_t *ksp, char *name)
6940Sstevel@tonic-gate {
6950Sstevel@tonic-gate 	void *fp = kstat_data_lookup(ksp, name);
6960Sstevel@tonic-gate 
6970Sstevel@tonic-gate 	if (fp == NULL) {
6980Sstevel@tonic-gate 		fail(0, "kstat_data_lookup('%s', '%s') failed",
6990Sstevel@tonic-gate 			ksp->ks_name, name);
7000Sstevel@tonic-gate 	}
7010Sstevel@tonic-gate 	return (fp);
7020Sstevel@tonic-gate }
7030Sstevel@tonic-gate 
7040Sstevel@tonic-gate /*
7050Sstevel@tonic-gate  * Get various KIDs for subsequent system_stat_load operations.
7060Sstevel@tonic-gate  */
7070Sstevel@tonic-gate 
7080Sstevel@tonic-gate static void
system_stat_init(void)7090Sstevel@tonic-gate system_stat_init(void)
7100Sstevel@tonic-gate {
7110Sstevel@tonic-gate 	kstat_t *ksp;
7120Sstevel@tonic-gate 	int i, nvmks;
7130Sstevel@tonic-gate 
7140Sstevel@tonic-gate 	/*
7150Sstevel@tonic-gate 	 * Global statistics
7160Sstevel@tonic-gate 	 */
7170Sstevel@tonic-gate 
7180Sstevel@tonic-gate 	system_misc_ksp	= safe_kstat_lookup(kc, "unix", 0, "system_misc");
7190Sstevel@tonic-gate 
7200Sstevel@tonic-gate 	safe_kstat_read(kc, system_misc_ksp, NULL);
7210Sstevel@tonic-gate 	boot_time_knp = safe_kstat_data_lookup(system_misc_ksp, "boot_time");
7220Sstevel@tonic-gate 	avenrun_1min_knp = safe_kstat_data_lookup(system_misc_ksp,
7230Sstevel@tonic-gate 		"avenrun_1min");
7240Sstevel@tonic-gate 	avenrun_5min_knp = safe_kstat_data_lookup(system_misc_ksp,
7250Sstevel@tonic-gate 		"avenrun_5min");
7260Sstevel@tonic-gate 	avenrun_15min_knp = safe_kstat_data_lookup(system_misc_ksp,
7270Sstevel@tonic-gate 		"avenrun_15min");
7280Sstevel@tonic-gate 
7290Sstevel@tonic-gate 	/*
7300Sstevel@tonic-gate 	 * Per-CPU statistics
7310Sstevel@tonic-gate 	 */
7320Sstevel@tonic-gate 
7330Sstevel@tonic-gate 	ncpus = 0;
7340Sstevel@tonic-gate 	for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next)
7350Sstevel@tonic-gate 		if (strcmp(ksp->ks_module, "cpu") == 0 &&
7360Sstevel@tonic-gate 		    strcmp(ksp->ks_name, "sys") == 0)
7370Sstevel@tonic-gate 			ncpus++;
7380Sstevel@tonic-gate 
7390Sstevel@tonic-gate 	safe_zalloc((void **)&cpu_stats_list, ncpus * sizeof (*cpu_stats_list),
7400Sstevel@tonic-gate 	    1);
7410Sstevel@tonic-gate 
7420Sstevel@tonic-gate 	ncpus = 0;
7430Sstevel@tonic-gate 	for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next)
7440Sstevel@tonic-gate 		if (strcmp(ksp->ks_module, "cpu") == 0 &&
7450Sstevel@tonic-gate 		    strcmp(ksp->ks_name, "sys") == 0 &&
7460Sstevel@tonic-gate 		    kstat_read(kc, ksp, NULL) != -1) {
7470Sstevel@tonic-gate 			kstat_copy(ksp, &cpu_stats_list[ncpus].sys,
7480Sstevel@tonic-gate 			    1);
7490Sstevel@tonic-gate 			if ((ksp = kstat_lookup(kc, "cpu", ksp->ks_instance,
7500Sstevel@tonic-gate 			    "vm")) != NULL && kstat_read(kc, ksp, NULL) != -1)
7510Sstevel@tonic-gate 				kstat_copy(ksp, &cpu_stats_list[ncpus].vm, 1);
7520Sstevel@tonic-gate 			else
7530Sstevel@tonic-gate 				fail(0, "couldn't find per-CPU VM statistics");
7540Sstevel@tonic-gate 			ncpus++;
7550Sstevel@tonic-gate 		    }
7560Sstevel@tonic-gate 
7570Sstevel@tonic-gate 	if (ncpus == 0)
7580Sstevel@tonic-gate 		fail(0, "couldn't find per-CPU statistics");
7590Sstevel@tonic-gate }
7600Sstevel@tonic-gate 
7610Sstevel@tonic-gate /*
7620Sstevel@tonic-gate  * load statistics, summing across CPUs where needed
7630Sstevel@tonic-gate  */
7640Sstevel@tonic-gate 
7650Sstevel@tonic-gate static int
system_stat_load(void)7660Sstevel@tonic-gate system_stat_load(void)
7670Sstevel@tonic-gate {
7680Sstevel@tonic-gate 	int i, j;
7690Sstevel@tonic-gate 	_cpu_stats_t cs;
7700Sstevel@tonic-gate 	ulong_t *np, *tp;
7710Sstevel@tonic-gate 
7720Sstevel@tonic-gate 	/*
7730Sstevel@tonic-gate 	 * Global statistics
7740Sstevel@tonic-gate 	 */
7750Sstevel@tonic-gate 
7760Sstevel@tonic-gate 	safe_kstat_read(kc, system_misc_ksp, NULL);
7770Sstevel@tonic-gate 
7780Sstevel@tonic-gate 	/*
7790Sstevel@tonic-gate 	 * Per-CPU statistics.
7800Sstevel@tonic-gate 	 */
7810Sstevel@tonic-gate 
7820Sstevel@tonic-gate 	for (i = 0; i < ncpus; i++) {
7830Sstevel@tonic-gate 		if (kstat_read(kc, &cpu_stats_list[i].sys, NULL) == -1 ||
7840Sstevel@tonic-gate 		    kstat_read(kc, &cpu_stats_list[i].vm, NULL) == -1)
7850Sstevel@tonic-gate 			return (1);
7860Sstevel@tonic-gate 		if (i == 0) {
7870Sstevel@tonic-gate 			kstat_copy(&cpu_stats_list[0].sys, &cpu_stats_all.sys,
7880Sstevel@tonic-gate 			    1);
7890Sstevel@tonic-gate 			kstat_copy(&cpu_stats_list[0].vm, &cpu_stats_all.vm, 1);
7900Sstevel@tonic-gate 		} else {
7910Sstevel@tonic-gate 			kstat_named_t *nkp;
7920Sstevel@tonic-gate 			kstat_named_t *tkp;
7930Sstevel@tonic-gate 
7940Sstevel@tonic-gate 			/*
7950Sstevel@tonic-gate 			 * Other CPUs' statistics are accumulated in
7960Sstevel@tonic-gate 			 * cpu_stats_all, initialized at the first iteration of
7970Sstevel@tonic-gate 			 * the loop.
7980Sstevel@tonic-gate 			 */
7990Sstevel@tonic-gate 			nkp = (kstat_named_t *)cpu_stats_all.sys.ks_data;
8000Sstevel@tonic-gate 			tkp = (kstat_named_t *)cpu_stats_list[i].sys.ks_data;
8010Sstevel@tonic-gate 			for (j = 0; j < cpu_stats_list[i].sys.ks_ndata; j++)
8020Sstevel@tonic-gate 				(nkp++)->value.ui64 += (tkp++)->value.ui64;
8030Sstevel@tonic-gate 			nkp = (kstat_named_t *)cpu_stats_all.vm.ks_data;
8040Sstevel@tonic-gate 			tkp = (kstat_named_t *)cpu_stats_list[i].vm.ks_data;
8050Sstevel@tonic-gate 			for (j = 0; j < cpu_stats_list[i].vm.ks_ndata; j++)
8060Sstevel@tonic-gate 				(nkp++)->value.ui64 += (tkp++)->value.ui64;
8070Sstevel@tonic-gate 		}
8080Sstevel@tonic-gate 	}
8090Sstevel@tonic-gate 	return (0);
8100Sstevel@tonic-gate }
8110Sstevel@tonic-gate 
8120Sstevel@tonic-gate static int
kscmp(kstat_t * ks1,kstat_t * ks2)8130Sstevel@tonic-gate kscmp(kstat_t *ks1, kstat_t *ks2)
8140Sstevel@tonic-gate {
8150Sstevel@tonic-gate 	int cmp;
8160Sstevel@tonic-gate 
8170Sstevel@tonic-gate 	cmp = strcmp(ks1->ks_module, ks2->ks_module);
8180Sstevel@tonic-gate 	if (cmp != 0)
8190Sstevel@tonic-gate 		return (cmp);
8200Sstevel@tonic-gate 	cmp = ks1->ks_instance - ks2->ks_instance;
8210Sstevel@tonic-gate 	if (cmp != 0)
8220Sstevel@tonic-gate 		return (cmp);
8230Sstevel@tonic-gate 	return (strcmp(ks1->ks_name, ks2->ks_name));
8240Sstevel@tonic-gate }
8250Sstevel@tonic-gate 
8260Sstevel@tonic-gate static void
init_disks(void)8270Sstevel@tonic-gate init_disks(void)
8280Sstevel@tonic-gate {
8290Sstevel@tonic-gate 	struct diskinfo *disk, *prevdisk, *comp;
8300Sstevel@tonic-gate 	kstat_t *ksp;
8310Sstevel@tonic-gate 
8320Sstevel@tonic-gate 	ndisks = 0;
8330Sstevel@tonic-gate 	disk = &zerodisk;
8340Sstevel@tonic-gate 
8350Sstevel@tonic-gate 	/*
8360Sstevel@tonic-gate 	 * Patch the snip in the diskinfo list (see below)
8370Sstevel@tonic-gate 	 */
8380Sstevel@tonic-gate 	if (snip)
8390Sstevel@tonic-gate 		lastdisk->next = snip;
8400Sstevel@tonic-gate 
8410Sstevel@tonic-gate 	for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
8420Sstevel@tonic-gate 
8430Sstevel@tonic-gate 		if (ksp->ks_type != KSTAT_TYPE_IO ||
8440Sstevel@tonic-gate 		    strcmp(ksp->ks_class, "disk") != 0)
8450Sstevel@tonic-gate 			continue;
8460Sstevel@tonic-gate 		prevdisk = disk;
8470Sstevel@tonic-gate 		if (disk->next)
8480Sstevel@tonic-gate 			disk = disk->next;
8490Sstevel@tonic-gate 		else {
8500Sstevel@tonic-gate 			safe_zalloc((void **)&disk->next,
8510Sstevel@tonic-gate 			    sizeof (struct diskinfo), 0);
8520Sstevel@tonic-gate 			disk = disk->next;
8530Sstevel@tonic-gate 			disk->next = NULLDISK;
8540Sstevel@tonic-gate 		}
8550Sstevel@tonic-gate 		disk->ks = ksp;
8560Sstevel@tonic-gate 		memset((void *)&disk->kios, 0, sizeof (kstat_io_t));
8570Sstevel@tonic-gate 		disk->kios.wlastupdate = disk->ks->ks_crtime;
8580Sstevel@tonic-gate 		disk->kios.rlastupdate = disk->ks->ks_crtime;
8590Sstevel@tonic-gate 
8600Sstevel@tonic-gate 		/*
8610Sstevel@tonic-gate 		 * Insertion sort on (ks_module, ks_instance, ks_name)
8620Sstevel@tonic-gate 		 */
8630Sstevel@tonic-gate 		comp = &zerodisk;
8640Sstevel@tonic-gate 		while (kscmp(disk->ks, comp->next->ks) > 0)
8650Sstevel@tonic-gate 			comp = comp->next;
8660Sstevel@tonic-gate 		if (prevdisk != comp) {
8670Sstevel@tonic-gate 			prevdisk->next = disk->next;
8680Sstevel@tonic-gate 			disk->next = comp->next;
8690Sstevel@tonic-gate 			comp->next = disk;
8700Sstevel@tonic-gate 			disk = prevdisk;
8710Sstevel@tonic-gate 		}
8720Sstevel@tonic-gate 		ndisks++;
8730Sstevel@tonic-gate 	}
8740Sstevel@tonic-gate 	/*
8750Sstevel@tonic-gate 	 * Put a snip in the linked list of diskinfos.  The idea:
8760Sstevel@tonic-gate 	 * If there was a state change such that now there are fewer
8770Sstevel@tonic-gate 	 * disks, we snip the list and retain the tail, rather than
8780Sstevel@tonic-gate 	 * freeing it.  At the next state change, we clip the tail back on.
8790Sstevel@tonic-gate 	 * This prevents a lot of malloc/free activity, and it's simpler.
8800Sstevel@tonic-gate 	 */
8810Sstevel@tonic-gate 	lastdisk = disk;
8820Sstevel@tonic-gate 	snip = disk->next;
8830Sstevel@tonic-gate 	disk->next = NULLDISK;
8840Sstevel@tonic-gate 
8850Sstevel@tonic-gate 	firstdisk = zerodisk.next;
8860Sstevel@tonic-gate 
8870Sstevel@tonic-gate 	if (ndisks > stats_s4.dk_xfer.dk_xfer_len) {
8880Sstevel@tonic-gate 		stats_s4.dk_xfer.dk_xfer_len = ndisks;
8890Sstevel@tonic-gate 		safe_zalloc((void **)&stats_s4.dk_xfer.dk_xfer_val,
8900Sstevel@tonic-gate 			ndisks * sizeof (int), 1);
8910Sstevel@tonic-gate 	}
8920Sstevel@tonic-gate }
8930Sstevel@tonic-gate 
8940Sstevel@tonic-gate static int
diskinfo_load(void)8950Sstevel@tonic-gate diskinfo_load(void)
8960Sstevel@tonic-gate {
8970Sstevel@tonic-gate 	struct diskinfo *disk;
8980Sstevel@tonic-gate 	int i;
8990Sstevel@tonic-gate 
9000Sstevel@tonic-gate 	for (disk = firstdisk, i = 0; disk; disk = disk->next, i++) {
9010Sstevel@tonic-gate 		if (kstat_read(kc, disk->ks, (void *)&disk->kios) == -1)
9020Sstevel@tonic-gate 			return (1);
9030Sstevel@tonic-gate 		stats_s4.dk_xfer.dk_xfer_val[i] = disk->kios.reads +
9040Sstevel@tonic-gate 			disk->kios.writes;
9050Sstevel@tonic-gate 	}
9060Sstevel@tonic-gate 	return (0);
9070Sstevel@tonic-gate }
9080Sstevel@tonic-gate 
9090Sstevel@tonic-gate static void
init_net(void)9100Sstevel@tonic-gate init_net(void)
9110Sstevel@tonic-gate {
9120Sstevel@tonic-gate 	static int sd;
9130Sstevel@tonic-gate 	mib_item_t *item;
9140Sstevel@tonic-gate 	mib2_ipAddrEntry_t *ap;
9150Sstevel@tonic-gate 	char namebuf[KSTAT_STRLEN];
9160Sstevel@tonic-gate 	struct netinfo *net, *prevnet, *comp;
9170Sstevel@tonic-gate 	kstat_t *ksp;
9180Sstevel@tonic-gate 
9190Sstevel@tonic-gate 	if (sd) {
9200Sstevel@tonic-gate 		close(sd);
9210Sstevel@tonic-gate 	}
9220Sstevel@tonic-gate 	while (netstat_item) {
9230Sstevel@tonic-gate 		item = netstat_item;
9240Sstevel@tonic-gate 		netstat_item = netstat_item->next_item;
9250Sstevel@tonic-gate 		if (item->valp) {
9260Sstevel@tonic-gate 			free(item->valp);
9270Sstevel@tonic-gate 		}
9280Sstevel@tonic-gate 		free(item);
9290Sstevel@tonic-gate 	}
9300Sstevel@tonic-gate 	sd = mibopen();
9310Sstevel@tonic-gate 	if (sd == -1) {
9320Sstevel@tonic-gate #ifdef DEBUG
9330Sstevel@tonic-gate 		fprintf(stderr, "mibopen() failed\n");
9340Sstevel@tonic-gate #endif
9350Sstevel@tonic-gate 		sd = 0;
9360Sstevel@tonic-gate 	} else {
9370Sstevel@tonic-gate 		if ((netstat_item = mibget(sd)) == NULL) {
9380Sstevel@tonic-gate #ifdef DEBUG
9390Sstevel@tonic-gate 			fprintf(stderr, "mibget() failed\n");
9400Sstevel@tonic-gate #endif
9410Sstevel@tonic-gate 			close(sd);
9420Sstevel@tonic-gate 			sd = 0;
9430Sstevel@tonic-gate 		}
9440Sstevel@tonic-gate 	}
9450Sstevel@tonic-gate #ifdef DEBUG
9460Sstevel@tonic-gate 	fprintf(stderr, "mibget returned item: %x\n", netstat_item);
9470Sstevel@tonic-gate #endif
9480Sstevel@tonic-gate 
9490Sstevel@tonic-gate 	nnets = 0;
9500Sstevel@tonic-gate 	net = &zeronet;
9510Sstevel@tonic-gate 
9520Sstevel@tonic-gate 	if (netsnip)
9530Sstevel@tonic-gate 		lastnet->next = netsnip;
9540Sstevel@tonic-gate 
9550Sstevel@tonic-gate 	for (item = netstat_item; item; item = item->next_item) {
9560Sstevel@tonic-gate #ifdef DEBUG_MIB
9570Sstevel@tonic-gate 		fprintf(stderr, "\n--- Item %x ---\n", item);
9580Sstevel@tonic-gate 		fprintf(stderr,
9590Sstevel@tonic-gate 		"Group = %d, mib_id = %d, length = %d, valp = 0x%x\n",
9600Sstevel@tonic-gate 		item->group, item->mib_id, item->length,
9610Sstevel@tonic-gate 		item->valp);
9620Sstevel@tonic-gate #endif
9630Sstevel@tonic-gate 		if (item->group != MIB2_IP || item->mib_id != MIB2_IP_20)
9640Sstevel@tonic-gate 			continue;
9650Sstevel@tonic-gate 		ap = (mib2_ipAddrEntry_t *)item->valp;
9660Sstevel@tonic-gate 		for (; (char *)ap < item->valp + item->length; ap++) {
9670Sstevel@tonic-gate 
9680Sstevel@tonic-gate 			octetstr(namebuf, &ap->ipAdEntIfIndex, 'a');
9690Sstevel@tonic-gate #ifdef DEBUG
9700Sstevel@tonic-gate 			fprintf(stderr, "%s ", namebuf);
9710Sstevel@tonic-gate #endif
9720Sstevel@tonic-gate 			if (strlen(namebuf) == 0)
9730Sstevel@tonic-gate 				continue;
9740Sstevel@tonic-gate 			/*
9750Sstevel@tonic-gate 			 * We found a device of interest.
9760Sstevel@tonic-gate 			 * Now, let's see if there's a kstat for it.
977*5895Syz147064 			 * First we try to query the "link" kstats in case
978*5895Syz147064 			 * the link is renamed. If that fails, fallback
979*5895Syz147064 			 * to legacy ktats for those non-GLDv3 links.
9800Sstevel@tonic-gate 			 */
981*5895Syz147064 			if (((ksp = kstat_lookup(kc, "link", 0, namebuf))
982*5895Syz147064 			    == NULL) && ((ksp = kstat_lookup(kc, NULL, -1,
983*5895Syz147064 			    namebuf)) == NULL)) {
9840Sstevel@tonic-gate 				continue;
985*5895Syz147064 			}
9860Sstevel@tonic-gate 			if (ksp->ks_type != KSTAT_TYPE_NAMED)
9870Sstevel@tonic-gate 				continue;
9880Sstevel@tonic-gate 			if (kstat_read(kc, ksp, NULL) == -1)
9890Sstevel@tonic-gate 				continue;
9900Sstevel@tonic-gate 			prevnet = net;
9910Sstevel@tonic-gate 			if (net->next)
9920Sstevel@tonic-gate 				net = net->next;
9930Sstevel@tonic-gate 			else {
9940Sstevel@tonic-gate 				safe_zalloc((void **)&net->next,
9950Sstevel@tonic-gate 					sizeof (struct netinfo), 0);
9960Sstevel@tonic-gate 				net = net->next;
9970Sstevel@tonic-gate 				net->next = NULLNET;
9980Sstevel@tonic-gate 			}
9990Sstevel@tonic-gate 			net->ks = ksp;
10000Sstevel@tonic-gate 			net->ipackets	= kstat_data_lookup(net->ks,
10010Sstevel@tonic-gate 				"ipackets");
10020Sstevel@tonic-gate 			net->opackets	= kstat_data_lookup(net->ks,
10030Sstevel@tonic-gate 				"opackets");
10040Sstevel@tonic-gate 			net->ierrors	= kstat_data_lookup(net->ks,
10050Sstevel@tonic-gate 				"ierrors");
10060Sstevel@tonic-gate 			net->oerrors	= kstat_data_lookup(net->ks,
10070Sstevel@tonic-gate 				"oerrors");
10080Sstevel@tonic-gate 			net->collisions	= kstat_data_lookup(net->ks,
10090Sstevel@tonic-gate 				"collisions");
10100Sstevel@tonic-gate 			/*
10110Sstevel@tonic-gate 			 * Insertion sort on the name
10120Sstevel@tonic-gate 			 */
10130Sstevel@tonic-gate 			comp = &zeronet;
10140Sstevel@tonic-gate 			while (strcmp(net->ks->ks_name,
10150Sstevel@tonic-gate 			    comp->next->ks->ks_name) > 0)
10160Sstevel@tonic-gate 				comp = comp->next;
10170Sstevel@tonic-gate 			if (prevnet != comp) {
10180Sstevel@tonic-gate 				prevnet->next = net->next;
10190Sstevel@tonic-gate 				net->next = comp->next;
10200Sstevel@tonic-gate 				comp->next = net;
10210Sstevel@tonic-gate 				net = prevnet;
10220Sstevel@tonic-gate 			}
10230Sstevel@tonic-gate 			nnets++;
10240Sstevel@tonic-gate 		}
10250Sstevel@tonic-gate #ifdef DEBUG
10260Sstevel@tonic-gate 		fprintf(stderr, "\n");
10270Sstevel@tonic-gate #endif
10280Sstevel@tonic-gate 	}
10290Sstevel@tonic-gate 	/*
10300Sstevel@tonic-gate 	 * Put a snip in the linked list of netinfos.  The idea:
10310Sstevel@tonic-gate 	 * If there was a state change such that now there are fewer
10320Sstevel@tonic-gate 	 * nets, we snip the list and retain the tail, rather than
10330Sstevel@tonic-gate 	 * freeing it.  At the next state change, we clip the tail back on.
10340Sstevel@tonic-gate 	 * This prevents a lot of malloc/free activity, and it's simpler.
10350Sstevel@tonic-gate 	 */
10360Sstevel@tonic-gate 	lastnet = net;
10370Sstevel@tonic-gate 	netsnip = net->next;
10380Sstevel@tonic-gate 	net->next = NULLNET;
10390Sstevel@tonic-gate 
10400Sstevel@tonic-gate 	firstnet = zeronet.next;
10410Sstevel@tonic-gate }
10420Sstevel@tonic-gate 
10430Sstevel@tonic-gate static int
netinfo_load(void)10440Sstevel@tonic-gate netinfo_load(void)
10450Sstevel@tonic-gate {
10460Sstevel@tonic-gate 	struct netinfo *net;
10470Sstevel@tonic-gate 
10480Sstevel@tonic-gate 	if (netstat_item == NULL) {
10490Sstevel@tonic-gate #ifdef DEBUG
10500Sstevel@tonic-gate 		fprintf(stderr, "No net stats\n");
10510Sstevel@tonic-gate #endif
10520Sstevel@tonic-gate 		return (0);
10530Sstevel@tonic-gate 	}
10540Sstevel@tonic-gate 
10550Sstevel@tonic-gate 	stats_s4.if_ipackets =
10560Sstevel@tonic-gate 	stats_s4.if_opackets =
10570Sstevel@tonic-gate 	stats_s4.if_ierrors =
10580Sstevel@tonic-gate 	stats_s4.if_oerrors =
10590Sstevel@tonic-gate 	stats_s4.if_collisions = 0;
10600Sstevel@tonic-gate 
10610Sstevel@tonic-gate 	for (net = firstnet; net; net = net->next) {
10620Sstevel@tonic-gate 		if (kstat_read(kc, net->ks, NULL) == -1)
10630Sstevel@tonic-gate 			return (1);
10640Sstevel@tonic-gate 		if (net->ipackets)
10650Sstevel@tonic-gate 			stats_s4.if_ipackets	+= net->ipackets->value.ul;
10660Sstevel@tonic-gate 		if (net->opackets)
10670Sstevel@tonic-gate 			stats_s4.if_opackets	+= net->opackets->value.ul;
10680Sstevel@tonic-gate 		if (net->ierrors)
10690Sstevel@tonic-gate 			stats_s4.if_ierrors	+= net->ierrors->value.ul;
10700Sstevel@tonic-gate 		if (net->oerrors)
10710Sstevel@tonic-gate 			stats_s4.if_oerrors	+= net->oerrors->value.ul;
10720Sstevel@tonic-gate 		if (net->collisions)
10730Sstevel@tonic-gate 			stats_s4.if_collisions	+= net->collisions->value.ul;
10740Sstevel@tonic-gate 	}
10750Sstevel@tonic-gate #ifdef DEBUG
10760Sstevel@tonic-gate 	fprintf(stderr,
10770Sstevel@tonic-gate 	    "ipackets: %d opackets: %d ierrors: %d oerrors: %d colls: %d\n",
10780Sstevel@tonic-gate 		stats_s4.if_ipackets,
10790Sstevel@tonic-gate 		stats_s4.if_opackets,
10800Sstevel@tonic-gate 		stats_s4.if_ierrors,
10810Sstevel@tonic-gate 		stats_s4.if_oerrors,
10820Sstevel@tonic-gate 		stats_s4.if_collisions);
10830Sstevel@tonic-gate #endif
10840Sstevel@tonic-gate 	return (0);
10850Sstevel@tonic-gate }
10860Sstevel@tonic-gate 
10870Sstevel@tonic-gate static void
kstat_copy(kstat_t * src,kstat_t * dst,int fr)10880Sstevel@tonic-gate kstat_copy(kstat_t *src, kstat_t *dst, int fr)
10890Sstevel@tonic-gate {
10900Sstevel@tonic-gate 	if (fr)
10910Sstevel@tonic-gate 		free(dst->ks_data);
10920Sstevel@tonic-gate 	*dst = *src;
10930Sstevel@tonic-gate 	if (src->ks_data != NULL) {
10940Sstevel@tonic-gate 		safe_zalloc(&dst->ks_data, src->ks_data_size, 0);
10950Sstevel@tonic-gate 		(void) memcpy(dst->ks_data, src->ks_data, src->ks_data_size);
10960Sstevel@tonic-gate 	} else {
10970Sstevel@tonic-gate 		dst->ks_data = NULL;
10980Sstevel@tonic-gate 		dst->ks_data_size = 0;
10990Sstevel@tonic-gate 	}
11000Sstevel@tonic-gate }
1101