3 * Contains FreeBSD specific stuff
8 #include <sys/dkstat.h>
10 #include <sys/resource.h>
11 #include <sys/socket.h>
12 #include <sys/sysctl.h>
14 #include <sys/types.h>
15 #include <sys/vmmeter.h>
19 #include <net/if_mib.h>
32 #define GETSYSCTL(name, var) getsysctl(name, &(var), sizeof (var))
33 #define KELVTOC(x) ((x - 2732) / 10.0)
34 #define MAXSHOWDEVS 16
40 inline void proc_find_top(struct process **cpu, struct process **mem);
42 u_int64_t diskio_prev = 0;
43 static short cpu_setup = 0;
44 static short diskio_setup = 0;
46 static int getsysctl(char *name, void *ptr, size_t len)
49 if (sysctlbyname(name, ptr, &nlen, NULL, 0) == -1) {
60 struct ifmibdata *data = NULL;
63 static int swapmode(int *retavail, int *retfree)
66 int pagesize = getpagesize();
67 struct kvm_swap swapary[1];
72 #define CONVERT(v) ((quad_t)(v) * pagesize / 1024)
74 n = kvm_getswapinfo(kd, swapary, 1, 0);
75 if (n < 0 || swapary[0].ksw_total == 0)
78 *retavail = CONVERT(swapary[0].ksw_total);
79 *retfree = CONVERT(swapary[0].ksw_total - swapary[0].ksw_used);
81 n = (int) ((double) swapary[0].ksw_used * 100.0 /
82 (double) swapary[0].ksw_total);
95 int mib[2] = { CTL_KERN, KERN_BOOTTIME };
96 struct timeval boottime;
98 size_t size = sizeof (boottime);
100 if ((sysctl(mib, 2, &boottime, &size, NULL, 0) != -1) &&
101 (boottime.tv_sec != 0)) {
103 info.uptime = now - boottime.tv_sec;
105 fprintf(stderr, "Could not get uptime\n");
113 int total_pages, inactive_pages, free_pages;
114 int swap_avail, swap_free;
116 int pagesize = getpagesize();
118 if (GETSYSCTL("vm.stats.vm.v_page_count", total_pages))
120 "Cannot read sysctl \"vm.stats.vm.v_page_count\"");
122 if (GETSYSCTL("vm.stats.vm.v_free_count", free_pages))
124 "Cannot read sysctl \"vm.stats.vm.v_free_count\"");
126 if (GETSYSCTL("vm.stats.vm.v_inactive_count", inactive_pages))
128 "Cannot read sysctl \"vm.stats.vm.v_inactive_count\"");
130 info.memmax = (total_pages * pagesize) >> 10;
132 ((total_pages - free_pages - inactive_pages) * pagesize) >> 10;
135 if ((swapmode(&swap_avail, &swap_free)) >= 0) {
136 info.swapmax = swap_avail;
137 info.swap = (swap_avail - swap_free);
149 long long r, t, last_recv, last_trans;
150 struct ifaddrs *ifap, *ifa;
155 delta = current_update_time - last_update_time;
159 if (getifaddrs(&ifap) < 0)
162 for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
163 ns = get_net_stat((const char *) ifa->ifa_name);
165 if (ifa->ifa_flags & IFF_UP) {
166 struct ifaddrs *iftmp;
170 last_recv = ns->recv;
171 last_trans = ns->trans;
173 if (ifa->ifa_addr->sa_family != AF_LINK)
176 for (iftmp = ifa->ifa_next; iftmp != NULL &&
177 strcmp(ifa->ifa_name, iftmp->ifa_name) == 0;
178 iftmp = iftmp->ifa_next)
179 if (iftmp->ifa_addr->sa_family == AF_INET)
180 memcpy(&(ns->addr), iftmp->ifa_addr,
181 iftmp->ifa_addr->sa_len);
183 ifd = (struct if_data *) ifa->ifa_data;
187 if (r < ns->last_read_recv)
189 ((long long) 4294967295U -
190 ns->last_read_recv) + r;
192 ns->recv += (r - ns->last_read_recv);
194 ns->last_read_recv = r;
196 if (t < ns->last_read_trans)
198 ((long long) 4294967295U -
199 ns->last_read_trans) + t;
201 ns->trans += (t - ns->last_read_trans);
203 ns->last_read_trans = t;
205 /* calculate speeds */
206 ns->recv_speed = (ns->recv - last_recv) / delta;
207 ns->trans_speed = (ns->trans - last_trans) / delta;
218 update_total_processes()
222 kvm_getprocs(kd, KERN_PROC_ALL, 0, &n_processes);
224 info.procs = n_processes;
228 update_running_processes()
230 struct kinfo_proc *p;
234 p = kvm_getprocs(kd, KERN_PROC_ALL, 0, &n_processes);
235 for (i = 0; i < n_processes; i++) {
237 if (p[i].kp_proc.p_stat == SRUN)
239 if (p[i].ki_stat == SRUN)
244 info.run_procs = cnt;
247 struct cpu_load_struct {
248 unsigned long load[5];
251 struct cpu_load_struct fresh = { {0, 0, 0, 0, 0} };
252 long cpu_used, oldtotal, oldused;
257 /* int cpu_count = 0; */
261 * FreeBSD doesn't allow to get per CPU load stats
262 * on SMP machines. It's possible to get a CPU count,
263 * but as we fulfil only info.cpu_usage[0], it's better
264 * to report there's only one CPU. It should fix some bugs
268 if (GETSYSCTL("hw.ncpu", cpu_count) == 0)
269 info.cpu_count = cpu_count;
273 info.cpu_usage = malloc(info.cpu_count * sizeof (float));
274 if (info.cpu_usage == NULL)
278 /* XXX: SMP support */
283 long cp_time[CPUSTATES];
284 size_t len = sizeof (cp_time);
286 if (cpu_setup == 0) {
291 if (sysctlbyname("kern.cp_time", &cp_time, &len, NULL, 0) < 0) {
292 (void) fprintf(stderr, "Cannot get kern.cp_time");
295 fresh.load[0] = cp_time[CP_USER];
296 fresh.load[1] = cp_time[CP_NICE];
297 fresh.load[2] = cp_time[CP_SYS];
298 fresh.load[3] = cp_time[CP_IDLE];
299 fresh.load[4] = cp_time[CP_IDLE];
301 used = fresh.load[0] + fresh.load[1] + fresh.load[2];
303 fresh.load[0] + fresh.load[1] + fresh.load[2] + fresh.load[3];
305 if ((total - oldtotal) != 0) {
306 info.cpu_usage[0] = ((double) (used - oldused)) /
307 (double) (total - oldtotal);
309 info.cpu_usage[0] = 0;
317 get_i2c_info(int *fd, int arg, char *devtype, char *type)
323 update_load_average()
328 info.loadavg[0] = (float) v[0];
329 info.loadavg[1] = (float) v[1];
330 info.loadavg[2] = (float) v[2];
334 get_acpi_temperature(int fd)
338 if (GETSYSCTL("hw.acpi.thermal.tz0.temperature", temp)) {
340 "Cannot read sysctl \"hw.acpi.thermal.tz0.temperature\"\n");
344 return (KELVTOC(temp));
348 get_battery_stuff(char *buf, unsigned int n, const char *bat)
352 if (GETSYSCTL("hw.acpi.battery.time", battime))
353 (void) fprintf(stderr,
354 "Cannot read sysctl \"hw.acpi.battery.time\"\n");
357 snprintf(buf, n, "Discharging, remaining %d:%2.2d",
358 battime / 60, battime % 60);
360 snprintf(buf, n, "Battery is charging");
364 open_i2c_sensor(const char *dev, const char *type, int n, int *div,
371 open_acpi_temperature(const char *name)
377 get_acpi_ac_adapter(char *p_client_buffer, size_t client_buffer_size)
381 if (!p_client_buffer || client_buffer_size <= 0)
384 if (GETSYSCTL("hw.acpi.acline", state)) {
386 "Cannot read sysctl \"hw.acpi.acline\"\n");
392 strncpy(p_client_buffer, "Running on AC Power",
395 strncpy(p_client_buffer, "Running on battery",
401 get_acpi_fan(char *p_client_buffer, size_t client_buffer_size)
403 if (!p_client_buffer || client_buffer_size <= 0)
406 /* not implemented */
407 memset(p_client_buffer, 0, client_buffer_size);
411 get_adt746x_cpu(char *p_client_buffer, size_t client_buffer_size)
413 if (!p_client_buffer || client_buffer_size <= 0)
416 /* not implemented */
417 memset(p_client_buffer, 0, client_buffer_size);
421 get_adt746x_fan(char *p_client_buffer, size_t client_buffer_size)
423 if (!p_client_buffer || client_buffer_size <= 0)
426 /* not implemented */
427 memset(p_client_buffer, 0, client_buffer_size);
430 /* rdtsc() and get_freq_dynamic() copied from linux.c */
432 #if defined(__i386) || defined(__x86_64)
433 __inline__ unsigned long long int
436 unsigned long long int x;
437 __asm__ volatile(".byte 0x0f, 0x31":"=A" (x));
442 /* return system frequency in MHz (use divisor=1) or GHz (use divisor=1000) */
444 get_freq_dynamic(char *p_client_buffer, size_t client_buffer_size,
445 char *p_format, int divisor)
447 #if defined(__i386) || defined(__x86_64)
449 struct timeval tvstart, tvstop;
450 unsigned long long cycles[2]; /* gotta be 64 bit */
451 unsigned int microseconds; /* total time taken */
453 memset(&tz, 0, sizeof (tz));
455 /* get this function in cached memory */
456 gettimeofday(&tvstart, &tz);
458 gettimeofday(&tvstart, &tz);
460 /* we don't trust that this is any specific length of time */
463 gettimeofday(&tvstop, &tz);
464 microseconds = ((tvstop.tv_sec - tvstart.tv_sec) * 1000000) +
465 (tvstop.tv_usec - tvstart.tv_usec);
467 snprintf(p_client_buffer, client_buffer_size, p_format,
468 (float)((cycles[1] - cycles[0]) / microseconds) / divisor);
470 get_freq(p_client_buffer, client_buffer_size, p_format, divisor);
474 /* return system frequency in MHz (use divisor=1) or GHz (use divisor=1000) */
476 get_freq(char *p_client_buffer, size_t client_buffer_size,
477 char *p_format, int divisor)
481 if (!p_client_buffer || client_buffer_size <= 0 ||
482 !p_format || divisor <= 0)
485 if (GETSYSCTL("dev.cpu.0.freq", freq) == 0)
486 snprintf(p_client_buffer, client_buffer_size,
487 p_format, freq/divisor);
489 snprintf(p_client_buffer, client_buffer_size, p_format, 0.0f);
495 proc_find_top(info.cpu, info.memu);
509 struct device_selection *dev_select = NULL;
510 long select_generation;
512 static struct statinfo statinfo_cur;
513 u_int64_t diskio_current = 0;
515 bzero(&statinfo_cur, sizeof (statinfo_cur));
516 statinfo_cur.dinfo = (struct devinfo *)malloc(sizeof (struct devinfo));
517 bzero(statinfo_cur.dinfo, sizeof (struct devinfo));
519 if (devstat_getdevs(NULL, &statinfo_cur) < 0)
522 devs_count = statinfo_cur.dinfo->numdevs;
523 if (devstat_selectdevs(&dev_select, &num_selected, &num_selections,
524 &select_generation, statinfo_cur.dinfo->generation,
525 statinfo_cur.dinfo->devices, devs_count, NULL, 0,
526 NULL, 0, DS_SELECT_ONLY, MAXSHOWDEVS, 1) >= 0) {
527 for (dn = 0; dn < devs_count; ++dn) {
531 di = dev_select[dn].position;
532 dev = &statinfo_cur.dinfo->devices[di];
534 diskio_current += dev->bytes[DEVSTAT_READ] +
535 dev->bytes[DEVSTAT_WRITE];
542 * Since we return (diskio_total_current - diskio_total_old), first
543 * frame will be way too high (it will be equal to
544 * diskio_total_current, i.e. all disk I/O since boot). That's why
545 * it is better to return 0 first time;
547 if (diskio_setup == 0) {
551 diskio_value = (unsigned int)((diskio_current - diskio_prev)/
553 diskio_prev = diskio_current;
555 free(statinfo_cur.dinfo);
559 * While topless is obviously better, top is also not bad.
563 comparecpu(const void *a, const void *b)
565 if (((struct process *)a)->amount > ((struct process *)b)->amount)
568 if (((struct process *)a)->amount < ((struct process *)b)->amount)
575 comparemem(const void *a, const void *b)
577 if (((struct process *)a)->totalmem > ((struct process *)b)->totalmem)
580 if (((struct process *)a)->totalmem < ((struct process *)b)->totalmem)
587 proc_find_top(struct process **cpu, struct process **mem)
589 struct kinfo_proc *p;
592 struct process *processes;
596 /* we get total pages count again to be sure it is up to date */
597 if (GETSYSCTL("vm.stats.vm.v_page_count", total_pages) != 0)
598 CRIT_ERR("Cannot read sysctl"
599 "\"vm.stats.vm.v_page_count\"");
601 p = kvm_getprocs(kd, KERN_PROC_PROC, 0, &n_processes);
602 processes = malloc(n_processes * sizeof (struct process));
604 for (i = 0; i < n_processes; i++) {
605 if (!((p[i].ki_flag & P_SYSTEM)) &&
606 p[i].ki_comm != NULL) {
607 processes[j].pid = p[i].ki_pid;
608 processes[j].name = strdup(p[i].ki_comm);
609 processes[j].amount = 100.0 *
610 p[i].ki_pctcpu / FSCALE;
611 processes[j].totalmem = (float)(p[i].ki_rssize /
612 (float)total_pages) * 100.0;
617 qsort(processes, j - 1, sizeof (struct process), comparemem);
618 for (i = 0; i < 10; i++) {
619 struct process *tmp, *ttmp;
621 tmp = malloc(sizeof (struct process));
622 tmp->pid = processes[i].pid;
623 tmp->amount = processes[i].amount;
624 tmp->totalmem = processes[i].totalmem;
625 tmp->name = strdup(processes[i].name);
635 qsort(processes, j - 1, sizeof (struct process), comparecpu);
636 for (i = 0; i < 10; i++) {
637 struct process *tmp, *ttmp;
639 tmp = malloc(sizeof (struct process));
640 tmp->pid = processes[i].pid;
641 tmp->amount = processes[i].amount;
642 tmp->totalmem = processes[i].totalmem;
643 tmp->name = strdup(processes[i].name);
653 #if defined(FREEBSD_DEBUG)
654 printf("=====\nmem\n");
655 for (i = 0; i < 10; i++) {
656 printf("%d: %s(%d) %.2f\n", i, mem[i]->name,
657 mem[i]->pid, mem[i]->totalmem);
661 for (i = 0; i < j; free(processes[i++].name));
665 #if defined(i386) || defined(__i386__)
666 #define APMDEV "/dev/apm"
667 #define APM_UNKNOWN 255
670 apm_getinfo(int fd, apm_info_t aip)
672 if (ioctl(fd, APMIO_GETINFO, aip) == -1)
682 struct apm_info info;
684 fd = open(APMDEV, O_RDONLY);
688 if (apm_getinfo(fd, &info) != 0) {
694 switch (info.ai_acline) {
699 if (info.ai_batt_stat == 3)
711 *get_apm_battery_life()
715 struct apm_info info;
718 out = (char *)calloc(16, sizeof (char));
720 fd = open(APMDEV, O_RDONLY);
722 strncpy(out, "ERR", 16);
726 if (apm_getinfo(fd, &info) != 0) {
728 strncpy(out, "ERR", 16);
733 batt_life = info.ai_batt_life;
734 if (batt_life == APM_UNKNOWN)
735 strncpy(out, "unknown", 16);
736 else if (batt_life <= 100) {
737 snprintf(out, 16, "%d%%", batt_life);
740 strncpy(out, "ERR", 16);
746 *get_apm_battery_time()
751 struct apm_info info;
754 out = (char *)calloc(16, sizeof (char));
756 fd = open(APMDEV, O_RDONLY);
758 strncpy(out, "ERR", 16);
762 if (apm_getinfo(fd, &info) != 0) {
764 strncpy(out, "ERR", 16);
769 batt_time = info.ai_batt_time;
772 strncpy(out, "unknown", 16);
779 snprintf(out, 16, "%2d:%02d:%02d", h, m, s);
787 /* empty stub so conky links */
789 free_all_processes(void)