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