/* * Copyright (c) 2018 Alastair Roy Poole * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ sensor_t ** system_sensors_thermal_get(int *sensor_count) { sensor_t **sensors = NULL; #if defined(__OpenBSD__) sensor_t *sensor; int mibs[5] = { CTL_HW, HW_SENSORS, 0, 0, 0 }; int devn, n; struct sensor snsr; size_t slen = sizeof(struct sensor); struct sensordev snsrdev; size_t sdlen = sizeof(struct sensordev); for (devn = 0;; devn++) { mibs[2] = devn; if (sysctl(mibs, 3, &snsrdev, &sdlen, NULL, 0) == -1) { if (errno == ENOENT) break; continue; } for (n = 0; n < snsrdev.maxnumt[SENSOR_TEMP]; n++) { mibs[4] = n; if (sysctl(mibs, 5, &snsr, &slen, NULL, 0) == -1) continue; if (slen > 0 && (snsr.flags & SENSOR_FINVALID) == 0) break; } if (sysctl(mibs, 5, &snsr, &slen, NULL, 0) == -1) continue; if (snsr.type != SENSOR_TEMP) continue; sensors = realloc(sensors, (1 + *sensor_count) * sizeof(sensor_t *)); sensors[(*sensor_count)++] = sensor = calloc(1, sizeof(sensor_t)); sensor->name = strdup(snsrdev.xname); sensor->value = (snsr.value - 273150000) / 1000000.0; // (uK -> C) } #elif defined(__FreeBSD__) || defined(__DragonFly__) sensor_t *sensor; int value; size_t len = sizeof(value); if ((sysctlbyname("hw.acpi.thermal.tz0.temperature", &value, &len, NULL, 0)) != -1) { sensors = realloc(sensors, (1 + *sensor_count) * sizeof(sensor_t *)); sensors[(*sensor_count)++] = sensor = calloc(1, sizeof(sensor_t)); sensor->name = strdup("hw.acpi.thermal.tz0"); sensor->value = (float) (value - 2732) / 10; } #elif defined(__linux__) sensor_t *sensor; char *type, *value; struct dirent **names; int i, n; n = scandir("/sys/class/thermal", &names, 0, alphasort); if (n < 0) return NULL; for (i = 0; i < n; i++) { if (strncmp(names[i]->d_name, "thermal_zone", 12)) { free(names[i]); continue; } type = file_contents(strsli_printf("/sys/class/thermal/%s/type", names[i]->d_name)); if (type) { sensors = realloc(sensors, (1 + (*sensor_count)) * sizeof(sensor_t *)); sensors[(*sensor_count)++] = sensor = calloc(1, sizeof(sensor_t)); sensor->name = type; value = file_contents(strsli_printf("/sys/class/thermal/%s/temp", names[i]->d_name)); if (!value) sensor->invalid = true; else { sensor->value = (float)atoi(value) / 1000.0; free(value); } } free(names[i]); } free(names); #elif defined(__MacOS__) #endif return sensors; } static int _power_battery_count_get(power_t *power) { #if defined(__OpenBSD__) struct sensordev snsrdev; size_t sdlen = sizeof(struct sensordev); int mibs[5] = { CTL_HW, HW_SENSORS, 0, 0, 0 }; int i, devn; for (devn = 0;; devn++) { mibs[2] = devn; if (sysctl(mibs, 3, &snsrdev, &sdlen, NULL, 0) == -1) { if (errno == ENXIO) continue; if (errno == ENOENT) break; } if (!strncmp(snsrdev.xname, "acpibat", 7)) { i = power->battery_count; power->batteries = realloc(power->batteries, 1 + power->battery_count++ * sizeof(bat_t **)); power->batteries[i] = calloc(1, sizeof(bat_t)); power->batteries[i]->name = strdup(snsrdev.xname); power->batteries[i]->present = true; power->batteries[i]->mibs = malloc(sizeof(int) * 5); int *tmp = power->batteries[i]->mibs; tmp[0] = mibs[0]; tmp[1] = mibs[1]; tmp[2] = mibs[2]; } if (!strcmp("acpiac0", snsrdev.xname)) { power->ac_mibs[0] = mibs[0]; power->ac_mibs[1] = mibs[1]; power->ac_mibs[2] = mibs[2]; } } #elif defined(__FreeBSD__) || defined(__DragonFly__) size_t len; if ((sysctlbyname("hw.acpi.battery.units", &power->battery_count, &len, NULL, 0)) < 0) power->battery_count = 0; if ((sysctlbyname("hw.acpi.acline", NULL, &len, NULL, 0)) != -1) sysctlnametomib("hw.acpi.acline", power->ac_mibs, &len); power->batteries = malloc(power->battery_count * sizeof(bat_t **)); for (int i = 0; i < power->battery_count; i++) { power->batteries[i] = calloc(1, sizeof(bat_t)); power->batteries[i]->present = true; } #elif defined(__linux__) char *type; struct dirent **names; int i, n, id; n = scandir("/sys/class/power_supply", &names, 0, alphasort); if (n < 0) return power->battery_count; for (i = 0; i < n; i++) { type = file_contents(strsli_printf("/sys/class/power_supply/%s/type", names[i]->d_name)); if (type) { if (!strncmp(type, "Battery", 7)) { id = power->battery_count; power->batteries = realloc(power->batteries, (1 + power->battery_count) * sizeof(bat_t **)); power->batteries[id] = calloc(1, sizeof(bat_t)); power->batteries[id]->name = strdup(names[i]->d_name); power->batteries[id]->present = true; power->battery_count++; } free(type); } free(names[i]); } free(names); #endif return power->battery_count; } static void _battery_state_get(power_t *power) { #if defined(__OpenBSD__) int *mib; double charge_full, charge_current; size_t slen = sizeof(struct sensor); struct sensor snsr; for (int i = 0; i < power->battery_count; i++) { charge_full = charge_current = 0; mib = power->batteries[i]->mibs; mib[3] = SENSOR_WATTHOUR; mib[4] = 0; if (sysctl(mib, 5, &snsr, &slen, NULL, 0) != -1) charge_full = (double)snsr.value; mib[3] = SENSOR_WATTHOUR; mib[4] = 3; if (sysctl(mib, 5, &snsr, &slen, NULL, 0) != -1) charge_current = (double)snsr.value; if (charge_current == 0 || charge_full == 0) { mib[3] = SENSOR_AMPHOUR; mib[4] = 0; if (sysctl(mib, 5, &snsr, &slen, NULL, 0) != -1) charge_full = (double)snsr.value; mib[3] = SENSOR_AMPHOUR; mib[4] = 3; if (sysctl(mib, 5, &snsr, &slen, NULL, 0) != -1) charge_current = (double)snsr.value; } power->batteries[i]->charge_full = charge_full; power->batteries[i]->charge_current = charge_current; } #elif defined(__FreeBSD__) || defined(__DragonFly__) int fd, i; union acpi_battery_ioctl_arg battio; char name[256]; if ((fd = open("/dev/acpi", O_RDONLY)) == -1) return; for (i = 0; i < power->battery_count; i++) { battio.unit = i; if (ioctl(fd, ACPIIO_BATT_GET_BIF, &battio) != -1) { if (battio.bif.lfcap == 0) power->batteries[i]->charge_full = battio.bif.dcap; else power->batteries[i]->charge_full = battio.bif.lfcap; } snprintf(name, sizeof(name), "%s %s", battio.bif.oeminfo, battio.bif.model); power->batteries[i]->name = strdup(name); battio.unit = i; if (ioctl(fd, ACPIIO_BATT_GET_BST, &battio) != -1) power->batteries[i]->charge_current = battio.bst.cap; if (battio.bst.state == ACPI_BATT_STAT_NOT_PRESENT) power->batteries[i]->present = false; } close(fd); #elif defined(__linux__) const char *path; struct dirent *dh; struct stat st; DIR *dir; char *model, *vendor; char *buf, *naming = NULL; for (int i = 0; i < power->battery_count; i++) { naming = NULL; path = strsli_printf("/sys/class/power_suppy/%s", power->batteries[i]->name); if (((stat(path, &st) < 0)) || (S_ISLNK(st.st_mode)) || (!S_ISDIR(st.st_mode))) continue; dir = opendir(path); if (!dir) return; while ((dh = readdir(dir)) != NULL) { char *e; if (dh->d_name[0] == '.') continue; if ((e = strstr(dh->d_name, "_full\0"))) { naming = strndup(dh->d_name, e - dh->d_name); break; } } closedir(dir); if (!naming) continue; buf = file_contents(strsli_printf("/sys/class/power_supply/%s/%s_full", power->batteries[i]->name, naming)); if (buf) { power->batteries[i]->charge_full = atol(buf); free(buf); } buf = file_contents(strsli_printf("/sys/class/power_supply/%s/%s_now", power->batteries[i]->name, naming)); if (buf) { power->batteries[i]->charge_current = atol(buf); free(buf); } vendor = file_contents(strsli_printf("/sys/class/power_supply/%s/manufacturer", power->batteries[i]->name)); model = file_contents(strsli_printf("/sys/class/power_supply/%s/model_name", power->batteries[i]->name)); if (vendor && vendor[0] && model && model[0]) { int len; len = strlen(vendor) - 1; if (vendor[len] == '\n' || vendor[len] == '\r') vendor[len] = '\0'; len = strlen(model) - 1; if (model[len] == '\n' || model[len] == '\r') model[len] = '\0'; free(power->batteries[i]->name);; power->batteries[i]->name = strdup(strsli_printf("%s %s", vendor, model)); } if (model) free(model); if (vendor) free(vendor); free(naming); } #endif } void system_power_state_get(power_t *power) { int i; #if defined(__OpenBSD__) struct sensor snsr; size_t slen = sizeof(struct sensor); #elif defined(__FreeBSD__) || defined(__DragonFly__) unsigned int value; size_t len; #elif defined(__linux__) char *buf; #endif if (!_power_battery_count_get(power)) return; #if defined(__OpenBSD__) power->ac_mibs[3] = 9; power->ac_mibs[4] = 0; if (sysctl(power->ac_mibs, 5, &snsr, &slen, NULL, 0) != -1) power->have_ac = (int)snsr.value; #elif defined(__FreeBSD__) || defined(__DragonFly__) len = sizeof(value); if ((sysctl(power->ac_mibs, 3, &value, &len, NULL, 0)) == -1) return; power->have_ac = value; #elif defined(__linux__) buf = file_contents("/sys/class/power_supply/AC/online"); if (buf) { power->have_ac = atoi(buf); free(buf); } #endif _battery_state_get(power); for (i = 0; i < power->battery_count; i++) { power->batteries[i]->percent = 100 * (power->batteries[i]->charge_current / power->batteries[i]->charge_full); } }