Implementation of loading rules from /etc/cgrules.d/. Explanation is in the
cover letter. New function cgroup_parse_rules_file created,
calling cgroup_parse_rules. cgroup_parse_rules is invoked only in
cgroup_change_cgroup_flags, cgroup_init_rules_cache and
cgroup_reload_cached_rules functions. For them the change in cgroup_parse_rules
implementation is transpart.

Tested with two configuration files in /etc/cgrules.d/ and all rules
in /etc/cgrules.conf commented out:

$ cat /etc/cgrules.conf
#*:ls       cpu             strom/%u
#*:sleep    memory          les/%g

$ cat /etc/cgrules.d/cgrules1.conf
*:ls       cpu             strom/%u

$ cat /etc/cgrules.d/cgrules2.conf
*:sleep    memory          les/%g

plus cgconfig.[c|d/*] files:
$ cat /etc/cgconfig.conf
mount {
        cpuset  = /cgroup/cpuset;
        cpu     = /cgroup/cpu;
        cpuacct = /cgroup/cpuacct;
        memory  = /cgroup/memory;
        devices = /cgroup/devices;
        freezer = /cgroup/freezer;
        net_cls = /cgroup/net_cls;
        blkio   = /cgroup/blkio;
}

$ cat /etc/cgconfig.d/small.conf
template strom/%u {
        cpu {}
}

group vetev {
        cpu {}
}

$ cat /etc/cgconfig.d/medium.conf
template les/%g {
        memory {}
}

group drevo/listi {
        memory {}
}

Tested to cache reload as well by sending SIGUSR2 signal to running
cgrulesengd process. After first reload I commented out all rules => no
rules match after invoking ls command. After second reload I uncommented
out ls rule => rule match after invoking ls command. After third reload
I uncommented out ls and sleep rule => debug output of cgrulesengd shows
both rules loaded in the cache

Changelog:
* CGROUP_PARSE_STATE_UNLOCK removed
* reformulation of comment to "Cannot read directory. However,
  CGRULES_CONF_FILE is succesfully parsed. Thus return as a success for
  back compatibility."
* errno = 0 removed, once it is not zero, function returns, so need to set
  it to 0 in every iteration
* fprintf replaced by cgroup_err
* added missing unlocks + new label unlock_list for all returns

This
- * finds a rule matching the given UID or GID.  It will store this rule in rl,
+ * finds a rule matching the given UID or GID.  It will store this rule in trl,
is valid correction. "It will store this rule in rl" talks about cache being
disabled. In this case, it is  stored into trl.

Signed-off-by: Jan Chaloupka <jchal...@redhat.com>
---
 src/api.c                |  159 +++++++++++++++++++++++++++++++++++++++++++---
 src/libcgroup-internal.h |    1 
 2 files changed, 148 insertions(+), 12 deletions(-)

diff --git a/src/api.c b/src/api.c
index 0b3d8a0..5751b8f 100644
--- a/src/api.c
+++ b/src/api.c
@@ -473,17 +473,19 @@ static char *cg_skip_unused_charactors_in_rule(char *rule)
  * The cache parameter alters the behavior of this function.  If true, this
  * function will read the entire configuration file and store the results in
  * rl (global rules list).  If false, this function will only parse until it
- * finds a rule matching the given UID or GID.  It will store this rule in rl,
+ * finds a rule matching the given UID or GID.  It will store this rule in trl,
  * as well as any children rules (rules that begin with a %) that it has.
  *
  * This function is NOT thread safe!
+ *     @param filename configuration file to parse
  *     @param cache True to cache rules, else false
  *     @param muid If cache is false, the UID to match against
  *     @param mgid If cache is false, the GID to match against
  *     @return 0 on success, -1 if no cache and match found, > 0 on error.
  * TODO: Make this function thread safe!
+ *
  */
-static int cgroup_parse_rules(bool cache, uid_t muid,
+static int cgroup_parse_rules_file(char *filename, bool cache, uid_t muid,
                                          gid_t mgid, const char *mprocname)
 {
        /* File descriptor for the configuration file */
@@ -544,21 +546,19 @@ static int cgroup_parse_rules(bool cache, uid_t muid,
        else
                lst = &trl;
 
-       /* If our list already exists, clean it. */
-       if (lst->head)
-               cgroup_free_rule_list(lst);
-
        /* Open the configuration file. */
-       pthread_rwlock_wrlock(&rl_lock);
-       fp = fopen(CGRULES_CONF_FILE, "re");
+       fp = fopen(filename, "re");
        if (!fp) {
                cgroup_warn("Warning: failed to open configuration file %s: 
%s\n",
-                               CGRULES_CONF_FILE, strerror(errno));
-               goto unlock;
+                               filename, strerror(errno));
+
+               ret = ECGRULESPARSEFAIL;  /* originally ret = 0, but */
+                                         /* this is parse fail, not success */
+               goto finish;
        }
 
        /* Now, parse the configuration file one line at a time. */
-       cgroup_dbg("Parsing configuration file.\n");
+       cgroup_dbg("Parsing configuration file %s.\n", filename);
        while (fgets(buff, sizeof(buff), fp) != NULL) {
                linenum++;
 
@@ -804,8 +804,143 @@ parsefail:
 
 close:
        fclose(fp);
-unlock:
+finish:
+       return ret;
+}
+
+/**
+ * Parse CGRULES_CONF_FILE and all files in CGRULES_CONF_FILE_DIR.
+ * If CGRULES_CONF_FILE_DIR does not exists or can not be read,
+ * parse only CGRULES_CONF_FILE. This way we keep the back compatibility.
+ *
+ * Original description of this function moved to cgroup_parse_rules_file.
+ * Also cloned and all occurences of file changed to files.
+ *
+ * Parse the configuration files that maps UID/GIDs to cgroups.  If ever the
+ * configuration files are modified, applications should call this function to
+ * load the new configuration rules.  The function caller is responsible for
+ * calling free() on each rule in the list.
+ *
+ * The cache parameter alters the behavior of this function.  If true, this
+ * function will read the entire content of all configuration files and store
+ * the results in rl (global rules list).  If false, this function will only
+ * parse until it finds a file and a rule matching the given UID or GID.
+ * The remaining files are skipped. It will store this rule in trl,
+ * as well as any children rules (rules that begin with a %) that it has.
+ *
+ * Files can be read in an random order so the first match must not be
+ * dependent on it. Thus construct the rules the way not to break
+ * this assumption.
+ *
+ * This function is NOT thread safe!
+ *     @param cache True to cache rules, else false
+ *     @param muid If cache is false, the UID to match against
+ *     @param mgid If cache is false, the GID to match against
+ *     @return 0 on success, -1 if no cache and match found, > 0 on error.
+ * TODO: Make this function thread safe!
+ */
+static int cgroup_parse_rules(bool cache, uid_t muid,
+                                         gid_t mgid, const char *mprocname)
+{
+       int ret;
+
+       /* Pointer to the list that we're using */
+       struct cgroup_rule_list *lst = NULL;
+
+       /* Directory variables */
+       DIR *d;
+       struct dirent *item;
+       const char *dirname = CGRULES_CONF_DIR;
+       char *tmp;
+       int sret;
+
+       /* 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);
+
+       pthread_rwlock_wrlock(&rl_lock);
+
+       /* Parse CGRULES_CONF_FILE configuration file (back compatibility). */
+       ret = cgroup_parse_rules_file(CGRULES_CONF_FILE,
+               cache, muid, mgid, mprocname);
+
+       /*
+        * if match (ret = -1), stop parsing other files, just return
+        * or ret > 0 => error
+        */
+       if (ret != 0) {
+               pthread_rwlock_unlock(&rl_lock);
+               return ret;
+       }
+
+       /* Continue parsing */
+       d = opendir(dirname);
+       if (!d) {
+               cgroup_warn("Warning: Failed to open directory %s: %s\n",
+                               dirname, strerror(errno));
+
+               /*
+                * Cannot read directory. However, CGRULES_CONF_FILE is
+                * succesfully parsed. Thus return as a success
+                * for back compatibility.
+                */
+               pthread_rwlock_unlock(&rl_lock);
+
+               return 0;
+       }
+
+       /* read all files from CGRULES_CONF_FILE_DIR */
+       do {
+               item = readdir(d);
+               if (item && (item->d_type == DT_REG
+                               || item->d_type == DT_LNK)) {
+
+                       sret = asprintf(&tmp, "%s/%s", dirname, item->d_name);
+                       if (sret < 0) {
+                               cgroup_err("Out of memory\n");
+
+                               /*
+                                * Cannot read directory. However, 
CGRULES_CONF_FILE is
+                                * succesfully parsed. Thus return as a success
+                                * for back compatibility.
+                                */
+                               ret = 0;
+                               goto unlock_list;
+                       }
+
+                       cgroup_dbg("Parsing cgrules file: %s\n", tmp);
+                       ret = cgroup_parse_rules_file(tmp,
+                               cache, muid, mgid, mprocname);
+
+                       free(tmp);
+
+                       /* match with cache disabled? */
+                       if (ret != 0)
+                               goto unlock_list;
+               }
+               if (!item && errno) {
+                       cgroup_warn("Warning: cannot read %s: %s\n",
+                                       dirname, strerror(errno));
+                       /*
+                        * Cannot read an item. But continue for
+                        * back compatibility as a success.
+                        */
+                       ret = 0;
+                       goto unlock_list;
+               }
+       } while (item != NULL);
+
+unlock_list:
+       closedir(d);
+
        pthread_rwlock_unlock(&rl_lock);
+
        return ret;
 }
 
diff --git a/src/libcgroup-internal.h b/src/libcgroup-internal.h
index c128788..9875dd9 100644
--- a/src/libcgroup-internal.h
+++ b/src/libcgroup-internal.h
@@ -53,6 +53,7 @@ __BEGIN_DECLS
 #define CGCONFIG_CONF_DIR               "/etc/cgconfig.d"
 
 #define CGRULES_CONF_FILE       "/etc/cgrules.conf"
+#define CGRULES_CONF_DIR        "/etc/cgrules.d"
 #define CGRULES_MAX_FIELDS_PER_LINE            3
 
 #define CGROUP_BUFFER_LEN (5 * FILENAME_MAX)


------------------------------------------------------------------------------
Want fast and easy access to all the code in your enterprise? Index and
search up to 200,000 lines of code with a free copy of Black Duck
Code Sight - the same software that powers the world's largest code
search on Ohloh, the Black Duck Open Hub! Try it now.
http://p.sf.net/sfu/bds
_______________________________________________
Libcg-devel mailing list
Libcg-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/libcg-devel

Reply via email to