]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/test/test-cgroup-util.c
Make systemctl --root look for files in the proper places
[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 <assert.h>
23
24 #include "util.h"
25 #include "cgroup-util.h"
26 #include "test-helper.h"
27
28 static void check_p_d_u(const char *path, int code, const char *result) {
29 _cleanup_free_ char *unit = NULL;
30 int r;
31
32 r = cg_path_decode_unit(path, &unit);
33 printf("%s: %s → %s %d expected %s %d\n", __func__, path, unit, r, result, code);
34 assert_se(r == code);
35 assert_se(streq_ptr(unit, result));
36 }
37
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");
48 }
49
50 static void check_p_g_u(const char *path, int code, const char *result) {
51 _cleanup_free_ char *unit = NULL;
52 int r;
53
54 r = cg_path_get_unit(path, &unit);
55 printf("%s: %s → %s %d expected %s %d\n", __func__, path, unit, r, result, code);
56 assert_se(r == code);
57 assert_se(streq_ptr(unit, result));
58 }
59
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);
72 }
73
74 static void check_p_g_u_u(const char *path, int code, const char *result) {
75 _cleanup_free_ char *unit = NULL;
76 int r;
77
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);
80 assert_se(r == code);
81 assert_se(streq_ptr(unit, result));
82 }
83
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);
97 }
98
99 static void check_p_g_s(const char *path, int code, const char *result) {
100 _cleanup_free_ char *s = NULL;
101
102 assert_se(cg_path_get_session(path, &s) == code);
103 assert_se(streq_ptr(s, result));
104 }
105
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);
110 }
111
112 static void check_p_g_o_u(const char *path, int code, uid_t result) {
113 uid_t uid = 0;
114
115 assert_se(cg_path_get_owner_uid(path, &uid) == code);
116 assert_se(uid == result);
117 }
118
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);
123 }
124
125 static void test_get_paths(void) {
126 _cleanup_free_ char *a = NULL;
127
128 assert_se(cg_get_root_path(&a) >= 0);
129 log_info("Root = %s", a);
130 }
131
132 static void test_proc(void) {
133 _cleanup_closedir_ DIR *d = NULL;
134 struct dirent *de;
135 int r;
136
137 d = opendir("/proc");
138 assert_se(d);
139
140 FOREACH_DIRENT(de, d, break) {
141 _cleanup_free_ char *path = NULL, *path_shifted = NULL, *session = NULL, *unit = NULL, *user_unit = NULL, *machine = NULL, *slice = NULL;
142 pid_t pid;
143 uid_t uid = (uid_t) -1;
144
145 if (de->d_type != DT_DIR &&
146 de->d_type != DT_UNKNOWN)
147 continue;
148
149 r = parse_pid(de->d_name, &pid);
150 if (r < 0)
151 continue;
152
153 if (is_kernel_thread(pid))
154 continue;
155
156 cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, pid, &path);
157 cg_pid_get_path_shifted(pid, NULL, &path_shifted);
158 cg_pid_get_owner_uid(pid, &uid);
159 cg_pid_get_session(pid, &session);
160 cg_pid_get_unit(pid, &unit);
161 cg_pid_get_user_unit(pid, &user_unit);
162 cg_pid_get_machine_name(pid, &machine);
163 cg_pid_get_slice(pid, &slice);
164
165 printf("%lu\t%s\t%s\t%lu\t%s\t%s\t%s\t%s\t%s\n",
166 (unsigned long) pid,
167 path,
168 path_shifted,
169 (unsigned long) uid,
170 session,
171 unit,
172 user_unit,
173 machine,
174 slice);
175 }
176 }
177
178 static void test_escape_one(const char *s, const char *r) {
179 _cleanup_free_ char *b;
180
181 b = cg_escape(s);
182 assert_se(b);
183 assert_se(streq(b, r));
184
185 assert_se(streq(cg_unescape(b), s));
186 }
187
188 static void test_escape(void) {
189 test_escape_one("foobar", "foobar");
190 test_escape_one(".foobar", "_.foobar");
191 test_escape_one("foobar.service", "foobar.service");
192 test_escape_one("cgroup.service", "_cgroup.service");
193 test_escape_one("tasks", "_tasks");
194 if (access("/sys/fs/cgroup/cpu", F_OK) == 0)
195 test_escape_one("cpu.service", "_cpu.service");
196 test_escape_one("_foobar", "__foobar");
197 test_escape_one("", "_");
198 test_escape_one("_", "__");
199 test_escape_one(".", "_.");
200 }
201
202 static void test_controller_is_valid(void) {
203 assert_se(cg_controller_is_valid("foobar", false));
204 assert_se(cg_controller_is_valid("foo_bar", false));
205 assert_se(cg_controller_is_valid("name=foo", true));
206 assert_se(!cg_controller_is_valid("", false));
207 assert_se(!cg_controller_is_valid("name=", true));
208 assert_se(!cg_controller_is_valid("=", false));
209 assert_se(!cg_controller_is_valid("cpu,cpuacct", false));
210 assert_se(!cg_controller_is_valid("_", false));
211 assert_se(!cg_controller_is_valid("_foobar", false));
212 assert_se(!cg_controller_is_valid("tatü", false));
213 }
214
215 static void test_slice_to_path_one(const char *unit, const char *path, int error) {
216 _cleanup_free_ char *ret = NULL;
217
218 assert_se(cg_slice_to_path(unit, &ret) == error);
219 assert_se(streq_ptr(ret, path));
220 }
221
222 static void test_slice_to_path(void) {
223
224 test_slice_to_path_one("foobar.slice", "foobar.slice", 0);
225 test_slice_to_path_one("foobar-waldo.slice", "foobar.slice/foobar-waldo.slice", 0);
226 test_slice_to_path_one("foobar-waldo.service", NULL, -EINVAL);
227 test_slice_to_path_one("-.slice", NULL, -EINVAL);
228 test_slice_to_path_one("-foo-.slice", NULL, -EINVAL);
229 test_slice_to_path_one("-foo.slice", NULL, -EINVAL);
230 test_slice_to_path_one("a-b.slice", "a.slice/a-b.slice", 0);
231 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);
232 }
233
234 static void test_shift_path_one(const char *raw, const char *root, const char *shifted) {
235 const char *s = NULL;
236
237 assert_se(cg_shift_path(raw, root, &s) >= 0);
238 assert_se(streq(s, shifted));
239 }
240
241 static void test_shift_path(void) {
242
243 test_shift_path_one("/foobar/waldo", "/", "/foobar/waldo");
244 test_shift_path_one("/foobar/waldo", "", "/foobar/waldo");
245 test_shift_path_one("/foobar/waldo", "/foobar", "/waldo");
246 test_shift_path_one("/foobar/waldo", "/fuckfuck", "/foobar/waldo");
247 }
248
249 int main(void) {
250 test_path_decode_unit();
251 test_path_get_unit();
252 test_path_get_user_unit();
253 test_path_get_session();
254 test_path_get_owner_uid();
255 TEST_REQ_RUNNING_SYSTEMD(test_get_paths());
256 test_proc();
257 TEST_REQ_RUNNING_SYSTEMD(test_escape());
258 test_controller_is_valid();
259 test_slice_to_path();
260 test_shift_path();
261
262 return 0;
263 }