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