511 lines
9.7 KiB
C
511 lines
9.7 KiB
C
/*
|
|
* Copyright (c) 2007 Daniel Borca All rights reserved.
|
|
*
|
|
* 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; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* 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 Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
|
|
#include <arpa/inet.h>
|
|
#include <ctype.h>
|
|
#include <net/ethernet.h>
|
|
#include <net/if.h>
|
|
#include <netinet/in.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <sys/ioctl.h>
|
|
#include <unistd.h>
|
|
#include <linux/wireless.h>
|
|
|
|
#include "../list.h"
|
|
#include "../sensors.h"
|
|
#include "../system.h"
|
|
|
|
|
|
int
|
|
system_get_uptime (int *days, int *hours, int *mins)
|
|
{
|
|
char buf[BUFSIZ];
|
|
|
|
unsigned long ut;
|
|
|
|
if (sensors_read_line("/proc/uptime", BUFSIZ, buf) <= 0) {
|
|
return 0;
|
|
}
|
|
|
|
if (sscanf(buf, "%lu", &ut) != 1) {
|
|
return 0;
|
|
}
|
|
|
|
ut /= 60;
|
|
*mins = ut % 60;
|
|
ut /= 60;
|
|
*hours = ut % 24;
|
|
ut /= 24;
|
|
*days = ut;
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
int
|
|
system_get_cpu_load (int num, CPUSTAT *avg, CPUSTAT load[])
|
|
{
|
|
FILE *f;
|
|
char buf[BUFSIZ];
|
|
|
|
int i;
|
|
int ok = 0;
|
|
|
|
f = fopen("/proc/stat", "rt");
|
|
if (f == NULL) {
|
|
return 0;
|
|
}
|
|
|
|
if (avg != NULL) {
|
|
avg->used = -1;
|
|
}
|
|
for (i = 0; i < num; i++) {
|
|
load[i].used = -1;
|
|
}
|
|
|
|
while (fgets(buf, BUFSIZ, f)) {
|
|
CPUSTAT *p;
|
|
int array[10], total;
|
|
int n;
|
|
|
|
if (buf[0] == 'c' && buf[1] == 'p' && buf[2] == 'u' && buf[3] == ' ') {
|
|
if (avg == NULL) {
|
|
continue;
|
|
}
|
|
n = sscanf(buf + 4, "%d %d %d %d %d %d %d %d %d %d",
|
|
&array[0], &array[1], &array[2], &array[3],
|
|
&array[4], &array[5], &array[6], &array[7],
|
|
&array[8], &array[9]);
|
|
if (n < 4 || avg == NULL) {
|
|
continue;
|
|
}
|
|
p = avg;
|
|
ok |= 1;
|
|
} else {
|
|
if (!num) {
|
|
continue;
|
|
}
|
|
n = sscanf(buf, "cpu%d %d %d %d %d %d %d %d %d %d %d", &i,
|
|
&array[0], &array[1], &array[2], &array[3],
|
|
&array[4], &array[5], &array[6], &array[7],
|
|
&array[8], &array[9]);
|
|
if (--n < 4 || i >= num) {
|
|
continue;
|
|
}
|
|
p = &load[i];
|
|
ok |= 2;
|
|
}
|
|
|
|
for (total = 0; n--; total += array[n]) {
|
|
}
|
|
|
|
p->used = 0;
|
|
if (total != p->old_total) {
|
|
p->used = 100 - 100 * (array[3] - p->old_idle) / (total - p->old_total);
|
|
}
|
|
|
|
p->old_idle = array[3];
|
|
p->old_total = total;
|
|
}
|
|
fclose(f);
|
|
|
|
return ok;
|
|
}
|
|
|
|
|
|
int
|
|
system_get_cpu_speed (int num, int speed[])
|
|
{
|
|
FILE *f;
|
|
char buf[BUFSIZ];
|
|
|
|
int i;
|
|
int ok = 0;
|
|
|
|
f = fopen("/proc/cpuinfo", "rt");
|
|
if (f == NULL) {
|
|
return 0;
|
|
}
|
|
|
|
for (i = 0; i < num; i++) {
|
|
speed[i] = -1;
|
|
}
|
|
|
|
while (fgets(buf, BUFSIZ, f)) {
|
|
sscanf(buf, "processor : %d", &i);
|
|
if (i < num) {
|
|
ok += sscanf(buf, "cpu MHz : %d", &speed[i]);
|
|
}
|
|
}
|
|
fclose(f);
|
|
|
|
return ok;
|
|
}
|
|
|
|
|
|
int
|
|
system_get_cpu_gov (int cpu, int max, char *out)
|
|
{
|
|
char filename[128];
|
|
|
|
sprintf(filename, "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_governor", cpu);
|
|
|
|
if (sensors_read_line(filename, max, out) <= 0) {
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
int
|
|
system_get_mem_stat (int *mem_free, int *mem_total, int *swp_free, int *swp_total)
|
|
{
|
|
FILE *f;
|
|
char buf[BUFSIZ];
|
|
|
|
f = fopen("/proc/meminfo", "rt");
|
|
if (f == NULL) {
|
|
return 0;
|
|
}
|
|
|
|
*mem_free = 0;
|
|
*mem_total = 0;
|
|
*swp_free = 0;
|
|
*swp_total = 0;
|
|
|
|
while (fgets(buf, BUFSIZ, f)) {
|
|
sscanf(buf, "MemTotal: %d", mem_total);
|
|
sscanf(buf, "MemFree: %d", mem_free);
|
|
sscanf(buf, "SwapTotal: %d", swp_total);
|
|
sscanf(buf, "SwapFree: %d", swp_free);
|
|
}
|
|
fclose(f);
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
int
|
|
system_get_max_temp (SENSOR *list, int *temp, int *crit)
|
|
{
|
|
SENSOR *s;
|
|
char buf[BUFSIZ];
|
|
|
|
int tmp, max = -1;
|
|
|
|
*crit = 0;
|
|
|
|
list_foreach (s, list) {
|
|
if (s->type == S_ACPI_THERMAL_ZONE &&
|
|
sensors_read_line(s->filename, BUFSIZ, buf) > 0 &&
|
|
sscanf(buf, "temperature: %d", &tmp) == 1) {
|
|
if (100 * tmp > 90 * s->idata) {
|
|
*crit = 1;
|
|
}
|
|
if (max < tmp) {
|
|
max = tmp;
|
|
}
|
|
}
|
|
if (s->type == S_HWMON_CORETEMP &&
|
|
sensors_read_line(s->filename, BUFSIZ, buf) > 0 &&
|
|
sscanf(buf, "%d", &tmp) == 1) {
|
|
if (100 * tmp > 90 * s->idata) {
|
|
*crit = 1;
|
|
}
|
|
if (max * 1000 < tmp) {
|
|
max = tmp / 1000;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (max < 0) {
|
|
return 0;
|
|
}
|
|
|
|
*temp = max;
|
|
return 1;
|
|
}
|
|
|
|
|
|
int
|
|
system_get_temperature (SENSOR *list, int num, TEMPSTAT temp[])
|
|
{
|
|
SENSOR *s;
|
|
char buf[BUFSIZ];
|
|
int i = 0;
|
|
|
|
list_foreach (s, list) {
|
|
if (i >= num) {
|
|
break;
|
|
}
|
|
if (s->type == S_ACPI_THERMAL_ZONE &&
|
|
sensors_read_line(s->filename, BUFSIZ, buf) > 0 &&
|
|
sscanf(buf, "temperature: %d", &temp[i].temp) == 1) {
|
|
temp[i].max = s->idata;
|
|
strncpy(temp[i].name, s->name, 7);
|
|
temp[i].name[7] = '\0';
|
|
i++;
|
|
}
|
|
if (s->type == S_HWMON_CORETEMP &&
|
|
sensors_read_line(s->filename, BUFSIZ, buf) > 0 &&
|
|
sscanf(buf, "%d", &temp[i].temp) == 1) {
|
|
temp[i].temp /= 1000;
|
|
temp[i].max = s->idata / 1000;
|
|
strncpy(temp[i].name, s->name, 7);
|
|
temp[i].name[7] = '\0';
|
|
i++;
|
|
}
|
|
if (s->type == S_NVIDIA_SETTINGS_GPUCORETEMP &&
|
|
sensors_nvidia(s->name, &temp[i].temp) == 0) {
|
|
temp[i].max = s->idata;
|
|
strncpy(temp[i].name, s->name, 7);
|
|
temp[i].name[7] = '\0';
|
|
i++;
|
|
}
|
|
}
|
|
|
|
return i;
|
|
}
|
|
|
|
|
|
int
|
|
system_get_best_wifi (int *wifi)
|
|
{
|
|
FILE *f;
|
|
char buf[BUFSIZ];
|
|
|
|
int tmp, max = -1;
|
|
|
|
f = fopen("/proc/net/wireless", "rt");
|
|
if (f == NULL) {
|
|
return 0;
|
|
}
|
|
|
|
while (fgets(buf, BUFSIZ, f)) {
|
|
if (sscanf(buf, "%*s %*d %d", &tmp) == 1 &&
|
|
max < tmp) {
|
|
max = tmp;
|
|
}
|
|
}
|
|
fclose(f);
|
|
|
|
if (max < 0) {
|
|
return 0;
|
|
}
|
|
|
|
*wifi = max;
|
|
return 1;
|
|
}
|
|
|
|
|
|
int
|
|
system_get_ac_adapter (SENSOR *list)
|
|
{
|
|
SENSOR *s;
|
|
char buf[BUFSIZ];
|
|
|
|
list_foreach (s, list) {
|
|
if (s->type == S_ACPI_AC_ADAPTER &&
|
|
sensors_read_line(s->filename, BUFSIZ, buf) > 0 &&
|
|
strstr(buf, "on-line")) {
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
int
|
|
system_get_battery (SENSOR *list, int num, BATSTAT *total, BATSTAT batt[])
|
|
{
|
|
SENSOR *s;
|
|
char buf[BUFSIZ];
|
|
|
|
int n = 0;
|
|
|
|
int all_state = 0;
|
|
total->name[0] = '\0';
|
|
total->full_cap = 0;
|
|
total->curr_cap = 0;
|
|
total->rate = 0;
|
|
|
|
list_foreach (s, list) {
|
|
if (s->type == S_ACPI_BATTERY) {
|
|
FILE *f;
|
|
int present = 0;
|
|
int full_cap = 0;
|
|
int curr_cap = 0;
|
|
int charging = 0;
|
|
int rate = 0;
|
|
|
|
strcpy(strrchr(s->filename, '/'), "/state");
|
|
f = fopen(s->filename, "rt");
|
|
if (f == NULL) {
|
|
continue;
|
|
}
|
|
while (fgets(buf, sizeof(buf), f)) {
|
|
if (strstr(buf, "present:") && strstr(buf, "yes")) {
|
|
present = 1;
|
|
}
|
|
/*if (strstr(buf, "charging state:")) {
|
|
if (strstr(buf + 15, "charging")) {
|
|
charging = 1;
|
|
}
|
|
if (strstr(buf + 15, "discharging")) {
|
|
charging = -1;
|
|
}
|
|
if (all_state * charging < 0) {
|
|
printf("cannot charge and discharge at the same time\n");
|
|
}
|
|
}*/
|
|
sscanf(buf, "remaining capacity: %d", &curr_cap);
|
|
sscanf(buf, "present rate: %d", &rate);
|
|
}
|
|
fclose(f);
|
|
|
|
if (!present) {
|
|
continue;
|
|
}
|
|
|
|
strcpy(strrchr(s->filename, '/'), "/info");
|
|
f = fopen(s->filename, "rt");
|
|
if (f == NULL) {
|
|
continue;
|
|
}
|
|
while (fgets(buf, sizeof(buf), f)) {
|
|
sscanf(buf, "design capacity: %d", &full_cap);
|
|
sscanf(buf, "last full capacity: %d", &full_cap);
|
|
}
|
|
fclose(f);
|
|
|
|
if (!full_cap) {
|
|
continue;
|
|
}
|
|
|
|
total->full_cap += full_cap;
|
|
total->curr_cap += curr_cap;
|
|
total->rate += rate;
|
|
if (n < num) {
|
|
strncpy(batt[n].name, s->name, sizeof(total->name) - 1);
|
|
batt[n].name[sizeof(total->name) - 1] = '\0';
|
|
batt[n].full_cap = full_cap;
|
|
batt[n].curr_cap = curr_cap;
|
|
batt[n].rate = rate;
|
|
}
|
|
all_state |= charging;
|
|
n++;
|
|
}
|
|
}
|
|
|
|
return n;
|
|
}
|
|
|
|
|
|
int
|
|
system_get_netif (int num, IFSTAT *ifaces)
|
|
{
|
|
FILE *f;
|
|
int sock;
|
|
char buf[BUFSIZ];
|
|
|
|
IFSTAT *q = ifaces;
|
|
int i = 0;
|
|
|
|
/* proc does not expose ethX:Y aliases */
|
|
/* http://www-128.ibm.com/developerworks/aix/library/au-ioctl-socket.html */
|
|
f = fopen("/proc/net/dev", "rt");
|
|
if (f == NULL) {
|
|
return 0;
|
|
}
|
|
|
|
sock = socket(AF_INET, SOCK_DGRAM, 0);
|
|
if (sock < 0) {
|
|
fclose(f);
|
|
return 0;
|
|
}
|
|
|
|
while (fgets(buf, BUFSIZ, f)) {
|
|
char *p;
|
|
struct ifreq ifr;
|
|
struct iwreq iwr;
|
|
struct iw_statistics iws;
|
|
|
|
if (i++ < 2) {
|
|
continue;
|
|
}
|
|
if (q - ifaces >= num) {
|
|
break;
|
|
}
|
|
p = strrchr(buf, ':');
|
|
if (p == NULL) {
|
|
continue;
|
|
}
|
|
*p = '\0';
|
|
for (p = buf; isspace(*p); p++) {
|
|
}
|
|
|
|
strcpy(ifr.ifr_name, p);
|
|
if (ioctl(sock, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) {
|
|
continue;
|
|
}
|
|
if (ifr.ifr_flags & IFF_LOOPBACK) {
|
|
continue;
|
|
}
|
|
if (!(ifr.ifr_flags & IFF_UP)) {
|
|
continue;
|
|
}
|
|
|
|
strncpy(q->name, p, sizeof(q->name));
|
|
q->name[sizeof(q->name) - 1] = '\0';
|
|
q->essid[0] = '\0';
|
|
q->ipv4 = -1;
|
|
q->wlink = -1;
|
|
|
|
if (ifr.ifr_flags & IFF_UP) {
|
|
if (ioctl(sock, SIOCGIFADDR, (caddr_t)&ifr) >= 0) {
|
|
q->ipv4 = ntohl(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr);
|
|
}
|
|
}
|
|
|
|
strncpy(iwr.ifr_name, p, IFNAMSIZ);
|
|
iwr.u.essid.pointer = (caddr_t)&q->essid;
|
|
iwr.u.essid.length = sizeof(q->essid);
|
|
iwr.u.essid.flags = 0;
|
|
if (ioctl(sock, SIOCGIWESSID, &iwr) >= 0) {
|
|
q->essid[iwr.u.essid.length] = '\0';
|
|
}
|
|
|
|
iwr.u.essid.pointer = (caddr_t)&iws;
|
|
iwr.u.essid.length = sizeof(iws);
|
|
iwr.u.essid.flags = 0;
|
|
if (ioctl(sock, SIOCGIWSTATS, &iwr) >= 0) {
|
|
q->wlink = iws.qual.qual;
|
|
}
|
|
|
|
q++;
|
|
}
|
|
close(sock);
|
|
fclose(f);
|
|
|
|
return q - ifaces;
|
|
}
|