1147999Semax/* 2147999Semax * Sun RPC is a product of Sun Microsystems, Inc. and is provided for 3147999Semax * unrestricted use provided that this legend is included on all tape 4147999Semax * media and as a part of the software program in whole or part. Users 5147999Semax * may copy or modify Sun RPC without charge, but are not authorized 6147999Semax * to license or distribute it to anyone else except as part of a product or 7147999Semax * program developed by the user. 8147999Semax * 9147999Semax * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE 10147999Semax * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR 11147999Semax * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. 12147999Semax * 13147999Semax * Sun RPC is provided with no support and without any obligation on the 14147999Semax * part of Sun Microsystems, Inc. to assist in its use, correction, 15147999Semax * modification or enhancement. 16147999Semax * 17147999Semax * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE 18147999Semax * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC 19147999Semax * OR ANY PART THEREOF. 20147999Semax * 21147999Semax * In no event will Sun Microsystems, Inc. be liable for any lost revenue 22147999Semax * or profits or other special, indirect and consequential damages, even if 23147999Semax * Sun has been advised of the possibility of such damages. 24147999Semax * 25147999Semax * Sun Microsystems, Inc. 26147999Semax * 2550 Garcia Avenue 27147999Semax * Mountain View, California 94043 28147999Semax */ 29147999Semax 30147999Semax/* 31147999Semax * rstat service: built with rstat.x and derived from rpc.rstatd.c 32147999Semax * 33147999Semax * Copyright (c) 1984 by Sun Microsystems, Inc. 34162711Sru */ 35147999Semax 36298430Semaste#include <sys/types.h> 37147999Semax#include <sys/socket.h> 38147999Semax#include <sys/sysctl.h> 39156167Semax#include <sys/time.h> 40147999Semax#include <sys/resource.h> 41147999Semax#include <sys/param.h> 42147999Semax 43147999Semax#include <err.h> 44147999Semax#include <errno.h> 45147999Semax#include <fcntl.h> 46147999Semax#include <limits.h> 47147999Semax#include <signal.h> 48147999Semax#include <stdio.h> 49147999Semax#include <stdlib.h> 50147999Semax#include <string.h> 51147999Semax#include <syslog.h> 52147999Semax#include <unistd.h> 53147999Semax#include <devstat.h> 54147999Semax 55147999Semax#include <net/if.h> 56147999Semax#include <net/if_mib.h> 57147999Semax 58298430Semaste#undef FSHIFT /* Use protocol's shift and scale values */ 59298430Semaste#undef FSCALE 60298430Semaste#undef if_ipackets 61298430Semaste#undef if_ierrors 62298430Semaste#undef if_opackets 63298430Semaste#undef if_oerrors 64298430Semaste#undef if_collisions 65147999Semax#include <rpcsvc/rstat.h> 66147999Semax 67147999Semaxint haveadisk(void); 68147999Semaxvoid updatexfers(int, int *); 69147999Semaxint stats_service(void); 70147999Semax 71147999Semaxextern int from_inetd; 72147999Semaxint sincelastreq = 0; /* number of alarms since last request */ 73147999Semaxextern int closedown; 74147999Semax 75147999Semaxunion { 76147999Semax struct stats s1; 77147999Semax struct statsswtch s2; 78147999Semax struct statstime s3; 79147999Semax} stats_all; 80147999Semax 81147999Semaxvoid updatestat(); 82147999Semaxstatic int stat_is_init = 0; 83147999Semax 84147999Semaxstatic int cp_time_xlat[RSTAT_CPUSTATES] = { CP_USER, CP_NICE, CP_SYS, 85147999Semax CP_IDLE }; 86147999Semaxstatic long bsd_cp_time[CPUSTATES]; 87147999Semax 88147999Semax 89147999Semax#ifndef FSCALE 90147999Semax#define FSCALE (1 << 8) 91147999Semax#endif 92147999Semax 93147999Semaxvoid 94147999Semaxstat_init(void) 95147999Semax{ 96147999Semax stat_is_init = 1; 97147999Semax alarm(0); 98147999Semax updatestat(); 99147999Semax (void) signal(SIGALRM, updatestat); 100147999Semax alarm(1); 101147999Semax} 102147999Semax 103147999Semaxstatstime * 104147999Semaxrstatproc_stats_3_svc(void *argp, struct svc_req *rqstp) 105147999Semax{ 106147999Semax if (! stat_is_init) 107147999Semax stat_init(); 108147999Semax sincelastreq = 0; 109147999Semax return(&stats_all.s3); 110147999Semax} 111147999Semax 112147999Semaxstatsswtch * 113147999Semaxrstatproc_stats_2_svc(void *argp, struct svc_req *rqstp) 114190857Semax{ 115190857Semax if (! stat_is_init) 116190857Semax stat_init(); 117190857Semax sincelastreq = 0; 118147999Semax return(&stats_all.s2); 119147999Semax} 120147999Semax 121147999Semaxstats * 122147999Semaxrstatproc_stats_1_svc(void *argp, struct svc_req *rqstp) 123147999Semax{ 124147999Semax if (! stat_is_init) 125147999Semax stat_init(); 126147999Semax sincelastreq = 0; 127147999Semax return(&stats_all.s1); 128147999Semax} 129147999Semax 130147999Semaxu_int * 131147999Semaxrstatproc_havedisk_3_svc(void *argp, struct svc_req *rqstp) 132147999Semax{ 133147999Semax static u_int have; 134147999Semax 135147999Semax if (! stat_is_init) 136147999Semax stat_init(); 137147999Semax sincelastreq = 0; 138147999Semax have = haveadisk(); 139147999Semax return(&have); 140147999Semax} 141147999Semax 142147999Semaxu_int * 143147999Semaxrstatproc_havedisk_2_svc(void *argp, struct svc_req *rqstp) 144193512Sed{ 145193512Sed return(rstatproc_havedisk_3_svc(argp, rqstp)); 146193512Sed} 147147999Semax 148147999Semaxu_int * 149147999Semaxrstatproc_havedisk_1_svc(void *argp, struct svc_req *rqstp) 150147999Semax{ 151147999Semax return(rstatproc_havedisk_3_svc(argp, rqstp)); 152147999Semax} 153147999Semax 154147999Semaxvoid 155147999Semaxupdatestat(void) 156147999Semax{ 157147999Semax int i, hz; 158147999Semax struct clockinfo clockrate; 159147999Semax struct ifmibdata ifmd; 160147999Semax double avrun[3]; 161147999Semax struct timeval tm, btm; 162147999Semax int mib[6]; 163147999Semax size_t len; 164147999Semax uint64_t val; 165147999Semax int ifcount; 166147999Semax 167147999Semax#ifdef DEBUG 168147999Semax fprintf(stderr, "entering updatestat\n"); 169147999Semax#endif 170147999Semax if (sincelastreq >= closedown) { 171147999Semax#ifdef DEBUG 172147999Semax fprintf(stderr, "about to closedown\n"); 173147999Semax#endif 174147999Semax if (from_inetd) 175147999Semax exit(0); 176147999Semax else { 177147999Semax stat_is_init = 0; 178147999Semax return; 179193512Sed } 180193512Sed } 181193512Sed sincelastreq++; 182193512Sed 183193512Sed mib[0] = CTL_KERN; 184193512Sed mib[1] = KERN_CLOCKRATE; 185193512Sed len = sizeof clockrate; 186193512Sed if (sysctl(mib, 2, &clockrate, &len, 0, 0) < 0) { 187193512Sed syslog(LOG_ERR, "sysctl(kern.clockrate): %m"); 188193512Sed exit(1); 189193512Sed } 190193512Sed hz = clockrate.hz; 191193512Sed 192193752Sed len = sizeof(bsd_cp_time); 193193512Sed if (sysctlbyname("kern.cp_time", bsd_cp_time, &len, 0, 0) < 0) { 194193512Sed syslog(LOG_ERR, "sysctl(kern.cp_time): %m"); 195193752Sed exit(1); 196193512Sed } 197193512Sed for(i = 0; i < RSTAT_CPUSTATES ; i++) 198193512Sed stats_all.s1.cp_time[i] = bsd_cp_time[cp_time_xlat[i]]; 199193512Sed 200193512Sed (void)getloadavg(avrun, sizeof(avrun) / sizeof(avrun[0])); 201193512Sed 202193512Sed stats_all.s2.avenrun[0] = avrun[0] * FSCALE; 203193512Sed stats_all.s2.avenrun[1] = avrun[1] * FSCALE; 204193512Sed stats_all.s2.avenrun[2] = avrun[2] * FSCALE; 205193512Sed 206193512Sed mib[0] = CTL_KERN; 207147999Semax mib[1] = KERN_BOOTTIME; 208147999Semax len = sizeof btm; 209147999Semax if (sysctl(mib, 2, &btm, &len, 0, 0) < 0) { 210147999Semax syslog(LOG_ERR, "sysctl(kern.boottime): %m"); 211147999Semax exit(1); 212147999Semax } 213147999Semax 214147999Semax stats_all.s2.boottime.tv_sec = btm.tv_sec; 215147999Semax stats_all.s2.boottime.tv_usec = btm.tv_usec; 216174984Swkoszek 217147999Semax 218147999Semax#ifdef DEBUG 219147999Semax fprintf(stderr, "%d %d %d %d\n", stats_all.s1.cp_time[0], 220147999Semax stats_all.s1.cp_time[1], stats_all.s1.cp_time[2], stats_all.s1.cp_time[3]); 221147999Semax#endif 222147999Semax 223147999Semax#define FETCH_CNT(stat, cnt) do { \ 224147999Semax len = sizeof(uint64_t); \ 225147999Semax if (sysctlbyname("vm.stats." #cnt , &val, &len, NULL, 0) < 0) { \ 226147999Semax syslog(LOG_ERR, "sysctl(vm.stats." #cnt "): %m"); \ 227147999Semax exit(1); \ 228147999Semax } \ 229147999Semax stat = val; \ 230147999Semax} while (0) 231147999Semax 232147999Semax FETCH_CNT(stats_all.s1.v_pgpgin, vm.v_vnodepgsin); 233147999Semax FETCH_CNT(stats_all.s1.v_pgpgout, vm.v_vnodepgsout); 234147999Semax FETCH_CNT(stats_all.s1.v_pswpin, vm.v_swappgsin); 235147999Semax FETCH_CNT(stats_all.s1.v_pswpout, vm.v_swappgsout); 236147999Semax FETCH_CNT(stats_all.s1.v_intr, sys.v_intr); 237147999Semax FETCH_CNT(stats_all.s2.v_swtch, sys.v_swtch); 238147999Semax (void)gettimeofday(&tm, NULL); 239147999Semax stats_all.s1.v_intr -= hz*(tm.tv_sec - btm.tv_sec) + 240147999Semax hz*(tm.tv_usec - btm.tv_usec)/1000000; 241147999Semax 242147999Semax /* update disk transfers */ 243147999Semax updatexfers(RSTAT_DK_NDRIVE, stats_all.s1.dk_xfer); 244147999Semax 245193512Sed mib[0] = CTL_NET; 246147999Semax mib[1] = PF_LINK; 247147999Semax mib[2] = NETLINK_GENERIC; 248147999Semax mib[3] = IFMIB_SYSTEM; 249147999Semax mib[4] = IFMIB_IFCOUNT; 250147999Semax len = sizeof ifcount; 251147999Semax if (sysctl(mib, 5, &ifcount, &len, 0, 0) < 0) { 252147999Semax syslog(LOG_ERR, "sysctl(net.link.generic.system.ifcount): %m"); 253147999Semax exit(1); 254147999Semax } 255147999Semax 256147999Semax stats_all.s1.if_ipackets = 0; 257147999Semax stats_all.s1.if_opackets = 0; 258147999Semax stats_all.s1.if_ierrors = 0; 259147999Semax stats_all.s1.if_oerrors = 0; 260147999Semax stats_all.s1.if_collisions = 0; 261147999Semax for (i = 1; i <= ifcount; i++) { 262147999Semax len = sizeof ifmd; 263147999Semax mib[3] = IFMIB_IFDATA; 264147999Semax mib[4] = i; 265147999Semax mib[5] = IFDATA_GENERAL; 266147999Semax if (sysctl(mib, 6, &ifmd, &len, 0, 0) < 0) { 267156013Semax if (errno == ENOENT) 268156013Semax continue; 269156013Semax 270156013Semax syslog(LOG_ERR, "sysctl(net.link.ifdata.%d.general)" 271156013Semax ": %m", i); 272156013Semax exit(1); 273156013Semax } 274156013Semax 275156013Semax stats_all.s1.if_ipackets += ifmd.ifmd_data.ifi_ipackets; 276156013Semax stats_all.s1.if_opackets += ifmd.ifmd_data.ifi_opackets; 277174984Swkoszek stats_all.s1.if_ierrors += ifmd.ifmd_data.ifi_ierrors; 278174984Swkoszek stats_all.s1.if_oerrors += ifmd.ifmd_data.ifi_oerrors; 279147999Semax stats_all.s1.if_collisions += ifmd.ifmd_data.ifi_collisions; 280156010Semax } 281147999Semax (void)gettimeofday(&tm, NULL); 282147999Semax stats_all.s3.curtime.tv_sec = tm.tv_sec; 283147999Semax stats_all.s3.curtime.tv_usec = tm.tv_usec; 284147999Semax alarm(1); 285147999Semax} 286193512Sed 287147999Semax/* 288147999Semax * returns true if have a disk 289147999Semax */ 290193512Sedint 291147999Semaxhaveadisk(void) 292147999Semax{ 293147999Semax register int i; 294147999Semax struct statinfo stats; 295147999Semax int num_devices, retval = 0; 296147999Semax 297147999Semax if ((num_devices = devstat_getnumdevs(NULL)) < 0) { 298147999Semax syslog(LOG_ERR, "rstatd: can't get number of devices: %s", 299147999Semax devstat_errbuf); 300147999Semax exit(1); 301147999Semax } 302147999Semax 303147999Semax if (devstat_checkversion(NULL) < 0) { 304147999Semax syslog(LOG_ERR, "rstatd: %s", devstat_errbuf); 305147999Semax exit(1); 306147999Semax } 307147999Semax 308147999Semax stats.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo)); 309147999Semax bzero(stats.dinfo, sizeof(struct devinfo)); 310147999Semax 311147999Semax if (devstat_getdevs(NULL, &stats) == -1) { 312147999Semax syslog(LOG_ERR, "rstatd: can't get device list: %s", 313147999Semax devstat_errbuf); 314147999Semax exit(1); 315147999Semax } 316147999Semax for (i = 0; i < stats.dinfo->numdevs; i++) { 317147999Semax if (((stats.dinfo->devices[i].device_type 318147999Semax & DEVSTAT_TYPE_MASK) == DEVSTAT_TYPE_DIRECT) 319147999Semax && ((stats.dinfo->devices[i].device_type 320147999Semax & DEVSTAT_TYPE_PASS) == 0)) { 321147999Semax retval = 1; 322147999Semax break; 323147999Semax } 324147999Semax } 325147999Semax 326147999Semax if (stats.dinfo->mem_ptr) 327147999Semax free(stats.dinfo->mem_ptr); 328147999Semax 329147999Semax free(stats.dinfo); 330147999Semax return(retval); 331147999Semax} 332147999Semax 333147999Semaxvoid 334147999Semaxupdatexfers(int numdevs, int *devs) 335147999Semax{ 336147999Semax register int i, j, k, t; 337147999Semax struct statinfo stats; 338147999Semax int num_devices = 0; 339147999Semax u_int64_t total_transfers; 340147999Semax 341147999Semax if ((num_devices = devstat_getnumdevs(NULL)) < 0) { 342147999Semax syslog(LOG_ERR, "rstatd: can't get number of devices: %s", 343147999Semax devstat_errbuf); 344147999Semax exit(1); 345147999Semax } 346147999Semax 347147999Semax if (devstat_checkversion(NULL) < 0) { 348147999Semax syslog(LOG_ERR, "rstatd: %s", devstat_errbuf); 349147999Semax exit(1); 350147999Semax } 351147999Semax 352147999Semax stats.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo)); 353147999Semax bzero(stats.dinfo, sizeof(struct devinfo)); 354147999Semax 355147999Semax if (devstat_getdevs(NULL, &stats) == -1) { 356147999Semax syslog(LOG_ERR, "rstatd: can't get device list: %s", 357147999Semax devstat_errbuf); 358147999Semax exit(1); 359147999Semax } 360147999Semax 361147999Semax for (i = 0, j = 0; i < stats.dinfo->numdevs && j < numdevs; i++) { 362147999Semax if (((stats.dinfo->devices[i].device_type 363147999Semax & DEVSTAT_TYPE_MASK) == DEVSTAT_TYPE_DIRECT) 364147999Semax && ((stats.dinfo->devices[i].device_type 365147999Semax & DEVSTAT_TYPE_PASS) == 0)) { 366147999Semax total_transfers = 0; 367147999Semax for (k = 0; k < DEVSTAT_N_TRANS_FLAGS; k++) 368147999Semax total_transfers += 369147999Semax stats.dinfo->devices[i].operations[k]; 370147999Semax /* 371147999Semax * XXX KDM If the total transfers for this device 372147999Semax * are greater than the amount we can fit in a 373147999Semax * signed integer, just set them to the maximum 374147999Semax * amount we can fit in a signed integer. I have a 375147999Semax * feeling that the rstat protocol assumes 32-bit 376147999Semax * integers, so this could well break on a 64-bit 377147999Semax * architecture like the Alpha. 378147999Semax */ 379147999Semax if (total_transfers > INT_MAX) 380147999Semax t = INT_MAX; 381147999Semax else 382147999Semax t = total_transfers; 383147999Semax devs[j] = t; 384147999Semax j++; 385147999Semax } 386147999Semax } 387147999Semax 388147999Semax if (stats.dinfo->mem_ptr) 389241885Seadler free(stats.dinfo->mem_ptr); 390241885Seadler 391156167Semax free(stats.dinfo); 392147999Semax} 393147999Semax 394147999Semaxvoid 395147999Semaxrstat_service(struct svc_req *rqstp, SVCXPRT *transp) 396147999Semax{ 397147999Semax union { 398147999Semax int fill; 399147999Semax } argument; 400147999Semax void *result; 401147999Semax xdrproc_t xdr_argument, xdr_result; 402147999Semax typedef void *(svc_cb)(void *arg, struct svc_req *rqstp); 403147999Semax svc_cb *local; 404147999Semax 405147999Semax switch (rqstp->rq_proc) { 406147999Semax case NULLPROC: 407147999Semax (void)svc_sendreply(transp, (xdrproc_t)xdr_void, NULL); 408147999Semax goto leave; 409147999Semax 410147999Semax case RSTATPROC_STATS: 411147999Semax xdr_argument = (xdrproc_t)xdr_void; 412147999Semax xdr_result = (xdrproc_t)xdr_statstime; 413147999Semax switch (rqstp->rq_vers) { 414147999Semax case RSTATVERS_ORIG: 415147999Semax local = (svc_cb *)rstatproc_stats_1_svc; 416147999Semax break; 417147999Semax case RSTATVERS_SWTCH: 418147999Semax local = (svc_cb *)rstatproc_stats_2_svc; 419147999Semax break; 420147999Semax case RSTATVERS_TIME: 421147999Semax local = (svc_cb *)rstatproc_stats_3_svc; 422147999Semax break; 423147999Semax default: 424147999Semax svcerr_progvers(transp, RSTATVERS_ORIG, RSTATVERS_TIME); 425147999Semax goto leave; 426147999Semax /*NOTREACHED*/ 427147999Semax } 428147999Semax break; 429147999Semax 430147999Semax case RSTATPROC_HAVEDISK: 431147999Semax xdr_argument = (xdrproc_t)xdr_void; 432147999Semax xdr_result = (xdrproc_t)xdr_u_int; 433147999Semax switch (rqstp->rq_vers) { 434147999Semax case RSTATVERS_ORIG: 435147999Semax local = (svc_cb *)rstatproc_havedisk_1_svc; 436147999Semax break; 437147999Semax case RSTATVERS_SWTCH: 438147999Semax local = (svc_cb *)rstatproc_havedisk_2_svc; 439147999Semax break; 440147999Semax case RSTATVERS_TIME: 441147999Semax local = (svc_cb *)rstatproc_havedisk_3_svc; 442147999Semax break; 443147999Semax default: 444147999Semax svcerr_progvers(transp, RSTATVERS_ORIG, RSTATVERS_TIME); 445147999Semax goto leave; 446147999Semax /*NOTREACHED*/ 447147999Semax } 448147999Semax break; 449147999Semax 450147999Semax default: 451147999Semax svcerr_noproc(transp); 452147999Semax goto leave; 453147999Semax } 454147999Semax bzero((char *)&argument, sizeof(argument)); 455147999Semax if (!svc_getargs(transp, xdr_argument, &argument)) { 456147999Semax svcerr_decode(transp); 457147999Semax goto leave; 458147999Semax } 459147999Semax result = (*local)(&argument, rqstp); 460147999Semax if (result != NULL && 461147999Semax !svc_sendreply(transp, xdr_result, result)) { 462147999Semax svcerr_systemerr(transp); 463147999Semax } 464147999Semax if (!svc_freeargs(transp, xdr_argument, &argument)) 465147999Semax errx(1, "unable to free arguments"); 466147999Semaxleave: 467147999Semax if (from_inetd) 468147999Semax exit(0); 469147999Semax} 470147999Semax