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