You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
317 lines
8.3 KiB
317 lines
8.3 KiB
/* |
|
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) { |
|
for (; count; 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; |
|
}
|
|
|