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 #if 0 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 #endif 35 static const char rcsid[] = 36 "$Id: rstat_proc.c,v 1.8 1997/11/26 07:34:55 charnier Exp $"; 37 #endif 38 39 /* 40 * rstat service: built with rstat.x and derived from rpc.rstatd.c 41 * 42 * Copyright (c) 1984 by Sun Microsystems, Inc. 43 */ 44 45 #include <sys/types.h> 46 #include <sys/dkstat.h> 47 #include <sys/socket.h> 48 #include <sys/sysctl.h> 49 #include <sys/time.h> 50 #include <sys/vmmeter.h> 51 52 #include <err.h> 53 #include <fcntl.h> 54 #include <kvm.h> 55 #include <limits.h> 56 #include <signal.h> 57 #include <stdio.h> 58 #include <stdlib.h> 59 #include <string.h> 60 #include <syslog.h> 61 #include <unistd.h> 62 63 #include <net/if.h> 64 #include <net/if_mib.h> 65 66 #undef FSHIFT /* Use protocol's shift and scale values */ 67 #undef FSCALE 68 #undef if_ipackets 69 #undef if_ierrors 70 #undef if_opackets 71 #undef if_oerrors 72 #undef if_collisions 73 #include <rpcsvc/rstat.h> 74 75 struct nlist nl[] = { 76 #define X_CPTIME 0 77 { "_cp_time" }, 78 #define X_CNT 1 79 { "_cnt" }, 80 #define X_DKXFER 2 81 { "_dk_xfer" }, 82 #define X_DKNDRIVE 3 83 { "_dk_ndrive" }, 84 { "" }, 85 }; 86 87 int havedisk __P((void)); 88 void setup __P((void)); 89 int stats_service(); 90 91 extern int from_inetd; 92 int sincelastreq = 0; /* number of alarms since last request */ 93 extern int closedown; 94 95 union { 96 struct stats s1; 97 struct statsswtch s2; 98 struct statstime s3; 99 } stats_all; 100 101 void updatestat(); 102 static stat_is_init = 0; 103 static kvm_t *kd; 104 105 static int cp_time_xlat[RSTAT_CPUSTATES] = { CP_USER, CP_NICE, CP_SYS, 106 CP_IDLE }; 107 static long bsd_cp_time[CPUSTATES]; 108 109 110 #ifndef FSCALE 111 #define FSCALE (1 << 8) 112 #endif 113 114 void 115 stat_init() 116 { 117 stat_is_init = 1; 118 setup(); 119 updatestat(); 120 (void) signal(SIGALRM, updatestat); 121 alarm(1); 122 } 123 124 statstime * 125 rstatproc_stats_3() 126 { 127 if (! stat_is_init) 128 stat_init(); 129 sincelastreq = 0; 130 return(&stats_all.s3); 131 } 132 133 statsswtch * 134 rstatproc_stats_2() 135 { 136 if (! stat_is_init) 137 stat_init(); 138 sincelastreq = 0; 139 return(&stats_all.s2); 140 } 141 142 stats * 143 rstatproc_stats_1() 144 { 145 if (! stat_is_init) 146 stat_init(); 147 sincelastreq = 0; 148 return(&stats_all.s1); 149 } 150 151 u_int * 152 rstatproc_havedisk_3() 153 { 154 static u_int have; 155 156 if (! stat_is_init) 157 stat_init(); 158 sincelastreq = 0; 159 have = havedisk(); 160 return(&have); 161 } 162 163 u_int * 164 rstatproc_havedisk_2() 165 { 166 return(rstatproc_havedisk_3()); 167 } 168 169 u_int * 170 rstatproc_havedisk_1() 171 { 172 return(rstatproc_havedisk_3()); 173 } 174 175 void 176 updatestat() 177 { 178 int i, hz; 179 struct clockinfo clockrate; 180 struct vmmeter cnt; 181 struct ifmibdata ifmd; 182 double avrun[3]; 183 struct timeval tm, btm; 184 int mib[6]; 185 size_t len; 186 int ifcount; 187 188 #ifdef DEBUG 189 fprintf(stderr, "entering updatestat\n"); 190 #endif 191 if (sincelastreq >= closedown) { 192 #ifdef DEBUG 193 fprintf(stderr, "about to closedown\n"); 194 #endif 195 if (from_inetd) 196 exit(0); 197 else { 198 stat_is_init = 0; 199 return; 200 } 201 } 202 sincelastreq++; 203 204 mib[0] = CTL_KERN; 205 mib[1] = KERN_CLOCKRATE; 206 len = sizeof clockrate; 207 if (sysctl(mib, 2, &clockrate, &len, 0, 0) < 0) { 208 syslog(LOG_ERR, "sysctl(kern.clockrate): %m"); 209 exit(1); 210 } 211 hz = clockrate.hz; 212 213 if (kvm_read(kd, (long)nl[X_CPTIME].n_value, (char *)bsd_cp_time, sizeof(bsd_cp_time)) 214 != sizeof(bsd_cp_time)) { 215 syslog(LOG_ERR, "rstat: can't read cp_time from kmem"); 216 exit(1); 217 } 218 for(i = 0; i < RSTAT_CPUSTATES ; i++) 219 stats_all.s1.cp_time[i] = bsd_cp_time[cp_time_xlat[i]]; 220 221 (void)getloadavg(avrun, sizeof(avrun) / sizeof(avrun[0])); 222 223 stats_all.s2.avenrun[0] = avrun[0] * FSCALE; 224 stats_all.s2.avenrun[1] = avrun[1] * FSCALE; 225 stats_all.s2.avenrun[2] = avrun[2] * FSCALE; 226 227 mib[0] = CTL_KERN; 228 mib[1] = KERN_BOOTTIME; 229 len = sizeof btm; 230 if (sysctl(mib, 2, &btm, &len, 0, 0) < 0) { 231 syslog(LOG_ERR, "sysctl(kern.boottime): %m"); 232 exit(1); 233 } 234 235 stats_all.s2.boottime.tv_sec = btm.tv_sec; 236 stats_all.s2.boottime.tv_usec = btm.tv_usec; 237 238 239 #ifdef DEBUG 240 fprintf(stderr, "%d %d %d %d\n", stats_all.s1.cp_time[0], 241 stats_all.s1.cp_time[1], stats_all.s1.cp_time[2], stats_all.s1.cp_time[3]); 242 #endif 243 244 /* XXX - should use sysctl */ 245 if (kvm_read(kd, (long)nl[X_CNT].n_value, (char *)&cnt, sizeof cnt) != sizeof cnt) { 246 syslog(LOG_ERR, "rstat: can't read cnt from kmem"); 247 exit(1); 248 } 249 stats_all.s1.v_pgpgin = cnt.v_vnodepgsin; 250 stats_all.s1.v_pgpgout = cnt.v_vnodepgsout; 251 stats_all.s1.v_pswpin = cnt.v_swappgsin; 252 stats_all.s1.v_pswpout = cnt.v_swappgsout; 253 stats_all.s1.v_intr = cnt.v_intr; 254 gettimeofday(&tm, (struct timezone *) 0); 255 stats_all.s1.v_intr -= hz*(tm.tv_sec - btm.tv_sec) + 256 hz*(tm.tv_usec - btm.tv_usec)/1000000; 257 stats_all.s2.v_swtch = cnt.v_swtch; 258 259 /* XXX - should use sysctl */ 260 if (kvm_read(kd, (long)nl[X_DKXFER].n_value, (char *)stats_all.s1.dk_xfer, sizeof (stats_all.s1.dk_xfer)) 261 != sizeof (stats_all.s1.dk_xfer)) { 262 syslog(LOG_ERR, "rstat: can't read dk_xfer from kmem"); 263 exit(1); 264 } 265 266 mib[0] = CTL_NET; 267 mib[1] = PF_LINK; 268 mib[2] = NETLINK_GENERIC; 269 mib[3] = IFMIB_SYSTEM; 270 mib[4] = IFMIB_IFCOUNT; 271 len = sizeof ifcount; 272 if (sysctl(mib, 5, &ifcount, &len, 0, 0) < 0) { 273 syslog(LOG_ERR, "sysctl(net.link.generic.system.ifcount): %m"); 274 exit(1); 275 } 276 277 stats_all.s1.if_ipackets = 0; 278 stats_all.s1.if_opackets = 0; 279 stats_all.s1.if_ierrors = 0; 280 stats_all.s1.if_oerrors = 0; 281 stats_all.s1.if_collisions = 0; 282 for (i = 1; i <= ifcount; i++) { 283 len = sizeof ifmd; 284 mib[3] = IFMIB_IFDATA; 285 mib[4] = i; 286 mib[5] = IFDATA_GENERAL; 287 if (sysctl(mib, 6, &ifmd, &len, 0, 0) < 0) { 288 syslog(LOG_ERR, "sysctl(net.link.ifdata.%d.general)" 289 ": %m", i); 290 exit(1); 291 } 292 293 stats_all.s1.if_ipackets += ifmd.ifmd_data.ifi_ipackets; 294 stats_all.s1.if_opackets += ifmd.ifmd_data.ifi_opackets; 295 stats_all.s1.if_ierrors += ifmd.ifmd_data.ifi_ierrors; 296 stats_all.s1.if_oerrors += ifmd.ifmd_data.ifi_oerrors; 297 stats_all.s1.if_collisions += ifmd.ifmd_data.ifi_collisions; 298 } 299 gettimeofday((struct timeval *)&stats_all.s3.curtime, 300 (struct timezone *) 0); 301 alarm(1); 302 } 303 304 void 305 setup() 306 { 307 char errbuf[_POSIX2_LINE_MAX]; 308 309 int en; 310 311 if ((kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf)) == NULL) { 312 syslog(LOG_ERR, "rpc.rstatd, %s", errbuf); 313 exit(1); 314 } 315 316 if ((en = kvm_nlist(kd, nl)) != 0) { 317 syslog(LOG_ERR, "rstatd: Can't get namelist. %d", en); 318 exit (1); 319 } 320 } 321 322 /* 323 * returns true if have a disk 324 */ 325 int 326 havedisk() 327 { 328 int dk_ndrive; 329 330 if (kvm_nlist(kd, nl) != 0) { 331 syslog(LOG_ERR, "rstatd: can't get namelist.(d)"); 332 exit (1); 333 } 334 335 if (kvm_read(kd, (long)nl[X_DKNDRIVE].n_value, (char *)&dk_ndrive, 336 sizeof dk_ndrive)!= sizeof dk_ndrive) { 337 syslog(LOG_ERR, "rstat: can't read kmem"); 338 exit(1); 339 } 340 return (dk_ndrive != 0); 341 } 342 343 void 344 rstat_service(rqstp, transp) 345 struct svc_req *rqstp; 346 SVCXPRT *transp; 347 { 348 union { 349 int fill; 350 } argument; 351 char *result; 352 bool_t (*xdr_argument)(), (*xdr_result)(); 353 char *(*local)(); 354 355 switch (rqstp->rq_proc) { 356 case NULLPROC: 357 (void)svc_sendreply(transp, xdr_void, (char *)NULL); 358 goto leave; 359 360 case RSTATPROC_STATS: 361 xdr_argument = xdr_void; 362 xdr_result = xdr_statstime; 363 switch (rqstp->rq_vers) { 364 case RSTATVERS_ORIG: 365 local = (char *(*)()) rstatproc_stats_1; 366 break; 367 case RSTATVERS_SWTCH: 368 local = (char *(*)()) rstatproc_stats_2; 369 break; 370 case RSTATVERS_TIME: 371 local = (char *(*)()) rstatproc_stats_3; 372 break; 373 default: 374 svcerr_progvers(transp, RSTATVERS_ORIG, RSTATVERS_TIME); 375 goto leave; 376 /*NOTREACHED*/ 377 } 378 break; 379 380 case RSTATPROC_HAVEDISK: 381 xdr_argument = xdr_void; 382 xdr_result = xdr_u_int; 383 switch (rqstp->rq_vers) { 384 case RSTATVERS_ORIG: 385 local = (char *(*)()) rstatproc_havedisk_1; 386 break; 387 case RSTATVERS_SWTCH: 388 local = (char *(*)()) rstatproc_havedisk_2; 389 break; 390 case RSTATVERS_TIME: 391 local = (char *(*)()) rstatproc_havedisk_3; 392 break; 393 default: 394 svcerr_progvers(transp, RSTATVERS_ORIG, RSTATVERS_TIME); 395 goto leave; 396 /*NOTREACHED*/ 397 } 398 break; 399 400 default: 401 svcerr_noproc(transp); 402 goto leave; 403 } 404 bzero((char *)&argument, sizeof(argument)); 405 if (!svc_getargs(transp, xdr_argument, &argument)) { 406 svcerr_decode(transp); 407 goto leave; 408 } 409 result = (*local)(&argument, rqstp); 410 if (result != NULL && !svc_sendreply(transp, xdr_result, result)) { 411 svcerr_systemerr(transp); 412 } 413 if (!svc_freeargs(transp, xdr_argument, &argument)) 414 errx(1, "unable to free arguments"); 415 leave: 416 if (from_inetd) 417 exit(0); 418 } 419