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.2 1994/10/15 13:39:54 davidg 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 <fcntl.h> 42 #include <kvm.h> 43 #include <limits.h> 44 #include <nlist.h> 45 #include <signal.h> 46 #include <stdio.h> 47 #include <stdlib.h> 48 #include <string.h> 49 #include <syslog.h> 50 51 #include <rpc/rpc.h> 52 #include <sys/socket.h> 53 #include <sys/errno.h> 54 #include <sys/param.h> 55 #ifdef BSD 56 #include <sys/vmmeter.h> 57 #include <sys/dkstat.h> 58 #else 59 #include <sys/dk.h> 60 #endif 61 #include <net/if.h> 62 63 #undef FSHIFT /* Use protocol's shift and scale values */ 64 #undef FSCALE 65 #undef if_ipackets 66 #undef if_ierrors 67 #undef if_opackets 68 #undef if_oerrors 69 #undef if_collisions 70 #include <rpcsvc/rstat.h> 71 72 struct nlist nl[] = { 73 #define X_CPTIME 0 74 { "_cp_time" }, 75 #define X_CNT 1 76 { "_cnt" }, 77 #define X_IFNET 2 78 { "_ifnet" }, 79 #define X_DKXFER 3 80 { "_dk_xfer" }, 81 #define X_BOOTTIME 4 82 { "_boottime" }, 83 #define X_HZ 5 84 { "_hz" }, 85 #ifdef vax 86 #define X_AVENRUN 6 87 { "_avenrun" }, 88 #endif 89 "", 90 }; 91 int firstifnet, numintfs; /* chain of ethernet interfaces */ 92 int stats_service(); 93 94 extern int from_inetd; 95 int sincelastreq = 0; /* number of alarms since last request */ 96 extern int closedown; 97 98 union { 99 struct stats s1; 100 struct statsswtch s2; 101 struct statstime s3; 102 } stats_all; 103 104 void updatestat(); 105 static stat_is_init = 0; 106 static kvm_t *kd; 107 extern int errno; 108 109 #if defined(BSD) 110 static int cp_time_xlat[RSTAT_CPUSTATES] = { CP_USER, CP_NICE, CP_SYS, 111 CP_IDLE }; 112 static long bsd_cp_time[CPUSTATES]; 113 #endif 114 115 116 #ifndef FSCALE 117 #define FSCALE (1 << 8) 118 #endif 119 120 #ifndef BSD 121 /* 122 * BSD has the kvm facility for getting info from the 123 * kernel. If you aren't on BSD, this surfices. 124 */ 125 int kmem; 126 127 kvm_read(kd, off, addr, size) 128 void * kd; 129 unsigned long off, size; 130 char *addr; 131 { 132 int len; 133 if (lseek(kmem, (long)off, 0) == -1) 134 return(-1); 135 return(read(kmem, addr, size)); 136 } 137 138 kvm_nlist(kd, nl) 139 void * kd; 140 struct nlist *nl; 141 { 142 int n = nlist("/vmunix", nl); 143 if (nl[0].n_value == 0) 144 return(n); 145 146 if ((kmem = open("/dev/kmem", 0)) < 0) 147 return(-1); 148 return(0); 149 } 150 #endif 151 152 stat_init() 153 { 154 stat_is_init = 1; 155 setup(); 156 updatestat(); 157 (void) signal(SIGALRM, updatestat); 158 alarm(1); 159 } 160 161 statstime * 162 rstatproc_stats_3() 163 { 164 if (! stat_is_init) 165 stat_init(); 166 sincelastreq = 0; 167 return(&stats_all.s3); 168 } 169 170 statsswtch * 171 rstatproc_stats_2() 172 { 173 if (! stat_is_init) 174 stat_init(); 175 sincelastreq = 0; 176 return(&stats_all.s2); 177 } 178 179 stats * 180 rstatproc_stats_1() 181 { 182 if (! stat_is_init) 183 stat_init(); 184 sincelastreq = 0; 185 return(&stats_all.s1); 186 } 187 188 u_int * 189 rstatproc_havedisk_3() 190 { 191 static u_int have; 192 193 if (! stat_is_init) 194 stat_init(); 195 sincelastreq = 0; 196 have = havedisk(); 197 return(&have); 198 } 199 200 u_int * 201 rstatproc_havedisk_2() 202 { 203 return(rstatproc_havedisk_3()); 204 } 205 206 u_int * 207 rstatproc_havedisk_1() 208 { 209 return(rstatproc_havedisk_3()); 210 } 211 212 void 213 updatestat() 214 { 215 int off, i, hz; 216 struct vmmeter cnt; 217 struct ifnet ifnet; 218 double avrun[3]; 219 struct timeval tm, btm; 220 221 #ifdef DEBUG 222 fprintf(stderr, "entering updatestat\n"); 223 #endif 224 if (sincelastreq >= closedown) { 225 #ifdef DEBUG 226 fprintf(stderr, "about to closedown\n"); 227 #endif 228 if (from_inetd) 229 exit(0); 230 else { 231 stat_is_init = 0; 232 return; 233 } 234 } 235 sincelastreq++; 236 237 if (kvm_read(kd, (long)nl[X_HZ].n_value, (char *)&hz, sizeof hz) != sizeof hz) { 238 syslog(LOG_ERR, "rstat: can't read hz from kmem\n"); 239 exit(1); 240 } 241 #if defined(BSD) 242 if (kvm_read(kd, (long)nl[X_CPTIME].n_value, (char *)bsd_cp_time, sizeof(bsd_cp_time)) 243 != sizeof(bsd_cp_time)) { 244 syslog(LOG_ERR, "rstat: can't read cp_time from kmem\n"); 245 exit(1); 246 } 247 for(i = 0; i < RSTAT_CPUSTATES ; i++) 248 stats_all.s1.cp_time[i] = bsd_cp_time[cp_time_xlat[i]]; 249 #else 250 if (kvm_read(kd, (long)nl[X_CPTIME].n_value, (char *)stats_all.s1.cp_time, sizeof (stats_all.s1.cp_time)) 251 != sizeof (stats_all.s1.cp_time)) { 252 syslog(LOG_ERR, "rstat: can't read cp_time from kmem\n"); 253 exit(1); 254 } 255 #endif 256 #ifdef vax 257 if (kvm_read(kd, (long)nl[X_AVENRUN].n_value, (char *)avrun, sizeof (avrun)) != sizeof (avrun)) { 258 syslog(LOG_ERR, "rstat: can't read avenrun from kmem\n"); 259 exit(1); 260 } 261 #endif 262 #ifdef BSD 263 (void)getloadavg(avrun, sizeof(avrun) / sizeof(avrun[0])); 264 #endif 265 stats_all.s2.avenrun[0] = avrun[0] * FSCALE; 266 stats_all.s2.avenrun[1] = avrun[1] * FSCALE; 267 stats_all.s2.avenrun[2] = avrun[2] * FSCALE; 268 if (kvm_read(kd, (long)nl[X_BOOTTIME].n_value, (char *)&btm, sizeof (stats_all.s2.boottime)) 269 != sizeof (stats_all.s2.boottime)) { 270 syslog(LOG_ERR, "rstat: can't read boottime from kmem\n"); 271 exit(1); 272 } 273 stats_all.s2.boottime.tv_sec = btm.tv_sec; 274 stats_all.s2.boottime.tv_usec = btm.tv_usec; 275 276 277 #ifdef DEBUG 278 fprintf(stderr, "%d %d %d %d\n", stats_all.s1.cp_time[0], 279 stats_all.s1.cp_time[1], stats_all.s1.cp_time[2], stats_all.s1.cp_time[3]); 280 #endif 281 282 if (kvm_read(kd, (long)nl[X_CNT].n_value, (char *)&cnt, sizeof cnt) != sizeof cnt) { 283 syslog(LOG_ERR, "rstat: can't read cnt from kmem\n"); 284 exit(1); 285 } 286 stats_all.s1.v_pgpgin = cnt.v_vnodepgsin; 287 stats_all.s1.v_pgpgout = cnt.v_vnodepgsout; 288 stats_all.s1.v_pswpin = cnt.v_swappgsin; 289 stats_all.s1.v_pswpout = cnt.v_swappgsout; 290 stats_all.s1.v_intr = cnt.v_intr; 291 gettimeofday(&tm, (struct timezone *) 0); 292 stats_all.s1.v_intr -= hz*(tm.tv_sec - btm.tv_sec) + 293 hz*(tm.tv_usec - btm.tv_usec)/1000000; 294 stats_all.s2.v_swtch = cnt.v_swtch; 295 296 if (kvm_read(kd, (long)nl[X_DKXFER].n_value, (char *)stats_all.s1.dk_xfer, sizeof (stats_all.s1.dk_xfer)) 297 != sizeof (stats_all.s1.dk_xfer)) { 298 syslog(LOG_ERR, "rstat: can't read dk_xfer from kmem\n"); 299 exit(1); 300 } 301 302 stats_all.s1.if_ipackets = 0; 303 stats_all.s1.if_opackets = 0; 304 stats_all.s1.if_ierrors = 0; 305 stats_all.s1.if_oerrors = 0; 306 stats_all.s1.if_collisions = 0; 307 for (off = firstifnet, i = 0; off && i < numintfs; i++) { 308 if (kvm_read(kd, off, (char *)&ifnet, sizeof ifnet) != sizeof ifnet) { 309 syslog(LOG_ERR, "rstat: can't read ifnet from kmem\n"); 310 exit(1); 311 } 312 stats_all.s1.if_ipackets += ifnet.if_data.ifi_ipackets; 313 stats_all.s1.if_opackets += ifnet.if_data.ifi_opackets; 314 stats_all.s1.if_ierrors += ifnet.if_data.ifi_ierrors; 315 stats_all.s1.if_oerrors += ifnet.if_data.ifi_oerrors; 316 stats_all.s1.if_collisions += ifnet.if_data.ifi_collisions; 317 off = (int) ifnet.if_next; 318 } 319 gettimeofday((struct timeval *)&stats_all.s3.curtime, 320 (struct timezone *) 0); 321 alarm(1); 322 } 323 324 setup() 325 { 326 struct ifnet ifnet; 327 int off; 328 char errbuf[_POSIX2_LINE_MAX]; 329 330 int en; 331 332 if ((kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf)) == NULL) { 333 syslog(LOG_ERR, "rpc.rstatd, %s", errbuf); 334 exit(1); 335 } 336 337 if ((en = kvm_nlist(kd, nl)) != 0) { 338 syslog(LOG_ERR, "rstatd: Can't get namelist. %d", en); 339 exit (1); 340 } 341 342 if (kvm_read(kd, (long)nl[X_IFNET].n_value, &firstifnet, 343 sizeof(int)) != sizeof(int)) { 344 syslog(LOG_ERR, "rstat: can't read firstifnet from kmem\n"); 345 exit(1); 346 } 347 348 numintfs = 0; 349 for (off = firstifnet; off;) { 350 if (kvm_read(kd, off, (char *)&ifnet, sizeof ifnet) != sizeof ifnet) { 351 syslog(LOG_ERR, "rstat: can't read ifnet from kmem\n"); 352 exit(1); 353 } 354 numintfs++; 355 off = (int) ifnet.if_next; 356 } 357 } 358 359 /* 360 * returns true if have a disk 361 */ 362 havedisk() 363 { 364 int i, cnt; 365 long xfer[DK_NDRIVE]; 366 367 if (kvm_nlist(kd, nl) != 0) { 368 syslog(LOG_ERR, "rstatd: Can't get namelist.(d)"); 369 exit (1); 370 } 371 372 if (kvm_read(kd, (long)nl[X_DKXFER].n_value, (char *)xfer, sizeof xfer)!= sizeof xfer) { 373 syslog(LOG_ERR, "rstat: can't read kmem\n"); 374 exit(1); 375 } 376 cnt = 0; 377 for (i=0; i < DK_NDRIVE; i++) 378 cnt += xfer[i]; 379 return (cnt != 0); 380 } 381 382 void 383 rstat_service(rqstp, transp) 384 struct svc_req *rqstp; 385 SVCXPRT *transp; 386 { 387 union { 388 int fill; 389 } argument; 390 char *result; 391 bool_t (*xdr_argument)(), (*xdr_result)(); 392 char *(*local)(); 393 394 switch (rqstp->rq_proc) { 395 case NULLPROC: 396 (void)svc_sendreply(transp, xdr_void, (char *)NULL); 397 goto leave; 398 399 case RSTATPROC_STATS: 400 xdr_argument = xdr_void; 401 xdr_result = xdr_statstime; 402 switch (rqstp->rq_vers) { 403 case RSTATVERS_ORIG: 404 local = (char *(*)()) rstatproc_stats_1; 405 break; 406 case RSTATVERS_SWTCH: 407 local = (char *(*)()) rstatproc_stats_2; 408 break; 409 case RSTATVERS_TIME: 410 local = (char *(*)()) rstatproc_stats_3; 411 break; 412 default: 413 svcerr_progvers(transp, RSTATVERS_ORIG, RSTATVERS_TIME); 414 goto leave; 415 /*NOTREACHED*/ 416 } 417 break; 418 419 case RSTATPROC_HAVEDISK: 420 xdr_argument = xdr_void; 421 xdr_result = xdr_u_int; 422 switch (rqstp->rq_vers) { 423 case RSTATVERS_ORIG: 424 local = (char *(*)()) rstatproc_havedisk_1; 425 break; 426 case RSTATVERS_SWTCH: 427 local = (char *(*)()) rstatproc_havedisk_2; 428 break; 429 case RSTATVERS_TIME: 430 local = (char *(*)()) rstatproc_havedisk_3; 431 break; 432 default: 433 svcerr_progvers(transp, RSTATVERS_ORIG, RSTATVERS_TIME); 434 goto leave; 435 /*NOTREACHED*/ 436 } 437 break; 438 439 default: 440 svcerr_noproc(transp); 441 goto leave; 442 } 443 bzero((char *)&argument, sizeof(argument)); 444 if (!svc_getargs(transp, xdr_argument, &argument)) { 445 svcerr_decode(transp); 446 goto leave; 447 } 448 result = (*local)(&argument, rqstp); 449 if (result != NULL && !svc_sendreply(transp, xdr_result, result)) { 450 svcerr_systemerr(transp); 451 } 452 if (!svc_freeargs(transp, xdr_argument, &argument)) { 453 (void)fprintf(stderr, "unable to free arguments\n"); 454 exit(1); 455 } 456 leave: 457 if (from_inetd) 458 exit(0); 459 } 460