]> git.ipfire.org Git - thirdparty/libcgroup.git/commitdiff
api.c: API to list mount points of a cgroup type
authorKamalesh Babulal <kamalesh.babulal@oracle.com>
Wed, 30 Mar 2022 06:19:03 +0000 (11:49 +0530)
committerTom Hromatka <tom.hromatka@oracle.com>
Fri, 1 Apr 2022 14:30:04 +0000 (08:30 -0600)
Currently, there is no easy way for a user to list cgroup mount points,
one way to acquire required information is by manually reading the
/proc/mounts and parsing the information they are interested in.

Add a new API:
cgroup_list_mount_points(cg_version_t version, char ***mnts),

where the first argument is either CGROUP_V1 or CGROUP_V2, that
specifies the mount point types and the second argument is a char**,
that will hold the mount point paths of the cgroup version specified in
the first agrument. Note that the mnts pointers are supposed to free'd.
mnts pointers.

$ cat get_mount.c

int main(void)
{
        enum cg_version_t t = CGROUP_V2;
        char **mount_paths = NULL;
        int i = 0;
        int ret;

        cgroup_init();

         ret = cgroup_list_mount_points(t, &mount_paths);
         if (ret != 0) {
                 fprintf(stderr, "Failed to get mount points\n");
                 return ret;
        }

        while (mount_paths[i]) {
                fprintf(stderr, "%s\n", mount_paths[i]);
                free(mount_paths[i]);
                i++;
        }
        free(mount_paths);

        return 0;
}

$ gcc -o get_mount get_mount.c -lcgroup

Signed-off-by: Kamalesh Babulal <kamalesh.babulal@oracle.com>
Signed-off-by: Tom Hromatka <tom.hromatka@oracle.com>
include/libcgroup/groups.h
src/api.c
src/libcgroup.map

index 14e194e4e114c2509cfa89e1d3b57f94e4b6011b..41edbda2b740b0f3792287005eee085c5f37e20b 100644 (file)
@@ -615,6 +615,17 @@ int cgroup_convert_cgroup(struct cgroup * const out_cgroup,
                          const struct cgroup * const in_cgroup,
                          enum cg_version_t in_version);
 
