NetBSD/libexec/rpc.rstatd/rstat_proc.c
cgd d09d0bdcc7 disable use of dk_xfer since it's no longer in the kernel. eventually,
this should be updated to use the new disk statistics structures, but it
would be good if there were an efficient way to get them from the kernel
before that's done.  Also, while here, terminate nlist struct array with
an entry with a NULL name, not the name "".
1996-10-01 04:01:52 +00:00

472 lines
12 KiB
C

/* $NetBSD: rstat_proc.c,v 1.17 1996/10/01 04:01:52 cgd Exp $ */
/*
* Sun RPC is a product of Sun Microsystems, Inc. and is provided for
* unrestricted use provided that this legend is included on all tape
* media and as a part of the software program in whole or part. Users
* may copy or modify Sun RPC without charge, but are not authorized
* to license or distribute it to anyone else except as part of a product or
* program developed by the user.
*
* SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
* WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
* PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
*
* Sun RPC is provided with no support and without any obligation on the
* part of Sun Microsystems, Inc. to assist in its use, correction,
* modification or enhancement.
*
* SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
* INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
* OR ANY PART THEREOF.
*
* In no event will Sun Microsystems, Inc. be liable for any lost revenue
* or profits or other special, indirect and consequential damages, even if
* Sun has been advised of the possibility of such damages.
*
* Sun Microsystems, Inc.
* 2550 Garcia Avenue
* Mountain View, California 94043
*/
#ifndef lint
/*static char sccsid[] = "from: @(#)rpc.rstatd.c 1.1 86/09/25 Copyr 1984 Sun Micro";*/
/*static char sccsid[] = "from: @(#)rstat_proc.c 2.2 88/08/01 4.0 RPCSRC";*/
static char rcsid[] = "$NetBSD: rstat_proc.c,v 1.17 1996/10/01 04:01:52 cgd Exp $";
#endif
/*
* rstat service: built with rstat.x and derived from rpc.rstatd.c
*
* Copyright (c) 1984 by Sun Microsystems, Inc.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <fcntl.h>
#include <kvm.h>
#include <limits.h>
#include <rpc/rpc.h>
#include <sys/socket.h>
#include <nlist.h>
#include <syslog.h>
#include <sys/errno.h>
#include <sys/param.h>
#ifdef BSD
#include <sys/vmmeter.h>
#include <sys/dkstat.h>
#else
#include <sys/dk.h>
#endif
#include <net/if.h>
#undef FSHIFT /* Use protocol's shift and scale values */
#undef FSCALE
#undef DK_NDRIVE
#undef CPUSTATES
#undef if_ipackets
#undef if_ierrors
#undef if_opackets
#undef if_oerrors
#undef if_collisions
#include <rpcsvc/rstat.h>
#ifdef BSD
#define BSD_CPUSTATES 5 /* Use protocol's idea of CPU states */
int cp_xlat[CPUSTATES] = { CP_USER, CP_NICE, CP_SYS, CP_IDLE };
#endif
#ifdef __NetBSD__
/*
* NetBSD does not (currently) support the rpc.rstatd functionality
* formerly provided by grabbing dk_xfer from kmem, since NetBSD's
* new disk attachment code makes the data harder to look up and the
* data is not usually used. If this becomes a problem, lookup via
* the new disk structures should be implemented.
*/
#define NO_DK_XFER
#endif
struct nlist nl[] = {
#define X_CPTIME 0
{ "_cp_time" },
#define X_CNT 1
{ "_cnt" },
#define X_IFNET 2
{ "_ifnet" },
#define X_BOOTTIME 3
{ "_boottime" },
#define X_HZ 4
{ "_hz" },
#ifndef NO_DK_XFER
#define X_DKXFER 5
{ "_dk_xfer" },
#endif
{ NULL },
};
struct ifnet_head ifnetq; /* chain of ethernet interfaces */
int numintfs;
int stats_service();
extern int from_inetd;
int sincelastreq = 0; /* number of alarms since last request */
extern int closedown;
kvm_t *kfd;
union {
struct stats s1;
struct statsswtch s2;
struct statstime s3;
} stats_all;
void updatestat();
static stat_is_init = 0;
extern int errno;
#ifndef FSCALE
#define FSCALE (1 << 8)
#endif
stat_init()
{
stat_is_init = 1;
setup();
updatestat();
(void) signal(SIGALRM, updatestat);
alarm(1);
}
statstime *
rstatproc_stats_3_svc(arg, rqstp)
void *arg;
struct svc_req *rqstp;
{
if (!stat_is_init)
stat_init();
sincelastreq = 0;
return (&stats_all.s3);
}
statsswtch *
rstatproc_stats_2_svc(arg, rqstp)
void *arg;
struct svc_req *rqstp;
{
if (!stat_is_init)
stat_init();
sincelastreq = 0;
return (&stats_all.s2);
}
stats *
rstatproc_stats_1_svc(arg, rqstp)
void *arg;
struct svc_req *rqstp;
{
if (!stat_is_init)
stat_init();
sincelastreq = 0;
return (&stats_all.s1);
}
u_int *
rstatproc_havedisk_3_svc(arg, rqstp)
void *arg;
struct svc_req *rqstp;
{
static u_int have;
if (!stat_is_init)
stat_init();
sincelastreq = 0;
have = havedisk();
return (&have);
}
u_int *
rstatproc_havedisk_2_svc(arg, rqstp)
void *arg;
struct svc_req *rqstp;
{
return (rstatproc_havedisk_3_svc(arg, rqstp));
}
u_int *
rstatproc_havedisk_1_svc(arg, rqstp)
void *arg;
struct svc_req *rqstp;
{
return (rstatproc_havedisk_3_svc(arg, rqstp));
}
void
updatestat()
{
long off;
int i, hz;
struct vmmeter cnt;
struct ifnet ifnet;
double avrun[3];
struct timeval tm, btm;
#ifdef BSD
int cp_time[BSD_CPUSTATES];
#endif
#ifdef DEBUG
syslog(LOG_DEBUG, "entering updatestat");
#endif
if (sincelastreq >= closedown) {
#ifdef DEBUG
syslog(LOG_DEBUG, "about to closedown");
#endif
if (from_inetd)
exit(0);
else {
stat_is_init = 0;
return;
}
}
sincelastreq++;
if (kvm_read(kfd, (long)nl[X_HZ].n_value, (char *)&hz, sizeof hz) !=
sizeof hz) {
syslog(LOG_ERR, "can't read hz from kmem");
exit(1);
}
#ifdef BSD
if (kvm_read(kfd, (long)nl[X_CPTIME].n_value, (char *)cp_time,
sizeof (cp_time))
!= sizeof (cp_time)) {
syslog(LOG_ERR, "can't read cp_time from kmem");
exit(1);
}
for (i = 0; i < CPUSTATES; i++)
stats_all.s1.cp_time[i] = cp_time[cp_xlat[i]];
#else
if (kvm_read(kfd, (long)nl[X_CPTIME].n_value,
(char *)stats_all.s1.cp_time,
sizeof (stats_all.s1.cp_time))
!= sizeof (stats_all.s1.cp_time)) {
syslog(LOG_ERR, "can't read cp_time from kmem");
exit(1);
}
#endif
#ifdef BSD
(void)getloadavg(avrun, sizeof(avrun) / sizeof(avrun[0]));
#endif
stats_all.s2.avenrun[0] = avrun[0] * FSCALE;
stats_all.s2.avenrun[1] = avrun[1] * FSCALE;
stats_all.s2.avenrun[2] = avrun[2] * FSCALE;
if (kvm_read(kfd, (long)nl[X_BOOTTIME].n_value,
(char *)&btm, sizeof (stats_all.s2.boottime))
!= sizeof (stats_all.s2.boottime)) {
syslog(LOG_ERR, "can't read boottime from kmem");
exit(1);
}
stats_all.s2.boottime.tv_sec = btm.tv_sec;
stats_all.s2.boottime.tv_usec = btm.tv_usec;
#ifdef DEBUG
syslog(LOG_DEBUG, "%d %d %d %d\n", stats_all.s1.cp_time[0],
stats_all.s1.cp_time[1], stats_all.s1.cp_time[2], stats_all.s1.cp_time[3]);
#endif
if (kvm_read(kfd, (long)nl[X_CNT].n_value, (char *)&cnt, sizeof cnt) !=
sizeof cnt) {
syslog(LOG_ERR, "can't read cnt from kmem");
exit(1);
}
stats_all.s1.v_pgpgin = cnt.v_pgpgin;
stats_all.s1.v_pgpgout = cnt.v_pgpgout;
stats_all.s1.v_pswpin = cnt.v_pswpin;
stats_all.s1.v_pswpout = cnt.v_pswpout;
stats_all.s1.v_intr = cnt.v_intr;
gettimeofday(&tm, (struct timezone *) 0);
stats_all.s1.v_intr -= hz*(tm.tv_sec - btm.tv_sec) +
hz*(tm.tv_usec - btm.tv_usec)/1000000;
stats_all.s2.v_swtch = cnt.v_swtch;
#ifdef NO_DK_XFER
memset(stats_all.s1.dk_xfer, 0, sizeof (stats_all.s1.dk_xfer));
#else
if (kvm_read(kfd, (long)nl[X_DKXFER].n_value,
(char *)stats_all.s1.dk_xfer,
sizeof (stats_all.s1.dk_xfer))
!= sizeof (stats_all.s1.dk_xfer)) {
syslog(LOG_ERR, "can't read dk_xfer from kmem");
exit(1);
}
#endif
stats_all.s1.if_ipackets = 0;
stats_all.s1.if_opackets = 0;
stats_all.s1.if_ierrors = 0;
stats_all.s1.if_oerrors = 0;
stats_all.s1.if_collisions = 0;
for (off = (long)ifnetq.tqh_first, i = 0; off && i < numintfs; i++) {
if (kvm_read(kfd, off, (char *)&ifnet, sizeof ifnet) !=
sizeof ifnet) {
syslog(LOG_ERR, "can't read ifnet from kmem");
exit(1);
}
stats_all.s1.if_ipackets += ifnet.if_data.ifi_ipackets;
stats_all.s1.if_opackets += ifnet.if_data.ifi_opackets;
stats_all.s1.if_ierrors += ifnet.if_data.ifi_ierrors;
stats_all.s1.if_oerrors += ifnet.if_data.ifi_oerrors;
stats_all.s1.if_collisions += ifnet.if_data.ifi_collisions;
off = (long)ifnet.if_list.tqe_next;
}
gettimeofday((struct timeval *)&stats_all.s3.curtime,
(struct timezone *) 0);
alarm(1);
}
setup()
{
struct ifnet ifnet;
long off;
char errbuf[_POSIX2_LINE_MAX];
kfd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf);
if (kfd == NULL) {
syslog(LOG_ERR, "%s", errbuf);
exit (1);
}
if (kvm_nlist(kfd, nl) != 0) {
syslog(LOG_ERR, "can't get namelist");
exit (1);
}
if (kvm_read(kfd, (long)nl[X_IFNET].n_value, &ifnetq,
sizeof ifnetq) != sizeof ifnetq) {
syslog(LOG_ERR, "can't read ifnet queue head from kmem");
exit(1);
}
numintfs = 0;
for (off = (long)ifnetq.tqh_first; off;) {
if (kvm_read(kfd, off, (char *)&ifnet, sizeof ifnet) !=
sizeof ifnet) {
syslog(LOG_ERR, "can't read ifnet from kmem");
exit(1);
}
numintfs++;
off = (long)ifnet.if_list.tqe_next;
}
}
/*
* returns true if have a disk
*/
int
havedisk()
{
#ifdef NO_DK_XFER
return (0);
#else
int i, cnt;
long xfer[DK_NDRIVE];
if (kvm_nlist(kfd, nl) != 0) {
syslog(LOG_ERR, "can't get namelist");
exit (1);
}
if (kvm_read(kfd, (long)nl[X_DKXFER].n_value,
(char *)xfer, sizeof xfer) != sizeof xfer) {
syslog(LOG_ERR, "can't read dk_xfer from kmem");
exit(1);
}
cnt = 0;
for (i=0; i < DK_NDRIVE; i++)
cnt += xfer[i];
return (cnt != 0);
#endif
}
void
rstat_service(rqstp, transp)
struct svc_req *rqstp;
SVCXPRT *transp;
{
union {
int fill;
} argument;
char *result;
xdrproc_t xdr_argument, xdr_result;
char *(*local) __P((void *, struct svc_req *));
switch (rqstp->rq_proc) {
case NULLPROC:
(void)svc_sendreply(transp, xdr_void, (char *)NULL);
goto leave;
case RSTATPROC_STATS:
xdr_argument = (xdrproc_t)xdr_void;
xdr_result = (xdrproc_t)xdr_statstime;
switch (rqstp->rq_vers) {
case RSTATVERS_ORIG:
local = (char *(*) __P((void *, struct svc_req *)))
rstatproc_stats_1_svc;
break;
case RSTATVERS_SWTCH:
local = (char *(*) __P((void *, struct svc_req *)))
rstatproc_stats_2_svc;
break;
case RSTATVERS_TIME:
local = (char *(*) __P((void *, struct svc_req *)))
rstatproc_stats_3_svc;
break;
default:
svcerr_progvers(transp, RSTATVERS_ORIG, RSTATVERS_TIME);
goto leave;
}
break;
case RSTATPROC_HAVEDISK:
xdr_argument = (xdrproc_t)xdr_void;
xdr_result = (xdrproc_t)xdr_u_int;
switch (rqstp->rq_vers) {
case RSTATVERS_ORIG:
local = (char *(*) __P((void *, struct svc_req *)))
rstatproc_havedisk_1_svc;
break;
case RSTATVERS_SWTCH:
local = (char *(*) __P((void *, struct svc_req *)))
rstatproc_havedisk_2_svc;
break;
case RSTATVERS_TIME:
local = (char *(*) __P((void *, struct svc_req *)))
rstatproc_havedisk_3_svc;
break;
default:
svcerr_progvers(transp, RSTATVERS_ORIG, RSTATVERS_TIME);
goto leave;
}
break;
default:
svcerr_noproc(transp);
goto leave;
}
bzero((char *)&argument, sizeof(argument));
if (!svc_getargs(transp, xdr_argument, (caddr_t)&argument)) {
svcerr_decode(transp);
goto leave;
}
result = (*local)(&argument, rqstp);
if (result != NULL && !svc_sendreply(transp, xdr_result, result)) {
svcerr_systemerr(transp);
}
if (!svc_freeargs(transp, xdr_argument, (caddr_t)&argument)) {
(void)fprintf(stderr, "unable to free arguments\n");
exit(1);
}
leave:
if (from_inetd)
exit(0);
}