From 807404116413414133a7adf40e964ab82192a68b Mon Sep 17 00:00:00 2001 From: Balbir Singh Date: Mon, 7 Apr 2008 13:27:39 +0000 Subject: This patch modifies libcg to use the new cgroup data structure. Signed-off-by: Dhaval Giani The code is yet to be tested though git-svn-id: https://libcg.svn.sourceforge.net/svnroot/libcg/branches/balbir@7 4f4bb910-9a46-0410-90c8-c897d4f1cd53 --- api.c | 150 +++++++++++++++++++++++++++++++----------------------------------- 1 file changed, 70 insertions(+), 80 deletions(-) (limited to 'api.c') diff --git a/api.c b/api.c index f842040..756a331 100644 --- a/api.c +++ b/api.c @@ -75,21 +75,33 @@ static inline pid_t cg_gettid() return syscall(__NR_gettid); } -/* +static char* cg_build_path(char *name, char *path) +{ + strcpy(path, MOUNT_POINT); + strcat(path, name); + strcat(path, "/"); + return path; +} + +/** cg_attach_task_pid is used to assign tasks to a cgroup. + * struct cgroup *cgroup: The cgroup to assign the thread to. + * pid_t tid: The thread to be assigned to the cgroup. + * + * returns 0 on success. + * returns ECGROUPNOTOWNER if the caller does not have access to the cgroup. + * returns ECGROUPNOTALLOWED for other causes of failure. */ -int cg_attach_task_pid(char *cgroup, pid_t tid) +int cg_attach_task_pid(struct cgroup *cgroup, pid_t tid) { char path[FILENAME_MAX]; FILE *tasks; - if (cgroup == NULL) { - cgroup = (char *) malloc(sizeof(char)); - cgroup = "\0"; + if (cgroup == NULL) + strcpy(path, MOUNT_POINT); + else { + cg_build_path(cgroup->name, path); } - strcpy(path, MOUNT_POINT); - strcat(path, "/"); - strcat(path, cgroup); strcat(path, "/tasks"); tasks = fopen(path, "w"); @@ -107,12 +119,12 @@ int cg_attach_task_pid(char *cgroup, pid_t tid) } -/* - * Used to attach the task to a control group. +/** cg_attach_task is used to attach the current thread to a cgroup. + * struct cgroup *cgroup: The cgroup to assign the current thread to. * - * WARNING: Will change to use struct cgroup when it is implemented. + * See cg_attach_task_pid for return values. */ -int cg_attach_task(char *cgroup) +int cg_attach_task(struct cgroup *cgroup) { pid_t tid = cg_gettid(); int error; @@ -192,46 +204,37 @@ static int cg_set_control_value(char *path, char *val) return 0; } -/* - * WARNING: This API is not final. It WILL change format to use - * struct cgroup. This API will then become internal and be called something - * else. +/** cg_modify_cgroup modifies the cgroup control files. + * struct cgroup *cgroup: The name will be the cgroup to be modified. + * The values will be the values to be modified, those not mentioned + * in the structure will not be modified. * - * I am still not happy with how the data structure is looking at the moment, - * plus there are a couple of additional details to be worked out. Please - * do not rely on this API. - * - * Be prepared to change the implementation later once it shifts to - * struct cgroup in the real alpha release. - * - * The final version is expected to be - * - * int modify_cgroup(struct cgroup *original, struct cgroup *final); + * The uids cannot be modified yet. * - * where original is the cgroup which is to be modified and final is how it - * should look. + * returns 0 on success. * - * Also this version is still at one level since we do not have - * multi-hierarchy support in kernel. The real alpha release should have this - * issue sorted out as well. */ -int cg_modify_cgroup(char *cgroup, struct control_value *values[], int n) +int cg_modify_cgroup(struct cgroup *cgroup) { char path[FILENAME_MAX], base[FILENAME_MAX]; int i; int error; - strcpy(base, MOUNT_POINT); - strcat(base, "/"); - strcat(base, cgroup); - strcat(base, "/"); - - for (i = 0; i < n; i++, strcpy(path, base)) { - strcat(path, values[i]->name); - error = cg_set_control_value(path, values[i]->value); - if (error) - goto err; + cg_build_path(cgroup->name, base); + + for (i = 0; i < CG_CONTROLLER_MAX && cgroup->controller[i]; + i++, strcpy(path, base)) { + int j; + for(j = 0; j < CG_NV_MAX && + cgroup->controller[i]->values[j]; + j++, strcpy(path, base)) { + strcat(path, cgroup->controller[i]->values[j]->name); + error = cg_set_control_value(path, + cgroup->controller[i]->values[j]->value); + if (error) + goto err; + } } return 0; err: @@ -261,7 +264,7 @@ err: * multi-hierarchy support in kernel. The real alpha release should have this * issue sorted out as well. */ -int cg_create_cgroup(char *cgroup, struct control_value *values[], int n) +int cg_create_cgroup(struct cgroup *cgroup) { char path[FILENAME_MAX], base[FILENAME_MAX]; int i; @@ -270,46 +273,37 @@ int cg_create_cgroup(char *cgroup, struct control_value *values[], int n) if (MOUNT_POINT == NULL) return ECGROUPNOTMOUNTED; - strcpy(path, MOUNT_POINT); - strcat(path, "/"); - strcat(path, cgroup); + cg_build_path(cgroup->name, path); error = cg_create_control_group(path); - strcat(path, "/"); + strcpy(base, path); - for (i = 0; i < n; i++, strcpy(path, base)) { - strcat(path, values[i]->name); - error = cg_set_control_value(path, values[i]->value); - if (!error) - return error; + for (i = 0; i < CG_CONTROLLER_MAX && cgroup->controller[i]; + i++, strcpy(path, base)) { + int j; + for(j = 0; j < CG_NV_MAX && cgroup->controller[i]->values[j]; + j++, strcpy(path, base)) { + strcat(path, cgroup->controller[i]->values[j]->name); + error = cg_set_control_value(path, + cgroup->controller[i]->values[j]->value); + chown(path, cgroup->control_uid, cgroup->control_gid); + if (!error) + return error; + } } + strcpy(path, base); + strcat(path, "tasks"); + chown(path, cgroup->tasks_uid, cgroup->tasks_gid); return error; } -/* - * WARNING: This API is not final. It WILL change format to use - * struct cgroup. This API will then become internal and be called something - * else. - * - * I am still not happy with how the data structure is looking at the moment, - * plus there are a couple of additional details to be worked out. Please - * do not rely on this API. - * - * Be prepared to change the implementation later once it shifts to - * struct cgroup in the real alpha release. - * - * The final version is expected to be +/** cg_delete cgroup deletes a control group. + * struct cgroup *cgroup takes the group which is to be deleted. * - * int delete_cgroup(struct cgroup *group); - * - * where group is the group to be deleted. - * - * Also this version is still at one level since we do not have - * multi-hierarchy support in kernel. The real alpha release should have this - * issue sorted out as well. + * returns 0 on success. */ -int cg_delete_cgroup(char *cgroup) +int cg_delete_cgroup(struct cgroup *cgroup) { FILE *delete_tasks, *base_tasks; int tids; @@ -321,10 +315,8 @@ int cg_delete_cgroup(char *cgroup) base_tasks = fopen(path, "w"); - strcpy(path, MOUNT_POINT); - strcat(path, "/"); - strcat(path, cgroup); - strcat(path,"/tasks"); + cg_build_path(cgroup->name, path); + strcat(path,"tasks"); delete_tasks = fopen(path, "r"); @@ -333,9 +325,7 @@ int cg_delete_cgroup(char *cgroup) fprintf(base_tasks, "%d", tids); } - strcpy(path, MOUNT_POINT); - strcat(path, "/"); - strcat(path, cgroup); + cg_build_path(cgroup->name, path); error = rmdir(path); -- cgit From 95a73795a8dc1dcd3888150bbafc52254296ab3c Mon Sep 17 00:00:00 2001 From: Balbir Singh Date: Thu, 10 Apr 2008 11:37:35 +0000 Subject: This patch fixes file handle leaks as noticed by Paul Menage. Signed-off-by: Dhaval Giani git-svn-id: https://libcg.svn.sourceforge.net/svnroot/libcg/branches/balbir@8 4f4bb910-9a46-0410-90c8-c897d4f1cd53 --- api.c | 28 ++++++++-------------------- 1 file changed, 8 insertions(+), 20 deletions(-) (limited to 'api.c') diff --git a/api.c b/api.c index 756a331..df594ea 100644 --- a/api.c +++ b/api.c @@ -48,6 +48,7 @@ int cg_init() return ECGROUPNOTMOUNTED; } strcpy(MOUNT_POINT, ent->mnt_dir); + fclose(proc_mount); return 0; } @@ -67,6 +68,7 @@ static int cg_test_mounted_fs() if (ent == NULL) return 0; } + fclose(proc_mount); return 1; } @@ -114,6 +116,7 @@ int cg_attach_task_pid(struct cgroup *cgroup, pid_t tid) } } fprintf(tasks, "%d", tid); + fclose(tasks); return 0; @@ -196,11 +199,13 @@ static int cg_set_control_value(char *path, char *val) if (errno == ENOENT) return ECGROUPSUBSYSNOTMOUNTED; } + fclose(control_file); return ECGROUPNOTALLOWED; } } fprintf(control_file, "%s", val); + fclose(control_file); return 0; } @@ -242,27 +247,10 @@ err: } -/* - * WARNING: This API is not final. It WILL change format to use - * struct cgroup. This API will then become internal and be called something - * else. - * - * I am still not happy with how the data structure is looking at the moment, - * plus there are a couple of additional details to be worked out. Please - * do not rely on this API. - * - * Be prepared to change the implementation later once it shifts to - * struct cgroup in the real alpha release. - * - * The final version is expected to be +/** create_cgroup creates a new control group. + * struct cgroup *cgroup: The control group to be created * - * int create_cgroup(struct cgroup *group); - * - * where group is the group to be created - * - * Also this version is still at one level since we do not have - * multi-hierarchy support in kernel. The real alpha release should have this - * issue sorted out as well. + * returns 0 on success. */ int cg_create_cgroup(struct cgroup *cgroup) { -- cgit From 2be6ec85fb430e17afcf16b0ab84e4f966920472 Mon Sep 17 00:00:00 2001 From: Balbir Singh Date: Fri, 11 Apr 2008 19:38:06 +0000 Subject: Several bug fixes, some API enhancements. The first basic acceptance test is under development and first prototype is released api.c | 161 +++++++++++++++++++++++++++++++++++++++++++---------- libcg.h | 14 +--- tests/Makefile | 9 ++ tests/libcg_ba.cpp | 127 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 274 insertions(+), 37 deletions(-) Signed-off-by: Balbir Singh git-svn-id: https://libcg.svn.sourceforge.net/svnroot/libcg/branches/balbir@12 4f4bb910-9a46-0410-90c8-c897d4f1cd53 --- api.c | 161 ++++++++++++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 133 insertions(+), 28 deletions(-) (limited to 'api.c') diff --git a/api.c b/api.c index df594ea..8bf5607 100644 --- a/api.c +++ b/api.c @@ -2,6 +2,7 @@ * Copyright IBM Corporation. 2007 * * Author: Dhaval Giani + * Author: Balbir Singh * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2.1 of the GNU Lesser General Public License @@ -31,25 +32,110 @@ #include #include #include +#include +/* + * Remember to bump this up for major API changes. + */ +const static char cg_version[] = "0.01"; + +/* + * Only one mount point is currently supported. This will be enhanced to + * support several hierarchies in the future + */ static char MOUNT_POINT[FILENAME_MAX]; +static int cg_chown_file(FTS *fts, FTSENT *ent, uid_t owner, gid_t group) +{ + int ret = 1; + const char *filename = fts->fts_path; + dbg("seeing file %s\n", filename); + switch (ent->fts_info) { + case FTS_ERR: + errno = ent->fts_errno; + break; + case FTS_D: + case FTS_DC: + case FTS_NSOK: + case FTS_NS: + case FTS_DNR: + case FTS_DP: + case FTS_F: + case FTS_DEFAULT: + ret = chown(filename, owner, group); + break; + } + return ret; +} + +/* + * TODO: Need to decide a better place to put this function. + */ +static int cg_chown_recursive(const char *path, uid_t owner, gid_t group) +{ + int ret = 1; + dbg("path is %s\n", path); + FTS *fts = fts_open((char **)&path, FTS_PHYSICAL | FTS_NOCHDIR | + FTS_NOSTAT, NULL); + while (1) { + FTSENT *ent; + ent = fts_read(fts); + if (!ent) { + dbg("fts_read failed\n"); + break; + } + cg_chown_file(fts, ent, owner, group); + } + fts_close(fts); + return ret; +} + +/** + * cg_init(), initializes the MOUNT_POINT. + * This code is not currently thread safe (hint: getmntent is not thread safe). + * This API is likely to change in the future to push state back to the caller + * to achieve thread safety. The code currently supports just one mount point. + * Complain if the cgroup filesystem controllers are bound to different mount + * points. + */ int cg_init() { FILE *proc_mount; - struct mntent *ent; + struct mntent *ent, *found_ent = NULL; + int found_mnt = 0; + int ret = 0; proc_mount = fopen("/proc/mounts", "r"); - ent = getmntent(proc_mount); - while (strcmp(ent->mnt_fsname,"cgroup") != 0) { - ent = getmntent(proc_mount); - if (ent == NULL) - return ECGROUPNOTMOUNTED; + while ((ent = getmntent(proc_mount)) != NULL) { + if (!strncmp(ent->mnt_fsname,"cgroup", strlen("cgroup"))) { + found_ent = ent; + found_mnt++; + dbg("Found cgroup option %s, count %d\n", + found_ent->mnt_opts, found_mnt); + } + } + + /* + * Currently we require that all controllers be bound together + */ + if (!found_mnt) + ret = ECGROUPNOTMOUNTED; + if (found_mnt > 1) + ret = ECGROUPMULTIMOUNTED; + else { + /* + * NOTE: FILENAME_MAX ensures that we don't need to worry + * about crossing MOUNT_POINT size. For the paranoid, yes + * this is a potential security hole - Balbir + * Dhaval - fix these things. + */ + strcpy(MOUNT_POINT, found_ent->mnt_dir); + strcat(MOUNT_POINT, "/"); } - strcpy(MOUNT_POINT, ent->mnt_dir); + fclose(proc_mount); - return 0; + return ret; } static int cg_test_mounted_fs() @@ -148,8 +234,8 @@ static int cg_create_control_group(char *path) int error; if (!cg_test_mounted_fs()) return ECGROUPNOTMOUNTED; - error = mkdir(path, 0700); - if (!error) { + error = mkdir(path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); + if (error) { switch(errno) { case EPERM: return ECGROUPNOTOWNER; @@ -202,6 +288,7 @@ static int cg_set_control_value(char *path, char *val) fclose(control_file); return ECGROUPNOTALLOWED; } + return errno; } fprintf(control_file, "%s", val); @@ -250,23 +337,28 @@ err: /** create_cgroup creates a new control group. * struct cgroup *cgroup: The control group to be created * - * returns 0 on success. + * returns 0 on success. We recommend calling cg_delete_cgroup + * if this routine fails. That should do the cleanup operation. */ int cg_create_cgroup(struct cgroup *cgroup) { - char path[FILENAME_MAX], base[FILENAME_MAX]; + char *path, base[FILENAME_MAX]; int i; int error; - if (MOUNT_POINT == NULL) - return ECGROUPNOTMOUNTED; + path = (char *)malloc(FILENAME_MAX); + if (!path) + return ENOMEM; cg_build_path(cgroup->name, path); - error = cg_create_control_group(path); + if (error) + goto err; strcpy(base, path); + cg_chown_recursive(path, cgroup->control_uid, cgroup->control_gid); + for (i = 0; i < CG_CONTROLLER_MAX && cgroup->controller[i]; i++, strcpy(path, base)) { int j; @@ -274,15 +366,21 @@ int cg_create_cgroup(struct cgroup *cgroup) j++, strcpy(path, base)) { strcat(path, cgroup->controller[i]->values[j]->name); error = cg_set_control_value(path, - cgroup->controller[i]->values[j]->value); - chown(path, cgroup->control_uid, cgroup->control_gid); - if (!error) - return error; + cgroup->controller[i]->values[j]->value); + + /* + * Should we undo, what we've done in the loops above? + */ + if (error) + goto err; } } + strcpy(path, base); - strcat(path, "tasks"); + strcat(path, "/tasks"); chown(path, cgroup->tasks_uid, cgroup->tasks_gid); +err: + free(path); return error; } @@ -291,22 +389,26 @@ int cg_create_cgroup(struct cgroup *cgroup) * * returns 0 on success. */ -int cg_delete_cgroup(struct cgroup *cgroup) +int cg_delete_cgroup(struct cgroup *cgroup, int force) { FILE *delete_tasks, *base_tasks; int tids; char path[FILENAME_MAX]; - int error; + int error = ECGROUPNOTALLOWED; strcpy(path, MOUNT_POINT); strcat(path,"/tasks"); base_tasks = fopen(path, "w"); + if (!base_tasks) + goto base_open_err; cg_build_path(cgroup->name, path); - strcat(path,"tasks"); + strcat(path,"/tasks"); delete_tasks = fopen(path, "r"); + if (!delete_tasks) + goto del_open_err; while (!feof(delete_tasks)) { fscanf(delete_tasks, "%d", &tids); @@ -314,12 +416,15 @@ int cg_delete_cgroup(struct cgroup *cgroup) } cg_build_path(cgroup->name, path); - error = rmdir(path); - if (!error) { - return ECGROUPNOTALLOWED; - } - + fclose(delete_tasks); +del_open_err: + fclose(base_tasks); +base_open_err: + if (force) { + cg_build_path(cgroup->name, path); + error = rmdir(path); + } return error; } -- cgit From bbb65f3bbe504ad029577618708068a6ef9a9e57 Mon Sep 17 00:00:00 2001 From: Balbir Singh Date: Sat, 12 Apr 2008 05:17:30 +0000 Subject: Got recursive chown to work. API needs more changes to be able to ignore ownership arguments. api.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) Signed-off-by: Balbir Singh git-svn-id: https://libcg.svn.sourceforge.net/svnroot/libcg/branches/balbir@13 4f4bb910-9a46-0410-90c8-c897d4f1cd53 --- api.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'api.c') diff --git a/api.c b/api.c index 8bf5607..8dbeab9 100644 --- a/api.c +++ b/api.c @@ -71,11 +71,11 @@ static int cg_chown_file(FTS *fts, FTSENT *ent, uid_t owner, gid_t group) /* * TODO: Need to decide a better place to put this function. */ -static int cg_chown_recursive(const char *path, uid_t owner, gid_t group) +static int cg_chown_recursive(char **path, uid_t owner, gid_t group) { int ret = 1; - dbg("path is %s\n", path); - FTS *fts = fts_open((char **)&path, FTS_PHYSICAL | FTS_NOCHDIR | + dbg("path is %s\n", *path); + FTS *fts = fts_open(path, FTS_PHYSICAL | FTS_NOCHDIR | FTS_NOSTAT, NULL); while (1) { FTSENT *ent; @@ -342,13 +342,15 @@ err: */ int cg_create_cgroup(struct cgroup *cgroup) { - char *path, base[FILENAME_MAX]; + char *fts_path[2], base[FILENAME_MAX], *path; int i; int error; - path = (char *)malloc(FILENAME_MAX); - if (!path) + fts_path[0] = (char *)malloc(FILENAME_MAX); + if (!fts_path[0]) return ENOMEM; + fts_path[1] = NULL; + path = fts_path[0]; cg_build_path(cgroup->name, path); error = cg_create_control_group(path); @@ -357,7 +359,7 @@ int cg_create_cgroup(struct cgroup *cgroup) strcpy(base, path); - cg_chown_recursive(path, cgroup->control_uid, cgroup->control_gid); + cg_chown_recursive(fts_path, cgroup->control_uid, cgroup->control_gid); for (i = 0; i < CG_CONTROLLER_MAX && cgroup->controller[i]; i++, strcpy(path, base)) { -- cgit From 1603195881d3d7902a24cca1861f5808d50202db Mon Sep 17 00:00:00 2001 From: Balbir Singh Date: Wed, 16 Apr 2008 10:53:55 +0000 Subject: api.c | 23 +++++++++++++++-------- libcg.h | 4 ++-- tests/libcg_ba.cpp | 2 +- Added additional parameters for create and destroy cgroup. Fixed a cg_init segfault (faulty, if-else check) Signed-off-by: Balbir Singh git-svn-id: https://libcg.svn.sourceforge.net/svnroot/libcg/branches/balbir@15 4f4bb910-9a46-0410-90c8-c897d4f1cd53 --- api.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) (limited to 'api.c') diff --git a/api.c b/api.c index 8dbeab9..c2d6ef9 100644 --- a/api.c +++ b/api.c @@ -121,7 +121,7 @@ int cg_init() */ if (!found_mnt) ret = ECGROUPNOTMOUNTED; - if (found_mnt > 1) + else if (found_mnt > 1) ret = ECGROUPMULTIMOUNTED; else { /* @@ -340,7 +340,7 @@ err: * returns 0 on success. We recommend calling cg_delete_cgroup * if this routine fails. That should do the cleanup operation. */ -int cg_create_cgroup(struct cgroup *cgroup) +int cg_create_cgroup(struct cgroup *cgroup, int ignore_ownership) { char *fts_path[2], base[FILENAME_MAX], *path; int i; @@ -359,7 +359,12 @@ int cg_create_cgroup(struct cgroup *cgroup) strcpy(base, path); - cg_chown_recursive(fts_path, cgroup->control_uid, cgroup->control_gid); + if (!ignore_ownership) + error = cg_chown_recursive(fts_path, cgroup->control_uid, + cgroup->control_gid); + + if (error) + goto err; for (i = 0; i < CG_CONTROLLER_MAX && cgroup->controller[i]; i++, strcpy(path, base)) { @@ -378,9 +383,11 @@ int cg_create_cgroup(struct cgroup *cgroup) } } - strcpy(path, base); - strcat(path, "/tasks"); - chown(path, cgroup->tasks_uid, cgroup->tasks_gid); + if (!ignore_ownership) { + strcpy(path, base); + strcat(path, "/tasks"); + chown(path, cgroup->tasks_uid, cgroup->tasks_gid); + } err: free(path); return error; @@ -391,7 +398,7 @@ err: * * returns 0 on success. */ -int cg_delete_cgroup(struct cgroup *cgroup, int force) +int cg_delete_cgroup(struct cgroup *cgroup, int ignore_migration) { FILE *delete_tasks, *base_tasks; int tids; @@ -424,7 +431,7 @@ int cg_delete_cgroup(struct cgroup *cgroup, int force) del_open_err: fclose(base_tasks); base_open_err: - if (force) { + if (ignore_migration) { cg_build_path(cgroup->name, path); error = rmdir(path); } -- cgit From 5ddac5d87d47ace625a04146b91eed6c1ef9daea Mon Sep 17 00:00:00 2001 From: Balbir Singh Date: Fri, 18 Apr 2008 05:34:12 +0000 Subject: Miscellaneous scripts and libcg bug fixes Turn off -DDEBUG in Makefile Signed-off-by: Sudhir Kumar Signed-off-by: Balbir Singh git-svn-id: https://libcg.svn.sourceforge.net/svnroot/libcg/branches/balbir@18 4f4bb910-9a46-0410-90c8-c897d4f1cd53 --- api.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'api.c') diff --git a/api.c b/api.c index c2d6ef9..b7a224f 100644 --- a/api.c +++ b/api.c @@ -106,6 +106,9 @@ int cg_init() int ret = 0; proc_mount = fopen("/proc/mounts", "r"); + if (proc_mount == NULL) { + return EIO; + } while ((ent = getmntent(proc_mount)) != NULL) { if (!strncmp(ent->mnt_fsname,"cgroup", strlen("cgroup"))) { @@ -406,14 +409,14 @@ int cg_delete_cgroup(struct cgroup *cgroup, int ignore_migration) int error = ECGROUPNOTALLOWED; strcpy(path, MOUNT_POINT); - strcat(path,"/tasks"); + strcat(path,"tasks"); base_tasks = fopen(path, "w"); if (!base_tasks) goto base_open_err; cg_build_path(cgroup->name, path); - strcat(path,"/tasks"); + strcat(path,"tasks"); delete_tasks = fopen(path, "r"); if (!delete_tasks) -- cgit From e62a201d4da2deadf021e5bc7b80f5fc7de44c7b Mon Sep 17 00:00:00 2001 From: Balbir Singh Date: Mon, 21 Apr 2008 10:46:09 +0000 Subject: chown recursive routines need to return zero on success Signed-off-by: Balbir Singh git-svn-id: https://libcg.svn.sourceforge.net/svnroot/libcg/branches/balbir@19 4f4bb910-9a46-0410-90c8-c897d4f1cd53 --- api.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'api.c') diff --git a/api.c b/api.c index b7a224f..9f144a3 100644 --- a/api.c +++ b/api.c @@ -47,7 +47,7 @@ static char MOUNT_POINT[FILENAME_MAX]; static int cg_chown_file(FTS *fts, FTSENT *ent, uid_t owner, gid_t group) { - int ret = 1; + int ret = 0; const char *filename = fts->fts_path; dbg("seeing file %s\n", filename); switch (ent->fts_info) { @@ -73,7 +73,7 @@ static int cg_chown_file(FTS *fts, FTSENT *ent, uid_t owner, gid_t group) */ static int cg_chown_recursive(char **path, uid_t owner, gid_t group) { - int ret = 1; + int ret = 0; dbg("path is %s\n", *path); FTS *fts = fts_open(path, FTS_PHYSICAL | FTS_NOCHDIR | FTS_NOSTAT, NULL); @@ -84,7 +84,7 @@ static int cg_chown_recursive(char **path, uid_t owner, gid_t group) dbg("fts_read failed\n"); break; } - cg_chown_file(fts, ent, owner, group); + ret = cg_chown_file(fts, ent, owner, group); } fts_close(fts); return ret; -- cgit From 96baa975d749de2580fd352473b8dde81e081f08 Mon Sep 17 00:00:00 2001 From: Balbir Singh Date: Sun, 11 May 2008 10:27:04 +0000 Subject: Merge with Dhaval's branch Signed-off-by: Balbir Singh git-svn-id: https://libcg.svn.sourceforge.net/svnroot/libcg/branches/balbir@26 4f4bb910-9a46-0410-90c8-c897d4f1cd53 --- api.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) (limited to 'api.c') diff --git a/api.c b/api.c index 9f144a3..b154de1 100644 --- a/api.c +++ b/api.c @@ -321,9 +321,8 @@ int cg_modify_cgroup(struct cgroup *cgroup) for (i = 0; i < CG_CONTROLLER_MAX && cgroup->controller[i]; i++, strcpy(path, base)) { int j; - for(j = 0; j < CG_NV_MAX && - cgroup->controller[i]->values[j]; - j++, strcpy(path, base)) { + for(j = 0; j < CG_NV_MAX && cgroup->controller[i]->values[j]; + j++, strcpy(path, base)) { strcat(path, cgroup->controller[i]->values[j]->name); error = cg_set_control_value(path, cgroup->controller[i]->values[j]->value); @@ -362,9 +361,15 @@ int cg_create_cgroup(struct cgroup *cgroup, int ignore_ownership) strcpy(base, path); +<<<<<<< .mine + if (!ignore_ownership) + cg_chown_recursive(fts_path, cgroup->control_uid, + cgroup->control_gid); +======= if (!ignore_ownership) error = cg_chown_recursive(fts_path, cgroup->control_uid, cgroup->control_gid); +>>>>>>> .r18 if (error) goto err; @@ -401,7 +406,11 @@ err: * * returns 0 on success. */ +<<<<<<< .mine +int cg_delete_cgroup(struct cgroup *cgroup, int ignore_tasks) +======= int cg_delete_cgroup(struct cgroup *cgroup, int ignore_migration) +>>>>>>> .r18 { FILE *delete_tasks, *base_tasks; int tids; @@ -434,7 +443,11 @@ int cg_delete_cgroup(struct cgroup *cgroup, int ignore_migration) del_open_err: fclose(base_tasks); base_open_err: +<<<<<<< .mine + if (ignore_tasks) { +======= if (ignore_migration) { +>>>>>>> .r18 cg_build_path(cgroup->name, path); error = rmdir(path); } -- cgit From 33cb18caa7316170781e0b2ec1dd362d99500df2 Mon Sep 17 00:00:00 2001 From: Balbir Singh Date: Sun, 11 May 2008 11:25:38 +0000 Subject: Remove merge comments and left overs from previous merge Signed-off-by: Balbir Singh git-svn-id: https://libcg.svn.sourceforge.net/svnroot/libcg/branches/balbir@27 4f4bb910-9a46-0410-90c8-c897d4f1cd53 --- api.c | 15 --------------- 1 file changed, 15 deletions(-) (limited to 'api.c') diff --git a/api.c b/api.c index b154de1..f88be3f 100644 --- a/api.c +++ b/api.c @@ -361,16 +361,9 @@ int cg_create_cgroup(struct cgroup *cgroup, int ignore_ownership) strcpy(base, path); -<<<<<<< .mine if (!ignore_ownership) cg_chown_recursive(fts_path, cgroup->control_uid, cgroup->control_gid); -======= - if (!ignore_ownership) - error = cg_chown_recursive(fts_path, cgroup->control_uid, - cgroup->control_gid); ->>>>>>> .r18 - if (error) goto err; @@ -406,11 +399,7 @@ err: * * returns 0 on success. */ -<<<<<<< .mine -int cg_delete_cgroup(struct cgroup *cgroup, int ignore_tasks) -======= int cg_delete_cgroup(struct cgroup *cgroup, int ignore_migration) ->>>>>>> .r18 { FILE *delete_tasks, *base_tasks; int tids; @@ -443,11 +432,7 @@ int cg_delete_cgroup(struct cgroup *cgroup, int ignore_migration) del_open_err: fclose(base_tasks); base_open_err: -<<<<<<< .mine - if (ignore_tasks) { -======= if (ignore_migration) { ->>>>>>> .r18 cg_build_path(cgroup->name, path); error = rmdir(path); } -- cgit From c74b7e334e27928cbfeee489adcc7c25d2efb369 Mon Sep 17 00:00:00 2001 From: Balbir Singh Date: Sat, 17 May 2008 16:06:20 +0000 Subject: Multiple mount point support. Patches built on top of Dhaval'a patches. Works for me on my testing. NOTE: The testing is insufficient as we only test cg_control_create_cgroup() and not delete_cgroup() or attach_task(). Sudhir's new test cases should really help Several coding style fixes and changes, enhancements to make the code work. NOTE: Since this is development release -DDEBUG is back in the makefile. Once this is committed, I'll bump up the version to 0.05 if no one objects. Test report ----------- debug log from the library matched cpuacct:cpuacct Found cgroup option rw,relatime,cpuacct, count 0 matched cpu:cpu Found cgroup option rw,relatime,cpu, count 1 tuid 0, tgid 0, cuid 1000, cgid 1000 path is /tmp/container_cpu/database/ path is /tmp/container_cpuacct/database/ NOTE: The database directory was created as expected on both mount points /tmp/container_cpu and /tmp/container_cpuacct balbir@localhost:~/deliverables/nextgen/libcg/branches/balbir/tests$ ls -al /tmp/container_cpuacct/ total 424 drwxrwxrwt 5 root root 0 2008-05-17 21:27 . drwxrwxrwt 32 root root 425984 2008-05-17 21:26 .. drwxr-xr-x 2 root root 0 2008-05-17 17:09 class1 drwxr-xr-x 2 balbir balbir 0 2008-05-17 17:09 class2 -rw-r--r-- 1 root root 0 2008-05-17 17:09 cpuacct.usage drwxr-xr-x 2 balbir balbir 0 2008-05-17 21:27 database -rw-r--r-- 1 root root 0 2008-05-17 17:09 notify_on_release -rw-r--r-- 1 root root 0 2008-05-17 17:09 releasable -rw-r--r-- 1 root root 0 2008-05-17 17:09 release_agent -rwxrwxrwx 1 root root 0 2008-05-17 17:09 tasks balbir@localhost:~/deliverables/nextgen/libcg/branches/balbir/tests$ ls -al /tmp/container_cpu total 424 drwxrwxrwt 5 root root 0 2008-05-17 21:27 . drwxrwxrwt 32 root root 425984 2008-05-17 21:26 .. drwxr-xr-x 2 root root 0 2008-05-17 17:09 class1 drwxr-xr-x 2 balbir balbir 0 2008-05-17 17:09 class2 -rw-r--r-- 1 root root 0 2008-05-17 17:09 cpu.rt_runtime_us -rw-r--r-- 1 root root 0 2008-05-17 17:09 cpu.shares drwxr-xr-x 2 balbir balbir 0 2008-05-17 21:27 database -rw-r--r-- 1 root root 0 2008-05-17 17:09 notify_on_release -rw-r--r-- 1 root root 0 2008-05-17 17:09 releasable -rw-r--r-- 1 root root 0 2008-05-17 17:09 release_agent -rwxrwxrwx 1 root root 0 2008-05-17 21:10 tasks Signed-off-by: Balbir Singh Signed-off-by: Dhaval Giani git-svn-id: https://libcg.svn.sourceforge.net/svnroot/libcg/branches/balbir@30 4f4bb910-9a46-0410-90c8-c897d4f1cd53 --- api.c | 313 ++++++++++++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 211 insertions(+), 102 deletions(-) (limited to 'api.c') diff --git a/api.c b/api.c index f88be3f..c0c779b 100644 --- a/api.c +++ b/api.c @@ -39,12 +39,6 @@ */ const static char cg_version[] = "0.01"; -/* - * Only one mount point is currently supported. This will be enhanced to - * support several hierarchies in the future - */ -static char MOUNT_POINT[FILENAME_MAX]; - static int cg_chown_file(FTS *fts, FTSENT *ent, uid_t owner, gid_t group) { int ret = 0; @@ -104,6 +98,38 @@ int cg_init() struct mntent *ent, *found_ent = NULL; int found_mnt = 0; int ret = 0; + char *mntent_tok; + static char *controllers[CG_CONTROLLER_MAX]; + FILE *proc_cgroup; + char subsys_name[FILENAME_MAX]; + int hierarchy, num_cgroups, enabled; + int i=0; + char *mntopt; + int err; + + proc_cgroup = fopen("/proc/cgroups", "r"); + + if (!proc_cgroup) + return EIO; + + /* + * The first line of the file has stuff we are not interested in. + * So just read it and discard the information. + * + * XX: fix the size for fgets + */ + fgets(subsys_name, FILENAME_MAX, proc_cgroup); + while (!feof(proc_cgroup)) { + err = fscanf(proc_cgroup, "%s %d %d %d", subsys_name, + &hierarchy, &num_cgroups, &enabled); + if (err < 0) + break; + controllers[i] = (char *)malloc(strlen(subsys_name)); + strcpy(controllers[i], subsys_name); + i++; + } + controllers[i] = NULL; + fclose(proc_cgroup); proc_mount = fopen("/proc/mounts", "r"); if (proc_mount == NULL) { @@ -111,36 +137,64 @@ int cg_init() } while ((ent = getmntent(proc_mount)) != NULL) { - if (!strncmp(ent->mnt_fsname,"cgroup", strlen("cgroup"))) { - found_ent = ent; - found_mnt++; - dbg("Found cgroup option %s, count %d\n", - found_ent->mnt_opts, found_mnt); + if (!strncmp(ent->mnt_type, "cgroup", strlen("cgroup"))) { + for (i = 0; controllers[i] != NULL; i++) { + mntopt = hasmntopt(ent, controllers[i]); + if (mntopt && + strcmp(mntopt, controllers[i]) == 0) { + dbg("matched %s:%s\n", mntopt, + controllers[i]); + strcpy(cg_mount_table[found_mnt].name, + controllers[i]); + strcpy(cg_mount_table[found_mnt].path, + ent->mnt_dir); + dbg("Found cgroup option %s, " + " count %d\n", + ent->mnt_opts, found_mnt); + found_mnt++; + } + } } } - /* - * Currently we require that all controllers be bound together - */ - if (!found_mnt) - ret = ECGROUPNOTMOUNTED; - else if (found_mnt > 1) - ret = ECGROUPMULTIMOUNTED; - else { - /* - * NOTE: FILENAME_MAX ensures that we don't need to worry - * about crossing MOUNT_POINT size. For the paranoid, yes - * this is a potential security hole - Balbir - * Dhaval - fix these things. - */ - strcpy(MOUNT_POINT, found_ent->mnt_dir); - strcat(MOUNT_POINT, "/"); + if (!found_mnt) { + cg_mount_table[0].name[0] = '\0'; + return ECGROUPNOTMOUNTED; } + found_mnt++; + cg_mount_table[found_mnt].name[0] = '\0'; + + fclose(proc_mount); return ret; } +static char **get_mounted_controllers(char *mountpoint) +{ + char **controllers; + int i, j; + + i = 0; + j = 0; + + controllers = (char **) malloc(sizeof(char *) * CG_CONTROLLER_MAX); + + for (i = 0; i < CG_CONTROLLER_MAX && cg_mount_table[i].name != NULL; + i++) { + if (strcmp(cg_mount_table[i].name, mountpoint) == 0) { + controllers[j] = (char *)malloc(sizeof(char) * + FILENAME_MAX); + strcpy(controllers[j], cg_mount_table[i].name); + j++; + } + } + controllers[j] = (char *)malloc(sizeof(char) * FILENAME_MAX); + controllers[j][0] = '\0'; + + return controllers; +} + static int cg_test_mounted_fs() { FILE *proc_mount; @@ -152,7 +206,7 @@ static int cg_test_mounted_fs() } ent = getmntent(proc_mount); - while (strcmp(ent->mnt_fsname, "cgroup") !=0) { + while (strcmp(ent->mnt_type, "cgroup") !=0) { ent = getmntent(proc_mount); if (ent == NULL) return 0; @@ -166,12 +220,19 @@ static inline pid_t cg_gettid() return syscall(__NR_gettid); } -static char* cg_build_path(char *name, char *path) +static char* cg_build_path(char *name, char *path, char *type) { - strcpy(path, MOUNT_POINT); - strcat(path, name); - strcat(path, "/"); - return path; + int i; + for (i = 0; cg_mount_table[i].name[0] != '\0'; i++) { + if (strcmp(cg_mount_table[i].name, type) == 0) { + strcpy(path, cg_mount_table[i].path); + strcat(path, "/"); + strcat(path, name); + strcat(path, "/"); + return path; + } + } + return NULL; } /** cg_attach_task_pid is used to assign tasks to a cgroup. @@ -186,27 +247,50 @@ int cg_attach_task_pid(struct cgroup *cgroup, pid_t tid) { char path[FILENAME_MAX]; FILE *tasks; + int i; - if (cgroup == NULL) - strcpy(path, MOUNT_POINT); - else { - cg_build_path(cgroup->name, path); - } - - strcat(path, "/tasks"); - - tasks = fopen(path, "w"); - if (!tasks) { - switch (errno) { - case EPERM: - return ECGROUPNOTOWNER; - default: - return ECGROUPNOTALLOWED; + if(!cgroup) + { + for(i = 0; i < CG_CONTROLLER_MAX && + cg_mount_table[i].name[0]!='\0'; i++) { + if (!cg_build_path(cgroup->name, path, NULL)) + continue; + strcat(path, "/tasks"); + + tasks = fopen(path, "w"); + if (!tasks) { + switch (errno) { + case EPERM: + return ECGROUPNOTOWNER; + default: + return ECGROUPNOTALLOWED; + } + } + fprintf(tasks, "%d", tid); + fclose(tasks); + } + } else { + for( i = 0; i <= CG_CONTROLLER_MAX && + cgroup->controller[i] != NULL ; i++) { + if (!cg_build_path(cgroup->name, path, + cgroup->controller[i]->name)) + continue; + + strcat(path, "/tasks"); + + tasks = fopen(path, "w"); + if (!tasks) { + switch (errno) { + case EPERM: + return ECGROUPNOTOWNER; + default: + return ECGROUPNOTALLOWED; + } + } + fprintf(tasks, "%d", tid); + fclose(tasks); } } - fprintf(tasks, "%d", tid); - fclose(tasks); - return 0; } @@ -316,11 +400,12 @@ int cg_modify_cgroup(struct cgroup *cgroup) int i; int error; - cg_build_path(cgroup->name, base); - for (i = 0; i < CG_CONTROLLER_MAX && cgroup->controller[i]; i++, strcpy(path, base)) { int j; + if (!cg_build_path(cgroup->name, base, + cgroup->controller[i]->name)) + continue; for(j = 0; j < CG_NV_MAX && cgroup->controller[i]->values[j]; j++, strcpy(path, base)) { strcat(path, cgroup->controller[i]->values[j]->name); @@ -345,8 +430,8 @@ err: int cg_create_cgroup(struct cgroup *cgroup, int ignore_ownership) { char *fts_path[2], base[FILENAME_MAX], *path; - int i; - int error; + int i, j, k; + int error = 0; fts_path[0] = (char *)malloc(FILENAME_MAX); if (!fts_path[0]) @@ -354,40 +439,49 @@ int cg_create_cgroup(struct cgroup *cgroup, int ignore_ownership) fts_path[1] = NULL; path = fts_path[0]; - cg_build_path(cgroup->name, path); - error = cg_create_control_group(path); - if (error) - goto err; + /* + * XX: One important test to be done is to check, if you have multiple + * subsystems mounted at one point, all of them *have* be on the cgroup + * data structure. If not, we fail. + */ + for (k = 0; k < CG_CONTROLLER_MAX && cgroup->controller[k]; k++) { + path[0] = '\0'; - strcpy(base, path); + if (!cg_build_path(cgroup->name, path, + cgroup->controller[k]->name)) + continue; - if (!ignore_ownership) - cg_chown_recursive(fts_path, cgroup->control_uid, - cgroup->control_gid); - if (error) - goto err; + dbg("path is %s\n", path); + error = cg_create_control_group(path); + if (error) + goto err; - for (i = 0; i < CG_CONTROLLER_MAX && cgroup->controller[i]; - i++, strcpy(path, base)) { - int j; - for(j = 0; j < CG_NV_MAX && cgroup->controller[i]->values[j]; - j++, strcpy(path, base)) { - strcat(path, cgroup->controller[i]->values[j]->name); - error = cg_set_control_value(path, - cgroup->controller[i]->values[j]->value); + strcpy(base, path); + + if (!ignore_ownership) + error = cg_chown_recursive(fts_path, + cgroup->control_uid, cgroup->control_gid); + if (error) + goto err; + + for (j = 0; j < CG_NV_MAX && cgroup->controller[k]->values[j]; + j++, strcpy(path, base)) { + strcat(path, cgroup->controller[k]->values[j]->name); + error = cg_set_control_value(path, + cgroup->controller[k]->values[j]->value); /* - * Should we undo, what we've done in the loops above? - */ + * Should we undo, what we've done in the loops above? + */ if (error) goto err; } - } - - if (!ignore_ownership) { - strcpy(path, base); - strcat(path, "/tasks"); - chown(path, cgroup->tasks_uid, cgroup->tasks_gid); + + if (!ignore_ownership) { + strcpy(path, base); + strcat(path, "/tasks"); + chown(path, cgroup->tasks_uid, cgroup->tasks_gid); + } } err: free(path); @@ -401,40 +495,55 @@ err: */ int cg_delete_cgroup(struct cgroup *cgroup, int ignore_migration) { - FILE *delete_tasks, *base_tasks; + FILE *delete_tasks, *base_tasks = NULL; int tids; char path[FILENAME_MAX]; int error = ECGROUPNOTALLOWED; + int i; - strcpy(path, MOUNT_POINT); - strcat(path,"tasks"); + for (i = 0; i < CG_CONTROLLER_MAX && cgroup->controller; i++) { + if (!cg_build_path(cgroup->name, path, + cgroup->controller[i]->name)) + continue; + strcat(path, "../tasks"); - base_tasks = fopen(path, "w"); - if (!base_tasks) - goto base_open_err; + base_tasks = fopen(path, "w"); + if (!base_tasks) + goto base_open_err; - cg_build_path(cgroup->name, path); - strcat(path,"tasks"); + if (!cg_build_path(cgroup->name, path, + cgroup->controller[i]->name)) + continue; - delete_tasks = fopen(path, "r"); - if (!delete_tasks) - goto del_open_err; + strcat(path, "tasks"); - while (!feof(delete_tasks)) { - fscanf(delete_tasks, "%d", &tids); - fprintf(base_tasks, "%d", tids); - } + delete_tasks = fopen(path, "r"); + if (!delete_tasks) + goto del_open_err; + + while (!feof(delete_tasks)) { + fscanf(delete_tasks, "%d", &tids); + fprintf(base_tasks, "%d", tids); + } - cg_build_path(cgroup->name, path); - error = rmdir(path); + if (!cg_build_path(cgroup->name, path, + cgroup->controller[i]->name)) + continue; + error = rmdir(path); - fclose(delete_tasks); + fclose(delete_tasks); + } del_open_err: - fclose(base_tasks); + if (base_tasks) + fclose(base_tasks); base_open_err: if (ignore_migration) { - cg_build_path(cgroup->name, path); - error = rmdir(path); + for (i = 0; cgroup->controller[i] != NULL; i++) { + if (!cg_build_path(cgroup->name, path, + cgroup->controller[i]->name)) + continue; + error = rmdir(path); + } } return error; } -- cgit From 6b0384f40a1eb8ff70b27b6dfed3553883c9141f Mon Sep 17 00:00:00 2001 From: Balbir Singh Date: Sat, 24 May 2008 11:08:57 +0000 Subject: Add v0.1b tag git-svn-id: https://libcg.svn.sourceforge.net/svnroot/libcg/tags/v0.1b@49 4f4bb910-9a46-0410-90c8-c897d4f1cd53 --- api.c | 51 +++++++++++++++++++++++++++++---------------------- 1 file changed, 29 insertions(+), 22 deletions(-) (limited to 'api.c') diff --git a/api.c b/api.c index c0c779b..fce70a7 100644 --- a/api.c +++ b/api.c @@ -23,7 +23,8 @@ */ #include -#include +#include +#include #include #include #include @@ -34,10 +35,18 @@ #include #include +#ifndef PACKAGE_VERSION +#define PACKAGE_VERSION 0.01 +#endif + +#define VERSION(ver) #ver + /* * Remember to bump this up for major API changes. */ -const static char cg_version[] = "0.01"; +const static char cg_version[] = VERSION(PACKAGE_VERSION); + +struct cg_mount_table_s cg_mount_table[CG_CONTROLLER_MAX]; static int cg_chown_file(FTS *fts, FTSENT *ent, uid_t owner, gid_t group) { @@ -85,14 +94,14 @@ static int cg_chown_recursive(char **path, uid_t owner, gid_t group) } /** - * cg_init(), initializes the MOUNT_POINT. + * cgroup_init(), initializes the MOUNT_POINT. * This code is not currently thread safe (hint: getmntent is not thread safe). * This API is likely to change in the future to push state back to the caller * to achieve thread safety. The code currently supports just one mount point. * Complain if the cgroup filesystem controllers are bound to different mount * points. */ -int cg_init() +int cgroup_init() { FILE *proc_mount; struct mntent *ent, *found_ent = NULL; @@ -235,7 +244,7 @@ static char* cg_build_path(char *name, char *path, char *type) return NULL; } -/** cg_attach_task_pid is used to assign tasks to a cgroup. +/** cgroup_attach_task_pid is used to assign tasks to a cgroup. * struct cgroup *cgroup: The cgroup to assign the thread to. * pid_t tid: The thread to be assigned to the cgroup. * @@ -243,7 +252,7 @@ static char* cg_build_path(char *name, char *path, char *type) * returns ECGROUPNOTOWNER if the caller does not have access to the cgroup. * returns ECGROUPNOTALLOWED for other causes of failure. */ -int cg_attach_task_pid(struct cgroup *cgroup, pid_t tid) +int cgroup_attach_task_pid(struct cgroup *cgroup, pid_t tid) { char path[FILENAME_MAX]; FILE *tasks; @@ -295,17 +304,17 @@ int cg_attach_task_pid(struct cgroup *cgroup, pid_t tid) } -/** cg_attach_task is used to attach the current thread to a cgroup. +/** cgroup_attach_task is used to attach the current thread to a cgroup. * struct cgroup *cgroup: The cgroup to assign the current thread to. * * See cg_attach_task_pid for return values. */ -int cg_attach_task(struct cgroup *cgroup) +int cgroup_attach_task(struct cgroup *cgroup) { pid_t tid = cg_gettid(); int error; - error = cg_attach_task_pid(cgroup, tid); + error = cgroup_attach_task_pid(cgroup, tid); return error; } @@ -338,10 +347,6 @@ static int cg_create_control_group(char *path) * This is the low level function for putting in a value in a control file. * This function takes in the complete path and sets the value in val in that * file. - * - * TODO: - * At this point I am not sure what all values the control file can take. So - * I put in an int arg. But this has to be made much more robust. */ static int cg_set_control_value(char *path, char *val) { @@ -383,7 +388,7 @@ static int cg_set_control_value(char *path, char *val) return 0; } -/** cg_modify_cgroup modifies the cgroup control files. +/** cgroup_modify_cgroup modifies the cgroup control files. * struct cgroup *cgroup: The name will be the cgroup to be modified. * The values will be the values to be modified, those not mentioned * in the structure will not be modified. @@ -394,7 +399,7 @@ static int cg_set_control_value(char *path, char *val) * */ -int cg_modify_cgroup(struct cgroup *cgroup) +int cgroup_modify_cgroup(struct cgroup *cgroup) { char path[FILENAME_MAX], base[FILENAME_MAX]; int i; @@ -406,8 +411,9 @@ int cg_modify_cgroup(struct cgroup *cgroup) if (!cg_build_path(cgroup->name, base, cgroup->controller[i]->name)) continue; - for(j = 0; j < CG_NV_MAX && cgroup->controller[i]->values[j]; - j++, strcpy(path, base)) { + for(j = 0; j < CG_NV_MAX && + cgroup->controller[i]->values[j]; + j++, strcpy(path, base)) { strcat(path, cgroup->controller[i]->values[j]->name); error = cg_set_control_value(path, cgroup->controller[i]->values[j]->value); @@ -421,13 +427,13 @@ err: } -/** create_cgroup creates a new control group. +/** cgroup_create_cgroup creates a new control group. * struct cgroup *cgroup: The control group to be created * * returns 0 on success. We recommend calling cg_delete_cgroup * if this routine fails. That should do the cleanup operation. */ -int cg_create_cgroup(struct cgroup *cgroup, int ignore_ownership) +int cgroup_create_cgroup(struct cgroup *cgroup, int ignore_ownership) { char *fts_path[2], base[FILENAME_MAX], *path; int i, j, k; @@ -476,24 +482,25 @@ int cg_create_cgroup(struct cgroup *cgroup, int ignore_ownership) if (error) goto err; } - + if (!ignore_ownership) { strcpy(path, base); strcat(path, "/tasks"); chown(path, cgroup->tasks_uid, cgroup->tasks_gid); } } + err: free(path); return error; } -/** cg_delete cgroup deletes a control group. +/** cgroup_delete cgroup deletes a control group. * struct cgroup *cgroup takes the group which is to be deleted. * * returns 0 on success. */ -int cg_delete_cgroup(struct cgroup *cgroup, int ignore_migration) +int cgroup_delete_cgroup(struct cgroup *cgroup, int ignore_migration) { FILE *delete_tasks, *base_tasks = NULL; int tids; -- cgit From 33b354a4c8c85a90ab4ac32c2a75f23a7eb8f81b Mon Sep 17 00:00:00 2001 From: Balbir Singh Date: Fri, 30 May 2008 17:50:23 +0000 Subject: Fix api.c warnings, include wrapper.c in Makefile. More changes to spec file based on bugzilla input. Removed %makeinstall Signed-off-by: Balbir Singh Signed-off-by: Dhaval Giani git-svn-id: https://libcg.svn.sourceforge.net/svnroot/libcg/tags/v0.1b@67 4f4bb910-9a46-0410-90c8-c897d4f1cd53 --- api.c | 36 +++++++----------------------------- 1 file changed, 7 insertions(+), 29 deletions(-) (limited to 'api.c') diff --git a/api.c b/api.c index fce70a7..b60d534 100644 --- a/api.c +++ b/api.c @@ -104,10 +104,9 @@ static int cg_chown_recursive(char **path, uid_t owner, gid_t group) int cgroup_init() { FILE *proc_mount; - struct mntent *ent, *found_ent = NULL; + struct mntent *ent; int found_mnt = 0; int ret = 0; - char *mntent_tok; static char *controllers[CG_CONTROLLER_MAX]; FILE *proc_cgroup; char subsys_name[FILENAME_MAX]; @@ -179,31 +178,6 @@ int cgroup_init() return ret; } -static char **get_mounted_controllers(char *mountpoint) -{ - char **controllers; - int i, j; - - i = 0; - j = 0; - - controllers = (char **) malloc(sizeof(char *) * CG_CONTROLLER_MAX); - - for (i = 0; i < CG_CONTROLLER_MAX && cg_mount_table[i].name != NULL; - i++) { - if (strcmp(cg_mount_table[i].name, mountpoint) == 0) { - controllers[j] = (char *)malloc(sizeof(char) * - FILENAME_MAX); - strcpy(controllers[j], cg_mount_table[i].name); - j++; - } - } - controllers[j] = (char *)malloc(sizeof(char) * FILENAME_MAX); - controllers[j][0] = '\0'; - - return controllers; -} - static int cg_test_mounted_fs() { FILE *proc_mount; @@ -350,7 +324,6 @@ static int cg_create_control_group(char *path) */ static int cg_set_control_value(char *path, char *val) { - int error; FILE *control_file; if (!cg_test_mounted_fs()) return ECGROUPNOTMOUNTED; @@ -486,7 +459,12 @@ int cgroup_create_cgroup(struct cgroup *cgroup, int ignore_ownership) if (!ignore_ownership) { strcpy(path, base); strcat(path, "/tasks"); - chown(path, cgroup->tasks_uid, cgroup->tasks_gid); + error = chown(path, cgroup->tasks_uid, + cgroup->tasks_gid); + if (!error) { + error = ECGFAIL; + goto err; + } } } -- cgit From 4f422b650ff4f33fde2a0a5b4167150c2f58b461 Mon Sep 17 00:00:00 2001 From: Balbir Singh Date: Fri, 30 May 2008 18:01:00 +0000 Subject: Fix more api.c warnings Signed-off-by: Balbir Singh git-svn-id: https://libcg.svn.sourceforge.net/svnroot/libcg/tags/v0.1b@68 4f4bb910-9a46-0410-90c8-c897d4f1cd53 --- api.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'api.c') diff --git a/api.c b/api.c index b60d534..a279631 100644 --- a/api.c +++ b/api.c @@ -114,6 +114,7 @@ int cgroup_init() int i=0; char *mntopt; int err; + char *buf; proc_cgroup = fopen("/proc/cgroups", "r"); @@ -126,7 +127,10 @@ int cgroup_init() * * XX: fix the size for fgets */ - fgets(subsys_name, FILENAME_MAX, proc_cgroup); + buf = fgets(subsys_name, FILENAME_MAX, proc_cgroup); + if (!buf) + return EIO; + while (!feof(proc_cgroup)) { err = fscanf(proc_cgroup, "%s %d %d %d", subsys_name, &hierarchy, &num_cgroups, &enabled); @@ -409,7 +413,7 @@ err: int cgroup_create_cgroup(struct cgroup *cgroup, int ignore_ownership) { char *fts_path[2], base[FILENAME_MAX], *path; - int i, j, k; + int j, k; int error = 0; fts_path[0] = (char *)malloc(FILENAME_MAX); @@ -484,7 +488,7 @@ int cgroup_delete_cgroup(struct cgroup *cgroup, int ignore_migration) int tids; char path[FILENAME_MAX]; int error = ECGROUPNOTALLOWED; - int i; + int i, ret; for (i = 0; i < CG_CONTROLLER_MAX && cgroup->controller; i++) { if (!cg_build_path(cgroup->name, path, @@ -507,7 +511,11 @@ int cgroup_delete_cgroup(struct cgroup *cgroup, int ignore_migration) goto del_open_err; while (!feof(delete_tasks)) { - fscanf(delete_tasks, "%d", &tids); + ret = fscanf(delete_tasks, "%d", &tids); + /* + * Don't know how to handle EOF yet, so + * ignore it + */ fprintf(base_tasks, "%d", tids); } -- cgit From f1bce06975c0c4d6b1e348bbd1cbc26694e57f82 Mon Sep 17 00:00:00 2001 From: Dhaval Giani Date: Tue, 10 Jun 2008 19:17:26 +0000 Subject: Some bugs were missed in v0.1b. Fixing those bugs and tagging v0.1c. Signed-off-by: Dhaval Giani git-svn-id: https://libcg.svn.sourceforge.net/svnroot/libcg/tags/v0.1c@76 4f4bb910-9a46-0410-90c8-c897d4f1cd53 --- api.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 60 insertions(+), 6 deletions(-) (limited to 'api.c') diff --git a/api.c b/api.c index a279631..6250ceb 100644 --- a/api.c +++ b/api.c @@ -48,6 +48,9 @@ const static char cg_version[] = VERSION(PACKAGE_VERSION); struct cg_mount_table_s cg_mount_table[CG_CONTROLLER_MAX]; +/* Check if cgroup_init has been called or not. */ +static int cgroup_initialized; + static int cg_chown_file(FTS *fts, FTSENT *ent, uid_t owner, gid_t group) { int ret = 0; @@ -93,6 +96,19 @@ static int cg_chown_recursive(char **path, uid_t owner, gid_t group) return ret; } +static int cgroup_test_subsys_mounted(const char *name) +{ + int i; + + for (i = 0; cg_mount_table[i].name[0] != '\0'; i++) { + if (strncmp(cg_mount_table[i].name, name, + sizeof(cg_mount_table[i].name)) == 0) { + return 1; + } + } + return 0; +} + /** * cgroup_init(), initializes the MOUNT_POINT. * This code is not currently thread safe (hint: getmntent is not thread safe). @@ -152,6 +168,7 @@ int cgroup_init() if (!strncmp(ent->mnt_type, "cgroup", strlen("cgroup"))) { for (i = 0; controllers[i] != NULL; i++) { mntopt = hasmntopt(ent, controllers[i]); + mntopt = strtok(mntopt, ","); if (mntopt && strcmp(mntopt, controllers[i]) == 0) { dbg("matched %s:%s\n", mntopt, @@ -177,8 +194,8 @@ int cgroup_init() found_mnt++; cg_mount_table[found_mnt].name[0] = '\0'; - fclose(proc_mount); + cgroup_initialized = 1; return ret; } @@ -214,8 +231,10 @@ static char* cg_build_path(char *name, char *path, char *type) if (strcmp(cg_mount_table[i].name, type) == 0) { strcpy(path, cg_mount_table[i].path); strcat(path, "/"); - strcat(path, name); - strcat(path, "/"); + if (name) { + strcat(path, name); + strcat(path, "/"); + } return path; } } @@ -236,11 +255,14 @@ int cgroup_attach_task_pid(struct cgroup *cgroup, pid_t tid) FILE *tasks; int i; + if (!cgroup_initialized) + return ECGROUPNOTINITALIZED; + if(!cgroup) { for(i = 0; i < CG_CONTROLLER_MAX && cg_mount_table[i].name[0]!='\0'; i++) { - if (!cg_build_path(cgroup->name, path, NULL)) + if (!cg_build_path(NULL, path, cg_mount_table[i].name)) continue; strcat(path, "/tasks"); @@ -257,7 +279,12 @@ int cgroup_attach_task_pid(struct cgroup *cgroup, pid_t tid) fclose(tasks); } } else { - for( i = 0; i <= CG_CONTROLLER_MAX && + for (i = 0; i <= CG_CONTROLLER_MAX && + cgroup->controller[i] != NULL; i++) { + if (!cgroup_test_subsys_mounted(cgroup->controller[i]->name)) + return ECGROUPSUBSYSNOTMOUNTED; + } + for (i = 0; i <= CG_CONTROLLER_MAX && cgroup->controller[i] != NULL ; i++) { if (!cg_build_path(cgroup->name, path, cgroup->controller[i]->name)) @@ -382,6 +409,15 @@ int cgroup_modify_cgroup(struct cgroup *cgroup) int i; int error; + if (!cgroup_initialized) + return ECGROUPNOTINITALIZED; + + for (i = 0; i <= CG_CONTROLLER_MAX && cgroup->controller[i] != NULL; + i++) { + if (!cgroup_test_subsys_mounted(cgroup->controller[i]->name)) + return ECGROUPSUBSYSNOTMOUNTED; + } + for (i = 0; i < CG_CONTROLLER_MAX && cgroup->controller[i]; i++, strcpy(path, base)) { int j; @@ -413,9 +449,18 @@ err: int cgroup_create_cgroup(struct cgroup *cgroup, int ignore_ownership) { char *fts_path[2], base[FILENAME_MAX], *path; - int j, k; + int i, j, k; int error = 0; + if (!cgroup_initialized) + return ECGROUPNOTINITALIZED; + + for (i = 0; i <= CG_CONTROLLER_MAX && cgroup->controller[i] != NULL; + i++) { + if (!cgroup_test_subsys_mounted(cgroup->controller[i]->name)) + return ECGROUPSUBSYSNOTMOUNTED; + } + fts_path[0] = (char *)malloc(FILENAME_MAX); if (!fts_path[0]) return ENOMEM; @@ -490,6 +535,15 @@ int cgroup_delete_cgroup(struct cgroup *cgroup, int ignore_migration) int error = ECGROUPNOTALLOWED; int i, ret; + if (!cgroup_initialized) + return ECGROUPNOTINITALIZED; + + for (i = 0; i <= CG_CONTROLLER_MAX && cgroup->controller[i] != NULL; + i++) { + if (!cgroup_test_subsys_mounted(cgroup->controller[i]->name)) + return ECGROUPSUBSYSNOTMOUNTED; + } + for (i = 0; i < CG_CONTROLLER_MAX && cgroup->controller; i++) { if (!cg_build_path(cgroup->name, path, cgroup->controller[i]->name)) -- cgit From f00b82b6f9114694e3c05e2bb3a5395ce59c85de Mon Sep 17 00:00:00 2001 From: Dhaval Giani Date: Wed, 11 Jun 2008 08:20:54 +0000 Subject: libcgroup: Fix segmentation fault in APIs. Dan Smith reported some segmentation faults. It turns out that we did not NULL terminate all the structures when we had moved to the wrapper based approach. With this in mind, the loop checks the index instead of a NULL structure. Also remove unwanted NULL terminations. Thanks to Dan for excellent debugging. Signed-off-by: Dhaval Giani git-svn-id: https://libcg.svn.sourceforge.net/svnroot/libcg/tags/v0.1c@77 4f4bb910-9a46-0410-90c8-c897d4f1cd53 --- api.c | 33 +++++++++++++-------------------- 1 file changed, 13 insertions(+), 20 deletions(-) (limited to 'api.c') diff --git a/api.c b/api.c index 6250ceb..0adeeb5 100644 --- a/api.c +++ b/api.c @@ -279,13 +279,11 @@ int cgroup_attach_task_pid(struct cgroup *cgroup, pid_t tid) fclose(tasks); } } else { - for (i = 0; i <= CG_CONTROLLER_MAX && - cgroup->controller[i] != NULL; i++) { + for (i = 0; i < cgroup->index; i++) { if (!cgroup_test_subsys_mounted(cgroup->controller[i]->name)) return ECGROUPSUBSYSNOTMOUNTED; } - for (i = 0; i <= CG_CONTROLLER_MAX && - cgroup->controller[i] != NULL ; i++) { + for (i = 0; i <= cgroup->index; i++) { if (!cg_build_path(cgroup->name, path, cgroup->controller[i]->name)) continue; @@ -412,21 +410,18 @@ int cgroup_modify_cgroup(struct cgroup *cgroup) if (!cgroup_initialized) return ECGROUPNOTINITALIZED; - for (i = 0; i <= CG_CONTROLLER_MAX && cgroup->controller[i] != NULL; - i++) { + for (i = 0; i < cgroup->index; i++) { if (!cgroup_test_subsys_mounted(cgroup->controller[i]->name)) return ECGROUPSUBSYSNOTMOUNTED; } - for (i = 0; i < CG_CONTROLLER_MAX && cgroup->controller[i]; - i++, strcpy(path, base)) { + for (i = 0; i < cgroup->index; i++, strcpy(path, base)) { int j; if (!cg_build_path(cgroup->name, base, cgroup->controller[i]->name)) continue; - for(j = 0; j < CG_NV_MAX && - cgroup->controller[i]->values[j]; - j++, strcpy(path, base)) { + for (j = 0; j < cgroup->controller[i]->index; j++, + strcpy(path, base)) { strcat(path, cgroup->controller[i]->values[j]->name); error = cg_set_control_value(path, cgroup->controller[i]->values[j]->value); @@ -455,8 +450,7 @@ int cgroup_create_cgroup(struct cgroup *cgroup, int ignore_ownership) if (!cgroup_initialized) return ECGROUPNOTINITALIZED; - for (i = 0; i <= CG_CONTROLLER_MAX && cgroup->controller[i] != NULL; - i++) { + for (i = 0; i < cgroup->index; i++) { if (!cgroup_test_subsys_mounted(cgroup->controller[i]->name)) return ECGROUPSUBSYSNOTMOUNTED; } @@ -472,7 +466,7 @@ int cgroup_create_cgroup(struct cgroup *cgroup, int ignore_ownership) * subsystems mounted at one point, all of them *have* be on the cgroup * data structure. If not, we fail. */ - for (k = 0; k < CG_CONTROLLER_MAX && cgroup->controller[k]; k++) { + for (k = 0; k < cgroup->index; k++) { path[0] = '\0'; if (!cg_build_path(cgroup->name, path, @@ -493,8 +487,8 @@ int cgroup_create_cgroup(struct cgroup *cgroup, int ignore_ownership) if (error) goto err; - for (j = 0; j < CG_NV_MAX && cgroup->controller[k]->values[j]; - j++, strcpy(path, base)) { + for (j = 0; j < cgroup->controller[k]->index; j++, + strcpy(path, base)) { strcat(path, cgroup->controller[k]->values[j]->name); error = cg_set_control_value(path, cgroup->controller[k]->values[j]->value); @@ -538,13 +532,12 @@ int cgroup_delete_cgroup(struct cgroup *cgroup, int ignore_migration) if (!cgroup_initialized) return ECGROUPNOTINITALIZED; - for (i = 0; i <= CG_CONTROLLER_MAX && cgroup->controller[i] != NULL; - i++) { + for (i = 0; i < cgroup->index; i++) { if (!cgroup_test_subsys_mounted(cgroup->controller[i]->name)) return ECGROUPSUBSYSNOTMOUNTED; } - for (i = 0; i < CG_CONTROLLER_MAX && cgroup->controller; i++) { + for (i = 0; i < cgroup->index; i++) { if (!cg_build_path(cgroup->name, path, cgroup->controller[i]->name)) continue; @@ -585,7 +578,7 @@ del_open_err: fclose(base_tasks); base_open_err: if (ignore_migration) { - for (i = 0; cgroup->controller[i] != NULL; i++) { + for (i = 0; i < cgroup->index; i++) { if (!cg_build_path(cgroup->name, path, cgroup->controller[i]->name)) continue; -- cgit