]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/test/test-cgroup-util.c
sd-bus,sd-login: add api for querying the slice within the the user systemd instance...
[thirdparty/systemd.git] / src / test / test-cgroup-util.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2013 Zbigniew Jędrzejewski-Szmek
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22
23 #include "util.h"
24 #include "cgroup-util.h"
25 #include "test-helper.h"
26 #include "formats-util.h"
27 #include "process-util.h"
28
29 static void check_p_d_u(const char *path, int code, const char *result) {
30 _cleanup_free_ char *unit = NULL;
31 int r;
32
33 r = cg_path_decode_unit(path, &unit);
34 printf("%s: %s → %s %d expected %s %d\n", __func__, path, unit, r, result, code);
35 assert_se(r == code);
36 assert_se(streq_ptr(unit, result));
37 }
38
39 static void test_path_decode_unit(void) {
40 check_p_d_u("getty@tty2.service", 0, "getty@tty2.service");
41 check_p_d_u("getty@tty2.service/", 0, "getty@tty2.service");
42 check_p_d_u("getty@tty2.service/xxx", 0, "getty@tty2.service");
43 check_p_d_u("getty@.service/", -ENXIO, NULL);
44 check_p_d_u("getty@.service", -ENXIO, NULL);
45 check_p_d_u("getty.service", 0, "getty.service");
46 check_p_d_u("getty", -ENXIO, NULL);
47 check_p_d_u("getty/waldo", -ENXIO, NULL);
48 check_p_d_u("_cpu.service", 0, "cpu.service");
49 }
50
51 static void check_p_g_u(const char *path, int code, const char *result) {
52 _cleanup_free_ char *unit = NULL;
53 int r;
54
55 r = cg_path_get_unit(path, &unit);
56 printf("%s: %s → %s %d expected %s %d\n", __func__, path, unit, r, result, code);
57 assert_se(r == code);
58 assert_se(streq_ptr(unit, result));
59 }
60
61 static void test_path_get_unit(void) {
62 check_p_g_u("/system.slice/foobar.service/sdfdsaf", 0, "foobar.service");
63 check_p_g_u("/system.slice/getty@tty5.service", 0, "getty@tty5.service");
64 check_p_g_u("/system.slice/getty@tty5.service/aaa/bbb", 0, "getty@tty5.service");
65 check_p_g_u("/system.slice/getty@tty5.service/", 0, "getty@tty5.service");
66 check_p_g_u("/system.slice/getty@tty6.service/tty5", 0, "getty@tty6.service");
67 check_p_g_u("sadfdsafsda", -ENXIO, NULL);
68 check_p_g_u("/system.slice/getty####@tty6.service/xxx", -ENXIO, NULL);
69 check_p_g_u("/system.slice/system-waldo.slice/foobar.service/sdfdsaf", 0, "foobar.service");
70 check_p_g_u("/system.slice/system-waldo.slice/_cpu.service/sdfdsaf", 0, "cpu.service");
71 check_p_g_u("/user.slice/user-1000.slice/user@1000.service/server.service", 0, "user@1000.service");
72 check_p_g_u("/user.slice/user-1000.slice/user@.service/server.service", -ENXIO, NULL);
73 }
74
75 static void check_p_g_u_u(const char *path, int code, const char *result) {
76 _cleanup_free_ char *unit = NULL;
77 int r;
78
79 r = cg_path_get_user_unit(path, &unit);
80 printf("%s: %s → %s %d expected %s %d\n", __func__, path, unit, r, result, code);
81 assert_se(r == code);
82 assert_se(streq_ptr(unit, result));
83 }
84
85 static void test_path_get_user_unit(void) {
86 check_p_g_u_u("/user.slice/user-1000.slice/session-2.scope/foobar.service", 0, "foobar.service");
87 check_p_g_u_u("/user.slice/user-1000.slice/session-2.scope/waldo.slice/foobar.service", 0, "foobar.service");
88 check_p_g_u_u("/user.slice/user-1002.slice/session-2.scope/foobar.service/waldo", 0, "foobar.service");
89 check_p_g_u_u("/user.slice/user-1000.slice/session-2.scope/foobar.service/waldo/uuuux", 0, "foobar.service");
90 check_p_g_u_u("/user.slice/user-1000.slice/session-2.scope/waldo/waldo/uuuux", -ENXIO, NULL);
91 check_p_g_u_u("/user.slice/user-1000.slice/session-2.scope/foobar@pie.service/pa/po", 0, "foobar@pie.service");
92 check_p_g_u_u("/session-2.scope/foobar@pie.service/pa/po", 0, "foobar@pie.service");
93 check_p_g_u_u("/xyz.slice/xyz-waldo.slice/session-77.scope/foobar@pie.service/pa/po", 0, "foobar@pie.service");
94 check_p_g_u_u("/meh.service", -ENXIO, NULL);
95 check_p_g_u_u("/session-3.scope/_cpu.service", 0, "cpu.service");
96 check_p_g_u_u("/user.slice/user-1000.slice/user@1000.service/server.service", 0, "server.service");
97 check_p_g_u_u("/user.slice/user-1000.slice/user@1000.service/foobar.slice/foobar@pie.service", 0, "foobar@pie.service");
98 check_p_g_u_u("/user.slice/user-1000.slice/user@.service/server.service", -ENXIO, NULL);
99 }
100
101 static void check_p_g_s(const char *path, int code, const char *result) {
102 _cleanup_free_ char *s = NULL;
103
104 assert_se(cg_path_get_session(path, &s) == code);
105 assert_se(streq_ptr(s, result));
106 }
107
108 static void test_path_get_session(void) {
109 check_p_g_s("/user.slice/user-1000.slice/session-2.scope/foobar.service", 0, "2");
110 check_p_g_s("/session-3.scope", 0, "3");
111 check_p_g_s("/session-.scope", -ENXIO, NULL);
112 check_p_g_s("", -ENXIO, NULL);
113 }
114
115 static void check_p_g_o_u(const char *path, int code, uid_t result) {
116 uid_t uid = 0;
117
118 assert_se(cg_path_get_owner_uid(path, &uid) == code);
119 assert_se(uid == result);
120 }
121
122 static void test_path_get_owner_uid(void) {
123 check_p_g_o_u("/user.slice/user-1000.slice/session-2.scope/foobar.service", 0, 1000);
124 check_p_g_o_u("/user.slice/user-1006.slice", 0, 1006);
125 check_p_g_o_u("", -ENXIO, 0);
126 }
127
128 static void check_p_g_slice(const char *path, int code, const char *result) {
129 _cleanup_free_ char *s = NULL;
130
131 assert_se(cg_path_get_slice(path, &s) == code);
132 assert_se(streq_ptr(s, result));
133 }
134
135 static void test_path_get_slice(void) {
136 check_p_g_slice("/user.slice", 0, "user.slice");
137 check_p_g_slice("/foobar", 0, "-.slice");
138 check_p_g_slice("/user.slice/user-waldo.slice", 0, "user-waldo.slice");
139 check_p_g_slice("", 0, "-.slice");
140 check_p_g_slice("foobar", 0, "-.slice");
141 check_p_g_slice("foobar.slice", 0, "foobar.slice");
142 check_p_g_slice("foo.slice/foo-bar.slice/waldo.service", 0, "foo-bar.slice");
143 }
144
145 static void check_p_g_u_slice(const char *path, int code, const char *result) {
146 _cleanup_free_ char *s = NULL;
147
148 assert_se(cg_path_get_user_slice(path, &s) == code);
149 assert_se(streq_ptr(s, result));
150 }
151
152 static void test_path_get_user_slice(void) {
153 check_p_g_u_slice("/user.slice", -ENXIO, NULL);
154 check_p_g_u_slice("/foobar", -ENXIO, NULL);
155 check_p_g_u_slice("/user.slice/user-waldo.slice", -ENXIO, NULL);
156 check_p_g_u_slice("", -ENXIO, NULL);
157 check_p_g_u_slice("foobar", -ENXIO, NULL);
158 check_p_g_u_slice("foobar.slice", -ENXIO, NULL);
159 check_p_g_u_slice("foo.slice/foo-bar.slice/waldo.service", -ENXIO, NULL);
160
161 check_p_g_u_slice("foo.slice/foo-bar.slice/user@1000.service", 0, "-.slice");
162 check_p_g_u_slice("foo.slice/foo-bar.slice/user@1000.service/", 0, "-.slice");
163 check_p_g_u_slice("foo.slice/foo-bar.slice/user@1000.service///", 0, "-.slice");
164 check_p_g_u_slice("foo.slice/foo-bar.slice/user@1000.service/waldo.service", 0, "-.slice");
165 check_p_g_u_slice("foo.slice/foo-bar.slice/user@1000.service/piep.slice/foo.service", 0, "piep.slice");
166 check_p_g_u_slice("/foo.slice//foo-bar.slice/user@1000.service/piep.slice//piep-pap.slice//foo.service", 0, "piep-pap.slice");
167 }
168
169 static void test_get_paths(void) {
170 _cleanup_free_ char *a = NULL;
171
172 assert_se(cg_get_root_path(&a) >= 0);
173 log_info("Root = %s", a);
174 }
175
176 static void test_proc(void) {
177 _cleanup_closedir_ DIR *d = NULL;
178 struct dirent *de;
179 int r;
180
181 d = opendir("/proc");
182 assert_se(d);
183
184 FOREACH_DIRENT(de, d, break) {
185 _cleanup_free_ char *path = NULL, *path_shifted = NULL, *session = NULL, *unit = NULL, *user_unit = NULL, *machine = NULL, *slice = NULL;
186 pid_t pid;
187 uid_t uid = UID_INVALID;
188
189 if (de->d_type != DT_DIR &&
190 de->d_type != DT_UNKNOWN)
191 continue;
192
193 r = parse_pid(de->d_name, &pid);
194 if (r < 0)
195 continue;
196
197 if (is_kernel_thread(pid))
198 continue;
199
200 cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, pid, &path);
201 cg_pid_get_path_shifted(pid, NULL, &path_shifted);
202 cg_pid_get_owner_uid(pid, &uid);
203 cg_pid_get_session(pid, &session);
204 cg_pid_get_unit(pid, &unit);
205 cg_pid_get_user_unit(pid, &user_unit);
206 cg_pid_get_machine_name(pid, &machine);
207 cg_pid_get_slice(pid, &slice);
208
209 printf(PID_FMT"\t%s\t%s\t"UID_FMT"\t%s\t%s\t%s\t%s\t%s\n",
210 pid,
211 path,
212 path_shifted,
213 uid,
214 session,
215 unit,
216 user_unit,
217 machine,
218 slice);
219 }
220 }
221
222 static void test_escape_one(const char *s, const char *r) {
223 _cleanup_free_ char *b;
224
225 b = cg_escape(s);
226 assert_se(b);
227 assert_se(streq(b, r));
228
229 assert_se(streq(cg_unescape(b), s));
230 }
231
232 static void test_escape(void) {
233 test_escape_one("foobar", "foobar");
234 test_escape_one(".foobar", "_.foobar");
235 test_escape_one("foobar.service", "foobar.service");
236 test_escape_one("cgroup.service", "_cgroup.service");
237 test_escape_one("tasks", "_tasks");
238 if (access("/sys/fs/cgroup/cpu", F_OK) == 0)
239 test_escape_one("cpu.service", "_cpu.service");
240 test_escape_one("_foobar", "__foobar");
241 test_escape_one("", "_");
242 test_escape_one("_", "__");
243 test_escape_one(".", "_.");
244 }
245
246 static void test_controller_is_valid(void) {
247 assert_se(cg_controller_is_valid("foobar", false));
248 assert_se(cg_controller_is_valid("foo_bar", false));
249 assert_se(cg_controller_is_valid("name=foo", true));
250 assert_se(!cg_controller_is_valid("", false));
251 assert_se(!cg_controller_is_valid("name=", true));
252 assert_se(!cg_controller_is_valid("=", false));
253 assert_se(!cg_controller_is_valid("cpu,cpuacct", false));
254 assert_se(!cg_controller_is_valid("_", false));
255 assert_se(!cg_controller_is_valid("_foobar", false));
256 assert_se(!cg_controller_is_valid("tatü", false));
257 }
258
259 static void test_slice_to_path_one(const char *unit, const char *path, int error) {
260 _cleanup_free_ char *ret = NULL;
261
262 assert_se(cg_slice_to_path(unit, &ret) == error);
263 assert_se(streq_ptr(ret, path));
264 }
265
266 static void test_slice_to_path(void) {
267
268 test_slice_to_path_one("foobar.slice", "foobar.slice", 0);
269 test_slice_to_path_one("foobar-waldo.slice", "foobar.slice/foobar-waldo.slice", 0);
270 test_slice_to_path_one("foobar-waldo.service", NULL, -EINVAL);
271 test_slice_to_path_one("-.slice", NULL, -EINVAL);
272 test_slice_to_path_one("-foo-.slice", NULL, -EINVAL);
273 test_slice_to_path_one("-foo.slice", NULL, -EINVAL);
274 test_slice_to_path_one("a-b.slice", "a.slice/a-b.slice", 0);
275 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);
276 }
277
278 static void test_shift_path_one(const char *raw, const char *root, const char *shifted) {
279 const char *s = NULL;
280
281 assert_se(cg_shift_path(raw, root, &s) >= 0);
282 assert_se(streq(s, shifted));
283 }
284
285 static void test_shift_path(void) {
286
287 test_shift_path_one("/foobar/waldo", "/", "/foobar/waldo");
288 test_shift_path_one("/foobar/waldo", "", "/foobar/waldo");
289 test_shift_path_one("/foobar/waldo", "/foobar", "/waldo");
290 test_shift_path_one("/foobar/waldo", "/fuckfuck", "/foobar/waldo");
291 }
292
293 int main(void) {
294 test_path_decode_unit();
295 test_path_get_unit();
296 test_path_get_user_unit();
297 test_path_get_session();
298 test_path_get_owner_uid();
299 test_path_get_slice();
300 test_path_get_user_slice();
301 TEST_REQ_RUNNING_SYSTEMD(test_get_paths());
302 test_proc();
303 TEST_REQ_RUNNING_SYSTEMD(test_escape());
304 test_controller_is_valid();
305 test_slice_to_path();
306 test_shift_path();
307
308 return 0;
309 }