]> git.ipfire.org Git - thirdparty/libcgroup.git/commitdiff
Substitutions in the destinations of the rules
authorMichal Hrusecky <michal@hrusecky.net>
Wed, 22 Dec 2010 19:39:10 +0000 (20:39 +0100)
committerJan Safranek <jsafrane@redhat.com>
Thu, 23 Dec 2010 11:59:23 +0000 (12:59 +0100)
Rules can be written using wildcards, but destinations had to be static.
This patch adds support for following strings in destination:

   %u - uid
   %U - username, uid in case of error
   %g - gid
   %G - group name, gid in case of error
   %p - pid
   %P - proccess name, pid in case of error

More general rules can be specified using wildcards. Example rule can be:

*@users        *     %G/%U

This will put all users in their own cgroups named by their login and
group.

Signed-off-by: Michal Hrusecky <Michal@Hrusecky.net>
Acked-by: Dhaval Giani <dhaval.giani@gmail.com>
Signed-off-by: Jan Safranek <jsafrane@redhat.com>
doc/man/cgrules.conf.5
src/api.c

index 4ca69371ef46bcdc89f197eb5319fb5a4678eaf9..9a8a0a35cb6acfcd0a8eab842a35069b904b4a22 100644 (file)
@@ -57,7 +57,16 @@ can be:
 can be:
 .nf
     - path relative to the controller hierarchy (ex. pgrp1/gid1/uid1)
-    
+    - following strings will get expanded
+
+          %u     username, uid if name resolving fails
+          %U     uid
+          %g     group name, gid if name resolving fails
+          %G     gid
+          %p     process name, pid if name not available
+          %P     pid
+
+          '\\' can be used to escape '%'
 .fi
 
 First rule which matches the criteria  will be executed.
index fa4f02e4b99466cbc0279ea188cfbdee89bdbae8..5ce6cf22d3d1ee37adeb20b7f07cf696466c0c4e 100644 (file)
--- a/src/api.c
+++ b/src/api.c
@@ -2393,6 +2393,14 @@ int cgroup_change_cgroup_flags(uid_t uid, gid_t gid,
        /* Temporary pointer to a rule */
        struct cgroup_rule *tmp = NULL;
 
+       /* Temporary variables for destination substitution */
+       char newdest[FILENAME_MAX];
+       int i, j;
+       int written;
+       int available;
+       struct passwd *user_info;
+       struct group *group_info;
+
        /* Return codes */
        int ret = 0;
 
@@ -2445,7 +2453,92 @@ int cgroup_change_cgroup_flags(uid_t uid, gid_t gid,
        do {
                cgroup_dbg("Executing rule %s for PID %d... ", tmp->username,
                                                                pid);
-               ret = cgroup_change_cgroup_path(tmp->destination,
+               /* Destination substitutions */
+               for(j = i = 0; i < strlen(tmp->destination) &&
+                       (j < FILENAME_MAX - 2); ++i, ++j) {
+                       if(tmp->destination[i] == '%') {
+                               /* How many bytes did we write / error check */
+                               written = 0;
+                               /* How many bytes can we write */
+                               available = FILENAME_MAX - j - 2;
+                               /* Substitution */
+                               switch(tmp->destination[++i]) {
+                               case 'u':
+                                       written = snprintf(newdest+j, available,
+                                               "%d", uid);
+                                       break;
+                               case 'U':
+                                       user_info = getpwuid(uid);
+                                       if(user_info) {
+                                               written = snprintf(newdest + j,
+                                                       available, "%s",
+                                                       user_info -> pw_name);
+                                       } else {
+                                               written = snprintf(newdest + j,
+                                                       available, "%d", uid);
+                                       }
+                                       break;
+                               case 'g':
+                                       written = snprintf(newdest + j,
+                                               available, "%d", gid);
+                                       break;
+                               case 'G':
+                                       group_info = getgrgid(gid);
+                                       if(group_info) {
+                                               written = snprintf(newdest + j,
+                                                       available, "%s",
+                                                       group_info -> gr_name);
+                                       } else {
+                                               written = snprintf(newdest + j,
+                                                       available, "%d", gid);
+                                       }
+                                       break;
+                               case 'p':
+                                       written = snprintf(newdest + j,
+                                               available, "%d", pid);
+                                       break;
+                               case 'P':
+                                       if(procname) {
+                                               written = snprintf(newdest + j,
+                                                       available, "%s",
+                                                       procname);
+                                       } else {
+                                               written = snprintf(newdest + j,
+                                                       available, "%d", pid);
+                                       }
+                                       break;
+                               }
+                               written = min(written, available);
+                               /*
+                                * written<1 only when either error occurred
+                                * during snprintf or if no substitution was
+                                * made at all. In both cases, we want to just
+                                * copy input string.
+                                */
+                               if(written<1) {
+                                       newdest[j] = '%';
+                                       if(available>1)
+                                               newdest[++j] =
+                                                       tmp->destination[i];
+                               } else {
+                                       /*
+                                        * In next iteration, we will write
+                                        * just after the substitution, but j
+                                        * will get incremented in the
+                                        * meantime.
+                                        */
+                                       j += written - 1;
+                               }
+                       } else {
+                               if(tmp->destination[i] == '\\')
+                                       ++i;
+                               newdest[j] = tmp->destination[i];
+                       }
+               }
+               newdest[j] = 0;
+
+               /* Apply the rule */
+               ret = cgroup_change_cgroup_path(newdest,
                                pid, (const char * const *)tmp->controllers);
                if (ret) {
                        cgroup_dbg("FAILED! (Error Code: %d)\n", ret);