]> git.ipfire.org Git - thirdparty/libcgroup.git/commitdiff
Add the key "process name" to find a matching rule.
authorKen'ichi Ohmichi <oomichi@mxs.nes.nec.co.jp>
Fri, 26 Jun 2009 05:49:50 +0000 (14:49 +0900)
committerDhaval Giani <dhaval@linux.vnet.ibm.com>
Mon, 29 Jun 2009 11:17:32 +0000 (16:47 +0530)
Hi,

Changelog of v6:
================
 * No change.

Changelog of v5.1:
==================
 * BUGFIX: Clear the flags meaning "found a matching rule"
   when a process name does not match.

   There was a problem that cgexec and cgclassify didn't work correctly
   if a user executes cgexec/cgclassify based on /etc/cgrules.conf.
   For example, if a root user executes `cgclassify $$` on the following
   /etc/cgrules.conf, the process ($$) should be moved to users/root on
   cpuset and memory subsystems. But the process was moved to users/root/cp
   on memory subsystem only.
     Example of /etc/cgrules.conf:
     =============================
     root:cp          cpuset  users/root/cp
     %                memory  users/root/cp
     root             cpuset  users/root
     %                memory  users/root

   The cause is why the flags meaning "found a matching rule" (uid, gid, and
   matched) is not cleared when a process name does not match. This problem
   is fixed on this patch.

Changelog of v5:
================
 * Rebase the patch to the latest code.

Changelog of v4:
================
 * No change.

Changelog of v3:
================
 * BUGFIX: Fix the handling of '%' in /etc/cgrules.conf.

Changelog of v2:
================
 * Use strcmp() instead of strncmp() for checking a process name strictly.
 * Some cleanups.

Description:
============
This patch adds the key "process name" to find a matching rule.

Thanks
Ken'ichi Ohmichi

Signed-off-by: Ken'ichi Ohmichi <oomichi@mxs.nes.nec.co.jp>
Signed-off-by: Dhaval Giani <dhaval@linux.vnet.ibm.com>
include/libcgroup.h
src/api.c
src/libcgroup.map

index 6155f09b2ff47647b10d1ce26b2d6c3891308150..a9799ab6f8742875a5b466970168d5e32225fe43 100644 (file)
@@ -148,6 +148,27 @@ int cgroup_get_cgroup(struct cgroup *cgroup);
 int cgroup_create_cgroup_from_parent(struct cgroup *cgroup, int ignore_ownership);
 int cgroup_copy_cgroup(struct cgroup *dst, struct cgroup *src);
 
+/**
+ * Changes the cgroup of a program based on the rules in the config file.
+ * If a rule exists for the given UID, GID or PROCESS NAME, then the given
+ * PID is placed into the correct group.  By default, this function parses
+ * the configuration file each time it is called.
+ *
+ * The flags can alter the behavior of this function:
+ *     CGFLAG_USECACHE: Use cached rules instead of parsing the config file
+ *
+ * This function may NOT be thread safe.
+ *     @param uid The UID to match
+ *     @param gid The GID to match
+ *     @param procname The PROCESS NAME to match
+ *     @param pid The PID of the process to move
+ *     @param flags Bit flags to change the behavior, as defined above
+ *     @return 0 on success, > 0 on error
+ * TODO: Determine thread-safeness and fix of not safe.
+ */
+int cgroup_change_cgroup_flags(const uid_t uid, const gid_t gid,
+               char *procname, const pid_t pid, const int flags);
+
 /**
  * Changes the cgroup of a program based on the rules in the config file.  If a
  * rule exists for the given UID or GID, then the given PID is placed into the
index c5a3579412c295f7ad1eebde86453eb94aacff1d..92bdebd589b1eca6c02c98b0e76a48bb5b5ce046 100644 (file)
--- a/src/api.c
+++ b/src/api.c
@@ -294,7 +294,8 @@ static char *cg_skip_unused_charactors_in_rule(char *rule)
  *     @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)
+static int cgroup_parse_rules(bool cache, uid_t muid,
+                                         gid_t mgid, char *mprocname)
 {
        /* File descriptor for the configuration file */
        FILE *fp = NULL;
@@ -486,8 +487,29 @@ static int cgroup_parse_rules(bool cache, uid_t muid, gid_t mgid)
                        matched = true;
                }
 
