]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/test/test-cgroup-util.c
shared: add process-util.[ch]
[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 #include "process-util.h"
28
29 static void check_p_d_u(const char *path, int code, const char *result) {
30 _cleanup_free_ char *unit = NULL;
31 int r;
32
33 r = cg_path_decode_unit(path, &unit);
34 printf("%s: %s → %s %d expected %s %d\n", __func__, path, unit, r, result, code);
35 assert_se(r == code);
36 assert_se(streq_ptr(unit, result));
37 }
38
39 static void test_path_decode_unit(void) {
40 check_p_d_u("getty@tty2.service", 0, "getty@tty2.service");
41 check_p_d_u("getty@tty2.service/", 0, "getty@tty2.service");
42 check_p_d_u("getty@tty2.service/xxx", 0, "getty@tty2.service");
43 check_p_d_u("getty@.service/", -EINVAL, NULL);
44 check_p_d_u("getty@.service", -EINVAL, NULL);
45 check_p_d_u("getty.service", 0, "getty.service");
46 check_p_d_u("getty", -EINVAL, NULL);
47 check_p_d_u("getty/waldo", -EINVAL, NULL);
48 check_p_d_u("_cpu.service", 0, "cpu.service");
49 }
50
51 static void check_p_g_u(const char *path, int code, const char *result) {
52 _cleanup_free_ char *unit = NULL;
53 int r;
54
55 r = cg_path_get_unit(path, &unit);
56 printf("%s: %s → %s %d expected %s %d\n", __func__, path, unit, r, result, code);
57 assert_se(r == code);
58 assert_se(streq_ptr(unit, result));
59 }
60
61 static void test_path_get_unit(void) {
62 check_p_g_u("/system.slice/foobar.service/sdfdsaf", 0, "foobar.service");
63 check_p_g_u("/system.slice/getty@tty5.service", 0, "getty@tty5.service");
64 check_p_g_u("/system.slice/getty@tty5.service/aaa/bbb", 0, "getty@tty5.service");
65 check_p_g_u("/system.slice/getty@tty5.service/", 0, "getty@tty5.service");
66 check_p_g_u("/system.slice/getty@tty6.service/tty5", 0, "getty@tty6.service");
67 check_p_g_u("sadfdsafsda", -EINVAL, NULL);
68 check_p_g_u("/system.slice/getty####@tty6.service/xxx", -EINVAL, NULL);
69 check_p_g_u("/system.slice/system-waldo.slice/foobar.service/sdfdsaf", 0, "foobar.service");
70 check_p_g_u("/system.slice/system-waldo.slice/_cpu.service/sdfdsaf", 0, "cpu.service");
71 check_p_g_u("/user.slice/user-1000.slice/user@1000.service/server.service", 0, "user@1000.service");
72 check_p_g_u("/user.slice/user-1000.slice/user@.service/server.service", -EINVAL, NULL);
73 }
74
75 static void check_p_g_u_u(const char *path, int code, const char *result) {
76 _cleanup_free_ char *unit = NULL;
77 int r;
78
79 r = cg_path_get_user_unit(path, &unit);
80 printf("%s: %s → %s %d expected %s %d\n", __func__, path, unit, r, result, code);
81 assert_se(r == code);
82 assert_se(streq_ptr(unit, result));
83 }
84
85 static void test_path_get_user_unit(void) {
86 check_p_g_u_u("/user.slice/user-1000.slice/session-2.scope/foobar.service", 0, "foobar.service");
87 check_p_g_u_u("/user.slice/user-1000.slice/session-2.scope/waldo.slice/foobar.service", 0, "foobar.service");
88 check_p_g_u_u("/user.slice/user-1002.slice/session-2.scope/foobar.service/waldo", 0, "foobar.service");
89 check_p_g_u_u("/user.slice/user-1000.slice/session-2.scope/foobar.service/waldo/uuuux", 0, "foobar.service");
90 check_p_g_u_u("/user.slice/user-1000.slice/session-2.scope/waldo/waldo/uuuux", -EINVAL, NULL);
91 check_p_g_u_u("/user.slice/user-1000.slice/session-2.scope/foobar@pie.service/pa/po", 0, "foobar@pie.service");
92 check_p_g_u_u("/session-2.scope/foobar@pie.service/pa/po", 0, "foobar@pie.service");
93 check_p_g_u_u("/xyz.slice/xyz-waldo.slice/session-77.scope/foobar@pie.service/pa/po", 0, "foobar@pie.service");
94 check_p_g_u_u("/meh.service", -ENOENT, NULL);
95 check_p_g_u_u("/session-3.scope/_cpu.service", 0, "cpu.service");
96 check_p_g_u_u("/user.slice/user-1000.slice/user@1000.service/server.service", 0, "server.service");
97 check_p_g_u_u("/user.slice/user-1000.slice/user@1000.service/foobar.slice/foobar@pie.service", 0, "foobar@pie.service");
98 check_p_g_u_u("/user.slice/user-1000.slice/user@.service/server.service", -ENOENT, NULL);
99 }
100
101 static void check_p_g_s(const char *path, int code, const char *result) {
102 _cleanup_free_ char *s = NULL;
103
104 assert_se(cg_path_get_session(path, &s) == code);
105 assert_se(streq_ptr(s, result));
106 }
107
108 static void test_path_get_session(void) {
109 check_p_g_s("/user.slice/user-1000.slice/session-2.scope/foobar.service", 0, "2");
110 check_p_g_s("/session-3.scope", 0, "3");
111 check_p_g_s("/session-.scope", -ENOENT, NULL);
112 check_p_g_s("", -ENOENT, NULL);
113 }
114
115 static void check_p_g_o_u(const char *path, int code, uid_t result) {
116 uid_t uid = 0;
117
118 assert_se(cg_path_get_owner_uid(path, &uid) == code);
119 assert_se(uid == result);
120 }
121
122 static void test_path_get_owner_uid(void) {
123 check_p_g_o_u("/user.slice/user-1000.slice/session-2.scope/foobar.service", 0, 1000);
124 check_p_g_o_u("/user.slice/user-1006.slice", 0, 1006);
125 check_p_g_o_u("", -ENOENT, 0);
126 }
127
128 static void test_get_paths(void) {
129 _cleanup_free_ char *a = NULL;
130
131 assert_se(cg_get_root_path(&a) >= 0);
132 log_info("Root = %s", a);
133 }
134
135 static void test_proc(void) {
136 _cleanup_closedir_ DIR *d = NULL;
137 struct dirent *de;
138 int r;
139
140 d = opendir("/proc");
141 assert_se(d);
142
143 FOREACH_DIRENT(de, d, break) {
144 _cleanup_free_ char *path = NULL, *path_shifted = NULL, *session = NULL, *unit = NULL, *user_unit = NULL, *machine = NULL, *slice = NULL;
145 pid_t pid;
146 uid_t uid = UID_INVALID;
147
148 if (de->d_type != DT_DIR &&
149 de->d_type != DT_UNKNOWN)
150 continue;
151
152 r = parse_pid(de->d_name, &pid);
153 if (r < 0)
154 continue;
155
156 if (is_kernel_thread(pid))
157 continue;
158
159 cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, pid, &path);
160 cg_pid_get_path_shifted(pid, NULL, &path_shifted);
161 cg_pid_get_owner_uid(pid, &uid);
162 cg_pid_get_session(pid, &session);
163 cg_pid_get_unit(pid, &unit);
164 cg_pid_get_user_unit(pid, &user_unit);
165 cg_pid_get_machine_name(pid, &machine);
166 cg_pid_get_slice(pid, &slice);
167
168 printf(PID_FMT"\t%s\t%s\t"UID_FMT"\t%s\t%s\t%s\t%s\t%s\n",
169 pid,
170 path,
171 path_shifted,
172 uid,
173 session,
174 unit,
175 user_unit,
176 machine,
177 slice);
178 }
179 }
180
181 static void test_escape_one(const char *s, const char *r) {
182 _cleanup_free_ char *b;
183
184 b = cg_escape(s);
185 assert_se(b);
186 assert_se(streq(b, r));
187
188 assert_se(streq(cg_unescape(b), s));
189 }
190
191 static void test_escape(void) {
192 test_escape_one("foobar", "foobar");
193 test_escape_one(".foobar", "_.foobar");
194 test_escape_one("foobar.service", "foobar.service");
195 test_escape_one("cgroup.service", "_cgroup.service");
196 test_escape_one("tasks", "_tasks");
197 if (access("/sys/fs/cgroup/cpu", F_OK) == 0)
198 test_escape_one("cpu.service", "_cpu.service");
199 test_escape_one("_foobar", "__foobar");
200 test_escape_one("", "_");
201 test_escape_one("_", "__");
202 test_escape_one(".", "_.");
203 }
204
205 static void test_controller_is_valid(void) {
206 assert_se(cg_controller_is_valid("foobar", false));
207 assert_se(cg_controller_is_valid("foo_bar", false));
208 assert_se(cg_controller_is_valid("name=foo", true));
209 assert_se(!cg_controller_is_valid("", false));
210 assert_se(!cg_controller_is_valid("name=", true));
211 assert_se(!cg_controller_is_valid("=", false));
212 assert_se(!cg_controller_is_valid("cpu,cpuacct", false));
213 assert_se(!cg_controller_is_valid("_", false));
214 assert_se(!cg_controller_is_valid("_foobar", false));
215 assert_se(!cg_controller_is_valid("tatü", false));
216 }
217
218 static void test_slice_to_path_one(const char *unit, const char *path, int error) {
219 _cleanup_free_ char *ret = NULL;
220
221 assert_se(cg_slice_to_path(unit, &ret) == error);
222 assert_se(streq_ptr(ret, path));
223 }
224
225 static void test_slice_to_path(void) {
226
227 test_slice_to_path_one("foobar.slice", "foobar.slice", 0);
228 test_slice_to_path_one("foobar-waldo.slice", "foobar.slice/foobar-waldo.slice", 0);
229 test_slice_to_path_one("foobar-waldo.service", NULL, -EINVAL);
230 test_slice_to_path_one("-.slice", NULL, -EINVAL);
231 test_slice_to_path_one("-foo-.slice", NULL, -EINVAL);
232 test_slice_to_path_one("-foo.slice", NULL, -EINVAL);
233 test_slice_to_path_one("a-b.slice", "a.slice/a-b.slice", 0);
234 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);
235 }
236
237 static void test_shift_path_one(const char *raw, const char *root, const char *shifted) {
238 const char *s = NULL;
239
240 assert_se(cg_shift_path(raw, root, &s) >= 0);
241 assert_se(streq(s, shifted));
242 }
243
244 static void test_shift_path(void) {
245
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", "/foobar", "/waldo");
249 test_shift_path_one("/foobar/waldo", "/fuckfuck", "/foobar/waldo");
250 }
251
252 int main(void) {
253 test_path_decode_unit();
254 test_path_get_unit();
255 test_path_get_user_unit();
256 test_path_get_session();
257 test_path_get_owner_uid();
258 TEST_REQ_RUNNING_SYSTEMD(test_get_paths());
259 test_proc();
260 TEST_REQ_RUNNING_SYSTEMD(test_escape());
261 test_controller_is_valid();
262 test_slice_to_path();
263 test_shift_path();
264
265 return 0;
266 }