summaryrefslogtreecommitdiffstats
path: root/config.c
diff options
context:
space:
mode:
authorBalbir Singh <balbir@linux.vnet.ibm.com>2008-09-29 12:26:50 +0000
committerBalbir Singh <balbir@linux.vnet.ibm.com>2008-09-29 12:26:50 +0000
commitd1ab753ba5d0d641b52cb90e00ce2eabfae476f4 (patch)
tree984149374ff224629121be769d9e6a4e0eedcf63 /config.c
parent1d00fc725ba26db40b2c792c75888c2ed777730d (diff)
downloadlibcg-d1ab753ba5d0d641b52cb90e00ce2eabfae476f4.tar.gz
libcg-d1ab753ba5d0d641b52cb90e00ce2eabfae476f4.tar.xz
libcg-d1ab753ba5d0d641b52cb90e00ce2eabfae476f4.zip
Configuration rewrite to use the main cgroups API and several bug fixes
and configuration enhancements. Primarliy Initiated by Dhaval Giani Please see svn log of all branches/balbir-config-cleanup Signed-off-by: Balbir Singh <balbir@linux.vnet.ibm.com> Signed-off-by: Dhaval Giani <dhaval@linux.vnet.ibm.com> git-svn-id: https://libcg.svn.sourceforge.net/svnroot/libcg/trunk@201 4f4bb910-9a46-0410-90c8-c897d4f1cd53
Diffstat (limited to 'config.c')
-rw-r--r--config.c854
1 files changed, 302 insertions, 552 deletions
diff --git a/config.c b/config.c
index b0d4604..baaf7d8 100644
--- a/config.c
+++ b/config.c
@@ -20,6 +20,9 @@
*
* Code initiated and designed by Balbir Singh. All faults are most likely
* his mistake.
+ *
+ * Cleanup and changes to use the "official" structures and functions made
+ * by Dhaval Giani. All faults will still be Balbir's mistake :)
*/
#include <assert.h>
@@ -27,8 +30,10 @@
#include <errno.h>
#include <grp.h>
#include <libcgroup.h>
+#include <libcgroup-internal.h>
#include <limits.h>
#include <pwd.h>
+#include <pthread.h>
#include <search.h>
#include <stdio.h>
#include <stdlib.h>
@@ -39,672 +44,417 @@
#include <sys/stat.h>
#include <sys/types.h>
+#define MAX_CGROUPS 1024
+
extern FILE *yyin;
extern int yyparse(void);
-extern int yydebug;
-extern int line_no;
-extern int verbose;
-
-struct hsearch_data group_hash;
-struct list_of_names *group_list;
-struct mount_table *mount_table;
-
-const char library_ver[] = "0.01";
-const char cg_filesystem[] = "cgroup";
-
-struct cg_group *current_group;
-
-const char *cg_controller_names[] = {
- "cpu",
- "cpuacct",
- "memory",
- "cpuset",
- NULL,
-};
/*
- * File traversal routines require the maximum number of open file
- * descriptors to be specified
+ * The basic global data structures.
+ *
+ * config_mount_table -> Where what controller is mounted
+ * table_index -> Where in the table are we.
+ * config_table_lock -> Serializing access to config_mount_table.
+ * cgroup_table -> Which cgroups have to be created.
+ * cgroup_table_index -> Where in the cgroup_table we are.
*/
-const int cg_max_openfd = 20;
+static struct cg_mount_table_s config_mount_table[CG_CONTROLLER_MAX];
+static int config_table_index;
+static pthread_rwlock_t config_table_lock = PTHREAD_RWLOCK_INITIALIZER;
+static struct cgroup config_cgroup_table[MAX_CGROUPS];
+int cgroup_table_index;
/*
- * Insert the group into the list of group names we maintain. This helps
- * us cleanup nicely
+ * Needed for the type while mounting cgroupfs.
*/
-int cg_insert_into_group_list(const char *name)
-{
- struct list_of_names *tmp, *curr;
-
- tmp = malloc(sizeof(*tmp));
- if (!tmp)
- return 0;
- tmp->next = NULL;
- tmp->name = (char *)name;
+static const char cgroup_filesystem[] = "cgroup";
- if (!group_list) {
- group_list = tmp;
- return 1;
- }
- curr = group_list;
- while (curr->next)
- curr = curr->next;
-
- curr->next = tmp;
- return 1;
-}
+/*
+ * NOTE: All these functions return 1 on success
+ * and not 0 as is the library convention
+ */
/*
- * Cleanup the group list. We walk the group list and free the entries in the
- * hash tables and controller specific entries.
+ * This call just sets the name of the cgroup. It will
+ * always be called in the end, because the parser will
+ * work bottom up.
*/
-int cg_cleanup_group_list(void)
+int cgroup_config_insert_cgroup(char *cg_name)
{
- struct list_of_names *curr = group_list, *tmp;
- ENTRY item, *found_item;
- int ret;
- struct cg_group *cg_group;
-
- while (curr) {
- tmp = curr;
- curr = curr->next;
- item.key = tmp->name;
- ret = hsearch_r(item, FIND, &found_item, &group_hash);
- if (!ret) {
- printf("Most likely a bug in the code\n");
- continue;
- }
- /*
- * Free the name and it's value
- */
- free(tmp->name);
- cg_group = (struct cg_group *)found_item->data;
- /*
- * Controller specific cleanup
- */
- if (cg_group->cpu_config.shares)
- free(cg_group->cpu_config.shares);
-
- free(found_item->data);
- }
+ struct cgroup *config_cgroup =
+ &config_cgroup_table[cgroup_table_index];
+ strncpy(config_cgroup->name, cg_name, FILENAME_MAX);
+ /*
+ * Since this will be the last part to be parsed.
+ */
+ cgroup_table_index++;
+ free(cg_name);
return 1;
}
/*
- * Find and walk the mount_table structures to find the specified controller
- * name. This routine is *NOT* thread safe.
+ * This function sets the various controller's control
+ * files. It will always append values for cgroup_table_index
+ * entry in the cgroup_table. The index is incremented in
+ * cgroup_config_insert_cgroup
*/
-struct mount_table *cg_find_mount_info(const char *controller_name)
+int cgroup_config_parse_controller_options(char *controller, char *name_value)
{
- struct mount_table *curr = mount_table;
- char *str;
-
- while (curr) {
- dbg("options %s mntpt %s next %p\n", curr->options,
- curr->mount_point, curr->next);
- dbg("passed controller name %s\n", controller_name);
- str = curr->options;
- if (!str)
- return NULL;
-
- str = strtok(curr->options, ",");
- do {
- if (!strcmp(str, controller_name))
- return curr;
- str = strtok(NULL, ",");
- } while(str);
- curr = curr->next;
- }
- return NULL;
-}
+ char *buffer;
+ char *name, *value;
+ struct cgroup_controller *cgc;
+ int error;
+ struct cgroup *config_cgroup =
+ &config_cgroup_table[cgroup_table_index];
-int cg_cpu_controller_settings(struct cg_group *cg_group,
- const char *group_path)
-{
- int ret = 1;
- char *shares_file;
+ cgc = cgroup_add_controller(config_cgroup, controller);
- shares_file = malloc(strlen(group_path) + strlen("/cpu.shares") + 1);
- if (!shares_file)
- return 0;
+ if (!cgc)
+ goto parse_error;
- strcpy(shares_file, group_path);
- shares_file = strcat(shares_file, "/cpu.shares");
- dbg("shares file is %s\n", shares_file);
- if (cg_group->cpu_config.shares) {
- FILE *fd = fopen(shares_file, "rw+");
- if (!fd)
- goto cleanup_shares;
- /*
- * Assume that one write will do it for us
- */
- fwrite(cg_group->cpu_config.shares,
- strlen(cg_group->cpu_config.shares), 1, fd);
- fclose(fd);
- }
-cleanup_shares:
- free(shares_file);
- return ret;
-}
+ /*
+ * Did we just specify the controller to create the correct
+ * set of directories, without setting any values?
+ */
+ if (!name_value)
+ goto done;
-int cg_controller_handle_option(struct cg_group *cg_group,
- const char *cg_controller_name,
- const char *group_path)
-{
- int ret = 0;
- if (!strncmp(cg_controller_name, "cpu", strlen("cpu"))) {
- ret = cg_cpu_controller_settings(cg_group, group_path);
- } else
- printf("config for %s pending\n", cg_controller_name);
- return ret;
-}
+ name = strtok_r(name_value, " ", &buffer);
-int cg_create_group(struct cg_group *cg_group)
-{
- int i, ret;
- struct mount_table *mount_info;
- char *group_path[2], *tasks_file, *shares_file;
+ if (!name)
+ goto parse_error;
- dbg("found group %s\n", cg_group->name);
- group_path[1] = NULL;
+ value = strtok_r(NULL, " ", &buffer);
- for (i = 0; cg_controller_names[i]; i++) {
+ if (!value)
+ goto parse_error;
- /*
- * Find the mount point related information
- */
- mount_info = cg_find_mount_info(cg_controller_names[i]);
- if (!mount_info)
- continue;
- dbg("mount_info for controller %s:%s\n",
- mount_info->mount_point, cg_controller_names[i]);
- /*
- * TODO: Namespace support is most likely going to be
- * plugged in here
- */
+ error = cgroup_add_value_string(cgc, name, value);
- /*
- * Find the path to the group directory
- */
- group_path[0] = cg_build_group_path(cg_group, mount_info);
- if (!group_path[0])
- goto cleanup_group;
- /*
- * Create the specified directory. Errors are ignored.
- * If the directory already exists, we are most likely
- * OK
- */
- ret = cg_make_directory(cg_group, group_path);
- if (!ret && (errno != EEXIST))
- goto cleanup_dir;
+ if (error)
+ goto parse_error;
- /*
- * Find the tasks file, should probably be encapsulated
- * like we encapsulate cg_build_group_path
- */
- tasks_file = malloc(strlen(group_path[0]) + strlen("/tasks") + 1);
- if (!tasks_file)
- goto cleanup_dir;
- strcpy(tasks_file, group_path[0]);
- tasks_file = strncat(tasks_file, "/tasks", strlen("/tasks"));
- dbg("tasks file is %s\n", tasks_file);
-
- /*
- * Assign task file ownership
- */
- ret = chown(tasks_file, cg_group->tasks_uid,
- cg_group->tasks_gid);
- if (ret < 0)
- goto cleanup_perm;
-
- /*
- * Controller specific work, errors are not fatal.
- */
- cg_controller_handle_option(cg_group, cg_controller_names[i],
- group_path[0]);
- free(tasks_file);
- free(group_path[0]);
- }
+done:
+ free(controller);
+ free(name_value);
return 1;
-cleanup_perm:
- rmdir(group_path[0]);
-cleanup_dir:
- free(group_path[0]);
-cleanup_group:
+
+parse_error:
+ free(controller);
+ free(name_value);
+ cgroup_delete_cgroup(config_cgroup, 1);
+ cgroup_table_index--;
return 0;
}
/*
- * Go ahead and create the groups in the filesystem. This routine will need
- * to be revisited everytime new controllers are added.
+ * Sets the tasks file's uid and gid
*/
-int cg_create_groups(void)
+int cgroup_config_group_task_perm(char *perm_type, char *value)
{
- struct list_of_names *curr = group_list, *tmp;
- ENTRY item, *found_item;
- struct cg_group *cg_group;
- int ret = 1;
-
- while (curr) {
- tmp = curr;
- curr = curr->next;
- item.key = tmp->name;
- ret = hsearch_r(item, FIND, &found_item, &group_hash);
- if (!ret)
- return 0;
- cg_group = (struct cg_group *)found_item->data;
- ret = cg_create_group(cg_group);
- if (!ret)
- break;
+ struct passwd *pw, *pw_buffer;
+ struct group *group, *group_buffer;
+ int error;
+ long val = atoi(value);
+ char buffer[CGROUP_BUFFER_LEN];
+ struct cgroup *config_cgroup =
+ &config_cgroup_table[cgroup_table_index];
+
+ if (!strcmp(perm_type, "uid")) {
+ if (!val) {
+ pw = (struct passwd *) malloc(sizeof(struct passwd));
+
+ if (!pw)
+ goto group_task_error;
+
+ error = getpwnam_r(value, pw, buffer, CGROUP_BUFFER_LEN,
+ &pw_buffer);
+ if (pw_buffer == NULL) {
+ free(pw);
+ goto group_task_error;
+ }
+
+ val = pw->pw_uid;
+ free(pw);
+ }
+ config_cgroup->tasks_uid = val;
}
- return ret;
-}
+ if (!strcmp(perm_type, "gid")) {
+ if (!val) {
+ group = (struct group *) malloc(sizeof(struct group));
-/*
- * Go ahead and create the groups in the filesystem. This routine will need
- * to be revisited everytime new controllers are added.
- */
-int cg_destroy_groups(void)
-{
- struct list_of_names *curr = group_list, *tmp;
- ENTRY item, *found_item;
- struct cg_group *cg_group;
- int ret;
- struct mount_table *mount_info;
- char *group_path;
-
- while (curr) {
- tmp = curr;
- curr = curr->next;
- item.key = tmp->name;
- ret = hsearch_r(item, FIND, &found_item, &group_hash);
- if (!ret)
- return 0;
- cg_group = (struct cg_group *)found_item->data;
- mount_info = cg_find_mount_info("cpu");
- dbg("mount_info for cpu %s\n", mount_info->mount_point);
- if (!mount_info)
- return 0;
- group_path = malloc(strlen(mount_info->mount_point) +
- strlen(cg_group->name) + 2);
- if (!group_path)
- return 0;
- strncpy(group_path, mount_info->mount_point,
- strlen(mount_info->mount_point) + 1);
- dbg("group_path is %s\n", group_path);
- strncat(group_path, "/", strlen("/"));
- strncat(group_path, cg_group->name, strlen(cg_group->name));
- dbg("group_path is %s\n", group_path);
- /*
- * We might strategically add migrate tasks here, so that
- * rmdir is successful. TODO: Later
- */
- ret = rmdir(group_path);
- if (ret < 0)
- goto err;
+ if (!group)
+ goto group_task_error;
+
+ error = getgrnam_r(value, group, buffer,
+ CGROUP_BUFFER_LEN, &group_buffer);
+
+ if (group_buffer == NULL) {
+ free(group);
+ goto group_task_error;
+ }
+
+ val = group->gr_gid;
+ free(group);
+ }
+ config_cgroup->tasks_gid = val;
}
return 1;
-err:
- free(group_path);
+
+group_task_error:
+ free(perm_type);
+ free(value);
+ cgroup_delete_cgroup(config_cgroup, 1);
+ cgroup_table_index--;
return 0;
}
+
/*
- * The cg_get_current_group routine is used by the parser to figure out
- * the current group that is being built and fill it in with the information
- * as it parses through the configuration file
+ * Set the control file's uid/gid
*/
-struct cg_group *cg_get_current_group(void)
+int cgroup_config_group_admin_perm(char *perm_type, char *value)
{
- if (!current_group)
- current_group = calloc(1, sizeof(*current_group));
+ struct passwd *pw, *pw_buffer;
+ struct group *group, *group_buffer;
+ int error;
+ struct cgroup *config_cgroup =
+ &config_cgroup_table[cgroup_table_index];
+ long val = atoi(value);
+ char buffer[CGROUP_BUFFER_LEN];
- return current_group;
-}
+ if (!strcmp(perm_type, "uid")) {
+ if (!val) {
+ pw = (struct passwd *) malloc(sizeof(struct passwd));
-/*
- * This routine should be invoked when the current group being parsed is
- * completely parsed
- */
-void cg_put_current_group(void)
-{
- /*
- * NOTE: we do not free the group, the group is installed into the
- * hash table, the cleanup routine will do the freeing of the group
- */
- current_group = NULL;
-}
+ if (!pw)
+ goto admin_error;
-int cg_insert_group(const char *group_name)
-{
- struct cg_group *cg_group = cg_get_current_group();
- ENTRY item, *found_item;
- int ret;
+ error = getpwnam_r(value, pw, buffer, CGROUP_BUFFER_LEN,
+ &pw_buffer);
+ if (error) {
+ free(pw);
+ goto admin_error;
+ }
- if (!cg_group)
- return 0;
- /*
- * Dont' copy the name over, just point to it
- */
- cg_group->name = (char *)group_name;
- item.key = (char *)group_name;
- item.data = cg_group;
- dbg("Inserting %s into hash table\n", group_name);
- ret = hsearch_r(item, ENTER, &found_item, &group_hash);
- if (!ret) {
- if (found_item)
- errno = EEXIST;
- errno = ENOMEM;
- goto err;
+ val = pw->pw_uid;
+ free(pw);
+ }
+ config_cgroup->control_uid = val;
}
- ret = cg_insert_into_group_list(group_name);
- if (!ret)
- goto err;
- dbg("Inserted %s into hash and list\n", group_name);
- cg_put_current_group();
+
+ if (!strcmp(perm_type, "gid")) {
+ if (!val) {
+ group = (struct group *) malloc(sizeof(struct group));
+
+ if (!group)
+ goto admin_error;
+
+ error = getgrnam_r(value, group, buffer,
+ CGROUP_BUFFER_LEN, &group_buffer);
+
+ if (error) {
+ free(group);
+ goto admin_error;
+ }
+
+ val = group->gr_gid;
+ free(group);
+ }
+ config_cgroup->control_gid = val;
+ }
+
return 1;
-err:
- cg_cleanup_group_list();
+
+admin_error:
+ free(perm_type);
+ free(value);
+ cgroup_delete_cgroup(config_cgroup, 1);
+ cgroup_table_index--;
return 0;
}
/*
- * Because of the way parsing works (bottom-up, shift-reduce), we don't
- * know the name of the controller yet. Compilers build an AST and use
- * a symbol table to deal with this problem. This code does simple things
- * like concatinating strings and passing them upwards. This routine is
- * *NOT* thread safe.
- *
- * This code will need modification everytime new controller support is
- * added.
+ * The moment we have found the controller's information
+ * insert it into the config_mount_table.
*/
-int cg_parse_controller_options(char *controller, char *name_value)
+int cgroup_config_insert_into_mount_table(char *name, char *mount_point)
{
- struct cg_group *cg_group = cg_get_current_group();
- char *name, *value;
+ int i;
- if (!cg_group)
+ if (config_table_index >= CG_CONTROLLER_MAX)
return 0;
- if (!strncmp(controller, "cpu", strlen("cpu"))) {
- name = strtok(name_value, " ");
- value = strtok(NULL, " ");
- if (!strncmp(name, "cpu.shares", strlen("cpu.shares")))
- cg_group->cpu_config.shares = strdup(value);
- else {
- free(controller);
- free(name_value);
- return 0;
+ pthread_rwlock_wrlock(&config_table_lock);
+
+ /*
+ * Merge controller names with the same mount point
+ */
+ for (i = 0; i < config_table_index; i++) {
+ if (strcmp(config_mount_table[i].path, mount_point) == 0) {
+ char *cname = config_mount_table[i].name;
+ strncat(cname, ",", FILENAME_MAX - strlen(cname) - 1);
+ strncat(cname, name,
+ FILENAME_MAX - strlen(cname) - 1);
+ goto done;
}
- dbg("cpu name %s value %s\n", name, value);
- } else {
- return 0;
}
- free(controller);
- free(name_value);
+
+ strcpy(config_mount_table[config_table_index].name, name);
+ strcpy(config_mount_table[config_table_index].path, mount_point);
+ config_table_index++;
+done:
+ pthread_rwlock_unlock(&config_table_lock);
+ free(name);
+ free(mount_point);
return 1;
}
/*
- * Convert the uid/gid field and supplied value to appropriate task
- * permissions. This routine is *NOT* thread safe.
+ * Cleanup all the data from the config_mount_table
*/
-int cg_group_task_perm(char *perm_type, char *value)
+void cgroup_config_cleanup_mount_table(void)
{
- struct cg_group *cg_group = cg_get_current_group();
- struct passwd *pw;
- struct group *group;
- long val = atoi(value);
- if (!strncmp(perm_type, "uid", strlen("uid"))) {
- if (!val) { /* We got the identifier as a name */
- pw = getpwnam(value);
- if (!pw) {
- free(perm_type);
- free(value);
- return 0;
- } else {
- cg_group->tasks_uid = pw->pw_uid;
- }
- } else {
- cg_group->tasks_uid = val;
- }
- dbg("TASKS %s: %d\n", perm_type, cg_group->tasks_uid);
- }
- if (!strncmp(perm_type, "gid", strlen("gid"))) {
- if (!val) { /* We got the identifier as a name */
- group = getgrnam(value);
- if (!group) {
- free(perm_type);
- free(value);
- return 0;
- } else {
- cg_group->tasks_gid = group->gr_gid;
- }
- } else {
- cg_group->tasks_gid = val;
- }
- dbg("TASKS %s: %d\n", perm_type, cg_group->tasks_gid);
- }
- free(perm_type);
- free(value);
- return 1;
-}
-
-int cg_group_admin_perm(char *perm_type, char *value)
-{
- struct cg_group *cg_group = cg_get_current_group();
- struct passwd *pw;
- struct group *group;
- long val = atoi(value);
- if (!strncmp(perm_type, "uid", strlen("uid"))) {
- if (!val) { /* We got the identifier as a name */
- pw = getpwnam(value);
- if (!pw) {
- free(perm_type);
- free(value);
- return 0;
- } else {
- cg_group->admin_uid = pw->pw_uid;
- }
- } else {
- cg_group->admin_uid = val;
- }
- dbg("ADMIN %s: %d\n", perm_type, cg_group->admin_uid);
- }
- if (!strncmp(perm_type, "gid", strlen("gid"))) {
- if (!val) { /* We got the identifier as a name */
- group = getgrnam(value);
- if (!group) {
- free(perm_type);
- free(value);
- return 0;
- } else {
- cg_group->admin_gid = group->gr_gid;
- }
- } else {
- cg_group->admin_gid = val;
- }
- dbg("ADMIN %s: %d\n", perm_type,
- cg_group->admin_gid);
- }
- free(perm_type);
- free(value);
- return 1;
+ memset(&config_mount_table, 0,
+ sizeof(struct cg_mount_table_s) * CG_CONTROLLER_MAX);
}
/*
- * We maintain a hash table. The group hash table maintains the parameters for
- * each group, including the parameters for each controller
- *
- * TODO: Make the initialization a run time configuration parameter
+ * Start mounting the mount table.
*/
-int cg_init_group_and_mount_info(void)
+int cgroup_config_mount_fs()
{
int ret;
+ struct stat buff;
+ int i;
- group_list = NULL;
- mount_table = NULL;
- current_group = NULL;
+ for (i = 0; i < config_table_index; i++) {
+ struct cg_mount_table_s *curr = &(config_mount_table[i]);
- ret = hcreate_r(MAX_GROUP_ELEMENTS, &group_hash);
- if (!ret)
- return 0;
- return 1;
+ ret = stat(curr->path, &buff);
+
+ if (ret < 0 && errno != ENOENT)
+ return ECGOTHER;
+
+ if (errno == ENOENT) {
+ ret = mkdir(curr->path,
+ S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
+ if (ret < 0)
+ return ECGOTHER;
+ } else if (!S_ISDIR(buff.st_mode)) {
+ errno = ENOTDIR;
+ return ECGOTHER;
+ }
+
+ ret = mount(cgroup_filesystem, curr->path, cgroup_filesystem,
+ 0, curr->name);
+
+ if (ret < 0)
+ return ECGMOUNTFAIL;
+ }
+ return 0;
}
/*
- * This routine should be called only once all elements of the hash table have
- * been freed. Otherwise, we'll end up with a memory leak.
+ * Actually create the groups once the parsing has been finished.
*/
-void cg_destroy_group_and_mount_info(void)
+int cgroup_config_create_groups()
{
- hdestroy_r(&group_hash);
- group_list = NULL;
- mount_table = NULL;
- current_group = NULL;
+ int error = 0;
+ int i;
+
+ for (i = 0; i < cgroup_table_index; i++) {
+ struct cgroup *cgroup = &config_cgroup_table[i];
+ error = cgroup_create_cgroup(cgroup, 0);
+ dbg("creating group %s, error %d\n", cgroup->name, error);
+ if (error)
+ return error;
+ }
+ return error;
}
/*
- * Insert a name, mount_point pair into the mount_table data structure
- * TODO: Validate names and mount points
+ * Destroy the cgroups
*/
-int cg_insert_into_mount_table(const char *name, const char *mount_point)
+int cgroup_config_destroy_groups(void)
{
- struct mount_table *tmp, *prev = mount_table;
-
- while (prev && prev->next != NULL &&
- (strncmp(mount_point, prev->mount_point, strlen(mount_point))))
- prev = prev->next;
-
- if (prev &&
- !(strncmp(mount_point, prev->mount_point, strlen(mount_point)))) {
- prev->options = realloc(prev->options, strlen(prev->options)
- + strlen(name) + 2);
- if (!prev->options)
- return 0;
- strncat(prev->options, ",", strlen(","));
- strncat(prev->options, name, strlen(name));
- dbg("options %s: mount_point %s\n", prev->options,
- prev->mount_point);
- return 1;
- }
-
- tmp = malloc(sizeof(*tmp));
- if (!tmp)
- return 0;
-
- tmp->next = NULL;
- tmp->mount_point = (char *)mount_point;
- tmp->options = (char *)name;
- dbg("options %s: mount_point %s\n", tmp->options, tmp->mount_point);
-
- if (!prev) {
- mount_table = tmp;
- return 1;
- } else {
- prev->next = tmp;
+ int error = 0;
+ int i;
+
+ for (i = 0; i < cgroup_table_index; i++) {
+ struct cgroup *cgroup = &config_cgroup_table[i];
+ error = cgroup_delete_cgroup(cgroup, 0);
+ if (error)
+ return error;
}
-
- return 1;
+ return error;
}
-void cg_cleanup_mount_table(void)
+/*
+ * Unmount the controllers
+ */
+int cgroup_config_unmount_controllers(void)
{
- struct mount_table *curr = mount_table, *tmp;
-
- while (curr) {
- tmp = curr;
- curr = curr->next;
- tmp->next = NULL;
+ int i;
+ int error;
+ for (i = 0; i < config_table_index; i++) {
/*
- * Some of this data might have been allocated by the lexer
- * while parsing tokens
+ * We ignore failures and ensure that all mounted
+ * containers are unmounted
*/
- free(tmp->mount_point);
- free(tmp->options);
-
- free(tmp);
+ error = umount(config_mount_table[i].path);
+ if (error < 0)
+ dbg("Unmount failed\n");
+ error = rmdir(config_mount_table[i].path);
+ if (error < 0)
+ dbg("rmdir failed\n");
}
+
+ return 0;
}
-int cg_load_config(const char *pathname)
+/*
+ * The main function which does all the setup of the data structures
+ * and finally creates the cgroups
+ */
+int cgroup_config_load_config(const char *pathname)
{
- yyin = fopen(pathname, "rw");
+ int error;
+ yyin = fopen(pathname, "r");
+
if (!yyin) {
dbg("Failed to open file %s\n", pathname);
- return 0;
+ return ECGOTHER;
}
- if (!cg_init_group_and_mount_info())
- return 0;
-
if (yyparse() != 0) {
dbg("Failed to parse file %s\n", pathname);
- return 0;
+ return ECGROUPPARSEFAIL;
}
- if (!cg_mount_controllers())
+ error = cgroup_config_mount_fs();
+ if (error)
+ goto err_mnt;
+
+ error = cgroup_init();
+ if (error)
goto err_mnt;
- if (!cg_create_groups())
+
+ error = cgroup_config_create_groups();
+ dbg("creating all cgroups now, error=%d\n", error);
+ if (error)
goto err_grp;
fclose(yyin);
- return 1;
+ return 0;
err_grp:
- dbg("Creating groups failed\n");
- cg_destroy_groups();
- cg_cleanup_group_list();
+ cgroup_config_destroy_groups();
err_mnt:
- dbg("Mounting controllers failed\n");
- cg_unmount_controllers();
- cg_cleanup_mount_table();
+ cgroup_config_unmount_controllers();
fclose(yyin);
- return 0;
-}
-
-void cg_unload_current_config(void)
-{
- cg_destroy_groups();
- cg_cleanup_group_list();
- cg_unmount_controllers();
- cg_cleanup_mount_table();
- cg_destroy_group_and_mount_info();
-}
-
-int main(int argc, char *argv[])
-{
- int c;
- char filename[PATH_MAX];
- int ret;
-
- if (argc < 2) {
- fprintf(stderr, "usage is %s <option> <config file>\n",
- argv[0]);
- exit(2);
- }
-
- while ((c = getopt(argc, argv, "l:ur:")) > 0) {
- switch (c) {
- case 'u':
- cg_unload_current_config();
- break;
- case 'r':
- cg_unload_current_config();
- /* FALLTHROUGH */
- case 'l':
- strncpy(filename, optarg, PATH_MAX);
- ret = cg_load_config(filename);
- if (!ret)
- exit(3);
- break;
- default:
- fprintf(stderr, "Invalid command line option\n");
- break;
- }
- }
-
+ return error;
}