As per the discussion on the mailing list, the daemon should have
the ability to load both configuration files and configuration directories.

Provide this ability.

TODO:
1. Move to a fts based walk as opposed to a readdir.
2. Decide whether a configuration file is default or a configuration directory.
3. Handle minor coding style issues.

Signed-off-by: Dhaval Giani <dhaval.gi...@gmail.com>

---
 src/cgrules.c            |   90 ++++++++++++++++++++++++++++++++++++++++++++++-
 src/daemon/cgrulesengd.c |   28 +++++++++++++-
 src/libcgroup-internal.h |    1 
 3 files changed, 116 insertions(+), 3 deletions(-)

Index: libcg/src/daemon/cgrulesengd.c
===================================================================
--- libcg.orig/src/daemon/cgrulesengd.c
+++ libcg/src/daemon/cgrulesengd.c
@@ -960,7 +960,7 @@ int main(int argc, char *argv[])
        struct group *gr;
 
        /* Command line arguments */
-       const char *short_options = "hvqf:s::ndQu:g:c:";
+       const char *short_options = "hvqf:s::ndQu:g:c:D:";
        struct option long_options[] = {
                {"help", no_argument, NULL, 'h'},
                {"verbose", no_argument, NULL, 'v'},
@@ -973,10 +973,12 @@ int main(int argc, char *argv[])
                {"socket-user", required_argument, NULL, 'u'},
                {"socket-group", required_argument, NULL, 'g'},
                {"config-file", required_argument, NULL, 'c'},
+               {"config-dir", required_argument, NULL, 'D'},
                {NULL, 0, NULL, 0}
        };
 
        cgrules_config_file = NULL;
+       cgrules_config_dir = NULL;
 
        /* Make sure the user is root. */
        if (getuid() != 0) {
@@ -1069,6 +1071,13 @@ int main(int argc, char *argv[])
                                goto finished;
                        }
                        break;
+               case 'D': /* --config-dir */
+                       cgrules_config_dir = strdup(optarg);
+                       if (!cgrules_config_dir) {
+                               ret = 4;
+                               goto finished;
+                       }
+                       break;
                default:
                        usage(stderr, "");
                        ret = 2;
@@ -1076,7 +1085,22 @@ int main(int argc, char *argv[])
                }
        }
 
