* Fixed potential issue on FreeBSD when nprocs < 10 (thanks zotrix)
[monky] / src / netbsd.c
1 /* NetBSD port */
2
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <fcntl.h>
7 #include <time.h>
8 #include <unistd.h>
9 #include <err.h>
10 #include <limits.h>
11 #include <paths.h>
12
13 #include <kvm.h>
14 #include <nlist.h>
15
16 #include <sys/time.h>
17 #include <sys/param.h>
18 #include <sys/sysctl.h>
19 #include <sys/types.h>
20 #include <sys/user.h>
21 #include <sys/socket.h>
22 #include <sys/swap.h>
23 #include <sys/sched.h>
24 #include <sys/envsys.h>
25
26 #include <net/if.h>
27
28 #include <uvm/uvm_extern.h>
29
30 #include <machine/param.h>
31
32 #include "conky.h"
33
34
35 static kvm_t *kd = NULL;
36 int kd_init = 0, nkd_init = 0;
37 u_int32_t sensvalue;
38 char errbuf[_POSIX2_LINE_MAX];
39
40 static int init_kvm(void)
41 {
42         if (kd_init)
43                 return 0;
44
45         kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, errbuf);
46         if (kd == NULL) {
47                 (void) warnx("cannot kvm_openfiles: %s", errbuf);
48                 return -1;
49         }
50         kd_init = 1;
51         return 0;
52 }
53
54 static int swapmode(int *retavail, int *retfree)
55 {
56         int n;
57         struct swapent *sep;
58
59         *retavail = 0;
60         *retfree = 0;
61
62         n = swapctl(SWAP_NSWAP, 0, 0);
63
64         if (n < 1) {
65                 (void) warn("could not get swap information");
66                 return 0;
67         }
68
69         sep = (struct swapent *) malloc(n * (sizeof(*sep)));
70
71         if (sep == NULL) {
72                 (void) warn("memory allocation failed");
73                 return 0;
74         }
75
76         if (swapctl(SWAP_STATS, (void *) sep, n) < n) {
77                 (void) warn("could not get swap stats");
78                 return 0;
79         }
80         for (; n > 0; n--) {
81                 *retavail += (int) dbtob(sep[n - 1].se_nblks);
82                 *retfree +=
83                     (int) dbtob(sep[n - 1].se_nblks - sep[n - 1].se_inuse);
84         }
85         *retavail = (int) (*retavail / 1024);
86         *retfree = (int) (*retfree / 1024);
87
88         return 1;
89 }
90
91
92 void prepare_update()
93 {
94 }
95
96 void update_uptime()
97 {
98         int mib[2] = { CTL_KERN, KERN_BOOTTIME };
99         struct timeval boottime;
100         time_t now;
101         int size = sizeof(boottime);
102
103         if ((sysctl(mib, 2, &boottime, &size, NULL, 0) != -1)
104             && (boottime.tv_sec != 0)) {
105                 (void) time(&now);
106                 info.uptime = now - boottime.tv_sec;
107         } else {
108                 (void) warn("could not get uptime");
109                 info.uptime = 0;
110         }
111 }
112
113 int check_mount(char *s)
114 {
115         /* stub */
116         return 0;
117 }
118
119 void update_meminfo()
120 {
121         int mib[] = { CTL_VM, VM_UVMEXP2 };
122         int total_pages, inactive_pages, free_pages;
123         int swap_avail, swap_free;
124         const int pagesize = getpagesize();
125         struct uvmexp_sysctl uvmexp;
126         size_t size = sizeof(uvmexp);
127
128         info.memmax = info.mem = 0;
129         info.swapmax = info.swap = 0;
130
131
132         if (sysctl(mib, 2, &uvmexp, &size, NULL, 0) < 0) {
133                 warn("could not get memory info");
134                 return;
135         }
136
137         total_pages = uvmexp.npages;
138         free_pages = uvmexp.free;
139         inactive_pages = uvmexp.inactive;
140
141         info.memmax = (total_pages * pagesize) >> 10;
142         info.mem =
143             ((total_pages - free_pages - inactive_pages) * pagesize) >> 10;
144
145         if (swapmode(&swap_avail, &swap_free) >= 0) {
146                 info.swapmax = swap_avail;
147                 info.swap = (swap_avail - swap_free);
148         }
149 }
150
151 void update_net_stats()
152 {
153         int i;
154         double delta;
155         struct ifnet ifnet;
156         struct ifnet_head ifhead;       /* interfaces are in a tail queue */
157         u_long ifnetaddr;
158         static struct nlist namelist[] = {
159                 {"_ifnet"},
160                 {NULL},
161         };
162         static kvm_t *nkd;
163
164         if (!nkd_init) {
165                 nkd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf);
166                 if (nkd == NULL) {
167                         (void) warnx("cannot kvm_openfiles: %s", errbuf);
168                         (void)
169                             warnx
170                             ("maybe you need to setgid kmem this program?");
171                         return;
172                 } else if (kvm_nlist(nkd, namelist) != 0) {
173                         (void) warn("cannot kvm_nlist");
174                         return;
175                 } else
176                         nkd_init = 1;
177         }
178
179         if (kvm_read(nkd, (u_long) namelist[0].n_value, (void *) &ifhead,
180                      sizeof(ifhead)) < 0) {
181                 (void) warn("cannot kvm_read");
182                 return;
183         }
184
185         /* get delta */
186         delta = current_update_time - last_update_time;
187         if (delta <= 0.0001)
188                 return;
189
190         for (i = 0, ifnetaddr = (u_long) ifhead.tqh_first;
191              ifnet.if_list.tqe_next && i < 16;
192              ifnetaddr = (u_long) ifnet.if_list.tqe_next, i++) {
193
194                 struct net_stat *ns;
195                 long long last_recv, last_trans;
196
197                 (void) kvm_read(nkd, (u_long) ifnetaddr, (void *) &ifnet,
198                                 sizeof(ifnet));
199                 ns = get_net_stat(ifnet.if_xname);
200                 ns->up = 1;
201                 last_recv = ns->recv;
202                 last_trans = ns->trans;
203
204                 if (ifnet.if_ibytes < ns->last_read_recv)
205                         ns->recv +=
206                             ((long long) 4294967295U -
207                              ns->last_read_recv) + ifnet.if_ibytes;
208                 else
209                         ns->recv += (ifnet.if_ibytes - ns->last_read_recv);
210
211                 ns->last_read_recv = ifnet.if_ibytes;
212
213                 if (ifnet.if_obytes < ns->last_read_trans)
214                         ns->trans +=
215                             ((long long) 4294967295U -
216                              ns->last_read_trans) + ifnet.if_obytes;
217                 else
218                         ns->trans +=
219                             (ifnet.if_obytes - ns->last_read_trans);
220
221                 ns->last_read_trans = ifnet.if_obytes;
222
223                 ns->recv += (ifnet.if_ibytes - ns->last_read_recv);
224                 ns->last_read_recv = ifnet.if_ibytes;
225                 ns->trans += (ifnet.if_obytes - ns->last_read_trans);
226                 ns->last_read_trans = ifnet.if_obytes;
227
228                 ns->recv_speed = (ns->recv - last_recv) / delta;
229                 ns->trans_speed = (ns->trans - last_trans) / delta;
230         }
231 }
232
233 void update_total_processes()
234 {
235         /* It's easier to use kvm here than sysctl */
236
237         int n_processes;
238
239         info.procs = 0;
240
241         if (init_kvm() < 0)
242                 return;
243         else
244                 kvm_getproc2(kd, KERN_PROC_ALL, 0,
245                              sizeof(struct kinfo_proc2), &n_processes);
246
247         info.procs = n_processes;
248 }
249
250 void update_running_processes()
251 {
252         struct kinfo_proc2 *p;
253         int n_processes;
254         int i, cnt = 0;
255
256         info.run_procs = 0;
257
258         if (init_kvm() < 0)
259                 return;
260         else {
261                 p = kvm_getproc2(kd, KERN_PROC_ALL, 0,
262                                  sizeof(struct kinfo_proc2), &n_processes);
263                 for (i = 0; i < n_processes; i++)
264                         if (p[i].p_stat == LSRUN || p[i].p_stat == LSIDL ||
265                             p[i].p_stat == LSONPROC)
266                                 cnt++;
267         }
268
269         info.run_procs = cnt;
270 }
271
272 struct cpu_load_struct {
273         unsigned long load[5];
274 };
275
276 struct cpu_load_struct fresh = {
277         {0, 0, 0, 0, 0}
278 };
279
280 long cpu_used, oldtotal, oldused;
281
282 void update_cpu_usage()
283 {
284         long used, total;
285         static u_int64_t cp_time[CPUSTATES];
286         size_t len = sizeof(cp_time);
287
288         info.cpu_usage = 0;
289
290         if (sysctlbyname("kern.cp_time", &cp_time, &len, NULL, 0) < 0)
291                 (void) warn("cannot get kern.cp_time");
292
293
294         fresh.load[0] = cp_time[CP_USER];
295         fresh.load[1] = cp_time[CP_NICE];
296         fresh.load[2] = cp_time[CP_SYS];
297         fresh.load[3] = cp_time[CP_IDLE];
298         fresh.load[4] = cp_time[CP_IDLE];
299
300         used = fresh.load[0] + fresh.load[1] + fresh.load[2];
301         total =
302             fresh.load[0] + fresh.load[1] + fresh.load[2] + fresh.load[3];
303
304         if ((total - oldtotal) != 0)
305                 info.cpu_usage =
306                     ((double) (used - oldused)) / (double) (total -
307                                                             oldtotal);
308         else
309                 info.cpu_usage = 0;
310
311         oldused = used;
312         oldtotal = total;
313
314 }
315
316 double get_i2c_info(int *fd, int div, char *devtype)
317 {
318         return -1;
319 }
320
321 void update_load_average()
322 {
323         double v[3];
324         getloadavg(v, 3);
325
326         info.loadavg[0] = (float) v[0];
327         info.loadavg[1] = (float) v[1];
328         info.loadavg[2] = (float) v[2];
329 }
330
331 double get_acpi_temperature(int fd)
332 {
333         return -1;
334 }
335
336 void get_battery_stuff(char *buf, unsigned int n, const char *bat, int item)
337 {
338 }
339
340 int
341 open_i2c_sensor(const char *dev, const char *type, int n, int *div,
342                 char *devtype)
343 {
344         return -1;
345 }
346
347 int open_acpi_temperature(const char *name)
348 {
349         return -1;
350 }
351
352 void get_acpi_ac_adapter( char * p_client_buffer, size_t client_buffer_size )
353 {
354         if ( !p_client_buffer || client_buffer_size <= 0 )
355                 return;
356
357         /* not implemented */
358         memset(p_client_buffer,0,client_buffer_size);
359
360         return;
361 }
362
363 /*char *get_acpi_fan()*/
364 void get_acpi_fan( char * p_client_buffer, size_t client_buffer_size )
365 {
366         if ( !p_client_buffer || client_buffer_size <= 0 )
367                 return;
368
369         /* not implemented */
370         memset(p_client_buffer,0,client_buffer_size);
371
372         return;
373 }
374
375 void update_entropy (void)
376 {
377 }