654 lines
14 KiB
C
654 lines
14 KiB
C
#ifndef lint
|
|
static char sccsid[] = "@(#)rpc.rstatd.c 1.1 94/10/31 Copyr 1984 Sun Micro";
|
|
#endif
|
|
|
|
/*
|
|
* Copyright (c) 1984 by Sun Microsystems, Inc.
|
|
*/
|
|
|
|
/*
|
|
* rstat demon: called from inetd, or self-started
|
|
*/
|
|
|
|
#include <signal.h>
|
|
#include <stdio.h>
|
|
#include <rpc/rpc.h>
|
|
#include <sys/socket.h>
|
|
#include <nlist.h>
|
|
#include <sys/errno.h>
|
|
#include <sys/vmmeter.h>
|
|
#include <net/if.h>
|
|
#include <sys/time.h>
|
|
#include <rpcsvc/rstat.h>
|
|
#include <syslog.h>
|
|
|
|
#define CLOSEDOWN 20 /* how long to wait before do_exiting */
|
|
#ifndef FSCALE
|
|
#define FSCALE (1 << 8)
|
|
#endif
|
|
|
|
struct nlist nl[] = {
|
|
#define X_CPTIME 0
|
|
{ "_cp_time" },
|
|
#define X_SUM 1
|
|
{ "_sum" },
|
|
#define X_IFNET 2
|
|
{ "_ifnet" },
|
|
#define X_DKXFER 3
|
|
{ "_dk_xfer" },
|
|
#define X_BOOTTIME 4
|
|
{ "_boottime" },
|
|
#define X_AVENRUN 5
|
|
{ "_avenrun" },
|
|
#define X_HZ 6
|
|
{ "_hz" },
|
|
"",
|
|
};
|
|
|
|
static void rstatprog_2();
|
|
static void rstatprog_3();
|
|
static void rstatprog_4();
|
|
int updatestat();
|
|
int stats_service();
|
|
void setup();
|
|
|
|
static int _rpcpmstart; /* Started by a port monitor ? */
|
|
static int _rpcfdtype; /* Whether Stream or Datagram ? */
|
|
int kmem;
|
|
int firstifnet, numintfs; /* chain of ethernet interfaces */
|
|
int sincelastreq = 0; /* number of alarms since last request */
|
|
extern int errno;
|
|
|
|
main()
|
|
{
|
|
register SVCXPRT *transp;
|
|
int sock;
|
|
int proto;
|
|
struct sockaddr_in saddr;
|
|
int asize = sizeof(saddr);
|
|
|
|
if (getsockname(0, (struct sockaddr *)&saddr, &asize) == 0) {
|
|
int ssize = sizeof(int);
|
|
|
|
if (saddr.sin_family != AF_INET)
|
|
exit(1);
|
|
if (getsockopt(0, SOL_SOCKET, SO_TYPE,
|
|
(char *)&_rpcfdtype, &ssize) == -1)
|
|
exit(1);
|
|
sock = 0;
|
|
_rpcpmstart = 1;
|
|
proto = 0;
|
|
} else {
|
|
#ifndef RPC_SVC_FG
|
|
int pid;
|
|
|
|
pid = fork();
|
|
if (pid < 0) {
|
|
perror("cannot fork");
|
|
exit(1);
|
|
}
|
|
if (pid)
|
|
exit(0);
|
|
#endif
|
|
sock = RPC_ANYSOCK;
|
|
(void) pmap_unset(RSTATPROG, RSTATVERS_SWTCH);
|
|
(void) pmap_unset(RSTATPROG, RSTATVERS_TIME);
|
|
(void) pmap_unset(RSTATPROG, RSTATVERS_VAR);
|
|
}
|
|
|
|
if ((_rpcfdtype == 0) || (_rpcfdtype == SOCK_DGRAM)) {
|
|
transp = svcudp_create(sock);
|
|
if (transp == NULL) {
|
|
_msgout("cannot create udp service.");
|
|
exit(1);
|
|
}
|
|
if (!_rpcpmstart)
|
|
proto = IPPROTO_UDP;
|
|
if (!svc_register(transp, RSTATPROG, RSTATVERS_SWTCH, rstatprog_2, proto)) {
|
|
_msgout("unable to register (RSTATPROG, RSTATVERS_SWTCH, udp).");
|
|
exit(1);
|
|
}
|
|
if (!svc_register(transp, RSTATPROG, RSTATVERS_TIME, rstatprog_3, proto)) {
|
|
_msgout("unable to register (RSTATPROG, RSTATVERS_TIME, udp).");
|
|
exit(1);
|
|
}
|
|
if (!svc_register(transp, RSTATPROG, RSTATVERS_VAR, rstatprog_4, proto)) {
|
|
_msgout("unable to register (RSTATPROG, RSTATVERS_VAR, udp).");
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
if (transp == (SVCXPRT *)NULL) {
|
|
_msgout("could not create a handle");
|
|
exit(1);
|
|
}
|
|
/*
|
|
* This portion of the code is not generated by rpcgen and is added.
|
|
*/
|
|
setup();
|
|
updatestat();
|
|
alarm(1);
|
|
signal(SIGALRM, updatestat);
|
|
svc_run();
|
|
_msgout("svc_run returned");
|
|
exit(1);
|
|
/* NOTREACHED */
|
|
}
|
|
|
|
static void
|
|
rstatprog_2(rqstp, transp)
|
|
struct svc_req *rqstp;
|
|
register SVCXPRT *transp;
|
|
{
|
|
union {
|
|
int fill;
|
|
} argument;
|
|
char *result;
|
|
bool_t (*xdr_argument)(), (*xdr_result)();
|
|
char *(*local)();
|
|
|
|
switch (rqstp->rq_proc) {
|
|
case NULLPROC:
|
|
(void) svc_sendreply(transp, xdr_void, (char *)NULL);
|
|
return;
|
|
|
|
case RSTATPROC_STATS:
|
|
xdr_argument = xdr_void;
|
|
xdr_result = xdr_statsswtch;
|
|
local = (char *(*)()) rstatproc_stats_2;
|
|
break;
|
|
|
|
case RSTATPROC_HAVEDISK:
|
|
xdr_argument = xdr_void;
|
|
xdr_result = xdr_long;
|
|
local = (char *(*)()) rstatproc_havedisk_2;
|
|
break;
|
|
|
|
default:
|
|
svcerr_noproc(transp);
|
|
return;
|
|
}
|
|
bzero((char *)&argument, sizeof(argument));
|
|
if (!svc_getargs(transp, xdr_argument, &argument)) {
|
|
svcerr_decode(transp);
|
|
return;
|
|
}
|
|
result = (*local)(&argument, rqstp);
|
|
if (result != NULL && !svc_sendreply(transp, xdr_result, result)) {
|
|
svcerr_systemerr(transp);
|
|
}
|
|
if (!svc_freeargs(transp, xdr_argument, &argument)) {
|
|
_msgout("unable to free arguments");
|
|
exit(1);
|
|
}
|
|
return;
|
|
}
|
|
|
|
static void
|
|
rstatprog_3(rqstp, transp)
|
|
struct svc_req *rqstp;
|
|
register SVCXPRT *transp;
|
|
{
|
|
union {
|
|
int fill;
|
|
} argument;
|
|
char *result;
|
|
bool_t (*xdr_argument)(), (*xdr_result)();
|
|
char *(*local)();
|
|
|
|
switch (rqstp->rq_proc) {
|
|
case NULLPROC:
|
|
(void) svc_sendreply(transp, xdr_void, (char *)NULL);
|
|
return;
|
|
|
|
case RSTATPROC_STATS:
|
|
xdr_argument = xdr_void;
|
|
xdr_result = xdr_statstime;
|
|
local = (char *(*)()) rstatproc_stats_3;
|
|
break;
|
|
|
|
case RSTATPROC_HAVEDISK:
|
|
xdr_argument = xdr_void;
|
|
xdr_result = xdr_long;
|
|
local = (char *(*)()) rstatproc_havedisk_3;
|
|
break;
|
|
|
|
default:
|
|
svcerr_noproc(transp);
|
|
return;
|
|
}
|
|
bzero((char *)&argument, sizeof(argument));
|
|
if (!svc_getargs(transp, xdr_argument, &argument)) {
|
|
svcerr_decode(transp);
|
|
return;
|
|
}
|
|
result = (*local)(&argument, rqstp);
|
|
if (result != NULL && !svc_sendreply(transp, xdr_result, result)) {
|
|
svcerr_systemerr(transp);
|
|
}
|
|
if (!svc_freeargs(transp, xdr_argument, &argument)) {
|
|
_msgout("unable to free arguments");
|
|
exit(1);
|
|
}
|
|
return;
|
|
}
|
|
|
|
static void
|
|
rstatprog_4(rqstp, transp)
|
|
struct svc_req *rqstp;
|
|
register SVCXPRT *transp;
|
|
{
|
|
union {
|
|
int fill;
|
|
} argument;
|
|
char *result;
|
|
bool_t (*xdr_argument)(), (*xdr_result)();
|
|
char *(*local)();
|
|
|
|
switch (rqstp->rq_proc) {
|
|
case NULLPROC:
|
|
(void) svc_sendreply(transp, xdr_void, (char *)NULL);
|
|
return;
|
|
|
|
case RSTATPROC_STATS:
|
|
xdr_argument = xdr_void;
|
|
xdr_result = xdr_statsvar;
|
|
local = (char *(*)()) rstatproc_stats_4;
|
|
break;
|
|
|
|
case RSTATPROC_HAVEDISK:
|
|
xdr_argument = xdr_void;
|
|
xdr_result = xdr_long;
|
|
local = (char *(*)()) rstatproc_havedisk_4;
|
|
break;
|
|
|
|
default:
|
|
svcerr_noproc(transp);
|
|
return;
|
|
}
|
|
bzero((char *)&argument, sizeof(argument));
|
|
if (!svc_getargs(transp, xdr_argument, &argument)) {
|
|
svcerr_decode(transp);
|
|
return;
|
|
}
|
|
result = (*local)(&argument, rqstp);
|
|
if (result != NULL && !svc_sendreply(transp, xdr_result, result)) {
|
|
svcerr_systemerr(transp);
|
|
}
|
|
if (!svc_freeargs(transp, xdr_argument, &argument)) {
|
|
_msgout("unable to free arguments");
|
|
exit(1);
|
|
}
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* This is the data structure for storing all the local status.
|
|
*/
|
|
struct local_stats {
|
|
int cp_time[CPUSTATES];
|
|
int dk_xfer[DK_NDRIVE];
|
|
u_int v_pgpgin;
|
|
u_int v_pgpgout;
|
|
u_int v_pswpin;
|
|
u_int v_pswpout;
|
|
u_int v_intr;
|
|
int if_ipackets;
|
|
int if_ierrors;
|
|
int if_opackets;
|
|
int if_oerrors;
|
|
int if_collisions;
|
|
u_int v_swtch;
|
|
long avenrun[3];
|
|
struct timeval boottime;
|
|
struct timeval curtime;
|
|
};
|
|
static struct local_stats local_store;
|
|
|
|
statsswtch *
|
|
rstatproc_stats_2()
|
|
{
|
|
static statsswtch ret;
|
|
|
|
#ifdef DEBUG
|
|
_msgout("entering stats_service");
|
|
#endif
|
|
sincelastreq = 0;
|
|
|
|
(void) memcpy((char *)&(ret.v_pgpgin), (char *)&(local_store.v_pgpgin),
|
|
sizeof(ret) - (sizeof(ret.cp_time) +
|
|
sizeof(ret.dk_xfer)));
|
|
(void) memcpy((char *)ret.cp_time,
|
|
(char *)local_store.cp_time, sizeof(ret.cp_time));
|
|
(void) memcpy((char *)ret.dk_xfer,
|
|
(char *)local_store.dk_xfer, sizeof(ret.dk_xfer));
|
|
return(&ret);
|
|
}
|
|
|
|
long *
|
|
rstatproc_havedisk_2()
|
|
{
|
|
static long have;
|
|
|
|
have = havedisk();
|
|
return (&have);
|
|
}
|
|
|
|
statstime *
|
|
rstatproc_stats_3()
|
|
{
|
|
static statstime ret;
|
|
|
|
#ifdef DEBUG
|
|
_msgout("entering stats_service");
|
|
#endif
|
|
sincelastreq = 0;
|
|
|
|
(void) memcpy((char *)&(ret.v_pgpgin), (char *)&(local_store.v_pgpgin),
|
|
sizeof(ret) - (sizeof(ret.cp_time) +
|
|
sizeof(ret.dk_xfer)));
|
|
(void) memcpy((char *)ret.cp_time,
|
|
(char *)local_store.cp_time, sizeof(ret.cp_time));
|
|
(void) memcpy((char *)ret.dk_xfer,
|
|
(char *)local_store.dk_xfer, sizeof(ret.dk_xfer));
|
|
return(&ret);
|
|
}
|
|
|
|
long *
|
|
rstatproc_havedisk_3()
|
|
{
|
|
static long have;
|
|
|
|
have = havedisk();
|
|
return (&have);
|
|
}
|
|
|
|
statsvar *
|
|
rstatproc_stats_4()
|
|
{
|
|
static statsvar ret;
|
|
|
|
#ifdef DEBUG
|
|
_msgout("entering stats_service - version 4");
|
|
#endif
|
|
sincelastreq = 0;
|
|
if (ret.cp_time.cp_time_val == (int *) NULL) {
|
|
if ((ret.cp_time.cp_time_val =
|
|
(int *) malloc(sizeof(local_store.cp_time))) == NULL) {
|
|
_msgout("failed in malloc()");
|
|
exit(1);
|
|
}
|
|
ret.cp_time.cp_time_len = sizeof(local_store.cp_time) /
|
|
sizeof(int);
|
|
if( (ret.dk_xfer.dk_xfer_val =
|
|
(int *) malloc(sizeof(local_store.dk_xfer))) == NULL) {
|
|
_msgout("failed in malloc()");
|
|
exit(1);
|
|
}
|
|
}
|
|
(void) memcpy((char *)&(ret.v_pgpgin),
|
|
(char *)&(local_store.v_pgpgin),
|
|
sizeof(ret) - (sizeof(ret.cp_time) + sizeof(ret.dk_xfer)));
|
|
(void) memcpy((char *)ret.cp_time.cp_time_val,
|
|
(char *) local_store.cp_time, sizeof(local_store.cp_time));
|
|
(void) memcpy((char *)ret.dk_xfer.dk_xfer_val,
|
|
(char *) local_store.dk_xfer, sizeof(local_store.dk_xfer));
|
|
ret.dk_xfer.dk_xfer_len = sizeof(local_store.dk_xfer) / sizeof(int);
|
|
return(&ret);
|
|
}
|
|
|
|
long *
|
|
rstatproc_havedisk_4()
|
|
{
|
|
static long have;
|
|
|
|
have = havedisk();
|
|
return (&have);
|
|
}
|
|
|
|
updatestat()
|
|
{
|
|
int off, i, hz;
|
|
struct vmmeter sum;
|
|
struct ifnet ifnet;
|
|
struct timeval tm, btm;
|
|
|
|
#ifdef DEBUG
|
|
_msgout("entering updatestat");
|
|
#endif
|
|
|
|
if ((sincelastreq >= CLOSEDOWN) && _rpcpmstart) {
|
|
do_exit(0);
|
|
}
|
|
sincelastreq++;
|
|
if (lseek(kmem, (long)nl[X_HZ].n_value, 0) == -1) {
|
|
_msgout("can't seek in kmem");
|
|
do_exit(1);
|
|
}
|
|
if (read(kmem, &hz, sizeof hz) != sizeof hz) {
|
|
_msgout("can't read hz from kmem");
|
|
do_exit(1);
|
|
}
|
|
if (lseek(kmem, (long)nl[X_CPTIME].n_value, 0) == -1) {
|
|
_msgout("can't seek in kmem");
|
|
do_exit(1);
|
|
}
|
|
if (read(kmem, local_store.cp_time, sizeof (local_store.cp_time))
|
|
!= sizeof (local_store.cp_time)) {
|
|
_msgout("can't read cp_time from kmem");
|
|
do_exit(1);
|
|
}
|
|
if (lseek(kmem, (long)nl[X_AVENRUN].n_value, 0) ==-1) {
|
|
_msgout("can't seek in kmem");
|
|
do_exit(1);
|
|
}
|
|
#ifdef vax
|
|
if (read(kmem, avrun, sizeof (avrun)) != sizeof (avrun)) {
|
|
_msgout("can't read avenrun from kmem");
|
|
do_exit(1);
|
|
}
|
|
local_store.avenrun[0] = avrun[0] * FSCALE;
|
|
local_store.avenrun[1] = avrun[1] * FSCALE;
|
|
local_store.avenrun[2] = avrun[2] * FSCALE;
|
|
#endif
|
|
#ifdef sun
|
|
if (read(kmem, local_store.avenrun, sizeof (local_store.avenrun))
|
|
!= sizeof (local_store.avenrun)) {
|
|
_msgout("can't read avenrun from kmem");
|
|
do_exit(1);
|
|
}
|
|
#endif
|
|
if (lseek(kmem, (long)nl[X_BOOTTIME].n_value, 0) == -1) {
|
|
_msgout("can't seek in kmem");
|
|
do_exit(1);
|
|
}
|
|
if (read(kmem, &btm, sizeof (local_store.boottime))
|
|
!= sizeof (local_store.boottime)) {
|
|
_msgout("can't read boottime from kmem");
|
|
do_exit(1);
|
|
}
|
|
local_store.boottime = btm;
|
|
|
|
#ifdef DEBUG
|
|
{
|
|
char logline[64];
|
|
|
|
sprintf(logline, "%d %d %d %d", local_store.cp_time[0],
|
|
local_store.cp_time[1], local_store.cp_time[2],
|
|
local_store.cp_time[3]);
|
|
_msgout(logline);
|
|
}
|
|
#endif
|
|
|
|
if (lseek(kmem, (long)nl[X_SUM].n_value, 0) ==-1) {
|
|
_msgout("can't seek in kmem");
|
|
do_exit(1);
|
|
}
|
|
if (read(kmem, &sum, sizeof sum) != sizeof sum) {
|
|
_msgout("can't read sum from kmem");
|
|
do_exit(1);
|
|
}
|
|
local_store.v_pgpgin = sum.v_pgpgin;
|
|
local_store.v_pgpgout = sum.v_pgpgout;
|
|
local_store.v_pswpin = sum.v_pswpin;
|
|
local_store.v_pswpout = sum.v_pswpout;
|
|
local_store.v_intr = sum.v_intr;
|
|
gettimeofday(&tm, NULL);
|
|
local_store.v_intr -= hz*(tm.tv_sec - btm.tv_sec) +
|
|
hz*(tm.tv_usec - btm.tv_usec)/1000000;
|
|
local_store.v_swtch = sum.v_swtch;
|
|
|
|
if (lseek(kmem, (long)nl[X_DKXFER].n_value, 0) == -1) {
|
|
_msgout("can't seek in kmem");
|
|
do_exit(1);
|
|
}
|
|
|
|
if (read(kmem, local_store.dk_xfer, sizeof (local_store.dk_xfer))
|
|
!= sizeof (local_store.dk_xfer)) {
|
|
_msgout("can't read dk_xfer from kmem");
|
|
do_exit(1);
|
|
}
|
|
|
|
local_store.if_ipackets = 0;
|
|
local_store.if_opackets = 0;
|
|
local_store.if_ierrors = 0;
|
|
local_store.if_oerrors = 0;
|
|
local_store.if_collisions = 0;
|
|
for (off = firstifnet, i = 0; off && i < numintfs; i++) {
|
|
if (lseek(kmem, off, 0) == -1) {
|
|
_msgout("can't seek in kmem");
|
|
do_exit(1);
|
|
}
|
|
if (read(kmem, &ifnet, sizeof ifnet) != sizeof ifnet) {
|
|
_msgout("can't read ifnet from kmem");
|
|
do_exit(1);
|
|
}
|
|
local_store.if_ipackets += ifnet.if_ipackets;
|
|
local_store.if_opackets += ifnet.if_opackets;
|
|
local_store.if_ierrors += ifnet.if_ierrors;
|
|
local_store.if_oerrors += ifnet.if_oerrors;
|
|
local_store.if_collisions += ifnet.if_collisions;
|
|
off = (int) ifnet.if_next;
|
|
}
|
|
gettimeofday(&local_store.curtime, NULL);
|
|
alarm(1);
|
|
}
|
|
|
|
void
|
|
setup()
|
|
{
|
|
struct ifnet ifnet;
|
|
int off;
|
|
|
|
nlist("/vmunix", nl);
|
|
if (nl[0].n_value == 0) {
|
|
_msgout("Variables missing from namelist");
|
|
do_exit(1);
|
|
}
|
|
if ((kmem = open("/dev/kmem", 0)) < 0) {
|
|
_msgout("can't open kmem");
|
|
do_exit(1);
|
|
}
|
|
|
|
off = nl[X_IFNET].n_value;
|
|
if (lseek(kmem, off, 0) == -1) {
|
|
_msgout("can't seek in kmem");
|
|
do_exit(1);
|
|
}
|
|
if (read(kmem, &firstifnet, sizeof(int)) != sizeof (int)) {
|
|
_msgout("can't read firstifnet from kmem");
|
|
do_exit(1);
|
|
}
|
|
numintfs = 0;
|
|
for (off = firstifnet; off;) {
|
|
if (lseek(kmem, off, 0) == -1) {
|
|
_msgout("can't seek in kmem");
|
|
do_exit(1);
|
|
}
|
|
if (read(kmem, &ifnet, sizeof ifnet) != sizeof ifnet) {
|
|
_msgout("can't read ifnet from kmem");
|
|
do_exit(1);
|
|
}
|
|
numintfs++;
|
|
off = (int) ifnet.if_next;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* returns true if have a disk
|
|
*/
|
|
static
|
|
havedisk()
|
|
{
|
|
int i, cnt;
|
|
long xfer[DK_NDRIVE];
|
|
|
|
if (nl[X_DKXFER].n_value == 0) {
|
|
_msgout("Variables missing from namelist");
|
|
do_exit(1);
|
|
}
|
|
if (lseek(kmem, (long)nl[X_DKXFER].n_value, 0) == -1) {
|
|
_msgout("can't seek in kmem");
|
|
do_exit(1);
|
|
}
|
|
if (read(kmem, xfer, sizeof xfer) != sizeof xfer) {
|
|
_msgout("can't read kmem");
|
|
do_exit(1);
|
|
}
|
|
cnt = 0;
|
|
for (i = 0; i < DK_NDRIVE; i++)
|
|
cnt += xfer[i];
|
|
return (cnt != 0);
|
|
}
|
|
|
|
static
|
|
do_exit(stat)
|
|
int stat;
|
|
{
|
|
|
|
#ifdef DEBUG
|
|
_msgout("about to closedown");
|
|
#endif
|
|
|
|
#ifndef DEBUG
|
|
if (stat != 0) {
|
|
/*
|
|
* something went wrong. Sleep awhile and drain our queue
|
|
* before exiting. This keeps inetd from immediately retrying.
|
|
*/
|
|
int cc, fromlen;
|
|
char buf[RPCSMALLMSGSIZE];
|
|
struct sockaddr from;
|
|
|
|
sleep(CLOSEDOWN);
|
|
for (;;) {
|
|
fromlen = sizeof (from);
|
|
cc = recvfrom(0, buf, sizeof (buf), 0, &from, &fromlen);
|
|
if (cc <= 0)
|
|
break;
|
|
}
|
|
}
|
|
#endif
|
|
exit(stat);
|
|
}
|
|
|
|
static
|
|
_msgout(msg)
|
|
char *msg;
|
|
{
|
|
#ifdef RPC_SVC_FG
|
|
if (_rpcpmstart)
|
|
syslog(LOG_ERR, msg);
|
|
else
|
|
(void) fprintf(stderr, "%s\n", msg);
|
|
#else
|
|
static int initted;
|
|
|
|
if (!initted) {
|
|
openlog("rstatd", LOG_PID, LOG_DAEMON);
|
|
initted = 1;
|
|
}
|
|
syslog(LOG_ERR, msg);
|
|
#endif
|
|
}
|