1 /* $OpenBSD: rstat_proc.c,v 1.15 2001/07/08 21:18:09 deraadt Exp $ */ 2 3 /* 4 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for 5 * unrestricted use provided that this legend is included on all tape 6 * media and as a part of the software program in whole or part. Users 7 * may copy or modify Sun RPC without charge, but are not authorized 8 * to license or distribute it to anyone else except as part of a product or 9 * program developed by the user. 10 * 11 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE 12 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR 13 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. 14 * 15 * Sun RPC is provided with no support and without any obligation on the 16 * part of Sun Microsystems, Inc. to assist in its use, correction, 17 * modification or enhancement. 18 * 19 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE 20 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC 21 * OR ANY PART THEREOF. 22 * 23 * In no event will Sun Microsystems, Inc. be liable for any lost revenue 24 * or profits or other special, indirect and consequential damages, even if 25 * Sun has been advised of the possibility of such damages. 26 * 27 * Sun Microsystems, Inc. 28 * 2550 Garcia Avenue 29 * Mountain View, California 94043 30 */ 31 #ifndef lint 32 /*static char sccsid[] = "from: @(#)rpc.rstatd.c 1.1 86/09/25 Copyr 1984 Sun Micro";*/ 33 /*static char sccsid[] = "from: @(#)rstat_proc.c 2.2 88/08/01 4.0 RPCSRC";*/ 34 static char rcsid[] = "$OpenBSD: rstat_proc.c,v 1.15 2001/07/08 21:18:09 deraadt Exp $"; 35 #endif 36 37 /* 38 * rstat service: built with rstat.x and derived from rpc.rstatd.c 39 * 40 * Copyright (c) 1984 by Sun Microsystems, Inc. 41 */ 42 43 #include <stdio.h> 44 #include <stdlib.h> 45 #include <string.h> 46 #include <signal.h> 47 #include <fcntl.h> 48 #include <kvm.h> 49 #include <limits.h> 50 #include <rpc/rpc.h> 51 #include <sys/socket.h> 52 #include <nlist.h> 53 #include <syslog.h> 54 #include <errno.h> 55 #include <sys/param.h> 56 #ifdef BSD 57 #include <sys/vmmeter.h> 58 #include <sys/dkstat.h> 59 #include "dkstats.h" 60 #else 61 #include <sys/dk.h> 62 #endif 63 #include <net/if.h> 64 65 #include <vm/vm.h> 66 #include <sys/sysctl.h> 67 #include <uvm/uvm_extern.h> 68 69 #undef FSHIFT /* Use protocol's shift and scale values */ 70 #undef FSCALE 71 #undef DK_NDRIVE 72 #undef CPUSTATES 73 #undef if_ipackets 74 #undef if_ierrors 75 #undef if_opackets 76 #undef if_oerrors 77 #undef if_collisions 78 #include <rpcsvc/rstat.h> 79 80 #ifdef BSD 81 #define BSD_CPUSTATES 5 /* Use protocol's idea of CPU states */ 82 int cp_xlat[CPUSTATES] = { CP_USER, CP_NICE, CP_SYS, CP_IDLE }; 83 #endif 84 85 struct nlist nl[] = { 86 #define X_IFNET 0 87 { "_ifnet" }, 88 #define X_BOOTTIME 1 89 { "_boottime" }, 90 #ifndef BSD 91 #define X_HZ 2 92 { "_hz" }, 93 #define X_CPTIME 3 94 { "_cp_time" }, 95 #define X_DKXFER 4 96 { "_dk_xfer" }, 97 #define X_CNT 5 98 { "_cnt" }, 99 #else 100 #endif 101 { NULL }, 102 }; 103 104 #ifdef BSD 105 extern int dk_ndrive; /* from dkstats.c */ 106 extern struct _disk cur, last; 107 char *memf = NULL, *nlistf = NULL; 108 #endif 109 int hz; 110 111 struct ifnet_head ifnetq; /* chain of ethernet interfaces */ 112 int numintfs; 113 114 extern int from_inetd; 115 int sincelastreq = 0; /* number of alarms since last request */ 116 extern int closedown; 117 kvm_t *kfd; 118 119 union { 120 struct stats s1; 121 struct statsswtch s2; 122 struct statstime s3; 123 } stats_all; 124 125 int stats_service(); 126 void updatestat(void); 127 void setup(void); 128 int havedisk(void); 129 130 static int stat_is_init = 0; 131 132 #ifndef FSCALE 133 #define FSCALE (1 << 8) 134 #endif 135 136 void 137 stat_init() 138 { 139 stat_is_init = 1; 140 setup(); 141 updatestat(); 142 (void) signal(SIGALRM, updatestat); /* XXX huge signal race */ 143 alarm(1); 144 } 145 146 statstime * 147 rstatproc_stats_3_svc(arg, rqstp) 148 void *arg; 149 struct svc_req *rqstp; 150 { 151 if (!stat_is_init) 152 stat_init(); 153 sincelastreq = 0; 154 return (&stats_all.s3); 155 } 156 157 statsswtch * 158 rstatproc_stats_2_svc(arg, rqstp) 159 void *arg; 160 struct svc_req *rqstp; 161 { 162 if (!stat_is_init) 163 stat_init(); 164 sincelastreq = 0; 165 return (&stats_all.s2); 166 } 167 168 stats * 169 rstatproc_stats_1_svc(arg, rqstp) 170 void *arg; 171 struct svc_req *rqstp; 172 { 173 if (!stat_is_init) 174 stat_init(); 175 sincelastreq = 0; 176 return (&stats_all.s1); 177 } 178 179 u_int * 180 rstatproc_havedisk_3_svc(arg, rqstp) 181 void *arg; 182 struct svc_req *rqstp; 183 { 184 static u_int have; 185 186 if (!stat_is_init) 187 stat_init(); 188 sincelastreq = 0; 189 have = havedisk(); 190 return (&have); 191 } 192 193 u_int * 194 rstatproc_havedisk_2_svc(arg, rqstp) 195 void *arg; 196 struct svc_req *rqstp; 197 { 198 return (rstatproc_havedisk_3_svc(arg, rqstp)); 199 } 200 201 u_int * 202 rstatproc_havedisk_1_svc(arg, rqstp) 203 void *arg; 204 struct svc_req *rqstp; 205 { 206 return (rstatproc_havedisk_3_svc(arg, rqstp)); 207 } 208 209 void 210 updatestat() 211 { 212 long off; 213 int i, save_errno = errno; 214 struct uvmexp uvmexp; 215 int mib[2]; 216 size_t len; 217 struct ifnet ifnet; 218 double avrun[3]; 219 struct timeval tm, btm; 220 #ifdef BSD 221 long *cp_time = cur.cp_time; 222 #endif 223 224 #ifdef DEBUG 225 syslog(LOG_DEBUG, "entering updatestat"); 226 #endif 227 if (sincelastreq >= closedown) { 228 #ifdef DEBUG 229 syslog(LOG_DEBUG, "about to closedown"); 230 #endif 231 if (from_inetd) 232 exit(0); 233 else { 234 stat_is_init = 0; 235 return; 236 } 237 } 238 sincelastreq++; 239 240 /* 241 * dkreadstats reads in the "disk_count" as well as the "disklist" 242 * statistics. It also retrieves "hz" and the "cp_time" array. 243 */ 244 dkreadstats(); 245 memset(stats_all.s1.dk_xfer, '\0', sizeof(stats_all.s1.dk_xfer)); 246 for (i = 0; i < dk_ndrive && i < DK_NDRIVE; i++) 247 stats_all.s1.dk_xfer[i] = cur.dk_xfer[i]; 248 249 #ifdef BSD 250 for (i = 0; i < CPUSTATES; i++) 251 stats_all.s1.cp_time[i] = cp_time[cp_xlat[i]]; 252 #else 253 if (kvm_read(kfd, (long)nl[X_HZ].n_value, (char *)&hz, sizeof hz) != 254 sizeof hz) { 255 syslog(LOG_ERR, "can't read hz from kmem"); 256 exit(1); 257 } 258 if (kvm_read(kfd, (long)nl[X_CPTIME].n_value, 259 (char *)stats_all.s1.cp_time, sizeof (stats_all.s1.cp_time)) 260 != sizeof (stats_all.s1.cp_time)) { 261 syslog(LOG_ERR, "can't read cp_time from kmem"); 262 exit(1); 263 } 264 #endif 265 #ifdef BSD 266 (void)getloadavg(avrun, sizeof(avrun) / sizeof(avrun[0])); 267 #endif 268 stats_all.s2.avenrun[0] = avrun[0] * FSCALE; 269 stats_all.s2.avenrun[1] = avrun[1] * FSCALE; 270 stats_all.s2.avenrun[2] = avrun[2] * FSCALE; 271 if (kvm_read(kfd, (long)nl[X_BOOTTIME].n_value, 272 (char *)&btm, sizeof (stats_all.s2.boottime)) 273 != sizeof (stats_all.s2.boottime)) { 274 syslog(LOG_ERR, "can't read boottime from kmem"); 275 exit(1); 276 } 277 stats_all.s2.boottime.tv_sec = btm.tv_sec; 278 stats_all.s2.boottime.tv_usec = btm.tv_usec; 279 280 281 #ifdef DEBUG 282 syslog(LOG_DEBUG, "%d %d %d %d", stats_all.s1.cp_time[0], 283 stats_all.s1.cp_time[1], stats_all.s1.cp_time[2], 284 stats_all.s1.cp_time[3]); 285 #endif 286 287 mib[0] = CTL_VM; 288 mib[1] = VM_UVMEXP; 289 len = sizeof(uvmexp); 290 if (sysctl(mib, 2, &uvmexp, &len, NULL, 0) < 0) { 291 syslog(LOG_ERR, "can't sysctl vm.uvmexp"); 292 exit(1); 293 } 294 stats_all.s1.v_pgpgin = uvmexp.fltanget; 295 stats_all.s1.v_pgpgout = uvmexp.pdpageouts; 296 stats_all.s1.v_pswpin = uvmexp.swapins; 297 stats_all.s1.v_pswpout = uvmexp.swapouts; 298 stats_all.s1.v_intr = uvmexp.intrs; 299 stats_all.s2.v_swtch = uvmexp.swtch; 300 gettimeofday(&tm, (struct timezone *) 0); 301 stats_all.s1.v_intr -= hz*(tm.tv_sec - btm.tv_sec) + 302 hz*(tm.tv_usec - btm.tv_usec)/1000000; 303 304 #ifndef BSD 305 if (kvm_read(kfd, (long)nl[X_DKXFER].n_value, 306 (char *)stats_all.s1.dk_xfer, sizeof (stats_all.s1.dk_xfer)) 307 != sizeof (stats_all.s1.dk_xfer)) { 308 syslog(LOG_ERR, "can't read dk_xfer from kmem"); 309 exit(1); 310 } 311 #endif 312 313 stats_all.s1.if_ipackets = 0; 314 stats_all.s1.if_opackets = 0; 315 stats_all.s1.if_ierrors = 0; 316 stats_all.s1.if_oerrors = 0; 317 stats_all.s1.if_collisions = 0; 318 for (off = (long)ifnetq.tqh_first, i = 0; off && i < numintfs; i++) { 319 if (kvm_read(kfd, off, (char *)&ifnet, sizeof ifnet) != 320 sizeof ifnet) { 321 syslog(LOG_ERR, "can't read ifnet from kmem"); 322 exit(1); 323 } 324 stats_all.s1.if_ipackets += ifnet.if_data.ifi_ipackets; 325 stats_all.s1.if_opackets += ifnet.if_data.ifi_opackets; 326 stats_all.s1.if_ierrors += ifnet.if_data.ifi_ierrors; 327 stats_all.s1.if_oerrors += ifnet.if_data.ifi_oerrors; 328 stats_all.s1.if_collisions += ifnet.if_data.ifi_collisions; 329 off = (long)ifnet.if_list.tqe_next; 330 } 331 gettimeofday((struct timeval *)&stats_all.s3.curtime, 332 (struct timezone *) 0); 333 alarm(1); 334 errno = save_errno; 335 } 336 337 void 338 setup() 339 { 340 struct ifnet ifnet; 341 long off; 342 char errbuf[_POSIX2_LINE_MAX]; 343 344 kfd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf); 345 if (kfd == NULL) { 346 syslog(LOG_ERR, "%s", errbuf); 347 exit (1); 348 } 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_IFNET].n_value, &ifnetq, 356 sizeof ifnetq) != sizeof ifnetq) { 357 syslog(LOG_ERR, "can't read ifnet queue head from kmem"); 358 exit(1); 359 } 360 361 numintfs = 0; 362 for (off = (long)ifnetq.tqh_first; off;) { 363 if (kvm_read(kfd, off, (char *)&ifnet, sizeof ifnet) != 364 sizeof ifnet) { 365 syslog(LOG_ERR, "can't read ifnet from kmem"); 366 exit(1); 367 } 368 numintfs++; 369 off = (long)ifnet.if_list.tqe_next; 370 } 371 #ifdef BSD 372 dkinit(0); 373 #endif 374 } 375 376 /* 377 * returns true if have a disk 378 */ 379 int 380 havedisk() 381 { 382 #ifdef BSD 383 return dk_ndrive != 0; 384 #else 385 int i, cnt; 386 long xfer[DK_NDRIVE]; 387 388 if (kvm_nlist(kfd, nl) != 0) { 389 syslog(LOG_ERR, "can't get namelist"); 390 exit (1); 391 } 392 393 if (kvm_read(kfd, (long)nl[X_DKXFER].n_value, 394 (char *)xfer, sizeof xfer) != sizeof xfer) { 395 syslog(LOG_ERR, "can't read dk_xfer from kmem"); 396 exit(1); 397 } 398 cnt = 0; 399 for (i=0; i < DK_NDRIVE; i++) 400 cnt += xfer[i]; 401 return (cnt != 0); 402 #endif 403 } 404 405 void 406 rstat_service(rqstp, transp) 407 struct svc_req *rqstp; 408 SVCXPRT *transp; 409 { 410 union { 411 int fill; 412 } argument; 413 char *result; 414 xdrproc_t xdr_argument, xdr_result; 415 char *(*local) __P((void *, struct svc_req *)); 416 417 switch (rqstp->rq_proc) { 418 case NULLPROC: 419 (void)svc_sendreply(transp, xdr_void, (char *)NULL); 420 return; 421 422 case RSTATPROC_STATS: 423 xdr_argument = (xdrproc_t)xdr_void; 424 xdr_result = (xdrproc_t)xdr_statstime; 425 switch (rqstp->rq_vers) { 426 case RSTATVERS_ORIG: 427 local = (char *(*) __P((void *, struct svc_req *))) 428 rstatproc_stats_1_svc; 429 break; 430 case RSTATVERS_SWTCH: 431 local = (char *(*) __P((void *, struct svc_req *))) 432 rstatproc_stats_2_svc; 433 break; 434 case RSTATVERS_TIME: 435 local = (char *(*) __P((void *, struct svc_req *))) 436 rstatproc_stats_3_svc; 437 break; 438 default: 439 svcerr_progvers(transp, RSTATVERS_ORIG, RSTATVERS_TIME); 440 return; 441 } 442 break; 443 444 case RSTATPROC_HAVEDISK: 445 xdr_argument = (xdrproc_t)xdr_void; 446 xdr_result = (xdrproc_t)xdr_u_int; 447 switch (rqstp->rq_vers) { 448 case RSTATVERS_ORIG: 449 local = (char *(*) __P((void *, struct svc_req *))) 450 rstatproc_havedisk_1_svc; 451 break; 452 case RSTATVERS_SWTCH: 453 local = (char *(*) __P((void *, struct svc_req *))) 454 rstatproc_havedisk_2_svc; 455 break; 456 case RSTATVERS_TIME: 457 local = (char *(*) __P((void *, struct svc_req *))) 458 rstatproc_havedisk_3_svc; 459 break; 460 default: 461 svcerr_progvers(transp, RSTATVERS_ORIG, RSTATVERS_TIME); 462 return; 463 } 464 break; 465 466 default: 467 svcerr_noproc(transp); 468 return; 469 } 470 bzero((char *)&argument, sizeof(argument)); 471 if (!svc_getargs(transp, xdr_argument, (caddr_t)&argument)) { 472 svcerr_decode(transp); 473 return; 474 } 475 result = (*local)(&argument, rqstp); 476 if (result != NULL && !svc_sendreply(transp, xdr_result, result)) { 477 svcerr_systemerr(transp); 478 } 479 if (!svc_freeargs(transp, xdr_argument, (caddr_t)&argument)) { 480 syslog(LOG_ERR, "unable to free arguments"); 481 exit(1); 482 } 483 } 484