chiark / gitweb /
rules: simplify mmc RPMB handling
[elogind.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@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 }