]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/test/test-unit-name.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2012 Lennart Poettering
7 Copyright 2013 Zbigniew Jędrzejewski-Szmek
8 Copyright 2014 Ronny Chevalier
10 systemd is free software; you can redistribute it and/or modify it
11 under the terms of the GNU Lesser General Public License as published by
12 the Free Software Foundation; either version 2.1 of the License, or
13 (at your option) any later version.
15 systemd is distributed in the hope that it will be useful, but
16 WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 Lesser General Public License for more details.
20 You should have received a copy of the GNU Lesser General Public License
21 along with systemd; If not, see <http://www.gnu.org/licenses/>.
29 #include "hostname-util.h"
32 #include "path-util.h"
33 #include "specifier.h"
34 #include "string-util.h"
35 #include "test-helper.h"
36 #include "unit-name.h"
37 #include "unit-printf.h"
41 static void test_unit_name_is_valid(void) {
42 assert_se(unit_name_is_valid("foo.service", UNIT_NAME_ANY
));
43 assert_se(unit_name_is_valid("foo.service", UNIT_NAME_PLAIN
));
44 assert_se(!unit_name_is_valid("foo.service", UNIT_NAME_INSTANCE
));
45 assert_se(!unit_name_is_valid("foo.service", UNIT_NAME_TEMPLATE
));
46 assert_se(!unit_name_is_valid("foo.service", UNIT_NAME_INSTANCE
|UNIT_NAME_TEMPLATE
));
48 assert_se(unit_name_is_valid("foo@bar.service", UNIT_NAME_ANY
));
49 assert_se(!unit_name_is_valid("foo@bar.service", UNIT_NAME_PLAIN
));
50 assert_se(unit_name_is_valid("foo@bar.service", UNIT_NAME_INSTANCE
));
51 assert_se(!unit_name_is_valid("foo@bar.service", UNIT_NAME_TEMPLATE
));
52 assert_se(unit_name_is_valid("foo@bar.service", UNIT_NAME_INSTANCE
|UNIT_NAME_TEMPLATE
));
54 assert_se(unit_name_is_valid("foo@.service", UNIT_NAME_ANY
));
55 assert_se(!unit_name_is_valid("foo@.service", UNIT_NAME_PLAIN
));
56 assert_se(!unit_name_is_valid("foo@.service", UNIT_NAME_INSTANCE
));
57 assert_se(unit_name_is_valid("foo@.service", UNIT_NAME_TEMPLATE
));
58 assert_se(unit_name_is_valid("foo@.service", UNIT_NAME_INSTANCE
|UNIT_NAME_TEMPLATE
));
60 assert_se(!unit_name_is_valid(".service", UNIT_NAME_ANY
));
61 assert_se(!unit_name_is_valid("", UNIT_NAME_ANY
));
62 assert_se(!unit_name_is_valid("foo.waldo", UNIT_NAME_ANY
));
63 assert_se(!unit_name_is_valid("@.service", UNIT_NAME_ANY
));
64 assert_se(!unit_name_is_valid("@piep.service", UNIT_NAME_ANY
));
67 static void test_u_n_r_i_one(const char *pattern
, const char *repl
, const char *expected
, int ret
) {
68 _cleanup_free_
char *t
= NULL
;
69 assert_se(unit_name_replace_instance(pattern
, repl
, &t
) == ret
);
71 assert_se(streq_ptr(t
, expected
));
74 static void test_u_n_r_i(void) {
75 puts("-------------------------------------------------");
76 test_u_n_r_i_one("foo@.service", "waldo", "foo@waldo.service", 0);
77 test_u_n_r_i_one("foo@xyz.service", "waldo", "foo@waldo.service", 0);
78 test_u_n_r_i_one("xyz", "waldo", NULL
, -EINVAL
);
79 test_u_n_r_i_one("", "waldo", NULL
, -EINVAL
);
80 test_u_n_r_i_one("foo.service", "waldo", NULL
, -EINVAL
);
81 test_u_n_r_i_one(".service", "waldo", NULL
, -EINVAL
);
82 test_u_n_r_i_one("foo@", "waldo", NULL
, -EINVAL
);
83 test_u_n_r_i_one("@bar", "waldo", NULL
, -EINVAL
);
86 static void test_u_n_f_p_one(const char *path
, const char *suffix
, const char *expected
, int ret
) {
87 _cleanup_free_
char *t
= NULL
;
89 assert_se(unit_name_from_path(path
, suffix
, &t
) == ret
);
91 assert_se(streq_ptr(t
, expected
));
94 _cleanup_free_
char *k
= NULL
;
95 assert_se(unit_name_to_path(t
, &k
) == 0);
97 assert_se(path_equal(k
, isempty(path
) ? "/" : path
));
101 static void test_u_n_f_p(void) {
102 puts("-------------------------------------------------");
103 test_u_n_f_p_one("/waldo", ".mount", "waldo.mount", 0);
104 test_u_n_f_p_one("/waldo/quuix", ".mount", "waldo-quuix.mount", 0);
105 test_u_n_f_p_one("/waldo/quuix/", ".mount", "waldo-quuix.mount", 0);
106 test_u_n_f_p_one("", ".mount", "-.mount", 0);
107 test_u_n_f_p_one("/", ".mount", "-.mount", 0);
108 test_u_n_f_p_one("///", ".mount", "-.mount", 0);
109 test_u_n_f_p_one("/foo/../bar", ".mount", NULL
, -EINVAL
);
110 test_u_n_f_p_one("/foo/./bar", ".mount", NULL
, -EINVAL
);
113 static void test_u_n_f_p_i_one(const char *pattern
, const char *path
, const char *suffix
, const char *expected
, int ret
) {
114 _cleanup_free_
char *t
= NULL
;
116 assert_se(unit_name_from_path_instance(pattern
, path
, suffix
, &t
) == ret
);
118 assert_se(streq_ptr(t
, expected
));
121 _cleanup_free_
char *k
= NULL
, *v
= NULL
;
123 assert_se(unit_name_to_instance(t
, &k
) > 0);
124 assert_se(unit_name_path_unescape(k
, &v
) == 0);
125 assert_se(path_equal(v
, isempty(path
) ? "/" : path
));
129 static void test_u_n_f_p_i(void) {
130 puts("-------------------------------------------------");
132 test_u_n_f_p_i_one("waldo", "/waldo", ".mount", "waldo@waldo.mount", 0);
133 test_u_n_f_p_i_one("waldo", "/waldo////quuix////", ".mount", "waldo@waldo-quuix.mount", 0);
134 test_u_n_f_p_i_one("waldo", "/", ".mount", "waldo@-.mount", 0);
135 test_u_n_f_p_i_one("waldo", "", ".mount", "waldo@-.mount", 0);
136 test_u_n_f_p_i_one("waldo", "///", ".mount", "waldo@-.mount", 0);
137 test_u_n_f_p_i_one("waldo", "..", ".mount", NULL
, -EINVAL
);
138 test_u_n_f_p_i_one("waldo", "/foo", ".waldi", NULL
, -EINVAL
);
139 test_u_n_f_p_i_one("wa--ldo", "/--", ".mount", "wa--ldo@\\x2d\\x2d.mount", 0);
142 static void test_u_n_t_p_one(const char *unit
, const char *path
, int ret
) {
143 _cleanup_free_
char *p
= NULL
;
145 assert_se(unit_name_to_path(unit
, &p
) == ret
);
146 assert_se(streq_ptr(path
, p
));
149 static void test_u_n_t_p(void) {
150 test_u_n_t_p_one("home.mount", "/home", 0);
151 test_u_n_t_p_one("home-lennart.mount", "/home/lennart", 0);
152 test_u_n_t_p_one("home-lennart-.mount", NULL
, -EINVAL
);
153 test_u_n_t_p_one("-home-lennart.mount", NULL
, -EINVAL
);
154 test_u_n_t_p_one("-home--lennart.mount", NULL
, -EINVAL
);
155 test_u_n_t_p_one("home-..-lennart.mount", NULL
, -EINVAL
);
156 test_u_n_t_p_one("", NULL
, -EINVAL
);
157 test_u_n_t_p_one("home/foo", NULL
, -EINVAL
);
160 static void test_u_n_m_one(const char *pattern
, const char *expect
, int ret
) {
161 _cleanup_free_
char *t
= NULL
;
163 assert_se(unit_name_mangle(pattern
, UNIT_NAME_NOGLOB
, &t
) == ret
);
165 assert_se(streq_ptr(t
, expect
));
168 _cleanup_free_
char *k
= NULL
;
170 assert_se(unit_name_is_valid(t
, UNIT_NAME_ANY
));
172 assert_se(unit_name_mangle(t
, UNIT_NAME_NOGLOB
, &k
) == 0);
173 assert_se(streq_ptr(t
, k
));
177 static void test_u_n_m(void) {
178 puts("-------------------------------------------------");
179 test_u_n_m_one("foo.service", "foo.service", 0);
180 test_u_n_m_one("/home", "home.mount", 1);
181 test_u_n_m_one("/dev/sda", "dev-sda.device", 1);
182 test_u_n_m_one("üxknürz.service", "\\xc3\\xbcxkn\\xc3\\xbcrz.service", 1);
183 test_u_n_m_one("foobar-meh...waldi.service", "foobar-meh...waldi.service", 0);
184 test_u_n_m_one("_____####----.....service", "_____\\x23\\x23\\x23\\x23----.....service", 1);
185 test_u_n_m_one("_____##@;;;,,,##----.....service", "_____\\x23\\x23@\\x3b\\x3b\\x3b\\x2c\\x2c\\x2c\\x23\\x23----.....service", 1);
186 test_u_n_m_one("xxx@@@@/////\\\\\\\\\\yyy.service", "xxx@@@@-----\\\\\\\\\\yyy.service", 1);
187 test_u_n_m_one("", NULL
, -EINVAL
);
190 static int test_unit_printf(void) {
195 _cleanup_free_
char *mid
, *bid
, *host
, *root_uid
;
198 assert_se(specifier_machine_id('m', NULL
, NULL
, &mid
) >= 0 && mid
);
199 assert_se(specifier_boot_id('b', NULL
, NULL
, &bid
) >= 0 && bid
);
200 assert_se((host
= gethostname_malloc()));
202 assert_se((root
= getpwnam("root")));
203 assert_se(asprintf(&root_uid
, "%d", (int) root
->pw_uid
) > 0);
205 r
= manager_new(MANAGER_USER
, true, &m
);
206 if (r
== -EPERM
|| r
== -EACCES
|| r
== -EADDRINUSE
) {
207 puts("manager_new: Permission denied. Skipping test.");
208 return EXIT_TEST_SKIP
;
212 #define expect(unit, pattern, expected) \
215 _cleanup_free_ char *t = NULL; \
216 assert_se(unit_full_printf(unit, pattern, &t) >= 0); \
217 printf("result: %s\nexpect: %s\n", t, expected); \
218 if ((e = endswith(expected, "*"))) \
219 assert_se(strncmp(t, e, e-expected)); \
221 assert_se(streq(t, expected)); \
224 assert_se(setenv("USER", "root", 1) == 0);
225 assert_se(setenv("HOME", "/root", 1) == 0);
226 assert_se(setenv("XDG_RUNTIME_DIR", "/run/user/1/", 1) == 0);
228 assert_se(u
= unit_new(m
, sizeof(Service
)));
229 assert_se(unit_add_name(u
, "blah.service") == 0);
230 assert_se(unit_add_name(u
, "blah.service") == 0);
233 expect(u
, "%%", "%");
234 expect(u
, "%%s", "%s");
235 expect(u
, "%", ""); // REALLY?
238 expect(u
, "%n", "blah.service");
239 expect(u
, "%f", "/blah");
240 expect(u
, "%N", "blah");
241 expect(u
, "%p", "blah");
242 expect(u
, "%P", "blah");
244 expect(u
, "%u", root
->pw_name
);
245 expect(u
, "%U", root_uid
);
246 expect(u
, "%h", root
->pw_dir
);
247 expect(u
, "%m", mid
);
248 expect(u
, "%b", bid
);
249 expect(u
, "%H", host
);
250 expect(u
, "%t", "/run/user/*");
253 assert_se(u2
= unit_new(m
, sizeof(Service
)));
254 assert_se(unit_add_name(u2
, "blah@foo-foo.service") == 0);
255 assert_se(unit_add_name(u2
, "blah@foo-foo.service") == 0);
257 expect(u2
, "%n", "blah@foo-foo.service");
258 expect(u2
, "%N", "blah@foo-foo");
259 expect(u2
, "%f", "/foo/foo");
260 expect(u2
, "%p", "blah");
261 expect(u2
, "%P", "blah");
262 expect(u2
, "%i", "foo-foo");
263 expect(u2
, "%I", "foo/foo");
264 expect(u2
, "%u", root
->pw_name
);
265 expect(u2
, "%U", root_uid
);
266 expect(u2
, "%h", root
->pw_dir
);
267 expect(u2
, "%m", mid
);
268 expect(u2
, "%b", bid
);
269 expect(u2
, "%H", host
);
270 expect(u2
, "%t", "/run/user/*");
278 static void test_unit_instance_is_valid(void) {
279 assert_se(unit_instance_is_valid("fooBar"));
280 assert_se(unit_instance_is_valid("foo-bar"));
281 assert_se(unit_instance_is_valid("foo.stUff"));
282 assert_se(unit_instance_is_valid("fOo123.stuff"));
283 assert_se(unit_instance_is_valid("@f_oo123.Stuff"));
285 assert_se(!unit_instance_is_valid("$¢£"));
286 assert_se(!unit_instance_is_valid(""));
287 assert_se(!unit_instance_is_valid("foo bar"));
288 assert_se(!unit_instance_is_valid("foo/bar"));
291 static void test_unit_prefix_is_valid(void) {
292 assert_se(unit_prefix_is_valid("fooBar"));
293 assert_se(unit_prefix_is_valid("foo-bar"));
294 assert_se(unit_prefix_is_valid("foo.stUff"));
295 assert_se(unit_prefix_is_valid("fOo123.stuff"));
296 assert_se(unit_prefix_is_valid("foo123.Stuff"));
298 assert_se(!unit_prefix_is_valid("$¢£"));
299 assert_se(!unit_prefix_is_valid(""));
300 assert_se(!unit_prefix_is_valid("foo bar"));
301 assert_se(!unit_prefix_is_valid("foo/bar"));
302 assert_se(!unit_prefix_is_valid("@foo-bar"));
305 static void test_unit_name_change_suffix(void) {
308 assert_se(unit_name_change_suffix("foo.mount", ".service", &t
) == 0);
309 assert_se(streq(t
, "foo.service"));
312 assert_se(unit_name_change_suffix("foo@stuff.service", ".socket", &t
) == 0);
313 assert_se(streq(t
, "foo@stuff.socket"));
317 static void test_unit_name_build(void) {
320 assert_se(unit_name_build("foo", "bar", ".service", &t
) == 0);
321 assert_se(streq(t
, "foo@bar.service"));
324 assert_se(unit_name_build("fo0-stUff_b", "bar", ".mount", &t
) == 0);
325 assert_se(streq(t
, "fo0-stUff_b@bar.mount"));
328 assert_se(unit_name_build("foo", NULL
, ".service", &t
) == 0);
329 assert_se(streq(t
, "foo.service"));
333 static void test_slice_name_is_valid(void) {
334 assert_se(slice_name_is_valid("-.slice"));
335 assert_se(slice_name_is_valid("foo.slice"));
336 assert_se(slice_name_is_valid("foo-bar.slice"));
337 assert_se(slice_name_is_valid("foo-bar-baz.slice"));
338 assert_se(!slice_name_is_valid("-foo-bar-baz.slice"));
339 assert_se(!slice_name_is_valid("foo-bar-baz-.slice"));
340 assert_se(!slice_name_is_valid("-foo-bar-baz-.slice"));
341 assert_se(!slice_name_is_valid("foo-bar--baz.slice"));
342 assert_se(!slice_name_is_valid("foo--bar--baz.slice"));
343 assert_se(!slice_name_is_valid(".slice"));
344 assert_se(!slice_name_is_valid(""));
345 assert_se(!slice_name_is_valid("foo.service"));
348 static void test_build_subslice(void) {
352 assert_se(slice_build_subslice("-.slice", "foo", &a
) >= 0);
353 assert_se(slice_build_subslice(a
, "bar", &b
) >= 0);
355 assert_se(slice_build_subslice(b
, "barfoo", &a
) >= 0);
357 assert_se(slice_build_subslice(a
, "foobar", &b
) >= 0);
359 assert_se(streq(b
, "foo-bar-barfoo-foobar.slice"));
362 assert_se(slice_build_subslice("foo.service", "bar", &a
) < 0);
363 assert_se(slice_build_subslice("foo", "bar", &a
) < 0);
366 static void test_build_parent_slice_one(const char *name
, const char *expect
, int ret
) {
367 _cleanup_free_
char *s
= NULL
;
369 assert_se(slice_build_parent_slice(name
, &s
) == ret
);
370 assert_se(streq_ptr(s
, expect
));
373 static void test_build_parent_slice(void) {
374 test_build_parent_slice_one("-.slice", NULL
, 0);
375 test_build_parent_slice_one("foo.slice", "-.slice", 1);
376 test_build_parent_slice_one("foo-bar.slice", "foo.slice", 1);
377 test_build_parent_slice_one("foo-bar-baz.slice", "foo-bar.slice", 1);
378 test_build_parent_slice_one("foo-bar--baz.slice", NULL
, -EINVAL
);
379 test_build_parent_slice_one("-foo-bar.slice", NULL
, -EINVAL
);
380 test_build_parent_slice_one("foo-bar-.slice", NULL
, -EINVAL
);
381 test_build_parent_slice_one("foo-bar.service", NULL
, -EINVAL
);
382 test_build_parent_slice_one(".slice", NULL
, -EINVAL
);
385 static void test_unit_name_to_instance(void) {
389 r
= unit_name_to_instance("foo@bar.service", &instance
);
391 assert_se(streq(instance
, "bar"));
394 r
= unit_name_to_instance("foo@.service", &instance
);
396 assert_se(streq(instance
, ""));
399 r
= unit_name_to_instance("fo0-stUff_b@b.service", &instance
);
401 assert_se(streq(instance
, "b"));
404 r
= unit_name_to_instance("foo.service", &instance
);
406 assert_se(!instance
);
408 r
= unit_name_to_instance("fooj@unk", &instance
);
411 r
= unit_name_to_instance("foo@", &instance
);
415 static void test_unit_name_escape(void) {
416 _cleanup_free_
char *r
;
418 r
= unit_name_escape("ab+-c.a/bc@foo.service");
420 assert_se(streq(r
, "ab\\x2b\\x2dc.a-bc\\x40foo.service"));
424 static void test_u_n_t_one(const char *name
, const char *expected
, int ret
) {
425 _cleanup_free_
char *f
= NULL
;
427 assert_se(unit_name_template(name
, &f
) == ret
);
428 printf("got: %s, expected: %s\n", strna(f
), strna(expected
));
429 assert_se(streq_ptr(f
, expected
));
432 static void test_unit_name_template(void) {
433 test_u_n_t_one("foo@bar.service", "foo@.service", 0);
434 test_u_n_t_one("foo.mount", NULL
, -EINVAL
);
437 static void test_unit_name_path_unescape_one(const char *name
, const char *path
, int ret
) {
438 _cleanup_free_
char *p
= NULL
;
440 assert_se(unit_name_path_unescape(name
, &p
) == ret
);
441 assert_se(streq_ptr(path
, p
));
444 static void test_unit_name_path_unescape(void) {
446 test_unit_name_path_unescape_one("foo", "/foo", 0);
447 test_unit_name_path_unescape_one("foo-bar", "/foo/bar", 0);
448 test_unit_name_path_unescape_one("foo-.bar", "/foo/.bar", 0);
449 test_unit_name_path_unescape_one("foo-bar-baz", "/foo/bar/baz", 0);
450 test_unit_name_path_unescape_one("-", "/", 0);
451 test_unit_name_path_unescape_one("--", NULL
, -EINVAL
);
452 test_unit_name_path_unescape_one("-foo-bar", NULL
, -EINVAL
);
453 test_unit_name_path_unescape_one("foo--bar", NULL
, -EINVAL
);
454 test_unit_name_path_unescape_one("foo-bar-", NULL
, -EINVAL
);
455 test_unit_name_path_unescape_one(".-bar", NULL
, -EINVAL
);
456 test_unit_name_path_unescape_one("foo-..", NULL
, -EINVAL
);
457 test_unit_name_path_unescape_one("", NULL
, -EINVAL
);
460 int main(int argc
, char* argv
[]) {
462 test_unit_name_is_valid();
468 TEST_REQ_RUNNING_SYSTEMD(rc
= test_unit_printf());
469 test_unit_instance_is_valid();
470 test_unit_prefix_is_valid();
471 test_unit_name_change_suffix();
472 test_unit_name_build();
473 test_slice_name_is_valid();
474 test_build_subslice();
475 test_build_parent_slice();
476 test_unit_name_to_instance();
477 test_unit_name_escape();
478 test_unit_name_template();
479 test_unit_name_path_unescape();