From e7372d18a1a661d8c3dba9f51e1f17b5f94171a7 Mon Sep 17 00:00:00 2001 From: Daniel Lange Date: Wed, 10 Jan 2024 11:17:08 +0100 Subject: New upstream version 3.3.0 --- Settings.c | 170 +++++++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 132 insertions(+), 38 deletions(-) (limited to 'Settings.c') diff --git a/Settings.c b/Settings.c index 7d6fca4..a01e249 100644 --- a/Settings.c +++ b/Settings.c @@ -5,11 +5,14 @@ Released under the GNU GPLv2+, see the COPYING file in the source distribution for its full text. */ +#include "config.h" // IWYU pragma: keep + #include "Settings.h" #include #include #include +#include #include #include #include @@ -18,9 +21,12 @@ in the source distribution for its full text. #include "CRT.h" #include "DynamicColumn.h" +#include "DynamicScreen.h" #include "Macros.h" #include "Meter.h" #include "Platform.h" +#include "Process.h" +#include "Table.h" #include "XUtils.h" @@ -202,13 +208,25 @@ static void Settings_defaultMeters(Settings* this, unsigned int initialCpuCount) this->hColumns[1].modes[r++] = TEXT_METERMODE; } -static const char* toFieldName(Hashtable* columns, int id) { - if (id < 0) +static const char* toFieldName(Hashtable* columns, int id, bool* enabled) { + if (id < 0) { + if (enabled) + *enabled = false; return NULL; - if (id >= LAST_PROCESSFIELD) { + } + if (id >= ROW_DYNAMIC_FIELDS) { const DynamicColumn* column = DynamicColumn_lookup(columns, id); + if (!column) { + if (enabled) + *enabled = false; + return NULL; + } + if (enabled) + *enabled = column->enabled; return column->name; } + if (enabled) + *enabled = true; return Process_fields[id].name; } @@ -216,7 +234,7 @@ 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, NULL)) { return id; } } else { @@ -236,7 +254,7 @@ 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++) { - const char* pName = toFieldName(columns, p); + const char* pName = toFieldName(columns, p, NULL); if (pName && strcmp(pName, str) == 0) return p; } @@ -261,42 +279,64 @@ static void ScreenSettings_readFields(ScreenSettings* ss, Hashtable* columns, co } int id = toFieldIndex(columns, ids[i]); if (id >= 0) - ss->fields[j] = id; + ss->fields[j++] = id; if (id > 0 && id < LAST_PROCESSFIELD) ss->flags |= Process_fields[id].flags; - j++; } String_freeArray(ids); } +static ScreenSettings* Settings_initScreenSettings(ScreenSettings* ss, Settings* this, const char* columns) { + ScreenSettings_readFields(ss, this->dynamicColumns, columns); + this->screens[this->nScreens] = ss; + this->nScreens++; + this->screens = xRealloc(this->screens, sizeof(ScreenSettings*) * (this->nScreens + 1)); + this->screens[this->nScreens] = NULL; + return ss; +} + ScreenSettings* Settings_newScreen(Settings* this, const ScreenDefaults* defaults) { int sortKey = defaults->sortKey ? toFieldIndex(this->dynamicColumns, defaults->sortKey) : PID; + int treeSortKey = defaults->treeSortKey ? toFieldIndex(this->dynamicColumns, defaults->treeSortKey) : PID; int sortDesc = (sortKey >= 0 && sortKey < LAST_PROCESSFIELD) ? Process_fields[sortKey].defaultSortDesc : 1; ScreenSettings* ss = xMalloc(sizeof(ScreenSettings)); *ss = (ScreenSettings) { - .name = xStrdup(defaults->name), + .heading = xStrdup(defaults->name), + .dynamic = NULL, + .table = NULL, .fields = xCalloc(LAST_PROCESSFIELD, sizeof(ProcessField)), .flags = 0, .direction = sortDesc ? -1 : 1, .treeDirection = 1, .sortKey = sortKey, - .treeSortKey = PID, + .treeSortKey = treeSortKey, .treeView = false, .treeViewAlwaysByPID = false, .allBranchesCollapsed = false, }; + return Settings_initScreenSettings(ss, this, defaults->columns); +} - ScreenSettings_readFields(ss, this->dynamicColumns, defaults->columns); - this->screens[this->nScreens] = ss; - this->nScreens++; - this->screens = xRealloc(this->screens, sizeof(ScreenSettings*) * (this->nScreens + 1)); - this->screens[this->nScreens] = NULL; - return ss; +ScreenSettings* Settings_newDynamicScreen(Settings* this, const char* tab, const DynamicScreen* screen, Table* table) { + int sortKey = toFieldIndex(this->dynamicColumns, screen->columnKeys); + + ScreenSettings* ss = xMalloc(sizeof(ScreenSettings)); + *ss = (ScreenSettings) { + .heading = xStrdup(tab), + .dynamic = xStrdup(screen->name), + .table = table, + .fields = xCalloc(LAST_PROCESSFIELD, sizeof(ProcessField)), + .direction = screen->direction, + .treeDirection = 1, + .sortKey = sortKey, + }; + return Settings_initScreenSettings(ss, this, screen->columnKeys); } void ScreenSettings_delete(ScreenSettings* this) { - free(this->name); + free(this->heading); + free(this->dynamic); free(this->fields); free(this); } @@ -308,6 +348,7 @@ static ScreenSettings* Settings_defaultScreens(Settings* this) { const ScreenDefaults* defaults = &Platform_defaultScreens[i]; Settings_newScreen(this, defaults); } + Platform_defaultDynamicScreens(this); return this->screens[0]; } @@ -381,6 +422,8 @@ static bool Settings_read(Settings* this, const char* fileName, unsigned int ini this->hideKernelThreads = atoi(option[1]); } else if (String_eq(option[0], "hide_userland_threads")) { this->hideUserlandThreads = atoi(option[1]); + } else if (String_eq(option[0], "hide_running_in_container")) { + this->hideRunningInContainer = atoi(option[1]); } else if (String_eq(option[0], "shadow_other_users")) { this->shadowOtherUsers = atoi(option[1]); } else if (String_eq(option[0], "show_thread_names")) { @@ -391,6 +434,8 @@ static bool Settings_read(Settings* this, const char* fileName, unsigned int ini this->highlightBaseName = atoi(option[1]); } else if (String_eq(option[0], "highlight_deleted_exe")) { this->highlightDeletedExe = atoi(option[1]); + } else if (String_eq(option[0], "shadow_distribution_path_prefix")) { + this->shadowDistPathPrefix = atoi(option[1]); } else if (String_eq(option[0], "highlight_megabytes")) { this->highlightMegabytes = atoi(option[1]); } else if (String_eq(option[0], "highlight_threads")) { @@ -475,13 +520,17 @@ static bool Settings_read(Settings* this, const char* fileName, unsigned int ini this->topologyAffinity = !!atoi(option[1]); #endif } 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")) { - if (screen) - screen->sortKey = toFieldIndex(this->dynamicColumns, option[1]); + if (screen) { + int key = toFieldIndex(this->dynamicColumns, option[1]); + screen->sortKey = key > 0 ? key : PID; + } } else if (String_eq(option[0], ".tree_sort_key")) { - if (screen) - screen->treeSortKey = toFieldIndex(this->dynamicColumns, option[1]); + if (screen) { + int key = toFieldIndex(this->dynamicColumns, option[1]); + screen->treeSortKey = key > 0 ? key : PID; + } } else if (String_eq(option[0], ".sort_direction")) { if (screen) screen->direction = atoi(option[1]); @@ -497,6 +546,11 @@ static bool Settings_read(Settings* this, const char* fileName, unsigned int ini } else if (String_eq(option[0], ".all_branches_collapsed")) { if (screen) screen->allBranchesCollapsed = atoi(option[1]); + } else if (String_eq(option[0], ".dynamic")) { + if (screen) { + free_and_xStrdup(&screen->dynamic, option[1]); + Platform_addDynamicScreen(screen); + } } String_freeArray(option); } @@ -512,11 +566,13 @@ static void writeFields(FILE* fd, const ProcessField* fields, Hashtable* columns const char* sep = ""; for (unsigned int i = 0; fields[i]; i++) { if (fields[i] < LAST_PROCESSFIELD && byName) { - const char* pName = toFieldName(columns, fields[i]); + const char* pName = toFieldName(columns, fields[i], NULL); fprintf(fd, "%s%s", sep, pName); } else if (fields[i] >= LAST_PROCESSFIELD && byName) { - const char* pName = toFieldName(columns, fields[i]); - fprintf(fd, " Dynamic(%s)", pName); + bool enabled; + const char* pName = toFieldName(columns, fields[i], &enabled); + if (enabled) + fprintf(fd, "%sDynamic(%s)", sep, pName); } else { // This "-1" is for compatibility with the older enum format. fprintf(fd, "%s%d", sep, (int) fields[i] - 1); @@ -536,26 +592,41 @@ static void writeList(FILE* fd, char** list, int len, char separator) { } static void writeMeters(const Settings* this, FILE* fd, char separator, unsigned int column) { - writeList(fd, this->hColumns[column].names, this->hColumns[column].len, separator); + if (this->hColumns[column].len) { + writeList(fd, this->hColumns[column].names, this->hColumns[column].len, separator); + } else { + fputc('!', fd); + fputc(separator, fd); + } } 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++) { - fprintf(fd, "%s%d", sep, this->hColumns[column].modes[i]); - sep = " "; + if (this->hColumns[column].len) { + const char* sep = ""; + for (size_t i = 0; i < this->hColumns[column].len; i++) { + fprintf(fd, "%s%d", sep, this->hColumns[column].modes[i]); + sep = " "; + } + } else { + fputc('!', fd); } + fputc(separator, fd); } int Settings_write(const Settings* this, bool onCrash) { FILE* fd; char separator; + char* tmpFilename = NULL; if (onCrash) { fd = stderr; separator = ';'; } else { - fd = fopen(this->filename, "w"); + xAsprintf(&tmpFilename, "%s.tmp.XXXXXX", this->filename); + int fdtmp = mkstemp(tmpFilename); + if (fdtmp == -1) + return -errno; + fd = fdopen(fdtmp, "w"); if (fd == NULL) return -errno; separator = '\n'; @@ -575,11 +646,13 @@ int Settings_write(const Settings* this, bool onCrash) { 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("hide_running_in_container", this->hideRunningInContainer); printSettingInteger("shadow_other_users", this->shadowOtherUsers); printSettingInteger("show_thread_names", this->showThreadNames); printSettingInteger("show_program_path", this->showProgramPath); printSettingInteger("highlight_base_name", this->highlightBaseName); printSettingInteger("highlight_deleted_exe", this->highlightDeletedExe); + printSettingInteger("shadow_distribution_path_prefix", this->shadowDistPathPrefix); printSettingInteger("highlight_megabytes", this->highlightMegabytes); printSettingInteger("highlight_threads", this->highlightThreads); printSettingInteger("highlight_changes", this->highlightChanges); @@ -629,12 +702,23 @@ int Settings_write(const Settings* this, bool onCrash) { for (unsigned int i = 0; i < this->nScreens; i++) { ScreenSettings* ss = this->screens[i]; - fprintf(fd, "screen:%s=", ss->name); + const char* sortKey = toFieldName(this->dynamicColumns, ss->sortKey, NULL); + const char* treeSortKey = toFieldName(this->dynamicColumns, ss->treeSortKey, NULL); + + fprintf(fd, "screen:%s=", ss->heading); writeFields(fd, ss->fields, this->dynamicColumns, true, separator); - printSettingString(".sort_key", toFieldName(this->dynamicColumns, ss->sortKey)); - printSettingString(".tree_sort_key", toFieldName(this->dynamicColumns, ss->treeSortKey)); + if (ss->dynamic) { + printSettingString(".dynamic", ss->dynamic); + if (ss->sortKey && ss->sortKey != PID) + fprintf(fd, "%s=Dynamic(%s)%c", ".sort_key", sortKey, separator); + if (ss->treeSortKey && ss->treeSortKey != PID) + fprintf(fd, "%s=Dynamic(%s)%c", ".tree_sort_key", treeSortKey, separator); + } else { + printSettingString(".sort_key", sortKey); + printSettingString(".tree_sort_key", treeSortKey); + printSettingInteger(".tree_view_always_by_pid", ss->treeViewAlwaysByPID); + } printSettingInteger(".tree_view", ss->treeView); - printSettingInteger(".tree_view_always_by_pid", ss->treeViewAlwaysByPID); printSettingInteger(".sort_direction", ss->direction); printSettingInteger(".tree_sort_direction", ss->treeDirection); printSettingInteger(".all_branches_collapsed", ss->allBranchesCollapsed); @@ -654,13 +738,20 @@ int Settings_write(const Settings* this, bool onCrash) { if (fclose(fd) != 0) r = r ? r : -errno; + if (r == 0) + r = (rename(tmpFilename, this->filename) == -1) ? -errno : 0; + + free(tmpFilename); + return r; } -Settings* Settings_new(unsigned int initialCpuCount, Hashtable* dynamicColumns) { +Settings* Settings_new(unsigned int initialCpuCount, Hashtable* dynamicMeters, Hashtable* dynamicColumns, Hashtable* dynamicScreens) { Settings* this = xCalloc(1, sizeof(Settings)); + this->dynamicScreens = dynamicScreens; this->dynamicColumns = dynamicColumns; + this->dynamicMeters = dynamicMeters; this->hLayout = HF_TWO_50_50; this->hColumns = xCalloc(HeaderLayout_getColumns(this->hLayout), sizeof(MeterColumnSetting)); @@ -668,8 +759,10 @@ Settings* Settings_new(unsigned int initialCpuCount, Hashtable* dynamicColumns) this->showThreadNames = false; this->hideKernelThreads = true; this->hideUserlandThreads = false; + this->hideRunningInContainer = false; this->highlightBaseName = false; this->highlightDeletedExe = true; + this->shadowDistPathPrefix = false; this->highlightMegabytes = true; this->detailedCPUTime = false; this->countCPUsFromOne = false; @@ -702,9 +795,10 @@ Settings* Settings_new(unsigned int initialCpuCount, Hashtable* dynamicColumns) this->filename = xStrdup(rcfile); } else { const char* home = getenv("HOME"); - if (!home) - home = ""; - + if (!home) { + const struct passwd* pw = getpwuid(getuid()); + home = pw ? pw->pw_dir : ""; + } const char* xdgConfigHome = getenv("XDG_CONFIG_HOME"); char* configDir = NULL; char* htopDir = NULL; -- cgit v1.2.3