1 /* $NetBSD: rstat_proc.c,v 1.16 1996/08/30 20:17:42 thorpej 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.16 1996/08/30 20:17:42 thorpej 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 struct nlist nl[] = { 81 #define X_CPTIME 0 82 { "_cp_time" }, 83 #define X_CNT 1 84 { "_cnt" }, 85 #define X_IFNET 2 86 { "_ifnet" }, 87 #define X_DKXFER 3 88 { "_dk_xfer" }, 89 #define X_BOOTTIME 4 90 { "_boottime" }, 91 #define X_HZ 5 92 { "_hz" }, 93 "", 94 }; 95 struct ifnet_head ifnetq; /* chain of ethernet interfaces */ 96 int numintfs; 97 int stats_service(); 98 99 extern int from_inetd; 100 int sincelastreq = 0; /* number of alarms since last request */ 101 extern int closedown; 102 kvm_t *kfd; 103 104 union { 105 struct stats s1; 106 struct statsswtch s2; 107 struct statstime s3; 108 } stats_all; 109 110 void updatestat(); 111 static stat_is_init = 0; 112 extern int errno; 113 114 #ifndef FSCALE 115 #define FSCALE (1 << 8) 116 #endif 117 118 stat_init() 119 { 120 stat_is_init = 1; 121 setup(); 122 updatestat(); 123 (void) signal(SIGALRM, updatestat); 124 alarm(1); 125 } 126 127 statstime * 128 rstatproc_stats_3_svc(arg, rqstp) 129 void *arg; 130 struct svc_req *rqstp; 131 { 132 if (!stat_is_init) 133 stat_init(); 134 sincelastreq = 0; 135 return (&stats_all.s3); 136 } 137 138 statsswtch * 139 rstatproc_stats_2_svc(arg, rqstp) 140 void *arg; 141 struct svc_req *rqstp; 142 { 143 if (!stat_is_init) 144 stat_init(); 145 sincelastreq = 0; 146 return (&stats_all.s2); 147 } 148 149 stats * 150 rstatproc_stats_1_svc(arg, rqstp) 151 void *arg; 152 struct svc_req *rqstp; 153 { 154 if (!stat_is_init) 155 stat_init(); 156 sincelastreq = 0; 157 return (&stats_all.s1); 158 } 159 160 u_int * 161 rstatproc_havedisk_3_svc(arg, rqstp) 162 void *arg; 163 struct svc_req *rqstp; 164 { 165 static u_int have; 166 167 if (!stat_is_init) 168 stat_init(); 169 sincelastreq = 0; 170 have = havedisk(); 171 return (&have); 172 } 173 174 u_int * 175 rstatproc_havedisk_2_svc(arg, rqstp) 176 void *arg; 177 struct svc_req *rqstp; 178 { 179 return (rstatproc_havedisk_3_svc(arg, rqstp)); 180 } 181 182 u_int * 183 rstatproc_havedisk_1_svc(arg, rqstp) 184 void *arg; 185 struct svc_req *rqstp; 186 { 187 return (rstatproc_havedisk_3_svc(arg, rqstp)); 188 } 189 190 void 191 updatestat() 192 { 193 long off; 194 int i, hz; 195 struct vmmeter cnt; 196 struct ifnet ifnet; 197 double avrun[3]; 198 struct timeval tm, btm; 199 #ifdef BSD 200 int cp_time[BSD_CPUSTATES]; 201 #endif 202 203 #ifdef DEBUG 204 syslog(LOG_DEBUG, "entering updatestat"); 205 #endif 206 if (sincelastreq >= closedown) { 207 #ifdef DEBUG 208 syslog(LOG_DEBUG, "about to closedown"); 209 #endif 210 if (from_inetd) 211 exit(0); 212 else { 213 stat_is_init = 0; 214 return; 215 } 216 } 217 sincelastreq++; 218 219 if (kvm_read(kfd, (long)nl[X_HZ].n_value, (char *)&hz, sizeof hz) != 220 sizeof hz) { 221 syslog(LOG_ERR, "can't read hz from kmem"); 222 exit(1); 223 } 224 #ifdef BSD 225 if (kvm_read(kfd, (long)nl[X_CPTIME].n_value, (char *)cp_time, 226 sizeof (cp_time)) 227 != sizeof (cp_time)) { 228 syslog(LOG_ERR, "can't read cp_time from kmem"); 229 exit(1); 230 } 231 for (i = 0; i < CPUSTATES; i++) 232 stats_all.s1.cp_time[i] = cp_time[cp_xlat[i]]; 233 #else 234 if (kvm_read(kfd, (long)nl[X_CPTIME].n_value, 235 (char *)stats_all.s1.cp_time, 236 sizeof (stats_all.s1.cp_time)) 237 != sizeof (stats_all.s1.cp_time)) { 238 syslog(LOG_ERR, "can't read cp_time from kmem"); 239 exit(1); 240 } 241 #endif 242 #ifdef BSD 243 (void)getloadavg(avrun, sizeof(avrun) / sizeof(avrun[0])); 244 #endif 245 stats_all.s2.avenrun[0] = avrun[0] * FSCALE; 246 stats_all.s2.avenrun[1] = avrun[1] * FSCALE; 247 stats_all.s2.avenrun[2] = avrun[2] * FSCALE; 248 if (kvm_read(kfd, (long)nl[X_BOOTTIME].n_value, 249 (char *)&btm, sizeof (stats_all.s2.boottime)) 250 != sizeof (stats_all.s2.boottime)) { 251 syslog(LOG_ERR, "can't read boottime from kmem"); 252 exit(1); 253 } 254 stats_all.s2.boottime.tv_sec = btm.tv_sec; 255 stats_all.s2.boottime.tv_usec = btm.tv_usec; 256 257 258 #ifdef DEBUG 259 syslog(LOG_DEBUG, "%d %d %d %d\n", stats_all.s1.cp_time[0], 260 stats_all.s1.cp_time[1], stats_all.s1.cp_time[2], stats_all.s1.cp_time[3]); 261 #endif 262 263 if (kvm_read(kfd, (long)nl[X_CNT].n_value, (char *)&cnt, sizeof cnt) != 264 sizeof cnt) { 265 syslog(LOG_ERR, "can't read cnt from kmem"); 266 exit(1); 267 } 268 stats_all.s1.v_pgpgin = cnt.v_pgpgin; 269 stats_all.s1.v_pgpgout = cnt.v_pgpgout; 270 stats_all.s1.v_pswpin = cnt.v_pswpin; 271 stats_all.s1.v_pswpout = cnt.v_pswpout; 272 stats_all.s1.v_intr = cnt.v_intr; 273 gettimeofday(&tm, (struct timezone *) 0); 274 stats_all.s1.v_intr -= hz*(tm.tv_sec - btm.tv_sec) + 275 hz*(tm.tv_usec - btm.tv_usec)/1000000; 276 stats_all.s2.v_swtch = cnt.v_swtch; 277 278 if (kvm_read(kfd, (long)nl[X_DKXFER].n_value, 279 (char *)stats_all.s1.dk_xfer, 280 sizeof (stats_all.s1.dk_xfer)) 281 != sizeof (stats_all.s1.dk_xfer)) { 282 syslog(LOG_ERR, "can't read dk_xfer from kmem"); 283 exit(1); 284 } 285 286 stats_all.s1.if_ipackets = 0; 287 stats_all.s1.if_opackets = 0; 288 stats_all.s1.if_ierrors = 0; 289 stats_all.s1.if_oerrors = 0; 290 stats_all.s1.if_collisions = 0; 291 for (off = (long)ifnetq.tqh_first, i = 0; off && i < numintfs; i++) { 292 if (kvm_read(kfd, off, (char *)&ifnet, sizeof ifnet) != 293 sizeof ifnet) { 294 syslog(LOG_ERR, "can't read ifnet from kmem"); 295 exit(1); 296 } 297 stats_all.s1.if_ipackets += ifnet.if_data.ifi_ipackets; 298 stats_all.s1.if_opackets += ifnet.if_data.ifi_opackets; 299 stats_all.s1.if_ierrors += ifnet.if_data.ifi_ierrors; 300 stats_all.s1.if_oerrors += ifnet.if_data.ifi_oerrors; 301 stats_all.s1.if_collisions += ifnet.if_data.ifi_collisions; 302 off = (long)ifnet.if_list.tqe_next; 303 } 304 gettimeofday((struct timeval *)&stats_all.s3.curtime, 305 (struct timezone *) 0); 306 alarm(1); 307 } 308 309 setup() 310 { 311 struct ifnet ifnet; 312 long off; 313 char errbuf[_POSIX2_LINE_MAX]; 314 315 kfd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf); 316 if (kfd == NULL) { 317 syslog(LOG_ERR, "%s", errbuf); 318 exit (1); 319 } 320 321 if (kvm_nlist(kfd, nl) != 0) { 322 syslog(LOG_ERR, "can't get namelist"); 323 exit (1); 324 } 325 326 if (kvm_read(kfd, (long)nl[X_IFNET].n_value, &ifnetq, 327 sizeof ifnetq) != sizeof ifnetq) { 328 syslog(LOG_ERR, "can't read ifnet queue head from kmem"); 329 exit(1); 330 } 331 332 numintfs = 0; 333 for (off = (long)ifnetq.tqh_first; off;) { 334 if (kvm_read(kfd, off, (char *)&ifnet, sizeof ifnet) != 335 sizeof ifnet) { 336 syslog(LOG_ERR, "can't read ifnet from kmem"); 337 exit(1); 338 } 339 numintfs++; 340 off = (long)ifnet.if_list.tqe_next; 341 } 342 } 343 344 /* 345 * returns true if have a disk 346 */ 347 int 348 havedisk() 349 { 350 int i, cnt; 351 long xfer[DK_NDRIVE]; 352 353 if (kvm_nlist(kfd, nl) != 0) { 354 syslog(LOG_ERR, "can't get namelist"); 355 exit (1); 356 } 357 358 if (kvm_read(kfd, (long)nl[X_DKXFER].n_value, 359 (char *)xfer, sizeof xfer) != sizeof xfer) { 360 syslog(LOG_ERR, "can't read dk_xfer from kmem"); 361 exit(1); 362 } 363 cnt = 0; 364 for (i=0; i < DK_NDRIVE; i++) 365 cnt += xfer[i]; 366 return (cnt != 0); 367 } 368 369 void 370 rstat_service(rqstp, transp) 371 struct svc_req *rqstp; 372 SVCXPRT *transp; 373 { 374 union { 375 int fill; 376 } argument; 377 char *result; 378 xdrproc_t xdr_argument, xdr_result; 379 char *(*local) __P((void *, struct svc_req *)); 380 381 switch (rqstp->rq_proc) { 382 case NULLPROC: 383 (void)svc_sendreply(transp, xdr_void, (char *)NULL); 384 goto leave; 385 386 case RSTATPROC_STATS: 387 xdr_argument = (xdrproc_t)xdr_void; 388 xdr_result = (xdrproc_t)xdr_statstime; 389 switch (rqstp->rq_vers) { 390 case RSTATVERS_ORIG: 391 local = (char *(*) __P((void *, struct svc_req *))) 392 rstatproc_stats_1_svc; 393 break; 394 case RSTATVERS_SWTCH: 395 local = (char *(*) __P((void *, struct svc_req *))) 396 rstatproc_stats_2_svc; 397 break; 398 case RSTATVERS_TIME: 399 local = (char *(*) __P((void *, struct svc_req *))) 400 rstatproc_stats_3_svc; 401 break; 402 default: 403 svcerr_progvers(transp, RSTATVERS_ORIG, RSTATVERS_TIME); 404 goto leave; 405 } 406 break; 407 408 case RSTATPROC_HAVEDISK: 409 xdr_argument = (xdrproc_t)xdr_void; 410 xdr_result = (xdrproc_t)xdr_u_int; 411 switch (rqstp->rq_vers) { 412 case RSTATVERS_ORIG: 413 local = (char *(*) __P((void *, struct svc_req *))) 414 rstatproc_havedisk_1_svc; 415 break; 416 case RSTATVERS_SWTCH: 417 local = (char *(*) __P((void *, struct svc_req *))) 418 rstatproc_havedisk_2_svc; 419 break; 420 case RSTATVERS_TIME: 421 local = (char *(*) __P((void *, struct svc_req *))) 422 rstatproc_havedisk_3_svc; 423 break; 424 default: 425 svcerr_progvers(transp, RSTATVERS_ORIG, RSTATVERS_TIME); 426 goto leave; 427 } 428 break; 429 430 default: 431 svcerr_noproc(transp); 432 goto leave; 433 } 434 bzero((char *)&argument, sizeof(argument)); 435 if (!svc_getargs(transp, xdr_argument, (caddr_t)&argument)) { 436 svcerr_decode(transp); 437 goto leave; 438 } 439 result = (*local)(&argument, rqstp); 440 if (result != NULL && !svc_sendreply(transp, xdr_result, result)) { 441 svcerr_systemerr(transp); 442 } 443 if (!svc_freeargs(transp, xdr_argument, (caddr_t)&argument)) { 444 (void)fprintf(stderr, "unable to free arguments\n"); 445 exit(1); 446 } 447 leave: 448 if (from_inetd) 449 exit(0); 450 } 451