/* * HardInfo - Displays System Information * Copyright (C) 2003-2006 L. A. F. Pereira * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, version 2 or later. * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include "hardinfo.h" #include "devices.h" const struct { gchar *key, *name; } ups_fields[] = { { "UPS Status", NULL }, { "STATUS", "Status" }, { "TIMELEFT", "Time Left" }, { "LINEV", "Line Voltage" }, { "LOADPCT", "Load Percent" }, { "UPS Battery Information", NULL }, { "BATTV", "Battery Voltage" }, { "BCHARGE", "Battery Charge" }, { "BATTDATE", "Battery Date" }, { "UPS Information", NULL }, { "APCMODEL", "Model" }, { "FIRMWARE", "Firmware Version" }, { "SERIALNO", "Serial Number" }, { "UPSMODE", "UPS Mode" }, { "CABLE", "Cable" }, { "UPSNAME", "UPS Name" }, { "UPS Nominal Values", NULL }, { "NOMINV", "Voltage" }, { "NOMBATTV", "Battery Voltage" }, { "NOMPOWER", "Power" } }; static void __scan_battery_apcupsd(void) { GHashTable *ups_data; FILE *apcaccess; char buffer[512], *apcaccess_path; guint i; apcaccess_path = find_program("apcaccess"); if (apcaccess_path && (apcaccess = popen(apcaccess_path, "r"))) { /* first line isn't important */ if (fgets(buffer, 512, apcaccess)) { /* allocate the key, value hash table */ ups_data = g_hash_table_new(g_str_hash, g_str_equal); /* read up all the apcaccess' output, saving it in the key, value hash table */ while (fgets(buffer, 512, apcaccess)) { buffer[9] = '\0'; g_hash_table_insert(ups_data, g_strdup(g_strstrip(buffer)), g_strdup(g_strstrip(buffer + 10))); } /* builds the ups info string, respecting the field order as found in ups_fields */ for (i = 0; i < G_N_ELEMENTS(ups_fields); i++) { if (!ups_fields[i].name) { /* there's no name: make a group with the key as its name */ battery_list = h_strdup_cprintf("[%s]\n", battery_list, ups_fields[i].key); } else { /* there's a name: adds a line */ const gchar *name = g_hash_table_lookup(ups_data, ups_fields[i].key); battery_list = h_strdup_cprintf("%s=%s\n", battery_list, ups_fields[i].name, name); } } g_hash_table_destroy(ups_data); } pclose(apcaccess); } g_free(apcaccess_path); } static void __scan_battery_acpi(void) { gchar *acpi_path; gchar *present = NULL; gchar *capacity = NULL; gchar *technology = NULL; gchar *voltage = NULL; gchar *model = NULL, *serial = NULL, *type = NULL; gchar *state = NULL, *rate = NULL; gchar *remaining = NULL; gchar *manufacturer = NULL; acpi_path = g_strdup("/proc/acpi/battery"); if (g_file_test(acpi_path, G_FILE_TEST_EXISTS)) { GDir *acpi; if ((acpi = g_dir_open(acpi_path, 0, NULL))) { const gchar *entry; while ((entry = g_dir_read_name(acpi))) { gchar *path = g_strdup_printf("%s/%s/info", acpi_path, entry); FILE *f; gchar buffer[256]; gdouble charge_rate = 1.0; f = fopen(path, "r"); g_free(path); if (!f) goto cleanup; while (fgets(buffer, 256, f)) { gchar **tmp = g_strsplit(buffer, ":", 2); GET_STR("present", present); GET_STR("design capacity", capacity); GET_STR("battery technology", technology); GET_STR("design voltage", voltage); GET_STR("model number", model); GET_STR("serial number", serial); GET_STR("battery type", type); GET_STR("OEM info", manufacturer); g_strfreev(tmp); } fclose(f); path = g_strdup_printf("%s/%s/state", acpi_path, entry); f = fopen(path, "r"); g_free(path); if (!f) goto cleanup; while (fgets(buffer, 256, f)) { gchar **tmp = g_strsplit(buffer, ":", 2); GET_STR("charging state", state); GET_STR("present rate", rate); GET_STR("remaining capacity", remaining); g_strfreev(tmp); } fclose(f); gchar *tmp = vendor_get_link(manufacturer); g_free(manufacturer); manufacturer = tmp; if (g_str_equal(present, "yes")) { if (remaining && capacity) charge_rate = atof(remaining) / atof(capacity); else charge_rate = 0; battery_list = h_strdup_cprintf(_("\n[Battery: %s]\n" "State=%s (load: %s)\n" "Capacity=%s / %s (%.2f%%)\n" "Battery Technology=%s (%s)\n" "Manufacturer=%s\n" "Model Number=%s\n" "Serial Number=%s\n"), battery_list, entry, state, rate, remaining, capacity, charge_rate * 100.0, technology, type, manufacturer, model, serial); } cleanup: g_free(present); g_free(capacity); g_free(technology); g_free(type); g_free(model); g_free(serial); g_free(state); g_free(remaining); g_free(rate); g_free(manufacturer); present = capacity = technology = type = \ model = serial = state = remaining = rate = manufacturer = NULL; } g_dir_close(acpi); } } g_free(acpi_path); } static gchar * read_contents(const gchar *base, const gchar *key) { gchar *value; gchar *path; path = g_strdup_printf("%s/%s", base, key); if (!path) return NULL; if (!g_file_get_contents(path, &value, NULL, NULL)) { g_free(path); return NULL; } g_free(path); return g_strchomp(value); } static void __scan_battery_sysfs_add_battery(const gchar *name) { gchar *path = g_strdup_printf("/sys/class/power_supply/%s", name); gchar *status, *capacity, *capacity_level, *technology, *manufacturer, *model_name, *serial_number; if (!path) return; status = read_contents(path, "status"); capacity = read_contents(path, "capacity"); capacity_level = read_contents(path, "capacity_level"); technology = read_contents(path, "technology"); manufacturer = read_contents(path, "manufacturer"); model_name = read_contents(path, "model_name"); serial_number = read_contents(path, "serial_number"); battery_list = h_strdup_cprintf(_("\n[Battery: %s]\n" "State=%s\n" "Capacity=%s / %s\n" "Battery Technology=%s\n" "Manufacturer=%s\n" "Model Number=%s\n" "Serial Number=%s\n"), battery_list, name, status, capacity, capacity_level, technology, manufacturer, model_name, serial_number); free(status); free(capacity); free(capacity_level); free(technology); free(manufacturer); free(model_name); free(serial_number); } static void __scan_battery_sysfs(void) { GDir *dir; const gchar *entry; dir = g_dir_open("/sys/class/power_supply", 0, NULL); if (!dir) return; while ((entry = g_dir_read_name(dir))) { if (g_str_has_prefix(entry, "BAT")) __scan_battery_sysfs_add_battery(entry); } g_dir_close(dir); } static void __scan_battery_apm(void) { FILE *procapm; static char *sremaining = NULL, *stotal = NULL; static unsigned int last_time = 0; static int percentage = 0; const char *ac_status[] = { "Battery", "AC Power", "Charging" }; int ac_bat; char apm_bios_ver[16], apm_drv_ver[16]; char trash[10]; if ((procapm = fopen("/proc/apm", "r"))) { int old_percentage = percentage; (void)fscanf(procapm, "%s %s %s 0x%x %s %s %d%%", apm_drv_ver, apm_bios_ver, trash, &ac_bat, trash, trash, &percentage); fclose(procapm); if (last_time == 0) { last_time = time(NULL); sremaining = stotal = NULL; } if (old_percentage - percentage > 0) { if (sremaining && stotal) { g_free(sremaining); g_free(stotal); } int secs_remaining = (time(NULL) - last_time) * percentage / (old_percentage - percentage); sremaining = seconds_to_string(secs_remaining); stotal = seconds_to_string((secs_remaining * 100) / percentage); last_time = time(NULL); } } else { return; } if (stotal && sremaining) { battery_list = h_strdup_cprintf(_("\n[Battery (APM)]\n" "Charge=%d%%\n" "Remaining Charge=%s of %s\n" "Using=%s\n" "APM driver version=%s\n" "APM BIOS version=%s\n"), battery_list, percentage, sremaining, stotal, ac_status[ac_bat], apm_drv_ver, apm_bios_ver); } else { battery_list = h_strdup_cprintf(_("\n[Battery (APM)]\n" "Charge=%d%%\n" "Using=%s\n" "APM driver version=%s\n" "APM BIOS version=%s\n"), battery_list, percentage, ac_status[ac_bat], apm_drv_ver, apm_bios_ver); } } void scan_battery_do(void) { g_free(battery_list); battery_list = g_strdup(""); __scan_battery_sysfs(); __scan_battery_acpi(); __scan_battery_apm(); __scan_battery_apcupsd(); if (*battery_list == '\0') { g_free(battery_list); battery_list = g_strdup(_("[No batteries]\n" "No batteries found on this system=\n")); } }