+/**
+ * List the mount paths, that matches the specified version
+ *
+ *     @param cgrp_version The cgroup type/version
+ *     @param mount_paths Holds the list of mount paths
+ *     @return 0 success and list of mounts paths in mount_paths
+ *             ECGOTHER on failure and mount_paths is NULL.
+ */
+int cgroup_list_mount_points(const enum cg_version_t cgrp_version,
+                            char ***mount_paths);
+
 /**
  * Get the cgroup version of a controller.  Version is set to CGROUP_UNK
  * if the version cannot be determined.
index 5f802b98a3e195eadfa307daa89604c7daa7ff8c..a1fc4a0df10def137f1de9e4e30b454238e2a4c0 100644 (file)
--- a/src/api.c
+++ b/src/api.c
@@ -93,6 +93,9 @@ __thread char *cg_namespace_table[CG_CONTROLLER_MAX];
 pthread_rwlock_t cg_mount_table_lock = PTHREAD_RWLOCK_INITIALIZER;
 struct cg_mount_table_s cg_mount_table[CG_CONTROLLER_MAX];
 
+/* Cgroup v2 mount paths, with empty controllers */
+struct cg_mount_point *cg_cgroup_v2_empty_mount_paths;
+
 const char * const cgroup_strerror_codes[] = {
        "Cgroup is not compiled in",
        "Cgroup is not mounted",
@@ -1221,7 +1224,32 @@ STATIC int cgroup_process_v2_mnt(struct mntent *ent, int *mnt_tbl_idx)
 
        ret_c = fgets(line, LL_MAX, fp);
        if (ret_c == NULL) {
+               struct cg_mount_point *tmp, *t;
+
                ret = ECGEOF;
+
+               tmp = malloc(sizeof(struct cg_mount_point));
+               if (tmp == NULL) {
+                       last_errno = errno;
+                       ret = ECGOTHER;
+                       goto out;
+               }
+
+               strncpy(tmp->path, cg_cgroup_v2_mount_path,
+                       sizeof(tmp->path) - 1);
+               tmp->path[sizeof(tmp->path)-1] = '\0';
+               tmp->next = NULL;
+
+               t = cg_cgroup_v2_empty_mount_paths;
+               if (t == NULL) {
+                       cg_cgroup_v2_empty_mount_paths = tmp;
+                       goto out;
+               }
+
+               while(t->next != NULL)
+                       t = t->next;
+               t->next = tmp;
+
                goto out;
        }
 
@@ -1292,6 +1320,8 @@ static void cgroup_free_cg_mount_table(void)
 
        memset(&cg_mount_table, 0, sizeof(cg_mount_table));
        memset(&cg_cgroup_v2_mount_path, 0, sizeof(cg_cgroup_v2_mount_path));
+       memset(&cg_cgroup_v2_empty_mount_paths, 0,
+              sizeof(cg_cgroup_v2_empty_mount_paths));
 }
 
 /*
@@ -5923,6 +5953,140 @@ int cgroup_get_controller_version(const char * const controller,
        return ECGROUPNOTEXIST;
 }
 
+static int search_and_append_mnt_path(struct cg_mount_point **mount_point,
+                                     char *path)
+{
+       struct cg_mount_point *mnt_point, *mnt_tmp, *mnt_prev;
+
+       mnt_tmp = *mount_point;
+       while(mnt_tmp) {
+               if (strcmp(mnt_tmp->path, path) == 0)
+                       return ECGVALUEEXISTS;
+
+               mnt_prev = mnt_tmp;
+               mnt_tmp = mnt_tmp->next;
+       }
+
+       mnt_point = malloc(sizeof(struct cg_mount_point));
+       if (mnt_point == NULL) {
+               last_errno = errno;
+               return ECGOTHER;
+       }
+
+       strcpy(mnt_point->path, path);
+       mnt_point->next = NULL;
+
+       if (*mount_point == NULL)
+               *mount_point = mnt_point;
+       else
+               mnt_prev->next = mnt_point;
+
+       return 0;
+}
+
+/**
+ * List the mount paths, that matches the specified version
+ *
+ *     @param cgrp_version The cgroup type/version
+ *     @param mount_paths Holds the list of mount paths
+ *     @return 0 success and list of mounts paths in mount_paths
+ *             ECGOTHER on failure and mount_paths is NULL.
+ */
+int cgroup_list_mount_points(const enum cg_version_t cgrp_version,
+                            char ***mount_paths)
+{
+       struct cg_mount_point *mount_point, *mnt_tmp = NULL;
+       char **mnt_paths = NULL;
+       int i, idx = 0;
+       int ret;
+
+       if (!cgroup_initialized)
+               return ECGROUPNOTINITIALIZED;
+
+       if (cgrp_version != CGROUP_V1 && cgrp_version != CGROUP_V2)
+               return ECGINVAL;
+
+       pthread_rwlock_rdlock(&cg_mount_table_lock);
+
+       for (i = 0; cg_mount_table[i].name[0] != '\0'; i++) {
+               if (cg_mount_table[i].version != cgrp_version)
+                       continue;
+
+               mount_point = &cg_mount_table[i].mount;
+               while (mount_point) {
+                       ret = search_and_append_mnt_path(&mnt_tmp,
+                                                        mount_point->path);
+                       if (ret != 0 && ret != ECGVALUEEXISTS)
+                               goto err;
+
+                       /* Avoid adding duplicate mount points */
+                       if (ret != ECGVALUEEXISTS)
+                               idx++;
+
+                       mount_point = mount_point->next;
+               }
+       }
+
+       /*
+        * Cgroup v2 can be mounted without any controller and these mount
+        * paths are not part of the cg_mount_table.  Check and append them
+        * to mnt_paths.
+        */
+       if (cgrp_version == CGROUP_V2 && cg_cgroup_v2_empty_mount_paths ) {
+               mount_point = cg_cgroup_v2_empty_mount_paths;
+               while(mount_point) {
+                       ret = search_and_append_mnt_path(&mnt_tmp,
+                                                        mount_point->path);
+                       if (ret)
+                               goto err;
+
+                       idx++;
+                       mount_point = mount_point->next;
+               }
+       }
+
+       mnt_paths = malloc(sizeof(char*) * (idx + 1));
+       if (mnt_paths == NULL) {
+               last_errno = errno;
+               ret = ECGOTHER;
+               goto err;
+       }
+
+       for (i = 0, mount_point = mnt_tmp;
+            mount_point;
+            mount_point = mount_point->next, i++) {
+
+               mnt_paths[i] = strdup(mount_point->path);
+               if (mnt_paths[i] == NULL) {
+                       last_errno = errno;
+                       ret = ECGOTHER;
+                       goto err;
+               }
+       }
+       mnt_paths[i] = '\0';
+
+       ret = 0;
+       *mount_paths = mnt_paths;
+
+err:
+       pthread_rwlock_unlock(&cg_mount_table_lock);
+
+       while(mnt_tmp) {
+               mount_point = mnt_tmp;
+               mnt_tmp = mnt_tmp->next;
+               free(mount_point);
+       }
+
+       if (ret != 0 && mnt_paths) {
+               for (i = 0; i < idx; i++)
+                       free(mnt_paths[i]);
+               free(mnt_paths);
+               *mount_paths = NULL;
+       }
+
+       return ret;
+}
+
 const struct cgroup_library_version *cgroup_version(void)
 {
        return &library_version;
index 99788ac56f459cd965f613a00b417c1b03880084..fbf4d5d510cdcda1ecb357c587a91b85ad207441 100644 (file)
@@ -145,4 +145,5 @@ CGROUP_3.0 {
        cgroup_cgxget;
        cgroup_cgxset;
        cgroup_version;
+       cgroup_list_mount_points;
 } CGROUP_2.0;