Home | History | Annotate | Line # | Download | only in rpc.rstatd
rstat_proc.c revision 1.17
      1 /*	$NetBSD: rstat_proc.c,v 1.17 1996/10/01 04:01:52 cgd Exp $	*/
      2 
      3 /*
      4  * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
      5  * unrestricted use provided that this legend is included on all tape
      6  * media and as a part of the software program in whole or part.  Users
      7  * may copy or modify Sun RPC without charge, but are not authorized
      8  * to license or distribute it to anyone else except as part of a product or
      9  * program developed by the user.
     10  *
     11  * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
     12  * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
     13  * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
     14  *
     15  * Sun RPC is provided with no support and without any obligation on the
     16  * part of Sun Microsystems, Inc. to assist in its use, correction,
     17  * modification or enhancement.
     18  *
     19  * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
     20  * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
     21  * OR ANY PART THEREOF.
     22  *
     23  * In no event will Sun Microsystems, Inc. be liable for any lost revenue
     24  * or profits or other special, indirect and consequential damages, even if
     25  * Sun has been advised of the possibility of such damages.
     26  *
     27  * Sun Microsystems, Inc.
     28  * 2550 Garcia Avenue
     29  * Mountain View, California  94043
     30  */
     31 #ifndef lint
     32 /*static char sccsid[] = "from: @(#)rpc.rstatd.c 1.1 86/09/25 Copyr 1984 Sun Micro";*/
     33 /*static char sccsid[] = "from: @(#)rstat_proc.c	2.2 88/08/01 4.0 RPCSRC";*/
     34 static char rcsid[] = "$NetBSD: rstat_proc.c,v 1.17 1996/10/01 04:01:52 cgd Exp $";
     35 #endif
     36 
     37 /*
     38  * rstat service:  built with rstat.x and derived from rpc.rstatd.c
     39  *
     40  * Copyright (c) 1984 by Sun Microsystems, Inc.
     41  */
     42 
     43 #include <stdio.h>
     44 #include <stdlib.h>
     45 #include <string.h>
     46 #include <signal.h>
     47 #include <fcntl.h>
     48 #include <kvm.h>
     49 #include <limits.h>
     50 #include <rpc/rpc.h>
     51 #include <sys/socket.h>
     52 #include <nlist.h>
     53 #include <syslog.h>
     54 #include <sys/errno.h>
     55 #include <sys/param.h>
     56 #ifdef BSD
     57 #include <sys/vmmeter.h>
     58 #include <sys/dkstat.h>
     59 #else
     60 #include <sys/dk.h>
     61 #endif
     62 #include <net/if.h>
     63 
     64 #undef FSHIFT			 /* Use protocol's shift and scale values */
     65 #undef FSCALE
     66 #undef DK_NDRIVE
     67 #undef CPUSTATES
     68 #undef if_ipackets
     69 #undef if_ierrors
     70 #undef if_opackets
     71 #undef if_oerrors
     72 #undef if_collisions
     73 #include <rpcsvc/rstat.h>
     74 
     75 #ifdef BSD
     76 #define BSD_CPUSTATES	5	/* Use protocol's idea of CPU states */
     77 int	cp_xlat[CPUSTATES] = { CP_USER, CP_NICE, CP_SYS, CP_IDLE };
     78 #endif
     79 
     80 #ifdef __NetBSD__
     81 /*
     82  * NetBSD does not (currently) support the rpc.rstatd functionality
     83  * formerly provided by grabbing dk_xfer from kmem, since NetBSD's
     84  * new disk attachment code makes the data harder to look up and the
     85  * data is not usually used.  If this becomes a problem, lookup via
     86  * the new disk structures should be implemented.
     87  */
     88 #define	NO_DK_XFER
     89 #endif
     90 
     91 struct nlist nl[] = {
     92 #define	X_CPTIME	0
     93 	{ "_cp_time" },
     94 #define	X_CNT		1
     95 	{ "_cnt" },
     96 #define	X_IFNET		2
     97 	{ "_ifnet" },
     98 #define	X_BOOTTIME	3
     99 	{ "_boottime" },
    100 #define X_HZ		4
    101 	{ "_hz" },
    102 #ifndef NO_DK_XFER
    103 #define	X_DKXFER	5
    104 	{ "_dk_xfer" },
    105 #endif
    106 	{ NULL },
    107 };
    108 struct ifnet_head ifnetq;	/* chain of ethernet interfaces */
    109 int numintfs;
    110 int stats_service();
    111 
    112 extern int from_inetd;
    113 int sincelastreq = 0;		/* number of alarms since last request */
    114 extern int closedown;
    115 kvm_t *kfd;
    116 
    117 union {
    118 	struct stats s1;
    119 	struct statsswtch s2;
    120 	struct statstime s3;
    121 } stats_all;
    122 
    123 void updatestat();
    124 static stat_is_init = 0;
    125 extern int errno;
    126 
    127 #ifndef FSCALE
    128 #define FSCALE (1 << 8)
    129 #endif
    130 
    131 stat_init()
    132 {
    133 	stat_is_init = 1;
    134 	setup();
    135 	updatestat();
    136 	(void) signal(SIGALRM, updatestat);
    137 	alarm(1);
    138 }
    139 
    140 statstime *
    141 rstatproc_stats_3_svc(arg, rqstp)
    142 	void *arg;
    143 	struct svc_req *rqstp;
    144 {
    145 	if (!stat_is_init)
    146 	        stat_init();
    147 	sincelastreq = 0;
    148 	return (&stats_all.s3);
    149 }
    150 
    151 statsswtch *
    152 rstatproc_stats_2_svc(arg, rqstp)
    153 	void *arg;
    154 	struct svc_req *rqstp;
    155 {
    156 	if (!stat_is_init)
    157 	        stat_init();
    158 	sincelastreq = 0;
    159 	return (&stats_all.s2);
    160 }
    161 
    162 stats *
    163 rstatproc_stats_1_svc(arg, rqstp)
    164 	void *arg;
    165 	struct svc_req *rqstp;
    166 {
    167 	if (!stat_is_init)
    168 	        stat_init();
    169 	sincelastreq = 0;
    170 	return (&stats_all.s1);
    171 }
    172 
    173 u_int *
    174 rstatproc_havedisk_3_svc(arg, rqstp)
    175 	void *arg;
    176 	struct svc_req *rqstp;
    177 {
    178 	static u_int have;
    179 
    180 	if (!stat_is_init)
    181 	        stat_init();
    182 	sincelastreq = 0;
    183 	have = havedisk();
    184 	return (&have);
    185 }
    186 
    187 u_int *
    188 rstatproc_havedisk_2_svc(arg, rqstp)
    189 	void *arg;
    190 	struct svc_req *rqstp;
    191 {
    192 	return (rstatproc_havedisk_3_svc(arg, rqstp));
    193 }
    194 
    195 u_int *
    196 rstatproc_havedisk_1_svc(arg, rqstp)
    197 	void *arg;
    198 	struct svc_req *rqstp;
    199 {
    200 	return (rstatproc_havedisk_3_svc(arg, rqstp));
    201 }
    202 
    203 void
    204 updatestat()
    205 {
    206 	long off;
    207 	int i, hz;
    208 	struct vmmeter cnt;
    209 	struct ifnet ifnet;
    210 	double avrun[3];
    211 	struct timeval tm, btm;
    212 #ifdef BSD
    213 	int cp_time[BSD_CPUSTATES];
    214 #endif
    215 
    216 #ifdef DEBUG
    217 	syslog(LOG_DEBUG, "entering updatestat");
    218 #endif
    219 	if (sincelastreq >= closedown) {
    220 #ifdef DEBUG
    221                 syslog(LOG_DEBUG, "about to closedown");
    222 #endif
    223                 if (from_inetd)
    224                         exit(0);
    225                 else {
    226                         stat_is_init = 0;
    227                         return;
    228                 }
    229 	}
    230 	sincelastreq++;
    231 
    232 	if (kvm_read(kfd, (long)nl[X_HZ].n_value, (char *)&hz, sizeof hz) !=
    233 	    sizeof hz) {
    234 		syslog(LOG_ERR, "can't read hz from kmem");
    235 		exit(1);
    236 	}
    237 #ifdef BSD
    238  	if (kvm_read(kfd, (long)nl[X_CPTIME].n_value, (char *)cp_time,
    239 		     sizeof (cp_time))
    240 	    != sizeof (cp_time)) {
    241 		syslog(LOG_ERR, "can't read cp_time from kmem");
    242 		exit(1);
    243 	}
    244 	for (i = 0; i < CPUSTATES; i++)
    245 		stats_all.s1.cp_time[i] = cp_time[cp_xlat[i]];
    246 #else
    247  	if (kvm_read(kfd, (long)nl[X_CPTIME].n_value,
    248 		     (char *)stats_all.s1.cp_time,
    249 		     sizeof (stats_all.s1.cp_time))
    250 	    != sizeof (stats_all.s1.cp_time)) {
    251 		syslog(LOG_ERR, "can't read cp_time from kmem");
    252 		exit(1);
    253 	}
    254 #endif
    255 #ifdef BSD
    256         (void)getloadavg(avrun, sizeof(avrun) / sizeof(avrun[0]));
    257 #endif
    258 	stats_all.s2.avenrun[0] = avrun[0] * FSCALE;
    259 	stats_all.s2.avenrun[1] = avrun[1] * FSCALE;
    260 	stats_all.s2.avenrun[2] = avrun[2] * FSCALE;
    261  	if (kvm_read(kfd, (long)nl[X_BOOTTIME].n_value,
    262 		     (char *)&btm, sizeof (stats_all.s2.boottime))
    263 	    != sizeof (stats_all.s2.boottime)) {
    264 		syslog(LOG_ERR, "can't read boottime from kmem");
    265 		exit(1);
    266 	}
    267 	stats_all.s2.boottime.tv_sec = btm.tv_sec;
    268 	stats_all.s2.boottime.tv_usec = btm.tv_usec;
    269 
    270 
    271 #ifdef DEBUG
    272 	syslog(LOG_DEBUG, "%d %d %d %d\n", stats_all.s1.cp_time[0],
    273 	    stats_all.s1.cp_time[1], stats_all.s1.cp_time[2], stats_all.s1.cp_time[3]);
    274 #endif
    275 
    276  	if (kvm_read(kfd, (long)nl[X_CNT].n_value, (char *)&cnt, sizeof cnt) !=
    277 	    sizeof cnt) {
    278 		syslog(LOG_ERR, "can't read cnt from kmem");
    279 		exit(1);
    280 	}
    281 	stats_all.s1.v_pgpgin = cnt.v_pgpgin;
    282 	stats_all.s1.v_pgpgout = cnt.v_pgpgout;
    283 	stats_all.s1.v_pswpin = cnt.v_pswpin;
    284 	stats_all.s1.v_pswpout = cnt.v_pswpout;
    285 	stats_all.s1.v_intr = cnt.v_intr;
    286 	gettimeofday(&tm, (struct timezone *) 0);
    287 	stats_all.s1.v_intr -= hz*(tm.tv_sec - btm.tv_sec) +
    288 	    hz*(tm.tv_usec - btm.tv_usec)/1000000;
    289 	stats_all.s2.v_swtch = cnt.v_swtch;
    290 
    291 #ifdef NO_DK_XFER
    292 	memset(stats_all.s1.dk_xfer, 0, sizeof (stats_all.s1.dk_xfer));
    293 #else
    294  	if (kvm_read(kfd, (long)nl[X_DKXFER].n_value,
    295 		     (char *)stats_all.s1.dk_xfer,
    296 		     sizeof (stats_all.s1.dk_xfer))
    297 	    != sizeof (stats_all.s1.dk_xfer)) {
    298 		syslog(LOG_ERR, "can't read dk_xfer from kmem");
    299 		exit(1);
    300 	}
    301 #endif
    302 
    303 	stats_all.s1.if_ipackets = 0;
    304 	stats_all.s1.if_opackets = 0;
    305 	stats_all.s1.if_ierrors = 0;
    306 	stats_all.s1.if_oerrors = 0;
    307 	stats_all.s1.if_collisions = 0;
    308 	for (off = (long)ifnetq.tqh_first, i = 0; off && i < numintfs; i++) {
    309 		if (kvm_read(kfd, off, (char *)&ifnet, sizeof ifnet) !=
    310 		    sizeof ifnet) {
    311 			syslog(LOG_ERR, "can't read ifnet from kmem");
    312 			exit(1);
    313 		}
    314 		stats_all.s1.if_ipackets += ifnet.if_data.ifi_ipackets;
    315 		stats_all.s1.if_opackets += ifnet.if_data.ifi_opackets;
    316 		stats_all.s1.if_ierrors += ifnet.if_data.ifi_ierrors;
    317 		stats_all.s1.if_oerrors += ifnet.if_data.ifi_oerrors;
    318 		stats_all.s1.if_collisions += ifnet.if_data.ifi_collisions;
    319 		off = (long)ifnet.if_list.tqe_next;
    320 	}
    321 	gettimeofday((struct timeval *)&stats_all.s3.curtime,
    322 		(struct timezone *) 0);
    323 	alarm(1);
    324 }
    325 
    326 setup()
    327 {
    328 	struct ifnet ifnet;
    329 	long off;
    330 	char errbuf[_POSIX2_LINE_MAX];
    331 
    332 	kfd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf);
    333 	if (kfd == NULL) {
    334 		syslog(LOG_ERR, "%s", errbuf);
    335 		exit (1);
    336 	}
    337 
    338 	if (kvm_nlist(kfd, nl) != 0) {
    339 		syslog(LOG_ERR, "can't get namelist");
    340 		exit (1);
    341         }
    342 
    343 	if (kvm_read(kfd, (long)nl[X_IFNET].n_value, &ifnetq,
    344                      sizeof ifnetq) != sizeof ifnetq)  {
    345 		syslog(LOG_ERR, "can't read ifnet queue head from kmem");
    346 		exit(1);
    347         }
    348 
    349 	numintfs = 0;
    350 	for (off = (long)ifnetq.tqh_first; off;) {
    351 		if (kvm_read(kfd, off, (char *)&ifnet, sizeof ifnet) !=
    352 		    sizeof ifnet) {
    353 			syslog(LOG_ERR, "can't read ifnet from kmem");
    354 			exit(1);
    355 		}
    356 		numintfs++;
    357 		off = (long)ifnet.if_list.tqe_next;
    358 	}
    359 }
    360 
    361 /*
    362  * returns true if have a disk
    363  */
    364 int
    365 havedisk()
    366 {
    367 #ifdef NO_DK_XFER
    368 	return (0);
    369 #else
    370 	int i, cnt;
    371 	long  xfer[DK_NDRIVE];
    372 
    373 	if (kvm_nlist(kfd, nl) != 0) {
    374 		syslog(LOG_ERR, "can't get namelist");
    375 		exit (1);
    376         }
    377 
    378 	if (kvm_read(kfd, (long)nl[X_DKXFER].n_value,
    379 		     (char *)xfer, sizeof xfer) != sizeof xfer) {
    380 		syslog(LOG_ERR, "can't read dk_xfer from kmem");
    381 		exit(1);
    382 	}
    383 	cnt = 0;
    384 	for (i=0; i < DK_NDRIVE; i++)
    385 		cnt += xfer[i];
    386 	return (cnt != 0);
    387 #endif
    388 }
    389 
    390 void
    391 rstat_service(rqstp, transp)
    392 	struct svc_req *rqstp;
    393 	SVCXPRT *transp;
    394 {
    395 	union {
    396 		int fill;
    397 	} argument;
    398 	char *result;
    399 	xdrproc_t xdr_argument, xdr_result;
    400 	char *(*local) __P((void *, struct svc_req *));
    401 
    402 	switch (rqstp->rq_proc) {
    403 	case NULLPROC:
    404 		(void)svc_sendreply(transp, xdr_void, (char *)NULL);
    405 		goto leave;
    406 
    407 	case RSTATPROC_STATS:
    408 		xdr_argument = (xdrproc_t)xdr_void;
    409 		xdr_result = (xdrproc_t)xdr_statstime;
    410                 switch (rqstp->rq_vers) {
    411                 case RSTATVERS_ORIG:
    412                         local = (char *(*) __P((void *, struct svc_req *)))
    413 				rstatproc_stats_1_svc;
    414                         break;
    415                 case RSTATVERS_SWTCH:
    416                         local = (char *(*) __P((void *, struct svc_req *)))
    417 				rstatproc_stats_2_svc;
    418                         break;
    419                 case RSTATVERS_TIME:
    420                         local = (char *(*) __P((void *, struct svc_req *)))
    421 				rstatproc_stats_3_svc;
    422                         break;
    423                 default:
    424                         svcerr_progvers(transp, RSTATVERS_ORIG, RSTATVERS_TIME);
    425                         goto leave;
    426                 }
    427 		break;
    428 
    429 	case RSTATPROC_HAVEDISK:
    430 		xdr_argument = (xdrproc_t)xdr_void;
    431 		xdr_result = (xdrproc_t)xdr_u_int;
    432                 switch (rqstp->rq_vers) {
    433                 case RSTATVERS_ORIG:
    434                         local = (char *(*) __P((void *, struct svc_req *)))
    435 				rstatproc_havedisk_1_svc;
    436                         break;
    437                 case RSTATVERS_SWTCH:
    438                         local = (char *(*) __P((void *, struct svc_req *)))
    439 				rstatproc_havedisk_2_svc;
    440                         break;
    441                 case RSTATVERS_TIME:
    442                         local = (char *(*) __P((void *, struct svc_req *)))
    443 				rstatproc_havedisk_3_svc;
    444                         break;
    445                 default:
    446                         svcerr_progvers(transp, RSTATVERS_ORIG, RSTATVERS_TIME);
    447                         goto leave;
    448                 }
    449 		break;
    450 
    451 	default:
    452 		svcerr_noproc(transp);
    453 		goto leave;
    454 	}
    455 	bzero((char *)&argument, sizeof(argument));
    456 	if (!svc_getargs(transp, xdr_argument, (caddr_t)&argument)) {
    457 		svcerr_decode(transp);
    458 		goto leave;
    459 	}
    460 	result = (*local)(&argument, rqstp);
    461 	if (result != NULL && !svc_sendreply(transp, xdr_result, result)) {
    462 		svcerr_systemerr(transp);
    463 	}
    464 	if (!svc_freeargs(transp, xdr_argument, (caddr_t)&argument)) {
    465 		(void)fprintf(stderr, "unable to free arguments\n");
    466 		exit(1);
    467 	}
    468 leave:
    469         if (from_inetd)
    470                 exit(0);
    471 }
    472