12334Scsgr/* 22334Scsgr * Sun RPC is a product of Sun Microsystems, Inc. and is provided for 32334Scsgr * unrestricted use provided that this legend is included on all tape 42334Scsgr * media and as a part of the software program in whole or part. Users 52334Scsgr * may copy or modify Sun RPC without charge, but are not authorized 62334Scsgr * to license or distribute it to anyone else except as part of a product or 72334Scsgr * program developed by the user. 82334Scsgr * 92334Scsgr * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE 102334Scsgr * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR 112334Scsgr * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. 122334Scsgr * 132334Scsgr * Sun RPC is provided with no support and without any obligation on the 142334Scsgr * part of Sun Microsystems, Inc. to assist in its use, correction, 152334Scsgr * modification or enhancement. 162334Scsgr * 172334Scsgr * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE 182334Scsgr * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC 192334Scsgr * OR ANY PART THEREOF. 202334Scsgr * 212334Scsgr * In no event will Sun Microsystems, Inc. be liable for any lost revenue 222334Scsgr * or profits or other special, indirect and consequential damages, even if 232334Scsgr * Sun has been advised of the possibility of such damages. 242334Scsgr * 252334Scsgr * Sun Microsystems, Inc. 262334Scsgr * 2550 Garcia Avenue 272334Scsgr * Mountain View, California 94043 282334Scsgr */ 2931421Scharnier 302334Scsgr#ifndef lint 3131421Scharnier#if 0 3231421Scharnierstatic char sccsid[] = "from: @(#)rpc.rstatd.c 1.1 86/09/25 Copyr 1984 Sun Micro"; 3331421Scharnierstatic char sccsid[] = "from: @(#)rstat_proc.c 2.2 88/08/01 4.0 RPCSRC"; 342334Scsgr#endif 3531421Scharnierstatic const char rcsid[] = 3650476Speter "$FreeBSD$"; 3731421Scharnier#endif 382334Scsgr 392334Scsgr/* 402334Scsgr * rstat service: built with rstat.x and derived from rpc.rstatd.c 412334Scsgr * 422334Scsgr * Copyright (c) 1984 by Sun Microsystems, Inc. 432334Scsgr */ 442334Scsgr 4520333Swollman#include <sys/types.h> 4620333Swollman#include <sys/socket.h> 4720333Swollman#include <sys/sysctl.h> 4820333Swollman#include <sys/time.h> 49111005Sphk#include <sys/resource.h> 5020333Swollman#include <sys/vmmeter.h> 5139228Sgibbs#include <sys/param.h> 5220333Swollman 5331421Scharnier#include <err.h> 5485040Sfenner#include <errno.h> 552334Scsgr#include <fcntl.h> 562334Scsgr#include <limits.h> 572334Scsgr#include <signal.h> 582334Scsgr#include <stdio.h> 592334Scsgr#include <stdlib.h> 602334Scsgr#include <string.h> 612334Scsgr#include <syslog.h> 6231421Scharnier#include <unistd.h> 6339228Sgibbs#include <devstat.h> 642334Scsgr 652334Scsgr#include <net/if.h> 6620333Swollman#include <net/if_mib.h> 672334Scsgr 682334Scsgr#undef FSHIFT /* Use protocol's shift and scale values */ 692334Scsgr#undef FSCALE 702334Scsgr#undef if_ipackets 712334Scsgr#undef if_ierrors 722334Scsgr#undef if_opackets 732334Scsgr#undef if_oerrors 742334Scsgr#undef if_collisions 752334Scsgr#include <rpcsvc/rstat.h> 762334Scsgr 77104384Smikeint haveadisk(void); 7890336Simpvoid updatexfers(int, int *); 7990336Simpint stats_service(void); 802334Scsgr 812334Scsgrextern int from_inetd; 822334Scsgrint sincelastreq = 0; /* number of alarms since last request */ 832334Scsgrextern int closedown; 842334Scsgr 852334Scsgrunion { 862334Scsgr struct stats s1; 872334Scsgr struct statsswtch s2; 882334Scsgr struct statstime s3; 892334Scsgr} stats_all; 902334Scsgr 912334Scsgrvoid updatestat(); 92115667Sobrienstatic int stat_is_init = 0; 932334Scsgr 948870Srgrimesstatic int cp_time_xlat[RSTAT_CPUSTATES] = { CP_USER, CP_NICE, CP_SYS, 952334Scsgr CP_IDLE }; 962334Scsgrstatic long bsd_cp_time[CPUSTATES]; 972334Scsgr 982334Scsgr 992334Scsgr#ifndef FSCALE 1002334Scsgr#define FSCALE (1 << 8) 1012334Scsgr#endif 1022334Scsgr 10331421Scharniervoid 10490336Simpstat_init(void) 1052334Scsgr{ 1062334Scsgr stat_is_init = 1; 10781080Sjon alarm(0); 1082334Scsgr updatestat(); 1092334Scsgr (void) signal(SIGALRM, updatestat); 1102334Scsgr alarm(1); 1112334Scsgr} 1122334Scsgr 1132334Scsgrstatstime * 11490336Simprstatproc_stats_3_svc(void *argp, struct svc_req *rqstp) 1152334Scsgr{ 1162334Scsgr if (! stat_is_init) 1172334Scsgr stat_init(); 1182334Scsgr sincelastreq = 0; 1192334Scsgr return(&stats_all.s3); 1202334Scsgr} 1212334Scsgr 1222334Scsgrstatsswtch * 12390336Simprstatproc_stats_2_svc(void *argp, struct svc_req *rqstp) 1242334Scsgr{ 1252334Scsgr if (! stat_is_init) 1262334Scsgr stat_init(); 1272334Scsgr sincelastreq = 0; 1282334Scsgr return(&stats_all.s2); 1292334Scsgr} 1302334Scsgr 1312334Scsgrstats * 13290336Simprstatproc_stats_1_svc(void *argp, struct svc_req *rqstp) 1332334Scsgr{ 1342334Scsgr if (! stat_is_init) 1352334Scsgr stat_init(); 1362334Scsgr sincelastreq = 0; 1372334Scsgr return(&stats_all.s1); 1382334Scsgr} 1392334Scsgr 1402334Scsgru_int * 14190336Simprstatproc_havedisk_3_svc(void *argp, struct svc_req *rqstp) 1422334Scsgr{ 1432334Scsgr static u_int have; 1442334Scsgr 1452334Scsgr if (! stat_is_init) 1462334Scsgr stat_init(); 1472334Scsgr sincelastreq = 0; 148104384Smike have = haveadisk(); 1492334Scsgr return(&have); 1502334Scsgr} 1512334Scsgr 1522334Scsgru_int * 15390336Simprstatproc_havedisk_2_svc(void *argp, struct svc_req *rqstp) 1542334Scsgr{ 15532629Swpaul return(rstatproc_havedisk_3_svc(argp, rqstp)); 1562334Scsgr} 1572334Scsgr 1582334Scsgru_int * 15990336Simprstatproc_havedisk_1_svc(void *argp, struct svc_req *rqstp) 1602334Scsgr{ 16132629Swpaul return(rstatproc_havedisk_3_svc(argp, rqstp)); 1622334Scsgr} 1632334Scsgr 1642334Scsgrvoid 16590336Simpupdatestat(void) 1662334Scsgr{ 16731421Scharnier int i, hz; 16820333Swollman struct clockinfo clockrate; 1692334Scsgr struct vmmeter cnt; 17020333Swollman struct ifmibdata ifmd; 1712334Scsgr double avrun[3]; 1722334Scsgr struct timeval tm, btm; 17320333Swollman int mib[6]; 17420333Swollman size_t len; 17520333Swollman int ifcount; 1762334Scsgr 1772334Scsgr#ifdef DEBUG 1782334Scsgr fprintf(stderr, "entering updatestat\n"); 1792334Scsgr#endif 1802334Scsgr if (sincelastreq >= closedown) { 1812334Scsgr#ifdef DEBUG 1822334Scsgr fprintf(stderr, "about to closedown\n"); 1832334Scsgr#endif 1842334Scsgr if (from_inetd) 1852334Scsgr exit(0); 1862334Scsgr else { 1872334Scsgr stat_is_init = 0; 1882334Scsgr return; 1892334Scsgr } 1902334Scsgr } 1912334Scsgr sincelastreq++; 1922334Scsgr 19320333Swollman mib[0] = CTL_KERN; 19420333Swollman mib[1] = KERN_CLOCKRATE; 19520333Swollman len = sizeof clockrate; 19620333Swollman if (sysctl(mib, 2, &clockrate, &len, 0, 0) < 0) { 19720333Swollman syslog(LOG_ERR, "sysctl(kern.clockrate): %m"); 1982334Scsgr exit(1); 1992334Scsgr } 20020333Swollman hz = clockrate.hz; 20120333Swollman 202179710Sjhb len = sizeof(bsd_cp_time); 203179710Sjhb if (sysctlbyname("kern.cp_time", bsd_cp_time, &len, 0, 0) < 0) { 204179710Sjhb syslog(LOG_ERR, "sysctl(kern.cp_time): %m"); 2052334Scsgr exit(1); 2062334Scsgr } 2072334Scsgr for(i = 0; i < RSTAT_CPUSTATES ; i++) 2082334Scsgr stats_all.s1.cp_time[i] = bsd_cp_time[cp_time_xlat[i]]; 20920333Swollman 2102334Scsgr (void)getloadavg(avrun, sizeof(avrun) / sizeof(avrun[0])); 21120333Swollman 2122334Scsgr stats_all.s2.avenrun[0] = avrun[0] * FSCALE; 2132334Scsgr stats_all.s2.avenrun[1] = avrun[1] * FSCALE; 2142334Scsgr stats_all.s2.avenrun[2] = avrun[2] * FSCALE; 21520333Swollman 21620333Swollman mib[0] = CTL_KERN; 21720333Swollman mib[1] = KERN_BOOTTIME; 21820333Swollman len = sizeof btm; 21920333Swollman if (sysctl(mib, 2, &btm, &len, 0, 0) < 0) { 22020333Swollman syslog(LOG_ERR, "sysctl(kern.boottime): %m"); 2212334Scsgr exit(1); 2222334Scsgr } 22320333Swollman 2242334Scsgr stats_all.s2.boottime.tv_sec = btm.tv_sec; 2252334Scsgr stats_all.s2.boottime.tv_usec = btm.tv_usec; 2262334Scsgr 2272334Scsgr 2282334Scsgr#ifdef DEBUG 2292334Scsgr fprintf(stderr, "%d %d %d %d\n", stats_all.s1.cp_time[0], 2302334Scsgr stats_all.s1.cp_time[1], stats_all.s1.cp_time[2], stats_all.s1.cp_time[3]); 2312334Scsgr#endif 2322334Scsgr 233179710Sjhb#define FETCH_CNT(stat, cnt) do { \ 234179710Sjhb len = sizeof((stat)); \ 235179710Sjhb if (sysctlbyname("vm.stats." #cnt , &(stat), &len, 0, 0) < 0) { \ 236179710Sjhb syslog(LOG_ERR, "sysctl(vm.stats." #cnt "): %m"); \ 237179710Sjhb exit(1); \ 238179710Sjhb } \ 239179710Sjhb} while (0) 240179710Sjhb 241179710Sjhb FETCH_CNT(stats_all.s1.v_pgpgin, vm.v_vnodepgsin); 242179710Sjhb FETCH_CNT(stats_all.s1.v_pgpgout, vm.v_vnodepgsout); 243179710Sjhb FETCH_CNT(stats_all.s1.v_pswpin, vm.v_swappgsin); 244179710Sjhb FETCH_CNT(stats_all.s1.v_pswpout, vm.v_swappgsout); 245179710Sjhb FETCH_CNT(stats_all.s1.v_intr, sys.v_intr); 246179710Sjhb FETCH_CNT(stats_all.s2.v_swtch, sys.v_swtch); 2472334Scsgr gettimeofday(&tm, (struct timezone *) 0); 2482334Scsgr stats_all.s1.v_intr -= hz*(tm.tv_sec - btm.tv_sec) + 2492334Scsgr hz*(tm.tv_usec - btm.tv_usec)/1000000; 2502334Scsgr 25139228Sgibbs /* update disk transfers */ 25239228Sgibbs updatexfers(RSTAT_DK_NDRIVE, stats_all.s1.dk_xfer); 2532334Scsgr 25420333Swollman mib[0] = CTL_NET; 25520333Swollman mib[1] = PF_LINK; 25620333Swollman mib[2] = NETLINK_GENERIC; 25720333Swollman mib[3] = IFMIB_SYSTEM; 25820333Swollman mib[4] = IFMIB_IFCOUNT; 25920333Swollman len = sizeof ifcount; 26020333Swollman if (sysctl(mib, 5, &ifcount, &len, 0, 0) < 0) { 26120333Swollman syslog(LOG_ERR, "sysctl(net.link.generic.system.ifcount): %m"); 26220333Swollman exit(1); 26320333Swollman } 26420333Swollman 2652334Scsgr stats_all.s1.if_ipackets = 0; 2662334Scsgr stats_all.s1.if_opackets = 0; 2672334Scsgr stats_all.s1.if_ierrors = 0; 2682334Scsgr stats_all.s1.if_oerrors = 0; 2692334Scsgr stats_all.s1.if_collisions = 0; 27020333Swollman for (i = 1; i <= ifcount; i++) { 27120333Swollman len = sizeof ifmd; 27220333Swollman mib[3] = IFMIB_IFDATA; 27320333Swollman mib[4] = i; 27420333Swollman mib[5] = IFDATA_GENERAL; 27520333Swollman if (sysctl(mib, 6, &ifmd, &len, 0, 0) < 0) { 27685040Sfenner if (errno == ENOENT) 27785040Sfenner continue; 27885040Sfenner 27920333Swollman syslog(LOG_ERR, "sysctl(net.link.ifdata.%d.general)" 28020333Swollman ": %m", i); 2812334Scsgr exit(1); 2822334Scsgr } 28320333Swollman 28420333Swollman stats_all.s1.if_ipackets += ifmd.ifmd_data.ifi_ipackets; 28520333Swollman stats_all.s1.if_opackets += ifmd.ifmd_data.ifi_opackets; 28620333Swollman stats_all.s1.if_ierrors += ifmd.ifmd_data.ifi_ierrors; 28720333Swollman stats_all.s1.if_oerrors += ifmd.ifmd_data.ifi_oerrors; 28820333Swollman stats_all.s1.if_collisions += ifmd.ifmd_data.ifi_collisions; 2892334Scsgr } 2902334Scsgr gettimeofday((struct timeval *)&stats_all.s3.curtime, 2912334Scsgr (struct timezone *) 0); 2922334Scsgr alarm(1); 2932334Scsgr} 2942334Scsgr 2952334Scsgr/* 2962334Scsgr * returns true if have a disk 2972334Scsgr */ 29831421Scharnierint 299104384Smikehaveadisk(void) 3002334Scsgr{ 30139228Sgibbs register int i; 30239228Sgibbs struct statinfo stats; 30339228Sgibbs int num_devices, retval = 0; 3042334Scsgr 305112283Sphk if ((num_devices = devstat_getnumdevs(NULL)) < 0) { 30639228Sgibbs syslog(LOG_ERR, "rstatd: can't get number of devices: %s", 30739228Sgibbs devstat_errbuf); 30839228Sgibbs exit(1); 30939228Sgibbs } 3102334Scsgr 311112283Sphk if (devstat_checkversion(NULL) < 0) { 31239228Sgibbs syslog(LOG_ERR, "rstatd: %s", devstat_errbuf); 3132334Scsgr exit(1); 3142334Scsgr } 31539228Sgibbs 31639228Sgibbs stats.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo)); 31739228Sgibbs bzero(stats.dinfo, sizeof(struct devinfo)); 31839228Sgibbs 319112283Sphk if (devstat_getdevs(NULL, &stats) == -1) { 32039228Sgibbs syslog(LOG_ERR, "rstatd: can't get device list: %s", 32139228Sgibbs devstat_errbuf); 32239228Sgibbs exit(1); 32339228Sgibbs } 32439228Sgibbs for (i = 0; i < stats.dinfo->numdevs; i++) { 32539228Sgibbs if (((stats.dinfo->devices[i].device_type 32639228Sgibbs & DEVSTAT_TYPE_MASK) == DEVSTAT_TYPE_DIRECT) 32739228Sgibbs && ((stats.dinfo->devices[i].device_type 32839228Sgibbs & DEVSTAT_TYPE_PASS) == 0)) { 32939228Sgibbs retval = 1; 33039228Sgibbs break; 33139228Sgibbs } 33239228Sgibbs } 33339228Sgibbs 33440078Sken if (stats.dinfo->mem_ptr) 33540078Sken free(stats.dinfo->mem_ptr); 33640078Sken 33739228Sgibbs free(stats.dinfo); 33839228Sgibbs return(retval); 3392334Scsgr} 3402334Scsgr 3412334Scsgrvoid 34290336Simpupdatexfers(int numdevs, int *devs) 34339228Sgibbs{ 344112288Sphk register int i, j, k, t; 34539228Sgibbs struct statinfo stats; 34639228Sgibbs int num_devices = 0; 34739228Sgibbs u_int64_t total_transfers; 34839228Sgibbs 349112283Sphk if ((num_devices = devstat_getnumdevs(NULL)) < 0) { 35039228Sgibbs syslog(LOG_ERR, "rstatd: can't get number of devices: %s", 35139228Sgibbs devstat_errbuf); 35239228Sgibbs exit(1); 35339228Sgibbs } 35439228Sgibbs 355112283Sphk if (devstat_checkversion(NULL) < 0) { 35639228Sgibbs syslog(LOG_ERR, "rstatd: %s", devstat_errbuf); 35739228Sgibbs exit(1); 35839228Sgibbs } 35939228Sgibbs 36039228Sgibbs stats.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo)); 36139228Sgibbs bzero(stats.dinfo, sizeof(struct devinfo)); 36239228Sgibbs 363112283Sphk if (devstat_getdevs(NULL, &stats) == -1) { 36439228Sgibbs syslog(LOG_ERR, "rstatd: can't get device list: %s", 36539228Sgibbs devstat_errbuf); 36639228Sgibbs exit(1); 36739228Sgibbs } 36839228Sgibbs 36939228Sgibbs for (i = 0, j = 0; i < stats.dinfo->numdevs && j < numdevs; i++) { 37039228Sgibbs if (((stats.dinfo->devices[i].device_type 37139228Sgibbs & DEVSTAT_TYPE_MASK) == DEVSTAT_TYPE_DIRECT) 37239228Sgibbs && ((stats.dinfo->devices[i].device_type 37339228Sgibbs & DEVSTAT_TYPE_PASS) == 0)) { 374112288Sphk total_transfers = 0; 375112288Sphk for (k = 0; k < DEVSTAT_N_TRANS_FLAGS; k++) 376112288Sphk total_transfers += 377112288Sphk stats.dinfo->devices[i].operations[k]; 37839228Sgibbs /* 37939228Sgibbs * XXX KDM If the total transfers for this device 38039228Sgibbs * are greater than the amount we can fit in a 38139228Sgibbs * signed integer, just set them to the maximum 38239228Sgibbs * amount we can fit in a signed integer. I have a 38339228Sgibbs * feeling that the rstat protocol assumes 32-bit 38439228Sgibbs * integers, so this could well break on a 64-bit 38539228Sgibbs * architecture like the Alpha. 38639228Sgibbs */ 38739228Sgibbs if (total_transfers > INT_MAX) 38839383Sdfr t = INT_MAX; 38939228Sgibbs else 39039383Sdfr t = total_transfers; 39139383Sdfr devs[j] = t; 39239228Sgibbs j++; 39339228Sgibbs } 39439228Sgibbs } 39539228Sgibbs 39640078Sken if (stats.dinfo->mem_ptr) 39740078Sken free(stats.dinfo->mem_ptr); 39840078Sken 39939228Sgibbs free(stats.dinfo); 40039228Sgibbs} 40139228Sgibbs 40239228Sgibbsvoid 40390336Simprstat_service(struct svc_req *rqstp, SVCXPRT *transp) 4042334Scsgr{ 4052334Scsgr union { 4062334Scsgr int fill; 4072334Scsgr } argument; 4082334Scsgr char *result; 4092334Scsgr bool_t (*xdr_argument)(), (*xdr_result)(); 4102334Scsgr char *(*local)(); 4112334Scsgr 4122334Scsgr switch (rqstp->rq_proc) { 4132334Scsgr case NULLPROC: 41495658Sdes (void)svc_sendreply(transp, (xdrproc_t)xdr_void, NULL); 4152334Scsgr goto leave; 4162334Scsgr 4172334Scsgr case RSTATPROC_STATS: 4182334Scsgr xdr_argument = xdr_void; 4192334Scsgr xdr_result = xdr_statstime; 4202334Scsgr switch (rqstp->rq_vers) { 4212334Scsgr case RSTATVERS_ORIG: 42232629Swpaul local = (char *(*)()) rstatproc_stats_1_svc; 4232334Scsgr break; 4242334Scsgr case RSTATVERS_SWTCH: 42532629Swpaul local = (char *(*)()) rstatproc_stats_2_svc; 4262334Scsgr break; 4272334Scsgr case RSTATVERS_TIME: 42832629Swpaul local = (char *(*)()) rstatproc_stats_3_svc; 4292334Scsgr break; 4302334Scsgr default: 4312334Scsgr svcerr_progvers(transp, RSTATVERS_ORIG, RSTATVERS_TIME); 4322334Scsgr goto leave; 4332334Scsgr /*NOTREACHED*/ 4342334Scsgr } 4352334Scsgr break; 4362334Scsgr 4372334Scsgr case RSTATPROC_HAVEDISK: 4382334Scsgr xdr_argument = xdr_void; 4392334Scsgr xdr_result = xdr_u_int; 4402334Scsgr switch (rqstp->rq_vers) { 4412334Scsgr case RSTATVERS_ORIG: 44232629Swpaul local = (char *(*)()) rstatproc_havedisk_1_svc; 4432334Scsgr break; 4442334Scsgr case RSTATVERS_SWTCH: 44532629Swpaul local = (char *(*)()) rstatproc_havedisk_2_svc; 4462334Scsgr break; 4472334Scsgr case RSTATVERS_TIME: 44832629Swpaul local = (char *(*)()) rstatproc_havedisk_3_svc; 4492334Scsgr break; 4502334Scsgr default: 4512334Scsgr svcerr_progvers(transp, RSTATVERS_ORIG, RSTATVERS_TIME); 4522334Scsgr goto leave; 4532334Scsgr /*NOTREACHED*/ 4542334Scsgr } 4552334Scsgr break; 4562334Scsgr 4572334Scsgr default: 4582334Scsgr svcerr_noproc(transp); 4592334Scsgr goto leave; 4602334Scsgr } 4612334Scsgr bzero((char *)&argument, sizeof(argument)); 46295658Sdes if (!svc_getargs(transp, (xdrproc_t)xdr_argument, &argument)) { 4632334Scsgr svcerr_decode(transp); 4642334Scsgr goto leave; 4652334Scsgr } 4662334Scsgr result = (*local)(&argument, rqstp); 46795658Sdes if (result != NULL && 46895658Sdes !svc_sendreply(transp, (xdrproc_t)xdr_result, result)) { 4692334Scsgr svcerr_systemerr(transp); 4702334Scsgr } 47195658Sdes if (!svc_freeargs(transp, (xdrproc_t)xdr_argument, &argument)) 47231421Scharnier errx(1, "unable to free arguments"); 4732334Scsgrleave: 4742334Scsgr if (from_inetd) 4752334Scsgr exit(0); 4762334Scsgr} 477