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