123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532 |
- /*
- htop - CGroupUtils.c
- (C) 2021 htop dev team
- Released under the GNU GPLv2+, see the COPYING file
- in the source distribution for its full text.
- */
- #include "config.h" // IWYU pragma: keep
- #include "linux/CGroupUtils.h"
- #include <stdbool.h>
- #include <stddef.h>
- #include <stdlib.h>
- #include <string.h>
- #include "Macros.h"
- #include "XUtils.h"
- static const char* str_slice_suffix = ".slice";
- static const char* str_system_slice = "system.slice";
- static const char* str_user_slice = "user.slice";
- static const char* str_machine_slice = "machine.slice";
- static const char* str_user_slice_prefix = "/user-";
- static const char* str_system_slice_prefix = "/system-";
- static const char* str_lxc_monitor_legacy = "lxc.monitor";
- static const char* str_lxc_payload_legacy = "lxc.payload";
- static const char* str_lxc_monitor_prefix = "lxc.monitor.";
- static const char* str_lxc_payload_prefix = "lxc.payload.";
- static const char* str_nspawn_scope_prefix = "machine-";
- static const char* str_nspawn_monitor_label = "/supervisor";
- static const char* str_nspawn_payload_label = "/payload";
- static const char* str_snap_scope_prefix = "snap.";
- static const char* str_pod_scope_prefix = "libpod-";
- static const char* str_docker_scope_prefix = "docker-";
- static const char* str_service_suffix = ".service";
- static const char* str_scope_suffix = ".scope";
- 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) {
- while (*cgroup) {
- if ('/' == *cgroup) {
- while ('/' == *cgroup)
- cgroup++;
- if (!w(s, '/'))
- return false;
- continue;
- }
- const char* labelStart = cgroup;
- const char* nextSlash = String_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;
- if (String_startsWith(cgroup, str_system_slice_prefix)) {
- cgroup = String_strchrnul(cgroup + 1, '/');
- continue;
- }
- 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 = String_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 = String_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;
- } else if (Label_checkPrefix(labelStart, scopeNameLen, str_snap_scope_prefix)) {
- const char* nextDot = String_strchrnul(labelStart + strlen(str_snap_scope_prefix), '.');
- if (!StrBuf_putsz(s, w, "!snap:"))
- return false;
- if (nextDot >= labelStart + scopeNameLen) {
- nextDot = labelStart + scopeNameLen;
- }
- if (!StrBuf_putsn(s, w, labelStart + strlen(str_snap_scope_prefix), nextDot - (labelStart + strlen(str_snap_scope_prefix))))
- return false;
- cgroup = nextSlash;
- continue;
- } else if (Label_checkPrefix(labelStart, scopeNameLen, str_pod_scope_prefix)) {
- const char* nextDot = String_strchrnul(labelStart + strlen(str_pod_scope_prefix), '.');
- if (!StrBuf_putsz(s, w, "!pod:"))
- return false;
- if (nextDot >= labelStart + scopeNameLen) {
- nextDot = labelStart + scopeNameLen;
- }
- if (!StrBuf_putsn(s, w, labelStart + strlen(str_pod_scope_prefix),
- MINIMUM( nextDot - (labelStart + strlen(str_pod_scope_prefix)), 12)))
- return false;
- cgroup = nextSlash;
- continue;
- } else if (Label_checkPrefix(labelStart, scopeNameLen, str_docker_scope_prefix)) {
- const char* nextDot = String_strchrnul(labelStart + strlen(str_docker_scope_prefix), '.');
- if (!StrBuf_putsz(s, w, "!docker:"))
- return false;
- if (nextDot >= labelStart + scopeNameLen) {
- nextDot = labelStart + scopeNameLen;
- }
- if (!StrBuf_putsn(s, w, labelStart + strlen(str_docker_scope_prefix),
- MINIMUM( nextDot - (labelStart + strlen(str_docker_scope_prefix)), 12)))
- return false;
- cgroup = nextSlash;
- 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;
- }
- static bool CGroup_filterContainer_internal(const char* cgroup, StrBuf_state* s, StrBuf_putc_t w) {
- while (*cgroup) {
- if ('/' == *cgroup) {
- while ('/' == *cgroup)
- cgroup++;
- continue;
- }
- const char* labelStart = cgroup;
- const char* nextSlash = String_strchrnul(labelStart, '/');
- const size_t labelLen = nextSlash - labelStart;
- 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;
- cgroup = nextSlash;
- continue;
- }
- // LXC legacy cgroup naming
- if (Label_checkEqual(labelStart, labelLen, str_lxc_payload_legacy)) {
- labelStart = nextSlash;
- while (*labelStart == '/')
- labelStart++;
- nextSlash = String_strchrnul(labelStart, '/');
- if (nextSlash - labelStart > 0) {
- if (!StrBuf_putsz(s, w, "/lxc:"))
- return false;
- if (!StrBuf_putsn(s, w, labelStart, nextSlash - labelStart))
- return false;
- cgroup = nextSlash;
- continue;
- }
- labelStart = cgroup;
- nextSlash = labelStart + labelLen;
- }
- 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 (!is_monitor) {
- if (!StrBuf_putsz(s, w, "/snc:"))
- return false;
- if (!StrBuf_putsn(s, w, cgroup + strlen(str_nspawn_scope_prefix), machineScopeNameLen))
- 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;
- } else if (Label_checkPrefix(labelStart, scopeNameLen, str_pod_scope_prefix)) {
- const char* nextDot = String_strchrnul(labelStart + strlen(str_pod_scope_prefix), '.');
- if (!StrBuf_putsz(s, w, "/pod:"))
- return false;
- if (nextDot >= labelStart + scopeNameLen) {
- nextDot = labelStart + scopeNameLen;
- }
- if (!StrBuf_putsn(s, w, labelStart + strlen(str_pod_scope_prefix),
- MINIMUM( nextDot - (labelStart + strlen(str_pod_scope_prefix)), 12)))
- return false;
- cgroup = nextSlash;
- continue;
- } else if (Label_checkPrefix(labelStart, scopeNameLen, str_docker_scope_prefix)) {
- const char* nextDot = String_strchrnul(labelStart + strlen(str_docker_scope_prefix), '.');
- if (!StrBuf_putsz(s, w, "!docker:"))
- return false;
- if (nextDot >= labelStart + scopeNameLen) {
- nextDot = labelStart + scopeNameLen;
- }
- if (!StrBuf_putsn(s, w, labelStart + strlen(str_docker_scope_prefix),
- MINIMUM( nextDot - (labelStart + strlen(str_docker_scope_prefix)), 12)))
- return false;
- cgroup = nextSlash;
- continue;
- }
- cgroup = nextSlash;
- continue;
- }
- cgroup = nextSlash;
- }
- return true;
- }
- char* CGroup_filterContainer(const char* cgroup) {
- StrBuf_state s = {
- .buf = NULL,
- .size = 0,
- .pos = 0,
- };
- if (!CGroup_filterContainer_internal(cgroup, &s, StrBuf_putc_count)) {
- return NULL;
- }
- if (!s.pos) {
- return xStrdup("/");
- }
- s.buf = xCalloc(s.pos + 1, sizeof(char));
- s.size = s.pos;
- s.pos = 0;
- if (!CGroup_filterContainer_internal(cgroup, &s, StrBuf_putc_write)) {
- free(s.buf);
- return NULL;
- }
- s.buf[s.size] = '\0';
- return s.buf;
- }
|