From: Kamalesh Babulal Date: Wed, 30 Mar 2022 06:19:03 +0000 (+0530) Subject: api.c: API to list mount points of a cgroup type X-Git-Tag: v3.0~95 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=90f586ef5d3f5d6d6226b6c612acd3b202d6469d;p=thirdparty%2Flibcgroup.git api.c: API to list mount points of a cgroup type 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 Signed-off-by: Tom Hromatka --- diff --git a/include/libcgroup/groups.h b/include/libcgroup/groups.h index 14e194e4..41edbda2 100644 --- a/include/libcgroup/groups.h +++ b/include/libcgroup/groups.h @@ -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. diff --git a/src/api.c b/src/api.c index 5f802b98..a1fc4a0d 100644 --- 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; diff --git a/src/libcgroup.map b/src/libcgroup.map index 99788ac5..fbf4d5d5 100644 --- a/src/libcgroup.map +++ b/src/libcgroup.map @@ -145,4 +145,5 @@ CGROUP_3.0 { cgroup_cgxget; cgroup_cgxset; cgroup_version; + cgroup_list_mount_points; } CGROUP_2.0;