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