]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/basic/cgroup-util.c
Merge pull request #8149 from poettering/fake-root-cgroup
[thirdparty/systemd.git] / src / basic / cgroup-util.c
index 52ae37e6b42b5c5f283441d5632423d78d35733d..9a4dd722700872f2f71d70aa21b3dbdd65756428 100644 (file)
@@ -2030,46 +2030,84 @@ int cg_get_attribute(const char *controller, const char *path, const char *attri
         return read_one_line_file(p, ret);
 }
 
-int cg_get_keyed_attribute(const char *controller, const char *path, const char *attribute, const char **keys, char **values) {
-        _cleanup_free_ char *filename = NULL, *content = NULL;
-        char *line, *p;
-        int i, r;
+int cg_get_keyed_attribute(
+                const char *controller,
+                const char *path,
+                const char *attribute,
+                char **keys,
+                char **ret_values) {
 
-        for (i = 0; keys[i]; i++)
-                values[i] = NULL;
+        _cleanup_free_ char *filename = NULL, *contents = NULL;
+        _cleanup_fclose_ FILE *f = NULL;
+        const char *p;
+        size_t n, i, n_done = 0;
+        char **v;
+        int r;
+
+        /* Reads one or more fields of a cgroupsv2 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
+         * 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. */
 
         r = cg_get_path(controller, path, attribute, &filename);
         if (r < 0)
                 return r;
 
-        r = read_full_file(filename, &content, NULL);
+        r = read_full_file(filename, &contents, NULL);
         if (r < 0)
                 return r;
 
-        p = content;
-        while ((line = strsep(&p, "\n"))) {
-                char *key;
+        n = strv_length(keys);
+        if (n == 0) /* No keys to retrieve? That's easy, we are done then */
+                return 0;
 
-                key = strsep(&line, " ");
+        /* 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);
 
-                for (i = 0; keys[i]; i++) {
-                        if (streq(key, keys[i])) {
-                                values[i] = strdup(line);
-                                break;
+        for (p = contents; *p;) {
+                const char *w = NULL;
+
+                for (i = 0; i < n; i++)
+                        if (!v[i]) {
+                                w = first_word(p, keys[i]);
+                                if (w)
+                                        break;
                         }
-                }
-        }
 
-        for (i = 0; keys[i]; i++) {
-                if (!values[i]) {
-                        for (i = 0; keys[i]; i++) {
-                                values[i] = mfree(values[i]);
+                if (w) {
+                        size_t l;
+
+                        l = strcspn(w, NEWLINE);
+                        v[i] = strndup(w, l);
+                        if (!v[i]) {
+                                r = -ENOMEM;
+                                goto fail;
                         }
-                        return -ENOENT;
-                }
+
+                        n_done++;
+                        if (n_done >= n)
+                                goto done;
+
+                        p = w + l;
+                } else
+                        p += strcspn(p, NEWLINE);
+
+                p += strspn(p, NEWLINE);
         }
 
+        r = -ENXIO;
+
+fail:
+        for (i = 0; i < n; i++)
+                free(v[i]);
+
+        return r;
+
+done:
+        memcpy(ret_values, v, sizeof(char*) * n);
         return 0;
+
 }
 
 int cg_create_everywhere(CGroupMask supported, CGroupMask mask, const char *path) {