diff --git a/DisplayOptionsPanel.c b/DisplayOptionsPanel.c index dd26989fe..e945edd9e 100644 --- a/DisplayOptionsPanel.c +++ b/DisplayOptionsPanel.c @@ -107,6 +107,7 @@ DisplayOptionsPanel* DisplayOptionsPanel_new(Settings* settings, ScreenManager* Panel_add(super, (Object*) CheckItem_newByRef("Show custom thread names", &(settings->showThreadNames))); Panel_add(super, (Object*) CheckItem_newByRef("Show program path", &(settings->showProgramPath))); Panel_add(super, (Object*) CheckItem_newByRef("Highlight program \"basename\"", &(settings->highlightBaseName))); + Panel_add(super, (Object*) CheckItem_newByRef("Highlight out-dated/removed programs", &(settings->highlightDeletedExe))); Panel_add(super, (Object*) CheckItem_newByRef("Merge exe, comm and cmdline in Command", &(settings->showMergedCommand))); Panel_add(super, (Object*) CheckItem_newByRef("- Try to find comm in cmdline (when Command is merged)", &(settings->findCommInCmdline))); Panel_add(super, (Object*) CheckItem_newByRef("- Try to strip exe from cmdline (when Command is merged)", &(settings->stripExeFromCmdline))); diff --git a/Process.c b/Process.c index 5236c8b12..f134be53f 100644 --- a/Process.c +++ b/Process.c @@ -594,7 +594,7 @@ void Process_writeCommand(const Process* this, int attr, int baseAttr, RichStrin const bool highlightBaseName = this->settings->highlightBaseName; const bool highlightSeparator = true; - const bool highlightDeleted = true; + const bool highlightDeleted = this->settings->highlightDeletedExe; if (!this->mergedCommand.str) { int len = 0; @@ -766,7 +766,7 @@ void Process_writeField(const Process* this, RichString* str, ProcessField field const char* procExe; if (this->procExe) { attr = CRT_colors[Process_isUserlandThread(this) ? PROCESS_THREAD_BASENAME : PROCESS_BASENAME]; - if (this->procExeDeleted) + if (this->procExeDeleted && this->settings->highlightDeletedExe) attr = CRT_colors[FAILED_READ]; procExe = this->procExe + this->procExeBasenameOffset; } else { diff --git a/Settings.c b/Settings.c index 92d96dd53..acb3edfa7 100644 --- a/Settings.c +++ b/Settings.c @@ -175,6 +175,8 @@ static bool Settings_read(Settings* this, const char* fileName, unsigned int ini this->showProgramPath = atoi(option[1]); } else if (String_eq(option[0], "highlight_base_name")) { 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], "highlight_megabytes")) { this->highlightMegabytes = atoi(option[1]); } else if (String_eq(option[0], "highlight_threads")) { @@ -307,6 +309,7 @@ int Settings_write(const Settings* this, bool onCrash) { fprintf(fd, "show_thread_names=%d\n", (int) this->showThreadNames); fprintf(fd, "show_program_path=%d\n", (int) this->showProgramPath); fprintf(fd, "highlight_base_name=%d\n", (int) this->highlightBaseName); + fprintf(fd, "highlight_deleted_exe=%d\n", (int) this->highlightDeletedExe); fprintf(fd, "highlight_megabytes=%d\n", (int) this->highlightMegabytes); fprintf(fd, "highlight_threads=%d\n", (int) this->highlightThreads); fprintf(fd, "highlight_changes=%d\n", (int) this->highlightChanges); @@ -368,6 +371,7 @@ Settings* Settings_new(unsigned int initialCpuCount) { this->treeView = false; this->allBranchesCollapsed = false; this->highlightBaseName = false; + this->highlightDeletedExe = true; this->highlightMegabytes = false; this->detailedCPUTime = false; this->countCPUsFromOne = false; diff --git a/Settings.h b/Settings.h index fb621adb2..6cda3a929 100644 --- a/Settings.h +++ b/Settings.h @@ -54,6 +54,7 @@ typedef struct Settings_ { bool hideKernelThreads; bool hideUserlandThreads; bool highlightBaseName; + bool highlightDeletedExe; bool highlightMegabytes; bool highlightThreads; bool highlightChanges; diff --git a/htop.1.in b/htop.1.in index af3ca6b74..972f823c3 100644 --- a/htop.1.in +++ b/htop.1.in @@ -254,10 +254,14 @@ shown in main screen, it is shown below in parenthesis. .TP 5 .B Command -The full command line of the process (i.e. program name and arguments). If the -option 'Merge exe, comm and cmdline in Command' (toggled by the 'm' key) is set, -and if readable, the executable path (/proc/[pid]/exe) and the command name -(/proc/[pid]/comm) are also shown merged with the command line. +The full command line of the process (i.e. program name and arguments). + +If the option 'Merge exe, comm and cmdline in Command' (toggled by the 'm' key) +is active, the executable path (/proc/[pid]/exe) and the command name +(/proc/[pid]/comm) are also shown merged with the command line, if available. + +The program basename is highlighted if set in the configuration. Additional +highlighting can be configured for stale executables (cf. Exe column below). .TP .B Comm The command name of the process obtained from /proc/[pid]/comm, if readable. @@ -266,6 +270,10 @@ The command name of the process obtained from /proc/[pid]/comm, if readable. The abbreviated basename of the executable of the process, obtained from /proc/[pid]/exe, if readable. htop is able to read this file on linux for ALL the processes only if it has the capability CAP_SYS_PTRACE or root privileges. + +The basename is marked in red if the executable used to run the process has +been replaced or deleted on disk since the process started. This additional +markup can be configured. .TP .B PID The process ID. diff --git a/linux/LinuxProcessList.c b/linux/LinuxProcessList.c index d82cac5e6..6d3bbc84e 100644 --- a/linux/LinuxProcessList.c +++ b/linux/LinuxProcessList.c @@ -1160,10 +1160,14 @@ static bool LinuxProcessList_readCmdlineFile(Process* process, openat_arg_t proc const size_t filenameLen = strlen(filename); if (filenameLen > markerLen) { + bool oldExeDeleted = process->procExeDeleted; + process->procExeDeleted = String_eq(filename + filenameLen - markerLen, deletedMarker); if (process->procExeDeleted) filename[filenameLen - markerLen] = '\0'; + + process->mergedCommand.exeChanged |= oldExeDeleted ^ process->procExeDeleted; } Process_updateExe(process, filename);