]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/test/test-cgroup-util.c
update TODO
[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("/session-.scope", -ENOENT, NULL);
110 check_p_g_s("", -ENOENT, NULL);
111 }
112
113 static void check_p_g_o_u(const char *path, int code, uid_t result) {
114 uid_t uid = 0;
115
116 assert_se(cg_path_get_owner_uid(path, &uid) == code);
117 assert_se(uid == result);
118 }
119
120 static void test_path_get_owner_uid(void) {
121 check_p_g_o_u("/user.slice/user-1000.slice/session-2.scope/foobar.service", 0, 1000);
122 check_p_g_o_u("/user.slice/user-1006.slice", 0, 1006);
123 check_p_g_o_u("", -ENOENT, 0);
124 }
125
126 static void test_get_paths(void) {
127 _cleanup_free_ char *a = NULL;
128
129 assert_se(cg_get_root_path(&a) >= 0);
130 log_info("Root = %s", a);
131 }
132
133 static void test_proc(void) {
134 _cleanup_closedir_ DIR *d = NULL;
135 struct dirent *de;
136 int r;
137
138 d = opendir("/proc");
139 assert_se(d);
140
141 FOREACH_DIRENT(de, d, break) {
142 _cleanup_free_ char *path = NULL, *path_shifted = NULL, *session = NULL, *unit = NULL, *user_unit = NULL, *machine = NULL, *slice = NULL;
143 pid_t pid;
144 uid_t uid = (uid_t) -1;
145
146 if (de->d_type != DT_DIR &&
147 de->d_type != DT_UNKNOWN)
148 continue;
149
150 r = parse_pid(de->d_name, &pid);
151 if (r < 0)
152 continue;
153
154 if (is_kernel_thread(pid))
155 continue;
156
157 cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, pid, &path);
158 cg_pid_get_path_shifted(pid, NULL, &path_shifted);
159 cg_pid_get_owner_uid(pid, &uid);
160 cg_pid_get_session(pid, &session);
161 cg_pid_get_unit(pid, &unit);
162 cg_pid_get_user_unit(pid, &user_unit);
163 cg_pid_get_machine_name(pid, &machine);
164 cg_pid_get_slice(pid, &slice);
165
166 printf(PID_FMT"\t%s\t%s\t"UID_FMT"\t%s\t%s\t%s\t%s\t%s\n",
167 pid,
168 path,
169 path_shifted,
170 uid,
171 session,
172 unit,
173 user_unit,
174 machine,
175 slice);
176 }
177 }
178
179 static void test_escape_one(const char *s, const char *r) {
180 _cleanup_free_ char *b;
181
182 b = cg_escape(s);
183 assert_se(b);
184 assert_se(streq(b, r));
185
186 assert_se(streq(cg_unescape(b), s));
187 }
188
189 static void test_escape(void) {
190 test_escape_one("foobar", "foobar");
191 test_escape_one(".foobar", "_.foobar");
192 test_escape_one("foobar.service", "foobar.service");
193 test_escape_one("cgroup.service", "_cgroup.service");
194 test_escape_one("tasks", "_tasks");
195 if (access("/sys/fs/cgroup/cpu", F_OK) == 0)
196 test_escape_one("cpu.service", "_cpu.service");
197 test_escape_one("_foobar", "__foobar");
198 test_escape_one("", "_");
199 test_escape_one("_", "__");
200 test_escape_one(".", "_.");
201 }
202
203 static void test_controller_is_valid(void) {
204 assert_se(cg_controller_is_valid("foobar", false));
205 assert_se(cg_controller_is_valid("foo_bar", false));
206 assert_se(cg_controller_is_valid("name=foo", true));
207 assert_se(!cg_controller_is_valid("", false));
208 assert_se(!cg_controller_is_valid("name=", true));
209 assert_se(!cg_controller_is_valid("=", false));
210 assert_se(!cg_controller_is_valid("cpu,cpuacct", false));
211 assert_se(!cg_controller_is_valid("_", false));
212 assert_se(!cg_controller_is_valid("_foobar", false));
213 assert_se(!cg_controller_is_valid("tatü", false));
214 }
215
216 static void test_slice_to_path_one(const char *unit, const char *path, int error) {
217 _cleanup_free_ char *ret = NULL;
218
219 assert_se(cg_slice_to_path(unit, &ret) == error);
220 assert_se(streq_ptr(ret, path));
221 }
222
223 static void test_slice_to_path(void) {
224
225 test_slice_to_path_one("foobar.slice", "foobar.slice", 0);
226 test_slice_to_path_one("foobar-waldo.slice", "foobar.slice/foobar-waldo.slice", 0);
227 test_slice_to_path_one("foobar-waldo.service", NULL, -EINVAL);
228 test_slice_to_path_one("-.slice", NULL, -EINVAL);
229 test_slice_to_path_one("-foo-.slice", NULL, -EINVAL);
230 test_slice_to_path_one("-foo.slice", NULL, -EINVAL);
231 test_slice_to_path_one("a-b.slice", "a.slice/a-b.slice", 0);
232 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);
233 }
234
235 static void test_shift_path_one(const char *raw, const char *root, const char *shifted) {
236 const char *s = NULL;
237
238 assert_se(cg_shift_path(raw, root, &s) >= 0);
239 assert_se(streq(s, shifted));
240 }
241
242 static void test_shift_path(void) {
243
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", "/foobar", "/waldo");
247 test_shift_path_one("/foobar/waldo", "/fuckfuck", "/foobar/waldo");
248 }
249
250 int main(void) {
251 test_path_decode_unit();
252 test_path_get_unit();
253 test_path_get_user_unit();
254 test_path_get_session();
255 test_path_get_owner_uid();
256 TEST_REQ_RUNNING_SYSTEMD(test_get_paths());
257 test_proc();
258 TEST_REQ_RUNNING_SYSTEMD(test_escape());
259 test_controller_is_valid();
260 test_slice_to_path();
261 test_shift_path();
262
263 return 0;
264 }