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