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