diff --git a/BatteryMeter.c b/BatteryMeter.c index f2dfa6ab..5cd0c389 100644 --- a/BatteryMeter.c +++ b/BatteryMeter.c @@ -9,14 +9,13 @@ This meter written by Ian P. Hands (iphands@gmail.com, ihands@redhat.com). #include "BatteryMeter.h" +#include "Platform.h" #include "ProcessList.h" #include "CRT.h" #include "String.h" #include #include -#include -#include /*{ #include "Meter.h" @@ -26,273 +25,22 @@ typedef enum ACPresence_ { AC_PRESENT, AC_ERROR } ACPresence; - }*/ int BatteryMeter_attributes[] = { BATTERY }; -static unsigned long int parseUevent(FILE * file, const char *key) { - char line[100]; - unsigned long int dValue = 0; - char* saveptr; - - while (fgets(line, sizeof line, file)) { - if (strncmp(line, key, strlen(key)) == 0) { - char *value; - strtok_r(line, "=", &saveptr); - value = strtok_r(NULL, "=", &saveptr); - dValue = atoi(value); - break; - } - } - return dValue; -} - -static unsigned long int parseBatInfo(const char *fileName, const unsigned short int lineNum, const unsigned short int wordNum) { - const char batteryPath[] = PROCDIR "/acpi/battery/"; - DIR* batteryDir = opendir(batteryPath); - if (!batteryDir) - return 0; - - #define MAX_BATTERIES 64 - char* batteries[MAX_BATTERIES]; - unsigned int nBatteries = 0; - memset(batteries, 0, MAX_BATTERIES * sizeof(char*)); - - struct dirent result; - struct dirent* dirEntry; - while (nBatteries < MAX_BATTERIES) { - int err = readdir_r(batteryDir, &result, &dirEntry); - if (err || !dirEntry) - break; - char* entryName = dirEntry->d_name; - if (strncmp(entryName, "BAT", 3)) - continue; - batteries[nBatteries] = strdup(entryName); - nBatteries++; - } - closedir(batteryDir); - - unsigned long int total = 0; - for (unsigned int i = 0; i < nBatteries; i++) { - char infoPath[30]; - snprintf(infoPath, sizeof infoPath, "%s%s/%s", batteryPath, batteries[i], fileName); - - FILE* file = fopen(infoPath, "r"); - if (!file) { - break; - } - - char line[50] = ""; - for (unsigned short int i = 0; i < lineNum; i++) { - char* ok = fgets(line, sizeof line, file); - if (!ok) break; - } - - fclose(file); - - char *foundNumStr = String_getToken(line, wordNum); - const unsigned long int foundNum = atoi(foundNumStr); - free(foundNumStr); - - total += foundNum; - } - - for (unsigned int i = 0; i < nBatteries; i++) { - free(batteries[i]); - } - - return total; -} - -static ACPresence procAcpiCheck() { - ACPresence isOn = AC_ERROR; - const char *power_supplyPath = PROCDIR "/acpi/ac_adapter"; - DIR *power_supplyDir = opendir(power_supplyPath); - if (!power_supplyDir) { - return AC_ERROR; - } - - struct dirent result; - struct dirent* dirEntry; - for (;;) { - int err = readdir_r((DIR *) power_supplyDir, &result, &dirEntry); - if (err || !dirEntry) - break; - - char* entryName = (char *) dirEntry->d_name; - - if (entryName[0] != 'A') - continue; - - char statePath[50]; - snprintf((char *) statePath, sizeof statePath, "%s/%s/state", power_supplyPath, entryName); - FILE* file = fopen(statePath, "r"); - - if (!file) { - isOn = AC_ERROR; - continue; - } - - char line[100]; - fgets(line, sizeof line, file); - line[sizeof(line) - 1] = '\0'; - - fclose(file); - - const char *isOnline = String_getToken(line, 2); - - if (strcmp(isOnline, "on-line") == 0) { - isOn = AC_PRESENT; - } else { - isOn = AC_ABSENT; - } - free((char *) isOnline); - if (isOn == AC_PRESENT) { - break; - } - } - - if (power_supplyDir) - closedir(power_supplyDir); - return isOn; -} - -static ACPresence sysCheck() { - ACPresence isOn = AC_ERROR; - const char *power_supplyPath = "/sys/class/power_supply"; - DIR *power_supplyDir = opendir(power_supplyPath); - if (!power_supplyDir) { - return AC_ERROR; - } - - struct dirent result; - struct dirent* dirEntry; - for (;;) { - int err = readdir_r((DIR *) power_supplyDir, &result, &dirEntry); - if (err || !dirEntry) - break; - - char* entryName = (char *) dirEntry->d_name; - if (strncmp(entryName, "A", 1)) { - continue; - } - char onlinePath[50]; - snprintf((char *) onlinePath, sizeof onlinePath, "%s/%s/online", power_supplyPath, entryName); - FILE* file = fopen(onlinePath, "r"); - if (!file) { - isOn = AC_ERROR; - } else { - isOn = (fgetc(file) - '0'); - fclose(file); - if (isOn == AC_PRESENT) { - // If any AC adapter is being used then stop - break; - } - } - } - - if (power_supplyDir) - closedir(power_supplyDir); - - return isOn; -} - -static ACPresence chkIsOnline() { - if (access(PROCDIR "/acpi/ac_adapter", F_OK) == 0) { - return procAcpiCheck(); - } else if (access("/sys/class/power_supply", F_OK) == 0) { - return sysCheck(); - } else { - return AC_ERROR; - } -} - -static double getProcBatData() { - const unsigned long int totalFull = parseBatInfo("info", 3, 4); - if (totalFull == 0) - return 0; - - const unsigned long int totalRemain = parseBatInfo("state", 5, 3); - if (totalRemain == 0) - return 0; - - return totalRemain * 100.0 / (double) totalFull; -} - -static double getSysBatData() { - const char *power_supplyPath = "/sys/class/power_supply/"; - DIR *power_supplyDir = opendir(power_supplyPath); - if (!power_supplyDir) - return 0; - - unsigned long int totalFull = 0; - unsigned long int totalRemain = 0; - - struct dirent result; - struct dirent* dirEntry; - for (;;) { - int err = readdir_r((DIR *) power_supplyDir, &result, &dirEntry); - if (err || !dirEntry) - break; - char* entryName = (char *) dirEntry->d_name; - - if (strncmp(entryName, "BAT", 3)) { - continue; - } - - const char ueventPath[50]; - - snprintf((char *) ueventPath, sizeof ueventPath, "%s%s/uevent", power_supplyPath, entryName); - - FILE *file; - if ((file = fopen(ueventPath, "r")) == NULL) { - closedir(power_supplyDir); - return 0; - } - - if ((totalFull += parseUevent(file, "POWER_SUPPLY_ENERGY_FULL="))) { - totalRemain += parseUevent(file, "POWER_SUPPLY_ENERGY_NOW="); - } else { - //reset file pointer - if (fseek(file, 0, SEEK_SET) < 0) { - closedir(power_supplyDir); - fclose(file); - return 0; - } - } - - //Some systems have it as CHARGE instead of ENERGY. - if ((totalFull += parseUevent(file, "POWER_SUPPLY_CHARGE_FULL="))) { - totalRemain += parseUevent(file, "POWER_SUPPLY_CHARGE_NOW="); - } else { - //reset file pointer - if (fseek(file, 0, SEEK_SET) < 0) { - closedir(power_supplyDir); - fclose(file); - return 0; - } - } - - fclose(file); - } - - const double percent = totalFull > 0 ? ((double) totalRemain * 100) / (double) totalFull : 0; - closedir(power_supplyDir); - return percent; -} - static void BatteryMeter_setValues(Meter * this, char *buffer, int len) { - double percent = getProcBatData(); + ACPresence isOnAC; + double percent; + + Platform_getBatteryLevel(&percent, &isOnAC); - if (percent == 0) { - percent = getSysBatData(); - if (percent == 0) { - snprintf(buffer, len, "n/a"); - return; - } + if (percent == -1) { + this->values[0] = 0; + snprintf(buffer, len, "n/a"); + return; } this->values[0] = percent; @@ -308,11 +56,9 @@ static void BatteryMeter_setValues(Meter * this, char *buffer, int len) { onBatteryText = "%.1f%%(bat)"; } - ACPresence isOnLine = chkIsOnline(); - - if (isOnLine == AC_PRESENT) { + if (isOnAC == AC_PRESENT) { snprintf(buffer, len, onAcText, percent); - } else if (isOnLine == AC_ABSENT) { + } else if (isOnAC == AC_ABSENT) { snprintf(buffer, len, onBatteryText, percent); } else { snprintf(buffer, len, unknownText, percent); diff --git a/BatteryMeter.h b/BatteryMeter.h index 25fd3c92..bf8d2e82 100644 --- a/BatteryMeter.h +++ b/BatteryMeter.h @@ -19,7 +19,6 @@ typedef enum ACPresence_ { AC_ERROR } ACPresence; - extern int BatteryMeter_attributes[]; extern MeterClass BatteryMeter_class; diff --git a/Makefile.am b/Makefile.am index 5ce4c23a..0c6eaca3 100644 --- a/Makefile.am +++ b/Makefile.am @@ -35,10 +35,10 @@ HostnameMeter.h OpenFilesScreen.h Affinity.h IncSet.h Action.h if HTOP_LINUX myhtopplatsources = linux/Platform.c linux/IOPriorityPanel.c linux/IOPriority.c \ -linux/LinuxProcess.c linux/LinuxProcessList.c linux/LinuxCRT.c +linux/LinuxProcess.c linux/LinuxProcessList.c linux/LinuxCRT.c linux/Battery.c myhtopplatheaders = linux/Platform.h linux/IOPriorityPanel.h linux/IOPriority.h \ -linux/LinuxProcess.h linux/LinuxProcessList.h linux/LinuxCRT.h +linux/LinuxProcess.h linux/LinuxProcessList.h linux/LinuxCRT.h linux/Battery.h endif if HTOP_UNSUPPORTED diff --git a/linux/Battery.c b/linux/Battery.c new file mode 100644 index 00000000..eb458af8 --- /dev/null +++ b/linux/Battery.c @@ -0,0 +1,269 @@ +/* +htop - linux/Battery.c +(C) 2004-2014 Hisham H. Muhammad +Released under the GNU GPL, see the COPYING file +in the source distribution for its full text. + +Linux battery readings written by Ian P. Hands (iphands@gmail.com, ihands@redhat.com). +*/ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif +#include +#include +#include +#include +#include "BatteryMeter.h" +#include "String.h" + +static unsigned long int parseUevent(FILE * file, const char *key) { + char line[100]; + unsigned long int dValue = 0; + char* saveptr; + + while (fgets(line, sizeof line, file)) { + if (strncmp(line, key, strlen(key)) == 0) { + char *value; + strtok_r(line, "=", &saveptr); + value = strtok_r(NULL, "=", &saveptr); + dValue = atoi(value); + break; + } + } + return dValue; +} + +static unsigned long int parseBatInfo(const char *fileName, const unsigned short int lineNum, const unsigned short int wordNum) { + const char batteryPath[] = PROCDIR "/acpi/battery/"; + DIR* batteryDir = opendir(batteryPath); + if (!batteryDir) + return 0; + + #define MAX_BATTERIES 64 + char* batteries[MAX_BATTERIES]; + unsigned int nBatteries = 0; + memset(batteries, 0, MAX_BATTERIES * sizeof(char*)); + + struct dirent result; + struct dirent* dirEntry; + while (nBatteries < MAX_BATTERIES) { + int err = readdir_r(batteryDir, &result, &dirEntry); + if (err || !dirEntry) + break; + char* entryName = dirEntry->d_name; + if (strncmp(entryName, "BAT", 3)) + continue; + batteries[nBatteries] = strdup(entryName); + nBatteries++; + } + closedir(batteryDir); + + unsigned long int total = 0; + for (unsigned int i = 0; i < nBatteries; i++) { + char infoPath[30]; + snprintf(infoPath, sizeof infoPath, "%s%s/%s", batteryPath, batteries[i], fileName); + + FILE* file = fopen(infoPath, "r"); + if (!file) { + break; + } + + char line[50] = ""; + for (unsigned short int i = 0; i < lineNum; i++) { + char* ok = fgets(line, sizeof line, file); + if (!ok) break; + } + + fclose(file); + + char *foundNumStr = String_getToken(line, wordNum); + const unsigned long int foundNum = atoi(foundNumStr); + free(foundNumStr); + + total += foundNum; + } + + for (unsigned int i = 0; i < nBatteries; i++) { + free(batteries[i]); + } + + return total; +} + +static ACPresence procAcpiCheck() { + ACPresence isOn = AC_ERROR; + const char *power_supplyPath = PROCDIR "/acpi/ac_adapter"; + DIR *power_supplyDir = opendir(power_supplyPath); + if (!power_supplyDir) { + return AC_ERROR; + } + + struct dirent result; + struct dirent* dirEntry; + for (;;) { + int err = readdir_r((DIR *) power_supplyDir, &result, &dirEntry); + if (err || !dirEntry) + break; + + char* entryName = (char *) dirEntry->d_name; + + if (entryName[0] != 'A') + continue; + + char statePath[50]; + snprintf((char *) statePath, sizeof statePath, "%s/%s/state", power_supplyPath, entryName); + FILE* file = fopen(statePath, "r"); + + if (!file) { + isOn = AC_ERROR; + continue; + } + + char line[100]; + fgets(line, sizeof line, file); + line[sizeof(line) - 1] = '\0'; + + fclose(file); + + const char *isOnline = String_getToken(line, 2); + + if (strcmp(isOnline, "on-line") == 0) { + isOn = AC_PRESENT; + } else { + isOn = AC_ABSENT; + } + free((char *) isOnline); + if (isOn == AC_PRESENT) { + break; + } + } + + if (power_supplyDir) + closedir(power_supplyDir); + return isOn; +} + +static ACPresence sysCheck() { + ACPresence isOn = AC_ERROR; + const char *power_supplyPath = "/sys/class/power_supply"; + DIR *power_supplyDir = opendir(power_supplyPath); + if (!power_supplyDir) { + return AC_ERROR; + } + + struct dirent result; + struct dirent* dirEntry; + for (;;) { + int err = readdir_r((DIR *) power_supplyDir, &result, &dirEntry); + if (err || !dirEntry) + break; + + char* entryName = (char *) dirEntry->d_name; + if (strncmp(entryName, "A", 1)) { + continue; + } + char onlinePath[50]; + snprintf((char *) onlinePath, sizeof onlinePath, "%s/%s/online", power_supplyPath, entryName); + FILE* file = fopen(onlinePath, "r"); + if (!file) { + isOn = AC_ERROR; + } else { + isOn = (fgetc(file) - '0'); + fclose(file); + if (isOn == AC_PRESENT) { + // If any AC adapter is being used then stop + break; + } + } + } + + if (power_supplyDir) + closedir(power_supplyDir); + + return isOn; +} + +ACPresence Battery_isOnAC() { + if (access(PROCDIR "/acpi/ac_adapter", F_OK) == 0) { + return procAcpiCheck(); + } else if (access("/sys/class/power_supply", F_OK) == 0) { + return sysCheck(); + } else { + return AC_ERROR; + } +} + +double Battery_getProcBatData() { + const unsigned long int totalFull = parseBatInfo("info", 3, 4); + if (totalFull == 0) + return 0; + + const unsigned long int totalRemain = parseBatInfo("state", 5, 3); + if (totalRemain == 0) + return 0; + + return totalRemain * 100.0 / (double) totalFull; +} + +double Battery_getSysBatData() { + const char *power_supplyPath = "/sys/class/power_supply/"; + DIR *power_supplyDir = opendir(power_supplyPath); + if (!power_supplyDir) + return 0; + + unsigned long int totalFull = 0; + unsigned long int totalRemain = 0; + + struct dirent result; + struct dirent* dirEntry; + for (;;) { + int err = readdir_r((DIR *) power_supplyDir, &result, &dirEntry); + if (err || !dirEntry) + break; + char* entryName = (char *) dirEntry->d_name; + + if (strncmp(entryName, "BAT", 3)) { + continue; + } + + const char ueventPath[50]; + + snprintf((char *) ueventPath, sizeof ueventPath, "%s%s/uevent", power_supplyPath, entryName); + + FILE *file; + if ((file = fopen(ueventPath, "r")) == NULL) { + closedir(power_supplyDir); + return 0; + } + + if ((totalFull += parseUevent(file, "POWER_SUPPLY_ENERGY_FULL="))) { + totalRemain += parseUevent(file, "POWER_SUPPLY_ENERGY_NOW="); + } else { + //reset file pointer + if (fseek(file, 0, SEEK_SET) < 0) { + closedir(power_supplyDir); + fclose(file); + return 0; + } + } + + //Some systems have it as CHARGE instead of ENERGY. + if ((totalFull += parseUevent(file, "POWER_SUPPLY_CHARGE_FULL="))) { + totalRemain += parseUevent(file, "POWER_SUPPLY_CHARGE_NOW="); + } else { + //reset file pointer + if (fseek(file, 0, SEEK_SET) < 0) { + closedir(power_supplyDir); + fclose(file); + return 0; + } + } + + fclose(file); + } + + const double percent = totalFull > 0 ? ((double) totalRemain * 100) / (double) totalFull : 0; + closedir(power_supplyDir); + return percent; +} diff --git a/linux/Battery.h b/linux/Battery.h new file mode 100644 index 00000000..88ba2b01 --- /dev/null +++ b/linux/Battery.h @@ -0,0 +1,24 @@ +/* Do not edit this file. It was automatically generated. */ + +#ifndef HEADER_Battery +#define HEADER_Battery +/* +htop - linux/Battery.h +(C) 2004-2014 Hisham H. Muhammad +Released under the GNU GPL, see the COPYING file +in the source distribution for its full text. + +Linux battery readings written by Ian P. Hands (iphands@gmail.com, ihands@redhat.com). +*/ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +ACPresence Battery_isOnAC(); + +double Battery_getProcBatData(); + +double Battery_getSysBatData(); + +#endif diff --git a/linux/LinuxCRT.h b/linux/LinuxCRT.h new file mode 100644 index 00000000..f8c43e4d --- /dev/null +++ b/linux/LinuxCRT.h @@ -0,0 +1,17 @@ +/* Do not edit this file. It was automatically generated. */ + +#ifndef HEADER_LinuxCRT +#define HEADER_LinuxCRT +/* +htop - LinuxCRT.h +(C) 2014 Hisham H. Muhammad +Released under the GNU GPL, see the COPYING file +in the source distribution for its full text. +*/ + +#ifdef HAVE_EXECINFO_H +#endif + +void CRT_handleSIGSEGV(int sgn); + +#endif diff --git a/linux/LinuxProcess.h b/linux/LinuxProcess.h new file mode 100644 index 00000000..97ddf90b --- /dev/null +++ b/linux/LinuxProcess.h @@ -0,0 +1,39 @@ +/* Do not edit this file. It was automatically generated. */ + +#ifndef HEADER_LinuxProcess +#define HEADER_LinuxProcess +/* +htop - LinuxProcess.h +(C) 2014 Hisham H. Muhammad +Released under the GNU GPL, see the COPYING file +in the source distribution for its full text. +*/ + + +#include "IOPriority.h" + +typedef struct LinuxProcess_ { + Process super; + IOPriority ioPriority; +} LinuxProcess; + + +/* +[1] Note that before kernel 2.6.26 a process that has not asked for +an io priority formally uses "none" as scheduling class, but the +io scheduler will treat such processes as if it were in the best +effort class. The priority within the best effort class will be +dynamically derived from the cpu nice level of the process: +extern io_priority; +*/ +#define LinuxProcess_effectiveIOPriority(p_) (IOPriority_class(p_->ioPriority) == IOPRIO_CLASS_NONE ? IOPriority_tuple(IOPRIO_CLASS_BE, (p_->super.nice + 20) / 5) : p_->ioPriority) + +IOPriority LinuxProcess_updateIOPriority(LinuxProcess* this); + +bool LinuxProcess_setIOPriority(LinuxProcess* this, IOPriority ioprio); + +void LinuxProcess_writeField(LinuxProcess* this, RichString* str, ProcessField field); + +long LinuxProcess_compare(const void* v1, const void* v2); + +#endif diff --git a/linux/LinuxProcessList.h b/linux/LinuxProcessList.h new file mode 100644 index 00000000..4f9482fa --- /dev/null +++ b/linux/LinuxProcessList.h @@ -0,0 +1,56 @@ +/* Do not edit this file. It was automatically generated. */ + +#ifndef HEADER_LinuxProcessList +#define HEADER_LinuxProcessList +/* +htop - LinuxProcessList.h +(C) 2014 Hisham H. Muhammad +Released under the GNU GPL, see the COPYING file +in the source distribution for its full text. +*/ + + +#include "ProcessList.h" + +#ifndef PROCDIR +#define PROCDIR "/proc" +#endif + +#ifndef PROCSTATFILE +#define PROCSTATFILE PROCDIR "/stat" +#endif + +#ifndef PROCMEMINFOFILE +#define PROCMEMINFOFILE PROCDIR "/meminfo" +#endif + + +ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidWhiteList); + +void ProcessList_delete(ProcessList* this); + + +#ifdef HAVE_TASKSTATS + +#endif + +#ifdef HAVE_OPENVZ + +#endif + +#ifdef HAVE_CGROUP + +#endif + +#ifdef HAVE_VSERVER + +#endif + +#ifdef HAVE_OOM + +#endif + +void ProcessList_scan(ProcessList* this); + + +#endif diff --git a/linux/Platform.c b/linux/Platform.c index 4607ad68..ee5abf81 100644 --- a/linux/Platform.c +++ b/linux/Platform.c @@ -9,6 +9,8 @@ in the source distribution for its full text. #include "IOPriority.h" #include "IOPriorityPanel.h" #include "LinuxProcess.h" +#include "Battery.h" + #include "Meter.h" #include "CPUMeter.h" #include "MemoryMeter.h" @@ -16,7 +18,6 @@ in the source distribution for its full text. #include "TasksMeter.h" #include "LoadAverageMeter.h" #include "UptimeMeter.h" -#include "BatteryMeter.h" #include "ClockMeter.h" #include "HostnameMeter.h" @@ -25,6 +26,7 @@ in the source distribution for its full text. /*{ #include "Action.h" +#include "BatteryMeter.h" }*/ static Htop_Reaction Platform_actionSetIOPriority(Panel* panel, ProcessList* pl, Header* header) { @@ -102,3 +104,19 @@ int Platform_getMaxPid() { return maxPid; } +void Platform_getBatteryLevel(double* level, ACPresence* isOnAC) { + + double percent = Battery_getProcBatData(); + + if (percent == 0) { + percent = Battery_getSysBatData(); + if (percent == 0) { + *level = -1; + *isOnAC = AC_ERROR; + return; + } + } + + *isOnAC = Battery_isOnAC(); + *level = percent; +} diff --git a/linux/Platform.h b/linux/Platform.h new file mode 100644 index 00000000..2058419c --- /dev/null +++ b/linux/Platform.h @@ -0,0 +1,27 @@ +/* Do not edit this file. It was automatically generated. */ + +#ifndef HEADER_Platform +#define HEADER_Platform +/* +htop - linux/Platform.h +(C) 2014 Hisham H. Muhammad +Released under the GNU GPL, see the COPYING file +in the source distribution for its full text. +*/ + +#include "Action.h" +#include "BatteryMeter.h" + +void Platform_setBindings(Htop_Action* keys); + +extern MeterClass* Platform_meterTypes[]; + +int Platform_getUptime(); + +void Platform_getLoadAverage(double* one, double* five, double* fifteen); + +int Platform_getMaxPid(); + +void Platform_getBatteryLevel(double* level, ACPresence* isOnAC); + +#endif diff --git a/unsupported/Platform.c b/unsupported/Platform.c index 764f890e..d8618919 100644 --- a/unsupported/Platform.c +++ b/unsupported/Platform.c @@ -11,13 +11,13 @@ in the source distribution for its full text. #include "SwapMeter.h" #include "TasksMeter.h" #include "LoadAverageMeter.h" -#include "BatteryMeter.h" #include "ClockMeter.h" #include "HostnameMeter.h" #include "UptimeMeter.h" /*{ #include "Action.h" +#include "BatteryMeter.h" }*/ void Platform_setBindings(Htop_Action* keys) { @@ -58,3 +58,9 @@ void Platform_getLoadAverage(double* one, double* five, double* fifteen) { int Platform_getMaxPid() { return -1; } + +void Platform_getBatteryLevel(double* level, ACPresence* isOnAC) { + *level = -1; + *isOnAC = AC_ERROR; +} +