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