diff options
-rw-r--r-- | api.c | 86 | ||||
-rw-r--r-- | libcgroup.h | 6 | ||||
-rw-r--r-- | tests/Makefile | 6 | ||||
-rw-r--r-- | tests/pathtest.c | 40 | ||||
-rwxr-xr-x | tests/pathtest.sh | 12 |
5 files changed, 149 insertions, 1 deletions
@@ -1908,3 +1908,89 @@ int cgroup_init_rules_cache() return ret; } + +/** + * cgroup_get_current_controller_path + * @pid: pid of the current process for which the path is to be determined + * @controller: name of the controller for which to determine current path + * @current_path: a pointer that is filled with the value of the current + * path as seen in /proc/<pid>/cgroup + */ +int cgroup_get_current_controller_path(pid_t pid, const char *controller, + char **current_path) +{ + char *path; + int ret; + FILE *pid_cgroup_fd; + + if (!controller) + return ECGOTHER; + + if (!cgroup_initialized) { + dbg("libcgroup is not initialized\n"); + return ECGROUPNOTINITIALIZED; + } + + ret = asprintf(&path, "/proc/%d/cgroup", pid); + if (ret <= 0) { + dbg("cannot allocate memory (/proc/pid/cgroup) ret %d\n", ret); + return ret; + } + + ret = ECGROUPNOTEXIST; + pid_cgroup_fd = fopen(path, "r"); + if (!pid_cgroup_fd) + goto cleanup_path; + + /* + * Why do we grab the cg_mount_table_lock?, the reason is that + * the cgroup of a pid can change via the cgroup_attach_task_pid() + * call. To make sure, we return consitent and safe results, + * we acquire the lock upfront. We can optimize by acquiring + * and releasing the lock in the while loop, but that + * will be more expensive. + */ + pthread_rwlock_rdlock(&cg_mount_table_lock); + while (!feof(pid_cgroup_fd)) { + char controllers[FILENAME_MAX]; + char cgroup_path[FILENAME_MAX]; + int num; + char *savedptr; + char *token; + + ret = fscanf(pid_cgroup_fd, "%d:%[^:]:%s\n", &num, controllers, + cgroup_path); + /* + * Magic numbers like "3" seem to be integrating into + * my daily life, I need some magic to help make them + * disappear :) + */ + if (ret != 3 || ret == EOF) { + dbg("read failed for pid_cgroup_fd ret %d\n", ret); + ret = ECGOTHER; + goto done; + } + + token = strtok_r(controllers, ",", &savedptr); + do { + if (strncmp(controller, token, strlen(controller) + 1) + == 0) { + *current_path = strdup(cgroup_path); + if (!*current_path) { + ret = ECGOTHER; + goto done; + } + ret = 0; + goto done; + } + token = strtok_r(NULL, ",", &savedptr); + } while (token); + } + +done: + pthread_rwlock_unlock(&cg_mount_table_lock); + fclose(pid_cgroup_fd); +cleanup_path: + free(path); + return ret; +} diff --git a/libcgroup.h b/libcgroup.h index c9e9689..97c663d 100644 --- a/libcgroup.h +++ b/libcgroup.h @@ -255,6 +255,12 @@ int cgroup_reload_cached_rules(void); */ int cgroup_init_rules_cache(void); +/** + * Get the current cgroup path where the task specified by pid_t pid + * has been classified + */ +int cgroup_get_current_controller_path(pid_t pid, const char *controller, + char **current_path); /* The wrappers for filling libcg structures */ diff --git a/tests/Makefile b/tests/Makefile index 7a38b7a..5c602cb 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -6,7 +6,8 @@ CFLAGS = -g -O2 -Wall -DDEBUG TARGET= libcgrouptest01 \ libcg_ba \ - setuid + setuid \ + pathtest all: $(TARGET) @@ -19,5 +20,8 @@ libcg_ba: libcg_ba.cpp setuid: setuid.c $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS) $(LIBS) +pathtest: pathtest.c + $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS) $(LIBS) + clean: \rm -f $(TARGET) diff --git a/tests/pathtest.c b/tests/pathtest.c new file mode 100644 index 0000000..076c38a --- /dev/null +++ b/tests/pathtest.c @@ -0,0 +1,40 @@ +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <unistd.h> +#include <string.h> +#include <libcgroup.h> + +int main(int argc, char *argv[]) +{ + char *path; + char *expected_path, *controller; + int ret; + + if (argc < 2) { + fprintf(stderr, "Usage %s: <controller name> <path>\n", + argv[0]); + exit(EXIT_FAILURE); + } + + controller = argv[1]; + expected_path = argv[2]; + + cgroup_init(); + + ret = cgroup_get_current_controller_path(getpid(), controller, &path); + if (ret) + printf("Test FAIL, get path failed for controller %s\n", + controller); + else { + if (strcmp(path, expected_path)) + printf("Test FAIL, expected_path %s, got path %s\n", + expected_path, path); + else + printf("Test PASS, controller %s path %s\n", + controller, path); + free(path); + } + + return EXIT_SUCCESS; +} diff --git a/tests/pathtest.sh b/tests/pathtest.sh new file mode 100755 index 0000000..b373389 --- /dev/null +++ b/tests/pathtest.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +while read name extra +do + echo $name | grep -q '^#' + if [ $? -eq 0 ] + then + continue + fi + path=`cat /proc/$$/cgroup | cut -d ':' -f 3` + ./pathtest $name $path +done < /proc/cgroups |