summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog14
-rw-r--r--Makefile.am2
-rw-r--r--OpenFilesScreen.c53
-rw-r--r--generic/gettime.c8
-rw-r--r--htop.1.in18
-rw-r--r--linux/CGroupUtils.c317
-rw-r--r--linux/CGroupUtils.h16
-rw-r--r--linux/LinuxProcess.c9
-rw-r--r--linux/LinuxProcess.h1
-rw-r--r--linux/LinuxProcessList.c33
-rw-r--r--linux/ProcessField.h1
11 files changed, 456 insertions, 16 deletions
diff --git a/ChangeLog b/ChangeLog
index 6f0a7dad..a103ed5d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,17 @@
+What's new in version 3.1.2
+
+* Bugfix for crash when storing modified settings at exit
+* Allow -u UID with numerical value as argument
+* Added documentation for obsolete/state libraries/program files highlighting
+* Some obsolete/stale library highlighting refinements
+* Column width issues resolved
+* Dynamic UID column sizing improved
+* Discard stale information from Disk and Network I/O meters
+* Refined Linux kernel thread detection
+* Reworked process state handling
+* New CCGROUP column showing abbreviated cgroup name
+* New OFFSET column in the list of open files screen
+
What's new in version 3.1.1
* Update license headers to explicitly say GPLv2+
diff --git a/Makefile.am b/Makefile.am
index 7ed500ca..2a9cc29f 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -153,6 +153,7 @@ linux_platform_headers = \
generic/gettime.h \
generic/hostname.h \
generic/uname.h \
+ linux/CGroupUtils.h \
linux/HugePageMeter.h \
linux/IOPriority.h \
linux/IOPriorityPanel.h \
@@ -174,6 +175,7 @@ linux_platform_sources = \
generic/gettime.c \
generic/hostname.c \
generic/uname.c \
+ linux/CGroupUtils.c \
linux/HugePageMeter.c \
linux/IOPriorityPanel.c \
linux/LibSensors.c \
diff --git a/OpenFilesScreen.c b/OpenFilesScreen.c
index e0bede0f..34367ebc 100644
--- a/OpenFilesScreen.c
+++ b/OpenFilesScreen.c
@@ -10,12 +10,14 @@ in the source distribution for its full text.
#include "OpenFilesScreen.h"
#include <fcntl.h>
+#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
+#include <sys/stat.h>
#include "Macros.h"
#include "Panel.h"
@@ -25,7 +27,7 @@ in the source distribution for its full text.
typedef struct OpenFiles_Data_ {
- char* data[7];
+ char* data[8];
} OpenFiles_Data;
typedef struct OpenFiles_ProcessData_ {
@@ -55,6 +57,8 @@ static size_t getIndexForType(char type) {
return 5;
case 't':
return 6;
+ case 'o':
+ return 7;
}
/* should never reach here */
@@ -74,7 +78,7 @@ OpenFilesScreen* OpenFilesScreen_new(const Process* process) {
} else {
this->pid = process->pid;
}
- return (OpenFilesScreen*) InfoScreen_init(&this->super, process, NULL, LINES - 2, " FD TYPE MODE DEVICE SIZE NODE NAME");
+ return (OpenFilesScreen*) InfoScreen_init(&this->super, process, NULL, LINES - 2, " FD TYPE MODE DEVICE SIZE OFFSET NODE NAME");
}
void OpenFilesScreen_delete(Object* this) {
@@ -115,13 +119,14 @@ static OpenFiles_ProcessData* OpenFilesScreen_getProcessData(pid_t pid) {
close(fdnull);
char buffer[32] = {0};
xSnprintf(buffer, sizeof(buffer), "%d", pid);
- execlp("lsof", "lsof", "-P", "-p", buffer, "-F", NULL);
+ execlp("lsof", "lsof", "-P", "-o", "-p", buffer, "-F", NULL);
exit(127);
}
close(fdpair[1]);
OpenFiles_Data* item = &(pdata->data);
OpenFiles_FileData* fdata = NULL;
+ bool lsofIncludesFileSize = false;
FILE* fd = fdopen(fdpair[0], "r");
if (!fd) {
@@ -155,8 +160,17 @@ static OpenFiles_ProcessData* OpenFilesScreen_getProcessData(pid_t pid) {
case 't': /* file's type */
{
size_t index = getIndexForType(cmd);
- free(item->data[index]);
- item->data[index] = xStrdup(line + 1);
+ free_and_xStrdup(&item->data[index], line + 1);
+ break;
+ }
+ case 'o': /* file's offset */
+ {
+ size_t index = getIndexForType(cmd);
+ if (String_startsWith(line + 1, "0t")) {
+ free_and_xStrdup(&item->data[index], line + 3);
+ } else {
+ free_and_xStrdup(&item->data[index], line + 1);
+ }
break;
}
case 'c': /* process command name */
@@ -166,7 +180,6 @@ static OpenFiles_ProcessData* OpenFilesScreen_getProcessData(pid_t pid) {
case 'k': /* link count */
case 'l': /* file's lock status */
case 'L': /* process login name */
- case 'o': /* file's offset */
case 'p': /* process ID */
case 'P': /* protocol name */
case 'R': /* parent process ID */
@@ -175,6 +188,10 @@ static OpenFiles_ProcessData* OpenFilesScreen_getProcessData(pid_t pid) {
/* ignore */
break;
}
+
+ if (cmd == 's')
+ lsofIncludesFileSize = true;
+
free(line);
}
fclose(fd);
@@ -191,6 +208,25 @@ static OpenFiles_ProcessData* OpenFilesScreen_getProcessData(pid_t pid) {
pdata->error = WEXITSTATUS(wstatus);
}
+ /* We got all information we need; no post-processing needed */
+ if (lsofIncludesFileSize)
+ return pdata;
+
+ /* On linux, `lsof -o -F` omits SIZE, so add it back. */
+ /* On macOS, `lsof -o -F` includes SIZE, so this block isn't needed. If no open files have a filesize, this will still run, unfortunately. */
+ size_t fileSizeIndex = getIndexForType('s');
+ for (fdata = pdata->files; fdata != NULL; fdata = fdata->next) {
+ item = &fdata->data;
+ const char* filename = getDataForType(item, 'n');
+
+ struct stat st;
+ if (stat(filename, &st) == 0) {
+ char fileSizeBuf[21]; /* 20 (long long) + 1 (NULL) */
+ xSnprintf(fileSizeBuf, sizeof(fileSizeBuf), "%"PRIu64, st.st_size); /* st.st_size is long long on macOS, long on linux */
+ free_and_xStrdup(&item->data[fileSizeIndex], fileSizeBuf);
+ }
+ }
+
return pdata;
}
@@ -213,14 +249,15 @@ static void OpenFilesScreen_scan(InfoScreen* this) {
while (fdata) {
OpenFiles_Data* data = &fdata->data;
size_t lenN = strlen(getDataForType(data, 'n'));
- size_t sizeEntry = 5 + 7 + 4 + 10 + 10 + 10 + lenN + 7 /*spaces*/ + 1 /*null*/;
+ size_t sizeEntry = 5 + 7 + 4 + 10 + 10 + 10 + 10 + lenN + 8 /*spaces*/ + 1 /*null*/;
char entry[sizeEntry];
- xSnprintf(entry, sizeof(entry), "%5.5s %-7.7s %-4.4s %-10.10s %10.10s %10.10s %s",
+ xSnprintf(entry, sizeof(entry), "%5.5s %-7.7s %-4.4s %-10.10s %10.10s %10.10s %10.10s %s",
getDataForType(data, 'f'),
getDataForType(data, 't'),
getDataForType(data, 'a'),
getDataForType(data, 'D'),
getDataForType(data, 's'),
+ getDataForType(data, 'o'),
getDataForType(data, 'i'),
getDataForType(data, 'n'));
InfoScreen_addLine(this, entry);
diff --git a/generic/gettime.c b/generic/gettime.c
index 975457fe..b7c4885e 100644
--- a/generic/gettime.c
+++ b/generic/gettime.c
@@ -49,9 +49,13 @@ void Generic_gettime_monotonic(uint64_t* msec) {
else
*msec = 0;
-#else
+#else /* lower resolution gettimeofday() should be always available */
-# error "No monotonic clock available"
+ struct timeval tv;
+ if (gettimeofday(&tv, NULL) == 0)
+ *msec = ((uint64_t)tv.tv_sec * 1000) + ((uint64_t)tv.tv_usec / 1000);
+ else
+ *msec = 0;
#endif
}
diff --git a/htop.1.in b/htop.1.in
index 702f7c23..49c4a52d 100644
--- a/htop.1.in
+++ b/htop.1.in
@@ -488,7 +488,23 @@ The I/O rate of write(2) in bytes per second, for the process.
The I/O rate, IO_READ_RATE + IO_WRITE_RATE (see above).
.TP
.B CGROUP
-Which cgroup the process is in.
+Which cgroup the process is in. For a shortened view see the CCGROUP column below.
+.TP
+.B CCGROUP
+Shortened view of the cgroup name that the process is in.
+This performs some pattern-based replacements to shorten the displayed string and thus condense the information.
+ \fB/*.slice\fR is shortened to \fB/[*]\fR (exceptions below)
+ \fB/system.slice\fR is shortened to \fB/[S]\fR
+ \fB/user.slice\fR is shortened to \fB/[U]\fR
+ \fB/user-*.slice\fR is shortened to \fB/[U:*]\fR (directly preceeding \fB/[U]\fR before dropped)
+ \fB/machine.slice\fR is shortened to \fB/[M]\fR
+ \fB/machine-*.scope\fR is shortened to \fB/[SNC:*]\fR (SNC: systemd nspawn container), uppercase for the monitor
+ \fB/lxc.monitor.*\fR is shortened to \fB/[LXC:*]\fR
+ \fB/lxc.payload.*\fR is shortened to \fB/[lxc:*]\fR
+ \fB/*.scope\fR is shortened to \fB/!*\fR
+ \fB/*.service\fR is shortened to \fB/*\fR (suffix removed)
+
+Encountered escape sequences (e.g. from systemd) inside the cgroup name are not decoded.
.TP
.B OOM
OOM killer score.
diff --git a/linux/CGroupUtils.c b/linux/CGroupUtils.c
new file mode 100644
index 00000000..6f3b6fe7
--- /dev/null
+++ b/linux/CGroupUtils.c
@@ -0,0 +1,317 @@
+/*
+htop - CGroupUtils.h
+(C) 2021 htop dev team
+Released under the GNU GPLv2+, see the COPYING file
+in the source distribution for its full text.
+*/
+
+#include "linux/CGroupUtils.h"
+
+#include "XUtils.h"
+
+
+typedef struct StrBuf_state {
+ char *buf;
+ size_t size;
+ size_t pos;
+} StrBuf_state;
+
+typedef bool (*StrBuf_putc_t)(StrBuf_state* p, char c);
+
+static bool StrBuf_putc_count(StrBuf_state* p, ATTR_UNUSED char c) {
+ p->pos++;
+ return true;
+}
+
+static bool StrBuf_putc_write(StrBuf_state* p, char c) {
+ if (p->pos >= p->size)
+ return false;
+
+ p->buf[p->pos] = c;
+ p->pos++;
+ return true;
+}
+
+static bool StrBuf_putsn(StrBuf_state* p, StrBuf_putc_t w, const char* s, size_t count) {
+ while (count--)
+ if (!w(p, *s++))
+ return false;
+
+ return true;
+}
+
+static bool StrBuf_putsz(StrBuf_state* p, StrBuf_putc_t w, const char* s) {
+ while (*s)
+ if (!w(p, *s++))
+ return false;
+
+ return true;
+}
+
+static bool Label_checkEqual(const char* labelStart, size_t labelLen, const char* expected) {
+ return labelLen == strlen(expected) && String_startsWith(labelStart, expected);
+}
+
+static bool Label_checkPrefix(const char* labelStart, size_t labelLen, const char* expected) {
+ return labelLen > strlen(expected) && String_startsWith(labelStart, expected);
+}
+
+static bool Label_checkSuffix(const char* labelStart, size_t labelLen, const char* expected) {
+ return labelLen > strlen(expected) && String_startsWith(labelStart + labelLen - strlen(expected), expected);
+}
+
+static bool CGroup_filterName_internal(const char *cgroup, StrBuf_state* s, StrBuf_putc_t w) {
+ const char* str_slice_suffix = ".slice";
+ const char* str_system_slice = "system.slice";
+ const char* str_user_slice = "user.slice";
+ const char* str_machine_slice = "machine.slice";
+ const char* str_user_slice_prefix = "/user-";
+
+ const char* str_lxc_monitor_legacy = "lxc.monitor";
+ const char* str_lxc_payload_legacy = "lxc.payload";
+ const char* str_lxc_monitor_prefix = "lxc.monitor.";
+ const char* str_lxc_payload_prefix = "lxc.payload.";
+
+ const char* str_nspawn_scope_prefix = "machine-";
+ const char* str_nspawn_monitor_label = "/supervisor";
+ const char* str_nspawn_payload_label = "/payload";
+
+ const char* str_service_suffix = ".service";
+ const char* str_scope_suffix = ".scope";
+
+ while (*cgroup) {
+ if ('/' == *cgroup) {
+ while ('/' == *cgroup)
+ cgroup++;
+
+ if (!w(s, '/'))
+ return false;
+
+ continue;
+ }
+
+ const char* labelStart = cgroup;
+ const char* nextSlash = strchrnul(labelStart, '/');
+ const size_t labelLen = nextSlash - labelStart;
+
+ if (Label_checkEqual(labelStart, labelLen, str_system_slice)) {
+ cgroup = nextSlash;
+
+ if (!StrBuf_putsz(s, w, "[S]"))
+ return false;
+
+ continue;
+ }
+
+ if (Label_checkEqual(labelStart, labelLen, str_machine_slice)) {
+ cgroup = nextSlash;
+
+ if (!StrBuf_putsz(s, w, "[M]"))
+ return false;
+
+ continue;
+ }
+
+ if (Label_checkEqual(labelStart, labelLen, str_user_slice)) {
+ cgroup = nextSlash;
+
+ if (!StrBuf_putsz(s, w, "[U]"))
+ return false;
+
+ if (!String_startsWith(cgroup, str_user_slice_prefix))
+ continue;
+
+ const char* userSliceSlash = strchrnul(cgroup + strlen(str_user_slice_prefix), '/');
+ const char* sliceSpec = userSliceSlash - strlen(str_slice_suffix);
+
+ if (!String_startsWith(sliceSpec, str_slice_suffix))
+ continue;
+
+ const size_t sliceNameLen = sliceSpec - (cgroup + strlen(str_user_slice_prefix));
+
+ s->pos--;
+ if (!w(s, ':'))
+ return false;
+
+ if (!StrBuf_putsn(s, w, cgroup + strlen(str_user_slice_prefix), sliceNameLen))
+ return false;
+
+ if (!w(s, ']'))
+ return false;
+
+ cgroup = userSliceSlash;
+
+ continue;
+ }
+
+ if (Label_checkSuffix(labelStart, labelLen, str_slice_suffix)) {
+ const size_t sliceNameLen = labelLen - strlen(str_slice_suffix);
+
+ if (!w(s, '['))
+ return false;
+
+ if (!StrBuf_putsn(s, w, cgroup, sliceNameLen))
+ return false;
+
+ if (!w(s, ']'))
+ return false;
+
+ cgroup = nextSlash;
+
+ continue;
+ }
+
+ if (Label_checkPrefix(labelStart, labelLen, str_lxc_payload_prefix)) {
+ const size_t cgroupNameLen = labelLen - strlen(str_lxc_payload_prefix);
+
+ if (!StrBuf_putsz(s, w, "[lxc:"))
+ return false;
+
+ if (!StrBuf_putsn(s, w, cgroup + strlen(str_lxc_payload_prefix), cgroupNameLen))
+ return false;
+
+ if (!w(s, ']'))
+ return false;
+
+ cgroup = nextSlash;
+
+ continue;
+ }
+
+ if (Label_checkPrefix(labelStart, labelLen, str_lxc_monitor_prefix)) {
+ const size_t cgroupNameLen = labelLen - strlen(str_lxc_monitor_prefix);
+
+ if (!StrBuf_putsz(s, w, "[LXC:"))
+ return false;
+
+ if (!StrBuf_putsn(s, w, cgroup + strlen(str_lxc_monitor_prefix), cgroupNameLen))
+ return false;
+
+ if (!w(s, ']'))
+ return false;
+
+ cgroup = nextSlash;
+
+ continue;
+ }
+
+ // LXC legacy cgroup naming
+ if (Label_checkEqual(labelStart, labelLen, str_lxc_monitor_legacy) ||
+ Label_checkEqual(labelStart, labelLen, str_lxc_payload_legacy)) {
+ bool isMonitor = Label_checkEqual(labelStart, labelLen, str_lxc_monitor_legacy);
+
+ labelStart = nextSlash;
+ while (*labelStart == '/')
+ labelStart++;
+
+ nextSlash = strchrnul(labelStart, '/');
+ if (nextSlash - labelStart > 0) {
+ if (!StrBuf_putsz(s, w, isMonitor ? "[LXC:" : "[lxc:"))
+ return false;
+
+ if (!StrBuf_putsn(s, w, labelStart, nextSlash - labelStart))
+ return false;
+
+ if (!w(s, ']'))
+ return false;
+
+ cgroup = nextSlash;
+ continue;
+ }
+
+ labelStart = cgroup;
+ nextSlash = labelStart + labelLen;
+ }
+
+ if (Label_checkSuffix(labelStart, labelLen, str_service_suffix)) {
+ const size_t serviceNameLen = labelLen - strlen(str_service_suffix);
+
+ if (String_startsWith(cgroup, "user@")) {
+ cgroup = nextSlash;
+
+ while(*cgroup == '/')
+ cgroup++;
+
+ continue;
+ }
+
+ if (!StrBuf_putsn(s, w, cgroup, serviceNameLen))
+ return false;
+
+ cgroup = nextSlash;
+
+ continue;
+ }
+
+ if (Label_checkSuffix(labelStart, labelLen, str_scope_suffix)) {
+ const size_t scopeNameLen = labelLen - strlen(str_scope_suffix);
+
+ if (Label_checkPrefix(labelStart, scopeNameLen, str_nspawn_scope_prefix)) {
+ const size_t machineScopeNameLen = scopeNameLen - strlen(str_nspawn_scope_prefix);
+
+ const bool is_monitor = String_startsWith(nextSlash, str_nspawn_monitor_label);
+
+ if (!StrBuf_putsz(s, w, is_monitor ? "[SNC:" : "[snc:"))
+ return false;
+
+ if (!StrBuf_putsn(s, w, cgroup + strlen(str_nspawn_scope_prefix), machineScopeNameLen))
+ return false;
+
+ if (!w(s, ']'))
+ return false;
+
+ cgroup = nextSlash;
+ if (String_startsWith(nextSlash, str_nspawn_monitor_label))
+ cgroup += strlen(str_nspawn_monitor_label);
+ else if (String_startsWith(nextSlash, str_nspawn_payload_label))
+ cgroup += strlen(str_nspawn_payload_label);
+
+ continue;
+ }
+
+ if (!w(s, '!'))
+ return false;
+
+ if (!StrBuf_putsn(s, w, cgroup, scopeNameLen))
+ return false;
+
+ cgroup = nextSlash;
+
+ continue;
+ }
+
+ // Default behavior: Copy the full label
+ cgroup = labelStart;
+
+ if (!StrBuf_putsn(s, w, cgroup, labelLen))
+ return false;
+
+ cgroup = nextSlash;
+ }
+
+ return true;
+}
+
+char* CGroup_filterName(const char *cgroup) {
+ StrBuf_state s = {
+ .buf = NULL,
+ .size = 0,
+ .pos = 0,
+ };
+
+ if (!CGroup_filterName_internal(cgroup, &s, StrBuf_putc_count)) {
+ return NULL;
+ }
+
+ s.buf = xCalloc(s.pos + 1, sizeof(char));
+ s.size = s.pos;
+ s.pos = 0;
+
+ if (!CGroup_filterName_internal(cgroup, &s, StrBuf_putc_write)) {
+ free(s.buf);
+ return NULL;
+ }
+
+ s.buf[s.size] = '\0';
+ return s.buf;
+}
diff --git a/linux/CGroupUtils.h b/linux/CGroupUtils.h
new file mode 100644
index 00000000..db2df7f4
--- /dev/null
+++ b/linux/CGroupUtils.h
@@ -0,0 +1,16 @@
+#ifndef HEADER_CGroupUtils
+#define HEADER_CGroupUtils
+/*
+htop - CGroupUtils.h
+(C) 2021 htop dev team
+Released under the GNU GPLv2+, see the COPYING file
+in the source distribution for its full text.
+*/
+
+#include <stdbool.h>
+#include <stddef.h>
+
+
+char* CGroup_filterName(const char *cgroup);
+
+#endif /* HEADER_CGroupUtils */
diff --git a/linux/LinuxProcess.c b/linux/LinuxProcess.c
index 7b48c936..ba2dbd46 100644
--- a/linux/LinuxProcess.c
+++ b/linux/LinuxProcess.c
@@ -81,7 +81,8 @@ const ProcessFieldData Process_fields[LAST_PROCESSFIELD] = {
[IO_READ_RATE] = { .name = "IO_READ_RATE", .title = " DISK READ ", .description = "The I/O rate of read(2) in bytes per second for the process", .flags = PROCESS_FLAG_IO, .defaultSortDesc = true, },
[IO_WRITE_RATE] = { .name = "IO_WRITE_RATE", .title = " DISK WRITE ", .description = "The I/O rate of write(2) in bytes per second for the process", .flags = PROCESS_FLAG_IO, .defaultSortDesc = true, },
[IO_RATE] = { .name = "IO_RATE", .title = " DISK R/W ", .description = "Total I/O rate in bytes per second", .flags = PROCESS_FLAG_IO, .defaultSortDesc = true, },
- [CGROUP] = { .name = "CGROUP", .title = " CGROUP ", .description = "Which cgroup the process is in", .flags = PROCESS_FLAG_LINUX_CGROUP, },
+ [CGROUP] = { .name = "CGROUP", .title = "CGROUP (raw) ", .description = "Which cgroup the process is in", .flags = PROCESS_FLAG_LINUX_CGROUP, },
+ [CCGROUP] = { .name = "CCGROUP", .title = "CGROUP (compressed) ", .description = "Which cgroup the process is in (condensed to essentials)", .flags = PROCESS_FLAG_LINUX_CGROUP, },
[OOM] = { .name = "OOM", .title = " OOM ", .description = "OOM (Out-of-Memory) killer score", .flags = PROCESS_FLAG_LINUX_OOM, .defaultSortDesc = true, },
[IO_PRIORITY] = { .name = "IO_PRIORITY", .title = "IO ", .description = "I/O priority", .flags = PROCESS_FLAG_LINUX_IOPRIO, },
#ifdef HAVE_DELAYACCT
@@ -111,6 +112,7 @@ Process* LinuxProcess_new(const Settings* settings) {
void Process_delete(Object* cast) {
LinuxProcess* this = (LinuxProcess*) cast;
Process_done((Process*)cast);
+ free(this->cgroup_short);
free(this->cgroup);
#ifdef HAVE_OPENVZ
free(this->ctid);
@@ -246,7 +248,8 @@ static void LinuxProcess_writeField(const Process* this, RichString* str, Proces
#ifdef HAVE_VSERVER
case VXID: xSnprintf(buffer, n, "%5u ", lp->vxid); break;
#endif
- case CGROUP: xSnprintf(buffer, n, "%-10s ", lp->cgroup ? lp->cgroup : ""); break;
+ case CGROUP: xSnprintf(buffer, n, "%-35.35s ", lp->cgroup ? lp->cgroup : "N/A"); break;
+ case CCGROUP: xSnprintf(buffer, n, "%-35.35s ", lp->cgroup_short ? lp->cgroup_short : (lp->cgroup ? lp->cgroup : "N/A")); break;
case OOM: xSnprintf(buffer, n, "%4u ", lp->oom); break;
case IO_PRIORITY: {
int klass = IOPriority_class(lp->ioPriority);
@@ -370,6 +373,8 @@ static int LinuxProcess_compareByKey(const Process* v1, const Process* v2, Proce
#endif
case CGROUP:
return SPACESHIP_NULLSTR(p1->cgroup, p2->cgroup);
+ case CCGROUP:
+ return SPACESHIP_NULLSTR(p1->cgroup_short, p2->cgroup_short);
case OOM:
return SPACESHIP_NUMBER(p1->oom, p2->oom);
#ifdef HAVE_DELAYACCT
diff --git a/linux/LinuxProcess.h b/linux/LinuxProcess.h
index b4e1a8bf..3e5d3804 100644
--- a/linux/LinuxProcess.h
+++ b/linux/LinuxProcess.h
@@ -89,6 +89,7 @@ typedef struct LinuxProcess_ {
unsigned int vxid;
#endif
char* cgroup;
+ char* cgroup_short;
unsigned int oom;
#ifdef HAVE_DELAYACCT
unsigned long long int delay_read_time;
diff --git a/linux/LinuxProcessList.c b/linux/LinuxProcessList.c
index a2d3d2be..3bfe7db5 100644
--- a/linux/LinuxProcessList.c
+++ b/linux/LinuxProcessList.c
@@ -45,6 +45,7 @@ in the source distribution for its full text.
#include "Process.h"
#include "Settings.h"
#include "XUtils.h"
+#include "linux/CGroupUtils.h"
#include "linux/LinuxProcess.h"
#include "linux/Platform.h" // needed for GNU/hurd to get PATH_MAX // IWYU pragma: keep
@@ -860,6 +861,10 @@ static void LinuxProcessList_readCGroupFile(LinuxProcess* process, openat_arg_t
free(process->cgroup);
process->cgroup = NULL;
}
+ if (process->cgroup_short) {
+ free(process->cgroup_short);
+ process->cgroup_short = NULL;
+ }
return;
}
char output[PROC_LINE_LENGTH + 1];
@@ -872,9 +877,16 @@ static void LinuxProcessList_readCGroupFile(LinuxProcess* process, openat_arg_t
if (!ok)
break;
- char* group = strchr(buffer, ':');
- if (!group)
- break;
+ char* group = buffer;
+ for (size_t i = 0; i < 2; i++) {
+ group = strchrnul(group, ':');
+ if (!*group)
+ break;
+ group++;
+ }
+
+ char* eol = strchrnul(group, '\n');
+ *eol = '\0';
if (at != output) {
*at = ';';
@@ -885,7 +897,22 @@ static void LinuxProcessList_readCGroupFile(LinuxProcess* process, openat_arg_t
left -= wrote;
}
fclose(file);
+
+ bool changed = !process->cgroup || !String_eq(process->cgroup, output);
+
free_and_xStrdup(&process->cgroup, output);
+
+ if (!changed)
+ return;
+
+ char* cgroup_short = CGroup_filterName(process->cgroup);
+ if (cgroup_short) {
+ free_and_xStrdup(&process->cgroup_short, cgroup_short);
+ free(cgroup_short);
+ } else {
+ free(process->cgroup_short);
+ process->cgroup_short = NULL;
+ }
}
#ifdef HAVE_VSERVER
diff --git a/linux/ProcessField.h b/linux/ProcessField.h
index 70475929..17cafa96 100644
--- a/linux/ProcessField.h
+++ b/linux/ProcessField.h
@@ -45,6 +45,7 @@ in the source distribution for its full text.
SECATTR = 123, \
AUTOGROUP_ID = 127, \
AUTOGROUP_NICE = 128, \
+ CCGROUP = 129, \
// End of list

© 2014-2024 Faster IT GmbH | imprint | privacy policy