4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #pragma ident "%Z%%M% %I% %E% SMI"
29 * rstat service: built with rstat.x
45 #include <sys/socket.h>
46 #include <sys/cpuvar.h>
47 #include <sys/sysinfo.h>
48 #include <sys/systm.h>
50 #include <sys/stropts.h>
51 #include <sys/tihdr.h>
52 #include <sys/sysmacros.h>
55 #include <inet/mib2.h>
66 * system and cpu stats
68 static kstat_ctl_t
*kc
; /* libkstat cookie */
70 static _cpu_stats_t
*cpu_stats_list
= NULL
;
71 static kstat_t
*system_misc_ksp
;
72 static kstat_named_t
*boot_time_knp
;
73 static kstat_named_t
*avenrun_1min_knp
, *avenrun_5min_knp
, *avenrun_15min_knp
;
75 static struct timeval btm
; /* boottime */
78 * network interface stats
81 typedef struct mib_item_s
{
82 struct mib_item_s
*next_item
;
89 mib_item_t
*netstat_item
;
96 struct diskinfo
*next
;
101 #define NULLDISK (struct diskinfo *)0
102 static struct diskinfo zerodisk
= { NULL
, NULL
};
103 static struct diskinfo
*firstdisk
= NULLDISK
;
104 static struct diskinfo
*lastdisk
= NULLDISK
;
105 static struct diskinfo
*snip
= NULLDISK
;
113 struct netinfo
*next
;
115 kstat_named_t
*ipackets
;
116 kstat_named_t
*opackets
;
117 kstat_named_t
*ierrors
;
118 kstat_named_t
*oerrors
;
119 kstat_named_t
*collisions
;
122 #define NULLNET (struct netinfo *)0
123 static struct netinfo zeronet
= { NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
};
124 static struct netinfo
*firstnet
= NULLNET
;
125 static struct netinfo
*lastnet
= NULLNET
;
126 static struct netinfo
*netsnip
= NULLNET
;
130 * Define EXIT_WHEN_IDLE if you are able to have this program invoked
131 * automatically on demand (as from inetd). When defined, the service
132 * will terminated after being idle for 120 seconds.
135 #define EXIT_WHEN_IDLE 1
137 int sincelastreq
= 0; /* number of alarms since last request */
138 #ifdef EXIT_WHEN_IDLE
139 #define CLOSEDOWN 120 /* how long to wait before exiting */
140 #endif /* def EXIT_WHEN_IDLE */
144 /* V2 support for backwards compatibility to pre-5.0 systems */
147 static int stat_is_init
= 0;
149 static void fail(int, char *, ...);
150 static void safe_zalloc(void **, int, int);
151 static kid_t
safe_kstat_read(kstat_ctl_t
*, kstat_t
*, void *);
152 static kstat_t
*safe_kstat_lookup(kstat_ctl_t
*, char *, int, char *);
153 static void *safe_kstat_data_lookup(kstat_t
*, char *);
154 static void system_stat_init(void);
155 static int system_stat_load(void);
156 static void init_disks(void);
157 static int diskinfo_load(void);
158 static void init_net(void);
159 static int netinfo_load(void);
161 static void updatestat(int);
163 static mib_item_t
*mibget(int sd
);
164 static int mibopen(void);
165 static char *octetstr(char *buf
, Octet_t
*op
, int code
);
167 static void kstat_copy(kstat_t
*, kstat_t
*, int);
169 static char *cmdname
= "rpc.rstatd";
171 #define CPU_STAT(ksp, name) (((kstat_named_t *)safe_kstat_data_lookup( \
172 (ksp), (name)))->value.ui64)
173 static _cpu_stats_t cpu_stats_all
= { 0 };
178 struct utmpx
*utmpx
, utmpx_id
;
182 if ((kc
= kstat_open()) == NULL
)
183 fail(1, "kstat_open(): can't open /dev/kstat");
186 * Preallocate minimal set of drive entries.
189 if (stats_s4
.dk_xfer
.dk_xfer_val
== NULL
) {
190 stats_s4
.dk_xfer
.dk_xfer_len
= RSTAT_DK_NDRIVE
;
191 stats_s4
.dk_xfer
.dk_xfer_val
=
192 (int *)calloc(RSTAT_DK_NDRIVE
, sizeof (int));
200 * To get the boot time, use utmpx, which is per-zone, but fall back
201 * to the system-wide kstat if utmpx is hosed for any reason.
203 utmpx_id
.ut_type
= BOOT_TIME
;
204 if ((utmpx
= getutxid(&utmpx_id
)) != NULL
)
207 btm
.tv_sec
= boot_time_knp
->value
.ul
;
208 btm
.tv_usec
= 0; /* don't bother with usecs for boot time */
211 stats_s4
.boottime
.tv_sec
=
212 stats_s2
.boottime
.tv_sec
=
213 stats_s3
.boottime
.tv_sec
= btm
.tv_sec
;
214 stats_s4
.boottime
.tv_usec
=
215 stats_s2
.boottime
.tv_usec
=
216 stats_s3
.boottime
.tv_usec
= btm
.tv_usec
;
220 signal(SIGALRM
, updatestat
);
221 sleep(2); /* allow for one wake-up */
225 rstatproc_stats_4_svc(argp
, svcrq
)
227 struct svc_req
*svcrq
;
231 #ifdef EXIT_WHEN_IDLE
238 rstatproc_stats_3_svc(argp
, svcrq
)
240 struct svc_req
*svcrq
;
244 #ifdef EXIT_WHEN_IDLE
251 rstatproc_stats_2_svc(argp
, svcrq
)
253 struct svc_req
*svcrq
;
257 #ifdef EXIT_WHEN_IDLE
265 rstatproc_havedisk_4_svc(argp
, svcrq
)
267 struct svc_req
*svcrq
;
269 return (rstatproc_havedisk_3_svc(argp
, svcrq
));
273 rstatproc_havedisk_3_svc(argp
, svcrq
)
275 struct svc_req
*svcrq
;
281 #ifdef EXIT_WHEN_IDLE
284 have
= (ndisks
!= 0);
289 rstatproc_havedisk_2_svc(argp
, svcrq
)
291 struct svc_req
*svcrq
;
293 return (rstatproc_havedisk_3_svc(argp
, svcrq
));
297 updatestat(int ignored
)
299 extern int _rpcpmstart
; /* Started by a port monitor ? */
300 extern int _rpcsvcdirty
; /* Still serving ? */
303 fprintf(stderr
, "entering updatestat\n");
305 #ifdef EXIT_WHEN_IDLE
306 if (_rpcpmstart
&& sincelastreq
>= CLOSEDOWN
&& !_rpcsvcdirty
) {
308 fprintf(stderr
, "about to closedown\n");
313 #endif /* def EXIT_WHEN_IDLE */
317 fprintf(stderr
, "boottime: %d %d\n", stats_s3
.boottime
.tv_sec
,
318 stats_s3
.boottime
.tv_usec
);
320 while (system_stat_load() || diskinfo_load() || netinfo_load()) {
321 (void) kstat_chain_update(kc
);
326 stats_s4
.cp_time
.cp_time_len
= CPU_STATES
;
327 if (stats_s4
.cp_time
.cp_time_val
== NULL
)
328 stats_s4
.cp_time
.cp_time_val
=
329 malloc(stats_s4
.cp_time
.cp_time_len
* sizeof (int));
330 stats_s2
.cp_time
[RSTAT_CPU_USER
] =
331 stats_s3
.cp_time
[RSTAT_CPU_USER
] =
332 stats_s4
.cp_time
.cp_time_val
[RSTAT_CPU_USER
] =
333 CPU_STAT(&cpu_stats_all
.sys
, "cpu_ticks_user");
334 stats_s2
.cp_time
[RSTAT_CPU_NICE
] =
335 stats_s3
.cp_time
[RSTAT_CPU_NICE
] =
336 stats_s4
.cp_time
.cp_time_val
[RSTAT_CPU_NICE
] =
337 CPU_STAT(&cpu_stats_all
.sys
, "cpu_ticks_wait");
338 stats_s2
.cp_time
[RSTAT_CPU_SYS
] =
339 stats_s3
.cp_time
[RSTAT_CPU_SYS
] =
340 stats_s4
.cp_time
.cp_time_val
[RSTAT_CPU_SYS
] =
341 CPU_STAT(&cpu_stats_all
.sys
, "cpu_ticks_kernel");
342 stats_s2
.cp_time
[RSTAT_CPU_IDLE
] =
343 stats_s3
.cp_time
[RSTAT_CPU_IDLE
] =
344 stats_s4
.cp_time
.cp_time_val
[RSTAT_CPU_IDLE
] =
345 CPU_STAT(&cpu_stats_all
.sys
, "cpu_ticks_idle");
348 fprintf(stderr
, "cpu: %d %d %d %d\n",
349 CPU_STAT(&cpu_stats_all
.sys
, "cpu_ticks_user"),
350 CPU_STAT(&cpu_stats_all
.sys
, "cpu_ticks_wait"),
351 CPU_STAT(&cpu_stats_all
.sys
, "cpu_ticks_kernel"),
352 CPU_STAT(&cpu_stats_all
.sys
, "cpu_ticks_idle"));
353 fprintf(stderr
, "cp_time: %d %d %d %d\n",
354 stats_s3
.cp_time
[RSTAT_CPU_USER
],
355 stats_s3
.cp_time
[RSTAT_CPU_NICE
],
356 stats_s3
.cp_time
[RSTAT_CPU_SYS
],
357 stats_s3
.cp_time
[RSTAT_CPU_IDLE
]);
361 gettimeofday((struct timeval
*)&stats_s3
.curtime
, NULL
);
362 stats_s4
.curtime
= stats_s3
.curtime
;
366 stats_s4
.v_pgpgin
= CPU_STAT(&cpu_stats_all
.vm
, "pgpgin");
369 stats_s4
.v_pgpgout
= CPU_STAT(&cpu_stats_all
.vm
, "pgpgout");
372 stats_s4
.v_pswpin
= CPU_STAT(&cpu_stats_all
.vm
, "pgswapin");
375 stats_s4
.v_pswpout
= CPU_STAT(&cpu_stats_all
.vm
, "pgswapout");
376 stats_s3
.v_intr
= CPU_STAT(&cpu_stats_all
.sys
, "intr");
377 stats_s3
.v_intr
-= hz
*(stats_s3
.curtime
.tv_sec
- btm
.tv_sec
) +
378 hz
*(stats_s3
.curtime
.tv_usec
- btm
.tv_usec
)/1000000;
380 stats_s4
.v_intr
= stats_s3
.v_intr
;
381 /* swtch not in V1 */
384 stats_s4
.v_swtch
= CPU_STAT(&cpu_stats_all
.sys
, "pswitch");
388 "pgin: %d pgout: %d swpin: %d swpout: %d intr: %d swtch: %d\n",
397 * V2 and V3 of rstat are limited to RSTAT_DK_NDRIVE drives
399 memcpy(stats_s3
.dk_xfer
, stats_s4
.dk_xfer
.dk_xfer_val
,
400 RSTAT_DK_NDRIVE
* sizeof (int));
401 memcpy(stats_s2
.dk_xfer
, stats_s4
.dk_xfer
.dk_xfer_val
,
402 RSTAT_DK_NDRIVE
* sizeof (int));
404 fprintf(stderr
, "dk_xfer: %d %d %d %d\n",
405 stats_s4
.dk_xfer
.dk_xfer_val
[0],
406 stats_s4
.dk_xfer
.dk_xfer_val
[1],
407 stats_s4
.dk_xfer
.dk_xfer_val
[2],
408 stats_s4
.dk_xfer
.dk_xfer_val
[3]);
411 stats_s2
.if_ipackets
=
412 stats_s3
.if_ipackets
= stats_s4
.if_ipackets
;
414 stats_s3
.if_opackets
= stats_s4
.if_opackets
;
415 stats_s2
.if_ierrors
=
416 stats_s3
.if_ierrors
= stats_s4
.if_ierrors
;
417 stats_s2
.if_oerrors
=
418 stats_s3
.if_oerrors
= stats_s4
.if_oerrors
;
419 stats_s2
.if_collisions
=
420 stats_s3
.if_collisions
= stats_s4
.if_collisions
;
422 stats_s2
.avenrun
[0] =
423 stats_s3
.avenrun
[0] =
424 stats_s4
.avenrun
[0] = avenrun_1min_knp
->value
.ul
;
425 stats_s2
.avenrun
[1] =
426 stats_s3
.avenrun
[1] =
427 stats_s4
.avenrun
[1] = avenrun_5min_knp
->value
.ul
;
428 stats_s2
.avenrun
[2] =
429 stats_s3
.avenrun
[2] =
430 stats_s4
.avenrun
[2] = avenrun_15min_knp
->value
.ul
;
432 fprintf(stderr
, "avenrun: %d %d %d\n", stats_s3
.avenrun
[0],
433 stats_s3
.avenrun
[1], stats_s3
.avenrun
[2]);
435 signal(SIGALRM
, updatestat
);
439 /* --------------------------------- MIBGET -------------------------------- */
446 struct strbuf ctlbuf
, databuf
;
448 struct T_optmgmt_req
*tor
= (struct T_optmgmt_req
*)buf
;
449 struct T_optmgmt_ack
*toa
= (struct T_optmgmt_ack
*)buf
;
450 struct T_error_ack
*tea
= (struct T_error_ack
*)buf
;
452 mib_item_t
*first_item
= NULL
;
453 mib_item_t
*last_item
= NULL
;
456 tor
->PRIM_type
= T_SVR4_OPTMGMT_REQ
;
457 tor
->OPT_offset
= sizeof (struct T_optmgmt_req
);
458 tor
->OPT_length
= sizeof (struct opthdr
);
459 tor
->MGMT_flags
= T_CURRENT
;
460 req
= (struct opthdr
*)&tor
[1];
461 req
->level
= MIB2_IP
; /* any MIB2_xxx value ok here */
466 ctlbuf
.len
= tor
->OPT_length
+ tor
->OPT_offset
;
468 if (putmsg(sd
, &ctlbuf
, NULL
, flags
) == -1) {
469 perror("mibget: putmsg(ctl) failed");
473 * each reply consists of a ctl part for one fixed structure
474 * or table, as defined in mib2.h. The format is a T_OPTMGMT_ACK,
475 * containing an opthdr structure. level/name identify the entry,
476 * len is the size of the data part of the message.
478 req
= (struct opthdr
*)&toa
[1];
479 ctlbuf
.maxlen
= sizeof (buf
);
483 getcode
= getmsg(sd
, &ctlbuf
, NULL
, &flags
);
486 perror("mibget getmsg(ctl) failed");
487 fprintf(stderr
, "# level name len\n");
489 for (last_item
= first_item
; last_item
;
490 last_item
= last_item
->next_item
)
491 fprintf(stderr
, "%d %4d %5d %d\n", ++i
,
495 #endif /* DEBUG_MIB */
499 (ctlbuf
.len
>= sizeof (struct T_optmgmt_ack
)) &&
500 (toa
->PRIM_type
== T_OPTMGMT_ACK
) &&
501 (toa
->MGMT_flags
== T_SUCCESS
) &&
505 "mibget getmsg() %d returned EOD (level %d, name %d)\n",
506 j
, req
->level
, req
->name
);
507 #endif /* DEBUG_MIB */
508 return (first_item
); /* this is EOD msg */
511 if (ctlbuf
.len
>= sizeof (struct T_error_ack
) &&
512 (tea
->PRIM_type
== T_ERROR_ACK
)) {
515 "mibget %d gives T_ERROR_ACK: TLI_error = 0x%x, UNIX_error = 0x%x\n",
516 j
, getcode
, tea
->TLI_error
, tea
->UNIX_error
);
517 #endif /* DEBUG_MIB */
518 errno
= (tea
->TLI_error
== TSYSERR
)
519 ? tea
->UNIX_error
: EPROTO
;
523 if (getcode
!= MOREDATA
||
524 (ctlbuf
.len
< sizeof (struct T_optmgmt_ack
)) ||
525 (toa
->PRIM_type
!= T_OPTMGMT_ACK
) ||
526 (toa
->MGMT_flags
!= T_SUCCESS
)) {
529 "mibget getmsg(ctl) %d returned %d, ctlbuf.len = %d, PRIM_type = %d\n",
530 j
, getcode
, ctlbuf
.len
, toa
->PRIM_type
);
531 if (toa
->PRIM_type
== T_OPTMGMT_ACK
)
533 "T_OPTMGMT_ACK: MGMT_flags = 0x%x, req->len = %d\n",
534 toa
->MGMT_flags
, req
->len
);
535 #endif /* DEBUG_MIB */
540 temp
= malloc(sizeof (mib_item_t
));
542 perror("mibget malloc failed");
546 last_item
->next_item
= temp
;
550 last_item
->next_item
= NULL
;
551 last_item
->group
= req
->level
;
552 last_item
->mib_id
= req
->name
;
553 last_item
->length
= req
->len
;
554 last_item
->valp
= malloc(req
->len
);
557 "msg %d: group = %4d mib_id = %5d length = %d\n",
558 j
, last_item
->group
, last_item
->mib_id
,
560 #endif /* DEBUG_MIB */
561 databuf
.maxlen
= last_item
->length
;
562 databuf
.buf
= last_item
->valp
;
565 getcode
= getmsg(sd
, NULL
, &databuf
, &flags
);
567 perror("mibget getmsg(data) failed");
569 } else if (getcode
!= 0) {
571 "mibget getmsg(data) returned %d, databuf.maxlen = %d, databuf.len = %d\n",
572 getcode
, databuf
.maxlen
, databuf
.len
);
579 last_item
= first_item
;
580 first_item
= first_item
->next_item
;
581 if (last_item
->valp
) {
582 free(last_item
->valp
);
594 /* gives us ip w/ arp on top */
595 sd
= open("/dev/arp", O_RDWR
);
601 if (ioctl(sd
, I_PUSH
, "tcp") == -1) {
602 perror("tcp I_PUSH");
606 if (ioctl(sd
, I_PUSH
, "udp") == -1) {
607 perror("udp I_PUSH");
615 octetstr(char *buf
, Octet_t
*op
, int code
)
622 for (i
= 0; i
< op
->o_length
; i
++)
625 sprintf(cp
, "%d.", 0xff & op
->o_bytes
[i
]);
626 cp
= strchr(cp
, '\0');
629 *cp
++ = op
->o_bytes
[i
];
633 sprintf(cp
, "%02x:", 0xff & op
->o_bytes
[i
]);
637 if (code
!= 'a' && cp
!= buf
)
644 fail(int do_perror
, char *message
, ...)
648 va_start(args
, message
);
649 fprintf(stderr
, "%s: ", cmdname
);
650 vfprintf(stderr
, message
, args
);
653 fprintf(stderr
, ": %s", strerror(errno
));
654 fprintf(stderr
, "\n");
659 safe_zalloc(void **ptr
, int size
, int free_first
)
661 if (free_first
&& *ptr
!= NULL
)
663 if ((*ptr
= malloc(size
)) == NULL
)
664 fail(1, "malloc failed");
665 memset(*ptr
, 0, size
);
669 safe_kstat_read(kstat_ctl_t
*kctl
, kstat_t
*ksp
, void *data
)
671 kid_t kstat_chain_id
= kstat_read(kctl
, ksp
, data
);
673 if (kstat_chain_id
== -1)
674 fail(1, "kstat_read(%x, '%s') failed", kctl
, ksp
->ks_name
);
675 return (kstat_chain_id
);
679 safe_kstat_lookup(kstat_ctl_t
*kctl
, char *ks_module
, int ks_instance
,
682 kstat_t
*ksp
= kstat_lookup(kctl
, ks_module
, ks_instance
, ks_name
);
685 fail(0, "kstat_lookup('%s', %d, '%s') failed",
686 ks_module
== NULL
? "" : ks_module
,
688 ks_name
== NULL
? "" : ks_name
);
693 safe_kstat_data_lookup(kstat_t
*ksp
, char *name
)
695 void *fp
= kstat_data_lookup(ksp
, name
);
698 fail(0, "kstat_data_lookup('%s', '%s') failed",
705 * Get various KIDs for subsequent system_stat_load operations.
709 system_stat_init(void)
718 system_misc_ksp
= safe_kstat_lookup(kc
, "unix", 0, "system_misc");
720 safe_kstat_read(kc
, system_misc_ksp
, NULL
);
721 boot_time_knp
= safe_kstat_data_lookup(system_misc_ksp
, "boot_time");
722 avenrun_1min_knp
= safe_kstat_data_lookup(system_misc_ksp
,
724 avenrun_5min_knp
= safe_kstat_data_lookup(system_misc_ksp
,
726 avenrun_15min_knp
= safe_kstat_data_lookup(system_misc_ksp
,
734 for (ksp
= kc
->kc_chain
; ksp
; ksp
= ksp
->ks_next
)
735 if (strcmp(ksp
->ks_module
, "cpu") == 0 &&
736 strcmp(ksp
->ks_name
, "sys") == 0)
739 safe_zalloc((void **)&cpu_stats_list
, ncpus
* sizeof (*cpu_stats_list
),
743 for (ksp
= kc
->kc_chain
; ksp
; ksp
= ksp
->ks_next
)
744 if (strcmp(ksp
->ks_module
, "cpu") == 0 &&
745 strcmp(ksp
->ks_name
, "sys") == 0 &&
746 kstat_read(kc
, ksp
, NULL
) != -1) {
747 kstat_copy(ksp
, &cpu_stats_list
[ncpus
].sys
,
749 if ((ksp
= kstat_lookup(kc
, "cpu", ksp
->ks_instance
,
750 "vm")) != NULL
&& kstat_read(kc
, ksp
, NULL
) != -1)
751 kstat_copy(ksp
, &cpu_stats_list
[ncpus
].vm
, 1);
753 fail(0, "couldn't find per-CPU VM statistics");
758 fail(0, "couldn't find per-CPU statistics");
762 * load statistics, summing across CPUs where needed
766 system_stat_load(void)
776 safe_kstat_read(kc
, system_misc_ksp
, NULL
);
779 * Per-CPU statistics.
782 for (i
= 0; i
< ncpus
; i
++) {
783 if (kstat_read(kc
, &cpu_stats_list
[i
].sys
, NULL
) == -1 ||
784 kstat_read(kc
, &cpu_stats_list
[i
].vm
, NULL
) == -1)
787 kstat_copy(&cpu_stats_list
[0].sys
, &cpu_stats_all
.sys
,
789 kstat_copy(&cpu_stats_list
[0].vm
, &cpu_stats_all
.vm
, 1);
795 * Other CPUs' statistics are accumulated in
796 * cpu_stats_all, initialized at the first iteration of
799 nkp
= (kstat_named_t
*)cpu_stats_all
.sys
.ks_data
;
800 tkp
= (kstat_named_t
*)cpu_stats_list
[i
].sys
.ks_data
;
801 for (j
= 0; j
< cpu_stats_list
[i
].sys
.ks_ndata
; j
++)
802 (nkp
++)->value
.ui64
+= (tkp
++)->value
.ui64
;
803 nkp
= (kstat_named_t
*)cpu_stats_all
.vm
.ks_data
;
804 tkp
= (kstat_named_t
*)cpu_stats_list
[i
].vm
.ks_data
;
805 for (j
= 0; j
< cpu_stats_list
[i
].vm
.ks_ndata
; j
++)
806 (nkp
++)->value
.ui64
+= (tkp
++)->value
.ui64
;
813 kscmp(kstat_t
*ks1
, kstat_t
*ks2
)
817 cmp
= strcmp(ks1
->ks_module
, ks2
->ks_module
);
820 cmp
= ks1
->ks_instance
- ks2
->ks_instance
;
823 return (strcmp(ks1
->ks_name
, ks2
->ks_name
));
829 struct diskinfo
*disk
, *prevdisk
, *comp
;
836 * Patch the snip in the diskinfo list (see below)
839 lastdisk
->next
= snip
;
841 for (ksp
= kc
->kc_chain
; ksp
; ksp
= ksp
->ks_next
) {
843 if (ksp
->ks_type
!= KSTAT_TYPE_IO
||
844 strcmp(ksp
->ks_class
, "disk") != 0)
850 safe_zalloc((void **)&disk
->next
,
851 sizeof (struct diskinfo
), 0);
853 disk
->next
= NULLDISK
;
856 memset((void *)&disk
->kios
, 0, sizeof (kstat_io_t
));
857 disk
->kios
.wlastupdate
= disk
->ks
->ks_crtime
;
858 disk
->kios
.rlastupdate
= disk
->ks
->ks_crtime
;
861 * Insertion sort on (ks_module, ks_instance, ks_name)
864 while (kscmp(disk
->ks
, comp
->next
->ks
) > 0)
866 if (prevdisk
!= comp
) {
867 prevdisk
->next
= disk
->next
;
868 disk
->next
= comp
->next
;
875 * Put a snip in the linked list of diskinfos. The idea:
876 * If there was a state change such that now there are fewer
877 * disks, we snip the list and retain the tail, rather than
878 * freeing it. At the next state change, we clip the tail back on.
879 * This prevents a lot of malloc/free activity, and it's simpler.
883 disk
->next
= NULLDISK
;
885 firstdisk
= zerodisk
.next
;
887 if (ndisks
> stats_s4
.dk_xfer
.dk_xfer_len
) {
888 stats_s4
.dk_xfer
.dk_xfer_len
= ndisks
;
889 safe_zalloc((void **)&stats_s4
.dk_xfer
.dk_xfer_val
,
890 ndisks
* sizeof (int), 1);
897 struct diskinfo
*disk
;
900 for (disk
= firstdisk
, i
= 0; disk
; disk
= disk
->next
, i
++) {
901 if (kstat_read(kc
, disk
->ks
, (void *)&disk
->kios
) == -1)
903 stats_s4
.dk_xfer
.dk_xfer_val
[i
] = disk
->kios
.reads
+
914 mib2_ipAddrEntry_t
*ap
;
915 char namebuf
[KSTAT_STRLEN
];
916 struct netinfo
*net
, *prevnet
, *comp
;
922 while (netstat_item
) {
924 netstat_item
= netstat_item
->next_item
;
933 fprintf(stderr
, "mibopen() failed\n");
937 if ((netstat_item
= mibget(sd
)) == NULL
) {
939 fprintf(stderr
, "mibget() failed\n");
946 fprintf(stderr
, "mibget returned item: %x\n", netstat_item
);
953 lastnet
->next
= netsnip
;
955 for (item
= netstat_item
; item
; item
= item
->next_item
) {
957 fprintf(stderr
, "\n--- Item %x ---\n", item
);
959 "Group = %d, mib_id = %d, length = %d, valp = 0x%x\n",
960 item
->group
, item
->mib_id
, item
->length
,
963 if (item
->group
!= MIB2_IP
|| item
->mib_id
!= MIB2_IP_20
)
965 ap
= (mib2_ipAddrEntry_t
*)item
->valp
;
966 for (; (char *)ap
< item
->valp
+ item
->length
; ap
++) {
968 octetstr(namebuf
, &ap
->ipAdEntIfIndex
, 'a');
970 fprintf(stderr
, "%s ", namebuf
);
972 if (strlen(namebuf
) == 0)
975 * We found a device of interest.
976 * Now, let's see if there's a kstat for it.
977 * First we try to query the "link" kstats in case
978 * the link is renamed. If that fails, fallback
979 * to legacy ktats for those non-GLDv3 links.
981 if (((ksp
= kstat_lookup(kc
, "link", 0, namebuf
))
982 == NULL
) && ((ksp
= kstat_lookup(kc
, NULL
, -1,
983 namebuf
)) == NULL
)) {
986 if (ksp
->ks_type
!= KSTAT_TYPE_NAMED
)
988 if (kstat_read(kc
, ksp
, NULL
) == -1)
994 safe_zalloc((void **)&net
->next
,
995 sizeof (struct netinfo
), 0);
1000 net
->ipackets
= kstat_data_lookup(net
->ks
,
1002 net
->opackets
= kstat_data_lookup(net
->ks
,
1004 net
->ierrors
= kstat_data_lookup(net
->ks
,
1006 net
->oerrors
= kstat_data_lookup(net
->ks
,
1008 net
->collisions
= kstat_data_lookup(net
->ks
,
1011 * Insertion sort on the name
1014 while (strcmp(net
->ks
->ks_name
,
1015 comp
->next
->ks
->ks_name
) > 0)
1017 if (prevnet
!= comp
) {
1018 prevnet
->next
= net
->next
;
1019 net
->next
= comp
->next
;
1026 fprintf(stderr
, "\n");
1030 * Put a snip in the linked list of netinfos. The idea:
1031 * If there was a state change such that now there are fewer
1032 * nets, we snip the list and retain the tail, rather than
1033 * freeing it. At the next state change, we clip the tail back on.
1034 * This prevents a lot of malloc/free activity, and it's simpler.
1037 netsnip
= net
->next
;
1038 net
->next
= NULLNET
;
1040 firstnet
= zeronet
.next
;
1046 struct netinfo
*net
;
1048 if (netstat_item
== NULL
) {
1050 fprintf(stderr
, "No net stats\n");
1055 stats_s4
.if_ipackets
=
1056 stats_s4
.if_opackets
=
1057 stats_s4
.if_ierrors
=
1058 stats_s4
.if_oerrors
=
1059 stats_s4
.if_collisions
= 0;
1061 for (net
= firstnet
; net
; net
= net
->next
) {
1062 if (kstat_read(kc
, net
->ks
, NULL
) == -1)
1065 stats_s4
.if_ipackets
+= net
->ipackets
->value
.ul
;
1067 stats_s4
.if_opackets
+= net
->opackets
->value
.ul
;
1069 stats_s4
.if_ierrors
+= net
->ierrors
->value
.ul
;
1071 stats_s4
.if_oerrors
+= net
->oerrors
->value
.ul
;
1072 if (net
->collisions
)
1073 stats_s4
.if_collisions
+= net
->collisions
->value
.ul
;
1077 "ipackets: %d opackets: %d ierrors: %d oerrors: %d colls: %d\n",
1078 stats_s4
.if_ipackets
,
1079 stats_s4
.if_opackets
,
1080 stats_s4
.if_ierrors
,
1081 stats_s4
.if_oerrors
,
1082 stats_s4
.if_collisions
);
1088 kstat_copy(kstat_t
*src
, kstat_t
*dst
, int fr
)
1093 if (src
->ks_data
!= NULL
) {
1094 safe_zalloc(&dst
->ks_data
, src
->ks_data_size
, 0);
1095 (void) memcpy(dst
->ks_data
, src
->ks_data
, src
->ks_data_size
);
1097 dst
->ks_data
= NULL
;
1098 dst
->ks_data_size
= 0;