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