]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/test/test-install-root.c
Add SPDX license identifiers to source files under the LGPL
[thirdparty/systemd.git] / src / test / test-install-root.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 This file is part of systemd.
4
5 Copyright 2011 Lennart Poettering
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19 ***/
20
21 #include "alloc-util.h"
22 #include "fileio.h"
23 #include "install.h"
24 #include "mkdir.h"
25 #include "rm-rf.h"
26 #include "special.h"
27 #include "string-util.h"
28
29 static void test_basic_mask_and_enable(const char *root) {
30 const char *p;
31 UnitFileState state;
32 UnitFileChange *changes = NULL;
33 unsigned n_changes = 0;
34
35 log_set_max_level(LOG_DEBUG);
36
37 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", NULL) == -ENOENT);
38 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", NULL) == -ENOENT);
39 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", NULL) == -ENOENT);
40 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", NULL) == -ENOENT);
41
42 p = strjoina(root, "/usr/lib/systemd/system/a.service");
43 assert_se(write_string_file(p,
44 "[Install]\n"
45 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE) >= 0);
46
47 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", NULL) >= 0);
48 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
49
50 p = strjoina(root, "/usr/lib/systemd/system/b.service");
51 assert_se(symlink("a.service", p) >= 0);
52
53 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", NULL) >= 0);
54 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
55
56 p = strjoina(root, "/usr/lib/systemd/system/c.service");
57 assert_se(symlink("/usr/lib/systemd/system/a.service", p) >= 0);
58
59 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", NULL) >= 0);
60 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
61
62 p = strjoina(root, "/usr/lib/systemd/system/d.service");
63 assert_se(symlink("c.service", p) >= 0);
64
65 /* This one is interesting, as d follows a relative, then an absolute symlink */
66 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", NULL) >= 0);
67 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
68
69 assert_se(unit_file_mask(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("a.service"), &changes, &n_changes) >= 0);
70 assert_se(n_changes == 1);
71 assert_se(changes[0].type == UNIT_FILE_SYMLINK);
72 assert_se(streq(changes[0].source, "/dev/null"));
73 p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/a.service");
74 assert_se(streq(changes[0].path, p));
75
76 unit_file_changes_free(changes, n_changes);
77 changes = NULL; n_changes = 0;
78
79 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", &state) >= 0 && state == UNIT_FILE_MASKED);
80 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_MASKED);
81 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_MASKED);
82 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_MASKED);
83
84 /* Enabling a masked unit should fail! */
85 assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("a.service"), &changes, &n_changes) == -ERFKILL);
86 unit_file_changes_free(changes, n_changes);
87 changes = NULL; n_changes = 0;
88
89 assert_se(unit_file_unmask(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("a.service"), &changes, &n_changes) >= 0);
90 assert_se(n_changes == 1);
91 assert_se(changes[0].type == UNIT_FILE_UNLINK);
92 p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/a.service");
93 assert_se(streq(changes[0].path, p));
94 unit_file_changes_free(changes, n_changes);
95 changes = NULL; n_changes = 0;
96
97 assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("a.service"), &changes, &n_changes) == 1);
98 assert_se(n_changes == 1);
99 assert_se(changes[0].type == UNIT_FILE_SYMLINK);
100 assert_se(streq(changes[0].source, "/usr/lib/systemd/system/a.service"));
101 p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/a.service");
102 assert_se(streq(changes[0].path, p));
103 unit_file_changes_free(changes, n_changes);
104 changes = NULL; n_changes = 0;
105
106 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
107 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
108 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
109 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
110
111 /* Enabling it again should succeed but be a NOP */
112 assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("a.service"), &changes, &n_changes) >= 0);
113 assert_se(n_changes == 0);
114 unit_file_changes_free(changes, n_changes);
115 changes = NULL; n_changes = 0;
116
117 assert_se(unit_file_disable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("a.service"), &changes, &n_changes) >= 0);
118 assert_se(n_changes == 1);
119 assert_se(changes[0].type == UNIT_FILE_UNLINK);
120 p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/a.service");
121 assert_se(streq(changes[0].path, p));
122 unit_file_changes_free(changes, n_changes);
123 changes = NULL; n_changes = 0;
124
125 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
126 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
127 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
128 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
129
130 /* Disabling a disabled unit must suceed but be a NOP */
131 assert_se(unit_file_disable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("a.service"), &changes, &n_changes) >= 0);
132 assert_se(n_changes == 0);
133 unit_file_changes_free(changes, n_changes);
134 changes = NULL; n_changes = 0;
135
136 /* Let's enable this indirectly via a symlink */
137 assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("d.service"), &changes, &n_changes) >= 0);
138 assert_se(n_changes == 1);
139 assert_se(changes[0].type == UNIT_FILE_SYMLINK);
140 assert_se(streq(changes[0].source, "/usr/lib/systemd/system/a.service"));
141 p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/a.service");
142 assert_se(streq(changes[0].path, p));
143 unit_file_changes_free(changes, n_changes);
144 changes = NULL; n_changes = 0;
145
146 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
147 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
148 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
149 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
150
151 /* Let's try to reenable */
152
153 assert_se(unit_file_reenable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("b.service"), &changes, &n_changes) >= 0);
154 assert_se(n_changes == 2);
155 assert_se(changes[0].type == UNIT_FILE_UNLINK);
156 p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/a.service");
157 assert_se(streq(changes[0].path, p));
158 assert_se(changes[1].type == UNIT_FILE_SYMLINK);
159 assert_se(streq(changes[1].source, "/usr/lib/systemd/system/a.service"));
160 assert_se(streq(changes[1].path, p));
161 unit_file_changes_free(changes, n_changes);
162 changes = NULL; n_changes = 0;
163
164 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
165 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
166 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
167 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
168 }
169
170 static void test_linked_units(const char *root) {
171 const char *p, *q;
172 UnitFileState state;
173 UnitFileChange *changes = NULL;
174 unsigned n_changes = 0, i;
175
176 /*
177 * We'll test three cases here:
178 *
179 * a) a unit file in /opt, that we use "systemctl link" and
180 * "systemctl enable" on to make it available to the system
181 *
182 * b) a unit file in /opt, that is statically linked into
183 * /usr/lib/systemd/system, that "enable" should work on
184 * correctly.
185 *
186 * c) a unit file in /opt, that is linked into
187 * /etc/systemd/system, and where "enable" should result in
188 * -ELOOP, since using information from /etc to generate
189 * information in /etc should not be allowed.
190 */
191
192 p = strjoina(root, "/opt/linked.service");
193 assert_se(write_string_file(p,
194 "[Install]\n"
195 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE) >= 0);
196
197 p = strjoina(root, "/opt/linked2.service");
198 assert_se(write_string_file(p,
199 "[Install]\n"
200 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE) >= 0);
201
202 p = strjoina(root, "/opt/linked3.service");
203 assert_se(write_string_file(p,
204 "[Install]\n"
205 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE) >= 0);
206
207 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked.service", NULL) == -ENOENT);
208 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked2.service", NULL) == -ENOENT);
209 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked3.service", NULL) == -ENOENT);
210
211 p = strjoina(root, "/usr/lib/systemd/system/linked2.service");
212 assert_se(symlink("/opt/linked2.service", p) >= 0);
213
214 p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/linked3.service");
215 assert_se(symlink("/opt/linked3.service", p) >= 0);
216
217 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked.service", &state) == -ENOENT);
218 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked2.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
219 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked3.service", &state) >= 0 && state == UNIT_FILE_LINKED);
220
221 /* First, let's link the unit into the search path */
222 assert_se(unit_file_link(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("/opt/linked.service"), &changes, &n_changes) >= 0);
223 assert_se(n_changes == 1);
224 assert_se(changes[0].type == UNIT_FILE_SYMLINK);
225 assert_se(streq(changes[0].source, "/opt/linked.service"));
226 p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/linked.service");
227 assert_se(streq(changes[0].path, p));
228 unit_file_changes_free(changes, n_changes);
229 changes = NULL; n_changes = 0;
230
231 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked.service", &state) >= 0 && state == UNIT_FILE_LINKED);
232
233 /* Let's unlink it from the search path again */
234 assert_se(unit_file_disable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("linked.service"), &changes, &n_changes) >= 0);
235 assert_se(n_changes == 1);
236 assert_se(changes[0].type == UNIT_FILE_UNLINK);
237 p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/linked.service");
238 assert_se(streq(changes[0].path, p));
239 unit_file_changes_free(changes, n_changes);
240 changes = NULL; n_changes = 0;
241
242 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked.service", NULL) == -ENOENT);
243
244 /* Now, let's not just link it, but also enable it */
245 assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("/opt/linked.service"), &changes, &n_changes) >= 0);
246 assert_se(n_changes == 2);
247 p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/linked.service");
248 q = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/linked.service");
249 for (i = 0 ; i < n_changes; i++) {
250 assert_se(changes[i].type == UNIT_FILE_SYMLINK);
251 assert_se(streq(changes[i].source, "/opt/linked.service"));
252
253 if (p && streq(changes[i].path, p))
254 p = NULL;
255 else if (q && streq(changes[i].path, q))
256 q = NULL;
257 else
258 assert_not_reached("wut?");
259 }
260 assert(!p && !q);
261 unit_file_changes_free(changes, n_changes);
262 changes = NULL; n_changes = 0;
263
264 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
265
266 /* And let's unlink it again */
267 assert_se(unit_file_disable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("linked.service"), &changes, &n_changes) >= 0);
268 assert_se(n_changes == 2);
269 p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/linked.service");
270 q = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/linked.service");
271 for (i = 0; i < n_changes; i++) {
272 assert_se(changes[i].type == UNIT_FILE_UNLINK);
273
274 if (p && streq(changes[i].path, p))
275 p = NULL;
276 else if (q && streq(changes[i].path, q))
277 q = NULL;
278 else
279 assert_not_reached("wut?");
280 }
281 assert(!p && !q);
282 unit_file_changes_free(changes, n_changes);
283 changes = NULL; n_changes = 0;
284
285 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked.service", NULL) == -ENOENT);
286
287 assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("linked2.service"), &changes, &n_changes) >= 0);
288 assert_se(n_changes == 2);
289 p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/linked2.service");
290 q = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/linked2.service");
291 for (i = 0 ; i < n_changes; i++) {
292 assert_se(changes[i].type == UNIT_FILE_SYMLINK);
293 assert_se(streq(changes[i].source, "/opt/linked2.service"));
294
295 if (p && streq(changes[i].path, p))
296 p = NULL;
297 else if (q && streq(changes[i].path, q))
298 q = NULL;
299 else
300 assert_not_reached("wut?");
301 }
302 assert(!p && !q);
303 unit_file_changes_free(changes, n_changes);
304 changes = NULL; n_changes = 0;
305
306 assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("linked3.service"), &changes, &n_changes) >= 0);
307 assert_se(n_changes == 1);
308 assert_se(changes[0].type == UNIT_FILE_SYMLINK);
309 assert_se(startswith(changes[0].path, root));
310 assert_se(endswith(changes[0].path, "linked3.service"));
311 assert_se(streq(changes[0].source, "/opt/linked3.service"));
312 unit_file_changes_free(changes, n_changes);
313 changes = NULL; n_changes = 0;
314 }
315
316 static void test_default(const char *root) {
317 _cleanup_free_ char *def = NULL;
318 UnitFileChange *changes = NULL;
319 unsigned n_changes = 0;
320 const char *p;
321
322 p = strjoina(root, "/usr/lib/systemd/system/test-default-real.target");
323 assert_se(write_string_file(p, "# pretty much empty", WRITE_STRING_FILE_CREATE) >= 0);
324
325 p = strjoina(root, "/usr/lib/systemd/system/test-default.target");
326 assert_se(symlink("test-default-real.target", p) >= 0);
327
328 assert_se(unit_file_get_default(UNIT_FILE_SYSTEM, root, &def) == -ENOENT);
329
330 assert_se(unit_file_set_default(UNIT_FILE_SYSTEM, 0, root, "idontexist.target", &changes, &n_changes) == -ENOENT);
331 assert_se(n_changes == 1);
332 assert_se(changes[0].type == -ENOENT);
333 assert_se(streq_ptr(changes[0].path, "idontexist.target"));
334 unit_file_changes_free(changes, n_changes);
335 changes = NULL; n_changes = 0;
336
337 assert_se(unit_file_get_default(UNIT_FILE_SYSTEM, root, &def) == -ENOENT);
338
339 assert_se(unit_file_set_default(UNIT_FILE_SYSTEM, 0, root, "test-default.target", &changes, &n_changes) >= 0);
340 assert_se(n_changes == 1);
341 assert_se(changes[0].type == UNIT_FILE_SYMLINK);
342 assert_se(streq(changes[0].source, "/usr/lib/systemd/system/test-default-real.target"));
343 p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH "/" SPECIAL_DEFAULT_TARGET);
344 assert_se(streq(changes[0].path, p));
345 unit_file_changes_free(changes, n_changes);
346 changes = NULL; n_changes = 0;
347
348 assert_se(unit_file_get_default(UNIT_FILE_SYSTEM, root, &def) >= 0);
349 assert_se(streq_ptr(def, "test-default-real.target"));
350 }
351
352 static void test_add_dependency(const char *root) {
353 UnitFileChange *changes = NULL;
354 unsigned n_changes = 0;
355 const char *p;
356
357 p = strjoina(root, "/usr/lib/systemd/system/real-add-dependency-test-target.target");
358 assert_se(write_string_file(p, "# pretty much empty", WRITE_STRING_FILE_CREATE) >= 0);
359
360 p = strjoina(root, "/usr/lib/systemd/system/add-dependency-test-target.target");
361 assert_se(symlink("real-add-dependency-test-target.target", p) >= 0);
362
363 p = strjoina(root, "/usr/lib/systemd/system/real-add-dependency-test-service.service");
364 assert_se(write_string_file(p, "# pretty much empty", WRITE_STRING_FILE_CREATE) >= 0);
365
366 p = strjoina(root, "/usr/lib/systemd/system/add-dependency-test-service.service");
367 assert_se(symlink("real-add-dependency-test-service.service", p) >= 0);
368
369 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);
370 assert_se(n_changes == 1);
371 assert_se(changes[0].type == UNIT_FILE_SYMLINK);
372 assert_se(streq(changes[0].source, "/usr/lib/systemd/system/real-add-dependency-test-service.service"));
373 p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/real-add-dependency-test-target.target.wants/real-add-dependency-test-service.service");
374 assert_se(streq(changes[0].path, p));
375 unit_file_changes_free(changes, n_changes);
376 changes = NULL; n_changes = 0;
377 }
378
379 static void test_template_enable(const char *root) {
380 UnitFileChange *changes = NULL;
381 unsigned n_changes = 0;
382 UnitFileState state;
383 const char *p;
384
385 log_info("== %s ==", __func__);
386
387 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@.service", &state) == -ENOENT);
388 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@def.service", &state) == -ENOENT);
389 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@foo.service", &state) == -ENOENT);
390 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) == -ENOENT);
391
392 p = strjoina(root, "/usr/lib/systemd/system/template@.service");
393 assert_se(write_string_file(p,
394 "[Install]\n"
395 "DefaultInstance=def\n"
396 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE) >= 0);
397
398 p = strjoina(root, "/usr/lib/systemd/system/template-symlink@.service");
399 assert_se(symlink("template@.service", p) >= 0);
400
401 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
402 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
403 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
404 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
405 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
406 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
407
408 log_info("== %s with template@.service enabled ==", __func__);
409
410 assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("template@.service"), &changes, &n_changes) >= 0);
411 assert_se(n_changes == 1);
412 assert_se(changes[0].type == UNIT_FILE_SYMLINK);
413 assert_se(streq(changes[0].source, "/usr/lib/systemd/system/template@.service"));
414 p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/template@def.service");
415 assert_se(streq(changes[0].path, p));
416 unit_file_changes_free(changes, n_changes);
417 changes = NULL; n_changes = 0;
418
419 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
420 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@def.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
421 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
422 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
423 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
424 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
425
426 assert_se(unit_file_disable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("template@.service"), &changes, &n_changes) >= 0);
427 assert_se(n_changes == 1);
428 assert_se(changes[0].type == UNIT_FILE_UNLINK);
429 assert_se(streq(changes[0].path, p));
430 unit_file_changes_free(changes, n_changes);
431 changes = NULL; n_changes = 0;
432
433 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
434 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
435 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
436 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
437 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
438 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
439
440 log_info("== %s with template@foo.service enabled ==", __func__);
441
442 assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("template@foo.service"), &changes, &n_changes) >= 0);
443 assert_se(changes[0].type == UNIT_FILE_SYMLINK);
444 assert_se(streq(changes[0].source, "/usr/lib/systemd/system/template@.service"));
445 p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/template@foo.service");
446 assert_se(streq(changes[0].path, p));
447 unit_file_changes_free(changes, n_changes);
448 changes = NULL; n_changes = 0;
449
450 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@.service", &state) >= 0 && state == UNIT_FILE_INDIRECT);
451 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
452 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@foo.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_ENABLED);
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_ENABLED);
456
457 assert_se(unit_file_disable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("template@foo.service"), &changes, &n_changes) >= 0);
458 assert_se(n_changes == 1);
459 assert_se(changes[0].type == UNIT_FILE_UNLINK);
460 assert_se(streq(changes[0].path, p));
461 unit_file_changes_free(changes, n_changes);
462 changes = NULL; n_changes = 0;
463
464 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
465 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
466 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
467 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@quux.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
468 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
469 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
470 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
471 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@quux.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
472
473 log_info("== %s with template-symlink@quux.service enabled ==", __func__);
474
475 assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("template-symlink@quux.service"), &changes, &n_changes) >= 0);
476 assert_se(changes[0].type == UNIT_FILE_SYMLINK);
477 assert_se(streq(changes[0].source, "/usr/lib/systemd/system/template@.service"));
478 p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/template@quux.service");
479 assert_se(streq(changes[0].path, p));
480 unit_file_changes_free(changes, n_changes);
481 changes = NULL; n_changes = 0;
482
483 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@.service", &state) >= 0 && state == UNIT_FILE_INDIRECT);
484 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
485 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
486 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@quux.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
487 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@.service", &state) >= 0 && state == UNIT_FILE_INDIRECT);
488 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
489 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
490 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@quux.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
491 }
492
493 static void test_indirect(const char *root) {
494 UnitFileChange *changes = NULL;
495 unsigned n_changes = 0;
496 UnitFileState state;
497 const char *p;
498
499 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirecta.service", &state) == -ENOENT);
500 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectb.service", &state) == -ENOENT);
501 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectc.service", &state) == -ENOENT);
502
503 p = strjoina(root, "/usr/lib/systemd/system/indirecta.service");
504 assert_se(write_string_file(p,
505 "[Install]\n"
506 "Also=indirectb.service\n", WRITE_STRING_FILE_CREATE) >= 0);
507
508 p = strjoina(root, "/usr/lib/systemd/system/indirectb.service");
509 assert_se(write_string_file(p,
510 "[Install]\n"
511 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE) >= 0);
512
513 p = strjoina(root, "/usr/lib/systemd/system/indirectc.service");
514 assert_se(symlink("indirecta.service", p) >= 0);
515
516 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirecta.service", &state) >= 0 && state == UNIT_FILE_INDIRECT);
517 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectb.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
518 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectc.service", &state) >= 0 && state == UNIT_FILE_INDIRECT);
519
520 assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("indirectc.service"), &changes, &n_changes) >= 0);
521 assert_se(n_changes == 1);
522 assert_se(changes[0].type == UNIT_FILE_SYMLINK);
523 assert_se(streq(changes[0].source, "/usr/lib/systemd/system/indirectb.service"));
524 p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/indirectb.service");
525 assert_se(streq(changes[0].path, p));
526 unit_file_changes_free(changes, n_changes);
527 changes = NULL; n_changes = 0;
528
529 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirecta.service", &state) >= 0 && state == UNIT_FILE_INDIRECT);
530 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectb.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
531 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectc.service", &state) >= 0 && state == UNIT_FILE_INDIRECT);
532
533 assert_se(unit_file_disable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("indirectc.service"), &changes, &n_changes) >= 0);
534 assert_se(n_changes == 1);
535 assert_se(changes[0].type == UNIT_FILE_UNLINK);
536 p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/indirectb.service");
537 assert_se(streq(changes[0].path, p));
538 unit_file_changes_free(changes, n_changes);
539 changes = NULL; n_changes = 0;
540 }
541
542 static void test_preset_and_list(const char *root) {
543 UnitFileChange *changes = NULL;
544 unsigned n_changes = 0, i;
545 const char *p, *q;
546 UnitFileState state;
547 bool got_yes = false, got_no = false;
548 Iterator j;
549 UnitFileList *fl;
550 Hashmap *h;
551
552 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-yes.service", &state) == -ENOENT);
553 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-no.service", &state) == -ENOENT);
554
555 p = strjoina(root, "/usr/lib/systemd/system/preset-yes.service");
556 assert_se(write_string_file(p,
557 "[Install]\n"
558 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE) >= 0);
559
560 p = strjoina(root, "/usr/lib/systemd/system/preset-no.service");
561 assert_se(write_string_file(p,
562 "[Install]\n"
563 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE) >= 0);
564
565 p = strjoina(root, "/usr/lib/systemd/system-preset/test.preset");
566 assert_se(write_string_file(p,
567 "enable *-yes.*\n"
568 "disable *\n", WRITE_STRING_FILE_CREATE) >= 0);
569
570 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-yes.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
571 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-no.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
572
573 assert_se(unit_file_preset(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("preset-yes.service"), UNIT_FILE_PRESET_FULL, &changes, &n_changes) >= 0);
574 assert_se(n_changes == 1);
575 assert_se(changes[0].type == UNIT_FILE_SYMLINK);
576 assert_se(streq(changes[0].source, "/usr/lib/systemd/system/preset-yes.service"));
577 p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/preset-yes.service");
578 assert_se(streq(changes[0].path, p));
579 unit_file_changes_free(changes, n_changes);
580 changes = NULL; n_changes = 0;
581
582 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-yes.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
583 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-no.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
584
585 assert_se(unit_file_disable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("preset-yes.service"), &changes, &n_changes) >= 0);
586 assert_se(n_changes == 1);
587 assert_se(changes[0].type == UNIT_FILE_UNLINK);
588 p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/preset-yes.service");
589 assert_se(streq(changes[0].path, p));
590 unit_file_changes_free(changes, n_changes);
591 changes = NULL; n_changes = 0;
592
593 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-yes.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
594 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-no.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
595
596 assert_se(unit_file_preset(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("preset-no.service"), UNIT_FILE_PRESET_FULL, &changes, &n_changes) >= 0);
597 assert_se(n_changes == 0);
598 unit_file_changes_free(changes, n_changes);
599 changes = NULL; n_changes = 0;
600
601 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-yes.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
602 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-no.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
603
604 assert_se(unit_file_preset_all(UNIT_FILE_SYSTEM, 0, root, UNIT_FILE_PRESET_FULL, &changes, &n_changes) >= 0);
605
606 assert_se(n_changes > 0);
607
608 p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/preset-yes.service");
609
610 for (i = 0; i < n_changes; i++) {
611
612 if (changes[i].type == UNIT_FILE_SYMLINK) {
613 assert_se(streq(changes[i].source, "/usr/lib/systemd/system/preset-yes.service"));
614 assert_se(streq(changes[i].path, p));
615 } else
616 assert_se(changes[i].type == UNIT_FILE_UNLINK);
617 }
618
619 unit_file_changes_free(changes, n_changes);
620 changes = NULL; n_changes = 0;
621
622 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-yes.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
623 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-no.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
624
625 assert_se(h = hashmap_new(&string_hash_ops));
626 assert_se(unit_file_get_list(UNIT_FILE_SYSTEM, root, h, NULL, NULL) >= 0);
627
628 p = strjoina(root, "/usr/lib/systemd/system/preset-yes.service");
629 q = strjoina(root, "/usr/lib/systemd/system/preset-no.service");
630
631 HASHMAP_FOREACH(fl, h, j) {
632 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, basename(fl->path), &state) >= 0);
633 assert_se(fl->state == state);
634
635 if (streq(fl->path, p)) {
636 got_yes = true;
637 assert_se(fl->state == UNIT_FILE_ENABLED);
638 } else if (streq(fl->path, q)) {
639 got_no = true;
640 assert_se(fl->state == UNIT_FILE_DISABLED);
641 } else
642 assert_se(IN_SET(fl->state, UNIT_FILE_DISABLED, UNIT_FILE_STATIC, UNIT_FILE_INDIRECT));
643 }
644
645 unit_file_list_free(h);
646
647 assert_se(got_yes && got_no);
648 }
649
650 static void test_revert(const char *root) {
651 const char *p;
652 UnitFileState state;
653 UnitFileChange *changes = NULL;
654 unsigned n_changes = 0;
655
656 assert(root);
657
658 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "xx.service", NULL) == -ENOENT);
659 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "yy.service", NULL) == -ENOENT);
660
661 p = strjoina(root, "/usr/lib/systemd/system/xx.service");
662 assert_se(write_string_file(p, "# Empty\n", WRITE_STRING_FILE_CREATE) >= 0);
663
664 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "xx.service", NULL) >= 0);
665 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "xx.service", &state) >= 0 && state == UNIT_FILE_STATIC);
666
667 /* Initially there's nothing to revert */
668 assert_se(unit_file_revert(UNIT_FILE_SYSTEM, root, STRV_MAKE("xx.service"), &changes, &n_changes) >= 0);
669 assert_se(n_changes == 0);
670 unit_file_changes_free(changes, n_changes);
671 changes = NULL; n_changes = 0;
672
673 p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/xx.service");
674 assert_se(write_string_file(p, "# Empty override\n", WRITE_STRING_FILE_CREATE) >= 0);
675
676 /* Revert the override file */
677 assert_se(unit_file_revert(UNIT_FILE_SYSTEM, root, STRV_MAKE("xx.service"), &changes, &n_changes) >= 0);
678 assert_se(n_changes == 1);
679 assert_se(changes[0].type == UNIT_FILE_UNLINK);
680 assert_se(streq(changes[0].path, p));
681 unit_file_changes_free(changes, n_changes);
682 changes = NULL; n_changes = 0;
683
684 p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/xx.service.d/dropin.conf");
685 assert_se(mkdir_parents(p, 0755) >= 0);
686 assert_se(write_string_file(p, "# Empty dropin\n", WRITE_STRING_FILE_CREATE) >= 0);
687
688 /* Revert the dropin file */
689 assert_se(unit_file_revert(UNIT_FILE_SYSTEM, root, STRV_MAKE("xx.service"), &changes, &n_changes) >= 0);
690 assert_se(n_changes == 2);
691 assert_se(changes[0].type == UNIT_FILE_UNLINK);
692 assert_se(streq(changes[0].path, p));
693
694 p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/xx.service.d");
695 assert_se(changes[1].type == UNIT_FILE_UNLINK);
696 assert_se(streq(changes[1].path, p));
697 unit_file_changes_free(changes, n_changes);
698 changes = NULL; n_changes = 0;
699 }
700
701 static void test_preset_order(const char *root) {
702 UnitFileChange *changes = NULL;
703 unsigned n_changes = 0;
704 const char *p;
705 UnitFileState state;
706
707 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "prefix-1.service", &state) == -ENOENT);
708 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "prefix-2.service", &state) == -ENOENT);
709
710 p = strjoina(root, "/usr/lib/systemd/system/prefix-1.service");
711 assert_se(write_string_file(p,
712 "[Install]\n"
713 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE) >= 0);
714
715 p = strjoina(root, "/usr/lib/systemd/system/prefix-2.service");
716 assert_se(write_string_file(p,
717 "[Install]\n"
718 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE) >= 0);
719
720 p = strjoina(root, "/usr/lib/systemd/system-preset/test.preset");
721 assert_se(write_string_file(p,
722 "enable prefix-1.service\n"
723 "disable prefix-*.service\n"
724 "enable prefix-2.service\n", WRITE_STRING_FILE_CREATE) >= 0);
725
726 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "prefix-1.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
727 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "prefix-2.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
728
729 assert_se(unit_file_preset(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("prefix-1.service"), UNIT_FILE_PRESET_FULL, &changes, &n_changes) >= 0);
730 assert_se(n_changes == 1);
731 assert_se(changes[0].type == UNIT_FILE_SYMLINK);
732 assert_se(streq(changes[0].source, "/usr/lib/systemd/system/prefix-1.service"));
733 p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/prefix-1.service");
734 assert_se(streq(changes[0].path, p));
735 unit_file_changes_free(changes, n_changes);
736 changes = NULL; n_changes = 0;
737
738 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "prefix-1.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
739 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "prefix-2.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
740
741 assert_se(unit_file_preset(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("prefix-2.service"), UNIT_FILE_PRESET_FULL, &changes, &n_changes) >= 0);
742 assert_se(n_changes == 0);
743
744 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "prefix-1.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
745 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "prefix-2.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
746 }
747
748 static void test_static_instance(const char *root) {
749 UnitFileState state;
750 const char *p;
751
752 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "static-instance@.service", &state) == -ENOENT);
753 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "static-instance@foo.service", &state) == -ENOENT);
754
755 p = strjoina(root, "/usr/lib/systemd/system/static-instance@.service");
756 assert_se(write_string_file(p,
757 "[Install]\n"
758 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE) >= 0);
759
760 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "static-instance@.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
761 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "static-instance@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
762
763 p = strjoina(root, "/usr/lib/systemd/system/static-instance@foo.service");
764 assert_se(symlink("static-instance@.service", p) >= 0);
765
766 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "static-instance@.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
767 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "static-instance@foo.service", &state) >= 0 && state == UNIT_FILE_STATIC);
768 }
769
770 static void test_with_dropin(const char *root) {
771 const char *p;
772 UnitFileState state;
773 UnitFileChange *changes = NULL;
774 unsigned n_changes = 0;
775
776 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-1.service", &state) == -ENOENT);
777 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-2.service", &state) == -ENOENT);
778 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-3.service", &state) == -ENOENT);
779 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-4a.service", &state) == -ENOENT);
780 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-4b.service", &state) == -ENOENT);
781
782 p = strjoina(root, "/usr/lib/systemd/system/with-dropin-1.service");
783 assert_se(write_string_file(p,
784 "[Install]\n"
785 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE) >= 0);
786
787 p = strjoina(root, "/usr/lib/systemd/system/with-dropin-1.service.d/dropin.conf");
788 assert_se(mkdir_parents(p, 0755) >= 0);
789 assert_se(write_string_file(p,
790 "[Install]\n"
791 "WantedBy=graphical.target\n", WRITE_STRING_FILE_CREATE) >= 0);
792
793 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-1.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
794
795 p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/with-dropin-2.service");
796 assert_se(write_string_file(p,
797 "[Install]\n"
798 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE) >= 0);
799
800 p = strjoina(root, "/usr/lib/systemd/system/with-dropin-2.service.d/dropin.conf");
801 assert_se(mkdir_parents(p, 0755) >= 0);
802 assert_se(write_string_file(p,
803 "[Install]\n"
804 "WantedBy=graphical.target\n", WRITE_STRING_FILE_CREATE) >= 0);
805
806 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-2.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
807
808 p = strjoina(root, "/usr/lib/systemd/system/with-dropin-3.service");
809 assert_se(write_string_file(p,
810 "[Install]\n"
811 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE) >= 0);
812
813 p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/with-dropin-3.service.d/dropin.conf");
814 assert_se(mkdir_parents(p, 0755) >= 0);
815 assert_se(write_string_file(p,
816 "[Install]\n"
817 "WantedBy=graphical.target\n", WRITE_STRING_FILE_CREATE) >= 0);
818
819 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-3.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
820
821 p = strjoina(root, "/usr/lib/systemd/system/with-dropin-4a.service");
822 assert_se(write_string_file(p,
823 "[Install]\n"
824 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE) >= 0);
825
826 p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/with-dropin-4a.service.d/dropin.conf");
827 assert_se(mkdir_parents(p, 0755) >= 0);
828 assert_se(write_string_file(p,
829 "[Install]\n"
830 "Also=with-dropin-4b.service\n", WRITE_STRING_FILE_CREATE) >= 0);
831
832 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-4a.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
833
834 p = strjoina(root, "/usr/lib/systemd/system/with-dropin-4b.service");
835 assert_se(write_string_file(p,
836 "[Install]\n"
837 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE) >= 0);
838
839 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-4b.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
840
841 assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("with-dropin-1.service"), &changes, &n_changes) == 1);
842 assert_se(n_changes == 2);
843 assert_se(changes[0].type == UNIT_FILE_SYMLINK);
844 assert_se(changes[1].type == UNIT_FILE_SYMLINK);
845 assert_se(streq(changes[0].source, "/usr/lib/systemd/system/with-dropin-1.service"));
846 assert_se(streq(changes[1].source, "/usr/lib/systemd/system/with-dropin-1.service"));
847 p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/with-dropin-1.service");
848 assert_se(streq(changes[0].path, p));
849 p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/graphical.target.wants/with-dropin-1.service");
850 assert_se(streq(changes[1].path, p));
851 unit_file_changes_free(changes, n_changes);
852 changes = NULL; n_changes = 0;
853
854 assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("with-dropin-2.service"), &changes, &n_changes) == 1);
855 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-2.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
856 assert_se(n_changes == 2);
857 assert_se(changes[0].type == UNIT_FILE_SYMLINK);
858 assert_se(changes[1].type == UNIT_FILE_SYMLINK);
859 assert_se(streq(changes[0].source, SYSTEM_CONFIG_UNIT_PATH"/with-dropin-2.service"));
860 assert_se(streq(changes[1].source, SYSTEM_CONFIG_UNIT_PATH"/with-dropin-2.service"));
861 p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/with-dropin-2.service");
862 assert_se(streq(changes[0].path, p));
863 p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/graphical.target.wants/with-dropin-2.service");
864 assert_se(streq(changes[1].path, p));
865 unit_file_changes_free(changes, n_changes);
866 changes = NULL; n_changes = 0;
867
868 assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("with-dropin-3.service"), &changes, &n_changes) == 1);
869 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-3.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
870 assert_se(n_changes == 2);
871 assert_se(changes[0].type == UNIT_FILE_SYMLINK);
872 assert_se(changes[1].type == UNIT_FILE_SYMLINK);
873 assert_se(streq(changes[0].source, "/usr/lib/systemd/system/with-dropin-3.service"));
874 assert_se(streq(changes[1].source, "/usr/lib/systemd/system/with-dropin-3.service"));
875 p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/with-dropin-3.service");
876 assert_se(streq(changes[0].path, p));
877 p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/graphical.target.wants/with-dropin-3.service");
878 assert_se(streq(changes[1].path, p));
879 unit_file_changes_free(changes, n_changes);
880 changes = NULL; n_changes = 0;
881
882 assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("with-dropin-4a.service"), &changes, &n_changes) == 1);
883 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-3.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
884 assert_se(n_changes == 2);
885 assert_se(changes[0].type == UNIT_FILE_SYMLINK);
886 assert_se(changes[1].type == UNIT_FILE_SYMLINK);
887 assert_se(streq(changes[0].source, "/usr/lib/systemd/system/with-dropin-4a.service"));
888 assert_se(streq(changes[1].source, "/usr/lib/systemd/system/with-dropin-4b.service"));
889 p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/with-dropin-4a.service");
890 assert_se(streq(changes[0].path, p));
891 p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/with-dropin-4b.service");
892 assert_se(streq(changes[1].path, p));
893 unit_file_changes_free(changes, n_changes);
894 changes = NULL; n_changes = 0;
895
896 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-1.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
897 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-2.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
898 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-3.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
899 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-4a.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
900 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-4b.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
901 }
902
903 static void test_with_dropin_template(const char *root) {
904 const char *p;
905 UnitFileState state;
906 UnitFileChange *changes = NULL;
907 unsigned n_changes = 0;
908
909 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-1@.service", &state) == -ENOENT);
910 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-2@.service", &state) == -ENOENT);
911 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-3@.service", &state) == -ENOENT);
912
913 p = strjoina(root, "/usr/lib/systemd/system/with-dropin-1@.service");
914 assert_se(write_string_file(p,
915 "[Install]\n"
916 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE) >= 0);
917
918 p = strjoina(root, "/usr/lib/systemd/system/with-dropin-1@.service.d/dropin.conf");
919 assert_se(mkdir_parents(p, 0755) >= 0);
920 assert_se(write_string_file(p,
921 "[Install]\n"
922 "WantedBy=graphical.target\n", WRITE_STRING_FILE_CREATE) >= 0);
923
924 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-1@.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
925
926 p = strjoina(root, "/usr/lib/systemd/system/with-dropin-2@.service");
927 assert_se(write_string_file(p,
928 "[Install]\n"
929 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE) >= 0);
930
931 p = strjoina(root, "/usr/lib/systemd/system/with-dropin-2@instance-1.service.d/dropin.conf");
932 assert_se(mkdir_parents(p, 0755) >= 0);
933 assert_se(write_string_file(p,
934 "[Install]\n"
935 "WantedBy=graphical.target\n", WRITE_STRING_FILE_CREATE) >= 0);
936
937 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-2@.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
938
939 p = strjoina(root, "/usr/lib/systemd/system/with-dropin-3@.service");
940 assert_se(write_string_file(p,
941 "[Install]\n"
942 "DefaultInstance=instance-1\n"
943 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE) >= 0);
944
945 p = strjoina(root, "/usr/lib/systemd/system/with-dropin-3@.service.d/dropin.conf");
946 assert_se(mkdir_parents(p, 0755) >= 0);
947 assert_se(write_string_file(p,
948 "[Install]\n"
949 "DefaultInstance=instance-2\n", WRITE_STRING_FILE_CREATE) >= 0);
950
951 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-3@.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
952
953 assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("with-dropin-1@instance-1.service"), &changes, &n_changes) == 1);
954 assert_se(n_changes == 2);
955 assert_se(changes[0].type == UNIT_FILE_SYMLINK);
956 assert_se(changes[1].type == UNIT_FILE_SYMLINK);
957 assert_se(streq(changes[0].source, "/usr/lib/systemd/system/with-dropin-1@.service"));
958 assert_se(streq(changes[1].source, "/usr/lib/systemd/system/with-dropin-1@.service"));
959 p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/with-dropin-1@instance-1.service");
960 assert_se(streq(changes[0].path, p));
961 p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/graphical.target.wants/with-dropin-1@instance-1.service");
962 assert_se(streq(changes[1].path, p));
963 unit_file_changes_free(changes, n_changes);
964 changes = NULL; n_changes = 0;
965
966 assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("with-dropin-2@instance-1.service"), &changes, &n_changes) == 1);
967 assert_se(n_changes == 2);
968 assert_se(changes[0].type == UNIT_FILE_SYMLINK);
969 assert_se(changes[1].type == UNIT_FILE_SYMLINK);
970 assert_se(streq(changes[0].source, "/usr/lib/systemd/system/with-dropin-2@.service"));
971 assert_se(streq(changes[1].source, "/usr/lib/systemd/system/with-dropin-2@.service"));
972 p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/with-dropin-2@instance-1.service");
973 assert_se(streq(changes[0].path, p));
974 p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/graphical.target.wants/with-dropin-2@instance-1.service");
975 assert_se(streq(changes[1].path, p));
976 unit_file_changes_free(changes, n_changes);
977 changes = NULL; n_changes = 0;
978
979 assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("with-dropin-2@instance-2.service"), &changes, &n_changes) == 1);
980 assert_se(n_changes == 1);
981 assert_se(changes[0].type == UNIT_FILE_SYMLINK);
982 assert_se(streq(changes[0].source, "/usr/lib/systemd/system/with-dropin-2@.service"));
983 p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/with-dropin-2@instance-2.service");
984 assert_se(streq(changes[0].path, p));
985 unit_file_changes_free(changes, n_changes);
986 changes = NULL; n_changes = 0;
987
988 assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("with-dropin-3@.service"), &changes, &n_changes) == 1);
989 assert_se(n_changes == 1);
990 assert_se(changes[0].type == UNIT_FILE_SYMLINK);
991 assert_se(streq(changes[0].source, "/usr/lib/systemd/system/with-dropin-3@.service"));
992 p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/with-dropin-3@instance-2.service");
993 assert_se(streq(changes[0].path, p));
994 unit_file_changes_free(changes, n_changes);
995 changes = NULL; n_changes = 0;
996
997 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-1@instance-1.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
998 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-2@instance-1.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
999 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-2@instance-2.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
1000 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-3@instance-1.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
1001 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-3@instance-2.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
1002 }
1003
1004 int main(int argc, char *argv[]) {
1005 char root[] = "/tmp/rootXXXXXX";
1006 const char *p;
1007
1008 assert_se(mkdtemp(root));
1009
1010 p = strjoina(root, "/usr/lib/systemd/system/");
1011 assert_se(mkdir_p(p, 0755) >= 0);
1012
1013 p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/");
1014 assert_se(mkdir_p(p, 0755) >= 0);
1015
1016 p = strjoina(root, "/run/systemd/system/");
1017 assert_se(mkdir_p(p, 0755) >= 0);
1018
1019 p = strjoina(root, "/opt/");
1020 assert_se(mkdir_p(p, 0755) >= 0);
1021
1022 p = strjoina(root, "/usr/lib/systemd/system-preset/");
1023 assert_se(mkdir_p(p, 0755) >= 0);
1024
1025 test_basic_mask_and_enable(root);
1026 test_linked_units(root);
1027 test_default(root);
1028 test_add_dependency(root);
1029 test_template_enable(root);
1030 test_indirect(root);
1031 test_preset_and_list(root);
1032 test_preset_order(root);
1033 test_revert(root);
1034 test_static_instance(root);
1035 test_with_dropin(root);
1036 test_with_dropin_template(root);
1037
1038 assert_se(rm_rf(root, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
1039
1040 return 0;
1041 }