]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/test/test-unit-name.c
Merge pull request #1359 from jengelh/ue
[thirdparty/systemd.git] / src / test / test-unit-name.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2012 Lennart Poettering
7 Copyright 2013 Zbigniew Jędrzejewski-Szmek
8 Copyright 2014 Ronny Chevalier
9
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.
14
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.
19
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/>.
22 ***/
23
24 #include <pwd.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28
29 #include "alloc-util.h"
30 #include "hostname-util.h"
31 #include "macro.h"
32 #include "manager.h"
33 #include "path-util.h"
34 #include "specifier.h"
35 #include "string-util.h"
36 #include "test-helper.h"
37 #include "unit-name.h"
38 #include "unit-printf.h"
39 #include "unit.h"
40 #include "user-util.h"
41 #include "util.h"
42
43 static void test_unit_name_is_valid(void) {
44 assert_se(unit_name_is_valid("foo.service", UNIT_NAME_ANY));
45 assert_se(unit_name_is_valid("foo.service", UNIT_NAME_PLAIN));
46 assert_se(!unit_name_is_valid("foo.service", UNIT_NAME_INSTANCE));
47 assert_se(!unit_name_is_valid("foo.service", UNIT_NAME_TEMPLATE));
48 assert_se(!unit_name_is_valid("foo.service", UNIT_NAME_INSTANCE|UNIT_NAME_TEMPLATE));
49
50 assert_se(unit_name_is_valid("foo@bar.service", UNIT_NAME_ANY));
51 assert_se(!unit_name_is_valid("foo@bar.service", UNIT_NAME_PLAIN));
52 assert_se(unit_name_is_valid("foo@bar.service", UNIT_NAME_INSTANCE));
53 assert_se(!unit_name_is_valid("foo@bar.service", UNIT_NAME_TEMPLATE));
54 assert_se(unit_name_is_valid("foo@bar.service", UNIT_NAME_INSTANCE|UNIT_NAME_TEMPLATE));
55
56 assert_se(unit_name_is_valid("foo@.service", UNIT_NAME_ANY));
57 assert_se(!unit_name_is_valid("foo@.service", UNIT_NAME_PLAIN));
58 assert_se(!unit_name_is_valid("foo@.service", UNIT_NAME_INSTANCE));
59 assert_se(unit_name_is_valid("foo@.service", UNIT_NAME_TEMPLATE));
60 assert_se(unit_name_is_valid("foo@.service", UNIT_NAME_INSTANCE|UNIT_NAME_TEMPLATE));
61
62 assert_se(!unit_name_is_valid(".service", UNIT_NAME_ANY));
63 assert_se(!unit_name_is_valid("", UNIT_NAME_ANY));
64 assert_se(!unit_name_is_valid("foo.waldo", UNIT_NAME_ANY));
65 assert_se(!unit_name_is_valid("@.service", UNIT_NAME_ANY));
66 assert_se(!unit_name_is_valid("@piep.service", UNIT_NAME_ANY));
67 }
68
69 static void test_u_n_r_i_one(const char *pattern, const char *repl, const char *expected, int ret) {
70 _cleanup_free_ char *t = NULL;
71 assert_se(unit_name_replace_instance(pattern, repl, &t) == ret);
72 puts(strna(t));
73 assert_se(streq_ptr(t, expected));
74 }
75
76 static void test_u_n_r_i(void) {
77 puts("-------------------------------------------------");
78 test_u_n_r_i_one("foo@.service", "waldo", "foo@waldo.service", 0);
79 test_u_n_r_i_one("foo@xyz.service", "waldo", "foo@waldo.service", 0);
80 test_u_n_r_i_one("xyz", "waldo", NULL, -EINVAL);
81 test_u_n_r_i_one("", "waldo", NULL, -EINVAL);
82 test_u_n_r_i_one("foo.service", "waldo", NULL, -EINVAL);
83 test_u_n_r_i_one(".service", "waldo", NULL, -EINVAL);
84 test_u_n_r_i_one("foo@", "waldo", NULL, -EINVAL);
85 test_u_n_r_i_one("@bar", "waldo", NULL, -EINVAL);
86 }
87
88 static void test_u_n_f_p_one(const char *path, const char *suffix, const char *expected, int ret) {
89 _cleanup_free_ char *t = NULL;
90
91 assert_se(unit_name_from_path(path, suffix, &t) == ret);
92 puts(strna(t));
93 assert_se(streq_ptr(t, expected));
94
95 if (t) {
96 _cleanup_free_ char *k = NULL;
97 assert_se(unit_name_to_path(t, &k) == 0);
98 puts(strna(k));
99 assert_se(path_equal(k, isempty(path) ? "/" : path));
100 }
101 }
102
103 static void test_u_n_f_p(void) {
104 puts("-------------------------------------------------");
105 test_u_n_f_p_one("/waldo", ".mount", "waldo.mount", 0);
106 test_u_n_f_p_one("/waldo/quuix", ".mount", "waldo-quuix.mount", 0);
107 test_u_n_f_p_one("/waldo/quuix/", ".mount", "waldo-quuix.mount", 0);
108 test_u_n_f_p_one("", ".mount", "-.mount", 0);
109 test_u_n_f_p_one("/", ".mount", "-.mount", 0);
110 test_u_n_f_p_one("///", ".mount", "-.mount", 0);
111 test_u_n_f_p_one("/foo/../bar", ".mount", NULL, -EINVAL);
112 test_u_n_f_p_one("/foo/./bar", ".mount", NULL, -EINVAL);
113 }
114
115 static void test_u_n_f_p_i_one(const char *pattern, const char *path, const char *suffix, const char *expected, int ret) {
116 _cleanup_free_ char *t = NULL;
117
118 assert_se(unit_name_from_path_instance(pattern, path, suffix, &t) == ret);
119 puts(strna(t));
120 assert_se(streq_ptr(t, expected));
121
122 if (t) {
123 _cleanup_free_ char *k = NULL, *v = NULL;
124
125 assert_se(unit_name_to_instance(t, &k) > 0);
126 assert_se(unit_name_path_unescape(k, &v) == 0);
127 assert_se(path_equal(v, isempty(path) ? "/" : path));
128 }
129 }
130
131 static void test_u_n_f_p_i(void) {
132 puts("-------------------------------------------------");
133
134 test_u_n_f_p_i_one("waldo", "/waldo", ".mount", "waldo@waldo.mount", 0);
135 test_u_n_f_p_i_one("waldo", "/waldo////quuix////", ".mount", "waldo@waldo-quuix.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", "waldo@-.mount", 0);
138 test_u_n_f_p_i_one("waldo", "///", ".mount", "waldo@-.mount", 0);
139 test_u_n_f_p_i_one("waldo", "..", ".mount", NULL, -EINVAL);
140 test_u_n_f_p_i_one("waldo", "/foo", ".waldi", NULL, -EINVAL);
141 test_u_n_f_p_i_one("wa--ldo", "/--", ".mount", "wa--ldo@\\x2d\\x2d.mount", 0);
142 }
143
144 static void test_u_n_t_p_one(const char *unit, const char *path, int ret) {
145 _cleanup_free_ char *p = NULL;
146
147 assert_se(unit_name_to_path(unit, &p) == ret);
148 assert_se(streq_ptr(path, p));
149 }
150
151 static void test_u_n_t_p(void) {
152 test_u_n_t_p_one("home.mount", "/home", 0);
153 test_u_n_t_p_one("home-lennart.mount", "/home/lennart", 0);
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("-home--lennart.mount", NULL, -EINVAL);
157 test_u_n_t_p_one("home-..-lennart.mount", NULL, -EINVAL);
158 test_u_n_t_p_one("", NULL, -EINVAL);
159 test_u_n_t_p_one("home/foo", NULL, -EINVAL);
160 }
161
162 static void test_u_n_m_one(const char *pattern, const char *expect, int ret) {
163 _cleanup_free_ char *t = NULL;
164
165 assert_se(unit_name_mangle(pattern, UNIT_NAME_NOGLOB, &t) == ret);
166 puts(strna(t));
167 assert_se(streq_ptr(t, expect));
168
169 if (t) {
170 _cleanup_free_ char *k = NULL;
171
172 assert_se(unit_name_is_valid(t, UNIT_NAME_ANY));
173
174 assert_se(unit_name_mangle(t, UNIT_NAME_NOGLOB, &k) == 0);
175 assert_se(streq_ptr(t, k));
176 }
177 }
178
179 static void test_u_n_m(void) {
180 puts("-------------------------------------------------");
181 test_u_n_m_one("foo.service", "foo.service", 0);
182 test_u_n_m_one("/home", "home.mount", 1);
183 test_u_n_m_one("/dev/sda", "dev-sda.device", 1);
184 test_u_n_m_one("üxknürz.service", "\\xc3\\xbcxkn\\xc3\\xbcrz.service", 1);
185 test_u_n_m_one("foobar-meh...waldi.service", "foobar-meh...waldi.service", 0);
186 test_u_n_m_one("_____####----.....service", "_____\\x23\\x23\\x23\\x23----.....service", 1);
187 test_u_n_m_one("_____##@;;;,,,##----.....service", "_____\\x23\\x23@\\x3b\\x3b\\x3b\\x2c\\x2c\\x2c\\x23\\x23----.....service", 1);
188 test_u_n_m_one("xxx@@@@/////\\\\\\\\\\yyy.service", "xxx@@@@-----\\\\\\\\\\yyy.service", 1);
189 test_u_n_m_one("", NULL, -EINVAL);
190 }
191
192 static int test_unit_printf(void) {
193 Manager *m = NULL;
194 Unit *u, *u2;
195 int r;
196
197 _cleanup_free_ char *mid = NULL, *bid = NULL, *host = NULL, *uid = NULL, *user = NULL, *shell = NULL, *home = NULL;
198
199 assert_se(specifier_machine_id('m', NULL, NULL, &mid) >= 0 && mid);
200 assert_se(specifier_boot_id('b', NULL, NULL, &bid) >= 0 && bid);
201 assert_se(host = gethostname_malloc());
202 assert_se(user = getusername_malloc());
203 assert_se(asprintf(&uid, UID_FMT, getuid()));
204 assert_se(get_home_dir(&home) >= 0);
205 assert_se(get_shell(&shell) >= 0);
206
207 r = manager_new(MANAGER_USER, true, &m);
208 if (r == -EPERM || r == -EACCES || r == -EADDRINUSE) {
209 puts("manager_new: Permission denied. Skipping test.");
210 return EXIT_TEST_SKIP;
211 }
212 assert_se(r == 0);
213
214 #define expect(unit, pattern, expected) \
215 { \
216 char *e; \
217 _cleanup_free_ char *t = NULL; \
218 assert_se(unit_full_printf(unit, pattern, &t) >= 0); \
219 printf("result: %s\nexpect: %s\n", t, expected); \
220 if ((e = endswith(expected, "*"))) \
221 assert_se(strncmp(t, e, e-expected)); \
222 else \
223 assert_se(streq(t, expected)); \
224 }
225
226 assert_se(setenv("XDG_RUNTIME_DIR", "/run/user/1/", 1) == 0);
227
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);
231
232 /* general tests */
233 expect(u, "%%", "%");
234 expect(u, "%%s", "%s");
235 expect(u, "%", ""); // REALLY?
236
237 /* normal unit */
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");
243 expect(u, "%i", "");
244 expect(u, "%u", user);
245 expect(u, "%U", uid);
246 expect(u, "%h", home);
247 expect(u, "%m", mid);
248 expect(u, "%b", bid);
249 expect(u, "%H", host);
250 expect(u, "%t", "/run/user/*");
251
252 /* templated */
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);
256
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", user);
265 expect(u2, "%U", uid);
266 expect(u2, "%h", home);
267 expect(u2, "%m", mid);
268 expect(u2, "%b", bid);
269 expect(u2, "%H", host);
270 expect(u2, "%t", "/run/user/*");
271
272 manager_free(m);
273 #undef expect
274
275 return 0;
276 }
277
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"));
284
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"));
289 }
290
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"));
297
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"));
303 }
304
305 static void test_unit_name_change_suffix(void) {
306 char *t;
307
308 assert_se(unit_name_change_suffix("foo.mount", ".service", &t) == 0);
309 assert_se(streq(t, "foo.service"));
310 free(t);
311
312 assert_se(unit_name_change_suffix("foo@stuff.service", ".socket", &t) == 0);
313 assert_se(streq(t, "foo@stuff.socket"));
314 free(t);
315 }
316
317 static void test_unit_name_build(void) {
318 char *t;
319
320 assert_se(unit_name_build("foo", "bar", ".service", &t) == 0);
321 assert_se(streq(t, "foo@bar.service"));
322 free(t);
323
324 assert_se(unit_name_build("fo0-stUff_b", "bar", ".mount", &t) == 0);
325 assert_se(streq(t, "fo0-stUff_b@bar.mount"));
326 free(t);
327
328 assert_se(unit_name_build("foo", NULL, ".service", &t) == 0);
329 assert_se(streq(t, "foo.service"));
330 free(t);
331 }
332
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"));
346 }
347
348 static void test_build_subslice(void) {
349 char *a;
350 char *b;
351
352 assert_se(slice_build_subslice("-.slice", "foo", &a) >= 0);
353 assert_se(slice_build_subslice(a, "bar", &b) >= 0);
354 free(a);
355 assert_se(slice_build_subslice(b, "barfoo", &a) >= 0);
356 free(b);
357 assert_se(slice_build_subslice(a, "foobar", &b) >= 0);
358 free(a);
359 assert_se(streq(b, "foo-bar-barfoo-foobar.slice"));
360 free(b);
361
362 assert_se(slice_build_subslice("foo.service", "bar", &a) < 0);
363 assert_se(slice_build_subslice("foo", "bar", &a) < 0);
364 }
365
366 static void test_build_parent_slice_one(const char *name, const char *expect, int ret) {
367 _cleanup_free_ char *s = NULL;
368
369 assert_se(slice_build_parent_slice(name, &s) == ret);
370 assert_se(streq_ptr(s, expect));
371 }
372
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);
383 }
384
385 static void test_unit_name_to_instance(void) {
386 char *instance;
387 int r;
388
389 r = unit_name_to_instance("foo@bar.service", &instance);
390 assert_se(r >= 0);
391 assert_se(streq(instance, "bar"));
392 free(instance);
393
394 r = unit_name_to_instance("foo@.service", &instance);
395 assert_se(r >= 0);
396 assert_se(streq(instance, ""));
397 free(instance);
398
399 r = unit_name_to_instance("fo0-stUff_b@b.service", &instance);
400 assert_se(r >= 0);
401 assert_se(streq(instance, "b"));
402 free(instance);
403
404 r = unit_name_to_instance("foo.service", &instance);
405 assert_se(r == 0);
406 assert_se(!instance);
407
408 r = unit_name_to_instance("fooj@unk", &instance);
409 assert_se(r < 0);
410
411 r = unit_name_to_instance("foo@", &instance);
412 assert_se(r < 0);
413 }
414
415 static void test_unit_name_escape(void) {
416 _cleanup_free_ char *r;
417
418 r = unit_name_escape("ab+-c.a/bc@foo.service");
419 assert_se(r);
420 assert_se(streq(r, "ab\\x2b\\x2dc.a-bc\\x40foo.service"));
421 }
422
423
424 static void test_u_n_t_one(const char *name, const char *expected, int ret) {
425 _cleanup_free_ char *f = NULL;
426
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));
430 }
431
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);
435 }
436
437 static void test_unit_name_path_unescape_one(const char *name, const char *path, int ret) {
438 _cleanup_free_ char *p = NULL;
439
440 assert_se(unit_name_path_unescape(name, &p) == ret);
441 assert_se(streq_ptr(path, p));
442 }
443
444 static void test_unit_name_path_unescape(void) {
445
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);
458 }
459
460 int main(int argc, char* argv[]) {
461 int rc = 0;
462 test_unit_name_is_valid();
463 test_u_n_r_i();
464 test_u_n_f_p();
465 test_u_n_f_p_i();
466 test_u_n_m();
467 test_u_n_t_p();
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();
480
481 return rc;
482 }