517 lines
14 KiB
Plaintext
517 lines
14 KiB
Plaintext
/*
|
|
* Copyright (c) 2018 Alastair Roy Poole <netstar@gmail.com>
|
|
*
|
|
* 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.
|
|
*/
|
|
|
|
void
|
|
system_sensor_thermal_free(sensor_t *sensor)
|
|
{
|
|
if (sensor->name)
|
|
free(sensor->name);
|
|
if (sensor->child_name)
|
|
free(sensor->child_name);
|
|
#if defined(__linux__)
|
|
if (sensor->path)
|
|
free(sensor->path);
|
|
#endif
|
|
free(sensor);
|
|
}
|
|
|
|
void
|
|
system_sensors_thermal_free(sensor_t **sensors, int count)
|
|
{
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
sensor_t *sensor = sensors[i];
|
|
system_sensor_thermal_free(sensor);
|
|
}
|
|
if (sensors)
|
|
free(sensors);
|
|
}
|
|
|
|
int
|
|
system_sensor_thermal_get(sensor_t *sensor)
|
|
{
|
|
#if defined(__linux__)
|
|
char *d = file_contents(sensor->path);
|
|
if (d)
|
|
{
|
|
double val = atof(d);
|
|
if (val)
|
|
sensor->value = val /= 1000;
|
|
free(d);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
#elif defined(__OpenBSD__)
|
|
struct sensor snsr;
|
|
size_t slen = sizeof(struct sensor);
|
|
|
|
if (sysctl(sensor->mibs, 5, &snsr, &slen, NULL, 0) == -1) return 0;
|
|
|
|
sensor->value = (snsr.value - 273150000) / 1000000.0;
|
|
|
|
return 1;
|
|
#elif defined(__FreeBSD__) || defined(__DragonFly__)
|
|
int value;
|
|
size_t len = sizeof(value);
|
|
if ((sysctlbyname(sensor->name, &value, &len, NULL, 0)) != -1)
|
|
{
|
|
sensor->value = (float) (value - 2732) / 10;
|
|
return 1;
|
|
}
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
sensor_t **
|
|
system_sensors_thermal_get(int *sensor_count)
|
|
{
|
|
sensor_t **sensors = NULL;
|
|
*sensor_count = 0;
|
|
#if defined(__OpenBSD__)
|
|
sensor_t *sensor;
|
|
int mibs[5] = { CTL_HW, HW_SENSORS, 0, 0, 0 };
|
|
int devn, n;
|
|
struct sensor snsr;
|
|
struct sensordev snsrdev;
|
|
size_t slen = sizeof(struct sensor);
|
|
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;
|
|
|
|
void *tmp = realloc(sensors, (1 + *sensor_count) * sizeof(sensor_t *));
|
|
sensors = tmp;
|
|
sensors[(*sensor_count)++] = sensor = calloc(1, sizeof(sensor_t));
|
|
sensor->name = strdup(snsrdev.xname);
|
|
sensor->value = (snsr.value - 273150000) / 1000000.0; // (uK -> C)
|
|
memcpy(sensor->mibs, &mibs, sizeof(mibs));
|
|
}
|
|
#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)
|
|
{
|
|
void *tmp = realloc(sensors, (1 + *sensor_count) * sizeof(sensor_t *));
|
|
sensors = tmp;
|
|
sensors[(*sensor_count)++] = sensor = calloc(1, sizeof(sensor_t));
|
|
sensor->name = strdup("hw.acpi.thermal.tz0.temperature");
|
|
sensor->value = (float) (value - 2732) / 10;
|
|
}
|
|
|
|
int n = system_cpu_count_get();
|
|
|
|
for (int i = 0; i < n; i++)
|
|
{
|
|
len = sizeof(value);
|
|
const char *mibname = strsli_printf("dev.cpu.%d.temperature", i);
|
|
if ((sysctlbyname(mibname, &value, &len, NULL, 0)) != -1)
|
|
{
|
|
void *tmp = realloc(sensors, (1 + *sensor_count) * sizeof(sensor_t *));
|
|
sensors = tmp;
|
|
sensors[(*sensor_count)++] = sensor = calloc(1, sizeof(sensor_t));
|
|
sensor->name = strdup(mibname);
|
|
sensor->value = (float) (value - 2732) / 10;
|
|
}
|
|
}
|
|
|
|
#elif defined(__linux__)
|
|
sensor_t *sensor;
|
|
DIR *dir;
|
|
struct dirent *dh;
|
|
char buf[4096];
|
|
int seen[128];
|
|
|
|
dir = opendir("/sys/class/hwmon");
|
|
if (!dir) return NULL;
|
|
|
|
while ((dh = readdir(dir)) != NULL)
|
|
{
|
|
struct dirent **names = NULL;
|
|
|
|
snprintf(buf, sizeof(buf), "/sys/class/hwmon/%s", dh->d_name);
|
|
char *link = realpath(buf, NULL);
|
|
if (!link) continue;
|
|
|
|
int n = scandir(link, &names, 0, alphasort);
|
|
if (n < 0) continue;
|
|
|
|
int idx = 0;
|
|
memset(&seen, 0, sizeof(seen));
|
|
|
|
for (int i = 0; i < n; i++)
|
|
{
|
|
if (!strncmp(names[i]->d_name, "temp", 4))
|
|
{
|
|
int id = atoi(names[i]->d_name + 4);
|
|
if ((!id) || (id > sizeof(seen)))
|
|
{
|
|
free(names[i]);
|
|
continue;
|
|
}
|
|
|
|
int found = 0;
|
|
|
|
for (int j = 0; seen[j] != 0 && j < sizeof(seen); j++)
|
|
if (seen[j] == id) found = 1;
|
|
|
|
if (found)
|
|
{
|
|
free(names[i]);
|
|
continue;
|
|
}
|
|
|
|
void *tmp = realloc(sensors, (1 + (*sensor_count)) * sizeof(sensor_t *));
|
|
sensors = tmp;
|
|
sensors[(*sensor_count)++] = sensor = calloc(1, sizeof(sensor_t));
|
|
|
|
snprintf(buf, sizeof(buf), "%s/name", link);
|
|
sensor->name = file_contents(buf);
|
|
if (sensor->name)
|
|
strimmer(sensor->name);
|
|
|
|
snprintf(buf, sizeof(buf), "%s/temp%d_label", link, id);
|
|
sensor->child_name = file_contents(buf);
|
|
if (sensor->child_name)
|
|
strimmer(sensor->child_name);
|
|
|
|
snprintf(buf, sizeof(buf), "%s/temp%d_input", link, id);
|
|
sensor->path = strdup(buf);
|
|
char *d = file_contents(buf);
|
|
if (d)
|
|
{
|
|
sensor->value = atoi(d);
|
|
if (sensor->value) sensor->value /= 1000;
|
|
free(d);
|
|
}
|
|
seen[idx++] = id;
|
|
}
|
|
free(names[i]);
|
|
}
|
|
|
|
free(names);
|
|
free(link);
|
|
}
|
|
|
|
closedir(dir);
|
|
|
|
#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 = sizeof(power->battery_count);
|
|
|
|
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 *buf, *link = NULL, *naming = NULL;
|
|
|
|
|
|
for (int i = 0; i < power->battery_count; i++) {
|
|
naming = NULL;
|
|
|
|
path = strsli_printf("/sys/class/power_supply/%s", power->batteries[i]->name);
|
|
|
|
if ((stat(path, &st) < 0) || (!S_ISDIR(st.st_mode)))
|
|
continue;
|
|
|
|
link = realpath(path, NULL);
|
|
if (!link) return;
|
|
|
|
dir = opendir(path);
|
|
if (!dir)
|
|
goto done;
|
|
|
|
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("%s/%s_full", link, naming));
|
|
if (buf)
|
|
{
|
|
power->batteries[i]->charge_full = atol(buf);
|
|
free(buf);
|
|
}
|
|
buf = file_contents(strsli_printf("%s/%s_now", link, naming));
|
|
if (buf)
|
|
{
|
|
power->batteries[i]->charge_current = atol(buf);
|
|
free(buf);
|
|
}
|
|
free(naming);
|
|
}
|
|
done:
|
|
if (link) free(link);
|
|
#endif
|
|
}
|
|
|
|
void
|
|
system_power_state_get(power_t *power)
|
|
{
|
|
int i;
|
|
memset(power, 0, sizeof(power_t));
|
|
#if defined(__OpenBSD__)
|
|
struct sensor snsr;
|
|
size_t slen = sizeof(struct sensor);
|
|
#elif defined(__FreeBSD__) || defined(__DragonFly__)
|
|
unsigned int value;
|
|
size_t len;
|
|
#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__)
|
|
char *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);
|
|
}
|
|
}
|
|
|
|
void
|
|
system_power_state_free(power_t *power)
|
|
{
|
|
for (int i = 0; i < power->battery_count; i++)
|
|
{
|
|
if (power->batteries[i]->name)
|
|
free(power->batteries[i]->name);
|
|
#if defined(__OpenBSD__)
|
|
if (power->batteries[i]->mibs)
|
|
free(power->batteries[i]->mibs);
|
|
#endif
|
|
free(power->batteries[i]);
|
|
}
|
|
if (power->batteries)
|
|
free(power->batteries);
|
|
}
|