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