This commit adds a function that, given a pid, can read in
the controllers and cgroups listed in /proc/{pid}/cgroup.
The caller is expected to allocate the controller_list[]
and cgroup_list[] arrays as well as null each entry in the
arrays.  cg_get_cgroups_from_proc_cgroups() will allocate
the necessary memory for each string within the arrays.

Note that it's common to have many controllers on newer
kernels, so MAX_MNT_ELEMENTS was increased to 16 to handle
these additional controllers.

Signed-off-by: Tom Hromatka <tom.hroma...@oracle.com>
---
 src/api.c                | 103 +++++++++++++++++++++++++++++++++++++++++++++++
 src/libcgroup-internal.h |   2 +-
 2 files changed, 104 insertions(+), 1 deletion(-)

diff --git a/src/api.c b/src/api.c
index 907475f8d6cf..105816a3ff51 100644
--- a/src/api.c
+++ b/src/api.c
@@ -4189,6 +4189,109 @@ int cgroup_get_uid_gid_from_procfs(pid_t pid, uid_t 
*euid, gid_t *egid)
 }
 
 /**
+ * Given a pid, this function will return the controllers and cgroups that
+ * the pid is a member of.  The caller is expected to allocate the
+ * controller_list[] and cgroup_list[] arrays as well as null each entry in
+ * the arrays.  This function will allocate the necessary memory for each
+ * string within the arrays.
+ *
+ *     @param pid The process id
+ *     @param cgroup_list[] An array of char pointers to hold the cgroups
+ *     @param controller_list[] An array of char pointers to hold the list
+ *            of controllers
+ *     @param list_len The size of the arrays
+ */
+static int cg_get_cgroups_from_proc_cgroups(pid_t pid, char *cgroup_list[],
+                                           char *controller_list[],
+                                           int list_len)
+{
+       char path[FILENAME_MAX];
+       char buf[4092];
+       char *stok_buff = NULL;
+       int ret = 0;
+       size_t buff_len;
+       int idx = 0;
+       FILE *f;
+
+       sprintf(path, "/proc/%d/cgroup", pid);
+       f = fopen(path, "re");
+       if (!f)
+               return ECGROUPNOTEXIST;
+
+       while (fgets(buf, sizeof(buf), f)) {
+               /*
+                * Each line in /proc/{pid}/cgroup is like the following:
+                *
+                * {cg#}:{controller}:{cgname}
+                *
+                * e.g.
+                * 7:devices:/user.slice
+                */
+
+               /* read in the cgroup number.  we don't care about it */
+               stok_buff = strtok(buf, ":");
+               /* read in the controller name */
+               stok_buff = strtok(NULL, ":");
+
+               /*
+                * after this point, we have allocated memory.  if we return
+                * an error code after this, it's up to us to free the
+                * memory we allocated
+                */
+               controller_list[idx] = strndup(stok_buff,
+                                              strlen(stok_buff) + 1);
+
+               /* read in the cgroup name */
+               stok_buff = strtok(NULL, ":");
+
+               if (stok_buff == NULL) {
+                       /*
+                        * An empty controller is reported on some kernels.
+                        * It may look like this:
+                        * 0::/user.slice/user-1000.slice/session-1.scope
+                        *
+                        * Ignore this controller and move on.  Note that we
+                        * need to free the controller list entry we made.
+                        */
+                       free(controller_list[idx]);
+                       controller_list[idx] = NULL;
+                       continue;
+               }
+
+               buff_len = strlen(stok_buff);
+               if (stok_buff[buff_len - 1] == '\n')
+                       /* Don't copy the trailing newline char */
+                       buff_len--;
+
+               /* read in the cgroup name */
+               if (buff_len > 1) {
+                       /*
+                        * Strip off the leading '/' for every cgroup but
+                        * the root cgroup
+                        */
+                       cgroup_list[idx] = malloc(buff_len);
+                       snprintf(cgroup_list[idx], buff_len, "%s",
+                                &stok_buff[1]);
+               } else {
+                       /*
+                        * Retain the leading '/' since we're in the root
+                        * cgroup
+                        */
+                       cgroup_list[idx] = strndup(stok_buff, buff_len);
+               }
+
+               idx++;
+               if (idx >= list_len) {
+                       cgroup_warn("Maximum mount elements reached.  "
+                                   "Consider increasing MAX_MNT_ELEMENTS\n");
+                       break;
+               }
+       }
+       fclose(f);
+       return ret;
+}
+
+/**
  * Get process name from /proc/<pid>/status file.
  * @param pid: The process id
  * @param pname_status : The process name
diff --git a/src/libcgroup-internal.h b/src/libcgroup-internal.h
index e438916dafaf..b52c82c3f042 100644
--- a/src/libcgroup-internal.h
+++ b/src/libcgroup-internal.h
@@ -28,7 +28,7 @@ __BEGIN_DECLS
 #include <setjmp.h>
 
 /* Maximum number of mount points/controllers */
-#define MAX_MNT_ELEMENTS       8
+#define MAX_MNT_ELEMENTS       16
 /* Estimated number of groups created */
 #define MAX_GROUP_ELEMENTS     128
 
-- 
1.8.3.1



_______________________________________________
Libcg-devel mailing list
Libcg-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/libcg-devel

Reply via email to