1 /* $OpenBSD: rstat_proc.c,v 1.20 2001/11/18 23:45:39 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.20 2001/11/18 23:45:39 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 <sys/param.h> 44 #include <sys/vmmeter.h> 45 #include <sys/dkstat.h> 46 #include <sys/socket.h> 47 #include <sys/sysctl.h> 48 #include <net/if.h> 49 #include <uvm/uvm_extern.h> 50 51 #include <stdio.h> 52 #include <stdlib.h> 53 #include <string.h> 54 #include <signal.h> 55 #include <syslog.h> 56 #include <fcntl.h> 57 #include <limits.h> 58 #include <errno.h> 59 #include <ifaddrs.h> 60 #include "dkstats.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 int cp_xlat[CPUSTATES] = { CP_USER, CP_NICE, CP_SYS, CP_IDLE }; 74 75 extern int dk_ndrive; /* from dkstats.c */ 76 extern struct _disk cur, last; 77 char *memf = NULL, *nlistf = NULL; 78 int hz; 79 80 extern int from_inetd; 81 int sincelastreq = 0; /* number of alarms since last request */ 82 extern int closedown; 83 84 union { 85 struct stats s1; 86 struct statsswtch s2; 87 struct statstime s3; 88 } stats_all; 89 90 void updatestat(void); 91 void updatestatsig(int sig); 92 void setup(void); 93 94 volatile sig_atomic_t wantupdatestat; 95 96 static int stat_is_init = 0; 97 98 #ifndef FSCALE 99 #define FSCALE (1 << 8) 100 #endif 101 102 void 103 stat_init() 104 { 105 stat_is_init = 1; 106 setup(); 107 updatestat(); 108 (void) signal(SIGALRM, updatestatsig); 109 alarm(1); 110 } 111 112 statstime * 113 rstatproc_stats_3_svc(arg, rqstp) 114 void *arg; 115 struct svc_req *rqstp; 116 { 117 if (!stat_is_init) 118 stat_init(); 119 sincelastreq = 0; 120 return (&stats_all.s3); 121 } 122 123 statsswtch * 124 rstatproc_stats_2_svc(arg, rqstp) 125 void *arg; 126 struct svc_req *rqstp; 127 { 128 if (!stat_is_init) 129 stat_init(); 130 sincelastreq = 0; 131 return (&stats_all.s2); 132 } 133 134 stats * 135 rstatproc_stats_1_svc(arg, rqstp) 136 void *arg; 137 struct svc_req *rqstp; 138 { 139 if (!stat_is_init) 140 stat_init(); 141 sincelastreq = 0; 142 return (&stats_all.s1); 143 } 144 145 u_int * 146 rstatproc_havedisk_3_svc(arg, rqstp) 147 void *arg; 148 struct svc_req *rqstp; 149 { 150 static u_int have; 151 152 if (!stat_is_init) 153 stat_init(); 154 sincelastreq = 0; 155 have = dk_ndrive != 0; 156 return (&have); 157 } 158 159 u_int * 160 rstatproc_havedisk_2_svc(arg, rqstp) 161 void *arg; 162 struct svc_req *rqstp; 163 { 164 return (rstatproc_havedisk_3_svc(arg, rqstp)); 165 } 166 167 u_int * 168 rstatproc_havedisk_1_svc(arg, rqstp) 169 void *arg; 170 struct svc_req *rqstp; 171 { 172 return (rstatproc_havedisk_3_svc(arg, rqstp)); 173 } 174 175 void 176 updatestatsig(int sig) 177 { 178 wantupdatestat = 1; 179 } 180 181 void 182 updatestat() 183 { 184 int i, mib[2], save_errno = errno; 185 struct uvmexp uvmexp; 186 size_t len; 187 struct if_data *ifdp; 188 struct ifaddrs *ifaddrs, *ifa; 189 double avrun[3]; 190 struct timeval tm, btm; 191 long *cp_time = cur.cp_time; 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 errno = save_errno; 205 return; 206 } 207 } 208 sincelastreq++; 209 210 /* 211 * dkreadstats reads in the "disk_count" as well as the "disklist" 212 * statistics. It also retrieves "hz" and the "cp_time" array. 213 */ 214 dkreadstats(); 215 memset(stats_all.s1.dk_xfer, '\0', sizeof(stats_all.s1.dk_xfer)); 216 for (i = 0; i < dk_ndrive && i < DK_NDRIVE; i++) 217 stats_all.s1.dk_xfer[i] = cur.dk_xfer[i]; 218 219 for (i = 0; i < CPUSTATES; i++) 220 stats_all.s1.cp_time[i] = cp_time[cp_xlat[i]]; 221 (void)getloadavg(avrun, sizeof(avrun) / sizeof(avrun[0])); 222 stats_all.s2.avenrun[0] = avrun[0] * FSCALE; 223 stats_all.s2.avenrun[1] = avrun[1] * FSCALE; 224 stats_all.s2.avenrun[2] = avrun[2] * FSCALE; 225 mib[0] = CTL_KERN; 226 mib[1] = KERN_BOOTTIME; 227 len = sizeof(btm); 228 if (sysctl(mib, 2, &btm, &len, NULL, 0) < 0) { 229 syslog(LOG_ERR, "can't sysctl kern.boottime: %m"); 230 _exit(1); 231 } 232 stats_all.s2.boottime.tv_sec = btm.tv_sec; 233 stats_all.s2.boottime.tv_usec = btm.tv_usec; 234 235 236 #ifdef DEBUG 237 syslog(LOG_DEBUG, "%d %d %d %d", stats_all.s1.cp_time[0], 238 stats_all.s1.cp_time[1], stats_all.s1.cp_time[2], 239 stats_all.s1.cp_time[3]); 240 #endif 241 242 mib[0] = CTL_VM; 243 mib[1] = VM_UVMEXP; 244 len = sizeof(uvmexp); 245 if (sysctl(mib, 2, &uvmexp, &len, NULL, 0) < 0) { 246 syslog(LOG_ERR, "can't sysctl vm.uvmexp: %m"); 247 _exit(1); 248 } 249 stats_all.s1.v_pgpgin = uvmexp.fltanget; 250 stats_all.s1.v_pgpgout = uvmexp.pdpageouts; 251 stats_all.s1.v_pswpin = uvmexp.swapins; 252 stats_all.s1.v_pswpout = uvmexp.swapouts; 253 stats_all.s1.v_intr = uvmexp.intrs; 254 stats_all.s2.v_swtch = uvmexp.swtch; 255 gettimeofday(&tm, (struct timezone *) 0); 256 stats_all.s1.v_intr -= hz*(tm.tv_sec - btm.tv_sec) + 257 hz*(tm.tv_usec - btm.tv_usec)/1000000; 258 stats_all.s1.if_ipackets = 0; 259 stats_all.s1.if_opackets = 0; 260 stats_all.s1.if_ierrors = 0; 261 stats_all.s1.if_oerrors = 0; 262 stats_all.s1.if_collisions = 0; 263 if (getifaddrs(&ifaddrs) == -1) { 264 syslog(LOG_ERR, "can't getifaddrs: %m"); 265 _exit(1); 266 } 267 for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) { 268 if (ifa->ifa_addr->sa_family != AF_LINK) 269 continue; 270 ifdp = (struct if_data *)ifa->ifa_data; 271 stats_all.s1.if_ipackets += ifdp->ifi_ipackets; 272 stats_all.s1.if_opackets += ifdp->ifi_opackets; 273 stats_all.s1.if_ierrors += ifdp->ifi_ierrors; 274 stats_all.s1.if_oerrors += ifdp->ifi_oerrors; 275 stats_all.s1.if_collisions += ifdp->ifi_collisions; 276 } 277 freeifaddrs(ifaddrs); 278 stats_all.s3.curtime.tv_sec = tm.tv_sec; 279 stats_all.s3.curtime.tv_usec = tm.tv_usec; 280 281 alarm(1); 282 errno = save_errno; 283 } 284 285 void 286 setup() 287 { 288 dkinit(0); 289 } 290 291 void 292 rstat_service(rqstp, transp) 293 struct svc_req *rqstp; 294 SVCXPRT *transp; 295 { 296 union { 297 int fill; 298 } argument; 299 char *result; 300 xdrproc_t xdr_argument, xdr_result; 301 char *(*local) __P((void *, struct svc_req *)); 302 303 switch (rqstp->rq_proc) { 304 case NULLPROC: 305 (void)svc_sendreply(transp, xdr_void, (char *)NULL); 306 return; 307 308 case RSTATPROC_STATS: 309 xdr_argument = (xdrproc_t)xdr_void; 310 xdr_result = (xdrproc_t)xdr_statstime; 311 switch (rqstp->rq_vers) { 312 case RSTATVERS_ORIG: 313 local = (char *(*) __P((void *, struct svc_req *))) 314 rstatproc_stats_1_svc; 315 break; 316 case RSTATVERS_SWTCH: 317 local = (char *(*) __P((void *, struct svc_req *))) 318 rstatproc_stats_2_svc; 319 break; 320 case RSTATVERS_TIME: 321 local = (char *(*) __P((void *, struct svc_req *))) 322 rstatproc_stats_3_svc; 323 break; 324 default: 325 svcerr_progvers(transp, RSTATVERS_ORIG, RSTATVERS_TIME); 326 return; 327 } 328 break; 329 330 case RSTATPROC_HAVEDISK: 331 xdr_argument = (xdrproc_t)xdr_void; 332 xdr_result = (xdrproc_t)xdr_u_int; 333 switch (rqstp->rq_vers) { 334 case RSTATVERS_ORIG: 335 local = (char *(*) __P((void *, struct svc_req *))) 336 rstatproc_havedisk_1_svc; 337 break; 338 case RSTATVERS_SWTCH: 339 local = (char *(*) __P((void *, struct svc_req *))) 340 rstatproc_havedisk_2_svc; 341 break; 342 case RSTATVERS_TIME: 343 local = (char *(*) __P((void *, struct svc_req *))) 344 rstatproc_havedisk_3_svc; 345 break; 346 default: 347 svcerr_progvers(transp, RSTATVERS_ORIG, RSTATVERS_TIME); 348 return; 349 } 350 break; 351 352 default: 353 svcerr_noproc(transp); 354 return; 355 } 356 bzero((char *)&argument, sizeof(argument)); 357 if (!svc_getargs(transp, xdr_argument, (caddr_t)&argument)) { 358 svcerr_decode(transp); 359 return; 360 } 361 result = (*local)(&argument, rqstp); 362 if (result != NULL && !svc_sendreply(transp, xdr_result, result)) { 363 svcerr_systemerr(transp); 364 } 365 if (!svc_freeargs(transp, xdr_argument, (caddr_t)&argument)) { 366 syslog(LOG_ERR, "unable to free arguments"); 367 exit(1); 368 } 369 } 370