mirror of https://github.com/xzeldon/htop.git
CPU Temperature and Frequency meter for Linux platform
This commit is contained in:
parent
611ea4606f
commit
36260b5814
175
CRT.c
175
CRT.c
|
@ -38,7 +38,6 @@ in the source distribution for its full text.
|
|||
#include <execinfo.h>
|
||||
#endif
|
||||
|
||||
|
||||
#define ColorIndex(i, j) ((7 - (i)) * 8 + (j))
|
||||
|
||||
#define ColorPair(i, j) COLOR_PAIR(ColorIndex(i, j))
|
||||
|
@ -95,7 +94,8 @@ static const int* CRT_delay;
|
|||
|
||||
const char *CRT_degreeSign;
|
||||
|
||||
static const char* initDegreeSign(void) {
|
||||
static const char *initDegreeSign(void)
|
||||
{
|
||||
#ifdef HAVE_LIBNCURSESW
|
||||
if (CRT_utf8)
|
||||
return "\xc2\xb0";
|
||||
|
@ -127,6 +127,8 @@ static int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
|
|||
[FAILED_READ] = A_BOLD | ColorPair(Red, Black),
|
||||
[PAUSED] = A_BOLD | ColorPair(Yellow, Cyan),
|
||||
[UPTIME] = A_BOLD | ColorPair(Cyan, Black),
|
||||
[TEMP] = A_BOLD | ColorPair(Cyan, Black),
|
||||
[FREQ] = A_BOLD | ColorPair(Cyan, Black),
|
||||
[BATTERY] = A_BOLD | ColorPair(Cyan, Black),
|
||||
[LARGE_NUMBER] = A_BOLD | ColorPair(Red, Black),
|
||||
[METER_SHADOW] = A_BOLD | ColorPairGrayBlack,
|
||||
|
@ -234,6 +236,8 @@ static int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
|
|||
[FAILED_READ] = A_BOLD,
|
||||
[PAUSED] = A_BOLD | A_REVERSE,
|
||||
[UPTIME] = A_BOLD,
|
||||
[TEMP] = A_BOLD,
|
||||
[FREQ] = A_BOLD,
|
||||
[BATTERY] = A_BOLD,
|
||||
[LARGE_NUMBER] = A_BOLD,
|
||||
[METER_SHADOW] = A_DIM,
|
||||
|
@ -341,6 +345,8 @@ static int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
|
|||
[FAILED_READ] = ColorPair(Red, White),
|
||||
[PAUSED] = A_BOLD | ColorPair(Yellow, Cyan),
|
||||
[UPTIME] = ColorPair(Yellow, White),
|
||||
[TEMP] = ColorPair(Yellow, White),
|
||||
[FREQ] = ColorPair(Yellow, White),
|
||||
[BATTERY] = ColorPair(Yellow, White),
|
||||
[LARGE_NUMBER] = ColorPair(Red, White),
|
||||
[METER_SHADOW] = ColorPair(Blue, White),
|
||||
|
@ -448,6 +454,8 @@ static int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
|
|||
[FAILED_READ] = ColorPair(Red, Black),
|
||||
[PAUSED] = A_BOLD | ColorPair(Yellow, Cyan),
|
||||
[UPTIME] = ColorPair(Yellow, Black),
|
||||
[TEMP] = ColorPair(Yellow, Black),
|
||||
[FREQ] = ColorPair(Yellow, Black),
|
||||
[BATTERY] = ColorPair(Yellow, Black),
|
||||
[LARGE_NUMBER] = ColorPair(Red, Black),
|
||||
[METER_SHADOW] = A_BOLD | ColorPairGrayBlack,
|
||||
|
@ -555,6 +563,8 @@ static int CRT_colorSchemes[LAST_COLORSCHEME][LAST_COLORELEMENT] = {
|
|||
[FAILED_READ] = A_BOLD | ColorPair(Red, Blue),
|
||||
[PAUSED] = A_BOLD | ColorPair(Yellow, Cyan),
|
||||
[UPTIME] = A_BOLD | ColorPair(Yellow, Blue),
|
||||
[TEMP] = A_BOLD | ColorPair(Yellow, Blue),
|
||||
[FREQ] = A_BOLD | ColorPair(Yellow, Blue),
|
||||
[BATTERY] = A_BOLD | ColorPair(Yellow, Blue),
|
||||
[LARGE_NUMBER] = A_BOLD | ColorPair(Red, 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),
|
||||
[PAUSED] = A_BOLD | ColorPair(Yellow, Green),
|
||||
[UPTIME] = ColorPair(Green, Black),
|
||||
[TEMP] = ColorPair(Green, Black),
|
||||
[FREQ] = ColorPair(Green, Black),
|
||||
[BATTERY] = ColorPair(Green, Black),
|
||||
[LARGE_NUMBER] = A_BOLD | ColorPair(Red, Black),
|
||||
[METER_SHADOW] = A_BOLD | ColorPairGrayBlack,
|
||||
|
@ -763,7 +775,8 @@ int CRT_scrollWheelVAmount = 10;
|
|||
ColorScheme CRT_colorScheme = COLORSCHEME_DEFAULT;
|
||||
|
||||
ATTR_NORETURN
|
||||
static void CRT_handleSIGTERM(ATTR_UNUSED int sgn) {
|
||||
static void CRT_handleSIGTERM(ATTR_UNUSED int sgn)
|
||||
{
|
||||
CRT_done();
|
||||
_exit(0);
|
||||
}
|
||||
|
@ -773,7 +786,8 @@ static void CRT_handleSIGTERM(ATTR_UNUSED int sgn) {
|
|||
static int stderrRedirectNewFd = -1;
|
||||
static int stderrRedirectBackupFd = -1;
|
||||
|
||||
static int createStderrCacheFile(void) {
|
||||
static int createStderrCacheFile(void)
|
||||
{
|
||||
#if defined(HAVE_MEMFD_CREATE)
|
||||
return memfd_create("htop.stderr-redirect", 0);
|
||||
#elif defined(O_TMPFILE)
|
||||
|
@ -792,9 +806,11 @@ static int createStderrCacheFile(void) {
|
|||
#endif /* HAVE_MEMFD_CREATE */
|
||||
}
|
||||
|
||||
static void redirectStderr(void) {
|
||||
static void redirectStderr(void)
|
||||
{
|
||||
stderrRedirectNewFd = createStderrCacheFile();
|
||||
if (stderrRedirectNewFd < 0) {
|
||||
if (stderrRedirectNewFd < 0)
|
||||
{
|
||||
/* ignore failure */
|
||||
return;
|
||||
}
|
||||
|
@ -803,7 +819,8 @@ static void redirectStderr(void) {
|
|||
dup2(stderrRedirectNewFd, STDERR_FILENO);
|
||||
}
|
||||
|
||||
static void dumpStderr(void) {
|
||||
static void dumpStderr(void)
|
||||
{
|
||||
if (stderrRedirectNewFd < 0)
|
||||
return;
|
||||
|
||||
|
@ -815,22 +832,27 @@ static void dumpStderr(void) {
|
|||
|
||||
bool header = false;
|
||||
char buffer[8192];
|
||||
for (;;) {
|
||||
for (;;)
|
||||
{
|
||||
errno = 0;
|
||||
ssize_t res = read(stderrRedirectNewFd, buffer, sizeof(buffer));
|
||||
if (res < 0) {
|
||||
if (res < 0)
|
||||
{
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (res == 0) {
|
||||
if (res == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (res > 0) {
|
||||
if (!header) {
|
||||
if (res > 0)
|
||||
{
|
||||
if (!header)
|
||||
{
|
||||
fprintf(stderr, ">>>>>>>>>> stderr output >>>>>>>>>>\n");
|
||||
header = true;
|
||||
}
|
||||
|
@ -845,7 +867,8 @@ static void dumpStderr(void) {
|
|||
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;
|
||||
|
||||
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 */
|
||||
|
||||
static void redirectStderr(void) {
|
||||
static void redirectStderr(void)
|
||||
{
|
||||
}
|
||||
|
||||
static void dumpStderr(void) {
|
||||
static void dumpStderr(void)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* !NDEBUG */
|
||||
|
||||
static struct sigaction old_sig_handler[32];
|
||||
|
||||
static void CRT_installSignalHandlers(void) {
|
||||
static void CRT_installSignalHandlers(void)
|
||||
{
|
||||
struct sigaction act;
|
||||
sigemptyset(&act.sa_mask);
|
||||
act.sa_flags = (int)SA_RESETHAND | SA_NODEFER;
|
||||
|
@ -886,7 +912,8 @@ static void CRT_installSignalHandlers(void) {
|
|||
signal(SIGQUIT, CRT_handleSIGTERM);
|
||||
}
|
||||
|
||||
void CRT_resetSignalHandlers(void) {
|
||||
void CRT_resetSignalHandlers(void)
|
||||
{
|
||||
sigaction(SIGSEGV, &old_sig_handler[SIGSEGV], NULL);
|
||||
sigaction(SIGFPE, &old_sig_handler[SIGFPE], NULL);
|
||||
sigaction(SIGILL, &old_sig_handler[SIGILL], NULL);
|
||||
|
@ -900,21 +927,26 @@ void CRT_resetSignalHandlers(void) {
|
|||
signal(SIGQUIT, SIG_DFL);
|
||||
}
|
||||
|
||||
void CRT_setMouse(bool enabled) {
|
||||
void CRT_setMouse(bool enabled)
|
||||
{
|
||||
#ifdef HAVE_GETMOUSE
|
||||
if (enabled) {
|
||||
if (enabled)
|
||||
{
|
||||
#if NCURSES_MOUSE_VERSION > 1
|
||||
mousemask(BUTTON1_RELEASED | BUTTON4_PRESSED | BUTTON5_PRESSED, NULL);
|
||||
#else
|
||||
mousemask(BUTTON1_RELEASED, NULL);
|
||||
#endif
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
mousemask(0, NULL);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void CRT_init(const Settings* settings, bool allowUnicode) {
|
||||
void CRT_init(const Settings *settings, bool allowUnicode)
|
||||
{
|
||||
redirectStderr();
|
||||
|
||||
initscr();
|
||||
|
@ -924,7 +956,8 @@ void CRT_init(const Settings* settings, bool allowUnicode) {
|
|||
CRT_colors = CRT_colorSchemes[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];
|
||||
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
|
||||
curs_set(0);
|
||||
|
||||
if (has_colors()) {
|
||||
if (has_colors())
|
||||
{
|
||||
start_color();
|
||||
}
|
||||
|
||||
const char *termType = getenv("TERM");
|
||||
if (termType && String_eq(termType, "linux")) {
|
||||
if (termType && String_eq(termType, "linux"))
|
||||
{
|
||||
CRT_scrollHAmount = 20;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
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
|
||||
#define define_key(s_, k_) define_key((char *)s_, k_)
|
||||
IGNORE_WCASTQUAL_BEGIN
|
||||
|
@ -971,7 +1009,8 @@ IGNORE_WCASTQUAL_BEGIN
|
|||
define_key("\033[17;2~", KEY_F(18));
|
||||
define_key("\033[Z", KEY_SHIFT_TAB);
|
||||
char sequence[3] = "\033a";
|
||||
for (char c = 'a'; c <= 'z'; c++) {
|
||||
for (char c = 'a'; c <= 'z'; c++)
|
||||
{
|
||||
sequence[1] = c;
|
||||
define_key(sequence, KEY_ALT('A' + (c - 'a')));
|
||||
}
|
||||
|
@ -980,7 +1019,8 @@ IGNORE_WCASTQUAL_END
|
|||
#undef define_key
|
||||
#endif
|
||||
}
|
||||
if (termType && (String_startsWith(termType, "rxvt"))) {
|
||||
if (termType && (String_startsWith(termType, "rxvt")))
|
||||
{
|
||||
define_key("\033[Z", KEY_SHIFT_TAB);
|
||||
}
|
||||
|
||||
|
@ -992,9 +1032,12 @@ IGNORE_WCASTQUAL_END
|
|||
CRT_setColors(CRT_colorScheme);
|
||||
|
||||
#ifdef HAVE_LIBNCURSESW
|
||||
if (allowUnicode && String_eq(nl_langinfo(CODESET), "UTF-8")) {
|
||||
if (allowUnicode && String_eq(nl_langinfo(CODESET), "UTF-8"))
|
||||
{
|
||||
CRT_utf8 = true;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
CRT_utf8 = false;
|
||||
}
|
||||
#else
|
||||
|
@ -1012,7 +1055,8 @@ IGNORE_WCASTQUAL_END
|
|||
CRT_degreeSign = initDegreeSign();
|
||||
}
|
||||
|
||||
void CRT_done() {
|
||||
void CRT_done()
|
||||
{
|
||||
int resetColor = CRT_colors ? CRT_colors[RESET_COLOR] : CRT_colorSchemes[COLORSCHEME_DEFAULT][RESET_COLOR];
|
||||
|
||||
attron(resetColor);
|
||||
|
@ -1026,14 +1070,16 @@ void CRT_done() {
|
|||
dumpStderr();
|
||||
}
|
||||
|
||||
void CRT_fatalError(const char* note) {
|
||||
void CRT_fatalError(const char *note)
|
||||
{
|
||||
const char *sysMsg = strerror(errno);
|
||||
CRT_done();
|
||||
fprintf(stderr, "%s: %s\n", note, sysMsg);
|
||||
exit(2);
|
||||
}
|
||||
|
||||
int CRT_readKey() {
|
||||
int CRT_readKey()
|
||||
{
|
||||
nocbreak();
|
||||
cbreak();
|
||||
nodelay(stdscr, FALSE);
|
||||
|
@ -1042,22 +1088,28 @@ int CRT_readKey() {
|
|||
return ret;
|
||||
}
|
||||
|
||||
void CRT_disableDelay() {
|
||||
void CRT_disableDelay()
|
||||
{
|
||||
nocbreak();
|
||||
cbreak();
|
||||
nodelay(stdscr, TRUE);
|
||||
}
|
||||
|
||||
void CRT_enableDelay() {
|
||||
void CRT_enableDelay()
|
||||
{
|
||||
halfdelay(*CRT_delay);
|
||||
}
|
||||
|
||||
void CRT_setColors(int colorScheme) {
|
||||
void CRT_setColors(int colorScheme)
|
||||
{
|
||||
CRT_colorScheme = colorScheme;
|
||||
|
||||
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 i = 0; i < 8; i++)
|
||||
{
|
||||
for (short int j = 0; j < 8; j++)
|
||||
{
|
||||
if (ColorIndex(i, j) != ColorIndexGrayBlack && ColorIndex(i, j) != ColorIndexWhiteDefault)
|
||||
{
|
||||
short int bg = (colorScheme != COLORSCHEME_BLACKNIGHT)
|
||||
? (j == 0 ? -1 : j)
|
||||
: j;
|
||||
|
@ -1076,7 +1128,8 @@ void CRT_setColors(int colorScheme) {
|
|||
}
|
||||
|
||||
#ifdef PRINT_BACKTRACE
|
||||
static void print_backtrace(void) {
|
||||
static void print_backtrace(void)
|
||||
{
|
||||
#if defined(HAVE_LIBUNWIND_H) && defined(HAVE_LIBUNWIND)
|
||||
unw_context_t context;
|
||||
unw_getcontext(&context);
|
||||
|
@ -1086,7 +1139,8 @@ static void print_backtrace(void) {
|
|||
|
||||
unsigned int item = 0;
|
||||
|
||||
while (unw_step(&cursor) > 0) {
|
||||
while (unw_step(&cursor) > 0)
|
||||
{
|
||||
unw_word_t pc;
|
||||
unw_get_reg(&cursor, UNW_REG_IP, &pc);
|
||||
if (pc == 0)
|
||||
|
@ -1101,7 +1155,8 @@ static void print_backtrace(void) {
|
|||
|
||||
const char *fname = "?";
|
||||
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);
|
||||
|
||||
#ifdef HAVE_DLADDR
|
||||
|
@ -1128,7 +1183,8 @@ static void print_backtrace(void) {
|
|||
}
|
||||
#endif
|
||||
|
||||
void CRT_handleSIGSEGV(int signal) {
|
||||
void CRT_handleSIGSEGV(int signal)
|
||||
{
|
||||
CRT_done();
|
||||
|
||||
fprintf(stderr, "\n\n"
|
||||
|
@ -1139,19 +1195,18 @@ void CRT_handleSIGSEGV(int signal) {
|
|||
" - Your " PACKAGE " version: '" VERSION "'\n"
|
||||
" - Your OS and kernel version (uname -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
|
||||
fprintf(stderr, " - Backtrace of the issue (see below)\n");
|
||||
#endif
|
||||
|
||||
fprintf(stderr,
|
||||
"\n"
|
||||
);
|
||||
"\n");
|
||||
|
||||
const char *signal_str = strsignal(signal);
|
||||
if (!signal_str) {
|
||||
if (!signal_str)
|
||||
{
|
||||
signal_str = "unknown reason";
|
||||
}
|
||||
fprintf(stderr,
|
||||
|
@ -1159,8 +1214,7 @@ void CRT_handleSIGSEGV(int signal) {
|
|||
"------------------\n"
|
||||
"A signal %d (%s) was received.\n"
|
||||
"\n",
|
||||
signal, signal_str
|
||||
);
|
||||
signal, signal_str);
|
||||
|
||||
fprintf(stderr,
|
||||
"Setting information:\n"
|
||||
|
@ -1171,8 +1225,7 @@ void CRT_handleSIGSEGV(int signal) {
|
|||
#ifdef PRINT_BACKTRACE
|
||||
fprintf(stderr,
|
||||
"Backtrace information:\n"
|
||||
"----------------------\n"
|
||||
);
|
||||
"----------------------\n");
|
||||
|
||||
print_backtrace();
|
||||
|
||||
|
@ -1181,8 +1234,7 @@ void CRT_handleSIGSEGV(int signal) {
|
|||
"To make the above information more practical to work with, "
|
||||
"please also provide a disassembly of your " PACKAGE " binary. "
|
||||
"This can usually be done by running the following command:\n"
|
||||
"\n"
|
||||
);
|
||||
"\n");
|
||||
|
||||
#ifdef HTOP_DARWIN
|
||||
fprintf(stderr, " otool -tvV `which " PACKAGE "` > ~/htop.otool\n");
|
||||
|
@ -1192,23 +1244,21 @@ void CRT_handleSIGSEGV(int signal) {
|
|||
|
||||
fprintf(stderr,
|
||||
"\n"
|
||||
"Please include the generated file in your report.\n"
|
||||
);
|
||||
"Please include the generated file in your report.\n");
|
||||
#endif
|
||||
|
||||
fprintf(stderr,
|
||||
"Running this program with debug symbols or inside a debugger may provide further insights.\n"
|
||||
"\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) */
|
||||
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. */
|
||||
fprintf(stderr,
|
||||
"!!! Chained handler could not be restored. Forcing exit.\n"
|
||||
);
|
||||
"!!! Chained handler could not be restored. Forcing exit.\n");
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
|
@ -1217,7 +1267,6 @@ void CRT_handleSIGSEGV(int signal) {
|
|||
|
||||
// Always terminate, even if installed handler returns
|
||||
fprintf(stderr,
|
||||
"!!! Chained handler did not exit. Forcing exit.\n"
|
||||
);
|
||||
"!!! Chained handler did not exit. Forcing exit.\n");
|
||||
_exit(1);
|
||||
}
|
||||
|
|
12
CRT.h
12
CRT.h
|
@ -15,8 +15,8 @@ in the source distribution for its full text.
|
|||
#include "ProvideCurses.h"
|
||||
#include "Settings.h"
|
||||
|
||||
|
||||
typedef enum TreeStr_ {
|
||||
typedef enum TreeStr_
|
||||
{
|
||||
TREE_STR_VERT,
|
||||
TREE_STR_RTEE,
|
||||
TREE_STR_BEND,
|
||||
|
@ -28,7 +28,8 @@ typedef enum TreeStr_ {
|
|||
LAST_TREE_STR
|
||||
} TreeStr;
|
||||
|
||||
typedef enum ColorScheme_ {
|
||||
typedef enum ColorScheme_
|
||||
{
|
||||
COLORSCHEME_DEFAULT,
|
||||
COLORSCHEME_MONOCHROME,
|
||||
COLORSCHEME_BLACKONWHITE,
|
||||
|
@ -39,7 +40,8 @@ typedef enum ColorScheme_ {
|
|||
LAST_COLORSCHEME
|
||||
} ColorScheme;
|
||||
|
||||
typedef enum ColorElements_ {
|
||||
typedef enum ColorElements_
|
||||
{
|
||||
RESET_COLOR,
|
||||
DEFAULT_COLOR,
|
||||
FUNCTION_BAR,
|
||||
|
@ -64,6 +66,8 @@ typedef enum ColorElements_ {
|
|||
METER_VALUE_WARN,
|
||||
LED_COLOR,
|
||||
UPTIME,
|
||||
TEMP,
|
||||
FREQ,
|
||||
BATTERY,
|
||||
TASKS_RUNNING,
|
||||
SWAP,
|
||||
|
|
|
@ -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: "};
|
|
@ -0,0 +1,8 @@
|
|||
#ifndef HEADER_FreqMeter
|
||||
#define HEADER_FreqMeter
|
||||
|
||||
#include "Meter.h"
|
||||
|
||||
extern const MeterClass FreqMeter_class;
|
||||
|
||||
#endif
|
|
@ -82,6 +82,8 @@ myhtopsources = \
|
|||
TasksMeter.c \
|
||||
TraceScreen.c \
|
||||
UptimeMeter.c \
|
||||
FreqMeter.c \
|
||||
TempMeter.c \
|
||||
UsersTable.c \
|
||||
Vector.c \
|
||||
XUtils.c
|
||||
|
@ -144,6 +146,8 @@ myhtopheaders = \
|
|||
TasksMeter.h \
|
||||
TraceScreen.h \
|
||||
UptimeMeter.h \
|
||||
FreqMeter.h \
|
||||
TempMeter.h \
|
||||
UsersTable.h \
|
||||
Vector.h \
|
||||
XUtils.h
|
||||
|
|
564
Settings.c
564
Settings.c
|
@ -23,6 +23,8 @@ in the source distribution for its full text.
|
|||
#include "Platform.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);
|
||||
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);
|
||||
free(this->hColumns[i].modes);
|
||||
}
|
||||
free(this->hColumns);
|
||||
if (this->screens) {
|
||||
for (unsigned int i = 0; this->screens[i]; i++) {
|
||||
if (this->screens)
|
||||
{
|
||||
for (unsigned int i = 0; this->screens[i]; i++)
|
||||
{
|
||||
ScreenSettings_delete(this->screens[i]);
|
||||
}
|
||||
free(this->screens);
|
||||
|
@ -82,7 +88,8 @@ void Settings_delete(Settings* 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 **ids = String_split(trim, ' ', NULL);
|
||||
free(trim);
|
||||
|
@ -90,30 +97,35 @@ static void Settings_readMeters(Settings* this, const char* line, unsigned int c
|
|||
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 **ids = String_split(trim, ' ', NULL);
|
||||
free(trim);
|
||||
int len = 0;
|
||||
for (int i = 0; ids[i]; i++) {
|
||||
for (int i = 0; ids[i]; i++)
|
||||
{
|
||||
len++;
|
||||
}
|
||||
column = MINIMUM(column, HeaderLayout_getColumns(this->hLayout) - 1);
|
||||
this->hColumns[column].len = len;
|
||||
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]);
|
||||
}
|
||||
String_freeArray(ids);
|
||||
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);
|
||||
|
||||
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;
|
||||
const int *modes = this->hColumns[column].modes;
|
||||
const size_t len = this->hColumns[column].len;
|
||||
|
@ -138,15 +150,18 @@ static bool Settings_validateMeters(Settings* this) {
|
|||
return anyMeter;
|
||||
}
|
||||
|
||||
static void Settings_defaultMeters(Settings* this, unsigned int initialCpuCount) {
|
||||
int sizes[] = { 3, 3 };
|
||||
static void Settings_defaultMeters(Settings *this, unsigned int initialCpuCount)
|
||||
{
|
||||
int sizes[] = {3, 5};
|
||||
|
||||
if (initialCpuCount > 4 && initialCpuCount <= 128) {
|
||||
if (initialCpuCount > 4 && initialCpuCount <= 128)
|
||||
{
|
||||
sizes[1]++;
|
||||
}
|
||||
|
||||
// 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);
|
||||
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->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].modes = xCalloc(sizes[i], sizeof(int));
|
||||
this->hColumns[i].len = sizes[i];
|
||||
|
@ -162,31 +178,42 @@ static void Settings_defaultMeters(Settings* this, unsigned int initialCpuCount)
|
|||
|
||||
int r = 0;
|
||||
|
||||
if (initialCpuCount > 128) {
|
||||
if (initialCpuCount > 128)
|
||||
{
|
||||
// Just show the average, ricers need to config for impressive screenshots
|
||||
this->hColumns[0].names[0] = xStrdup("CPU");
|
||||
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].modes[0] = BAR_METERMODE;
|
||||
this->hColumns[1].names[r] = xStrdup("RightCPUs8");
|
||||
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].modes[0] = BAR_METERMODE;
|
||||
this->hColumns[1].names[r] = xStrdup("RightCPUs4");
|
||||
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].modes[0] = BAR_METERMODE;
|
||||
this->hColumns[1].names[r] = xStrdup("RightCPUs2");
|
||||
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].modes[0] = BAR_METERMODE;
|
||||
this->hColumns[1].names[r] = xStrdup("RightCPUs");
|
||||
this->hColumns[1].modes[r++] = BAR_METERMODE;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
this->hColumns[0].names[0] = xStrdup("AllCPUs");
|
||||
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].names[r] = xStrdup("Uptime");
|
||||
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)
|
||||
return NULL;
|
||||
if (id >= LAST_PROCESSFIELD) {
|
||||
if (id >= LAST_PROCESSFIELD)
|
||||
{
|
||||
const DynamicColumn *column = DynamicColumn_lookup(columns, id);
|
||||
return column->name;
|
||||
}
|
||||
return Process_fields[id].name;
|
||||
}
|
||||
|
||||
static int toFieldIndex(Hashtable* columns, const char* str) {
|
||||
if (isdigit(str[0])) {
|
||||
static int toFieldIndex(Hashtable *columns, const char *str)
|
||||
{
|
||||
if (isdigit(str[0]))
|
||||
{
|
||||
// This "+1" is for compatibility with the older enum format.
|
||||
int id = atoi(str) + 1;
|
||||
if (toFieldName(columns, id)) {
|
||||
if (toFieldName(columns, id))
|
||||
{
|
||||
return id;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
// Dynamically-defined columns are always stored by-name.
|
||||
char dynamic[32] = {0};
|
||||
if (sscanf(str, "Dynamic(%30s)", dynamic)) {
|
||||
if (sscanf(str, "Dynamic(%30s)", dynamic))
|
||||
{
|
||||
char *end;
|
||||
if ((end = strrchr(dynamic, ')')) != NULL) {
|
||||
if ((end = strrchr(dynamic, ')')) != NULL)
|
||||
{
|
||||
bool success;
|
||||
unsigned int key;
|
||||
*end = '\0';
|
||||
|
@ -235,7 +275,8 @@ static int toFieldIndex(Hashtable* columns, const char* str) {
|
|||
}
|
||||
}
|
||||
// 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);
|
||||
if (pName && strcmp(pName, str) == 0)
|
||||
return p;
|
||||
|
@ -244,7 +285,8 @@ static int toFieldIndex(Hashtable* columns, const char* str) {
|
|||
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 **ids = String_split(trim, ' ', NULL);
|
||||
free(trim);
|
||||
|
@ -252,10 +294,12 @@ static void ScreenSettings_readFields(ScreenSettings* ss, Hashtable* columns, co
|
|||
/* reset default fields */
|
||||
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))
|
||||
continue;
|
||||
if (j >= LAST_PROCESSFIELD) {
|
||||
if (j >= LAST_PROCESSFIELD)
|
||||
{
|
||||
ss->fields = xRealloc(ss->fields, (j + 1) * 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);
|
||||
}
|
||||
|
||||
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 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;
|
||||
}
|
||||
|
||||
void ScreenSettings_delete(ScreenSettings* this) {
|
||||
void ScreenSettings_delete(ScreenSettings *this)
|
||||
{
|
||||
free(this->name);
|
||||
free(this->fields);
|
||||
free(this);
|
||||
}
|
||||
|
||||
static ScreenSettings* Settings_defaultScreens(Settings* this) {
|
||||
static ScreenSettings *Settings_defaultScreens(Settings *this)
|
||||
{
|
||||
if (this->nScreens)
|
||||
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];
|
||||
Settings_newScreen(this, defaults);
|
||||
}
|
||||
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");
|
||||
if (!fd)
|
||||
return false;
|
||||
|
@ -319,22 +368,27 @@ static bool Settings_read(Settings* this, const char* fileName, unsigned int ini
|
|||
ScreenSettings *screen = NULL;
|
||||
bool didReadMeters = false;
|
||||
bool didReadAny = false;
|
||||
for (;;) {
|
||||
for (;;)
|
||||
{
|
||||
char *line = String_readLine(fd);
|
||||
if (!line) {
|
||||
if (!line)
|
||||
{
|
||||
break;
|
||||
}
|
||||
didReadAny = true;
|
||||
size_t nOptions;
|
||||
char **option = String_split(line, '=', &nOptions);
|
||||
free(line);
|
||||
if (nOptions < 2) {
|
||||
if (nOptions < 2)
|
||||
{
|
||||
String_freeArray(option);
|
||||
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]);
|
||||
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
|
||||
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);
|
||||
|
@ -343,181 +397,367 @@ static bool Settings_read(Settings* this, const char* fileName, unsigned int ini
|
|||
fclose(fd);
|
||||
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
|
||||
screen = Settings_defaultScreens(this);
|
||||
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
|
||||
// This "+1" is for compatibility with the older enum format.
|
||||
screen = Settings_defaultScreens(this);
|
||||
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
|
||||
// This "+1" is for compatibility with the older enum format.
|
||||
screen = Settings_defaultScreens(this);
|
||||
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
|
||||
screen = Settings_defaultScreens(this);
|
||||
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
|
||||
screen = Settings_defaultScreens(this);
|
||||
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
|
||||
screen = Settings_defaultScreens(this);
|
||||
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
|
||||
screen = Settings_defaultScreens(this);
|
||||
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
|
||||
screen = Settings_defaultScreens(this);
|
||||
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]);
|
||||
} else if (String_eq(option[0], "hide_userland_threads")) {
|
||||
}
|
||||
else if (String_eq(option[0], "hide_userland_threads"))
|
||||
{
|
||||
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]);
|
||||
} else if (String_eq(option[0], "show_thread_names")) {
|
||||
}
|
||||
else if (String_eq(option[0], "show_thread_names"))
|
||||
{
|
||||
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]);
|
||||
} else if (String_eq(option[0], "highlight_base_name")) {
|
||||
}
|
||||
else if (String_eq(option[0], "highlight_base_name"))
|
||||
{
|
||||
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]);
|
||||
} else if (String_eq(option[0], "highlight_megabytes")) {
|
||||
}
|
||||
else if (String_eq(option[0], "highlight_megabytes"))
|
||||
{
|
||||
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]);
|
||||
} else if (String_eq(option[0], "highlight_changes")) {
|
||||
}
|
||||
else if (String_eq(option[0], "highlight_changes"))
|
||||
{
|
||||
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);
|
||||
} 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]);
|
||||
} 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]);
|
||||
} else if (String_eq(option[0], "show_merged_command")) {
|
||||
}
|
||||
else if (String_eq(option[0], "show_merged_command"))
|
||||
{
|
||||
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]);
|
||||
} else if (String_eq(option[0], "screen_tabs")) {
|
||||
}
|
||||
else if (String_eq(option[0], "screen_tabs"))
|
||||
{
|
||||
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.
|
||||
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]);
|
||||
} 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]);
|
||||
} 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
|
||||
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]);
|
||||
} else if (String_eq(option[0], "show_cpu_frequency")) {
|
||||
}
|
||||
else if (String_eq(option[0], "show_cpu_frequency"))
|
||||
{
|
||||
this->showCPUFrequency = atoi(option[1]);
|
||||
#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]);
|
||||
} else if (String_eq(option[0], "degree_fahrenheit")) {
|
||||
}
|
||||
else if (String_eq(option[0], "degree_fahrenheit"))
|
||||
{
|
||||
this->degreeFahrenheit = atoi(option[1]);
|
||||
#endif
|
||||
} else if (String_eq(option[0], "update_process_names")) {
|
||||
}
|
||||
else if (String_eq(option[0], "update_process_names"))
|
||||
{
|
||||
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]);
|
||||
} else if (String_eq(option[0], "delay")) {
|
||||
}
|
||||
else if (String_eq(option[0], "delay"))
|
||||
{
|
||||
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]);
|
||||
if (this->colorScheme < 0 || this->colorScheme >= LAST_COLORSCHEME) {
|
||||
if (this->colorScheme < 0 || this->colorScheme >= LAST_COLORSCHEME)
|
||||
{
|
||||
this->colorScheme = 0;
|
||||
}
|
||||
#ifdef HAVE_GETMOUSE
|
||||
} else if (String_eq(option[0], "enable_mouse")) {
|
||||
}
|
||||
else if (String_eq(option[0], "enable_mouse"))
|
||||
{
|
||||
this->enableMouse = atoi(option[1]);
|
||||
#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]);
|
||||
if (this->hLayout < 0 || this->hLayout >= LAST_HEADER_LAYOUT)
|
||||
this->hLayout = HF_TWO_50_50;
|
||||
free(this->hColumns);
|
||||
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);
|
||||
didReadMeters = true;
|
||||
} else if (String_eq(option[0], "right_meters")) {
|
||||
}
|
||||
else if (String_eq(option[0], "right_meters"))
|
||||
{
|
||||
Settings_readMeters(this, option[1], 1);
|
||||
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);
|
||||
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);
|
||||
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_")));
|
||||
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_")));
|
||||
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]);
|
||||
#ifdef HAVE_LIBHWLOC
|
||||
} else if (String_eq(option[0], "topology_affinity")) {
|
||||
}
|
||||
else if (String_eq(option[0], "topology_affinity"))
|
||||
{
|
||||
this->topologyAffinity = !!atoi(option[1]);
|
||||
#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]});
|
||||
} else if (String_eq(option[0], ".sort_key")) {
|
||||
}
|
||||
else if (String_eq(option[0], ".sort_key"))
|
||||
{
|
||||
if (screen)
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
screen->treeDirection = atoi(option[1]);
|
||||
} else if (String_eq(option[0], ".tree_view")) {
|
||||
}
|
||||
else if (String_eq(option[0], ".tree_view"))
|
||||
{
|
||||
if (screen)
|
||||
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)
|
||||
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)
|
||||
screen->allBranchesCollapsed = atoi(option[1]);
|
||||
}
|
||||
String_freeArray(option);
|
||||
}
|
||||
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);
|
||||
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 = "";
|
||||
for (unsigned int i = 0; fields[i]; i++) {
|
||||
if (fields[i] < LAST_PROCESSFIELD && byName) {
|
||||
for (unsigned int i = 0; fields[i]; i++)
|
||||
{
|
||||
if (fields[i] < LAST_PROCESSFIELD && byName)
|
||||
{
|
||||
const char *pName = toFieldName(columns, fields[i]);
|
||||
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]);
|
||||
fprintf(fd, " Dynamic(%s)", pName);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
// This "-1" is for compatibility with the older enum format.
|
||||
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);
|
||||
}
|
||||
|
||||
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 = "";
|
||||
for (int i = 0; i < len; i++) {
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
fprintf(fd, "%s%s", sep, list[i]);
|
||||
sep = " ";
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
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 = "";
|
||||
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]);
|
||||
sep = " ";
|
||||
}
|
||||
fputc(separator, fd);
|
||||
}
|
||||
|
||||
int Settings_write(const Settings* this, bool onCrash) {
|
||||
int Settings_write(const Settings *this, bool onCrash)
|
||||
{
|
||||
FILE *fd;
|
||||
char separator;
|
||||
if (onCrash) {
|
||||
if (onCrash)
|
||||
{
|
||||
fd = stderr;
|
||||
separator = ';';
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
fd = fopen(this->filename, "w");
|
||||
if (fd == NULL)
|
||||
return -errno;
|
||||
|
@ -566,13 +815,15 @@ int Settings_write(const Settings* this, bool onCrash) {
|
|||
#define printSettingString(setting_, value_) \
|
||||
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, "# The parser is also very primitive, and not human-friendly.\n");
|
||||
}
|
||||
printSettingString("htop_version", 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_userland_threads", this->hideUserlandThreads);
|
||||
printSettingInteger("shadow_other_users", this->shadowOtherUsers);
|
||||
|
@ -610,7 +861,8 @@ int Settings_write(const Settings* this, bool onCrash) {
|
|||
#endif
|
||||
|
||||
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);
|
||||
writeMeters(this, fd, separator, 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("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];
|
||||
fprintf(fd, "screen:%s=", ss->name);
|
||||
writeFields(fd, ss->fields, this->dynamicColumns, true, separator);
|
||||
|
@ -657,7 +910,8 @@ int Settings_write(const Settings* this, bool onCrash) {
|
|||
return r;
|
||||
}
|
||||
|
||||
Settings* Settings_new(unsigned int initialCpuCount, Hashtable* dynamicColumns) {
|
||||
Settings *Settings_new(unsigned int initialCpuCount, Hashtable *dynamicColumns)
|
||||
{
|
||||
Settings *this = xCalloc(1, sizeof(Settings));
|
||||
|
||||
this->dynamicColumns = dynamicColumns;
|
||||
|
@ -698,9 +952,12 @@ Settings* Settings_new(unsigned int initialCpuCount, Hashtable* dynamicColumns)
|
|||
|
||||
char *legacyDotfile = NULL;
|
||||
const char *rcfile = getenv("HTOPRC");
|
||||
if (rcfile) {
|
||||
if (rcfile)
|
||||
{
|
||||
this->filename = xStrdup(rcfile);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
const char *home = getenv("HOME");
|
||||
if (!home)
|
||||
home = "";
|
||||
|
@ -708,11 +965,14 @@ Settings* Settings_new(unsigned int initialCpuCount, Hashtable* dynamicColumns)
|
|||
const char *xdgConfigHome = getenv("XDG_CONFIG_HOME");
|
||||
char *configDir = NULL;
|
||||
char *htopDir = NULL;
|
||||
if (xdgConfigHome) {
|
||||
if (xdgConfigHome)
|
||||
{
|
||||
this->filename = String_cat(xdgConfigHome, "/htop/htoprc");
|
||||
configDir = xStrdup(xdgConfigHome);
|
||||
htopDir = String_cat(xdgConfigHome, "/htop");
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
this->filename = String_cat(home, "/.config/htop/htoprc");
|
||||
configDir = String_cat(home, "/.config");
|
||||
htopDir = String_cat(home, "/.config/htop");
|
||||
|
@ -724,7 +984,8 @@ Settings* Settings_new(unsigned int initialCpuCount, Hashtable* dynamicColumns)
|
|||
free(configDir);
|
||||
struct stat st;
|
||||
int err = lstat(legacyDotfile, &st);
|
||||
if (err || S_ISLNK(st.st_mode)) {
|
||||
if (err || S_ISLNK(st.st_mode))
|
||||
{
|
||||
free(legacyDotfile);
|
||||
legacyDotfile = NULL;
|
||||
}
|
||||
|
@ -736,25 +997,31 @@ Settings* Settings_new(unsigned int initialCpuCount, Hashtable* dynamicColumns)
|
|||
this->changed = false;
|
||||
this->delay = DEFAULT_DELAY;
|
||||
bool ok = false;
|
||||
if (legacyDotfile) {
|
||||
if (legacyDotfile)
|
||||
{
|
||||
ok = Settings_read(this, legacyDotfile, initialCpuCount);
|
||||
if (ok) {
|
||||
if (ok)
|
||||
{
|
||||
// Transition to new location and delete old configuration file
|
||||
if (Settings_write(this, false) == 0) {
|
||||
if (Settings_write(this, false) == 0)
|
||||
{
|
||||
unlink(legacyDotfile);
|
||||
}
|
||||
}
|
||||
free(legacyDotfile);
|
||||
}
|
||||
if (!ok) {
|
||||
if (!ok)
|
||||
{
|
||||
ok = Settings_read(this, this->filename, initialCpuCount);
|
||||
}
|
||||
if (!ok) {
|
||||
if (!ok)
|
||||
{
|
||||
this->screenTabs = true;
|
||||
this->changed = true;
|
||||
ok = Settings_read(this, SYSCONFDIR "/htoprc", initialCpuCount);
|
||||
}
|
||||
if (!ok) {
|
||||
if (!ok)
|
||||
{
|
||||
Settings_defaultMeters(this, initialCpuCount);
|
||||
Settings_defaultScreens(this);
|
||||
}
|
||||
|
@ -767,17 +1034,22 @@ Settings* Settings_new(unsigned int initialCpuCount, Hashtable* dynamicColumns)
|
|||
return this;
|
||||
}
|
||||
|
||||
void ScreenSettings_invertSortOrder(ScreenSettings* this) {
|
||||
void ScreenSettings_invertSortOrder(ScreenSettings *this)
|
||||
{
|
||||
int *attr = (this->treeView) ? &(this->treeDirection) : &(this->direction);
|
||||
*attr = (*attr == 1) ? -1 : 1;
|
||||
}
|
||||
|
||||
void ScreenSettings_setSortKey(ScreenSettings* this, ProcessField sortKey) {
|
||||
if (this->treeViewAlwaysByPID || !this->treeView) {
|
||||
void ScreenSettings_setSortKey(ScreenSettings *this, ProcessField sortKey)
|
||||
{
|
||||
if (this->treeViewAlwaysByPID || !this->treeView)
|
||||
{
|
||||
this->sortKey = sortKey;
|
||||
this->direction = (Process_fields[sortKey].defaultSortDesc) ? -1 : 1;
|
||||
this->treeView = false;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
this->treeSortKey = sortKey;
|
||||
this->treeDirection = (Process_fields[sortKey].defaultSortDesc) ? -1 : 1;
|
||||
}
|
||||
|
@ -785,24 +1057,32 @@ void ScreenSettings_setSortKey(ScreenSettings* this, ProcessField sortKey) {
|
|||
|
||||
static bool readonly = false;
|
||||
|
||||
void Settings_enableReadonly(void) {
|
||||
void Settings_enableReadonly(void)
|
||||
{
|
||||
readonly = true;
|
||||
}
|
||||
|
||||
bool Settings_isReadonly(void) {
|
||||
bool Settings_isReadonly(void)
|
||||
{
|
||||
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 newColumns = HeaderLayout_getColumns(hLayout);
|
||||
|
||||
if (newColumns > oldColumns) {
|
||||
if (newColumns > oldColumns)
|
||||
{
|
||||
this->hColumns = xReallocArray(this->hColumns, newColumns, sizeof(MeterColumnSetting));
|
||||
memset(this->hColumns + oldColumns, 0, (newColumns - oldColumns) * sizeof(MeterColumnSetting));
|
||||
} else if (newColumns < oldColumns) {
|
||||
for (unsigned int i = newColumns; i < oldColumns; i++) {
|
||||
if (this->hColumns[i].names) {
|
||||
}
|
||||
else if (newColumns < oldColumns)
|
||||
{
|
||||
for (unsigned int i = newColumns; i < oldColumns; i++)
|
||||
{
|
||||
if (this->hColumns[i].names)
|
||||
{
|
||||
for (size_t j = 0; j < this->hColumns[i].len; j++)
|
||||
free(this->hColumns[i].names[j]);
|
||||
free(this->hColumns[i].names);
|
||||
|
|
|
@ -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: "};
|
|
@ -0,0 +1,8 @@
|
|||
#ifndef HEADER_TempMeter
|
||||
#define HEADER_TempMeter
|
||||
|
||||
#include "Meter.h"
|
||||
|
||||
extern const MeterClass TempMeter_class;
|
||||
|
||||
#endif
|
7
XUtils.h
7
XUtils.h
|
@ -17,7 +17,6 @@ in the source distribution for its full text.
|
|||
#include "Compat.h"
|
||||
#include "Macros.h"
|
||||
|
||||
|
||||
void fail(void) ATTR_NORETURN;
|
||||
|
||||
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
|
||||
* 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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
372
linux/Platform.c
372
linux/Platform.c
|
@ -49,6 +49,8 @@ in the source distribution for its full text.
|
|||
#include "SysArchMeter.h"
|
||||
#include "TasksMeter.h"
|
||||
#include "UptimeMeter.h"
|
||||
#include "FreqMeter.h"
|
||||
#include "TempMeter.h"
|
||||
#include "XUtils.h"
|
||||
#include "linux/IOPriority.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
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef HAVE_LIBCAP
|
||||
enum CapMode {
|
||||
enum CapMode
|
||||
{
|
||||
CAP_MODE_OFF,
|
||||
CAP_MODE_BASIC,
|
||||
CAP_MODE_STRICT
|
||||
|
@ -139,7 +141,9 @@ const SignalItem 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 double Platform_Battery_cachePercent = NAN;
|
||||
static ACPresence Platform_Battery_cacheIsOnAC;
|
||||
|
@ -148,7 +152,8 @@ static ACPresence Platform_Battery_cacheIsOnAC;
|
|||
static enum CapMode Platform_capabilitiesMode = CAP_MODE_BASIC;
|
||||
#endif
|
||||
|
||||
static Htop_Reaction Platform_actionSetIOPriority(State* st) {
|
||||
static Htop_Reaction Platform_actionSetIOPriority(State *st)
|
||||
{
|
||||
if (Settings_isReadonly())
|
||||
return HTOP_OK;
|
||||
|
||||
|
@ -159,10 +164,12 @@ static Htop_Reaction Platform_actionSetIOPriority(State* st) {
|
|||
IOPriority ioprio1 = p->ioPriority;
|
||||
Panel *ioprioPanel = IOPriorityPanel_new(ioprio1);
|
||||
const void *set = Action_pickFromVector(st, ioprioPanel, 20, true);
|
||||
if (set) {
|
||||
if (set)
|
||||
{
|
||||
IOPriority ioprio2 = IOPriorityPanel_getIOPriority(ioprioPanel);
|
||||
bool ok = MainPanel_foreachProcess(st->mainPanel, LinuxProcess_setIOPriority, (Arg){.i = ioprio2}, NULL);
|
||||
if (!ok) {
|
||||
if (!ok)
|
||||
{
|
||||
beep();
|
||||
}
|
||||
}
|
||||
|
@ -170,8 +177,10 @@ static Htop_Reaction Platform_actionSetIOPriority(State* st) {
|
|||
return HTOP_REFRESH | HTOP_REDRAW_BAR | HTOP_UPDATE_PANELHDR;
|
||||
}
|
||||
|
||||
static bool Platform_changeAutogroupPriority(MainPanel* panel, int delta) {
|
||||
if (LinuxProcess_isAutogroupEnabled() == false) {
|
||||
static bool Platform_changeAutogroupPriority(MainPanel *panel, int delta)
|
||||
{
|
||||
if (LinuxProcess_isAutogroupEnabled() == false)
|
||||
{
|
||||
beep();
|
||||
return false;
|
||||
}
|
||||
|
@ -182,7 +191,8 @@ static bool Platform_changeAutogroupPriority(MainPanel* panel, int delta) {
|
|||
return anyTagged;
|
||||
}
|
||||
|
||||
static Htop_Reaction Platform_actionHigherAutogroupPriority(State* st) {
|
||||
static Htop_Reaction Platform_actionHigherAutogroupPriority(State *st)
|
||||
{
|
||||
if (Settings_isReadonly())
|
||||
return HTOP_OK;
|
||||
|
||||
|
@ -190,7 +200,8 @@ static Htop_Reaction Platform_actionHigherAutogroupPriority(State* st) {
|
|||
return changed ? HTOP_REFRESH : HTOP_OK;
|
||||
}
|
||||
|
||||
static Htop_Reaction Platform_actionLowerAutogroupPriority(State* st) {
|
||||
static Htop_Reaction Platform_actionLowerAutogroupPriority(State *st)
|
||||
{
|
||||
if (Settings_isReadonly())
|
||||
return HTOP_OK;
|
||||
|
||||
|
@ -198,7 +209,8 @@ static Htop_Reaction Platform_actionLowerAutogroupPriority(State* st) {
|
|||
return changed ? HTOP_REFRESH : HTOP_OK;
|
||||
}
|
||||
|
||||
void Platform_setBindings(Htop_Action* keys) {
|
||||
void Platform_setBindings(Htop_Action *keys)
|
||||
{
|
||||
keys['i'] = Platform_actionSetIOPriority;
|
||||
keys['{'] = Platform_actionLowerAutogroupPriority;
|
||||
keys['}'] = Platform_actionHigherAutogroupPriority;
|
||||
|
@ -220,6 +232,8 @@ const MeterClass* const Platform_meterTypes[] = {
|
|||
&HugePageMeter_class,
|
||||
&TasksMeter_class,
|
||||
&UptimeMeter_class,
|
||||
&FreqMeter_class,
|
||||
&TempMeter_class,
|
||||
&BatteryMeter_class,
|
||||
&HostnameMeter_class,
|
||||
&AllCPUsMeter_class,
|
||||
|
@ -247,23 +261,78 @@ const MeterClass* const Platform_meterTypes[] = {
|
|||
&NetworkIOMeter_class,
|
||||
&SELinuxMeter_class,
|
||||
&SystemdMeter_class,
|
||||
NULL
|
||||
};
|
||||
NULL};
|
||||
|
||||
int Platform_getUptime() {
|
||||
int Platform_getUptime()
|
||||
{
|
||||
double uptime = 0;
|
||||
FILE *fd = fopen(PROCDIR "/uptime", "r");
|
||||
if (fd) {
|
||||
if (fd)
|
||||
{
|
||||
int n = fscanf(fd, "%64lf", &uptime);
|
||||
fclose(fd);
|
||||
if (n <= 0) {
|
||||
if (n <= 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
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");
|
||||
if (!fd)
|
||||
goto err;
|
||||
|
@ -285,7 +354,8 @@ err:
|
|||
*fifteen = NAN;
|
||||
}
|
||||
|
||||
int Platform_getMaxPid() {
|
||||
int Platform_getMaxPid()
|
||||
{
|
||||
FILE *file = fopen(PROCDIR "/sys/kernel/pid_max", "r");
|
||||
if (!file)
|
||||
return -1;
|
||||
|
@ -297,21 +367,24 @@ int Platform_getMaxPid() {
|
|||
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 CPUData *cpuData = &(pl->cpuData[cpu]);
|
||||
double total = (double)(cpuData->totalPeriod == 0 ? 1 : cpuData->totalPeriod);
|
||||
double percent;
|
||||
double *v = this->values;
|
||||
|
||||
if (!cpuData->online) {
|
||||
if (!cpuData->online)
|
||||
{
|
||||
this->curItems = 0;
|
||||
return NAN;
|
||||
}
|
||||
|
||||
v[CPU_METER_NICE] = cpuData->nicePeriod / 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_IRQ] = cpuData->irqPeriod / 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_IOWAIT] = cpuData->ioWaitPeriod / total * 100.0;
|
||||
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];
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
percent = v[0] + v[1] + v[2] + v[3] + v[4];
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
v[2] = cpuData->systemAllPeriod / total * 100.0;
|
||||
v[3] = (cpuData->stealPeriod + cpuData->guestPeriod) / total * 100.0;
|
||||
this->curItems = 4;
|
||||
percent = v[0] + v[1] + v[2] + v[3];
|
||||
}
|
||||
percent = CLAMP(percent, 0.0, 100.0);
|
||||
if (isnan(percent)) {
|
||||
if (isnan(percent))
|
||||
{
|
||||
percent = 0.0;
|
||||
}
|
||||
|
||||
|
@ -346,7 +425,8 @@ double Platform_setCPUValues(Meter* this, unsigned int cpu) {
|
|||
return percent;
|
||||
}
|
||||
|
||||
void Platform_setMemoryValues(Meter* this) {
|
||||
void Platform_setMemoryValues(Meter *this)
|
||||
{
|
||||
const ProcessList *pl = this->pl;
|
||||
const LinuxProcessList *lpl = (const LinuxProcessList *)pl;
|
||||
|
||||
|
@ -357,7 +437,8 @@ void Platform_setMemoryValues(Meter* this) {
|
|||
this->values[3] = pl->cachedMem;
|
||||
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.
|
||||
unsigned long long int shrinkableSize = 0;
|
||||
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;
|
||||
this->total = pl->totalSwap;
|
||||
this->values[0] = pl->usedSwap;
|
||||
this->values[1] = pl->cachedSwap;
|
||||
}
|
||||
|
||||
void Platform_setZramValues(Meter* this) {
|
||||
void Platform_setZramValues(Meter *this)
|
||||
{
|
||||
const LinuxProcessList *lpl = (const LinuxProcessList *)this->pl;
|
||||
this->total = lpl->zram.totalZram;
|
||||
this->values[0] = lpl->zram.usedZramComp;
|
||||
this->values[1] = lpl->zram.usedZramOrig;
|
||||
}
|
||||
|
||||
void Platform_setZfsArcValues(Meter* this) {
|
||||
void Platform_setZfsArcValues(Meter *this)
|
||||
{
|
||||
const LinuxProcessList *lpl = (const LinuxProcessList *)this->pl;
|
||||
|
||||
ZfsArcMeter_readStats(this, &(lpl->zfs));
|
||||
}
|
||||
|
||||
void Platform_setZfsCompressedArcValues(Meter* this) {
|
||||
void Platform_setZfsCompressedArcValues(Meter *this)
|
||||
{
|
||||
const LinuxProcessList *lpl = (const LinuxProcessList *)this->pl;
|
||||
|
||||
ZfsCompressedArcMeter_readStats(this, &(lpl->zfs));
|
||||
}
|
||||
|
||||
char* Platform_getProcessEnv(pid_t pid) {
|
||||
char *Platform_getProcessEnv(pid_t pid)
|
||||
{
|
||||
char procname[128];
|
||||
xSnprintf(procname, sizeof(procname), PROCDIR "/%d/environ", pid);
|
||||
FILE *fd = fopen(procname, "r");
|
||||
|
@ -407,7 +493,8 @@ char* Platform_getProcessEnv(pid_t pid) {
|
|||
size_t size = 0;
|
||||
ssize_t bytes = 0;
|
||||
|
||||
do {
|
||||
do
|
||||
{
|
||||
size += bytes;
|
||||
capacity += 4096;
|
||||
env = xRealloc(env, capacity);
|
||||
|
@ -415,7 +502,8 @@ char* Platform_getProcessEnv(pid_t pid) {
|
|||
|
||||
fclose(fd);
|
||||
|
||||
if (bytes < 0) {
|
||||
if (bytes < 0)
|
||||
{
|
||||
free(env);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -436,7 +524,8 @@ char* Platform_getProcessEnv(pid_t pid) {
|
|||
* Based on implementation of lslocks from util-linux:
|
||||
* 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;
|
||||
const struct dirent *de;
|
||||
DIR *dirp;
|
||||
|
@ -460,7 +549,8 @@ char* Platform_getInodeFilename(pid_t pid, ino_t inode) {
|
|||
if ((fd = dirfd(dirp)) < 0)
|
||||
goto out;
|
||||
|
||||
while ((de = readdir(dirp))) {
|
||||
while ((de = readdir(dirp)))
|
||||
{
|
||||
if (String_eq(de->d_name, ".") || String_eq(de->d_name, ".."))
|
||||
continue;
|
||||
|
||||
|
@ -485,18 +575,21 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
FileLocks_ProcessData* Platform_getProcessLocks(pid_t pid) {
|
||||
FileLocks_ProcessData *Platform_getProcessLocks(pid_t pid)
|
||||
{
|
||||
FileLocks_ProcessData *pdata = xCalloc(1, sizeof(FileLocks_ProcessData));
|
||||
|
||||
FILE *f = fopen(PROCDIR "/locks", "r");
|
||||
if (!f) {
|
||||
if (!f)
|
||||
{
|
||||
pdata->error = true;
|
||||
return pdata;
|
||||
}
|
||||
|
||||
char buffer[1024];
|
||||
FileLocks_LockData **data_ref = &pdata->locks;
|
||||
while(fgets(buffer, sizeof(buffer), f)) {
|
||||
while (fgets(buffer, sizeof(buffer), f))
|
||||
{
|
||||
if (!strchr(buffer, '\n'))
|
||||
continue;
|
||||
|
||||
|
@ -530,9 +623,12 @@ FileLocks_ProcessData* Platform_getProcessLocks(pid_t pid) {
|
|||
data->dev[1] = lock_dev[1];
|
||||
data->inode = lock_inode;
|
||||
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);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
data->end = ULLONG_MAX;
|
||||
}
|
||||
|
||||
|
@ -544,17 +640,20 @@ FileLocks_ProcessData* Platform_getProcessLocks(pid_t pid) {
|
|||
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;
|
||||
char procname[128];
|
||||
xSnprintf(procname, sizeof(procname), PROCDIR "/pressure/%s", file);
|
||||
FILE *fd = fopen(procname, "r");
|
||||
if (!fd) {
|
||||
if (!fd)
|
||||
{
|
||||
*ten = *sixty = *threehundred = NAN;
|
||||
return;
|
||||
}
|
||||
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);
|
||||
}
|
||||
(void)total;
|
||||
|
@ -562,7 +661,8 @@ void Platform_getPressureStall(const char* file, bool some, double* ten, double*
|
|||
fclose(fd);
|
||||
}
|
||||
|
||||
bool Platform_getDiskIO(DiskIOData* data) {
|
||||
bool Platform_getDiskIO(DiskIOData *data)
|
||||
{
|
||||
FILE *fd = fopen(PROCDIR "/diskstats", "r");
|
||||
if (!fd)
|
||||
return false;
|
||||
|
@ -571,10 +671,12 @@ bool Platform_getDiskIO(DiskIOData* data) {
|
|||
|
||||
unsigned long long int read_sum = 0, write_sum = 0, timeSpend_sum = 0;
|
||||
char lineBuffer[256];
|
||||
while (fgets(lineBuffer, sizeof(lineBuffer), fd)) {
|
||||
while (fgets(lineBuffer, sizeof(lineBuffer), fd))
|
||||
{
|
||||
char diskname[32];
|
||||
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-"))
|
||||
continue;
|
||||
|
||||
|
@ -601,14 +703,16 @@ bool Platform_getDiskIO(DiskIOData* data) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool Platform_getNetworkIO(NetworkIOData* data) {
|
||||
bool Platform_getNetworkIO(NetworkIOData *data)
|
||||
{
|
||||
FILE *fd = fopen(PROCDIR "/net/dev", "r");
|
||||
if (!fd)
|
||||
return false;
|
||||
|
||||
memset(data, 0, sizeof(NetworkIOData));
|
||||
char lineBuffer[512];
|
||||
while (fgets(lineBuffer, sizeof(lineBuffer), fd)) {
|
||||
while (fgets(lineBuffer, sizeof(lineBuffer), fd))
|
||||
{
|
||||
char interfaceName[32];
|
||||
unsigned long long int bytesReceived, packetsReceived, bytesTransmitted, packetsTransmitted;
|
||||
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
|
||||
// ----------------------------------------
|
||||
|
||||
static double Platform_Battery_getProcBatInfo(void) {
|
||||
static double Platform_Battery_getProcBatInfo(void)
|
||||
{
|
||||
DIR *batteryDir = opendir(PROC_BATTERY_DIR);
|
||||
if (!batteryDir)
|
||||
return NAN;
|
||||
|
@ -653,7 +758,8 @@ static double Platform_Battery_getProcBatInfo(void) {
|
|||
uint64_t totalRemain = 0;
|
||||
|
||||
struct dirent *dirEntry = NULL;
|
||||
while ((dirEntry = readdir(batteryDir))) {
|
||||
while ((dirEntry = readdir(batteryDir)))
|
||||
{
|
||||
const char *entryName = dirEntry->d_name;
|
||||
if (!String_startsWith(entryName, "BAT"))
|
||||
continue;
|
||||
|
@ -675,13 +781,15 @@ static double Platform_Battery_getProcBatInfo(void) {
|
|||
|
||||
// Getting total charge for all batteries
|
||||
char *buf = bufInfo;
|
||||
while ((line = strsep(&buf, "\n")) != NULL) {
|
||||
while ((line = strsep(&buf, "\n")) != NULL)
|
||||
{
|
||||
char field[100] = {0};
|
||||
int val = 0;
|
||||
if (2 != sscanf(line, "%99[^:]:%d", field, &val))
|
||||
continue;
|
||||
|
||||
if (String_eq(field, "last full capacity")) {
|
||||
if (String_eq(field, "last full capacity"))
|
||||
{
|
||||
totalFull += val;
|
||||
break;
|
||||
}
|
||||
|
@ -689,13 +797,15 @@ static double Platform_Battery_getProcBatInfo(void) {
|
|||
|
||||
// Getting remaining charge for all batteries
|
||||
buf = bufState;
|
||||
while ((line = strsep(&buf, "\n")) != NULL) {
|
||||
while ((line = strsep(&buf, "\n")) != NULL)
|
||||
{
|
||||
char field[100] = {0};
|
||||
int val = 0;
|
||||
if (2 != sscanf(line, "%99[^:]:%d", field, &val))
|
||||
continue;
|
||||
|
||||
if (String_eq(field, "remaining capacity")) {
|
||||
if (String_eq(field, "remaining capacity"))
|
||||
{
|
||||
totalRemain += val;
|
||||
break;
|
||||
}
|
||||
|
@ -707,7 +817,8 @@ static double Platform_Battery_getProcBatInfo(void) {
|
|||
return totalFull > 0 ? ((double)totalRemain * 100.0) / (double)totalFull : NAN;
|
||||
}
|
||||
|
||||
static ACPresence procAcpiCheck(void) {
|
||||
static ACPresence procAcpiCheck(void)
|
||||
{
|
||||
char buffer[1024] = {0};
|
||||
ssize_t r = xReadfile(PROC_POWERSUPPLY_ACSTATE_FILE, buffer, sizeof(buffer));
|
||||
if (r < 1)
|
||||
|
@ -716,7 +827,8 @@ static ACPresence procAcpiCheck(void) {
|
|||
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();
|
||||
*percent = AC_ERROR != *isOnAC ? Platform_Battery_getProcBatInfo() : NAN;
|
||||
}
|
||||
|
@ -725,7 +837,8 @@ static void Platform_Battery_getProcData(double* percent, ACPresence* isOnAC) {
|
|||
// READ FROM /sys
|
||||
// ----------------------------------------
|
||||
|
||||
static void Platform_Battery_getSysData(double* percent, ACPresence* isOnAC) {
|
||||
static void Platform_Battery_getSysData(double *percent, ACPresence *isOnAC)
|
||||
{
|
||||
*percent = NAN;
|
||||
*isOnAC = AC_ERROR;
|
||||
|
||||
|
@ -737,7 +850,8 @@ static void Platform_Battery_getSysData(double* percent, ACPresence* isOnAC) {
|
|||
uint64_t totalRemain = 0;
|
||||
|
||||
const struct dirent *dirEntry;
|
||||
while ((dirEntry = readdir(dir))) {
|
||||
while ((dirEntry = readdir(dir)))
|
||||
{
|
||||
const char *entryName = dirEntry->d_name;
|
||||
|
||||
#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);
|
||||
#endif
|
||||
|
||||
enum { AC, BAT } type;
|
||||
if (String_startsWith(entryName, "BAT")) {
|
||||
enum
|
||||
{
|
||||
AC,
|
||||
BAT
|
||||
} type;
|
||||
if (String_startsWith(entryName, "BAT"))
|
||||
{
|
||||
type = BAT;
|
||||
} else if (String_startsWith(entryName, "AC")) {
|
||||
}
|
||||
else if (String_startsWith(entryName, "AC"))
|
||||
{
|
||||
type = AC;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
char buffer[32];
|
||||
ssize_t ret = xReadfileat(entryFd, "type", buffer, sizeof(buffer));
|
||||
if (ret <= 0)
|
||||
|
@ -772,7 +895,8 @@ static void Platform_Battery_getSysData(double* percent, ACPresence* isOnAC) {
|
|||
goto next;
|
||||
}
|
||||
|
||||
if (type == BAT) {
|
||||
if (type == BAT)
|
||||
{
|
||||
char buffer[1024];
|
||||
ssize_t r = xReadfileat(entryFd, "uevent", buffer, sizeof(buffer));
|
||||
if (r < 0)
|
||||
|
@ -786,18 +910,21 @@ static void Platform_Battery_getSysData(double* percent, ACPresence* isOnAC) {
|
|||
const char *line;
|
||||
|
||||
char *buf = buffer;
|
||||
while ((line = strsep(&buf, "\n")) != NULL) {
|
||||
while ((line = strsep(&buf, "\n")) != NULL)
|
||||
{
|
||||
char field[100] = {0};
|
||||
int val = 0;
|
||||
if (2 != sscanf(line, "POWER_SUPPLY_%99[^=]=%d", field, &val))
|
||||
continue;
|
||||
|
||||
if (String_eq(field, "CAPACITY")) {
|
||||
if (String_eq(field, "CAPACITY"))
|
||||
{
|
||||
capacityLevel = val / 100.0;
|
||||
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;
|
||||
totalFull += fullCharge;
|
||||
full = true;
|
||||
|
@ -806,7 +933,8 @@ static void Platform_Battery_getSysData(double* percent, ACPresence* isOnAC) {
|
|||
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;
|
||||
now = true;
|
||||
if (full)
|
||||
|
@ -817,14 +945,16 @@ static void Platform_Battery_getSysData(double* percent, ACPresence* isOnAC) {
|
|||
|
||||
if (!now && full && !isnan(capacityLevel))
|
||||
totalRemain += capacityLevel * fullCharge;
|
||||
|
||||
} else if (type == AC) {
|
||||
}
|
||||
else if (type == AC)
|
||||
{
|
||||
if (*isOnAC != AC_ERROR)
|
||||
goto next;
|
||||
|
||||
char buffer[2];
|
||||
ssize_t r = xReadfileat(entryFd, "online", buffer, sizeof(buffer));
|
||||
if (r < 1) {
|
||||
if (r < 1)
|
||||
{
|
||||
*isOnAC = AC_ERROR;
|
||||
goto next;
|
||||
}
|
||||
|
@ -844,29 +974,36 @@ next:
|
|||
*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);
|
||||
// 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;
|
||||
*isOnAC = Platform_Battery_cacheIsOnAC;
|
||||
return;
|
||||
}
|
||||
|
||||
if (Platform_Battery_method == BAT_PROC) {
|
||||
if (Platform_Battery_method == BAT_PROC)
|
||||
{
|
||||
Platform_Battery_getProcData(percent, isOnAC);
|
||||
if (isnan(*percent))
|
||||
Platform_Battery_method = BAT_SYS;
|
||||
}
|
||||
if (Platform_Battery_method == BAT_SYS) {
|
||||
if (Platform_Battery_method == BAT_SYS)
|
||||
{
|
||||
Platform_Battery_getSysData(percent, isOnAC);
|
||||
if (isnan(*percent))
|
||||
Platform_Battery_method = BAT_ERR;
|
||||
}
|
||||
if (Platform_Battery_method == BAT_ERR) {
|
||||
if (Platform_Battery_method == BAT_ERR)
|
||||
{
|
||||
*percent = NAN;
|
||||
*isOnAC = AC_ERROR;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
*percent = CLAMP(*percent, 0.0, 100.0);
|
||||
}
|
||||
Platform_Battery_cachePercent = *percent;
|
||||
|
@ -882,34 +1019,46 @@ void Platform_longOptionsUsage(const char* name)
|
|||
" off - do not drop any capabilities\n"
|
||||
" basic (default) - drop all capabilities not needed by %s\n"
|
||||
" strict - drop all capabilities except those needed for\n"
|
||||
" core functionality\n", name);
|
||||
" core functionality\n",
|
||||
name);
|
||||
#else
|
||||
(void)name;
|
||||
#endif
|
||||
}
|
||||
|
||||
CommandLineStatus Platform_getLongOption(int opt, int argc, char** argv) {
|
||||
CommandLineStatus Platform_getLongOption(int opt, int argc, char **argv)
|
||||
{
|
||||
#ifndef HAVE_LIBCAP
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
#endif
|
||||
|
||||
switch (opt) {
|
||||
switch (opt)
|
||||
{
|
||||
#ifdef HAVE_LIBCAP
|
||||
case 160: {
|
||||
case 160:
|
||||
{
|
||||
const char *mode = optarg;
|
||||
if (!mode && optind < argc && argv[optind] != NULL &&
|
||||
(argv[optind][0] != '\0' && argv[optind][0] != '-')) {
|
||||
(argv[optind][0] != '\0' && argv[optind][0] != '-'))
|
||||
{
|
||||
mode = argv[optind++];
|
||||
}
|
||||
|
||||
if (!mode || String_eq(mode, "basic")) {
|
||||
if (!mode || String_eq(mode, "basic"))
|
||||
{
|
||||
Platform_capabilitiesMode = CAP_MODE_BASIC;
|
||||
} else if (String_eq(mode, "off")) {
|
||||
}
|
||||
else if (String_eq(mode, "off"))
|
||||
{
|
||||
Platform_capabilitiesMode = CAP_MODE_OFF;
|
||||
} else if (String_eq(mode, "strict")) {
|
||||
}
|
||||
else if (String_eq(mode, "strict"))
|
||||
{
|
||||
Platform_capabilitiesMode = CAP_MODE_STRICT;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "Error: invalid capabilities mode \"%s\".\n", mode);
|
||||
return STATUS_ERROR_EXIT;
|
||||
}
|
||||
|
@ -924,7 +1073,8 @@ CommandLineStatus Platform_getLongOption(int opt, int argc, char** argv) {
|
|||
}
|
||||
|
||||
#ifdef HAVE_LIBCAP
|
||||
static int dropCapabilities(enum CapMode mode) {
|
||||
static int dropCapabilities(enum CapMode mode)
|
||||
{
|
||||
|
||||
if (mode == CAP_MODE_OFF)
|
||||
return 0;
|
||||
|
@ -947,30 +1097,35 @@ static int dropCapabilities(enum CapMode mode) {
|
|||
const size_t ncap = (mode == CAP_MODE_BASIC) ? ARRAYSIZE(keepcapsBasic) : ARRAYSIZE(keepcapsStrict);
|
||||
|
||||
cap_t caps = cap_init();
|
||||
if (caps == NULL) {
|
||||
if (caps == NULL)
|
||||
{
|
||||
fprintf(stderr, "Error: can not initialize capabilities: %s\n", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (cap_clear(caps) < 0) {
|
||||
if (cap_clear(caps) < 0)
|
||||
{
|
||||
fprintf(stderr, "Error: can not clear capabilities: %s\n", strerror(errno));
|
||||
cap_free(caps);
|
||||
return -1;
|
||||
}
|
||||
|
||||
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));
|
||||
cap_free(caps);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < ncap; i++) {
|
||||
for (size_t i = 0; i < ncap; i++)
|
||||
{
|
||||
if (!CAP_IS_SUPPORTED(keepcaps[i]))
|
||||
continue;
|
||||
|
||||
cap_flag_value_t current;
|
||||
if (cap_get_flag(currCaps, keepcaps[i], CAP_PERMITTED, ¤t) < 0) {
|
||||
if (cap_get_flag(currCaps, keepcaps[i], CAP_PERMITTED, ¤t) < 0)
|
||||
{
|
||||
fprintf(stderr, "Error: can not get current value of capability %d: %s\n", keepcaps[i], strerror(errno));
|
||||
cap_free(currCaps);
|
||||
cap_free(caps);
|
||||
|
@ -980,14 +1135,16 @@ static int dropCapabilities(enum CapMode mode) {
|
|||
if (current != CAP_SET)
|
||||
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));
|
||||
cap_free(currCaps);
|
||||
cap_free(caps);
|
||||
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));
|
||||
cap_free(currCaps);
|
||||
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));
|
||||
cap_free(currCaps);
|
||||
cap_free(caps);
|
||||
|
@ -1009,13 +1167,15 @@ static int dropCapabilities(enum CapMode mode) {
|
|||
}
|
||||
#endif
|
||||
|
||||
bool Platform_init(void) {
|
||||
bool Platform_init(void)
|
||||
{
|
||||
#ifdef HAVE_LIBCAP
|
||||
if (dropCapabilities(Platform_capabilitiesMode) < 0)
|
||||
return false;
|
||||
#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);
|
||||
return false;
|
||||
}
|
||||
|
@ -1026,21 +1186,26 @@ bool Platform_init(void) {
|
|||
|
||||
char target[PATH_MAX];
|
||||
ssize_t ret = readlink(PROCDIR "/self/ns/pid", target, sizeof(target) - 1);
|
||||
if (ret > 0) {
|
||||
if (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;
|
||||
return true; // early return
|
||||
}
|
||||
}
|
||||
|
||||
FILE *fd = fopen(PROCDIR "/1/mounts", "r");
|
||||
if (fd) {
|
||||
if (fd)
|
||||
{
|
||||
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
|
||||
if (String_startsWith(lineBuffer, "lxcfs /proc") || String_startsWith(lineBuffer, "overlay ")) {
|
||||
if (String_startsWith(lineBuffer, "lxcfs /proc") || String_startsWith(lineBuffer, "overlay "))
|
||||
{
|
||||
Running_containerized = true;
|
||||
break;
|
||||
}
|
||||
|
@ -1051,7 +1216,8 @@ bool Platform_init(void) {
|
|||
return true;
|
||||
}
|
||||
|
||||
void Platform_done(void) {
|
||||
void Platform_done(void)
|
||||
{
|
||||
#ifdef HAVE_SENSORS_SENSORS_H
|
||||
LibSensors_cleanup();
|
||||
#endif
|
||||
|
|
|
@ -37,7 +37,6 @@ in the source distribution for its full text.
|
|||
#define PATH_MAX 4096
|
||||
#endif
|
||||
|
||||
|
||||
extern const ScreenDefaults Platform_defaultScreens[];
|
||||
|
||||
extern const unsigned int Platform_numberOfDefaultScreens;
|
||||
|
@ -57,6 +56,10 @@ void Platform_setBindings(Htop_Action* keys);
|
|||
|
||||
int Platform_getUptime(void);
|
||||
|
||||
float Platform_getTemp(void);
|
||||
|
||||
float Platform_getFreq(void);
|
||||
|
||||
void Platform_getLoadAverage(double *one, double *five, double *fifteen);
|
||||
|
||||
int Platform_getMaxPid(void);
|
||||
|
@ -87,11 +90,13 @@ bool Platform_getNetworkIO(NetworkIOData* data);
|
|||
|
||||
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);
|
||||
}
|
||||
|
||||
static inline void Platform_getRelease(char** string) {
|
||||
static inline void Platform_getRelease(char **string)
|
||||
{
|
||||
*string = Generic_uname();
|
||||
}
|
||||
|
||||
|
@ -106,11 +111,13 @@ void Platform_longOptionsUsage(const char* name);
|
|||
|
||||
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);
|
||||
}
|
||||
|
||||
static inline void Platform_gettime_monotonic(uint64_t* msec) {
|
||||
static inline void Platform_gettime_monotonic(uint64_t *msec)
|
||||
{
|
||||
Generic_gettime_monotonic(msec);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue