4cad4c
From 5aefc153b25b42a80942e5c367ce143817551870 Mon Sep 17 00:00:00 2001
4cad4c
From: =?UTF-8?q?Michal=20Sekleta=CC=81r?= <msekleta@redhat.com>
4cad4c
Date: Wed, 29 Apr 2020 17:40:22 +0200
4cad4c
Subject: [PATCH] basic/cgroup-util: introduce cg_get_keyed_attribute_full()
4cad4c
4cad4c
Callers of cg_get_keyed_attribute_full() can now specify via the flag whether the
4cad4c
missing keyes in cgroup attribute file are OK or not. Also the wrappers for both
4cad4c
strict and graceful version are provided.
4cad4c
4cad4c
(cherry picked from commit 25a1f04c682260bb9b96e25bdf33665d6172db98)
4cad4c
4cad4c
Related: #1830861
4cad4c
---
4cad4c
 src/basic/cgroup-util.c     | 13 ++++++++++---
4cad4c
 src/basic/cgroup-util.h     | 24 +++++++++++++++++++++++-
4cad4c
 src/test/test-cgroup-util.c | 20 ++++++++++++++++++++
4cad4c
 3 files changed, 53 insertions(+), 4 deletions(-)
4cad4c
4cad4c
diff --git a/src/basic/cgroup-util.c b/src/basic/cgroup-util.c
4cad4c
index 92bc1f2543..4c0b73850d 100644
4cad4c
--- a/src/basic/cgroup-util.c
4cad4c
+++ b/src/basic/cgroup-util.c
4cad4c
@@ -2021,12 +2021,13 @@ int cg_get_attribute(const char *controller, const char *path, const char *attri
4cad4c
         return read_one_line_file(p, ret);
4cad4c
 }
4cad4c
 
