]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/test/test-cgroup-util.c
resolved: add code to join/leave mDNS multicast groups
[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 #include "alloc-util.h"
23 #include "cgroup-util.h"
24 #include "dirent-util.h"
25 #include "fd-util.h"
26 #include "formats-util.h"
27 #include "parse-util.h"
28 #include "process-util.h"
29 #include "string-util.h"
30 #include "test-helper.h"
31 #include "user-util.h"
32 #include "util.h"
33
34 static void check_p_d_u(const char *path, int code, const char *result) {
35 _cleanup_free_ char *unit = NULL;
36 int r;
37
38 r = cg_path_decode_unit(path, &unit);
39 printf("%s: %s → %s %d expected %s %d\n", __func__, path, unit, r, result, code);
40 assert_se(r == code);
41 assert_se(streq_ptr(unit, result));
42 }
43
44 static void test_path_decode_unit(void) {
45 check_p_d_u("getty@tty2.service", 0, "getty@tty2.service");
46 check_p_d_u("getty@tty2.service/", 0, "getty@tty2.service");
47 check_p_d_u("getty@tty2.service/xxx", 0, "getty@tty2.service");
48 check_p_d_u("getty@.service/", -ENXIO, NULL);
49 check_p_d_u("getty@.service", -ENXIO, NULL);
50 check_p_d_u("getty.service", 0, "getty.service");
51 check_p_d_u("getty", -ENXIO, NULL);
52 check_p_d_u("getty/waldo", -ENXIO, NULL);
53 check_p_d_u("_cpu.service", 0, "cpu.service");
54 }
55
56 static void check_p_g_u(const char *path, int code, const char *result) {
57 _cleanup_free_ char *unit = NULL;
58 int r;
59
60 r = cg_path_get_unit(path, &unit);
61 printf("%s: %s → %s %d expected %s %d\n", __func__, path, unit, r, result, code);
62 assert_se(r == code);
63 assert_se(streq_ptr(unit, result));
64 }
65
66 static void test_path_get_unit(void) {
67 check_p_g_u("/system.slice/foobar.service/sdfdsaf", 0, "foobar.service");
68 check_p_g_u("/system.slice/getty@tty5.service", 0, "getty@tty5.service");
69 check_p_g_u("/system.slice/getty@tty5.service/aaa/bbb", 0, "getty@tty5.service");
70 check_p_g_u("/system.slice/getty@tty5.service/", 0, "getty@tty5.service");
71 check_p_g_u("/system.slice/getty@tty6.service/tty5", 0, "getty@tty6.service");
72 check_p_g_u("sadfdsafsda", -ENXIO, NULL);
73 check_p_g_u("/system.slice/getty####@tty6.service/xxx", -ENXIO, NULL);
74 check_p_g_u("/system.slice/system-waldo.slice/foobar.service/sdfdsaf", 0, "foobar.service");
75 check_p_g_u("/system.slice/system-waldo.slice/_cpu.service/sdfdsaf", 0, "cpu.service");
76 check_p_g_u("/user.slice/user-1000.slice/user@1000.service/server.service", 0, "user@1000.service");
77 check_p_g_u("/user.slice/user-1000.slice/user@.service/server.service", -ENXIO, NULL);
78 }
79
80 static void check_p_g_u_u(const char *path, int code, const char *result) {
81 _cleanup_free_ char *unit = NULL;
82 int r;
83
84 r = cg_path_get_user_unit(path, &unit);
85 printf("%s: %s → %s %d expected %s %d\n", __func__, path, unit, r, result, code);
86 assert_se(r == code);
87 assert_se(streq_ptr(unit, result));
88 }
89
90 static void test_path_get_user_unit(void) {
91 check_p_g_u_u("/user.slice/user-1000.slice/session-2.scope/foobar.service", 0, "foobar.service");
92 check_p_g_u_u("/user.slice/user-1000.slice/session-2.scope/waldo.slice/foobar.service", 0, "foobar.service");
93 check_p_g_u_u("/user.slice/user-1002.slice/session-2.scope/foobar.service/waldo", 0, "foobar.service");
94 check_p_g_u_u("/user.slice/user-1000.slice/session-2.scope/foobar.service/waldo/uuuux", 0, "foobar.service");
95 check_p_g_u_u("/user.slice/user-1000.slice/session-2.scope/waldo/waldo/uuuux", -ENXIO, NULL);
96 check_p_g_u_u("/user.slice/user-1000.slice/session-2.scope/foobar@pie.service/pa/po", 0, "foobar@pie.service");
97 check_p_g_u_u("/session-2.scope/foobar@pie.service/pa/po", 0, "foobar@pie.service");
98 check_p_g_u_u("/xyz.slice/xyz-waldo.slice/session-77.scope/foobar@pie.service/pa/po", 0, "foobar@pie.service");
99 check_p_g_u_u("/meh.service", -ENXIO, NULL);
100 check_p_g_u_u("/session-3.scope/_cpu.service", 0, "cpu.service");
101 check_p_g_u_u("/user.slice/user-1000.slice/user@1000.service/server.service", 0, "server.service");
102 check_p_g_u_u("/user.slice/user-1000.slice/user@1000.service/foobar.slice/foobar@pie.service", 0, "foobar@pie.service");
103 check_p_g_u_u("/user.slice/user-1000.slice/user@.service/server.service", -ENXIO, NULL);
104 }
105
106 static void check_p_g_s(const char *path, int code, const char *result) {
107 _cleanup_free_ char *s = NULL;
108
109 assert_se(cg_path_get_session(path, &s) == code);
110 assert_se(streq_ptr(s, result));
111 }
112
113 static void test_path_get_session(void) {
114 check_p_g_s("/user.slice/user-1000.slice/session-2.scope/foobar.service", 0, "2");
115 check_p_g_s("/session-3.scope", 0, "3");
116 check_p_g_s("/session-.scope", -ENXIO, NULL);
117 check_p_g_s("", -ENXIO, NULL);
118 }
119
120 static void check_p_g_o_u(const char *path, int code, uid_t result) {
121 uid_t uid = 0;
122
123 assert_se(cg_path_get_owner_uid(path, &uid) == code);
124 assert_se(uid == result);
125 }
126
127 static void test_path_get_owner_uid(void) {
128 check_p_g_o_u("/user.slice/user-1000.slice/session-2.scope/foobar.service", 0, 1000);
129 check_p_g_o_u("/user.slice/user-1006.slice", 0, 1006);
130 check_p_g_o_u("", -ENXIO, 0);
131 }
132
133 static void check_p_g_slice(const char *path, int code, const char *result) {
134 _cleanup_free_ char *s = NULL;
135
136 assert_se(cg_path_get_slice(path, &s) == code);
137 assert_se(streq_ptr(s, result));
138 }
139
140 static void test_path_get_slice(void) {
141 check_p_g_slice("/user.slice", 0, "user.slice");
142 check_p_g_slice("/foobar", 0, "-.slice");
143 check_p_g_slice("/user.slice/user-waldo.slice", 0, "user-waldo.slice");
144 check_p_g_slice("", 0, "-.slice");
145 check_p_g_slice("foobar", 0, "-.slice");
146 check_p_g_slice("foobar.slice", 0, "foobar.slice");
147 check_p_g_slice("foo.slice/foo-bar.slice/waldo.service", 0, "foo-bar.slice");
148 }
149
150 static void check_p_g_u_slice(const char *path, int code, const char *result) {
151 _cleanup_free_ char *s = NULL;
152
153 assert_se(cg_path_get_user_slice(path, &s) == code);
154 assert_se(streq_ptr(s, result));
155 }
156
157 static void test_path_get_user_slice(void) {
158 check_p_g_u_slice("/user.slice", -ENXIO, NULL);
159 check_p_g_u_slice("/foobar", -ENXIO, NULL);
160 check_p_g_u_slice("/user.slice/user-waldo.slice", -ENXIO, NULL);
161 check_p_g_u_slice("", -ENXIO, NULL);
162 check_p_g_u_slice("foobar", -ENXIO, NULL);
163 check_p_g_u_slice("foobar.slice", -ENXIO, NULL);
164 check_p_g_u_slice("foo.slice/foo-bar.slice/waldo.service", -ENXIO, NULL);
165
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///", 0, "-.slice");
169 check_p_g_u_slice("foo.slice/foo-bar.slice/user@1000.service/waldo.service", 0, "-.slice");
170 check_p_g_u_slice("foo.slice/foo-bar.slice/user@1000.service/piep.slice/foo.service", 0, "piep.slice");
171 check_p_g_u_slice("/foo.slice//foo-bar.slice/user@1000.service/piep.slice//piep-pap.slice//foo.service", 0, "piep-pap.slice");
172 }
173
174 static void test_get_paths(void) {
175 _cleanup_free_ char *a = NULL;
176
177 assert_se(cg_get_root_path(&a) >= 0);
178 log_info("Root = %s", a);
179 }
180
181 static void test_proc(void) {
182 _cleanup_closedir_ DIR *d = NULL;
183 struct dirent *de;
184 int r;
185
186 d = opendir("/proc");
187 assert_se(d);
188
189 FOREACH_DIRENT(de, d, break) {
190 _cleanup_free_ char *path = NULL, *path_shifted = NULL, *session = NULL, *unit = NULL, *user_unit = NULL, *machine = NULL, *slice = NULL;
191 pid_t pid;
192 uid_t uid = UID_INVALID;
193
194 if (de->d_type != DT_DIR &&
195 de->d_type != DT_UNKNOWN)
196 continue;
197
198 r = parse_pid(de->d_name, &pid);
199 if (r < 0)
200 continue;
201
202 if (is_kernel_thread(pid))
203 continue;
204
205 cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, pid, &path);
206 cg_pid_get_path_shifted(pid, NULL, &path_shifted);
207 cg_pid_get_owner_uid(pid, &uid);
208 cg_pid_get_session(pid, &session);
209 cg_pid_get_unit(pid, &unit);
210 cg_pid_get_user_unit(pid, &user_unit);
211 cg_pid_get_machine_name(pid, &machine);
212 cg_pid_get_slice(pid, &slice);
213
214 printf(PID_FMT"\t%s\t%s\t"UID_FMT"\t%s\t%s\t%s\t%s\t%s\n",
215 pid,
216 path,
217 path_shifted,
218 uid,
219 session,
220 unit,
221 user_unit,
222 machine,
223 slice);
224 }
225 }
226
227 static void test_escape_one(const char *s, const char *r) {
228 _cleanup_free_ char *b;
229
230 b = cg_escape(s);
231 assert_se(b);
232 assert_se(streq(b, r));
233
234 assert_se(streq(cg_unescape(b), s));
235 }
236
237 static void test_escape(void) {
238 test_escape_one("foobar", "foobar");
239 test_escape_one(".foobar", "_.foobar");
240 test_escape_one("foobar.service", "foobar.service");
241 test_escape_one("cgroup.service", "_cgroup.service");
242 test_escape_one("tasks", "_tasks");
243 if (access("/sys/fs/cgroup/cpu", F_OK) == 0)
244 test_escape_one("cpu.service", "_cpu.service");
245 test_escape_one("_foobar", "__foobar");
246 test_escape_one("", "_");
247 test_escape_one("_", "__");
248 test_escape_one(".", "_.");
249 }
250
251 static void test_controller_is_valid(void) {
252 assert_se(cg_controller_is_valid("foobar"));
253 assert_se(cg_controller_is_valid("foo_bar"));
254 assert_se(cg_controller_is_valid("name=foo"));
255 assert_se(!cg_controller_is_valid(""));
256 assert_se(!cg_controller_is_valid("name="));
257 assert_se(!cg_controller_is_valid("="));
258 assert_se(!cg_controller_is_valid("cpu,cpuacct"));
259 assert_se(!cg_controller_is_valid("_"));
260 assert_se(!cg_controller_is_valid("_foobar"));
261 assert_se(!cg_controller_is_valid("tatü"));
262 }
263
264 static void test_slice_to_path_one(const char *unit, const char *path, int error) {
265 _cleanup_free_ char *ret = NULL;
266
267 assert_se(cg_slice_to_path(unit, &ret) == error);
268 assert_se(streq_ptr(ret, path));
269 }
270
271 static void test_slice_to_path(void) {
272
273 test_slice_to_path_one("foobar.slice", "foobar.slice", 0);
274 test_slice_to_path_one("foobar-waldo.slice", "foobar.slice/foobar-waldo.slice", 0);
275 test_slice_to_path_one("foobar-waldo.service", NULL, -EINVAL);
276 test_slice_to_path_one("-.slice", "", 0);
277 test_slice_to_path_one("--.slice", NULL, -EINVAL);
278 test_slice_to_path_one("-", NULL, -EINVAL);
279 test_slice_to_path_one("-foo-.slice", NULL, -EINVAL);
280 test_slice_to_path_one("-foo.slice", NULL, -EINVAL);
281 test_slice_to_path_one("foo-.slice", NULL, -EINVAL);
282 test_slice_to_path_one("foo--bar.slice", NULL, -EINVAL);
283 test_slice_to_path_one("foo.slice/foo--bar.slice", NULL, -EINVAL);
284 test_slice_to_path_one("a-b.slice", "a.slice/a-b.slice", 0);
285 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);
286 }
287
288 static void test_shift_path_one(const char *raw, const char *root, const char *shifted) {
289 const char *s = NULL;
290
291 assert_se(cg_shift_path(raw, root, &s) >= 0);
292 assert_se(streq(s, shifted));
293 }
294
295 static void test_shift_path(void) {
296
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", "/foobar", "/waldo");
300 test_shift_path_one("/foobar/waldo", "/fuckfuck", "/foobar/waldo");
301 }
302
303 static void test_mask_supported(void) {
304
305 CGroupMask m;
306 CGroupController c;
307
308 assert_se(cg_mask_supported(&m) >= 0);
309
310 for (c = 0; c < _CGROUP_CONTROLLER_MAX; c++)
311 printf("'%s' is supported: %s\n", cgroup_controller_to_string(c), yes_no(m & CGROUP_CONTROLLER_TO_MASK(c)));
312 }
313
314 int main(void) {
315 test_path_decode_unit();
316 test_path_get_unit();
317 test_path_get_user_unit();
318 test_path_get_session();
319 test_path_get_owner_uid();
320 test_path_get_slice();
321 test_path_get_user_slice();
322 TEST_REQ_RUNNING_SYSTEMD(test_get_paths());
323 test_proc();
324 TEST_REQ_RUNNING_SYSTEMD(test_escape());
325 test_controller_is_valid();
326 test_slice_to_path();
327 test_shift_path();
328 TEST_REQ_RUNNING_SYSTEMD(test_mask_supported());
329
330 return 0;
331 }