| Commit | Line | Data |
|---|---|---|
| 984263bc MD |
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 | |
| 1de703da MD |
28 | * |
| 29 | * @(#)rpc.rstatd.c 1.1 86/09/25 Copyr 1984 Sun Micro | |
| 30 | * @(#)rstat_proc.c 2.2 88/08/01 4.0 RPCSRC | |
| 31 | * $FreeBSD: src/libexec/rpc.rstatd/rstat_proc.c,v 1.14.2.1 2002/07/11 17:17:56 alfred Exp $ | |
| 984263bc MD |
32 | */ |
| 33 | ||
| 984263bc MD |
34 | /* |
| 35 | * rstat service: built with rstat.x and derived from rpc.rstatd.c | |
| 36 | * | |
| 37 | * Copyright (c) 1984 by Sun Microsystems, Inc. | |
| 38 | */ | |
| 39 | ||
| e0ecab34 | 40 | #include <sys/param.h> |
| 984263bc MD |
41 | #include <sys/socket.h> |
| 42 | #include <sys/sysctl.h> | |
| 43 | #include <sys/time.h> | |
| 44 | #include <sys/vmmeter.h> | |
| 984263bc MD |
45 | |
| 46 | #include <err.h> | |
| 47 | #include <fcntl.h> | |
| 8f5c3d2a | 48 | #include <kinfo.h> |
| 984263bc MD |
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 | ||
| f2b7decb | 70 | int haveadisk (void); |
| 3eefb696 MD |
71 | void updatexfers (int, int *); |
| 72 | void setup (void); | |
| 984263bc MD |
73 | int stats_service(); |
| 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(); | |
| 8f5c3d2a | 86 | static int stat_is_init = 0; |
| 984263bc MD |
87 | |
| 88 | #ifndef FSCALE | |
| 89 | #define FSCALE (1 << 8) | |
| 90 | #endif | |
| 91 | ||
| 92 | void | |
| 89a89091 | 93 | stat_init(void) |
| 984263bc MD |
94 | { |
| 95 | stat_is_init = 1; | |
| 984263bc MD |
96 | alarm(0); |
| 97 | updatestat(); | |
| 98 | (void) signal(SIGALRM, updatestat); | |
| 99 | alarm(1); | |
| 100 | } | |
| 101 | ||
| 102 | statstime * | |
| 89a89091 | 103 | rstatproc_stats_3_svc(void *argp, struct svc_req *rqstp) |
| 984263bc MD |
104 | { |
| 105 | if (! stat_is_init) | |
| 106 | stat_init(); | |
| 107 | sincelastreq = 0; | |
| 108 | return(&stats_all.s3); | |
| 109 | } | |
| 110 | ||
| 111 | statsswtch * | |
| 89a89091 | 112 | rstatproc_stats_2_svc(void *argp, struct svc_req *rqstp) |
| 984263bc MD |
113 | { |
| 114 | if (! stat_is_init) | |
| 115 | stat_init(); | |
| 116 | sincelastreq = 0; | |
| 117 | return(&stats_all.s2); | |
| 118 | } | |
| 119 | ||
| 120 | stats * | |
| 89a89091 | 121 | rstatproc_stats_1_svc(void *argp, struct svc_req *rqstp) |
| 984263bc MD |
122 | { |
| 123 | if (! stat_is_init) | |
| 124 | stat_init(); | |
| 125 | sincelastreq = 0; | |
| 126 | return(&stats_all.s1); | |
| 127 | } | |
| 128 | ||
| 129 | u_int * | |
| 89a89091 | 130 | rstatproc_havedisk_3_svc(void *argp, struct svc_req *rqstp) |
| 984263bc MD |
131 | { |
| 132 | static u_int have; | |
| 133 | ||
| 134 | if (! stat_is_init) | |
| 135 | stat_init(); | |
| 136 | sincelastreq = 0; | |
| f2b7decb | 137 | have = haveadisk(); |
| 984263bc MD |
138 | return(&have); |
| 139 | } | |
| 140 | ||
| 141 | u_int * | |
| 89a89091 | 142 | rstatproc_havedisk_2_svc(void *argp, struct svc_req *rqstp) |
| 984263bc MD |
143 | { |
| 144 | return(rstatproc_havedisk_3_svc(argp, rqstp)); | |
| 145 | } | |
| 146 | ||
| 147 | u_int * | |
| 89a89091 | 148 | rstatproc_havedisk_1_svc(void *argp, struct svc_req *rqstp) |
| 984263bc MD |
149 | { |
| 150 | return(rstatproc_havedisk_3_svc(argp, rqstp)); | |
| 151 | } | |
| 152 | ||
| 153 | void | |
| 89a89091 | 154 | updatestat(void) |
| 984263bc MD |
155 | { |
| 156 | int i, hz; | |
| 157 | struct clockinfo clockrate; | |
| f5d21610 JS |
158 | struct vmmeter vmm; |
| 159 | size_t vmm_size = sizeof(vmm); | |
| 984263bc MD |
160 | struct ifmibdata ifmd; |
| 161 | double avrun[3]; | |
| 162 | struct timeval tm, btm; | |
| f5d21610 | 163 | struct kinfo_cputime cp_time; |
| 984263bc MD |
164 | int mib[6]; |
| 165 | size_t len; | |
| 166 | int ifcount; | |
| 167 | ||
| 168 | #ifdef DEBUG | |
| 169 | fprintf(stderr, "entering updatestat\n"); | |
| 170 | #endif | |
| 171 | if (sincelastreq >= closedown) { | |
| 172 | #ifdef DEBUG | |
| 173 | fprintf(stderr, "about to closedown\n"); | |
| 174 | #endif | |
| 984263bc MD |
175 | if (from_inetd) |
| 176 | exit(0); | |
| 177 | else { | |
| 178 | stat_is_init = 0; | |
| 179 | return; | |
| 180 | } | |
| 181 | } | |
| 182 | sincelastreq++; | |
| 183 | ||
| 184 | mib[0] = CTL_KERN; | |
| 185 | mib[1] = KERN_CLOCKRATE; | |
| 186 | len = sizeof clockrate; | |
| 187 | if (sysctl(mib, 2, &clockrate, &len, 0, 0) < 0) { | |
| 188 | syslog(LOG_ERR, "sysctl(kern.clockrate): %m"); | |
| 189 | exit(1); | |
| 190 | } | |
| 191 | hz = clockrate.hz; | |
| 192 | ||
| f5d21610 | 193 | if (kinfo_get_sched_cputime(&cp_time)) { |
| 984263bc MD |
194 | syslog(LOG_ERR, "rstat: can't read cp_time from kmem"); |
| 195 | exit(1); | |
| 196 | } | |
| f5d21610 JS |
197 | stats_all.s1.cp_time[0] = cp_time.cp_user; |
| 198 | stats_all.s1.cp_time[1] = cp_time.cp_nice; | |
| 199 | stats_all.s1.cp_time[2] = cp_time.cp_sys; | |
| 200 | stats_all.s1.cp_time[3] = cp_time.cp_idle; | |
| 984263bc MD |
201 | |
| 202 | (void)getloadavg(avrun, sizeof(avrun) / sizeof(avrun[0])); | |
| 203 | ||
| 204 | stats_all.s2.avenrun[0] = avrun[0] * FSCALE; | |
| 205 | stats_all.s2.avenrun[1] = avrun[1] * FSCALE; | |
| 206 | stats_all.s2.avenrun[2] = avrun[2] * FSCALE; | |
| 207 | ||
| 208 | mib[0] = CTL_KERN; | |
| 209 | mib[1] = KERN_BOOTTIME; | |
| 210 | len = sizeof btm; | |
| 211 | if (sysctl(mib, 2, &btm, &len, 0, 0) < 0) { | |
| 212 | syslog(LOG_ERR, "sysctl(kern.boottime): %m"); | |
| 213 | exit(1); | |
| 214 | } | |
| 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 | fprintf(stderr, "%d %d %d %d\n", stats_all.s1.cp_time[0], | |
| 222 | stats_all.s1.cp_time[1], stats_all.s1.cp_time[2], stats_all.s1.cp_time[3]); | |
| 223 | #endif | |
| 224 | ||
| f5d21610 JS |
225 | if (sysctlbyname("vm.vmmeter", &vmm, &vmm_size, NULL, 0)) { |
| 226 | syslog(LOG_ERR, "sysctlbyname: vm.vmmeter"); | |
| 984263bc MD |
227 | exit(1); |
| 228 | } | |
| f5d21610 JS |
229 | stats_all.s1.v_pgpgin = vmm.v_vnodepgsin; |
| 230 | stats_all.s1.v_pgpgout = vmm.v_vnodepgsout; | |
| 231 | stats_all.s1.v_pswpin = vmm.v_swappgsin; | |
| 232 | stats_all.s1.v_pswpout = vmm.v_swappgsout; | |
| 233 | stats_all.s1.v_intr = vmm.v_intr; | |
| 902ec341 | 234 | gettimeofday(&tm, NULL); |
| 984263bc MD |
235 | stats_all.s1.v_intr -= hz*(tm.tv_sec - btm.tv_sec) + |
| 236 | hz*(tm.tv_usec - btm.tv_usec)/1000000; | |
| f5d21610 | 237 | stats_all.s2.v_swtch = vmm.v_swtch; |
| 984263bc MD |
238 | |
| 239 | /* update disk transfers */ | |
| 240 | updatexfers(RSTAT_DK_NDRIVE, stats_all.s1.dk_xfer); | |
| 241 | ||
| 242 | mib[0] = CTL_NET; | |
| 243 | mib[1] = PF_LINK; | |
| 244 | mib[2] = NETLINK_GENERIC; | |
| 245 | mib[3] = IFMIB_SYSTEM; | |
| 246 | mib[4] = IFMIB_IFCOUNT; | |
| 247 | len = sizeof ifcount; | |
| 248 | if (sysctl(mib, 5, &ifcount, &len, 0, 0) < 0) { | |
| 249 | syslog(LOG_ERR, "sysctl(net.link.generic.system.ifcount): %m"); | |
| 250 | exit(1); | |
| 251 | } | |
| 252 | ||
| 253 | stats_all.s1.if_ipackets = 0; | |
| 254 | stats_all.s1.if_opackets = 0; | |
| 255 | stats_all.s1.if_ierrors = 0; | |
| 256 | stats_all.s1.if_oerrors = 0; | |
| 257 | stats_all.s1.if_collisions = 0; | |
| 258 | for (i = 1; i <= ifcount; i++) { | |
| 259 | len = sizeof ifmd; | |
| 260 | mib[3] = IFMIB_IFDATA; | |
| 261 | mib[4] = i; | |
| 262 | mib[5] = IFDATA_GENERAL; | |
| 263 | if (sysctl(mib, 6, &ifmd, &len, 0, 0) < 0) { | |
| 264 | syslog(LOG_ERR, "sysctl(net.link.ifdata.%d.general)" | |
| 265 | ": %m", i); | |
| 266 | exit(1); | |
| 267 | } | |
| 268 | ||
| 269 | stats_all.s1.if_ipackets += ifmd.ifmd_data.ifi_ipackets; | |
| 270 | stats_all.s1.if_opackets += ifmd.ifmd_data.ifi_opackets; | |
| 271 | stats_all.s1.if_ierrors += ifmd.ifmd_data.ifi_ierrors; | |
| 272 | stats_all.s1.if_oerrors += ifmd.ifmd_data.ifi_oerrors; | |
| 273 | stats_all.s1.if_collisions += ifmd.ifmd_data.ifi_collisions; | |
| 274 | } | |
| 902ec341 | 275 | gettimeofday((struct timeval *)&stats_all.s3.curtime, NULL); |
| 984263bc MD |
276 | alarm(1); |
| 277 | } | |
| 278 | ||
| 984263bc MD |
279 | /* |
| 280 | * returns true if have a disk | |
| 281 | */ | |
| 282 | int | |
| 89a89091 | 283 | haveadisk(void) |
| 984263bc MD |
284 | { |
| 285 | register int i; | |
| 286 | struct statinfo stats; | |
| 287 | int num_devices, retval = 0; | |
| 288 | ||
| 289 | if ((num_devices = getnumdevs()) < 0) { | |
| 290 | syslog(LOG_ERR, "rstatd: can't get number of devices: %s", | |
| 291 | devstat_errbuf); | |
| 292 | exit(1); | |
| 293 | } | |
| 294 | ||
| 295 | if (checkversion() < 0) { | |
| 296 | syslog(LOG_ERR, "rstatd: %s", devstat_errbuf); | |
| 297 | exit(1); | |
| 298 | } | |
| 299 | ||
| 300 | stats.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo)); | |
| 301 | bzero(stats.dinfo, sizeof(struct devinfo)); | |
| 302 | ||
| 303 | if (getdevs(&stats) == -1) { | |
| 304 | syslog(LOG_ERR, "rstatd: can't get device list: %s", | |
| 305 | devstat_errbuf); | |
| 306 | exit(1); | |
| 307 | } | |
| 308 | for (i = 0; i < stats.dinfo->numdevs; i++) { | |
| 309 | if (((stats.dinfo->devices[i].device_type | |
| 310 | & DEVSTAT_TYPE_MASK) == DEVSTAT_TYPE_DIRECT) | |
| 311 | && ((stats.dinfo->devices[i].device_type | |
| 312 | & DEVSTAT_TYPE_PASS) == 0)) { | |
| 313 | retval = 1; | |
| 314 | break; | |
| 315 | } | |
| 316 | } | |
| 317 | ||
| 318 | if (stats.dinfo->mem_ptr) | |
| 319 | free(stats.dinfo->mem_ptr); | |
| 320 | ||
| 321 | free(stats.dinfo); | |
| 322 | return(retval); | |
| 323 | } | |
| 324 | ||
| 325 | void | |
| 89a89091 | 326 | updatexfers(int numdevs, int *devs) |
| 984263bc MD |
327 | { |
| 328 | register int i, j, t; | |
| 329 | struct statinfo stats; | |
| 330 | int num_devices = 0; | |
| 331 | u_int64_t total_transfers; | |
| 332 | ||
| 333 | if ((num_devices = getnumdevs()) < 0) { | |
| 334 | syslog(LOG_ERR, "rstatd: can't get number of devices: %s", | |
| 335 | devstat_errbuf); | |
| 336 | exit(1); | |
| 337 | } | |
| 338 | ||
| 339 | if (checkversion() < 0) { | |
| 340 | syslog(LOG_ERR, "rstatd: %s", devstat_errbuf); | |
| 341 | exit(1); | |
| 342 | } | |
| 343 | ||
| 344 | stats.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo)); | |
| 345 | bzero(stats.dinfo, sizeof(struct devinfo)); | |
| 346 | ||
| 347 | if (getdevs(&stats) == -1) { | |
| 348 | syslog(LOG_ERR, "rstatd: can't get device list: %s", | |
| 349 | devstat_errbuf); | |
| 350 | exit(1); | |
| 351 | } | |
| 352 | ||
| 353 | for (i = 0, j = 0; i < stats.dinfo->numdevs && j < numdevs; i++) { | |
| 354 | if (((stats.dinfo->devices[i].device_type | |
| 355 | & DEVSTAT_TYPE_MASK) == DEVSTAT_TYPE_DIRECT) | |
| 356 | && ((stats.dinfo->devices[i].device_type | |
| 357 | & DEVSTAT_TYPE_PASS) == 0)) { | |
| 358 | total_transfers = stats.dinfo->devices[i].num_reads + | |
| 359 | stats.dinfo->devices[i].num_writes + | |
| 360 | stats.dinfo->devices[i].num_other; | |
| 361 | /* | |
| 362 | * XXX KDM If the total transfers for this device | |
| 363 | * are greater than the amount we can fit in a | |
| 364 | * signed integer, just set them to the maximum | |
| 365 | * amount we can fit in a signed integer. I have a | |
| 366 | * feeling that the rstat protocol assumes 32-bit | |
| 367 | * integers, so this could well break on a 64-bit | |
| 368 | * architecture like the Alpha. | |
| 369 | */ | |
| 370 | if (total_transfers > INT_MAX) | |
| 371 | t = INT_MAX; | |
| 372 | else | |
| 373 | t = total_transfers; | |
| 374 | devs[j] = t; | |
| 375 | j++; | |
| 376 | } | |
| 377 | } | |
| 378 | ||
| 379 | if (stats.dinfo->mem_ptr) | |
| 380 | free(stats.dinfo->mem_ptr); | |
| 381 | ||
| 382 | free(stats.dinfo); | |
| 383 | } | |
| 384 | ||
| 385 | void | |
| 89a89091 | 386 | rstat_service(struct svc_req *rqstp, SVCXPRT *transp) |
| 984263bc MD |
387 | { |
| 388 | union { | |
| 389 | int fill; | |
| 390 | } argument; | |
| 391 | char *result; | |
| 392 | bool_t (*xdr_argument)(), (*xdr_result)(); | |
| 393 | char *(*local)(); | |
| 394 | ||
| 395 | switch (rqstp->rq_proc) { | |
| 396 | case NULLPROC: | |
| 4260e333 | 397 | (void)svc_sendreply(transp, (xdrproc_t)xdr_void, NULL); |
| 984263bc MD |
398 | goto leave; |
| 399 | ||
| 400 | case RSTATPROC_STATS: | |
| 401 | xdr_argument = xdr_void; | |
| 402 | xdr_result = xdr_statstime; | |
| 403 | switch (rqstp->rq_vers) { | |
| 404 | case RSTATVERS_ORIG: | |
| 405 | local = (char *(*)()) rstatproc_stats_1_svc; | |
| 406 | break; | |
| 407 | case RSTATVERS_SWTCH: | |
| 408 | local = (char *(*)()) rstatproc_stats_2_svc; | |
| 409 | break; | |
| 410 | case RSTATVERS_TIME: | |
| 411 | local = (char *(*)()) rstatproc_stats_3_svc; | |
| 412 | break; | |
| 413 | default: | |
| 414 | svcerr_progvers(transp, RSTATVERS_ORIG, RSTATVERS_TIME); | |
| 415 | goto leave; | |
| 416 | /*NOTREACHED*/ | |
| 417 | } | |
| 418 | break; | |
| 419 | ||
| 420 | case RSTATPROC_HAVEDISK: | |
| 421 | xdr_argument = xdr_void; | |
| 422 | xdr_result = xdr_u_int; | |
| 423 | switch (rqstp->rq_vers) { | |
| 424 | case RSTATVERS_ORIG: | |
| 425 | local = (char *(*)()) rstatproc_havedisk_1_svc; | |
| 426 | break; | |
| 427 | case RSTATVERS_SWTCH: | |
| 428 | local = (char *(*)()) rstatproc_havedisk_2_svc; | |
| 429 | break; | |
| 430 | case RSTATVERS_TIME: | |
| 431 | local = (char *(*)()) rstatproc_havedisk_3_svc; | |
| 432 | break; | |
| 433 | default: | |
| 434 | svcerr_progvers(transp, RSTATVERS_ORIG, RSTATVERS_TIME); | |
| 435 | goto leave; | |
| 436 | /*NOTREACHED*/ | |
| 437 | } | |
| 438 | break; | |
| 439 | ||
| 440 | default: | |
| 441 | svcerr_noproc(transp); | |
| 442 | goto leave; | |
| 443 | } | |
| 444 | bzero((char *)&argument, sizeof(argument)); | |
| 4260e333 | 445 | if (!svc_getargs(transp, (xdrproc_t)xdr_argument, (caddr_t)&argument)) { |
| 984263bc MD |
446 | svcerr_decode(transp); |
| 447 | goto leave; | |
| 448 | } | |
| 449 | result = (*local)(&argument, rqstp); | |
| 4260e333 SW |
450 | if (result != NULL && |
| 451 | !svc_sendreply(transp, (xdrproc_t)xdr_result, result)) { | |
| 984263bc MD |
452 | svcerr_systemerr(transp); |
| 453 | } | |
| 4260e333 | 454 | if (!svc_freeargs(transp, (xdrproc_t)xdr_argument, (caddr_t)&argument)) |
| 984263bc MD |
455 | errx(1, "unable to free arguments"); |
| 456 | leave: | |
| 457 | if (from_inetd) | |
| 458 | exit(0); | |
| 459 | } |