]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/test/test-cgroup-util.c
systemd-nspawn: decrease non-fatal mount errors to debug level (#4569)
[thirdparty/systemd.git] / src / test / test-cgroup-util.c
CommitLineData
6c03089c
LP
1/***
2 This file is part of systemd.
3
4 Copyright 2013 Zbigniew Jędrzejewski-Szmek
5
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
10
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
18***/
19
b5efdb8a 20#include "alloc-util.h"
96cde13a 21#include "cgroup-util.h"
a0956174 22#include "dirent-util.h"
3ffd4af2 23#include "fd-util.h"
6482f626 24#include "formats-util.h"
6bedfcbb 25#include "parse-util.h"
0b452006 26#include "process-util.h"
f0bef277 27#include "stat-util.h"
07630cea 28#include "string-util.h"
3ffd4af2 29#include "test-helper.h"
ee104e11 30#include "user-util.h"
3ffd4af2 31#include "util.h"
96cde13a 32
7027ff61 33static void check_p_d_u(const char *path, int code, const char *result) {
6c03089c 34 _cleanup_free_ char *unit = NULL;
d4fffc4b 35 int r;
96cde13a 36
d4fffc4b
ZJS
37 r = cg_path_decode_unit(path, &unit);
38 printf("%s: %s → %s %d expected %s %d\n", __func__, path, unit, r, result, code);
39 assert_se(r == code);
6c03089c
LP
40 assert_se(streq_ptr(unit, result));
41}
96cde13a 42
7027ff61 43static void test_path_decode_unit(void) {
d7bd3de0
LP
44 check_p_d_u("getty@tty2.service", 0, "getty@tty2.service");
45 check_p_d_u("getty@tty2.service/", 0, "getty@tty2.service");
46 check_p_d_u("getty@tty2.service/xxx", 0, "getty@tty2.service");
cfeaa44a
LP
47 check_p_d_u("getty@.service/", -ENXIO, NULL);
48 check_p_d_u("getty@.service", -ENXIO, NULL);
7027ff61 49 check_p_d_u("getty.service", 0, "getty.service");
cfeaa44a
LP
50 check_p_d_u("getty", -ENXIO, NULL);
51 check_p_d_u("getty/waldo", -ENXIO, NULL);
d7bd3de0 52 check_p_d_u("_cpu.service", 0, "cpu.service");
6c03089c
LP
53}
54
55static void check_p_g_u(const char *path, int code, const char *result) {
56 _cleanup_free_ char *unit = NULL;
d4fffc4b 57 int r;
6c03089c 58
d4fffc4b
ZJS
59 r = cg_path_get_unit(path, &unit);
60 printf("%s: %s → %s %d expected %s %d\n", __func__, path, unit, r, result, code);
61 assert_se(r == code);
6c03089c
LP
62 assert_se(streq_ptr(unit, result));
63}
64
9444b1f2
LP
65static void test_path_get_unit(void) {
66 check_p_g_u("/system.slice/foobar.service/sdfdsaf", 0, "foobar.service");
d7bd3de0
LP
67 check_p_g_u("/system.slice/getty@tty5.service", 0, "getty@tty5.service");
68 check_p_g_u("/system.slice/getty@tty5.service/aaa/bbb", 0, "getty@tty5.service");
69 check_p_g_u("/system.slice/getty@tty5.service/", 0, "getty@tty5.service");
9444b1f2 70 check_p_g_u("/system.slice/getty@tty6.service/tty5", 0, "getty@tty6.service");
cfeaa44a
LP
71 check_p_g_u("sadfdsafsda", -ENXIO, NULL);
72 check_p_g_u("/system.slice/getty####@tty6.service/xxx", -ENXIO, NULL);
9444b1f2 73 check_p_g_u("/system.slice/system-waldo.slice/foobar.service/sdfdsaf", 0, "foobar.service");
d7bd3de0 74 check_p_g_u("/system.slice/system-waldo.slice/_cpu.service/sdfdsaf", 0, "cpu.service");
d4fffc4b 75 check_p_g_u("/user.slice/user-1000.slice/user@1000.service/server.service", 0, "user@1000.service");
cfeaa44a 76 check_p_g_u("/user.slice/user-1000.slice/user@.service/server.service", -ENXIO, NULL);
9444b1f2
LP
77}
78
6c03089c
LP
79static void check_p_g_u_u(const char *path, int code, const char *result) {
80 _cleanup_free_ char *unit = NULL;
d4fffc4b 81 int r;
6c03089c 82
d4fffc4b
ZJS
83 r = cg_path_get_user_unit(path, &unit);
84 printf("%s: %s → %s %d expected %s %d\n", __func__, path, unit, r, result, code);
85 assert_se(r == code);
6c03089c
LP
86 assert_se(streq_ptr(unit, result));
87}
88
9444b1f2 89static void test_path_get_user_unit(void) {
374ec6ab
LP
90 check_p_g_u_u("/user.slice/user-1000.slice/session-2.scope/foobar.service", 0, "foobar.service");
91 check_p_g_u_u("/user.slice/user-1000.slice/session-2.scope/waldo.slice/foobar.service", 0, "foobar.service");
92 check_p_g_u_u("/user.slice/user-1002.slice/session-2.scope/foobar.service/waldo", 0, "foobar.service");
93 check_p_g_u_u("/user.slice/user-1000.slice/session-2.scope/foobar.service/waldo/uuuux", 0, "foobar.service");
cfeaa44a 94 check_p_g_u_u("/user.slice/user-1000.slice/session-2.scope/waldo/waldo/uuuux", -ENXIO, NULL);
d7bd3de0
LP
95 check_p_g_u_u("/user.slice/user-1000.slice/session-2.scope/foobar@pie.service/pa/po", 0, "foobar@pie.service");
96 check_p_g_u_u("/session-2.scope/foobar@pie.service/pa/po", 0, "foobar@pie.service");
97 check_p_g_u_u("/xyz.slice/xyz-waldo.slice/session-77.scope/foobar@pie.service/pa/po", 0, "foobar@pie.service");
cfeaa44a 98 check_p_g_u_u("/meh.service", -ENXIO, NULL);
d7bd3de0 99 check_p_g_u_u("/session-3.scope/_cpu.service", 0, "cpu.service");
d4fffc4b 100 check_p_g_u_u("/user.slice/user-1000.slice/user@1000.service/server.service", 0, "server.service");
32081481 101 check_p_g_u_u("/user.slice/user-1000.slice/user@1000.service/foobar.slice/foobar@pie.service", 0, "foobar@pie.service");
cfeaa44a 102 check_p_g_u_u("/user.slice/user-1000.slice/user@.service/server.service", -ENXIO, NULL);
7027ff61 103}
6c03089c 104
9444b1f2
LP
105static void check_p_g_s(const char *path, int code, const char *result) {
106 _cleanup_free_ char *s = NULL;
107
108 assert_se(cg_path_get_session(path, &s) == code);
109 assert_se(streq_ptr(s, result));
96cde13a
ZJS
110}
111
9444b1f2 112static void test_path_get_session(void) {
374ec6ab
LP
113 check_p_g_s("/user.slice/user-1000.slice/session-2.scope/foobar.service", 0, "2");
114 check_p_g_s("/session-3.scope", 0, "3");
cfeaa44a
LP
115 check_p_g_s("/session-.scope", -ENXIO, NULL);
116 check_p_g_s("", -ENXIO, NULL);
9444b1f2 117}
7027ff61 118
9444b1f2
LP
119static void check_p_g_o_u(const char *path, int code, uid_t result) {
120 uid_t uid = 0;
7027ff61 121
9444b1f2
LP
122 assert_se(cg_path_get_owner_uid(path, &uid) == code);
123 assert_se(uid == result);
124}
125
126static void test_path_get_owner_uid(void) {
374ec6ab
LP
127 check_p_g_o_u("/user.slice/user-1000.slice/session-2.scope/foobar.service", 0, 1000);
128 check_p_g_o_u("/user.slice/user-1006.slice", 0, 1006);
cfeaa44a 129 check_p_g_o_u("", -ENXIO, 0);
9444b1f2 130}
7027ff61 131
8b0849e9
LP
132static void check_p_g_slice(const char *path, int code, const char *result) {
133 _cleanup_free_ char *s = NULL;
134
135 assert_se(cg_path_get_slice(path, &s) == code);
136 assert_se(streq_ptr(s, result));
137}
138
139static void test_path_get_slice(void) {
140 check_p_g_slice("/user.slice", 0, "user.slice");
141 check_p_g_slice("/foobar", 0, "-.slice");
142 check_p_g_slice("/user.slice/user-waldo.slice", 0, "user-waldo.slice");
143 check_p_g_slice("", 0, "-.slice");
144 check_p_g_slice("foobar", 0, "-.slice");
145 check_p_g_slice("foobar.slice", 0, "foobar.slice");
146 check_p_g_slice("foo.slice/foo-bar.slice/waldo.service", 0, "foo-bar.slice");
147}
148
329ac4bc
LP
149static void check_p_g_u_slice(const char *path, int code, const char *result) {
150 _cleanup_free_ char *s = NULL;
151
152 assert_se(cg_path_get_user_slice(path, &s) == code);
153 assert_se(streq_ptr(s, result));
154}
155
156static void test_path_get_user_slice(void) {
157 check_p_g_u_slice("/user.slice", -ENXIO, NULL);
158 check_p_g_u_slice("/foobar", -ENXIO, NULL);
159 check_p_g_u_slice("/user.slice/user-waldo.slice", -ENXIO, NULL);
160 check_p_g_u_slice("", -ENXIO, NULL);
161 check_p_g_u_slice("foobar", -ENXIO, NULL);
162 check_p_g_u_slice("foobar.slice", -ENXIO, NULL);
163 check_p_g_u_slice("foo.slice/foo-bar.slice/waldo.service", -ENXIO, NULL);
164
165 check_p_g_u_slice("foo.slice/foo-bar.slice/user@1000.service", 0, "-.slice");
166 check_p_g_u_slice("foo.slice/foo-bar.slice/user@1000.service/", 0, "-.slice");
167 check_p_g_u_slice("foo.slice/foo-bar.slice/user@1000.service///", 0, "-.slice");
168 check_p_g_u_slice("foo.slice/foo-bar.slice/user@1000.service/waldo.service", 0, "-.slice");
169 check_p_g_u_slice("foo.slice/foo-bar.slice/user@1000.service/piep.slice/foo.service", 0, "piep.slice");
170 check_p_g_u_slice("/foo.slice//foo-bar.slice/user@1000.service/piep.slice//piep-pap.slice//foo.service", 0, "piep-pap.slice");
171}
172
9444b1f2
LP
173static void test_get_paths(void) {
174 _cleanup_free_ char *a = NULL;
175
176 assert_se(cg_get_root_path(&a) >= 0);
177 log_info("Root = %s", a);
7027ff61
LP
178}
179
aff38e74
LP
180static void test_proc(void) {
181 _cleanup_closedir_ DIR *d = NULL;
182 struct dirent *de;
183 int r;
184
185 d = opendir("/proc");
186 assert_se(d);
187
188 FOREACH_DIRENT(de, d, break) {
e9174f29 189 _cleanup_free_ char *path = NULL, *path_shifted = NULL, *session = NULL, *unit = NULL, *user_unit = NULL, *machine = NULL, *slice = NULL;
aff38e74 190 pid_t pid;
fed1e721 191 uid_t uid = UID_INVALID;
aff38e74
LP
192
193 if (de->d_type != DT_DIR &&
194 de->d_type != DT_UNKNOWN)
195 continue;
196
197 r = parse_pid(de->d_name, &pid);
198 if (r < 0)
199 continue;
200
ae018d9b
LP
201 if (is_kernel_thread(pid))
202 continue;
203
aff38e74 204 cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, pid, &path);
e9174f29 205 cg_pid_get_path_shifted(pid, NULL, &path_shifted);
ae018d9b 206 cg_pid_get_owner_uid(pid, &uid);
aff38e74
LP
207 cg_pid_get_session(pid, &session);
208 cg_pid_get_unit(pid, &unit);
209 cg_pid_get_user_unit(pid, &user_unit);
210 cg_pid_get_machine_name(pid, &machine);
1021b21b 211 cg_pid_get_slice(pid, &slice);
aff38e74 212
de0671ee
ZJS
213 printf(PID_FMT"\t%s\t%s\t"UID_FMT"\t%s\t%s\t%s\t%s\t%s\n",
214 pid,
aff38e74 215 path,
aff38e74 216 path_shifted,
de0671ee 217 uid,
aff38e74
LP
218 session,
219 unit,
220 user_unit,
1021b21b
LP
221 machine,
222 slice);
aff38e74
LP
223 }
224}
225
ae018d9b
LP
226static void test_escape_one(const char *s, const char *r) {
227 _cleanup_free_ char *b;
228
229 b = cg_escape(s);
230 assert_se(b);
231 assert_se(streq(b, r));
232
233 assert_se(streq(cg_unescape(b), s));
234}
235
236static void test_escape(void) {
237 test_escape_one("foobar", "foobar");
a0ab5665 238 test_escape_one(".foobar", "_.foobar");
ae018d9b
LP
239 test_escape_one("foobar.service", "foobar.service");
240 test_escape_one("cgroup.service", "_cgroup.service");
ae018d9b 241 test_escape_one("tasks", "_tasks");
e13bb5d2
KS
242 if (access("/sys/fs/cgroup/cpu", F_OK) == 0)
243 test_escape_one("cpu.service", "_cpu.service");
ae018d9b 244 test_escape_one("_foobar", "__foobar");
a0ab5665
LP
245 test_escape_one("", "_");
246 test_escape_one("_", "__");
247 test_escape_one(".", "_.");
ae018d9b
LP
248}
249
78edb35a 250static void test_controller_is_valid(void) {
185a0874
DJL
251 assert_se(cg_controller_is_valid("foobar"));
252 assert_se(cg_controller_is_valid("foo_bar"));
253 assert_se(cg_controller_is_valid("name=foo"));
254 assert_se(!cg_controller_is_valid(""));
255 assert_se(!cg_controller_is_valid("name="));
256 assert_se(!cg_controller_is_valid("="));
257 assert_se(!cg_controller_is_valid("cpu,cpuacct"));
258 assert_se(!cg_controller_is_valid("_"));
259 assert_se(!cg_controller_is_valid("_foobar"));
260 assert_se(!cg_controller_is_valid("tatü"));
78edb35a
LP
261}
262
a016b922
LP
263static void test_slice_to_path_one(const char *unit, const char *path, int error) {
264 _cleanup_free_ char *ret = NULL;
265
266 assert_se(cg_slice_to_path(unit, &ret) == error);
267 assert_se(streq_ptr(ret, path));
268}
269
270static void test_slice_to_path(void) {
271
272 test_slice_to_path_one("foobar.slice", "foobar.slice", 0);
273 test_slice_to_path_one("foobar-waldo.slice", "foobar.slice/foobar-waldo.slice", 0);
274 test_slice_to_path_one("foobar-waldo.service", NULL, -EINVAL);
c96cc582
LP
275 test_slice_to_path_one("-.slice", "", 0);
276 test_slice_to_path_one("--.slice", NULL, -EINVAL);
277 test_slice_to_path_one("-", NULL, -EINVAL);
a016b922
LP
278 test_slice_to_path_one("-foo-.slice", NULL, -EINVAL);
279 test_slice_to_path_one("-foo.slice", NULL, -EINVAL);
c96cc582 280 test_slice_to_path_one("foo-.slice", NULL, -EINVAL);
e66e5b61 281 test_slice_to_path_one("foo--bar.slice", NULL, -EINVAL);
c96cc582 282 test_slice_to_path_one("foo.slice/foo--bar.slice", NULL, -EINVAL);
a016b922
LP
283 test_slice_to_path_one("a-b.slice", "a.slice/a-b.slice", 0);
284 test_slice_to_path_one("a-b-c-d-e.slice", "a.slice/a-b.slice/a-b-c.slice/a-b-c-d.slice/a-b-c-d-e.slice", 0);
285}
286
751bc6ac
LP
287static void test_shift_path_one(const char *raw, const char *root, const char *shifted) {
288 const char *s = NULL;
289
290 assert_se(cg_shift_path(raw, root, &s) >= 0);
291 assert_se(streq(s, shifted));
292}
293
294static void test_shift_path(void) {
295
296 test_shift_path_one("/foobar/waldo", "/", "/foobar/waldo");
297 test_shift_path_one("/foobar/waldo", "", "/foobar/waldo");
298 test_shift_path_one("/foobar/waldo", "/foobar", "/waldo");
299 test_shift_path_one("/foobar/waldo", "/fuckfuck", "/foobar/waldo");
300}
301
5f4c5fef
LP
302static void test_mask_supported(void) {
303
304 CGroupMask m;
305 CGroupController c;
306
307 assert_se(cg_mask_supported(&m) >= 0);
308
309 for (c = 0; c < _CGROUP_CONTROLLER_MAX; c++)
310 printf("'%s' is supported: %s\n", cgroup_controller_to_string(c), yes_no(m & CGROUP_CONTROLLER_TO_MASK(c)));
311}
312
f0bef277
EV
313static void test_is_cgroup_fs(void) {
314 struct statfs sfs;
315 assert_se(statfs("/sys/fs/cgroup", &sfs) == 0);
316 if (is_temporary_fs(&sfs))
317 assert_se(statfs("/sys/fs/cgroup/systemd", &sfs) == 0);
318 assert_se(is_cgroup_fs(&sfs));
319}
320
321static void test_fd_is_cgroup_fs(void) {
322 int fd;
323
324 fd = open("/sys/fs/cgroup", O_RDONLY|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
325 assert_se(fd >= 0);
326 if (fd_is_temporary_fs(fd)) {
327 fd = safe_close(fd);
328 fd = open("/sys/fs/cgroup/systemd", O_RDONLY|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
329 assert_se(fd >= 0);
330 }
331 assert_se(fd_is_cgroup_fs(fd));
332 fd = safe_close(fd);
333}
334
96cde13a 335int main(void) {
7027ff61 336 test_path_decode_unit();
6c03089c 337 test_path_get_unit();
7027ff61 338 test_path_get_user_unit();
9444b1f2
LP
339 test_path_get_session();
340 test_path_get_owner_uid();
8b0849e9 341 test_path_get_slice();
329ac4bc 342 test_path_get_user_slice();
143bfdaf 343 TEST_REQ_RUNNING_SYSTEMD(test_get_paths());
aff38e74 344 test_proc();
143bfdaf 345 TEST_REQ_RUNNING_SYSTEMD(test_escape());
78edb35a 346 test_controller_is_valid();
a016b922 347 test_slice_to_path();
751bc6ac 348 test_shift_path();
b3a7ba89 349 TEST_REQ_RUNNING_SYSTEMD(test_mask_supported());
f0bef277
EV
350 TEST_REQ_RUNNING_SYSTEMD(test_is_cgroup_fs());
351 TEST_REQ_RUNNING_SYSTEMD(test_fd_is_cgroup_fs());
96cde13a
ZJS
352
353 return 0;
354}