]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/test/test-install-root.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2011 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
22 #include "alloc-util.h"
27 #include "string-util.h"
29 static void test_basic_mask_and_enable(const char *root
) {
32 UnitFileChange
*changes
= NULL
;
33 unsigned n_changes
= 0;
35 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "a.service", NULL
) == -ENOENT
);
36 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "b.service", NULL
) == -ENOENT
);
37 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "c.service", NULL
) == -ENOENT
);
38 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "d.service", NULL
) == -ENOENT
);
40 p
= strjoina(root
, "/usr/lib/systemd/system/a.service");
41 assert_se(write_string_file(p
,
43 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
45 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "a.service", NULL
) >= 0);
46 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "a.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
48 p
= strjoina(root
, "/usr/lib/systemd/system/b.service");
49 assert_se(symlink("a.service", p
) >= 0);
51 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "b.service", NULL
) >= 0);
52 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "b.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
54 p
= strjoina(root
, "/usr/lib/systemd/system/c.service");
55 assert_se(symlink("/usr/lib/systemd/system/a.service", p
) >= 0);
57 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "c.service", NULL
) >= 0);
58 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "c.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
60 p
= strjoina(root
, "/usr/lib/systemd/system/d.service");
61 assert_se(symlink("c.service", p
) >= 0);
63 /* This one is interesting, as d follows a relative, then an absolute symlink */
64 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "d.service", NULL
) >= 0);
65 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "d.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
67 assert_se(unit_file_mask(UNIT_FILE_SYSTEM
, false, root
, STRV_MAKE("a.service"), false, &changes
, &n_changes
) >= 0);
68 assert_se(n_changes
== 1);
69 assert_se(changes
[0].type
== UNIT_FILE_SYMLINK
);
70 assert_se(streq(changes
[0].source
, "/dev/null"));
71 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_PATH
"/a.service");
72 assert_se(streq(changes
[0].path
, p
));
74 unit_file_changes_free(changes
, n_changes
);
75 changes
= NULL
; n_changes
= 0;
77 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "a.service", &state
) >= 0 && state
== UNIT_FILE_MASKED
);
78 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "b.service", &state
) >= 0 && state
== UNIT_FILE_MASKED
);
79 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "c.service", &state
) >= 0 && state
== UNIT_FILE_MASKED
);
80 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "d.service", &state
) >= 0 && state
== UNIT_FILE_MASKED
);
82 /* Enabling a masked unit should fail! */
83 assert_se(unit_file_enable(UNIT_FILE_SYSTEM
, false, root
, STRV_MAKE("a.service"), false, &changes
, &n_changes
) == -ESHUTDOWN
);
84 unit_file_changes_free(changes
, n_changes
);
85 changes
= NULL
; n_changes
= 0;
87 assert_se(unit_file_unmask(UNIT_FILE_SYSTEM
, false, root
, STRV_MAKE("a.service"), &changes
, &n_changes
) >= 0);
88 assert_se(n_changes
== 1);
89 assert_se(changes
[0].type
== UNIT_FILE_UNLINK
);
90 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_PATH
"/a.service");
91 assert_se(streq(changes
[0].path
, p
));
92 unit_file_changes_free(changes
, n_changes
);
93 changes
= NULL
; n_changes
= 0;
95 assert_se(unit_file_enable(UNIT_FILE_SYSTEM
, false, root
, STRV_MAKE("a.service"), false, &changes
, &n_changes
) == 1);
96 assert_se(n_changes
== 1);
97 assert_se(changes
[0].type
== UNIT_FILE_SYMLINK
);
98 assert_se(streq(changes
[0].source
, "/usr/lib/systemd/system/a.service"));
99 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_PATH
"/multi-user.target.wants/a.service");
100 assert_se(streq(changes
[0].path
, p
));
101 unit_file_changes_free(changes
, n_changes
);
102 changes
= NULL
; n_changes
= 0;
104 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "a.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
105 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "b.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
106 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "c.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
107 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "d.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
109 /* Enabling it again should succeed but be a NOP */
110 assert_se(unit_file_enable(UNIT_FILE_SYSTEM
, false, root
, STRV_MAKE("a.service"), false, &changes
, &n_changes
) == 1);
111 assert_se(n_changes
== 0);
112 unit_file_changes_free(changes
, n_changes
);
113 changes
= NULL
; n_changes
= 0;
115 assert_se(unit_file_disable(UNIT_FILE_SYSTEM
, false, root
, STRV_MAKE("a.service"), &changes
, &n_changes
) >= 0);
116 assert_se(n_changes
== 1);
117 assert_se(changes
[0].type
== UNIT_FILE_UNLINK
);
118 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_PATH
"/multi-user.target.wants/a.service");
119 assert_se(streq(changes
[0].path
, p
));
120 unit_file_changes_free(changes
, n_changes
);
121 changes
= NULL
; n_changes
= 0;
123 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "a.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
124 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "b.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
125 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "c.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
126 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "d.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
128 /* Disabling a disabled unit must suceed but be a NOP */
129 assert_se(unit_file_disable(UNIT_FILE_SYSTEM
, false, root
, STRV_MAKE("a.service"), &changes
, &n_changes
) >= 0);
130 assert_se(n_changes
== 0);
131 unit_file_changes_free(changes
, n_changes
);
132 changes
= NULL
; n_changes
= 0;
134 /* Let's enable this indirectly via a symlink */
135 assert_se(unit_file_enable(UNIT_FILE_SYSTEM
, false, root
, STRV_MAKE("d.service"), false, &changes
, &n_changes
) >= 0);
136 assert_se(n_changes
== 1);
137 assert_se(changes
[0].type
== UNIT_FILE_SYMLINK
);
138 assert_se(streq(changes
[0].source
, "/usr/lib/systemd/system/a.service"));
139 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_PATH
"/multi-user.target.wants/a.service");
140 assert_se(streq(changes
[0].path
, p
));
141 unit_file_changes_free(changes
, n_changes
);
142 changes
= NULL
; n_changes
= 0;
144 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "a.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
145 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "b.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
146 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "c.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
147 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "d.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
149 /* Let's try to reenable */
151 assert_se(unit_file_reenable(UNIT_FILE_SYSTEM
, false, root
, STRV_MAKE("b.service"), false, &changes
, &n_changes
) >= 0);
152 assert_se(n_changes
== 2);
153 assert_se(changes
[0].type
== UNIT_FILE_UNLINK
);
154 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_PATH
"/multi-user.target.wants/a.service");
155 assert_se(streq(changes
[0].path
, p
));
156 assert_se(changes
[1].type
== UNIT_FILE_SYMLINK
);
157 assert_se(streq(changes
[1].source
, "/usr/lib/systemd/system/a.service"));
158 assert_se(streq(changes
[1].path
, p
));
159 unit_file_changes_free(changes
, n_changes
);
160 changes
= NULL
; n_changes
= 0;
162 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "a.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
163 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "b.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
164 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "c.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
165 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "d.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
168 static void test_linked_units(const char *root
) {
171 UnitFileChange
*changes
= NULL
;
172 unsigned n_changes
= 0, i
;
175 * We'll test three cases here:
177 * a) a unit file in /opt, that we use "systemctl link" and
178 * "systemctl enable" on to make it available to the system
180 * b) a unit file in /opt, that is statically linked into
181 * /usr/lib/systemd/system, that "enable" should work on
184 * c) a unit file in /opt, that is linked into
185 * /etc/systemd/system, and where "enable" should result in
186 * -ELOOP, since using information from /etc to generate
187 * information in /etc should not be allowed.
190 p
= strjoina(root
, "/opt/linked.service");
191 assert_se(write_string_file(p
,
193 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
195 p
= strjoina(root
, "/opt/linked2.service");
196 assert_se(write_string_file(p
,
198 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
200 p
= strjoina(root
, "/opt/linked3.service");
201 assert_se(write_string_file(p
,
203 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
205 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "linked.service", NULL
) == -ENOENT
);
206 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "linked2.service", NULL
) == -ENOENT
);
207 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "linked3.service", NULL
) == -ENOENT
);
209 p
= strjoina(root
, "/usr/lib/systemd/system/linked2.service");
210 assert_se(symlink("/opt/linked2.service", p
) >= 0);
212 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_PATH
"/linked3.service");
213 assert_se(symlink("/opt/linked3.service", p
) >= 0);
215 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "linked.service", &state
) == -ENOENT
);
216 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "linked2.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
217 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "linked3.service", &state
) >= 0 && state
== UNIT_FILE_LINKED
);
219 /* First, let's link the unit into the search path */
220 assert_se(unit_file_link(UNIT_FILE_SYSTEM
, false, root
, STRV_MAKE("/opt/linked.service"), false, &changes
, &n_changes
) >= 0);
221 assert_se(n_changes
== 1);
222 assert_se(changes
[0].type
== UNIT_FILE_SYMLINK
);
223 assert_se(streq(changes
[0].source
, "/opt/linked.service"));
224 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_PATH
"/linked.service");
225 assert_se(streq(changes
[0].path
, p
));
226 unit_file_changes_free(changes
, n_changes
);
227 changes
= NULL
; n_changes
= 0;
229 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "linked.service", &state
) >= 0 && state
== UNIT_FILE_LINKED
);
231 /* Let's unlink it from the search path again */
232 assert_se(unit_file_disable(UNIT_FILE_SYSTEM
, false, root
, STRV_MAKE("linked.service"), &changes
, &n_changes
) >= 0);
233 assert_se(n_changes
== 1);
234 assert_se(changes
[0].type
== UNIT_FILE_UNLINK
);
235 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_PATH
"/linked.service");
236 assert_se(streq(changes
[0].path
, p
));
237 unit_file_changes_free(changes
, n_changes
);
238 changes
= NULL
; n_changes
= 0;
240 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "linked.service", NULL
) == -ENOENT
);
242 /* Now, let's not just link it, but also enable it */
243 assert_se(unit_file_enable(UNIT_FILE_SYSTEM
, false, root
, STRV_MAKE("/opt/linked.service"), false, &changes
, &n_changes
) >= 0);
244 assert_se(n_changes
== 2);
245 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_PATH
"/multi-user.target.wants/linked.service");
246 q
= strjoina(root
, SYSTEM_CONFIG_UNIT_PATH
"/linked.service");
247 for (i
= 0 ; i
< n_changes
; i
++) {
248 assert_se(changes
[i
].type
== UNIT_FILE_SYMLINK
);
249 assert_se(streq(changes
[i
].source
, "/opt/linked.service"));
251 if (p
&& streq(changes
[i
].path
, p
))
253 else if (q
&& streq(changes
[i
].path
, q
))
256 assert_not_reached("wut?");
259 unit_file_changes_free(changes
, n_changes
);
260 changes
= NULL
; n_changes
= 0;
262 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "linked.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
264 /* And let's unlink it again */
265 assert_se(unit_file_disable(UNIT_FILE_SYSTEM
, false, root
, STRV_MAKE("linked.service"), &changes
, &n_changes
) >= 0);
266 assert_se(n_changes
== 2);
267 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_PATH
"/multi-user.target.wants/linked.service");
268 q
= strjoina(root
, SYSTEM_CONFIG_UNIT_PATH
"/linked.service");
269 for (i
= 0; i
< n_changes
; i
++) {
270 assert_se(changes
[i
].type
== UNIT_FILE_UNLINK
);
272 if (p
&& streq(changes
[i
].path
, p
))
274 else if (q
&& streq(changes
[i
].path
, q
))
277 assert_not_reached("wut?");
280 unit_file_changes_free(changes
, n_changes
);
281 changes
= NULL
; n_changes
= 0;
283 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "linked.service", NULL
) == -ENOENT
);
285 assert_se(unit_file_enable(UNIT_FILE_SYSTEM
, false, root
, STRV_MAKE("linked2.service"), false, &changes
, &n_changes
) >= 0);
286 assert_se(n_changes
== 2);
287 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_PATH
"/multi-user.target.wants/linked2.service");
288 q
= strjoina(root
, SYSTEM_CONFIG_UNIT_PATH
"/linked2.service");
289 for (i
= 0 ; i
< n_changes
; i
++) {
290 assert_se(changes
[i
].type
== UNIT_FILE_SYMLINK
);
291 assert_se(streq(changes
[i
].source
, "/opt/linked2.service"));
293 if (p
&& streq(changes
[i
].path
, p
))
295 else if (q
&& streq(changes
[i
].path
, q
))
298 assert_not_reached("wut?");
301 unit_file_changes_free(changes
, n_changes
);
302 changes
= NULL
; n_changes
= 0;
304 assert_se(unit_file_enable(UNIT_FILE_SYSTEM
, false, root
, STRV_MAKE("linked3.service"), false, &changes
, &n_changes
) == -ELOOP
);
305 unit_file_changes_free(changes
, n_changes
);
306 changes
= NULL
; n_changes
= 0;
309 static void test_default(const char *root
) {
310 _cleanup_free_
char *def
= NULL
;
311 UnitFileChange
*changes
= NULL
;
312 unsigned n_changes
= 0;
315 p
= strjoina(root
, "/usr/lib/systemd/system/test-default-real.target");
316 assert_se(write_string_file(p
, "# pretty much empty", WRITE_STRING_FILE_CREATE
) >= 0);
318 p
= strjoina(root
, "/usr/lib/systemd/system/test-default.target");
319 assert_se(symlink("test-default-real.target", p
) >= 0);
321 assert_se(unit_file_get_default(UNIT_FILE_SYSTEM
, root
, &def
) == -ENOENT
);
323 assert_se(unit_file_set_default(UNIT_FILE_SYSTEM
, root
, "idontexist.target", false, &changes
, &n_changes
) == -ENOENT
);
324 assert_se(n_changes
== 0);
325 unit_file_changes_free(changes
, n_changes
);
326 changes
= NULL
; n_changes
= 0;
328 assert_se(unit_file_get_default(UNIT_FILE_SYSTEM
, root
, &def
) == -ENOENT
);
330 assert_se(unit_file_set_default(UNIT_FILE_SYSTEM
, root
, "test-default.target", false, &changes
, &n_changes
) >= 0);
331 assert_se(n_changes
== 1);
332 assert_se(changes
[0].type
== UNIT_FILE_SYMLINK
);
333 assert_se(streq(changes
[0].source
, "/usr/lib/systemd/system/test-default-real.target"));
334 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_PATH
"/default.target");
335 assert_se(streq(changes
[0].path
, p
));
336 unit_file_changes_free(changes
, n_changes
);
337 changes
= NULL
; n_changes
= 0;
339 assert_se(unit_file_get_default(UNIT_FILE_SYSTEM
, root
, &def
) >= 0);
340 assert_se(streq_ptr(def
, "test-default-real.target"));
343 static void test_add_dependency(const char *root
) {
344 UnitFileChange
*changes
= NULL
;
345 unsigned n_changes
= 0;
348 p
= strjoina(root
, "/usr/lib/systemd/system/real-add-dependency-test-target.target");
349 assert_se(write_string_file(p
, "# pretty much empty", WRITE_STRING_FILE_CREATE
) >= 0);
351 p
= strjoina(root
, "/usr/lib/systemd/system/add-dependency-test-target.target");
352 assert_se(symlink("real-add-dependency-test-target.target", p
) >= 0);
354 p
= strjoina(root
, "/usr/lib/systemd/system/real-add-dependency-test-service.service");
355 assert_se(write_string_file(p
, "# pretty much empty", WRITE_STRING_FILE_CREATE
) >= 0);
357 p
= strjoina(root
, "/usr/lib/systemd/system/add-dependency-test-service.service");
358 assert_se(symlink("real-add-dependency-test-service.service", p
) >= 0);
360 assert_se(unit_file_add_dependency(UNIT_FILE_SYSTEM
, false, root
, STRV_MAKE("add-dependency-test-service.service"), "add-dependency-test-target.target", UNIT_WANTS
, false, &changes
, &n_changes
) >= 0);
361 assert_se(n_changes
== 1);
362 assert_se(changes
[0].type
== UNIT_FILE_SYMLINK
);
363 assert_se(streq(changes
[0].source
, "/usr/lib/systemd/system/real-add-dependency-test-service.service"));
364 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_PATH
"/real-add-dependency-test-target.target.wants/real-add-dependency-test-service.service");
365 assert_se(streq(changes
[0].path
, p
));
366 unit_file_changes_free(changes
, n_changes
);
367 changes
= NULL
; n_changes
= 0;
370 static void test_template_enable(const char *root
) {
371 UnitFileChange
*changes
= NULL
;
372 unsigned n_changes
= 0;
376 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template@.service", &state
) == -ENOENT
);
377 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template@def.service", &state
) == -ENOENT
);
378 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template@foo.service", &state
) == -ENOENT
);
379 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template-symlink@foo.service", &state
) == -ENOENT
);
381 p
= strjoina(root
, "/usr/lib/systemd/system/template@.service");
382 assert_se(write_string_file(p
,
384 "DefaultInstance=def\n"
385 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
387 p
= strjoina(root
, "/usr/lib/systemd/system/template-symlink@.service");
388 assert_se(symlink("template@.service", p
) >= 0);
390 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template@.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
391 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template@def.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
392 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template@foo.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
393 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template-symlink@.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
394 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template-symlink@def.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
395 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template-symlink@foo.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
397 assert_se(unit_file_enable(UNIT_FILE_SYSTEM
, false, root
, STRV_MAKE("template@.service"), false, &changes
, &n_changes
) >= 0);
398 assert_se(n_changes
== 1);
399 assert_se(changes
[0].type
== UNIT_FILE_SYMLINK
);
400 assert_se(streq(changes
[0].source
, "/usr/lib/systemd/system/template@.service"));
401 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_PATH
"/multi-user.target.wants/template@def.service");
402 assert_se(streq(changes
[0].path
, p
));
403 unit_file_changes_free(changes
, n_changes
);
404 changes
= NULL
; n_changes
= 0;
406 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template@.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
407 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template@def.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
408 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template@foo.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
409 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template-symlink@.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
410 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template-symlink@def.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
411 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template-symlink@foo.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
413 assert_se(unit_file_disable(UNIT_FILE_SYSTEM
, false, root
, STRV_MAKE("template@.service"), &changes
, &n_changes
) >= 0);
414 assert_se(n_changes
== 1);
415 assert_se(changes
[0].type
== UNIT_FILE_UNLINK
);
416 assert_se(streq(changes
[0].path
, p
));
417 unit_file_changes_free(changes
, n_changes
);
418 changes
= NULL
; n_changes
= 0;
420 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template@.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
421 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template@def.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
422 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template@foo.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
423 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template-symlink@.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
424 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template-symlink@def.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
425 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template-symlink@foo.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
427 assert_se(unit_file_enable(UNIT_FILE_SYSTEM
, false, root
, STRV_MAKE("template@foo.service"), false, &changes
, &n_changes
) >= 0);
428 assert_se(changes
[0].type
== UNIT_FILE_SYMLINK
);
429 assert_se(streq(changes
[0].source
, "/usr/lib/systemd/system/template@.service"));
430 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_PATH
"/multi-user.target.wants/template@foo.service");
431 assert_se(streq(changes
[0].path
, p
));
432 unit_file_changes_free(changes
, n_changes
);
433 changes
= NULL
; n_changes
= 0;
435 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template@.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
436 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template@def.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
437 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template@foo.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
438 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template-symlink@foo.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
439 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template-symlink@def.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
440 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template-symlink@foo.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
442 assert_se(unit_file_disable(UNIT_FILE_SYSTEM
, false, root
, STRV_MAKE("template@foo.service"), &changes
, &n_changes
) >= 0);
443 assert_se(n_changes
== 1);
444 assert_se(changes
[0].type
== UNIT_FILE_UNLINK
);
445 assert_se(streq(changes
[0].path
, p
));
446 unit_file_changes_free(changes
, n_changes
);
447 changes
= NULL
; n_changes
= 0;
449 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template@.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
450 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template@def.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
451 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template@foo.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
452 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template@quux.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
453 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template-symlink@.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
454 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template-symlink@def.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
455 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template-symlink@foo.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
456 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template-symlink@quux.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
458 assert_se(unit_file_enable(UNIT_FILE_SYSTEM
, false, root
, STRV_MAKE("template-symlink@quux.service"), false, &changes
, &n_changes
) >= 0);
459 assert_se(changes
[0].type
== UNIT_FILE_SYMLINK
);
460 assert_se(streq(changes
[0].source
, "/usr/lib/systemd/system/template@.service"));
461 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_PATH
"/multi-user.target.wants/template@quux.service");
462 assert_se(streq(changes
[0].path
, p
));
463 unit_file_changes_free(changes
, n_changes
);
464 changes
= NULL
; n_changes
= 0;
466 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template@.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
467 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template@def.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
468 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template@foo.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
469 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template@quux.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
470 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template-symlink@.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
471 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template-symlink@def.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
472 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template-symlink@foo.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
473 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "template-symlink@quux.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
476 static void test_indirect(const char *root
) {
477 UnitFileChange
*changes
= NULL
;
478 unsigned n_changes
= 0;
482 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "indirecta.service", &state
) == -ENOENT
);
483 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "indirectb.service", &state
) == -ENOENT
);
484 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "indirectc.service", &state
) == -ENOENT
);
486 p
= strjoina(root
, "/usr/lib/systemd/system/indirecta.service");
487 assert_se(write_string_file(p
,
489 "Also=indirectb.service\n", WRITE_STRING_FILE_CREATE
) >= 0);
491 p
= strjoina(root
, "/usr/lib/systemd/system/indirectb.service");
492 assert_se(write_string_file(p
,
494 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
496 p
= strjoina(root
, "/usr/lib/systemd/system/indirectc.service");
497 assert_se(symlink("indirecta.service", p
) >= 0);
499 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "indirecta.service", &state
) >= 0 && state
== UNIT_FILE_INDIRECT
);
500 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "indirectb.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
501 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "indirectc.service", &state
) >= 0 && state
== UNIT_FILE_INDIRECT
);
503 assert_se(unit_file_enable(UNIT_FILE_SYSTEM
, false, root
, STRV_MAKE("indirectc.service"), false, &changes
, &n_changes
) >= 0);
504 assert_se(n_changes
== 1);
505 assert_se(changes
[0].type
== UNIT_FILE_SYMLINK
);
506 assert_se(streq(changes
[0].source
, "/usr/lib/systemd/system/indirectb.service"));
507 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_PATH
"/multi-user.target.wants/indirectb.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
, "indirecta.service", &state
) >= 0 && state
== UNIT_FILE_INDIRECT
);
513 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "indirectb.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
514 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "indirectc.service", &state
) >= 0 && state
== UNIT_FILE_INDIRECT
);
516 assert_se(unit_file_disable(UNIT_FILE_SYSTEM
, false, root
, STRV_MAKE("indirectc.service"), &changes
, &n_changes
) >= 0);
517 assert_se(n_changes
== 1);
518 assert_se(changes
[0].type
== UNIT_FILE_UNLINK
);
519 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_PATH
"/multi-user.target.wants/indirectb.service");
520 assert_se(streq(changes
[0].path
, p
));
521 unit_file_changes_free(changes
, n_changes
);
522 changes
= NULL
; n_changes
= 0;
525 static void test_preset_and_list(const char *root
) {
526 UnitFileChange
*changes
= NULL
;
527 unsigned n_changes
= 0, i
;
530 bool got_yes
= false, got_no
= false;
535 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "preset-yes.service", &state
) == -ENOENT
);
536 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "preset-no.service", &state
) == -ENOENT
);
538 p
= strjoina(root
, "/usr/lib/systemd/system/preset-yes.service");
539 assert_se(write_string_file(p
,
541 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
543 p
= strjoina(root
, "/usr/lib/systemd/system/preset-no.service");
544 assert_se(write_string_file(p
,
546 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE
) >= 0);
548 p
= strjoina(root
, "/usr/lib/systemd/system-preset/test.preset");
549 assert_se(write_string_file(p
,
551 "disable *\n", WRITE_STRING_FILE_CREATE
) >= 0);
553 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "preset-yes.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
554 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "preset-no.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
556 assert_se(unit_file_preset(UNIT_FILE_SYSTEM
, false, root
, STRV_MAKE("preset-yes.service"), UNIT_FILE_PRESET_FULL
, false, &changes
, &n_changes
) >= 0);
557 assert_se(n_changes
== 1);
558 assert_se(changes
[0].type
== UNIT_FILE_SYMLINK
);
559 assert_se(streq(changes
[0].source
, "/usr/lib/systemd/system/preset-yes.service"));
560 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_PATH
"/multi-user.target.wants/preset-yes.service");
561 assert_se(streq(changes
[0].path
, p
));
562 unit_file_changes_free(changes
, n_changes
);
563 changes
= NULL
; n_changes
= 0;
565 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "preset-yes.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
566 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "preset-no.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
568 assert_se(unit_file_disable(UNIT_FILE_SYSTEM
, false, root
, STRV_MAKE("preset-yes.service"), &changes
, &n_changes
) >= 0);
569 assert_se(n_changes
== 1);
570 assert_se(changes
[0].type
== UNIT_FILE_UNLINK
);
571 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_PATH
"/multi-user.target.wants/preset-yes.service");
572 assert_se(streq(changes
[0].path
, p
));
573 unit_file_changes_free(changes
, n_changes
);
574 changes
= NULL
; n_changes
= 0;
576 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "preset-yes.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
577 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "preset-no.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
579 assert_se(unit_file_preset(UNIT_FILE_SYSTEM
, false, root
, STRV_MAKE("preset-no.service"), UNIT_FILE_PRESET_FULL
, false, &changes
, &n_changes
) >= 0);
580 assert_se(n_changes
== 0);
581 unit_file_changes_free(changes
, n_changes
);
582 changes
= NULL
; n_changes
= 0;
584 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "preset-yes.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
585 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "preset-no.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
587 assert_se(unit_file_preset_all(UNIT_FILE_SYSTEM
, false, root
, UNIT_FILE_PRESET_FULL
, false, &changes
, &n_changes
) >= 0);
589 assert_se(n_changes
> 0);
591 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_PATH
"/multi-user.target.wants/preset-yes.service");
593 for (i
= 0; i
< n_changes
; i
++) {
595 if (changes
[i
].type
== UNIT_FILE_SYMLINK
) {
596 assert_se(streq(changes
[i
].source
, "/usr/lib/systemd/system/preset-yes.service"));
597 assert_se(streq(changes
[i
].path
, p
));
599 assert_se(changes
[i
].type
== UNIT_FILE_UNLINK
);
602 unit_file_changes_free(changes
, n_changes
);
603 changes
= NULL
; n_changes
= 0;
605 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "preset-yes.service", &state
) >= 0 && state
== UNIT_FILE_ENABLED
);
606 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, "preset-no.service", &state
) >= 0 && state
== UNIT_FILE_DISABLED
);
608 assert_se(h
= hashmap_new(&string_hash_ops
));
609 assert_se(unit_file_get_list(UNIT_FILE_SYSTEM
, root
, h
) >= 0);
611 p
= strjoina(root
, "/usr/lib/systemd/system/preset-yes.service");
612 q
= strjoina(root
, "/usr/lib/systemd/system/preset-no.service");
614 HASHMAP_FOREACH(fl
, h
, j
) {
615 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM
, root
, basename(fl
->path
), &state
) >= 0);
616 assert_se(fl
->state
== state
);
618 if (streq(fl
->path
, p
)) {
620 assert_se(fl
->state
== UNIT_FILE_ENABLED
);
621 } else if (streq(fl
->path
, q
)) {
623 assert_se(fl
->state
== UNIT_FILE_DISABLED
);
625 assert_se(IN_SET(fl
->state
, UNIT_FILE_DISABLED
, UNIT_FILE_STATIC
, UNIT_FILE_INDIRECT
));
628 unit_file_list_free(h
);
630 assert_se(got_yes
&& got_no
);
633 int main(int argc
, char *argv
[]) {
634 char root
[] = "/tmp/rootXXXXXX";
637 assert_se(mkdtemp(root
));
639 p
= strjoina(root
, "/usr/lib/systemd/system/");
640 assert_se(mkdir_p(p
, 0755) >= 0);
642 p
= strjoina(root
, SYSTEM_CONFIG_UNIT_PATH
"/");
643 assert_se(mkdir_p(p
, 0755) >= 0);
645 p
= strjoina(root
, "/run/systemd/system/");
646 assert_se(mkdir_p(p
, 0755) >= 0);
648 p
= strjoina(root
, "/opt/");
649 assert_se(mkdir_p(p
, 0755) >= 0);
651 p
= strjoina(root
, "/usr/lib/systemd/system-preset/");
652 assert_se(mkdir_p(p
, 0755) >= 0);
654 test_basic_mask_and_enable(root
);
655 test_linked_units(root
);
657 test_add_dependency(root
);
658 test_template_enable(root
);
660 test_preset_and_list(root
);
662 assert_se(rm_rf(root
, REMOVE_ROOT
|REMOVE_PHYSICAL
) >= 0);