xref: /titanic_50/usr/src/cmd/rpcsvc/rstat_proc.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate /*
30*7c478bd9Sstevel@tonic-gate  * rstat service:  built with rstat.x
31*7c478bd9Sstevel@tonic-gate  */
32*7c478bd9Sstevel@tonic-gate 
33*7c478bd9Sstevel@tonic-gate #include <stdio.h>
34*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
35*7c478bd9Sstevel@tonic-gate #include <stdarg.h>
36*7c478bd9Sstevel@tonic-gate #include <string.h>
37*7c478bd9Sstevel@tonic-gate #include <signal.h>
38*7c478bd9Sstevel@tonic-gate #include <utmpx.h>
39*7c478bd9Sstevel@tonic-gate #include <nlist.h>
40*7c478bd9Sstevel@tonic-gate #include <fcntl.h>
41*7c478bd9Sstevel@tonic-gate #include <syslog.h>
42*7c478bd9Sstevel@tonic-gate #include <kstat.h>
43*7c478bd9Sstevel@tonic-gate 
44*7c478bd9Sstevel@tonic-gate #include <rpc/rpc.h>
45*7c478bd9Sstevel@tonic-gate 
46*7c478bd9Sstevel@tonic-gate #include <sys/socket.h>
47*7c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h>
48*7c478bd9Sstevel@tonic-gate #include <sys/sysinfo.h>
49*7c478bd9Sstevel@tonic-gate #include <sys/systm.h>
50*7c478bd9Sstevel@tonic-gate #include <errno.h>
51*7c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
52*7c478bd9Sstevel@tonic-gate #include <sys/tihdr.h>
53*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
54*7c478bd9Sstevel@tonic-gate 
55*7c478bd9Sstevel@tonic-gate #include <net/if.h>
56*7c478bd9Sstevel@tonic-gate #include <inet/mib2.h>
57*7c478bd9Sstevel@tonic-gate 
58*7c478bd9Sstevel@tonic-gate #include "rstat.h"
59*7c478bd9Sstevel@tonic-gate #include "rstat_v2.h"
60*7c478bd9Sstevel@tonic-gate 
61*7c478bd9Sstevel@tonic-gate typedef struct {
62*7c478bd9Sstevel@tonic-gate 	kstat_t	sys;
63*7c478bd9Sstevel@tonic-gate 	kstat_t	vm;
64*7c478bd9Sstevel@tonic-gate } _cpu_stats_t;
65*7c478bd9Sstevel@tonic-gate 
66*7c478bd9Sstevel@tonic-gate /*
67*7c478bd9Sstevel@tonic-gate  *	system and cpu stats
68*7c478bd9Sstevel@tonic-gate  */
69*7c478bd9Sstevel@tonic-gate static	kstat_ctl_t	*kc;		/* libkstat cookie */
70*7c478bd9Sstevel@tonic-gate static	int	ncpus;
71*7c478bd9Sstevel@tonic-gate static	_cpu_stats_t	*cpu_stats_list = NULL;
72*7c478bd9Sstevel@tonic-gate static	kstat_t	*system_misc_ksp;
73*7c478bd9Sstevel@tonic-gate static	kstat_named_t *boot_time_knp;
74*7c478bd9Sstevel@tonic-gate static	kstat_named_t *avenrun_1min_knp, *avenrun_5min_knp, *avenrun_15min_knp;
75*7c478bd9Sstevel@tonic-gate static	int	hz;
76*7c478bd9Sstevel@tonic-gate static	struct	timeval btm;		/* boottime */
77*7c478bd9Sstevel@tonic-gate 
78*7c478bd9Sstevel@tonic-gate /*
79*7c478bd9Sstevel@tonic-gate  *	network interface stats
80*7c478bd9Sstevel@tonic-gate  */
81*7c478bd9Sstevel@tonic-gate 
82*7c478bd9Sstevel@tonic-gate typedef struct mib_item_s {
83*7c478bd9Sstevel@tonic-gate 	struct mib_item_s	*next_item;
84*7c478bd9Sstevel@tonic-gate 	long			group;
85*7c478bd9Sstevel@tonic-gate 	long			mib_id;
86*7c478bd9Sstevel@tonic-gate 	long			length;
87*7c478bd9Sstevel@tonic-gate 	char			*valp;
88*7c478bd9Sstevel@tonic-gate } mib_item_t;
89*7c478bd9Sstevel@tonic-gate 
90*7c478bd9Sstevel@tonic-gate mib_item_t	*netstat_item;
91*7c478bd9Sstevel@tonic-gate 
92*7c478bd9Sstevel@tonic-gate /*
93*7c478bd9Sstevel@tonic-gate  * disk stats
94*7c478bd9Sstevel@tonic-gate  */
95*7c478bd9Sstevel@tonic-gate 
96*7c478bd9Sstevel@tonic-gate struct diskinfo {
97*7c478bd9Sstevel@tonic-gate 	struct diskinfo *next;
98*7c478bd9Sstevel@tonic-gate 	kstat_t *ks;
99*7c478bd9Sstevel@tonic-gate 	kstat_io_t kios;
100*7c478bd9Sstevel@tonic-gate };
101*7c478bd9Sstevel@tonic-gate 
102*7c478bd9Sstevel@tonic-gate #define	NULLDISK (struct diskinfo *)0
103*7c478bd9Sstevel@tonic-gate static	struct diskinfo zerodisk = { NULL, NULL };
104*7c478bd9Sstevel@tonic-gate static	struct diskinfo *firstdisk = NULLDISK;
105*7c478bd9Sstevel@tonic-gate static	struct diskinfo *lastdisk = NULLDISK;
106*7c478bd9Sstevel@tonic-gate static	struct diskinfo *snip = NULLDISK;
107*7c478bd9Sstevel@tonic-gate static	int ndisks;
108*7c478bd9Sstevel@tonic-gate 
109*7c478bd9Sstevel@tonic-gate /*
110*7c478bd9Sstevel@tonic-gate  * net stats
111*7c478bd9Sstevel@tonic-gate  */
112*7c478bd9Sstevel@tonic-gate 
113*7c478bd9Sstevel@tonic-gate struct netinfo {
114*7c478bd9Sstevel@tonic-gate 	struct netinfo *next;
115*7c478bd9Sstevel@tonic-gate 	kstat_t	*ks;
116*7c478bd9Sstevel@tonic-gate 	kstat_named_t *ipackets;
117*7c478bd9Sstevel@tonic-gate 	kstat_named_t *opackets;
118*7c478bd9Sstevel@tonic-gate 	kstat_named_t *ierrors;
119*7c478bd9Sstevel@tonic-gate 	kstat_named_t *oerrors;
120*7c478bd9Sstevel@tonic-gate 	kstat_named_t *collisions;
121*7c478bd9Sstevel@tonic-gate };
122*7c478bd9Sstevel@tonic-gate 
123*7c478bd9Sstevel@tonic-gate #define	NULLNET (struct netinfo *)0
124*7c478bd9Sstevel@tonic-gate static	struct netinfo zeronet = { NULL, NULL, NULL, NULL, NULL, NULL, NULL };
125*7c478bd9Sstevel@tonic-gate static	struct netinfo *firstnet = NULLNET;
126*7c478bd9Sstevel@tonic-gate static	struct netinfo *lastnet = NULLNET;
127*7c478bd9Sstevel@tonic-gate static	struct netinfo *netsnip = NULLNET;
128*7c478bd9Sstevel@tonic-gate static	int nnets;
129*7c478bd9Sstevel@tonic-gate 
130*7c478bd9Sstevel@tonic-gate /*
131*7c478bd9Sstevel@tonic-gate  *  Define EXIT_WHEN_IDLE if you are able to have this program invoked
132*7c478bd9Sstevel@tonic-gate  *  automatically on demand (as from inetd).  When defined, the service
133*7c478bd9Sstevel@tonic-gate  *  will terminated after being idle for 120 seconds.
134*7c478bd9Sstevel@tonic-gate  */
135*7c478bd9Sstevel@tonic-gate 
136*7c478bd9Sstevel@tonic-gate #define	EXIT_WHEN_IDLE	1
137*7c478bd9Sstevel@tonic-gate 
138*7c478bd9Sstevel@tonic-gate int sincelastreq = 0;		/* number of alarms since last request */
139*7c478bd9Sstevel@tonic-gate #ifdef EXIT_WHEN_IDLE
140*7c478bd9Sstevel@tonic-gate #define	CLOSEDOWN 120		/* how long to wait before exiting */
141*7c478bd9Sstevel@tonic-gate #endif /* def EXIT_WHEN_IDLE */
142*7c478bd9Sstevel@tonic-gate 
143*7c478bd9Sstevel@tonic-gate statstime stats_s3;
144*7c478bd9Sstevel@tonic-gate statsvar stats_s4;
145*7c478bd9Sstevel@tonic-gate /* V2 support for backwards compatibility to pre-5.0 systems */
146*7c478bd9Sstevel@tonic-gate statsswtch stats_s2;
147*7c478bd9Sstevel@tonic-gate 
148*7c478bd9Sstevel@tonic-gate static stat_is_init = 0;
149*7c478bd9Sstevel@tonic-gate 
150*7c478bd9Sstevel@tonic-gate static	void	fail(int, char *, ...);
151*7c478bd9Sstevel@tonic-gate static	void	safe_zalloc(void **, int, int);
152*7c478bd9Sstevel@tonic-gate static	kid_t	safe_kstat_read(kstat_ctl_t *, kstat_t *, void *);
153*7c478bd9Sstevel@tonic-gate static	kstat_t	*safe_kstat_lookup(kstat_ctl_t *, char *, int, char *);
154*7c478bd9Sstevel@tonic-gate static	void	*safe_kstat_data_lookup(kstat_t *, char *);
155*7c478bd9Sstevel@tonic-gate static	void	system_stat_init(void);
156*7c478bd9Sstevel@tonic-gate static	int	system_stat_load(void);
157*7c478bd9Sstevel@tonic-gate static	void	init_disks(void);
158*7c478bd9Sstevel@tonic-gate static	int	diskinfo_load(void);
159*7c478bd9Sstevel@tonic-gate static	void	init_net(void);
160*7c478bd9Sstevel@tonic-gate static	int	netinfo_load(void);
161*7c478bd9Sstevel@tonic-gate 
162*7c478bd9Sstevel@tonic-gate static	void	updatestat(int);
163*7c478bd9Sstevel@tonic-gate 
164*7c478bd9Sstevel@tonic-gate static	mib_item_t	*mibget(int sd);
165*7c478bd9Sstevel@tonic-gate static	int	mibopen(void);
166*7c478bd9Sstevel@tonic-gate static  char	*octetstr(char *buf, Octet_t *op, int code);
167*7c478bd9Sstevel@tonic-gate 
168*7c478bd9Sstevel@tonic-gate static	void	kstat_copy(kstat_t *, kstat_t *, int);
169*7c478bd9Sstevel@tonic-gate 
170*7c478bd9Sstevel@tonic-gate static	char	*cmdname = "rpc.rstatd";
171*7c478bd9Sstevel@tonic-gate 
172*7c478bd9Sstevel@tonic-gate #define	CPU_STAT(ksp, name)	(((kstat_named_t *)safe_kstat_data_lookup( \
173*7c478bd9Sstevel@tonic-gate 				    (ksp), (name)))->value.ui64)
174*7c478bd9Sstevel@tonic-gate static	_cpu_stats_t	cpu_stats_all = { 0 };
175*7c478bd9Sstevel@tonic-gate 
176*7c478bd9Sstevel@tonic-gate static void
177*7c478bd9Sstevel@tonic-gate stat_init(void)
178*7c478bd9Sstevel@tonic-gate {
179*7c478bd9Sstevel@tonic-gate 	struct utmpx *utmpx, utmpx_id;
180*7c478bd9Sstevel@tonic-gate 
181*7c478bd9Sstevel@tonic-gate 	stat_is_init = 1;
182*7c478bd9Sstevel@tonic-gate 
183*7c478bd9Sstevel@tonic-gate 	if ((kc = kstat_open()) == NULL)
184*7c478bd9Sstevel@tonic-gate 		fail(1, "kstat_open(): can't open /dev/kstat");
185*7c478bd9Sstevel@tonic-gate 
186*7c478bd9Sstevel@tonic-gate 	/*
187*7c478bd9Sstevel@tonic-gate 	 * Preallocate minimal set of drive entries.
188*7c478bd9Sstevel@tonic-gate 	 */
189*7c478bd9Sstevel@tonic-gate 
190*7c478bd9Sstevel@tonic-gate 	if (stats_s4.dk_xfer.dk_xfer_val == NULL) {
191*7c478bd9Sstevel@tonic-gate 		stats_s4.dk_xfer.dk_xfer_len = RSTAT_DK_NDRIVE;
192*7c478bd9Sstevel@tonic-gate 		stats_s4.dk_xfer.dk_xfer_val =
193*7c478bd9Sstevel@tonic-gate 		    (int *)calloc(RSTAT_DK_NDRIVE, sizeof (int));
194*7c478bd9Sstevel@tonic-gate 	}
195*7c478bd9Sstevel@tonic-gate 
196*7c478bd9Sstevel@tonic-gate 	system_stat_init();
197*7c478bd9Sstevel@tonic-gate 	init_disks();
198*7c478bd9Sstevel@tonic-gate 	init_net();
199*7c478bd9Sstevel@tonic-gate 
200*7c478bd9Sstevel@tonic-gate 	/*
201*7c478bd9Sstevel@tonic-gate 	 * To get the boot time, use utmpx, which is per-zone, but fall back
202*7c478bd9Sstevel@tonic-gate 	 * to the system-wide kstat if utmpx is hosed for any reason.
203*7c478bd9Sstevel@tonic-gate 	 */
204*7c478bd9Sstevel@tonic-gate 	utmpx_id.ut_type = BOOT_TIME;
205*7c478bd9Sstevel@tonic-gate 	if ((utmpx = getutxid(&utmpx_id)) != NULL)
206*7c478bd9Sstevel@tonic-gate 		btm = utmpx->ut_tv;
207*7c478bd9Sstevel@tonic-gate 	else {
208*7c478bd9Sstevel@tonic-gate 		btm.tv_sec = boot_time_knp->value.ul;
209*7c478bd9Sstevel@tonic-gate 		btm.tv_usec = 0; /* don't bother with usecs for boot time */
210*7c478bd9Sstevel@tonic-gate 	}
211*7c478bd9Sstevel@tonic-gate 	endutxent();
212*7c478bd9Sstevel@tonic-gate 	stats_s4.boottime.tv_sec =
213*7c478bd9Sstevel@tonic-gate 		stats_s2.boottime.tv_sec =
214*7c478bd9Sstevel@tonic-gate 		stats_s3.boottime.tv_sec = btm.tv_sec;
215*7c478bd9Sstevel@tonic-gate 	stats_s4.boottime.tv_usec =
216*7c478bd9Sstevel@tonic-gate 		stats_s2.boottime.tv_usec =
217*7c478bd9Sstevel@tonic-gate 		stats_s3.boottime.tv_usec = btm.tv_usec;
218*7c478bd9Sstevel@tonic-gate 
219*7c478bd9Sstevel@tonic-gate 	updatestat(0);
220*7c478bd9Sstevel@tonic-gate 	alarm(1);
221*7c478bd9Sstevel@tonic-gate 	signal(SIGALRM, updatestat);
222*7c478bd9Sstevel@tonic-gate 	sleep(2);		/* allow for one wake-up */
223*7c478bd9Sstevel@tonic-gate }
224*7c478bd9Sstevel@tonic-gate 
225*7c478bd9Sstevel@tonic-gate statsvar *
226*7c478bd9Sstevel@tonic-gate rstatproc_stats_4_svc(argp, svcrq)
227*7c478bd9Sstevel@tonic-gate void *argp;
228*7c478bd9Sstevel@tonic-gate struct svc_req *svcrq;
229*7c478bd9Sstevel@tonic-gate {
230*7c478bd9Sstevel@tonic-gate 	if (! stat_is_init)
231*7c478bd9Sstevel@tonic-gate 		stat_init();
232*7c478bd9Sstevel@tonic-gate #ifdef EXIT_WHEN_IDLE
233*7c478bd9Sstevel@tonic-gate 	sincelastreq = 0;
234*7c478bd9Sstevel@tonic-gate #endif
235*7c478bd9Sstevel@tonic-gate 	return (&stats_s4);
236*7c478bd9Sstevel@tonic-gate }
237*7c478bd9Sstevel@tonic-gate 
238*7c478bd9Sstevel@tonic-gate statstime *
239*7c478bd9Sstevel@tonic-gate rstatproc_stats_3_svc(argp, svcrq)
240*7c478bd9Sstevel@tonic-gate void *argp;
241*7c478bd9Sstevel@tonic-gate struct svc_req *svcrq;
242*7c478bd9Sstevel@tonic-gate {
243*7c478bd9Sstevel@tonic-gate 	if (! stat_is_init)
244*7c478bd9Sstevel@tonic-gate 		stat_init();
245*7c478bd9Sstevel@tonic-gate #ifdef EXIT_WHEN_IDLE
246*7c478bd9Sstevel@tonic-gate 	sincelastreq = 0;
247*7c478bd9Sstevel@tonic-gate #endif
248*7c478bd9Sstevel@tonic-gate 	return (&stats_s3);
249*7c478bd9Sstevel@tonic-gate }
250*7c478bd9Sstevel@tonic-gate 
251*7c478bd9Sstevel@tonic-gate statsswtch *
252*7c478bd9Sstevel@tonic-gate rstatproc_stats_2_svc(argp, svcrq)
253*7c478bd9Sstevel@tonic-gate void *argp;
254*7c478bd9Sstevel@tonic-gate struct svc_req *svcrq;
255*7c478bd9Sstevel@tonic-gate {
256*7c478bd9Sstevel@tonic-gate 	if (! stat_is_init)
257*7c478bd9Sstevel@tonic-gate 		stat_init();
258*7c478bd9Sstevel@tonic-gate #ifdef EXIT_WHEN_IDLE
259*7c478bd9Sstevel@tonic-gate 	sincelastreq = 0;
260*7c478bd9Sstevel@tonic-gate #endif
261*7c478bd9Sstevel@tonic-gate 	return (&stats_s2);
262*7c478bd9Sstevel@tonic-gate }
263*7c478bd9Sstevel@tonic-gate 
264*7c478bd9Sstevel@tonic-gate 
265*7c478bd9Sstevel@tonic-gate uint_t *
266*7c478bd9Sstevel@tonic-gate rstatproc_havedisk_4_svc(argp, svcrq)
267*7c478bd9Sstevel@tonic-gate void *argp;
268*7c478bd9Sstevel@tonic-gate struct svc_req *svcrq;
269*7c478bd9Sstevel@tonic-gate {
270*7c478bd9Sstevel@tonic-gate 	return (rstatproc_havedisk_3_svc(argp, svcrq));
271*7c478bd9Sstevel@tonic-gate }
272*7c478bd9Sstevel@tonic-gate 
273*7c478bd9Sstevel@tonic-gate uint_t *
274*7c478bd9Sstevel@tonic-gate rstatproc_havedisk_3_svc(argp, svcrq)
275*7c478bd9Sstevel@tonic-gate void *argp;
276*7c478bd9Sstevel@tonic-gate struct svc_req *svcrq;
277*7c478bd9Sstevel@tonic-gate {
278*7c478bd9Sstevel@tonic-gate 	static uint_t have;
279*7c478bd9Sstevel@tonic-gate 
280*7c478bd9Sstevel@tonic-gate 	if (! stat_is_init)
281*7c478bd9Sstevel@tonic-gate 		stat_init();
282*7c478bd9Sstevel@tonic-gate #ifdef EXIT_WHEN_IDLE
283*7c478bd9Sstevel@tonic-gate 	sincelastreq = 0;
284*7c478bd9Sstevel@tonic-gate #endif
285*7c478bd9Sstevel@tonic-gate 	have = (ndisks != 0);
286*7c478bd9Sstevel@tonic-gate 	return (&have);
287*7c478bd9Sstevel@tonic-gate }
288*7c478bd9Sstevel@tonic-gate 
289*7c478bd9Sstevel@tonic-gate uint_t *
290*7c478bd9Sstevel@tonic-gate rstatproc_havedisk_2_svc(argp, svcrq)
291*7c478bd9Sstevel@tonic-gate void *argp;
292*7c478bd9Sstevel@tonic-gate struct svc_req *svcrq;
293*7c478bd9Sstevel@tonic-gate {
294*7c478bd9Sstevel@tonic-gate 	return (rstatproc_havedisk_3_svc(argp, svcrq));
295*7c478bd9Sstevel@tonic-gate }
296*7c478bd9Sstevel@tonic-gate 
297*7c478bd9Sstevel@tonic-gate void
298*7c478bd9Sstevel@tonic-gate updatestat(int ignored)
299*7c478bd9Sstevel@tonic-gate {
300*7c478bd9Sstevel@tonic-gate extern int _rpcpmstart;		 /* Started by a port monitor ? */
301*7c478bd9Sstevel@tonic-gate extern int _rpcsvcdirty;	 /* Still serving ? */
302*7c478bd9Sstevel@tonic-gate 
303*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
304*7c478bd9Sstevel@tonic-gate 	fprintf(stderr, "entering updatestat\n");
305*7c478bd9Sstevel@tonic-gate #endif
306*7c478bd9Sstevel@tonic-gate #ifdef EXIT_WHEN_IDLE
307*7c478bd9Sstevel@tonic-gate 	if (_rpcpmstart && sincelastreq >= CLOSEDOWN && !_rpcsvcdirty) {
308*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
309*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, "about to closedown\n");
310*7c478bd9Sstevel@tonic-gate #endif
311*7c478bd9Sstevel@tonic-gate 		exit(0);
312*7c478bd9Sstevel@tonic-gate 	}
313*7c478bd9Sstevel@tonic-gate 	sincelastreq++;
314*7c478bd9Sstevel@tonic-gate #endif /* def EXIT_WHEN_IDLE */
315*7c478bd9Sstevel@tonic-gate 
316*7c478bd9Sstevel@tonic-gate 	(void) alarm(0);
317*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
318*7c478bd9Sstevel@tonic-gate 	fprintf(stderr, "boottime: %d %d\n", stats_s3.boottime.tv_sec,
319*7c478bd9Sstevel@tonic-gate 		stats_s3.boottime.tv_usec);
320*7c478bd9Sstevel@tonic-gate #endif
321*7c478bd9Sstevel@tonic-gate 	while (system_stat_load() || diskinfo_load() || netinfo_load()) {
322*7c478bd9Sstevel@tonic-gate 		(void) kstat_chain_update(kc);
323*7c478bd9Sstevel@tonic-gate 		system_stat_init();
324*7c478bd9Sstevel@tonic-gate 		init_disks();
325*7c478bd9Sstevel@tonic-gate 		init_net();
326*7c478bd9Sstevel@tonic-gate 	}
327*7c478bd9Sstevel@tonic-gate 	stats_s4.cp_time.cp_time_len = CPU_STATES;
328*7c478bd9Sstevel@tonic-gate 	if (stats_s4.cp_time.cp_time_val == NULL)
329*7c478bd9Sstevel@tonic-gate 		stats_s4.cp_time.cp_time_val =
330*7c478bd9Sstevel@tonic-gate 		malloc(stats_s4.cp_time.cp_time_len * sizeof (int));
331*7c478bd9Sstevel@tonic-gate 	stats_s2.cp_time[RSTAT_CPU_USER] =
332*7c478bd9Sstevel@tonic-gate 	stats_s3.cp_time[RSTAT_CPU_USER] =
333*7c478bd9Sstevel@tonic-gate 	stats_s4.cp_time.cp_time_val[RSTAT_CPU_USER] =
334*7c478bd9Sstevel@tonic-gate 		CPU_STAT(&cpu_stats_all.sys, "cpu_ticks_user");
335*7c478bd9Sstevel@tonic-gate 	stats_s2.cp_time[RSTAT_CPU_NICE] =
336*7c478bd9Sstevel@tonic-gate 	stats_s3.cp_time[RSTAT_CPU_NICE] =
337*7c478bd9Sstevel@tonic-gate 	stats_s4.cp_time.cp_time_val[RSTAT_CPU_NICE] =
338*7c478bd9Sstevel@tonic-gate 		CPU_STAT(&cpu_stats_all.sys, "cpu_ticks_wait");
339*7c478bd9Sstevel@tonic-gate 	stats_s2.cp_time[RSTAT_CPU_SYS] =
340*7c478bd9Sstevel@tonic-gate 	stats_s3.cp_time[RSTAT_CPU_SYS] =
341*7c478bd9Sstevel@tonic-gate 	stats_s4.cp_time.cp_time_val[RSTAT_CPU_SYS] =
342*7c478bd9Sstevel@tonic-gate 		CPU_STAT(&cpu_stats_all.sys, "cpu_ticks_kernel");
343*7c478bd9Sstevel@tonic-gate 	stats_s2.cp_time[RSTAT_CPU_IDLE] =
344*7c478bd9Sstevel@tonic-gate 	stats_s3.cp_time[RSTAT_CPU_IDLE] =
345*7c478bd9Sstevel@tonic-gate 	stats_s4.cp_time.cp_time_val[RSTAT_CPU_IDLE] =
346*7c478bd9Sstevel@tonic-gate 		CPU_STAT(&cpu_stats_all.sys, "cpu_ticks_idle");
347*7c478bd9Sstevel@tonic-gate 
348*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
349*7c478bd9Sstevel@tonic-gate 	fprintf(stderr, "cpu: %d %d %d %d\n",
350*7c478bd9Sstevel@tonic-gate 		CPU_STAT(&cpu_stats_all.sys, "cpu_ticks_user"),
351*7c478bd9Sstevel@tonic-gate 		CPU_STAT(&cpu_stats_all.sys, "cpu_ticks_wait"),
352*7c478bd9Sstevel@tonic-gate 		CPU_STAT(&cpu_stats_all.sys, "cpu_ticks_kernel"),
353*7c478bd9Sstevel@tonic-gate 		CPU_STAT(&cpu_stats_all.sys, "cpu_ticks_idle"));
354*7c478bd9Sstevel@tonic-gate 	fprintf(stderr, "cp_time: %d %d %d %d\n",
355*7c478bd9Sstevel@tonic-gate 		stats_s3.cp_time[RSTAT_CPU_USER],
356*7c478bd9Sstevel@tonic-gate 		stats_s3.cp_time[RSTAT_CPU_NICE],
357*7c478bd9Sstevel@tonic-gate 		stats_s3.cp_time[RSTAT_CPU_SYS],
358*7c478bd9Sstevel@tonic-gate 		stats_s3.cp_time[RSTAT_CPU_IDLE]);
359*7c478bd9Sstevel@tonic-gate #endif
360*7c478bd9Sstevel@tonic-gate 
361*7c478bd9Sstevel@tonic-gate 	/* current time */
362*7c478bd9Sstevel@tonic-gate 	gettimeofday((struct timeval *)&stats_s3.curtime, NULL);
363*7c478bd9Sstevel@tonic-gate 	stats_s4.curtime = stats_s3.curtime;
364*7c478bd9Sstevel@tonic-gate 
365*7c478bd9Sstevel@tonic-gate 	stats_s2.v_pgpgin =
366*7c478bd9Sstevel@tonic-gate 	stats_s3.v_pgpgin =
367*7c478bd9Sstevel@tonic-gate 	stats_s4.v_pgpgin = CPU_STAT(&cpu_stats_all.vm, "pgpgin");
368*7c478bd9Sstevel@tonic-gate 	stats_s2.v_pgpgout =
369*7c478bd9Sstevel@tonic-gate 	stats_s3.v_pgpgout =
370*7c478bd9Sstevel@tonic-gate 	stats_s4.v_pgpgout = CPU_STAT(&cpu_stats_all.vm, "pgpgout");
371*7c478bd9Sstevel@tonic-gate 	stats_s2.v_pswpin =
372*7c478bd9Sstevel@tonic-gate 	stats_s3.v_pswpin =
373*7c478bd9Sstevel@tonic-gate 	stats_s4.v_pswpin = CPU_STAT(&cpu_stats_all.vm, "pgswapin");
374*7c478bd9Sstevel@tonic-gate 	stats_s2.v_pswpout =
375*7c478bd9Sstevel@tonic-gate 	stats_s3.v_pswpout =
376*7c478bd9Sstevel@tonic-gate 	stats_s4.v_pswpout = CPU_STAT(&cpu_stats_all.vm, "pgswapout");
377*7c478bd9Sstevel@tonic-gate 	stats_s3.v_intr = CPU_STAT(&cpu_stats_all.sys, "intr");
378*7c478bd9Sstevel@tonic-gate 	stats_s3.v_intr -= hz*(stats_s3.curtime.tv_sec - btm.tv_sec) +
379*7c478bd9Sstevel@tonic-gate 		hz*(stats_s3.curtime.tv_usec - btm.tv_usec)/1000000;
380*7c478bd9Sstevel@tonic-gate 	stats_s2.v_intr =
381*7c478bd9Sstevel@tonic-gate 	stats_s4.v_intr = stats_s3.v_intr;
382*7c478bd9Sstevel@tonic-gate 	/* swtch not in V1 */
383*7c478bd9Sstevel@tonic-gate 	stats_s2.v_swtch =
384*7c478bd9Sstevel@tonic-gate 	stats_s3.v_swtch =
385*7c478bd9Sstevel@tonic-gate 	stats_s4.v_swtch = CPU_STAT(&cpu_stats_all.sys, "pswitch");
386*7c478bd9Sstevel@tonic-gate 
387*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
388*7c478bd9Sstevel@tonic-gate 	fprintf(stderr,
389*7c478bd9Sstevel@tonic-gate 		"pgin: %d pgout: %d swpin: %d swpout: %d intr: %d swtch: %d\n",
390*7c478bd9Sstevel@tonic-gate 		stats_s3.v_pgpgin,
391*7c478bd9Sstevel@tonic-gate 		stats_s3.v_pgpgout,
392*7c478bd9Sstevel@tonic-gate 		stats_s3.v_pswpin,
393*7c478bd9Sstevel@tonic-gate 		stats_s3.v_pswpout,
394*7c478bd9Sstevel@tonic-gate 		stats_s3.v_intr,
395*7c478bd9Sstevel@tonic-gate 		stats_s3.v_swtch);
396*7c478bd9Sstevel@tonic-gate #endif
397*7c478bd9Sstevel@tonic-gate 	/*
398*7c478bd9Sstevel@tonic-gate 	 * V2 and V3 of rstat are limited to RSTAT_DK_NDRIVE drives
399*7c478bd9Sstevel@tonic-gate 	 */
400*7c478bd9Sstevel@tonic-gate 	memcpy(stats_s3.dk_xfer, stats_s4.dk_xfer.dk_xfer_val,
401*7c478bd9Sstevel@tonic-gate 		RSTAT_DK_NDRIVE * sizeof (int));
402*7c478bd9Sstevel@tonic-gate 	memcpy(stats_s2.dk_xfer, stats_s4.dk_xfer.dk_xfer_val,
403*7c478bd9Sstevel@tonic-gate 		RSTAT_DK_NDRIVE * sizeof (int));
404*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
405*7c478bd9Sstevel@tonic-gate 	fprintf(stderr, "dk_xfer: %d %d %d %d\n",
406*7c478bd9Sstevel@tonic-gate 		stats_s4.dk_xfer.dk_xfer_val[0],
407*7c478bd9Sstevel@tonic-gate 		stats_s4.dk_xfer.dk_xfer_val[1],
408*7c478bd9Sstevel@tonic-gate 		stats_s4.dk_xfer.dk_xfer_val[2],
409*7c478bd9Sstevel@tonic-gate 		stats_s4.dk_xfer.dk_xfer_val[3]);
410*7c478bd9Sstevel@tonic-gate #endif
411*7c478bd9Sstevel@tonic-gate 
412*7c478bd9Sstevel@tonic-gate 	stats_s2.if_ipackets =
413*7c478bd9Sstevel@tonic-gate 	stats_s3.if_ipackets = stats_s4.if_ipackets;
414*7c478bd9Sstevel@tonic-gate 	/* no s2 opackets */
415*7c478bd9Sstevel@tonic-gate 	stats_s3.if_opackets = stats_s4.if_opackets;
416*7c478bd9Sstevel@tonic-gate 	stats_s2.if_ierrors =
417*7c478bd9Sstevel@tonic-gate 	stats_s3.if_ierrors = stats_s4.if_ierrors;
418*7c478bd9Sstevel@tonic-gate 	stats_s2.if_oerrors =
419*7c478bd9Sstevel@tonic-gate 	stats_s3.if_oerrors = stats_s4.if_oerrors;
420*7c478bd9Sstevel@tonic-gate 	stats_s2.if_collisions =
421*7c478bd9Sstevel@tonic-gate 	stats_s3.if_collisions = stats_s4.if_collisions;
422*7c478bd9Sstevel@tonic-gate 
423*7c478bd9Sstevel@tonic-gate 	stats_s2.avenrun[0] =
424*7c478bd9Sstevel@tonic-gate 	stats_s3.avenrun[0] =
425*7c478bd9Sstevel@tonic-gate 	stats_s4.avenrun[0] = avenrun_1min_knp->value.ul;
426*7c478bd9Sstevel@tonic-gate 	stats_s2.avenrun[1] =
427*7c478bd9Sstevel@tonic-gate 	stats_s3.avenrun[1] =
428*7c478bd9Sstevel@tonic-gate 	stats_s4.avenrun[1] = avenrun_5min_knp->value.ul;
429*7c478bd9Sstevel@tonic-gate 	stats_s2.avenrun[2] =
430*7c478bd9Sstevel@tonic-gate 	stats_s3.avenrun[2] =
431*7c478bd9Sstevel@tonic-gate 	stats_s4.avenrun[2] = avenrun_15min_knp->value.ul;
432*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
433*7c478bd9Sstevel@tonic-gate 	fprintf(stderr, "avenrun: %d %d %d\n", stats_s3.avenrun[0],
434*7c478bd9Sstevel@tonic-gate 		stats_s3.avenrun[1], stats_s3.avenrun[2]);
435*7c478bd9Sstevel@tonic-gate #endif
436*7c478bd9Sstevel@tonic-gate 	signal(SIGALRM, updatestat);
437*7c478bd9Sstevel@tonic-gate 	alarm(1);
438*7c478bd9Sstevel@tonic-gate }
439*7c478bd9Sstevel@tonic-gate 
440*7c478bd9Sstevel@tonic-gate /* --------------------------------- MIBGET -------------------------------- */
441*7c478bd9Sstevel@tonic-gate 
442*7c478bd9Sstevel@tonic-gate static mib_item_t *
443*7c478bd9Sstevel@tonic-gate mibget(int sd)
444*7c478bd9Sstevel@tonic-gate {
445*7c478bd9Sstevel@tonic-gate 	int			flags;
446*7c478bd9Sstevel@tonic-gate 	int			j, getcode;
447*7c478bd9Sstevel@tonic-gate 	struct strbuf		ctlbuf, databuf;
448*7c478bd9Sstevel@tonic-gate 	char			buf[512];
449*7c478bd9Sstevel@tonic-gate 	struct T_optmgmt_req	*tor = (struct T_optmgmt_req *)buf;
450*7c478bd9Sstevel@tonic-gate 	struct T_optmgmt_ack	*toa = (struct T_optmgmt_ack *)buf;
451*7c478bd9Sstevel@tonic-gate 	struct T_error_ack	*tea = (struct T_error_ack *)buf;
452*7c478bd9Sstevel@tonic-gate 	struct opthdr		*req;
453*7c478bd9Sstevel@tonic-gate 	mib_item_t		*first_item = NULL;
454*7c478bd9Sstevel@tonic-gate 	mib_item_t		*last_item  = NULL;
455*7c478bd9Sstevel@tonic-gate 	mib_item_t		*temp;
456*7c478bd9Sstevel@tonic-gate 
457*7c478bd9Sstevel@tonic-gate 	tor->PRIM_type = T_SVR4_OPTMGMT_REQ;
458*7c478bd9Sstevel@tonic-gate 	tor->OPT_offset = sizeof (struct T_optmgmt_req);
459*7c478bd9Sstevel@tonic-gate 	tor->OPT_length = sizeof (struct opthdr);
460*7c478bd9Sstevel@tonic-gate 	tor->MGMT_flags = T_CURRENT;
461*7c478bd9Sstevel@tonic-gate 	req = (struct opthdr *)&tor[1];
462*7c478bd9Sstevel@tonic-gate 	req->level = MIB2_IP;		/* any MIB2_xxx value ok here */
463*7c478bd9Sstevel@tonic-gate 	req->name  = 0;
464*7c478bd9Sstevel@tonic-gate 	req->len   = 0;
465*7c478bd9Sstevel@tonic-gate 
466*7c478bd9Sstevel@tonic-gate 	ctlbuf.buf = buf;
467*7c478bd9Sstevel@tonic-gate 	ctlbuf.len = tor->OPT_length + tor->OPT_offset;
468*7c478bd9Sstevel@tonic-gate 	flags = 0;
469*7c478bd9Sstevel@tonic-gate 	if (putmsg(sd, &ctlbuf, NULL, flags) == -1) {
470*7c478bd9Sstevel@tonic-gate 		perror("mibget: putmsg(ctl) failed");
471*7c478bd9Sstevel@tonic-gate 		goto error_exit;
472*7c478bd9Sstevel@tonic-gate 	}
473*7c478bd9Sstevel@tonic-gate 	/*
474*7c478bd9Sstevel@tonic-gate 	 * each reply consists of a ctl part for one fixed structure
475*7c478bd9Sstevel@tonic-gate 	 * or table, as defined in mib2.h.  The format is a T_OPTMGMT_ACK,
476*7c478bd9Sstevel@tonic-gate 	 * containing an opthdr structure.  level/name identify the entry,
477*7c478bd9Sstevel@tonic-gate 	 * len is the size of the data part of the message.
478*7c478bd9Sstevel@tonic-gate 	 */
479*7c478bd9Sstevel@tonic-gate 	req = (struct opthdr *)&toa[1];
480*7c478bd9Sstevel@tonic-gate 	ctlbuf.maxlen = sizeof (buf);
481*7c478bd9Sstevel@tonic-gate 	/*CSTYLED*/
482*7c478bd9Sstevel@tonic-gate 	for (j = 1; ; j++) {
483*7c478bd9Sstevel@tonic-gate 		flags = 0;
484*7c478bd9Sstevel@tonic-gate 		getcode = getmsg(sd, &ctlbuf, NULL, &flags);
485*7c478bd9Sstevel@tonic-gate 		if (getcode == -1) {
486*7c478bd9Sstevel@tonic-gate #ifdef DEBUG_MIB
487*7c478bd9Sstevel@tonic-gate 			perror("mibget getmsg(ctl) failed");
488*7c478bd9Sstevel@tonic-gate 			fprintf(stderr, "#   level   name    len\n");
489*7c478bd9Sstevel@tonic-gate 			i = 0;
490*7c478bd9Sstevel@tonic-gate 			for (last_item = first_item; last_item;
491*7c478bd9Sstevel@tonic-gate 				last_item = last_item->next_item)
492*7c478bd9Sstevel@tonic-gate 				fprintf(stderr, "%d  %4d   %5d   %d\n", ++i,
493*7c478bd9Sstevel@tonic-gate 					last_item->group,
494*7c478bd9Sstevel@tonic-gate 					last_item->mib_id,
495*7c478bd9Sstevel@tonic-gate 					last_item->length);
496*7c478bd9Sstevel@tonic-gate #endif /* DEBUG_MIB */
497*7c478bd9Sstevel@tonic-gate 			goto error_exit;
498*7c478bd9Sstevel@tonic-gate 		}
499*7c478bd9Sstevel@tonic-gate 		if (getcode == 0 &&
500*7c478bd9Sstevel@tonic-gate 			(ctlbuf.len >= sizeof (struct T_optmgmt_ack)) &&
501*7c478bd9Sstevel@tonic-gate 			(toa->PRIM_type == T_OPTMGMT_ACK) &&
502*7c478bd9Sstevel@tonic-gate 			(toa->MGMT_flags == T_SUCCESS) &&
503*7c478bd9Sstevel@tonic-gate 			req->len == 0) {
504*7c478bd9Sstevel@tonic-gate #ifdef DEBUG_MIB
505*7c478bd9Sstevel@tonic-gate 			fprintf(stderr,
506*7c478bd9Sstevel@tonic-gate 		"mibget getmsg() %d returned EOD (level %d, name %d)\n",
507*7c478bd9Sstevel@tonic-gate 				j, req->level, req->name);
508*7c478bd9Sstevel@tonic-gate #endif /* DEBUG_MIB */
509*7c478bd9Sstevel@tonic-gate 			return (first_item);		/* this is EOD msg */
510*7c478bd9Sstevel@tonic-gate 		}
511*7c478bd9Sstevel@tonic-gate 
512*7c478bd9Sstevel@tonic-gate 		if (ctlbuf.len >= sizeof (struct T_error_ack) &&
513*7c478bd9Sstevel@tonic-gate 			(tea->PRIM_type == T_ERROR_ACK)) {
514*7c478bd9Sstevel@tonic-gate #ifdef DEBUG_MIB
515*7c478bd9Sstevel@tonic-gate 			fprintf(stderr,
516*7c478bd9Sstevel@tonic-gate 	"mibget %d gives T_ERROR_ACK: TLI_error = 0x%x, UNIX_error = 0x%x\n",
517*7c478bd9Sstevel@tonic-gate 				j, getcode, tea->TLI_error, tea->UNIX_error);
518*7c478bd9Sstevel@tonic-gate #endif /* DEBUG_MIB */
519*7c478bd9Sstevel@tonic-gate 			errno = (tea->TLI_error == TSYSERR)
520*7c478bd9Sstevel@tonic-gate 				? tea->UNIX_error : EPROTO;
521*7c478bd9Sstevel@tonic-gate 			goto error_exit;
522*7c478bd9Sstevel@tonic-gate 		}
523*7c478bd9Sstevel@tonic-gate 
524*7c478bd9Sstevel@tonic-gate 		if (getcode != MOREDATA ||
525*7c478bd9Sstevel@tonic-gate 			(ctlbuf.len < sizeof (struct T_optmgmt_ack)) ||
526*7c478bd9Sstevel@tonic-gate 			(toa->PRIM_type != T_OPTMGMT_ACK) ||
527*7c478bd9Sstevel@tonic-gate 			(toa->MGMT_flags != T_SUCCESS)) {
528*7c478bd9Sstevel@tonic-gate #ifdef DEBUG_MIB
529*7c478bd9Sstevel@tonic-gate 			fprintf(stderr,
530*7c478bd9Sstevel@tonic-gate 	"mibget getmsg(ctl) %d returned %d, ctlbuf.len = %d, PRIM_type = %d\n",
531*7c478bd9Sstevel@tonic-gate 				j, getcode, ctlbuf.len, toa->PRIM_type);
532*7c478bd9Sstevel@tonic-gate 			if (toa->PRIM_type == T_OPTMGMT_ACK)
533*7c478bd9Sstevel@tonic-gate 				fprintf(stderr,
534*7c478bd9Sstevel@tonic-gate 	"T_OPTMGMT_ACK: MGMT_flags = 0x%x, req->len = %d\n",
535*7c478bd9Sstevel@tonic-gate 					toa->MGMT_flags, req->len);
536*7c478bd9Sstevel@tonic-gate #endif /* DEBUG_MIB */
537*7c478bd9Sstevel@tonic-gate 			errno = ENOMSG;
538*7c478bd9Sstevel@tonic-gate 			goto error_exit;
539*7c478bd9Sstevel@tonic-gate 		}
540*7c478bd9Sstevel@tonic-gate 
541*7c478bd9Sstevel@tonic-gate 		temp = malloc(sizeof (mib_item_t));
542*7c478bd9Sstevel@tonic-gate 		if (!temp) {
543*7c478bd9Sstevel@tonic-gate 			perror("mibget malloc failed");
544*7c478bd9Sstevel@tonic-gate 			goto error_exit;
545*7c478bd9Sstevel@tonic-gate 		}
546*7c478bd9Sstevel@tonic-gate 		if (last_item)
547*7c478bd9Sstevel@tonic-gate 			last_item->next_item = temp;
548*7c478bd9Sstevel@tonic-gate 		else
549*7c478bd9Sstevel@tonic-gate 			first_item = temp;
550*7c478bd9Sstevel@tonic-gate 		last_item = temp;
551*7c478bd9Sstevel@tonic-gate 		last_item->next_item = NULL;
552*7c478bd9Sstevel@tonic-gate 		last_item->group = req->level;
553*7c478bd9Sstevel@tonic-gate 		last_item->mib_id = req->name;
554*7c478bd9Sstevel@tonic-gate 		last_item->length = req->len;
555*7c478bd9Sstevel@tonic-gate 		last_item->valp = malloc(req->len);
556*7c478bd9Sstevel@tonic-gate #ifdef DEBUG_MIB
557*7c478bd9Sstevel@tonic-gate 		fprintf(stderr,
558*7c478bd9Sstevel@tonic-gate 			"msg %d:  group = %4d   mib_id = %5d   length = %d\n",
559*7c478bd9Sstevel@tonic-gate 			j, last_item->group, last_item->mib_id,
560*7c478bd9Sstevel@tonic-gate 			last_item->length);
561*7c478bd9Sstevel@tonic-gate #endif /* DEBUG_MIB */
562*7c478bd9Sstevel@tonic-gate 		databuf.maxlen = last_item->length;
563*7c478bd9Sstevel@tonic-gate 		databuf.buf    = last_item->valp;
564*7c478bd9Sstevel@tonic-gate 		databuf.len    = 0;
565*7c478bd9Sstevel@tonic-gate 		flags = 0;
566*7c478bd9Sstevel@tonic-gate 		getcode = getmsg(sd, NULL, &databuf, &flags);
567*7c478bd9Sstevel@tonic-gate 		if (getcode == -1) {
568*7c478bd9Sstevel@tonic-gate 			perror("mibget getmsg(data) failed");
569*7c478bd9Sstevel@tonic-gate 			goto error_exit;
570*7c478bd9Sstevel@tonic-gate 		} else if (getcode != 0) {
571*7c478bd9Sstevel@tonic-gate 			fprintf(stderr,
572*7c478bd9Sstevel@tonic-gate "mibget getmsg(data) returned %d, databuf.maxlen = %d, databuf.len = %d\n",
573*7c478bd9Sstevel@tonic-gate 				getcode, databuf.maxlen, databuf.len);
574*7c478bd9Sstevel@tonic-gate 			goto error_exit;
575*7c478bd9Sstevel@tonic-gate 		}
576*7c478bd9Sstevel@tonic-gate 	}
577*7c478bd9Sstevel@tonic-gate 
578*7c478bd9Sstevel@tonic-gate error_exit:
579*7c478bd9Sstevel@tonic-gate 	while (first_item) {
580*7c478bd9Sstevel@tonic-gate 		last_item = first_item;
581*7c478bd9Sstevel@tonic-gate 		first_item = first_item->next_item;
582*7c478bd9Sstevel@tonic-gate 		if (last_item->valp) {
583*7c478bd9Sstevel@tonic-gate 			free(last_item->valp);
584*7c478bd9Sstevel@tonic-gate 		}
585*7c478bd9Sstevel@tonic-gate 		free(last_item);
586*7c478bd9Sstevel@tonic-gate 	}
587*7c478bd9Sstevel@tonic-gate 	return (first_item);
588*7c478bd9Sstevel@tonic-gate }
589*7c478bd9Sstevel@tonic-gate 
590*7c478bd9Sstevel@tonic-gate static int
591*7c478bd9Sstevel@tonic-gate mibopen(void)
592*7c478bd9Sstevel@tonic-gate {
593*7c478bd9Sstevel@tonic-gate 	int	sd;
594*7c478bd9Sstevel@tonic-gate 
595*7c478bd9Sstevel@tonic-gate 	/* gives us ip w/ arp on top */
596*7c478bd9Sstevel@tonic-gate 	sd = open("/dev/arp", O_RDWR);
597*7c478bd9Sstevel@tonic-gate 	if (sd == -1) {
598*7c478bd9Sstevel@tonic-gate 		perror("arp open");
599*7c478bd9Sstevel@tonic-gate 		close(sd);
600*7c478bd9Sstevel@tonic-gate 		return (-1);
601*7c478bd9Sstevel@tonic-gate 	}
602*7c478bd9Sstevel@tonic-gate 	if (ioctl(sd, I_PUSH, "tcp") == -1) {
603*7c478bd9Sstevel@tonic-gate 		perror("tcp I_PUSH");
604*7c478bd9Sstevel@tonic-gate 		close(sd);
605*7c478bd9Sstevel@tonic-gate 		return (-1);
606*7c478bd9Sstevel@tonic-gate 	}
607*7c478bd9Sstevel@tonic-gate 	if (ioctl(sd, I_PUSH, "udp") == -1) {
608*7c478bd9Sstevel@tonic-gate 		perror("udp I_PUSH");
609*7c478bd9Sstevel@tonic-gate 		close(sd);
610*7c478bd9Sstevel@tonic-gate 		return (-1);
611*7c478bd9Sstevel@tonic-gate 	}
612*7c478bd9Sstevel@tonic-gate 	return (sd);
613*7c478bd9Sstevel@tonic-gate }
614*7c478bd9Sstevel@tonic-gate 
615*7c478bd9Sstevel@tonic-gate static char *
616*7c478bd9Sstevel@tonic-gate octetstr(char *buf, Octet_t *op, int code)
617*7c478bd9Sstevel@tonic-gate {
618*7c478bd9Sstevel@tonic-gate 	int	i;
619*7c478bd9Sstevel@tonic-gate 	char	*cp;
620*7c478bd9Sstevel@tonic-gate 
621*7c478bd9Sstevel@tonic-gate 	cp = buf;
622*7c478bd9Sstevel@tonic-gate 	if (op)
623*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < op->o_length; i++)
624*7c478bd9Sstevel@tonic-gate 			switch (code) {
625*7c478bd9Sstevel@tonic-gate 			case 'd':
626*7c478bd9Sstevel@tonic-gate 				sprintf(cp, "%d.", 0xff & op->o_bytes[i]);
627*7c478bd9Sstevel@tonic-gate 				cp = strchr(cp, '\0');
628*7c478bd9Sstevel@tonic-gate 				break;
629*7c478bd9Sstevel@tonic-gate 			case 'a':
630*7c478bd9Sstevel@tonic-gate 				*cp++ = op->o_bytes[i];
631*7c478bd9Sstevel@tonic-gate 				break;
632*7c478bd9Sstevel@tonic-gate 			case 'h':
633*7c478bd9Sstevel@tonic-gate 			default:
634*7c478bd9Sstevel@tonic-gate 				sprintf(cp, "%02x:", 0xff & op->o_bytes[i]);
635*7c478bd9Sstevel@tonic-gate 				cp += 3;
636*7c478bd9Sstevel@tonic-gate 				break;
637*7c478bd9Sstevel@tonic-gate 			}
638*7c478bd9Sstevel@tonic-gate 	if (code != 'a' && cp != buf)
639*7c478bd9Sstevel@tonic-gate 		cp--;
640*7c478bd9Sstevel@tonic-gate 	*cp = '\0';
641*7c478bd9Sstevel@tonic-gate 	return (buf);
642*7c478bd9Sstevel@tonic-gate }
643*7c478bd9Sstevel@tonic-gate 
644*7c478bd9Sstevel@tonic-gate static void
645*7c478bd9Sstevel@tonic-gate fail(int do_perror, char *message, ...)
646*7c478bd9Sstevel@tonic-gate {
647*7c478bd9Sstevel@tonic-gate 	va_list args;
648*7c478bd9Sstevel@tonic-gate 
649*7c478bd9Sstevel@tonic-gate 	va_start(args, message);
650*7c478bd9Sstevel@tonic-gate 	fprintf(stderr, "%s: ", cmdname);
651*7c478bd9Sstevel@tonic-gate 	vfprintf(stderr, message, args);
652*7c478bd9Sstevel@tonic-gate 	va_end(args);
653*7c478bd9Sstevel@tonic-gate 	if (do_perror)
654*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, ": %s", strerror(errno));
655*7c478bd9Sstevel@tonic-gate 	fprintf(stderr, "\n");
656*7c478bd9Sstevel@tonic-gate 	exit(2);
657*7c478bd9Sstevel@tonic-gate }
658*7c478bd9Sstevel@tonic-gate 
659*7c478bd9Sstevel@tonic-gate static void
660*7c478bd9Sstevel@tonic-gate safe_zalloc(void **ptr, int size, int free_first)
661*7c478bd9Sstevel@tonic-gate {
662*7c478bd9Sstevel@tonic-gate 	if (free_first && *ptr != NULL)
663*7c478bd9Sstevel@tonic-gate 		free(*ptr);
664*7c478bd9Sstevel@tonic-gate 	if ((*ptr = malloc(size)) == NULL)
665*7c478bd9Sstevel@tonic-gate 		fail(1, "malloc failed");
666*7c478bd9Sstevel@tonic-gate 	memset(*ptr, 0, size);
667*7c478bd9Sstevel@tonic-gate }
668*7c478bd9Sstevel@tonic-gate 
669*7c478bd9Sstevel@tonic-gate kid_t
670*7c478bd9Sstevel@tonic-gate safe_kstat_read(kstat_ctl_t *kctl, kstat_t *ksp, void *data)
671*7c478bd9Sstevel@tonic-gate {
672*7c478bd9Sstevel@tonic-gate 	kid_t kstat_chain_id = kstat_read(kctl, ksp, data);
673*7c478bd9Sstevel@tonic-gate 
674*7c478bd9Sstevel@tonic-gate 	if (kstat_chain_id == -1)
675*7c478bd9Sstevel@tonic-gate 		fail(1, "kstat_read(%x, '%s') failed", kctl, ksp->ks_name);
676*7c478bd9Sstevel@tonic-gate 	return (kstat_chain_id);
677*7c478bd9Sstevel@tonic-gate }
678*7c478bd9Sstevel@tonic-gate 
679*7c478bd9Sstevel@tonic-gate kstat_t *
680*7c478bd9Sstevel@tonic-gate safe_kstat_lookup(kstat_ctl_t *kctl, char *ks_module, int ks_instance,
681*7c478bd9Sstevel@tonic-gate 	char *ks_name)
682*7c478bd9Sstevel@tonic-gate {
683*7c478bd9Sstevel@tonic-gate 	kstat_t *ksp = kstat_lookup(kctl, ks_module, ks_instance, ks_name);
684*7c478bd9Sstevel@tonic-gate 
685*7c478bd9Sstevel@tonic-gate 	if (ksp == NULL)
686*7c478bd9Sstevel@tonic-gate 		fail(0, "kstat_lookup('%s', %d, '%s') failed",
687*7c478bd9Sstevel@tonic-gate 			ks_module == NULL ? "" : ks_module,
688*7c478bd9Sstevel@tonic-gate 			ks_instance,
689*7c478bd9Sstevel@tonic-gate 			ks_name == NULL ? "" : ks_name);
690*7c478bd9Sstevel@tonic-gate 	return (ksp);
691*7c478bd9Sstevel@tonic-gate }
692*7c478bd9Sstevel@tonic-gate 
693*7c478bd9Sstevel@tonic-gate void *
694*7c478bd9Sstevel@tonic-gate safe_kstat_data_lookup(kstat_t *ksp, char *name)
695*7c478bd9Sstevel@tonic-gate {
696*7c478bd9Sstevel@tonic-gate 	void *fp = kstat_data_lookup(ksp, name);
697*7c478bd9Sstevel@tonic-gate 
698*7c478bd9Sstevel@tonic-gate 	if (fp == NULL) {
699*7c478bd9Sstevel@tonic-gate 		fail(0, "kstat_data_lookup('%s', '%s') failed",
700*7c478bd9Sstevel@tonic-gate 			ksp->ks_name, name);
701*7c478bd9Sstevel@tonic-gate 	}
702*7c478bd9Sstevel@tonic-gate 	return (fp);
703*7c478bd9Sstevel@tonic-gate }
704*7c478bd9Sstevel@tonic-gate 
705*7c478bd9Sstevel@tonic-gate /*
706*7c478bd9Sstevel@tonic-gate  * Get various KIDs for subsequent system_stat_load operations.
707*7c478bd9Sstevel@tonic-gate  */
708*7c478bd9Sstevel@tonic-gate 
709*7c478bd9Sstevel@tonic-gate static void
710*7c478bd9Sstevel@tonic-gate system_stat_init(void)
711*7c478bd9Sstevel@tonic-gate {
712*7c478bd9Sstevel@tonic-gate 	kstat_t *ksp;
713*7c478bd9Sstevel@tonic-gate 	int i, nvmks;
714*7c478bd9Sstevel@tonic-gate 
715*7c478bd9Sstevel@tonic-gate 	/*
716*7c478bd9Sstevel@tonic-gate 	 * Global statistics
717*7c478bd9Sstevel@tonic-gate 	 */
718*7c478bd9Sstevel@tonic-gate 
719*7c478bd9Sstevel@tonic-gate 	system_misc_ksp	= safe_kstat_lookup(kc, "unix", 0, "system_misc");
720*7c478bd9Sstevel@tonic-gate 
721*7c478bd9Sstevel@tonic-gate 	safe_kstat_read(kc, system_misc_ksp, NULL);
722*7c478bd9Sstevel@tonic-gate 	boot_time_knp = safe_kstat_data_lookup(system_misc_ksp, "boot_time");
723*7c478bd9Sstevel@tonic-gate 	avenrun_1min_knp = safe_kstat_data_lookup(system_misc_ksp,
724*7c478bd9Sstevel@tonic-gate 		"avenrun_1min");
725*7c478bd9Sstevel@tonic-gate 	avenrun_5min_knp = safe_kstat_data_lookup(system_misc_ksp,
726*7c478bd9Sstevel@tonic-gate 		"avenrun_5min");
727*7c478bd9Sstevel@tonic-gate 	avenrun_15min_knp = safe_kstat_data_lookup(system_misc_ksp,
728*7c478bd9Sstevel@tonic-gate 		"avenrun_15min");
729*7c478bd9Sstevel@tonic-gate 
730*7c478bd9Sstevel@tonic-gate 	/*
731*7c478bd9Sstevel@tonic-gate 	 * Per-CPU statistics
732*7c478bd9Sstevel@tonic-gate 	 */
733*7c478bd9Sstevel@tonic-gate 
734*7c478bd9Sstevel@tonic-gate 	ncpus = 0;
735*7c478bd9Sstevel@tonic-gate 	for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next)
736*7c478bd9Sstevel@tonic-gate 		if (strcmp(ksp->ks_module, "cpu") == 0 &&
737*7c478bd9Sstevel@tonic-gate 		    strcmp(ksp->ks_name, "sys") == 0)
738*7c478bd9Sstevel@tonic-gate 			ncpus++;
739*7c478bd9Sstevel@tonic-gate 
740*7c478bd9Sstevel@tonic-gate 	safe_zalloc((void **)&cpu_stats_list, ncpus * sizeof (*cpu_stats_list),
741*7c478bd9Sstevel@tonic-gate 	    1);
742*7c478bd9Sstevel@tonic-gate 
743*7c478bd9Sstevel@tonic-gate 	ncpus = 0;
744*7c478bd9Sstevel@tonic-gate 	for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next)
745*7c478bd9Sstevel@tonic-gate 		if (strcmp(ksp->ks_module, "cpu") == 0 &&
746*7c478bd9Sstevel@tonic-gate 		    strcmp(ksp->ks_name, "sys") == 0 &&
747*7c478bd9Sstevel@tonic-gate 		    kstat_read(kc, ksp, NULL) != -1) {
748*7c478bd9Sstevel@tonic-gate 			kstat_copy(ksp, &cpu_stats_list[ncpus].sys,
749*7c478bd9Sstevel@tonic-gate 			    1);
750*7c478bd9Sstevel@tonic-gate 			if ((ksp = kstat_lookup(kc, "cpu", ksp->ks_instance,
751*7c478bd9Sstevel@tonic-gate 			    "vm")) != NULL && kstat_read(kc, ksp, NULL) != -1)
752*7c478bd9Sstevel@tonic-gate 				kstat_copy(ksp, &cpu_stats_list[ncpus].vm, 1);
753*7c478bd9Sstevel@tonic-gate 			else
754*7c478bd9Sstevel@tonic-gate 				fail(0, "couldn't find per-CPU VM statistics");
755*7c478bd9Sstevel@tonic-gate 			ncpus++;
756*7c478bd9Sstevel@tonic-gate 		    }
757*7c478bd9Sstevel@tonic-gate 
758*7c478bd9Sstevel@tonic-gate 	if (ncpus == 0)
759*7c478bd9Sstevel@tonic-gate 		fail(0, "couldn't find per-CPU statistics");
760*7c478bd9Sstevel@tonic-gate }
761*7c478bd9Sstevel@tonic-gate 
762*7c478bd9Sstevel@tonic-gate /*
763*7c478bd9Sstevel@tonic-gate  * load statistics, summing across CPUs where needed
764*7c478bd9Sstevel@tonic-gate  */
765*7c478bd9Sstevel@tonic-gate 
766*7c478bd9Sstevel@tonic-gate static int
767*7c478bd9Sstevel@tonic-gate system_stat_load(void)
768*7c478bd9Sstevel@tonic-gate {
769*7c478bd9Sstevel@tonic-gate 	int i, j;
770*7c478bd9Sstevel@tonic-gate 	_cpu_stats_t cs;
771*7c478bd9Sstevel@tonic-gate 	ulong_t *np, *tp;
772*7c478bd9Sstevel@tonic-gate 
773*7c478bd9Sstevel@tonic-gate 	/*
774*7c478bd9Sstevel@tonic-gate 	 * Global statistics
775*7c478bd9Sstevel@tonic-gate 	 */
776*7c478bd9Sstevel@tonic-gate 
777*7c478bd9Sstevel@tonic-gate 	safe_kstat_read(kc, system_misc_ksp, NULL);
778*7c478bd9Sstevel@tonic-gate 
779*7c478bd9Sstevel@tonic-gate 	/*
780*7c478bd9Sstevel@tonic-gate 	 * Per-CPU statistics.
781*7c478bd9Sstevel@tonic-gate 	 */
782*7c478bd9Sstevel@tonic-gate 
783*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < ncpus; i++) {
784*7c478bd9Sstevel@tonic-gate 		if (kstat_read(kc, &cpu_stats_list[i].sys, NULL) == -1 ||
785*7c478bd9Sstevel@tonic-gate 		    kstat_read(kc, &cpu_stats_list[i].vm, NULL) == -1)
786*7c478bd9Sstevel@tonic-gate 			return (1);
787*7c478bd9Sstevel@tonic-gate 		if (i == 0) {
788*7c478bd9Sstevel@tonic-gate 			kstat_copy(&cpu_stats_list[0].sys, &cpu_stats_all.sys,
789*7c478bd9Sstevel@tonic-gate 			    1);
790*7c478bd9Sstevel@tonic-gate 			kstat_copy(&cpu_stats_list[0].vm, &cpu_stats_all.vm, 1);
791*7c478bd9Sstevel@tonic-gate 		} else {
792*7c478bd9Sstevel@tonic-gate 			kstat_named_t *nkp;
793*7c478bd9Sstevel@tonic-gate 			kstat_named_t *tkp;
794*7c478bd9Sstevel@tonic-gate 
795*7c478bd9Sstevel@tonic-gate 			/*
796*7c478bd9Sstevel@tonic-gate 			 * Other CPUs' statistics are accumulated in
797*7c478bd9Sstevel@tonic-gate 			 * cpu_stats_all, initialized at the first iteration of
798*7c478bd9Sstevel@tonic-gate 			 * the loop.
799*7c478bd9Sstevel@tonic-gate 			 */
800*7c478bd9Sstevel@tonic-gate 			nkp = (kstat_named_t *)cpu_stats_all.sys.ks_data;
801*7c478bd9Sstevel@tonic-gate 			tkp = (kstat_named_t *)cpu_stats_list[i].sys.ks_data;
802*7c478bd9Sstevel@tonic-gate 			for (j = 0; j < cpu_stats_list[i].sys.ks_ndata; j++)
803*7c478bd9Sstevel@tonic-gate 				(nkp++)->value.ui64 += (tkp++)->value.ui64;
804*7c478bd9Sstevel@tonic-gate 			nkp = (kstat_named_t *)cpu_stats_all.vm.ks_data;
805*7c478bd9Sstevel@tonic-gate 			tkp = (kstat_named_t *)cpu_stats_list[i].vm.ks_data;
806*7c478bd9Sstevel@tonic-gate 			for (j = 0; j < cpu_stats_list[i].vm.ks_ndata; j++)
807*7c478bd9Sstevel@tonic-gate 				(nkp++)->value.ui64 += (tkp++)->value.ui64;
808*7c478bd9Sstevel@tonic-gate 		}
809*7c478bd9Sstevel@tonic-gate 	}
810*7c478bd9Sstevel@tonic-gate 	return (0);
811*7c478bd9Sstevel@tonic-gate }
812*7c478bd9Sstevel@tonic-gate 
813*7c478bd9Sstevel@tonic-gate static int
814*7c478bd9Sstevel@tonic-gate kscmp(kstat_t *ks1, kstat_t *ks2)
815*7c478bd9Sstevel@tonic-gate {
816*7c478bd9Sstevel@tonic-gate 	int cmp;
817*7c478bd9Sstevel@tonic-gate 
818*7c478bd9Sstevel@tonic-gate 	cmp = strcmp(ks1->ks_module, ks2->ks_module);
819*7c478bd9Sstevel@tonic-gate 	if (cmp != 0)
820*7c478bd9Sstevel@tonic-gate 		return (cmp);
821*7c478bd9Sstevel@tonic-gate 	cmp = ks1->ks_instance - ks2->ks_instance;
822*7c478bd9Sstevel@tonic-gate 	if (cmp != 0)
823*7c478bd9Sstevel@tonic-gate 		return (cmp);
824*7c478bd9Sstevel@tonic-gate 	return (strcmp(ks1->ks_name, ks2->ks_name));
825*7c478bd9Sstevel@tonic-gate }
826*7c478bd9Sstevel@tonic-gate 
827*7c478bd9Sstevel@tonic-gate static void
828*7c478bd9Sstevel@tonic-gate init_disks(void)
829*7c478bd9Sstevel@tonic-gate {
830*7c478bd9Sstevel@tonic-gate 	struct diskinfo *disk, *prevdisk, *comp;
831*7c478bd9Sstevel@tonic-gate 	kstat_t *ksp;
832*7c478bd9Sstevel@tonic-gate 
833*7c478bd9Sstevel@tonic-gate 	ndisks = 0;
834*7c478bd9Sstevel@tonic-gate 	disk = &zerodisk;
835*7c478bd9Sstevel@tonic-gate 
836*7c478bd9Sstevel@tonic-gate 	/*
837*7c478bd9Sstevel@tonic-gate 	 * Patch the snip in the diskinfo list (see below)
838*7c478bd9Sstevel@tonic-gate 	 */
839*7c478bd9Sstevel@tonic-gate 	if (snip)
840*7c478bd9Sstevel@tonic-gate 		lastdisk->next = snip;
841*7c478bd9Sstevel@tonic-gate 
842*7c478bd9Sstevel@tonic-gate 	for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
843*7c478bd9Sstevel@tonic-gate 
844*7c478bd9Sstevel@tonic-gate 		if (ksp->ks_type != KSTAT_TYPE_IO ||
845*7c478bd9Sstevel@tonic-gate 		    strcmp(ksp->ks_class, "disk") != 0)
846*7c478bd9Sstevel@tonic-gate 			continue;
847*7c478bd9Sstevel@tonic-gate 		prevdisk = disk;
848*7c478bd9Sstevel@tonic-gate 		if (disk->next)
849*7c478bd9Sstevel@tonic-gate 			disk = disk->next;
850*7c478bd9Sstevel@tonic-gate 		else {
851*7c478bd9Sstevel@tonic-gate 			safe_zalloc((void **)&disk->next,
852*7c478bd9Sstevel@tonic-gate 			    sizeof (struct diskinfo), 0);
853*7c478bd9Sstevel@tonic-gate 			disk = disk->next;
854*7c478bd9Sstevel@tonic-gate 			disk->next = NULLDISK;
855*7c478bd9Sstevel@tonic-gate 		}
856*7c478bd9Sstevel@tonic-gate 		disk->ks = ksp;
857*7c478bd9Sstevel@tonic-gate 		memset((void *)&disk->kios, 0, sizeof (kstat_io_t));
858*7c478bd9Sstevel@tonic-gate 		disk->kios.wlastupdate = disk->ks->ks_crtime;
859*7c478bd9Sstevel@tonic-gate 		disk->kios.rlastupdate = disk->ks->ks_crtime;
860*7c478bd9Sstevel@tonic-gate 
861*7c478bd9Sstevel@tonic-gate 		/*
862*7c478bd9Sstevel@tonic-gate 		 * Insertion sort on (ks_module, ks_instance, ks_name)
863*7c478bd9Sstevel@tonic-gate 		 */
864*7c478bd9Sstevel@tonic-gate 		comp = &zerodisk;
865*7c478bd9Sstevel@tonic-gate 		while (kscmp(disk->ks, comp->next->ks) > 0)
866*7c478bd9Sstevel@tonic-gate 			comp = comp->next;
867*7c478bd9Sstevel@tonic-gate 		if (prevdisk != comp) {
868*7c478bd9Sstevel@tonic-gate 			prevdisk->next = disk->next;
869*7c478bd9Sstevel@tonic-gate 			disk->next = comp->next;
870*7c478bd9Sstevel@tonic-gate 			comp->next = disk;
871*7c478bd9Sstevel@tonic-gate 			disk = prevdisk;
872*7c478bd9Sstevel@tonic-gate 		}
873*7c478bd9Sstevel@tonic-gate 		ndisks++;
874*7c478bd9Sstevel@tonic-gate 	}
875*7c478bd9Sstevel@tonic-gate 	/*
876*7c478bd9Sstevel@tonic-gate 	 * Put a snip in the linked list of diskinfos.  The idea:
877*7c478bd9Sstevel@tonic-gate 	 * If there was a state change such that now there are fewer
878*7c478bd9Sstevel@tonic-gate 	 * disks, we snip the list and retain the tail, rather than
879*7c478bd9Sstevel@tonic-gate 	 * freeing it.  At the next state change, we clip the tail back on.
880*7c478bd9Sstevel@tonic-gate 	 * This prevents a lot of malloc/free activity, and it's simpler.
881*7c478bd9Sstevel@tonic-gate 	 */
882*7c478bd9Sstevel@tonic-gate 	lastdisk = disk;
883*7c478bd9Sstevel@tonic-gate 	snip = disk->next;
884*7c478bd9Sstevel@tonic-gate 	disk->next = NULLDISK;
885*7c478bd9Sstevel@tonic-gate 
886*7c478bd9Sstevel@tonic-gate 	firstdisk = zerodisk.next;
887*7c478bd9Sstevel@tonic-gate 
888*7c478bd9Sstevel@tonic-gate 	if (ndisks > stats_s4.dk_xfer.dk_xfer_len) {
889*7c478bd9Sstevel@tonic-gate 		stats_s4.dk_xfer.dk_xfer_len = ndisks;
890*7c478bd9Sstevel@tonic-gate 		safe_zalloc((void **)&stats_s4.dk_xfer.dk_xfer_val,
891*7c478bd9Sstevel@tonic-gate 			ndisks * sizeof (int), 1);
892*7c478bd9Sstevel@tonic-gate 	}
893*7c478bd9Sstevel@tonic-gate }
894*7c478bd9Sstevel@tonic-gate 
895*7c478bd9Sstevel@tonic-gate static int
896*7c478bd9Sstevel@tonic-gate diskinfo_load(void)
897*7c478bd9Sstevel@tonic-gate {
898*7c478bd9Sstevel@tonic-gate 	struct diskinfo *disk;
899*7c478bd9Sstevel@tonic-gate 	int i;
900*7c478bd9Sstevel@tonic-gate 
901*7c478bd9Sstevel@tonic-gate 	for (disk = firstdisk, i = 0; disk; disk = disk->next, i++) {
902*7c478bd9Sstevel@tonic-gate 		if (kstat_read(kc, disk->ks, (void *)&disk->kios) == -1)
903*7c478bd9Sstevel@tonic-gate 			return (1);
904*7c478bd9Sstevel@tonic-gate 		stats_s4.dk_xfer.dk_xfer_val[i] = disk->kios.reads +
905*7c478bd9Sstevel@tonic-gate 			disk->kios.writes;
906*7c478bd9Sstevel@tonic-gate 	}
907*7c478bd9Sstevel@tonic-gate 	return (0);
908*7c478bd9Sstevel@tonic-gate }
909*7c478bd9Sstevel@tonic-gate 
910*7c478bd9Sstevel@tonic-gate static void
911*7c478bd9Sstevel@tonic-gate init_net(void)
912*7c478bd9Sstevel@tonic-gate {
913*7c478bd9Sstevel@tonic-gate 	static int sd;
914*7c478bd9Sstevel@tonic-gate 	mib_item_t *item;
915*7c478bd9Sstevel@tonic-gate 	mib2_ipAddrEntry_t *ap;
916*7c478bd9Sstevel@tonic-gate 	char namebuf[KSTAT_STRLEN];
917*7c478bd9Sstevel@tonic-gate 	struct netinfo *net, *prevnet, *comp;
918*7c478bd9Sstevel@tonic-gate 	kstat_t *ksp;
919*7c478bd9Sstevel@tonic-gate 
920*7c478bd9Sstevel@tonic-gate 	if (sd) {
921*7c478bd9Sstevel@tonic-gate 		close(sd);
922*7c478bd9Sstevel@tonic-gate 	}
923*7c478bd9Sstevel@tonic-gate 	while (netstat_item) {
924*7c478bd9Sstevel@tonic-gate 		item = netstat_item;
925*7c478bd9Sstevel@tonic-gate 		netstat_item = netstat_item->next_item;
926*7c478bd9Sstevel@tonic-gate 		if (item->valp) {
927*7c478bd9Sstevel@tonic-gate 			free(item->valp);
928*7c478bd9Sstevel@tonic-gate 		}
929*7c478bd9Sstevel@tonic-gate 		free(item);
930*7c478bd9Sstevel@tonic-gate 	}
931*7c478bd9Sstevel@tonic-gate 	sd = mibopen();
932*7c478bd9Sstevel@tonic-gate 	if (sd == -1) {
933*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
934*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, "mibopen() failed\n");
935*7c478bd9Sstevel@tonic-gate #endif
936*7c478bd9Sstevel@tonic-gate 		sd = 0;
937*7c478bd9Sstevel@tonic-gate 	} else {
938*7c478bd9Sstevel@tonic-gate 		if ((netstat_item = mibget(sd)) == NULL) {
939*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
940*7c478bd9Sstevel@tonic-gate 			fprintf(stderr, "mibget() failed\n");
941*7c478bd9Sstevel@tonic-gate #endif
942*7c478bd9Sstevel@tonic-gate 			close(sd);
943*7c478bd9Sstevel@tonic-gate 			sd = 0;
944*7c478bd9Sstevel@tonic-gate 		}
945*7c478bd9Sstevel@tonic-gate 	}
946*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
947*7c478bd9Sstevel@tonic-gate 	fprintf(stderr, "mibget returned item: %x\n", netstat_item);
948*7c478bd9Sstevel@tonic-gate #endif
949*7c478bd9Sstevel@tonic-gate 
950*7c478bd9Sstevel@tonic-gate 	nnets = 0;
951*7c478bd9Sstevel@tonic-gate 	net = &zeronet;
952*7c478bd9Sstevel@tonic-gate 
953*7c478bd9Sstevel@tonic-gate 	if (netsnip)
954*7c478bd9Sstevel@tonic-gate 		lastnet->next = netsnip;
955*7c478bd9Sstevel@tonic-gate 
956*7c478bd9Sstevel@tonic-gate 	for (item = netstat_item; item; item = item->next_item) {
957*7c478bd9Sstevel@tonic-gate #ifdef DEBUG_MIB
958*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, "\n--- Item %x ---\n", item);
959*7c478bd9Sstevel@tonic-gate 		fprintf(stderr,
960*7c478bd9Sstevel@tonic-gate 		"Group = %d, mib_id = %d, length = %d, valp = 0x%x\n",
961*7c478bd9Sstevel@tonic-gate 		item->group, item->mib_id, item->length,
962*7c478bd9Sstevel@tonic-gate 		item->valp);
963*7c478bd9Sstevel@tonic-gate #endif
964*7c478bd9Sstevel@tonic-gate 		if (item->group != MIB2_IP || item->mib_id != MIB2_IP_20)
965*7c478bd9Sstevel@tonic-gate 			continue;
966*7c478bd9Sstevel@tonic-gate 		ap = (mib2_ipAddrEntry_t *)item->valp;
967*7c478bd9Sstevel@tonic-gate 		for (; (char *)ap < item->valp + item->length; ap++) {
968*7c478bd9Sstevel@tonic-gate 
969*7c478bd9Sstevel@tonic-gate 			octetstr(namebuf, &ap->ipAdEntIfIndex, 'a');
970*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
971*7c478bd9Sstevel@tonic-gate 			fprintf(stderr, "%s ", namebuf);
972*7c478bd9Sstevel@tonic-gate #endif
973*7c478bd9Sstevel@tonic-gate 			if (strlen(namebuf) == 0)
974*7c478bd9Sstevel@tonic-gate 				continue;
975*7c478bd9Sstevel@tonic-gate 			/*
976*7c478bd9Sstevel@tonic-gate 			 * We found a device of interest.
977*7c478bd9Sstevel@tonic-gate 			 * Now, let's see if there's a kstat for it.
978*7c478bd9Sstevel@tonic-gate 			 */
979*7c478bd9Sstevel@tonic-gate 			if ((ksp = kstat_lookup(kc, NULL, -1, namebuf)) == NULL)
980*7c478bd9Sstevel@tonic-gate 				continue;
981*7c478bd9Sstevel@tonic-gate 			if (ksp->ks_type != KSTAT_TYPE_NAMED)
982*7c478bd9Sstevel@tonic-gate 				continue;
983*7c478bd9Sstevel@tonic-gate 			if (kstat_read(kc, ksp, NULL) == -1)
984*7c478bd9Sstevel@tonic-gate 				continue;
985*7c478bd9Sstevel@tonic-gate 			prevnet = net;
986*7c478bd9Sstevel@tonic-gate 			if (net->next)
987*7c478bd9Sstevel@tonic-gate 				net = net->next;
988*7c478bd9Sstevel@tonic-gate 			else {
989*7c478bd9Sstevel@tonic-gate 				safe_zalloc((void **)&net->next,
990*7c478bd9Sstevel@tonic-gate 					sizeof (struct netinfo), 0);
991*7c478bd9Sstevel@tonic-gate 				net = net->next;
992*7c478bd9Sstevel@tonic-gate 				net->next = NULLNET;
993*7c478bd9Sstevel@tonic-gate 			}
994*7c478bd9Sstevel@tonic-gate 			net->ks = ksp;
995*7c478bd9Sstevel@tonic-gate 			net->ipackets	= kstat_data_lookup(net->ks,
996*7c478bd9Sstevel@tonic-gate 				"ipackets");
997*7c478bd9Sstevel@tonic-gate 			net->opackets	= kstat_data_lookup(net->ks,
998*7c478bd9Sstevel@tonic-gate 				"opackets");
999*7c478bd9Sstevel@tonic-gate 			net->ierrors	= kstat_data_lookup(net->ks,
1000*7c478bd9Sstevel@tonic-gate 				"ierrors");
1001*7c478bd9Sstevel@tonic-gate 			net->oerrors	= kstat_data_lookup(net->ks,
1002*7c478bd9Sstevel@tonic-gate 				"oerrors");
1003*7c478bd9Sstevel@tonic-gate 			net->collisions	= kstat_data_lookup(net->ks,
1004*7c478bd9Sstevel@tonic-gate 				"collisions");
1005*7c478bd9Sstevel@tonic-gate 			/*
1006*7c478bd9Sstevel@tonic-gate 			 * Insertion sort on the name
1007*7c478bd9Sstevel@tonic-gate 			 */
1008*7c478bd9Sstevel@tonic-gate 			comp = &zeronet;
1009*7c478bd9Sstevel@tonic-gate 			while (strcmp(net->ks->ks_name,
1010*7c478bd9Sstevel@tonic-gate 			    comp->next->ks->ks_name) > 0)
1011*7c478bd9Sstevel@tonic-gate 				comp = comp->next;
1012*7c478bd9Sstevel@tonic-gate 			if (prevnet != comp) {
1013*7c478bd9Sstevel@tonic-gate 				prevnet->next = net->next;
1014*7c478bd9Sstevel@tonic-gate 				net->next = comp->next;
1015*7c478bd9Sstevel@tonic-gate 				comp->next = net;
1016*7c478bd9Sstevel@tonic-gate 				net = prevnet;
1017*7c478bd9Sstevel@tonic-gate 			}
1018*7c478bd9Sstevel@tonic-gate 			nnets++;
1019*7c478bd9Sstevel@tonic-gate 		}
1020*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
1021*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, "\n");
1022*7c478bd9Sstevel@tonic-gate #endif
1023*7c478bd9Sstevel@tonic-gate 	}
1024*7c478bd9Sstevel@tonic-gate 	/*
1025*7c478bd9Sstevel@tonic-gate 	 * Put a snip in the linked list of netinfos.  The idea:
1026*7c478bd9Sstevel@tonic-gate 	 * If there was a state change such that now there are fewer
1027*7c478bd9Sstevel@tonic-gate 	 * nets, we snip the list and retain the tail, rather than
1028*7c478bd9Sstevel@tonic-gate 	 * freeing it.  At the next state change, we clip the tail back on.
1029*7c478bd9Sstevel@tonic-gate 	 * This prevents a lot of malloc/free activity, and it's simpler.
1030*7c478bd9Sstevel@tonic-gate 	 */
1031*7c478bd9Sstevel@tonic-gate 	lastnet = net;
1032*7c478bd9Sstevel@tonic-gate 	netsnip = net->next;
1033*7c478bd9Sstevel@tonic-gate 	net->next = NULLNET;
1034*7c478bd9Sstevel@tonic-gate 
1035*7c478bd9Sstevel@tonic-gate 	firstnet = zeronet.next;
1036*7c478bd9Sstevel@tonic-gate }
1037*7c478bd9Sstevel@tonic-gate 
1038*7c478bd9Sstevel@tonic-gate static int
1039*7c478bd9Sstevel@tonic-gate netinfo_load(void)
1040*7c478bd9Sstevel@tonic-gate {
1041*7c478bd9Sstevel@tonic-gate 	struct netinfo *net;
1042*7c478bd9Sstevel@tonic-gate 
1043*7c478bd9Sstevel@tonic-gate 	if (netstat_item == NULL) {
1044*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
1045*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, "No net stats\n");
1046*7c478bd9Sstevel@tonic-gate #endif
1047*7c478bd9Sstevel@tonic-gate 		return (0);
1048*7c478bd9Sstevel@tonic-gate 	}
1049*7c478bd9Sstevel@tonic-gate 
1050*7c478bd9Sstevel@tonic-gate 	stats_s4.if_ipackets =
1051*7c478bd9Sstevel@tonic-gate 	stats_s4.if_opackets =
1052*7c478bd9Sstevel@tonic-gate 	stats_s4.if_ierrors =
1053*7c478bd9Sstevel@tonic-gate 	stats_s4.if_oerrors =
1054*7c478bd9Sstevel@tonic-gate 	stats_s4.if_collisions = 0;
1055*7c478bd9Sstevel@tonic-gate 
1056*7c478bd9Sstevel@tonic-gate 	for (net = firstnet; net; net = net->next) {
1057*7c478bd9Sstevel@tonic-gate 		if (kstat_read(kc, net->ks, NULL) == -1)
1058*7c478bd9Sstevel@tonic-gate 			return (1);
1059*7c478bd9Sstevel@tonic-gate 		if (net->ipackets)
1060*7c478bd9Sstevel@tonic-gate 			stats_s4.if_ipackets	+= net->ipackets->value.ul;
1061*7c478bd9Sstevel@tonic-gate 		if (net->opackets)
1062*7c478bd9Sstevel@tonic-gate 			stats_s4.if_opackets	+= net->opackets->value.ul;
1063*7c478bd9Sstevel@tonic-gate 		if (net->ierrors)
1064*7c478bd9Sstevel@tonic-gate 			stats_s4.if_ierrors	+= net->ierrors->value.ul;
1065*7c478bd9Sstevel@tonic-gate 		if (net->oerrors)
1066*7c478bd9Sstevel@tonic-gate 			stats_s4.if_oerrors	+= net->oerrors->value.ul;
1067*7c478bd9Sstevel@tonic-gate 		if (net->collisions)
1068*7c478bd9Sstevel@tonic-gate 			stats_s4.if_collisions	+= net->collisions->value.ul;
1069*7c478bd9Sstevel@tonic-gate 	}
1070*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
1071*7c478bd9Sstevel@tonic-gate 	fprintf(stderr,
1072*7c478bd9Sstevel@tonic-gate 	    "ipackets: %d opackets: %d ierrors: %d oerrors: %d colls: %d\n",
1073*7c478bd9Sstevel@tonic-gate 		stats_s4.if_ipackets,
1074*7c478bd9Sstevel@tonic-gate 		stats_s4.if_opackets,
1075*7c478bd9Sstevel@tonic-gate 		stats_s4.if_ierrors,
1076*7c478bd9Sstevel@tonic-gate 		stats_s4.if_oerrors,
1077*7c478bd9Sstevel@tonic-gate 		stats_s4.if_collisions);
1078*7c478bd9Sstevel@tonic-gate #endif
1079*7c478bd9Sstevel@tonic-gate 	return (0);
1080*7c478bd9Sstevel@tonic-gate }
1081*7c478bd9Sstevel@tonic-gate 
1082*7c478bd9Sstevel@tonic-gate static void
1083*7c478bd9Sstevel@tonic-gate kstat_copy(kstat_t *src, kstat_t *dst, int fr)
1084*7c478bd9Sstevel@tonic-gate {
1085*7c478bd9Sstevel@tonic-gate 	if (fr)
1086*7c478bd9Sstevel@tonic-gate 		free(dst->ks_data);
1087*7c478bd9Sstevel@tonic-gate 	*dst = *src;
1088*7c478bd9Sstevel@tonic-gate 	if (src->ks_data != NULL) {
1089*7c478bd9Sstevel@tonic-gate 		safe_zalloc(&dst->ks_data, src->ks_data_size, 0);
1090*7c478bd9Sstevel@tonic-gate 		(void) memcpy(dst->ks_data, src->ks_data, src->ks_data_size);
1091*7c478bd9Sstevel@tonic-gate 	} else {
1092*7c478bd9Sstevel@tonic-gate 		dst->ks_data = NULL;
1093*7c478bd9Sstevel@tonic-gate 		dst->ks_data_size = 0;
1094*7c478bd9Sstevel@tonic-gate 	}
1095*7c478bd9Sstevel@tonic-gate }
1096