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;
n_done++;
if (n_done >= n)
- goto done;
+ break;
p = w + l;
} else
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) {
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);
}
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) {