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