1 /* $NetBSD: rstat_proc.c,v 1.18 1997/02/22 01:41:35 thorpej 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[] = "$NetBSD: rstat_proc.c,v 1.18 1997/02/22 01:41:35 thorpej 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 <sys/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 #undef FSHIFT /* Use protocol's shift and scale values */ 66 #undef FSCALE 67 #undef DK_NDRIVE 68 #undef CPUSTATES 69 #undef if_ipackets 70 #undef if_ierrors 71 #undef if_opackets 72 #undef if_oerrors 73 #undef if_collisions 74 #include <rpcsvc/rstat.h> 75 76 #ifdef BSD 77 #define BSD_CPUSTATES 5 /* Use protocol's idea of CPU states */ 78 int cp_xlat[CPUSTATES] = { CP_USER, CP_NICE, CP_SYS, CP_IDLE }; 79 #endif 80 81 struct nlist nl[] = { 82 #define X_CNT 0 83 { "_cnt" }, 84 #define X_IFNET 1 85 { "_ifnet" }, 86 #define X_BOOTTIME 2 87 { "_boottime" }, 88 { NULL }, 89 }; 90 91 extern int dk_ndrive; /* From dkstats.c */ 92 extern struct _disk cur, last; 93 int hz; 94 char *memf = NULL, *nlistf = NULL; 95 96 struct ifnet_head ifnetq; /* chain of ethernet interfaces */ 97 int numintfs; 98 int stats_service(); 99 100 extern int from_inetd; 101 int sincelastreq = 0; /* number of alarms since last request */ 102 extern int closedown; 103 kvm_t *kfd; 104 105 union { 106 struct stats s1; 107 struct statsswtch s2; 108 struct statstime s3; 109 } stats_all; 110 111 void updatestat(); 112 static stat_is_init = 0; 113 extern int errno; 114 115 #ifndef FSCALE 116 #define FSCALE (1 << 8) 117 #endif 118 119 stat_init() 120 { 121 stat_is_init = 1; 122 setup(); 123 updatestat(); 124 (void) signal(SIGALRM, updatestat); 125 alarm(1); 126 } 127 128 statstime * 129 rstatproc_stats_3_svc(arg, rqstp) 130 void *arg; 131 struct svc_req *rqstp; 132 { 133 if (!stat_is_init) 134 stat_init(); 135 sincelastreq = 0; 136 return (&stats_all.s3); 137 } 138 139 statsswtch * 140 rstatproc_stats_2_svc(arg, rqstp) 141 void *arg; 142 struct svc_req *rqstp; 143 { 144 if (!stat_is_init) 145 stat_init(); 146 sincelastreq = 0; 147 return (&stats_all.s2); 148 } 149 150 stats * 151 rstatproc_stats_1_svc(arg, rqstp) 152 void *arg; 153 struct svc_req *rqstp; 154 { 155 if (!stat_is_init) 156 stat_init(); 157 sincelastreq = 0; 158 return (&stats_all.s1); 159 } 160 161 u_int * 162 rstatproc_havedisk_3_svc(arg, rqstp) 163 void *arg; 164 struct svc_req *rqstp; 165 { 166 static u_int have; 167 168 if (!stat_is_init) 169 stat_init(); 170 sincelastreq = 0; 171 have = havedisk(); 172 return (&have); 173 } 174 175 u_int * 176 rstatproc_havedisk_2_svc(arg, rqstp) 177 void *arg; 178 struct svc_req *rqstp; 179 { 180 return (rstatproc_havedisk_3_svc(arg, rqstp)); 181 } 182 183 u_int * 184 rstatproc_havedisk_1_svc(arg, rqstp) 185 void *arg; 186 struct svc_req *rqstp; 187 { 188 return (rstatproc_havedisk_3_svc(arg, rqstp)); 189 } 190 191 void 192 updatestat() 193 { 194 long off; 195 int i; 196 struct vmmeter cnt; 197 struct ifnet ifnet; 198 double avrun[3]; 199 struct timeval tm, btm; 200 #ifdef BSD 201 int cp_time[BSD_CPUSTATES]; 202 #endif 203 204 #ifdef DEBUG 205 syslog(LOG_DEBUG, "entering updatestat"); 206 #endif 207 if (sincelastreq >= closedown) { 208 #ifdef DEBUG 209 syslog(LOG_DEBUG, "about to closedown"); 210 #endif 211 if (from_inetd) 212 exit(0); 213 else { 214 stat_is_init = 0; 215 return; 216 } 217 } 218 sincelastreq++; 219 220 /* 221 * dkreadstats reads in the "disk_count" as well as the "disklist" 222 * statistics. It also retrieves "hz" and the "cp_time" array. 223 */ 224 dkreadstats(); 225 memset(stats_all.s1.dk_xfer, 0, sizeof(stats_all.s1.dk_xfer)); 226 for (i = 0; i < dk_ndrive && i < DK_NDRIVE; i++) 227 stats_all.s1.dk_xfer[i] = cur.dk_xfer[i]; 228 229 #ifdef BSD 230 for (i = 0; i < CPUSTATES; i++) 231 stats_all.s1.cp_time[i] = cur.cp_time[cp_xlat[i]]; 232 #else 233 if (kvm_read(kfd, (long)nl[X_CPTIME].n_value, 234 (char *)stats_all.s1.cp_time, 235 sizeof (stats_all.s1.cp_time)) 236 != sizeof (stats_all.s1.cp_time)) { 237 syslog(LOG_ERR, "can't read cp_time from kmem"); 238 exit(1); 239 } 240 #endif 241 #ifdef BSD 242 (void)getloadavg(avrun, sizeof(avrun) / sizeof(avrun[0])); 243 #endif 244 stats_all.s2.avenrun[0] = avrun[0] * FSCALE; 245 stats_all.s2.avenrun[1] = avrun[1] * FSCALE; 246 stats_all.s2.avenrun[2] = avrun[2] * FSCALE; 247 if (kvm_read(kfd, (long)nl[X_BOOTTIME].n_value, 248 (char *)&btm, sizeof (stats_all.s2.boottime)) 249 != sizeof (stats_all.s2.boottime)) { 250 syslog(LOG_ERR, "can't read boottime from kmem"); 251 exit(1); 252 } 253 stats_all.s2.boottime.tv_sec = btm.tv_sec; 254 stats_all.s2.boottime.tv_usec = btm.tv_usec; 255 256 257 #ifdef DEBUG 258 syslog(LOG_DEBUG, "%d %d %d %d\n", stats_all.s1.cp_time[0], 259 stats_all.s1.cp_time[1], stats_all.s1.cp_time[2], stats_all.s1.cp_time[3]); 260 #endif 261 262 if (kvm_read(kfd, (long)nl[X_CNT].n_value, (char *)&cnt, sizeof cnt) != 263 sizeof cnt) { 264 syslog(LOG_ERR, "can't read cnt from kmem"); 265 exit(1); 266 } 267 stats_all.s1.v_pgpgin = cnt.v_pgpgin; 268 stats_all.s1.v_pgpgout = cnt.v_pgpgout; 269 stats_all.s1.v_pswpin = cnt.v_pswpin; 270 stats_all.s1.v_pswpout = cnt.v_pswpout; 271 stats_all.s1.v_intr = cnt.v_intr; 272 gettimeofday(&tm, (struct timezone *) 0); 273 stats_all.s1.v_intr -= hz*(tm.tv_sec - btm.tv_sec) + 274 hz*(tm.tv_usec - btm.tv_usec)/1000000; 275 stats_all.s2.v_swtch = cnt.v_swtch; 276 277 stats_all.s1.if_ipackets = 0; 278 stats_all.s1.if_opackets = 0; 279 stats_all.s1.if_ierrors = 0; 280 stats_all.s1.if_oerrors = 0; 281 stats_all.s1.if_collisions = 0; 282 for (off = (long)ifnetq.tqh_first, i = 0; off && i < numintfs; i++) { 283 if (kvm_read(kfd, off, (char *)&ifnet, sizeof ifnet) != 284 sizeof ifnet) { 285 syslog(LOG_ERR, "can't read ifnet from kmem"); 286 exit(1); 287 } 288 stats_all.s1.if_ipackets += ifnet.if_data.ifi_ipackets; 289 stats_all.s1.if_opackets += ifnet.if_data.ifi_opackets; 290 stats_all.s1.if_ierrors += ifnet.if_data.ifi_ierrors; 291 stats_all.s1.if_oerrors += ifnet.if_data.ifi_oerrors; 292 stats_all.s1.if_collisions += ifnet.if_data.ifi_collisions; 293 off = (long)ifnet.if_list.tqe_next; 294 } 295 gettimeofday((struct timeval *)&stats_all.s3.curtime, 296 (struct timezone *) 0); 297 alarm(1); 298 } 299 300 setup() 301 { 302 struct ifnet ifnet; 303 long off; 304 char errbuf[_POSIX2_LINE_MAX]; 305 306 kfd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf); 307 if (kfd == NULL) { 308 syslog(LOG_ERR, "%s", errbuf); 309 exit (1); 310 } 311 312 if (kvm_nlist(kfd, nl) != 0) { 313 syslog(LOG_ERR, "can't get namelist"); 314 exit (1); 315 } 316 317 if (kvm_read(kfd, (long)nl[X_IFNET].n_value, &ifnetq, 318 sizeof ifnetq) != sizeof ifnetq) { 319 syslog(LOG_ERR, "can't read ifnet queue head from kmem"); 320 exit(1); 321 } 322 323 numintfs = 0; 324 for (off = (long)ifnetq.tqh_first; off;) { 325 if (kvm_read(kfd, off, (char *)&ifnet, sizeof ifnet) != 326 sizeof ifnet) { 327 syslog(LOG_ERR, "can't read ifnet from kmem"); 328 exit(1); 329 } 330 numintfs++; 331 off = (long)ifnet.if_list.tqe_next; 332 } 333 dkinit(0); 334 } 335 336 /* 337 * returns true if have a disk 338 */ 339 int 340 havedisk() 341 { 342 return dk_ndrive != 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 xdrproc_t xdr_argument, xdr_result; 355 char *(*local) __P((void *, struct svc_req *)); 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 = (xdrproc_t)xdr_void; 364 xdr_result = (xdrproc_t)xdr_statstime; 365 switch (rqstp->rq_vers) { 366 case RSTATVERS_ORIG: 367 local = (char *(*) __P((void *, struct svc_req *))) 368 rstatproc_stats_1_svc; 369 break; 370 case RSTATVERS_SWTCH: 371 local = (char *(*) __P((void *, struct svc_req *))) 372 rstatproc_stats_2_svc; 373 break; 374 case RSTATVERS_TIME: 375 local = (char *(*) __P((void *, struct svc_req *))) 376 rstatproc_stats_3_svc; 377 break; 378 default: 379 svcerr_progvers(transp, RSTATVERS_ORIG, RSTATVERS_TIME); 380 goto leave; 381 } 382 break; 383 384 case RSTATPROC_HAVEDISK: 385 xdr_argument = (xdrproc_t)xdr_void; 386 xdr_result = (xdrproc_t)xdr_u_int; 387 switch (rqstp->rq_vers) { 388 case RSTATVERS_ORIG: 389 local = (char *(*) __P((void *, struct svc_req *))) 390 rstatproc_havedisk_1_svc; 391 break; 392 case RSTATVERS_SWTCH: 393 local = (char *(*) __P((void *, struct svc_req *))) 394 rstatproc_havedisk_2_svc; 395 break; 396 case RSTATVERS_TIME: 397 local = (char *(*) __P((void *, struct svc_req *))) 398 rstatproc_havedisk_3_svc; 399 break; 400 default: 401 svcerr_progvers(transp, RSTATVERS_ORIG, RSTATVERS_TIME); 402 goto leave; 403 } 404 break; 405 406 default: 407 svcerr_noproc(transp); 408 goto leave; 409 } 410 bzero((char *)&argument, sizeof(argument)); 411 if (!svc_getargs(transp, xdr_argument, (caddr_t)&argument)) { 412 svcerr_decode(transp); 413 goto leave; 414 } 415 result = (*local)(&argument, rqstp); 416 if (result != NULL && !svc_sendreply(transp, xdr_result, result)) { 417 svcerr_systemerr(transp); 418 } 419 if (!svc_freeargs(transp, xdr_argument, (caddr_t)&argument)) { 420 (void)fprintf(stderr, "unable to free arguments\n"); 421 exit(1); 422 } 423 leave: 424 if (from_inetd) 425 exit(0); 426 } 427