1 /* $NetBSD: rstat_proc.c,v 1.52 2014/06/26 03:24:51 dholland 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 #if 0 34 static char sccsid[] = 35 "from: @(#)rpc.rstatd.c 1.1 86/09/25 Copyr 1984 Sun Micro"; 36 static char sccsid[] = 37 "from: @(#)rstat_proc.c 2.2 88/08/01 4.0 RPCSRC"; 38 #endif 39 __RCSID("$NetBSD: rstat_proc.c,v 1.52 2014/06/26 03:24:51 dholland Exp $"); 40 41 /* 42 * rstat service: built with rstat.x and derived from rpc.rstatd.c 43 * 44 * Copyright (c) 1984 by Sun Microsystems, Inc. 45 */ 46 47 #include <sys/param.h> 48 #include <sys/sched.h> 49 #include <sys/socket.h> 50 #include <sys/ioctl.h> 51 52 #include <errno.h> 53 #include <stdio.h> 54 #include <stdlib.h> 55 #include <string.h> 56 #include <signal.h> 57 #include <fcntl.h> 58 #include <limits.h> 59 #include <syslog.h> 60 #include <sys/sysctl.h> 61 #include <uvm/uvm_extern.h> 62 #include "drvstats.h" 63 #include <net/if.h> 64 65 /* 66 * XXX 67 * 68 * this is a huge hack to stop `struct pmap' being 69 * defined twice! 70 */ 71 #define _RPC_PMAP_PROT_H_ 72 #include <rpc/rpc.h> 73 74 #undef FSHIFT /* Use protocol's shift and scale values */ 75 #undef FSCALE 76 #undef DK_NDRIVE 77 #undef CPUSTATES 78 #undef if_ipackets 79 #undef if_ierrors 80 #undef if_opackets 81 #undef if_oerrors 82 #undef if_collisions 83 #include <rpcsvc/rstat.h> 84 85 #define BSD_CPUSTATES 5 /* Use protocol's idea of CPU states */ 86 int cp_xlat[CPUSTATES] = { CP_USER, CP_NICE, CP_SYS, CP_IDLE }; 87 88 int hz; 89 90 extern int from_inetd; 91 int sincelastreq = 0; /* number of alarms since last request */ 92 extern int closedown; 93 94 union { 95 struct stats s1; 96 struct statsswtch s2; 97 struct statstime s3; 98 } stats_all; 99 100 void updatestat(int); 101 void stat_init(void); 102 int havedisk(void); 103 void rstat_service(struct svc_req *, SVCXPRT *); 104 105 static int stat_is_init = 0; 106 107 #ifndef FSCALE 108 #define FSCALE (1 << 8) 109 #endif 110 111 void 112 stat_init(void) 113 { 114 stat_is_init = 1; 115 drvinit(0); 116 updatestat(0); 117 (void) signal(SIGALRM, updatestat); 118 alarm(1); 119 } 120 121 statstime * 122 rstatproc_stats_3_svc(void *arg, struct svc_req *rqstp) 123 { 124 if (!stat_is_init) 125 stat_init(); 126 sincelastreq = 0; 127 return (&stats_all.s3); 128 } 129 130 statsswtch * 131 rstatproc_stats_2_svc(void *arg, struct svc_req *rqstp) 132 { 133 if (!stat_is_init) 134 stat_init(); 135 sincelastreq = 0; 136 stats_all.s2.if_opackets = stats_all.s3.if_opackets; 137 return (&stats_all.s2); 138 } 139 140 stats * 141 rstatproc_stats_1_svc(void *arg, struct svc_req *rqstp) 142 { 143 if (!stat_is_init) 144 stat_init(); 145 sincelastreq = 0; 146 stats_all.s1.if_opackets = stats_all.s3.if_opackets; 147 return (&stats_all.s1); 148 } 149 150 u_int * 151 rstatproc_havedisk_3_svc(void *arg, struct svc_req *rqstp) 152 { 153 static u_int have; 154 155 if (!stat_is_init) 156 stat_init(); 157 sincelastreq = 0; 158 have = havedisk(); 159 return (&have); 160 } 161 162 u_int * 163 rstatproc_havedisk_2_svc(void *arg, struct svc_req *rqstp) 164 { 165 return (rstatproc_havedisk_3_svc(arg, rqstp)); 166 } 167 168 u_int * 169 rstatproc_havedisk_1_svc(void *arg, struct svc_req *rqstp) 170 { 171 return (rstatproc_havedisk_3_svc(arg, rqstp)); 172 } 173 174 void 175 updatestat(int dummy) 176 { 177 struct if_nameindex *ifps; 178 struct ifdatareq ifdr; 179 size_t i, len; 180 int mib[2], s; 181 struct uvmexp_sysctl uvmexp; 182 double avrun[3]; 183 struct timeval tm, btm; 184 185 #ifdef DEBUG 186 syslog(LOG_DEBUG, "entering updatestat"); 187 #endif 188 if (sincelastreq >= closedown) { 189 #ifdef DEBUG 190 syslog(LOG_DEBUG, "about to closedown"); 191 #endif 192 if (from_inetd) 193 exit(0); 194 else { 195 stat_is_init = 0; 196 return; 197 } 198 } 199 sincelastreq++; 200 201 /* 202 * drvreadstats reads in the "disk_count" as well as the "disklist" 203 * statistics. It also retrieves "hz" and the "cp_time" array. 204 */ 205 drvreadstats(); 206 memset(stats_all.s3.dk_xfer, 0, sizeof(stats_all.s3.dk_xfer)); 207 for (i = 0; i < ndrive && i < DK_NDRIVE; i++) 208 stats_all.s3.dk_xfer[i] = cur.rxfer[i] + cur.wxfer[i]; 209 210 for (i = 0; i < CPUSTATES; i++) 211 stats_all.s3.cp_time[i] = cur.cp_time[cp_xlat[i]]; 212 (void)getloadavg(avrun, sizeof(avrun) / sizeof(avrun[0])); 213 stats_all.s3.avenrun[0] = avrun[0] * FSCALE; 214 stats_all.s3.avenrun[1] = avrun[1] * FSCALE; 215 stats_all.s3.avenrun[2] = avrun[2] * FSCALE; 216 mib[0] = CTL_KERN; 217 mib[1] = KERN_BOOTTIME; 218 len = sizeof(btm); 219 if (sysctl(mib, 2, &btm, &len, NULL, 0) < 0) { 220 syslog(LOG_ERR, "can't sysctl kern.boottime"); 221 exit(1); 222 } 223 stats_all.s3.boottime.tv_sec = btm.tv_sec; 224 stats_all.s3.boottime.tv_usec = btm.tv_usec; 225 226 227 #ifdef DEBUG 228 syslog(LOG_DEBUG, "%d %d %d %d %d\n", stats_all.s3.cp_time[0], 229 stats_all.s3.cp_time[1], stats_all.s3.cp_time[2], 230 stats_all.s3.cp_time[3], stats_all.s3.cp_time[4]); 231 #endif 232 233 mib[0] = CTL_VM; 234 mib[1] = VM_UVMEXP2; 235 len = sizeof(uvmexp); 236 if (sysctl(mib, 2, &uvmexp, &len, NULL, 0) < 0) { 237 syslog(LOG_ERR, "can't sysctl vm.uvmexp2"); 238 exit(1); 239 } 240 stats_all.s3.v_pgpgin = uvmexp.fltanget; 241 stats_all.s3.v_pgpgout = uvmexp.pdpageouts; 242 stats_all.s3.v_pswpin = uvmexp.swapins; 243 stats_all.s3.v_pswpout = uvmexp.swapouts; 244 stats_all.s3.v_intr = uvmexp.intrs; 245 stats_all.s3.v_swtch = uvmexp.swtch; 246 gettimeofday(&tm, (struct timezone *) 0); 247 stats_all.s3.v_intr -= hz*(tm.tv_sec - btm.tv_sec) + 248 hz*(tm.tv_usec - btm.tv_usec)/1000000; 249 250 stats_all.s3.if_ipackets = 0; 251 stats_all.s3.if_opackets = 0; 252 stats_all.s3.if_ierrors = 0; 253 stats_all.s3.if_oerrors = 0; 254 stats_all.s3.if_collisions = 0; 255 256 ifps = if_nameindex(); 257 if (ifps == NULL) { 258 syslog(LOG_ERR, "can't read interface list from kernel"); 259 exit(1); 260 } 261 s = socket(AF_INET, SOCK_DGRAM, 0); 262 for (i = 0; s != -1 && ifps[i].if_name != NULL; ++i) { 263 strlcpy(ifdr.ifdr_name, ifps[i].if_name, sizeof(ifdr.ifdr_name)); 264 if (ioctl(s, SIOCGIFDATA, &ifdr) != 0) 265 continue; 266 stats_all.s3.if_ipackets += ifdr.ifdr_data.ifi_ipackets; 267 stats_all.s3.if_opackets += ifdr.ifdr_data.ifi_opackets; 268 stats_all.s3.if_ierrors += ifdr.ifdr_data.ifi_ierrors; 269 stats_all.s3.if_oerrors += ifdr.ifdr_data.ifi_oerrors; 270 stats_all.s3.if_collisions += ifdr.ifdr_data.ifi_collisions; 271 } 272 if (s != -1) 273 close(s); 274 if_freenameindex(ifps); 275 276 stats_all.s3.curtime.tv_sec = tm.tv_sec; 277 stats_all.s3.curtime.tv_usec = tm.tv_usec; 278 alarm(1); 279 } 280 281 /* 282 * returns true if have a disk 283 */ 284 int 285 havedisk(void) 286 { 287 return ndrive != 0; 288 } 289 290 void 291 rstat_service(struct svc_req *rqstp, SVCXPRT *transp) 292 { 293 union { 294 int fill; 295 } argument; 296 char *result; 297 xdrproc_t xdr_argument, xdr_result; 298 char *(*local)(void *, struct svc_req *); 299 300 switch (rqstp->rq_proc) { 301 case NULLPROC: 302 (void)svc_sendreply(transp, (xdrproc_t)xdr_void, NULL); 303 goto leave; 304 305 case RSTATPROC_STATS: 306 xdr_argument = (xdrproc_t)xdr_void; 307 xdr_result = (xdrproc_t)xdr_statstime; 308 switch (rqstp->rq_vers) { 309 case RSTATVERS_ORIG: 310 local = (char *(*)(void *, struct svc_req *)) 311 rstatproc_stats_1_svc; 312 break; 313 case RSTATVERS_SWTCH: 314 local = (char *(*)(void *, struct svc_req *)) 315 rstatproc_stats_2_svc; 316 break; 317 case RSTATVERS_TIME: 318 local = (char *(*)(void *, struct svc_req *)) 319 rstatproc_stats_3_svc; 320 break; 321 default: 322 svcerr_progvers(transp, RSTATVERS_ORIG, RSTATVERS_TIME); 323 goto leave; 324 } 325 break; 326 327 case RSTATPROC_HAVEDISK: 328 xdr_argument = (xdrproc_t)xdr_void; 329 xdr_result = (xdrproc_t)xdr_u_int; 330 switch (rqstp->rq_vers) { 331 case RSTATVERS_ORIG: 332 local = (char *(*)(void *, struct svc_req *)) 333 rstatproc_havedisk_1_svc; 334 break; 335 case RSTATVERS_SWTCH: 336 local = (char *(*)(void *, struct svc_req *)) 337 rstatproc_havedisk_2_svc; 338 break; 339 case RSTATVERS_TIME: 340 local = (char *(*)(void *, struct svc_req *)) 341 rstatproc_havedisk_3_svc; 342 break; 343 default: 344 svcerr_progvers(transp, RSTATVERS_ORIG, RSTATVERS_TIME); 345 goto leave; 346 } 347 break; 348 349 default: 350 svcerr_noproc(transp); 351 goto leave; 352 } 353 memset((char *)&argument, 0, sizeof(argument)); 354 if (!svc_getargs(transp, xdr_argument, (caddr_t)&argument)) { 355 svcerr_decode(transp); 356 goto leave; 357 } 358 result = (*local)(&argument, rqstp); 359 if (result != NULL && !svc_sendreply(transp, xdr_result, result)) { 360 svcerr_systemerr(transp); 361 } 362 if (!svc_freeargs(transp, xdr_argument, (caddr_t)&argument)) { 363 (void)fprintf(stderr, "unable to free arguments\n"); 364 exit(1); 365 } 366 leave: 367 if (from_inetd) 368 exit(0); 369 } 370