Package: gkrellm Version: 2.3.1-1 Followup-For: Bug #476641 Naturally, I found a small bug in my patch right after I sent it out. Updated patch attached.
Schwab -- System Information: Debian Release: lenny/sid APT prefers unstable APT policy: (500, 'unstable'), (500, 'testing'), (500, 'stable') Architecture: i386 (i686) Kernel: Linux 2.6.24 (SMP w/2 CPU cores; PREEMPT) Locale: LANG=en_US.UTF-8, LC_CTYPE=en_US.UTF-8 (charmap=UTF-8) Shell: /bin/sh linked to /bin/bash Versions of packages gkrellm depends on: ii libatk1.0-0 1.22.0-1 The ATK accessibility toolkit ii libc6 2.7-6 GNU C Library: Shared libraries ii libcairo2 1.4.14-1 The Cairo 2D vector graphics libra ii libgcrypt11 1.4.0-3 LGPL Crypto library - runtime libr ii libglib2.0-0 2.16.3-1 The GLib library of C routines ii libgnutls13 2.0.4-3 the GNU TLS library - runtime libr ii libgtk2.0-0 2.12.9-2 The GTK+ graphical user interface ii libice6 2:1.0.4-1 X11 Inter-Client Exchange library ii libpango1.0-0 1.20.2-2 Layout and rendering of internatio ii libsm6 2:1.0.3-1+b1 X11 Session Management library ii libx11-6 2:1.0.3-7 X11 client-side library gkrellm recommends no packages. -- no debconf information
diff -ru gkrellm-2.3.1/src/sysdeps/linux.c gkrellm-2.3.1-new/src/sysdeps/linux.c --- gkrellm-2.3.1/src/sysdeps/linux.c 2007-10-30 12:12:46.000000000 -0700 +++ gkrellm-2.3.1-new/src/sysdeps/linux.c 2008-04-18 00:02:16.000000000 -0700 @@ -1441,12 +1441,13 @@ /* ===================================================================== */ /* Battery monitor interface */ -/* ---------------------------- */ -/* ACPI battery interface */ +/* ---------------------- */ +/* ACPI battery interface */ #define ACPI_BATTERY_DIR "/proc/acpi/battery/" #define ACPI_AC_ADAPTOR_DIR "/proc/acpi/ac_adapter/" + typedef struct { gint id; @@ -1557,6 +1558,7 @@ } } + static gboolean fgets_lower_case(gchar *buf, gint len, FILE *f) { @@ -1727,6 +1729,328 @@ return TRUE; } + +/* ---------------------------- */ +/* sysfs power interface */ +#define SYSFS_POWER_SUPPLIES "/sys/class/power_supply/" +#define SYSFS_TYPE_BATTERY "battery" +#define SYSFS_TYPE_AC_ADAPTER "mains" + + +typedef struct syspower + { + gint type; + gint id; + gint charge_units; + gchar const *sysdir; + gchar const *sys_charge_full; + gchar const *sys_charge_now; + gboolean present; + gboolean ac_present; + gboolean charging; + } + syspower; +#define PWRTYPE_BATTERY 0 +#define PWRTYPE_UPS 1 +#define PWRTYPE_MAINS 2 +#define PWRTYPE_USB 3 + +#define CHGUNITS_INVALID 0 +#define CHGUNITS_PERCENT 1 /* 'capacity' */ +#define CHGUNITS_uWH 2 /* 'energy' */ +#define CHGUNITS_uAH 3 /* 'charge' */ + +/* + * Ordering in this list is significant: Mains power sources appear before + * battery sources. + */ +static GList *g_sysfs_power_list; +static gint g_on_line; +static gint g_pwr_id; + + +static gboolean +read_sysfs_entry (gchar *buf, gint buflen, gchar const *sysentry) + { + FILE *f; + + if ((f = fopen (sysentry, "r"))) + { + if (fgets (buf, buflen, f)) + { + gchar *nl; + + /* Squash trailing newline if present. */ + nl = buf + strlen (buf) - 1; + if (*nl == '\n') + *nl = '\0'; + fclose (f); + return TRUE; + } + fclose (f); + } + return FALSE; + } + +static gboolean +sysfs_power_data (struct syspower *sp) + { + uint64_t charge_full, charge_now; + gint time_left; + gint present; + gint percent; + gchar sysentry[128]; + gchar buf[128]; + gchar *syszap; + gboolean charging; + gboolean stat_full; + + time_left = -1; + charge_full = charge_now = 0; + present = 0; + percent = 0; + charging = FALSE; + + strcpy (sysentry, sp->sysdir); + syszap = sysentry + strlen (sysentry); + + /* What type of entry is this? */ + if (sp->type == PWRTYPE_MAINS) + { + /* Get the 'on-line' status. */ + *syszap = '\0'; + strcat (sysentry, "/online"); + if (read_sysfs_entry (buf, sizeof (buf), sysentry)) + g_on_line = strtol (buf, NULL, 0); + return TRUE; + } + + /* + * The rest of this code doesn't know how to handle anything other than + * a battery. + */ + if (sp->type != PWRTYPE_BATTERY) + return FALSE; + + /* Is the battery still there? */ + *syszap = '\0'; + strcat (sysentry, "/present"); + if (read_sysfs_entry (buf, sizeof (buf), sysentry)) + present = strtol (buf, NULL, 0); + + if (present) + { + if (read_sysfs_entry (buf, sizeof (buf), sp->sys_charge_full)) + { + charge_full = strtoll (buf, NULL, 0); + } + if (read_sysfs_entry (buf, sizeof (buf), sp->sys_charge_now)) + { + charge_now = strtoll (buf, NULL, 0); + } + if (sp->charge_units == CHGUNITS_PERCENT) + { + percent = charge_now; + } + else + { + percent = charge_now * 100 / charge_full; + } + + /* Get charging status. */ + *syszap = '\0'; + strcat (sysentry, "/status"); + if (read_sysfs_entry (buf, sizeof (buf), sysentry)) + { + charging = !strcasecmp (buf, "charging"); + stat_full = !strcasecmp (buf, "full"); + } + } + + gkrellm_battery_assign_data (sp->id, present, g_on_line, charging, + percent, time_left); + return TRUE; + } + + +static gboolean +setup_sysfs_ac_power (gchar const *sysdir) + { + syspower *sp; + + if (_GK.debug_level & DEBUG_BATTERY) + printf ("setup_sysfs_ac_power: %s\n", sysdir); + sp = g_new0 (syspower, 1); + sp->type = PWRTYPE_MAINS; + sp->id = g_pwr_id++; + sp->charge_units = CHGUNITS_INVALID; + sp->sysdir = g_strdup (sysdir); + sp->sys_charge_full = + sp->sys_charge_now = NULL; + + /* Add mains power sources to head of list. */ + g_sysfs_power_list = g_list_prepend (g_sysfs_power_list, sp); + + return TRUE; + } + +static gboolean +setup_sysfs_battery (gchar const *sysdir) + { + syspower *sp; + gchar *sys_charge_full = NULL, + *sys_charge_now = NULL; + gint units; + gboolean retval = FALSE; + + /* + * There are three flavors of reporting: 'energy', 'charge', and + * 'capacity'. Check for them in that order. (Apologies for the + * ugliness; you try coding an unrolled 'if ((A || B) && C)' and make it + * pretty.) + */ + if (_GK.debug_level & DEBUG_BATTERY) + printf ("setup_sysfs_battery: %s\n", sysdir); + units = CHGUNITS_uWH; + sys_charge_full = g_strconcat (sysdir, "/energy_full", NULL); + if (access (sys_charge_full, F_OK | R_OK)) + { + free (sys_charge_full); + sys_charge_full = g_strconcat (sysdir, "/energy_full_design", NULL); + if (access (sys_charge_full, F_OK | R_OK)) + { + goto try_charge; /* Look down */ + } + } + sys_charge_now = g_strconcat (sysdir, "/energy_now", NULL); + if (!access (sys_charge_now, F_OK | R_OK)) + goto done; /* Look down */ + +try_charge: + if (sys_charge_full) free (sys_charge_full), sys_charge_full = NULL; + if (sys_charge_now) free (sys_charge_now), sys_charge_now = NULL; + + units = CHGUNITS_uAH; + sys_charge_full = g_strconcat (sysdir, "/charge_full", NULL); + if (access (sys_charge_full, F_OK | R_OK)) + { + free (sys_charge_full); + sys_charge_full = g_strconcat (sysdir, "/charge_full_design", NULL); + if (access (sys_charge_full, F_OK | R_OK)) + { + goto try_capacity; /* Look down */ + } + } + sys_charge_now = g_strconcat (sysdir, "/charge_now", NULL); + if (!access (sys_charge_now, F_OK | R_OK)) + goto done; /* Look down */ + +try_capacity: + if (sys_charge_full) free (sys_charge_full), sys_charge_full = NULL; + if (sys_charge_now) free (sys_charge_now), sys_charge_now = NULL; + + /* This one's a little simpler... */ + units = CHGUNITS_PERCENT; + /* + * FIXME: I have no idea if 'capacity_full' actually shows up, since + * 'capacity' always defines "full" as always 100% + */ + sys_charge_full = g_strconcat (sysdir, "/capacity_full", NULL); + if (access (sys_charge_full, F_OK | R_OK)) + goto ackphft; /* Look down */ + + sys_charge_now = g_strconcat (sysdir, "/capacity_now", NULL); + if (access (sys_charge_now, F_OK | R_OK)) + goto ackphft; /* Look down */ + +done: + sp = g_new0 (syspower, 1); + sp->type = PWRTYPE_BATTERY; + sp->id = g_pwr_id++; + sp->charge_units = units; + sp->sysdir = g_strdup (sysdir); + sp->sys_charge_full = sys_charge_full; + sp->sys_charge_now = sys_charge_now; + + /* Battery power sources are appended to the end of the list. */ + g_sysfs_power_list = g_list_append (g_sysfs_power_list, sp); + if (_GK.debug_level & DEBUG_BATTERY) + printf ("setup_sysfs_battery: %s, %s\n", + sys_charge_full, sys_charge_now); + retval = TRUE; + + if (0) + { +ackphft: + if (sys_charge_full) free (sys_charge_full); + if (sys_charge_now) free (sys_charge_now); + } + return retval; + } + +static gboolean +setup_sysfs_power_entry (gchar const *sysentry) + { + gchar *sysdir; + gboolean retval = FALSE; + + sysdir = g_strconcat (SYSFS_POWER_SUPPLIES, sysentry, NULL); + if (!access (sysdir, F_OK | R_OK)) + { + /* + * Read the type of this power source, and setup the appropriate + * entry for it. + */ + gchar *type; + gchar buf[64]; + + type = g_strconcat (sysdir, "/type", NULL); + if (_GK.debug_level & DEBUG_BATTERY) + printf ("setup_sysfs_power_entry: checking %s\n", type); + if (read_sysfs_entry (buf, sizeof (buf), type)) + { + if (!strcasecmp (buf, SYSFS_TYPE_AC_ADAPTER)) + retval = setup_sysfs_ac_power (sysdir); + else if (!strcasecmp (buf, SYSFS_TYPE_BATTERY)) + retval = setup_sysfs_battery (sysdir); + else if (_GK.debug_level & DEBUG_BATTERY) + printf ("setup_sysfs_power_entry: unknown power type: %s\n", + buf); + } + g_free (type); + } + free (sysdir); + + return retval; + } + +static gboolean +sysfs_power_setup (void) + { + DIR *d; + struct dirent *de; + gboolean retval = FALSE; + + if (_GK.debug_level & DEBUG_BATTERY) + printf ("sysfs_power_setup() entry\n"); + if ((d = opendir (SYSFS_POWER_SUPPLIES)) == NULL) + return retval; + + while ((de = readdir (d)) != NULL) + { + if ( !strcmp (de->d_name, ".") + || !strcmp (de->d_name, "..")) + { + continue; + } + retval |= setup_sysfs_power_entry (de->d_name); + } + closedir (d); + + return retval; + } + + /* ---------------------------- */ /* APM battery interface */ @@ -1871,9 +2195,16 @@ { GList *list; - if (acpi_battery_list) - for (list = acpi_battery_list; list; list = list->next) + if (g_sysfs_power_list) + { + for (list = g_sysfs_power_list; list; list = list->next) + sysfs_power_data ((syspower *) (list->data)); + } + else if (acpi_battery_list) + { + for (list = acpi_battery_list; list; list = list->next) acpi_battery_data((BatteryFile *)(list->data)); + } else apm_battery_data(); } @@ -1881,7 +2212,9 @@ gboolean gkrellm_sys_battery_init() { - acpi_setup(); + /* Prefer sysfs power data to /proc/acpi (which is deprecated). */ + if (!sysfs_power_setup ()) + acpi_setup(); return TRUE; }