We need to make it possible to use multiple configuration files
so that packages can just insert their own configuration files at the
time of installation as opposed to doing a messy appending/removing
from a common file.

This patch makes it possible. By default it searchesf or the configuration
files in /etc/cgrules.d but that still needs to be discussed out.

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

---
 src/cgrules.c            |  480 +++++++++++++++++++++++++----------------------
 src/daemon/cgrulesengd.c |   14 -
 src/libcgroup-internal.h |    4 
 3 files changed, 270 insertions(+), 228 deletions(-)

Index: libcg/src/cgrules.c
===================================================================
--- libcg.orig/src/cgrules.c
+++ libcg/src/cgrules.c
@@ -38,6 +38,7 @@
 #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;
@@ -205,269 +206,310 @@ static int cgroup_parse_rules(bool cache
        /* Loop variable. */
        int i = 0;
 
-       /* Open the configuration file. */
-       pthread_rwlock_wrlock(&rl_lock);
-       fp = fopen(cgrules_config_file, "re");
-       if (!fp) {
-               cgroup_dbg("Failed to open configuration file %s with"
-                               " error: %s\n", cgrules_config_file_file,
-                               strerror(errno));
+       DIR *cgrules_dir;
+       struct dirent *curr_ent = NULL;
+       int len;
+       struct dirent *dir_buff;
+       int read_ret;
+
+       cgrules_dir = opendir(cgrules_config_dir);
+       if (!cgrules_dir) {
                last_errno = errno;
                ret = ECGOTHER;
-               goto unlock;
+               goto fail_dir;
        }
 
-       /* Determine which list we're using. */
-       if (cache)
-               lst = &rl;
-       else
-               lst = &trl;
-
-       /* If our list already exists, clean it. */
-       if (lst->head)
-               cgroup_free_rule_list(lst);
-
-       /* Now, parse the configuration file one line at a time. */
-       cgroup_dbg("Parsing configuration file.\n");
-       while (fgets(buff, sizeof(buff), fp) != NULL) {
-               linenum++;
+       len = offsetof(struct dirent, d_name) +
+                       pathconf(cgrules_config_dir, _PC_NAME_MAX) + 1;
+       dir_buff = malloc(len);
+       if (!dir_buff) {
+               last_errno = errno;
+               ret = ECGOTHER;
+               goto fail_dir;
+       }
 
-               itr = cg_skip_unused_charactors_in_rule(buff);
-               if (!itr)
-                       continue;
+
+       /* Open the configuration file. */
+       pthread_rwlock_wrlock(&rl_lock);
+
+       read_ret = readdir_r(cgrules_dir, curr_ent, &dir_buff);
+
+       while (read_ret == 0 && curr_ent) {
+               char *cgrules_config_file;
 
                /*
-                * If we skipped the last rule and this rule is a continuation
-                * of it (begins with %), then we should skip this rule too.
+                * Well, we need a better way to handle DT_UNKNOWN, but for now
+                * we just pray to $DEITY that we can handle it :-)
                 */
-               if (skipped && *itr == '%') {
-                       cgroup_dbg("Warning: Skipped child of invalid rule,"
-                                       " line %d.\n", linenum);
+               if (curr_ent->d_type != DT_REG || curr_ent->d_type != 
DT_UNKNOWN)
                        continue;
-               }
 
-               /*
-                * If there is something left, it should be a rule.  Otherwise,
-                * there's an error in the configuration file.
-                */
-               skipped = false;
-               i = sscanf(itr, "%s%s%s", key, controllers, destination);
-               if (i != 3) {
-                       cgroup_dbg("Failed to parse configuration file on"
-                                       " line %d.\n", linenum);
-                       goto parsefail;
+               cgrules_config_file = strdup(curr_ent->d_name);
+               fp = fopen(cgrules_config_file, "re");
+               if (!fp) {
+                       cgroup_dbg("Failed to open configuration file %s with"
+                                       " error: %s\n", cgrules_config_file,
+                                       strerror(errno));
+                       last_errno = errno;
+                       ret = ECGOTHER;
+                       goto unlock;
                }
-               procname = strchr(key, ':');
-               if (procname) {
-                       /* <user>:<procname>  <subsystem>  <destination> */
-                       procname++;     /* skip ':' */
-                       len_username = procname - key - 1;
-                       len_procname = strlen(procname);
-                       if (len_procname < 0) {
-                               cgroup_dbg("Failed to parse configuration file"
-                                               " on line %d.\n", linenum);
-                               goto parsefail;
-                       }
-               } else {
-                       len_username = strlen(key);
-                       len_procname = 0;
-               }
-               len_username = min(len_username, sizeof(user) - 1);
-               memset(user, '\0', sizeof(user));
-               strncpy(user, key, len_username);
 
-               /*
-                * Next, check the user/group.  If it's a % sign, then we
-                * are continuing another rule and UID/GID should not be
-                * reset.  If it's a @, we're dealing with a GID rule.  If
-                * it's a *, then we do not need to do a lookup because the
-                * rule always applies (it's a wildcard).  If we're using
-                * non-cache mode and we've found a matching rule, we only
-                * continue to parse if we're looking at a child rule.
-                */
-               if ((!cache) && matched && (strncmp(user, "%", 1) != 0)) {
-                       /* If we make it here, we finished (non-cache). */
-                       cgroup_dbg("Parsing of configuration file"
-                               " complete.\n\n");
-                       ret = -1;
-                       goto close;
-               }
-               if (strncmp(user, "@", 1) == 0) {
-                       /* New GID rule. */
-                       itr = &(user[1]);
-                       grp = getgrnam(itr);
-                       if (grp) {
-                               uid = CGRULE_INVALID;
-                               gid = grp->gr_gid;
-                       } else {
-                               cgroup_dbg("Warning: Entry for %s not"
-                                               "found.  Skipping rule on line"
-                                               " %d.\n", itr, linenum);
-                               skipped = true;
+               /* Determine which list we're using. */
+               if (cache)
+                       lst = &rl;
+               else
+                       lst = &trl;
+
+               /* If our list already exists, clean it. */
+               if (lst->head)
+                       cgroup_free_rule_list(lst);
+
+               /* Now, parse the configuration file one line at a time. */
+               cgroup_dbg("Parsing configuration file.\n");
+               while (fgets(buff, sizeof(buff), fp) != NULL) {
+                       linenum++;
+
+                       itr = cg_skip_unused_charactors_in_rule(buff);
+                       if (!itr)
                                continue;
-                       }
-               } else if (strncmp(user, "*", 1) == 0) {
-                       /* Special wildcard rule. */
-                       uid = CGRULE_WILD;
-                       gid = CGRULE_WILD;
-               } else if (*itr != '%') {
-                       /* New UID rule. */
-                       pwd = getpwnam(user);
-                       if (pwd) {
-                               uid = pwd->pw_uid;
-                               gid = CGRULE_INVALID;
-                       } else {
-                               cgroup_dbg("Warning: Entry for %s not"
-                                               "found.  Skipping rule on line"
-                                               " %d.\n", user, linenum);
-                               skipped = true;
+
+                       /*
+                        * If we skipped the last rule and this rule is a 
continuation
+                        * of it (begins with %), then we should skip this rule 
too.
+                        */
+                       if (skipped && *itr == '%') {
+                               cgroup_dbg("Warning: Skipped child of invalid 
rule,"
+                                               " line %d.\n", linenum);
                                continue;
                        }
-               } /* Else, we're continuing another rule (UID/GID are okay). */
 
-               /*
-                * If we are not caching rules, then we need to check for a
-                * match before doing anything else.  We consider four cases:
-                * The UID matches, the GID matches, the UID is a member of the
-                * GID, or we're looking at the wildcard rule, which always
-                * matches.  If none of these are true, we simply continue to
-                * the next line in the file.
-                */
-               if (grp && muid != CGRULE_INVALID) {
-                       pwd = getpwuid(muid);
-                       for (i = 0; grp->gr_mem[i]; i++) {
-                               if (!(strcmp(pwd->pw_name, grp->gr_mem[i])))
-                                       matched = true;
+                       /*
+                        * If there is something left, it should be a rule.  
Otherwise,
+                        * there's an error in the configuration file.
+                        */
+                       skipped = false;
+                       i = sscanf(itr, "%s%s%s", key, controllers, 
destination);
+                       if (i != 3) {
+                               cgroup_dbg("Failed to parse configuration file 
on"
+                                       " line %d.\n", linenum);
+                               goto parsefail;
                        }
-               }
-
-               if (uid == muid || gid == mgid || uid == CGRULE_WILD)
-                       matched = true;
-
-               if (!cache) {
-                       if (!matched)
-                               continue;
-                       if (len_procname) {
-                               char *mproc_base;
-                               /*
-                                * If there is a rule based on process name,
-                                * it should be matched with mprocname.
-                                */
-                               if (!mprocname) {
+                       procname = strchr(key, ':');
+                       if (procname) {
+                               /* <user>:<procname>  <subsystem>  
<destination> */
+                               procname++;     /* skip ':' */
+                               len_username = procname - key - 1;
+                               len_procname = strlen(procname);
+                               if (len_procname < 0) {
+                                       cgroup_dbg("Failed to parse 
configuration file"
+                                                       " on line %d.\n", 
linenum);
+                                       goto parsefail;
+                               }
+                       } else {
+                               len_username = strlen(key);
+                               len_procname = 0;
+                       }
+                       len_username = min(len_username, sizeof(user) - 1);
+                       memset(user, '\0', sizeof(user));
+                       strncpy(user, key, len_username);
+
+                       /*
+                        * Next, check the user/group.  If it's a % sign, then 
we
+                        * are continuing another rule and UID/GID should not be
+                        * reset.  If it's a @, we're dealing with a GID rule.  
If
+                        * it's a *, then we do not need to do a lookup because 
the
+                        * rule always applies (it's a wildcard).  If we're 
using
+                        * non-cache mode and we've found a matching rule, we 
only
+                        * continue to parse if we're looking at a child rule.
+                        */
+                       if ((!cache) && matched && (strncmp(user, "%", 1) != 
0)) {
+                               /* If we make it here, we finished (non-cache). 
*/
+                               cgroup_dbg("Parsing of configuration file"
+                                       " complete.\n\n");
+                               ret = -1;
+                               goto close;
+                       }
+                       if (strncmp(user, "@", 1) == 0) {
+                               /* New GID rule. */
+                               itr = &(user[1]);
+                               grp = getgrnam(itr);
+                               if (grp) {
                                        uid = CGRULE_INVALID;
-                                       gid = CGRULE_INVALID;
-                                       matched = false;
+                                       gid = grp->gr_gid;
+                               } else {
+                                       cgroup_dbg("Warning: Entry for %s not"
+                                                       "found.  Skipping rule 
on line"
+                                                       " %d.\n", itr, linenum);
+                                       skipped = true;
                                        continue;
                                }
-
-                               mproc_base = cgroup_basename(mprocname);
-                               if (strcmp(mprocname, procname) &&
-                                       strcmp(mproc_base, procname)) {
-                                       uid = CGRULE_INVALID;
+                       } else if (strncmp(user, "*", 1) == 0) {
+                               /* Special wildcard rule. */
+                               uid = CGRULE_WILD;
+                               gid = CGRULE_WILD;
+                       } else if (*itr != '%') {
+                               /* New UID rule. */
+                               pwd = getpwnam(user);
+                               if (pwd) {
+                                       uid = pwd->pw_uid;
                                        gid = CGRULE_INVALID;
-                                       matched = false;
-                                       free(mproc_base);
+                               } else {
+                                       cgroup_dbg("Warning: Entry for %s not"
+                                                       "found.  Skipping rule 
on line"
+                                                       " %d.\n", user, 
linenum);
+                                       skipped = true;
                                        continue;
                                }
-                               free(mproc_base);
+                       } /* Else, we're continuing another rule (UID/GID are 
okay). */
+
+                       /*
+                        * If we are not caching rules, then we need to check 
for a
+                        * match before doing anything else.  We consider four 
cases:
+                        * The UID matches, the GID matches, the UID is a 
member of the
+                        * GID, or we're looking at the wildcard rule, which 
always
+                        * matches.  If none of these are true, we simply 
continue to
+                        * the next line in the file.
+                        */
+                       if (grp && muid != CGRULE_INVALID) {
+                               pwd = getpwuid(muid);
+                               for (i = 0; grp->gr_mem[i]; i++) {
+                                       if (!(strcmp(pwd->pw_name, 
grp->gr_mem[i])))
+                                               matched = true;
+                               }
                        }
-               }
 
-               /*
-                * Now, we're either caching rules or we found a match.  Either
-                * way, copy everything into a new rule and push it into the
-                * list.
-                */
-               newrule = calloc(1, sizeof(struct cgroup_rule));
-               if (!newrule) {
-                       cgroup_dbg("Out of memory?  Error: %s\n",
-                               strerror(errno));
-                       last_errno = errno;
-                       ret = ECGOTHER;
-                       goto close;
-               }
+                       if (uid == muid || gid == mgid || uid == CGRULE_WILD)
+                               matched = true;
+
+                       if (!cache) {
+                               if (!matched)
+                                       continue;
+                               if (len_procname) {
+                                       char *mproc_base;
+                                       /*
+                                        * If there is a rule based on process 
name,
+                                        * it should be matched with mprocname.
+                                        */
+                                       if (!mprocname) {
+                                               uid = CGRULE_INVALID;
+                                               gid = CGRULE_INVALID;
+                                               matched = false;
+                                               continue;
+                                       }
+
+                                       mproc_base = cgroup_basename(mprocname);
+                                       if (strcmp(mprocname, procname) &&
+                                               strcmp(mproc_base, procname)) {
+                                               uid = CGRULE_INVALID;
+                                               gid = CGRULE_INVALID;
+                                               matched = false;
+                                               free(mproc_base);
+                                               continue;
+                                       }
+                                       free(mproc_base);
+                               }
+                       }
 
-               newrule->uid = uid;
-               newrule->gid = gid;
-               len_username = min(len_username,
-                                       sizeof(newrule->username) - 1);
-               strncpy(newrule->username, user, len_username);
-               if (len_procname) {
-                       newrule->procname = strdup(procname);
-                       if (!newrule->procname) {
+                       /*
+                        * Now, we're either caching rules or we found a match. 
 Either
+                        * way, copy everything into a new rule and push it 
into the
+                        * list.
+                        */
+                       newrule = calloc(1, sizeof(struct cgroup_rule));
+                       if (!newrule) {
+                               cgroup_dbg("Out of memory?  Error: %s\n",
+                                       strerror(errno));
                                last_errno = errno;
                                ret = ECGOTHER;
                                goto close;
                        }
-               } else {
-                       newrule->procname = NULL;
-               }
-               strncpy(newrule->destination, destination,
-                       sizeof(newrule->destination) - 1);
-               newrule->next = NULL;
-
-               /* Parse the controller list, and add that to newrule too. */
-               stok_buff = strtok(controllers, ",");
-               if (!stok_buff) {
-                       cgroup_dbg("Failed to parse controllers on line"
-                                       " %d\n", linenum);
-                       goto destroyrule;
-               }
 
-               i = 0;
-               do {
-                       if (i >= MAX_MNT_ELEMENTS) {
-                               cgroup_dbg("Too many controllers listed"
-                                       " on line %d\n", linenum);
+                       newrule->uid = uid;
+                       newrule->gid = gid;
+                       len_username = min(len_username,
+                                               sizeof(newrule->username) - 1);
+                       strncpy(newrule->username, user, len_username);
+                       if (len_procname) {
+                               newrule->procname = strdup(procname);
+                               if (!newrule->procname) {
+                                       last_errno = errno;
+                                       ret = ECGOTHER;
+                                       goto close;
+                               }
+                       } else {
+                               newrule->procname = NULL;
+                       }
+                       strncpy(newrule->destination, destination,
+                               sizeof(newrule->destination) - 1);
+                       newrule->next = NULL;
+
+                       /* Parse the controller list, and add that to newrule 
too. */
+                       stok_buff = strtok(controllers, ",");
+                       if (!stok_buff) {
+                               cgroup_dbg("Failed to parse controllers on line"
+                                       " %d\n", linenum);
                                goto destroyrule;
                        }
 
-                       newrule->controllers[i] = strndup(stok_buff,
+                       i = 0;
+                       do {
+                               if (i >= MAX_MNT_ELEMENTS) {
+                                       cgroup_dbg("Too many controllers listed"
+                                               " on line %d\n", linenum);
+                                       goto destroyrule;
+                               }
+
+                               newrule->controllers[i] = strndup(stok_buff,
                                                        strlen(stok_buff) + 1);
-                       if (!(newrule->controllers[i])) {
-                               cgroup_dbg("Out of memory?  Error was: %s\n",
-                                       strerror(errno));
-                               goto destroyrule;
+                               if (!(newrule->controllers[i])) {
+                                       cgroup_dbg("Out of memory?  Error was: 
%s\n",
+                                               strerror(errno));
+                                       goto destroyrule;
+                               }
+                               i++;
+                       } while ((stok_buff = strtok(NULL, ",")));
+
+                       /* Now, push the rule. */
+                       if (lst->head == NULL) {
+                               lst->head = newrule;
+                               lst->tail = newrule;
+                       } else {
+                               lst->tail->next = newrule;
+                               lst->tail = newrule;
                        }
-                       i++;
-               } while ((stok_buff = strtok(NULL, ",")));
 
-               /* Now, push the rule. */
-               if (lst->head == NULL) {
-                       lst->head = newrule;
-                       lst->tail = newrule;
-               } else {
-                       lst->tail->next = newrule;
-                       lst->tail = newrule;
-               }
-
-               cgroup_dbg("Added rule %s (UID: %d, GID: %d) -> %s for"
-                       " controllers:", lst->tail->username, lst->tail->uid,
-                       lst->tail->gid, lst->tail->destination);
-               for (i = 0; lst->tail->controllers[i]; i++)
-                       cgroup_dbg(" %s", lst->tail->controllers[i]);
-               cgroup_dbg("\n");
-
-               /* Finally, clear the buffer. */
-               grp = NULL;
-               pwd = NULL;
-       }
-
-       /* If we make it here, there were no errors. */
-       cgroup_dbg("Parsing of configuration file complete.\n\n");
-       ret = (matched && !cache) ? -1 : 0;
-       goto close;
+                       cgroup_dbg("Added rule %s (UID: %d, GID: %d) -> %s for"
+                               " controllers:", lst->tail->username, 
lst->tail->uid,
+                               lst->tail->gid, lst->tail->destination);
+                       for (i = 0; lst->tail->controllers[i]; i++)
+                               cgroup_dbg(" %s", lst->tail->controllers[i]);
+                       cgroup_dbg("\n");
+
+                       /* Finally, clear the buffer. */
+                       grp = NULL;
+                       pwd = NULL;
+               }
+
+               /* If we make it here, there were no errors. */
+               cgroup_dbg("Parsing of configuration file complete.\n\n");
+               ret = (matched && !cache) ? -1 : 0;
+               fclose(fp);
+               read_ret = readdir_r(cgrules_dir, curr_ent, &dir_buff);
+       }
+       closedir(cgrules_dir);
+       goto unlock;
 
 destroyrule:
        cgroup_free_rule(newrule);
 
 parsefail:
        ret = ECGRULESPARSEFAIL;
-
 close:
        fclose(fp);
 unlock:
        pthread_rwlock_unlock(&rl_lock);
+fail_dir:
        return ret;
 }
 
@@ -841,11 +883,11 @@ int cgroup_reload_cached_rules(void)
        /* Return codes */
        int ret = 0;
 
-       cgroup_dbg("Reloading cached rules from %s.\n", cgrules_config_file);
+       cgroup_dbg("Reloading cached rules from %s.\n", cgrules_config_dir);
        ret = cgroup_parse_rules(true, CGRULE_INVALID, CGRULE_INVALID, NULL);
        if (ret) {
-               cgroup_dbg("Error parsing configuration file \"%s\": %d.\n",
-                       cgrules_config_file, ret);
+               cgroup_dbg("Error parsing configuration directory\"%s\": %d.\n",
+                       cgrules_config_dir, ret);
                ret = ECGRULESPARSEFAIL;
                goto finished;
        }
Index: libcg/src/daemon/cgrulesengd.c
===================================================================
--- libcg.orig/src/daemon/cgrulesengd.c
+++ libcg/src/daemon/cgrulesengd.c
@@ -976,7 +976,7 @@ int main(int argc, char *argv[])
                {NULL, 0, NULL, 0}
        };
 
-       cgrules_config_file = NULL;
+       cgrules_config_dir = NULL;
 
        /* Make sure the user is root. */
        if (getuid() != 0) {
@@ -1063,8 +1063,8 @@ int main(int argc, char *argv[])
                                        optarg, (int)socket_group);
                        break;
                case 'c': /* config_file */
-                       cgrules_config_file = strdup(optarg);
-                       if (!cgrules_config_file) {
+                       cgrules_config_dir = strdup(optarg);
+                       if (!cgrules_config_dir) {
                                ret = 4;
                                goto finished;
                        }
@@ -1076,9 +1076,9 @@ int main(int argc, char *argv[])
                }
        }
 
-       if (!cgrules_config_file) {
-               cgrules_config_file = strdup(CGRULES_DEFAULT_CONFIG);
-               if (!cgrules_config_file) {
+       if (!cgrules_config_dir) {
+               cgrules_config_dir = strdup(CGRULES_DEFAULT_CONFIG);
+               if (!cgrules_config_dir) {
                        fprintf(stderr, "Failed to set the correct"\
                                                        " configuration\n");
                        goto finished;
@@ -1095,7 +1095,7 @@ int main(int argc, char *argv[])
        /* Ask libcgroup to load the configuration rules. */
        if ((ret = cgroup_init_rules_cache()) != 0) {
                fprintf(stderr, "Error: libcgroup failed to initialize rules"
-                               "cache from %s. %s\n", cgrules_config_file,
+                               "cache from %s. %s\n", cgrules_config_dir,
                                cgroup_strerror(ret));
                goto finished;
        }
Index: libcg/src/libcgroup-internal.h
===================================================================
--- libcg.orig/src/libcgroup-internal.h
+++ libcg/src/libcgroup-internal.h
@@ -46,7 +46,7 @@ __BEGIN_DECLS
 #define CGRULE_SUCCESS_STORE_PID       "SUCCESS_STORE_PID"
 
 
-#define CGRULES_DEFAULT_CONFIG       "/etc/cgrules.conf"
+#define CGRULES_DEFAULT_CONFIG       "/etc/cgrules.d/"
 #define CGRULES_MAX_FIELDS_PER_LINE            3
 
 #define CGROUP_BUFFER_LEN (5 * FILENAME_MAX)
@@ -67,7 +67,7 @@ __BEGIN_DECLS
 #define max(x,y) ((y)<(x)?(x):(y))
 #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;



------------------------------------------------------------------------------
Forrester recently released a report on the Return on Investment (ROI) of
Google Apps. They found a 300% ROI, 38%-56% cost savings, and break-even
within 7 months.  Over 3 million businesses have gone Google with Google Apps:
an online email calendar, and document program that's accessible from your 
browser. Read the Forrester report: http://p.sf.net/sfu/googleapps-sfnew
_______________________________________________
Libcg-devel mailing list
Libcg-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/libcg-devel

Reply via email to