1 /* 2 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for 3 * unrestricted use provided that this legend is included on all tape 4 * media and as a part of the software program in whole or part. Users 5 * may copy or modify Sun RPC without charge, but are not authorized 6 * to license or distribute it to anyone else except as part of a product or 7 * program developed by the user. 8 * 9 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE 10 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR 11 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. 12 * 13 * Sun RPC is provided with no support and without any obligation on the 14 * part of Sun Microsystems, Inc. to assist in its use, correction, 15 * modification or enhancement. 16 * 17 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE 18 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC 19 * OR ANY PART THEREOF. 20 * 21 * In no event will Sun Microsystems, Inc. be liable for any lost revenue 22 * or profits or other special, indirect and consequential damages, even if 23 * Sun has been advised of the possibility of such damages. 24 * 25 * Sun Microsystems, Inc. 26 * 2550 Garcia Avenue 27 * Mountain View, California 94043 28 */ 29 30 #ifndef lint 31 #endif 32 33 /* 34 * rstat service: built with rstat.x and derived from rpc.rstatd.c 35 * 36 * Copyright (c) 1984 by Sun Microsystems, Inc. 37 */ 38 39 #include <sys/types.h> 40 #include <sys/socket.h> 41 #include <sys/sysctl.h> 42 #include <sys/time.h> 43 #include <sys/resource.h> 44 #include <sys/param.h> 45 46 #include <err.h> 47 #include <errno.h> 48 #include <fcntl.h> 49 #include <limits.h> 50 #include <signal.h> 51 #include <stdio.h> 52 #include <stdlib.h> 53 #include <string.h> 54 #include <syslog.h> 55 #include <unistd.h> 56 #include <devstat.h> 57 58 #include <net/if.h> 59 #include <net/if_mib.h> 60 61 #undef FSHIFT /* Use protocol's shift and scale values */ 62 #undef FSCALE 63 #undef if_ipackets 64 #undef if_ierrors 65 #undef if_opackets 66 #undef if_oerrors 67 #undef if_collisions 68 #include <rpcsvc/rstat.h> 69 70 int haveadisk(void); 71 void updatexfers(int, int *); 72 int stats_service(void); 73 74 extern int from_inetd; 75 int sincelastreq = 0; /* number of alarms since last request */ 76 extern int closedown; 77 78 union { 79 struct stats s1; 80 struct statsswtch s2; 81 struct statstime s3; 82 } stats_all; 83 84 void updatestat(); 85 static int stat_is_init = 0; 86 87 static int cp_time_xlat[RSTAT_CPUSTATES] = { CP_USER, CP_NICE, CP_SYS, 88 CP_IDLE }; 89 static long bsd_cp_time[CPUSTATES]; 90 91 92 #ifndef FSCALE 93 #define FSCALE (1 << 8) 94 #endif 95 96 void 97 stat_init(void) 98 { 99 stat_is_init = 1; 100 alarm(0); 101 updatestat(); 102 (void) signal(SIGALRM, updatestat); 103 alarm(1); 104 } 105 106 statstime * 107 rstatproc_stats_3_svc(void *argp, struct svc_req *rqstp) 108 { 109 if (! stat_is_init) 110 stat_init(); 111 sincelastreq = 0; 112 return(&stats_all.s3); 113 } 114 115 statsswtch * 116 rstatproc_stats_2_svc(void *argp, struct svc_req *rqstp) 117 { 118 if (! stat_is_init) 119 stat_init(); 120 sincelastreq = 0; 121 return(&stats_all.s2); 122 } 123 124 stats * 125 rstatproc_stats_1_svc(void *argp, struct svc_req *rqstp) 126 { 127 if (! stat_is_init) 128 stat_init(); 129 sincelastreq = 0; 130 return(&stats_all.s1); 131 } 132 133 u_int * 134 rstatproc_havedisk_3_svc(void *argp, struct svc_req *rqstp) 135 { 136 static u_int have; 137 138 if (! stat_is_init) 139 stat_init(); 140 sincelastreq = 0; 141 have = haveadisk(); 142 return(&have); 143 } 144 145 u_int * 146 rstatproc_havedisk_2_svc(void *argp, struct svc_req *rqstp) 147 { 148 return(rstatproc_havedisk_3_svc(argp, rqstp)); 149 } 150 151 u_int * 152 rstatproc_havedisk_1_svc(void *argp, struct svc_req *rqstp) 153 { 154 return(rstatproc_havedisk_3_svc(argp, rqstp)); 155 } 156 157 void 158 updatestat(void) 159 { 160 int i, hz; 161 struct clockinfo clockrate; 162 struct ifmibdata ifmd; 163 double avrun[3]; 164 struct timeval tm, btm; 165 int mib[6]; 166 size_t len; 167 uint64_t val; 168 int ifcount; 169 170 #ifdef DEBUG 171 fprintf(stderr, "entering updatestat\n"); 172 #endif 173 if (sincelastreq >= closedown) { 174 #ifdef DEBUG 175 fprintf(stderr, "about to closedown\n"); 176 #endif 177 if (from_inetd) 178 exit(0); 179 else { 180 stat_is_init = 0; 181 return; 182 } 183 } 184 sincelastreq++; 185 186 mib[0] = CTL_KERN; 187 mib[1] = KERN_CLOCKRATE; 188 len = sizeof clockrate; 189 if (sysctl(mib, 2, &clockrate, &len, 0, 0) < 0) { 190 syslog(LOG_ERR, "sysctl(kern.clockrate): %m"); 191 exit(1); 192 } 193 hz = clockrate.hz; 194 195 len = sizeof(bsd_cp_time); 196 if (sysctlbyname("kern.cp_time", bsd_cp_time, &len, 0, 0) < 0) { 197 syslog(LOG_ERR, "sysctl(kern.cp_time): %m"); 198 exit(1); 199 } 200 for(i = 0; i < RSTAT_CPUSTATES ; i++) 201 stats_all.s1.cp_time[i] = bsd_cp_time[cp_time_xlat[i]]; 202 203 (void)getloadavg(avrun, sizeof(avrun) / sizeof(avrun[0])); 204 205 stats_all.s2.avenrun[0] = avrun[0] * FSCALE; 206 stats_all.s2.avenrun[1] = avrun[1] * FSCALE; 207 stats_all.s2.avenrun[2] = avrun[2] * FSCALE; 208 209 mib[0] = CTL_KERN; 210 mib[1] = KERN_BOOTTIME; 211 len = sizeof btm; 212 if (sysctl(mib, 2, &btm, &len, 0, 0) < 0) { 213 syslog(LOG_ERR, "sysctl(kern.boottime): %m"); 214 exit(1); 215 } 216 217 stats_all.s2.boottime.tv_sec = btm.tv_sec; 218 stats_all.s2.boottime.tv_usec = btm.tv_usec; 219 220 221 #ifdef DEBUG 222 fprintf(stderr, "%d %d %d %d\n", stats_all.s1.cp_time[0], 223 stats_all.s1.cp_time[1], stats_all.s1.cp_time[2], stats_all.s1.cp_time[3]); 224 #endif 225 226 #define FETCH_CNT(stat, cnt) do { \ 227 len = sizeof(uint64_t); \ 228 if (sysctlbyname("vm.stats." #cnt , &val, &len, NULL, 0) < 0) { \ 229 syslog(LOG_ERR, "sysctl(vm.stats." #cnt "): %m"); \ 230 exit(1); \ 231 } \ 232 stat = val; \ 233 } while (0) 234 235 FETCH_CNT(stats_all.s1.v_pgpgin, vm.v_vnodepgsin); 236 FETCH_CNT(stats_all.s1.v_pgpgout, vm.v_vnodepgsout); 237 FETCH_CNT(stats_all.s1.v_pswpin, vm.v_swappgsin); 238 FETCH_CNT(stats_all.s1.v_pswpout, vm.v_swappgsout); 239 FETCH_CNT(stats_all.s1.v_intr, sys.v_intr); 240 FETCH_CNT(stats_all.s2.v_swtch, sys.v_swtch); 241 (void)gettimeofday(&tm, NULL); 242 stats_all.s1.v_intr -= hz*(tm.tv_sec - btm.tv_sec) + 243 hz*(tm.tv_usec - btm.tv_usec)/1000000; 244 245 /* update disk transfers */ 246 updatexfers(RSTAT_DK_NDRIVE, stats_all.s1.dk_xfer); 247 248 mib[0] = CTL_NET; 249 mib[1] = PF_LINK; 250 mib[2] = NETLINK_GENERIC; 251 mib[3] = IFMIB_SYSTEM; 252 mib[4] = IFMIB_IFCOUNT; 253 len = sizeof ifcount; 254 if (sysctl(mib, 5, &ifcount, &len, 0, 0) < 0) { 255 syslog(LOG_ERR, "sysctl(net.link.generic.system.ifcount): %m"); 256 exit(1); 257 } 258 259 stats_all.s1.if_ipackets = 0; 260 stats_all.s1.if_opackets = 0; 261 stats_all.s1.if_ierrors = 0; 262 stats_all.s1.if_oerrors = 0; 263 stats_all.s1.if_collisions = 0; 264 for (i = 1; i <= ifcount; i++) { 265 len = sizeof ifmd; 266 mib[3] = IFMIB_IFDATA; 267 mib[4] = i; 268 mib[5] = IFDATA_GENERAL; 269 if (sysctl(mib, 6, &ifmd, &len, 0, 0) < 0) { 270 if (errno == ENOENT) 271 continue; 272 273 syslog(LOG_ERR, "sysctl(net.link.ifdata.%d.general)" 274 ": %m", i); 275 exit(1); 276 } 277 278 stats_all.s1.if_ipackets += ifmd.ifmd_data.ifi_ipackets; 279 stats_all.s1.if_opackets += ifmd.ifmd_data.ifi_opackets; 280 stats_all.s1.if_ierrors += ifmd.ifmd_data.ifi_ierrors; 281 stats_all.s1.if_oerrors += ifmd.ifmd_data.ifi_oerrors; 282 stats_all.s1.if_collisions += ifmd.ifmd_data.ifi_collisions; 283 } 284 (void)gettimeofday(&tm, NULL); 285 stats_all.s3.curtime.tv_sec = tm.tv_sec; 286 stats_all.s3.curtime.tv_usec = tm.tv_usec; 287 alarm(1); 288 } 289 290 /* 291 * returns true if have a disk 292 */ 293 int 294 haveadisk(void) 295 { 296 register int i; 297 struct statinfo stats; 298 int num_devices, retval = 0; 299 300 if ((num_devices = devstat_getnumdevs(NULL)) < 0) { 301 syslog(LOG_ERR, "rstatd: can't get number of devices: %s", 302 devstat_errbuf); 303 exit(1); 304 } 305 306 if (devstat_checkversion(NULL) < 0) { 307 syslog(LOG_ERR, "rstatd: %s", devstat_errbuf); 308 exit(1); 309 } 310 311 stats.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo)); 312 bzero(stats.dinfo, sizeof(struct devinfo)); 313 314 if (devstat_getdevs(NULL, &stats) == -1) { 315 syslog(LOG_ERR, "rstatd: can't get device list: %s", 316 devstat_errbuf); 317 exit(1); 318 } 319 for (i = 0; i < stats.dinfo->numdevs; i++) { 320 if (((stats.dinfo->devices[i].device_type 321 & DEVSTAT_TYPE_MASK) == DEVSTAT_TYPE_DIRECT) 322 && ((stats.dinfo->devices[i].device_type 323 & DEVSTAT_TYPE_PASS) == 0)) { 324 retval = 1; 325 break; 326 } 327 } 328 329 if (stats.dinfo->mem_ptr) 330 free(stats.dinfo->mem_ptr); 331 332 free(stats.dinfo); 333 return(retval); 334 } 335 336 void 337 updatexfers(int numdevs, int *devs) 338 { 339 register int i, j, k, t; 340 struct statinfo stats; 341 int num_devices = 0; 342 u_int64_t total_transfers; 343 344 if ((num_devices = devstat_getnumdevs(NULL)) < 0) { 345 syslog(LOG_ERR, "rstatd: can't get number of devices: %s", 346 devstat_errbuf); 347 exit(1); 348 } 349 350 if (devstat_checkversion(NULL) < 0) { 351 syslog(LOG_ERR, "rstatd: %s", devstat_errbuf); 352 exit(1); 353 } 354 355 stats.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo)); 356 bzero(stats.dinfo, sizeof(struct devinfo)); 357 358 if (devstat_getdevs(NULL, &stats) == -1) { 359 syslog(LOG_ERR, "rstatd: can't get device list: %s", 360 devstat_errbuf); 361 exit(1); 362 } 363 364 for (i = 0, j = 0; i < stats.dinfo->numdevs && j < numdevs; i++) { 365 if (((stats.dinfo->devices[i].device_type 366 & DEVSTAT_TYPE_MASK) == DEVSTAT_TYPE_DIRECT) 367 && ((stats.dinfo->devices[i].device_type 368 & DEVSTAT_TYPE_PASS) == 0)) { 369 total_transfers = 0; 370 for (k = 0; k < DEVSTAT_N_TRANS_FLAGS; k++) 371 total_transfers += 372 stats.dinfo->devices[i].operations[k]; 373 /* 374 * XXX KDM If the total transfers for this device 375 * are greater than the amount we can fit in a 376 * signed integer, just set them to the maximum 377 * amount we can fit in a signed integer. I have a 378 * feeling that the rstat protocol assumes 32-bit 379 * integers, so this could well break on a 64-bit 380 * architecture like the Alpha. 381 */ 382 if (total_transfers > INT_MAX) 383 t = INT_MAX; 384 else 385 t = total_transfers; 386 devs[j] = t; 387 j++; 388 } 389 } 390 391 if (stats.dinfo->mem_ptr) 392 free(stats.dinfo->mem_ptr); 393 394 free(stats.dinfo); 395 } 396 397 void 398 rstat_service(struct svc_req *rqstp, SVCXPRT *transp) 399 { 400 union { 401 int fill; 402 } argument; 403 void *result; 404 xdrproc_t xdr_argument, xdr_result; 405 typedef void *(svc_cb)(void *arg, struct svc_req *rqstp); 406 svc_cb *local; 407 408 switch (rqstp->rq_proc) { 409 case NULLPROC: 410 (void)svc_sendreply(transp, (xdrproc_t)xdr_void, NULL); 411 goto leave; 412 413 case RSTATPROC_STATS: 414 xdr_argument = (xdrproc_t)xdr_void; 415 xdr_result = (xdrproc_t)xdr_statstime; 416 switch (rqstp->rq_vers) { 417 case RSTATVERS_ORIG: 418 local = (svc_cb *)rstatproc_stats_1_svc; 419 break; 420 case RSTATVERS_SWTCH: 421 local = (svc_cb *)rstatproc_stats_2_svc; 422 break; 423 case RSTATVERS_TIME: 424 local = (svc_cb *)rstatproc_stats_3_svc; 425 break; 426 default: 427 svcerr_progvers(transp, RSTATVERS_ORIG, RSTATVERS_TIME); 428 goto leave; 429 /*NOTREACHED*/ 430 } 431 break; 432 433 case RSTATPROC_HAVEDISK: 434 xdr_argument = (xdrproc_t)xdr_void; 435 xdr_result = (xdrproc_t)xdr_u_int; 436 switch (rqstp->rq_vers) { 437 case RSTATVERS_ORIG: 438 local = (svc_cb *)rstatproc_havedisk_1_svc; 439 break; 440 case RSTATVERS_SWTCH: 441 local = (svc_cb *)rstatproc_havedisk_2_svc; 442 break; 443 case RSTATVERS_TIME: 444 local = (svc_cb *)rstatproc_havedisk_3_svc; 445 break; 446 default: 447 svcerr_progvers(transp, RSTATVERS_ORIG, RSTATVERS_TIME); 448 goto leave; 449 /*NOTREACHED*/ 450 } 451 break; 452 453 default: 454 svcerr_noproc(transp); 455 goto leave; 456 } 457 bzero((char *)&argument, sizeof(argument)); 458 if (!svc_getargs(transp, xdr_argument, &argument)) { 459 svcerr_decode(transp); 460 goto leave; 461 } 462 result = (*local)(&argument, rqstp); 463 if (result != NULL && 464 !svc_sendreply(transp, xdr_result, result)) { 465 svcerr_systemerr(transp); 466 } 467 if (!svc_freeargs(transp, xdr_argument, &argument)) 468 errx(1, "unable to free arguments"); 469 leave: 470 if (from_inetd) 471 exit(0); 472 } 473