1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2013 Zbigniew Jędrzejewski-Szmek
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.
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.
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/>.
22 #include "cgroup-util.h"
23 #include "dirent-util.h"
25 #include "formats-util.h"
26 #include "parse-util.h"
27 #include "process-util.h"
28 #include "string-util.h"
29 #include "test-helper.h"
32 static void check_p_d_u(const char *path
, int code
, const char *result
) {
33 _cleanup_free_
char *unit
= NULL
;
36 r
= cg_path_decode_unit(path
, &unit
);
37 printf("%s: %s → %s %d expected %s %d\n", __func__
, path
, unit
, r
, result
, code
);
39 assert_se(streq_ptr(unit
, result
));
42 static void test_path_decode_unit(void) {
43 check_p_d_u("getty@tty2.service", 0, "getty@tty2.service");
44 check_p_d_u("getty@tty2.service/", 0, "getty@tty2.service");
45 check_p_d_u("getty@tty2.service/xxx", 0, "getty@tty2.service");
46 check_p_d_u("getty@.service/", -ENXIO
, NULL
);
47 check_p_d_u("getty@.service", -ENXIO
, NULL
);
48 check_p_d_u("getty.service", 0, "getty.service");
49 check_p_d_u("getty", -ENXIO
, NULL
);
50 check_p_d_u("getty/waldo", -ENXIO
, NULL
);
51 check_p_d_u("_cpu.service", 0, "cpu.service");
54 static void check_p_g_u(const char *path
, int code
, const char *result
) {
55 _cleanup_free_
char *unit
= NULL
;
58 r
= cg_path_get_unit(path
, &unit
);
59 printf("%s: %s → %s %d expected %s %d\n", __func__
, path
, unit
, r
, result
, code
);
61 assert_se(streq_ptr(unit
, result
));
64 static void test_path_get_unit(void) {
65 check_p_g_u("/system.slice/foobar.service/sdfdsaf", 0, "foobar.service");
66 check_p_g_u("/system.slice/getty@tty5.service", 0, "getty@tty5.service");
67 check_p_g_u("/system.slice/getty@tty5.service/aaa/bbb", 0, "getty@tty5.service");
68 check_p_g_u("/system.slice/getty@tty5.service/", 0, "getty@tty5.service");
69 check_p_g_u("/system.slice/getty@tty6.service/tty5", 0, "getty@tty6.service");
70 check_p_g_u("sadfdsafsda", -ENXIO
, NULL
);
71 check_p_g_u("/system.slice/getty####@tty6.service/xxx", -ENXIO
, NULL
);
72 check_p_g_u("/system.slice/system-waldo.slice/foobar.service/sdfdsaf", 0, "foobar.service");
73 check_p_g_u("/system.slice/system-waldo.slice/_cpu.service/sdfdsaf", 0, "cpu.service");
74 check_p_g_u("/user.slice/user-1000.slice/user@1000.service/server.service", 0, "user@1000.service");
75 check_p_g_u("/user.slice/user-1000.slice/user@.service/server.service", -ENXIO
, NULL
);
78 static void check_p_g_u_u(const char *path
, int code
, const char *result
) {
79 _cleanup_free_
char *unit
= NULL
;
82 r
= cg_path_get_user_unit(path
, &unit
);
83 printf("%s: %s → %s %d expected %s %d\n", __func__
, path
, unit
, r
, result
, code
);
85 assert_se(streq_ptr(unit
, result
));
88 static void test_path_get_user_unit(void) {
89 check_p_g_u_u("/user.slice/user-1000.slice/session-2.scope/foobar.service", 0, "foobar.service");
90 check_p_g_u_u("/user.slice/user-1000.slice/session-2.scope/waldo.slice/foobar.service", 0, "foobar.service");
91 check_p_g_u_u("/user.slice/user-1002.slice/session-2.scope/foobar.service/waldo", 0, "foobar.service");
92 check_p_g_u_u("/user.slice/user-1000.slice/session-2.scope/foobar.service/waldo/uuuux", 0, "foobar.service");
93 check_p_g_u_u("/user.slice/user-1000.slice/session-2.scope/waldo/waldo/uuuux", -ENXIO
, NULL
);
94 check_p_g_u_u("/user.slice/user-1000.slice/session-2.scope/foobar@pie.service/pa/po", 0, "foobar@pie.service");
95 check_p_g_u_u("/session-2.scope/foobar@pie.service/pa/po", 0, "foobar@pie.service");
96 check_p_g_u_u("/xyz.slice/xyz-waldo.slice/session-77.scope/foobar@pie.service/pa/po", 0, "foobar@pie.service");
97 check_p_g_u_u("/meh.service", -ENXIO
, NULL
);
98 check_p_g_u_u("/session-3.scope/_cpu.service", 0, "cpu.service");
99 check_p_g_u_u("/user.slice/user-1000.slice/user@1000.service/server.service", 0, "server.service");
100 check_p_g_u_u("/user.slice/user-1000.slice/user@1000.service/foobar.slice/foobar@pie.service", 0, "foobar@pie.service");
101 check_p_g_u_u("/user.slice/user-1000.slice/user@.service/server.service", -ENXIO
, NULL
);
104 static void check_p_g_s(const char *path
, int code
, const char *result
) {
105 _cleanup_free_
char *s
= NULL
;
107 assert_se(cg_path_get_session(path
, &s
) == code
);
108 assert_se(streq_ptr(s
, result
));
111 static void test_path_get_session(void) {
112 check_p_g_s("/user.slice/user-1000.slice/session-2.scope/foobar.service", 0, "2");
113 check_p_g_s("/session-3.scope", 0, "3");
114 check_p_g_s("/session-.scope", -ENXIO
, NULL
);
115 check_p_g_s("", -ENXIO
, NULL
);
118 static void check_p_g_o_u(const char *path
, int code
, uid_t result
) {
121 assert_se(cg_path_get_owner_uid(path
, &uid
) == code
);
122 assert_se(uid
== result
);
125 static void test_path_get_owner_uid(void) {
126 check_p_g_o_u("/user.slice/user-1000.slice/session-2.scope/foobar.service", 0, 1000);
127 check_p_g_o_u("/user.slice/user-1006.slice", 0, 1006);
128 check_p_g_o_u("", -ENXIO
, 0);
131 static void check_p_g_slice(const char *path
, int code
, const char *result
) {
132 _cleanup_free_
char *s
= NULL
;
134 assert_se(cg_path_get_slice(path
, &s
) == code
);
135 assert_se(streq_ptr(s
, result
));
138 static void test_path_get_slice(void) {
139 check_p_g_slice("/user.slice", 0, "user.slice");
140 check_p_g_slice("/foobar", 0, "-.slice");
141 check_p_g_slice("/user.slice/user-waldo.slice", 0, "user-waldo.slice");
142 check_p_g_slice("", 0, "-.slice");
143 check_p_g_slice("foobar", 0, "-.slice");
144 check_p_g_slice("foobar.slice", 0, "foobar.slice");
145 check_p_g_slice("foo.slice/foo-bar.slice/waldo.service", 0, "foo-bar.slice");
148 static void check_p_g_u_slice(const char *path
, int code
, const char *result
) {
149 _cleanup_free_
char *s
= NULL
;
151 assert_se(cg_path_get_user_slice(path
, &s
) == code
);
152 assert_se(streq_ptr(s
, result
));
155 static void test_path_get_user_slice(void) {
156 check_p_g_u_slice("/user.slice", -ENXIO
, NULL
);
157 check_p_g_u_slice("/foobar", -ENXIO
, NULL
);
158 check_p_g_u_slice("/user.slice/user-waldo.slice", -ENXIO
, NULL
);
159 check_p_g_u_slice("", -ENXIO
, NULL
);
160 check_p_g_u_slice("foobar", -ENXIO
, NULL
);
161 check_p_g_u_slice("foobar.slice", -ENXIO
, NULL
);
162 check_p_g_u_slice("foo.slice/foo-bar.slice/waldo.service", -ENXIO
, NULL
);
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/", 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/waldo.service", 0, "-.slice");
168 check_p_g_u_slice("foo.slice/foo-bar.slice/user@1000.service/piep.slice/foo.service", 0, "piep.slice");
169 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 static void test_get_paths(void) {
173 _cleanup_free_
char *a
= NULL
;
175 assert_se(cg_get_root_path(&a
) >= 0);
176 log_info("Root = %s", a
);
179 static void test_proc(void) {
180 _cleanup_closedir_
DIR *d
= NULL
;
184 d
= opendir("/proc");
187 FOREACH_DIRENT(de
, d
, break) {
188 _cleanup_free_
char *path
= NULL
, *path_shifted
= NULL
, *session
= NULL
, *unit
= NULL
, *user_unit
= NULL
, *machine
= NULL
, *slice
= NULL
;
190 uid_t uid
= UID_INVALID
;
192 if (de
->d_type
!= DT_DIR
&&
193 de
->d_type
!= DT_UNKNOWN
)
196 r
= parse_pid(de
->d_name
, &pid
);
200 if (is_kernel_thread(pid
))
203 cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER
, pid
, &path
);
204 cg_pid_get_path_shifted(pid
, NULL
, &path_shifted
);
205 cg_pid_get_owner_uid(pid
, &uid
);
206 cg_pid_get_session(pid
, &session
);
207 cg_pid_get_unit(pid
, &unit
);
208 cg_pid_get_user_unit(pid
, &user_unit
);
209 cg_pid_get_machine_name(pid
, &machine
);
210 cg_pid_get_slice(pid
, &slice
);
212 printf(PID_FMT
"\t%s\t%s\t"UID_FMT
"\t%s\t%s\t%s\t%s\t%s\n",
225 static void test_escape_one(const char *s
, const char *r
) {
226 _cleanup_free_
char *b
;
230 assert_se(streq(b
, r
));
232 assert_se(streq(cg_unescape(b
), s
));
235 static void test_escape(void) {
236 test_escape_one("foobar", "foobar");
237 test_escape_one(".foobar", "_.foobar");
238 test_escape_one("foobar.service", "foobar.service");
239 test_escape_one("cgroup.service", "_cgroup.service");
240 test_escape_one("tasks", "_tasks");
241 if (access("/sys/fs/cgroup/cpu", F_OK
) == 0)
242 test_escape_one("cpu.service", "_cpu.service");
243 test_escape_one("_foobar", "__foobar");
244 test_escape_one("", "_");
245 test_escape_one("_", "__");
246 test_escape_one(".", "_.");
249 static void test_controller_is_valid(void) {
250 assert_se(cg_controller_is_valid("foobar"));
251 assert_se(cg_controller_is_valid("foo_bar"));
252 assert_se(cg_controller_is_valid("name=foo"));
253 assert_se(!cg_controller_is_valid(""));
254 assert_se(!cg_controller_is_valid("name="));
255 assert_se(!cg_controller_is_valid("="));
256 assert_se(!cg_controller_is_valid("cpu,cpuacct"));
257 assert_se(!cg_controller_is_valid("_"));
258 assert_se(!cg_controller_is_valid("_foobar"));
259 assert_se(!cg_controller_is_valid("tatü"));
262 static void test_slice_to_path_one(const char *unit
, const char *path
, int error
) {
263 _cleanup_free_
char *ret
= NULL
;
265 assert_se(cg_slice_to_path(unit
, &ret
) == error
);
266 assert_se(streq_ptr(ret
, path
));
269 static void test_slice_to_path(void) {
271 test_slice_to_path_one("foobar.slice", "foobar.slice", 0);
272 test_slice_to_path_one("foobar-waldo.slice", "foobar.slice/foobar-waldo.slice", 0);
273 test_slice_to_path_one("foobar-waldo.service", NULL
, -EINVAL
);
274 test_slice_to_path_one("-.slice", "", 0);
275 test_slice_to_path_one("--.slice", NULL
, -EINVAL
);
276 test_slice_to_path_one("-", NULL
, -EINVAL
);
277 test_slice_to_path_one("-foo-.slice", NULL
, -EINVAL
);
278 test_slice_to_path_one("-foo.slice", NULL
, -EINVAL
);
279 test_slice_to_path_one("foo-.slice", NULL
, -EINVAL
);
280 test_slice_to_path_one("foo--bar.slice", NULL
, -EINVAL
);
281 test_slice_to_path_one("foo.slice/foo--bar.slice", NULL
, -EINVAL
);
282 test_slice_to_path_one("a-b.slice", "a.slice/a-b.slice", 0);
283 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 static void test_shift_path_one(const char *raw
, const char *root
, const char *shifted
) {
287 const char *s
= NULL
;
289 assert_se(cg_shift_path(raw
, root
, &s
) >= 0);
290 assert_se(streq(s
, shifted
));
293 static void test_shift_path(void) {
295 test_shift_path_one("/foobar/waldo", "/", "/foobar/waldo");
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", "/fuckfuck", "/foobar/waldo");
301 static void test_mask_supported(void) {
306 assert_se(cg_mask_supported(&m
) >= 0);
308 for (c
= 0; c
< _CGROUP_CONTROLLER_MAX
; c
++)
309 printf("'%s' is supported: %s\n", cgroup_controller_to_string(c
), yes_no(m
& CGROUP_CONTROLLER_TO_MASK(c
)));
313 test_path_decode_unit();
314 test_path_get_unit();
315 test_path_get_user_unit();
316 test_path_get_session();
317 test_path_get_owner_uid();
318 test_path_get_slice();
319 test_path_get_user_slice();
320 TEST_REQ_RUNNING_SYSTEMD(test_get_paths());
322 TEST_REQ_RUNNING_SYSTEMD(test_escape());
323 test_controller_is_valid();
324 test_slice_to_path();
326 TEST_REQ_RUNNING_SYSTEMD(test_mask_supported());