-               if (!cache && !matched)
-                       continue;
+               if (!cache) {
+                       if (!matched)
+                               continue;
+                       if (len_procname) {
+                               /*
+                                * 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;
+                               }
+                               if (strcmp(mprocname, procname) &&
+                                       strcmp(basename(mprocname), procname)) {
+                                       uid = CGRULE_INVALID;
+                                       gid = CGRULE_INVALID;
+                                       matched = false;
+                                       continue;
+                               }
+                       }
+               }
 
                /*
                 * Now, we're either caching rules or we found a match.  Either
@@ -1821,22 +1843,9 @@ static int cg_prepare_cgroup(struct cgroup *cgroup, pid_t pid,
        return ret;
 }
 
-/**
- * Finds the first rule in the cached list that matches the given UID or GID,
- * and returns a pointer to that rule.  This function uses rl_lock.
- *
- * This function may NOT be thread safe.
- *     @param uid The UID to match
- *     @param gid The GID to match
- *     @return Pointer to the first matching rule, or NULL if no match
- * TODO: Determine thread-safeness and fix if not safe.
- */
 static struct cgroup_rule *cgroup_find_matching_rule_uid_gid(const uid_t uid,
-                               const gid_t gid)
+                               const gid_t gid, struct cgroup_rule *rule)
 {
-       /* Return value */
-       struct cgroup_rule *ret = rl.head;
-
        /* Temporary user data */
        struct passwd *usr = NULL;
 
@@ -1849,76 +1858,96 @@ static struct cgroup_rule *cgroup_find_matching_rule_uid_gid(const uid_t uid,
        /* Loop variable */
        int i = 0;
 
-       pthread_rwlock_wrlock(&rl_lock);
-       while (ret) {
-               /* The wildcard rule always matches. */
-               if ((ret->uid == CGRULE_WILD) && (ret->gid == CGRULE_WILD)) {
-                       goto finished;
+       while (rule) {
+               /* Skip "%" which indicates continuation of previous rule. */
+               if (rule->username[0] == '%') {
+                       rule = rule->next;
+                       continue;
                }
+               /* The wildcard rule always matches. */
+               if ((rule->uid == CGRULE_WILD) && (rule->gid == CGRULE_WILD))
+                       return rule;
 
                /* This is the simple case of the UID matching. */
-               if (ret->uid == uid) {
-                       goto finished;
-               }
+               if (rule->uid == uid)
+                       return rule;
 
                /* This is the simple case of the GID matching. */
-               if (ret->gid == gid) {
-                       goto finished;
-               }
+               if (rule->gid == gid)
+                       return rule;
 
                /* If this is a group rule, the UID might be a member. */
-               if (ret->username[0] == '@') {
+               if (rule->username[0] == '@') {
                        /* Get the group data. */
-                       sp = &(ret->username[1]);
+                       sp = &(rule->username[1]);
                        grp = getgrnam(sp);
-                       if (!grp) {
+                       if (!grp)
                                continue;
-                       }
 
                        /* Get the data for UID. */
                        usr = getpwuid(uid);
-                       if (!usr) {
+                       if (!usr)
                                continue;
-                       }
 
                        /* If UID is a member of group, we matched. */
                        for (i = 0; grp->gr_mem[i]; i++) {
                                if (!(strcmp(usr->pw_name, grp->gr_mem[i])))
-                                       goto finished;
+                                       return rule;
                        }
                }
 
                /* If we haven't matched, try the next rule. */
-               ret = ret->next;
+               rule = rule->next;
        }
 
        /* If we get here, no rules matched. */
-       ret = NULL;
-
-finished:
-       pthread_rwlock_unlock(&rl_lock);
-       return ret;
+       return NULL;
 }
 
 /**
- * Changes the cgroup of a program based on the rules in the config file.  If a
- * rule exists for the given UID or GID, then the given PID is placed into the
- * correct group.  By default, this function parses the configuration file each
- * time it is called.
- * 
- * The flags can alter the behavior of this function:
- *     CGFLAG_USECACHE: Use cached rules instead of parsing the config file
+ * Finds the first rule in the cached list that matches the given UID, GID
+ * or PROCESS NAME, and returns a pointer to that rule.
+ * This function uses rl_lock.
  *
- * This function may NOT be thread safe. 
+ * This function may NOT be thread safe.
  *     @param uid The UID to match
  *     @param gid The GID to match
- *     @param pid The PID of the process to move
- *     @param flags Bit flags to change the behavior, as defined above
- *     @return 0 on success, > 0 on error
- * TODO: Determine thread-safeness and fix of not safe.
+ *     @param procname The PROCESS NAME to match
+ *     @return Pointer to the first matching rule, or NULL if no match
+ * TODO: Determine thread-safeness and fix if not safe.
  */
-int cgroup_change_cgroup_uid_gid_flags(const uid_t uid, const gid_t gid,
-                               const pid_t pid, const int flags)
+static struct cgroup_rule *cgroup_find_matching_rule(const uid_t uid,
+                               const gid_t gid, char *procname)
+{
+       /* Return value */
+       struct cgroup_rule *ret = rl.head;
+
+       pthread_rwlock_wrlock(&rl_lock);
+       while (ret) {
+               ret = cgroup_find_matching_rule_uid_gid(uid, gid, ret);
+               if (!ret)
+                       break;
+               if (!procname)
+                       /* If procname is NULL, return a rule matching
+                        * UID or GID */
+                       break;
+               if (!ret->procname)
+                       /* If no process name in a rule, that means wildcard */
+                       break;
+               if (!strcmp(ret->procname, procname))
+                       break;
+               if (!strcmp(ret->procname, basename(procname)))
+                       /* Check a rule of basename. */
+                       break;
+               ret = ret->next;
+       }
+       pthread_rwlock_unlock(&rl_lock);
+
+       return ret;
+}
+
+int cgroup_change_cgroup_flags(const uid_t uid, const gid_t gid,
+               char *procname, const pid_t pid, const int flags)
 {
        /* Temporary pointer to a rule */
        struct cgroup_rule *tmp = NULL;
@@ -1940,7 +1969,7 @@ int cgroup_change_cgroup_uid_gid_flags(const uid_t uid, const gid_t gid,
         */
        if (!(flags & CGFLAG_USECACHE)) {
                cgroup_dbg("Not using cached rules for PID %d.\n", pid);
-               ret = cgroup_parse_rules(false, uid, gid);
+               ret = cgroup_parse_rules(false, uid, gid, procname);
 
                /* The configuration file has an error!  We must exit now. */
                if (ret != -1 && ret != 0) {
@@ -1960,7 +1989,7 @@ int cgroup_change_cgroup_uid_gid_flags(const uid_t uid, const gid_t gid,
                tmp = trl.head;
        } else {
                /* Find the first matching rule in the cached list. */
-               tmp = cgroup_find_matching_rule_uid_gid(uid, gid);
+               tmp = cgroup_find_matching_rule_uid_gid(uid, gid, procname);
                if (!tmp) {
                        cgroup_dbg("No rule found to match PID: %d, UID: %d, "
                                "GID: %d\n", pid, uid, gid);
@@ -1994,6 +2023,12 @@ finished:
        return ret;
 }
 
+int cgroup_change_cgroup_uid_gid_flags(const uid_t uid, const gid_t gid,
+                               const pid_t pid, const int flags)
+{
+       return cgroup_change_cgroup_flags(uid, gid, NULL, pid, flags);
+}
+
 /**
  * Provides backwards-compatibility with older versions of the API.  This
  * function is deprecated, and cgroup_change_cgroup_uid_gid_flags() should be
@@ -2107,7 +2142,8 @@ int cgroup_reload_cached_rules()
        int ret = 0;
 
        cgroup_dbg("Reloading cached rules from %s.\n", CGRULES_CONF_FILE);
-       if ((ret = cgroup_parse_rules(true, CGRULE_INVALID, CGRULE_INVALID))) {
+       ret = cgroup_parse_rules(true, CGRULE_INVALID, CGRULE_INVALID, NULL);
+       if (ret) {
                cgroup_dbg("Error parsing configuration file \"%s\": %d.\n",
                        CGRULES_CONF_FILE, ret);
                ret = ECGROUPPARSEFAIL;
@@ -2132,7 +2168,7 @@ int cgroup_init_rules_cache()
        int ret = 0;
 
        /* Attempt to read the configuration file and cache the rules. */
-       ret = cgroup_parse_rules(true, CGRULE_INVALID, CGRULE_INVALID);
+       ret = cgroup_parse_rules(true, CGRULE_INVALID, CGRULE_INVALID, NULL);
        if (ret) {
                cgroup_dbg("Could not initialize rule cache, error was: %d\n",
                        ret);
index a101ca116bb2750af709591c8e67fa7db698c47c..2935d48a6fecf212ce36830fffe4aba180e54863 100644 (file)
@@ -71,4 +71,5 @@ global:
        cgroup_get_uid_gid_from_procfs;
        cgroup_get_subsys_mount_point;
        cgroup_get_procname_from_procfs;
+       cgroup_change_cgroup_flags;
 } CGROUP_0.33;