]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/test/test-install-root.c
Merge pull request #1515 from poettering/install-symlink
[thirdparty/systemd.git] / src / test / test-install-root.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2011 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include "alloc-util.h"
23 #include "fileio.h"
24 #include "install.h"
25 #include "mkdir.h"
26 #include "rm-rf.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 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", NULL) == -ENOENT);
36 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", NULL) == -ENOENT);
37 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", NULL) == -ENOENT);
38 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", NULL) == -ENOENT);
39
40 p = strjoina(root, "/usr/lib/systemd/system/a.service");
41 assert_se(write_string_file(p,
42 "[Install]\n"
43 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE) >= 0);
44
45 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", NULL) >= 0);
46 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
47
48 p = strjoina(root, "/usr/lib/systemd/system/b.service");
49 assert_se(symlink("a.service", p) >= 0);
50
51 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", NULL) >= 0);
52 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
53
54 p = strjoina(root, "/usr/lib/systemd/system/c.service");
55 assert_se(symlink("/usr/lib/systemd/system/a.service", p) >= 0);
56
57 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", NULL) >= 0);
58 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
59
60 p = strjoina(root, "/usr/lib/systemd/system/d.service");
61 assert_se(symlink("c.service", p) >= 0);
62
63 /* This one is interesting, as d follows a relative, then an absolute symlink */
64 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", NULL) >= 0);
65 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
66
67 assert_se(unit_file_mask(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("a.service"), false, &changes, &n_changes) >= 0);
68 assert_se(n_changes == 1);
69 assert_se(changes[0].type == UNIT_FILE_SYMLINK);
70 assert_se(streq(changes[0].source, "/dev/null"));
71 p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/a.service");
72 assert_se(streq(changes[0].path, p));
73
74 unit_file_changes_free(changes, n_changes);
75 changes = NULL; n_changes = 0;
76
77 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", &state) >= 0 && state == UNIT_FILE_MASKED);
78 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_MASKED);
79 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_MASKED);
80 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_MASKED);
81
82 /* Enabling a masked unit should fail! */
83 assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("a.service"), false, &changes, &n_changes) == -ESHUTDOWN);
84 unit_file_changes_free(changes, n_changes);
85 changes = NULL; n_changes = 0;
86
87 assert_se(unit_file_unmask(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("a.service"), &changes, &n_changes) >= 0);
88 assert_se(n_changes == 1);
89 assert_se(changes[0].type == UNIT_FILE_UNLINK);
90 p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/a.service");
91 assert_se(streq(changes[0].path, p));
92 unit_file_changes_free(changes, n_changes);
93 changes = NULL; n_changes = 0;
94
95 assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("a.service"), false, &changes, &n_changes) == 1);
96 assert_se(n_changes == 1);
97 assert_se(changes[0].type == UNIT_FILE_SYMLINK);
98 assert_se(streq(changes[0].source, "/usr/lib/systemd/system/a.service"));
99 p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/a.service");
100 assert_se(streq(changes[0].path, p));
101 unit_file_changes_free(changes, n_changes);
102 changes = NULL; n_changes = 0;
103
104 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
105 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
106 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
107 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
108
109 /* Enabling it again should succeed but be a NOP */
110 assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("a.service"), false, &changes, &n_changes) == 1);
111 assert_se(n_changes == 0);
112 unit_file_changes_free(changes, n_changes);
113 changes = NULL; n_changes = 0;
114
115 assert_se(unit_file_disable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("a.service"), &changes, &n_changes) >= 0);
116 assert_se(n_changes == 1);
117 assert_se(changes[0].type == UNIT_FILE_UNLINK);
118 p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/a.service");
119 assert_se(streq(changes[0].path, p));
120 unit_file_changes_free(changes, n_changes);
121 changes = NULL; n_changes = 0;
122
123 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
124 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
125 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
126 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
127
128 /* Disabling a disabled unit must suceed but be a NOP */
129 assert_se(unit_file_disable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("a.service"), &changes, &n_changes) >= 0);
130 assert_se(n_changes == 0);
131 unit_file_changes_free(changes, n_changes);
132 changes = NULL; n_changes = 0;
133
134 /* Let's enable this indirectly via a symlink */
135 assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("d.service"), false, &changes, &n_changes) >= 0);
136 assert_se(n_changes == 1);
137 assert_se(changes[0].type == UNIT_FILE_SYMLINK);
138 assert_se(streq(changes[0].source, "/usr/lib/systemd/system/a.service"));
139 p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/a.service");
140 assert_se(streq(changes[0].path, p));
141 unit_file_changes_free(changes, n_changes);
142 changes = NULL; n_changes = 0;
143
144 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
145 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
146 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
147 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
148
149 /* Let's try to reenable */
150
151 assert_se(unit_file_reenable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("b.service"), false, &changes, &n_changes) >= 0);
152 assert_se(n_changes == 2);
153 assert_se(changes[0].type == UNIT_FILE_UNLINK);
154 p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/a.service");
155 assert_se(streq(changes[0].path, p));
156 assert_se(changes[1].type == UNIT_FILE_SYMLINK);
157 assert_se(streq(changes[1].source, "/usr/lib/systemd/system/a.service"));
158 assert_se(streq(changes[1].path, p));
159 unit_file_changes_free(changes, n_changes);
160 changes = NULL; n_changes = 0;
161
162 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
163 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
164 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
165 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
166 }
167
168 static void test_linked_units(const char *root) {
169 const char *p, *q;
170 UnitFileState state;
171 UnitFileChange *changes = NULL;
172 unsigned n_changes = 0, i;
173
174 /*
175 * We'll test three cases here:
176 *
177 * a) a unit file in /opt, that we use "systemctl link" and
178 * "systemctl enable" on to make it available to the system
179 *
180 * b) a unit file in /opt, that is statically linked into
181 * /usr/lib/systemd/system, that "enable" should work on
182 * correctly.
183 *
184 * c) a unit file in /opt, that is linked into
185 * /etc/systemd/system, and where "enable" should result in
186 * -ELOOP, since using information from /etc to generate
187 * information in /etc should not be allowed.
188 */
189
190 p = strjoina(root, "/opt/linked.service");
191 assert_se(write_string_file(p,
192 "[Install]\n"
193 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE) >= 0);
194
195 p = strjoina(root, "/opt/linked2.service");
196 assert_se(write_string_file(p,
197 "[Install]\n"
198 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE) >= 0);
199
200 p = strjoina(root, "/opt/linked3.service");
201 assert_se(write_string_file(p,
202 "[Install]\n"
203 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE) >= 0);
204
205 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked.service", NULL) == -ENOENT);
206 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked2.service", NULL) == -ENOENT);
207 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked3.service", NULL) == -ENOENT);
208
209 p = strjoina(root, "/usr/lib/systemd/system/linked2.service");
210 assert_se(symlink("/opt/linked2.service", p) >= 0);
211
212 p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/linked3.service");
213 assert_se(symlink("/opt/linked3.service", p) >= 0);
214
215 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked.service", &state) == -ENOENT);
216 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked2.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
217 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked3.service", &state) >= 0 && state == UNIT_FILE_LINKED);
218
219 /* First, let's link the unit into the search path */
220 assert_se(unit_file_link(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("/opt/linked.service"), false, &changes, &n_changes) >= 0);
221 assert_se(n_changes == 1);
222 assert_se(changes[0].type == UNIT_FILE_SYMLINK);
223 assert_se(streq(changes[0].source, "/opt/linked.service"));
224 p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/linked.service");
225 assert_se(streq(changes[0].path, p));
226 unit_file_changes_free(changes, n_changes);
227 changes = NULL; n_changes = 0;
228
229 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked.service", &state) >= 0 && state == UNIT_FILE_LINKED);
230
231 /* Let's unlink it from the search path again */
232 assert_se(unit_file_disable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("linked.service"), &changes, &n_changes) >= 0);
233 assert_se(n_changes == 1);
234 assert_se(changes[0].type == UNIT_FILE_UNLINK);
235 p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/linked.service");
236 assert_se(streq(changes[0].path, p));
237 unit_file_changes_free(changes, n_changes);
238 changes = NULL; n_changes = 0;
239
240 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked.service", NULL) == -ENOENT);
241
242 /* Now, let's not just link it, but also enable it */
243 assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("/opt/linked.service"), false, &changes, &n_changes) >= 0);
244 assert_se(n_changes == 2);
245 p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/linked.service");
246 q = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/linked.service");
247 for (i = 0 ; i < n_changes; i++) {
248 assert_se(changes[i].type == UNIT_FILE_SYMLINK);
249 assert_se(streq(changes[i].source, "/opt/linked.service"));
250
251 if (p && streq(changes[i].path, p))
252 p = NULL;
253 else if (q && streq(changes[i].path, q))
254 q = NULL;
255 else
256 assert_not_reached("wut?");
257 }
258 assert(!p && !q);
259 unit_file_changes_free(changes, n_changes);
260 changes = NULL; n_changes = 0;
261
262 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
263
264 /* And let's unlink it again */
265 assert_se(unit_file_disable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("linked.service"), &changes, &n_changes) >= 0);
266 assert_se(n_changes == 2);
267 p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/linked.service");
268 q = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/linked.service");
269 for (i = 0; i < n_changes; i++) {
270 assert_se(changes[i].type == UNIT_FILE_UNLINK);
271
272 if (p && streq(changes[i].path, p))
273 p = NULL;
274 else if (q && streq(changes[i].path, q))
275 q = NULL;
276 else
277 assert_not_reached("wut?");
278 }
279 assert(!p && !q);
280 unit_file_changes_free(changes, n_changes);
281 changes = NULL; n_changes = 0;
282
283 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked.service", NULL) == -ENOENT);
284
285 assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("linked2.service"), false, &changes, &n_changes) >= 0);
286 assert_se(n_changes == 2);
287 p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/linked2.service");
288 q = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/linked2.service");
289 for (i = 0 ; i < n_changes; i++) {
290 assert_se(changes[i].type == UNIT_FILE_SYMLINK);
291 assert_se(streq(changes[i].source, "/opt/linked2.service"));
292
293 if (p && streq(changes[i].path, p))
294 p = NULL;
295 else if (q && streq(changes[i].path, q))
296 q = NULL;
297 else
298 assert_not_reached("wut?");
299 }
300 assert(!p && !q);
301 unit_file_changes_free(changes, n_changes);
302 changes = NULL; n_changes = 0;
303
304 assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("linked3.service"), false, &changes, &n_changes) == -ELOOP);
305 unit_file_changes_free(changes, n_changes);
306 changes = NULL; n_changes = 0;
307 }
308
309 static void test_default(const char *root) {
310 _cleanup_free_ char *def = NULL;
311 UnitFileChange *changes = NULL;
312 unsigned n_changes = 0;
313 const char *p;
314
315 p = strjoina(root, "/usr/lib/systemd/system/test-default-real.target");
316 assert_se(write_string_file(p, "# pretty much empty", WRITE_STRING_FILE_CREATE) >= 0);
317
318 p = strjoina(root, "/usr/lib/systemd/system/test-default.target");
319 assert_se(symlink("test-default-real.target", p) >= 0);
320
321 assert_se(unit_file_get_default(UNIT_FILE_SYSTEM, root, &def) == -ENOENT);
322
323 assert_se(unit_file_set_default(UNIT_FILE_SYSTEM, root, "idontexist.target", false, &changes, &n_changes) == -ENOENT);
324 assert_se(n_changes == 0);
325 unit_file_changes_free(changes, n_changes);
326 changes = NULL; n_changes = 0;
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, root, "test-default.target", false, &changes, &n_changes) >= 0);
331 assert_se(n_changes == 1);
332 assert_se(changes[0].type == UNIT_FILE_SYMLINK);
333 assert_se(streq(changes[0].source, "/usr/lib/systemd/system/test-default-real.target"));
334 p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/default.target");
335 assert_se(streq(changes[0].path, p));
336 unit_file_changes_free(changes, n_changes);
337 changes = NULL; n_changes = 0;
338
339 assert_se(unit_file_get_default(UNIT_FILE_SYSTEM, root, &def) >= 0);
340 assert_se(streq_ptr(def, "test-default-real.target"));
341 }
342
343 static void test_add_dependency(const char *root) {
344 UnitFileChange *changes = NULL;
345 unsigned n_changes = 0;
346 const char *p;
347
348 p = strjoina(root, "/usr/lib/systemd/system/real-add-dependency-test-target.target");
349 assert_se(write_string_file(p, "# pretty much empty", WRITE_STRING_FILE_CREATE) >= 0);
350
351 p = strjoina(root, "/usr/lib/systemd/system/add-dependency-test-target.target");
352 assert_se(symlink("real-add-dependency-test-target.target", p) >= 0);
353
354 p = strjoina(root, "/usr/lib/systemd/system/real-add-dependency-test-service.service");
355 assert_se(write_string_file(p, "# pretty much empty", WRITE_STRING_FILE_CREATE) >= 0);
356
357 p = strjoina(root, "/usr/lib/systemd/system/add-dependency-test-service.service");
358 assert_se(symlink("real-add-dependency-test-service.service", p) >= 0);
359
360 assert_se(unit_file_add_dependency(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("add-dependency-test-service.service"), "add-dependency-test-target.target", UNIT_WANTS, false, &changes, &n_changes) >= 0);
361 assert_se(n_changes == 1);
362 assert_se(changes[0].type == UNIT_FILE_SYMLINK);
363 assert_se(streq(changes[0].source, "/usr/lib/systemd/system/real-add-dependency-test-service.service"));
364 p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/real-add-dependency-test-target.target.wants/real-add-dependency-test-service.service");
365 assert_se(streq(changes[0].path, p));
366 unit_file_changes_free(changes, n_changes);
367 changes = NULL; n_changes = 0;
368 }
369
370 static void test_template_enable(const char *root) {
371 UnitFileChange *changes = NULL;
372 unsigned n_changes = 0;
373 UnitFileState state;
374 const char *p;
375
376 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@.service", &state) == -ENOENT);
377 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@def.service", &state) == -ENOENT);
378 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@foo.service", &state) == -ENOENT);
379 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) == -ENOENT);
380
381 p = strjoina(root, "/usr/lib/systemd/system/template@.service");
382 assert_se(write_string_file(p,
383 "[Install]\n"
384 "DefaultInstance=def\n"
385 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE) >= 0);
386
387 p = strjoina(root, "/usr/lib/systemd/system/template-symlink@.service");
388 assert_se(symlink("template@.service", p) >= 0);
389
390 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
391 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
392 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
393 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
394 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
395 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
396
397 assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("template@.service"), false, &changes, &n_changes) >= 0);
398 assert_se(n_changes == 1);
399 assert_se(changes[0].type == UNIT_FILE_SYMLINK);
400 assert_se(streq(changes[0].source, "/usr/lib/systemd/system/template@.service"));
401 p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/template@def.service");
402 assert_se(streq(changes[0].path, p));
403 unit_file_changes_free(changes, n_changes);
404 changes = NULL; n_changes = 0;
405
406 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
407 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@def.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
408 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
409 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
410 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
411 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
412
413 assert_se(unit_file_disable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("template@.service"), &changes, &n_changes) >= 0);
414 assert_se(n_changes == 1);
415 assert_se(changes[0].type == UNIT_FILE_UNLINK);
416 assert_se(streq(changes[0].path, p));
417 unit_file_changes_free(changes, n_changes);
418 changes = NULL; n_changes = 0;
419
420 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
421 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
422 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
423 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
424 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
425 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
426
427 assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("template@foo.service"), false, &changes, &n_changes) >= 0);
428 assert_se(changes[0].type == UNIT_FILE_SYMLINK);
429 assert_se(streq(changes[0].source, "/usr/lib/systemd/system/template@.service"));
430 p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/template@foo.service");
431 assert_se(streq(changes[0].path, p));
432 unit_file_changes_free(changes, n_changes);
433 changes = NULL; n_changes = 0;
434
435 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
436 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
437 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@foo.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
438 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
439 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
440 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
441
442 assert_se(unit_file_disable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("template@foo.service"), &changes, &n_changes) >= 0);
443 assert_se(n_changes == 1);
444 assert_se(changes[0].type == UNIT_FILE_UNLINK);
445 assert_se(streq(changes[0].path, p));
446 unit_file_changes_free(changes, n_changes);
447 changes = NULL; n_changes = 0;
448
449 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
450 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
451 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
452 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@quux.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
453 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
454 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
455 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
456 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@quux.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
457
458 assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("template-symlink@quux.service"), false, &changes, &n_changes) >= 0);
459 assert_se(changes[0].type == UNIT_FILE_SYMLINK);
460 assert_se(streq(changes[0].source, "/usr/lib/systemd/system/template@.service"));
461 p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/template@quux.service");
462 assert_se(streq(changes[0].path, p));
463 unit_file_changes_free(changes, n_changes);
464 changes = NULL; n_changes = 0;
465
466 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
467 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
468 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
469 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@quux.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
470 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
471 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
472 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
473 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@quux.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
474 }
475
476 static void test_indirect(const char *root) {
477 UnitFileChange *changes = NULL;
478 unsigned n_changes = 0;
479 UnitFileState state;
480 const char *p;
481
482 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirecta.service", &state) == -ENOENT);
483 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectb.service", &state) == -ENOENT);
484 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectc.service", &state) == -ENOENT);
485
486 p = strjoina(root, "/usr/lib/systemd/system/indirecta.service");
487 assert_se(write_string_file(p,
488 "[Install]\n"
489 "Also=indirectb.service\n", WRITE_STRING_FILE_CREATE) >= 0);
490
491 p = strjoina(root, "/usr/lib/systemd/system/indirectb.service");
492 assert_se(write_string_file(p,
493 "[Install]\n"
494 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE) >= 0);
495
496 p = strjoina(root, "/usr/lib/systemd/system/indirectc.service");
497 assert_se(symlink("indirecta.service", p) >= 0);
498
499 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirecta.service", &state) >= 0 && state == UNIT_FILE_INDIRECT);
500 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectb.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
501 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectc.service", &state) >= 0 && state == UNIT_FILE_INDIRECT);
502
503 assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("indirectc.service"), false, &changes, &n_changes) >= 0);
504 assert_se(n_changes == 1);
505 assert_se(changes[0].type == UNIT_FILE_SYMLINK);
506 assert_se(streq(changes[0].source, "/usr/lib/systemd/system/indirectb.service"));
507 p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/indirectb.service");
508 assert_se(streq(changes[0].path, p));
509 unit_file_changes_free(changes, n_changes);
510 changes = NULL; n_changes = 0;
511
512 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirecta.service", &state) >= 0 && state == UNIT_FILE_INDIRECT);
513 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectb.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
514 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectc.service", &state) >= 0 && state == UNIT_FILE_INDIRECT);
515
516 assert_se(unit_file_disable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("indirectc.service"), &changes, &n_changes) >= 0);
517 assert_se(n_changes == 1);
518 assert_se(changes[0].type == UNIT_FILE_UNLINK);
519 p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/indirectb.service");
520 assert_se(streq(changes[0].path, p));
521 unit_file_changes_free(changes, n_changes);
522 changes = NULL; n_changes = 0;
523 }
524
525 static void test_preset_and_list(const char *root) {
526 UnitFileChange *changes = NULL;
527 unsigned n_changes = 0, i;
528 const char *p, *q;
529 UnitFileState state;
530 bool got_yes = false, got_no = false;
531 Iterator j;
532 UnitFileList *fl;
533 Hashmap *h;
534
535 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-yes.service", &state) == -ENOENT);
536 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-no.service", &state) == -ENOENT);
537
538 p = strjoina(root, "/usr/lib/systemd/system/preset-yes.service");
539 assert_se(write_string_file(p,
540 "[Install]\n"
541 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE) >= 0);
542
543 p = strjoina(root, "/usr/lib/systemd/system/preset-no.service");
544 assert_se(write_string_file(p,
545 "[Install]\n"
546 "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE) >= 0);
547
548 p = strjoina(root, "/usr/lib/systemd/system-preset/test.preset");
549 assert_se(write_string_file(p,
550 "enable *-yes.*\n"
551 "disable *\n", WRITE_STRING_FILE_CREATE) >= 0);
552
553 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-yes.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
554 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-no.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
555
556 assert_se(unit_file_preset(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("preset-yes.service"), UNIT_FILE_PRESET_FULL, false, &changes, &n_changes) >= 0);
557 assert_se(n_changes == 1);
558 assert_se(changes[0].type == UNIT_FILE_SYMLINK);
559 assert_se(streq(changes[0].source, "/usr/lib/systemd/system/preset-yes.service"));
560 p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/preset-yes.service");
561 assert_se(streq(changes[0].path, p));
562 unit_file_changes_free(changes, n_changes);
563 changes = NULL; n_changes = 0;
564
565 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-yes.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
566 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-no.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
567
568 assert_se(unit_file_disable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("preset-yes.service"), &changes, &n_changes) >= 0);
569 assert_se(n_changes == 1);
570 assert_se(changes[0].type == UNIT_FILE_UNLINK);
571 p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/preset-yes.service");
572 assert_se(streq(changes[0].path, p));
573 unit_file_changes_free(changes, n_changes);
574 changes = NULL; n_changes = 0;
575
576 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-yes.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
577 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-no.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
578
579 assert_se(unit_file_preset(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("preset-no.service"), UNIT_FILE_PRESET_FULL, false, &changes, &n_changes) >= 0);
580 assert_se(n_changes == 0);
581 unit_file_changes_free(changes, n_changes);
582 changes = NULL; n_changes = 0;
583
584 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-yes.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
585 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-no.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
586
587 assert_se(unit_file_preset_all(UNIT_FILE_SYSTEM, false, root, UNIT_FILE_PRESET_FULL, false, &changes, &n_changes) >= 0);
588
589 assert_se(n_changes > 0);
590
591 p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/preset-yes.service");
592
593 for (i = 0; i < n_changes; i++) {
594
595 if (changes[i].type == UNIT_FILE_SYMLINK) {
596 assert_se(streq(changes[i].source, "/usr/lib/systemd/system/preset-yes.service"));
597 assert_se(streq(changes[i].path, p));
598 } else
599 assert_se(changes[i].type == UNIT_FILE_UNLINK);
600 }
601
602 unit_file_changes_free(changes, n_changes);
603 changes = NULL; n_changes = 0;
604
605 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-yes.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
606 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-no.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
607
608 assert_se(h = hashmap_new(&string_hash_ops));
609 assert_se(unit_file_get_list(UNIT_FILE_SYSTEM, root, h) >= 0);
610
611 p = strjoina(root, "/usr/lib/systemd/system/preset-yes.service");
612 q = strjoina(root, "/usr/lib/systemd/system/preset-no.service");
613
614 HASHMAP_FOREACH(fl, h, j) {
615 assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, basename(fl->path), &state) >= 0);
616 assert_se(fl->state == state);
617
618 if (streq(fl->path, p)) {
619 got_yes = true;
620 assert_se(fl->state == UNIT_FILE_ENABLED);
621 } else if (streq(fl->path, q)) {
622 got_no = true;
623 assert_se(fl->state == UNIT_FILE_DISABLED);
624 } else
625 assert_se(IN_SET(fl->state, UNIT_FILE_DISABLED, UNIT_FILE_STATIC, UNIT_FILE_INDIRECT));
626 }
627
628 unit_file_list_free(h);
629
630 assert_se(got_yes && got_no);
631 }
632
633 int main(int argc, char *argv[]) {
634 char root[] = "/tmp/rootXXXXXX";
635 const char *p;
636
637 assert_se(mkdtemp(root));
638
639 p = strjoina(root, "/usr/lib/systemd/system/");
640 assert_se(mkdir_p(p, 0755) >= 0);
641
642 p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/");
643 assert_se(mkdir_p(p, 0755) >= 0);
644
645 p = strjoina(root, "/run/systemd/system/");
646 assert_se(mkdir_p(p, 0755) >= 0);
647
648 p = strjoina(root, "/opt/");
649 assert_se(mkdir_p(p, 0755) >= 0);
650
651 p = strjoina(root, "/usr/lib/systemd/system-preset/");
652 assert_se(mkdir_p(p, 0755) >= 0);
653
654 test_basic_mask_and_enable(root);
655 test_linked_units(root);
656 test_default(root);
657 test_add_dependency(root);
658 test_template_enable(root);
659 test_indirect(root);
660 test_preset_and_list(root);
661
662 assert_se(rm_rf(root, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
663
664 return 0;
665 }