chiark / gitweb /
udev: support ENV{}=="" global property matches
[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@.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 }