#include <config.h> #include <cstring> #include <glib/gi18n.h> #include "cgroups.h" #include "util.h" gboolean cgroups_enabled(void) { static gboolean initialized = FALSE; static gboolean has_cgroups; if (!initialized) { initialized = TRUE; has_cgroups = g_file_test("/proc/cgroups", G_FILE_TEST_EXISTS); } return has_cgroups; } static void append_cgroup_name(char *line, gchar **current_cgroup_name) { gchar *controller, *path, *tmp, *path_plus_space; int paren_offset, off, tmp_size; controller = g_strstr_len(line, -1, ":") + 1; if (!controller) return; path = g_strstr_len(controller, -1, ":") + 1; if (!path) return; *(path - 1) = '\0'; g_strdelimit(controller, ",", '/'); if ((std::strcmp(path, "/") == 0) || (std::strncmp(controller, "name=", 5) == 0)) return; if (*current_cgroup_name == NULL) { *current_cgroup_name = g_strdup_printf("%s (%s)", path, controller); return; } /* add a space to the end of the path string */ path_plus_space = g_strdup_printf("%s ", path); if ((tmp = g_strstr_len(*current_cgroup_name, -1, path_plus_space))) { tmp_size = strlen(*current_cgroup_name) + strlen(controller) + 1; paren_offset = g_strstr_len(tmp + strlen(path), -1, ")") - *current_cgroup_name; *(*current_cgroup_name + paren_offset) = '\0'; tmp = (gchar *)g_strnfill(tmp_size, '\0'); off = g_strlcat(tmp, *current_cgroup_name, tmp_size); *(tmp + off) = '/'; off++; off += g_strlcat(tmp + off, controller, tmp_size); *(tmp + off) = ')'; off++; g_strlcat(tmp + off, *current_cgroup_name + paren_offset + 1, tmp_size); } else tmp = g_strdup_printf("%s, %s(%s)", *current_cgroup_name, path_plus_space, controller); g_free(path_plus_space); g_free(*current_cgroup_name); *current_cgroup_name = tmp; } static int check_cgroup_changed(gchar *line, gchar *current_cgroup_set) { /* check if line is contained in current_cgroup_set */ gchar *controller, *path, *tmp, *found, *close_paren, *open_paren; int ret = 0; controller = g_strstr_len(line, -1, ":") + 1; if (!controller) return 1; path = g_strstr_len(controller, -1, ":") + 1; if (!path) return 1; *(path - 1) = '\0'; if (std::strncmp(controller, "name=", 5) == 0) goto out; /* if there are multiple controllers just report string has changed */ if (g_strstr_len(controller, -1, ",")) { ret = 1; goto out; } if (!current_cgroup_set) { if (std::strcmp(path, "/") != 0) ret = 1; goto out; } /* special case for root cgroup */ tmp = current_cgroup_set; if (std::strcmp(path, "/") == 0) { while ((found = g_strstr_len(tmp, -1, controller))) { close_paren = g_strstr_len(found, -1, ")"); open_paren = g_strstr_len(found, -1, "("); if (close_paren) { if (!open_paren || (close_paren < open_paren)) { ret = 1; goto out; } } tmp = found + strlen(controller); } goto out; } tmp = current_cgroup_set; while ((found = g_strstr_len(tmp, -1, path))) { found = found + strlen(path); close_paren = g_strstr_len(found, -1, ")"); if (*found == ' ') { if (g_strstr_len(found + 1, close_paren - found, controller)) goto out; } tmp = close_paren + 1; } ret = 1; out: *(path - 1) = ':'; return ret; } void get_process_cgroup_info(ProcInfo *info) { gchar *path; gchar *cgroup_name = NULL; int cgroups_changed = 0; gchar *text; char **lines; int i; if (!cgroups_enabled()) return; /* read out of /proc/pid/cgroup */ path = g_strdup_printf("/proc/%d/cgroup", info->pid); if (!path) return; if(!g_file_get_contents(path, &text, NULL, NULL)) goto out; lines = g_strsplit(text, "\n", -1); g_free(text); if (!lines) goto out; for (i = 0; lines[i] != NULL; i++) { if (lines[i][0] == '\0') continue; if (check_cgroup_changed(lines[i], info->cgroup_name)) { cgroups_changed = 1; break; } } if (cgroups_changed) { for (i = 0; lines[i] != NULL; i++) { if (lines[i][0] == '\0') continue; append_cgroup_name(lines[i], &cgroup_name); } if (info->cgroup_name) g_free(info->cgroup_name); if (!cgroup_name) info->cgroup_name = g_strdup(""); else info->cgroup_name = cgroup_name; } g_strfreev(lines); out: g_free(path); }