1*5b133f3fSguenther /* $OpenBSD: rstat_proc.c,v 1.38 2023/03/08 04:43:05 guenther Exp $ */
25ca872f5Sniklas
3df930be7Sderaadt /*
4cb7760d1Smillert * Copyright (c) 2010, Oracle America, Inc.
5df930be7Sderaadt *
6cb7760d1Smillert * Redistribution and use in source and binary forms, with or without
7cb7760d1Smillert * modification, are permitted provided that the following conditions are
8cb7760d1Smillert * met:
9df930be7Sderaadt *
10cb7760d1Smillert * * Redistributions of source code must retain the above copyright
11cb7760d1Smillert * notice, this list of conditions and the following disclaimer.
12cb7760d1Smillert * * Redistributions in binary form must reproduce the above
13cb7760d1Smillert * copyright notice, this list of conditions and the following
14cb7760d1Smillert * disclaimer in the documentation and/or other materials
15cb7760d1Smillert * provided with the distribution.
16cb7760d1Smillert * * Neither the name of the "Oracle America, Inc." nor the names of its
17cb7760d1Smillert * contributors may be used to endorse or promote products derived
18cb7760d1Smillert * from this software without specific prior written permission.
19df930be7Sderaadt *
20cb7760d1Smillert * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21cb7760d1Smillert * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22cb7760d1Smillert * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23cb7760d1Smillert * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24cb7760d1Smillert * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
25cb7760d1Smillert * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26cb7760d1Smillert * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
27cb7760d1Smillert * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28cb7760d1Smillert * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29cb7760d1Smillert * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30cb7760d1Smillert * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31cb7760d1Smillert * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32df930be7Sderaadt */
33df930be7Sderaadt
34df930be7Sderaadt /*
35df930be7Sderaadt * rstat service: built with rstat.x and derived from rpc.rstatd.c
36df930be7Sderaadt */
37df930be7Sderaadt
38b9fc9a72Sderaadt #include <sys/types.h>
395e645fa6Sguenther #include <sys/time.h>
40b7cf9720Smiod #include <sys/sched.h>
41ec5c8394Smillert #include <sys/socket.h>
42ec5c8394Smillert #include <sys/sysctl.h>
43ec5c8394Smillert #include <net/if.h>
44ec5c8394Smillert
45df930be7Sderaadt #include <stdio.h>
46df930be7Sderaadt #include <stdlib.h>
47df930be7Sderaadt #include <string.h>
48df930be7Sderaadt #include <signal.h>
49df930be7Sderaadt #include <syslog.h>
50ec5c8394Smillert #include <fcntl.h>
51ec5c8394Smillert #include <limits.h>
52a5553e71Sderaadt #include <errno.h>
53ec5c8394Smillert #include <ifaddrs.h>
5497bbbe8bStholo #include "dkstats.h"
552b324f2dSart
56df930be7Sderaadt #undef FSHIFT /* Use protocol's shift and scale values */
57df930be7Sderaadt #undef FSCALE
58df930be7Sderaadt #undef DK_NDRIVE
59df930be7Sderaadt #undef CPUSTATES
60df930be7Sderaadt #undef if_ipackets
61df930be7Sderaadt #undef if_ierrors
62df930be7Sderaadt #undef if_opackets
63df930be7Sderaadt #undef if_oerrors
64df930be7Sderaadt #undef if_collisions
65df930be7Sderaadt #include <rpcsvc/rstat.h>
66df930be7Sderaadt
67df930be7Sderaadt int cp_xlat[CPUSTATES] = { CP_USER, CP_NICE, CP_SYS, CP_IDLE };
68df930be7Sderaadt
6997bbbe8bStholo extern int dk_ndrive; /* from dkstats.c */
7097bbbe8bStholo extern struct _disk cur, last;
7197bbbe8bStholo char *memf = NULL, *nlistf = NULL;
7297bbbe8bStholo int hz;
7397bbbe8bStholo
74df930be7Sderaadt extern int from_inetd;
75df930be7Sderaadt int sincelastreq = 0; /* number of alarms since last request */
76df930be7Sderaadt extern int closedown;
77df930be7Sderaadt
78df930be7Sderaadt union {
79df930be7Sderaadt struct stats s1;
80df930be7Sderaadt struct statsswtch s2;
81df930be7Sderaadt struct statstime s3;
82df930be7Sderaadt } stats_all;
83df930be7Sderaadt
84bad7586eSderaadt void updatestat(void);
85bad7586eSderaadt void updatestatsig(int sig);
86a5553e71Sderaadt void setup(void);
87a5553e71Sderaadt
88bad7586eSderaadt volatile sig_atomic_t wantupdatestat;
89bad7586eSderaadt
90a5553e71Sderaadt static int stat_is_init = 0;
91df930be7Sderaadt
92df930be7Sderaadt #ifndef FSCALE
93df930be7Sderaadt #define FSCALE (1 << 8)
94df930be7Sderaadt #endif
95df930be7Sderaadt
96aa31cba2Sderaadt static void
stat_init(void)977f04c10bSderaadt stat_init(void)
98df930be7Sderaadt {
99df930be7Sderaadt stat_is_init = 1;
100df930be7Sderaadt setup();
101bad7586eSderaadt updatestat();
102bad7586eSderaadt (void) signal(SIGALRM, updatestatsig);
103df930be7Sderaadt alarm(1);
104df930be7Sderaadt }
105df930be7Sderaadt
106df930be7Sderaadt statstime *
rstatproc_stats_3_svc(void * arg,struct svc_req * rqstp)1077f04c10bSderaadt rstatproc_stats_3_svc(void *arg, struct svc_req *rqstp)
108df930be7Sderaadt {
109df930be7Sderaadt if (!stat_is_init)
110df930be7Sderaadt stat_init();
111df930be7Sderaadt sincelastreq = 0;
112df930be7Sderaadt return (&stats_all.s3);
113df930be7Sderaadt }
114df930be7Sderaadt
115df930be7Sderaadt statsswtch *
rstatproc_stats_2_svc(void * arg,struct svc_req * rqstp)1167f04c10bSderaadt rstatproc_stats_2_svc(void *arg, struct svc_req *rqstp)
117df930be7Sderaadt {
118df930be7Sderaadt if (!stat_is_init)
119df930be7Sderaadt stat_init();
120df930be7Sderaadt sincelastreq = 0;
121df930be7Sderaadt return (&stats_all.s2);
122df930be7Sderaadt }
123df930be7Sderaadt
124df930be7Sderaadt stats *
rstatproc_stats_1_svc(void * arg,struct svc_req * rqstp)1257f04c10bSderaadt rstatproc_stats_1_svc(void *arg, struct svc_req *rqstp)
126df930be7Sderaadt {
127df930be7Sderaadt if (!stat_is_init)
128df930be7Sderaadt stat_init();
129df930be7Sderaadt sincelastreq = 0;
130df930be7Sderaadt return (&stats_all.s1);
131df930be7Sderaadt }
132df930be7Sderaadt
133df930be7Sderaadt u_int *
rstatproc_havedisk_3_svc(void * arg,struct svc_req * rqstp)1347f04c10bSderaadt rstatproc_havedisk_3_svc(void *arg, struct svc_req *rqstp)
135df930be7Sderaadt {
136df930be7Sderaadt static u_int have;
137df930be7Sderaadt
138df930be7Sderaadt if (!stat_is_init)
139df930be7Sderaadt stat_init();
140df930be7Sderaadt sincelastreq = 0;
141ec5c8394Smillert have = dk_ndrive != 0;
142df930be7Sderaadt return (&have);
143df930be7Sderaadt }
144df930be7Sderaadt
145df930be7Sderaadt u_int *
rstatproc_havedisk_2_svc(void * arg,struct svc_req * rqstp)1467f04c10bSderaadt rstatproc_havedisk_2_svc(void *arg, struct svc_req *rqstp)
147df930be7Sderaadt {
148df930be7Sderaadt return (rstatproc_havedisk_3_svc(arg, rqstp));
149df930be7Sderaadt }
150df930be7Sderaadt
151df930be7Sderaadt u_int *
rstatproc_havedisk_1_svc(void * arg,struct svc_req * rqstp)1527f04c10bSderaadt rstatproc_havedisk_1_svc(void *arg, struct svc_req *rqstp)
153df930be7Sderaadt {
154df930be7Sderaadt return (rstatproc_havedisk_3_svc(arg, rqstp));
155df930be7Sderaadt }
156df930be7Sderaadt
157df930be7Sderaadt void
updatestatsig(int sig)158bad7586eSderaadt updatestatsig(int sig)
159bad7586eSderaadt {
160bad7586eSderaadt wantupdatestat = 1;
161bad7586eSderaadt }
162bad7586eSderaadt
163bad7586eSderaadt void
updatestat(void)1647f04c10bSderaadt updatestat(void)
165df930be7Sderaadt {
166303e77f9Sderaadt int i, mib[2], save_errno = errno;
1672b324f2dSart struct uvmexp uvmexp;
168c18c6a65Sderaadt size_t len;
169ec5c8394Smillert struct if_data *ifdp;
170ec5c8394Smillert struct ifaddrs *ifaddrs, *ifa;
171df930be7Sderaadt double avrun[3];
172df930be7Sderaadt struct timeval tm, btm;
173ac708d7bSweingart long *cp_time = cur.cp_time;
174df930be7Sderaadt
175df930be7Sderaadt #ifdef DEBUG
176df930be7Sderaadt syslog(LOG_DEBUG, "entering updatestat");
177df930be7Sderaadt #endif
178df930be7Sderaadt if (sincelastreq >= closedown) {
179df930be7Sderaadt #ifdef DEBUG
180df930be7Sderaadt syslog(LOG_DEBUG, "about to closedown");
181df930be7Sderaadt #endif
182df930be7Sderaadt if (from_inetd)
183303e77f9Sderaadt _exit(0);
184df930be7Sderaadt else {
185df930be7Sderaadt stat_is_init = 0;
186303e77f9Sderaadt errno = save_errno;
187df930be7Sderaadt return;
188df930be7Sderaadt }
189df930be7Sderaadt }
190df930be7Sderaadt sincelastreq++;
191df930be7Sderaadt
19297bbbe8bStholo /*
19397bbbe8bStholo * dkreadstats reads in the "disk_count" as well as the "disklist"
19497bbbe8bStholo * statistics. It also retrieves "hz" and the "cp_time" array.
19597bbbe8bStholo */
19697bbbe8bStholo dkreadstats();
19797bbbe8bStholo memset(stats_all.s1.dk_xfer, '\0', sizeof(stats_all.s1.dk_xfer));
19897bbbe8bStholo for (i = 0; i < dk_ndrive && i < DK_NDRIVE; i++)
19935fa4c39Stedu stats_all.s1.dk_xfer[i] = cur.dk_rxfer[i] + cur.dk_wxfer[i];
20097bbbe8bStholo
20197bbbe8bStholo for (i = 0; i < CPUSTATES; i++)
20297bbbe8bStholo stats_all.s1.cp_time[i] = cp_time[cp_xlat[i]];
203df930be7Sderaadt (void)getloadavg(avrun, sizeof(avrun) / sizeof(avrun[0]));
204df930be7Sderaadt stats_all.s2.avenrun[0] = avrun[0] * FSCALE;
205df930be7Sderaadt stats_all.s2.avenrun[1] = avrun[1] * FSCALE;
206df930be7Sderaadt stats_all.s2.avenrun[2] = avrun[2] * FSCALE;
207ec5c8394Smillert mib[0] = CTL_KERN;
208ec5c8394Smillert mib[1] = KERN_BOOTTIME;
209ec5c8394Smillert len = sizeof(btm);
210df69c215Sderaadt if (sysctl(mib, 2, &btm, &len, NULL, 0) == -1) {
211ec5c8394Smillert syslog(LOG_ERR, "can't sysctl kern.boottime: %m");
212303e77f9Sderaadt _exit(1);
213df930be7Sderaadt }
214df930be7Sderaadt stats_all.s2.boottime.tv_sec = btm.tv_sec;
215df930be7Sderaadt stats_all.s2.boottime.tv_usec = btm.tv_usec;
216df930be7Sderaadt
217df930be7Sderaadt
218df930be7Sderaadt #ifdef DEBUG
219ea0b9ac4Sderaadt syslog(LOG_DEBUG, "%d %d %d %d", stats_all.s1.cp_time[0],
2206c5c844cSderaadt stats_all.s1.cp_time[1], stats_all.s1.cp_time[2],
2216c5c844cSderaadt stats_all.s1.cp_time[3]);
222df930be7Sderaadt #endif
223df930be7Sderaadt
2242b324f2dSart mib[0] = CTL_VM;
2252b324f2dSart mib[1] = VM_UVMEXP;
2262b324f2dSart len = sizeof(uvmexp);
227df69c215Sderaadt if (sysctl(mib, 2, &uvmexp, &len, NULL, 0) == -1) {
228ec5c8394Smillert syslog(LOG_ERR, "can't sysctl vm.uvmexp: %m");
229303e77f9Sderaadt _exit(1);
2302b324f2dSart }
2312b324f2dSart stats_all.s1.v_pgpgin = uvmexp.fltanget;
2322b324f2dSart stats_all.s1.v_pgpgout = uvmexp.pdpageouts;
233924fab55Smiod stats_all.s1.v_pswpin = 0;
234924fab55Smiod stats_all.s1.v_pswpout = 0;
2352b324f2dSart stats_all.s1.v_intr = uvmexp.intrs;
2362b324f2dSart stats_all.s2.v_swtch = uvmexp.swtch;
2375bec4ecbScheloha gettimeofday(&tm, NULL);
2382b324f2dSart stats_all.s1.v_intr -= hz*(tm.tv_sec - btm.tv_sec) +
2392b324f2dSart hz*(tm.tv_usec - btm.tv_usec)/1000000;
240df930be7Sderaadt stats_all.s1.if_ipackets = 0;
241df930be7Sderaadt stats_all.s1.if_opackets = 0;
242df930be7Sderaadt stats_all.s1.if_ierrors = 0;
243df930be7Sderaadt stats_all.s1.if_oerrors = 0;
244df930be7Sderaadt stats_all.s1.if_collisions = 0;
245ec5c8394Smillert if (getifaddrs(&ifaddrs) == -1) {
246ec5c8394Smillert syslog(LOG_ERR, "can't getifaddrs: %m");
247303e77f9Sderaadt _exit(1);
248df930be7Sderaadt }
249ec5c8394Smillert for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
250ec5c8394Smillert if (ifa->ifa_addr->sa_family != AF_LINK)
251ec5c8394Smillert continue;
252ec5c8394Smillert ifdp = (struct if_data *)ifa->ifa_data;
253ec5c8394Smillert stats_all.s1.if_ipackets += ifdp->ifi_ipackets;
254ec5c8394Smillert stats_all.s1.if_opackets += ifdp->ifi_opackets;
255ec5c8394Smillert stats_all.s1.if_ierrors += ifdp->ifi_ierrors;
256ec5c8394Smillert stats_all.s1.if_oerrors += ifdp->ifi_oerrors;
257ec5c8394Smillert stats_all.s1.if_collisions += ifdp->ifi_collisions;
258df930be7Sderaadt }
259ec5c8394Smillert freeifaddrs(ifaddrs);
2602ad02940Sderaadt stats_all.s3.curtime.tv_sec = tm.tv_sec;
2612ad02940Sderaadt stats_all.s3.curtime.tv_usec = tm.tv_usec;
2622ad02940Sderaadt
263df930be7Sderaadt alarm(1);
264f6a5c8c1Sangelos errno = save_errno;
265df930be7Sderaadt }
266df930be7Sderaadt
267a5553e71Sderaadt void
setup(void)2687f04c10bSderaadt setup(void)
269df930be7Sderaadt {
27097bbbe8bStholo dkinit(0);
271df930be7Sderaadt }
272df930be7Sderaadt
273aa31cba2Sderaadt void rstat_service(struct svc_req *, SVCXPRT *);
274aa31cba2Sderaadt
275df930be7Sderaadt void
rstat_service(struct svc_req * rqstp,SVCXPRT * transp)2767f04c10bSderaadt rstat_service(struct svc_req *rqstp, SVCXPRT *transp)
277df930be7Sderaadt {
2787f04c10bSderaadt char *(*local)(void *, struct svc_req *);
2797f04c10bSderaadt xdrproc_t xdr_argument, xdr_result;
280df930be7Sderaadt union {
281df930be7Sderaadt int fill;
282df930be7Sderaadt } argument;
283df930be7Sderaadt char *result;
284df930be7Sderaadt
285df930be7Sderaadt switch (rqstp->rq_proc) {
286df930be7Sderaadt case NULLPROC:
287df930be7Sderaadt (void)svc_sendreply(transp, xdr_void, (char *)NULL);
288eaf93a9dSkstailey return;
289df930be7Sderaadt
290df930be7Sderaadt case RSTATPROC_STATS:
291df930be7Sderaadt xdr_argument = (xdrproc_t)xdr_void;
292df930be7Sderaadt xdr_result = (xdrproc_t)xdr_statstime;
293df930be7Sderaadt switch (rqstp->rq_vers) {
294df930be7Sderaadt case RSTATVERS_ORIG:
295c72b5b24Smillert local = (char *(*)(void *, struct svc_req *))
296df930be7Sderaadt rstatproc_stats_1_svc;
297df930be7Sderaadt break;
298df930be7Sderaadt case RSTATVERS_SWTCH:
299c72b5b24Smillert local = (char *(*)(void *, struct svc_req *))
300df930be7Sderaadt rstatproc_stats_2_svc;
301df930be7Sderaadt break;
302df930be7Sderaadt case RSTATVERS_TIME:
303c72b5b24Smillert local = (char *(*)(void *, struct svc_req *))
304df930be7Sderaadt rstatproc_stats_3_svc;
305df930be7Sderaadt break;
306df930be7Sderaadt default:
307df930be7Sderaadt svcerr_progvers(transp, RSTATVERS_ORIG, RSTATVERS_TIME);
308eaf93a9dSkstailey return;
309df930be7Sderaadt }
310df930be7Sderaadt break;
311df930be7Sderaadt
312df930be7Sderaadt case RSTATPROC_HAVEDISK:
313df930be7Sderaadt xdr_argument = (xdrproc_t)xdr_void;
314df930be7Sderaadt xdr_result = (xdrproc_t)xdr_u_int;
315df930be7Sderaadt switch (rqstp->rq_vers) {
316df930be7Sderaadt case RSTATVERS_ORIG:
317c72b5b24Smillert local = (char *(*)(void *, struct svc_req *))
318df930be7Sderaadt rstatproc_havedisk_1_svc;
319df930be7Sderaadt break;
320df930be7Sderaadt case RSTATVERS_SWTCH:
321c72b5b24Smillert local = (char *(*)(void *, struct svc_req *))
322df930be7Sderaadt rstatproc_havedisk_2_svc;
323df930be7Sderaadt break;
324df930be7Sderaadt case RSTATVERS_TIME:
325c72b5b24Smillert local = (char *(*)(void *, struct svc_req *))
326df930be7Sderaadt rstatproc_havedisk_3_svc;
327df930be7Sderaadt break;
328df930be7Sderaadt default:
329df930be7Sderaadt svcerr_progvers(transp, RSTATVERS_ORIG, RSTATVERS_TIME);
330eaf93a9dSkstailey return;
331df930be7Sderaadt }
332df930be7Sderaadt break;
333df930be7Sderaadt
334df930be7Sderaadt default:
335df930be7Sderaadt svcerr_noproc(transp);
336eaf93a9dSkstailey return;
337df930be7Sderaadt }
3384c93be48Stedu memset(&argument, 0, sizeof(argument));
339df930be7Sderaadt if (!svc_getargs(transp, xdr_argument, (caddr_t)&argument)) {
340df930be7Sderaadt svcerr_decode(transp);
341eaf93a9dSkstailey return;
342df930be7Sderaadt }
343df930be7Sderaadt result = (*local)(&argument, rqstp);
344df930be7Sderaadt if (result != NULL && !svc_sendreply(transp, xdr_result, result)) {
345df930be7Sderaadt svcerr_systemerr(transp);
346df930be7Sderaadt }
347df930be7Sderaadt if (!svc_freeargs(transp, xdr_argument, (caddr_t)&argument)) {
34891dcaf16Skstailey syslog(LOG_ERR, "unable to free arguments");
349df930be7Sderaadt exit(1);
350df930be7Sderaadt }
351df930be7Sderaadt }
352