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(LOOKUP_SCOPE_SYSTEM
, root
, "a.service", NULL
) == -ENOENT
);
27 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "b.service", NULL
) == -ENOENT
);
28 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "c.service", NULL
) == -ENOENT
);
29 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "d.service", NULL
) == -ENOENT
);
30 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "e.service", NULL
) == -ENOENT
);
31 assert_se(unit_file_get_state(LOOKUP_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(LOOKUP_SCOPE_SYSTEM
, root
, "a.service", NULL
) >= 0);
39 assert_se(unit_file_get_state(LOOKUP_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(LOOKUP_SCOPE_SYSTEM
, root
, "b.service", NULL
) >= 0);
45 assert_se(unit_file_get_state(LOOKUP_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(LOOKUP_SCOPE_SYSTEM
, root
, "c.service", NULL
) >= 0);
51 assert_se(unit_file_get_state(LOOKUP_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(LOOKUP_SCOPE_SYSTEM
, root
, "d.service", NULL
) >= 0);
58 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "d.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
60 assert_se(unit_file_mask(LOOKUP_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_se(streq(changes
[0].source
, "/dev/null"));
64 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/a.service");
65 assert_se(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(LOOKUP_SCOPE_SYSTEM
, root
, "a.service", &state
) >= 0 && state
== UNIT_FILE_MASKED
);
71 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "b.service", &state
) >= 0 && state
== UNIT_FILE_MASKED
);
72 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "c.service", &state
) >= 0 && state
== UNIT_FILE_MASKED
);
73 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "d.service", &state
) >= 0 && state
== UNIT_FILE_MASKED
);
75 /* Enabling a masked unit should fail! */
76 assert_se(unit_file_enable(LOOKUP_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(LOOKUP_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_se(streq(changes
[0].path
, p
));
85 install_changes_free(changes
, n_changes
);
86 changes
= NULL
; n_changes
= 0;
88 assert_se(unit_file_enable(LOOKUP_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_se(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_se(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(LOOKUP_SCOPE_SYSTEM
, root
, "a.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
98 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "b.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
99 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "c.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
100 assert_se(unit_file_get_state(LOOKUP_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(LOOKUP_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(LOOKUP_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_se(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(LOOKUP_SCOPE_SYSTEM
, root
, "a.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
117 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "b.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
118 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "c.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
119 assert_se(unit_file_get_state(LOOKUP_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(LOOKUP_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(LOOKUP_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_se(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_se(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(LOOKUP_SCOPE_SYSTEM
, root
, "a.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
138 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "b.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
139 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "c.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
140 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "d.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
142 /* Let's try to reenable */
144 assert_se(unit_file_reenable(LOOKUP_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_se(streq(changes
[0].path
, p
));
149 assert_se(changes
[1].type
== INSTALL_CHANGE_SYMLINK
);
150 assert_se(streq(changes
[1].source
, "/usr/lib/systemd/system/a.service"));
151 assert_se(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(LOOKUP_SCOPE_SYSTEM
, root
, "a.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
156 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "b.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
157 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "c.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
158 assert_se(unit_file_get_state(LOOKUP_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(LOOKUP_SCOPE_SYSTEM
, root
, "e.service", NULL
) >= 0);
166 assert_se(unit_file_get_state(LOOKUP_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(LOOKUP_SCOPE_SYSTEM
, root
, "e.service", NULL
) >= 0);
172 assert_se(unit_file_get_state(LOOKUP_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(LOOKUP_SCOPE_SYSTEM
, root
, "f.service", NULL
) >= 0);
184 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "f.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
186 assert_se(unit_file_enable(LOOKUP_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_se(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_se(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_se(streq(changes
[1].source
, p
));
195 assert_se(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(LOOKUP_SCOPE_SYSTEM
, root
, "f.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
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 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
229 p
= strjoina(root
, "/opt/linked2.service");
230 assert_se(write_string_file(p
,
232 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
234 p
= strjoina(root
, "/opt/linked3.service");
235 assert_se(write_string_file(p
,
237 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
239 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "linked.service", NULL
) == -ENOENT
);
240 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "linked2.service", NULL
) == -ENOENT
);
241 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "linked3.service", NULL
) == -ENOENT
);
243 p
= strjoina(root
, "/usr/lib/systemd/system/linked2.service");
244 assert_se(symlink("/opt/linked2.service", p
) >= 0);
246 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/linked3.service");
247 assert_se(symlink("/opt/linked3.service", p
) >= 0);
249 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "linked.service", &state
) == -ENOENT
);
250 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "linked2.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
251 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "linked3.service", &state
) >= 0 && state
== UNIT_FILE_LINKED
);
253 /* First, let's link the unit into the search path */
254 assert_se(unit_file_link(LOOKUP_SCOPE_SYSTEM
, 0, root
, STRV_MAKE("/opt/linked.service"), &changes
, &n_changes
) >= 0);
255 assert_se(n_changes
== 1);
256 assert_se(changes
[0].type
== INSTALL_CHANGE_SYMLINK
);
257 assert_se(streq(changes
[0].source
, "/opt/linked.service"));
258 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/linked.service");
259 assert_se(streq(changes
[0].path
, p
));
260 install_changes_free(changes
, n_changes
);
261 changes
= NULL
; n_changes
= 0;
263 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "linked.service", &state
) >= 0 && state
== UNIT_FILE_LINKED
);
265 /* Let's unlink it from the search path again */
266 assert_se(unit_file_disable(LOOKUP_SCOPE_SYSTEM
, 0, root
, STRV_MAKE("linked.service"), &changes
, &n_changes
) >= 0);
267 assert_se(n_changes
== 1);
268 assert_se(changes
[0].type
== INSTALL_CHANGE_UNLINK
);
269 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/linked.service");
270 assert_se(streq(changes
[0].path
, p
));
271 install_changes_free(changes
, n_changes
);
272 changes
= NULL
; n_changes
= 0;
274 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "linked.service", NULL
) == -ENOENT
);
276 /* Now, let's not just link it, but also enable it */
277 assert_se(unit_file_enable(LOOKUP_SCOPE_SYSTEM
, 0, root
, STRV_MAKE("/opt/linked.service"), &changes
, &n_changes
) >= 0);
278 assert_se(n_changes
== 2);
279 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/linked.service");
280 q
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/linked.service");
281 for (i
= 0 ; i
< n_changes
; i
++) {
282 assert_se(changes
[i
].type
== INSTALL_CHANGE_SYMLINK
);
283 assert_se(streq(changes
[i
].source
, "/opt/linked.service"));
285 if (p
&& streq(changes
[i
].path
, p
))
287 else if (q
&& streq(changes
[i
].path
, q
))
290 assert_not_reached();
293 install_changes_free(changes
, n_changes
);
294 changes
= NULL
; n_changes
= 0;
296 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "linked.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
298 /* And let's unlink it again */
299 assert_se(unit_file_disable(LOOKUP_SCOPE_SYSTEM
, 0, root
, STRV_MAKE("linked.service"), &changes
, &n_changes
) >= 0);
300 assert_se(n_changes
== 2);
301 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/linked.service");
302 q
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/linked.service");
303 for (i
= 0; i
< n_changes
; i
++) {
304 assert_se(changes
[i
].type
== INSTALL_CHANGE_UNLINK
);
306 if (p
&& streq(changes
[i
].path
, p
))
308 else if (q
&& streq(changes
[i
].path
, q
))
311 assert_not_reached();
314 install_changes_free(changes
, n_changes
);
315 changes
= NULL
; n_changes
= 0;
317 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "linked.service", NULL
) == -ENOENT
);
319 assert_se(unit_file_enable(LOOKUP_SCOPE_SYSTEM
, 0, root
, STRV_MAKE("linked2.service"), &changes
, &n_changes
) >= 0);
320 assert_se(n_changes
== 2);
321 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/linked2.service");
322 q
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/linked2.service");
323 for (i
= 0 ; i
< n_changes
; i
++) {
324 assert_se(changes
[i
].type
== INSTALL_CHANGE_SYMLINK
);
325 assert_se(streq(changes
[i
].source
, "/opt/linked2.service"));
327 if (p
&& streq(changes
[i
].path
, p
))
329 else if (q
&& streq(changes
[i
].path
, q
))
332 assert_not_reached();
335 install_changes_free(changes
, n_changes
);
336 changes
= NULL
; n_changes
= 0;
338 assert_se(unit_file_enable(LOOKUP_SCOPE_SYSTEM
, 0, root
, STRV_MAKE("linked3.service"), &changes
, &n_changes
) >= 0);
339 assert_se(n_changes
== 1);
340 assert_se(changes
[0].type
== INSTALL_CHANGE_SYMLINK
);
341 assert_se(startswith(changes
[0].path
, root
));
342 assert_se(endswith(changes
[0].path
, "linked3.service"));
343 assert_se(streq(changes
[0].source
, "/opt/linked3.service"));
344 install_changes_free(changes
, n_changes
);
345 changes
= NULL
; n_changes
= 0;
349 _cleanup_free_
char *def
= NULL
;
350 InstallChange
*changes
= NULL
;
351 size_t n_changes
= 0;
354 p
= strjoina(root
, "/usr/lib/systemd/system/test-default-real.target");
355 assert_se(write_string_file(p
, "# pretty much empty", WRITE_STRING_FILE_CREATE
) >= 0);
357 p
= strjoina(root
, "/usr/lib/systemd/system/test-default.target");
358 assert_se(symlink("test-default-real.target", p
) >= 0);
360 assert_se(unit_file_get_default(LOOKUP_SCOPE_SYSTEM
, root
, &def
) == -ENOENT
);
362 assert_se(unit_file_set_default(LOOKUP_SCOPE_SYSTEM
, 0, root
, "idontexist.target", &changes
, &n_changes
) == -ENOENT
);
363 assert_se(n_changes
== 1);
364 assert_se(changes
[0].type
== -ENOENT
);
365 assert_se(streq_ptr(changes
[0].path
, "idontexist.target"));
366 install_changes_free(changes
, n_changes
);
367 changes
= NULL
; n_changes
= 0;
369 assert_se(unit_file_get_default(LOOKUP_SCOPE_SYSTEM
, root
, &def
) == -ENOENT
);
371 assert_se(unit_file_set_default(LOOKUP_SCOPE_SYSTEM
, 0, root
, "test-default.target", &changes
, &n_changes
) >= 0);
372 assert_se(n_changes
== 1);
373 assert_se(changes
[0].type
== INSTALL_CHANGE_SYMLINK
);
374 assert_se(streq(changes
[0].source
, "/usr/lib/systemd/system/test-default-real.target"));
375 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/" SPECIAL_DEFAULT_TARGET
);
376 assert_se(streq(changes
[0].path
, p
));
377 install_changes_free(changes
, n_changes
);
378 changes
= NULL
; n_changes
= 0;
380 assert_se(unit_file_get_default(LOOKUP_SCOPE_SYSTEM
, root
, &def
) >= 0);
381 assert_se(streq_ptr(def
, "test-default-real.target"));
384 TEST(add_dependency
) {
385 InstallChange
*changes
= NULL
;
386 size_t n_changes
= 0;
389 p
= strjoina(root
, "/usr/lib/systemd/system/real-add-dependency-test-target.target");
390 assert_se(write_string_file(p
, "# pretty much empty", WRITE_STRING_FILE_CREATE
) >= 0);
392 p
= strjoina(root
, "/usr/lib/systemd/system/add-dependency-test-target.target");
393 assert_se(symlink("real-add-dependency-test-target.target", p
) >= 0);
395 p
= strjoina(root
, "/usr/lib/systemd/system/real-add-dependency-test-service.service");
396 assert_se(write_string_file(p
, "# pretty much empty", WRITE_STRING_FILE_CREATE
) >= 0);
398 p
= strjoina(root
, "/usr/lib/systemd/system/add-dependency-test-service.service");
399 assert_se(symlink("real-add-dependency-test-service.service", p
) >= 0);
401 assert_se(unit_file_add_dependency(LOOKUP_SCOPE_SYSTEM
, 0, root
, STRV_MAKE("add-dependency-test-service.service"), "add-dependency-test-target.target", UNIT_WANTS
, &changes
, &n_changes
) >= 0);
402 assert_se(n_changes
== 1);
403 assert_se(changes
[0].type
== INSTALL_CHANGE_SYMLINK
);
404 assert_se(streq(changes
[0].source
, "/usr/lib/systemd/system/real-add-dependency-test-service.service"));
405 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/real-add-dependency-test-target.target.wants/real-add-dependency-test-service.service");
406 assert_se(streq(changes
[0].path
, p
));
407 install_changes_free(changes
, n_changes
);
408 changes
= NULL
; n_changes
= 0;
411 TEST(template_enable
) {
412 InstallChange
*changes
= NULL
;
413 size_t n_changes
= 0;
417 log_info("== %s ==", __func__
);
419 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "template@.service", &state
) == -ENOENT
);
420 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "template@def.service", &state
) == -ENOENT
);
421 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "template@foo.service", &state
) == -ENOENT
);
422 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "template-symlink@foo.service", &state
) == -ENOENT
);
424 p
= strjoina(root
, "/usr/lib/systemd/system/template@.service");
425 assert_se(write_string_file(p
,
427 "DefaultInstance=def\n"
428 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
430 p
= strjoina(root
, "/usr/lib/systemd/system/template-symlink@.service");
431 assert_se(symlink("template@.service", p
) >= 0);
433 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "template@.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
434 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "template@def.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
435 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "template@foo.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
436 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "template-symlink@.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
437 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "template-symlink@def.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
438 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "template-symlink@foo.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
440 log_info("== %s with template@.service enabled ==", __func__
);
442 assert_se(unit_file_enable(LOOKUP_SCOPE_SYSTEM
, 0, root
, STRV_MAKE("template@.service"), &changes
, &n_changes
) >= 0);
443 assert_se(n_changes
== 1);
444 assert_se(changes
[0].type
== INSTALL_CHANGE_SYMLINK
);
445 assert_se(streq(changes
[0].source
, "/usr/lib/systemd/system/template@.service"));
446 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/template@def.service");
447 assert_se(streq(changes
[0].path
, p
));
448 install_changes_free(changes
, n_changes
);
449 changes
= NULL
; n_changes
= 0;
451 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "template@.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
452 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "template@def.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
453 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "template@foo.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
454 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "template-symlink@.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
455 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "template-symlink@def.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
456 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "template-symlink@foo.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
458 assert_se(unit_file_disable(LOOKUP_SCOPE_SYSTEM
, 0, root
, STRV_MAKE("template@.service"), &changes
, &n_changes
) >= 0);
459 assert_se(n_changes
== 1);
460 assert_se(changes
[0].type
== INSTALL_CHANGE_UNLINK
);
461 assert_se(streq(changes
[0].path
, p
));
462 install_changes_free(changes
, n_changes
);
463 changes
= NULL
; n_changes
= 0;
465 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "template@.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
466 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "template@def.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
467 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "template@foo.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
468 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "template-symlink@.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
469 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "template-symlink@def.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
470 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "template-symlink@foo.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
472 log_info("== %s with template@foo.service enabled ==", __func__
);
474 assert_se(unit_file_enable(LOOKUP_SCOPE_SYSTEM
, 0, root
, STRV_MAKE("template@foo.service"), &changes
, &n_changes
) >= 0);
475 assert_se(changes
[0].type
== INSTALL_CHANGE_SYMLINK
);
476 assert_se(streq(changes
[0].source
, "/usr/lib/systemd/system/template@.service"));
477 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/template@foo.service");
478 assert_se(streq(changes
[0].path
, p
));
479 install_changes_free(changes
, n_changes
);
480 changes
= NULL
; n_changes
= 0;
482 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "template@.service", &state
) >= 0 && state
== UNIT_FILE_INDIRECT
);
483 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "template@def.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
484 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "template@foo.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
485 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "template-symlink@foo.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
486 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "template-symlink@def.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
487 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "template-symlink@foo.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
489 assert_se(unit_file_disable(LOOKUP_SCOPE_SYSTEM
, 0, root
, STRV_MAKE("template@foo.service"), &changes
, &n_changes
) >= 0);
490 assert_se(n_changes
== 1);
491 assert_se(changes
[0].type
== INSTALL_CHANGE_UNLINK
);
492 assert_se(streq(changes
[0].path
, p
));
493 install_changes_free(changes
, n_changes
);
494 changes
= NULL
; n_changes
= 0;
496 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "template@.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
497 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "template@def.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
498 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "template@foo.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
499 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "template@quux.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
500 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "template-symlink@.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
501 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "template-symlink@def.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
502 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "template-symlink@foo.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
503 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "template-symlink@quux.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
505 log_info("== %s with template-symlink@quux.service enabled ==", __func__
);
507 assert_se(unit_file_enable(LOOKUP_SCOPE_SYSTEM
, 0, root
, STRV_MAKE("template-symlink@quux.service"), &changes
, &n_changes
) >= 0);
508 assert_se(changes
[0].type
== INSTALL_CHANGE_SYMLINK
);
509 assert_se(streq(changes
[0].source
, "/usr/lib/systemd/system/template@.service"));
510 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/template@quux.service");
511 assert_se(streq(changes
[0].path
, p
));
512 install_changes_free(changes
, n_changes
);
513 changes
= NULL
; n_changes
= 0;
515 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "template@.service", &state
) >= 0 && state
== UNIT_FILE_INDIRECT
);
516 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "template@def.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
517 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "template@foo.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
518 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "template@quux.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
519 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "template-symlink@.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
520 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "template-symlink@def.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
521 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "template-symlink@foo.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
522 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "template-symlink@quux.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
526 InstallChange
*changes
= NULL
;
527 size_t n_changes
= 0;
531 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "indirecta.service", &state
) == -ENOENT
);
532 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "indirectb.service", &state
) == -ENOENT
);
533 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "indirectc.service", &state
) == -ENOENT
);
535 p
= strjoina(root
, "/usr/lib/systemd/system/indirecta.service");
536 assert_se(write_string_file(p
,
538 "Also=indirectb.service\n", WRITE_STRING_FILE_CREATE
) >= 0);
540 p
= strjoina(root
, "/usr/lib/systemd/system/indirectb.service");
541 assert_se(write_string_file(p
,
543 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
545 p
= strjoina(root
, "/usr/lib/systemd/system/indirectc.service");
546 assert_se(symlink("indirecta.service", p
) >= 0);
548 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "indirecta.service", &state
) >= 0 && state
== UNIT_FILE_INDIRECT
);
549 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "indirectb.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
550 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "indirectc.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
552 assert_se(unit_file_enable(LOOKUP_SCOPE_SYSTEM
, 0, root
, STRV_MAKE("indirectc.service"), &changes
, &n_changes
) >= 0);
553 assert_se(n_changes
== 1);
554 assert_se(changes
[0].type
== INSTALL_CHANGE_SYMLINK
);
555 assert_se(streq(changes
[0].source
, "/usr/lib/systemd/system/indirectb.service"));
556 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/indirectb.service");
557 assert_se(streq(changes
[0].path
, p
));
558 install_changes_free(changes
, n_changes
);
559 changes
= NULL
; n_changes
= 0;
561 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "indirecta.service", &state
) >= 0 && state
== UNIT_FILE_INDIRECT
);
562 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "indirectb.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
563 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "indirectc.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
565 assert_se(unit_file_disable(LOOKUP_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_UNLINK
);
568 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/indirectb.service");
569 assert_se(streq(changes
[0].path
, p
));
570 install_changes_free(changes
, n_changes
);
571 changes
= NULL
; n_changes
= 0;
574 TEST(preset_and_list
) {
575 InstallChange
*changes
= NULL
;
576 size_t n_changes
= 0, i
;
579 bool got_yes
= false, got_no
= false;
583 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "preset-yes.service", &state
) == -ENOENT
);
584 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "preset-no.service", &state
) == -ENOENT
);
586 p
= strjoina(root
, "/usr/lib/systemd/system/preset-yes.service");
587 assert_se(write_string_file(p
,
589 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
591 p
= strjoina(root
, "/usr/lib/systemd/system/preset-no.service");
592 assert_se(write_string_file(p
,
594 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
596 p
= strjoina(root
, "/usr/lib/systemd/system-preset/test.preset");
597 assert_se(write_string_file(p
,
599 "disable *\n", WRITE_STRING_FILE_CREATE
) >= 0);
601 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "preset-yes.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
602 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "preset-no.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
604 assert_se(unit_file_preset(LOOKUP_SCOPE_SYSTEM
, 0, root
, STRV_MAKE("preset-yes.service"), UNIT_FILE_PRESET_FULL
, &changes
, &n_changes
) >= 0);
605 assert_se(n_changes
== 1);
606 assert_se(changes
[0].type
== INSTALL_CHANGE_SYMLINK
);
607 assert_se(streq(changes
[0].source
, "/usr/lib/systemd/system/preset-yes.service"));
608 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/preset-yes.service");
609 assert_se(streq(changes
[0].path
, p
));
610 install_changes_free(changes
, n_changes
);
611 changes
= NULL
; n_changes
= 0;
613 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "preset-yes.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
614 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "preset-no.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
616 assert_se(unit_file_disable(LOOKUP_SCOPE_SYSTEM
, 0, root
, STRV_MAKE("preset-yes.service"), &changes
, &n_changes
) >= 0);
617 assert_se(n_changes
== 1);
618 assert_se(changes
[0].type
== INSTALL_CHANGE_UNLINK
);
619 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/preset-yes.service");
620 assert_se(streq(changes
[0].path
, p
));
621 install_changes_free(changes
, n_changes
);
622 changes
= NULL
; n_changes
= 0;
624 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "preset-yes.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
625 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "preset-no.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
627 assert_se(unit_file_preset(LOOKUP_SCOPE_SYSTEM
, 0, root
, STRV_MAKE("preset-no.service"), UNIT_FILE_PRESET_FULL
, &changes
, &n_changes
) >= 0);
628 assert_se(n_changes
== 0);
629 install_changes_free(changes
, n_changes
);
630 changes
= NULL
; n_changes
= 0;
632 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "preset-yes.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
633 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "preset-no.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
635 assert_se(unit_file_preset_all(LOOKUP_SCOPE_SYSTEM
, 0, root
, UNIT_FILE_PRESET_FULL
, &changes
, &n_changes
) >= 0);
637 assert_se(n_changes
> 0);
639 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/preset-yes.service");
641 for (i
= 0; i
< n_changes
; i
++) {
643 if (changes
[i
].type
== INSTALL_CHANGE_SYMLINK
) {
644 assert_se(streq(changes
[i
].source
, "/usr/lib/systemd/system/preset-yes.service"));
645 assert_se(streq(changes
[i
].path
, p
));
647 assert_se(changes
[i
].type
== INSTALL_CHANGE_UNLINK
);
650 install_changes_free(changes
, n_changes
);
651 changes
= NULL
; n_changes
= 0;
653 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "preset-yes.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
654 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "preset-no.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
656 assert_se(h
= hashmap_new(&string_hash_ops
));
657 assert_se(unit_file_get_list(LOOKUP_SCOPE_SYSTEM
, root
, h
, NULL
, NULL
) >= 0);
659 p
= strjoina(root
, "/usr/lib/systemd/system/preset-yes.service");
660 q
= strjoina(root
, "/usr/lib/systemd/system/preset-no.service");
662 HASHMAP_FOREACH(fl
, h
) {
663 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, basename(fl
->path
), &state
) >= 0);
664 assert_se(fl
->state
== state
);
666 if (streq(fl
->path
, p
)) {
668 assert_se(fl
->state
== UNIT_FILE_ENABLED
);
669 } else if (streq(fl
->path
, q
)) {
671 assert_se(fl
->state
== UNIT_FILE_DISABLED
);
673 assert_se(IN_SET(fl
->state
, UNIT_FILE_DISABLED
, UNIT_FILE_STATIC
, UNIT_FILE_INDIRECT
, UNIT_FILE_ALIAS
));
676 unit_file_list_free(h
);
678 assert_se(got_yes
&& got_no
);
684 InstallChange
*changes
= NULL
;
685 size_t n_changes
= 0;
687 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "xx.service", NULL
) == -ENOENT
);
688 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "yy.service", NULL
) == -ENOENT
);
690 p
= strjoina(root
, "/usr/lib/systemd/system/xx.service");
691 assert_se(write_string_file(p
, "# Empty\n", WRITE_STRING_FILE_CREATE
) >= 0);
693 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "xx.service", NULL
) >= 0);
694 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "xx.service", &state
) >= 0 && state
== UNIT_FILE_STATIC
);
696 /* Initially there's nothing to revert */
697 assert_se(unit_file_revert(LOOKUP_SCOPE_SYSTEM
, root
, STRV_MAKE("xx.service"), &changes
, &n_changes
) >= 0);
698 assert_se(n_changes
== 0);
699 install_changes_free(changes
, n_changes
);
700 changes
= NULL
; n_changes
= 0;
702 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/xx.service");
703 assert_se(write_string_file(p
, "# Empty override\n", WRITE_STRING_FILE_CREATE
) >= 0);
705 /* Revert the override file */
706 assert_se(unit_file_revert(LOOKUP_SCOPE_SYSTEM
, root
, STRV_MAKE("xx.service"), &changes
, &n_changes
) >= 0);
707 assert_se(n_changes
== 1);
708 assert_se(changes
[0].type
== INSTALL_CHANGE_UNLINK
);
709 assert_se(streq(changes
[0].path
, p
));
710 install_changes_free(changes
, n_changes
);
711 changes
= NULL
; n_changes
= 0;
713 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/xx.service.d/dropin.conf");
714 assert_se(write_string_file(p
, "# Empty dropin\n", WRITE_STRING_FILE_CREATE
|WRITE_STRING_FILE_MKDIR_0755
) >= 0);
716 /* Revert the dropin file */
717 assert_se(unit_file_revert(LOOKUP_SCOPE_SYSTEM
, root
, STRV_MAKE("xx.service"), &changes
, &n_changes
) >= 0);
718 assert_se(n_changes
== 2);
719 assert_se(changes
[0].type
== INSTALL_CHANGE_UNLINK
);
720 assert_se(streq(changes
[0].path
, p
));
722 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/xx.service.d");
723 assert_se(changes
[1].type
== INSTALL_CHANGE_UNLINK
);
724 assert_se(streq(changes
[1].path
, p
));
725 install_changes_free(changes
, n_changes
);
726 changes
= NULL
; n_changes
= 0;
730 InstallChange
*changes
= NULL
;
731 size_t n_changes
= 0;
735 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "prefix-1.service", &state
) == -ENOENT
);
736 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "prefix-2.service", &state
) == -ENOENT
);
738 p
= strjoina(root
, "/usr/lib/systemd/system/prefix-1.service");
739 assert_se(write_string_file(p
,
741 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
743 p
= strjoina(root
, "/usr/lib/systemd/system/prefix-2.service");
744 assert_se(write_string_file(p
,
746 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
748 p
= strjoina(root
, "/usr/lib/systemd/system-preset/test.preset");
749 assert_se(write_string_file(p
,
750 "enable prefix-1.service\n"
751 "disable prefix-*.service\n"
752 "enable prefix-2.service\n", WRITE_STRING_FILE_CREATE
) >= 0);
754 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "prefix-1.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
755 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "prefix-2.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
757 assert_se(unit_file_preset(LOOKUP_SCOPE_SYSTEM
, 0, root
, STRV_MAKE("prefix-1.service"), UNIT_FILE_PRESET_FULL
, &changes
, &n_changes
) >= 0);
758 assert_se(n_changes
== 1);
759 assert_se(changes
[0].type
== INSTALL_CHANGE_SYMLINK
);
760 assert_se(streq(changes
[0].source
, "/usr/lib/systemd/system/prefix-1.service"));
761 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/prefix-1.service");
762 assert_se(streq(changes
[0].path
, p
));
763 install_changes_free(changes
, n_changes
);
764 changes
= NULL
; n_changes
= 0;
766 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "prefix-1.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
767 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "prefix-2.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
769 assert_se(unit_file_preset(LOOKUP_SCOPE_SYSTEM
, 0, root
, STRV_MAKE("prefix-2.service"), UNIT_FILE_PRESET_FULL
, &changes
, &n_changes
) >= 0);
770 assert_se(n_changes
== 0);
772 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "prefix-1.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
773 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "prefix-2.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
776 TEST(static_instance
) {
780 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "static-instance@.service", &state
) == -ENOENT
);
781 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "static-instance@foo.service", &state
) == -ENOENT
);
783 p
= strjoina(root
, "/usr/lib/systemd/system/static-instance@.service");
784 assert_se(write_string_file(p
,
786 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
788 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "static-instance@.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
789 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "static-instance@foo.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
791 p
= strjoina(root
, "/usr/lib/systemd/system/static-instance@foo.service");
792 assert_se(symlink("static-instance@.service", p
) >= 0);
794 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "static-instance@.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
795 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "static-instance@foo.service", &state
) >= 0 && state
== UNIT_FILE_STATIC
);
801 InstallChange
*changes
= NULL
;
802 size_t n_changes
= 0;
804 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "with-dropin-1.service", &state
) == -ENOENT
);
805 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "with-dropin-2.service", &state
) == -ENOENT
);
806 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "with-dropin-3.service", &state
) == -ENOENT
);
807 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "with-dropin-4a.service", &state
) == -ENOENT
);
808 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "with-dropin-4b.service", &state
) == -ENOENT
);
810 p
= strjoina(root
, "/usr/lib/systemd/system/with-dropin-1.service");
811 assert_se(write_string_file(p
,
813 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
815 p
= strjoina(root
, "/usr/lib/systemd/system/with-dropin-1.service.d/dropin.conf");
816 assert_se(write_string_file(p
,
818 "WantedBy=graphical.target\n", WRITE_STRING_FILE_CREATE
|WRITE_STRING_FILE_MKDIR_0755
) >= 0);
820 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "with-dropin-1.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
822 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/with-dropin-2.service");
823 assert_se(write_string_file(p
,
825 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
827 p
= strjoina(root
, "/usr/lib/systemd/system/with-dropin-2.service.d/dropin.conf");
828 assert_se(write_string_file(p
,
830 "WantedBy=graphical.target\n", WRITE_STRING_FILE_CREATE
|WRITE_STRING_FILE_MKDIR_0755
) >= 0);
832 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "with-dropin-2.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
834 p
= strjoina(root
, "/usr/lib/systemd/system/with-dropin-3.service");
835 assert_se(write_string_file(p
,
837 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
839 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/with-dropin-3.service.d/dropin.conf");
840 assert_se(write_string_file(p
,
842 "WantedBy=graphical.target\n", WRITE_STRING_FILE_CREATE
|WRITE_STRING_FILE_MKDIR_0755
) >= 0);
844 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "with-dropin-3.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
846 p
= strjoina(root
, "/usr/lib/systemd/system/with-dropin-4a.service");
847 assert_se(write_string_file(p
,
849 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
851 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/with-dropin-4a.service.d/dropin.conf");
852 assert_se(write_string_file(p
,
854 "Also=with-dropin-4b.service\n", WRITE_STRING_FILE_CREATE
|WRITE_STRING_FILE_MKDIR_0755
) >= 0);
856 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "with-dropin-4a.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
858 p
= strjoina(root
, "/usr/lib/systemd/system/with-dropin-4b.service");
859 assert_se(write_string_file(p
,
861 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
863 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "with-dropin-4b.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
865 assert_se(unit_file_enable(LOOKUP_SCOPE_SYSTEM
, 0, root
, STRV_MAKE("with-dropin-1.service"), &changes
, &n_changes
) == 1);
866 assert_se(n_changes
== 2);
867 assert_se(changes
[0].type
== INSTALL_CHANGE_SYMLINK
);
868 assert_se(changes
[1].type
== INSTALL_CHANGE_SYMLINK
);
869 assert_se(streq(changes
[0].source
, "/usr/lib/systemd/system/with-dropin-1.service"));
870 assert_se(streq(changes
[1].source
, "/usr/lib/systemd/system/with-dropin-1.service"));
871 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/with-dropin-1.service");
872 assert_se(streq(changes
[0].path
, p
));
873 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/graphical.target.wants/with-dropin-1.service");
874 assert_se(streq(changes
[1].path
, p
));
875 install_changes_free(changes
, n_changes
);
876 changes
= NULL
; n_changes
= 0;
878 assert_se(unit_file_enable(LOOKUP_SCOPE_SYSTEM
, 0, root
, STRV_MAKE("with-dropin-2.service"), &changes
, &n_changes
) == 1);
879 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "with-dropin-2.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
880 assert_se(n_changes
== 2);
881 assert_se(changes
[0].type
== INSTALL_CHANGE_SYMLINK
);
882 assert_se(changes
[1].type
== INSTALL_CHANGE_SYMLINK
);
883 assert_se(streq(changes
[0].source
, SYSTEM_CONFIG_UNIT_DIR
"/with-dropin-2.service"));
884 assert_se(streq(changes
[1].source
, SYSTEM_CONFIG_UNIT_DIR
"/with-dropin-2.service"));
885 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/with-dropin-2.service");
886 assert_se(streq(changes
[0].path
, p
));
887 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/graphical.target.wants/with-dropin-2.service");
888 assert_se(streq(changes
[1].path
, p
));
889 install_changes_free(changes
, n_changes
);
890 changes
= NULL
; n_changes
= 0;
892 assert_se(unit_file_enable(LOOKUP_SCOPE_SYSTEM
, 0, root
, STRV_MAKE("with-dropin-3.service"), &changes
, &n_changes
) == 1);
893 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "with-dropin-3.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
894 assert_se(n_changes
== 2);
895 assert_se(changes
[0].type
== INSTALL_CHANGE_SYMLINK
);
896 assert_se(changes
[1].type
== INSTALL_CHANGE_SYMLINK
);
897 assert_se(streq(changes
[0].source
, "/usr/lib/systemd/system/with-dropin-3.service"));
898 assert_se(streq(changes
[1].source
, "/usr/lib/systemd/system/with-dropin-3.service"));
899 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/with-dropin-3.service");
900 assert_se(streq(changes
[0].path
, p
));
901 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/graphical.target.wants/with-dropin-3.service");
902 assert_se(streq(changes
[1].path
, p
));
903 install_changes_free(changes
, n_changes
);
904 changes
= NULL
; n_changes
= 0;
906 assert_se(unit_file_enable(LOOKUP_SCOPE_SYSTEM
, 0, root
, STRV_MAKE("with-dropin-4a.service"), &changes
, &n_changes
) == 2);
907 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "with-dropin-3.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
908 assert_se(n_changes
== 2);
909 assert_se(changes
[0].type
== INSTALL_CHANGE_SYMLINK
);
910 assert_se(changes
[1].type
== INSTALL_CHANGE_SYMLINK
);
911 assert_se(streq(changes
[0].source
, "/usr/lib/systemd/system/with-dropin-4a.service"));
912 assert_se(streq(changes
[1].source
, "/usr/lib/systemd/system/with-dropin-4b.service"));
913 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/with-dropin-4a.service");
914 assert_se(streq(changes
[0].path
, p
));
915 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/with-dropin-4b.service");
916 assert_se(streq(changes
[1].path
, p
));
917 install_changes_free(changes
, n_changes
);
918 changes
= NULL
; n_changes
= 0;
920 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "with-dropin-1.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
921 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "with-dropin-2.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
922 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "with-dropin-3.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
923 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "with-dropin-4a.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
924 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "with-dropin-4b.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
927 TEST(with_dropin_template
) {
930 InstallChange
*changes
= NULL
;
931 size_t n_changes
= 0;
933 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "with-dropin-1@.service", &state
) == -ENOENT
);
934 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "with-dropin-2@.service", &state
) == -ENOENT
);
935 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "with-dropin-3@.service", &state
) == -ENOENT
);
937 p
= strjoina(root
, "/usr/lib/systemd/system/with-dropin-1@.service");
938 assert_se(write_string_file(p
,
940 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
942 p
= strjoina(root
, "/usr/lib/systemd/system/with-dropin-1@.service.d/dropin.conf");
943 assert_se(write_string_file(p
,
945 "WantedBy=graphical.target\n", WRITE_STRING_FILE_CREATE
|WRITE_STRING_FILE_MKDIR_0755
) >= 0);
947 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "with-dropin-1@.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
949 p
= strjoina(root
, "/usr/lib/systemd/system/with-dropin-2@.service");
950 assert_se(write_string_file(p
,
952 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
954 p
= strjoina(root
, "/usr/lib/systemd/system/with-dropin-2@instance-1.service.d/dropin.conf");
955 assert_se(write_string_file(p
,
957 "WantedBy=graphical.target\n", WRITE_STRING_FILE_CREATE
|WRITE_STRING_FILE_MKDIR_0755
) >= 0);
959 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "with-dropin-2@.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
961 p
= strjoina(root
, "/usr/lib/systemd/system/with-dropin-3@.service");
962 assert_se(write_string_file(p
,
964 "DefaultInstance=instance-1\n"
965 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
967 p
= strjoina(root
, "/usr/lib/systemd/system/with-dropin-3@.service.d/dropin.conf");
968 assert_se(write_string_file(p
,
970 "DefaultInstance=instance-2\n", WRITE_STRING_FILE_CREATE
|WRITE_STRING_FILE_MKDIR_0755
) >= 0);
972 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "with-dropin-3@.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
974 assert_se(unit_file_enable(LOOKUP_SCOPE_SYSTEM
, 0, root
, STRV_MAKE("with-dropin-1@instance-1.service"), &changes
, &n_changes
) == 1);
975 assert_se(n_changes
== 2);
976 assert_se(changes
[0].type
== INSTALL_CHANGE_SYMLINK
);
977 assert_se(changes
[1].type
== INSTALL_CHANGE_SYMLINK
);
978 assert_se(streq(changes
[0].source
, "/usr/lib/systemd/system/with-dropin-1@.service"));
979 assert_se(streq(changes
[1].source
, "/usr/lib/systemd/system/with-dropin-1@.service"));
980 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/with-dropin-1@instance-1.service");
981 assert_se(streq(changes
[0].path
, p
));
982 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/graphical.target.wants/with-dropin-1@instance-1.service");
983 assert_se(streq(changes
[1].path
, p
));
984 install_changes_free(changes
, n_changes
);
985 changes
= NULL
; n_changes
= 0;
987 assert_se(unit_file_enable(LOOKUP_SCOPE_SYSTEM
, 0, root
, STRV_MAKE("with-dropin-2@instance-1.service"), &changes
, &n_changes
) == 1);
988 assert_se(n_changes
== 2);
989 assert_se(changes
[0].type
== INSTALL_CHANGE_SYMLINK
);
990 assert_se(changes
[1].type
== INSTALL_CHANGE_SYMLINK
);
991 assert_se(streq(changes
[0].source
, "/usr/lib/systemd/system/with-dropin-2@.service"));
992 assert_se(streq(changes
[1].source
, "/usr/lib/systemd/system/with-dropin-2@.service"));
993 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/with-dropin-2@instance-1.service");
994 assert_se(streq(changes
[0].path
, p
));
995 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/graphical.target.wants/with-dropin-2@instance-1.service");
996 assert_se(streq(changes
[1].path
, p
));
997 install_changes_free(changes
, n_changes
);
998 changes
= NULL
; n_changes
= 0;
1000 assert_se(unit_file_enable(LOOKUP_SCOPE_SYSTEM
, 0, root
, STRV_MAKE("with-dropin-2@instance-2.service"), &changes
, &n_changes
) == 1);
1001 assert_se(n_changes
== 1);
1002 assert_se(changes
[0].type
== INSTALL_CHANGE_SYMLINK
);
1003 assert_se(streq(changes
[0].source
, "/usr/lib/systemd/system/with-dropin-2@.service"));
1004 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/with-dropin-2@instance-2.service");
1005 assert_se(streq(changes
[0].path
, p
));
1006 install_changes_free(changes
, n_changes
);
1007 changes
= NULL
; n_changes
= 0;
1009 assert_se(unit_file_enable(LOOKUP_SCOPE_SYSTEM
, 0, root
, STRV_MAKE("with-dropin-3@.service"), &changes
, &n_changes
) == 1);
1010 assert_se(n_changes
== 1);
1011 assert_se(changes
[0].type
== INSTALL_CHANGE_SYMLINK
);
1012 assert_se(streq(changes
[0].source
, "/usr/lib/systemd/system/with-dropin-3@.service"));
1013 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/with-dropin-3@instance-2.service");
1014 assert_se(streq(changes
[0].path
, p
));
1015 install_changes_free(changes
, n_changes
);
1016 changes
= NULL
; n_changes
= 0;
1018 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "with-dropin-1@instance-1.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
1019 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "with-dropin-2@instance-1.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
1020 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "with-dropin-2@instance-2.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
1021 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "with-dropin-3@instance-1.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
1022 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "with-dropin-3@instance-2.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
1025 TEST(preset_multiple_instances
) {
1026 InstallChange
*changes
= NULL
;
1027 size_t n_changes
= 0;
1029 UnitFileState state
;
1031 /* Set up template service files and preset file */
1032 p
= strjoina(root
, "/usr/lib/systemd/system/foo@.service");
1033 assert_se(write_string_file(p
,
1035 "DefaultInstance=def\n"
1036 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
1038 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "foo@.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
1040 p
= strjoina(root
, "/usr/lib/systemd/system-preset/test.preset");
1041 assert_se(write_string_file(p
,
1042 "enable foo@.service bar0 bar1 bartest\n"
1043 "enable emptylist@.service\n" /* This line ensures the old functionality for templated unit still works */
1044 "disable *\n" , WRITE_STRING_FILE_CREATE
) >= 0);
1046 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "foo@bar0.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
1048 /* Preset a single instantiated unit specified in the list */
1049 assert_se(unit_file_preset(LOOKUP_SCOPE_SYSTEM
, 0, root
, STRV_MAKE("foo@bar0.service"), UNIT_FILE_PRESET_FULL
, &changes
, &n_changes
) >= 0);
1050 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "foo@bar0.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
1051 assert_se(n_changes
== 1);
1052 assert_se(changes
[0].type
== INSTALL_CHANGE_SYMLINK
);
1053 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/foo@bar0.service");
1054 assert_se(streq(changes
[0].path
, p
));
1055 install_changes_free(changes
, n_changes
);
1056 changes
= NULL
; n_changes
= 0;
1058 assert_se(unit_file_disable(LOOKUP_SCOPE_SYSTEM
, 0, root
, STRV_MAKE("foo@bar0.service"), &changes
, &n_changes
) >= 0);
1059 assert_se(n_changes
== 1);
1060 assert_se(changes
[0].type
== INSTALL_CHANGE_UNLINK
);
1061 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/foo@bar0.service");
1062 assert_se(streq(changes
[0].path
, p
));
1063 install_changes_free(changes
, n_changes
);
1064 changes
= NULL
; n_changes
= 0;
1066 /* Check for preset-all case, only instances on the list should be enabled, not including the default instance */
1067 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "foo@def.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
1068 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "foo@bar1.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
1069 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "foo@bartest.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
1071 assert_se(unit_file_preset_all(LOOKUP_SCOPE_SYSTEM
, 0, root
, UNIT_FILE_PRESET_FULL
, &changes
, &n_changes
) >= 0);
1072 assert_se(n_changes
> 0);
1074 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "foo@def.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
1075 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "foo@bar0.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
1076 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "foo@bar1.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
1077 assert_se(unit_file_get_state(LOOKUP_SCOPE_SYSTEM
, root
, "foo@bartest.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
1079 install_changes_free(changes
, n_changes
);
1082 static void verify_one(
1083 const InstallInfo
*i
,
1086 const char *updated_name
) {
1088 static const InstallInfo
*last_info
= NULL
;
1089 _cleanup_free_
char *alias2
= NULL
;
1092 log_info("-- %s --", (last_info
= i
)->name
);
1094 r
= unit_file_verify_alias(i
, alias
, &alias2
, NULL
, NULL
);
1095 log_info_errno(r
, "alias %s ← %s: %d/%m (expected %d)%s%s%s",
1096 i
->name
, alias
, r
, expected
,
1097 alias2
? " [" : "", strempty(alias2
),
1099 assert_se(r
== expected
);
1101 /* This is test for "instance propagation". This propagation matters mostly for WantedBy= and
1102 * RequiredBy= settings, and less so for Alias=. The only case where it should happen is when we have
1103 * an Alias=alias@.service an instantiated template template@instance. In that case the instance name
1104 * should be propagated into the alias as alias@instance. */
1105 assert_se(streq_ptr(alias2
, updated_name
));
1108 TEST(verify_alias
) {
1110 plain_service
= { .name
= (char*) "plain.service" },
1111 bare_template
= { .name
= (char*) "template1@.service" },
1112 di_template
= { .name
= (char*) "template2@.service",
1113 .default_instance
= (char*) "di" },
1114 inst_template
= { .name
= (char*) "template3@inst.service" },
1115 di_inst_template
= { .name
= (char*) "template4@inst.service",
1116 .default_instance
= (char*) "di" };
1118 verify_one(&plain_service
, "alias.service", 0, NULL
);
1119 verify_one(&plain_service
, "alias.socket", -EXDEV
, NULL
);
1120 verify_one(&plain_service
, "alias@.service", -EXDEV
, NULL
);
1121 verify_one(&plain_service
, "alias@inst.service", -EXDEV
, NULL
);
1122 verify_one(&plain_service
, "foo.target.wants/plain.service", 0, NULL
);
1123 verify_one(&plain_service
, "foo.target.wants/plain.socket", -EXDEV
, NULL
);
1124 verify_one(&plain_service
, "foo.target.wants/plain@.service", -EXDEV
, NULL
);
1125 verify_one(&plain_service
, "foo.target.wants/service", -EXDEV
, NULL
);
1126 verify_one(&plain_service
, "foo.target.requires/plain.service", 0, NULL
);
1127 verify_one(&plain_service
, "foo.target.requires/plain.socket", -EXDEV
, NULL
);
1128 verify_one(&plain_service
, "foo.target.requires/plain@.service", -EXDEV
, NULL
);
1129 verify_one(&plain_service
, "foo.target.requires/service", -EXDEV
, NULL
);
1130 verify_one(&plain_service
, "foo.target.conf/plain.service", -EXDEV
, NULL
);
1131 verify_one(&plain_service
, "foo.service/plain.service", -EXDEV
, NULL
); /* missing dir suffix */
1132 verify_one(&plain_service
, "asdf.requires/plain.service", -EXDEV
, NULL
); /* invalid unit name component */
1134 verify_one(&bare_template
, "alias.service", -EXDEV
, NULL
);
1135 verify_one(&bare_template
, "alias.socket", -EXDEV
, NULL
);
1136 verify_one(&bare_template
, "alias@.socket", -EXDEV
, NULL
);
1137 verify_one(&bare_template
, "alias@inst.socket", -EXDEV
, NULL
);
1138 /* A general alias alias@.service → template1@.service. */
1139 verify_one(&bare_template
, "alias@.service", 0, NULL
);
1140 /* Only a specific instance is aliased, see the discussion in https://github.com/systemd/systemd/pull/13119. */
1141 verify_one(&bare_template
, "alias@inst.service", 0, NULL
);
1142 verify_one(&bare_template
, "foo.target.wants/plain.service", -EXDEV
, NULL
);
1143 verify_one(&bare_template
, "foo.target.wants/plain.socket", -EXDEV
, NULL
);
1144 verify_one(&bare_template
, "foo.target.wants/plain@.service", -EXDEV
, NULL
);
1145 /* Name mismatch: we cannot allow this, because plain@foo.service would be pulled in by foo.target,
1146 * but would not be resolveable on its own, since systemd doesn't know how to load the fragment. */
1147 verify_one(&bare_template
, "foo.target.wants/plain@foo.service", -EXDEV
, NULL
);
1148 verify_one(&bare_template
, "foo.target.wants/template1@foo.service", 0, NULL
);
1149 verify_one(&bare_template
, "foo.target.wants/service", -EXDEV
, NULL
);
1150 verify_one(&bare_template
, "foo.target.requires/plain.service", -EXDEV
, NULL
);
1151 verify_one(&bare_template
, "foo.target.requires/plain.socket", -EXDEV
, NULL
);
1152 verify_one(&bare_template
, "foo.target.requires/plain@.service", -EXDEV
, NULL
); /* instance missing */
1153 verify_one(&bare_template
, "foo.target.requires/template1@inst.service", 0, NULL
);
1154 verify_one(&bare_template
, "foo.target.requires/service", -EXDEV
, NULL
);
1155 verify_one(&bare_template
, "foo.target.conf/plain.service", -EXDEV
, NULL
);
1156 verify_one(&bare_template
, "FOO@.target.requires/plain@.service", -EXDEV
, NULL
); /* template name mismatch */
1157 verify_one(&bare_template
, "FOO@inst.target.requires/plain@.service", -EXDEV
, NULL
);
1158 verify_one(&bare_template
, "FOO@inst.target.requires/plain@inst.service", -EXDEV
, NULL
);
1159 verify_one(&bare_template
, "FOO@.target.requires/template1@.service", 0, NULL
); /* instance propagated */
1160 verify_one(&bare_template
, "FOO@inst.target.requires/template1@.service", -EXDEV
, NULL
); /* instance missing */
1161 verify_one(&bare_template
, "FOO@inst.target.requires/template1@inst.service", 0, NULL
); /* instance provided */
1163 verify_one(&di_template
, "alias.service", -EXDEV
, NULL
);
1164 verify_one(&di_template
, "alias.socket", -EXDEV
, NULL
);
1165 verify_one(&di_template
, "alias@.socket", -EXDEV
, NULL
);
1166 verify_one(&di_template
, "alias@inst.socket", -EXDEV
, NULL
);
1167 verify_one(&di_template
, "alias@inst.service", 0, NULL
);
1168 verify_one(&di_template
, "alias@.service", 0, NULL
);
1169 verify_one(&di_template
, "alias@di.service", 0, NULL
);
1170 verify_one(&di_template
, "foo.target.wants/plain.service", -EXDEV
, NULL
);
1171 verify_one(&di_template
, "foo.target.wants/plain.socket", -EXDEV
, NULL
);
1172 verify_one(&di_template
, "foo.target.wants/plain@.service", -EXDEV
, NULL
);
1173 verify_one(&di_template
, "foo.target.wants/plain@di.service", -EXDEV
, NULL
);
1174 verify_one(&di_template
, "foo.target.wants/template2@di.service", 0, NULL
);
1175 verify_one(&di_template
, "foo.target.wants/service", -EXDEV
, NULL
);
1176 verify_one(&di_template
, "foo.target.requires/plain.service", -EXDEV
, NULL
);
1177 verify_one(&di_template
, "foo.target.requires/plain.socket", -EXDEV
, NULL
);
1178 verify_one(&di_template
, "foo.target.requires/plain@.service", -EXDEV
, NULL
);
1179 verify_one(&di_template
, "foo.target.requires/plain@di.service", -EXDEV
, NULL
);
1180 verify_one(&di_template
, "foo.target.requires/plain@foo.service", -EXDEV
, NULL
);
1181 verify_one(&di_template
, "foo.target.requires/template2@.service", -EXDEV
, NULL
); /* instance missing */
1182 verify_one(&di_template
, "foo.target.requires/template2@di.service", 0, NULL
);
1183 verify_one(&di_template
, "foo.target.requires/service", -EXDEV
, NULL
);
1184 verify_one(&di_template
, "foo.target.conf/plain.service", -EXDEV
, NULL
);
1186 verify_one(&inst_template
, "alias.service", -EXDEV
, NULL
);
1187 verify_one(&inst_template
, "alias.socket", -EXDEV
, NULL
);
1188 verify_one(&inst_template
, "alias@.socket", -EXDEV
, NULL
);
1189 verify_one(&inst_template
, "alias@inst.socket", -EXDEV
, NULL
);
1190 verify_one(&inst_template
, "alias@inst.service", 0, NULL
);
1191 verify_one(&inst_template
, "alias@.service", 0, "alias@inst.service");
1192 verify_one(&inst_template
, "alias@di.service", -EXDEV
, NULL
);
1193 verify_one(&inst_template
, "bar.target.wants/plain.service", -EXDEV
, NULL
);
1194 verify_one(&inst_template
, "bar.target.wants/plain.socket", -EXDEV
, NULL
);
1195 verify_one(&inst_template
, "bar.target.wants/plain@.service", -EXDEV
, NULL
);
1196 verify_one(&inst_template
, "bar.target.wants/plain@di.service", -EXDEV
, NULL
);
1197 verify_one(&inst_template
, "bar.target.wants/plain@inst.service", -EXDEV
, NULL
);
1198 verify_one(&inst_template
, "bar.target.wants/template3@foo.service", -EXDEV
, NULL
);
1199 verify_one(&inst_template
, "bar.target.wants/template3@inst.service", 0, NULL
);
1200 verify_one(&inst_template
, "bar.target.wants/service", -EXDEV
, NULL
);
1201 verify_one(&inst_template
, "bar.target.requires/plain.service", -EXDEV
, NULL
);
1202 verify_one(&inst_template
, "bar.target.requires/plain.socket", -EXDEV
, NULL
);
1203 verify_one(&inst_template
, "bar.target.requires/plain@.service", -EXDEV
, NULL
);
1204 verify_one(&inst_template
, "bar.target.requires/plain@di.service", -EXDEV
, NULL
);
1205 verify_one(&inst_template
, "bar.target.requires/plain@inst.service", -EXDEV
, NULL
);
1206 verify_one(&inst_template
, "bar.target.requires/template3@foo.service", -EXDEV
, NULL
);
1207 verify_one(&inst_template
, "bar.target.requires/template3@inst.service", 0, NULL
);
1208 verify_one(&inst_template
, "bar.target.requires/service", -EXDEV
, NULL
);
1209 verify_one(&inst_template
, "bar.target.conf/plain.service", -EXDEV
, NULL
);
1210 verify_one(&inst_template
, "BAR@.target.requires/plain@.service", -EXDEV
, NULL
); /* template name mismatch */
1211 verify_one(&inst_template
, "BAR@inst.target.requires/plain@.service", -EXDEV
, NULL
);
1212 verify_one(&inst_template
, "BAR@inst.target.requires/plain@inst.service", -EXDEV
, NULL
);
1213 verify_one(&inst_template
, "BAR@.target.requires/template3@.service", -EXDEV
, NULL
); /* instance missing */
1214 verify_one(&inst_template
, "BAR@inst.target.requires/template3@.service", -EXDEV
, NULL
); /* instance missing */
1215 verify_one(&inst_template
, "BAR@inst.target.requires/template3@inst.service", 0, NULL
); /* instance provided */
1216 verify_one(&inst_template
, "BAR@inst.target.requires/template3@ins2.service", -EXDEV
, NULL
); /* instance mismatch */
1218 /* explicit alias overrides DefaultInstance */
1219 verify_one(&di_inst_template
, "alias.service", -EXDEV
, NULL
);
1220 verify_one(&di_inst_template
, "alias.socket", -EXDEV
, NULL
);
1221 verify_one(&di_inst_template
, "alias@.socket", -EXDEV
, NULL
);
1222 verify_one(&di_inst_template
, "alias@inst.socket", -EXDEV
, NULL
);
1223 verify_one(&di_inst_template
, "alias@inst.service", 0, NULL
);
1224 verify_one(&di_inst_template
, "alias@.service", 0, "alias@inst.service");
1225 verify_one(&di_inst_template
, "alias@di.service", -EXDEV
, NULL
);
1226 verify_one(&di_inst_template
, "goo.target.wants/plain.service", -EXDEV
, NULL
);
1227 verify_one(&di_inst_template
, "goo.target.wants/plain.socket", -EXDEV
, NULL
);
1228 verify_one(&di_inst_template
, "goo.target.wants/plain@.service", -EXDEV
, NULL
);
1229 verify_one(&di_inst_template
, "goo.target.wants/plain@di.service", -EXDEV
, NULL
);
1230 verify_one(&di_inst_template
, "goo.target.wants/template4@foo.service", -EXDEV
, NULL
);
1231 verify_one(&di_inst_template
, "goo.target.wants/template4@inst.service", 0, NULL
);
1232 verify_one(&di_inst_template
, "goo.target.wants/template4@di.service", -EXDEV
, NULL
);
1233 verify_one(&di_inst_template
, "goo.target.wants/service", -EXDEV
, NULL
);
1234 verify_one(&di_inst_template
, "goo.target.requires/plain.service", -EXDEV
, NULL
);
1235 verify_one(&di_inst_template
, "goo.target.requires/plain.socket", -EXDEV
, NULL
);
1236 verify_one(&di_inst_template
, "goo.target.requires/plain@.service", -EXDEV
, NULL
);
1237 verify_one(&di_inst_template
, "goo.target.requires/plain@di.service", -EXDEV
, NULL
);
1238 verify_one(&di_inst_template
, "goo.target.requires/plain@inst.service", -EXDEV
, NULL
);
1239 verify_one(&di_inst_template
, "goo.target.requires/template4@foo.service", -EXDEV
, NULL
);
1240 verify_one(&di_inst_template
, "goo.target.requires/template4@inst.service", 0, NULL
);
1241 verify_one(&di_inst_template
, "goo.target.requires/service", -EXDEV
, NULL
);
1242 verify_one(&di_inst_template
, "goo.target.conf/plain.service", -EXDEV
, NULL
);
1245 static int intro(void) {
1248 assert_se(mkdtemp_malloc("/tmp/rootXXXXXX", &root
) >= 0);
1250 p
= strjoina(root
, "/usr/lib/systemd/system/");
1251 assert_se(mkdir_p(p
, 0755) >= 0);
1253 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/");
1254 assert_se(mkdir_p(p
, 0755) >= 0);
1256 p
= strjoina(root
, "/run/systemd/system/");
1257 assert_se(mkdir_p(p
, 0755) >= 0);
1259 p
= strjoina(root
, "/opt/");
1260 assert_se(mkdir_p(p
, 0755) >= 0);
1262 p
= strjoina(root
, "/usr/lib/systemd/system-preset/");
1263 assert_se(mkdir_p(p
, 0755) >= 0);
1265 p
= strjoina(root
, "/usr/lib/systemd/system/multi-user.target");
1266 assert_se(write_string_file(p
, "# pretty much empty", WRITE_STRING_FILE_CREATE
) >= 0);
1268 p
= strjoina(root
, "/usr/lib/systemd/system/graphical.target");
1269 assert_se(write_string_file(p
, "# pretty much empty", WRITE_STRING_FILE_CREATE
) >= 0);
1271 return EXIT_SUCCESS
;
1275 DEFINE_TEST_MAIN_WITH_INTRO(LOG_INFO
, intro
);