1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
5 #include "alloc-util.h"
12 #include "string-util.h"
14 #include "tmpfile-util.h"
16 static char *root
= NULL
;
18 STATIC_DESTRUCTOR_REGISTER(root
, rm_rf_physical_and_freep
);
20 TEST(basic_mask_and_enable
) {
23 InstallChange
*changes
= NULL
;
26 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "a.service", NULL
) == -ENOENT
);
27 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "b.service", NULL
) == -ENOENT
);
28 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "c.service", NULL
) == -ENOENT
);
29 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "d.service", NULL
) == -ENOENT
);
30 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "e.service", NULL
) == -ENOENT
);
31 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "f.service", NULL
) == -ENOENT
);
33 p
= strjoina(root
, "/usr/lib/systemd/system/a.service");
34 assert_se(write_string_file(p
,
36 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
38 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "a.service", NULL
) >= 0);
39 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "a.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
41 p
= strjoina(root
, "/usr/lib/systemd/system/b.service");
42 assert_se(symlink("a.service", p
) >= 0);
44 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "b.service", NULL
) >= 0);
45 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "b.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
47 p
= strjoina(root
, "/usr/lib/systemd/system/c.service");
48 assert_se(symlink("/usr/lib/systemd/system/a.service", p
) >= 0);
50 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "c.service", NULL
) >= 0);
51 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "c.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
53 p
= strjoina(root
, "/usr/lib/systemd/system/d.service");
54 assert_se(symlink("c.service", p
) >= 0);
56 /* This one is interesting, as d follows a relative, then an absolute symlink */
57 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "d.service", NULL
) >= 0);
58 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "d.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
60 assert_se(unit_file_mask(RUNTIME_SCOPE_SYSTEM
, 0, root
, STRV_MAKE("a.service"), &changes
, &n_changes
) >= 0);
61 assert_se(n_changes
== 1);
62 assert_se(changes
[0].type
== INSTALL_CHANGE_SYMLINK
);
63 ASSERT_STREQ(changes
[0].source
, "/dev/null");
64 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/a.service");
65 ASSERT_STREQ(changes
[0].path
, p
);
67 install_changes_free(changes
, n_changes
);
68 changes
= NULL
; n_changes
= 0;
70 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "a.service", &state
) >= 0 && state
== UNIT_FILE_MASKED
);
71 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "b.service", &state
) >= 0 && state
== UNIT_FILE_MASKED
);
72 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "c.service", &state
) >= 0 && state
== UNIT_FILE_MASKED
);
73 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "d.service", &state
) >= 0 && state
== UNIT_FILE_MASKED
);
75 /* Enabling a masked unit should fail! */
76 assert_se(unit_file_enable(RUNTIME_SCOPE_SYSTEM
, 0, root
, STRV_MAKE("a.service"), &changes
, &n_changes
) == -ERFKILL
);
77 install_changes_free(changes
, n_changes
);
78 changes
= NULL
; n_changes
= 0;
80 assert_se(unit_file_unmask(RUNTIME_SCOPE_SYSTEM
, 0, root
, STRV_MAKE("a.service"), &changes
, &n_changes
) >= 0);
81 assert_se(n_changes
== 1);
82 assert_se(changes
[0].type
== INSTALL_CHANGE_UNLINK
);
83 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/a.service");
84 ASSERT_STREQ(changes
[0].path
, p
);
85 install_changes_free(changes
, n_changes
);
86 changes
= NULL
; n_changes
= 0;
88 assert_se(unit_file_enable(RUNTIME_SCOPE_SYSTEM
, 0, root
, STRV_MAKE("a.service"), &changes
, &n_changes
) == 1);
89 assert_se(n_changes
== 1);
90 assert_se(changes
[0].type
== INSTALL_CHANGE_SYMLINK
);
91 ASSERT_STREQ(changes
[0].source
, "/usr/lib/systemd/system/a.service");
92 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/a.service");
93 ASSERT_STREQ(changes
[0].path
, p
);
94 install_changes_free(changes
, n_changes
);
95 changes
= NULL
; n_changes
= 0;
97 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "a.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
98 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "b.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
99 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "c.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
100 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "d.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
102 /* Enabling it again should succeed but be a NOP */
103 assert_se(unit_file_enable(RUNTIME_SCOPE_SYSTEM
, 0, root
, STRV_MAKE("a.service"), &changes
, &n_changes
) >= 0);
104 assert_se(n_changes
== 0);
105 install_changes_free(changes
, n_changes
);
106 changes
= NULL
; n_changes
= 0;
108 assert_se(unit_file_disable(RUNTIME_SCOPE_SYSTEM
, 0, root
, STRV_MAKE("a.service"), &changes
, &n_changes
) >= 0);
109 assert_se(n_changes
== 1);
110 assert_se(changes
[0].type
== INSTALL_CHANGE_UNLINK
);
111 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/a.service");
112 ASSERT_STREQ(changes
[0].path
, p
);
113 install_changes_free(changes
, n_changes
);
114 changes
= NULL
; n_changes
= 0;
116 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "a.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
117 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "b.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
118 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "c.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
119 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "d.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
121 /* Disabling a disabled unit must succeed but be a NOP */
122 assert_se(unit_file_disable(RUNTIME_SCOPE_SYSTEM
, 0, root
, STRV_MAKE("a.service"), &changes
, &n_changes
) >= 0);
123 assert_se(n_changes
== 0);
124 install_changes_free(changes
, n_changes
);
125 changes
= NULL
; n_changes
= 0;
127 /* Let's enable this indirectly via a symlink */
128 assert_se(unit_file_enable(RUNTIME_SCOPE_SYSTEM
, 0, root
, STRV_MAKE("d.service"), &changes
, &n_changes
) >= 0);
129 assert_se(n_changes
== 1);
130 assert_se(changes
[0].type
== INSTALL_CHANGE_SYMLINK
);
131 ASSERT_STREQ(changes
[0].source
, "/usr/lib/systemd/system/a.service");
132 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/a.service");
133 ASSERT_STREQ(changes
[0].path
, p
);
134 install_changes_free(changes
, n_changes
);
135 changes
= NULL
; n_changes
= 0;
137 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "a.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
138 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "b.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
139 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "c.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
140 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "d.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
142 /* Let's try to reenable */
144 assert_se(unit_file_reenable(RUNTIME_SCOPE_SYSTEM
, 0, root
, STRV_MAKE("b.service"), &changes
, &n_changes
) >= 0);
145 assert_se(n_changes
== 2);
146 assert_se(changes
[0].type
== INSTALL_CHANGE_UNLINK
);
147 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/a.service");
148 ASSERT_STREQ(changes
[0].path
, p
);
149 assert_se(changes
[1].type
== INSTALL_CHANGE_SYMLINK
);
150 ASSERT_STREQ(changes
[1].source
, "/usr/lib/systemd/system/a.service");
151 ASSERT_STREQ(changes
[1].path
, p
);
152 install_changes_free(changes
, n_changes
);
153 changes
= NULL
; n_changes
= 0;
155 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "a.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
156 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "b.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
157 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "c.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
158 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "d.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
160 /* Test masking with relative symlinks */
162 p
= strjoina(root
, "/usr/lib/systemd/system/e.service");
163 assert_se(symlink("../../../../../../dev/null", p
) >= 0);
165 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "e.service", NULL
) >= 0);
166 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "e.service", &state
) >= 0 && state
== UNIT_FILE_MASKED
);
168 assert_se(unlink(p
) == 0);
169 assert_se(symlink("/usr/../dev/null", p
) >= 0);
171 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "e.service", NULL
) >= 0);
172 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "e.service", &state
) >= 0 && state
== UNIT_FILE_MASKED
);
174 assert_se(unlink(p
) == 0);
176 /* Test enabling with unknown dependency target */
178 p
= strjoina(root
, "/usr/lib/systemd/system/f.service");
179 assert_se(write_string_file(p
,
181 "WantedBy=x.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
183 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "f.service", NULL
) >= 0);
184 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "f.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
186 assert_se(unit_file_enable(RUNTIME_SCOPE_SYSTEM
, 0, root
, STRV_MAKE("f.service"), &changes
, &n_changes
) == 1);
187 assert_se(n_changes
== 2);
188 assert_se(changes
[0].type
== INSTALL_CHANGE_SYMLINK
);
189 ASSERT_STREQ(changes
[0].source
, "/usr/lib/systemd/system/f.service");
190 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/x.target.wants/f.service");
191 ASSERT_STREQ(changes
[0].path
, p
);
192 assert_se(changes
[1].type
== INSTALL_CHANGE_DESTINATION_NOT_PRESENT
);
193 p
= strjoina(root
, "/usr/lib/systemd/system/f.service");
194 ASSERT_STREQ(changes
[1].source
, p
);
195 ASSERT_STREQ(changes
[1].path
, "x.target");
196 install_changes_free(changes
, n_changes
);
197 changes
= NULL
; n_changes
= 0;
199 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "f.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
203 const char *p
, *q
, *s
;
205 InstallChange
*changes
= NULL
;
206 size_t n_changes
= 0, i
;
209 * We'll test three cases here:
211 * a) a unit file in /opt, that we use "systemctl link" and
212 * "systemctl enable" on to make it available to the system
214 * b) a unit file in /opt, that is statically linked into
215 * /usr/lib/systemd/system, that "enable" should work on
218 * c) a unit file in /opt, that is linked into
219 * /etc/systemd/system, and where "enable" should result in
220 * -ELOOP, since using information from /etc to generate
221 * information in /etc should not be allowed.
224 p
= strjoina(root
, "/opt/linked.service");
225 assert_se(write_string_file(p
,
227 "Alias=linked-alias.service\n"
228 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
230 p
= strjoina(root
, "/opt/linked2.service");
231 assert_se(write_string_file(p
,
233 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
235 p
= strjoina(root
, "/opt/linked3.service");
236 assert_se(write_string_file(p
,
238 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
240 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "linked.service", NULL
) == -ENOENT
);
241 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "linked2.service", NULL
) == -ENOENT
);
242 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "linked3.service", NULL
) == -ENOENT
);
244 p
= strjoina(root
, "/usr/lib/systemd/system/linked2.service");
245 assert_se(symlink("/opt/linked2.service", p
) >= 0);
247 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/linked3.service");
248 assert_se(symlink("/opt/linked3.service", p
) >= 0);
250 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "linked.service", &state
) == -ENOENT
);
251 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "linked2.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
252 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "linked3.service", &state
) >= 0 && state
== UNIT_FILE_LINKED
);
254 /* First, let's link the unit into the search path */
255 assert_se(unit_file_link(RUNTIME_SCOPE_SYSTEM
, 0, root
, STRV_MAKE("/opt/linked.service"), &changes
, &n_changes
) >= 0);
256 assert_se(n_changes
== 1);
257 assert_se(changes
[0].type
== INSTALL_CHANGE_SYMLINK
);
258 ASSERT_STREQ(changes
[0].source
, "/opt/linked.service");
259 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/linked.service");
260 ASSERT_STREQ(changes
[0].path
, p
);
261 install_changes_free(changes
, n_changes
);
262 changes
= NULL
; n_changes
= 0;
264 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "linked.service", &state
) >= 0 && state
== UNIT_FILE_LINKED
);
266 /* Let's unlink it from the search path again */
267 assert_se(unit_file_disable(RUNTIME_SCOPE_SYSTEM
, 0, root
, STRV_MAKE("linked.service"), &changes
, &n_changes
) >= 0);
268 assert_se(n_changes
== 1);
269 assert_se(changes
[0].type
== INSTALL_CHANGE_UNLINK
);
270 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/linked.service");
271 ASSERT_STREQ(changes
[0].path
, p
);
272 install_changes_free(changes
, n_changes
);
273 changes
= NULL
; n_changes
= 0;
275 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "linked.service", NULL
) == -ENOENT
);
277 /* Now, let's not just link it, but also enable it */
278 assert_se(unit_file_enable(RUNTIME_SCOPE_SYSTEM
, 0, root
, STRV_MAKE("/opt/linked.service"), &changes
, &n_changes
) >= 0);
279 assert_se(n_changes
== 3);
280 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/linked.service");
281 q
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/linked.service");
282 s
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/linked-alias.service");
283 for (i
= 0 ; i
< n_changes
; i
++) {
284 assert_se(changes
[i
].type
== INSTALL_CHANGE_SYMLINK
);
286 if (s
&& streq(changes
[i
].path
, s
))
287 /* The alias symlink should point within the search path. */
288 ASSERT_STREQ(changes
[i
].source
, SYSTEM_CONFIG_UNIT_DIR
"/linked.service");
290 ASSERT_STREQ(changes
[i
].source
, "/opt/linked.service");
292 if (p
&& streq(changes
[i
].path
, p
))
294 else if (q
&& streq(changes
[i
].path
, q
))
296 else if (s
&& streq(changes
[i
].path
, s
))
299 assert_not_reached();
301 assert_se(!p
&& !q
&& !s
);
302 install_changes_free(changes
, n_changes
);
303 changes
= NULL
; n_changes
= 0;
305 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "linked.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
306 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "linked-alias.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
308 /* And let's unlink it again */
309 assert_se(unit_file_disable(RUNTIME_SCOPE_SYSTEM
, 0, root
, STRV_MAKE("linked.service"), &changes
, &n_changes
) >= 0);
310 assert_se(n_changes
== 3);
311 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/linked.service");
312 q
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/linked.service");
313 s
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/linked-alias.service");
314 for (i
= 0; i
< n_changes
; i
++) {
315 assert_se(changes
[i
].type
== INSTALL_CHANGE_UNLINK
);
317 if (p
&& streq(changes
[i
].path
, p
))
319 else if (q
&& streq(changes
[i
].path
, q
))
321 else if (s
&& streq(changes
[i
].path
, s
))
324 assert_not_reached();
326 assert_se(!p
&& !q
&& !s
);
327 install_changes_free(changes
, n_changes
);
328 changes
= NULL
; n_changes
= 0;
330 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "linked.service", NULL
) == -ENOENT
);
332 assert_se(unit_file_enable(RUNTIME_SCOPE_SYSTEM
, 0, root
, STRV_MAKE("linked2.service"), &changes
, &n_changes
) >= 0);
333 assert_se(n_changes
== 2);
334 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/linked2.service");
335 q
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/linked2.service");
336 for (i
= 0 ; i
< n_changes
; i
++) {
337 assert_se(changes
[i
].type
== INSTALL_CHANGE_SYMLINK
);
338 ASSERT_STREQ(changes
[i
].source
, "/opt/linked2.service");
340 if (p
&& streq(changes
[i
].path
, p
))
342 else if (q
&& streq(changes
[i
].path
, q
))
345 assert_not_reached();
348 install_changes_free(changes
, n_changes
);
349 changes
= NULL
; n_changes
= 0;
351 assert_se(unit_file_enable(RUNTIME_SCOPE_SYSTEM
, 0, root
, STRV_MAKE("linked3.service"), &changes
, &n_changes
) >= 0);
352 assert_se(n_changes
== 1);
353 assert_se(changes
[0].type
== INSTALL_CHANGE_SYMLINK
);
354 assert_se(startswith(changes
[0].path
, root
));
355 assert_se(endswith(changes
[0].path
, "linked3.service"));
356 ASSERT_STREQ(changes
[0].source
, "/opt/linked3.service");
357 install_changes_free(changes
, n_changes
);
358 changes
= NULL
; n_changes
= 0;
362 _cleanup_free_
char *def
= NULL
;
363 InstallChange
*changes
= NULL
;
364 size_t n_changes
= 0;
367 p
= strjoina(root
, "/usr/lib/systemd/system/test-default-real.target");
368 assert_se(write_string_file(p
, "# pretty much empty", WRITE_STRING_FILE_CREATE
) >= 0);
370 p
= strjoina(root
, "/usr/lib/systemd/system/test-default.target");
371 assert_se(symlink("test-default-real.target", p
) >= 0);
373 assert_se(unit_file_get_default(RUNTIME_SCOPE_SYSTEM
, root
, &def
) == -ENOENT
);
375 assert_se(unit_file_set_default(RUNTIME_SCOPE_SYSTEM
, 0, root
, "idontexist.target", &changes
, &n_changes
) == -ENOENT
);
376 assert_se(n_changes
== 1);
377 assert_se(changes
[0].type
== -ENOENT
);
378 ASSERT_STREQ(changes
[0].path
, "idontexist.target");
379 install_changes_free(changes
, n_changes
);
380 changes
= NULL
; n_changes
= 0;
382 assert_se(unit_file_get_default(RUNTIME_SCOPE_SYSTEM
, root
, &def
) == -ENOENT
);
384 assert_se(unit_file_set_default(RUNTIME_SCOPE_SYSTEM
, 0, root
, "test-default.target", &changes
, &n_changes
) >= 0);
385 assert_se(n_changes
== 1);
386 assert_se(changes
[0].type
== INSTALL_CHANGE_SYMLINK
);
387 ASSERT_STREQ(changes
[0].source
, "/usr/lib/systemd/system/test-default-real.target");
388 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/" SPECIAL_DEFAULT_TARGET
);
389 ASSERT_STREQ(changes
[0].path
, p
);
390 install_changes_free(changes
, n_changes
);
391 changes
= NULL
; n_changes
= 0;
393 assert_se(unit_file_get_default(RUNTIME_SCOPE_SYSTEM
, root
, &def
) >= 0);
394 ASSERT_STREQ(def
, "test-default-real.target");
397 TEST(add_dependency
) {
398 InstallChange
*changes
= NULL
;
399 size_t n_changes
= 0;
402 p
= strjoina(root
, "/usr/lib/systemd/system/real-add-dependency-test-target.target");
403 assert_se(write_string_file(p
, "# pretty much empty", WRITE_STRING_FILE_CREATE
) >= 0);
405 p
= strjoina(root
, "/usr/lib/systemd/system/add-dependency-test-target.target");
406 assert_se(symlink("real-add-dependency-test-target.target", p
) >= 0);
408 p
= strjoina(root
, "/usr/lib/systemd/system/real-add-dependency-test-service.service");
409 assert_se(write_string_file(p
, "# pretty much empty", WRITE_STRING_FILE_CREATE
) >= 0);
411 p
= strjoina(root
, "/usr/lib/systemd/system/add-dependency-test-service.service");
412 assert_se(symlink("real-add-dependency-test-service.service", p
) >= 0);
414 assert_se(unit_file_add_dependency(RUNTIME_SCOPE_SYSTEM
, 0, root
, STRV_MAKE("add-dependency-test-service.service"), "add-dependency-test-target.target", UNIT_WANTS
, &changes
, &n_changes
) >= 0);
415 assert_se(n_changes
== 1);
416 assert_se(changes
[0].type
== INSTALL_CHANGE_SYMLINK
);
417 ASSERT_STREQ(changes
[0].source
, "/usr/lib/systemd/system/real-add-dependency-test-service.service");
418 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/real-add-dependency-test-target.target.wants/real-add-dependency-test-service.service");
419 ASSERT_STREQ(changes
[0].path
, p
);
420 install_changes_free(changes
, n_changes
);
421 changes
= NULL
; n_changes
= 0;
424 TEST(template_enable
) {
425 InstallChange
*changes
= NULL
;
426 size_t n_changes
= 0;
430 log_info("== %s ==", __func__
);
432 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "template@.service", &state
) == -ENOENT
);
433 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "template@def.service", &state
) == -ENOENT
);
434 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "template@foo.service", &state
) == -ENOENT
);
435 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "template-symlink@foo.service", &state
) == -ENOENT
);
437 p
= strjoina(root
, "/usr/lib/systemd/system/template@.service");
438 assert_se(write_string_file(p
,
440 "DefaultInstance=def\n"
441 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
443 p
= strjoina(root
, "/usr/lib/systemd/system/template-symlink@.service");
444 assert_se(symlink("template@.service", p
) >= 0);
446 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "template@.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
447 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "template@def.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
448 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "template@foo.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
449 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "template-symlink@.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
450 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "template-symlink@def.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
451 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "template-symlink@foo.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
453 log_info("== %s with template@.service enabled ==", __func__
);
455 assert_se(unit_file_enable(RUNTIME_SCOPE_SYSTEM
, 0, root
, STRV_MAKE("template@.service"), &changes
, &n_changes
) >= 0);
456 assert_se(n_changes
== 1);
457 assert_se(changes
[0].type
== INSTALL_CHANGE_SYMLINK
);
458 ASSERT_STREQ(changes
[0].source
, "/usr/lib/systemd/system/template@.service");
459 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/template@def.service");
460 ASSERT_STREQ(changes
[0].path
, p
);
461 install_changes_free(changes
, n_changes
);
462 changes
= NULL
; n_changes
= 0;
464 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "template@.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
465 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "template@def.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
466 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "template@foo.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
467 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "template-symlink@.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
468 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "template-symlink@def.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
469 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "template-symlink@foo.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
471 assert_se(unit_file_disable(RUNTIME_SCOPE_SYSTEM
, 0, root
, STRV_MAKE("template@.service"), &changes
, &n_changes
) >= 0);
472 assert_se(n_changes
== 1);
473 assert_se(changes
[0].type
== INSTALL_CHANGE_UNLINK
);
474 ASSERT_STREQ(changes
[0].path
, p
);
475 install_changes_free(changes
, n_changes
);
476 changes
= NULL
; n_changes
= 0;
478 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "template@.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
479 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "template@def.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
480 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "template@foo.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
481 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "template-symlink@.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
482 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "template-symlink@def.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
483 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "template-symlink@foo.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
485 log_info("== %s with template@foo.service enabled ==", __func__
);
487 assert_se(unit_file_enable(RUNTIME_SCOPE_SYSTEM
, 0, root
, STRV_MAKE("template@foo.service"), &changes
, &n_changes
) >= 0);
488 assert_se(changes
[0].type
== INSTALL_CHANGE_SYMLINK
);
489 ASSERT_STREQ(changes
[0].source
, "/usr/lib/systemd/system/template@.service");
490 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/template@foo.service");
491 ASSERT_STREQ(changes
[0].path
, p
);
492 install_changes_free(changes
, n_changes
);
493 changes
= NULL
; n_changes
= 0;
495 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "template@.service", &state
) >= 0 && state
== UNIT_FILE_INDIRECT
);
496 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "template@def.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
497 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "template@foo.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
498 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "template-symlink@foo.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
499 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "template-symlink@def.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
500 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "template-symlink@foo.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
502 assert_se(unit_file_disable(RUNTIME_SCOPE_SYSTEM
, 0, root
, STRV_MAKE("template@foo.service"), &changes
, &n_changes
) >= 0);
503 assert_se(n_changes
== 1);
504 assert_se(changes
[0].type
== INSTALL_CHANGE_UNLINK
);
505 ASSERT_STREQ(changes
[0].path
, p
);
506 install_changes_free(changes
, n_changes
);
507 changes
= NULL
; n_changes
= 0;
509 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "template@.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
510 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "template@def.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
511 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "template@foo.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
512 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "template@quux.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
513 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "template-symlink@.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
514 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "template-symlink@def.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
515 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "template-symlink@foo.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
516 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "template-symlink@quux.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
518 log_info("== %s with template-symlink@quux.service enabled ==", __func__
);
520 assert_se(unit_file_enable(RUNTIME_SCOPE_SYSTEM
, 0, root
, STRV_MAKE("template-symlink@quux.service"), &changes
, &n_changes
) >= 0);
521 assert_se(changes
[0].type
== INSTALL_CHANGE_SYMLINK
);
522 ASSERT_STREQ(changes
[0].source
, "/usr/lib/systemd/system/template@.service");
523 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/template@quux.service");
524 ASSERT_STREQ(changes
[0].path
, p
);
525 install_changes_free(changes
, n_changes
);
526 changes
= NULL
; n_changes
= 0;
528 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "template@.service", &state
) >= 0 && state
== UNIT_FILE_INDIRECT
);
529 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "template@def.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
530 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "template@foo.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
531 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "template@quux.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
532 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "template-symlink@.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
533 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "template-symlink@def.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
534 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "template-symlink@foo.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
535 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "template-symlink@quux.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
539 InstallChange
*changes
= NULL
;
540 size_t n_changes
= 0;
544 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "indirecta.service", &state
) == -ENOENT
);
545 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "indirectb.service", &state
) == -ENOENT
);
546 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "indirectc.service", &state
) == -ENOENT
);
548 p
= strjoina(root
, "/usr/lib/systemd/system/indirecta.service");
549 assert_se(write_string_file(p
,
551 "Also=indirectb.service\n", WRITE_STRING_FILE_CREATE
) >= 0);
553 p
= strjoina(root
, "/usr/lib/systemd/system/indirectb.service");
554 assert_se(write_string_file(p
,
556 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
558 p
= strjoina(root
, "/usr/lib/systemd/system/indirectc.service");
559 assert_se(symlink("indirecta.service", p
) >= 0);
561 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "indirecta.service", &state
) >= 0 && state
== UNIT_FILE_INDIRECT
);
562 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "indirectb.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
563 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "indirectc.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
565 assert_se(unit_file_enable(RUNTIME_SCOPE_SYSTEM
, 0, root
, STRV_MAKE("indirectc.service"), &changes
, &n_changes
) >= 0);
566 assert_se(n_changes
== 1);
567 assert_se(changes
[0].type
== INSTALL_CHANGE_SYMLINK
);
568 ASSERT_STREQ(changes
[0].source
, "/usr/lib/systemd/system/indirectb.service");
569 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/indirectb.service");
570 ASSERT_STREQ(changes
[0].path
, p
);
571 install_changes_free(changes
, n_changes
);
572 changes
= NULL
; n_changes
= 0;
574 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "indirecta.service", &state
) >= 0 && state
== UNIT_FILE_INDIRECT
);
575 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "indirectb.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
576 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "indirectc.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
578 assert_se(unit_file_disable(RUNTIME_SCOPE_SYSTEM
, 0, root
, STRV_MAKE("indirectc.service"), &changes
, &n_changes
) >= 0);
579 assert_se(n_changes
== 1);
580 assert_se(changes
[0].type
== INSTALL_CHANGE_UNLINK
);
581 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/indirectb.service");
582 ASSERT_STREQ(changes
[0].path
, p
);
583 install_changes_free(changes
, n_changes
);
584 changes
= NULL
; n_changes
= 0;
587 TEST(preset_and_list
) {
588 InstallChange
*changes
= NULL
;
589 size_t n_changes
= 0, i
;
592 bool got_yes
= false, got_no
= false;
594 _cleanup_hashmap_free_ Hashmap
*h
= NULL
;
596 CLEANUP_ARRAY(changes
, n_changes
, install_changes_free
);
598 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "preset-yes.service", &state
) == -ENOENT
);
599 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "preset-no.service", &state
) == -ENOENT
);
600 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "preset-ignore.service", &state
) == -ENOENT
);
602 p
= strjoina(root
, "/usr/lib/systemd/system/preset-yes.service");
603 assert_se(write_string_file(p
,
605 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
607 p
= strjoina(root
, "/usr/lib/systemd/system/preset-no.service");
608 assert_se(write_string_file(p
,
610 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
612 p
= strjoina(root
, "/usr/lib/systemd/system/preset-ignore.service");
613 assert_se(write_string_file(p
,
615 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
617 p
= strjoina(root
, "/usr/lib/systemd/system-preset/test.preset");
618 assert_se(write_string_file(p
,
620 "ignore *-ignore.*\n"
621 "disable *\n", WRITE_STRING_FILE_CREATE
) >= 0);
623 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "preset-yes.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
624 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "preset-no.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
625 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "preset-ignore.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
627 assert_se(unit_file_preset(RUNTIME_SCOPE_SYSTEM
, 0, root
, STRV_MAKE("preset-yes.service"), UNIT_FILE_PRESET_FULL
, &changes
, &n_changes
) >= 0);
628 assert_se(n_changes
== 1);
629 assert_se(changes
[0].type
== INSTALL_CHANGE_SYMLINK
);
630 ASSERT_STREQ(changes
[0].source
, "/usr/lib/systemd/system/preset-yes.service");
631 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/preset-yes.service");
632 ASSERT_STREQ(changes
[0].path
, p
);
633 install_changes_free(changes
, n_changes
);
634 changes
= NULL
; n_changes
= 0;
636 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "preset-yes.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
637 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "preset-no.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
638 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "preset-ignore.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
640 assert_se(unit_file_disable(RUNTIME_SCOPE_SYSTEM
, 0, root
, STRV_MAKE("preset-yes.service"), &changes
, &n_changes
) >= 0);
641 assert_se(n_changes
== 1);
642 assert_se(changes
[0].type
== INSTALL_CHANGE_UNLINK
);
643 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/preset-yes.service");
644 ASSERT_STREQ(changes
[0].path
, p
);
645 install_changes_free(changes
, n_changes
);
646 changes
= NULL
; n_changes
= 0;
648 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "preset-yes.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
649 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "preset-no.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
650 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "preset-ignore.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
652 assert_se(unit_file_preset(RUNTIME_SCOPE_SYSTEM
, 0, root
, STRV_MAKE("preset-no.service"), UNIT_FILE_PRESET_FULL
, &changes
, &n_changes
) >= 0);
653 assert_se(n_changes
== 0);
654 install_changes_free(changes
, n_changes
);
655 changes
= NULL
; n_changes
= 0;
657 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "preset-yes.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
658 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "preset-no.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
659 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "preset-ignore.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
661 assert_se(unit_file_preset_all(RUNTIME_SCOPE_SYSTEM
, 0, root
, UNIT_FILE_PRESET_FULL
, &changes
, &n_changes
) >= 0);
663 assert_se(n_changes
> 0);
665 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/preset-yes.service");
667 for (i
= 0; i
< n_changes
; i
++) {
669 if (changes
[i
].type
== INSTALL_CHANGE_SYMLINK
) {
670 ASSERT_STREQ(changes
[i
].source
, "/usr/lib/systemd/system/preset-yes.service");
671 ASSERT_STREQ(changes
[i
].path
, p
);
673 assert_se(changes
[i
].type
== INSTALL_CHANGE_UNLINK
);
676 install_changes_free(changes
, n_changes
);
677 changes
= NULL
; n_changes
= 0;
679 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "preset-yes.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
680 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "preset-no.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
681 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "preset-ignore.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
683 assert_se(h
= hashmap_new(&unit_file_list_hash_ops_free
));
684 assert_se(unit_file_get_list(RUNTIME_SCOPE_SYSTEM
, root
, h
, NULL
, NULL
) >= 0);
686 p
= strjoina(root
, "/usr/lib/systemd/system/preset-yes.service");
687 q
= strjoina(root
, "/usr/lib/systemd/system/preset-no.service");
689 HASHMAP_FOREACH(fl
, h
) {
690 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, basename(fl
->path
), &state
) >= 0);
691 assert_se(fl
->state
== state
);
693 if (streq(fl
->path
, p
)) {
695 assert_se(fl
->state
== UNIT_FILE_ENABLED
);
696 } else if (streq(fl
->path
, q
)) {
698 assert_se(fl
->state
== UNIT_FILE_DISABLED
);
700 assert_se(IN_SET(fl
->state
, UNIT_FILE_DISABLED
, UNIT_FILE_STATIC
, UNIT_FILE_INDIRECT
, UNIT_FILE_ALIAS
));
703 assert_se(got_yes
&& got_no
);
705 assert_se(unit_file_enable(RUNTIME_SCOPE_SYSTEM
, 0, root
, STRV_MAKE("preset-ignore.service"), &changes
, &n_changes
) >= 0);
706 assert_se(unit_file_preset(RUNTIME_SCOPE_SYSTEM
, 0, root
, STRV_MAKE("preset-ignore.service"), UNIT_FILE_PRESET_FULL
, &changes
, &n_changes
) >= 0);
707 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "preset-ignore.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
713 InstallChange
*changes
= NULL
;
714 size_t n_changes
= 0;
716 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "xx.service", NULL
) == -ENOENT
);
717 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "yy.service", NULL
) == -ENOENT
);
719 p
= strjoina(root
, "/usr/lib/systemd/system/xx.service");
720 assert_se(write_string_file(p
, "# Empty\n", WRITE_STRING_FILE_CREATE
) >= 0);
722 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "xx.service", NULL
) >= 0);
723 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "xx.service", &state
) >= 0 && state
== UNIT_FILE_STATIC
);
725 /* Initially there's nothing to revert */
726 assert_se(unit_file_revert(RUNTIME_SCOPE_SYSTEM
, root
, STRV_MAKE("xx.service"), &changes
, &n_changes
) >= 0);
727 assert_se(n_changes
== 0);
728 install_changes_free(changes
, n_changes
);
729 changes
= NULL
; n_changes
= 0;
731 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/xx.service");
732 assert_se(write_string_file(p
, "# Empty override\n", WRITE_STRING_FILE_CREATE
) >= 0);
734 /* Revert the override file */
735 assert_se(unit_file_revert(RUNTIME_SCOPE_SYSTEM
, root
, STRV_MAKE("xx.service"), &changes
, &n_changes
) >= 0);
736 assert_se(n_changes
== 1);
737 assert_se(changes
[0].type
== INSTALL_CHANGE_UNLINK
);
738 ASSERT_STREQ(changes
[0].path
, p
);
739 install_changes_free(changes
, n_changes
);
740 changes
= NULL
; n_changes
= 0;
742 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/xx.service.d/dropin.conf");
743 assert_se(write_string_file(p
, "# Empty dropin\n", WRITE_STRING_FILE_CREATE
|WRITE_STRING_FILE_MKDIR_0755
) >= 0);
745 /* Revert the dropin file */
746 assert_se(unit_file_revert(RUNTIME_SCOPE_SYSTEM
, root
, STRV_MAKE("xx.service"), &changes
, &n_changes
) >= 0);
747 assert_se(n_changes
== 2);
748 assert_se(changes
[0].type
== INSTALL_CHANGE_UNLINK
);
749 ASSERT_STREQ(changes
[0].path
, p
);
751 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/xx.service.d");
752 assert_se(changes
[1].type
== INSTALL_CHANGE_UNLINK
);
753 ASSERT_STREQ(changes
[1].path
, p
);
754 install_changes_free(changes
, n_changes
);
755 changes
= NULL
; n_changes
= 0;
759 InstallChange
*changes
= NULL
;
760 size_t n_changes
= 0;
764 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "prefix-1.service", &state
) == -ENOENT
);
765 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "prefix-2.service", &state
) == -ENOENT
);
767 p
= strjoina(root
, "/usr/lib/systemd/system/prefix-1.service");
768 assert_se(write_string_file(p
,
770 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
772 p
= strjoina(root
, "/usr/lib/systemd/system/prefix-2.service");
773 assert_se(write_string_file(p
,
775 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
777 p
= strjoina(root
, "/usr/lib/systemd/system-preset/test.preset");
778 assert_se(write_string_file(p
,
779 "enable prefix-1.service\n"
780 "disable prefix-*.service\n"
781 "enable prefix-2.service\n", WRITE_STRING_FILE_CREATE
) >= 0);
783 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "prefix-1.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
784 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "prefix-2.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
786 assert_se(unit_file_preset(RUNTIME_SCOPE_SYSTEM
, 0, root
, STRV_MAKE("prefix-1.service"), UNIT_FILE_PRESET_FULL
, &changes
, &n_changes
) >= 0);
787 assert_se(n_changes
== 1);
788 assert_se(changes
[0].type
== INSTALL_CHANGE_SYMLINK
);
789 ASSERT_STREQ(changes
[0].source
, "/usr/lib/systemd/system/prefix-1.service");
790 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/prefix-1.service");
791 ASSERT_STREQ(changes
[0].path
, p
);
792 install_changes_free(changes
, n_changes
);
793 changes
= NULL
; n_changes
= 0;
795 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "prefix-1.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
796 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "prefix-2.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
798 assert_se(unit_file_preset(RUNTIME_SCOPE_SYSTEM
, 0, root
, STRV_MAKE("prefix-2.service"), UNIT_FILE_PRESET_FULL
, &changes
, &n_changes
) >= 0);
799 assert_se(n_changes
== 0);
801 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "prefix-1.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
802 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "prefix-2.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
805 TEST(static_instance
) {
809 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "static-instance@.service", &state
) == -ENOENT
);
810 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "static-instance@foo.service", &state
) == -ENOENT
);
812 p
= strjoina(root
, "/usr/lib/systemd/system/static-instance@.service");
813 assert_se(write_string_file(p
,
815 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
817 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "static-instance@.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
818 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "static-instance@foo.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
820 p
= strjoina(root
, "/usr/lib/systemd/system/static-instance@foo.service");
821 assert_se(symlink("static-instance@.service", p
) >= 0);
823 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "static-instance@.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
824 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "static-instance@foo.service", &state
) >= 0 && state
== UNIT_FILE_STATIC
);
830 InstallChange
*changes
= NULL
;
831 size_t n_changes
= 0;
833 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "with-dropin-1.service", &state
) == -ENOENT
);
834 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "with-dropin-2.service", &state
) == -ENOENT
);
835 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "with-dropin-3.service", &state
) == -ENOENT
);
836 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "with-dropin-4a.service", &state
) == -ENOENT
);
837 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "with-dropin-4b.service", &state
) == -ENOENT
);
839 p
= strjoina(root
, "/usr/lib/systemd/system/with-dropin-1.service");
840 assert_se(write_string_file(p
,
842 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
844 p
= strjoina(root
, "/usr/lib/systemd/system/with-dropin-1.service.d/dropin.conf");
845 assert_se(write_string_file(p
,
847 "WantedBy=graphical.target\n", WRITE_STRING_FILE_CREATE
|WRITE_STRING_FILE_MKDIR_0755
) >= 0);
849 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "with-dropin-1.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
851 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/with-dropin-2.service");
852 assert_se(write_string_file(p
,
854 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
856 p
= strjoina(root
, "/usr/lib/systemd/system/with-dropin-2.service.d/dropin.conf");
857 assert_se(write_string_file(p
,
859 "WantedBy=graphical.target\n", WRITE_STRING_FILE_CREATE
|WRITE_STRING_FILE_MKDIR_0755
) >= 0);
861 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "with-dropin-2.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
863 p
= strjoina(root
, "/usr/lib/systemd/system/with-dropin-3.service");
864 assert_se(write_string_file(p
,
866 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
868 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/with-dropin-3.service.d/dropin.conf");
869 assert_se(write_string_file(p
,
871 "WantedBy=graphical.target\n", WRITE_STRING_FILE_CREATE
|WRITE_STRING_FILE_MKDIR_0755
) >= 0);
873 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "with-dropin-3.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
875 p
= strjoina(root
, "/usr/lib/systemd/system/with-dropin-4a.service");
876 assert_se(write_string_file(p
,
878 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
880 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/with-dropin-4a.service.d/dropin.conf");
881 assert_se(write_string_file(p
,
883 "Also=with-dropin-4b.service\n", WRITE_STRING_FILE_CREATE
|WRITE_STRING_FILE_MKDIR_0755
) >= 0);
885 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "with-dropin-4a.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
887 p
= strjoina(root
, "/usr/lib/systemd/system/with-dropin-4b.service");
888 assert_se(write_string_file(p
,
890 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
892 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "with-dropin-4b.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
894 assert_se(unit_file_enable(RUNTIME_SCOPE_SYSTEM
, 0, root
, STRV_MAKE("with-dropin-1.service"), &changes
, &n_changes
) == 1);
895 assert_se(n_changes
== 2);
896 assert_se(changes
[0].type
== INSTALL_CHANGE_SYMLINK
);
897 assert_se(changes
[1].type
== INSTALL_CHANGE_SYMLINK
);
898 ASSERT_STREQ(changes
[0].source
, "/usr/lib/systemd/system/with-dropin-1.service");
899 ASSERT_STREQ(changes
[1].source
, "/usr/lib/systemd/system/with-dropin-1.service");
900 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/with-dropin-1.service");
901 ASSERT_STREQ(changes
[0].path
, p
);
902 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/graphical.target.wants/with-dropin-1.service");
903 ASSERT_STREQ(changes
[1].path
, p
);
904 install_changes_free(changes
, n_changes
);
905 changes
= NULL
; n_changes
= 0;
907 assert_se(unit_file_enable(RUNTIME_SCOPE_SYSTEM
, 0, root
, STRV_MAKE("with-dropin-2.service"), &changes
, &n_changes
) == 1);
908 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "with-dropin-2.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
909 assert_se(n_changes
== 2);
910 assert_se(changes
[0].type
== INSTALL_CHANGE_SYMLINK
);
911 assert_se(changes
[1].type
== INSTALL_CHANGE_SYMLINK
);
912 ASSERT_STREQ(changes
[0].source
, SYSTEM_CONFIG_UNIT_DIR
"/with-dropin-2.service");
913 ASSERT_STREQ(changes
[1].source
, SYSTEM_CONFIG_UNIT_DIR
"/with-dropin-2.service");
914 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/with-dropin-2.service");
915 ASSERT_STREQ(changes
[0].path
, p
);
916 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/graphical.target.wants/with-dropin-2.service");
917 ASSERT_STREQ(changes
[1].path
, p
);
918 install_changes_free(changes
, n_changes
);
919 changes
= NULL
; n_changes
= 0;
921 assert_se(unit_file_enable(RUNTIME_SCOPE_SYSTEM
, 0, root
, STRV_MAKE("with-dropin-3.service"), &changes
, &n_changes
) == 1);
922 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "with-dropin-3.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
923 assert_se(n_changes
== 2);
924 assert_se(changes
[0].type
== INSTALL_CHANGE_SYMLINK
);
925 assert_se(changes
[1].type
== INSTALL_CHANGE_SYMLINK
);
926 ASSERT_STREQ(changes
[0].source
, "/usr/lib/systemd/system/with-dropin-3.service");
927 ASSERT_STREQ(changes
[1].source
, "/usr/lib/systemd/system/with-dropin-3.service");
928 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/with-dropin-3.service");
929 ASSERT_STREQ(changes
[0].path
, p
);
930 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/graphical.target.wants/with-dropin-3.service");
931 ASSERT_STREQ(changes
[1].path
, p
);
932 install_changes_free(changes
, n_changes
);
933 changes
= NULL
; n_changes
= 0;
935 assert_se(unit_file_enable(RUNTIME_SCOPE_SYSTEM
, 0, root
, STRV_MAKE("with-dropin-4a.service"), &changes
, &n_changes
) == 2);
936 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "with-dropin-3.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
937 assert_se(n_changes
== 2);
938 assert_se(changes
[0].type
== INSTALL_CHANGE_SYMLINK
);
939 assert_se(changes
[1].type
== INSTALL_CHANGE_SYMLINK
);
940 ASSERT_STREQ(changes
[0].source
, "/usr/lib/systemd/system/with-dropin-4a.service");
941 ASSERT_STREQ(changes
[1].source
, "/usr/lib/systemd/system/with-dropin-4b.service");
942 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/with-dropin-4a.service");
943 ASSERT_STREQ(changes
[0].path
, p
);
944 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/with-dropin-4b.service");
945 ASSERT_STREQ(changes
[1].path
, p
);
946 install_changes_free(changes
, n_changes
);
947 changes
= NULL
; n_changes
= 0;
949 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "with-dropin-1.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
950 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "with-dropin-2.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
951 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "with-dropin-3.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
952 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "with-dropin-4a.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
953 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "with-dropin-4b.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
956 TEST(with_dropin_template
) {
959 InstallChange
*changes
= NULL
;
960 size_t n_changes
= 0;
962 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "with-dropin-1@.service", &state
) == -ENOENT
);
963 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "with-dropin-2@.service", &state
) == -ENOENT
);
964 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "with-dropin-3@.service", &state
) == -ENOENT
);
966 p
= strjoina(root
, "/usr/lib/systemd/system/with-dropin-1@.service");
967 assert_se(write_string_file(p
,
969 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
971 p
= strjoina(root
, "/usr/lib/systemd/system/with-dropin-1@.service.d/dropin.conf");
972 assert_se(write_string_file(p
,
974 "WantedBy=graphical.target\n", WRITE_STRING_FILE_CREATE
|WRITE_STRING_FILE_MKDIR_0755
) >= 0);
976 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "with-dropin-1@.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
978 p
= strjoina(root
, "/usr/lib/systemd/system/with-dropin-2@.service");
979 assert_se(write_string_file(p
,
981 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
983 p
= strjoina(root
, "/usr/lib/systemd/system/with-dropin-2@instance-1.service.d/dropin.conf");
984 assert_se(write_string_file(p
,
986 "WantedBy=graphical.target\n", WRITE_STRING_FILE_CREATE
|WRITE_STRING_FILE_MKDIR_0755
) >= 0);
988 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "with-dropin-2@.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
990 p
= strjoina(root
, "/usr/lib/systemd/system/with-dropin-3@.service");
991 assert_se(write_string_file(p
,
993 "DefaultInstance=instance-1\n"
994 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
996 p
= strjoina(root
, "/usr/lib/systemd/system/with-dropin-3@.service.d/dropin.conf");
997 assert_se(write_string_file(p
,
999 "DefaultInstance=instance-2\n", WRITE_STRING_FILE_CREATE
|WRITE_STRING_FILE_MKDIR_0755
) >= 0);
1001 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "with-dropin-3@.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
1003 assert_se(unit_file_enable(RUNTIME_SCOPE_SYSTEM
, 0, root
, STRV_MAKE("with-dropin-1@instance-1.service"), &changes
, &n_changes
) == 1);
1004 assert_se(n_changes
== 2);
1005 assert_se(changes
[0].type
== INSTALL_CHANGE_SYMLINK
);
1006 assert_se(changes
[1].type
== INSTALL_CHANGE_SYMLINK
);
1007 ASSERT_STREQ(changes
[0].source
, "/usr/lib/systemd/system/with-dropin-1@.service");
1008 ASSERT_STREQ(changes
[1].source
, "/usr/lib/systemd/system/with-dropin-1@.service");
1009 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/with-dropin-1@instance-1.service");
1010 ASSERT_STREQ(changes
[0].path
, p
);
1011 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/graphical.target.wants/with-dropin-1@instance-1.service");
1012 ASSERT_STREQ(changes
[1].path
, p
);
1013 install_changes_free(changes
, n_changes
);
1014 changes
= NULL
; n_changes
= 0;
1016 assert_se(unit_file_enable(RUNTIME_SCOPE_SYSTEM
, 0, root
, STRV_MAKE("with-dropin-2@instance-1.service"), &changes
, &n_changes
) == 1);
1017 assert_se(n_changes
== 2);
1018 assert_se(changes
[0].type
== INSTALL_CHANGE_SYMLINK
);
1019 assert_se(changes
[1].type
== INSTALL_CHANGE_SYMLINK
);
1020 ASSERT_STREQ(changes
[0].source
, "/usr/lib/systemd/system/with-dropin-2@.service");
1021 ASSERT_STREQ(changes
[1].source
, "/usr/lib/systemd/system/with-dropin-2@.service");
1022 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/with-dropin-2@instance-1.service");
1023 ASSERT_STREQ(changes
[0].path
, p
);
1024 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/graphical.target.wants/with-dropin-2@instance-1.service");
1025 ASSERT_STREQ(changes
[1].path
, p
);
1026 install_changes_free(changes
, n_changes
);
1027 changes
= NULL
; n_changes
= 0;
1029 assert_se(unit_file_enable(RUNTIME_SCOPE_SYSTEM
, 0, root
, STRV_MAKE("with-dropin-2@instance-2.service"), &changes
, &n_changes
) == 1);
1030 assert_se(n_changes
== 1);
1031 assert_se(changes
[0].type
== INSTALL_CHANGE_SYMLINK
);
1032 ASSERT_STREQ(changes
[0].source
, "/usr/lib/systemd/system/with-dropin-2@.service");
1033 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/with-dropin-2@instance-2.service");
1034 ASSERT_STREQ(changes
[0].path
, p
);
1035 install_changes_free(changes
, n_changes
);
1036 changes
= NULL
; n_changes
= 0;
1038 assert_se(unit_file_enable(RUNTIME_SCOPE_SYSTEM
, 0, root
, STRV_MAKE("with-dropin-3@.service"), &changes
, &n_changes
) == 1);
1039 assert_se(n_changes
== 1);
1040 assert_se(changes
[0].type
== INSTALL_CHANGE_SYMLINK
);
1041 ASSERT_STREQ(changes
[0].source
, "/usr/lib/systemd/system/with-dropin-3@.service");
1042 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/with-dropin-3@instance-2.service");
1043 ASSERT_STREQ(changes
[0].path
, p
);
1044 install_changes_free(changes
, n_changes
);
1045 changes
= NULL
; n_changes
= 0;
1047 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "with-dropin-1@instance-1.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
1048 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "with-dropin-2@instance-1.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
1049 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "with-dropin-2@instance-2.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
1050 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "with-dropin-3@instance-1.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
1051 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "with-dropin-3@instance-2.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
1054 TEST(preset_multiple_instances
) {
1055 InstallChange
*changes
= NULL
;
1056 size_t n_changes
= 0;
1058 UnitFileState state
;
1060 /* Set up template service files and preset file */
1061 p
= strjoina(root
, "/usr/lib/systemd/system/foo@.service");
1062 assert_se(write_string_file(p
,
1064 "DefaultInstance=def\n"
1065 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
1067 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "foo@.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
1069 p
= strjoina(root
, "/usr/lib/systemd/system-preset/test.preset");
1070 assert_se(write_string_file(p
,
1071 "enable foo@.service bar0 bar1 bartest\n"
1072 "enable emptylist@.service\n" /* This line ensures the old functionality for templated unit still works */
1073 "disable *\n" , WRITE_STRING_FILE_CREATE
) >= 0);
1075 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "foo@bar0.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
1077 /* Preset a single instantiated unit specified in the list */
1078 assert_se(unit_file_preset(RUNTIME_SCOPE_SYSTEM
, 0, root
, STRV_MAKE("foo@bar0.service"), UNIT_FILE_PRESET_FULL
, &changes
, &n_changes
) >= 0);
1079 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "foo@bar0.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
1080 assert_se(n_changes
== 1);
1081 assert_se(changes
[0].type
== INSTALL_CHANGE_SYMLINK
);
1082 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/foo@bar0.service");
1083 ASSERT_STREQ(changes
[0].path
, p
);
1084 install_changes_free(changes
, n_changes
);
1085 changes
= NULL
; n_changes
= 0;
1087 assert_se(unit_file_disable(RUNTIME_SCOPE_SYSTEM
, 0, root
, STRV_MAKE("foo@bar0.service"), &changes
, &n_changes
) >= 0);
1088 assert_se(n_changes
== 1);
1089 assert_se(changes
[0].type
== INSTALL_CHANGE_UNLINK
);
1090 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/foo@bar0.service");
1091 ASSERT_STREQ(changes
[0].path
, p
);
1092 install_changes_free(changes
, n_changes
);
1093 changes
= NULL
; n_changes
= 0;
1095 /* Check for preset-all case, only instances on the list should be enabled, not including the default instance */
1096 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "foo@def.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
1097 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "foo@bar1.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
1098 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "foo@bartest.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
1100 assert_se(unit_file_preset_all(RUNTIME_SCOPE_SYSTEM
, 0, root
, UNIT_FILE_PRESET_FULL
, &changes
, &n_changes
) >= 0);
1101 assert_se(n_changes
> 0);
1103 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "foo@def.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
1104 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "foo@bar0.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
1105 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "foo@bar1.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
1106 assert_se(unit_file_get_state(RUNTIME_SCOPE_SYSTEM
, root
, "foo@bartest.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
1108 install_changes_free(changes
, n_changes
);
1111 static void verify_one(
1112 const InstallInfo
*i
,
1115 const char *updated_name
) {
1117 static const InstallInfo
*last_info
= NULL
;
1118 _cleanup_free_
char *alias2
= NULL
;
1121 log_info("-- %s --", (last_info
= i
)->name
);
1123 r
= unit_file_verify_alias(i
, alias
, &alias2
, NULL
, NULL
);
1124 log_info_errno(r
, "alias %s ← %s: %d/%m (expected %d)%s%s%s",
1125 i
->name
, alias
, r
, expected
,
1126 alias2
? " [" : "", strempty(alias2
),
1128 assert_se(r
== expected
);
1130 /* This is test for "instance propagation". This propagation matters mostly for WantedBy= and
1131 * RequiredBy= settings, and less so for Alias=. The only case where it should happen is when we have
1132 * an Alias=alias@.service an instantiated template template@instance. In that case the instance name
1133 * should be propagated into the alias as alias@instance. */
1134 ASSERT_STREQ(alias2
, updated_name
);
1137 TEST(verify_alias
) {
1139 plain_service
= { .name
= (char*) "plain.service" },
1140 bare_template
= { .name
= (char*) "template1@.service" },
1141 di_template
= { .name
= (char*) "template2@.service",
1142 .default_instance
= (char*) "di" },
1143 inst_template
= { .name
= (char*) "template3@inst.service" },
1144 di_inst_template
= { .name
= (char*) "template4@inst.service",
1145 .default_instance
= (char*) "di" };
1147 verify_one(&plain_service
, "alias.service", 0, NULL
);
1148 verify_one(&plain_service
, "alias.socket", -EXDEV
, NULL
);
1149 verify_one(&plain_service
, "alias@.service", -EXDEV
, NULL
);
1150 verify_one(&plain_service
, "alias@inst.service", -EXDEV
, NULL
);
1152 /* Setting WantedBy= and RequiredBy= through Alias= is supported for the sake of backwards
1154 verify_one(&plain_service
, "foo.target.wants/plain.service", 0, NULL
);
1155 verify_one(&plain_service
, "foo.target.wants/plain.socket", -EXDEV
, NULL
);
1156 verify_one(&plain_service
, "foo.target.wants/plain@.service", -EXDEV
, NULL
);
1157 verify_one(&plain_service
, "foo.target.wants/service", -EXDEV
, NULL
);
1158 verify_one(&plain_service
, "foo.target.requires/plain.service", 0, NULL
);
1159 verify_one(&plain_service
, "foo.target.requires/plain.socket", -EXDEV
, NULL
);
1160 verify_one(&plain_service
, "foo.target.requires/plain@.service", -EXDEV
, NULL
);
1161 verify_one(&plain_service
, "foo.target.requires/service", -EXDEV
, NULL
);
1162 verify_one(&plain_service
, "asdf.requires/plain.service", -EXDEV
, NULL
); /* invalid unit name component */
1163 /* The newly-added UpheldBy= (.upholds/) and other suffixes should be rejected */
1164 verify_one(&plain_service
, "foo.target.upholds/plain.service", -EXDEV
, NULL
);
1165 verify_one(&plain_service
, "foo.target.upholds/plain.socket", -EXDEV
, NULL
);
1166 verify_one(&plain_service
, "foo.target.upholds/plain@.service", -EXDEV
, NULL
);
1167 verify_one(&plain_service
, "foo.target.upholds/service", -EXDEV
, NULL
);
1168 verify_one(&plain_service
, "foo.service/plain.service", -EXDEV
, NULL
); /* missing dir suffix */
1169 verify_one(&plain_service
, "foo.target.conf/plain.service", -EXDEV
, NULL
);
1171 verify_one(&bare_template
, "alias.service", -EXDEV
, NULL
);
1172 verify_one(&bare_template
, "alias.socket", -EXDEV
, NULL
);
1173 verify_one(&bare_template
, "alias@.socket", -EXDEV
, NULL
);
1174 verify_one(&bare_template
, "alias@inst.socket", -EXDEV
, NULL
);
1175 /* A general alias alias@.service → template1@.service. */
1176 verify_one(&bare_template
, "alias@.service", 0, NULL
);
1177 /* Only a specific instance is aliased, see the discussion in https://github.com/systemd/systemd/pull/13119. */
1178 verify_one(&bare_template
, "alias@inst.service", 0, NULL
);
1179 verify_one(&bare_template
, "foo.target.wants/plain.service", -EXDEV
, NULL
);
1180 verify_one(&bare_template
, "foo.target.wants/plain.socket", -EXDEV
, NULL
);
1181 verify_one(&bare_template
, "foo.target.wants/plain@.service", -EXDEV
, NULL
);
1182 /* Name mismatch: we cannot allow this, because plain@foo.service would be pulled in by foo.target,
1183 * but would not be resolveable on its own, since systemd doesn't know how to load the fragment. */
1184 verify_one(&bare_template
, "foo.target.wants/plain@foo.service", -EXDEV
, NULL
);
1185 verify_one(&bare_template
, "foo.target.wants/template1@foo.service", 0, NULL
);
1186 verify_one(&bare_template
, "foo.target.wants/service", -EXDEV
, NULL
);
1187 verify_one(&bare_template
, "foo.target.requires/plain.service", -EXDEV
, NULL
);
1188 verify_one(&bare_template
, "foo.target.requires/plain.socket", -EXDEV
, NULL
);
1189 verify_one(&bare_template
, "foo.target.requires/plain@.service", -EXDEV
, NULL
); /* instance missing */
1190 verify_one(&bare_template
, "foo.target.requires/template1@inst.service", 0, NULL
);
1191 verify_one(&bare_template
, "foo.target.requires/service", -EXDEV
, NULL
);
1192 verify_one(&bare_template
, "foo.target.conf/plain.service", -EXDEV
, NULL
);
1193 verify_one(&bare_template
, "FOO@.target.requires/plain@.service", -EXDEV
, NULL
); /* template name mismatch */
1194 verify_one(&bare_template
, "FOO@inst.target.requires/plain@.service", -EXDEV
, NULL
);
1195 verify_one(&bare_template
, "FOO@inst.target.requires/plain@inst.service", -EXDEV
, NULL
);
1196 verify_one(&bare_template
, "FOO@.target.requires/template1@.service", 0, NULL
); /* instance propagated */
1197 verify_one(&bare_template
, "FOO@inst.target.requires/template1@.service", -EXDEV
, NULL
); /* instance missing */
1198 verify_one(&bare_template
, "FOO@inst.target.requires/template1@inst.service", 0, NULL
); /* instance provided */
1200 verify_one(&di_template
, "alias.service", -EXDEV
, NULL
);
1201 verify_one(&di_template
, "alias.socket", -EXDEV
, NULL
);
1202 verify_one(&di_template
, "alias@.socket", -EXDEV
, NULL
);
1203 verify_one(&di_template
, "alias@inst.socket", -EXDEV
, NULL
);
1204 verify_one(&di_template
, "alias@inst.service", 0, NULL
);
1205 verify_one(&di_template
, "alias@.service", 0, NULL
);
1206 verify_one(&di_template
, "alias@di.service", 0, NULL
);
1207 verify_one(&di_template
, "foo.target.wants/plain.service", -EXDEV
, NULL
);
1208 verify_one(&di_template
, "foo.target.wants/plain.socket", -EXDEV
, NULL
);
1209 verify_one(&di_template
, "foo.target.wants/plain@.service", -EXDEV
, NULL
);
1210 verify_one(&di_template
, "foo.target.wants/plain@di.service", -EXDEV
, NULL
);
1211 verify_one(&di_template
, "foo.target.wants/template2@di.service", 0, NULL
);
1212 verify_one(&di_template
, "foo.target.wants/service", -EXDEV
, NULL
);
1213 verify_one(&di_template
, "foo.target.requires/plain.service", -EXDEV
, NULL
);
1214 verify_one(&di_template
, "foo.target.requires/plain.socket", -EXDEV
, NULL
);
1215 verify_one(&di_template
, "foo.target.requires/plain@.service", -EXDEV
, NULL
);
1216 verify_one(&di_template
, "foo.target.requires/plain@di.service", -EXDEV
, NULL
);
1217 verify_one(&di_template
, "foo.target.requires/plain@foo.service", -EXDEV
, NULL
);
1218 verify_one(&di_template
, "foo.target.requires/template2@.service", -EXDEV
, NULL
); /* instance missing */
1219 verify_one(&di_template
, "foo.target.requires/template2@di.service", 0, NULL
);
1220 verify_one(&di_template
, "foo.target.requires/service", -EXDEV
, NULL
);
1221 verify_one(&di_template
, "foo.target.conf/plain.service", -EXDEV
, NULL
);
1223 verify_one(&inst_template
, "alias.service", -EXDEV
, NULL
);
1224 verify_one(&inst_template
, "alias.socket", -EXDEV
, NULL
);
1225 verify_one(&inst_template
, "alias@.socket", -EXDEV
, NULL
);
1226 verify_one(&inst_template
, "alias@inst.socket", -EXDEV
, NULL
);
1227 verify_one(&inst_template
, "alias@inst.service", 0, NULL
);
1228 verify_one(&inst_template
, "alias@.service", 0, "alias@inst.service");
1229 verify_one(&inst_template
, "alias@di.service", -EXDEV
, NULL
);
1230 verify_one(&inst_template
, "bar.target.wants/plain.service", -EXDEV
, NULL
);
1231 verify_one(&inst_template
, "bar.target.wants/plain.socket", -EXDEV
, NULL
);
1232 verify_one(&inst_template
, "bar.target.wants/plain@.service", -EXDEV
, NULL
);
1233 verify_one(&inst_template
, "bar.target.wants/plain@di.service", -EXDEV
, NULL
);
1234 verify_one(&inst_template
, "bar.target.wants/plain@inst.service", -EXDEV
, NULL
);
1235 verify_one(&inst_template
, "bar.target.wants/template3@foo.service", -EXDEV
, NULL
);
1236 verify_one(&inst_template
, "bar.target.wants/template3@inst.service", 0, NULL
);
1237 verify_one(&inst_template
, "bar.target.wants/service", -EXDEV
, NULL
);
1238 verify_one(&inst_template
, "bar.target.requires/plain.service", -EXDEV
, NULL
);
1239 verify_one(&inst_template
, "bar.target.requires/plain.socket", -EXDEV
, NULL
);
1240 verify_one(&inst_template
, "bar.target.requires/plain@.service", -EXDEV
, NULL
);
1241 verify_one(&inst_template
, "bar.target.requires/plain@di.service", -EXDEV
, NULL
);
1242 verify_one(&inst_template
, "bar.target.requires/plain@inst.service", -EXDEV
, NULL
);
1243 verify_one(&inst_template
, "bar.target.requires/template3@foo.service", -EXDEV
, NULL
);
1244 verify_one(&inst_template
, "bar.target.requires/template3@inst.service", 0, NULL
);
1245 verify_one(&inst_template
, "bar.target.requires/service", -EXDEV
, NULL
);
1246 verify_one(&inst_template
, "bar.target.conf/plain.service", -EXDEV
, NULL
);
1247 verify_one(&inst_template
, "BAR@.target.requires/plain@.service", -EXDEV
, NULL
); /* template name mismatch */
1248 verify_one(&inst_template
, "BAR@inst.target.requires/plain@.service", -EXDEV
, NULL
);
1249 verify_one(&inst_template
, "BAR@inst.target.requires/plain@inst.service", -EXDEV
, NULL
);
1250 verify_one(&inst_template
, "BAR@.target.requires/template3@.service", -EXDEV
, NULL
); /* instance missing */
1251 verify_one(&inst_template
, "BAR@inst.target.requires/template3@.service", -EXDEV
, NULL
); /* instance missing */
1252 verify_one(&inst_template
, "BAR@inst.target.requires/template3@inst.service", 0, NULL
); /* instance provided */
1253 verify_one(&inst_template
, "BAR@inst.target.requires/template3@ins2.service", -EXDEV
, NULL
); /* instance mismatch */
1255 /* explicit alias overrides DefaultInstance */
1256 verify_one(&di_inst_template
, "alias.service", -EXDEV
, NULL
);
1257 verify_one(&di_inst_template
, "alias.socket", -EXDEV
, NULL
);
1258 verify_one(&di_inst_template
, "alias@.socket", -EXDEV
, NULL
);
1259 verify_one(&di_inst_template
, "alias@inst.socket", -EXDEV
, NULL
);
1260 verify_one(&di_inst_template
, "alias@inst.service", 0, NULL
);
1261 verify_one(&di_inst_template
, "alias@.service", 0, "alias@inst.service");
1262 verify_one(&di_inst_template
, "alias@di.service", -EXDEV
, NULL
);
1263 verify_one(&di_inst_template
, "goo.target.wants/plain.service", -EXDEV
, NULL
);
1264 verify_one(&di_inst_template
, "goo.target.wants/plain.socket", -EXDEV
, NULL
);
1265 verify_one(&di_inst_template
, "goo.target.wants/plain@.service", -EXDEV
, NULL
);
1266 verify_one(&di_inst_template
, "goo.target.wants/plain@di.service", -EXDEV
, NULL
);
1267 verify_one(&di_inst_template
, "goo.target.wants/template4@foo.service", -EXDEV
, NULL
);
1268 verify_one(&di_inst_template
, "goo.target.wants/template4@inst.service", 0, NULL
);
1269 verify_one(&di_inst_template
, "goo.target.wants/template4@di.service", -EXDEV
, NULL
);
1270 verify_one(&di_inst_template
, "goo.target.wants/service", -EXDEV
, NULL
);
1271 verify_one(&di_inst_template
, "goo.target.requires/plain.service", -EXDEV
, NULL
);
1272 verify_one(&di_inst_template
, "goo.target.requires/plain.socket", -EXDEV
, NULL
);
1273 verify_one(&di_inst_template
, "goo.target.requires/plain@.service", -EXDEV
, NULL
);
1274 verify_one(&di_inst_template
, "goo.target.requires/plain@di.service", -EXDEV
, NULL
);
1275 verify_one(&di_inst_template
, "goo.target.requires/plain@inst.service", -EXDEV
, NULL
);
1276 verify_one(&di_inst_template
, "goo.target.requires/template4@foo.service", -EXDEV
, NULL
);
1277 verify_one(&di_inst_template
, "goo.target.requires/template4@inst.service", 0, NULL
);
1278 verify_one(&di_inst_template
, "goo.target.requires/service", -EXDEV
, NULL
);
1279 verify_one(&di_inst_template
, "goo.target.conf/plain.service", -EXDEV
, NULL
);
1282 static int intro(void) {
1285 assert_se(mkdtemp_malloc("/tmp/rootXXXXXX", &root
) >= 0);
1287 p
= strjoina(root
, "/usr/lib/systemd/system/");
1288 assert_se(mkdir_p(p
, 0755) >= 0);
1290 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/");
1291 assert_se(mkdir_p(p
, 0755) >= 0);
1293 p
= strjoina(root
, "/run/systemd/system/");
1294 assert_se(mkdir_p(p
, 0755) >= 0);
1296 p
= strjoina(root
, "/opt/");
1297 assert_se(mkdir_p(p
, 0755) >= 0);
1299 p
= strjoina(root
, "/usr/lib/systemd/system-preset/");
1300 assert_se(mkdir_p(p
, 0755) >= 0);
1302 p
= strjoina(root
, "/usr/lib/systemd/system/multi-user.target");
1303 assert_se(write_string_file(p
, "# pretty much empty", WRITE_STRING_FILE_CREATE
) >= 0);
1305 p
= strjoina(root
, "/usr/lib/systemd/system/graphical.target");
1306 assert_se(write_string_file(p
, "# pretty much empty", WRITE_STRING_FILE_CREATE
) >= 0);
1308 return EXIT_SUCCESS
;
1312 DEFINE_TEST_MAIN_WITH_INTRO(LOG_INFO
, intro
);