From: Mike Yuan Date: Mon, 19 May 2025 19:06:17 +0000 (+0200) Subject: cgroup-util: modernize cg_get_keyed_attribute() X-Git-Tag: v258-rc1~572^2 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=dbe592a067490a0de6ca5bdfd0e6ae4f2f7fe537;p=thirdparty%2Fsystemd.git cgroup-util: modernize cg_get_keyed_attribute() - assert on supplied keys being unique - Reject duplicate attributes with -EBADMSG - Rename 'ret_values' to just 'values', given we don't allocate the array - Remove now unused cg_get_keyed_attribute_graceful() --- diff --git a/src/basic/cgroup-util.c b/src/basic/cgroup-util.c index 21e8811e8d3..d8e94c3ed9d 100644 --- a/src/basic/cgroup-util.c +++ b/src/basic/cgroup-util.c @@ -1777,56 +1777,61 @@ int cg_get_owner(const char *path, uid_t *ret_uid) { return 0; } -int cg_get_keyed_attribute_full( +int cg_get_keyed_attribute( const char *controller, const char *path, const char *attribute, - char **keys, - char **ret_values, - CGroupKeyMode mode) { + char * const *keys, + char **values) { _cleanup_free_ char *filename = NULL, *contents = NULL; - const char *p; - size_t n, i, n_done = 0; - char **v; + size_t n; int r; + assert(path); + assert(attribute); + /* Reads one or more fields of a cgroup v2 keyed attribute file. The 'keys' parameter should be an strv with - * all keys to retrieve. The 'ret_values' parameter should be passed as string size with the same number of + * all keys to retrieve. The 'values' parameter should be passed as string size with the same number of * entries as 'keys'. On success each entry will be set to the value of the matching key. * - * If the attribute file doesn't exist at all returns ENOENT, if any key is not found returns ENXIO. If mode - * is set to GG_KEY_MODE_GRACEFUL we ignore missing keys and return those that were parsed successfully. */ + * If the attribute file doesn't exist at all returns ENOENT, if any key is not found returns ENXIO. */ r = cg_get_path(controller, path, attribute, &filename); if (r < 0) return r; - r = read_full_file(filename, &contents, NULL); + r = read_full_file(filename, &contents, /* ret_size = */ NULL); if (r < 0) return r; n = strv_length(keys); if (n == 0) /* No keys to retrieve? That's easy, we are done then */ return 0; + assert(strv_is_uniq(keys)); /* Let's build this up in a temporary array for now in order not to clobber the return parameter on failure */ - v = newa0(char*, n); + char **v = newa0(char*, n); + size_t n_done = 0; - for (p = contents; *p;) { - const char *w = NULL; + for (const char *p = contents; *p;) { + const char *w; + size_t i; - for (i = 0; i < n; i++) - if (!v[i]) { - w = first_word(p, keys[i]); - if (w) - break; - } + for (i = 0; i < n; i++) { + w = first_word(p, keys[i]); + if (w) + break; + } if (w) { - size_t l; + if (v[i]) { /* duplicate entry? */ + r = -EBADMSG; + goto fail; + } + + size_t l = strcspn(w, NEWLINE); - l = strcspn(w, NEWLINE); v[i] = strndup(w, l); if (!v[i]) { r = -ENOMEM; @@ -1835,7 +1840,7 @@ int cg_get_keyed_attribute_full( n_done++; if (n_done >= n) - goto done; + break; p = w + l; } else @@ -1844,21 +1849,17 @@ int cg_get_keyed_attribute_full( p += strspn(p, NEWLINE); } - if (mode & CG_KEY_MODE_GRACEFUL) - goto done; + if (n_done < n) { + r = -ENXIO; + goto fail; + } - r = -ENXIO; + memcpy(values, v, sizeof(char*) * n); + return 0; fail: free_many_charp(v, n); return r; - -done: - memcpy(ret_values, v, sizeof(char*) * n); - if (mode & CG_KEY_MODE_GRACEFUL) - return n_done; - - return 0; } int cg_mask_to_string(CGroupMask mask, char **ret) { diff --git a/src/basic/cgroup-util.h b/src/basic/cgroup-util.h index 5af7643b6f0..1d67174b43c 100644 --- a/src/basic/cgroup-util.h +++ b/src/basic/cgroup-util.h @@ -226,31 +226,9 @@ int cg_is_delegated_fd(int fd); int cg_has_coredump_receive(const char *path); -typedef enum { - CG_KEY_MODE_GRACEFUL = 1 << 0, -} CGroupKeyMode; - int cg_set_attribute(const char *controller, const char *path, const char *attribute, const char *value); int cg_get_attribute(const char *controller, const char *path, const char *attribute, char **ret); -int cg_get_keyed_attribute_full(const char *controller, const char *path, const char *attribute, char **keys, char **values, CGroupKeyMode mode); - -static inline int cg_get_keyed_attribute( - const char *controller, - const char *path, - const char *attribute, - char **keys, - char **ret_values) { - return cg_get_keyed_attribute_full(controller, path, attribute, keys, ret_values, 0); -} - -static inline int cg_get_keyed_attribute_graceful( - const char *controller, - const char *path, - const char *attribute, - char **keys, - char **ret_values) { - return cg_get_keyed_attribute_full(controller, path, attribute, keys, ret_values, CG_KEY_MODE_GRACEFUL); -} +int cg_get_keyed_attribute(const char *controller, const char *path, const char *attribute, char * const *keys, char **values); int cg_get_attribute_as_uint64(const char *controller, const char *path, const char *attribute, uint64_t *ret); diff --git a/src/test/test-cgroup-util.c b/src/test/test-cgroup-util.c index 32505f82932..5bd3427ab4a 100644 --- a/src/test/test-cgroup-util.c +++ b/src/test/test-cgroup-util.c @@ -426,49 +426,22 @@ TEST(cg_get_keyed_attribute) { } assert_se(cg_get_keyed_attribute("cpu", "/init.scope", "cpu.stat", STRV_MAKE("no_such_attr"), &val) == -ENXIO); - assert_se(cg_get_keyed_attribute_graceful("cpu", "/init.scope", "cpu.stat", STRV_MAKE("no_such_attr"), &val) == 0); ASSERT_NULL(val); assert_se(cg_get_keyed_attribute("cpu", "/init.scope", "cpu.stat", STRV_MAKE("usage_usec"), &val) == 0); val = mfree(val); - assert_se(cg_get_keyed_attribute_graceful("cpu", "/init.scope", "cpu.stat", STRV_MAKE("usage_usec"), &val) == 1); - log_info("cpu /init.scope cpu.stat [usage_usec] → \"%s\"", val); - assert_se(cg_get_keyed_attribute("cpu", "/init.scope", "cpu.stat", STRV_MAKE("usage_usec", "no_such_attr"), vals3) == -ENXIO); - assert_se(cg_get_keyed_attribute_graceful("cpu", "/init.scope", "cpu.stat", STRV_MAKE("usage_usec", "no_such_attr"), vals3) == 1); - assert_se(vals3[0] && !vals3[1]); - free(vals3[0]); - - assert_se(cg_get_keyed_attribute("cpu", "/init.scope", "cpu.stat", STRV_MAKE("usage_usec", "usage_usec"), vals3) == -ENXIO); - assert_se(cg_get_keyed_attribute_graceful("cpu", "/init.scope", "cpu.stat", STRV_MAKE("usage_usec", "usage_usec"), vals3) == 1); - assert_se(vals3[0] && !vals3[1]); - free(vals3[0]); assert_se(cg_get_keyed_attribute("cpu", "/init.scope", "cpu.stat", STRV_MAKE("usage_usec", "user_usec", "system_usec"), vals3) == 0); for (size_t i = 0; i < 3; i++) free(vals3[i]); - assert_se(cg_get_keyed_attribute_graceful("cpu", "/init.scope", "cpu.stat", - STRV_MAKE("usage_usec", "user_usec", "system_usec"), vals3) == 3); - log_info("cpu /init.scope cpu.stat [usage_usec user_usec system_usec] → \"%s\", \"%s\", \"%s\"", - vals3[0], vals3[1], vals3[2]); - assert_se(cg_get_keyed_attribute("cpu", "/init.scope", "cpu.stat", STRV_MAKE("system_usec", "user_usec", "usage_usec"), vals3a) == 0); for (size_t i = 0; i < 3; i++) free(vals3a[i]); - - assert_se(cg_get_keyed_attribute_graceful("cpu", "/init.scope", "cpu.stat", - STRV_MAKE("system_usec", "user_usec", "usage_usec"), vals3a) == 3); - log_info("cpu /init.scope cpu.stat [system_usec user_usec usage_usec] → \"%s\", \"%s\", \"%s\"", - vals3a[0], vals3a[1], vals3a[2]); - - for (size_t i = 0; i < 3; i++) { - free(vals3[i]); - free(vals3a[i]); - } } TEST(bfq_weight_conversion) {