]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/test/test-unit-name.c
util-lib: split out allocation calls into alloc-util.[ch]
[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 "util.h"
41
42 static void test_unit_name_is_valid(void) {
43 assert_se(unit_name_is_valid("foo.service", UNIT_NAME_ANY));
44 assert_se(unit_name_is_valid("foo.service", UNIT_NAME_PLAIN));
45 assert_se(!unit_name_is_valid("foo.service", UNIT_NAME_INSTANCE));
46 assert_se(!unit_name_is_valid("foo.service", UNIT_NAME_TEMPLATE));
47 assert_se(!unit_name_is_valid("foo.service", UNIT_NAME_INSTANCE|UNIT_NAME_TEMPLATE));
48
49 assert_se(unit_name_is_valid("foo@bar.service", UNIT_NAME_ANY));
50 assert_se(!unit_name_is_valid("foo@bar.service", UNIT_NAME_PLAIN));
51 assert_se(unit_name_is_valid("foo@bar.service", UNIT_NAME_INSTANCE));
52 assert_se(!unit_name_is_valid("foo@bar.service", UNIT_NAME_TEMPLATE));
53 assert_se(unit_name_is_valid("foo@bar.service", UNIT_NAME_INSTANCE|UNIT_NAME_TEMPLATE));
54
55 assert_se(unit_name_is_valid("foo@.service", UNIT_NAME_ANY));
56 assert_se(!unit_name_is_valid("foo@.service", UNIT_NAME_PLAIN));
57 assert_se(!unit_name_is_valid("foo@.service", UNIT_NAME_INSTANCE));
58 assert_se(unit_name_is_valid("foo@.service", UNIT_NAME_TEMPLATE));
59 assert_se(unit_name_is_valid("foo@.service", UNIT_NAME_INSTANCE|UNIT_NAME_TEMPLATE));
60
61 assert_se(!unit_name_is_valid(".service", UNIT_NAME_ANY));
62 assert_se(!unit_name_is_valid("", UNIT_NAME_ANY));
63 assert_se(!unit_name_is_valid("foo.waldo", UNIT_NAME_ANY));
64 assert_se(!unit_name_is_valid("@.service", UNIT_NAME_ANY));
65 assert_se(!unit_name_is_valid("@piep.service", UNIT_NAME_ANY));
66 }
67
68 static void test_u_n_r_i_one(const char *pattern, const char *repl, const char *expected, int ret) {
69 _cleanup_free_ char *t = NULL;
70 assert_se(unit_name_replace_instance(pattern, repl, &t) == ret);
71 puts(strna(t));
72 assert_se(streq_ptr(t, expected));
73 }
74
75 static void test_u_n_r_i(void) {
76 puts("-------------------------------------------------");
77 test_u_n_r_i_one("foo@.service", "waldo", "foo@waldo.service", 0);
78 test_u_n_r_i_one("foo@xyz.service", "waldo", "foo@waldo.service", 0);
79 test_u_n_r_i_one("xyz", "waldo", NULL, -EINVAL);
80 test_u_n_r_i_one("", "waldo", NULL, -EINVAL);
81 test_u_n_r_i_one("foo.service", "waldo", NULL, -EINVAL);
82 test_u_n_r_i_one(".service", "waldo", NULL, -EINVAL);
83 test_u_n_r_i_one("foo@", "waldo", NULL, -EINVAL);
84 test_u_n_r_i_one("@bar", "waldo", NULL, -EINVAL);
85 }
86
87 static void test_u_n_f_p_one(const char *path, const char *suffix, const char *expected, int ret) {
88 _cleanup_free_ char *t = NULL;
89
90 assert_se(unit_name_from_path(path, suffix, &t) == ret);
91 puts(strna(t));
92 assert_se(streq_ptr(t, expected));
93
94 if (t) {
95 _cleanup_free_ char *k = NULL;
96 assert_se(unit_name_to_path(t, &k) == 0);
97 puts(strna(k));
98 assert_se(path_equal(k, isempty(path) ? "/" : path));
99 }
100 }
101
102 static void test_u_n_f_p(void) {
103 puts("-------------------------------------------------");
104 test_u_n_f_p_one("/waldo", ".mount", "waldo.mount", 0);
105 test_u_n_f_p_one("/waldo/quuix", ".mount", "waldo-quuix.mount", 0);
106 test_u_n_f_p_one("/waldo/quuix/", ".mount", "waldo-quuix.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("///", ".mount", "-.mount", 0);
110 test_u_n_f_p_one("/foo/../bar", ".mount", NULL, -EINVAL);
111 test_u_n_f_p_one("/foo/./bar", ".mount", NULL, -EINVAL);
112 }
113
114 static void test_u_n_f_p_i_one(const char *pattern, const char *path, const char *suffix, const char *expected, int ret) {
115 _cleanup_free_ char *t = NULL;
116
117 assert_se(unit_name_from_path_instance(pattern, path, suffix, &t) == ret);
118 puts(strna(t));
119 assert_se(streq_ptr(t, expected));
120
121 if (t) {
122 _cleanup_free_ char *k = NULL, *v = NULL;
123
124 assert_se(unit_name_to_instance(t, &k) > 0);
125 assert_se(unit_name_path_unescape(k, &v) == 0);
126 assert_se(path_equal(v, isempty(path) ? "/" : path));
127 }
128 }
129
130 static void test_u_n_f_p_i(void) {
131 puts("-------------------------------------------------");
132
133 test_u_n_f_p_i_one("waldo", "/waldo", ".mount", "waldo@waldo.mount", 0);
134 test_u_n_f_p_i_one("waldo", "/waldo////quuix////", ".mount", "waldo@waldo-quuix.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", "waldo@-.mount", 0);
138 test_u_n_f_p_i_one("waldo", "..", ".mount", NULL, -EINVAL);
139 test_u_n_f_p_i_one("waldo", "/foo", ".waldi", NULL, -EINVAL);
140 test_u_n_f_p_i_one("wa--ldo", "/--", ".mount", "wa--ldo@\\x2d\\x2d.mount", 0);
141 }
142
143 static void test_u_n_t_p_one(const char *unit, const char *path, int ret) {
144 _cleanup_free_ char *p = NULL;
145
146 assert_se(unit_name_to_path(unit, &p) == ret);
147 assert_se(streq_ptr(path, p));
148 }
149
150 static void test_u_n_t_p(void) {
151 test_u_n_t_p_one("home.mount", "/home", 0);
152 test_u_n_t_p_one("home-lennart.mount", "/home/lennart", 0);
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("home-..-lennart.mount", NULL, -EINVAL);
157 test_u_n_t_p_one("", NULL, -EINVAL);
158 test_u_n_t_p_one("home/foo", NULL, -EINVAL);
159 }
160
161 static void test_u_n_m_one(const char *pattern, const char *expect, int ret) {
162 _cleanup_free_ char *t = NULL;
163
164 assert_se(unit_name_mangle(pattern, UNIT_NAME_NOGLOB, &t) == ret);
165 puts(strna(t));
166 assert_se(streq_ptr(t, expect));
167
168 if (t) {
169 _cleanup_free_ char *k = NULL;
170
171 assert_se(unit_name_is_valid(t, UNIT_NAME_ANY));
172
173 assert_se(unit_name_mangle(t, UNIT_NAME_NOGLOB, &k) == 0);
174 assert_se(streq_ptr(t, k));
175 }
176 }
177
178 static void test_u_n_m(void) {
179 puts("-------------------------------------------------");
180 test_u_n_m_one("foo.service", "foo.service", 0);
181 test_u_n_m_one("/home", "home.mount", 1);
182 test_u_n_m_one("/dev/sda", "dev-sda.device", 1);
183 test_u_n_m_one("üxknürz.service", "\\xc3\\xbcxkn\\xc3\\xbcrz.service", 1);
184 test_u_n_m_one("foobar-meh...waldi.service", "foobar-meh...waldi.service", 0);
185 test_u_n_m_one("_____####----.....service", "_____\\x23\\x23\\x23\\x23----.....service", 1);
186 test_u_n_m_one("_____##@;;;,,,##----.....service", "_____\\x23\\x23@\\x3b\\x3b\\x3b\\x2c\\x2c\\x2c\\x23\\x23----.....service", 1);
187 test_u_n_m_one("xxx@@@@/////\\\\\\\\\\yyy.service", "xxx@@@@-----\\\\\\\\\\yyy.service", 1);
188 test_u_n_m_one("", NULL, -EINVAL);
189 }
190
191 static int test_unit_printf(void) {
192 Manager *m = NULL;
193 Unit *u, *u2;
194 int r;
195
196 _cleanup_free_ char *mid, *bid, *host, *root_uid;
197 struct passwd *root;
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
203 assert_se((root = getpwnam("root")));
204 assert_se(asprintf(&root_uid, "%d", (int) root->pw_uid) > 0);
205
206 r = manager_new(MANAGER_USER, true, &m);
207 if (r == -EPERM || r == -EACCES || r == -EADDRINUSE) {
208 puts("manager_new: Permission denied. Skipping test.");
209 return EXIT_TEST_SKIP;
210 }
211 assert_se(r == 0);
212
213 #define expect(unit, pattern, expected) \
214 { \
215 char *e; \
216 _cleanup_free_ char *t = NULL; \
217 assert_se(unit_full_printf(unit, pattern, &t) >= 0); \
218 printf("result: %s\nexpect: %s\n", t, expected); \
219 if ((e = endswith(expected, "*"))) \
220 assert_se(strncmp(t, e, e-expected)); \
221 else \
222 assert_se(streq(t, expected)); \
223 }
224
225 assert_se(setenv("USER", "root", 1) == 0);
226 assert_se(setenv("HOME", "/root", 1) == 0);
227 assert_se(setenv("XDG_RUNTIME_DIR", "/run/user/1/", 1) == 0);
228
229 assert_se(u = unit_new(m, sizeof(Service)));
230 assert_se(unit_add_name(u, "blah.service") == 0);
231 assert_se(unit_add_name(u, "blah.service") == 0);
232
233 /* general tests */
234 expect(u, "%%", "%");
235 expect(u, "%%s", "%s");
236 expect(u, "%", ""); // REALLY?
237
238 /* normal unit */
239 expect(u, "%n", "blah.service");
240 expect(u, "%f", "/blah");
241 expect(u, "%N", "blah");
242 expect(u, "%p", "blah");
243 expect(u, "%P", "blah");
244 expect(u, "%i", "");
245 expect(u, "%u", root->pw_name);
246 expect(u, "%U", root_uid);
247 expect(u, "%h", root->pw_dir);
248 expect(u, "%m", mid);
249 expect(u, "%b", bid);
250 expect(u, "%H", host);
251 expect(u, "%t", "/run/user/*");
252
253 /* templated */
254 assert_se(u2 = unit_new(m, sizeof(Service)));
255 assert_se(unit_add_name(u2, "blah@foo-foo.service") == 0);
256 assert_se(unit_add_name(u2, "blah@foo-foo.service") == 0);
257
258 expect(u2, "%n", "blah@foo-foo.service");
259 expect(u2, "%N", "blah@foo-foo");
260 expect(u2, "%f", "/foo/foo");
261 expect(u2, "%p", "blah");
262 expect(u2, "%P", "blah");
263 expect(u2, "%i", "foo-foo");
264 expect(u2, "%I", "foo/foo");
265 expect(u2, "%u", root->pw_name);
266 expect(u2, "%U", root_uid);
267 expect(u2, "%h", root->pw_dir);
268 expect(u2, "%m", mid);
269 expect(u2, "%b", bid);
270 expect(u2, "%H", host);
271 expect(u2, "%t", "/run/user/*");
272
273 manager_free(m);
274 #undef expect
275
276 return 0;
277 }
278
279 static void test_unit_instance_is_valid(void) {
280 assert_se(unit_instance_is_valid("fooBar"));
281 assert_se(unit_instance_is_valid("foo-bar"));
282 assert_se(unit_instance_is_valid("foo.stUff"));
283 assert_se(unit_instance_is_valid("fOo123.stuff"));
284 assert_se(unit_instance_is_valid("@f_oo123.Stuff"));
285
286 assert_se(!unit_instance_is_valid("$¢£"));
287 assert_se(!unit_instance_is_valid(""));
288 assert_se(!unit_instance_is_valid("foo bar"));
289 assert_se(!unit_instance_is_valid("foo/bar"));
290 }
291
292 static void test_unit_prefix_is_valid(void) {
293 assert_se(unit_prefix_is_valid("fooBar"));
294 assert_se(unit_prefix_is_valid("foo-bar"));
295 assert_se(unit_prefix_is_valid("foo.stUff"));
296 assert_se(unit_prefix_is_valid("fOo123.stuff"));
297 assert_se(unit_prefix_is_valid("foo123.Stuff"));
298
299 assert_se(!unit_prefix_is_valid("$¢£"));
300 assert_se(!unit_prefix_is_valid(""));
301 assert_se(!unit_prefix_is_valid("foo bar"));
302 assert_se(!unit_prefix_is_valid("foo/bar"));
303 assert_se(!unit_prefix_is_valid("@foo-bar"));
304 }
305
306 static void test_unit_name_change_suffix(void) {
307 char *t;
308
309 assert_se(unit_name_change_suffix("foo.mount", ".service", &t) == 0);
310 assert_se(streq(t, "foo.service"));
311 free(t);
312
313 assert_se(unit_name_change_suffix("foo@stuff.service", ".socket", &t) == 0);
314 assert_se(streq(t, "foo@stuff.socket"));
315 free(t);
316 }
317
318 static void test_unit_name_build(void) {
319 char *t;
320
321 assert_se(unit_name_build("foo", "bar", ".service", &t) == 0);
322 assert_se(streq(t, "foo@bar.service"));
323 free(t);
324
325 assert_se(unit_name_build("fo0-stUff_b", "bar", ".mount", &t) == 0);
326 assert_se(streq(t, "fo0-stUff_b@bar.mount"));
327 free(t);
328
329 assert_se(unit_name_build("foo", NULL, ".service", &t) == 0);
330 assert_se(streq(t, "foo.service"));
331 free(t);
332 }
333
334 static void test_slice_name_is_valid(void) {
335 assert_se(slice_name_is_valid("-.slice"));
336 assert_se(slice_name_is_valid("foo.slice"));
337 assert_se(slice_name_is_valid("foo-bar.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("foo--bar--baz.slice"));
344 assert_se(!slice_name_is_valid(".slice"));
345 assert_se(!slice_name_is_valid(""));
346 assert_se(!slice_name_is_valid("foo.service"));
347 }
348
349 static void test_build_subslice(void) {
350 char *a;
351 char *b;
352
353 assert_se(slice_build_subslice("-.slice", "foo", &a) >= 0);
354 assert_se(slice_build_subslice(a, "bar", &b) >= 0);
355 free(a);
356 assert_se(slice_build_subslice(b, "barfoo", &a) >= 0);
357 free(b);
358 assert_se(slice_build_subslice(a, "foobar", &b) >= 0);
359 free(a);
360 assert_se(streq(b, "foo-bar-barfoo-foobar.slice"));
361 free(b);
362
363 assert_se(slice_build_subslice("foo.service", "bar", &a) < 0);
364 assert_se(slice_build_subslice("foo", "bar", &a) < 0);
365 }
366
367 static void test_build_parent_slice_one(const char *name, const char *expect, int ret) {
368 _cleanup_free_ char *s = NULL;
369
370 assert_se(slice_build_parent_slice(name, &s) == ret);
371 assert_se(streq_ptr(s, expect));
372 }
373
374 static void test_build_parent_slice(void) {
375 test_build_parent_slice_one("-.slice", NULL, 0);
376 test_build_parent_slice_one("foo.slice", "-.slice", 1);
377 test_build_parent_slice_one("foo-bar.slice", "foo.slice", 1);
378 test_build_parent_slice_one("foo-bar-baz.slice", "foo-bar.slice", 1);
379 test_build_parent_slice_one("foo-bar--baz.slice", NULL, -EINVAL);
380 test_build_parent_slice_one("-foo-bar.slice", NULL, -EINVAL);
381 test_build_parent_slice_one("foo-bar-.slice", NULL, -EINVAL);
382 test_build_parent_slice_one("foo-bar.service", NULL, -EINVAL);
383 test_build_parent_slice_one(".slice", NULL, -EINVAL);
384 }
385
386 static void test_unit_name_to_instance(void) {
387 char *instance;
388 int r;
389
390 r = unit_name_to_instance("foo@bar.service", &instance);
391 assert_se(r >= 0);
392 assert_se(streq(instance, "bar"));
393 free(instance);
394
395 r = unit_name_to_instance("foo@.service", &instance);
396 assert_se(r >= 0);
397 assert_se(streq(instance, ""));
398 free(instance);
399
400 r = unit_name_to_instance("fo0-stUff_b@b.service", &instance);
401 assert_se(r >= 0);
402 assert_se(streq(instance, "b"));
403 free(instance);
404
405 r = unit_name_to_instance("foo.service", &instance);
406 assert_se(r == 0);
407 assert_se(!instance);
408
409 r = unit_name_to_instance("fooj@unk", &instance);
410 assert_se(r < 0);
411
412 r = unit_name_to_instance("foo@", &instance);
413 assert_se(r < 0);
414 }
415
416 static void test_unit_name_escape(void) {
417 _cleanup_free_ char *r;
418
419 r = unit_name_escape("ab+-c.a/bc@foo.service");
420 assert_se(r);
421 assert_se(streq(r, "ab\\x2b\\x2dc.a-bc\\x40foo.service"));
422 }
423
424
425 static void test_u_n_t_one(const char *name, const char *expected, int ret) {
426 _cleanup_free_ char *f = NULL;
427
428 assert_se(unit_name_template(name, &f) == ret);
429 printf("got: %s, expected: %s\n", strna(f), strna(expected));
430 assert_se(streq_ptr(f, expected));
431 }
432
433 static void test_unit_name_template(void) {
434 test_u_n_t_one("foo@bar.service", "foo@.service", 0);
435 test_u_n_t_one("foo.mount", NULL, -EINVAL);
436 }
437
438 static void test_unit_name_path_unescape_one(const char *name, const char *path, int ret) {
439 _cleanup_free_ char *p = NULL;
440
441 assert_se(unit_name_path_unescape(name, &p) == ret);
442 assert_se(streq_ptr(path, p));
443 }
444
445 static void test_unit_name_path_unescape(void) {
446
447 test_unit_name_path_unescape_one("foo", "/foo", 0);
448 test_unit_name_path_unescape_one("foo-bar", "/foo/bar", 0);
449 test_unit_name_path_unescape_one("foo-.bar", "/foo/.bar", 0);
450 test_unit_name_path_unescape_one("foo-bar-baz", "/foo/bar/baz", 0);
451 test_unit_name_path_unescape_one("-", "/", 0);
452 test_unit_name_path_unescape_one("--", 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("foo-bar-", NULL, -EINVAL);
456 test_unit_name_path_unescape_one(".-bar", NULL, -EINVAL);
457 test_unit_name_path_unescape_one("foo-..", NULL, -EINVAL);
458 test_unit_name_path_unescape_one("", NULL, -EINVAL);
459 }
460
461 int main(int argc, char* argv[]) {
462 int rc = 0;
463 test_unit_name_is_valid();
464 test_u_n_r_i();
465 test_u_n_f_p();
466 test_u_n_f_p_i();
467 test_u_n_m();
468 test_u_n_t_p();
469 TEST_REQ_RUNNING_SYSTEMD(rc = test_unit_printf());
470 test_unit_instance_is_valid();
471 test_unit_prefix_is_valid();
472 test_unit_name_change_suffix();
473 test_unit_name_build();
474 test_slice_name_is_valid();
475 test_build_subslice();
476 test_build_parent_slice();
477 test_unit_name_to_instance();
478 test_unit_name_escape();
479 test_unit_name_template();
480 test_unit_name_path_unescape();
481
482 return rc;
483 }