4cad4c
-int cg_get_keyed_attribute(
4cad4c
+int cg_get_keyed_attribute_full(
4cad4c
                 const char *controller,
4cad4c
                 const char *path,
4cad4c
                 const char *attribute,
4cad4c
                 char **keys,
4cad4c
-                char **ret_values) {
4cad4c
+                char **ret_values,
4cad4c
+                CGroupKeyMode mode) {
4cad4c
 
4cad4c
         _cleanup_free_ char *filename = NULL, *contents = NULL;
4cad4c
         const char *p;
4cad4c
@@ -2086,7 +2087,10 @@ int cg_get_keyed_attribute(
4cad4c
                 p += strspn(p, NEWLINE);
4cad4c
         }
4cad4c
 
4cad4c
-        r = -ENXIO;
4cad4c
+        if (mode & CG_KEY_MODE_GRACEFUL)
4cad4c
+                goto done;
4cad4c
+        else
4cad4c
+                r = -ENXIO;
4cad4c
 
4cad4c
 fail:
4cad4c
         for (i = 0; i < n; i++)
4cad4c
@@ -2096,6 +2100,9 @@ fail:
4cad4c
 
4cad4c
 done:
4cad4c
         memcpy(ret_values, v, sizeof(char*) * n);
4cad4c
+        if (mode & CG_KEY_MODE_GRACEFUL)
4cad4c
+                return n_done;
4cad4c
+
4cad4c
         return 0;
4cad4c
 
4cad4c
 }
4cad4c
diff --git a/src/basic/cgroup-util.h b/src/basic/cgroup-util.h
4cad4c
index b414600dca..0673f4b4ce 100644
4cad4c
--- a/src/basic/cgroup-util.h
4cad4c
+++ b/src/basic/cgroup-util.h
4cad4c
@@ -167,9 +167,31 @@ int cg_attach(const char *controller, const char *path, pid_t pid);
4cad4c
 int cg_attach_fallback(const char *controller, const char *path, pid_t pid);
4cad4c
 int cg_create_and_attach(const char *controller, const char *path, pid_t pid);
4cad4c
 
4cad4c
+typedef enum  {
4cad4c
+        CG_KEY_MODE_GRACEFUL = 1 << 0,
4cad4c
+} CGroupKeyMode;
4cad4c
+
4cad4c
 int cg_set_attribute(const char *controller, const char *path, const char *attribute, const char *value);
4cad4c
 int cg_get_attribute(const char *controller, const char *path, const char *attribute, char **ret);
4cad4c
-int cg_get_keyed_attribute(const char *controller, const char *path, const char *attribute, char **keys, char **values);
4cad4c
+int cg_get_keyed_attribute_full(const char *controller, const char *path, const char *attribute, char **keys, char **values, CGroupKeyMode mode);
4cad4c
+
4cad4c
+static inline int cg_get_keyed_attribute(
4cad4c
+                const char *controller,
4cad4c
+                const char *path,
4cad4c
+                const char *attribute,
4cad4c
+                char **keys,
4cad4c
+                char **ret_values) {
4cad4c
+        return cg_get_keyed_attribute_full(controller, path, attribute, keys, ret_values, 0);
4cad4c
+}
4cad4c
+
4cad4c
+static inline int cg_get_keyed_attribute_graceful(
4cad4c
+                const char *controller,
4cad4c
+                const char *path,
4cad4c
+                const char *attribute,
4cad4c
+                char **keys,
4cad4c
+                char **ret_values) {
4cad4c
+        return cg_get_keyed_attribute_full(controller, path, attribute, keys, ret_values, CG_KEY_MODE_GRACEFUL);
4cad4c
+}
4cad4c
 
4cad4c
 int cg_set_access(const char *controller, const char *path, uid_t uid, gid_t gid);
4cad4c
 
4cad4c
diff --git a/src/test/test-cgroup-util.c b/src/test/test-cgroup-util.c
4cad4c
index d49356315e..60d7bb19cb 100644
4cad4c
--- a/src/test/test-cgroup-util.c
4cad4c
+++ b/src/test/test-cgroup-util.c
4cad4c
@@ -421,22 +421,42 @@ static void test_cg_get_keyed_attribute(void) {
4cad4c
         }
4cad4c
 
4cad4c
         assert_se(cg_get_keyed_attribute("cpu", "/init.scope", "cpu.stat", STRV_MAKE("no_such_attr"), &val) == -ENXIO);
4cad4c
+        assert_se(cg_get_keyed_attribute_graceful("cpu", "/init.scope", "cpu.stat", STRV_MAKE("no_such_attr"), &val) == 0);
4cad4c
         assert_se(val == NULL);
4cad4c
 
4cad4c
         assert_se(cg_get_keyed_attribute("cpu", "/init.scope", "cpu.stat", STRV_MAKE("usage_usec"), &val) == 0);
4cad4c
+        free(val);
4cad4c
+
4cad4c
+        assert_se(cg_get_keyed_attribute_graceful("cpu", "/init.scope", "cpu.stat", STRV_MAKE("usage_usec"), &val) == 1);
4cad4c
         log_info("cpu /init.scope cpu.stat [usage_usec] → \"%s\"", val);
4cad4c
 
4cad4c
         assert_se(cg_get_keyed_attribute("cpu", "/init.scope", "cpu.stat", STRV_MAKE("usage_usec", "no_such_attr"), vals3) == -ENXIO);
4cad4c
+        assert_se(cg_get_keyed_attribute_graceful("cpu", "/init.scope", "cpu.stat", STRV_MAKE("usage_usec", "no_such_attr"), vals3) == 1);
4cad4c
+        assert(vals3[0] && !vals3[1]);
4cad4c
+        free(vals3[0]);
4cad4c
 
4cad4c
         assert_se(cg_get_keyed_attribute("cpu", "/init.scope", "cpu.stat", STRV_MAKE("usage_usec", "usage_usec"), vals3) == -ENXIO);
4cad4c
+        assert_se(cg_get_keyed_attribute_graceful("cpu", "/init.scope", "cpu.stat", STRV_MAKE("usage_usec", "usage_usec"), vals3) == 1);
4cad4c
+        assert(vals3[0] && !vals3[1]);
4cad4c
+        free(vals3[0]);
4cad4c
 
4cad4c
         assert_se(cg_get_keyed_attribute("cpu", "/init.scope", "cpu.stat",
4cad4c
                                          STRV_MAKE("usage_usec", "user_usec", "system_usec"), vals3) == 0);
4cad4c
+        for (i = 0; i < 3; i++)
4cad4c
+                free(vals3[i]);
4cad4c
+
4cad4c
+        assert_se(cg_get_keyed_attribute_graceful("cpu", "/init.scope", "cpu.stat",
4cad4c
+                                         STRV_MAKE("usage_usec", "user_usec", "system_usec"), vals3) == 3);
4cad4c
         log_info("cpu /init.scope cpu.stat [usage_usec user_usec system_usec] → \"%s\", \"%s\", \"%s\"",
4cad4c
                  vals3[0], vals3[1], vals3[2]);
4cad4c
 
4cad4c
         assert_se(cg_get_keyed_attribute("cpu", "/init.scope", "cpu.stat",
4cad4c
                                          STRV_MAKE("system_usec", "user_usec", "usage_usec"), vals3a) == 0);
4cad4c
+        for (i = 0; i < 3; i++)
4cad4c
+                free(vals3a[i]);
4cad4c
+
4cad4c
+        assert_se(cg_get_keyed_attribute_graceful("cpu", "/init.scope", "cpu.stat",
4cad4c
+                                         STRV_MAKE("system_usec", "user_usec", "usage_usec"), vals3a) == 3);
4cad4c
         log_info("cpu /init.scope cpu.stat [system_usec user_usec usage_usec] → \"%s\", \"%s\", \"%s\"",
4cad4c
                  vals3a[0], vals3a[1], vals3a[2]);
4cad4c