#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 #include #include #include #include #include #include #include #include #include #include #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 }