-       if (!cgrules_config_file) {
+       /*
+        * Cannot have both config dir and config file set.
+        * This will confuse the implementation. So just mark such a
+        * configuration as invalid and fail.
+        */
+       if (cgrules_config_file && cgrules_config_dir) {
+               fprintf(stderr, "Error: Both configuration directory and " \
+                               "configuration file are mentioned\n");
+               goto finished;
+       }
+
+       /*
+        * XX: TODO: Decide if config dir is the default or the config file is
+        * Current implementation just keeps the config file as default.
+        */
+       if (!cgrules_config_file && !cgrules_config_dir) {
                cgrules_config_file = strdup(CGRULES_DEFAULT_CONFIG);
                if (!cgrules_config_file) {
                        fprintf(stderr, "Failed to set the correct"\
Index: libcg/src/libcgroup-internal.h
===================================================================
--- libcg.orig/src/libcgroup-internal.h
+++ libcg/src/libcgroup-internal.h
@@ -68,6 +68,7 @@ __BEGIN_DECLS
 #define min(x,y) ((y)>(x)?(x):(y))
 
 char *cgrules_config_file;
+char *cgrules_config_dir;
 
 /* Check if cgroup_init has been called or not. */
 int cgroup_initialized;
Index: libcg/src/cgrules.c
===================================================================
--- libcg.orig/src/cgrules.c
+++ libcg/src/cgrules.c
@@ -17,6 +17,8 @@
  *
  */
 
+#define _GNU_SOURCE
+
 #include <dirent.h>
 #include <errno.h>
 #include <libcgroup.h>
@@ -38,9 +40,11 @@
 #include <assert.h>
 #include <linux/un.h>
 #include <grp.h>
+#include <stddef.h>
 
 /* Check if the rules cache has been loaded or not. */
 static bool cgroup_rules_loaded;
+static bool cgrules_dir_provided;
 
 /* List of configuration rules */
 static struct cgroup_rule_list rl;
@@ -474,8 +478,92 @@ unlock:
 static int cgroup_parse_rules(bool cache, uid_t muid,
                                          gid_t mgid, const char *mprocname)
 {
-       return cgroup_parse_rules_file(cache, muid, mgid, mprocname, 
cgrules_config_file);
+       DIR *cgrules_dir;
+       struct dirent *curr_ent = NULL;
+       int len;
+       struct dirent *dir_buff;
+       int read_ret;
+       int parse_fail_count = 0;
+       char *parse_fail_list = NULL;
+
+       if (cgrules_config_file)
+               return cgroup_parse_rules_file(cache, muid, mgid, mprocname,
+                                                       cgrules_config_file);
+
+       /*
+        * This means we have a directory defined, and we parse using that
+        * TODO: Implement using fts if folks think that is a better option
+        */
+
+       cgrules_dir = opendir(cgrules_config_dir);
+       if (!cgrules_dir) {
+               last_errno = errno;
+               return ECGOTHER;
+       }
+
+       len = offsetof(struct dirent, d_name) +
+               pathconf(cgrules_config_dir, _PC_NAME_MAX) + 1;
+
+       dir_buff = malloc(len);
+       if (!dir_buff) {
+               last_errno = errno;
+               return ECGOTHER;
+       }
+
+       read_ret = readdir_r(cgrules_dir, curr_ent, &dir_buff);
+
+       while(read_ret == 0 && curr_ent) {
+               char *cgrules_file;
+               int parse_ret;
+
+               /*
+                * We need a better way to handle DT_UNKNOWN, but for now we
+                * just pray to $DEITY that we can handle it :-)
+                */
+
+               if (curr_ent->d_type != DT_REG || curr_ent->d_type != 
DT_UNKNOWN) {
+                       read_ret = readdir_r(cgrules_dir, curr_ent, &dir_buff);
+                       continue;
+               }
+
+               cgrules_file = strdup(curr_ent->d_name);
+
+               parse_ret = cgroup_parse_rules_file(cache, muid, mgid, 
mprocname,
+                               cgrules_file);
+
+               if (parse_ret) {
+                       char *tmp_list;
+                       parse_fail_count++;
+                       if (parse_fail_list) {
+                               tmp_list = strdup(parse_fail_list);
+                               if (!tmp_list) {
+                                       last_errno = errno;
+                                       return ECGOTHER;
+                               }
+
+                               free(parse_fail_list);
+                               asprintf(&parse_fail_list, "%s, %s", tmp_list, 
curr_ent->d_name);
+                       } else {
+                               parse_fail_list = strdup(curr_ent->d_name);
+                       }
+
+               }
+               read_ret = readdir_r(cgrules_dir, curr_ent, &dir_buff);
+
+       }
+       fprintf(stderr, "Failed to parse %d files\n", parse_fail_count);
+       fprintf(stderr, "Failed to parse %s\n", parse_fail_list);
+
+       /*
+        * TODO: Right return value
+        */
+       if (parse_fail_count)
+               return 0;
+
+       return 0;
+
 }
+
 /** cg_prepare_cgroup
  * Process the selected rule. Prepare the cgroup structure which can be
  * used to add the task to destination cgroup.



------------------------------------------------------------------------------
The modern datacenter depends on network connectivity to access resources
and provide services. The best practices for maximizing a physical server's
connectivity to a physical network are well understood - see how these
rules translate into the virtual world? 
http://p.sf.net/sfu/oracle-sfdevnlfb
_______________________________________________
Libcg-devel mailing list
Libcg-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/libcg-devel

Reply via email to