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/>.
25 #include "cgroup-util.h"
26 #include "test-helper.h"
28 static void check_p_d_u(const char *path, int code, const char *result) {
29 _cleanup_free_ char *unit = NULL;
32 r = cg_path_decode_unit(path, &unit);
33 printf("%s: %s → %s %d expected %s %d\n", __func__, path, unit, r, result, code);
35 assert_se(streq_ptr(unit, result));
38 static void test_path_decode_unit(void) {
39 check_p_d_u("getty@tty2.service", 0, "getty@tty2.service");
40 check_p_d_u("getty@tty2.service/", 0, "getty@tty2.service");
41 check_p_d_u("getty@tty2.service/xxx", 0, "getty@tty2.service");
42 check_p_d_u("getty@.service/", -EINVAL, NULL);
43 check_p_d_u("getty@.service", -EINVAL, NULL);
44 check_p_d_u("getty.service", 0, "getty.service");
45 check_p_d_u("getty", -EINVAL, NULL);
46 check_p_d_u("getty/waldo", -EINVAL, NULL);
47 check_p_d_u("_cpu.service", 0, "cpu.service");
50 static void check_p_g_u(const char *path, int code, const char *result) {
51 _cleanup_free_ char *unit = NULL;
54 r = cg_path_get_unit(path, &unit);
55 printf("%s: %s → %s %d expected %s %d\n", __func__, path, unit, r, result, code);
57 assert_se(streq_ptr(unit, result));
60 static void test_path_get_unit(void) {
61 check_p_g_u("/system.slice/foobar.service/sdfdsaf", 0, "foobar.service");
62 check_p_g_u("/system.slice/getty@tty5.service", 0, "getty@tty5.service");
63 check_p_g_u("/system.slice/getty@tty5.service/aaa/bbb", 0, "getty@tty5.service");
64 check_p_g_u("/system.slice/getty@tty5.service/", 0, "getty@tty5.service");
65 check_p_g_u("/system.slice/getty@tty6.service/tty5", 0, "getty@tty6.service");
66 check_p_g_u("sadfdsafsda", -EINVAL, NULL);
67 check_p_g_u("/system.slice/getty####@tty6.service/xxx", -EINVAL, NULL);
68 check_p_g_u("/system.slice/system-waldo.slice/foobar.service/sdfdsaf", 0, "foobar.service");
69 check_p_g_u("/system.slice/system-waldo.slice/_cpu.service/sdfdsaf", 0, "cpu.service");
70 check_p_g_u("/user.slice/user-1000.slice/user@1000.service/server.service", 0, "user@1000.service");
71 check_p_g_u("/user.slice/user-1000.slice/user@.service/server.service", -EINVAL, NULL);
74 static void check_p_g_u_u(const char *path, int code, const char *result) {
75 _cleanup_free_ char *unit = NULL;
78 r = cg_path_get_user_unit(path, &unit);
79 printf("%s: %s → %s %d expected %s %d\n", __func__, path, unit, r, result, code);
81 assert_se(streq_ptr(unit, result));
84 static void test_path_get_user_unit(void) {
85 check_p_g_u_u("/user.slice/user-1000.slice/session-2.scope/foobar.service", 0, "foobar.service");
86 check_p_g_u_u("/user.slice/user-1000.slice/session-2.scope/waldo.slice/foobar.service", 0, "foobar.service");
87 check_p_g_u_u("/user.slice/user-1002.slice/session-2.scope/foobar.service/waldo", 0, "foobar.service");
88 check_p_g_u_u("/user.slice/user-1000.slice/session-2.scope/foobar.service/waldo/uuuux", 0, "foobar.service");
89 check_p_g_u_u("/user.slice/user-1000.slice/session-2.scope/waldo/waldo/uuuux", -EINVAL, NULL);
90 check_p_g_u_u("/user.slice/user-1000.slice/session-2.scope/foobar@pie.service/pa/po", 0, "foobar@pie.service");
91 check_p_g_u_u("/session-2.scope/foobar@pie.service/pa/po", 0, "foobar@pie.service");
92 check_p_g_u_u("/xyz.slice/xyz-waldo.slice/session-77.scope/foobar@pie.service/pa/po", 0, "foobar@pie.service");
93 check_p_g_u_u("/meh.service", -ENOENT, NULL);
94 check_p_g_u_u("/session-3.scope/_cpu.service", 0, "cpu.service");
95 check_p_g_u_u("/user.slice/user-1000.slice/user@1000.service/server.service", 0, "server.service");
96 check_p_g_u_u("/user.slice/user-1000.slice/user@.service/server.service", -ENOENT, NULL);
99 static void check_p_g_s(const char *path, int code, const char *result) {
100 _cleanup_free_ char *s = NULL;
102 assert_se(cg_path_get_session(path, &s) == code);
103 assert_se(streq_ptr(s, result));
106 static void test_path_get_session(void) {
107 check_p_g_s("/user.slice/user-1000.slice/session-2.scope/foobar.service", 0, "2");
108 check_p_g_s("/session-3.scope", 0, "3");
109 check_p_g_s("", -ENOENT, 0);
112 static void check_p_g_o_u(const char *path, int code, uid_t result) {
115 assert_se(cg_path_get_owner_uid(path, &uid) == code);
116 assert_se(uid == result);
119 static void test_path_get_owner_uid(void) {
120 check_p_g_o_u("/user.slice/user-1000.slice/session-2.scope/foobar.service", 0, 1000);
121 check_p_g_o_u("/user.slice/user-1006.slice", 0, 1006);
122 check_p_g_o_u("", -ENOENT, 0);
125 static void check_p_g_m_n(const char *path, int code, const char *result) {
126 _cleanup_free_ char *m = NULL;
128 assert_se(cg_path_get_machine_name(path, &m) == code);
129 assert_se(streq_ptr(m, result));
132 static void test_path_get_machine_name(void) {
133 check_p_g_m_n("/user.slice/machine-foobar.scope", 0, "foobar");
134 check_p_g_m_n("/machine-foobar.scope", 0, "foobar");
135 check_p_g_m_n("/user.slice/user-kuux.slice/machine-foobar.scope", 0, "foobar");
136 check_p_g_m_n("/user.slice/user-kuux.slice/machine-foobar.scope/asjhdkj", 0, "foobar");
137 check_p_g_m_n("", -ENOENT, NULL);
140 static void test_get_paths(void) {
141 _cleanup_free_ char *a = NULL;
143 assert_se(cg_get_root_path(&a) >= 0);
144 log_info("Root = %s", a);
147 static void test_proc(void) {
148 _cleanup_closedir_ DIR *d = NULL;
152 d = opendir("/proc");
155 FOREACH_DIRENT(de, d, break) {
156 _cleanup_free_ char *path = NULL, *path_shifted = NULL, *session = NULL, *unit = NULL, *user_unit = NULL, *machine = NULL, *slice = NULL;
158 uid_t uid = (uid_t) -1;
160 if (de->d_type != DT_DIR &&
161 de->d_type != DT_UNKNOWN)
164 r = parse_pid(de->d_name, &pid);
168 if (is_kernel_thread(pid))
171 cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, pid, &path);
172 cg_pid_get_path_shifted(pid, NULL, &path_shifted);
173 cg_pid_get_owner_uid(pid, &uid);
174 cg_pid_get_session(pid, &session);
175 cg_pid_get_unit(pid, &unit);
176 cg_pid_get_user_unit(pid, &user_unit);
177 cg_pid_get_machine_name(pid, &machine);
178 cg_pid_get_slice(pid, &slice);
180 printf("%lu\t%s\t%s\t%lu\t%s\t%s\t%s\t%s\t%s\n",
193 static void test_escape_one(const char *s, const char *r) {
194 _cleanup_free_ char *b;
198 assert_se(streq(b, r));
200 assert_se(streq(cg_unescape(b), s));
203 static void test_escape(void) {
204 test_escape_one("foobar", "foobar");
205 test_escape_one(".foobar", "_.foobar");
206 test_escape_one("foobar.service", "foobar.service");
207 test_escape_one("cgroup.service", "_cgroup.service");
208 test_escape_one("tasks", "_tasks");
209 if (access("/sys/fs/cgroup/cpu", F_OK) == 0)
210 test_escape_one("cpu.service", "_cpu.service");
211 test_escape_one("_foobar", "__foobar");
212 test_escape_one("", "_");
213 test_escape_one("_", "__");
214 test_escape_one(".", "_.");
217 static void test_controller_is_valid(void) {
218 assert_se(cg_controller_is_valid("foobar", false));
219 assert_se(cg_controller_is_valid("foo_bar", false));
220 assert_se(cg_controller_is_valid("name=foo", true));
221 assert_se(!cg_controller_is_valid("", false));
222 assert_se(!cg_controller_is_valid("name=", true));
223 assert_se(!cg_controller_is_valid("=", false));
224 assert_se(!cg_controller_is_valid("cpu,cpuacct", false));
225 assert_se(!cg_controller_is_valid("_", false));
226 assert_se(!cg_controller_is_valid("_foobar", false));
227 assert_se(!cg_controller_is_valid("tatü", false));
230 static void test_slice_to_path_one(const char *unit, const char *path, int error) {
231 _cleanup_free_ char *ret = NULL;
233 assert_se(cg_slice_to_path(unit, &ret) == error);
234 assert_se(streq_ptr(ret, path));
237 static void test_slice_to_path(void) {
239 test_slice_to_path_one("foobar.slice", "foobar.slice", 0);
240 test_slice_to_path_one("foobar-waldo.slice", "foobar.slice/foobar-waldo.slice", 0);
241 test_slice_to_path_one("foobar-waldo.service", NULL, -EINVAL);
242 test_slice_to_path_one("-.slice", NULL, -EINVAL);
243 test_slice_to_path_one("-foo-.slice", NULL, -EINVAL);
244 test_slice_to_path_one("-foo.slice", NULL, -EINVAL);
245 test_slice_to_path_one("a-b.slice", "a.slice/a-b.slice", 0);
246 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);
249 static void test_shift_path_one(const char *raw, const char *root, const char *shifted) {
250 const char *s = NULL;
252 assert_se(cg_shift_path(raw, root, &s) >= 0);
253 assert_se(streq(s, shifted));
256 static void test_shift_path(void) {
258 test_shift_path_one("/foobar/waldo", "/", "/foobar/waldo");
259 test_shift_path_one("/foobar/waldo", "", "/foobar/waldo");
260 test_shift_path_one("/foobar/waldo", "/foobar", "/waldo");
261 test_shift_path_one("/foobar/waldo", "/fuckfuck", "/foobar/waldo");
265 test_path_decode_unit();
266 test_path_get_unit();
267 test_path_get_user_unit();
268 test_path_get_session();
269 test_path_get_owner_uid();
270 test_path_get_machine_name();
271 TEST_REQ_RUNNING_SYSTEMD(test_get_paths());
273 TEST_REQ_RUNNING_SYSTEMD(test_escape());
274 test_controller_is_valid();
275 test_slice_to_path();