1 /*
2  * vmstat_netbsd1.c
3  */
4 
5 #include <net-snmp/net-snmp-config.h>
6 
7 /*
8  * Ripped from /usr/scr/usr.bin/vmstat/vmstat.c (covering all bases)
9  */
10 #include <sys/param.h>
11 #include <sys/time.h>
12 #include <sys/proc.h>
13 #include <sys/dkstat.h>
14 #include <sys/buf.h>
15 #include <sys/uio.h>
16 #include <sys/namei.h>
17 #include <sys/malloc.h>
18 #include <sys/signal.h>
19 #include <sys/fcntl.h>
20 #include <sys/ioctl.h>
21 #include <sys/sysctl.h>
22 #include <sys/vmmeter.h>
23 #include <sys/sched.h>
24 
25 #if defined(HAVE_UVM_UVM_PARAM_H) && defined(HAVE_UVM_UVM_EXTERN_H)
26 #include <uvm/uvm_param.h>
27 #include <uvm/uvm_extern.h>
28 #elif defined(HAVE_VM_VM_PARAM_H) && defined(HAVE_VM_VM_EXTERN_H)
29 #include <vm/vm_param.h>
30 #include <vm/vm_extern.h>
31 #else
32 #error vmstat_netbsd1.c: Is this really a NetBSD system?
33 #endif
34 
35 #include <time.h>
36 #include <nlist.h>
37 #include <kvm.h>
38 #include <errno.h>
39 #include <unistd.h>
40 #include <stdio.h>
41 #include <ctype.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <paths.h>
45 #include <limits.h>
46 
47 
48 #include <net-snmp/net-snmp-includes.h>
49 #include <net-snmp/agent/net-snmp-agent-includes.h>
50 #include <net-snmp/agent/auto_nlist.h>
51 
52 #include "util_funcs/header_generic.h"
53 #include "vmstat.h"
54 
55 /*
56  * CPU percentage
57  */
58 #define CPU_PRC         100
59 #define CPTIME_SYMBOL	"cp_time"
60 #define BOOTTIME_SYMBOL	"boottime"
61 
62 FindVarMethod var_extensible_vmstat;
63 
64 void
init_vmstat_netbsd1(void)65 init_vmstat_netbsd1(void)
66 {
67 
68     struct variable2 extensible_vmstat_variables[] = {
69         {MIBINDEX, ASN_INTEGER, NETSNMP_OLDAPI_RONLY,
70          var_extensible_vmstat, 1, {MIBINDEX}},
71         {ERRORNAME, ASN_OCTET_STR, NETSNMP_OLDAPI_RONLY,
72          var_extensible_vmstat, 1, {ERRORNAME}},
73         {SWAPIN, ASN_INTEGER, NETSNMP_OLDAPI_RONLY,
74          var_extensible_vmstat, 1, {SWAPIN}},
75         {SWAPOUT, ASN_INTEGER, NETSNMP_OLDAPI_RONLY,
76          var_extensible_vmstat, 1, {SWAPOUT}},
77         {IOSENT, ASN_INTEGER, NETSNMP_OLDAPI_RONLY,
78          var_extensible_vmstat, 1, {IOSENT}},
79         {IORECEIVE, ASN_INTEGER, NETSNMP_OLDAPI_RONLY,
80          var_extensible_vmstat, 1, {IORECEIVE}},
81         {SYSINTERRUPTS, ASN_INTEGER, NETSNMP_OLDAPI_RONLY,
82          var_extensible_vmstat, 1, {SYSINTERRUPTS}},
83         {SYSCONTEXT, ASN_INTEGER, NETSNMP_OLDAPI_RONLY,
84          var_extensible_vmstat, 1, {SYSCONTEXT}},
85         {CPUUSER, ASN_INTEGER, NETSNMP_OLDAPI_RONLY,
86          var_extensible_vmstat, 1, {CPUUSER}},
87         {CPUSYSTEM, ASN_INTEGER, NETSNMP_OLDAPI_RONLY,
88          var_extensible_vmstat, 1, {CPUSYSTEM}},
89         {CPUIDLE, ASN_INTEGER, NETSNMP_OLDAPI_RONLY,
90          var_extensible_vmstat, 1, {CPUIDLE}},
91         {CPURAWUSER, ASN_COUNTER, NETSNMP_OLDAPI_RONLY,
92          var_extensible_vmstat, 1, {CPURAWUSER}},
93         {CPURAWNICE, ASN_COUNTER, NETSNMP_OLDAPI_RONLY,
94          var_extensible_vmstat, 1, {CPURAWNICE}},
95         {CPURAWSYSTEM, ASN_COUNTER, NETSNMP_OLDAPI_RONLY,
96          var_extensible_vmstat, 1, {CPURAWSYSTEM}},
97         {CPURAWIDLE, ASN_COUNTER, NETSNMP_OLDAPI_RONLY,
98          var_extensible_vmstat, 1, {CPURAWIDLE}},
99         {CPURAWKERNEL, ASN_COUNTER, NETSNMP_OLDAPI_RONLY,
100          var_extensible_vmstat, 1, {CPURAWKERNEL}},
101         {CPURAWINTR, ASN_COUNTER, NETSNMP_OLDAPI_RONLY,
102          var_extensible_vmstat, 1, {CPURAWINTR}},
103 
104         /*
105          * Future use:
106          */
107         /*
108          * {ERRORFLAG, ASN_INTEGER, NETSNMP_OLDAPI_RONLY,
109          *  var_extensible_vmstat, 1, {ERRORFLAG }},
110          * {ERRORMSG, ASN_OCTET_STR, NETSNMP_OLDAPI_RONLY,
111          *  var_extensible_vmstat, 1, {ERRORMSG }}
112          */
113     };
114 
115     /*
116      * Define the OID pointer to the top of the mib tree that we're
117      * registering underneath
118      */
119     oid             vmstat_variables_oid[] = { NETSNMP_UCDAVIS_MIB, 11 };
120 
121     /*
122      * register ourselves with the agent to handle our mib tree
123      */
124     REGISTER_MIB("ucd-snmp/vmstat", extensible_vmstat_variables, variable2,
125                  vmstat_variables_oid);
126 
127 }
128 
129 
130 long
getuptime(void)131 getuptime(void)
132 {
133     static time_t   now, boottime;
134     time_t          uptime;
135 
136     if (boottime == 0)
137         auto_nlist(BOOTTIME_SYMBOL, (char *) &boottime, sizeof(boottime));
138 
139     time(&now);
140     uptime = now - boottime;
141 
142     return (uptime);
143 }
144 
145 unsigned char  *
var_extensible_vmstat(struct variable * vp,oid * name,size_t * length,int exact,size_t * var_len,WriteMethod ** write_method)146 var_extensible_vmstat(struct variable *vp,
147                       oid * name,
148                       size_t * length,
149                       int exact,
150                       size_t * var_len, WriteMethod ** write_method)
151 {
152 
153     int             loop;
154 
155     time_t          time_new = getuptime();
156     static time_t   time_old;
157     static time_t   time_diff;
158 
159 #if defined(KERN_CP_TIME)
160     static uint64_t  cpu_old[CPUSTATES];
161     static uint64_t  cpu_new[CPUSTATES];
162     static uint64_t  cpu_diff[CPUSTATES];
163     static uint64_t  cpu_total;
164 #elif defined(KERN_CPTIME)
165     static long     cpu_old[CPUSTATES];
166     static long     cpu_new[CPUSTATES];
167     static long     cpu_diff[CPUSTATES];
168     static long     cpu_total;
169 #else
170     static long     cpu_old[CPUSTATES];
171     static long     cpu_new[CPUSTATES];
172     static long     cpu_diff[CPUSTATES];
173     static long     cpu_total;
174 #endif
175     long            cpu_sum;
176     double          cpu_prc;
177 
178     static struct uvmexp mem_old, mem_new;
179     int             mem_mib[] = { CTL_VM, VM_UVMEXP };
180     size_t          mem_size = sizeof(struct uvmexp);
181 
182     static long     long_ret;
183     static char     errmsg[300];
184 
185     long_ret = 0;               /* set to 0 as default */
186 
187     if (header_generic(vp, name, length, exact, var_len, write_method))
188         return (NULL);
189 
190     /*
191      * Update structures (only if time has passed)
192      */
193     if (time_new != time_old) {
194 #ifdef KERN_CP_TIME
195         int             mib[2] = { CTL_KERN, KERN_CP_TIME };
196         size_t          ssize = sizeof(cpu_new);
197 
198         if (sysctl(mib, 2, cpu_new, &ssize, NULL, 0) < 0)
199             memset(cpu_new, 0, sizeof(cpu_new));
200 #elif defined(KERN_CPTIME)
201         int             mib[2] = { CTL_KERN, KERN_CPTIME };
202         size_t          ssize = sizeof(cpu_new);
203 
204         if (sysctl(mib, 2, cpu_new, &ssize, NULL, 0) < 0)
205             memset(cpu_new, 0, sizeof(cpu_new));
206 #else
207         /*
208          * CPU usage
209          */
210         auto_nlist(CPTIME_SYMBOL, (char *) cpu_new, sizeof(cpu_new));
211 #endif
212 
213         time_diff = time_new - time_old;
214         time_old = time_new;
215 
216         cpu_total = 0;
217 
218         for (loop = 0; loop < CPUSTATES; loop++) {
219             cpu_diff[loop] = cpu_new[loop] - cpu_old[loop];
220             cpu_old[loop] = cpu_new[loop];
221             cpu_total += cpu_diff[loop];
222         }
223 
224         if (cpu_total == 0)
225             cpu_total = 1;
226 
227         /*
228          * Memory info
229          */
230         mem_old = mem_new;
231         sysctl(mem_mib, 2, &mem_new, &mem_size, NULL, 0);
232     }
233 
234     /*
235      * Rate macro
236      */
237 #define rate(x) (((x)+ time_diff/2) / time_diff)
238 
239     /*
240      * Page-to-kb macro
241      */
242 #define ptok(p) ((p) * (mem_new.pagesize >> 10))
243 
244     switch (vp->magic) {
245     case MIBINDEX:
246         long_ret = 1;
247         return ((u_char *) (&long_ret));
248     case ERRORNAME:            /* dummy name */
249         sprintf(errmsg, "systemStats");
250         *var_len = strlen(errmsg);
251         return ((u_char *) (errmsg));
252     case SWAPIN:
253         long_ret = ptok(mem_new.swapins - mem_old.swapins);
254         long_ret = rate(long_ret);
255         return ((u_char *) (&long_ret));
256     case SWAPOUT:
257         long_ret = ptok(mem_new.swapouts - mem_old.swapouts);
258         long_ret = rate(long_ret);
259         return ((u_char *) (&long_ret));
260     case IOSENT:
261 #if NETSNMP_NO_DUMMY_VALUES
262         return NULL;
263 #endif
264         long_ret = -1;
265         return ((u_char *) (&long_ret));
266     case IORECEIVE:
267 #if NETSNMP_NO_DUMMY_VALUES
268         return NULL;
269 #endif
270         long_ret = -1;
271         return ((u_char *) (&long_ret));
272     case SYSINTERRUPTS:
273         long_ret = rate(mem_new.intrs - mem_old.intrs);
274         return ((u_char *) (&long_ret));
275     case SYSCONTEXT:
276         long_ret = rate(mem_new.swtch - mem_old.swtch);
277         return ((u_char *) (&long_ret));
278     case CPUUSER:
279         cpu_sum = cpu_diff[CP_USER] + cpu_diff[CP_NICE];
280         cpu_prc = (float) cpu_sum / (float) cpu_total;
281         long_ret = cpu_prc * CPU_PRC;
282         return ((u_char *) (&long_ret));
283     case CPUSYSTEM:
284         cpu_sum = cpu_diff[CP_SYS] + cpu_diff[CP_INTR];
285         cpu_prc = (float) cpu_sum / (float) cpu_total;
286         long_ret = cpu_prc * CPU_PRC;
287         return ((u_char *) (&long_ret));
288     case CPUIDLE:
289         cpu_sum = cpu_diff[CP_IDLE];
290         cpu_prc = (float) cpu_sum / (float) cpu_total;
291         long_ret = cpu_prc * CPU_PRC;
292         return ((u_char *) (&long_ret));
293     case CPURAWUSER:
294         long_ret = cpu_new[CP_USER];
295         return ((u_char *) (&long_ret));
296     case CPURAWNICE:
297         long_ret = cpu_new[CP_NICE];
298         return ((u_char *) (&long_ret));
299     case CPURAWSYSTEM:
300         long_ret = cpu_new[CP_SYS] + cpu_new[CP_INTR];
301         return ((u_char *) (&long_ret));
302     case CPURAWIDLE:
303         long_ret = cpu_new[CP_IDLE];
304         return ((u_char *) (&long_ret));
305     case CPURAWKERNEL:
306         long_ret = cpu_new[CP_SYS];
307         return ((u_char *) (&long_ret));
308     case CPURAWINTR:
309         long_ret = cpu_new[CP_INTR];
310         return ((u_char *) (&long_ret));
311         /*
312          * reserved for future use
313          */
314         /*
315          * case ERRORFLAG:
316          * return((u_char *) (&long_ret));
317          * case ERRORMSG:
318          * return((u_char *) (&long_ret));
319          */
320     }
321     return NULL;
322 }
323