CPU Temperature and Frequency meter for Linux platform

This commit is contained in:
Timofey Gelazoniya 2022-06-07 22:16:47 +03:00
parent 611ea4606f
commit 36260b5814
Signed by: zeldon
GPG Key ID: 047886915281DD2A
11 changed files with 1975 additions and 1390 deletions

175
CRT.c
View File

@ -38,7 +38,6 @@ in the source distribution for its full text.
#include <execinfo.h> #include <execinfo.h>
#endif #endif
#define ColorIndex(i, j) ((7 - (i)) * 8 + (j)) #define ColorIndex(i, j) ((7 - (i)) * 8 + (j))
#define ColorPair(i, j) COLOR_PAIR(ColorIndex(i, j)) #define ColorPair(i, j) COLOR_PAIR(ColorIndex(i, j))
@ -95,7 +94,8 @@ static const int* CRT_delay;
const char *CRT_degreeSign; const char *CRT_degreeSign;
static const char* initDegreeSign(void) { static const char *initDegreeSign(void)
{
#ifdef HAVE_LIBNCURSESW #ifdef HAVE_LIBNCURSESW
if (CRT_utf8) if (CRT_utf8)
return "\xc2\xb0"; return "\xc2\xb0";
@ -127,6 +127,8 @@ static int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
[FAILED_READ] = A_BOLD | ColorPair(Red, Black), [FAILED_READ] = A_BOLD | ColorPair(Red, Black),
[PAUSED] = A_BOLD | ColorPair(Yellow, Cyan), [PAUSED] = A_BOLD | ColorPair(Yellow, Cyan),
[UPTIME] = A_BOLD | ColorPair(Cyan, Black), [UPTIME] = A_BOLD | ColorPair(Cyan, Black),
[TEMP] = A_BOLD | ColorPair(Cyan, Black),
[FREQ] = A_BOLD | ColorPair(Cyan, Black),
[BATTERY] = A_BOLD | ColorPair(Cyan, Black), [BATTERY] = A_BOLD | ColorPair(Cyan, Black),
[LARGE_NUMBER] = A_BOLD | ColorPair(Red, Black), [LARGE_NUMBER] = A_BOLD | ColorPair(Red, Black),
[METER_SHADOW] = A_BOLD | ColorPairGrayBlack, [METER_SHADOW] = A_BOLD | ColorPairGrayBlack,
@ -234,6 +236,8 @@ static int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
[FAILED_READ] = A_BOLD, [FAILED_READ] = A_BOLD,
[PAUSED] = A_BOLD | A_REVERSE, [PAUSED] = A_BOLD | A_REVERSE,
[UPTIME] = A_BOLD, [UPTIME] = A_BOLD,
[TEMP] = A_BOLD,
[FREQ] = A_BOLD,
[BATTERY] = A_BOLD, [BATTERY] = A_BOLD,
[LARGE_NUMBER] = A_BOLD, [LARGE_NUMBER] = A_BOLD,
[METER_SHADOW] = A_DIM, [METER_SHADOW] = A_DIM,
@ -341,6 +345,8 @@ static int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
[FAILED_READ] = ColorPair(Red, White), [FAILED_READ] = ColorPair(Red, White),
[PAUSED] = A_BOLD | ColorPair(Yellow, Cyan), [PAUSED] = A_BOLD | ColorPair(Yellow, Cyan),
[UPTIME] = ColorPair(Yellow, White), [UPTIME] = ColorPair(Yellow, White),
[TEMP] = ColorPair(Yellow, White),
[FREQ] = ColorPair(Yellow, White),
[BATTERY] = ColorPair(Yellow, White), [BATTERY] = ColorPair(Yellow, White),
[LARGE_NUMBER] = ColorPair(Red, White), [LARGE_NUMBER] = ColorPair(Red, White),
[METER_SHADOW] = ColorPair(Blue, White), [METER_SHADOW] = ColorPair(Blue, White),
@ -448,6 +454,8 @@ static int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
[FAILED_READ] = ColorPair(Red, Black), [FAILED_READ] = ColorPair(Red, Black),
[PAUSED] = A_BOLD | ColorPair(Yellow, Cyan), [PAUSED] = A_BOLD | ColorPair(Yellow, Cyan),
[UPTIME] = ColorPair(Yellow, Black), [UPTIME] = ColorPair(Yellow, Black),
[TEMP] = ColorPair(Yellow, Black),
[FREQ] = ColorPair(Yellow, Black),
[BATTERY] = ColorPair(Yellow, Black), [BATTERY] = ColorPair(Yellow, Black),
[LARGE_NUMBER] = ColorPair(Red, Black), [LARGE_NUMBER] = ColorPair(Red, Black),
[METER_SHADOW] = A_BOLD | ColorPairGrayBlack, [METER_SHADOW] = A_BOLD | ColorPairGrayBlack,
@ -555,6 +563,8 @@ static int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
[FAILED_READ] = A_BOLD | ColorPair(Red, Blue), [FAILED_READ] = A_BOLD | ColorPair(Red, Blue),
[PAUSED] = A_BOLD | ColorPair(Yellow, Cyan), [PAUSED] = A_BOLD | ColorPair(Yellow, Cyan),
[UPTIME] = A_BOLD | ColorPair(Yellow, Blue), [UPTIME] = A_BOLD | ColorPair(Yellow, Blue),
[TEMP] = A_BOLD | ColorPair(Yellow, Blue),
[FREQ] = A_BOLD | ColorPair(Yellow, Blue),
[BATTERY] = A_BOLD | ColorPair(Yellow, Blue), [BATTERY] = A_BOLD | ColorPair(Yellow, Blue),
[LARGE_NUMBER] = A_BOLD | ColorPair(Red, Blue), [LARGE_NUMBER] = A_BOLD | ColorPair(Red, Blue),
[METER_SHADOW] = ColorPair(Cyan, Blue), [METER_SHADOW] = ColorPair(Cyan, Blue),
@ -662,6 +672,8 @@ static int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
[FAILED_READ] = A_BOLD | ColorPair(Red, Black), [FAILED_READ] = A_BOLD | ColorPair(Red, Black),
[PAUSED] = A_BOLD | ColorPair(Yellow, Green), [PAUSED] = A_BOLD | ColorPair(Yellow, Green),
[UPTIME] = ColorPair(Green, Black), [UPTIME] = ColorPair(Green, Black),
[TEMP] = ColorPair(Green, Black),
[FREQ] = ColorPair(Green, Black),
[BATTERY] = ColorPair(Green, Black), [BATTERY] = ColorPair(Green, Black),
[LARGE_NUMBER] = A_BOLD | ColorPair(Red, Black), [LARGE_NUMBER] = A_BOLD | ColorPair(Red, Black),
[METER_SHADOW] = A_BOLD | ColorPairGrayBlack, [METER_SHADOW] = A_BOLD | ColorPairGrayBlack,
@ -763,7 +775,8 @@ int CRT_scrollWheelVAmount = 10;
ColorScheme CRT_colorScheme = COLORSCHEME_DEFAULT; ColorScheme CRT_colorScheme = COLORSCHEME_DEFAULT;
ATTR_NORETURN ATTR_NORETURN
static void CRT_handleSIGTERM(ATTR_UNUSED int sgn) { static void CRT_handleSIGTERM(ATTR_UNUSED int sgn)
{
CRT_done(); CRT_done();
_exit(0); _exit(0);
} }
@ -773,7 +786,8 @@ static void CRT_handleSIGTERM(ATTR_UNUSED int sgn) {
static int stderrRedirectNewFd = -1; static int stderrRedirectNewFd = -1;
static int stderrRedirectBackupFd = -1; static int stderrRedirectBackupFd = -1;
static int createStderrCacheFile(void) { static int createStderrCacheFile(void)
{
#if defined(HAVE_MEMFD_CREATE) #if defined(HAVE_MEMFD_CREATE)
return memfd_create("htop.stderr-redirect", 0); return memfd_create("htop.stderr-redirect", 0);
#elif defined(O_TMPFILE) #elif defined(O_TMPFILE)
@ -792,9 +806,11 @@ static int createStderrCacheFile(void) {
#endif /* HAVE_MEMFD_CREATE */ #endif /* HAVE_MEMFD_CREATE */
} }
static void redirectStderr(void) { static void redirectStderr(void)
{
stderrRedirectNewFd = createStderrCacheFile(); stderrRedirectNewFd = createStderrCacheFile();
if (stderrRedirectNewFd < 0) { if (stderrRedirectNewFd < 0)
{
/* ignore failure */ /* ignore failure */
return; return;
} }
@ -803,7 +819,8 @@ static void redirectStderr(void) {
dup2(stderrRedirectNewFd, STDERR_FILENO); dup2(stderrRedirectNewFd, STDERR_FILENO);
} }
static void dumpStderr(void) { static void dumpStderr(void)
{
if (stderrRedirectNewFd < 0) if (stderrRedirectNewFd < 0)
return; return;
@ -815,22 +832,27 @@ static void dumpStderr(void) {
bool header = false; bool header = false;
char buffer[8192]; char buffer[8192];
for (;;) { for (;;)
{
errno = 0; errno = 0;
ssize_t res = read(stderrRedirectNewFd, buffer, sizeof(buffer)); ssize_t res = read(stderrRedirectNewFd, buffer, sizeof(buffer));
if (res < 0) { if (res < 0)
{
if (errno == EINTR) if (errno == EINTR)
continue; continue;
break; break;
} }
if (res == 0) { if (res == 0)
{
break; break;
} }
if (res > 0) { if (res > 0)
if (!header) { {
if (!header)
{
fprintf(stderr, ">>>>>>>>>> stderr output >>>>>>>>>>\n"); fprintf(stderr, ">>>>>>>>>> stderr output >>>>>>>>>>\n");
header = true; header = true;
} }
@ -845,7 +867,8 @@ static void dumpStderr(void) {
stderrRedirectNewFd = -1; stderrRedirectNewFd = -1;
} }
void CRT_debug_impl(const char* file, size_t lineno, const char* func, const char* fmt, ...) { void CRT_debug_impl(const char *file, size_t lineno, const char *func, const char *fmt, ...)
{
va_list args; va_list args;
fprintf(stderr, "[%s:%zu (%s)]: ", file, lineno, func); fprintf(stderr, "[%s:%zu (%s)]: ", file, lineno, func);
@ -857,17 +880,20 @@ void CRT_debug_impl(const char* file, size_t lineno, const char* func, const cha
#else /* !NDEBUG */ #else /* !NDEBUG */
static void redirectStderr(void) { static void redirectStderr(void)
{
} }
static void dumpStderr(void) { static void dumpStderr(void)
{
} }
#endif /* !NDEBUG */ #endif /* !NDEBUG */
static struct sigaction old_sig_handler[32]; static struct sigaction old_sig_handler[32];
static void CRT_installSignalHandlers(void) { static void CRT_installSignalHandlers(void)
{
struct sigaction act; struct sigaction act;
sigemptyset(&act.sa_mask); sigemptyset(&act.sa_mask);
act.sa_flags = (int)SA_RESETHAND | SA_NODEFER; act.sa_flags = (int)SA_RESETHAND | SA_NODEFER;
@ -886,7 +912,8 @@ static void CRT_installSignalHandlers(void) {
signal(SIGQUIT, CRT_handleSIGTERM); signal(SIGQUIT, CRT_handleSIGTERM);
} }
void CRT_resetSignalHandlers(void) { void CRT_resetSignalHandlers(void)
{
sigaction(SIGSEGV, &old_sig_handler[SIGSEGV], NULL); sigaction(SIGSEGV, &old_sig_handler[SIGSEGV], NULL);
sigaction(SIGFPE, &old_sig_handler[SIGFPE], NULL); sigaction(SIGFPE, &old_sig_handler[SIGFPE], NULL);
sigaction(SIGILL, &old_sig_handler[SIGILL], NULL); sigaction(SIGILL, &old_sig_handler[SIGILL], NULL);
@ -900,21 +927,26 @@ void CRT_resetSignalHandlers(void) {
signal(SIGQUIT, SIG_DFL); signal(SIGQUIT, SIG_DFL);
} }
void CRT_setMouse(bool enabled) { void CRT_setMouse(bool enabled)
{
#ifdef HAVE_GETMOUSE #ifdef HAVE_GETMOUSE
if (enabled) { if (enabled)
{
#if NCURSES_MOUSE_VERSION > 1 #if NCURSES_MOUSE_VERSION > 1
mousemask(BUTTON1_RELEASED | BUTTON4_PRESSED | BUTTON5_PRESSED, NULL); mousemask(BUTTON1_RELEASED | BUTTON4_PRESSED | BUTTON5_PRESSED, NULL);
#else #else
mousemask(BUTTON1_RELEASED, NULL); mousemask(BUTTON1_RELEASED, NULL);
#endif #endif
} else { }
else
{
mousemask(0, NULL); mousemask(0, NULL);
} }
#endif #endif
} }
void CRT_init(const Settings* settings, bool allowUnicode) { void CRT_init(const Settings *settings, bool allowUnicode)
{
redirectStderr(); redirectStderr();
initscr(); initscr();
@ -924,7 +956,8 @@ void CRT_init(const Settings* settings, bool allowUnicode) {
CRT_colors = CRT_colorSchemes[settings->colorScheme]; CRT_colors = CRT_colorSchemes[settings->colorScheme];
CRT_colorScheme = settings->colorScheme; CRT_colorScheme = settings->colorScheme;
for (int i = 0; i < LAST_COLORELEMENT; i++) { for (int i = 0; i < LAST_COLORELEMENT; i++)
{
unsigned int color = CRT_colorSchemes[COLORSCHEME_DEFAULT][i]; unsigned int color = CRT_colorSchemes[COLORSCHEME_DEFAULT][i];
CRT_colorSchemes[COLORSCHEME_BROKENGRAY][i] = color == (A_BOLD | ColorPairGrayBlack) ? ColorPair(White, Black) : color; CRT_colorSchemes[COLORSCHEME_BROKENGRAY][i] = color == (A_BOLD | ColorPairGrayBlack) ? ColorPair(White, Black) : color;
} }
@ -938,18 +971,23 @@ void CRT_init(const Settings* settings, bool allowUnicode) {
#endif #endif
curs_set(0); curs_set(0);
if (has_colors()) { if (has_colors())
{
start_color(); start_color();
} }
const char *termType = getenv("TERM"); const char *termType = getenv("TERM");
if (termType && String_eq(termType, "linux")) { if (termType && String_eq(termType, "linux"))
{
CRT_scrollHAmount = 20; CRT_scrollHAmount = 20;
} else { }
else
{
CRT_scrollHAmount = 5; CRT_scrollHAmount = 5;
} }
if (termType && (String_startsWith(termType, "xterm") || String_eq(termType, "vt220"))) { if (termType && (String_startsWith(termType, "xterm") || String_eq(termType, "vt220")))
{
#ifdef HTOP_NETBSD #ifdef HTOP_NETBSD
#define define_key(s_, k_) define_key((char *)s_, k_) #define define_key(s_, k_) define_key((char *)s_, k_)
IGNORE_WCASTQUAL_BEGIN IGNORE_WCASTQUAL_BEGIN
@ -971,7 +1009,8 @@ IGNORE_WCASTQUAL_BEGIN
define_key("\033[17;2~", KEY_F(18)); define_key("\033[17;2~", KEY_F(18));
define_key("\033[Z", KEY_SHIFT_TAB); define_key("\033[Z", KEY_SHIFT_TAB);
char sequence[3] = "\033a"; char sequence[3] = "\033a";
for (char c = 'a'; c <= 'z'; c++) { for (char c = 'a'; c <= 'z'; c++)
{
sequence[1] = c; sequence[1] = c;
define_key(sequence, KEY_ALT('A' + (c - 'a'))); define_key(sequence, KEY_ALT('A' + (c - 'a')));
} }
@ -980,7 +1019,8 @@ IGNORE_WCASTQUAL_END
#undef define_key #undef define_key
#endif #endif
} }
if (termType && (String_startsWith(termType, "rxvt"))) { if (termType && (String_startsWith(termType, "rxvt")))
{
define_key("\033[Z", KEY_SHIFT_TAB); define_key("\033[Z", KEY_SHIFT_TAB);
} }
@ -992,9 +1032,12 @@ IGNORE_WCASTQUAL_END
CRT_setColors(CRT_colorScheme); CRT_setColors(CRT_colorScheme);
#ifdef HAVE_LIBNCURSESW #ifdef HAVE_LIBNCURSESW
if (allowUnicode && String_eq(nl_langinfo(CODESET), "UTF-8")) { if (allowUnicode && String_eq(nl_langinfo(CODESET), "UTF-8"))
{
CRT_utf8 = true; CRT_utf8 = true;
} else { }
else
{
CRT_utf8 = false; CRT_utf8 = false;
} }
#else #else
@ -1012,7 +1055,8 @@ IGNORE_WCASTQUAL_END
CRT_degreeSign = initDegreeSign(); CRT_degreeSign = initDegreeSign();
} }
void CRT_done() { void CRT_done()
{
int resetColor = CRT_colors ? CRT_colors[RESET_COLOR] : CRT_colorSchemes[COLORSCHEME_DEFAULT][RESET_COLOR]; int resetColor = CRT_colors ? CRT_colors[RESET_COLOR] : CRT_colorSchemes[COLORSCHEME_DEFAULT][RESET_COLOR];
attron(resetColor); attron(resetColor);
@ -1026,14 +1070,16 @@ void CRT_done() {
dumpStderr(); dumpStderr();
} }
void CRT_fatalError(const char* note) { void CRT_fatalError(const char *note)
{
const char *sysMsg = strerror(errno); const char *sysMsg = strerror(errno);
CRT_done(); CRT_done();
fprintf(stderr, "%s: %s\n", note, sysMsg); fprintf(stderr, "%s: %s\n", note, sysMsg);
exit(2); exit(2);
} }
int CRT_readKey() { int CRT_readKey()
{
nocbreak(); nocbreak();
cbreak(); cbreak();
nodelay(stdscr, FALSE); nodelay(stdscr, FALSE);
@ -1042,22 +1088,28 @@ int CRT_readKey() {
return ret; return ret;
} }
void CRT_disableDelay() { void CRT_disableDelay()
{
nocbreak(); nocbreak();
cbreak(); cbreak();
nodelay(stdscr, TRUE); nodelay(stdscr, TRUE);
} }
void CRT_enableDelay() { void CRT_enableDelay()
{
halfdelay(*CRT_delay); halfdelay(*CRT_delay);
} }
void CRT_setColors(int colorScheme) { void CRT_setColors(int colorScheme)
{
CRT_colorScheme = colorScheme; CRT_colorScheme = colorScheme;
for (short int i = 0; i < 8; i++) { for (short int i = 0; i < 8; i++)
for (short int j = 0; j < 8; j++) { {
if (ColorIndex(i, j) != ColorIndexGrayBlack && ColorIndex(i, j) != ColorIndexWhiteDefault) { for (short int j = 0; j < 8; j++)
{
if (ColorIndex(i, j) != ColorIndexGrayBlack && ColorIndex(i, j) != ColorIndexWhiteDefault)
{
short int bg = (colorScheme != COLORSCHEME_BLACKNIGHT) short int bg = (colorScheme != COLORSCHEME_BLACKNIGHT)
? (j == 0 ? -1 : j) ? (j == 0 ? -1 : j)
: j; : j;
@ -1076,7 +1128,8 @@ void CRT_setColors(int colorScheme) {
} }
#ifdef PRINT_BACKTRACE #ifdef PRINT_BACKTRACE
static void print_backtrace(void) { static void print_backtrace(void)
{
#if defined(HAVE_LIBUNWIND_H) && defined(HAVE_LIBUNWIND) #if defined(HAVE_LIBUNWIND_H) && defined(HAVE_LIBUNWIND)
unw_context_t context; unw_context_t context;
unw_getcontext(&context); unw_getcontext(&context);
@ -1086,7 +1139,8 @@ static void print_backtrace(void) {
unsigned int item = 0; unsigned int item = 0;
while (unw_step(&cursor) > 0) { while (unw_step(&cursor) > 0)
{
unw_word_t pc; unw_word_t pc;
unw_get_reg(&cursor, UNW_REG_IP, &pc); unw_get_reg(&cursor, UNW_REG_IP, &pc);
if (pc == 0) if (pc == 0)
@ -1101,7 +1155,8 @@ static void print_backtrace(void) {
const char *fname = "?"; const char *fname = "?";
const void *ptr = 0; const void *ptr = 0;
if (unw_get_proc_info(&cursor, &pip) == 0) { if (unw_get_proc_info(&cursor, &pip) == 0)
{
ptr = (const void *)(pip.start_ip + offset); ptr = (const void *)(pip.start_ip + offset);
#ifdef HAVE_DLADDR #ifdef HAVE_DLADDR
@ -1128,7 +1183,8 @@ static void print_backtrace(void) {
} }
#endif #endif
void CRT_handleSIGSEGV(int signal) { void CRT_handleSIGSEGV(int signal)
{
CRT_done(); CRT_done();
fprintf(stderr, "\n\n" fprintf(stderr, "\n\n"
@ -1139,19 +1195,18 @@ void CRT_handleSIGSEGV(int signal) {
" - Your " PACKAGE " version: '" VERSION "'\n" " - Your " PACKAGE " version: '" VERSION "'\n"
" - Your OS and kernel version (uname -a)\n" " - Your OS and kernel version (uname -a)\n"
" - Your distribution and release (lsb_release -a)\n" " - Your distribution and release (lsb_release -a)\n"
" - Likely steps to reproduce (How did it happen?)\n" " - Likely steps to reproduce (How did it happen?)\n");
);
#ifdef PRINT_BACKTRACE #ifdef PRINT_BACKTRACE
fprintf(stderr, " - Backtrace of the issue (see below)\n"); fprintf(stderr, " - Backtrace of the issue (see below)\n");
#endif #endif
fprintf(stderr, fprintf(stderr,
"\n" "\n");
);
const char *signal_str = strsignal(signal); const char *signal_str = strsignal(signal);
if (!signal_str) { if (!signal_str)
{
signal_str = "unknown reason"; signal_str = "unknown reason";
} }
fprintf(stderr, fprintf(stderr,
@ -1159,8 +1214,7 @@ void CRT_handleSIGSEGV(int signal) {
"------------------\n" "------------------\n"
"A signal %d (%s) was received.\n" "A signal %d (%s) was received.\n"
"\n", "\n",
signal, signal_str signal, signal_str);
);
fprintf(stderr, fprintf(stderr,
"Setting information:\n" "Setting information:\n"
@ -1171,8 +1225,7 @@ void CRT_handleSIGSEGV(int signal) {
#ifdef PRINT_BACKTRACE #ifdef PRINT_BACKTRACE
fprintf(stderr, fprintf(stderr,
"Backtrace information:\n" "Backtrace information:\n"
"----------------------\n" "----------------------\n");
);
print_backtrace(); print_backtrace();
@ -1181,8 +1234,7 @@ void CRT_handleSIGSEGV(int signal) {
"To make the above information more practical to work with, " "To make the above information more practical to work with, "
"please also provide a disassembly of your " PACKAGE " binary. " "please also provide a disassembly of your " PACKAGE " binary. "
"This can usually be done by running the following command:\n" "This can usually be done by running the following command:\n"
"\n" "\n");
);
#ifdef HTOP_DARWIN #ifdef HTOP_DARWIN
fprintf(stderr, " otool -tvV `which " PACKAGE "` > ~/htop.otool\n"); fprintf(stderr, " otool -tvV `which " PACKAGE "` > ~/htop.otool\n");
@ -1192,23 +1244,21 @@ void CRT_handleSIGSEGV(int signal) {
fprintf(stderr, fprintf(stderr,
"\n" "\n"
"Please include the generated file in your report.\n" "Please include the generated file in your report.\n");
);
#endif #endif
fprintf(stderr, fprintf(stderr,
"Running this program with debug symbols or inside a debugger may provide further insights.\n" "Running this program with debug symbols or inside a debugger may provide further insights.\n"
"\n" "\n"
"Thank you for helping to improve " PACKAGE "!\n" "Thank you for helping to improve " PACKAGE "!\n"
"\n" "\n");
);
/* Call old sigsegv handler; may be default exit or third party one (e.g. ASAN) */ /* Call old sigsegv handler; may be default exit or third party one (e.g. ASAN) */
if (sigaction (signal, &old_sig_handler[signal], NULL) < 0) { if (sigaction(signal, &old_sig_handler[signal], NULL) < 0)
{
/* This avoids an infinite loop in case the handler could not be reset. */ /* This avoids an infinite loop in case the handler could not be reset. */
fprintf(stderr, fprintf(stderr,
"!!! Chained handler could not be restored. Forcing exit.\n" "!!! Chained handler could not be restored. Forcing exit.\n");
);
_exit(1); _exit(1);
} }
@ -1217,7 +1267,6 @@ void CRT_handleSIGSEGV(int signal) {
// Always terminate, even if installed handler returns // Always terminate, even if installed handler returns
fprintf(stderr, fprintf(stderr,
"!!! Chained handler did not exit. Forcing exit.\n" "!!! Chained handler did not exit. Forcing exit.\n");
);
_exit(1); _exit(1);
} }

12
CRT.h
View File

@ -15,8 +15,8 @@ in the source distribution for its full text.
#include "ProvideCurses.h" #include "ProvideCurses.h"
#include "Settings.h" #include "Settings.h"
typedef enum TreeStr_
typedef enum TreeStr_ { {
TREE_STR_VERT, TREE_STR_VERT,
TREE_STR_RTEE, TREE_STR_RTEE,
TREE_STR_BEND, TREE_STR_BEND,
@ -28,7 +28,8 @@ typedef enum TreeStr_ {
LAST_TREE_STR LAST_TREE_STR
} TreeStr; } TreeStr;
typedef enum ColorScheme_ { typedef enum ColorScheme_
{
COLORSCHEME_DEFAULT, COLORSCHEME_DEFAULT,
COLORSCHEME_MONOCHROME, COLORSCHEME_MONOCHROME,
COLORSCHEME_BLACKONWHITE, COLORSCHEME_BLACKONWHITE,
@ -39,7 +40,8 @@ typedef enum ColorScheme_ {
LAST_COLORSCHEME LAST_COLORSCHEME
} ColorScheme; } ColorScheme;
typedef enum ColorElements_ { typedef enum ColorElements_
{
RESET_COLOR, RESET_COLOR,
DEFAULT_COLOR, DEFAULT_COLOR,
FUNCTION_BAR, FUNCTION_BAR,
@ -64,6 +66,8 @@ typedef enum ColorElements_ {
METER_VALUE_WARN, METER_VALUE_WARN,
LED_COLOR, LED_COLOR,
UPTIME, UPTIME,
TEMP,
FREQ,
BATTERY, BATTERY,
TASKS_RUNNING, TASKS_RUNNING,
SWAP, SWAP,

29
FreqMeter.c Normal file
View File

@ -0,0 +1,29 @@
#include "FreqMeter.h"
#include "CRT.h"
#include "Object.h"
#include "Platform.h"
#include "XUtils.h"
static const int FreqMeter_attributes[] = {
FREQ};
static void FreqMeter_updateValues(Meter *this)
{
float freq = Platform_getFreq();
xSnprintf(this->txtBuffer, sizeof(this->txtBuffer), "%.1lf GHz", freq);
}
const MeterClass FreqMeter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete},
.updateValues = FreqMeter_updateValues,
.defaultMode = TEXT_METERMODE,
.maxItems = 1,
.total = 100.0,
.attributes = FreqMeter_attributes,
.name = "Freq",
.uiName = "Freq",
.caption = "CPU/Frequency: "};

8
FreqMeter.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef HEADER_FreqMeter
#define HEADER_FreqMeter
#include "Meter.h"
extern const MeterClass FreqMeter_class;
#endif

View File

@ -82,6 +82,8 @@ myhtopsources = \
TasksMeter.c \ TasksMeter.c \
TraceScreen.c \ TraceScreen.c \
UptimeMeter.c \ UptimeMeter.c \
FreqMeter.c \
TempMeter.c \
UsersTable.c \ UsersTable.c \
Vector.c \ Vector.c \
XUtils.c XUtils.c
@ -144,6 +146,8 @@ myhtopheaders = \
TasksMeter.h \ TasksMeter.h \
TraceScreen.h \ TraceScreen.h \
UptimeMeter.h \ UptimeMeter.h \
FreqMeter.h \
TempMeter.h \
UsersTable.h \ UsersTable.h \
Vector.h \ Vector.h \
XUtils.h XUtils.h

View File

@ -23,6 +23,8 @@ in the source distribution for its full text.
#include "Platform.h" #include "Platform.h"
#include "XUtils.h" #include "XUtils.h"
#define FORCE_TEMP_METER
#define FORCE_FREQ_METER
/* /*
@ -66,15 +68,19 @@ static void writeQuotedList(FILE* fd, char** list) {
*/ */
void Settings_delete(Settings* this) { void Settings_delete(Settings *this)
{
free(this->filename); free(this->filename);
for (unsigned int i = 0; i < HeaderLayout_getColumns(this->hLayout); i++) { for (unsigned int i = 0; i < HeaderLayout_getColumns(this->hLayout); i++)
{
String_freeArray(this->hColumns[i].names); String_freeArray(this->hColumns[i].names);
free(this->hColumns[i].modes); free(this->hColumns[i].modes);
} }
free(this->hColumns); free(this->hColumns);
if (this->screens) { if (this->screens)
for (unsigned int i = 0; this->screens[i]; i++) { {
for (unsigned int i = 0; this->screens[i]; i++)
{
ScreenSettings_delete(this->screens[i]); ScreenSettings_delete(this->screens[i]);
} }
free(this->screens); free(this->screens);
@ -82,7 +88,8 @@ void Settings_delete(Settings* this) {
free(this); free(this);
} }
static void Settings_readMeters(Settings* this, const char* line, unsigned int column) { static void Settings_readMeters(Settings *this, const char *line, unsigned int column)
{
char *trim = String_trim(line); char *trim = String_trim(line);
char **ids = String_split(trim, ' ', NULL); char **ids = String_split(trim, ' ', NULL);
free(trim); free(trim);
@ -90,30 +97,35 @@ static void Settings_readMeters(Settings* this, const char* line, unsigned int c
this->hColumns[column].names = ids; this->hColumns[column].names = ids;
} }
static void Settings_readMeterModes(Settings* this, const char* line, unsigned int column) { static void Settings_readMeterModes(Settings *this, const char *line, unsigned int column)
{
char *trim = String_trim(line); char *trim = String_trim(line);
char **ids = String_split(trim, ' ', NULL); char **ids = String_split(trim, ' ', NULL);
free(trim); free(trim);
int len = 0; int len = 0;
for (int i = 0; ids[i]; i++) { for (int i = 0; ids[i]; i++)
{
len++; len++;
} }
column = MINIMUM(column, HeaderLayout_getColumns(this->hLayout) - 1); column = MINIMUM(column, HeaderLayout_getColumns(this->hLayout) - 1);
this->hColumns[column].len = len; this->hColumns[column].len = len;
int *modes = len ? xCalloc(len, sizeof(int)) : NULL; int *modes = len ? xCalloc(len, sizeof(int)) : NULL;
for (int i = 0; i < len; i++) { for (int i = 0; i < len; i++)
{
modes[i] = atoi(ids[i]); modes[i] = atoi(ids[i]);
} }
String_freeArray(ids); String_freeArray(ids);
this->hColumns[column].modes = modes; this->hColumns[column].modes = modes;
} }
static bool Settings_validateMeters(Settings* this) { static bool Settings_validateMeters(Settings *this)
{
const size_t colCount = HeaderLayout_getColumns(this->hLayout); const size_t colCount = HeaderLayout_getColumns(this->hLayout);
bool anyMeter = false; bool anyMeter = false;
for (size_t column = 0; column < colCount; column++) { for (size_t column = 0; column < colCount; column++)
{
char **names = this->hColumns[column].names; char **names = this->hColumns[column].names;
const int *modes = this->hColumns[column].modes; const int *modes = this->hColumns[column].modes;
const size_t len = this->hColumns[column].len; const size_t len = this->hColumns[column].len;
@ -138,15 +150,18 @@ static bool Settings_validateMeters(Settings* this) {
return anyMeter; return anyMeter;
} }
static void Settings_defaultMeters(Settings* this, unsigned int initialCpuCount) { static void Settings_defaultMeters(Settings *this, unsigned int initialCpuCount)
int sizes[] = { 3, 3 }; {
int sizes[] = {3, 5};
if (initialCpuCount > 4 && initialCpuCount <= 128) { if (initialCpuCount > 4 && initialCpuCount <= 128)
{
sizes[1]++; sizes[1]++;
} }
// Release any previously allocated memory // Release any previously allocated memory
for (size_t i = 0; i < HeaderLayout_getColumns(this->hLayout); i++) { for (size_t i = 0; i < HeaderLayout_getColumns(this->hLayout); i++)
{
String_freeArray(this->hColumns[i].names); String_freeArray(this->hColumns[i].names);
free(this->hColumns[i].modes); free(this->hColumns[i].modes);
} }
@ -154,7 +169,8 @@ static void Settings_defaultMeters(Settings* this, unsigned int initialCpuCount)
this->hLayout = HF_TWO_50_50; this->hLayout = HF_TWO_50_50;
this->hColumns = xCalloc(HeaderLayout_getColumns(this->hLayout), sizeof(MeterColumnSetting)); this->hColumns = xCalloc(HeaderLayout_getColumns(this->hLayout), sizeof(MeterColumnSetting));
for (size_t i = 0; i < 2; i++) { for (size_t i = 0; i < 2; i++)
{
this->hColumns[i].names = xCalloc(sizes[i] + 1, sizeof(char *)); this->hColumns[i].names = xCalloc(sizes[i] + 1, sizeof(char *));
this->hColumns[i].modes = xCalloc(sizes[i], sizeof(int)); this->hColumns[i].modes = xCalloc(sizes[i], sizeof(int));
this->hColumns[i].len = sizes[i]; this->hColumns[i].len = sizes[i];
@ -162,31 +178,42 @@ static void Settings_defaultMeters(Settings* this, unsigned int initialCpuCount)
int r = 0; int r = 0;
if (initialCpuCount > 128) { if (initialCpuCount > 128)
{
// Just show the average, ricers need to config for impressive screenshots // Just show the average, ricers need to config for impressive screenshots
this->hColumns[0].names[0] = xStrdup("CPU"); this->hColumns[0].names[0] = xStrdup("CPU");
this->hColumns[0].modes[0] = BAR_METERMODE; this->hColumns[0].modes[0] = BAR_METERMODE;
} else if (initialCpuCount > 32) { }
else if (initialCpuCount > 32)
{
this->hColumns[0].names[0] = xStrdup("LeftCPUs8"); this->hColumns[0].names[0] = xStrdup("LeftCPUs8");
this->hColumns[0].modes[0] = BAR_METERMODE; this->hColumns[0].modes[0] = BAR_METERMODE;
this->hColumns[1].names[r] = xStrdup("RightCPUs8"); this->hColumns[1].names[r] = xStrdup("RightCPUs8");
this->hColumns[1].modes[r++] = BAR_METERMODE; this->hColumns[1].modes[r++] = BAR_METERMODE;
} else if (initialCpuCount > 16) { }
else if (initialCpuCount > 16)
{
this->hColumns[0].names[0] = xStrdup("LeftCPUs4"); this->hColumns[0].names[0] = xStrdup("LeftCPUs4");
this->hColumns[0].modes[0] = BAR_METERMODE; this->hColumns[0].modes[0] = BAR_METERMODE;
this->hColumns[1].names[r] = xStrdup("RightCPUs4"); this->hColumns[1].names[r] = xStrdup("RightCPUs4");
this->hColumns[1].modes[r++] = BAR_METERMODE; this->hColumns[1].modes[r++] = BAR_METERMODE;
} else if (initialCpuCount > 8) { }
else if (initialCpuCount > 8)
{
this->hColumns[0].names[0] = xStrdup("LeftCPUs2"); this->hColumns[0].names[0] = xStrdup("LeftCPUs2");
this->hColumns[0].modes[0] = BAR_METERMODE; this->hColumns[0].modes[0] = BAR_METERMODE;
this->hColumns[1].names[r] = xStrdup("RightCPUs2"); this->hColumns[1].names[r] = xStrdup("RightCPUs2");
this->hColumns[1].modes[r++] = BAR_METERMODE; this->hColumns[1].modes[r++] = BAR_METERMODE;
} else if (initialCpuCount > 4) { }
else if (initialCpuCount > 4)
{
this->hColumns[0].names[0] = xStrdup("LeftCPUs"); this->hColumns[0].names[0] = xStrdup("LeftCPUs");
this->hColumns[0].modes[0] = BAR_METERMODE; this->hColumns[0].modes[0] = BAR_METERMODE;
this->hColumns[1].names[r] = xStrdup("RightCPUs"); this->hColumns[1].names[r] = xStrdup("RightCPUs");
this->hColumns[1].modes[r++] = BAR_METERMODE; this->hColumns[1].modes[r++] = BAR_METERMODE;
} else { }
else
{
this->hColumns[0].names[0] = xStrdup("AllCPUs"); this->hColumns[0].names[0] = xStrdup("AllCPUs");
this->hColumns[0].modes[0] = BAR_METERMODE; this->hColumns[0].modes[0] = BAR_METERMODE;
} }
@ -200,31 +227,44 @@ static void Settings_defaultMeters(Settings* this, unsigned int initialCpuCount)
this->hColumns[1].modes[r++] = TEXT_METERMODE; this->hColumns[1].modes[r++] = TEXT_METERMODE;
this->hColumns[1].names[r] = xStrdup("Uptime"); this->hColumns[1].names[r] = xStrdup("Uptime");
this->hColumns[1].modes[r++] = TEXT_METERMODE; this->hColumns[1].modes[r++] = TEXT_METERMODE;
this->hColumns[1].names[r] = xStrdup("Temp");
this->hColumns[1].modes[r++] = TEXT_METERMODE;
this->hColumns[1].names[r] = xStrdup("Freq");
this->hColumns[1].modes[r++] = TEXT_METERMODE;
} }
static const char* toFieldName(Hashtable* columns, int id) { static const char *toFieldName(Hashtable *columns, int id)
{
if (id < 0) if (id < 0)
return NULL; return NULL;
if (id >= LAST_PROCESSFIELD) { if (id >= LAST_PROCESSFIELD)
{
const DynamicColumn *column = DynamicColumn_lookup(columns, id); const DynamicColumn *column = DynamicColumn_lookup(columns, id);
return column->name; return column->name;
} }
return Process_fields[id].name; return Process_fields[id].name;
} }
static int toFieldIndex(Hashtable* columns, const char* str) { static int toFieldIndex(Hashtable *columns, const char *str)
if (isdigit(str[0])) { {
if (isdigit(str[0]))
{
// This "+1" is for compatibility with the older enum format. // This "+1" is for compatibility with the older enum format.
int id = atoi(str) + 1; int id = atoi(str) + 1;
if (toFieldName(columns, id)) { if (toFieldName(columns, id))
{
return id; return id;
} }
} else { }
else
{
// Dynamically-defined columns are always stored by-name. // Dynamically-defined columns are always stored by-name.
char dynamic[32] = {0}; char dynamic[32] = {0};
if (sscanf(str, "Dynamic(%30s)", dynamic)) { if (sscanf(str, "Dynamic(%30s)", dynamic))
{
char *end; char *end;
if ((end = strrchr(dynamic, ')')) != NULL) { if ((end = strrchr(dynamic, ')')) != NULL)
{
bool success; bool success;
unsigned int key; unsigned int key;
*end = '\0'; *end = '\0';
@ -235,7 +275,8 @@ static int toFieldIndex(Hashtable* columns, const char* str) {
} }
} }
// Fallback to iterative scan of table of fields by-name. // Fallback to iterative scan of table of fields by-name.
for (int p = 1; p < LAST_PROCESSFIELD; p++) { for (int p = 1; p < LAST_PROCESSFIELD; p++)
{
const char *pName = toFieldName(columns, p); const char *pName = toFieldName(columns, p);
if (pName && strcmp(pName, str) == 0) if (pName && strcmp(pName, str) == 0)
return p; return p;
@ -244,7 +285,8 @@ static int toFieldIndex(Hashtable* columns, const char* str) {
return -1; return -1;
} }
static void ScreenSettings_readFields(ScreenSettings* ss, Hashtable* columns, const char* line) { static void ScreenSettings_readFields(ScreenSettings *ss, Hashtable *columns, const char *line)
{
char *trim = String_trim(line); char *trim = String_trim(line);
char **ids = String_split(trim, ' ', NULL); char **ids = String_split(trim, ' ', NULL);
free(trim); free(trim);
@ -252,10 +294,12 @@ static void ScreenSettings_readFields(ScreenSettings* ss, Hashtable* columns, co
/* reset default fields */ /* reset default fields */
memset(ss->fields, '\0', LAST_PROCESSFIELD * sizeof(ProcessField)); memset(ss->fields, '\0', LAST_PROCESSFIELD * sizeof(ProcessField));
for (size_t j = 0, i = 0; ids[i]; i++) { for (size_t j = 0, i = 0; ids[i]; i++)
{
if (j >= UINT_MAX / sizeof(ProcessField)) if (j >= UINT_MAX / sizeof(ProcessField))
continue; continue;
if (j >= LAST_PROCESSFIELD) { if (j >= LAST_PROCESSFIELD)
{
ss->fields = xRealloc(ss->fields, (j + 1) * sizeof(ProcessField)); ss->fields = xRealloc(ss->fields, (j + 1) * sizeof(ProcessField));
memset(&ss->fields[j], 0, sizeof(ProcessField)); memset(&ss->fields[j], 0, sizeof(ProcessField));
} }
@ -269,7 +313,8 @@ static void ScreenSettings_readFields(ScreenSettings* ss, Hashtable* columns, co
String_freeArray(ids); String_freeArray(ids);
} }
ScreenSettings* Settings_newScreen(Settings* this, const ScreenDefaults* defaults) { ScreenSettings *Settings_newScreen(Settings *this, const ScreenDefaults *defaults)
{
int sortKey = defaults->sortKey ? toFieldIndex(this->dynamicColumns, defaults->sortKey) : PID; int sortKey = defaults->sortKey ? toFieldIndex(this->dynamicColumns, defaults->sortKey) : PID;
int sortDesc = (sortKey >= 0 && sortKey < LAST_PROCESSFIELD) ? Process_fields[sortKey].defaultSortDesc : 1; int sortDesc = (sortKey >= 0 && sortKey < LAST_PROCESSFIELD) ? Process_fields[sortKey].defaultSortDesc : 1;
@ -295,23 +340,27 @@ ScreenSettings* Settings_newScreen(Settings* this, const ScreenDefaults* default
return ss; return ss;
} }
void ScreenSettings_delete(ScreenSettings* this) { void ScreenSettings_delete(ScreenSettings *this)
{
free(this->name); free(this->name);
free(this->fields); free(this->fields);
free(this); free(this);
} }
static ScreenSettings* Settings_defaultScreens(Settings* this) { static ScreenSettings *Settings_defaultScreens(Settings *this)
{
if (this->nScreens) if (this->nScreens)
return this->screens[0]; return this->screens[0];
for (unsigned int i = 0; i < Platform_numberOfDefaultScreens; i++) { for (unsigned int i = 0; i < Platform_numberOfDefaultScreens; i++)
{
const ScreenDefaults *defaults = &Platform_defaultScreens[i]; const ScreenDefaults *defaults = &Platform_defaultScreens[i];
Settings_newScreen(this, defaults); Settings_newScreen(this, defaults);
} }
return this->screens[0]; return this->screens[0];
} }
static bool Settings_read(Settings* this, const char* fileName, unsigned int initialCpuCount) { static bool Settings_read(Settings *this, const char *fileName, unsigned int initialCpuCount)
{
FILE *fd = fopen(fileName, "r"); FILE *fd = fopen(fileName, "r");
if (!fd) if (!fd)
return false; return false;
@ -319,22 +368,27 @@ static bool Settings_read(Settings* this, const char* fileName, unsigned int ini
ScreenSettings *screen = NULL; ScreenSettings *screen = NULL;
bool didReadMeters = false; bool didReadMeters = false;
bool didReadAny = false; bool didReadAny = false;
for (;;) { for (;;)
{
char *line = String_readLine(fd); char *line = String_readLine(fd);
if (!line) { if (!line)
{
break; break;
} }
didReadAny = true; didReadAny = true;
size_t nOptions; size_t nOptions;
char **option = String_split(line, '=', &nOptions); char **option = String_split(line, '=', &nOptions);
free(line); free(line);
if (nOptions < 2) { if (nOptions < 2)
{
String_freeArray(option); String_freeArray(option);
continue; continue;
} }
if (String_eq(option[0], "config_reader_min_version")) { if (String_eq(option[0], "config_reader_min_version"))
{
this->config_version = atoi(option[1]); this->config_version = atoi(option[1]);
if (this->config_version > CONFIG_READER_MIN_VERSION) { if (this->config_version > CONFIG_READER_MIN_VERSION)
{
// the version of the config file on disk is newer than what we can read // the version of the config file on disk is newer than what we can read
fprintf(stderr, "WARNING: %s specifies configuration format\n", fileName); fprintf(stderr, "WARNING: %s specifies configuration format\n", fileName);
fprintf(stderr, " version v%d, but this %s binary only supports up to version v%d.\n", this->config_version, PACKAGE, CONFIG_READER_MIN_VERSION); fprintf(stderr, " version v%d, but this %s binary only supports up to version v%d.\n", this->config_version, PACKAGE, CONFIG_READER_MIN_VERSION);
@ -343,181 +397,367 @@ static bool Settings_read(Settings* this, const char* fileName, unsigned int ini
fclose(fd); fclose(fd);
return false; return false;
} }
} else if (String_eq(option[0], "fields") && this->config_version <= 2) { }
else if (String_eq(option[0], "fields") && this->config_version <= 2)
{
// old (no screen) naming also supported for backwards compatibility // old (no screen) naming also supported for backwards compatibility
screen = Settings_defaultScreens(this); screen = Settings_defaultScreens(this);
ScreenSettings_readFields(screen, this->dynamicColumns, option[1]); ScreenSettings_readFields(screen, this->dynamicColumns, option[1]);
} else if (String_eq(option[0], "sort_key") && this->config_version <= 2) { }
else if (String_eq(option[0], "sort_key") && this->config_version <= 2)
{
// old (no screen) naming also supported for backwards compatibility // old (no screen) naming also supported for backwards compatibility
// This "+1" is for compatibility with the older enum format. // This "+1" is for compatibility with the older enum format.
screen = Settings_defaultScreens(this); screen = Settings_defaultScreens(this);
screen->sortKey = atoi(option[1]) + 1; screen->sortKey = atoi(option[1]) + 1;
} else if (String_eq(option[0], "tree_sort_key") && this->config_version <= 2) { }
else if (String_eq(option[0], "tree_sort_key") && this->config_version <= 2)
{
// old (no screen) naming also supported for backwards compatibility // old (no screen) naming also supported for backwards compatibility
// This "+1" is for compatibility with the older enum format. // This "+1" is for compatibility with the older enum format.
screen = Settings_defaultScreens(this); screen = Settings_defaultScreens(this);
screen->treeSortKey = atoi(option[1]) + 1; screen->treeSortKey = atoi(option[1]) + 1;
} else if (String_eq(option[0], "sort_direction") && this->config_version <= 2) { }
else if (String_eq(option[0], "sort_direction") && this->config_version <= 2)
{
// old (no screen) naming also supported for backwards compatibility // old (no screen) naming also supported for backwards compatibility
screen = Settings_defaultScreens(this); screen = Settings_defaultScreens(this);
screen->direction = atoi(option[1]); screen->direction = atoi(option[1]);
} else if (String_eq(option[0], "tree_sort_direction") && this->config_version <= 2) { }
else if (String_eq(option[0], "tree_sort_direction") && this->config_version <= 2)
{
// old (no screen) naming also supported for backwards compatibility // old (no screen) naming also supported for backwards compatibility
screen = Settings_defaultScreens(this); screen = Settings_defaultScreens(this);
screen->treeDirection = atoi(option[1]); screen->treeDirection = atoi(option[1]);
} else if (String_eq(option[0], "tree_view") && this->config_version <= 2) { }
else if (String_eq(option[0], "tree_view") && this->config_version <= 2)
{
// old (no screen) naming also supported for backwards compatibility // old (no screen) naming also supported for backwards compatibility
screen = Settings_defaultScreens(this); screen = Settings_defaultScreens(this);
screen->treeView = atoi(option[1]); screen->treeView = atoi(option[1]);
} else if (String_eq(option[0], "tree_view_always_by_pid") && this->config_version <= 2) { }
else if (String_eq(option[0], "tree_view_always_by_pid") && this->config_version <= 2)
{
// old (no screen) naming also supported for backwards compatibility // old (no screen) naming also supported for backwards compatibility
screen = Settings_defaultScreens(this); screen = Settings_defaultScreens(this);
screen->treeViewAlwaysByPID = atoi(option[1]); screen->treeViewAlwaysByPID = atoi(option[1]);
} else if (String_eq(option[0], "all_branches_collapsed") && this->config_version <= 2) { }
else if (String_eq(option[0], "all_branches_collapsed") && this->config_version <= 2)
{
// old (no screen) naming also supported for backwards compatibility // old (no screen) naming also supported for backwards compatibility
screen = Settings_defaultScreens(this); screen = Settings_defaultScreens(this);
screen->allBranchesCollapsed = atoi(option[1]); screen->allBranchesCollapsed = atoi(option[1]);
} else if (String_eq(option[0], "hide_kernel_threads")) { }
else if (String_eq(option[0], "hide_kernel_threads"))
{
this->hideKernelThreads = atoi(option[1]); this->hideKernelThreads = atoi(option[1]);
} else if (String_eq(option[0], "hide_userland_threads")) { }
else if (String_eq(option[0], "hide_userland_threads"))
{
this->hideUserlandThreads = atoi(option[1]); this->hideUserlandThreads = atoi(option[1]);
} else if (String_eq(option[0], "shadow_other_users")) { }
else if (String_eq(option[0], "shadow_other_users"))
{
this->shadowOtherUsers = atoi(option[1]); this->shadowOtherUsers = atoi(option[1]);
} else if (String_eq(option[0], "show_thread_names")) { }
else if (String_eq(option[0], "show_thread_names"))
{
this->showThreadNames = atoi(option[1]); this->showThreadNames = atoi(option[1]);
} else if (String_eq(option[0], "show_program_path")) { }
else if (String_eq(option[0], "show_program_path"))
{
this->showProgramPath = atoi(option[1]); this->showProgramPath = atoi(option[1]);
} else if (String_eq(option[0], "highlight_base_name")) { }
else if (String_eq(option[0], "highlight_base_name"))
{
this->highlightBaseName = atoi(option[1]); this->highlightBaseName = atoi(option[1]);
} else if (String_eq(option[0], "highlight_deleted_exe")) { }
else if (String_eq(option[0], "highlight_deleted_exe"))
{
this->highlightDeletedExe = atoi(option[1]); this->highlightDeletedExe = atoi(option[1]);
} else if (String_eq(option[0], "highlight_megabytes")) { }
else if (String_eq(option[0], "highlight_megabytes"))
{
this->highlightMegabytes = atoi(option[1]); this->highlightMegabytes = atoi(option[1]);
} else if (String_eq(option[0], "highlight_threads")) { }
else if (String_eq(option[0], "highlight_threads"))
{
this->highlightThreads = atoi(option[1]); this->highlightThreads = atoi(option[1]);
} else if (String_eq(option[0], "highlight_changes")) { }
else if (String_eq(option[0], "highlight_changes"))
{
this->highlightChanges = atoi(option[1]); this->highlightChanges = atoi(option[1]);
} else if (String_eq(option[0], "highlight_changes_delay_secs")) { }
else if (String_eq(option[0], "highlight_changes_delay_secs"))
{
this->highlightDelaySecs = CLAMP(atoi(option[1]), 1, 24 * 60 * 60); this->highlightDelaySecs = CLAMP(atoi(option[1]), 1, 24 * 60 * 60);
} else if (String_eq(option[0], "find_comm_in_cmdline")) { }
else if (String_eq(option[0], "find_comm_in_cmdline"))
{
this->findCommInCmdline = atoi(option[1]); this->findCommInCmdline = atoi(option[1]);
} else if (String_eq(option[0], "strip_exe_from_cmdline")) { }
else if (String_eq(option[0], "strip_exe_from_cmdline"))
{
this->stripExeFromCmdline = atoi(option[1]); this->stripExeFromCmdline = atoi(option[1]);
} else if (String_eq(option[0], "show_merged_command")) { }
else if (String_eq(option[0], "show_merged_command"))
{
this->showMergedCommand = atoi(option[1]); this->showMergedCommand = atoi(option[1]);
} else if (String_eq(option[0], "header_margin")) { }
else if (String_eq(option[0], "header_margin"))
{
this->headerMargin = atoi(option[1]); this->headerMargin = atoi(option[1]);
} else if (String_eq(option[0], "screen_tabs")) { }
else if (String_eq(option[0], "screen_tabs"))
{
this->screenTabs = atoi(option[1]); this->screenTabs = atoi(option[1]);
} else if (String_eq(option[0], "expand_system_time")) { }
else if (String_eq(option[0], "expand_system_time"))
{
// Compatibility option. // Compatibility option.
this->detailedCPUTime = atoi(option[1]); this->detailedCPUTime = atoi(option[1]);
} else if (String_eq(option[0], "detailed_cpu_time")) { }
else if (String_eq(option[0], "detailed_cpu_time"))
{
this->detailedCPUTime = atoi(option[1]); this->detailedCPUTime = atoi(option[1]);
} else if (String_eq(option[0], "cpu_count_from_one")) { }
else if (String_eq(option[0], "cpu_count_from_one"))
{
this->countCPUsFromOne = atoi(option[1]); this->countCPUsFromOne = atoi(option[1]);
} else if (String_eq(option[0], "cpu_count_from_zero")) { }
else if (String_eq(option[0], "cpu_count_from_zero"))
{
// old (inverted) naming also supported for backwards compatibility // old (inverted) naming also supported for backwards compatibility
this->countCPUsFromOne = !atoi(option[1]); this->countCPUsFromOne = !atoi(option[1]);
} else if (String_eq(option[0], "show_cpu_usage")) { }
else if (String_eq(option[0], "show_cpu_usage"))
{
this->showCPUUsage = atoi(option[1]); this->showCPUUsage = atoi(option[1]);
} else if (String_eq(option[0], "show_cpu_frequency")) { }
else if (String_eq(option[0], "show_cpu_frequency"))
{
this->showCPUFrequency = atoi(option[1]); this->showCPUFrequency = atoi(option[1]);
#ifdef BUILD_WITH_CPU_TEMP #ifdef BUILD_WITH_CPU_TEMP
} else if (String_eq(option[0], "show_cpu_temperature")) { }
else if (String_eq(option[0], "show_cpu_temperature"))
{
this->showCPUTemperature = atoi(option[1]); this->showCPUTemperature = atoi(option[1]);
} else if (String_eq(option[0], "degree_fahrenheit")) { }
else if (String_eq(option[0], "degree_fahrenheit"))
{
this->degreeFahrenheit = atoi(option[1]); this->degreeFahrenheit = atoi(option[1]);
#endif #endif
} else if (String_eq(option[0], "update_process_names")) { }
else if (String_eq(option[0], "update_process_names"))
{
this->updateProcessNames = atoi(option[1]); this->updateProcessNames = atoi(option[1]);
} else if (String_eq(option[0], "account_guest_in_cpu_meter")) { }
else if (String_eq(option[0], "account_guest_in_cpu_meter"))
{
this->accountGuestInCPUMeter = atoi(option[1]); this->accountGuestInCPUMeter = atoi(option[1]);
} else if (String_eq(option[0], "delay")) { }
else if (String_eq(option[0], "delay"))
{
this->delay = CLAMP(atoi(option[1]), 1, 255); this->delay = CLAMP(atoi(option[1]), 1, 255);
} else if (String_eq(option[0], "color_scheme")) { }
else if (String_eq(option[0], "color_scheme"))
{
this->colorScheme = atoi(option[1]); this->colorScheme = atoi(option[1]);
if (this->colorScheme < 0 || this->colorScheme >= LAST_COLORSCHEME) { if (this->colorScheme < 0 || this->colorScheme >= LAST_COLORSCHEME)
{
this->colorScheme = 0; this->colorScheme = 0;
} }
#ifdef HAVE_GETMOUSE #ifdef HAVE_GETMOUSE
} else if (String_eq(option[0], "enable_mouse")) { }
else if (String_eq(option[0], "enable_mouse"))
{
this->enableMouse = atoi(option[1]); this->enableMouse = atoi(option[1]);
#endif #endif
} else if (String_eq(option[0], "header_layout")) { }
else if (String_eq(option[0], "header_layout"))
{
this->hLayout = isdigit((unsigned char)option[1][0]) ? ((HeaderLayout)atoi(option[1])) : HeaderLayout_fromName(option[1]); this->hLayout = isdigit((unsigned char)option[1][0]) ? ((HeaderLayout)atoi(option[1])) : HeaderLayout_fromName(option[1]);
if (this->hLayout < 0 || this->hLayout >= LAST_HEADER_LAYOUT) if (this->hLayout < 0 || this->hLayout >= LAST_HEADER_LAYOUT)
this->hLayout = HF_TWO_50_50; this->hLayout = HF_TWO_50_50;
free(this->hColumns); free(this->hColumns);
this->hColumns = xCalloc(HeaderLayout_getColumns(this->hLayout), sizeof(MeterColumnSetting)); this->hColumns = xCalloc(HeaderLayout_getColumns(this->hLayout), sizeof(MeterColumnSetting));
} else if (String_eq(option[0], "left_meters")) { }
else if (String_eq(option[0], "left_meters"))
{
Settings_readMeters(this, option[1], 0); Settings_readMeters(this, option[1], 0);
didReadMeters = true; didReadMeters = true;
} else if (String_eq(option[0], "right_meters")) { }
else if (String_eq(option[0], "right_meters"))
{
Settings_readMeters(this, option[1], 1); Settings_readMeters(this, option[1], 1);
didReadMeters = true; didReadMeters = true;
} else if (String_eq(option[0], "left_meter_modes")) { }
else if (String_eq(option[0], "left_meter_modes"))
{
Settings_readMeterModes(this, option[1], 0); Settings_readMeterModes(this, option[1], 0);
didReadMeters = true; didReadMeters = true;
} else if (String_eq(option[0], "right_meter_modes")) { }
else if (String_eq(option[0], "right_meter_modes"))
{
Settings_readMeterModes(this, option[1], 1); Settings_readMeterModes(this, option[1], 1);
didReadMeters = true; didReadMeters = true;
} else if (String_startsWith(option[0], "column_meters_")) { }
else if (String_startsWith(option[0], "column_meters_"))
{
Settings_readMeters(this, option[1], atoi(option[0] + strlen("column_meters_"))); Settings_readMeters(this, option[1], atoi(option[0] + strlen("column_meters_")));
didReadMeters = true; didReadMeters = true;
} else if (String_startsWith(option[0], "column_meter_modes_")) { }
else if (String_startsWith(option[0], "column_meter_modes_"))
{
Settings_readMeterModes(this, option[1], atoi(option[0] + strlen("column_meter_modes_"))); Settings_readMeterModes(this, option[1], atoi(option[0] + strlen("column_meter_modes_")));
didReadMeters = true; didReadMeters = true;
} else if (String_eq(option[0], "hide_function_bar")) { }
else if (String_eq(option[0], "hide_function_bar"))
{
this->hideFunctionBar = atoi(option[1]); this->hideFunctionBar = atoi(option[1]);
#ifdef HAVE_LIBHWLOC #ifdef HAVE_LIBHWLOC
} else if (String_eq(option[0], "topology_affinity")) { }
else if (String_eq(option[0], "topology_affinity"))
{
this->topologyAffinity = !!atoi(option[1]); this->topologyAffinity = !!atoi(option[1]);
#endif #endif
} else if (strncmp(option[0], "screen:", 7) == 0) { }
else if (strncmp(option[0], "screen:", 7) == 0)
{
screen = Settings_newScreen(this, &(const ScreenDefaults){.name = option[0] + 7, .columns = option[1]}); screen = Settings_newScreen(this, &(const ScreenDefaults){.name = option[0] + 7, .columns = option[1]});
} else if (String_eq(option[0], ".sort_key")) { }
else if (String_eq(option[0], ".sort_key"))
{
if (screen) if (screen)
screen->sortKey = toFieldIndex(this->dynamicColumns, option[1]); screen->sortKey = toFieldIndex(this->dynamicColumns, option[1]);
} else if (String_eq(option[0], ".tree_sort_key")) { }
else if (String_eq(option[0], ".tree_sort_key"))
{
if (screen) if (screen)
screen->treeSortKey = toFieldIndex(this->dynamicColumns, option[1]); screen->treeSortKey = toFieldIndex(this->dynamicColumns, option[1]);
} else if (String_eq(option[0], ".sort_direction")) { }
else if (String_eq(option[0], ".sort_direction"))
{
if (screen) if (screen)
screen->direction = atoi(option[1]); screen->direction = atoi(option[1]);
} else if (String_eq(option[0], ".tree_sort_direction")) { }
else if (String_eq(option[0], ".tree_sort_direction"))
{
if (screen) if (screen)
screen->treeDirection = atoi(option[1]); screen->treeDirection = atoi(option[1]);
} else if (String_eq(option[0], ".tree_view")) { }
else if (String_eq(option[0], ".tree_view"))
{
if (screen) if (screen)
screen->treeView = atoi(option[1]); screen->treeView = atoi(option[1]);
} else if (String_eq(option[0], ".tree_view_always_by_pid")) { }
else if (String_eq(option[0], ".tree_view_always_by_pid"))
{
if (screen) if (screen)
screen->treeViewAlwaysByPID = atoi(option[1]); screen->treeViewAlwaysByPID = atoi(option[1]);
} else if (String_eq(option[0], ".all_branches_collapsed")) { }
else if (String_eq(option[0], ".all_branches_collapsed"))
{
if (screen) if (screen)
screen->allBranchesCollapsed = atoi(option[1]); screen->allBranchesCollapsed = atoi(option[1]);
} }
String_freeArray(option); String_freeArray(option);
} }
fclose(fd); fclose(fd);
if (!didReadMeters || !Settings_validateMeters(this))
if (didReadMeters)
{
if (didReadMeters)
{
#if defined FORCE_TEMP_METER || defined FORCE_FREQ_METER
int ftidx = this->hColumns[1].len;
size_t realloc_len = ftidx;
#ifdef FORCE_TEMP_METER
uint8_t t_det = 0;
#endif
#ifdef FORCE_FREQ_METER
uint8_t f_det = 0;
#endif
char **cnames = this->hColumns[1].names;
for (int i = 0; i < ftidx; ++i)
{
#ifdef FORCE_TEMP_METER
if (strcmp("Temp", cnames[i]) == 0)
{
t_det = 1;
break;
}
#endif
#ifdef FORCE_FREQ_METER
if (strcmp("Freq", cnames[i]) == 0)
{
f_det = 1;
break;
}
#endif
}
#ifdef FORCE_TEMP_METER
if (!t_det)
{
++realloc_len;
}
#endif
#ifdef FORCE_FREQ_METER
if (!f_det)
{
++realloc_len;
}
#endif
this->hColumns[1].names = xReallocArray(this->hColumns[1].names, realloc_len + 1, sizeof(char *));
this->hColumns[1].modes = xReallocArray(this->hColumns[1].modes, realloc_len, sizeof(int));
#ifdef FORCE_TEMP_METER
if (!t_det)
{
this->hColumns[1].names[ftidx] = xStrdup("Temp");
this->hColumns[1].modes[ftidx++] = TEXT_METERMODE;
}
#endif
#ifdef FORCE_FREQ_METER
if (!f_det)
{
this->hColumns[1].names[ftidx] = xStrdup("Freq");
this->hColumns[1].modes[ftidx++] = TEXT_METERMODE;
}
#endif
this->hColumns[1].len = ftidx;
#endif
}
else
{
Settings_defaultMeters(this, initialCpuCount); Settings_defaultMeters(this, initialCpuCount);
if (!this->nScreens)
Settings_defaultScreens(this);
return didReadAny;
} }
static void writeFields(FILE* fd, const ProcessField* fields, Hashtable* columns, bool byName, char separator) { if (!this->nScreens)
Settings_defaultScreens(this);
return didReadAny;
}
}
static void writeFields(FILE *fd, const ProcessField *fields, Hashtable *columns, bool byName, char separator)
{
const char *sep = ""; const char *sep = "";
for (unsigned int i = 0; fields[i]; i++) { for (unsigned int i = 0; fields[i]; i++)
if (fields[i] < LAST_PROCESSFIELD && byName) { {
if (fields[i] < LAST_PROCESSFIELD && byName)
{
const char *pName = toFieldName(columns, fields[i]); const char *pName = toFieldName(columns, fields[i]);
fprintf(fd, "%s%s", sep, pName); fprintf(fd, "%s%s", sep, pName);
} else if (fields[i] >= LAST_PROCESSFIELD && byName) { }
else if (fields[i] >= LAST_PROCESSFIELD && byName)
{
const char *pName = toFieldName(columns, fields[i]); const char *pName = toFieldName(columns, fields[i]);
fprintf(fd, " Dynamic(%s)", pName); fprintf(fd, " Dynamic(%s)", pName);
} else { }
else
{
// This "-1" is for compatibility with the older enum format. // This "-1" is for compatibility with the older enum format.
fprintf(fd, "%s%d", sep, (int)fields[i] - 1); fprintf(fd, "%s%d", sep, (int)fields[i] - 1);
} }
@ -526,35 +766,44 @@ static void writeFields(FILE* fd, const ProcessField* fields, Hashtable* columns
fputc(separator, fd); fputc(separator, fd);
} }
static void writeList(FILE* fd, char** list, int len, char separator) { static void writeList(FILE *fd, char **list, int len, char separator)
{
const char *sep = ""; const char *sep = "";
for (int i = 0; i < len; i++) { for (int i = 0; i < len; i++)
{
fprintf(fd, "%s%s", sep, list[i]); fprintf(fd, "%s%s", sep, list[i]);
sep = " "; sep = " ";
} }
fputc(separator, fd); fputc(separator, fd);
} }
static void writeMeters(const Settings* this, FILE* fd, char separator, unsigned int column) { static void writeMeters(const Settings *this, FILE *fd, char separator, unsigned int column)
{
writeList(fd, this->hColumns[column].names, this->hColumns[column].len, separator); writeList(fd, this->hColumns[column].names, this->hColumns[column].len, separator);
} }
static void writeMeterModes(const Settings* this, FILE* fd, char separator, unsigned int column) { static void writeMeterModes(const Settings *this, FILE *fd, char separator, unsigned int column)
{
const char *sep = ""; const char *sep = "";
for (size_t i = 0; i < this->hColumns[column].len; i++) { for (size_t i = 0; i < this->hColumns[column].len; i++)
{
fprintf(fd, "%s%d", sep, this->hColumns[column].modes[i]); fprintf(fd, "%s%d", sep, this->hColumns[column].modes[i]);
sep = " "; sep = " ";
} }
fputc(separator, fd); fputc(separator, fd);
} }
int Settings_write(const Settings* this, bool onCrash) { int Settings_write(const Settings *this, bool onCrash)
{
FILE *fd; FILE *fd;
char separator; char separator;
if (onCrash) { if (onCrash)
{
fd = stderr; fd = stderr;
separator = ';'; separator = ';';
} else { }
else
{
fd = fopen(this->filename, "w"); fd = fopen(this->filename, "w");
if (fd == NULL) if (fd == NULL)
return -errno; return -errno;
@ -566,13 +815,15 @@ int Settings_write(const Settings* this, bool onCrash) {
#define printSettingString(setting_, value_) \ #define printSettingString(setting_, value_) \
fprintf(fd, setting_ "=%s%c", value_, separator) fprintf(fd, setting_ "=%s%c", value_, separator)
if (!onCrash) { if (!onCrash)
{
fprintf(fd, "# Beware! This file is rewritten by htop when settings are changed in the interface.\n"); fprintf(fd, "# Beware! This file is rewritten by htop when settings are changed in the interface.\n");
fprintf(fd, "# The parser is also very primitive, and not human-friendly.\n"); fprintf(fd, "# The parser is also very primitive, and not human-friendly.\n");
} }
printSettingString("htop_version", VERSION); printSettingString("htop_version", VERSION);
printSettingInteger("config_reader_min_version", CONFIG_READER_MIN_VERSION); printSettingInteger("config_reader_min_version", CONFIG_READER_MIN_VERSION);
fprintf(fd, "fields="); writeFields(fd, this->screens[0]->fields, this->dynamicColumns, false, separator); fprintf(fd, "fields=");
writeFields(fd, this->screens[0]->fields, this->dynamicColumns, false, separator);
printSettingInteger("hide_kernel_threads", this->hideKernelThreads); printSettingInteger("hide_kernel_threads", this->hideKernelThreads);
printSettingInteger("hide_userland_threads", this->hideUserlandThreads); printSettingInteger("hide_userland_threads", this->hideUserlandThreads);
printSettingInteger("shadow_other_users", this->shadowOtherUsers); printSettingInteger("shadow_other_users", this->shadowOtherUsers);
@ -610,7 +861,8 @@ int Settings_write(const Settings* this, bool onCrash) {
#endif #endif
printSettingString("header_layout", HeaderLayout_getName(this->hLayout)); printSettingString("header_layout", HeaderLayout_getName(this->hLayout));
for (unsigned int i = 0; i < HeaderLayout_getColumns(this->hLayout); i++) { for (unsigned int i = 0; i < HeaderLayout_getColumns(this->hLayout); i++)
{
fprintf(fd, "column_meters_%u=", i); fprintf(fd, "column_meters_%u=", i);
writeMeters(this, fd, separator, i); writeMeters(this, fd, separator, i);
fprintf(fd, "column_meter_modes_%u=", i); fprintf(fd, "column_meter_modes_%u=", i);
@ -627,7 +879,8 @@ int Settings_write(const Settings* this, bool onCrash) {
printSettingInteger("tree_view_always_by_pid", this->screens[0]->treeViewAlwaysByPID); printSettingInteger("tree_view_always_by_pid", this->screens[0]->treeViewAlwaysByPID);
printSettingInteger("all_branches_collapsed", this->screens[0]->allBranchesCollapsed); printSettingInteger("all_branches_collapsed", this->screens[0]->allBranchesCollapsed);
for (unsigned int i = 0; i < this->nScreens; i++) { for (unsigned int i = 0; i < this->nScreens; i++)
{
ScreenSettings *ss = this->screens[i]; ScreenSettings *ss = this->screens[i];
fprintf(fd, "screen:%s=", ss->name); fprintf(fd, "screen:%s=", ss->name);
writeFields(fd, ss->fields, this->dynamicColumns, true, separator); writeFields(fd, ss->fields, this->dynamicColumns, true, separator);
@ -657,7 +910,8 @@ int Settings_write(const Settings* this, bool onCrash) {
return r; return r;
} }
Settings* Settings_new(unsigned int initialCpuCount, Hashtable* dynamicColumns) { Settings *Settings_new(unsigned int initialCpuCount, Hashtable *dynamicColumns)
{
Settings *this = xCalloc(1, sizeof(Settings)); Settings *this = xCalloc(1, sizeof(Settings));
this->dynamicColumns = dynamicColumns; this->dynamicColumns = dynamicColumns;
@ -698,9 +952,12 @@ Settings* Settings_new(unsigned int initialCpuCount, Hashtable* dynamicColumns)
char *legacyDotfile = NULL; char *legacyDotfile = NULL;
const char *rcfile = getenv("HTOPRC"); const char *rcfile = getenv("HTOPRC");
if (rcfile) { if (rcfile)
{
this->filename = xStrdup(rcfile); this->filename = xStrdup(rcfile);
} else { }
else
{
const char *home = getenv("HOME"); const char *home = getenv("HOME");
if (!home) if (!home)
home = ""; home = "";
@ -708,11 +965,14 @@ Settings* Settings_new(unsigned int initialCpuCount, Hashtable* dynamicColumns)
const char *xdgConfigHome = getenv("XDG_CONFIG_HOME"); const char *xdgConfigHome = getenv("XDG_CONFIG_HOME");
char *configDir = NULL; char *configDir = NULL;
char *htopDir = NULL; char *htopDir = NULL;
if (xdgConfigHome) { if (xdgConfigHome)
{
this->filename = String_cat(xdgConfigHome, "/htop/htoprc"); this->filename = String_cat(xdgConfigHome, "/htop/htoprc");
configDir = xStrdup(xdgConfigHome); configDir = xStrdup(xdgConfigHome);
htopDir = String_cat(xdgConfigHome, "/htop"); htopDir = String_cat(xdgConfigHome, "/htop");
} else { }
else
{
this->filename = String_cat(home, "/.config/htop/htoprc"); this->filename = String_cat(home, "/.config/htop/htoprc");
configDir = String_cat(home, "/.config"); configDir = String_cat(home, "/.config");
htopDir = String_cat(home, "/.config/htop"); htopDir = String_cat(home, "/.config/htop");
@ -724,7 +984,8 @@ Settings* Settings_new(unsigned int initialCpuCount, Hashtable* dynamicColumns)
free(configDir); free(configDir);
struct stat st; struct stat st;
int err = lstat(legacyDotfile, &st); int err = lstat(legacyDotfile, &st);
if (err || S_ISLNK(st.st_mode)) { if (err || S_ISLNK(st.st_mode))
{
free(legacyDotfile); free(legacyDotfile);
legacyDotfile = NULL; legacyDotfile = NULL;
} }
@ -736,25 +997,31 @@ Settings* Settings_new(unsigned int initialCpuCount, Hashtable* dynamicColumns)
this->changed = false; this->changed = false;
this->delay = DEFAULT_DELAY; this->delay = DEFAULT_DELAY;
bool ok = false; bool ok = false;
if (legacyDotfile) { if (legacyDotfile)
{
ok = Settings_read(this, legacyDotfile, initialCpuCount); ok = Settings_read(this, legacyDotfile, initialCpuCount);
if (ok) { if (ok)
{
// Transition to new location and delete old configuration file // Transition to new location and delete old configuration file
if (Settings_write(this, false) == 0) { if (Settings_write(this, false) == 0)
{
unlink(legacyDotfile); unlink(legacyDotfile);
} }
} }
free(legacyDotfile); free(legacyDotfile);
} }
if (!ok) { if (!ok)
{
ok = Settings_read(this, this->filename, initialCpuCount); ok = Settings_read(this, this->filename, initialCpuCount);
} }
if (!ok) { if (!ok)
{
this->screenTabs = true; this->screenTabs = true;
this->changed = true; this->changed = true;
ok = Settings_read(this, SYSCONFDIR "/htoprc", initialCpuCount); ok = Settings_read(this, SYSCONFDIR "/htoprc", initialCpuCount);
} }
if (!ok) { if (!ok)
{
Settings_defaultMeters(this, initialCpuCount); Settings_defaultMeters(this, initialCpuCount);
Settings_defaultScreens(this); Settings_defaultScreens(this);
} }
@ -767,17 +1034,22 @@ Settings* Settings_new(unsigned int initialCpuCount, Hashtable* dynamicColumns)
return this; return this;
} }
void ScreenSettings_invertSortOrder(ScreenSettings* this) { void ScreenSettings_invertSortOrder(ScreenSettings *this)
{
int *attr = (this->treeView) ? &(this->treeDirection) : &(this->direction); int *attr = (this->treeView) ? &(this->treeDirection) : &(this->direction);
*attr = (*attr == 1) ? -1 : 1; *attr = (*attr == 1) ? -1 : 1;
} }
void ScreenSettings_setSortKey(ScreenSettings* this, ProcessField sortKey) { void ScreenSettings_setSortKey(ScreenSettings *this, ProcessField sortKey)
if (this->treeViewAlwaysByPID || !this->treeView) { {
if (this->treeViewAlwaysByPID || !this->treeView)
{
this->sortKey = sortKey; this->sortKey = sortKey;
this->direction = (Process_fields[sortKey].defaultSortDesc) ? -1 : 1; this->direction = (Process_fields[sortKey].defaultSortDesc) ? -1 : 1;
this->treeView = false; this->treeView = false;
} else { }
else
{
this->treeSortKey = sortKey; this->treeSortKey = sortKey;
this->treeDirection = (Process_fields[sortKey].defaultSortDesc) ? -1 : 1; this->treeDirection = (Process_fields[sortKey].defaultSortDesc) ? -1 : 1;
} }
@ -785,24 +1057,32 @@ void ScreenSettings_setSortKey(ScreenSettings* this, ProcessField sortKey) {
static bool readonly = false; static bool readonly = false;
void Settings_enableReadonly(void) { void Settings_enableReadonly(void)
{
readonly = true; readonly = true;
} }
bool Settings_isReadonly(void) { bool Settings_isReadonly(void)
{
return readonly; return readonly;
} }
void Settings_setHeaderLayout(Settings* this, HeaderLayout hLayout) { void Settings_setHeaderLayout(Settings *this, HeaderLayout hLayout)
{
unsigned int oldColumns = HeaderLayout_getColumns(this->hLayout); unsigned int oldColumns = HeaderLayout_getColumns(this->hLayout);
unsigned int newColumns = HeaderLayout_getColumns(hLayout); unsigned int newColumns = HeaderLayout_getColumns(hLayout);
if (newColumns > oldColumns) { if (newColumns > oldColumns)
{
this->hColumns = xReallocArray(this->hColumns, newColumns, sizeof(MeterColumnSetting)); this->hColumns = xReallocArray(this->hColumns, newColumns, sizeof(MeterColumnSetting));
memset(this->hColumns + oldColumns, 0, (newColumns - oldColumns) * sizeof(MeterColumnSetting)); memset(this->hColumns + oldColumns, 0, (newColumns - oldColumns) * sizeof(MeterColumnSetting));
} else if (newColumns < oldColumns) { }
for (unsigned int i = newColumns; i < oldColumns; i++) { else if (newColumns < oldColumns)
if (this->hColumns[i].names) { {
for (unsigned int i = newColumns; i < oldColumns; i++)
{
if (this->hColumns[i].names)
{
for (size_t j = 0; j < this->hColumns[i].len; j++) for (size_t j = 0; j < this->hColumns[i].len; j++)
free(this->hColumns[i].names[j]); free(this->hColumns[i].names[j]);
free(this->hColumns[i].names); free(this->hColumns[i].names);

29
TempMeter.c Normal file
View File

@ -0,0 +1,29 @@
#include "TempMeter.h"
#include "CRT.h"
#include "Object.h"
#include "Platform.h"
#include "XUtils.h"
static const int TempMeter_attributes[] = {
TEMP};
static void TempMeter_updateValues(Meter *this)
{
float temp_c = Platform_getTemp();
xSnprintf(this->txtBuffer, sizeof(this->txtBuffer), "%.1lf °C", temp_c);
}
const MeterClass TempMeter_class = {
.super = {
.extends = Class(Meter),
.delete = Meter_delete},
.updateValues = TempMeter_updateValues,
.defaultMode = TEXT_METERMODE,
.maxItems = 1,
.total = 100.0,
.attributes = TempMeter_attributes,
.name = "Temp",
.uiName = "Temp",
.caption = "CPU/Temperature: "};

8
TempMeter.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef HEADER_TempMeter
#define HEADER_TempMeter
#include "Meter.h"
extern const MeterClass TempMeter_class;
#endif

View File

@ -17,7 +17,6 @@ in the source distribution for its full text.
#include "Compat.h" #include "Compat.h"
#include "Macros.h" #include "Macros.h"
void fail(void) ATTR_NORETURN; void fail(void) ATTR_NORETURN;
void *xMalloc(size_t size) ATTR_ALLOC_SIZE1(1) ATTR_MALLOC; void *xMalloc(size_t size) ATTR_ALLOC_SIZE1(1) ATTR_MALLOC;
@ -36,13 +35,15 @@ void* xReallocArrayZero(void* ptr, size_t prevmemb, size_t newmemb, size_t size)
* String_startsWith gives better performance if strlen(match) can be computed * String_startsWith gives better performance if strlen(match) can be computed
* at compile time (e.g. when they are immutable string literals). :) * at compile time (e.g. when they are immutable string literals). :)
*/ */
static inline bool String_startsWith(const char* s, const char* match) { static inline bool String_startsWith(const char *s, const char *match)
{
return strncmp(s, match, strlen(match)) == 0; return strncmp(s, match, strlen(match)) == 0;
} }
bool String_contains_i(const char *s1, const char *s2, bool multi); bool String_contains_i(const char *s1, const char *s2, bool multi);
static inline bool String_eq(const char* s1, const char* s2) { static inline bool String_eq(const char *s1, const char *s2)
{
return strcmp(s1, s2) == 0; return strcmp(s1, s2) == 0;
} }

View File

@ -49,6 +49,8 @@ in the source distribution for its full text.
#include "SysArchMeter.h" #include "SysArchMeter.h"
#include "TasksMeter.h" #include "TasksMeter.h"
#include "UptimeMeter.h" #include "UptimeMeter.h"
#include "FreqMeter.h"
#include "TempMeter.h"
#include "XUtils.h" #include "XUtils.h"
#include "linux/IOPriority.h" #include "linux/IOPriority.h"
#include "linux/IOPriorityPanel.h" #include "linux/IOPriorityPanel.h"
@ -74,9 +76,9 @@ in the source distribution for its full text.
#define O_PATH 010000000 // declare for ancient glibc versions #define O_PATH 010000000 // declare for ancient glibc versions
#endif #endif
#ifdef HAVE_LIBCAP #ifdef HAVE_LIBCAP
enum CapMode { enum CapMode
{
CAP_MODE_OFF, CAP_MODE_OFF,
CAP_MODE_BASIC, CAP_MODE_BASIC,
CAP_MODE_STRICT CAP_MODE_STRICT
@ -139,7 +141,9 @@ const SignalItem Platform_signals[] = {
const unsigned int Platform_numberOfSignals = ARRAYSIZE(Platform_signals); const unsigned int Platform_numberOfSignals = ARRAYSIZE(Platform_signals);
static enum { BAT_PROC, BAT_SYS, BAT_ERR } Platform_Battery_method = BAT_PROC; static enum { BAT_PROC,
BAT_SYS,
BAT_ERR } Platform_Battery_method = BAT_PROC;
static time_t Platform_Battery_cacheTime; static time_t Platform_Battery_cacheTime;
static double Platform_Battery_cachePercent = NAN; static double Platform_Battery_cachePercent = NAN;
static ACPresence Platform_Battery_cacheIsOnAC; static ACPresence Platform_Battery_cacheIsOnAC;
@ -148,7 +152,8 @@ static ACPresence Platform_Battery_cacheIsOnAC;
static enum CapMode Platform_capabilitiesMode = CAP_MODE_BASIC; static enum CapMode Platform_capabilitiesMode = CAP_MODE_BASIC;
#endif #endif
static Htop_Reaction Platform_actionSetIOPriority(State* st) { static Htop_Reaction Platform_actionSetIOPriority(State *st)
{
if (Settings_isReadonly()) if (Settings_isReadonly())
return HTOP_OK; return HTOP_OK;
@ -159,10 +164,12 @@ static Htop_Reaction Platform_actionSetIOPriority(State* st) {
IOPriority ioprio1 = p->ioPriority; IOPriority ioprio1 = p->ioPriority;
Panel *ioprioPanel = IOPriorityPanel_new(ioprio1); Panel *ioprioPanel = IOPriorityPanel_new(ioprio1);
const void *set = Action_pickFromVector(st, ioprioPanel, 20, true); const void *set = Action_pickFromVector(st, ioprioPanel, 20, true);
if (set) { if (set)
{
IOPriority ioprio2 = IOPriorityPanel_getIOPriority(ioprioPanel); IOPriority ioprio2 = IOPriorityPanel_getIOPriority(ioprioPanel);
bool ok = MainPanel_foreachProcess(st->mainPanel, LinuxProcess_setIOPriority, (Arg){.i = ioprio2}, NULL); bool ok = MainPanel_foreachProcess(st->mainPanel, LinuxProcess_setIOPriority, (Arg){.i = ioprio2}, NULL);
if (!ok) { if (!ok)
{
beep(); beep();
} }
} }
@ -170,8 +177,10 @@ static Htop_Reaction Platform_actionSetIOPriority(State* st) {
return HTOP_REFRESH | HTOP_REDRAW_BAR | HTOP_UPDATE_PANELHDR; return HTOP_REFRESH | HTOP_REDRAW_BAR | HTOP_UPDATE_PANELHDR;
} }
static bool Platform_changeAutogroupPriority(MainPanel* panel, int delta) { static bool Platform_changeAutogroupPriority(MainPanel *panel, int delta)
if (LinuxProcess_isAutogroupEnabled() == false) { {
if (LinuxProcess_isAutogroupEnabled() == false)
{
beep(); beep();
return false; return false;
} }
@ -182,7 +191,8 @@ static bool Platform_changeAutogroupPriority(MainPanel* panel, int delta) {
return anyTagged; return anyTagged;
} }
static Htop_Reaction Platform_actionHigherAutogroupPriority(State* st) { static Htop_Reaction Platform_actionHigherAutogroupPriority(State *st)
{
if (Settings_isReadonly()) if (Settings_isReadonly())
return HTOP_OK; return HTOP_OK;
@ -190,7 +200,8 @@ static Htop_Reaction Platform_actionHigherAutogroupPriority(State* st) {
return changed ? HTOP_REFRESH : HTOP_OK; return changed ? HTOP_REFRESH : HTOP_OK;
} }
static Htop_Reaction Platform_actionLowerAutogroupPriority(State* st) { static Htop_Reaction Platform_actionLowerAutogroupPriority(State *st)
{
if (Settings_isReadonly()) if (Settings_isReadonly())
return HTOP_OK; return HTOP_OK;
@ -198,7 +209,8 @@ static Htop_Reaction Platform_actionLowerAutogroupPriority(State* st) {
return changed ? HTOP_REFRESH : HTOP_OK; return changed ? HTOP_REFRESH : HTOP_OK;
} }
void Platform_setBindings(Htop_Action* keys) { void Platform_setBindings(Htop_Action *keys)
{
keys['i'] = Platform_actionSetIOPriority; keys['i'] = Platform_actionSetIOPriority;
keys['{'] = Platform_actionLowerAutogroupPriority; keys['{'] = Platform_actionLowerAutogroupPriority;
keys['}'] = Platform_actionHigherAutogroupPriority; keys['}'] = Platform_actionHigherAutogroupPriority;
@ -220,6 +232,8 @@ const MeterClass* const Platform_meterTypes[] = {
&HugePageMeter_class, &HugePageMeter_class,
&TasksMeter_class, &TasksMeter_class,
&UptimeMeter_class, &UptimeMeter_class,
&FreqMeter_class,
&TempMeter_class,
&BatteryMeter_class, &BatteryMeter_class,
&HostnameMeter_class, &HostnameMeter_class,
&AllCPUsMeter_class, &AllCPUsMeter_class,
@ -247,23 +261,78 @@ const MeterClass* const Platform_meterTypes[] = {
&NetworkIOMeter_class, &NetworkIOMeter_class,
&SELinuxMeter_class, &SELinuxMeter_class,
&SystemdMeter_class, &SystemdMeter_class,
NULL NULL};
};
int Platform_getUptime() { int Platform_getUptime()
{
double uptime = 0; double uptime = 0;
FILE *fd = fopen(PROCDIR "/uptime", "r"); FILE *fd = fopen(PROCDIR "/uptime", "r");
if (fd) { if (fd)
{
int n = fscanf(fd, "%64lf", &uptime); int n = fscanf(fd, "%64lf", &uptime);
fclose(fd); fclose(fd);
if (n <= 0) { if (n <= 0)
{
return 0; return 0;
} }
} }
return floor(uptime); return floor(uptime);
} }
void Platform_getLoadAverage(double* one, double* five, double* fifteen) { float Platform_getTemp()
{
float ftemp = 0;
FILE *fd = fopen("/sys/class/thermal/thermal_zone0/temp", "r");
if (!fd)
{
return ftemp;
}
int itemp = 0;
fscanf(fd, "%d", &itemp);
ftemp = itemp;
if (ftemp >= 1000)
{
ftemp /= 1000;
}
fclose(fd);
return ftemp;
}
float Platform_getFreq()
{
float freq = 0;
FILE *fd = fopen("/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq", "r");
if (!fd)
{
return freq;
}
int ifreq = 0;
fscanf(fd, "%d", &ifreq);
freq = ifreq;
fclose(fd);
if (freq < 10)
{
freq *= 1000000;
}
else
{
freq /= 1000000;
}
return freq;
}
void Platform_getLoadAverage(double *one, double *five, double *fifteen)
{
FILE *fd = fopen(PROCDIR "/loadavg", "r"); FILE *fd = fopen(PROCDIR "/loadavg", "r");
if (!fd) if (!fd)
goto err; goto err;
@ -285,7 +354,8 @@ err:
*fifteen = NAN; *fifteen = NAN;
} }
int Platform_getMaxPid() { int Platform_getMaxPid()
{
FILE *file = fopen(PROCDIR "/sys/kernel/pid_max", "r"); FILE *file = fopen(PROCDIR "/sys/kernel/pid_max", "r");
if (!file) if (!file)
return -1; return -1;
@ -297,21 +367,24 @@ int Platform_getMaxPid() {
return maxPid; return maxPid;
} }
double Platform_setCPUValues(Meter* this, unsigned int cpu) { double Platform_setCPUValues(Meter *this, unsigned int cpu)
{
const LinuxProcessList *pl = (const LinuxProcessList *)this->pl; const LinuxProcessList *pl = (const LinuxProcessList *)this->pl;
const CPUData *cpuData = &(pl->cpuData[cpu]); const CPUData *cpuData = &(pl->cpuData[cpu]);
double total = (double)(cpuData->totalPeriod == 0 ? 1 : cpuData->totalPeriod); double total = (double)(cpuData->totalPeriod == 0 ? 1 : cpuData->totalPeriod);
double percent; double percent;
double *v = this->values; double *v = this->values;
if (!cpuData->online) { if (!cpuData->online)
{
this->curItems = 0; this->curItems = 0;
return NAN; return NAN;
} }
v[CPU_METER_NICE] = cpuData->nicePeriod / total * 100.0; v[CPU_METER_NICE] = cpuData->nicePeriod / total * 100.0;
v[CPU_METER_NORMAL] = cpuData->userPeriod / total * 100.0; v[CPU_METER_NORMAL] = cpuData->userPeriod / total * 100.0;
if (this->pl->settings->detailedCPUTime) { if (this->pl->settings->detailedCPUTime)
{
v[CPU_METER_KERNEL] = cpuData->systemPeriod / total * 100.0; v[CPU_METER_KERNEL] = cpuData->systemPeriod / total * 100.0;
v[CPU_METER_IRQ] = cpuData->irqPeriod / total * 100.0; v[CPU_METER_IRQ] = cpuData->irqPeriod / total * 100.0;
v[CPU_METER_SOFTIRQ] = cpuData->softIrqPeriod / total * 100.0; v[CPU_METER_SOFTIRQ] = cpuData->softIrqPeriod / total * 100.0;
@ -319,19 +392,25 @@ double Platform_setCPUValues(Meter* this, unsigned int cpu) {
v[CPU_METER_GUEST] = cpuData->guestPeriod / total * 100.0; v[CPU_METER_GUEST] = cpuData->guestPeriod / total * 100.0;
v[CPU_METER_IOWAIT] = cpuData->ioWaitPeriod / total * 100.0; v[CPU_METER_IOWAIT] = cpuData->ioWaitPeriod / total * 100.0;
this->curItems = 8; this->curItems = 8;
if (this->pl->settings->accountGuestInCPUMeter) { if (this->pl->settings->accountGuestInCPUMeter)
{
percent = v[0] + v[1] + v[2] + v[3] + v[4] + v[5] + v[6]; percent = v[0] + v[1] + v[2] + v[3] + v[4] + v[5] + v[6];
} else { }
else
{
percent = v[0] + v[1] + v[2] + v[3] + v[4]; percent = v[0] + v[1] + v[2] + v[3] + v[4];
} }
} else { }
else
{
v[2] = cpuData->systemAllPeriod / total * 100.0; v[2] = cpuData->systemAllPeriod / total * 100.0;
v[3] = (cpuData->stealPeriod + cpuData->guestPeriod) / total * 100.0; v[3] = (cpuData->stealPeriod + cpuData->guestPeriod) / total * 100.0;
this->curItems = 4; this->curItems = 4;
percent = v[0] + v[1] + v[2] + v[3]; percent = v[0] + v[1] + v[2] + v[3];
} }
percent = CLAMP(percent, 0.0, 100.0); percent = CLAMP(percent, 0.0, 100.0);
if (isnan(percent)) { if (isnan(percent))
{
percent = 0.0; percent = 0.0;
} }
@ -346,7 +425,8 @@ double Platform_setCPUValues(Meter* this, unsigned int cpu) {
return percent; return percent;
} }
void Platform_setMemoryValues(Meter* this) { void Platform_setMemoryValues(Meter *this)
{
const ProcessList *pl = this->pl; const ProcessList *pl = this->pl;
const LinuxProcessList *lpl = (const LinuxProcessList *)pl; const LinuxProcessList *lpl = (const LinuxProcessList *)pl;
@ -357,7 +437,8 @@ void Platform_setMemoryValues(Meter* this) {
this->values[3] = pl->cachedMem; this->values[3] = pl->cachedMem;
this->values[4] = pl->availableMem; this->values[4] = pl->availableMem;
if (lpl->zfs.enabled != 0 && !Running_containerized) { if (lpl->zfs.enabled != 0 && !Running_containerized)
{
// ZFS does not shrink below the value of zfs_arc_min. // ZFS does not shrink below the value of zfs_arc_min.
unsigned long long int shrinkableSize = 0; unsigned long long int shrinkableSize = 0;
if (lpl->zfs.size > lpl->zfs.min) if (lpl->zfs.size > lpl->zfs.min)
@ -368,33 +449,38 @@ void Platform_setMemoryValues(Meter* this) {
} }
} }
void Platform_setSwapValues(Meter* this) { void Platform_setSwapValues(Meter *this)
{
const ProcessList *pl = this->pl; const ProcessList *pl = this->pl;
this->total = pl->totalSwap; this->total = pl->totalSwap;
this->values[0] = pl->usedSwap; this->values[0] = pl->usedSwap;
this->values[1] = pl->cachedSwap; this->values[1] = pl->cachedSwap;
} }
void Platform_setZramValues(Meter* this) { void Platform_setZramValues(Meter *this)
{
const LinuxProcessList *lpl = (const LinuxProcessList *)this->pl; const LinuxProcessList *lpl = (const LinuxProcessList *)this->pl;
this->total = lpl->zram.totalZram; this->total = lpl->zram.totalZram;
this->values[0] = lpl->zram.usedZramComp; this->values[0] = lpl->zram.usedZramComp;
this->values[1] = lpl->zram.usedZramOrig; this->values[1] = lpl->zram.usedZramOrig;
} }
void Platform_setZfsArcValues(Meter* this) { void Platform_setZfsArcValues(Meter *this)
{
const LinuxProcessList *lpl = (const LinuxProcessList *)this->pl; const LinuxProcessList *lpl = (const LinuxProcessList *)this->pl;
ZfsArcMeter_readStats(this, &(lpl->zfs)); ZfsArcMeter_readStats(this, &(lpl->zfs));
} }
void Platform_setZfsCompressedArcValues(Meter* this) { void Platform_setZfsCompressedArcValues(Meter *this)
{
const LinuxProcessList *lpl = (const LinuxProcessList *)this->pl; const LinuxProcessList *lpl = (const LinuxProcessList *)this->pl;
ZfsCompressedArcMeter_readStats(this, &(lpl->zfs)); ZfsCompressedArcMeter_readStats(this, &(lpl->zfs));
} }
char* Platform_getProcessEnv(pid_t pid) { char *Platform_getProcessEnv(pid_t pid)
{
char procname[128]; char procname[128];
xSnprintf(procname, sizeof(procname), PROCDIR "/%d/environ", pid); xSnprintf(procname, sizeof(procname), PROCDIR "/%d/environ", pid);
FILE *fd = fopen(procname, "r"); FILE *fd = fopen(procname, "r");
@ -407,7 +493,8 @@ char* Platform_getProcessEnv(pid_t pid) {
size_t size = 0; size_t size = 0;
ssize_t bytes = 0; ssize_t bytes = 0;
do { do
{
size += bytes; size += bytes;
capacity += 4096; capacity += 4096;
env = xRealloc(env, capacity); env = xRealloc(env, capacity);
@ -415,7 +502,8 @@ char* Platform_getProcessEnv(pid_t pid) {
fclose(fd); fclose(fd);
if (bytes < 0) { if (bytes < 0)
{
free(env); free(env);
return NULL; return NULL;
} }
@ -436,7 +524,8 @@ char* Platform_getProcessEnv(pid_t pid) {
* Based on implementation of lslocks from util-linux: * Based on implementation of lslocks from util-linux:
* https://sources.debian.org/src/util-linux/2.36-3/misc-utils/lslocks.c/#L162 * https://sources.debian.org/src/util-linux/2.36-3/misc-utils/lslocks.c/#L162
*/ */
char* Platform_getInodeFilename(pid_t pid, ino_t inode) { char *Platform_getInodeFilename(pid_t pid, ino_t inode)
{
struct stat sb; struct stat sb;
const struct dirent *de; const struct dirent *de;
DIR *dirp; DIR *dirp;
@ -460,7 +549,8 @@ char* Platform_getInodeFilename(pid_t pid, ino_t inode) {
if ((fd = dirfd(dirp)) < 0) if ((fd = dirfd(dirp)) < 0)
goto out; goto out;
while ((de = readdir(dirp))) { while ((de = readdir(dirp)))
{
if (String_eq(de->d_name, ".") || String_eq(de->d_name, "..")) if (String_eq(de->d_name, ".") || String_eq(de->d_name, ".."))
continue; continue;
@ -485,18 +575,21 @@ out:
return ret; return ret;
} }
FileLocks_ProcessData* Platform_getProcessLocks(pid_t pid) { FileLocks_ProcessData *Platform_getProcessLocks(pid_t pid)
{
FileLocks_ProcessData *pdata = xCalloc(1, sizeof(FileLocks_ProcessData)); FileLocks_ProcessData *pdata = xCalloc(1, sizeof(FileLocks_ProcessData));
FILE *f = fopen(PROCDIR "/locks", "r"); FILE *f = fopen(PROCDIR "/locks", "r");
if (!f) { if (!f)
{
pdata->error = true; pdata->error = true;
return pdata; return pdata;
} }
char buffer[1024]; char buffer[1024];
FileLocks_LockData **data_ref = &pdata->locks; FileLocks_LockData **data_ref = &pdata->locks;
while(fgets(buffer, sizeof(buffer), f)) { while (fgets(buffer, sizeof(buffer), f))
{
if (!strchr(buffer, '\n')) if (!strchr(buffer, '\n'))
continue; continue;
@ -530,9 +623,12 @@ FileLocks_ProcessData* Platform_getProcessLocks(pid_t pid) {
data->dev[1] = lock_dev[1]; data->dev[1] = lock_dev[1];
data->inode = lock_inode; data->inode = lock_inode;
data->start = strtoull(lock_start, NULL, 10); data->start = strtoull(lock_start, NULL, 10);
if (!String_eq(lock_end, "EOF")) { if (!String_eq(lock_end, "EOF"))
{
data->end = strtoull(lock_end, NULL, 10); data->end = strtoull(lock_end, NULL, 10);
} else { }
else
{
data->end = ULLONG_MAX; data->end = ULLONG_MAX;
} }
@ -544,17 +640,20 @@ FileLocks_ProcessData* Platform_getProcessLocks(pid_t pid) {
return pdata; return pdata;
} }
void Platform_getPressureStall(const char* file, bool some, double* ten, double* sixty, double* threehundred) { void Platform_getPressureStall(const char *file, bool some, double *ten, double *sixty, double *threehundred)
{
*ten = *sixty = *threehundred = 0; *ten = *sixty = *threehundred = 0;
char procname[128]; char procname[128];
xSnprintf(procname, sizeof(procname), PROCDIR "/pressure/%s", file); xSnprintf(procname, sizeof(procname), PROCDIR "/pressure/%s", file);
FILE *fd = fopen(procname, "r"); FILE *fd = fopen(procname, "r");
if (!fd) { if (!fd)
{
*ten = *sixty = *threehundred = NAN; *ten = *sixty = *threehundred = NAN;
return; return;
} }
int total = fscanf(fd, "some avg10=%32lf avg60=%32lf avg300=%32lf total=%*f ", ten, sixty, threehundred); int total = fscanf(fd, "some avg10=%32lf avg60=%32lf avg300=%32lf total=%*f ", ten, sixty, threehundred);
if (!some) { if (!some)
{
total = fscanf(fd, "full avg10=%32lf avg60=%32lf avg300=%32lf total=%*f ", ten, sixty, threehundred); total = fscanf(fd, "full avg10=%32lf avg60=%32lf avg300=%32lf total=%*f ", ten, sixty, threehundred);
} }
(void)total; (void)total;
@ -562,7 +661,8 @@ void Platform_getPressureStall(const char* file, bool some, double* ten, double*
fclose(fd); fclose(fd);
} }
bool Platform_getDiskIO(DiskIOData* data) { bool Platform_getDiskIO(DiskIOData *data)
{
FILE *fd = fopen(PROCDIR "/diskstats", "r"); FILE *fd = fopen(PROCDIR "/diskstats", "r");
if (!fd) if (!fd)
return false; return false;
@ -571,10 +671,12 @@ bool Platform_getDiskIO(DiskIOData* data) {
unsigned long long int read_sum = 0, write_sum = 0, timeSpend_sum = 0; unsigned long long int read_sum = 0, write_sum = 0, timeSpend_sum = 0;
char lineBuffer[256]; char lineBuffer[256];
while (fgets(lineBuffer, sizeof(lineBuffer), fd)) { while (fgets(lineBuffer, sizeof(lineBuffer), fd))
{
char diskname[32]; char diskname[32];
unsigned long long int read_tmp, write_tmp, timeSpend_tmp; unsigned long long int read_tmp, write_tmp, timeSpend_tmp;
if (sscanf(lineBuffer, "%*d %*d %31s %*u %*u %llu %*u %*u %*u %llu %*u %*u %llu", diskname, &read_tmp, &write_tmp, &timeSpend_tmp) == 4) { if (sscanf(lineBuffer, "%*d %*d %31s %*u %*u %llu %*u %*u %*u %llu %*u %*u %llu", diskname, &read_tmp, &write_tmp, &timeSpend_tmp) == 4)
{
if (String_startsWith(diskname, "dm-")) if (String_startsWith(diskname, "dm-"))
continue; continue;
@ -601,14 +703,16 @@ bool Platform_getDiskIO(DiskIOData* data) {
return true; return true;
} }
bool Platform_getNetworkIO(NetworkIOData* data) { bool Platform_getNetworkIO(NetworkIOData *data)
{
FILE *fd = fopen(PROCDIR "/net/dev", "r"); FILE *fd = fopen(PROCDIR "/net/dev", "r");
if (!fd) if (!fd)
return false; return false;
memset(data, 0, sizeof(NetworkIOData)); memset(data, 0, sizeof(NetworkIOData));
char lineBuffer[512]; char lineBuffer[512];
while (fgets(lineBuffer, sizeof(lineBuffer), fd)) { while (fgets(lineBuffer, sizeof(lineBuffer), fd))
{
char interfaceName[32]; char interfaceName[32];
unsigned long long int bytesReceived, packetsReceived, bytesTransmitted, packetsTransmitted; unsigned long long int bytesReceived, packetsReceived, bytesTransmitted, packetsTransmitted;
if (sscanf(lineBuffer, "%31s %llu %llu %*u %*u %*u %*u %*u %*u %llu %llu", if (sscanf(lineBuffer, "%31s %llu %llu %*u %*u %*u %*u %*u %*u %llu %llu",
@ -644,7 +748,8 @@ bool Platform_getNetworkIO(NetworkIOData* data) {
// READ FROM /proc // READ FROM /proc
// ---------------------------------------- // ----------------------------------------
static double Platform_Battery_getProcBatInfo(void) { static double Platform_Battery_getProcBatInfo(void)
{
DIR *batteryDir = opendir(PROC_BATTERY_DIR); DIR *batteryDir = opendir(PROC_BATTERY_DIR);
if (!batteryDir) if (!batteryDir)
return NAN; return NAN;
@ -653,7 +758,8 @@ static double Platform_Battery_getProcBatInfo(void) {
uint64_t totalRemain = 0; uint64_t totalRemain = 0;
struct dirent *dirEntry = NULL; struct dirent *dirEntry = NULL;
while ((dirEntry = readdir(batteryDir))) { while ((dirEntry = readdir(batteryDir)))
{
const char *entryName = dirEntry->d_name; const char *entryName = dirEntry->d_name;
if (!String_startsWith(entryName, "BAT")) if (!String_startsWith(entryName, "BAT"))
continue; continue;
@ -675,13 +781,15 @@ static double Platform_Battery_getProcBatInfo(void) {
// Getting total charge for all batteries // Getting total charge for all batteries
char *buf = bufInfo; char *buf = bufInfo;
while ((line = strsep(&buf, "\n")) != NULL) { while ((line = strsep(&buf, "\n")) != NULL)
{
char field[100] = {0}; char field[100] = {0};
int val = 0; int val = 0;
if (2 != sscanf(line, "%99[^:]:%d", field, &val)) if (2 != sscanf(line, "%99[^:]:%d", field, &val))
continue; continue;
if (String_eq(field, "last full capacity")) { if (String_eq(field, "last full capacity"))
{
totalFull += val; totalFull += val;
break; break;
} }
@ -689,13 +797,15 @@ static double Platform_Battery_getProcBatInfo(void) {
// Getting remaining charge for all batteries // Getting remaining charge for all batteries
buf = bufState; buf = bufState;
while ((line = strsep(&buf, "\n")) != NULL) { while ((line = strsep(&buf, "\n")) != NULL)
{
char field[100] = {0}; char field[100] = {0};
int val = 0; int val = 0;
if (2 != sscanf(line, "%99[^:]:%d", field, &val)) if (2 != sscanf(line, "%99[^:]:%d", field, &val))
continue; continue;
if (String_eq(field, "remaining capacity")) { if (String_eq(field, "remaining capacity"))
{
totalRemain += val; totalRemain += val;
break; break;
} }
@ -707,7 +817,8 @@ static double Platform_Battery_getProcBatInfo(void) {
return totalFull > 0 ? ((double)totalRemain * 100.0) / (double)totalFull : NAN; return totalFull > 0 ? ((double)totalRemain * 100.0) / (double)totalFull : NAN;
} }
static ACPresence procAcpiCheck(void) { static ACPresence procAcpiCheck(void)
{
char buffer[1024] = {0}; char buffer[1024] = {0};
ssize_t r = xReadfile(PROC_POWERSUPPLY_ACSTATE_FILE, buffer, sizeof(buffer)); ssize_t r = xReadfile(PROC_POWERSUPPLY_ACSTATE_FILE, buffer, sizeof(buffer));
if (r < 1) if (r < 1)
@ -716,7 +827,8 @@ static ACPresence procAcpiCheck(void) {
return String_eq(buffer, "on-line") ? AC_PRESENT : AC_ABSENT; return String_eq(buffer, "on-line") ? AC_PRESENT : AC_ABSENT;
} }
static void Platform_Battery_getProcData(double* percent, ACPresence* isOnAC) { static void Platform_Battery_getProcData(double *percent, ACPresence *isOnAC)
{
*isOnAC = procAcpiCheck(); *isOnAC = procAcpiCheck();
*percent = AC_ERROR != *isOnAC ? Platform_Battery_getProcBatInfo() : NAN; *percent = AC_ERROR != *isOnAC ? Platform_Battery_getProcBatInfo() : NAN;
} }
@ -725,7 +837,8 @@ static void Platform_Battery_getProcData(double* percent, ACPresence* isOnAC) {
// READ FROM /sys // READ FROM /sys
// ---------------------------------------- // ----------------------------------------
static void Platform_Battery_getSysData(double* percent, ACPresence* isOnAC) { static void Platform_Battery_getSysData(double *percent, ACPresence *isOnAC)
{
*percent = NAN; *percent = NAN;
*isOnAC = AC_ERROR; *isOnAC = AC_ERROR;
@ -737,7 +850,8 @@ static void Platform_Battery_getSysData(double* percent, ACPresence* isOnAC) {
uint64_t totalRemain = 0; uint64_t totalRemain = 0;
const struct dirent *dirEntry; const struct dirent *dirEntry;
while ((dirEntry = readdir(dir))) { while ((dirEntry = readdir(dir)))
{
const char *entryName = dirEntry->d_name; const char *entryName = dirEntry->d_name;
#ifdef HAVE_OPENAT #ifdef HAVE_OPENAT
@ -749,12 +863,21 @@ static void Platform_Battery_getSysData(double* percent, ACPresence* isOnAC) {
xSnprintf(entryFd, sizeof(entryFd), SYS_POWERSUPPLY_DIR "/%s", entryName); xSnprintf(entryFd, sizeof(entryFd), SYS_POWERSUPPLY_DIR "/%s", entryName);
#endif #endif
enum { AC, BAT } type; enum
if (String_startsWith(entryName, "BAT")) { {
AC,
BAT
} type;
if (String_startsWith(entryName, "BAT"))
{
type = BAT; type = BAT;
} else if (String_startsWith(entryName, "AC")) { }
else if (String_startsWith(entryName, "AC"))
{
type = AC; type = AC;
} else { }
else
{
char buffer[32]; char buffer[32];
ssize_t ret = xReadfileat(entryFd, "type", buffer, sizeof(buffer)); ssize_t ret = xReadfileat(entryFd, "type", buffer, sizeof(buffer));
if (ret <= 0) if (ret <= 0)
@ -772,7 +895,8 @@ static void Platform_Battery_getSysData(double* percent, ACPresence* isOnAC) {
goto next; goto next;
} }
if (type == BAT) { if (type == BAT)
{
char buffer[1024]; char buffer[1024];
ssize_t r = xReadfileat(entryFd, "uevent", buffer, sizeof(buffer)); ssize_t r = xReadfileat(entryFd, "uevent", buffer, sizeof(buffer));
if (r < 0) if (r < 0)
@ -786,18 +910,21 @@ static void Platform_Battery_getSysData(double* percent, ACPresence* isOnAC) {
const char *line; const char *line;
char *buf = buffer; char *buf = buffer;
while ((line = strsep(&buf, "\n")) != NULL) { while ((line = strsep(&buf, "\n")) != NULL)
{
char field[100] = {0}; char field[100] = {0};
int val = 0; int val = 0;
if (2 != sscanf(line, "POWER_SUPPLY_%99[^=]=%d", field, &val)) if (2 != sscanf(line, "POWER_SUPPLY_%99[^=]=%d", field, &val))
continue; continue;
if (String_eq(field, "CAPACITY")) { if (String_eq(field, "CAPACITY"))
{
capacityLevel = val / 100.0; capacityLevel = val / 100.0;
continue; continue;
} }
if (String_eq(field, "ENERGY_FULL") || String_eq(field, "CHARGE_FULL")) { if (String_eq(field, "ENERGY_FULL") || String_eq(field, "CHARGE_FULL"))
{
fullCharge = val; fullCharge = val;
totalFull += fullCharge; totalFull += fullCharge;
full = true; full = true;
@ -806,7 +933,8 @@ static void Platform_Battery_getSysData(double* percent, ACPresence* isOnAC) {
continue; continue;
} }
if (String_eq(field, "ENERGY_NOW") || String_eq(field, "CHARGE_NOW")) { if (String_eq(field, "ENERGY_NOW") || String_eq(field, "CHARGE_NOW"))
{
totalRemain += val; totalRemain += val;
now = true; now = true;
if (full) if (full)
@ -817,14 +945,16 @@ static void Platform_Battery_getSysData(double* percent, ACPresence* isOnAC) {
if (!now && full && !isnan(capacityLevel)) if (!now && full && !isnan(capacityLevel))
totalRemain += capacityLevel * fullCharge; totalRemain += capacityLevel * fullCharge;
}
} else if (type == AC) { else if (type == AC)
{
if (*isOnAC != AC_ERROR) if (*isOnAC != AC_ERROR)
goto next; goto next;
char buffer[2]; char buffer[2];
ssize_t r = xReadfileat(entryFd, "online", buffer, sizeof(buffer)); ssize_t r = xReadfileat(entryFd, "online", buffer, sizeof(buffer));
if (r < 1) { if (r < 1)
{
*isOnAC = AC_ERROR; *isOnAC = AC_ERROR;
goto next; goto next;
} }
@ -844,29 +974,36 @@ next:
*percent = totalFull > 0 ? ((double)totalRemain * 100.0) / (double)totalFull : NAN; *percent = totalFull > 0 ? ((double)totalRemain * 100.0) / (double)totalFull : NAN;
} }
void Platform_getBattery(double* percent, ACPresence* isOnAC) { void Platform_getBattery(double *percent, ACPresence *isOnAC)
{
time_t now = time(NULL); time_t now = time(NULL);
// update battery reading is slow. Update it each 10 seconds only. // update battery reading is slow. Update it each 10 seconds only.
if (now < Platform_Battery_cacheTime + 10) { if (now < Platform_Battery_cacheTime + 10)
{
*percent = Platform_Battery_cachePercent; *percent = Platform_Battery_cachePercent;
*isOnAC = Platform_Battery_cacheIsOnAC; *isOnAC = Platform_Battery_cacheIsOnAC;
return; return;
} }
if (Platform_Battery_method == BAT_PROC) { if (Platform_Battery_method == BAT_PROC)
{
Platform_Battery_getProcData(percent, isOnAC); Platform_Battery_getProcData(percent, isOnAC);
if (isnan(*percent)) if (isnan(*percent))
Platform_Battery_method = BAT_SYS; Platform_Battery_method = BAT_SYS;
} }
if (Platform_Battery_method == BAT_SYS) { if (Platform_Battery_method == BAT_SYS)
{
Platform_Battery_getSysData(percent, isOnAC); Platform_Battery_getSysData(percent, isOnAC);
if (isnan(*percent)) if (isnan(*percent))
Platform_Battery_method = BAT_ERR; Platform_Battery_method = BAT_ERR;
} }
if (Platform_Battery_method == BAT_ERR) { if (Platform_Battery_method == BAT_ERR)
{
*percent = NAN; *percent = NAN;
*isOnAC = AC_ERROR; *isOnAC = AC_ERROR;
} else { }
else
{
*percent = CLAMP(*percent, 0.0, 100.0); *percent = CLAMP(*percent, 0.0, 100.0);
} }
Platform_Battery_cachePercent = *percent; Platform_Battery_cachePercent = *percent;
@ -882,34 +1019,46 @@ void Platform_longOptionsUsage(const char* name)
" off - do not drop any capabilities\n" " off - do not drop any capabilities\n"
" basic (default) - drop all capabilities not needed by %s\n" " basic (default) - drop all capabilities not needed by %s\n"
" strict - drop all capabilities except those needed for\n" " strict - drop all capabilities except those needed for\n"
" core functionality\n", name); " core functionality\n",
name);
#else #else
(void)name; (void)name;
#endif #endif
} }
CommandLineStatus Platform_getLongOption(int opt, int argc, char** argv) { CommandLineStatus Platform_getLongOption(int opt, int argc, char **argv)
{
#ifndef HAVE_LIBCAP #ifndef HAVE_LIBCAP
(void)argc; (void)argc;
(void)argv; (void)argv;
#endif #endif
switch (opt) { switch (opt)
{
#ifdef HAVE_LIBCAP #ifdef HAVE_LIBCAP
case 160: { case 160:
{
const char *mode = optarg; const char *mode = optarg;
if (!mode && optind < argc && argv[optind] != NULL && if (!mode && optind < argc && argv[optind] != NULL &&
(argv[optind][0] != '\0' && argv[optind][0] != '-')) { (argv[optind][0] != '\0' && argv[optind][0] != '-'))
{
mode = argv[optind++]; mode = argv[optind++];
} }
if (!mode || String_eq(mode, "basic")) { if (!mode || String_eq(mode, "basic"))
{
Platform_capabilitiesMode = CAP_MODE_BASIC; Platform_capabilitiesMode = CAP_MODE_BASIC;
} else if (String_eq(mode, "off")) { }
else if (String_eq(mode, "off"))
{
Platform_capabilitiesMode = CAP_MODE_OFF; Platform_capabilitiesMode = CAP_MODE_OFF;
} else if (String_eq(mode, "strict")) { }
else if (String_eq(mode, "strict"))
{
Platform_capabilitiesMode = CAP_MODE_STRICT; Platform_capabilitiesMode = CAP_MODE_STRICT;
} else { }
else
{
fprintf(stderr, "Error: invalid capabilities mode \"%s\".\n", mode); fprintf(stderr, "Error: invalid capabilities mode \"%s\".\n", mode);
return STATUS_ERROR_EXIT; return STATUS_ERROR_EXIT;
} }
@ -924,7 +1073,8 @@ CommandLineStatus Platform_getLongOption(int opt, int argc, char** argv) {
} }
#ifdef HAVE_LIBCAP #ifdef HAVE_LIBCAP
static int dropCapabilities(enum CapMode mode) { static int dropCapabilities(enum CapMode mode)
{
if (mode == CAP_MODE_OFF) if (mode == CAP_MODE_OFF)
return 0; return 0;
@ -947,30 +1097,35 @@ static int dropCapabilities(enum CapMode mode) {
const size_t ncap = (mode == CAP_MODE_BASIC) ? ARRAYSIZE(keepcapsBasic) : ARRAYSIZE(keepcapsStrict); const size_t ncap = (mode == CAP_MODE_BASIC) ? ARRAYSIZE(keepcapsBasic) : ARRAYSIZE(keepcapsStrict);
cap_t caps = cap_init(); cap_t caps = cap_init();
if (caps == NULL) { if (caps == NULL)
{
fprintf(stderr, "Error: can not initialize capabilities: %s\n", strerror(errno)); fprintf(stderr, "Error: can not initialize capabilities: %s\n", strerror(errno));
return -1; return -1;
} }
if (cap_clear(caps) < 0) { if (cap_clear(caps) < 0)
{
fprintf(stderr, "Error: can not clear capabilities: %s\n", strerror(errno)); fprintf(stderr, "Error: can not clear capabilities: %s\n", strerror(errno));
cap_free(caps); cap_free(caps);
return -1; return -1;
} }
cap_t currCaps = cap_get_proc(); cap_t currCaps = cap_get_proc();
if (currCaps == NULL) { if (currCaps == NULL)
{
fprintf(stderr, "Error: can not get current process capabilities: %s\n", strerror(errno)); fprintf(stderr, "Error: can not get current process capabilities: %s\n", strerror(errno));
cap_free(caps); cap_free(caps);
return -1; return -1;
} }
for (size_t i = 0; i < ncap; i++) { for (size_t i = 0; i < ncap; i++)
{
if (!CAP_IS_SUPPORTED(keepcaps[i])) if (!CAP_IS_SUPPORTED(keepcaps[i]))
continue; continue;
cap_flag_value_t current; cap_flag_value_t current;
if (cap_get_flag(currCaps, keepcaps[i], CAP_PERMITTED, &current) < 0) { if (cap_get_flag(currCaps, keepcaps[i], CAP_PERMITTED, &current) < 0)
{
fprintf(stderr, "Error: can not get current value of capability %d: %s\n", keepcaps[i], strerror(errno)); fprintf(stderr, "Error: can not get current value of capability %d: %s\n", keepcaps[i], strerror(errno));
cap_free(currCaps); cap_free(currCaps);
cap_free(caps); cap_free(caps);
@ -980,14 +1135,16 @@ static int dropCapabilities(enum CapMode mode) {
if (current != CAP_SET) if (current != CAP_SET)
continue; continue;
if (cap_set_flag(caps, CAP_PERMITTED, 1, &keepcaps[i], CAP_SET) < 0) { if (cap_set_flag(caps, CAP_PERMITTED, 1, &keepcaps[i], CAP_SET) < 0)
{
fprintf(stderr, "Error: can not set permitted capability %d: %s\n", keepcaps[i], strerror(errno)); fprintf(stderr, "Error: can not set permitted capability %d: %s\n", keepcaps[i], strerror(errno));
cap_free(currCaps); cap_free(currCaps);
cap_free(caps); cap_free(caps);
return -1; return -1;
} }
if (cap_set_flag(caps, CAP_EFFECTIVE, 1, &keepcaps[i], CAP_SET) < 0) { if (cap_set_flag(caps, CAP_EFFECTIVE, 1, &keepcaps[i], CAP_SET) < 0)
{
fprintf(stderr, "Error: can not set effective capability %d: %s\n", keepcaps[i], strerror(errno)); fprintf(stderr, "Error: can not set effective capability %d: %s\n", keepcaps[i], strerror(errno));
cap_free(currCaps); cap_free(currCaps);
cap_free(caps); cap_free(caps);
@ -995,7 +1152,8 @@ static int dropCapabilities(enum CapMode mode) {
} }
} }
if (cap_set_proc(caps) < 0) { if (cap_set_proc(caps) < 0)
{
fprintf(stderr, "Error: can not set process capabilities: %s\n", strerror(errno)); fprintf(stderr, "Error: can not set process capabilities: %s\n", strerror(errno));
cap_free(currCaps); cap_free(currCaps);
cap_free(caps); cap_free(caps);
@ -1009,13 +1167,15 @@ static int dropCapabilities(enum CapMode mode) {
} }
#endif #endif
bool Platform_init(void) { bool Platform_init(void)
{
#ifdef HAVE_LIBCAP #ifdef HAVE_LIBCAP
if (dropCapabilities(Platform_capabilitiesMode) < 0) if (dropCapabilities(Platform_capabilitiesMode) < 0)
return false; return false;
#endif #endif
if (access(PROCDIR, R_OK) != 0) { if (access(PROCDIR, R_OK) != 0)
{
fprintf(stderr, "Error: could not read procfs (compiled to look in %s).\n", PROCDIR); fprintf(stderr, "Error: could not read procfs (compiled to look in %s).\n", PROCDIR);
return false; return false;
} }
@ -1026,21 +1186,26 @@ bool Platform_init(void) {
char target[PATH_MAX]; char target[PATH_MAX];
ssize_t ret = readlink(PROCDIR "/self/ns/pid", target, sizeof(target) - 1); ssize_t ret = readlink(PROCDIR "/self/ns/pid", target, sizeof(target) - 1);
if (ret > 0) { if (ret > 0)
{
target[ret] = '\0'; target[ret] = '\0';
if (!String_eq("pid:[4026531836]", target)) { // magic constant PROC_PID_INIT_INO from include/linux/proc_ns.h#L46 if (!String_eq("pid:[4026531836]", target))
{ // magic constant PROC_PID_INIT_INO from include/linux/proc_ns.h#L46
Running_containerized = true; Running_containerized = true;
return true; // early return return true; // early return
} }
} }
FILE *fd = fopen(PROCDIR "/1/mounts", "r"); FILE *fd = fopen(PROCDIR "/1/mounts", "r");
if (fd) { if (fd)
{
char lineBuffer[256]; char lineBuffer[256];
while (fgets(lineBuffer, sizeof(lineBuffer), fd)) { while (fgets(lineBuffer, sizeof(lineBuffer), fd))
{
// detect lxc or overlayfs and guess that this means we are running containerized // detect lxc or overlayfs and guess that this means we are running containerized
if (String_startsWith(lineBuffer, "lxcfs /proc") || String_startsWith(lineBuffer, "overlay ")) { if (String_startsWith(lineBuffer, "lxcfs /proc") || String_startsWith(lineBuffer, "overlay "))
{
Running_containerized = true; Running_containerized = true;
break; break;
} }
@ -1051,7 +1216,8 @@ bool Platform_init(void) {
return true; return true;
} }
void Platform_done(void) { void Platform_done(void)
{
#ifdef HAVE_SENSORS_SENSORS_H #ifdef HAVE_SENSORS_SENSORS_H
LibSensors_cleanup(); LibSensors_cleanup();
#endif #endif

View File

@ -37,7 +37,6 @@ in the source distribution for its full text.
#define PATH_MAX 4096 #define PATH_MAX 4096
#endif #endif
extern const ScreenDefaults Platform_defaultScreens[]; extern const ScreenDefaults Platform_defaultScreens[];
extern const unsigned int Platform_numberOfDefaultScreens; extern const unsigned int Platform_numberOfDefaultScreens;
@ -57,6 +56,10 @@ void Platform_setBindings(Htop_Action* keys);
int Platform_getUptime(void); int Platform_getUptime(void);
float Platform_getTemp(void);
float Platform_getFreq(void);
void Platform_getLoadAverage(double *one, double *five, double *fifteen); void Platform_getLoadAverage(double *one, double *five, double *fifteen);
int Platform_getMaxPid(void); int Platform_getMaxPid(void);
@ -87,11 +90,13 @@ bool Platform_getNetworkIO(NetworkIOData* data);
void Platform_getBattery(double *percent, ACPresence *isOnAC); void Platform_getBattery(double *percent, ACPresence *isOnAC);
static inline void Platform_getHostname(char* buffer, size_t size) { static inline void Platform_getHostname(char *buffer, size_t size)
{
Generic_hostname(buffer, size); Generic_hostname(buffer, size);
} }
static inline void Platform_getRelease(char** string) { static inline void Platform_getRelease(char **string)
{
*string = Generic_uname(); *string = Generic_uname();
} }
@ -106,11 +111,13 @@ void Platform_longOptionsUsage(const char* name);
CommandLineStatus Platform_getLongOption(int opt, int argc, char **argv); CommandLineStatus Platform_getLongOption(int opt, int argc, char **argv);
static inline void Platform_gettime_realtime(struct timeval* tv, uint64_t* msec) { static inline void Platform_gettime_realtime(struct timeval *tv, uint64_t *msec)
{
Generic_gettime_realtime(tv, msec); Generic_gettime_realtime(tv, msec);
} }
static inline void Platform_gettime_monotonic(uint64_t* msec) { static inline void Platform_gettime_monotonic(uint64_t *msec)
{
Generic_gettime_monotonic(msec); Generic_gettime_monotonic(msec);
} }