Fix build on FreeBSD.
[monky] / src / freebsd.c
1 #include "conky.h"
2 #include <fcntl.h>
3 #include <limits.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <kvm.h>
8 #include <sys/param.h>
9 #include <sys/types.h>
10 #include <sys/time.h>
11 #include <sys/resource.h>
12 #include <sys/sysctl.h>
13 #include <sys/vmmeter.h>
14 #include <sys/dkstat.h>
15 #include <unistd.h>
16 #include <sys/user.h>
17 #include <sys/socket.h>
18 #include <net/if.h>
19 #include <net/if_mib.h>
20 #include <sys/socket.h>
21 #include <ifaddrs.h>
22
23 #define GETSYSCTL(name, var) getsysctl(name, &(var), sizeof(var))
24 #define KELVTOC(x)      ((x - 2732) / 10.0)
25
26 #if defined(i386) || defined(__i386__)
27 static unsigned int get_timer();
28 static unsigned int get_cpu_speed(void);
29 static inline unsigned long long int rdtsc(void);
30
31 /* cpu frequency detection code based on mplayer's one */
32
33 static unsigned int get_timer()
34 {
35         struct timeval tv;
36         struct timezone tz;
37         gettimeofday(&tv, &tz);
38
39         return (tv.tv_sec * 1000000 + tv.tv_usec);
40 }
41
42 static inline unsigned long long int rdtsc(void)
43 {
44         unsigned long long int retval;
45         __asm __volatile("rdtsc":"=A"(retval)::"memory");
46         return retval;
47 }
48
49 static unsigned int get_cpu_speed(void)
50 {
51         unsigned long long int tscstart, tscstop;
52         unsigned int start, stop;
53
54         tscstart = rdtsc();
55         start = get_timer();
56         usleep(50000);
57         stop = get_timer();
58         tscstop = rdtsc();
59
60         return ((tscstop - tscstart) / ((stop - start) / 1000.0));
61 }
62 #endif
63
64
65 static int getsysctl(char *name, void *ptr, size_t len)
66 {
67         size_t nlen = len;
68         if (sysctlbyname(name, ptr, &nlen, NULL, 0) == -1) {
69                 return -1;
70         }
71
72         if (nlen != len) {
73                 return -1;
74         }
75
76         return 0;
77 }
78
79 static kvm_t *kd = NULL;
80 struct ifmibdata *data = NULL;
81 size_t len = 0;
82
83
84 static int swapmode(int *retavail, int *retfree)
85 {
86         int n;
87         int pagesize = getpagesize();
88         struct kvm_swap swapary[1];
89         static int kd_init = 1;
90
91         if (kd_init) {
92                 kd_init = 0;
93                 if ((kd = kvm_open("/dev/null", "/dev/null", "/dev/null",
94                                    O_RDONLY, "kvm_open")) == NULL) {
95                         (void) fprintf(stderr, "Cannot read kvm.");
96                         return -1;
97                 }
98         }
99
100         if (kd == NULL) {
101                 return -1;
102         }
103
104         *retavail = 0;
105         *retfree = 0;
106
107 #define CONVERT(v)      ((quad_t)(v) * pagesize / 1024)
108
109         n = kvm_getswapinfo(kd, swapary, 1, 0);
110         if (n < 0 || swapary[0].ksw_total == 0)
111                 return (0);
112
113         *retavail = CONVERT(swapary[0].ksw_total);
114         *retfree = CONVERT(swapary[0].ksw_total - swapary[0].ksw_used);
115
116         n = (int) ((double) swapary[0].ksw_used * 100.0 /
117                    (double) swapary[0].ksw_total);
118
119         return n;
120 }
121
122
123 void prepare_update()
124 {
125 }
126
127 /*double get_uptime() */
128 void update_uptime()
129 {
130         int mib[2] = { CTL_KERN, KERN_BOOTTIME };
131         struct timeval boottime;
132         time_t now;
133         size_t size = sizeof(boottime);
134
135         if ((sysctl(mib, 2, &boottime, &size, NULL, 0) != -1)
136             && (boottime.tv_sec != 0)) {
137                 time(&now);
138                 info.uptime = now - boottime.tv_sec;
139         } else {
140                 (void) fprintf(stderr, "Could not get uptime\n");
141                 info.uptime = 0;
142         }
143 }
144
145
146 void update_meminfo()
147 {
148         int total_pages, inactive_pages, free_pages;
149         int swap_avail, swap_free;
150
151         int pagesize = getpagesize();
152
153         if (GETSYSCTL("vm.stats.vm.v_page_count", total_pages))
154                 (void) fprintf(stderr,
155                                "Cannot read sysctl \"vm.stats.vm.v_page_count\"");
156
157         if (GETSYSCTL("vm.stats.vm.v_free_count", free_pages))
158                 (void) fprintf(stderr,
159                                "Cannot read sysctl \"vm.stats.vm.v_free_count\"");
160
161         if (GETSYSCTL("vm.stats.vm.v_inactive_count", inactive_pages))
162                 (void) fprintf(stderr,
163                                "Cannot read sysctl \"vm.stats.vm.v_inactive_count\"");
164
165         info.memmax = (total_pages * pagesize) >> 10;
166         info.mem =
167             ((total_pages - free_pages - inactive_pages) * pagesize) >> 10;
168
169
170         if ((swapmode(&swap_avail, &swap_free)) >= 0) {
171                 info.swapmax = swap_avail;
172                 info.swap = (swap_avail - swap_free);
173         } else {
174                 info.swapmax = 0;
175                 info.swap = 0;
176         }
177 }
178
179 void update_net_stats()
180 {
181         struct net_stat *ns;
182         double delta;
183         long long r, t, last_recv, last_trans;
184         struct ifaddrs *ifap, *ifa;
185         struct if_data *ifd;
186
187
188         /* get delta */
189         delta = current_update_time - last_update_time;
190         if (delta <= 0.0001)
191                 return;
192
193         if (getifaddrs(&ifap) < 0)
194                 return;
195
196         for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
197                 ns = get_net_stat((const char *) ifa->ifa_name);
198
199                 if (ifa->ifa_flags & IFF_UP) {
200                         last_recv = ns->recv;
201                         last_trans = ns->trans;
202
203                         if (ifa->ifa_addr->sa_family != AF_LINK)
204                                 continue;
205
206                         ifd = (struct if_data *) ifa->ifa_data;
207                         r = ifd->ifi_ibytes;
208                         t = ifd->ifi_obytes;
209
210                         if (r < ns->last_read_recv)
211                                 ns->recv +=
212                                     ((long long) 4294967295U -
213                                      ns->last_read_recv) + r;
214                         else
215                                 ns->recv += (r - ns->last_read_recv);
216
217                         ns->last_read_recv = r;
218
219                         if (t < ns->last_read_trans)
220                                 ns->trans +=
221                                     ((long long) 4294967295U -
222                                      ns->last_read_trans) + t;
223                         else
224                                 ns->trans += (t - ns->last_read_trans);
225
226                         ns->last_read_trans = t;
227
228
229                         /* calculate speeds */
230                         ns->recv_speed = (ns->recv - last_recv) / delta;
231                         ns->trans_speed = (ns->trans - last_trans) / delta;
232                 }
233         }
234
235         freeifaddrs(ifap);
236 }
237
238 void update_total_processes()
239 {
240         /* It's easier to use kvm here than sysctl */
241
242         int n_processes;
243         static int kd_init = 1;
244
245         if (kd_init) {
246                 kd_init = 0;
247                 if ((kd = kvm_open("/dev/null", "/dev/null", "/dev/null",
248                                    O_RDONLY, "kvm_open")) == NULL) {
249                         (void) fprintf(stderr, "Cannot read kvm.");
250                         return;
251                 }
252         }
253
254
255         if (kd != NULL)
256                 kvm_getprocs(kd, KERN_PROC_ALL, 0, &n_processes);
257         else
258                 return;
259
260         info.procs = n_processes;
261 }
262
263 void update_running_processes()
264 {
265         static int kd_init = 1;
266         struct kinfo_proc *p;
267         int n_processes;
268         int i, cnt = 0;
269
270         if (kd_init) {
271                 kd_init = 0;
272                 if ((kd =
273                      kvm_open("/dev/null", "/dev/null", "/dev/null",
274                               O_RDONLY, "kvm_open")) == NULL) {
275                         (void) fprintf(stderr, "Cannot read kvm.");
276                 }
277         }
278
279         if (kd != NULL) {
280                 p = kvm_getprocs(kd, KERN_PROC_ALL, 0, &n_processes);
281                 for (i = 0; i < n_processes; i++) {
282 #if __FreeBSD__ < 5
283                         if (p[i].kp_proc.p_stat == SRUN)
284 #else
285                         if (p[i].ki_stat == SRUN)
286 #endif
287                                 cnt++;
288                 }
289         } else
290                 return;
291
292         info.run_procs = cnt;
293 }
294
295 struct cpu_load_struct {
296         unsigned long load[5];
297 };
298
299 struct cpu_load_struct fresh = { {0, 0, 0, 0, 0} };
300 long cpu_used, oldtotal, oldused;
301
302 void update_cpu_usage()
303 {
304         long used, total;
305         long cp_time[CPUSTATES];
306         size_t len = sizeof(cp_time);
307
308         if (sysctlbyname("kern.cp_time", &cp_time, &len, NULL, 0) < 0) {
309                 (void) fprintf(stderr, "Cannot get kern.cp_time");
310         }
311
312         fresh.load[0] = cp_time[CP_USER];
313         fresh.load[1] = cp_time[CP_NICE];
314         fresh.load[2] = cp_time[CP_SYS];
315         fresh.load[3] = cp_time[CP_IDLE];
316         fresh.load[4] = cp_time[CP_IDLE];
317
318         used = fresh.load[0] + fresh.load[1] + fresh.load[2];
319         total =
320             fresh.load[0] + fresh.load[1] + fresh.load[2] + fresh.load[3];
321
322         if ((total - oldtotal) != 0) {
323                 info.cpu_usage =
324                     ((double) (used - oldused)) / (double) (total -
325                                                             oldtotal);
326         } else {
327                 info.cpu_usage = 0;
328         }
329
330         oldused = used;
331         oldtotal = total;
332 }
333
334 double get_i2c_info(int *fd, int arg, char *devtype, char *type)
335 {
336         return 0;
337 }
338
339 void update_load_average()
340 {
341         double v[3];
342         getloadavg(v, 3);
343
344         info.loadavg[0] = (float) v[0];
345         info.loadavg[1] = (float) v[1];
346         info.loadavg[2] = (float) v[2];
347 }
348
349 double get_acpi_temperature(int fd)
350 {
351         int temp;
352
353         if (GETSYSCTL("hw.acpi.thermal.tz0.temperature", temp)) {
354                 (void) fprintf(stderr,
355                                "Cannot read sysctl \"hw.acpi.thermal.tz0.temperature\"\n");
356                 return 0.0;
357         }
358
359         return KELVTOC(temp);
360 }
361
362 void get_battery_stuff(char *buf, unsigned int n, const char *bat)
363 {
364         int battime;
365
366         if (GETSYSCTL("hw.acpi.battery.time", battime))
367                 (void) fprintf(stderr,
368                                "Cannot read sysctl \"hw.acpi.battery.time\"\n");
369
370         if (battime != -1)
371                 snprintf(buf, n, "Discharging, remaining %d:%2.2d",
372                          battime / 60, battime % 60);
373         else
374                 snprintf(buf, n, "Battery is charging");
375 }
376
377 int
378 open_i2c_sensor(const char *dev, const char *type, int n, int *div,
379                 char *devtype)
380 {
381         return 0;
382 }
383
384 int open_acpi_temperature(const char *name)
385 {
386         return 0;
387 }
388
389 char *get_acpi_ac_adapter(void)
390 {
391         int state;
392         char *acstate = (char *) malloc(100);
393
394         if (GETSYSCTL("hw.acpi.acline", state)) {
395                 (void) fprintf(stderr,
396                                "Cannot read sysctl \"hw.acpi.acline\"\n");
397                 return "n\\a";
398         }
399
400
401         if (state)
402                 strcpy(acstate, "Running on AC Power");
403         else
404                 strcpy(acstate, "Running on battery");
405
406         return acstate;
407 }
408
409 char *get_acpi_fan()
410 {
411         return "";
412 }
413
414 char *get_adt746x_cpu()
415 {
416         return "";
417 }
418
419 char *get_adt746x_fan()
420 {
421         return "";
422 }
423
424 char *get_freq()
425 {
426 #if defined(i386) || defined(__i386__)
427         int i;
428         char *cpuspeed;
429
430         if ((cpuspeed = (char *) malloc(16)) == NULL) {
431                 CRIT_ERR("get_freq()");
432         }
433
434         i = 0;
435         if ((i = get_cpu_speed()) > 0) {
436                 if (i < 1000000) {
437                         i += 50;        /* for rounding */
438                         snprintf(cpuspeed, 15, "%d.%d MHz", i / 1000,
439                                  (i / 100) % 10);
440                 } else {
441                         snprintf(cpuspeed, 15, "%d MHz", i / 1000);
442                 }
443         } else {
444                 cpuspeed = "";
445         }
446
447         return cpuspeed;
448 #else
449         return "";
450 #endif
451 }
452
453 void update_top()
454 {
455 }
456
457 void update_wifi_stats()
458 {
459 }