diff --git a/Changelog b/Changelog index 9936a28..c553b88 100644 --- a/Changelog +++ b/Changelog @@ -2,6 +2,9 @@ GKrellM Changelog ----------------- 2.3.6 - Not released ------------------------ + * Patch from Neil Booth: Add multiple CPU capability to CPU monitor for + Dragonfly. Acquired dragonfly.c from web so could apply patch. + I have no clue why I never had a dragonfly.c. * Patch from Jindrich Makovicka: update multiple GKrellM files to compile with -DGTK_DISABLE_DEPRECATED -DGSEAL_ENABLE for GTK3 compatibility. Replaces GtkItemFactory and GtkTooltips. diff --git a/server/Makefile b/server/Makefile index 254142f..5e30eda 100644 --- a/server/Makefile +++ b/server/Makefile @@ -231,7 +231,7 @@ clean: SYSDEPS = ../src/sysdeps/bsd-common.c ../src/sysdeps/bsd-net-open.c \ ../src/sysdeps/darwin.c \ ../src/sysdeps/freebsd.c ../src/sysdeps/gtop.c \ - ../src/sysdeps/linux.c ../src/sysdeps/netbsd.c \ + ../src/sysdeps/linux.c ../src/sysdeps/netbsd.c ../src/sysdeps/dragonfly.c \ ../src/sysdeps/openbsd.c ../src/sysdeps/sensors-common.c \ ../src/sysdeps/solaris.c ../src/sysdeps/win32.c diff --git a/src/Makefile b/src/Makefile index 6d482a7..c38683b 100644 --- a/src/Makefile +++ b/src/Makefile @@ -170,7 +170,7 @@ macosx: LINK_FLAGS="-Wl,-bind_at_load" \ X11_LIBS="" \ UNIXOBJS="" \ - gkrellm + gkrellm netbsd1: $(MAKE) EXTRAOBJS= SYS_LIBS="-lkvm" \ @@ -303,7 +303,7 @@ IMAGES = \ SYSDEPS_SRC = sysdeps/bsd-common.c sysdeps/bsd-net-open.c sysdeps/freebsd.c \ sysdeps/gtop.c sysdeps/linux.c sysdeps/netbsd.c sysdeps/openbsd.c \ sysdeps/solaris.c sysdeps/darwin.c sysdeps/sensors-common.c \ - sysdeps/win32.c + sysdeps/dragonfly.c sysdeps/win32.c GKRELLM_H = gkrellm.h gkrellm-private.h GKRELLM_H_SYS = gkrellm.h gkrellm-public-proto.h gkrellm-private.h \ diff --git a/src/sysdeps/dragonfly.c b/src/sysdeps/dragonfly.c new file mode 100644 index 0000000..362567f --- /dev/null +++ b/src/sysdeps/dragonfly.c @@ -0,0 +1,1176 @@ +/* GKrellM +| Copyright (C) 1999-2005 Bill Wilson +| +| Author: Bill Wilson bill@gkrellm.net +| Latest versions might be found at: http://gkrellm.net +| +| DragonFly code: Joerg Sonnenberger +| Derived from FreeBSD code: Hajimu UMEMOTO +| +| This program is free software which I release under the GNU General Public +| License. You may redistribute and/or modify this program under the terms +| of that license as published by the Free Software Foundation; either +| version 2 of the License, or (at your option) any later version. +| +| This program is distributed in the hope that it will be useful, +| but WITHOUT ANY WARRANTY; without even the implied warranty of +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +| GNU General Public License for more details. Version 2 is in the +| COPYRIGHT file in the top level directory of this distribution. +| +| To get a copy of the GNU General Puplic License, write to the Free Software +| Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include + +kvm_t *kvmd = NULL; +char errbuf[_POSIX2_LINE_MAX]; + + +// extern gboolean force_meminfo_update(void); +#if defined(__i386__) +static void scan_for_sensors(); +#endif + + +void +gkrellm_sys_main_init(void) + { + /* We just ignore error, here. Even if GKrellM doesn't have + | kmem privilege, it runs with available information. + */ + kvmd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf); + if (setgid(getgid()) != 0) + { + fprintf(stderr, "Can't drop setgid privileges."); + exit(1); + } +#if defined(__i386__) + scan_for_sensors(); +#endif + if (setuid(getuid()) != 0) + { + fprintf(stderr, "Can't drop setuid privileges."); + exit(1); + } + } + +void +gkrellm_sys_main_cleanup(void) + { + } + +#include +#include + +static int +gk_sysctlnametomib(const char *name, int *mibp, size_t *lenp) + { + static int oid_name2oid[2] = { 0, 3 }; + + if (sysctl(oid_name2oid, 2, mibp, lenp, + (void *)name, strlen(name)) < 0) + return -1; + *lenp /= sizeof(int); + return 0; + } + +/* ===================================================================== */ +/* CPU monitor interface */ + +#include +#include + +static gint ncpus; +static struct kinfo_cputime *cp_time; + +static gint +get_ncpus(void) +{ + static int mib[] = { CTL_HW, HW_NCPU }; + int ncpus; + int len = sizeof(int); + + if (sysctl(mib, 2, &ncpus, &len, NULL, 0) < 0) + return 1; + else + return ncpus; +} + +void +gkrellm_sys_cpu_read_data(void) +{ + int len, n; + + if (!cp_time) + return; + + len = sizeof (*cp_time) * ncpus; + if (sysctlbyname("kern.cputime", cp_time, &len, NULL, 0) != 0) + return; + + for (n = 0; n < ncpus; n++) + gkrellm_cpu_assign_data(n, cp_time[n].cp_user, + cp_time[n].cp_nice, + cp_time[n].cp_sys, + cp_time[n].cp_idle); +} + +gboolean +gkrellm_sys_cpu_init(void) +{ + ncpus = get_ncpus(); + gkrellm_cpu_set_number_of_cpus(ncpus); + cp_time = malloc (ncpus * sizeof *cp_time); + return TRUE; +} + +/* ===================================================================== */ +/* Proc monitor interface */ + +#include +#include +#include + +/* + * This is ugly, but we need PID_MAX, in anyway. Since 5.0-RELEASE + * will have vm.stats.vm.v_forks, this will be obsolete in the future. + */ +#define PID_MAX 99999 + +#include +#include +#include +#include + +extern kvm_t *kvmd; + +static int oid_v_forks[CTL_MAXNAME + 2]; +static int oid_v_vforks[CTL_MAXNAME + 2]; +static int oid_v_rforks[CTL_MAXNAME + 2]; +static size_t oid_v_forks_len = sizeof(oid_v_forks); +static size_t oid_v_vforks_len = sizeof(oid_v_vforks); +static size_t oid_v_rforks_len = sizeof(oid_v_rforks); + +gboolean +gkrellm_sys_proc_init(void) + { + static const char *name = "vm.stats.vm.v_forks"; + static const char *vname = "vm.stats.vm.v_vforks"; + static const char *rname = "vm.stats.vm.v_rforks"; + + /* check if vm.stats.vm.v_forks is available */ + if (gk_sysctlnametomib(name, oid_v_forks, &oid_v_forks_len) < 0) + return FALSE; + if (gk_sysctlnametomib(vname, oid_v_vforks, &oid_v_vforks_len) < 0) + return FALSE; + if (gk_sysctlnametomib(rname, oid_v_rforks, &oid_v_rforks_len) < 0) + return FALSE; + return TRUE; + } + +void +gkrellm_sys_proc_read_data(void) + { + static int oid_proc[] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL }; + double avenrun; + u_int n_forks, n_vforks, n_rforks, n_processes; + int r_forks, r_vforks, r_rforks; + size_t len; + + if (getloadavg(&avenrun, 1) <= 0) + avenrun = 0; + + /* We don't want to just use sysctlbyname(). Because, + * we call it so often. */ + len = sizeof(n_forks); + r_forks = sysctl(oid_v_forks, oid_v_forks_len, + &n_forks, &len, NULL, 0); + len = sizeof(n_vforks); + r_vforks = sysctl(oid_v_vforks, oid_v_vforks_len, + &n_vforks, &len, NULL, 0); + len = sizeof(n_rforks); + r_rforks = sysctl(oid_v_rforks, oid_v_rforks_len, + &n_rforks, &len, NULL, 0); + if (r_forks >= 0 && r_vforks >= 0 && r_rforks >= 0) + n_forks = n_forks + n_vforks + n_rforks; + else + n_forks = 0; + + if (sysctl(oid_proc, 3, NULL, &len, NULL, 0) >= 0) + n_processes = len / sizeof(struct kinfo_proc); + else + n_processes = 0; + gkrellm_proc_assign_data(n_processes, 0, n_forks, avenrun); + } + +void +gkrellm_sys_proc_read_users(void) + { + gint n_users; + struct stat sb, s; + gchar ttybuf[MAXPATHLEN]; + FILE *ut; + struct utmp utmp; + static time_t utmp_mtime; + + if (stat(_PATH_UTMP, &s) != 0 || s.st_mtime == utmp_mtime) + return; + if ((ut = fopen(_PATH_UTMP, "r")) != NULL) + { + n_users = 0; + while (fread(&utmp, sizeof(utmp), 1, ut)) + { + if (utmp.ut_name[0] == '\0') + continue; + (void)snprintf(ttybuf, sizeof(ttybuf), "%s/%s", + _PATH_DEV, utmp.ut_line); + /* corrupted record */ + if (stat(ttybuf, &sb)) + continue; + ++n_users; + } + (void)fclose(ut); + gkrellm_proc_assign_users(n_users); + } + utmp_mtime = s.st_mtime; + } + + +/* ===================================================================== */ +/* Disk monitor interface */ + +#include +static struct statinfo statinfo_cur; + +gchar * +gkrellm_sys_disk_name_from_device(gint device_number, gint unit_number, + gint *order) + { + return NULL; /* Not implemented */ + } + +gint +gkrellm_sys_disk_order_from_name(gchar *name) + { + return -1; /* Append as added */ + } + +void +gkrellm_sys_disk_read_data(void) + { + int ndevs; + int num_selected; + int num_selections; + int maxshowdevs = 10; + struct device_selection *dev_select = NULL; + long select_generation; + int dn; + gchar name[32]; + + if (getdevs(&statinfo_cur) < 0) + return; + ndevs = statinfo_cur.dinfo->numdevs; + if (selectdevs(&dev_select, &num_selected, &num_selections, + &select_generation, statinfo_cur.dinfo->generation, + statinfo_cur.dinfo->devices, ndevs, + NULL, 0, NULL, 0, + DS_SELECT_ONLY, maxshowdevs, 1) >= 0) + { + for (dn = 0; dn < ndevs; ++dn) + { + int di; + struct devstat *dev; +// int block_size; +// int blocks_read, blocks_written; + + di = dev_select[dn].position; + dev = &statinfo_cur.dinfo->devices[di]; +// block_size = (dev->block_size > 0) +// ? dev->block_size : 512; +// blocks_read = dev->bytes_read / block_size; +// blocks_written = dev->bytes_written / block_size; + + /* to use gkrellm_disk_assign_data_by_device() would need + gkrellm_sys_disk_name_from_device() implemented */ + snprintf(name, sizeof(name), "%s%d", dev->device_name, + dev->unit_number); + gkrellm_disk_assign_data_by_name(name, + dev->bytes_read, dev->bytes_written, FALSE); + } + free(dev_select); + } + } + +gboolean +gkrellm_sys_disk_init(void) + { + bzero(&statinfo_cur, sizeof(statinfo_cur)); + statinfo_cur.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo)); + bzero(statinfo_cur.dinfo, sizeof(struct devinfo)); + return TRUE; + } + + +/* ===================================================================== */ +/* Inet monitor interface */ + +#include "../inet.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +void +gkrellm_sys_inet_read_tcp_data(void) + { + void *so_begin, *so_end; + struct xtcpcb *xtp; + struct inpcb *inp; + struct xsocket *so; + const char *varname, *protoname; + size_t len; + void *buf; + int vflag; + ActiveTCP tcp; + gint tcp_status; + + varname = "net.inet.tcp.pcblist"; + protoname = "tcp"; + + vflag = INP_IPV4 | INP_IPV6; + + buf = NULL; + len = 0; + + if (sysctlbyname(varname, NULL, &len, NULL, 0)) { + goto out; + } + if ((buf = malloc(len)) == NULL) + goto out; + if (sysctlbyname(varname, buf, &len, NULL, 0)) { + goto out; + + so_begin = buf; + so_end = (uint8_t *)buf + len; + + for (so_begin = buf, so_end = (uint8_t *)so_begin + len; + (uint8_t *)so_begin + sizeof(size_t) < (uint8_t *)so_end && + (uint8_t *)so_begin + *(size_t *)so_begin <= (uint8_t *)so_end; + so_begin = (uint8_t *)so_begin + *(size_t *)so_begin) { + xtp = (struct xtcpcb *)so_begin; + if (xtp->xt_len != sizeof *xtp) + goto out; + inp = &xtp->xt_inp; + so = &xtp->xt_socket; + if ((inp->inp_vflag & vflag) == 0) + continue; + if (inp->inp_vflag & INP_IPV4) { + tcp.remote_addr.s_addr = inp->inp_faddr.s_addr; + tcp.family = AF_INET; + } else if (inp->inp_vflag & INP_IPV6) { + memcpy(&tcp.remote_addr6, + &inp->in6p_faddr, + sizeof(struct in6_addr)); + tcp.family = AF_INET6; + } + + tcp.remote_port = ntohs(inp->inp_fport); + tcp.local_port = ntohs(inp->inp_lport); + tcp_status = (xtp->xt_tp.t_state == TCPS_ESTABLISHED); + if (tcp_status == TCP_ALIVE) + gkrellm_inet_log_tcp_port_data(&tcp); + } + } +out: + free(buf); + } + + +gboolean +gkrellm_sys_inet_init(void) + { + return TRUE; + } + + +/* ===================================================================== */ +/* Memory/Swap monitor interface */ + +#include +#include +#include +#include +#include +#include +#include + +extern char errbuf[]; + +static int +swapmode(guint64 *retavail, guint64 *retfree) + { + guint64 used, avail; + static int psize = -1; + struct kvm_swap kvmswap; + + /* + * Counter for error messages. If we reach the limit, + * stop reading information from swap devices and + * return zero. This prevent endless 'bad address' + * messages. + */ + static int warning = 10; + + if (warning <= 0) + { + /* a single warning */ + if (!warning) + { + warning--; + fprintf(stderr, "Too much errors, stop reading swap devices ...\n"); + } + return(0); + } + warning--; /* decrease counter, see end of function */ + + if (kvmd == NULL) + return(0); + if (kvm_getswapinfo(kvmd, &kvmswap, 1, 0) < 0) + { + fprintf(stderr, "kvm_getswapinfo failed\n"); + return(0); + } + + if (psize < 0) + psize = getpagesize(); + *retavail = avail = (quad_t)kvmswap.ksw_total * psize; + used = (quad_t)kvmswap.ksw_used * psize; + *retfree = avail - used; + + /* increase counter, no errors occurs */ + warning++; + + return (int)(((double)used / (double)avail * 100.0) + 0.5); + } + +static int +get_bufspace(guint64 *bufspacep) + { + static const char *name = "vfs.bufspace"; + static int oid_bufspace[CTL_MAXNAME + 2]; + static size_t oid_bufspace_len = sizeof(oid_bufspace); + static gint initialized = 0; + u_int bufspace; + size_t bufspace_len = sizeof(bufspace); + + if (!initialized) + { + if (gk_sysctlnametomib(name, oid_bufspace, + &oid_bufspace_len) < 0) + return 0; + ++initialized; + } + + if (sysctl(oid_bufspace, oid_bufspace_len, + &bufspace, &bufspace_len, 0, 0) < 0) + return 0; + *bufspacep = bufspace; + return 1; + } + +struct mibtab { + char *name; + int oid[CTL_MAXNAME + 2]; + size_t oid_len; + u_int value; + size_t value_len; +}; + +static struct mibtab mibs[] = { +#define MIB_V_PAGE_COUNT 0 + { "vm.stats.vm.v_page_count" }, +#define MIB_V_FREE_COUNT 1 + { "vm.stats.vm.v_free_count" }, +#define MIB_V_WIRE_COUNT 2 + { "vm.stats.vm.v_wire_count" }, +#define MIB_V_ACTIVE_COUNT 3 + { "vm.stats.vm.v_active_count" }, +#define MIB_V_INACTIVE_COUNT 4 + { "vm.stats.vm.v_inactive_count" }, +#define MIB_V_CACHE_COUNT 5 + { "vm.stats.vm.v_cache_count" }, +#define MIB_V_SWAPPGSIN 6 + { "vm.stats.vm.v_swappgsin" }, +#define MIB_V_SWAPPGSOUT 7 + { "vm.stats.vm.v_swappgsout" }, + { NULL } +}; + +#define PROC_MEMINFO_FILE "/compat/linux/proc/meminfo" + +#ifndef VM_TOTAL +#define VM_TOTAL VM_METER +#endif + +static guint64 swapin, + swapout, + swap_total, + swap_used; + +void +gkrellm_sys_mem_read_data(void) + { + static gint psize, pshift = 0; + static gint first_time_done = 0; + guint64 total, used, x_used, free, shared, buffers, cached; + struct vmtotal vmt; + size_t length_vmt = sizeof(vmt); + static int oid_vmt[] = { CTL_VM, VM_TOTAL }; + gint i; + FILE *f; + gchar buf[160]; + +#if 0 + /* mem.c does a force_meminfo_update() before calling this */ + /* Collecting meminfo data is expensive under FreeBSD, so + | take extra precautions to minimize reading it. + */ + if (!GK.ten_second_tick && !force_meminfo_update()) + return; +#endif + + if (pshift == 0) + { + for (psize = getpagesize(); psize > 1; psize >>= 1) + pshift++; + } + + shared = 0; + + if (!first_time_done) + { + for (i = 0; mibs[i].name; ++i) + { + mibs[i].oid_len = sizeof(mibs[i].oid); + if (gk_sysctlnametomib(mibs[i].name, + mibs[i].oid, + &mibs[i].oid_len) < 0) + return; + mibs[i].value_len = sizeof(mibs[i].value); + } + ++first_time_done; + } + for (i = 0; mibs[i].name; ++i) + if (sysctl(mibs[i].oid, mibs[i].oid_len, + &mibs[i].value, + &mibs[i].value_len, 0, 0) < 0) + return; + total = (mibs[MIB_V_PAGE_COUNT].value - + mibs[MIB_V_WIRE_COUNT].value) << pshift; + x_used = (mibs[MIB_V_ACTIVE_COUNT].value + + mibs[MIB_V_INACTIVE_COUNT].value) << pshift; + free = mibs[MIB_V_FREE_COUNT].value << pshift; + if (sysctl(oid_vmt, 2, &vmt, &length_vmt, NULL, 0) == 0) + shared = vmt.t_rmshr << pshift; + get_bufspace(&buffers); + cached = mibs[MIB_V_CACHE_COUNT].value << pshift; + used = x_used - buffers - cached; + gkrellm_mem_assign_data(total, used, free, shared, buffers, cached); + + swapin = mibs[MIB_V_SWAPPGSIN].value; + swapout = mibs[MIB_V_SWAPPGSOUT].value; + + if (kvmd == NULL) { + /* Try linprocfs for swap info */ + if ((f = fopen(PROC_MEMINFO_FILE, "r")) == NULL) + return; + /* total: used: free: shared: buffers: cached: */ + while ((fgets(buf, sizeof(buf), f)) != NULL) + { + if (strncmp(buf, "Swap:", 5) == 0) + { + sscanf(buf, "Swap: %llu %llu", + &swap_total, &swap_used); + break; + } + } + fclose(f); + return; + } + + if (first_time_done == 0) + { + swapmode(&swap_total, &swap_used); + swap_used = swap_total - swap_used; + first_time_done = 1; + } + } + +void +gkrellm_sys_swap_read_data(void) + { + gkrellm_swap_assign_data(swap_total, swap_used, swapin, swapout); + } + +gboolean +gkrellm_sys_mem_init(void) + { + return TRUE; + } + + +/* ===================================================================== */ +/* Battery monitor interface */ + +#if defined(__i386__) +#include +#include +#define APMDEV "/dev/apm" + +#define L_NO_BATTERY 0x80 +#define L_ON_LINE 1 +#define L_CHARGING 3 +#define L_UNKNOWN 0xFF + +/* following two definitions are taken from sys/dev/acpica/acpiio.h */ +#define ACPI_BATT_STAT_CHARGING 0x0002 +#define ACPI_BATT_STAT_NOT_PRESENT 0x0007 + +#define ACPI_ACLINE 0 +#define ACPI_BATT_LIFE 1 +#define ACPI_BATT_TIME 2 +#define ACPI_BATT_STATE 3 + +void +gkrellm_sys_battery_read_data(void) + { + static const char *name[] = { "hw.acpi.acline", + "hw.acpi.battery.life", + "hw.acpi.battery.time", + "hw.acpi.battery.state", + NULL }; + static int oid[CTL_MAXNAME + 2][4]; + static size_t oid_len[4] = { sizeof(oid[0]), sizeof(oid[1]), + sizeof(oid[2]), sizeof(oid[3]) }; + static gboolean first_time_done = FALSE; + static gboolean acpi_enabled = FALSE; + size_t size; + int acpi_info[4]; + int i; + int f, r; + struct apm_info info; + gboolean available, on_line, charging; + gint percent, time_left; + gint batt_num = 0; + + if (!first_time_done) + { + first_time_done = TRUE; +#ifdef ACPI_SUPPORTS_MULTIPLE_BATTERIES + /* + * XXX: Disable getting battery information via ACPI + * to support multiple batteries via APM sim until + * ACPI sysctls support multiple batteries. + */ + for (i = 0; name[i] != NULL; ++i) + { + if (gk_sysctlnametomib(name[i], oid[i], + &oid_len[i]) < 0) + break; + } + if (name[i] == NULL) + acpi_enabled = TRUE; +#endif + } + + if (acpi_enabled) + { + for (i = 0; name[i] != NULL; ++i) + { + size = sizeof(acpi_info[i]); + if (sysctl(oid[i], oid_len[i], + &acpi_info[i], &size, NULL, 0) < 0) + return; + } + available = (acpi_info[ACPI_BATT_STATE] != ACPI_BATT_STAT_NOT_PRESENT); + on_line = acpi_info[ACPI_ACLINE]; + charging = (acpi_info[ACPI_BATT_STATE] == ACPI_BATT_STAT_CHARGING); + percent = acpi_info[ACPI_BATT_LIFE]; + if (acpi_info[ACPI_BATT_TIME] == 0 && percent > 0) + time_left = -1; + else + time_left = acpi_info[ACPI_BATT_TIME]; + gkrellm_battery_assign_data( + GKRELLM_BATTERY_COMPOSITE_ID, available, + on_line, charging, percent, time_left); + return; + } + + if ((f = open(APMDEV, O_RDONLY)) == -1) + return; + if ((r = ioctl(f, APMIO_GETINFO, &info)) == -1) { + close(f); + return; + } + + available = (info.ai_batt_stat != L_UNKNOWN || + info.ai_acline == L_ON_LINE); + on_line = (info.ai_acline == L_ON_LINE) ? TRUE : FALSE; + charging = (info.ai_batt_stat == L_CHARGING) ? TRUE : FALSE; + percent = info.ai_batt_life; +#if defined(APM_GETCAPABILITIES) + if (info.ai_batt_time == -1 || (info.ai_batt_time == 0 && percent > 0)) + time_left = -1; + else + time_left = info.ai_batt_time / 60; +#else + time_left = -1; +#endif + gkrellm_battery_assign_data(GKRELLM_BATTERY_COMPOSITE_ID, available, + on_line, charging, percent, time_left); + +#if defined(APMIO_GETPWSTATUS) + if (info.ai_infoversion >= 1 && info.ai_batteries != (u_int) -1 && + info.ai_batteries > 1) + { + gint i; + struct apm_pwstatus aps; + + for (i = 0; i < info.ai_batteries; ++i) + { + bzero(&aps, sizeof(aps)); + aps.ap_device = PMDV_BATT0 + i; + if (ioctl(f, APMIO_GETPWSTATUS, &aps) == -1 || + (aps.ap_batt_flag != 255 && + (aps.ap_batt_flag & APM_BATT_NOT_PRESENT))) + continue; + available = (aps.ap_batt_stat != L_UNKNOWN || + aps.ap_acline == L_ON_LINE); + on_line = (aps.ap_acline == L_ON_LINE) ? TRUE : FALSE; + charging = (aps.ap_batt_stat == L_CHARGING) ? + TRUE : FALSE; + percent = aps.ap_batt_life; + if (aps.ap_batt_time == -1 || + (aps.ap_batt_time == 0 && percent > 0)) + time_left = -1; + else + time_left = aps.ap_batt_time / 60; + gkrellm_battery_assign_data(batt_num++, available, + on_line, charging, percent, + time_left); + } + } +#endif + + close(f); + } + +gboolean +gkrellm_sys_battery_init(void) + { + return TRUE; + } + +#else + +void +gkrellm_sys_battery_read_data(void) + { + } + +gboolean +gkrellm_sys_battery_init(void) + { + return FALSE; + } + +#endif + + +/* ===================================================================== */ +/* Sensor monitor interface */ + +#if defined(__i386__) + +typedef struct + { + gchar *name; + gfloat factor; + gfloat offset; + gchar *vref; + } + VoltDefault; + + /* Tables of voltage correction factors and offsets derived from the + | compute lines in sensors.conf. See the README file. + */ + /* "lm78-*" "lm78-j-*" "lm79-*" "w83781d-*" "sis5595-*" "as99127f-*" */ + /* Values from LM78/LM79 data sheets */ +static VoltDefault voltdefault0[] = + { + { "Vcor1", 1.0, 0, NULL }, + { "Vcor2", 1.0, 0, NULL }, + { "+3.3V", 1.0, 0, NULL }, + { "+5V", 1.68, 0, NULL }, /* in3 ((6.8/10)+1)*@ */ + { "+12V", 4.0, 0, NULL }, /* in4 ((30/10)+1)*@ */ + { "-12V", -4.0, 0, NULL }, /* in5 -(240/60)*@ */ + { "-5V", -1.667, 0, NULL } /* in6 -(100/60)*@ */ + }; + +#include +#include +#include +#if (__DragonFly_version < 200700) +#include +#else +#include +#endif + +/* Interface types */ +#define INTERFACE_IO 0 +#define INTERFACE_SMB 1 +#define INTERFACE_ACPI 2 + +/* Addresses to use for /dev/io */ +#define WBIO1 0x295 +#define WBIO2 0x296 + +/* LM78/79 addresses */ +#define LM78_VOLT(val) (0x20 + (val)) +#define LM78_TEMP 0x27 +#define LM78_FAN(val) (0x28 + (val)) +#define LM78_FANDIV 0x47 + +#define SENSORS_DIR "/dev" + +#define TZ_ZEROC 2732 +#define TZ_KELVTOC(x) ((gfloat)((x) - TZ_ZEROC) / 10.0) + + +static gint +get_data(int iodev, u_char command, int interface, u_char *ret) + { + u_char byte = 0; + + if (interface == INTERFACE_IO) + { + outb(WBIO1, command); + byte = inb(WBIO2); + } + else if (interface == INTERFACE_SMB) + { + struct smbcmd cmd; + + bzero(&cmd, sizeof(cmd)); + cmd.data.byte_ptr = &byte; + cmd.slave = 0x5a; + cmd.cmd = command; + if (ioctl(iodev, SMB_READB, (caddr_t)&cmd) == -1) + { + close(iodev); + return FALSE; + } + } + else + { + return FALSE; + } + if (byte == 0xff) + return FALSE; + *ret = byte; + return TRUE; + } + +gboolean +gkrellm_sys_sensors_get_temperature(gchar *path, gint id, + gint iodev, gint interface, gfloat *temp) + + { + u_char byte; + + if (interface == MBMON_INTERFACE) + { + gkrellm_sys_sensors_mbmon_check(FALSE); + return gkrellm_sys_sensors_mbmon_get_value(path, temp); + } + + if (interface == INTERFACE_ACPI) + { + int value; + size_t size = sizeof(value); + + if (sysctlbyname(path, &value, &size, NULL, 0) < 0) + return FALSE; + if (temp) + *temp = (gfloat) TZ_KELVTOC(value); + return TRUE; + } + if (get_data(iodev, LM78_TEMP, interface, &byte)) + { + if (temp) + *temp = (gfloat) byte; + return TRUE; + } + return FALSE; + } + +gboolean +gkrellm_sys_sensors_get_fan(gchar *path, gint id, + gint iodev, gint interface, gfloat *fan) + { + u_char byte; + + if (interface == MBMON_INTERFACE) + { + gkrellm_sys_sensors_mbmon_check(FALSE); + return gkrellm_sys_sensors_mbmon_get_value(path, fan); + } + + if (get_data(iodev, LM78_FAN(id), interface, &byte)) + { + if (byte == 0) + return FALSE; + if (fan) + *fan = 1.35E6 / (gfloat) byte; + return TRUE; + } + return FALSE; + } + +gboolean +gkrellm_sys_sensors_get_voltage(gchar *path, gint id, + gint iodev, gint interface, gfloat *volt) + { + u_char byte; + + if (interface == MBMON_INTERFACE) + { + gkrellm_sys_sensors_mbmon_check(FALSE); + return gkrellm_sys_sensors_mbmon_get_value(path, volt); + } + + if (get_data(iodev, LM78_VOLT(id), interface, &byte)) + { + if (volt) + *volt = (gfloat) byte / 64.0; + return TRUE; + } + return FALSE; + } + +struct freebsd_sensor { + gint type; + gchar *id_name; + gint id; + gint iodev; + gint inter; + gfloat factor; + gfloat offset; + gchar *default_label; +}; + +static GList *freebsd_sensor_list; + +gboolean +gkrellm_sys_sensors_init(void) + { + gchar mib_name[256], label[8]; + gint interface, id; + int oid_acpi_temp[CTL_MAXNAME + 2]; + size_t oid_acpi_temp_len = sizeof(oid_acpi_temp); + GList *list; + struct freebsd_sensor *sensor; + + /* Do intial daemon reads to get sensors loaded into sensors.c + */ + gkrellm_sys_sensors_mbmon_check(TRUE); + + for (id = 0;;) + { + snprintf(mib_name, sizeof(mib_name), + "hw.acpi.thermal.tz%d.temperature", id); + if (gk_sysctlnametomib(mib_name, oid_acpi_temp, + &oid_acpi_temp_len) < 0) + break; + interface = INTERFACE_ACPI; + if (!gkrellm_sys_sensors_get_temperature(mib_name, 0, 0, + interface, NULL)) + continue; + snprintf(label, sizeof(label), "tz%d", id); + gkrellm_sensors_add_sensor(SENSOR_TEMPERATURE, NULL, + mib_name, 0, 0, + interface, 1.0, 0.0, NULL, label); + } + + if (freebsd_sensor_list) + { + for (list = freebsd_sensor_list; list; list = list->next) + { + sensor = (struct freebsd_sensor *)list->data; + gkrellm_sensors_add_sensor(sensor->type, NULL, + sensor->id_name, sensor->id, + sensor->iodev, sensor->inter, + sensor->factor, sensor->offset, + NULL, sensor->default_label); + } + } + + return (TRUE); + } + +static gboolean +sensors_add_sensor(gint type, gchar *id_name, gint id, gint iodev, gint inter, + gfloat factor, gfloat offset, gchar *default_label) +{ + struct freebsd_sensor *sensor; + + if ((sensor = g_new0(struct freebsd_sensor, 1)) == NULL) + return FALSE; + sensor->type = type; + sensor->id_name = g_strdup(id_name); + sensor->id = id; + sensor->iodev = iodev; + sensor->inter = inter; + sensor->factor = factor; + sensor->offset = offset; + sensor->default_label = default_label ? g_strdup(default_label) : NULL; + if (g_list_append(freebsd_sensor_list, sensor) == NULL) { + g_free(sensor->id_name); + if (sensor->default_label) + g_free(sensor->default_label); + g_free(sensor); + return FALSE; + } + return TRUE; +} + +static void +scan_for_sensors(void) + { + gchar *chip_dir = SENSORS_DIR; + DIR *dir; + struct dirent *dentry; + gchar temp_file[256], id_name[8]; + gint iodev = -1, interface = -1, id; + gint fandiv[3]; + u_char byte; + gboolean found_sensors = FALSE; + + if ((dir = opendir(chip_dir)) != NULL) + { + while ((dentry = readdir(dir)) != NULL) + { + if (dentry->d_name[0] == '.' || dentry->d_ino <= 0) + continue; + if (strncmp(dentry->d_name, "smb", 3) != 0) + continue; + snprintf(temp_file, sizeof(temp_file), "%s/%s", + chip_dir, dentry->d_name); + if ((iodev = open(temp_file, O_RDWR)) == -1) + continue; + sprintf(id_name, "%s%3s", "temp", dentry->d_name + 3); + interface = INTERFACE_SMB; + if (!gkrellm_sys_sensors_get_temperature(NULL, 0, iodev, + interface, NULL)) + { + close(iodev); + continue; + } + sensors_add_sensor(SENSOR_TEMPERATURE, id_name, 0, + iodev, interface, 1.0, 0.0, NULL); + found_sensors = TRUE; + break; + } + closedir(dir); + } + if (!found_sensors) + { + snprintf(temp_file, sizeof(temp_file), "%s/%s", + chip_dir, "io"); + if ((iodev = open(temp_file, O_RDWR)) == -1) + return; + interface = INTERFACE_IO; + if (!gkrellm_sys_sensors_get_temperature(NULL, 0, iodev, + interface, NULL)) + { + close(iodev); + return; + } + sensors_add_sensor(SENSOR_TEMPERATURE, "temp0", 0, iodev, + interface, 1.0, 0.0, NULL); + found_sensors = TRUE; + } + if (found_sensors) + { + if (get_data(iodev, LM78_FANDIV, interface, &byte)) + { + fandiv[0] = 1 << ((byte & 0x30) >> 4); + fandiv[1] = 1 << ((byte & 0xc0) >> 6); + fandiv[2] = 2; + for (id = 0; id < 3; ++id) + { + if (!gkrellm_sys_sensors_get_fan(NULL, id, iodev, + interface, NULL)) + continue; + sprintf(id_name, "%s%d", "fan", id); + sensors_add_sensor(SENSOR_FAN, id_name, id, + iodev, interface, + 1.0 / (gfloat) fandiv[id], 0.0, + NULL); + } + } + for (id = 0; id < 7; ++id) + { + if (!gkrellm_sys_sensors_get_voltage(NULL, id, iodev, + interface, NULL)) + continue; + sprintf(id_name, "%s%d", "in", id); + sensors_add_sensor(SENSOR_VOLTAGE, id_name, id, + iodev, interface, + voltdefault0[id].factor, 0.0, + voltdefault0[id].name); + } + } + } + +#else + +gboolean +gkrellm_sys_sensors_get_temperature(gchar *path, gint id, + gint iodev, gint interface, gfloat *temp) + + { + return FALSE; + } + +gboolean +gkrellm_sys_sensors_get_fan(gchar *path, gint id, + gint iodev, gint interface, gfloat *fan) + { + return FALSE; + } + +gboolean +gkrellm_sys_sensors_get_voltage(gchar *path, gint id, + gint iodev, gint interface, gfloat *volt) + { + return FALSE; + } + +gboolean +gkrellm_sys_sensors_init(void) + { + return FALSE; + } + +#endif