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