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