]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/generator.c
Merge pull request #11827 from keszybz/pkgconfig-variables
[thirdparty/systemd.git] / src / shared / generator.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
e48fdd84 2
a8fbdf54 3#include <errno.h>
fb883e75 4#include <stdio_ext.h>
e48fdd84
LP
5#include <unistd.h>
6
b5efdb8a 7#include "alloc-util.h"
4f5dd394
LP
8#include "dropin.h"
9#include "escape.h"
3ffd4af2 10#include "fd-util.h"
4f5dd394
LP
11#include "fileio.h"
12#include "fstab-util.h"
3ffd4af2 13#include "generator.h"
a8fbdf54
TA
14#include "log.h"
15#include "macro.h"
e48fdd84 16#include "mkdir.h"
4f5dd394
LP
17#include "path-util.h"
18#include "special.h"
98bad05e 19#include "specifier.h"
07630cea 20#include "string-util.h"
a8fbdf54 21#include "time-util.h"
e48fdd84 22#include "unit-name.h"
4f5dd394 23#include "util.h"
e48fdd84 24
fb883e75
ZJS
25int generator_open_unit_file(
26 const char *dest,
27 const char *source,
28 const char *name,
29 FILE **file) {
30
31 const char *unit;
32 FILE *f;
33
34 unit = strjoina(dest, "/", name);
35
36 f = fopen(unit, "wxe");
37 if (!f) {
38 if (source && errno == EEXIST)
39 return log_error_errno(errno,
40 "Failed to create unit file %s, as it already exists. Duplicate entry in %s?",
41 unit, source);
42 else
43 return log_error_errno(errno,
44 "Failed to create unit file %s: %m",
45 unit);
46 }
47
48 (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
49
50 fprintf(f,
51 "# Automatically generated by %s\n\n",
52 program_invocation_short_name);
53
54 *file = f;
55 return 0;
56}
57
5c176eb4
ZJS
58int generator_add_symlink(const char *dir, const char *dst, const char *dep_type, const char *src) {
59 /* Adds a symlink from <dst>.<dep_type>/ to <src> (if src is absolute)
60 * or ../<src> (otherwise). */
b559616f
ZJS
61
62 const char *from, *to;
63
5c176eb4
ZJS
64 from = path_is_absolute(src) ? src : strjoina("../", src);
65 to = strjoina(dir, "/", dst, ".", dep_type, "/", basename(src));
b559616f
ZJS
66
67 mkdir_parents_label(to, 0755);
68 if (symlink(from, to) < 0)
7f0cc637
ZJS
69 if (errno != EEXIST)
70 return log_error_errno(errno, "Failed to create symlink \"%s\": %m", to);
b559616f
ZJS
71
72 return 0;
73}
74
4dda4e63 75static int write_fsck_sysroot_service(const char *dir, const char *what) {
98bad05e 76 _cleanup_free_ char *device = NULL, *escaped = NULL, *escaped2 = NULL;
4dda4e63 77 _cleanup_fclose_ FILE *f = NULL;
85eca92e 78 const char *unit;
4dda4e63
ZJS
79 int r;
80
98bad05e 81 escaped = specifier_escape(what);
fa05e972
AB
82 if (!escaped)
83 return log_oom();
84
98bad05e
LP
85 escaped2 = cescape(escaped);
86 if (!escaped2)
87 return log_oom();
88
5ff8da10 89 unit = strjoina(dir, "/"SPECIAL_FSCK_ROOT_SERVICE);
4dda4e63
ZJS
90 log_debug("Creating %s", unit);
91
92 r = unit_name_from_path(what, ".device", &device);
93 if (r < 0)
94 return log_error_errno(r, "Failed to convert device \"%s\" to unit name: %m", what);
95
96 f = fopen(unit, "wxe");
97 if (!f)
98 return log_error_errno(errno, "Failed to create unit file %s: %m", unit);
99
100 fprintf(f,
101 "# Automatically generated by %1$s\n\n"
102 "[Unit]\n"
4dda4e63 103 "Description=File System Check on %2$s\n"
da495a03 104 "Documentation=man:systemd-fsck-root.service(8)\n"
4dda4e63
ZJS
105 "DefaultDependencies=no\n"
106 "BindsTo=%3$s\n"
ff9bf8d0 107 "Conflicts=shutdown.target\n"
0900593e 108 "After=initrd-root-device.target local-fs-pre.target %3$s\n"
4dda4e63
ZJS
109 "Before=shutdown.target\n"
110 "\n"
111 "[Service]\n"
112 "Type=oneshot\n"
113 "RemainAfterExit=yes\n"
fa05e972 114 "ExecStart=" SYSTEMD_FSCK_PATH " %4$s\n"
4dda4e63
ZJS
115 "TimeoutSec=0\n",
116 program_invocation_short_name,
98bad05e 117 escaped,
fa05e972 118 device,
98bad05e 119 escaped2);
4dda4e63 120
2929b4a6
LP
121 r = fflush_and_check(f);
122 if (r < 0)
123 return log_error_errno(r, "Failed to write unit file %s: %m", unit);
4dda4e63
ZJS
124
125 return 0;
126}
127
e48fdd84
LP
128int generator_write_fsck_deps(
129 FILE *f,
2e852276 130 const char *dir,
e48fdd84
LP
131 const char *what,
132 const char *where,
6db615c1 133 const char *fstype) {
e48fdd84 134
7410616c
LP
135 int r;
136
e48fdd84 137 assert(f);
2e852276 138 assert(dir);
6db615c1
LP
139 assert(what);
140 assert(where);
e48fdd84
LP
141
142 if (!is_device_path(what)) {
143 log_warning("Checking was requested for \"%s\", but it is not a device.", what);
144 return 0;
145 }
146
6db615c1 147 if (!isempty(fstype) && !streq(fstype, "auto")) {
eb66db55 148 r = fsck_exists(fstype);
85eca92e
LP
149 if (r < 0)
150 log_warning_errno(r, "Checking was requested for %s, but couldn't detect if fsck.%s may be used, proceeding: %m", what, fstype);
151 else if (r == 0) {
e48fdd84 152 /* treat missing check as essentially OK */
85eca92e 153 log_debug("Checking was requested for %s, but fsck.%s does not exist.", what, fstype);
571d0134 154 return 0;
85eca92e 155 }
e48fdd84
LP
156 }
157
2e852276 158 if (path_equal(where, "/")) {
85eca92e 159 const char *lnk;
e48fdd84 160
5ff8da10 161 lnk = strjoina(dir, "/" SPECIAL_LOCAL_FS_TARGET ".wants/"SPECIAL_FSCK_ROOT_SERVICE);
e48fdd84
LP
162
163 mkdir_parents(lnk, 0755);
5ff8da10 164 if (symlink(SYSTEM_DATA_UNIT_PATH "/"SPECIAL_FSCK_ROOT_SERVICE, lnk) < 0)
4a62c710 165 return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
e48fdd84
LP
166
167 } else {
4dda4e63
ZJS
168 _cleanup_free_ char *_fsck = NULL;
169 const char *fsck;
170
171 if (in_initrd() && path_equal(where, "/sysroot")) {
172 r = write_fsck_sysroot_service(dir, what);
173 if (r < 0)
174 return r;
175
5ff8da10 176 fsck = SPECIAL_FSCK_ROOT_SERVICE;
4dda4e63
ZJS
177 } else {
178 r = unit_name_from_path_instance("systemd-fsck", what, ".service", &_fsck);
179 if (r < 0)
180 return log_error_errno(r, "Failed to create fsck service name: %m");
181
182 fsck = _fsck;
183 }
e48fdd84
LP
184
185 fprintf(f,
f32b43bd 186 "Requires=%1$s\n"
2e852276 187 "After=%1$s\n",
e48fdd84
LP
188 fsck);
189 }
190
191 return 0;
192}
29686440 193
2e852276
ZJS
194int generator_write_timeouts(
195 const char *dir,
196 const char *what,
197 const char *where,
198 const char *opts,
199 char **filtered) {
29686440 200
c2f4bcfc
ZJS
201 /* Configure how long we wait for a device that backs a mount point or a
202 * swap partition to show up. This is useful to support endless device timeouts
203 * for devices that show up only after user input, like crypto devices. */
29686440 204
d15d0333 205 _cleanup_free_ char *node = NULL, *unit = NULL, *timeout = NULL;
29686440
ZJS
206 usec_t u;
207 int r;
29686440 208
0004f698
ZJS
209 r = fstab_filter_options(opts, "comment=systemd.device-timeout\0"
210 "x-systemd.device-timeout\0",
d15d0333
ZJS
211 NULL, &timeout, filtered);
212 if (r <= 0)
213 return r;
b3208b66 214
0004f698 215 r = parse_sec_fix_0(timeout, &u);
29686440 216 if (r < 0) {
7410616c 217 log_warning("Failed to parse timeout for %s, ignoring: %s", where, timeout);
29686440
ZJS
218 return 0;
219 }
220
221 node = fstab_node_to_udev_node(what);
222 if (!node)
223 return log_oom();
c67bd1f7
N
224 if (!is_device_path(node)) {
225 log_warning("x-systemd.device-timeout ignored for %s", what);
226 return 0;
227 }
29686440 228
7410616c
LP
229 r = unit_name_from_path(node, ".device", &unit);
230 if (r < 0)
231 return log_error_errno(r, "Failed to make unit name from path: %m");
29686440 232
8eea8687
ZJS
233 return write_drop_in_format(dir, unit, 50, "device-timeout",
234 "# Automatically generated by %s\n\n"
acd53eaa
LP
235 "[Unit]\n"
236 "JobRunningTimeoutSec=%s",
237 program_invocation_short_name,
238 timeout);
29686440 239}
7163e1ca 240
4195077a
MK
241int generator_write_device_deps(
242 const char *dir,
243 const char *what,
244 const char *where,
245 const char *opts) {
246
247 /* fstab records that specify _netdev option should apply the network
248 * ordering on the actual device depending on network connection. If we
249 * are not mounting real device (NFS, CIFS), we rely on _netdev effect
250 * on the mount unit itself. */
251
252 _cleanup_free_ char *node = NULL, *unit = NULL;
253 int r;
254
255 if (!fstab_test_option(opts, "_netdev\0"))
256 return 0;
257
258 node = fstab_node_to_udev_node(what);
259 if (!node)
260 return log_oom();
261
262 /* Nothing to apply dependencies to. */
263 if (!is_device_path(node))
264 return 0;
265
266 r = unit_name_from_path(node, ".device", &unit);
267 if (r < 0)
da495a03
ZJS
268 return log_error_errno(r, "Failed to make unit name from path \"%s\": %m",
269 node);
4195077a
MK
270
271 /* See mount_add_default_dependencies for explanation why we create such
272 * dependencies. */
273 return write_drop_in_format(dir, unit, 50, "netdev-dependencies",
274 "# Automatically generated by %s\n\n"
275 "[Unit]\n"
276 "After=" SPECIAL_NETWORK_ONLINE_TARGET " " SPECIAL_NETWORK_TARGET "\n"
277 "Wants=" SPECIAL_NETWORK_ONLINE_TARGET "\n",
278 program_invocation_short_name);
279}
280
7163e1ca
DD
281int generator_write_initrd_root_device_deps(const char *dir, const char *what) {
282 _cleanup_free_ char *unit = NULL;
283 int r;
284
285 r = unit_name_from_path(what, ".device", &unit);
286 if (r < 0)
da495a03
ZJS
287 return log_error_errno(r, "Failed to make unit name from path \"%s\": %m",
288 what);
7163e1ca
DD
289
290 return write_drop_in_format(dir, SPECIAL_INITRD_ROOT_DEVICE_TARGET, 50, "root-device",
291 "# Automatically generated by %s\n\n"
acd53eaa
LP
292 "[Unit]\n"
293 "Requires=%s\n"
294 "After=%s",
295 program_invocation_short_name,
296 unit,
297 unit);
7163e1ca 298}
da495a03
ZJS
299
300int generator_hook_up_mkswap(
301 const char *dir,
302 const char *what) {
303
304 _cleanup_free_ char *node = NULL, *unit = NULL, *escaped = NULL, *where_unit = NULL;
305 _cleanup_fclose_ FILE *f = NULL;
306 const char *unit_file;
307 int r;
308
309 node = fstab_node_to_udev_node(what);
310 if (!node)
311 return log_oom();
312
313 /* Nothing to work on. */
baaa35ad
ZJS
314 if (!is_device_path(node))
315 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
316 "Cannot format something that is not a device node: %s",
317 node);
da495a03
ZJS
318
319 r = unit_name_from_path_instance("systemd-mkswap", node, ".service", &unit);
320 if (r < 0)
321 return log_error_errno(r, "Failed to make unit instance name from path \"%s\": %m",
322 node);
323
324 unit_file = strjoina(dir, "/", unit);
325 log_debug("Creating %s", unit_file);
326
327 escaped = cescape(node);
328 if (!escaped)
329 return log_oom();
330
331 r = unit_name_from_path(what, ".swap", &where_unit);
332 if (r < 0)
333 return log_error_errno(r, "Failed to make unit name from path \"%s\": %m",
334 what);
335
336 f = fopen(unit_file, "wxe");
337 if (!f)
338 return log_error_errno(errno, "Failed to create unit file %s: %m",
339 unit_file);
340
341 fprintf(f,
342 "# Automatically generated by %s\n\n"
343 "[Unit]\n"
344 "Description=Make Swap on %%f\n"
345 "Documentation=man:systemd-mkswap@.service(8)\n"
346 "DefaultDependencies=no\n"
347 "BindsTo=%%i.device\n"
ff9bf8d0 348 "Conflicts=shutdown.target\n"
da495a03 349 "After=%%i.device\n"
ff9bf8d0 350 "Before=shutdown.target %s\n"
da495a03
ZJS
351 "\n"
352 "[Service]\n"
353 "Type=oneshot\n"
354 "RemainAfterExit=yes\n"
355 "ExecStart="SYSTEMD_MAKEFS_PATH " swap %s\n"
356 "TimeoutSec=0\n",
357 program_invocation_short_name,
358 where_unit,
359 escaped);
360
361 r = fflush_and_check(f);
362 if (r < 0)
363 return log_error_errno(r, "Failed to write unit file %s: %m", unit_file);
364
365 return generator_add_symlink(dir, where_unit, "requires", unit);
366}
367
368int generator_hook_up_mkfs(
369 const char *dir,
370 const char *what,
371 const char *where,
372 const char *type) {
373
374 _cleanup_free_ char *node = NULL, *unit = NULL, *escaped = NULL, *where_unit = NULL;
375 _cleanup_fclose_ FILE *f = NULL;
376 const char *unit_file;
377 int r;
378
379 node = fstab_node_to_udev_node(what);
380 if (!node)
381 return log_oom();
382
383 /* Nothing to work on. */
baaa35ad
ZJS
384 if (!is_device_path(node))
385 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
386 "Cannot format something that is not a device node: %s",
387 node);
da495a03 388
baaa35ad
ZJS
389 if (!type || streq(type, "auto"))
390 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
391 "Cannot format partition %s, filesystem type is not specified",
392 node);
da495a03 393
804f8e17 394 r = unit_name_from_path_instance("systemd-makefs", node, ".service", &unit);
da495a03
ZJS
395 if (r < 0)
396 return log_error_errno(r, "Failed to make unit instance name from path \"%s\": %m",
397 node);
398
399 unit_file = strjoina(dir, "/", unit);
400 log_debug("Creating %s", unit_file);
401
402 escaped = cescape(node);
403 if (!escaped)
404 return log_oom();
405
406 r = unit_name_from_path(where, ".mount", &where_unit);
407 if (r < 0)
408 return log_error_errno(r, "Failed to make unit name from path \"%s\": %m",
409 where);
410
411 f = fopen(unit_file, "wxe");
412 if (!f)
413 return log_error_errno(errno, "Failed to create unit file %s: %m",
414 unit_file);
415
416 fprintf(f,
417 "# Automatically generated by %s\n\n"
418 "[Unit]\n"
419 "Description=Make File System on %%f\n"
804f8e17 420 "Documentation=man:systemd-makefs@.service(8)\n"
da495a03
ZJS
421 "DefaultDependencies=no\n"
422 "BindsTo=%%i.device\n"
ff9bf8d0 423 "Conflicts=shutdown.target\n"
da495a03
ZJS
424 "After=%%i.device\n"
425 /* fsck might or might not be used, so let's be safe and order
426 * ourselves before both systemd-fsck@.service and the mount unit. */
ff9bf8d0 427 "Before=shutdown.target systemd-fsck@%%i.service %s\n"
da495a03
ZJS
428 "\n"
429 "[Service]\n"
430 "Type=oneshot\n"
431 "RemainAfterExit=yes\n"
432 "ExecStart="SYSTEMD_MAKEFS_PATH " %s %s\n"
433 "TimeoutSec=0\n",
434 program_invocation_short_name,
435 where_unit,
436 type,
437 escaped);
438 // XXX: what about local-fs-pre.target?
439
440 r = fflush_and_check(f);
441 if (r < 0)
442 return log_error_errno(r, "Failed to write unit file %s: %m", unit_file);
443
444 return generator_add_symlink(dir, where_unit, "requires", unit);
445}
7f2806d5
ZJS
446
447int generator_hook_up_growfs(
448 const char *dir,
449 const char *where,
450 const char *target) {
451
452 _cleanup_free_ char *unit = NULL, *escaped = NULL, *where_unit = NULL;
453 _cleanup_fclose_ FILE *f = NULL;
454 const char *unit_file;
455 int r;
456
457 escaped = cescape(where);
458 if (!escaped)
459 return log_oom();
460
461 r = unit_name_from_path_instance("systemd-growfs", where, ".service", &unit);
462 if (r < 0)
463 return log_error_errno(r, "Failed to make unit instance name from path \"%s\": %m",
464 where);
465
466 r = unit_name_from_path(where, ".mount", &where_unit);
467 if (r < 0)
468 return log_error_errno(r, "Failed to make unit name from path \"%s\": %m",
469 where);
470
471 unit_file = strjoina(dir, "/", unit);
472 log_debug("Creating %s", unit_file);
473
474 f = fopen(unit_file, "wxe");
475 if (!f)
476 return log_error_errno(errno, "Failed to create unit file %s: %m",
477 unit_file);
478
479 fprintf(f,
480 "# Automatically generated by %s\n\n"
481 "[Unit]\n"
482 "Description=Grow File System on %%f\n"
483 "Documentation=man:systemd-growfs@.service(8)\n"
484 "DefaultDependencies=no\n"
485 "BindsTo=%%i.mount\n"
ff9bf8d0 486 "Conflicts=shutdown.target\n"
7f2806d5 487 "After=%%i.mount\n"
ff9bf8d0 488 "Before=shutdown.target %s\n"
7f2806d5
ZJS
489 "\n"
490 "[Service]\n"
491 "Type=oneshot\n"
492 "RemainAfterExit=yes\n"
493 "ExecStart="SYSTEMD_GROWFS_PATH " %s\n"
494 "TimeoutSec=0\n",
495 program_invocation_short_name,
496 target,
497 escaped);
498
499 return generator_add_symlink(dir, where_unit, "wants", unit);
500}
afe44c8f 501
9b69569d
ZJS
502int generator_enable_remount_fs_service(const char *dir) {
503 /* Pull in systemd-remount-fs.service */
504 return generator_add_symlink(dir, SPECIAL_LOCAL_FS_TARGET, "wants",
505 SYSTEM_DATA_UNIT_PATH "/" SPECIAL_REMOUNT_FS_SERVICE);
506}
507
afe44c8f
LP
508void log_setup_generator(void) {
509 log_set_prohibit_ipc(true);
6bf3c61c 510 log_setup_service();
afe44c8f 511}