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