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