1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
5 #include "alloc-util.h"
12 #include "string-util.h"
15 static void test_basic_mask_and_enable(const char *root
) {
18 UnitFileChange
*changes
= NULL
;
21 test_setup_logging(LOG_DEBUG
);
23 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "a.service", NULL
) == -ENOENT
);
24 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "b.service", NULL
) == -ENOENT
);
25 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "c.service", NULL
) == -ENOENT
);
26 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "d.service", NULL
) == -ENOENT
);
27 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "e.service", NULL
) == -ENOENT
);
28 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "f.service", NULL
) == -ENOENT
);
30 p
= strjoina(root
, "/usr/lib/systemd/system/a.service");
31 assert_se(write_string_file(p
,
33 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
35 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "a.service", NULL
) >= 0);
36 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "a.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
38 p
= strjoina(root
, "/usr/lib/systemd/system/b.service");
39 assert_se(symlink("a.service", p
) >= 0);
41 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "b.service", NULL
) >= 0);
42 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "b.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
44 p
= strjoina(root
, "/usr/lib/systemd/system/c.service");
45 assert_se(symlink("/usr/lib/systemd/system/a.service", p
) >= 0);
47 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "c.service", NULL
) >= 0);
48 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "c.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
50 p
= strjoina(root
, "/usr/lib/systemd/system/d.service");
51 assert_se(symlink("c.service", p
) >= 0);
53 /* This one is interesting, as d follows a relative, then an absolute symlink */
54 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "d.service", NULL
) >= 0);
55 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "d.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
57 assert_se(unit_file_mask(UNIT_FILE_SYSTEM
, 0, root
, STRV_MAKE("a.service"), &changes
, &n_changes
) >= 0);
58 assert_se(n_changes
== 1);
59 assert_se(changes
[0].type_or_errno
== UNIT_FILE_SYMLINK
);
60 assert_se(streq(changes
[0].source
, "/dev/null"));
61 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/a.service");
62 assert_se(streq(changes
[0].path
, p
));
64 unit_file_changes_free(changes
, n_changes
);
65 changes
= NULL
; n_changes
= 0;
67 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "a.service", &state
) >= 0 && state
== UNIT_FILE_MASKED
);
68 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "b.service", &state
) >= 0 && state
== UNIT_FILE_MASKED
);
69 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "c.service", &state
) >= 0 && state
== UNIT_FILE_MASKED
);
70 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "d.service", &state
) >= 0 && state
== UNIT_FILE_MASKED
);
72 /* Enabling a masked unit should fail! */
73 assert_se(unit_file_enable(UNIT_FILE_SYSTEM
, 0, root
, STRV_MAKE("a.service"), &changes
, &n_changes
) == -ERFKILL
);
74 unit_file_changes_free(changes
, n_changes
);
75 changes
= NULL
; n_changes
= 0;
77 assert_se(unit_file_unmask(UNIT_FILE_SYSTEM
, 0, root
, STRV_MAKE("a.service"), &changes
, &n_changes
) >= 0);
78 assert_se(n_changes
== 1);
79 assert_se(changes
[0].type_or_errno
== UNIT_FILE_UNLINK
);
80 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/a.service");
81 assert_se(streq(changes
[0].path
, p
));
82 unit_file_changes_free(changes
, n_changes
);
83 changes
= NULL
; n_changes
= 0;
85 assert_se(unit_file_enable(UNIT_FILE_SYSTEM
, 0, root
, STRV_MAKE("a.service"), &changes
, &n_changes
) == 1);
86 assert_se(n_changes
== 1);
87 assert_se(changes
[0].type_or_errno
== UNIT_FILE_SYMLINK
);
88 assert_se(streq(changes
[0].source
, "/usr/lib/systemd/system/a.service"));
89 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/a.service");
90 assert_se(streq(changes
[0].path
, p
));
91 unit_file_changes_free(changes
, n_changes
);
92 changes
= NULL
; n_changes
= 0;
94 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "a.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
95 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "b.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
96 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "c.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
97 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "d.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
99 /* Enabling it again should succeed but be a NOP */
100 assert_se(unit_file_enable(UNIT_FILE_SYSTEM
, 0, root
, STRV_MAKE("a.service"), &changes
, &n_changes
) >= 0);
101 assert_se(n_changes
== 0);
102 unit_file_changes_free(changes
, n_changes
);
103 changes
= NULL
; n_changes
= 0;
105 assert_se(unit_file_disable(UNIT_FILE_SYSTEM
, 0, root
, STRV_MAKE("a.service"), &changes
, &n_changes
) >= 0);
106 assert_se(n_changes
== 1);
107 assert_se(changes
[0].type_or_errno
== UNIT_FILE_UNLINK
);
108 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/a.service");
109 assert_se(streq(changes
[0].path
, p
));
110 unit_file_changes_free(changes
, n_changes
);
111 changes
= NULL
; n_changes
= 0;
113 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "a.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
114 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "b.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
115 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "c.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
116 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "d.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
118 /* Disabling a disabled unit must succeed but be a NOP */
119 assert_se(unit_file_disable(UNIT_FILE_SYSTEM
, 0, root
, STRV_MAKE("a.service"), &changes
, &n_changes
) >= 0);
120 assert_se(n_changes
== 0);
121 unit_file_changes_free(changes
, n_changes
);
122 changes
= NULL
; n_changes
= 0;
124 /* Let's enable this indirectly via a symlink */
125 assert_se(unit_file_enable(UNIT_FILE_SYSTEM
, 0, root
, STRV_MAKE("d.service"), &changes
, &n_changes
) >= 0);
126 assert_se(n_changes
== 1);
127 assert_se(changes
[0].type_or_errno
== UNIT_FILE_SYMLINK
);
128 assert_se(streq(changes
[0].source
, "/usr/lib/systemd/system/a.service"));
129 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/a.service");
130 assert_se(streq(changes
[0].path
, p
));
131 unit_file_changes_free(changes
, n_changes
);
132 changes
= NULL
; n_changes
= 0;
134 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "a.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
135 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "b.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
136 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "c.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
137 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "d.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
139 /* Let's try to reenable */
141 assert_se(unit_file_reenable(UNIT_FILE_SYSTEM
, 0, root
, STRV_MAKE("b.service"), &changes
, &n_changes
) >= 0);
142 assert_se(n_changes
== 2);
143 assert_se(changes
[0].type_or_errno
== UNIT_FILE_UNLINK
);
144 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/a.service");
145 assert_se(streq(changes
[0].path
, p
));
146 assert_se(changes
[1].type_or_errno
== UNIT_FILE_SYMLINK
);
147 assert_se(streq(changes
[1].source
, "/usr/lib/systemd/system/a.service"));
148 assert_se(streq(changes
[1].path
, p
));
149 unit_file_changes_free(changes
, n_changes
);
150 changes
= NULL
; n_changes
= 0;
152 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "a.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
153 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "b.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
154 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "c.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
155 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "d.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
157 /* Test masking with relative symlinks */
159 p
= strjoina(root
, "/usr/lib/systemd/system/e.service");
160 assert_se(symlink("../../../../../../dev/null", p
) >= 0);
162 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "e.service", NULL
) >= 0);
163 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "e.service", &state
) >= 0 && state
== UNIT_FILE_MASKED
);
165 assert_se(unlink(p
) == 0);
166 assert_se(symlink("/usr/../dev/null", p
) >= 0);
168 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "e.service", NULL
) >= 0);
169 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "e.service", &state
) >= 0 && state
== UNIT_FILE_MASKED
);
171 assert_se(unlink(p
) == 0);
173 /* Test enabling with unknown dependency target */
175 p
= strjoina(root
, "/usr/lib/systemd/system/f.service");
176 assert_se(write_string_file(p
,
178 "WantedBy=x.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
180 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "f.service", NULL
) >= 0);
181 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "f.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
183 assert_se(unit_file_enable(UNIT_FILE_SYSTEM
, 0, root
, STRV_MAKE("f.service"), &changes
, &n_changes
) == 1);
184 assert_se(n_changes
== 2);
185 assert_se(changes
[0].type_or_errno
== UNIT_FILE_SYMLINK
);
186 assert_se(streq(changes
[0].source
, "/usr/lib/systemd/system/f.service"));
187 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/x.target.wants/f.service");
188 assert_se(streq(changes
[0].path
, p
));
189 assert_se(changes
[1].type_or_errno
== UNIT_FILE_DESTINATION_NOT_PRESENT
);
190 p
= strjoina(root
, "/usr/lib/systemd/system/f.service");
191 assert_se(streq(changes
[1].source
, p
));
192 assert_se(streq(changes
[1].path
, "x.target"));
193 unit_file_changes_free(changes
, n_changes
);
194 changes
= NULL
; n_changes
= 0;
196 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "f.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
199 static void test_linked_units(const char *root
) {
202 UnitFileChange
*changes
= NULL
;
203 size_t n_changes
= 0, i
;
206 * We'll test three cases here:
208 * a) a unit file in /opt, that we use "systemctl link" and
209 * "systemctl enable" on to make it available to the system
211 * b) a unit file in /opt, that is statically linked into
212 * /usr/lib/systemd/system, that "enable" should work on
215 * c) a unit file in /opt, that is linked into
216 * /etc/systemd/system, and where "enable" should result in
217 * -ELOOP, since using information from /etc to generate
218 * information in /etc should not be allowed.
221 p
= strjoina(root
, "/opt/linked.service");
222 assert_se(write_string_file(p
,
224 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
226 p
= strjoina(root
, "/opt/linked2.service");
227 assert_se(write_string_file(p
,
229 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
231 p
= strjoina(root
, "/opt/linked3.service");
232 assert_se(write_string_file(p
,
234 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
236 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "linked.service", NULL
) == -ENOENT
);
237 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "linked2.service", NULL
) == -ENOENT
);
238 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "linked3.service", NULL
) == -ENOENT
);
240 p
= strjoina(root
, "/usr/lib/systemd/system/linked2.service");
241 assert_se(symlink("/opt/linked2.service", p
) >= 0);
243 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/linked3.service");
244 assert_se(symlink("/opt/linked3.service", p
) >= 0);
246 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "linked.service", &state
) == -ENOENT
);
247 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "linked2.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
248 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "linked3.service", &state
) >= 0 && state
== UNIT_FILE_LINKED
);
250 /* First, let's link the unit into the search path */
251 assert_se(unit_file_link(UNIT_FILE_SYSTEM
, 0, root
, STRV_MAKE("/opt/linked.service"), &changes
, &n_changes
) >= 0);
252 assert_se(n_changes
== 1);
253 assert_se(changes
[0].type_or_errno
== UNIT_FILE_SYMLINK
);
254 assert_se(streq(changes
[0].source
, "/opt/linked.service"));
255 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/linked.service");
256 assert_se(streq(changes
[0].path
, p
));
257 unit_file_changes_free(changes
, n_changes
);
258 changes
= NULL
; n_changes
= 0;
260 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "linked.service", &state
) >= 0 && state
== UNIT_FILE_LINKED
);
262 /* Let's unlink it from the search path again */
263 assert_se(unit_file_disable(UNIT_FILE_SYSTEM
, 0, root
, STRV_MAKE("linked.service"), &changes
, &n_changes
) >= 0);
264 assert_se(n_changes
== 1);
265 assert_se(changes
[0].type_or_errno
== UNIT_FILE_UNLINK
);
266 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/linked.service");
267 assert_se(streq(changes
[0].path
, p
));
268 unit_file_changes_free(changes
, n_changes
);
269 changes
= NULL
; n_changes
= 0;
271 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "linked.service", NULL
) == -ENOENT
);
273 /* Now, let's not just link it, but also enable it */
274 assert_se(unit_file_enable(UNIT_FILE_SYSTEM
, 0, root
, STRV_MAKE("/opt/linked.service"), &changes
, &n_changes
) >= 0);
275 assert_se(n_changes
== 2);
276 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/linked.service");
277 q
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/linked.service");
278 for (i
= 0 ; i
< n_changes
; i
++) {
279 assert_se(changes
[i
].type_or_errno
== UNIT_FILE_SYMLINK
);
280 assert_se(streq(changes
[i
].source
, "/opt/linked.service"));
282 if (p
&& streq(changes
[i
].path
, p
))
284 else if (q
&& streq(changes
[i
].path
, q
))
287 assert_not_reached();
290 unit_file_changes_free(changes
, n_changes
);
291 changes
= NULL
; n_changes
= 0;
293 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "linked.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
295 /* And let's unlink it again */
296 assert_se(unit_file_disable(UNIT_FILE_SYSTEM
, 0, root
, STRV_MAKE("linked.service"), &changes
, &n_changes
) >= 0);
297 assert_se(n_changes
== 2);
298 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/linked.service");
299 q
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/linked.service");
300 for (i
= 0; i
< n_changes
; i
++) {
301 assert_se(changes
[i
].type_or_errno
== UNIT_FILE_UNLINK
);
303 if (p
&& streq(changes
[i
].path
, p
))
305 else if (q
&& streq(changes
[i
].path
, q
))
308 assert_not_reached();
311 unit_file_changes_free(changes
, n_changes
);
312 changes
= NULL
; n_changes
= 0;
314 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "linked.service", NULL
) == -ENOENT
);
316 assert_se(unit_file_enable(UNIT_FILE_SYSTEM
, 0, root
, STRV_MAKE("linked2.service"), &changes
, &n_changes
) >= 0);
317 assert_se(n_changes
== 2);
318 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/linked2.service");
319 q
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/linked2.service");
320 for (i
= 0 ; i
< n_changes
; i
++) {
321 assert_se(changes
[i
].type_or_errno
== UNIT_FILE_SYMLINK
);
322 assert_se(streq(changes
[i
].source
, "/opt/linked2.service"));
324 if (p
&& streq(changes
[i
].path
, p
))
326 else if (q
&& streq(changes
[i
].path
, q
))
329 assert_not_reached();
332 unit_file_changes_free(changes
, n_changes
);
333 changes
= NULL
; n_changes
= 0;
335 assert_se(unit_file_enable(UNIT_FILE_SYSTEM
, 0, root
, STRV_MAKE("linked3.service"), &changes
, &n_changes
) >= 0);
336 assert_se(n_changes
== 1);
337 assert_se(changes
[0].type_or_errno
== UNIT_FILE_SYMLINK
);
338 assert_se(startswith(changes
[0].path
, root
));
339 assert_se(endswith(changes
[0].path
, "linked3.service"));
340 assert_se(streq(changes
[0].source
, "/opt/linked3.service"));
341 unit_file_changes_free(changes
, n_changes
);
342 changes
= NULL
; n_changes
= 0;
345 static void test_default(const char *root
) {
346 _cleanup_free_
char *def
= NULL
;
347 UnitFileChange
*changes
= NULL
;
348 size_t n_changes
= 0;
351 p
= strjoina(root
, "/usr/lib/systemd/system/test-default-real.target");
352 assert_se(write_string_file(p
, "# pretty much empty", WRITE_STRING_FILE_CREATE
) >= 0);
354 p
= strjoina(root
, "/usr/lib/systemd/system/test-default.target");
355 assert_se(symlink("test-default-real.target", p
) >= 0);
357 assert_se(unit_file_get_default(UNIT_FILE_SYSTEM
, root
, &def
) == -ENOENT
);
359 assert_se(unit_file_set_default(UNIT_FILE_SYSTEM
, 0, root
, "idontexist.target", &changes
, &n_changes
) == -ENOENT
);
360 assert_se(n_changes
== 1);
361 assert_se(changes
[0].type_or_errno
== -ENOENT
);
362 assert_se(streq_ptr(changes
[0].path
, "idontexist.target"));
363 unit_file_changes_free(changes
, n_changes
);
364 changes
= NULL
; n_changes
= 0;
366 assert_se(unit_file_get_default(UNIT_FILE_SYSTEM
, root
, &def
) == -ENOENT
);
368 assert_se(unit_file_set_default(UNIT_FILE_SYSTEM
, 0, root
, "test-default.target", &changes
, &n_changes
) >= 0);
369 assert_se(n_changes
== 1);
370 assert_se(changes
[0].type_or_errno
== UNIT_FILE_SYMLINK
);
371 assert_se(streq(changes
[0].source
, "/usr/lib/systemd/system/test-default-real.target"));
372 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/" SPECIAL_DEFAULT_TARGET
);
373 assert_se(streq(changes
[0].path
, p
));
374 unit_file_changes_free(changes
, n_changes
);
375 changes
= NULL
; n_changes
= 0;
377 assert_se(unit_file_get_default(UNIT_FILE_SYSTEM
, root
, &def
) >= 0);
378 assert_se(streq_ptr(def
, "test-default-real.target"));
381 static void test_add_dependency(const char *root
) {
382 UnitFileChange
*changes
= NULL
;
383 size_t n_changes
= 0;
386 p
= strjoina(root
, "/usr/lib/systemd/system/real-add-dependency-test-target.target");
387 assert_se(write_string_file(p
, "# pretty much empty", WRITE_STRING_FILE_CREATE
) >= 0);
389 p
= strjoina(root
, "/usr/lib/systemd/system/add-dependency-test-target.target");
390 assert_se(symlink("real-add-dependency-test-target.target", p
) >= 0);
392 p
= strjoina(root
, "/usr/lib/systemd/system/real-add-dependency-test-service.service");
393 assert_se(write_string_file(p
, "# pretty much empty", WRITE_STRING_FILE_CREATE
) >= 0);
395 p
= strjoina(root
, "/usr/lib/systemd/system/add-dependency-test-service.service");
396 assert_se(symlink("real-add-dependency-test-service.service", p
) >= 0);
398 assert_se(unit_file_add_dependency(UNIT_FILE_SYSTEM
, 0, root
, STRV_MAKE("add-dependency-test-service.service"), "add-dependency-test-target.target", UNIT_WANTS
, &changes
, &n_changes
) >= 0);
399 assert_se(n_changes
== 1);
400 assert_se(changes
[0].type_or_errno
== UNIT_FILE_SYMLINK
);
401 assert_se(streq(changes
[0].source
, "/usr/lib/systemd/system/real-add-dependency-test-service.service"));
402 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/real-add-dependency-test-target.target.wants/real-add-dependency-test-service.service");
403 assert_se(streq(changes
[0].path
, p
));
404 unit_file_changes_free(changes
, n_changes
);
405 changes
= NULL
; n_changes
= 0;
408 static void test_template_enable(const char *root
) {
409 UnitFileChange
*changes
= NULL
;
410 size_t n_changes
= 0;
414 log_info("== %s ==", __func__
);
416 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template@.service", &state
) == -ENOENT
);
417 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template@def.service", &state
) == -ENOENT
);
418 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template@foo.service", &state
) == -ENOENT
);
419 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template-symlink@foo.service", &state
) == -ENOENT
);
421 p
= strjoina(root
, "/usr/lib/systemd/system/template@.service");
422 assert_se(write_string_file(p
,
424 "DefaultInstance=def\n"
425 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
427 p
= strjoina(root
, "/usr/lib/systemd/system/template-symlink@.service");
428 assert_se(symlink("template@.service", p
) >= 0);
430 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template@.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
431 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template@def.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
432 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template@foo.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
433 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template-symlink@.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
434 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template-symlink@def.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
435 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template-symlink@foo.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
437 log_info("== %s with template@.service enabled ==", __func__
);
439 assert_se(unit_file_enable(UNIT_FILE_SYSTEM
, 0, root
, STRV_MAKE("template@.service"), &changes
, &n_changes
) >= 0);
440 assert_se(n_changes
== 1);
441 assert_se(changes
[0].type_or_errno
== UNIT_FILE_SYMLINK
);
442 assert_se(streq(changes
[0].source
, "/usr/lib/systemd/system/template@.service"));
443 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/template@def.service");
444 assert_se(streq(changes
[0].path
, p
));
445 unit_file_changes_free(changes
, n_changes
);
446 changes
= NULL
; n_changes
= 0;
448 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template@.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
449 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template@def.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
450 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template@foo.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
451 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template-symlink@.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
452 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template-symlink@def.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
453 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template-symlink@foo.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
455 assert_se(unit_file_disable(UNIT_FILE_SYSTEM
, 0, root
, STRV_MAKE("template@.service"), &changes
, &n_changes
) >= 0);
456 assert_se(n_changes
== 1);
457 assert_se(changes
[0].type_or_errno
== UNIT_FILE_UNLINK
);
458 assert_se(streq(changes
[0].path
, p
));
459 unit_file_changes_free(changes
, n_changes
);
460 changes
= NULL
; n_changes
= 0;
462 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template@.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
463 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template@def.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
464 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template@foo.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
465 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template-symlink@.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
466 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template-symlink@def.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
467 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template-symlink@foo.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
469 log_info("== %s with template@foo.service enabled ==", __func__
);
471 assert_se(unit_file_enable(UNIT_FILE_SYSTEM
, 0, root
, STRV_MAKE("template@foo.service"), &changes
, &n_changes
) >= 0);
472 assert_se(changes
[0].type_or_errno
== UNIT_FILE_SYMLINK
);
473 assert_se(streq(changes
[0].source
, "/usr/lib/systemd/system/template@.service"));
474 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/template@foo.service");
475 assert_se(streq(changes
[0].path
, p
));
476 unit_file_changes_free(changes
, n_changes
);
477 changes
= NULL
; n_changes
= 0;
479 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template@.service", &state
) >= 0 && state
== UNIT_FILE_INDIRECT
);
480 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template@def.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
481 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template@foo.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
482 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template-symlink@foo.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
483 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template-symlink@def.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
484 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template-symlink@foo.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
486 assert_se(unit_file_disable(UNIT_FILE_SYSTEM
, 0, root
, STRV_MAKE("template@foo.service"), &changes
, &n_changes
) >= 0);
487 assert_se(n_changes
== 1);
488 assert_se(changes
[0].type_or_errno
== UNIT_FILE_UNLINK
);
489 assert_se(streq(changes
[0].path
, p
));
490 unit_file_changes_free(changes
, n_changes
);
491 changes
= NULL
; n_changes
= 0;
493 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template@.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
494 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template@def.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
495 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template@foo.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
496 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template@quux.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
497 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template-symlink@.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
498 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template-symlink@def.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
499 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template-symlink@foo.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
500 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template-symlink@quux.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
502 log_info("== %s with template-symlink@quux.service enabled ==", __func__
);
504 assert_se(unit_file_enable(UNIT_FILE_SYSTEM
, 0, root
, STRV_MAKE("template-symlink@quux.service"), &changes
, &n_changes
) >= 0);
505 assert_se(changes
[0].type_or_errno
== UNIT_FILE_SYMLINK
);
506 assert_se(streq(changes
[0].source
, "/usr/lib/systemd/system/template@.service"));
507 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/template@quux.service");
508 assert_se(streq(changes
[0].path
, p
));
509 unit_file_changes_free(changes
, n_changes
);
510 changes
= NULL
; n_changes
= 0;
512 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template@.service", &state
) >= 0 && state
== UNIT_FILE_INDIRECT
);
513 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template@def.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
514 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template@foo.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
515 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template@quux.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
516 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template-symlink@.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
517 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template-symlink@def.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
518 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template-symlink@foo.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
519 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template-symlink@quux.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
522 static void test_indirect(const char *root
) {
523 UnitFileChange
*changes
= NULL
;
524 size_t n_changes
= 0;
528 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "indirecta.service", &state
) == -ENOENT
);
529 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "indirectb.service", &state
) == -ENOENT
);
530 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "indirectc.service", &state
) == -ENOENT
);
532 p
= strjoina(root
, "/usr/lib/systemd/system/indirecta.service");
533 assert_se(write_string_file(p
,
535 "Also=indirectb.service\n", WRITE_STRING_FILE_CREATE
) >= 0);
537 p
= strjoina(root
, "/usr/lib/systemd/system/indirectb.service");
538 assert_se(write_string_file(p
,
540 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
542 p
= strjoina(root
, "/usr/lib/systemd/system/indirectc.service");
543 assert_se(symlink("indirecta.service", p
) >= 0);
545 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "indirecta.service", &state
) >= 0 && state
== UNIT_FILE_INDIRECT
);
546 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "indirectb.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
547 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "indirectc.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
549 assert_se(unit_file_enable(UNIT_FILE_SYSTEM
, 0, root
, STRV_MAKE("indirectc.service"), &changes
, &n_changes
) >= 0);
550 assert_se(n_changes
== 1);
551 assert_se(changes
[0].type_or_errno
== UNIT_FILE_SYMLINK
);
552 assert_se(streq(changes
[0].source
, "/usr/lib/systemd/system/indirectb.service"));
553 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/indirectb.service");
554 assert_se(streq(changes
[0].path
, p
));
555 unit_file_changes_free(changes
, n_changes
);
556 changes
= NULL
; n_changes
= 0;
558 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "indirecta.service", &state
) >= 0 && state
== UNIT_FILE_INDIRECT
);
559 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "indirectb.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
560 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "indirectc.service", &state
) >= 0 && state
== UNIT_FILE_ALIAS
);
562 assert_se(unit_file_disable(UNIT_FILE_SYSTEM
, 0, root
, STRV_MAKE("indirectc.service"), &changes
, &n_changes
) >= 0);
563 assert_se(n_changes
== 1);
564 assert_se(changes
[0].type_or_errno
== UNIT_FILE_UNLINK
);
565 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/indirectb.service");
566 assert_se(streq(changes
[0].path
, p
));
567 unit_file_changes_free(changes
, n_changes
);
568 changes
= NULL
; n_changes
= 0;
571 static void test_preset_and_list(const char *root
) {
572 UnitFileChange
*changes
= NULL
;
573 size_t n_changes
= 0, i
;
576 bool got_yes
= false, got_no
= false;
580 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "preset-yes.service", &state
) == -ENOENT
);
581 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "preset-no.service", &state
) == -ENOENT
);
583 p
= strjoina(root
, "/usr/lib/systemd/system/preset-yes.service");
584 assert_se(write_string_file(p
,
586 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
588 p
= strjoina(root
, "/usr/lib/systemd/system/preset-no.service");
589 assert_se(write_string_file(p
,
591 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
593 p
= strjoina(root
, "/usr/lib/systemd/system-preset/test.preset");
594 assert_se(write_string_file(p
,
596 "disable *\n", WRITE_STRING_FILE_CREATE
) >= 0);
598 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "preset-yes.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
599 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "preset-no.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
601 assert_se(unit_file_preset(UNIT_FILE_SYSTEM
, 0, root
, STRV_MAKE("preset-yes.service"), UNIT_FILE_PRESET_FULL
, &changes
, &n_changes
) >= 0);
602 assert_se(n_changes
== 1);
603 assert_se(changes
[0].type_or_errno
== UNIT_FILE_SYMLINK
);
604 assert_se(streq(changes
[0].source
, "/usr/lib/systemd/system/preset-yes.service"));
605 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/preset-yes.service");
606 assert_se(streq(changes
[0].path
, p
));
607 unit_file_changes_free(changes
, n_changes
);
608 changes
= NULL
; n_changes
= 0;
610 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "preset-yes.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
611 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "preset-no.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
613 assert_se(unit_file_disable(UNIT_FILE_SYSTEM
, 0, root
, STRV_MAKE("preset-yes.service"), &changes
, &n_changes
) >= 0);
614 assert_se(n_changes
== 1);
615 assert_se(changes
[0].type_or_errno
== UNIT_FILE_UNLINK
);
616 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/preset-yes.service");
617 assert_se(streq(changes
[0].path
, p
));
618 unit_file_changes_free(changes
, n_changes
);
619 changes
= NULL
; n_changes
= 0;
621 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "preset-yes.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
622 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "preset-no.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
624 assert_se(unit_file_preset(UNIT_FILE_SYSTEM
, 0, root
, STRV_MAKE("preset-no.service"), UNIT_FILE_PRESET_FULL
, &changes
, &n_changes
) >= 0);
625 assert_se(n_changes
== 0);
626 unit_file_changes_free(changes
, n_changes
);
627 changes
= NULL
; n_changes
= 0;
629 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "preset-yes.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
630 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "preset-no.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
632 assert_se(unit_file_preset_all(UNIT_FILE_SYSTEM
, 0, root
, UNIT_FILE_PRESET_FULL
, &changes
, &n_changes
) >= 0);
634 assert_se(n_changes
> 0);
636 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/preset-yes.service");
638 for (i
= 0; i
< n_changes
; i
++) {
640 if (changes
[i
].type_or_errno
== UNIT_FILE_SYMLINK
) {
641 assert_se(streq(changes
[i
].source
, "/usr/lib/systemd/system/preset-yes.service"));
642 assert_se(streq(changes
[i
].path
, p
));
644 assert_se(changes
[i
].type_or_errno
== UNIT_FILE_UNLINK
);
647 unit_file_changes_free(changes
, n_changes
);
648 changes
= NULL
; n_changes
= 0;
650 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "preset-yes.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
651 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "preset-no.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
653 assert_se(h
= hashmap_new(&string_hash_ops
));
654 assert_se(unit_file_get_list(UNIT_FILE_SYSTEM
, root
, h
, NULL
, NULL
) >= 0);
656 p
= strjoina(root
, "/usr/lib/systemd/system/preset-yes.service");
657 q
= strjoina(root
, "/usr/lib/systemd/system/preset-no.service");
659 HASHMAP_FOREACH(fl
, h
) {
660 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, basename(fl
->path
), &state
) >= 0);
661 assert_se(fl
->state
== state
);
663 if (streq(fl
->path
, p
)) {
665 assert_se(fl
->state
== UNIT_FILE_ENABLED
);
666 } else if (streq(fl
->path
, q
)) {
668 assert_se(fl
->state
== UNIT_FILE_DISABLED
);
670 assert_se(IN_SET(fl
->state
, UNIT_FILE_DISABLED
, UNIT_FILE_STATIC
, UNIT_FILE_INDIRECT
, UNIT_FILE_ALIAS
));
673 unit_file_list_free(h
);
675 assert_se(got_yes
&& got_no
);
678 static void test_revert(const char *root
) {
681 UnitFileChange
*changes
= NULL
;
682 size_t n_changes
= 0;
686 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "xx.service", NULL
) == -ENOENT
);
687 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "yy.service", NULL
) == -ENOENT
);
689 p
= strjoina(root
, "/usr/lib/systemd/system/xx.service");
690 assert_se(write_string_file(p
, "# Empty\n", WRITE_STRING_FILE_CREATE
) >= 0);
692 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "xx.service", NULL
) >= 0);
693 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "xx.service", &state
) >= 0 && state
== UNIT_FILE_STATIC
);
695 /* Initially there's nothing to revert */
696 assert_se(unit_file_revert(UNIT_FILE_SYSTEM
, root
, STRV_MAKE("xx.service"), &changes
, &n_changes
) >= 0);
697 assert_se(n_changes
== 0);
698 unit_file_changes_free(changes
, n_changes
);
699 changes
= NULL
; n_changes
= 0;
701 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/xx.service");
702 assert_se(write_string_file(p
, "# Empty override\n", WRITE_STRING_FILE_CREATE
) >= 0);
704 /* Revert the override file */
705 assert_se(unit_file_revert(UNIT_FILE_SYSTEM
, root
, STRV_MAKE("xx.service"), &changes
, &n_changes
) >= 0);
706 assert_se(n_changes
== 1);
707 assert_se(changes
[0].type_or_errno
== UNIT_FILE_UNLINK
);
708 assert_se(streq(changes
[0].path
, p
));
709 unit_file_changes_free(changes
, n_changes
);
710 changes
= NULL
; n_changes
= 0;
712 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/xx.service.d/dropin.conf");
713 assert_se(mkdir_parents(p
, 0755) >= 0);
714 assert_se(write_string_file(p
, "# Empty dropin\n", WRITE_STRING_FILE_CREATE
) >= 0);
716 /* Revert the dropin file */
717 assert_se(unit_file_revert(UNIT_FILE_SYSTEM
, root
, STRV_MAKE("xx.service"), &changes
, &n_changes
) >= 0);
718 assert_se(n_changes
== 2);
719 assert_se(changes
[0].type_or_errno
== UNIT_FILE_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_or_errno
== UNIT_FILE_UNLINK
);
724 assert_se(streq(changes
[1].path
, p
));
725 unit_file_changes_free(changes
, n_changes
);
726 changes
= NULL
; n_changes
= 0;
729 static void test_preset_order(const char *root
) {
730 UnitFileChange
*changes
= NULL
;
731 size_t n_changes
= 0;
735 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "prefix-1.service", &state
) == -ENOENT
);
736 assert_se(unit_file_get_state(UNIT_FILE_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(UNIT_FILE_SYSTEM
, root
, "prefix-1.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
755 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "prefix-2.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
757 assert_se(unit_file_preset(UNIT_FILE_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_or_errno
== UNIT_FILE_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 unit_file_changes_free(changes
, n_changes
);
764 changes
= NULL
; n_changes
= 0;
766 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "prefix-1.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
767 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "prefix-2.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
769 assert_se(unit_file_preset(UNIT_FILE_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(UNIT_FILE_SYSTEM
, root
, "prefix-1.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
773 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "prefix-2.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
776 static void test_static_instance(const char *root
) {
780 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "static-instance@.service", &state
) == -ENOENT
);
781 assert_se(unit_file_get_state(UNIT_FILE_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(UNIT_FILE_SYSTEM
, root
, "static-instance@.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
789 assert_se(unit_file_get_state(UNIT_FILE_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(UNIT_FILE_SYSTEM
, root
, "static-instance@.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
795 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "static-instance@foo.service", &state
) >= 0 && state
== UNIT_FILE_STATIC
);
798 static void test_with_dropin(const char *root
) {
801 UnitFileChange
*changes
= NULL
;
802 size_t n_changes
= 0;
804 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "with-dropin-1.service", &state
) == -ENOENT
);
805 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "with-dropin-2.service", &state
) == -ENOENT
);
806 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "with-dropin-3.service", &state
) == -ENOENT
);
807 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "with-dropin-4a.service", &state
) == -ENOENT
);
808 assert_se(unit_file_get_state(UNIT_FILE_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(mkdir_parents(p
, 0755) >= 0);
817 assert_se(write_string_file(p
,
819 "WantedBy=graphical.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
821 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "with-dropin-1.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
823 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/with-dropin-2.service");
824 assert_se(write_string_file(p
,
826 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
828 p
= strjoina(root
, "/usr/lib/systemd/system/with-dropin-2.service.d/dropin.conf");
829 assert_se(mkdir_parents(p
, 0755) >= 0);
830 assert_se(write_string_file(p
,
832 "WantedBy=graphical.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
834 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "with-dropin-2.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
836 p
= strjoina(root
, "/usr/lib/systemd/system/with-dropin-3.service");
837 assert_se(write_string_file(p
,
839 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
841 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/with-dropin-3.service.d/dropin.conf");
842 assert_se(mkdir_parents(p
, 0755) >= 0);
843 assert_se(write_string_file(p
,
845 "WantedBy=graphical.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
847 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "with-dropin-3.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
849 p
= strjoina(root
, "/usr/lib/systemd/system/with-dropin-4a.service");
850 assert_se(write_string_file(p
,
852 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
854 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/with-dropin-4a.service.d/dropin.conf");
855 assert_se(mkdir_parents(p
, 0755) >= 0);
856 assert_se(write_string_file(p
,
858 "Also=with-dropin-4b.service\n", WRITE_STRING_FILE_CREATE
) >= 0);
860 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "with-dropin-4a.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
862 p
= strjoina(root
, "/usr/lib/systemd/system/with-dropin-4b.service");
863 assert_se(write_string_file(p
,
865 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
867 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "with-dropin-4b.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
869 assert_se(unit_file_enable(UNIT_FILE_SYSTEM
, 0, root
, STRV_MAKE("with-dropin-1.service"), &changes
, &n_changes
) == 1);
870 assert_se(n_changes
== 2);
871 assert_se(changes
[0].type_or_errno
== UNIT_FILE_SYMLINK
);
872 assert_se(changes
[1].type_or_errno
== UNIT_FILE_SYMLINK
);
873 assert_se(streq(changes
[0].source
, "/usr/lib/systemd/system/with-dropin-1.service"));
874 assert_se(streq(changes
[1].source
, "/usr/lib/systemd/system/with-dropin-1.service"));
875 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/with-dropin-1.service");
876 assert_se(streq(changes
[0].path
, p
));
877 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/graphical.target.wants/with-dropin-1.service");
878 assert_se(streq(changes
[1].path
, p
));
879 unit_file_changes_free(changes
, n_changes
);
880 changes
= NULL
; n_changes
= 0;
882 assert_se(unit_file_enable(UNIT_FILE_SYSTEM
, 0, root
, STRV_MAKE("with-dropin-2.service"), &changes
, &n_changes
) == 1);
883 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "with-dropin-2.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
884 assert_se(n_changes
== 2);
885 assert_se(changes
[0].type_or_errno
== UNIT_FILE_SYMLINK
);
886 assert_se(changes
[1].type_or_errno
== UNIT_FILE_SYMLINK
);
887 assert_se(streq(changes
[0].source
, SYSTEM_CONFIG_UNIT_DIR
"/with-dropin-2.service"));
888 assert_se(streq(changes
[1].source
, SYSTEM_CONFIG_UNIT_DIR
"/with-dropin-2.service"));
889 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/with-dropin-2.service");
890 assert_se(streq(changes
[0].path
, p
));
891 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/graphical.target.wants/with-dropin-2.service");
892 assert_se(streq(changes
[1].path
, p
));
893 unit_file_changes_free(changes
, n_changes
);
894 changes
= NULL
; n_changes
= 0;
896 assert_se(unit_file_enable(UNIT_FILE_SYSTEM
, 0, root
, STRV_MAKE("with-dropin-3.service"), &changes
, &n_changes
) == 1);
897 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "with-dropin-3.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
898 assert_se(n_changes
== 2);
899 assert_se(changes
[0].type_or_errno
== UNIT_FILE_SYMLINK
);
900 assert_se(changes
[1].type_or_errno
== UNIT_FILE_SYMLINK
);
901 assert_se(streq(changes
[0].source
, "/usr/lib/systemd/system/with-dropin-3.service"));
902 assert_se(streq(changes
[1].source
, "/usr/lib/systemd/system/with-dropin-3.service"));
903 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/with-dropin-3.service");
904 assert_se(streq(changes
[0].path
, p
));
905 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/graphical.target.wants/with-dropin-3.service");
906 assert_se(streq(changes
[1].path
, p
));
907 unit_file_changes_free(changes
, n_changes
);
908 changes
= NULL
; n_changes
= 0;
910 assert_se(unit_file_enable(UNIT_FILE_SYSTEM
, 0, root
, STRV_MAKE("with-dropin-4a.service"), &changes
, &n_changes
) == 2);
911 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "with-dropin-3.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
912 assert_se(n_changes
== 2);
913 assert_se(changes
[0].type_or_errno
== UNIT_FILE_SYMLINK
);
914 assert_se(changes
[1].type_or_errno
== UNIT_FILE_SYMLINK
);
915 assert_se(streq(changes
[0].source
, "/usr/lib/systemd/system/with-dropin-4a.service"));
916 assert_se(streq(changes
[1].source
, "/usr/lib/systemd/system/with-dropin-4b.service"));
917 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/with-dropin-4a.service");
918 assert_se(streq(changes
[0].path
, p
));
919 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/with-dropin-4b.service");
920 assert_se(streq(changes
[1].path
, p
));
921 unit_file_changes_free(changes
, n_changes
);
922 changes
= NULL
; n_changes
= 0;
924 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "with-dropin-1.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
925 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "with-dropin-2.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
926 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "with-dropin-3.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
927 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "with-dropin-4a.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
928 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "with-dropin-4b.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
931 static void test_with_dropin_template(const char *root
) {
934 UnitFileChange
*changes
= NULL
;
935 size_t n_changes
= 0;
937 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "with-dropin-1@.service", &state
) == -ENOENT
);
938 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "with-dropin-2@.service", &state
) == -ENOENT
);
939 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "with-dropin-3@.service", &state
) == -ENOENT
);
941 p
= strjoina(root
, "/usr/lib/systemd/system/with-dropin-1@.service");
942 assert_se(write_string_file(p
,
944 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
946 p
= strjoina(root
, "/usr/lib/systemd/system/with-dropin-1@.service.d/dropin.conf");
947 assert_se(mkdir_parents(p
, 0755) >= 0);
948 assert_se(write_string_file(p
,
950 "WantedBy=graphical.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
952 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "with-dropin-1@.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
954 p
= strjoina(root
, "/usr/lib/systemd/system/with-dropin-2@.service");
955 assert_se(write_string_file(p
,
957 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
959 p
= strjoina(root
, "/usr/lib/systemd/system/with-dropin-2@instance-1.service.d/dropin.conf");
960 assert_se(mkdir_parents(p
, 0755) >= 0);
961 assert_se(write_string_file(p
,
963 "WantedBy=graphical.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
965 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "with-dropin-2@.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
967 p
= strjoina(root
, "/usr/lib/systemd/system/with-dropin-3@.service");
968 assert_se(write_string_file(p
,
970 "DefaultInstance=instance-1\n"
971 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
973 p
= strjoina(root
, "/usr/lib/systemd/system/with-dropin-3@.service.d/dropin.conf");
974 assert_se(mkdir_parents(p
, 0755) >= 0);
975 assert_se(write_string_file(p
,
977 "DefaultInstance=instance-2\n", WRITE_STRING_FILE_CREATE
) >= 0);
979 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "with-dropin-3@.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
981 assert_se(unit_file_enable(UNIT_FILE_SYSTEM
, 0, root
, STRV_MAKE("with-dropin-1@instance-1.service"), &changes
, &n_changes
) == 1);
982 assert_se(n_changes
== 2);
983 assert_se(changes
[0].type_or_errno
== UNIT_FILE_SYMLINK
);
984 assert_se(changes
[1].type_or_errno
== UNIT_FILE_SYMLINK
);
985 assert_se(streq(changes
[0].source
, "/usr/lib/systemd/system/with-dropin-1@.service"));
986 assert_se(streq(changes
[1].source
, "/usr/lib/systemd/system/with-dropin-1@.service"));
987 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/with-dropin-1@instance-1.service");
988 assert_se(streq(changes
[0].path
, p
));
989 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/graphical.target.wants/with-dropin-1@instance-1.service");
990 assert_se(streq(changes
[1].path
, p
));
991 unit_file_changes_free(changes
, n_changes
);
992 changes
= NULL
; n_changes
= 0;
994 assert_se(unit_file_enable(UNIT_FILE_SYSTEM
, 0, root
, STRV_MAKE("with-dropin-2@instance-1.service"), &changes
, &n_changes
) == 1);
995 assert_se(n_changes
== 2);
996 assert_se(changes
[0].type_or_errno
== UNIT_FILE_SYMLINK
);
997 assert_se(changes
[1].type_or_errno
== UNIT_FILE_SYMLINK
);
998 assert_se(streq(changes
[0].source
, "/usr/lib/systemd/system/with-dropin-2@.service"));
999 assert_se(streq(changes
[1].source
, "/usr/lib/systemd/system/with-dropin-2@.service"));
1000 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/with-dropin-2@instance-1.service");
1001 assert_se(streq(changes
[0].path
, p
));
1002 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/graphical.target.wants/with-dropin-2@instance-1.service");
1003 assert_se(streq(changes
[1].path
, p
));
1004 unit_file_changes_free(changes
, n_changes
);
1005 changes
= NULL
; n_changes
= 0;
1007 assert_se(unit_file_enable(UNIT_FILE_SYSTEM
, 0, root
, STRV_MAKE("with-dropin-2@instance-2.service"), &changes
, &n_changes
) == 1);
1008 assert_se(n_changes
== 1);
1009 assert_se(changes
[0].type_or_errno
== UNIT_FILE_SYMLINK
);
1010 assert_se(streq(changes
[0].source
, "/usr/lib/systemd/system/with-dropin-2@.service"));
1011 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/with-dropin-2@instance-2.service");
1012 assert_se(streq(changes
[0].path
, p
));
1013 unit_file_changes_free(changes
, n_changes
);
1014 changes
= NULL
; n_changes
= 0;
1016 assert_se(unit_file_enable(UNIT_FILE_SYSTEM
, 0, root
, STRV_MAKE("with-dropin-3@.service"), &changes
, &n_changes
) == 1);
1017 assert_se(n_changes
== 1);
1018 assert_se(changes
[0].type_or_errno
== UNIT_FILE_SYMLINK
);
1019 assert_se(streq(changes
[0].source
, "/usr/lib/systemd/system/with-dropin-3@.service"));
1020 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/with-dropin-3@instance-2.service");
1021 assert_se(streq(changes
[0].path
, p
));
1022 unit_file_changes_free(changes
, n_changes
);
1023 changes
= NULL
; n_changes
= 0;
1025 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "with-dropin-1@instance-1.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
1026 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "with-dropin-2@instance-1.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
1027 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "with-dropin-2@instance-2.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
1028 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "with-dropin-3@instance-1.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
1029 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "with-dropin-3@instance-2.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
1032 static void test_preset_multiple_instances(const char *root
) {
1033 UnitFileChange
*changes
= NULL
;
1034 size_t n_changes
= 0;
1036 UnitFileState state
;
1038 /* Set up template service files and preset file */
1039 p
= strjoina(root
, "/usr/lib/systemd/system/foo@.service");
1040 assert_se(write_string_file(p
,
1042 "DefaultInstance=def\n"
1043 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
1045 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "foo@.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
1047 p
= strjoina(root
, "/usr/lib/systemd/system-preset/test.preset");
1048 assert_se(write_string_file(p
,
1049 "enable foo@.service bar0 bar1 bartest\n"
1050 "enable emptylist@.service\n" /* This line ensures the old functionality for templated unit still works */
1051 "disable *\n" , WRITE_STRING_FILE_CREATE
) >= 0);
1053 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "foo@bar0.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
1055 /* Preset a single instantiated unit specified in the list */
1056 assert_se(unit_file_preset(UNIT_FILE_SYSTEM
, 0, root
, STRV_MAKE("foo@bar0.service"), UNIT_FILE_PRESET_FULL
, &changes
, &n_changes
) >= 0);
1057 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "foo@bar0.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
1058 assert_se(n_changes
== 1);
1059 assert_se(changes
[0].type_or_errno
== UNIT_FILE_SYMLINK
);
1060 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/foo@bar0.service");
1061 assert_se(streq(changes
[0].path
, p
));
1062 unit_file_changes_free(changes
, n_changes
);
1063 changes
= NULL
; n_changes
= 0;
1065 assert_se(unit_file_disable(UNIT_FILE_SYSTEM
, 0, root
, STRV_MAKE("foo@bar0.service"), &changes
, &n_changes
) >= 0);
1066 assert_se(n_changes
== 1);
1067 assert_se(changes
[0].type_or_errno
== UNIT_FILE_UNLINK
);
1068 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/multi-user.target.wants/foo@bar0.service");
1069 assert_se(streq(changes
[0].path
, p
));
1070 unit_file_changes_free(changes
, n_changes
);
1071 changes
= NULL
; n_changes
= 0;
1073 /* Check for preset-all case, only instances on the list should be enabled, not including the default instance */
1074 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "foo@def.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
1075 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "foo@bar1.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
1076 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "foo@bartest.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
1078 assert_se(unit_file_preset_all(UNIT_FILE_SYSTEM
, 0, root
, UNIT_FILE_PRESET_FULL
, &changes
, &n_changes
) >= 0);
1079 assert_se(n_changes
> 0);
1081 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "foo@def.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
1082 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "foo@bar0.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
1083 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "foo@bar1.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
1084 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "foo@bartest.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
1086 unit_file_changes_free(changes
, n_changes
);
1089 static void verify_one(
1090 const UnitFileInstallInfo
*i
,
1093 const char *updated_name
) {
1095 static const UnitFileInstallInfo
*last_info
= NULL
;
1096 _cleanup_free_
char *alias2
= NULL
;
1099 log_info("-- %s --", (last_info
= i
)->name
);
1101 r
= unit_file_verify_alias(i
, alias
, &alias2
);
1102 log_info_errno(r
, "alias %s ← %s: %d/%m (expected %d)%s%s%s",
1103 i
->name
, alias
, r
, expected
,
1104 alias2
? " [" : "", strempty(alias2
),
1106 assert(r
== expected
);
1108 /* This is test for "instance propagation". This propagation matters mostly for WantedBy= and
1109 * RequiredBy= settings, and less so for Alias=. The only case where it should happen is when we have
1110 * an Alias=alias@.service an instantiated template template@instance. In that case the instance name
1111 * should be propagated into the alias as alias@instance. */
1112 assert(streq_ptr(alias2
, updated_name
));
1115 static void test_verify_alias(void) {
1116 const UnitFileInstallInfo
1117 plain_service
= { .name
= (char*) "plain.service" },
1118 bare_template
= { .name
= (char*) "template1@.service" },
1119 di_template
= { .name
= (char*) "template2@.service",
1120 .default_instance
= (char*) "di" },
1121 inst_template
= { .name
= (char*) "template3@inst.service" },
1122 di_inst_template
= { .name
= (char*) "template4@inst.service",
1123 .default_instance
= (char*) "di" };
1125 verify_one(&plain_service
, "alias.service", 0, NULL
);
1126 verify_one(&plain_service
, "alias.socket", -EXDEV
, NULL
);
1127 verify_one(&plain_service
, "alias@.service", -EXDEV
, NULL
);
1128 verify_one(&plain_service
, "alias@inst.service", -EXDEV
, NULL
);
1129 verify_one(&plain_service
, "foo.target.wants/plain.service", 0, NULL
);
1130 verify_one(&plain_service
, "foo.target.wants/plain.socket", -EXDEV
, NULL
);
1131 verify_one(&plain_service
, "foo.target.wants/plain@.service", -EXDEV
, NULL
);
1132 verify_one(&plain_service
, "foo.target.wants/service", -EXDEV
, NULL
);
1133 verify_one(&plain_service
, "foo.target.requires/plain.service", 0, NULL
);
1134 verify_one(&plain_service
, "foo.target.requires/plain.socket", -EXDEV
, NULL
);
1135 verify_one(&plain_service
, "foo.target.requires/plain@.service", -EXDEV
, NULL
);
1136 verify_one(&plain_service
, "foo.target.requires/service", -EXDEV
, NULL
);
1137 verify_one(&plain_service
, "foo.target.conf/plain.service", -EXDEV
, NULL
);
1138 verify_one(&plain_service
, "foo.service/plain.service", -EXDEV
, NULL
); /* missing dir suffix */
1139 verify_one(&plain_service
, "asdf.requires/plain.service", -EXDEV
, NULL
); /* invalid unit name component */
1141 verify_one(&bare_template
, "alias.service", -EXDEV
, NULL
);
1142 verify_one(&bare_template
, "alias.socket", -EXDEV
, NULL
);
1143 verify_one(&bare_template
, "alias@.socket", -EXDEV
, NULL
);
1144 verify_one(&bare_template
, "alias@inst.socket", -EXDEV
, NULL
);
1145 /* A general alias alias@.service → template1@.service. */
1146 verify_one(&bare_template
, "alias@.service", 0, NULL
);
1147 /* Only a specific instance is aliased, see the discussion in https://github.com/systemd/systemd/pull/13119. */
1148 verify_one(&bare_template
, "alias@inst.service", 0, NULL
);
1149 verify_one(&bare_template
, "foo.target.wants/plain.service", -EXDEV
, NULL
);
1150 verify_one(&bare_template
, "foo.target.wants/plain.socket", -EXDEV
, NULL
);
1151 verify_one(&bare_template
, "foo.target.wants/plain@.service", -EXDEV
, NULL
);
1152 /* Name mismatch: we cannot allow this, because plain@foo.service would be pulled in by foo.target,
1153 * but would not be resolveable on its own, since systemd doesn't know how to load the fragment. */
1154 verify_one(&bare_template
, "foo.target.wants/plain@foo.service", -EXDEV
, NULL
);
1155 verify_one(&bare_template
, "foo.target.wants/template1@foo.service", 0, NULL
);
1156 verify_one(&bare_template
, "foo.target.wants/service", -EXDEV
, NULL
);
1157 verify_one(&bare_template
, "foo.target.requires/plain.service", -EXDEV
, NULL
);
1158 verify_one(&bare_template
, "foo.target.requires/plain.socket", -EXDEV
, NULL
);
1159 verify_one(&bare_template
, "foo.target.requires/plain@.service", -EXDEV
, NULL
); /* instance missing */
1160 verify_one(&bare_template
, "foo.target.requires/template1@inst.service", 0, NULL
);
1161 verify_one(&bare_template
, "foo.target.requires/service", -EXDEV
, NULL
);
1162 verify_one(&bare_template
, "foo.target.conf/plain.service", -EXDEV
, NULL
);
1163 verify_one(&bare_template
, "FOO@.target.requires/plain@.service", -EXDEV
, NULL
); /* template name mismatch */
1164 verify_one(&bare_template
, "FOO@inst.target.requires/plain@.service", -EXDEV
, NULL
);
1165 verify_one(&bare_template
, "FOO@inst.target.requires/plain@inst.service", -EXDEV
, NULL
);
1166 verify_one(&bare_template
, "FOO@.target.requires/template1@.service", 0, NULL
); /* instance propagated */
1167 verify_one(&bare_template
, "FOO@inst.target.requires/template1@.service", -EXDEV
, NULL
); /* instance missing */
1168 verify_one(&bare_template
, "FOO@inst.target.requires/template1@inst.service", 0, NULL
); /* instance provided */
1170 verify_one(&di_template
, "alias.service", -EXDEV
, NULL
);
1171 verify_one(&di_template
, "alias.socket", -EXDEV
, NULL
);
1172 verify_one(&di_template
, "alias@.socket", -EXDEV
, NULL
);
1173 verify_one(&di_template
, "alias@inst.socket", -EXDEV
, NULL
);
1174 verify_one(&di_template
, "alias@inst.service", 0, NULL
);
1175 verify_one(&di_template
, "alias@.service", 0, NULL
);
1176 verify_one(&di_template
, "alias@di.service", 0, NULL
);
1177 verify_one(&di_template
, "foo.target.wants/plain.service", -EXDEV
, NULL
);
1178 verify_one(&di_template
, "foo.target.wants/plain.socket", -EXDEV
, NULL
);
1179 verify_one(&di_template
, "foo.target.wants/plain@.service", -EXDEV
, NULL
);
1180 verify_one(&di_template
, "foo.target.wants/plain@di.service", -EXDEV
, NULL
);
1181 verify_one(&di_template
, "foo.target.wants/template2@di.service", 0, NULL
);
1182 verify_one(&di_template
, "foo.target.wants/service", -EXDEV
, NULL
);
1183 verify_one(&di_template
, "foo.target.requires/plain.service", -EXDEV
, NULL
);
1184 verify_one(&di_template
, "foo.target.requires/plain.socket", -EXDEV
, NULL
);
1185 verify_one(&di_template
, "foo.target.requires/plain@.service", -EXDEV
, NULL
);
1186 verify_one(&di_template
, "foo.target.requires/plain@di.service", -EXDEV
, NULL
);
1187 verify_one(&di_template
, "foo.target.requires/plain@foo.service", -EXDEV
, NULL
);
1188 verify_one(&di_template
, "foo.target.requires/template2@.service", -EXDEV
, NULL
); /* instance missing */
1189 verify_one(&di_template
, "foo.target.requires/template2@di.service", 0, NULL
);
1190 verify_one(&di_template
, "foo.target.requires/service", -EXDEV
, NULL
);
1191 verify_one(&di_template
, "foo.target.conf/plain.service", -EXDEV
, NULL
);
1193 verify_one(&inst_template
, "alias.service", -EXDEV
, NULL
);
1194 verify_one(&inst_template
, "alias.socket", -EXDEV
, NULL
);
1195 verify_one(&inst_template
, "alias@.socket", -EXDEV
, NULL
);
1196 verify_one(&inst_template
, "alias@inst.socket", -EXDEV
, NULL
);
1197 verify_one(&inst_template
, "alias@inst.service", 0, NULL
);
1198 verify_one(&inst_template
, "alias@.service", 0, "alias@inst.service");
1199 verify_one(&inst_template
, "alias@di.service", -EXDEV
, NULL
);
1200 verify_one(&inst_template
, "bar.target.wants/plain.service", -EXDEV
, NULL
);
1201 verify_one(&inst_template
, "bar.target.wants/plain.socket", -EXDEV
, NULL
);
1202 verify_one(&inst_template
, "bar.target.wants/plain@.service", -EXDEV
, NULL
);
1203 verify_one(&inst_template
, "bar.target.wants/plain@di.service", -EXDEV
, NULL
);
1204 verify_one(&inst_template
, "bar.target.wants/plain@inst.service", -EXDEV
, NULL
);
1205 verify_one(&inst_template
, "bar.target.wants/template3@foo.service", -EXDEV
, NULL
);
1206 verify_one(&inst_template
, "bar.target.wants/template3@inst.service", 0, NULL
);
1207 verify_one(&inst_template
, "bar.target.wants/service", -EXDEV
, NULL
);
1208 verify_one(&inst_template
, "bar.target.requires/plain.service", -EXDEV
, NULL
);
1209 verify_one(&inst_template
, "bar.target.requires/plain.socket", -EXDEV
, NULL
);
1210 verify_one(&inst_template
, "bar.target.requires/plain@.service", -EXDEV
, NULL
);
1211 verify_one(&inst_template
, "bar.target.requires/plain@di.service", -EXDEV
, NULL
);
1212 verify_one(&inst_template
, "bar.target.requires/plain@inst.service", -EXDEV
, NULL
);
1213 verify_one(&inst_template
, "bar.target.requires/template3@foo.service", -EXDEV
, NULL
);
1214 verify_one(&inst_template
, "bar.target.requires/template3@inst.service", 0, NULL
);
1215 verify_one(&inst_template
, "bar.target.requires/service", -EXDEV
, NULL
);
1216 verify_one(&inst_template
, "bar.target.conf/plain.service", -EXDEV
, NULL
);
1217 verify_one(&inst_template
, "BAR@.target.requires/plain@.service", -EXDEV
, NULL
); /* template name mismatch */
1218 verify_one(&inst_template
, "BAR@inst.target.requires/plain@.service", -EXDEV
, NULL
);
1219 verify_one(&inst_template
, "BAR@inst.target.requires/plain@inst.service", -EXDEV
, NULL
);
1220 verify_one(&inst_template
, "BAR@.target.requires/template3@.service", -EXDEV
, NULL
); /* instance missing */
1221 verify_one(&inst_template
, "BAR@inst.target.requires/template3@.service", -EXDEV
, NULL
); /* instance missing */
1222 verify_one(&inst_template
, "BAR@inst.target.requires/template3@inst.service", 0, NULL
); /* instance provided */
1223 verify_one(&inst_template
, "BAR@inst.target.requires/template3@ins2.service", -EXDEV
, NULL
); /* instance mismatch */
1225 /* explicit alias overrides DefaultInstance */
1226 verify_one(&di_inst_template
, "alias.service", -EXDEV
, NULL
);
1227 verify_one(&di_inst_template
, "alias.socket", -EXDEV
, NULL
);
1228 verify_one(&di_inst_template
, "alias@.socket", -EXDEV
, NULL
);
1229 verify_one(&di_inst_template
, "alias@inst.socket", -EXDEV
, NULL
);
1230 verify_one(&di_inst_template
, "alias@inst.service", 0, NULL
);
1231 verify_one(&di_inst_template
, "alias@.service", 0, "alias@inst.service");
1232 verify_one(&di_inst_template
, "alias@di.service", -EXDEV
, NULL
);
1233 verify_one(&di_inst_template
, "goo.target.wants/plain.service", -EXDEV
, NULL
);
1234 verify_one(&di_inst_template
, "goo.target.wants/plain.socket", -EXDEV
, NULL
);
1235 verify_one(&di_inst_template
, "goo.target.wants/plain@.service", -EXDEV
, NULL
);
1236 verify_one(&di_inst_template
, "goo.target.wants/plain@di.service", -EXDEV
, NULL
);
1237 verify_one(&di_inst_template
, "goo.target.wants/template4@foo.service", -EXDEV
, NULL
);
1238 verify_one(&di_inst_template
, "goo.target.wants/template4@inst.service", 0, NULL
);
1239 verify_one(&di_inst_template
, "goo.target.wants/template4@di.service", -EXDEV
, NULL
);
1240 verify_one(&di_inst_template
, "goo.target.wants/service", -EXDEV
, NULL
);
1241 verify_one(&di_inst_template
, "goo.target.requires/plain.service", -EXDEV
, NULL
);
1242 verify_one(&di_inst_template
, "goo.target.requires/plain.socket", -EXDEV
, NULL
);
1243 verify_one(&di_inst_template
, "goo.target.requires/plain@.service", -EXDEV
, NULL
);
1244 verify_one(&di_inst_template
, "goo.target.requires/plain@di.service", -EXDEV
, NULL
);
1245 verify_one(&di_inst_template
, "goo.target.requires/plain@inst.service", -EXDEV
, NULL
);
1246 verify_one(&di_inst_template
, "goo.target.requires/template4@foo.service", -EXDEV
, NULL
);
1247 verify_one(&di_inst_template
, "goo.target.requires/template4@inst.service", 0, NULL
);
1248 verify_one(&di_inst_template
, "goo.target.requires/service", -EXDEV
, NULL
);
1249 verify_one(&di_inst_template
, "goo.target.conf/plain.service", -EXDEV
, NULL
);
1252 int main(int argc
, char *argv
[]) {
1253 char root
[] = "/tmp/rootXXXXXX";
1256 assert_se(mkdtemp(root
));
1258 p
= strjoina(root
, "/usr/lib/systemd/system/");
1259 assert_se(mkdir_p(p
, 0755) >= 0);
1261 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_DIR
"/");
1262 assert_se(mkdir_p(p
, 0755) >= 0);
1264 p
= strjoina(root
, "/run/systemd/system/");
1265 assert_se(mkdir_p(p
, 0755) >= 0);
1267 p
= strjoina(root
, "/opt/");
1268 assert_se(mkdir_p(p
, 0755) >= 0);
1270 p
= strjoina(root
, "/usr/lib/systemd/system-preset/");
1271 assert_se(mkdir_p(p
, 0755) >= 0);
1273 p
= strjoina(root
, "/usr/lib/systemd/system/multi-user.target");
1274 assert_se(write_string_file(p
, "# pretty much empty", WRITE_STRING_FILE_CREATE
) >= 0);
1276 p
= strjoina(root
, "/usr/lib/systemd/system/graphical.target");
1277 assert_se(write_string_file(p
, "# pretty much empty", WRITE_STRING_FILE_CREATE
) >= 0);
1279 test_basic_mask_and_enable(root
);
1280 test_linked_units(root
);
1282 test_add_dependency(root
);
1283 test_template_enable(root
);
1284 test_indirect(root
);
1285 test_preset_and_list(root
);
1286 test_preset_order(root
);
1287 test_preset_multiple_instances(root
);
1289 test_static_instance(root
);
1290 test_with_dropin(root
);
1291 test_with_dropin_template(root
);
1293 assert_se(rm_rf(root
, REMOVE_ROOT
|REMOVE_PHYSICAL
) >= 0);
1295 test_verify_alias();