mirror of https://github.com/xzeldon/htop.git
Linux: dynamically adjust the SECATTR column width
SELinux contexts can be quite long; adjust the column width dynamically at each cycle to the longest value. Also with the recent addition of multiple screens, over-long columns can be moved into their own screen.
This commit is contained in:
parent
6133cac721
commit
3ba695293c
20
Process.c
20
Process.c
|
@ -1252,3 +1252,23 @@ void Process_updateExe(Process* this, const char* exe) {
|
||||||
}
|
}
|
||||||
this->mergedCommand.exeChanged = true;
|
this->mergedCommand.exeChanged = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint8_t Process_fieldWidths[LAST_PROCESSFIELD] = { 0 };
|
||||||
|
|
||||||
|
void Process_resetFieldWidths() {
|
||||||
|
for (size_t i = 0; i < LAST_PROCESSFIELD; i++) {
|
||||||
|
if (!Process_fields[i].autoWidth)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
size_t len = strlen(Process_fields[i].title);
|
||||||
|
assert(len <= UINT8_MAX);
|
||||||
|
Process_fieldWidths[i] = (uint8_t)len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Process_updateFieldWidth(ProcessField key, size_t width) {
|
||||||
|
if (width > UINT8_MAX)
|
||||||
|
Process_fieldWidths[key] = UINT8_MAX;
|
||||||
|
else if (width > Process_fieldWidths[key])
|
||||||
|
Process_fieldWidths[key] = (uint8_t)width;
|
||||||
|
}
|
||||||
|
|
|
@ -279,6 +279,9 @@ typedef struct ProcessFieldData_ {
|
||||||
|
|
||||||
/* Whether the column should be sorted in descending order by default */
|
/* Whether the column should be sorted in descending order by default */
|
||||||
bool defaultSortDesc;
|
bool defaultSortDesc;
|
||||||
|
|
||||||
|
/* Whether the column width is dynamically adjusted (the minimum width is determined by the title length) */
|
||||||
|
bool autoWidth;
|
||||||
} ProcessFieldData;
|
} ProcessFieldData;
|
||||||
|
|
||||||
// Implemented in platform-specific code:
|
// Implemented in platform-specific code:
|
||||||
|
@ -286,6 +289,7 @@ void Process_writeField(const Process* this, RichString* str, ProcessField field
|
||||||
int Process_compare(const void* v1, const void* v2);
|
int Process_compare(const void* v1, const void* v2);
|
||||||
void Process_delete(Object* cast);
|
void Process_delete(Object* cast);
|
||||||
extern const ProcessFieldData Process_fields[LAST_PROCESSFIELD];
|
extern const ProcessFieldData Process_fields[LAST_PROCESSFIELD];
|
||||||
|
extern uint8_t Process_fieldWidths[LAST_PROCESSFIELD];
|
||||||
#define PROCESS_MIN_PID_DIGITS 5
|
#define PROCESS_MIN_PID_DIGITS 5
|
||||||
#define PROCESS_MAX_PID_DIGITS 19
|
#define PROCESS_MAX_PID_DIGITS 19
|
||||||
#define PROCESS_MIN_UID_DIGITS 5
|
#define PROCESS_MIN_UID_DIGITS 5
|
||||||
|
@ -406,4 +410,7 @@ void Process_makeCommandStr(Process* this);
|
||||||
|
|
||||||
void Process_writeCommand(const Process* this, int attr, int baseAttr, RichString* str);
|
void Process_writeCommand(const Process* this, int attr, int baseAttr, RichString* str);
|
||||||
|
|
||||||
|
void Process_resetFieldWidths(void);
|
||||||
|
void Process_updateFieldWidth(ProcessField key, size_t width);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -114,6 +114,12 @@ static const char* alignedProcessFieldTitle(const ProcessList* this, ProcessFiel
|
||||||
return titleBuffer;
|
return titleBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Process_fields[field].autoWidth) {
|
||||||
|
static char titleBuffer[UINT8_MAX + 1];
|
||||||
|
xSnprintf(titleBuffer, sizeof(titleBuffer), "%-*.*s ", Process_fieldWidths[field], Process_fieldWidths[field], title);
|
||||||
|
return titleBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
return title;
|
return title;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -453,6 +459,7 @@ void ProcessList_scan(ProcessList* this, bool pauseProcessUpdate) {
|
||||||
this->kernelThreads = 0;
|
this->kernelThreads = 0;
|
||||||
this->runningTasks = 0;
|
this->runningTasks = 0;
|
||||||
|
|
||||||
|
Process_resetFieldWidths();
|
||||||
|
|
||||||
// set scan timestamp
|
// set scan timestamp
|
||||||
static bool firstScanDone = false;
|
static bool firstScanDone = false;
|
||||||
|
|
|
@ -94,7 +94,7 @@ const ProcessFieldData Process_fields[LAST_PROCESSFIELD] = {
|
||||||
[M_SWAP] = { .name = "M_SWAP", .title = " SWAP ", .description = "Size of the process's swapped pages", .flags = PROCESS_FLAG_LINUX_SMAPS, .defaultSortDesc = true, },
|
[M_SWAP] = { .name = "M_SWAP", .title = " SWAP ", .description = "Size of the process's swapped pages", .flags = PROCESS_FLAG_LINUX_SMAPS, .defaultSortDesc = true, },
|
||||||
[M_PSSWP] = { .name = "M_PSSWP", .title = " PSSWP ", .description = "shows proportional swap share of this mapping, unlike \"Swap\", this does not take into account swapped out page of underlying shmem objects", .flags = PROCESS_FLAG_LINUX_SMAPS, .defaultSortDesc = true, },
|
[M_PSSWP] = { .name = "M_PSSWP", .title = " PSSWP ", .description = "shows proportional swap share of this mapping, unlike \"Swap\", this does not take into account swapped out page of underlying shmem objects", .flags = PROCESS_FLAG_LINUX_SMAPS, .defaultSortDesc = true, },
|
||||||
[CTXT] = { .name = "CTXT", .title = " CTXT ", .description = "Context switches (incremental sum of voluntary_ctxt_switches and nonvoluntary_ctxt_switches)", .flags = PROCESS_FLAG_LINUX_CTXT, .defaultSortDesc = true, },
|
[CTXT] = { .name = "CTXT", .title = " CTXT ", .description = "Context switches (incremental sum of voluntary_ctxt_switches and nonvoluntary_ctxt_switches)", .flags = PROCESS_FLAG_LINUX_CTXT, .defaultSortDesc = true, },
|
||||||
[SECATTR] = { .name = "SECATTR", .title = "Security Attribute ", .description = "Security attribute of the process (e.g. SELinux or AppArmor)", .flags = PROCESS_FLAG_LINUX_SECATTR, },
|
[SECATTR] = { .name = "SECATTR", .title = "Security Attribute", .description = "Security attribute of the process (e.g. SELinux or AppArmor)", .flags = PROCESS_FLAG_LINUX_SECATTR, .autoWidth = true, },
|
||||||
[PROC_COMM] = { .name = "COMM", .title = "COMM ", .description = "comm string of the process from /proc/[pid]/comm", .flags = 0, },
|
[PROC_COMM] = { .name = "COMM", .title = "COMM ", .description = "comm string of the process from /proc/[pid]/comm", .flags = 0, },
|
||||||
[PROC_EXE] = { .name = "EXE", .title = "EXE ", .description = "Basename of exe of the process from /proc/[pid]/exe", .flags = 0, },
|
[PROC_EXE] = { .name = "EXE", .title = "EXE ", .description = "Basename of exe of the process from /proc/[pid]/exe", .flags = 0, },
|
||||||
[CWD] = { .name = "CWD", .title = "CWD ", .description = "The current working directory of the process", .flags = PROCESS_FLAG_CWD, },
|
[CWD] = { .name = "CWD", .title = "CWD ", .description = "The current working directory of the process", .flags = PROCESS_FLAG_CWD, },
|
||||||
|
@ -280,7 +280,7 @@ static void LinuxProcess_writeField(const Process* this, RichString* str, Proces
|
||||||
}
|
}
|
||||||
xSnprintf(buffer, n, "%5lu ", lp->ctxt_diff);
|
xSnprintf(buffer, n, "%5lu ", lp->ctxt_diff);
|
||||||
break;
|
break;
|
||||||
case SECATTR: snprintf(buffer, n, "%-30.30s ", lp->secattr ? lp->secattr : "?"); break;
|
case SECATTR: snprintf(buffer, n, "%-*.*s ", Process_fieldWidths[SECATTR], Process_fieldWidths[SECATTR], lp->secattr ? lp->secattr : "N/A"); break;
|
||||||
case AUTOGROUP_ID:
|
case AUTOGROUP_ID:
|
||||||
if (lp->autogroup_id != -1) {
|
if (lp->autogroup_id != -1) {
|
||||||
xSnprintf(buffer, n, "%4ld ", lp->autogroup_id);
|
xSnprintf(buffer, n, "%4ld ", lp->autogroup_id);
|
||||||
|
|
|
@ -1029,6 +1029,9 @@ static void LinuxProcessList_readSecattrData(LinuxProcess* process, openat_arg_t
|
||||||
if (newline) {
|
if (newline) {
|
||||||
*newline = '\0';
|
*newline = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Process_updateFieldWidth(SECATTR, strlen(buffer));
|
||||||
|
|
||||||
if (process->secattr && String_eq(process->secattr, buffer)) {
|
if (process->secattr && String_eq(process->secattr, buffer)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue