]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/test/test-install-root.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
5 #include "alloc-util.h"
12 #include "string-util.h"
15 static void test_basic_mask_and_enable(const char *root
) {
18 UnitFileChange
*changes
= NULL
;
21 test_setup_logging(LOG_DEBUG
);
23 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "a.service", NULL
) == -ENOENT
);
24 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "b.service", NULL
) == -ENOENT
);
25 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "c.service", NULL
) == -ENOENT
);
26 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "d.service", NULL
) == -ENOENT
);
27 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "e.service", NULL
) == -ENOENT
);
29 p
= strjoina(root
, "/usr/lib/systemd/system/a.service");
30 assert_se(write_string_file(p
,
32 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
34 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "a.service", NULL
) >= 0);
35 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "a.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
37 p
= strjoina(root
, "/usr/lib/systemd/system/b.service");
38 assert_se(symlink("a.service", p
) >= 0);
40 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "b.service", NULL
) >= 0);
41 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "b.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
43 p
= strjoina(root
, "/usr/lib/systemd/system/c.service");
44 assert_se(symlink("/usr/lib/systemd/system/a.service", p
) >= 0);
46 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "c.service", NULL
) >= 0);
47 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "c.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
49 p
= strjoina(root
, "/usr/lib/systemd/system/d.service");
50 assert_se(symlink("c.service", p
) >= 0);
52 /* This one is interesting, as d follows a relative, then an absolute symlink */
53 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "d.service", NULL
) >= 0);
54 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "d.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
56 assert_se(unit_file_mask(UNIT_FILE_SYSTEM
, 0, root
, STRV_MAKE("a.service"), &changes
, &n_changes
) >= 0);
57 assert_se(n_changes
== 1);
58 assert_se(changes
[0].type
== UNIT_FILE_SYMLINK
);
59 assert_se(streq(changes
[0].source
, "/dev/null"));
60 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/a.service");
61 assert_se(streq(changes
[0].path
, p
));
63 unit_file_changes_free(changes
, n_changes
);
64 changes
= NULL
; n_changes
= 0;
66 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "a.service", &state
) >= 0 && state
== UNIT_FILE_MASKED
);
67 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "b.service", &state
) >= 0 && state
== UNIT_FILE_MASKED
);
68 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "c.service", &state
) >= 0 && state
== UNIT_FILE_MASKED
);
69 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "d.service", &state
) >= 0 && state
== UNIT_FILE_MASKED
);
71 /* Enabling a masked unit should fail! */
72 assert_se(unit_file_enable(UNIT_FILE_SYSTEM
, 0, root
, STRV_MAKE("a.service"), &changes
, &n_changes
) == -ERFKILL
);
73 unit_file_changes_free(changes
, n_changes
);
74 changes
= NULL
; n_changes
= 0;
76 assert_se(unit_file_unmask(UNIT_FILE_SYSTEM
, 0, root
, STRV_MAKE("a.service"), &changes
, &n_changes
) >= 0);
77 assert_se(n_changes
== 1);
78 assert_se(changes
[0].type
== UNIT_FILE_UNLINK
);
79 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/a.service");
80 assert_se(streq(changes
[0].path
, p
));
81 unit_file_changes_free(changes
, n_changes
);
82 changes
= NULL
; n_changes
= 0;
84 assert_se(unit_file_enable(UNIT_FILE_SYSTEM
, 0, root
, STRV_MAKE("a.service"), &changes
, &n_changes
) == 1);
85 assert_se(n_changes
== 1);
86 assert_se(changes
[0].type
== UNIT_FILE_SYMLINK
);
87 assert_se(streq(changes
[0].source
, "/usr/lib/systemd/system/a.service"));
88 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/a.service");
89 assert_se(streq(changes
[0].path
, p
));
90 unit_file_changes_free(changes
, n_changes
);
91 changes
= NULL
; n_changes
= 0;
93 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "a.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
94 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "b.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
95 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "c.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
96 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "d.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
98 /* Enabling it again should succeed but be a NOP */
99 assert_se(unit_file_enable(UNIT_FILE_SYSTEM
, 0, root
, STRV_MAKE("a.service"), &changes
, &n_changes
) >= 0);
100 assert_se(n_changes
== 0);
101 unit_file_changes_free(changes
, n_changes
);
102 changes
= NULL
; n_changes
= 0;
104 assert_se(unit_file_disable(UNIT_FILE_SYSTEM
, 0, root
, STRV_MAKE("a.service"), &changes
, &n_changes
) >= 0);
105 assert_se(n_changes
== 1);
106 assert_se(changes
[0].type
== UNIT_FILE_UNLINK
);
107 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/a.service");
108 assert_se(streq(changes
[0].path
, p
));
109 unit_file_changes_free(changes
, n_changes
);
110 changes
= NULL
; n_changes
= 0;
112 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "a.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
113 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "b.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
114 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "c.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
115 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "d.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
117 /* Disabling a disabled unit must succeed but be a NOP */
118 assert_se(unit_file_disable(UNIT_FILE_SYSTEM
, 0, root
, STRV_MAKE("a.service"), &changes
, &n_changes
) >= 0);
119 assert_se(n_changes
== 0);
120 unit_file_changes_free(changes
, n_changes
);
121 changes
= NULL
; n_changes
= 0;
123 /* Let's enable this indirectly via a symlink */
124 assert_se(unit_file_enable(UNIT_FILE_SYSTEM
, 0, root
, STRV_MAKE("d.service"), &changes
, &n_changes
) >= 0);
125 assert_se(n_changes
== 1);
126 assert_se(changes
[0].type
== UNIT_FILE_SYMLINK
);
127 assert_se(streq(changes
[0].source
, "/usr/lib/systemd/system/a.service"));
128 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/a.service");
129 assert_se(streq(changes
[0].path
, p
));
130 unit_file_changes_free(changes
, n_changes
);
131 changes
= NULL
; n_changes
= 0;
133 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "a.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
134 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "b.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
135 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "c.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
136 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "d.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
138 /* Let's try to reenable */
140 assert_se(unit_file_reenable(UNIT_FILE_SYSTEM
, 0, root
, STRV_MAKE("b.service"), &changes
, &n_changes
) >= 0);
141 assert_se(n_changes
== 2);
142 assert_se(changes
[0].type
== UNIT_FILE_UNLINK
);
143 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/a.service");
144 assert_se(streq(changes
[0].path
, p
));
145 assert_se(changes
[1].type
== UNIT_FILE_SYMLINK
);
146 assert_se(streq(changes
[1].source
, "/usr/lib/systemd/system/a.service"));
147 assert_se(streq(changes
[1].path
, p
));
148 unit_file_changes_free(changes
, n_changes
);
149 changes
= NULL
; n_changes
= 0;
151 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "a.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
152 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "b.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
153 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "c.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
154 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "d.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
156 /* Test masking with relative symlinks */
158 p
= strjoina(root
, "/usr/lib/systemd/system/e.service");
159 assert_se(symlink("../../../../../../dev/null", p
) >= 0);
161 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "e.service", NULL
) >= 0);
162 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "e.service", &state
) >= 0 && state
== UNIT_FILE_MASKED
);
164 assert_se(unlink(p
) == 0);
165 assert_se(symlink("/usr/../dev/null", p
) >= 0);
167 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "e.service", NULL
) >= 0);
168 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "e.service", &state
) >= 0 && state
== UNIT_FILE_MASKED
);
170 assert_se(unlink(p
) == 0);
173 static void test_linked_units(const char *root
) {
176 UnitFileChange
*changes
= NULL
;
177 size_t n_changes
= 0, i
;
180 * We'll test three cases here:
182 * a) a unit file in /opt, that we use "systemctl link" and
183 * "systemctl enable" on to make it available to the system
185 * b) a unit file in /opt, that is statically linked into
186 * /usr/lib/systemd/system, that "enable" should work on
189 * c) a unit file in /opt, that is linked into
190 * /etc/systemd/system, and where "enable" should result in
191 * -ELOOP, since using information from /etc to generate
192 * information in /etc should not be allowed.
195 p
= strjoina(root
, "/opt/linked.service");
196 assert_se(write_string_file(p
,
198 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
200 p
= strjoina(root
, "/opt/linked2.service");
201 assert_se(write_string_file(p
,
203 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
205 p
= strjoina(root
, "/opt/linked3.service");
206 assert_se(write_string_file(p
,
208 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
210 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "linked.service", NULL
) == -ENOENT
);
211 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "linked2.service", NULL
) == -ENOENT
);
212 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "linked3.service", NULL
) == -ENOENT
);
214 p
= strjoina(root
, "/usr/lib/systemd/system/linked2.service");
215 assert_se(symlink("/opt/linked2.service", p
) >= 0);
217 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/linked3.service");
218 assert_se(symlink("/opt/linked3.service", p
) >= 0);
220 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "linked.service", &state
) == -ENOENT
);
221 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "linked2.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
222 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "linked3.service", &state
) >= 0 && state
== UNIT_FILE_LINKED
);
224 /* First, let's link the unit into the search path */
225 assert_se(unit_file_link(UNIT_FILE_SYSTEM
, 0, root
, STRV_MAKE("/opt/linked.service"), &changes
, &n_changes
) >= 0);
226 assert_se(n_changes
== 1);
227 assert_se(changes
[0].type
== UNIT_FILE_SYMLINK
);
228 assert_se(streq(changes
[0].source
, "/opt/linked.service"));
229 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/linked.service");
230 assert_se(streq(changes
[0].path
, p
));
231 unit_file_changes_free(changes
, n_changes
);
232 changes
= NULL
; n_changes
= 0;
234 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "linked.service", &state
) >= 0 && state
== UNIT_FILE_LINKED
);
236 /* Let's unlink it from the search path again */
237 assert_se(unit_file_disable(UNIT_FILE_SYSTEM
, 0, root
, STRV_MAKE("linked.service"), &changes
, &n_changes
) >= 0);
238 assert_se(n_changes
== 1);
239 assert_se(changes
[0].type
== UNIT_FILE_UNLINK
);
240 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/linked.service");
241 assert_se(streq(changes
[0].path
, p
));
242 unit_file_changes_free(changes
, n_changes
);
243 changes
= NULL
; n_changes
= 0;
245 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "linked.service", NULL
) == -ENOENT
);
247 /* Now, let's not just link it, but also enable it */
248 assert_se(unit_file_enable(UNIT_FILE_SYSTEM
, 0, root
, STRV_MAKE("/opt/linked.service"), &changes
, &n_changes
) >= 0);
249 assert_se(n_changes
== 2);
250 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/linked.service");
251 q
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/linked.service");
252 for (i
= 0 ; i
< n_changes
; i
++) {
253 assert_se(changes
[i
].type
== UNIT_FILE_SYMLINK
);
254 assert_se(streq(changes
[i
].source
, "/opt/linked.service"));
256 if (p
&& streq(changes
[i
].path
, p
))
258 else if (q
&& streq(changes
[i
].path
, q
))
261 assert_not_reached("wut?");
264 unit_file_changes_free(changes
, n_changes
);
265 changes
= NULL
; n_changes
= 0;
267 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "linked.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
269 /* And let's unlink it again */
270 assert_se(unit_file_disable(UNIT_FILE_SYSTEM
, 0, root
, STRV_MAKE("linked.service"), &changes
, &n_changes
) >= 0);
271 assert_se(n_changes
== 2);
272 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/linked.service");
273 q
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/linked.service");
274 for (i
= 0; i
< n_changes
; i
++) {
275 assert_se(changes
[i
].type
== UNIT_FILE_UNLINK
);
277 if (p
&& streq(changes
[i
].path
, p
))
279 else if (q
&& streq(changes
[i
].path
, q
))
282 assert_not_reached("wut?");
285 unit_file_changes_free(changes
, n_changes
);
286 changes
= NULL
; n_changes
= 0;
288 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "linked.service", NULL
) == -ENOENT
);
290 assert_se(unit_file_enable(UNIT_FILE_SYSTEM
, 0, root
, STRV_MAKE("linked2.service"), &changes
, &n_changes
) >= 0);
291 assert_se(n_changes
== 2);
292 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/linked2.service");
293 q
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/linked2.service");
294 for (i
= 0 ; i
< n_changes
; i
++) {
295 assert_se(changes
[i
].type
== UNIT_FILE_SYMLINK
);
296 assert_se(streq(changes
[i
].source
, "/opt/linked2.service"));
298 if (p
&& streq(changes
[i
].path
, p
))
300 else if (q
&& streq(changes
[i
].path
, q
))
303 assert_not_reached("wut?");
306 unit_file_changes_free(changes
, n_changes
);
307 changes
= NULL
; n_changes
= 0;
309 assert_se(unit_file_enable(UNIT_FILE_SYSTEM
, 0, root
, STRV_MAKE("linked3.service"), &changes
, &n_changes
) >= 0);
310 assert_se(n_changes
== 1);
311 assert_se(changes
[0].type
== UNIT_FILE_SYMLINK
);
312 assert_se(startswith(changes
[0].path
, root
));
313 assert_se(endswith(changes
[0].path
, "linked3.service"));
314 assert_se(streq(changes
[0].source
, "/opt/linked3.service"));
315 unit_file_changes_free(changes
, n_changes
);
316 changes
= NULL
; n_changes
= 0;
319 static void test_default(const char *root
) {
320 _cleanup_free_
char *def
= NULL
;
321 UnitFileChange
*changes
= NULL
;
322 size_t n_changes
= 0;
325 p
= strjoina(root
, "/usr/lib/systemd/system/test-default-real.target");
326 assert_se(write_string_file(p
, "# pretty much empty", WRITE_STRING_FILE_CREATE
) >= 0);
328 p
= strjoina(root
, "/usr/lib/systemd/system/test-default.target");
329 assert_se(symlink("test-default-real.target", p
) >= 0);
331 assert_se(unit_file_get_default(UNIT_FILE_SYSTEM
, root
, &def
) == -ENOENT
);
333 assert_se(unit_file_set_default(UNIT_FILE_SYSTEM
, 0, root
, "idontexist.target", &changes
, &n_changes
) == -ENOENT
);
334 assert_se(n_changes
== 1);
335 assert_se(changes
[0].type
== -ENOENT
);
336 assert_se(streq_ptr(changes
[0].path
, "idontexist.target"));
337 unit_file_changes_free(changes
, n_changes
);
338 changes
= NULL
; n_changes
= 0;
340 assert_se(unit_file_get_default(UNIT_FILE_SYSTEM
, root
, &def
) == -ENOENT
);
342 assert_se(unit_file_set_default(UNIT_FILE_SYSTEM
, 0, root
, "test-default.target", &changes
, &n_changes
) >= 0);
343 assert_se(n_changes
== 1);
344 assert_se(changes
[0].type
== UNIT_FILE_SYMLINK
);
345 assert_se(streq(changes
[0].source
, "/usr/lib/systemd/system/test-default-real.target"));
346 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/" SPECIAL_DEFAULT_TARGET
);
347 assert_se(streq(changes
[0].path
, p
));
348 unit_file_changes_free(changes
, n_changes
);
349 changes
= NULL
; n_changes
= 0;
351 assert_se(unit_file_get_default(UNIT_FILE_SYSTEM
, root
, &def
) >= 0);
352 assert_se(streq_ptr(def
, "test-default-real.target"));
355 static void test_add_dependency(const char *root
) {
356 UnitFileChange
*changes
= NULL
;
357 size_t n_changes
= 0;
360 p
= strjoina(root
, "/usr/lib/systemd/system/real-add-dependency-test-target.target");
361 assert_se(write_string_file(p
, "# pretty much empty", WRITE_STRING_FILE_CREATE
) >= 0);
363 p
= strjoina(root
, "/usr/lib/systemd/system/add-dependency-test-target.target");
364 assert_se(symlink("real-add-dependency-test-target.target", p
) >= 0);
366 p
= strjoina(root
, "/usr/lib/systemd/system/real-add-dependency-test-service.service");
367 assert_se(write_string_file(p
, "# pretty much empty", WRITE_STRING_FILE_CREATE
) >= 0);
369 p
= strjoina(root
, "/usr/lib/systemd/system/add-dependency-test-service.service");
370 assert_se(symlink("real-add-dependency-test-service.service", p
) >= 0);
372 assert_se(unit_file_add_dependency(UNIT_FILE_SYSTEM
, 0, root
, STRV_MAKE("add-dependency-test-service.service"), "add-dependency-test-target.target", UNIT_WANTS
, &changes
, &n_changes
) >= 0);
373 assert_se(n_changes
== 1);
374 assert_se(changes
[0].type
== UNIT_FILE_SYMLINK
);
375 assert_se(streq(changes
[0].source
, "/usr/lib/systemd/system/real-add-dependency-test-service.service"));
376 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/real-add-dependency-test-target.target.wants/real-add-dependency-test-service.service");
377 assert_se(streq(changes
[0].path
, p
));
378 unit_file_changes_free(changes
, n_changes
);
379 changes
= NULL
; n_changes
= 0;
382 static void test_template_enable(const char *root
) {
383 UnitFileChange
*changes
= NULL
;
384 size_t n_changes
= 0;
388 log_info("== %s ==", __func__
);
390 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template@.service", &state
) == -ENOENT
);
391 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template@def.service", &state
) == -ENOENT
);
392 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template@foo.service", &state
) == -ENOENT
);
393 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template-symlink@foo.service", &state
) == -ENOENT
);
395 p
= strjoina(root
, "/usr/lib/systemd/system/template@.service");
396 assert_se(write_string_file(p
,
398 "DefaultInstance=def\n"
399 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
401 p
= strjoina(root
, "/usr/lib/systemd/system/template-symlink@.service");
402 assert_se(symlink("template@.service", p
) >= 0);
404 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template@.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
405 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template@def.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
406 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template@foo.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
407 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template-symlink@.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
408 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template-symlink@def.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
409 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template-symlink@foo.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
411 log_info("== %s with template@.service enabled ==", __func__
);
413 assert_se(unit_file_enable(UNIT_FILE_SYSTEM
, 0, root
, STRV_MAKE("template@.service"), &changes
, &n_changes
) >= 0);
414 assert_se(n_changes
== 1);
415 assert_se(changes
[0].type
== UNIT_FILE_SYMLINK
);
416 assert_se(streq(changes
[0].source
, "/usr/lib/systemd/system/template@.service"));
417 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/template@def.service");
418 assert_se(streq(changes
[0].path
, p
));
419 unit_file_changes_free(changes
, n_changes
);
420 changes
= NULL
; n_changes
= 0;
422 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template@.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
423 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template@def.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
424 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template@foo.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
425 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template-symlink@.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
426 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template-symlink@def.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
427 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template-symlink@foo.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
429 assert_se(unit_file_disable(UNIT_FILE_SYSTEM
, 0, root
, STRV_MAKE("template@.service"), &changes
, &n_changes
) >= 0);
430 assert_se(n_changes
== 1);
431 assert_se(changes
[0].type
== UNIT_FILE_UNLINK
);
432 assert_se(streq(changes
[0].path
, p
));
433 unit_file_changes_free(changes
, n_changes
);
434 changes
= NULL
; n_changes
= 0;
436 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template@.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
437 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template@def.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
438 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template@foo.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
439 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template-symlink@.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
440 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template-symlink@def.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
441 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template-symlink@foo.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
443 log_info("== %s with template@foo.service enabled ==", __func__
);
445 assert_se(unit_file_enable(UNIT_FILE_SYSTEM
, 0, root
, STRV_MAKE("template@foo.service"), &changes
, &n_changes
) >= 0);
446 assert_se(changes
[0].type
== UNIT_FILE_SYMLINK
);
447 assert_se(streq(changes
[0].source
, "/usr/lib/systemd/system/template@.service"));
448 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/template@foo.service");
449 assert_se(streq(changes
[0].path
, p
));
450 unit_file_changes_free(changes
, n_changes
);
451 changes
= NULL
; n_changes
= 0;
453 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template@.service", &state
) >= 0 && state
== UNIT_FILE_INDIRECT
);
454 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template@def.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
455 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template@foo.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
456 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template-symlink@foo.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
457 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template-symlink@def.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
458 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template-symlink@foo.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
460 assert_se(unit_file_disable(UNIT_FILE_SYSTEM
, 0, root
, STRV_MAKE("template@foo.service"), &changes
, &n_changes
) >= 0);
461 assert_se(n_changes
== 1);
462 assert_se(changes
[0].type
== UNIT_FILE_UNLINK
);
463 assert_se(streq(changes
[0].path
, p
));
464 unit_file_changes_free(changes
, n_changes
);
465 changes
= NULL
; n_changes
= 0;
467 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template@.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
468 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template@def.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
469 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template@foo.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
470 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template@quux.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
471 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template-symlink@.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
472 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template-symlink@def.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
473 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template-symlink@foo.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
474 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template-symlink@quux.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
476 log_info("== %s with template-symlink@quux.service enabled ==", __func__
);
478 assert_se(unit_file_enable(UNIT_FILE_SYSTEM
, 0, root
, STRV_MAKE("template-symlink@quux.service"), &changes
, &n_changes
) >= 0);
479 assert_se(changes
[0].type
== UNIT_FILE_SYMLINK
);
480 assert_se(streq(changes
[0].source
, "/usr/lib/systemd/system/template@.service"));
481 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/template@quux.service");
482 assert_se(streq(changes
[0].path
, p
));
483 unit_file_changes_free(changes
, n_changes
);
484 changes
= NULL
; n_changes
= 0;
486 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template@.service", &state
) >= 0 && state
== UNIT_FILE_INDIRECT
);
487 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template@def.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
488 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template@foo.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
489 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template@quux.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
490 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template-symlink@.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
491 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template-symlink@def.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
492 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template-symlink@foo.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
493 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template-symlink@quux.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
496 static void test_indirect(const char *root
) {
497 UnitFileChange
*changes
= NULL
;
498 size_t n_changes
= 0;
502 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "indirecta.service", &state
) == -ENOENT
);
503 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "indirectb.service", &state
) == -ENOENT
);
504 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "indirectc.service", &state
) == -ENOENT
);
506 p
= strjoina(root
, "/usr/lib/systemd/system/indirecta.service");
507 assert_se(write_string_file(p
,
509 "Also=indirectb.service\n", WRITE_STRING_FILE_CREATE
) >= 0);
511 p
= strjoina(root
, "/usr/lib/systemd/system/indirectb.service");
512 assert_se(write_string_file(p
,
514 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
516 p
= strjoina(root
, "/usr/lib/systemd/system/indirectc.service");
517 assert_se(symlink("indirecta.service", p
) >= 0);
519 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "indirecta.service", &state
) >= 0 && state
== UNIT_FILE_INDIRECT
);
520 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "indirectb.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
521 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "indirectc.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
523 assert_se(unit_file_enable(UNIT_FILE_SYSTEM
, 0, root
, STRV_MAKE("indirectc.service"), &changes
, &n_changes
) >= 0);
524 assert_se(n_changes
== 1);
525 assert_se(changes
[0].type
== UNIT_FILE_SYMLINK
);
526 assert_se(streq(changes
[0].source
, "/usr/lib/systemd/system/indirectb.service"));
527 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/indirectb.service");
528 assert_se(streq(changes
[0].path
, p
));
529 unit_file_changes_free(changes
, n_changes
);
530 changes
= NULL
; n_changes
= 0;
532 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "indirecta.service", &state
) >= 0 && state
== UNIT_FILE_INDIRECT
);
533 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "indirectb.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
534 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "indirectc.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
536 assert_se(unit_file_disable(UNIT_FILE_SYSTEM
, 0, root
, STRV_MAKE("indirectc.service"), &changes
, &n_changes
) >= 0);
537 assert_se(n_changes
== 1);
538 assert_se(changes
[0].type
== UNIT_FILE_UNLINK
);
539 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/indirectb.service");
540 assert_se(streq(changes
[0].path
, p
));
541 unit_file_changes_free(changes
, n_changes
);
542 changes
= NULL
; n_changes
= 0;
545 static void test_preset_and_list(const char *root
) {
546 UnitFileChange
*changes
= NULL
;
547 size_t n_changes
= 0, i
;
550 bool got_yes
= false, got_no
= false;
554 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "preset-yes.service", &state
) == -ENOENT
);
555 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "preset-no.service", &state
) == -ENOENT
);
557 p
= strjoina(root
, "/usr/lib/systemd/system/preset-yes.service");
558 assert_se(write_string_file(p
,
560 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
562 p
= strjoina(root
, "/usr/lib/systemd/system/preset-no.service");
563 assert_se(write_string_file(p
,
565 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
567 p
= strjoina(root
, "/usr/lib/systemd/system-preset/test.preset");
568 assert_se(write_string_file(p
,
570 "disable *\n", WRITE_STRING_FILE_CREATE
) >= 0);
572 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "preset-yes.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
573 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "preset-no.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
575 assert_se(unit_file_preset(UNIT_FILE_SYSTEM
, 0, root
, STRV_MAKE("preset-yes.service"), UNIT_FILE_PRESET_FULL
, &changes
, &n_changes
) >= 0);
576 assert_se(n_changes
== 1);
577 assert_se(changes
[0].type
== UNIT_FILE_SYMLINK
);
578 assert_se(streq(changes
[0].source
, "/usr/lib/systemd/system/preset-yes.service"));
579 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/preset-yes.service");
580 assert_se(streq(changes
[0].path
, p
));
581 unit_file_changes_free(changes
, n_changes
);
582 changes
= NULL
; n_changes
= 0;
584 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "preset-yes.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
585 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "preset-no.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
587 assert_se(unit_file_disable(UNIT_FILE_SYSTEM
, 0, root
, STRV_MAKE("preset-yes.service"), &changes
, &n_changes
) >= 0);
588 assert_se(n_changes
== 1);
589 assert_se(changes
[0].type
== UNIT_FILE_UNLINK
);
590 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/preset-yes.service");
591 assert_se(streq(changes
[0].path
, p
));
592 unit_file_changes_free(changes
, n_changes
);
593 changes
= NULL
; n_changes
= 0;
595 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "preset-yes.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
596 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "preset-no.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
598 assert_se(unit_file_preset(UNIT_FILE_SYSTEM
, 0, root
, STRV_MAKE("preset-no.service"), UNIT_FILE_PRESET_FULL
, &changes
, &n_changes
) >= 0);
599 assert_se(n_changes
== 0);
600 unit_file_changes_free(changes
, n_changes
);
601 changes
= NULL
; n_changes
= 0;
603 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "preset-yes.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
604 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "preset-no.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
606 assert_se(unit_file_preset_all(UNIT_FILE_SYSTEM
, 0, root
, UNIT_FILE_PRESET_FULL
, &changes
, &n_changes
) >= 0);
608 assert_se(n_changes
> 0);
610 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/preset-yes.service");
612 for (i
= 0; i
< n_changes
; i
++) {
614 if (changes
[i
].type
== UNIT_FILE_SYMLINK
) {
615 assert_se(streq(changes
[i
].source
, "/usr/lib/systemd/system/preset-yes.service"));
616 assert_se(streq(changes
[i
].path
, p
));
618 assert_se(changes
[i
].type
== UNIT_FILE_UNLINK
);
621 unit_file_changes_free(changes
, n_changes
);
622 changes
= NULL
; n_changes
= 0;
624 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "preset-yes.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
625 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "preset-no.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
627 assert_se(h
= hashmap_new(&string_hash_ops
));
628 assert_se(unit_file_get_list(UNIT_FILE_SYSTEM
, root
, h
, NULL
, NULL
) >= 0);
630 p
= strjoina(root
, "/usr/lib/systemd/system/preset-yes.service");
631 q
= strjoina(root
, "/usr/lib/systemd/system/preset-no.service");
633 HASHMAP_FOREACH(fl
, h
) {
634 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, basename(fl
->path
), &state
) >= 0);
635 assert_se(fl
->state
== state
);
637 if (streq(fl
->path
, p
)) {
639 assert_se(fl
->state
== UNIT_FILE_ENABLED
);
640 } else if (streq(fl
->path
, q
)) {
642 assert_se(fl
->state
== UNIT_FILE_DISABLED
);
644 assert_se(IN_SET(fl
->state
, UNIT_FILE_DISABLED
, UNIT_FILE_STATIC
, UNIT_FILE_INDIRECT
, UNIT_FILE_ALIAS
));
647 unit_file_list_free(h
);
649 assert_se(got_yes
&& got_no
);
652 static void test_revert(const char *root
) {
655 UnitFileChange
*changes
= NULL
;
656 size_t n_changes
= 0;
660 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "xx.service", NULL
) == -ENOENT
);
661 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "yy.service", NULL
) == -ENOENT
);
663 p
= strjoina(root
, "/usr/lib/systemd/system/xx.service");
664 assert_se(write_string_file(p
, "# Empty\n", WRITE_STRING_FILE_CREATE
) >= 0);
666 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "xx.service", NULL
) >= 0);
667 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "xx.service", &state
) >= 0 && state
== UNIT_FILE_STATIC
);
669 /* Initially there's nothing to revert */
670 assert_se(unit_file_revert(UNIT_FILE_SYSTEM
, root
, STRV_MAKE("xx.service"), &changes
, &n_changes
) >= 0);
671 assert_se(n_changes
== 0);
672 unit_file_changes_free(changes
, n_changes
);
673 changes
= NULL
; n_changes
= 0;
675 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/xx.service");
676 assert_se(write_string_file(p
, "# Empty override\n", WRITE_STRING_FILE_CREATE
) >= 0);
678 /* Revert the override file */
679 assert_se(unit_file_revert(UNIT_FILE_SYSTEM
, root
, STRV_MAKE("xx.service"), &changes
, &n_changes
) >= 0);
680 assert_se(n_changes
== 1);
681 assert_se(changes
[0].type
== UNIT_FILE_UNLINK
);
682 assert_se(streq(changes
[0].path
, p
));
683 unit_file_changes_free(changes
, n_changes
);
684 changes
= NULL
; n_changes
= 0;
686 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/xx.service.d/dropin.conf");
687 assert_se(mkdir_parents(p
, 0755) >= 0);
688 assert_se(write_string_file(p
, "# Empty dropin\n", WRITE_STRING_FILE_CREATE
) >= 0);
690 /* Revert the dropin file */
691 assert_se(unit_file_revert(UNIT_FILE_SYSTEM
, root
, STRV_MAKE("xx.service"), &changes
, &n_changes
) >= 0);
692 assert_se(n_changes
== 2);
693 assert_se(changes
[0].type
== UNIT_FILE_UNLINK
);
694 assert_se(streq(changes
[0].path
, p
));
696 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/xx.service.d");
697 assert_se(changes
[1].type
== UNIT_FILE_UNLINK
);
698 assert_se(streq(changes
[1].path
, p
));
699 unit_file_changes_free(changes
, n_changes
);
700 changes
= NULL
; n_changes
= 0;
703 static void test_preset_order(const char *root
) {
704 UnitFileChange
*changes
= NULL
;
705 size_t n_changes
= 0;
709 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "prefix-1.service", &state
) == -ENOENT
);
710 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "prefix-2.service", &state
) == -ENOENT
);
712 p
= strjoina(root
, "/usr/lib/systemd/system/prefix-1.service");
713 assert_se(write_string_file(p
,
715 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
717 p
= strjoina(root
, "/usr/lib/systemd/system/prefix-2.service");
718 assert_se(write_string_file(p
,
720 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
722 p
= strjoina(root
, "/usr/lib/systemd/system-preset/test.preset");
723 assert_se(write_string_file(p
,
724 "enable prefix-1.service\n"
725 "disable prefix-*.service\n"
726 "enable prefix-2.service\n", WRITE_STRING_FILE_CREATE
) >= 0);
728 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "prefix-1.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
729 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "prefix-2.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
731 assert_se(unit_file_preset(UNIT_FILE_SYSTEM
, 0, root
, STRV_MAKE("prefix-1.service"), UNIT_FILE_PRESET_FULL
, &changes
, &n_changes
) >= 0);
732 assert_se(n_changes
== 1);
733 assert_se(changes
[0].type
== UNIT_FILE_SYMLINK
);
734 assert_se(streq(changes
[0].source
, "/usr/lib/systemd/system/prefix-1.service"));
735 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/prefix-1.service");
736 assert_se(streq(changes
[0].path
, p
));
737 unit_file_changes_free(changes
, n_changes
);
738 changes
= NULL
; n_changes
= 0;
740 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "prefix-1.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
741 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "prefix-2.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
743 assert_se(unit_file_preset(UNIT_FILE_SYSTEM
, 0, root
, STRV_MAKE("prefix-2.service"), UNIT_FILE_PRESET_FULL
, &changes
, &n_changes
) >= 0);
744 assert_se(n_changes
== 0);
746 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "prefix-1.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
747 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "prefix-2.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
750 static void test_static_instance(const char *root
) {
754 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "static-instance@.service", &state
) == -ENOENT
);
755 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "static-instance@foo.service", &state
) == -ENOENT
);
757 p
= strjoina(root
, "/usr/lib/systemd/system/static-instance@.service");
758 assert_se(write_string_file(p
,
760 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
762 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "static-instance@.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
763 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "static-instance@foo.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
765 p
= strjoina(root
, "/usr/lib/systemd/system/static-instance@foo.service");
766 assert_se(symlink("static-instance@.service", p
) >= 0);
768 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "static-instance@.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
769 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "static-instance@foo.service", &state
) >= 0 && state
== UNIT_FILE_STATIC
);
772 static void test_with_dropin(const char *root
) {
775 UnitFileChange
*changes
= NULL
;
776 size_t n_changes
= 0;
778 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "with-dropin-1.service", &state
) == -ENOENT
);
779 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "with-dropin-2.service", &state
) == -ENOENT
);
780 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "with-dropin-3.service", &state
) == -ENOENT
);
781 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "with-dropin-4a.service", &state
) == -ENOENT
);
782 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "with-dropin-4b.service", &state
) == -ENOENT
);
784 p
= strjoina(root
, "/usr/lib/systemd/system/with-dropin-1.service");
785 assert_se(write_string_file(p
,
787 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
789 p
= strjoina(root
, "/usr/lib/systemd/system/with-dropin-1.service.d/dropin.conf");
790 assert_se(mkdir_parents(p
, 0755) >= 0);
791 assert_se(write_string_file(p
,
793 "WantedBy=graphical.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
795 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "with-dropin-1.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
797 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/with-dropin-2.service");
798 assert_se(write_string_file(p
,
800 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
802 p
= strjoina(root
, "/usr/lib/systemd/system/with-dropin-2.service.d/dropin.conf");
803 assert_se(mkdir_parents(p
, 0755) >= 0);
804 assert_se(write_string_file(p
,
806 "WantedBy=graphical.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
808 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "with-dropin-2.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
810 p
= strjoina(root
, "/usr/lib/systemd/system/with-dropin-3.service");
811 assert_se(write_string_file(p
,
813 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
815 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/with-dropin-3.service.d/dropin.conf");
816 assert_se(mkdir_parents(p
, 0755) >= 0);
817 assert_se(write_string_file(p
,
819 "WantedBy=graphical.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
821 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "with-dropin-3.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
823 p
= strjoina(root
, "/usr/lib/systemd/system/with-dropin-4a.service");
824 assert_se(write_string_file(p
,
826 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
828 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/with-dropin-4a.service.d/dropin.conf");
829 assert_se(mkdir_parents(p
, 0755) >= 0);
830 assert_se(write_string_file(p
,
832 "Also=with-dropin-4b.service\n", WRITE_STRING_FILE_CREATE
) >= 0);
834 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "with-dropin-4a.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
836 p
= strjoina(root
, "/usr/lib/systemd/system/with-dropin-4b.service");
837 assert_se(write_string_file(p
,
839 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
841 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "with-dropin-4b.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
843 assert_se(unit_file_enable(UNIT_FILE_SYSTEM
, 0, root
, STRV_MAKE("with-dropin-1.service"), &changes
, &n_changes
) == 1);
844 assert_se(n_changes
== 2);
845 assert_se(changes
[0].type
== UNIT_FILE_SYMLINK
);
846 assert_se(changes
[1].type
== UNIT_FILE_SYMLINK
);
847 assert_se(streq(changes
[0].source
, "/usr/lib/systemd/system/with-dropin-1.service"));
848 assert_se(streq(changes
[1].source
, "/usr/lib/systemd/system/with-dropin-1.service"));
849 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/with-dropin-1.service");
850 assert_se(streq(changes
[0].path
, p
));
851 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/graphical.target.wants/with-dropin-1.service");
852 assert_se(streq(changes
[1].path
, p
));
853 unit_file_changes_free(changes
, n_changes
);
854 changes
= NULL
; n_changes
= 0;
856 assert_se(unit_file_enable(UNIT_FILE_SYSTEM
, 0, root
, STRV_MAKE("with-dropin-2.service"), &changes
, &n_changes
) == 1);
857 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "with-dropin-2.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
858 assert_se(n_changes
== 2);
859 assert_se(changes
[0].type
== UNIT_FILE_SYMLINK
);
860 assert_se(changes
[1].type
== UNIT_FILE_SYMLINK
);
861 assert_se(streq(changes
[0].source
, SYSTEM_CONFIG_UNIT_DIR
"/with-dropin-2.service"));
862 assert_se(streq(changes
[1].source
, SYSTEM_CONFIG_UNIT_DIR
"/with-dropin-2.service"));
863 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/with-dropin-2.service");
864 assert_se(streq(changes
[0].path
, p
));
865 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/graphical.target.wants/with-dropin-2.service");
866 assert_se(streq(changes
[1].path
, p
));
867 unit_file_changes_free(changes
, n_changes
);
868 changes
= NULL
; n_changes
= 0;
870 assert_se(unit_file_enable(UNIT_FILE_SYSTEM
, 0, root
, STRV_MAKE("with-dropin-3.service"), &changes
, &n_changes
) == 1);
871 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "with-dropin-3.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
872 assert_se(n_changes
== 2);
873 assert_se(changes
[0].type
== UNIT_FILE_SYMLINK
);
874 assert_se(changes
[1].type
== UNIT_FILE_SYMLINK
);
875 assert_se(streq(changes
[0].source
, "/usr/lib/systemd/system/with-dropin-3.service"));
876 assert_se(streq(changes
[1].source
, "/usr/lib/systemd/system/with-dropin-3.service"));
877 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/with-dropin-3.service");
878 assert_se(streq(changes
[0].path
, p
));
879 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/graphical.target.wants/with-dropin-3.service");
880 assert_se(streq(changes
[1].path
, p
));
881 unit_file_changes_free(changes
, n_changes
);
882 changes
= NULL
; n_changes
= 0;
884 assert_se(unit_file_enable(UNIT_FILE_SYSTEM
, 0, root
, STRV_MAKE("with-dropin-4a.service"), &changes
, &n_changes
) == 2);
885 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "with-dropin-3.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
886 assert_se(n_changes
== 2);
887 assert_se(changes
[0].type
== UNIT_FILE_SYMLINK
);
888 assert_se(changes
[1].type
== UNIT_FILE_SYMLINK
);
889 assert_se(streq(changes
[0].source
, "/usr/lib/systemd/system/with-dropin-4a.service"));
890 assert_se(streq(changes
[1].source
, "/usr/lib/systemd/system/with-dropin-4b.service"));
891 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/with-dropin-4a.service");
892 assert_se(streq(changes
[0].path
, p
));
893 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/with-dropin-4b.service");
894 assert_se(streq(changes
[1].path
, p
));
895 unit_file_changes_free(changes
, n_changes
);
896 changes
= NULL
; n_changes
= 0;
898 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "with-dropin-1.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
899 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "with-dropin-2.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
900 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "with-dropin-3.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
901 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "with-dropin-4a.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
902 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "with-dropin-4b.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
905 static void test_with_dropin_template(const char *root
) {
908 UnitFileChange
*changes
= NULL
;
909 size_t n_changes
= 0;
911 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "with-dropin-1@.service", &state
) == -ENOENT
);
912 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "with-dropin-2@.service", &state
) == -ENOENT
);
913 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "with-dropin-3@.service", &state
) == -ENOENT
);
915 p
= strjoina(root
, "/usr/lib/systemd/system/with-dropin-1@.service");
916 assert_se(write_string_file(p
,
918 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
920 p
= strjoina(root
, "/usr/lib/systemd/system/with-dropin-1@.service.d/dropin.conf");
921 assert_se(mkdir_parents(p
, 0755) >= 0);
922 assert_se(write_string_file(p
,
924 "WantedBy=graphical.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
926 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "with-dropin-1@.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
928 p
= strjoina(root
, "/usr/lib/systemd/system/with-dropin-2@.service");
929 assert_se(write_string_file(p
,
931 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
933 p
= strjoina(root
, "/usr/lib/systemd/system/with-dropin-2@instance-1.service.d/dropin.conf");
934 assert_se(mkdir_parents(p
, 0755) >= 0);
935 assert_se(write_string_file(p
,
937 "WantedBy=graphical.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
939 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "with-dropin-2@.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
941 p
= strjoina(root
, "/usr/lib/systemd/system/with-dropin-3@.service");
942 assert_se(write_string_file(p
,
944 "DefaultInstance=instance-1\n"
945 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
947 p
= strjoina(root
, "/usr/lib/systemd/system/with-dropin-3@.service.d/dropin.conf");
948 assert_se(mkdir_parents(p
, 0755) >= 0);
949 assert_se(write_string_file(p
,
951 "DefaultInstance=instance-2\n", WRITE_STRING_FILE_CREATE
) >= 0);
953 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "with-dropin-3@.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
955 assert_se(unit_file_enable(UNIT_FILE_SYSTEM
, 0, root
, STRV_MAKE("with-dropin-1@instance-1.service"), &changes
, &n_changes
) == 1);
956 assert_se(n_changes
== 2);
957 assert_se(changes
[0].type
== UNIT_FILE_SYMLINK
);
958 assert_se(changes
[1].type
== UNIT_FILE_SYMLINK
);
959 assert_se(streq(changes
[0].source
, "/usr/lib/systemd/system/with-dropin-1@.service"));
960 assert_se(streq(changes
[1].source
, "/usr/lib/systemd/system/with-dropin-1@.service"));
961 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/with-dropin-1@instance-1.service");
962 assert_se(streq(changes
[0].path
, p
));
963 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/graphical.target.wants/with-dropin-1@instance-1.service");
964 assert_se(streq(changes
[1].path
, p
));
965 unit_file_changes_free(changes
, n_changes
);
966 changes
= NULL
; n_changes
= 0;
968 assert_se(unit_file_enable(UNIT_FILE_SYSTEM
, 0, root
, STRV_MAKE("with-dropin-2@instance-1.service"), &changes
, &n_changes
) == 1);
969 assert_se(n_changes
== 2);
970 assert_se(changes
[0].type
== UNIT_FILE_SYMLINK
);
971 assert_se(changes
[1].type
== UNIT_FILE_SYMLINK
);
972 assert_se(streq(changes
[0].source
, "/usr/lib/systemd/system/with-dropin-2@.service"));
973 assert_se(streq(changes
[1].source
, "/usr/lib/systemd/system/with-dropin-2@.service"));
974 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/with-dropin-2@instance-1.service");
975 assert_se(streq(changes
[0].path
, p
));
976 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/graphical.target.wants/with-dropin-2@instance-1.service");
977 assert_se(streq(changes
[1].path
, p
));
978 unit_file_changes_free(changes
, n_changes
);
979 changes
= NULL
; n_changes
= 0;
981 assert_se(unit_file_enable(UNIT_FILE_SYSTEM
, 0, root
, STRV_MAKE("with-dropin-2@instance-2.service"), &changes
, &n_changes
) == 1);
982 assert_se(n_changes
== 1);
983 assert_se(changes
[0].type
== UNIT_FILE_SYMLINK
);
984 assert_se(streq(changes
[0].source
, "/usr/lib/systemd/system/with-dropin-2@.service"));
985 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/with-dropin-2@instance-2.service");
986 assert_se(streq(changes
[0].path
, p
));
987 unit_file_changes_free(changes
, n_changes
);
988 changes
= NULL
; n_changes
= 0;
990 assert_se(unit_file_enable(UNIT_FILE_SYSTEM
, 0, root
, STRV_MAKE("with-dropin-3@.service"), &changes
, &n_changes
) == 1);
991 assert_se(n_changes
== 1);
992 assert_se(changes
[0].type
== UNIT_FILE_SYMLINK
);
993 assert_se(streq(changes
[0].source
, "/usr/lib/systemd/system/with-dropin-3@.service"));
994 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/with-dropin-3@instance-2.service");
995 assert_se(streq(changes
[0].path
, p
));
996 unit_file_changes_free(changes
, n_changes
);
997 changes
= NULL
; n_changes
= 0;
999 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "with-dropin-1@instance-1.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
1000 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "with-dropin-2@instance-1.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
1001 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "with-dropin-2@instance-2.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
1002 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "with-dropin-3@instance-1.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
1003 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "with-dropin-3@instance-2.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
1006 static void test_preset_multiple_instances(const char *root
) {
1007 UnitFileChange
*changes
= NULL
;
1008 size_t n_changes
= 0;
1010 UnitFileState state
;
1012 /* Set up template service files and preset file */
1013 p
= strjoina(root
, "/usr/lib/systemd/system/foo@.service");
1014 assert_se(write_string_file(p
,
1016 "DefaultInstance=def\n"
1017 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
1019 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "foo@.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
1021 p
= strjoina(root
, "/usr/lib/systemd/system-preset/test.preset");
1022 assert_se(write_string_file(p
,
1023 "enable foo@.service bar0 bar1 bartest\n"
1024 "enable emptylist@.service\n" /* This line ensures the old functionality for templated unit still works */
1025 "disable *\n" , WRITE_STRING_FILE_CREATE
) >= 0);
1027 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "foo@bar0.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
1029 /* Preset a single instantiated unit specified in the list */
1030 assert_se(unit_file_preset(UNIT_FILE_SYSTEM
, 0, root
, STRV_MAKE("foo@bar0.service"), UNIT_FILE_PRESET_FULL
, &changes
, &n_changes
) >= 0);
1031 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "foo@bar0.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
1032 assert_se(n_changes
== 1);
1033 assert_se(changes
[0].type
== UNIT_FILE_SYMLINK
);
1034 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/foo@bar0.service");
1035 assert_se(streq(changes
[0].path
, p
));
1036 unit_file_changes_free(changes
, n_changes
);
1037 changes
= NULL
; n_changes
= 0;
1039 assert_se(unit_file_disable(UNIT_FILE_SYSTEM
, 0, root
, STRV_MAKE("foo@bar0.service"), &changes
, &n_changes
) >= 0);
1040 assert_se(n_changes
== 1);
1041 assert_se(changes
[0].type
== UNIT_FILE_UNLINK
);
1042 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/foo@bar0.service");
1043 assert_se(streq(changes
[0].path
, p
));
1044 unit_file_changes_free(changes
, n_changes
);
1045 changes
= NULL
; n_changes
= 0;
1047 /* Check for preset-all case, only instances on the list should be enabled, not including the default instance */
1048 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "foo@def.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
1049 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "foo@bar1.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
1050 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "foo@bartest.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
1052 assert_se(unit_file_preset_all(UNIT_FILE_SYSTEM
, 0, root
, UNIT_FILE_PRESET_FULL
, &changes
, &n_changes
) >= 0);
1053 assert_se(n_changes
> 0);
1055 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "foo@def.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
1056 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "foo@bar0.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
1057 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "foo@bar1.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
1058 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "foo@bartest.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
1060 unit_file_changes_free(changes
, n_changes
);
1063 static void verify_one(
1064 const UnitFileInstallInfo
*i
,
1067 const char *updated_name
) {
1069 static const UnitFileInstallInfo
*last_info
= NULL
;
1070 _cleanup_free_
char *alias2
= NULL
;
1073 log_info("-- %s --", (last_info
= i
)->name
);
1075 r
= unit_file_verify_alias(i
, alias
, &alias2
);
1076 log_info_errno(r
, "alias %s ← %s: %d/%m (expected %d)%s%s%s",
1077 i
->name
, alias
, r
, expected
,
1078 alias2
? " [" : "", strempty(alias2
),
1080 assert(r
== expected
);
1082 /* This is is test for "instance propagation". This propagation matters mostly for WantedBy= and
1083 * RequiredBy= settings, and less so for Alias=. The only case where it should happen is when we have
1084 * an Alias=alias@.service an instantiated template template@instance. In that case the instance name
1085 * should be propagated into the alias as alias@instance. */
1086 assert(streq_ptr(alias2
, updated_name
));
1089 static void test_verify_alias(void) {
1090 const UnitFileInstallInfo
1091 plain_service
= { .name
= (char*) "plain.service" },
1092 bare_template
= { .name
= (char*) "template1@.service" },
1093 di_template
= { .name
= (char*) "template2@.service",
1094 .default_instance
= (char*) "di" },
1095 inst_template
= { .name
= (char*) "template3@inst.service" },
1096 di_inst_template
= { .name
= (char*) "template4@inst.service",
1097 .default_instance
= (char*) "di" };
1099 verify_one(&plain_service
, "alias.service", 0, NULL
);
1100 verify_one(&plain_service
, "alias.socket", -EXDEV
, NULL
);
1101 verify_one(&plain_service
, "alias@.service", -EXDEV
, NULL
);
1102 verify_one(&plain_service
, "alias@inst.service", -EXDEV
, NULL
);
1103 verify_one(&plain_service
, "foo.target.wants/plain.service", 0, NULL
);
1104 verify_one(&plain_service
, "foo.target.wants/plain.socket", -EXDEV
, NULL
);
1105 verify_one(&plain_service
, "foo.target.wants/plain@.service", -EXDEV
, NULL
);
1106 verify_one(&plain_service
, "foo.target.wants/service", -EXDEV
, NULL
);
1107 verify_one(&plain_service
, "foo.target.requires/plain.service", 0, NULL
);
1108 verify_one(&plain_service
, "foo.target.requires/plain.socket", -EXDEV
, NULL
);
1109 verify_one(&plain_service
, "foo.target.requires/plain@.service", -EXDEV
, NULL
);
1110 verify_one(&plain_service
, "foo.target.requires/service", -EXDEV
, NULL
);
1111 verify_one(&plain_service
, "foo.target.conf/plain.service", -EXDEV
, NULL
);
1112 verify_one(&plain_service
, "foo.service/plain.service", -EXDEV
, NULL
); /* missing dir suffix */
1113 verify_one(&plain_service
, "asdf.requires/plain.service", -EXDEV
, NULL
); /* invalid unit name component */
1115 verify_one(&bare_template
, "alias.service", -EXDEV
, NULL
);
1116 verify_one(&bare_template
, "alias.socket", -EXDEV
, NULL
);
1117 verify_one(&bare_template
, "alias@.socket", -EXDEV
, NULL
);
1118 verify_one(&bare_template
, "alias@inst.socket", -EXDEV
, NULL
);
1119 /* A general alias alias@.service → template1@.service. */
1120 verify_one(&bare_template
, "alias@.service", 0, NULL
);
1121 /* Only a specific instance is aliased, see the discussion in https://github.com/systemd/systemd/pull/13119. */
1122 verify_one(&bare_template
, "alias@inst.service", 0, NULL
);
1123 verify_one(&bare_template
, "foo.target.wants/plain.service", -EXDEV
, NULL
);
1124 verify_one(&bare_template
, "foo.target.wants/plain.socket", -EXDEV
, NULL
);
1125 verify_one(&bare_template
, "foo.target.wants/plain@.service", -EXDEV
, NULL
);
1126 /* Name mismatch: we cannot allow this, because plain@foo.service would be pulled in by foo.target,
1127 * but would not be resolveable on its own, since systemd doesn't know how to load the fragment. */
1128 verify_one(&bare_template
, "foo.target.wants/plain@foo.service", -EXDEV
, NULL
);
1129 verify_one(&bare_template
, "foo.target.wants/template1@foo.service", 0, NULL
);
1130 verify_one(&bare_template
, "foo.target.wants/service", -EXDEV
, NULL
);
1131 verify_one(&bare_template
, "foo.target.requires/plain.service", -EXDEV
, NULL
);
1132 verify_one(&bare_template
, "foo.target.requires/plain.socket", -EXDEV
, NULL
);
1133 verify_one(&bare_template
, "foo.target.requires/plain@.service", -EXDEV
, NULL
); /* instance missing */
1134 verify_one(&bare_template
, "foo.target.requires/template1@inst.service", 0, NULL
);
1135 verify_one(&bare_template
, "foo.target.requires/service", -EXDEV
, NULL
);
1136 verify_one(&bare_template
, "foo.target.conf/plain.service", -EXDEV
, NULL
);
1137 verify_one(&bare_template
, "FOO@.target.requires/plain@.service", -EXDEV
, NULL
); /* template name mismatch */
1138 verify_one(&bare_template
, "FOO@inst.target.requires/plain@.service", -EXDEV
, NULL
);
1139 verify_one(&bare_template
, "FOO@inst.target.requires/plain@inst.service", -EXDEV
, NULL
);
1140 verify_one(&bare_template
, "FOO@.target.requires/template1@.service", 0, NULL
); /* instance propagated */
1141 verify_one(&bare_template
, "FOO@inst.target.requires/template1@.service", -EXDEV
, NULL
); /* instance missing */
1142 verify_one(&bare_template
, "FOO@inst.target.requires/template1@inst.service", 0, NULL
); /* instance provided */
1144 verify_one(&di_template
, "alias.service", -EXDEV
, NULL
);
1145 verify_one(&di_template
, "alias.socket", -EXDEV
, NULL
);
1146 verify_one(&di_template
, "alias@.socket", -EXDEV
, NULL
);
1147 verify_one(&di_template
, "alias@inst.socket", -EXDEV
, NULL
);
1148 verify_one(&di_template
, "alias@inst.service", 0, NULL
);
1149 verify_one(&di_template
, "alias@.service", 0, NULL
);
1150 verify_one(&di_template
, "alias@di.service", 0, NULL
);
1151 verify_one(&di_template
, "foo.target.wants/plain.service", -EXDEV
, NULL
);
1152 verify_one(&di_template
, "foo.target.wants/plain.socket", -EXDEV
, NULL
);
1153 verify_one(&di_template
, "foo.target.wants/plain@.service", -EXDEV
, NULL
);
1154 verify_one(&di_template
, "foo.target.wants/plain@di.service", -EXDEV
, NULL
);
1155 verify_one(&di_template
, "foo.target.wants/template2@di.service", 0, NULL
);
1156 verify_one(&di_template
, "foo.target.wants/service", -EXDEV
, NULL
);
1157 verify_one(&di_template
, "foo.target.requires/plain.service", -EXDEV
, NULL
);
1158 verify_one(&di_template
, "foo.target.requires/plain.socket", -EXDEV
, NULL
);
1159 verify_one(&di_template
, "foo.target.requires/plain@.service", -EXDEV
, NULL
);
1160 verify_one(&di_template
, "foo.target.requires/plain@di.service", -EXDEV
, NULL
);
1161 verify_one(&di_template
, "foo.target.requires/plain@foo.service", -EXDEV
, NULL
);
1162 verify_one(&di_template
, "foo.target.requires/template2@.service", -EXDEV
, NULL
); /* instance missing */
1163 verify_one(&di_template
, "foo.target.requires/template2@di.service", 0, NULL
);
1164 verify_one(&di_template
, "foo.target.requires/service", -EXDEV
, NULL
);
1165 verify_one(&di_template
, "foo.target.conf/plain.service", -EXDEV
, NULL
);
1167 verify_one(&inst_template
, "alias.service", -EXDEV
, NULL
);
1168 verify_one(&inst_template
, "alias.socket", -EXDEV
, NULL
);
1169 verify_one(&inst_template
, "alias@.socket", -EXDEV
, NULL
);
1170 verify_one(&inst_template
, "alias@inst.socket", -EXDEV
, NULL
);
1171 verify_one(&inst_template
, "alias@inst.service", 0, NULL
);
1172 verify_one(&inst_template
, "alias@.service", 0, "alias@inst.service");
1173 verify_one(&inst_template
, "alias@di.service", -EXDEV
, NULL
);
1174 verify_one(&inst_template
, "bar.target.wants/plain.service", -EXDEV
, NULL
);
1175 verify_one(&inst_template
, "bar.target.wants/plain.socket", -EXDEV
, NULL
);
1176 verify_one(&inst_template
, "bar.target.wants/plain@.service", -EXDEV
, NULL
);
1177 verify_one(&inst_template
, "bar.target.wants/plain@di.service", -EXDEV
, NULL
);
1178 verify_one(&inst_template
, "bar.target.wants/plain@inst.service", -EXDEV
, NULL
);
1179 verify_one(&inst_template
, "bar.target.wants/template3@foo.service", -EXDEV
, NULL
);
1180 verify_one(&inst_template
, "bar.target.wants/template3@inst.service", 0, NULL
);
1181 verify_one(&inst_template
, "bar.target.wants/service", -EXDEV
, NULL
);
1182 verify_one(&inst_template
, "bar.target.requires/plain.service", -EXDEV
, NULL
);
1183 verify_one(&inst_template
, "bar.target.requires/plain.socket", -EXDEV
, NULL
);
1184 verify_one(&inst_template
, "bar.target.requires/plain@.service", -EXDEV
, NULL
);
1185 verify_one(&inst_template
, "bar.target.requires/plain@di.service", -EXDEV
, NULL
);
1186 verify_one(&inst_template
, "bar.target.requires/plain@inst.service", -EXDEV
, NULL
);
1187 verify_one(&inst_template
, "bar.target.requires/template3@foo.service", -EXDEV
, NULL
);
1188 verify_one(&inst_template
, "bar.target.requires/template3@inst.service", 0, NULL
);
1189 verify_one(&inst_template
, "bar.target.requires/service", -EXDEV
, NULL
);
1190 verify_one(&inst_template
, "bar.target.conf/plain.service", -EXDEV
, NULL
);
1191 verify_one(&inst_template
, "BAR@.target.requires/plain@.service", -EXDEV
, NULL
); /* template name mismatch */
1192 verify_one(&inst_template
, "BAR@inst.target.requires/plain@.service", -EXDEV
, NULL
);
1193 verify_one(&inst_template
, "BAR@inst.target.requires/plain@inst.service", -EXDEV
, NULL
);
1194 verify_one(&inst_template
, "BAR@.target.requires/template3@.service", -EXDEV
, NULL
); /* instance missing */
1195 verify_one(&inst_template
, "BAR@inst.target.requires/template3@.service", -EXDEV
, NULL
); /* instance missing */
1196 verify_one(&inst_template
, "BAR@inst.target.requires/template3@inst.service", 0, NULL
); /* instance provided */
1197 verify_one(&inst_template
, "BAR@inst.target.requires/template3@ins2.service", -EXDEV
, NULL
); /* instance mismatch */
1199 /* explicit alias overrides DefaultInstance */
1200 verify_one(&di_inst_template
, "alias.service", -EXDEV
, NULL
);
1201 verify_one(&di_inst_template
, "alias.socket", -EXDEV
, NULL
);
1202 verify_one(&di_inst_template
, "alias@.socket", -EXDEV
, NULL
);
1203 verify_one(&di_inst_template
, "alias@inst.socket", -EXDEV
, NULL
);
1204 verify_one(&di_inst_template
, "alias@inst.service", 0, NULL
);
1205 verify_one(&di_inst_template
, "alias@.service", 0, "alias@inst.service");
1206 verify_one(&di_inst_template
, "alias@di.service", -EXDEV
, NULL
);
1207 verify_one(&di_inst_template
, "goo.target.wants/plain.service", -EXDEV
, NULL
);
1208 verify_one(&di_inst_template
, "goo.target.wants/plain.socket", -EXDEV
, NULL
);
1209 verify_one(&di_inst_template
, "goo.target.wants/plain@.service", -EXDEV
, NULL
);
1210 verify_one(&di_inst_template
, "goo.target.wants/plain@di.service", -EXDEV
, NULL
);
1211 verify_one(&di_inst_template
, "goo.target.wants/template4@foo.service", -EXDEV
, NULL
);
1212 verify_one(&di_inst_template
, "goo.target.wants/template4@inst.service", 0, NULL
);
1213 verify_one(&di_inst_template
, "goo.target.wants/template4@di.service", -EXDEV
, NULL
);
1214 verify_one(&di_inst_template
, "goo.target.wants/service", -EXDEV
, NULL
);
1215 verify_one(&di_inst_template
, "goo.target.requires/plain.service", -EXDEV
, NULL
);
1216 verify_one(&di_inst_template
, "goo.target.requires/plain.socket", -EXDEV
, NULL
);
1217 verify_one(&di_inst_template
, "goo.target.requires/plain@.service", -EXDEV
, NULL
);
1218 verify_one(&di_inst_template
, "goo.target.requires/plain@di.service", -EXDEV
, NULL
);
1219 verify_one(&di_inst_template
, "goo.target.requires/plain@inst.service", -EXDEV
, NULL
);
1220 verify_one(&di_inst_template
, "goo.target.requires/template4@foo.service", -EXDEV
, NULL
);
1221 verify_one(&di_inst_template
, "goo.target.requires/template4@inst.service", 0, NULL
);
1222 verify_one(&di_inst_template
, "goo.target.requires/service", -EXDEV
, NULL
);
1223 verify_one(&di_inst_template
, "goo.target.conf/plain.service", -EXDEV
, NULL
);
1226 int main(int argc
, char *argv
[]) {
1227 char root
[] = "/tmp/rootXXXXXX";
1230 assert_se(mkdtemp(root
));
1232 p
= strjoina(root
, "/usr/lib/systemd/system/");
1233 assert_se(mkdir_p(p
, 0755) >= 0);
1235 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/");
1236 assert_se(mkdir_p(p
, 0755) >= 0);
1238 p
= strjoina(root
, "/run/systemd/system/");
1239 assert_se(mkdir_p(p
, 0755) >= 0);
1241 p
= strjoina(root
, "/opt/");
1242 assert_se(mkdir_p(p
, 0755) >= 0);
1244 p
= strjoina(root
, "/usr/lib/systemd/system-preset/");
1245 assert_se(mkdir_p(p
, 0755) >= 0);
1247 test_basic_mask_and_enable(root
);
1248 test_linked_units(root
);
1250 test_add_dependency(root
);
1251 test_template_enable(root
);
1252 test_indirect(root
);
1253 test_preset_and_list(root
);
1254 test_preset_order(root
);
1255 test_preset_multiple_instances(root
);
1257 test_static_instance(root
);
1258 test_with_dropin(root
);
1259 test_with_dropin_template(root
);
1261 assert_se(rm_rf(root
, REMOVE_ROOT
|REMOVE_PHYSICAL
) >= 0);
1263 test_verify_alias();