diff options
Diffstat (limited to 'battstat/acpi-linux.c')
-rw-r--r-- | battstat/acpi-linux.c | 632 |
1 files changed, 321 insertions, 311 deletions
diff --git a/battstat/acpi-linux.c b/battstat/acpi-linux.c index afda8fd7..c383bd2e 100644 --- a/battstat/acpi-linux.c +++ b/battstat/acpi-linux.c @@ -24,7 +24,7 @@ */ #ifdef HAVE_CONFIG_H - #include <config.h> + #include <config.h> #endif #ifdef __linux__ @@ -44,91 +44,92 @@ #include <dirent.h> #include "acpi-linux.h" -static GHashTable* read_file(const char* file, char* buf, size_t bufsize) +static GHashTable* +read_file (const char* file, char* buf, size_t bufsize) { - GHashTable* hash = NULL; - - int fd, len, i; - char* key; - char* value; - gboolean reading_key; - - fd = open(file, O_RDONLY); - - if (fd == -1) - { - return hash; - } - - len = read(fd, buf, bufsize); - - close (fd); - - if (len < 0) - { - if (getenv("BATTSTAT_DEBUG")) - { - g_message("Error reading %s: %s", file, g_strerror(errno)); - } - - return hash; - } - - hash = g_hash_table_new(g_str_hash, g_str_equal); - - for (i = 0, value = key = buf, reading_key = TRUE; i < len; i++) - { - if (buf[i] == ':' && reading_key) - { - reading_key = FALSE; - buf[i] = '\0'; - value = buf + i + 1; - } - else if (buf[i] == '\n') - { - reading_key = TRUE; - buf[i] = '\0'; - /* g_message ("Read: %s => %s\n", key, value); */ - g_hash_table_insert(hash, key, g_strstrip(value)); - key = buf + i + 1; - } - else if (reading_key) - { - /* in acpi 20020214 it switched to lower-case proc - * entries. fixing this up here simplifies the - * code. - */ - buf[i] = g_ascii_tolower(buf[i]); - } - } - - return hash; + GHashTable* hash = NULL; + + int fd, len, i; + char* key; + char* value; + gboolean reading_key; + + fd = open (file, O_RDONLY); + + if (fd == -1) + { + return hash; + } + + len = read (fd, buf, bufsize); + + close (fd); + + if (len < 0) + { + if (getenv ("BATTSTAT_DEBUG")) + { + g_message ("Error reading %s: %s", file, g_strerror (errno)); + } + + return hash; + } + + hash = g_hash_table_new (g_str_hash, g_str_equal); + + for (i = 0, value = key = buf, reading_key = TRUE; i < len; i++) + { + if (buf[i] == ':' && reading_key) + { + reading_key = FALSE; + buf[i] = '\0'; + value = buf + i + 1; + } + else if (buf[i] == '\n') + { + reading_key = TRUE; + buf[i] = '\0'; + /* g_message ("Read: %s => %s\n", key, value); */ + g_hash_table_insert (hash, key, g_strstrip (value)); + key = buf + i + 1; + } + else if (reading_key) + { + /* in acpi 20020214 it switched to lower-case proc + * entries. fixing this up here simplifies the + * code. + */ + buf[i] = g_ascii_tolower (buf[i]); + } + } + + return hash; } #if 0 static gboolean read_bool (GHashTable *hash, const char *key) { - char *s; + char *s; - g_return_val_if_fail (hash, FALSE); - g_return_val_if_fail (key, FALSE); + g_return_val_if_fail (hash, FALSE); + g_return_val_if_fail (key, FALSE); - s = g_hash_table_lookup (hash, key); - return s && (*s == 'y'); + s = g_hash_table_lookup (hash, key); + return s && (*s == 'y'); } #endif static long read_long (GHashTable *hash, const char *key) { - char* s; + char* s; - g_return_val_if_fail(hash, 0); - g_return_val_if_fail(key, 0); + g_return_val_if_fail (hash, 0); + g_return_val_if_fail (key, 0); - s = g_hash_table_lookup(hash, key); - return s ? strtol(s, NULL, 10) : 0; + s = g_hash_table_lookup (hash, key); + return s ? strtol (s, NULL, 10) : 0; } static gulong @@ -136,112 +137,114 @@ read_ulong (GHashTable *hash, const char *key) { char *s; - g_return_val_if_fail (hash, 0); - g_return_val_if_fail (key, 0); + g_return_val_if_fail (hash, 0); + g_return_val_if_fail (key, 0); - s = g_hash_table_lookup (hash, key); - return s ? strtoul (s, NULL, 10) : 0; + s = g_hash_table_lookup (hash, key); + return s ? strtoul (s, NULL, 10) : 0; } static const char * read_string (GHashTable *hash, const char *key) { - return g_hash_table_lookup (hash, key); + return g_hash_table_lookup (hash, key); } /* Reads the current status of the AC adapter and stores the * result in acpiinfo->ac_online. */ -static gboolean update_ac_info(struct acpi_info * acpiinfo) +static gboolean +update_ac_info (struct acpi_info * acpiinfo) { - gchar *ac_state = NULL; - DIR * procdir; - struct dirent * procdirentry; - char buf[BUFSIZ]; - GHashTable *hash; - gboolean have_adaptor = FALSE; - - acpiinfo->ac_online = FALSE; - - procdir=opendir("/proc/acpi/ac_adapter/"); - if (!procdir) - return FALSE; - - while ((procdirentry=readdir(procdir))) - { - if (procdirentry->d_name[0]!='.') - { - have_adaptor = TRUE; - ac_state = g_strconcat("/proc/acpi/ac_adapter/", - procdirentry->d_name, - "/", - acpiinfo->ac_state_state, - NULL); - hash = read_file (ac_state, buf, sizeof (buf)); - if (hash && !acpiinfo->ac_online) - { - const char *s; - s = read_string (hash, acpiinfo->ac_state_state); - acpiinfo->ac_online = s ? (strcmp (s, "on-line") == 0) : 0; - g_hash_table_destroy (hash); - } - g_free(ac_state); - } - } + gchar *ac_state = NULL; + DIR * procdir; + struct dirent * procdirentry; + char buf[BUFSIZ]; + GHashTable *hash; + gboolean have_adaptor = FALSE; + + acpiinfo->ac_online = FALSE; + + procdir=opendir ("/proc/acpi/ac_adapter/"); + if (!procdir) + return FALSE; + + while ((procdirentry=readdir (procdir))) + { + if (procdirentry->d_name[0]!='.') + { + have_adaptor = TRUE; + ac_state = g_strconcat ("/proc/acpi/ac_adapter/", + procdirentry->d_name, + "/", + acpiinfo->ac_state_state, + NULL); + hash = read_file (ac_state, buf, sizeof (buf)); + if (hash && !acpiinfo->ac_online) + { + const char *s; + s = read_string (hash, acpiinfo->ac_state_state); + acpiinfo->ac_online = s ? (strcmp (s, "on-line") == 0) : 0; + g_hash_table_destroy (hash); + } + g_free (ac_state); + } + } /* If there are no AC adaptors registered in the system, then we're probably on a desktop (and therefore, on AC power). */ - if (have_adaptor == FALSE) - acpiinfo->ac_online = 1; + if (have_adaptor == FALSE) + acpiinfo->ac_online = 1; - closedir(procdir); + closedir (procdir); - return TRUE; + return TRUE; } /* Reads the ACPI info for the system batteries, and finds * the total capacity, which is stored in acpiinfo. */ -static gboolean update_battery_info(struct acpi_info* acpiinfo) +static gboolean +update_battery_info (struct acpi_info* acpiinfo) { - gchar* batt_info = NULL; - GHashTable* hash; - DIR* procdir; - struct dirent* procdirentry; - char buf[BUFSIZ]; - - acpiinfo->max_capacity = 0; - acpiinfo->low_capacity = 0; - acpiinfo->critical_capacity = 0; - - procdir = opendir("/proc/acpi/battery/"); - - if (!procdir) - { - return FALSE; - } - - while ((procdirentry = readdir(procdir))) - { - if (procdirentry->d_name[0] != '.') - { - batt_info = g_strconcat("/proc/acpi/battery/", procdirentry->d_name, "/info", NULL); - hash = read_file(batt_info, buf, sizeof(buf)); - - if (hash) - { - acpiinfo->max_capacity += read_long(hash, "last full capacity"); - acpiinfo->low_capacity += read_long(hash, "design capacity warning"); - acpiinfo->critical_capacity += read_long(hash, "design capacity low"); - - g_hash_table_destroy(hash); - } - g_free(batt_info); - } - } - - closedir(procdir); - - return TRUE; + gchar* batt_info = NULL; + GHashTable* hash; + DIR* procdir; + struct dirent* procdirentry; + char buf[BUFSIZ]; + + acpiinfo->max_capacity = 0; + acpiinfo->low_capacity = 0; + acpiinfo->critical_capacity = 0; + + procdir = opendir ("/proc/acpi/battery/"); + + if (!procdir) + { + return FALSE; + } + + while ((procdirentry = readdir (procdir))) + { + if (procdirentry->d_name[0] != '.') + { + batt_info = g_strconcat ("/proc/acpi/battery/", procdirentry->d_name, "/info", NULL); + hash = read_file (batt_info, buf, sizeof (buf)); + + if (hash) + { + acpiinfo->max_capacity += read_long (hash, "last full capacity"); + acpiinfo->low_capacity += read_long (hash, "design capacity warning"); + acpiinfo->critical_capacity += read_long (hash, "design capacity low"); + + g_hash_table_destroy (hash); + } + g_free (batt_info); + } + } + + closedir (procdir); + + return TRUE; } @@ -250,72 +253,74 @@ static gboolean update_battery_info(struct acpi_info* acpiinfo) * /proc/acpi/event exported by the kernel, or if it's already * in use, the /var/run/acpid.socket maintained by acpid. Also * initializes the stored battery and AC adapter information. */ -gboolean acpi_linux_init(struct acpi_info * acpiinfo) +gboolean +acpi_linux_init (struct acpi_info * acpiinfo) { - GHashTable *hash; - char buf[BUFSIZ]; - gchar *pbuf; - gulong acpi_ver; - int fd; - - g_assert(acpiinfo); - - if (g_file_get_contents ("/sys/module/acpi/parameters/acpica_version", &pbuf, NULL, NULL)) { - acpi_ver = strtoul (pbuf, NULL, 10); - g_free (pbuf); - } else if ((hash = read_file ("/proc/acpi/info", buf, sizeof (buf)))) { - acpi_ver = read_ulong (hash, "version"); - g_hash_table_destroy (hash); - } else - return FALSE; - - if (acpi_ver < (gulong)20020208) { - acpiinfo->ac_state_state = "status"; - acpiinfo->batt_state_state = "status"; - acpiinfo->charging_state = "state"; - } else { - acpiinfo->ac_state_state = "state"; - acpiinfo->batt_state_state = "state"; - acpiinfo->charging_state = "charging state"; - } - - if (!update_battery_info(acpiinfo) || !update_ac_info(acpiinfo)) - return FALSE; + GHashTable *hash; + char buf[BUFSIZ]; + gchar *pbuf; + gulong acpi_ver; + int fd; + + g_assert (acpiinfo); + + if (g_file_get_contents ("/sys/module/acpi/parameters/acpica_version", &pbuf, NULL, NULL)) { + acpi_ver = strtoul (pbuf, NULL, 10); + g_free (pbuf); + } else if ((hash = read_file ("/proc/acpi/info", buf, sizeof (buf)))) { + acpi_ver = read_ulong (hash, "version"); + g_hash_table_destroy (hash); + } else + return FALSE; + + if (acpi_ver < (gulong)20020208) { + acpiinfo->ac_state_state = "status"; + acpiinfo->batt_state_state = "status"; + acpiinfo->charging_state = "state"; + } else { + acpiinfo->ac_state_state = "state"; + acpiinfo->batt_state_state = "state"; + acpiinfo->charging_state = "charging state"; + } - fd = open("/proc/acpi/event", 0); - if (fd >= 0) { - acpiinfo->event_fd = fd; - acpiinfo->channel = g_io_channel_unix_new(fd); - return TRUE; - } - - fd = socket(PF_UNIX, SOCK_STREAM, 0); - if (fd >= 0) { - struct sockaddr_un addr; - addr.sun_family = AF_UNIX; - strcpy(addr.sun_path, "/var/run/acpid.socket"); - if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) == 0) { - acpiinfo->event_fd = fd; - acpiinfo->channel = g_io_channel_unix_new(fd); - return TRUE; + if (!update_battery_info (acpiinfo) || !update_ac_info (acpiinfo)) + return FALSE; + + fd = open ("/proc/acpi/event", 0); + if (fd >= 0) { + acpiinfo->event_fd = fd; + acpiinfo->channel = g_io_channel_unix_new (fd); + return TRUE; + } + + fd = socket (PF_UNIX, SOCK_STREAM, 0); + if (fd >= 0) { + struct sockaddr_un addr; + addr.sun_family = AF_UNIX; + strcpy (addr.sun_path, "/var/run/acpid.socket"); + if (connect (fd, (struct sockaddr *) &addr, sizeof (addr)) == 0) { + acpiinfo->event_fd = fd; + acpiinfo->channel = g_io_channel_unix_new (fd); + return TRUE; + } } - } - close(fd); - acpiinfo->event_fd = -1; - return FALSE; + close (fd); + acpiinfo->event_fd = -1; + return FALSE; } /* Cleans up ACPI */ -void acpi_linux_cleanup(struct acpi_info * acpiinfo) +void +acpi_linux_cleanup (struct acpi_info * acpiinfo) { - g_assert(acpiinfo); + g_assert (acpiinfo); - if (acpiinfo->event_fd >= 0) { - g_io_channel_unref(acpiinfo->channel); - close(acpiinfo->event_fd); - acpiinfo->event_fd = -1; - } + if (acpiinfo->event_fd >= 0) { + g_io_channel_unref (acpiinfo->channel); + close (acpiinfo->event_fd); + acpiinfo->event_fd = -1; + } } #define ACPI_EVENT_IGNORE 0 @@ -326,56 +331,60 @@ void acpi_linux_cleanup(struct acpi_info * acpiinfo) /* Given a string event from the ACPI system, returns the type * of event if we're interested in it. str is updated to point * to the next event. */ -static int parse_acpi_event(GString *buffer) +static int +parse_acpi_event (GString *buffer) { - if (strstr(buffer->str, "ac_adapter")) - return ACPI_EVENT_AC; - if (strstr(buffer->str, "battery") ) - return ACPI_EVENT_BATTERY_INFO; + if (strstr (buffer->str, "ac_adapter")) + return ACPI_EVENT_AC; + if (strstr (buffer->str, "battery")) + return ACPI_EVENT_BATTERY_INFO; - return ACPI_EVENT_IGNORE; + return ACPI_EVENT_IGNORE; } /* Handles a new ACPI event by reading it from the event file * and calling any handlers. Since this does a blocking read, * it should only be called when there is a new event as indicated - * by select(). */ -gboolean acpi_process_event(struct acpi_info * acpiinfo) + * by select (). */ +gboolean acpi_process_event (struct acpi_info * acpiinfo) { gsize i; int evt; GString *buffer; GError *gerror=NULL; - buffer=g_string_new(NULL); - g_io_channel_read_line_string ( acpiinfo->channel,buffer,&i,&gerror); + buffer=g_string_new (NULL); + g_io_channel_read_line_string (acpiinfo->channel, + buffer, + &i, + &gerror); if (gerror != NULL) { - g_warning ("%s", gerror->message); - g_error_free (gerror); + g_warning ("%s", gerror->message); + g_error_free (gerror); } gboolean result; - evt = parse_acpi_event(buffer); - switch (evt) { + evt = parse_acpi_event (buffer); + switch (evt) { case ACPI_EVENT_AC: - result = update_ac_info(acpiinfo); - break; - case ACPI_EVENT_BATTERY_INFO: - if (update_battery_info(acpiinfo)) { - /* Update AC info on battery info updates. This works around - * a bug in ACPI (as per bug #163013). - */ - result = update_ac_info(acpiinfo); + result = update_ac_info (acpiinfo); break; - } - /* fall-through */ + case ACPI_EVENT_BATTERY_INFO: + if (update_battery_info (acpiinfo)) { + /* Update AC info on battery info updates. This works around + * a bug in ACPI (as per bug #163013). + */ + result = update_ac_info (acpiinfo); + break; + } + /* fall-through */ default: - result = FALSE; - } + result = FALSE; + } - g_string_free(buffer, FALSE); + g_string_free (buffer, FALSE); return result; } @@ -383,82 +392,83 @@ gboolean acpi_process_event(struct acpi_info * acpiinfo) * Fills out a classic apm_info structure with the data gathered from * the ACPI kernel interface in /proc */ -gboolean acpi_linux_read(struct apm_info *apminfo, struct acpi_info * acpiinfo) +gboolean +acpi_linux_read (struct apm_info *apminfo, struct acpi_info * acpiinfo) { - guint32 remain; - guint32 rate; - gboolean charging; - GHashTable *hash; - gchar* batt_state = NULL; - DIR * procdir; - struct dirent * procdirentry; - char buf[BUFSIZ]; - - g_assert(acpiinfo); - - /* - * apminfo.ac_line_status must be one when on ac power - * apminfo.battery_status must be 0 for high, 1 for low, 2 for critical, 3 for charging - * apminfo.battery_percentage must contain batter charge percentage - * apminfo.battery_flags & 0x8 must be nonzero when charging - */ - - g_assert(apminfo); - - charging = FALSE; - remain = 0; - rate = 0; - - procdir=opendir("/proc/acpi/battery/"); - if (!procdir) - return FALSE; + guint32 remain; + guint32 rate; + gboolean charging; + GHashTable *hash; + gchar* batt_state = NULL; + DIR * procdir; + struct dirent * procdirentry; + char buf[BUFSIZ]; + + g_assert (acpiinfo); + + /* + * apminfo.ac_line_status must be one when on ac power + * apminfo.battery_status must be 0 for high, 1 for low, 2 for critical, 3 for charging + * apminfo.battery_percentage must contain batter charge percentage + * apminfo.battery_flags & 0x8 must be nonzero when charging + */ + + g_assert (apminfo); + + charging = FALSE; + remain = 0; + rate = 0; + + procdir=opendir ("/proc/acpi/battery/"); + if (!procdir) + return FALSE; + + /* Get the remaining capacity for the batteries. Other information + * such as AC state and battery max capacity are read only when they + * change using acpi_process_event (). */ + while ((procdirentry=readdir (procdir))) + { + if (procdirentry->d_name[0]!='.') + { + batt_state = g_strconcat ("/proc/acpi/battery/", + procdirentry->d_name, + "/", + acpiinfo->batt_state_state, + NULL); + hash = read_file (batt_state, buf, sizeof (buf)); + if (hash) + { + const char *s; + if (!charging) + { + s = read_string (hash, acpiinfo->charging_state); + charging = s ? (strcmp (s, "charging") == 0) : 0; + } + remain += read_long (hash, "remaining capacity"); + rate += read_long (hash, "present rate"); + g_hash_table_destroy (hash); + } + g_free (batt_state); + } + } + closedir (procdir); + + apminfo->ac_line_status = acpiinfo->ac_online ? 1 : 0; + apminfo->battery_status = + remain < acpiinfo->low_capacity ? 1 : remain < acpiinfo->critical_capacity ? 2 : 0; + if (!acpiinfo->max_capacity) + apminfo->battery_percentage = -1; + else + apminfo->battery_percentage = (int) (remain/(float)acpiinfo->max_capacity*100); + apminfo->battery_flags = charging ? 0x8 : 0; + if (rate && !charging) + apminfo->battery_time = (int) (remain/(float)rate * 60); + else if (rate && charging) + apminfo->battery_time = (int) ((acpiinfo->max_capacity-remain)/(float)rate * 60); + else + apminfo->battery_time = -1; - /* Get the remaining capacity for the batteries. Other information - * such as AC state and battery max capacity are read only when they - * change using acpi_process_event(). */ - while ((procdirentry=readdir(procdir))) - { - if (procdirentry->d_name[0]!='.') - { - batt_state = g_strconcat("/proc/acpi/battery/", - procdirentry->d_name, - "/", - acpiinfo->batt_state_state, - NULL); - hash = read_file (batt_state, buf, sizeof (buf)); - if (hash) - { - const char *s; - if (!charging) - { - s = read_string (hash, acpiinfo->charging_state); - charging = s ? (strcmp (s, "charging") == 0) : 0; - } - remain += read_long (hash, "remaining capacity"); - rate += read_long (hash, "present rate"); - g_hash_table_destroy (hash); - } - g_free(batt_state); - } - } - closedir(procdir); - - apminfo->ac_line_status = acpiinfo->ac_online ? 1 : 0; - apminfo->battery_status = remain < acpiinfo->low_capacity ? 1 : remain < acpiinfo->critical_capacity ? 2 : 0; - if (!acpiinfo->max_capacity) - apminfo->battery_percentage = -1; - else - apminfo->battery_percentage = (int) (remain/(float)acpiinfo->max_capacity*100); - apminfo->battery_flags = charging ? 0x8 : 0; - if (rate && !charging) - apminfo->battery_time = (int) (remain/(float)rate * 60); - else if (rate && charging) - apminfo->battery_time = (int) ((acpiinfo->max_capacity-remain)/(float)rate * 60); - else - apminfo->battery_time = -1; - - return TRUE; + return TRUE; } - #endif /* __linux__ */ |