]> git.ipfire.org Git - thirdparty/libcgroup.git/commitdiff
api.c: Add options field for rules defined in cgrules conf file
authorTom Hromatka <tom.hromatka@oracle.com>
Mon, 4 Nov 2019 23:15:11 +0000 (23:15 +0000)
committerTom Hromatka <tom.hromatka@oracle.com>
Thu, 12 Dec 2019 22:10:28 +0000 (15:10 -0700)
This commit adds a fourth field called options to the rules
entry in cgrules configuration files.  Note that the field is
optional and existing rules will be parsed exactly as before.

Also, this commit only adds the parsing of the options field.
It doesn't change the rule behavior logic; that will come in
a subsequent commit.

An example cgrules.conf using this feature:

<user>    <controller>    <destination>           <options>
*         cpu             MyCgroup                ignore
*         cpu             DefaultCgroup

In the above example (and once the subsequent processing is
added), any process currently in the cpu controller and
MyCgroup will be ignored by cgrulesengd.  In other words,
cgrules will not try to move these processes to another cgroup
or manage them in any fashion.  It is anticipated that a
separate user process (outside of the scope of libcgroup) will
manage pids in this scenario.

Signed-off-by: Tom Hromatka <tom.hromatka@oracle.com>
src/api.c
src/libcgroup-internal.h

index 41daa11a0fca7decb1782a2bdbdb0fa707692191..c418223bd6a6b155e6580722b5e6e041f60e869f 100644 (file)
--- a/src/api.c
+++ b/src/api.c
@@ -464,6 +464,48 @@ static char *cg_skip_unused_charactors_in_rule(char *rule)
        return itr;
 }
 
+/**
+ * Parse the options field in the rule from the cgrules configuration file
+ *
+ *     @param options Comma-separated string of options
+ *     @param rule Rule that will contain the parsed options
+ *     @return 0 on success, -EINVAL if the options are invalid
+ * TODO: Make this function thread safe!
+ *
+ */
+static int cgroup_parse_rules_options(char *options,
+                                     struct cgroup_rule * const rule)
+{
+       char *stok_buff = NULL;
+       size_t cmp_len;
+       int ret = 0;
+
+       stok_buff = strtok(options, ",");
+       if (!stok_buff) {
+               cgroup_err("Error: failed to parse options: %s\n",
+                          options);
+               return -EINVAL;
+       }
+
+       do {
+               cmp_len = min(strlen(stok_buff), strlen(CGRULE_OPTION_IGNORE));
+               if (strlen(stok_buff) == strlen(CGRULE_OPTION_IGNORE) &&
+                   strncmp(stok_buff, CGRULE_OPTION_IGNORE, cmp_len) == 0) {
+                       rule->is_ignore = true;
+                       continue;
+               }
+
+               /*
+                * "ignore" is the only currently supported option.  raise
+                * an error if we get here
+                */
+               cgroup_err("Error: Unsupported option: %s\n", stok_buff);
+               ret = -EINVAL;
+               break;
+       } while ((stok_buff = strtok(NULL, ",")));
+
+       return ret;
+}
 /**
  * Parse the configuration file that maps UID/GIDs to cgroups.  If ever the
  * configuration file is modified, applications should call this function to
@@ -517,10 +559,12 @@ static int cgroup_parse_rules_file(char *filename, bool cache, uid_t muid,
        char user[LOGIN_NAME_MAX] = { '\0' };
        char controllers[CG_CONTROLLER_MAX] = { '\0' };
        char destination[FILENAME_MAX] = { '\0' };
+       char options[CG_OPTIONS_MAX] = { '\0' };
        uid_t uid = CGRULE_INVALID;
        gid_t gid = CGRULE_INVALID;
        size_t len_username;
        int len_procname;
+       bool has_options = false;
 
        /* The current line number */
        unsigned int linenum = 0;
@@ -581,13 +625,19 @@ static int cgroup_parse_rules_file(char *filename, bool cache, uid_t muid,
                 * there's an error in the configuration file.
                 */
                skipped = false;
-               i = sscanf(itr, "%s%s%s", key, controllers, destination);
-               if (i != 3) {
+               i = sscanf(itr, "%s%s%s%s", key, controllers, destination,
+                          options);
+               if (i < 3) {
                        cgroup_err(
                                        "Error: failed to parse configuration file on line %d\n",
                                        linenum);
                        goto parsefail;
+               } else if (i == 3) {
+                       has_options = false;
+               } else if (i == 4) {
+                       has_options = true;
                }
+
                procname = strchr(key, ':');
                if (procname) {
                        /* <user>:<procname>  <subsystem>  <destination> */
@@ -724,6 +774,7 @@ static int cgroup_parse_rules_file(char *filename, bool cache, uid_t muid,
 
                newrule->uid = uid;
                newrule->gid = gid;
+               newrule->is_ignore = false;
                len_username = min(len_username,
                                        sizeof(newrule->username) - 1);
                strncpy(newrule->username, user, len_username);
@@ -742,6 +793,13 @@ static int cgroup_parse_rules_file(char *filename, bool cache, uid_t muid,
                }
                strncpy(newrule->destination, destination,
                        sizeof(newrule->destination) - 1);
+
+               if (has_options) {
+                       ret = cgroup_parse_rules_options(options, newrule);
+                       if (ret < 0)
+                               goto destroyrule;
+               }
+
                newrule->next = NULL;
 
                /* Parse the controller list, and add that to newrule too. */
@@ -3408,6 +3466,11 @@ void cgroup_print_rules_config(FILE *fp)
                        if (itr->controllers[i])
                                fprintf(fp, "    %s\n", itr->controllers[i]);
                }
+               fprintf(fp, "  OPTIONS:\n");
+               if (itr->is_ignore)
+                       fprintf(fp, "    IS_IGNORE: True\n");
+               else
+                       fprintf(fp, "    IS_IGNORE: False\n");
                fprintf(fp, "\n");
                itr = itr->next;
        }
index 3ee8c1baa89dfd40018351b63af74fd233f76559..b8c3324646e69a334188be9e2faf6e55bb32479c 100644 (file)
@@ -34,6 +34,7 @@ __BEGIN_DECLS
 
 #define CG_NV_MAX 100
 #define CG_CONTROLLER_MAX 100
+#define CG_OPTIONS_MAX 100
 /* Max number of mounted hierarchies. Event if one controller is mounted per
  * hier, it can not exceed CG_CONTROLLER_MAX
  */
@@ -46,6 +47,8 @@ __BEGIN_DECLS
 
 #define CGRULE_SUCCESS_STORE_PID       "SUCCESS_STORE_PID"
 
+/* Definitions for the cgrules options field */
+#define CGRULE_OPTION_IGNORE           "ignore"
 
 #define CGCONFIG_CONF_FILE             "/etc/cgconfig.conf"
 /* Minimum number of file in template file list for cgrulesengd */
@@ -129,6 +132,7 @@ struct cgroup_rules_data {
 struct cgroup_rule {
        uid_t uid;
        gid_t gid;
+       bool is_ignore;
        char *procname;
        char username[LOGIN_NAME_MAX];
        char destination[FILENAME_MAX];