debian building now does it with everything enabled in ./configure
[monky] / src / freebsd.c
1 /** freebsd.c
2  * Contains FreeBSD specific stuff
3  *
4  * $Id$
5  */
6
7 #include <fcntl.h>
8 #include <limits.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <kvm.h>
13 #include <sys/param.h>
14 #include <sys/types.h>
15 #include <sys/time.h>
16 #include <sys/resource.h>
17 #include <sys/sysctl.h>
18 #include <sys/vmmeter.h>
19 #include <sys/dkstat.h>
20 #include <unistd.h>
21 #include <sys/user.h>
22 #include <sys/socket.h>
23 #include <net/if.h>
24 #include <net/if_mib.h>
25 #include <sys/socket.h>
26 #include <ifaddrs.h>
27
28 #include "conky.h"
29
30 #define GETSYSCTL(name, var) getsysctl(name, &(var), sizeof(var))
31 #define KELVTOC(x)      ((x - 2732) / 10.0)
32
33 #if defined(i386) || defined(__i386__)
34 static unsigned int get_timer();
35 static unsigned int get_cpu_speed(void);
36 static inline unsigned long long int rdtsc(void);
37
38 /* cpu frequency detection code based on mplayer's one */
39
40 static unsigned int get_timer()
41 {
42         struct timeval tv;
43         struct timezone tz;
44         gettimeofday(&tv, &tz);
45
46         return (tv.tv_sec * 1000000 + tv.tv_usec);
47 }
48
49 static inline unsigned long long int rdtsc(void)
50 {
51         unsigned long long int retval;
52         __asm __volatile("rdtsc":"=A"(retval)::"memory");
53         return retval;
54 }
55
56 static unsigned int get_cpu_speed(void)
57 {
58         unsigned long long int tscstart, tscstop;
59         unsigned int start, stop;
60
61         tscstart = rdtsc();
62         start = get_timer();
63         usleep(50000);
64         stop = get_timer();
65         tscstop = rdtsc();
66
67         return ((tscstop - tscstart) / ((stop - start) / 1000.0));
68 }
69 #endif /* i386 */
70
71 static int getsysctl(char *name, void *ptr, size_t len)
72 {
73         size_t nlen = len;
74         if (sysctlbyname(name, ptr, &nlen, NULL, 0) == -1) {
75                 return -1;
76         }
77
78         if (nlen != len) {
79                 return -1;
80         }
81
82         return 0;
83 }
84
85 static kvm_t *kd = NULL;
86 struct ifmibdata *data = NULL;
87 size_t len = 0;
88
89 static int swapmode(int *retavail, int *retfree)
90 {
91         int n;
92         int pagesize = getpagesize();
93         struct kvm_swap swapary[1];
94         static int kd_init = 1;
95
96         if (kd_init) {
97                 kd_init = 0;
98                 if ((kd = kvm_open("/dev/null", "/dev/null", "/dev/null",
99                                    O_RDONLY, "kvm_open")) == NULL) {
100                         (void) fprintf(stderr, "Cannot read kvm.");
101                         return -1;
102                 }
103         }
104
105         if (kd == NULL) {
106                 return -1;
107         }
108
109         *retavail = 0;
110         *retfree = 0;
111
112 #define CONVERT(v)      ((quad_t)(v) * pagesize / 1024)
113
114         n = kvm_getswapinfo(kd, swapary, 1, 0);
115         if (n < 0 || swapary[0].ksw_total == 0)
116                 return (0);
117
118         *retavail = CONVERT(swapary[0].ksw_total);
119         *retfree = CONVERT(swapary[0].ksw_total - swapary[0].ksw_used);
120
121         n = (int) ((double) swapary[0].ksw_used * 100.0 /
122                    (double) swapary[0].ksw_total);
123
124         return n;
125 }
126
127 void prepare_update()
128 {
129 }
130
131 void update_uptime()
132 {
133         int mib[2] = { CTL_KERN, KERN_BOOTTIME };
134         struct timeval boottime;
135         time_t now;
136         size_t size = sizeof(boottime);
137
138         if ((sysctl(mib, 2, &boottime, &size, NULL, 0) != -1)
139             && (boottime.tv_sec != 0)) {
140                 time(&now);
141                 info.uptime = now - boottime.tv_sec;
142         } else {
143                 (void) fprintf(stderr, "Could not get uptime\n");
144                 info.uptime = 0;
145         }
146 }
147
148 void update_meminfo()
149 {
150         int total_pages, inactive_pages, free_pages;
151         int swap_avail, swap_free;
152
153         int pagesize = getpagesize();
154
155         if (GETSYSCTL("vm.stats.vm.v_page_count", total_pages))
156                 (void) fprintf(stderr,
157                                "Cannot read sysctl \"vm.stats.vm.v_page_count\"");
158
159         if (GETSYSCTL("vm.stats.vm.v_free_count", free_pages))
160                 (void) fprintf(stderr,
161                                "Cannot read sysctl \"vm.stats.vm.v_free_count\"");
162
163         if (GETSYSCTL("vm.stats.vm.v_inactive_count", inactive_pages))
164                 (void) fprintf(stderr,
165                                "Cannot read sysctl \"vm.stats.vm.v_inactive_count\"");
166
167         info.memmax = (total_pages * pagesize) >> 10;
168         info.mem =
169             ((total_pages - free_pages - inactive_pages) * pagesize) >> 10;
170
171
172         if ((swapmode(&swap_avail, &swap_free)) >= 0) {
173                 info.swapmax = swap_avail;
174                 info.swap = (swap_avail - swap_free);
175         } else {
176                 info.swapmax = 0;
177                 info.swap = 0;
178         }
179 }
180
181 void update_net_stats()
182 {
183         struct net_stat *ns;
184         double delta;
185         long long r, t, last_recv, last_trans;
186         struct ifaddrs *ifap, *ifa;
187         struct if_data *ifd;
188
189
190         /* get delta */
191         delta = current_update_time - last_update_time;
192         if (delta <= 0.0001)
193                 return;
194
195         if (getifaddrs(&ifap) < 0)
196                 return;
197
198         for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
199                 ns = get_net_stat((const char *) ifa->ifa_name);
200
201                 if (ifa->ifa_flags & IFF_UP) {
202                         last_recv = ns->recv;
203                         last_trans = ns->trans;
204
205                         if (ifa->ifa_addr->sa_family != AF_LINK)
206                                 continue;
207
208                         ifd = (struct if_data *) ifa->ifa_data;
209                         r = ifd->ifi_ibytes;
210                         t = ifd->ifi_obytes;
211
212                         if (r < ns->last_read_recv)
213                                 ns->recv +=
214                                     ((long long) 4294967295U -
215                                      ns->last_read_recv) + r;
216                         else
217                                 ns->recv += (r - ns->last_read_recv);
218
219                         ns->last_read_recv = r;
220
221                         if (t < ns->last_read_trans)
222                                 ns->trans +=
223                                     ((long long) 4294967295U -
224                                      ns->last_read_trans) + t;
225                         else
226                                 ns->trans += (t - ns->last_read_trans);
227
228                         ns->last_read_trans = t;
229
230
231                         /* calculate speeds */
232                         ns->recv_speed = (ns->recv - last_recv) / delta;
233                         ns->trans_speed = (ns->trans - last_trans) / delta;
234                 }
235         }
236
237         freeifaddrs(ifap);
238 }
239
240 void update_total_processes()
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 float get_freq_dynamic()
425 {
426     /* TODO: implement */
427     reeturn get_freq();
428 }
429
430 float get_freq()
431 {
432         /* First, try to obtain CPU frequency via dev.cpu.0.freq sysctl
433          * (cpufreq(4)). If failed, do i386 magic. */
434         int freq;
435         
436         if (GETSYSCTL("dev.cpu.0.freq", freq) == 0)
437                 return (float)freq;
438         else {
439 #if defined(i386) || defined(__i386__)
440                 int i;
441
442                 i = 0;
443                 if ((i = get_cpu_speed()) > 0) {
444                         return (float)(i / 1000);
445                 } else
446                         return 0;
447         }
448 #else
449                 return 0;
450         }
451 #endif /* i386 */
452 }
453
454 void update_top()
455 {
456 }
457
458 void update_wifi_stats()
459 {
460 }