]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/generator.c
gpt-auto-generator: use our usual ret_xyz parameter naming
[thirdparty/systemd.git] / src / shared / generator.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
e48fdd84 2
a8fbdf54 3#include <errno.h>
e48fdd84
LP
4#include <unistd.h>
5
b5efdb8a 6#include "alloc-util.h"
dee29aeb 7#include "cgroup-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"
35cd0ba5 16#include "mkdir-label.h"
4f5dd394 17#include "path-util.h"
911017f0 18#include "process-util.h"
4f5dd394 19#include "special.h"
98bad05e 20#include "specifier.h"
07630cea 21#include "string-util.h"
a8fbdf54 22#include "time-util.h"
e48fdd84 23#include "unit-name.h"
4f5dd394 24#include "util.h"
e48fdd84 25
fb883e75
ZJS
26int generator_open_unit_file(
27 const char *dest,
28 const char *source,
29 const char *name,
30 FILE **file) {
31
8e7e4a73 32 _cleanup_free_ char *unit = NULL;
fb883e75 33 FILE *f;
41f6e627 34 int r;
fb883e75 35
8e7e4a73
LP
36 unit = path_join(dest, name);
37 if (!unit)
38 return log_oom();
fb883e75 39
41f6e627
ZJS
40 r = fopen_unlocked(unit, "wxe", &f);
41 if (r < 0) {
42 if (source && r == -EEXIST)
43 return log_error_errno(r,
fb883e75
ZJS
44 "Failed to create unit file %s, as it already exists. Duplicate entry in %s?",
45 unit, source);
46 else
41f6e627 47 return log_error_errno(r,
fb883e75
ZJS
48 "Failed to create unit file %s: %m",
49 unit);
50 }
51
fb883e75
ZJS
52 fprintf(f,
53 "# Automatically generated by %s\n\n",
54 program_invocation_short_name);
55
56 *file = f;
57 return 0;
58}
59
5c176eb4
ZJS
60int generator_add_symlink(const char *dir, const char *dst, const char *dep_type, const char *src) {
61 /* Adds a symlink from <dst>.<dep_type>/ to <src> (if src is absolute)
62 * or ../<src> (otherwise). */
b559616f
ZJS
63
64 const char *from, *to;
65
5c176eb4
ZJS
66 from = path_is_absolute(src) ? src : strjoina("../", src);
67 to = strjoina(dir, "/", dst, ".", dep_type, "/", basename(src));
b559616f 68
35cd0ba5 69 (void) mkdir_parents_label(to, 0755);
b559616f 70 if (symlink(from, to) < 0)
7f0cc637
ZJS
71 if (errno != EEXIST)
72 return log_error_errno(errno, "Failed to create symlink \"%s\": %m", to);
b559616f
ZJS
73
74 return 0;
75}
76
2b66f48e
LP
77static int write_fsck_sysroot_service(
78 const char *unit, /* Either SPECIAL_FSCK_ROOT_SERVICE or SPECIAL_FSCK_USR_SERVICE */
79 const char *dir,
80 const char *what,
81 const char *extra_after) {
82
98bad05e 83 _cleanup_free_ char *device = NULL, *escaped = NULL, *escaped2 = NULL;
4dda4e63 84 _cleanup_fclose_ FILE *f = NULL;
2b66f48e 85 const char *fn;
4dda4e63
ZJS
86 int r;
87
2b66f48e
LP
88 /* Writes out special versions of systemd-root-fsck.service and systemd-usr-fsck.service for use in
89 * the initrd. The regular statically shipped versions of these unit files use / and /usr for as
90 * paths, which doesn't match what we need for the initrd (where the dirs are /sysroot +
91 * /sysusr/usr), hence we overwrite those versions here. */
92
98bad05e 93 escaped = specifier_escape(what);
fa05e972
AB
94 if (!escaped)
95 return log_oom();
96
98bad05e
LP
97 escaped2 = cescape(escaped);
98 if (!escaped2)
99 return log_oom();
100
2b66f48e
LP
101 fn = strjoina(dir, "/", unit);
102 log_debug("Creating %s", fn);
4dda4e63
ZJS
103
104 r = unit_name_from_path(what, ".device", &device);
105 if (r < 0)
106 return log_error_errno(r, "Failed to convert device \"%s\" to unit name: %m", what);
107
2b66f48e 108 f = fopen(fn, "wxe");
4dda4e63 109 if (!f)
2b66f48e 110 return log_error_errno(errno, "Failed to create unit file %s: %m", fn);
4dda4e63
ZJS
111
112 fprintf(f,
113 "# Automatically generated by %1$s\n\n"
114 "[Unit]\n"
4dda4e63 115 "Description=File System Check on %2$s\n"
2b66f48e 116 "Documentation=man:%3$s(8)\n"
4dda4e63 117 "DefaultDependencies=no\n"
2b66f48e 118 "BindsTo=%4$s\n"
ff9bf8d0 119 "Conflicts=shutdown.target\n"
2b66f48e 120 "After=%5$s%6$slocal-fs-pre.target %4$s\n"
4dda4e63
ZJS
121 "Before=shutdown.target\n"
122 "\n"
123 "[Service]\n"
124 "Type=oneshot\n"
125 "RemainAfterExit=yes\n"
2b66f48e 126 "ExecStart=" SYSTEMD_FSCK_PATH " %7$s\n"
4dda4e63
ZJS
127 "TimeoutSec=0\n",
128 program_invocation_short_name,
98bad05e 129 escaped,
2b66f48e 130 unit,
fa05e972 131 device,
2b66f48e
LP
132 strempty(extra_after),
133 isempty(extra_after) ? "" : " ",
98bad05e 134 escaped2);
4dda4e63 135
2929b4a6
LP
136 r = fflush_and_check(f);
137 if (r < 0)
2b66f48e 138 return log_error_errno(r, "Failed to write unit file %s: %m", fn);
4dda4e63
ZJS
139
140 return 0;
141}
142
e48fdd84
LP
143int generator_write_fsck_deps(
144 FILE *f,
2e852276 145 const char *dir,
e48fdd84
LP
146 const char *what,
147 const char *where,
6db615c1 148 const char *fstype) {
e48fdd84 149
7410616c
LP
150 int r;
151
e48fdd84 152 assert(f);
2e852276 153 assert(dir);
6db615c1
LP
154 assert(what);
155 assert(where);
e48fdd84 156
122860f1
LP
157 /* Let's do an early exit if we are invoked for the root and /usr/ trees in the initrd, to avoid
158 * generating confusing log messages */
159 if (in_initrd() && PATH_IN_SET(where, "/", "/usr")) {
160 log_debug("Skipping fsck for %s in initrd.", where);
161 return 0;
162 }
163
e48fdd84
LP
164 if (!is_device_path(what)) {
165 log_warning("Checking was requested for \"%s\", but it is not a device.", what);
166 return 0;
167 }
168
6db615c1 169 if (!isempty(fstype) && !streq(fstype, "auto")) {
13556724 170 r = fsck_exists_for_fstype(fstype);
85eca92e
LP
171 if (r < 0)
172 log_warning_errno(r, "Checking was requested for %s, but couldn't detect if fsck.%s may be used, proceeding: %m", what, fstype);
173 else if (r == 0) {
e48fdd84 174 /* treat missing check as essentially OK */
85eca92e 175 log_debug("Checking was requested for %s, but fsck.%s does not exist.", what, fstype);
571d0134 176 return 0;
85eca92e 177 }
13556724
JK
178 } else {
179 r = fsck_exists();
180 if (r < 0)
181 log_warning_errno(r, "Checking was requested for %s, but couldn't detect if the fsck command may be used, proceeding: %m", what);
182 else if (r == 0) {
183 /* treat missing fsck as essentially OK */
184 log_debug("Checking was requested for %s, but the fsck command does not exist.", what);
185 return 0;
186 }
e48fdd84
LP
187 }
188
2e852276 189 if (path_equal(where, "/")) {
85eca92e 190 const char *lnk;
e48fdd84 191
599aee40
LP
192 /* We support running the fsck instance for the root fs while it is already mounted, for
193 * compatibility with non-initrd boots. It's ugly, but it is how it is. Since – unlike for
194 * regular file systems – this means the ordering is reversed (i.e. mount *before* fsck) we
195 * have a separate fsck unit for this, independent of systemd-fsck@.service. */
196
cbdc9cfe 197 lnk = strjoina(dir, "/" SPECIAL_LOCAL_FS_TARGET ".wants/" SPECIAL_FSCK_ROOT_SERVICE);
e48fdd84 198
37dc34f7 199 (void) mkdir_parents(lnk, 0755);
835cf75a 200 if (symlink(SYSTEM_DATA_UNIT_DIR "/" SPECIAL_FSCK_ROOT_SERVICE, lnk) < 0)
4a62c710 201 return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
e48fdd84
LP
202
203 } else {
4dda4e63 204 _cleanup_free_ char *_fsck = NULL;
afacf3fc 205 const char *fsck, *dep;
4dda4e63
ZJS
206
207 if (in_initrd() && path_equal(where, "/sysroot")) {
2b66f48e 208 r = write_fsck_sysroot_service(SPECIAL_FSCK_ROOT_SERVICE, dir, what, SPECIAL_INITRD_ROOT_DEVICE_TARGET);
4dda4e63
ZJS
209 if (r < 0)
210 return r;
211
5ff8da10 212 fsck = SPECIAL_FSCK_ROOT_SERVICE;
afacf3fc 213 dep = "Requires";
2b66f48e
LP
214
215 } else if (in_initrd() && path_equal(where, "/sysusr/usr")) {
216 r = write_fsck_sysroot_service(SPECIAL_FSCK_USR_SERVICE, dir, what, NULL);
217 if (r < 0)
218 return r;
219
220 fsck = SPECIAL_FSCK_USR_SERVICE;
221 dep = "Requires";
4dda4e63 222 } else {
afacf3fc
LP
223 /* When this is /usr, then let's add a Wants= dependency, otherwise a Requires=
224 * dependency. Why? We can't possibly unmount /usr during shutdown, but if we have a
225 * Requires= from /usr onto a fsck@.service unit and that unit is shut down, then
226 * we'd have to unmount /usr too. */
227
122860f1 228 dep = path_equal(where, "/usr") ? "Wants" : "Requires";
afacf3fc 229
4dda4e63
ZJS
230 r = unit_name_from_path_instance("systemd-fsck", what, ".service", &_fsck);
231 if (r < 0)
232 return log_error_errno(r, "Failed to create fsck service name: %m");
233
234 fsck = _fsck;
235 }
e48fdd84
LP
236
237 fprintf(f,
afacf3fc
LP
238 "%1$s=%2$s\n"
239 "After=%2$s\n",
240 dep, fsck);
e48fdd84
LP
241 }
242
243 return 0;
244}
29686440 245
2e852276
ZJS
246int generator_write_timeouts(
247 const char *dir,
248 const char *what,
249 const char *where,
250 const char *opts,
251 char **filtered) {
29686440 252
c2f4bcfc
ZJS
253 /* Configure how long we wait for a device that backs a mount point or a
254 * swap partition to show up. This is useful to support endless device timeouts
255 * for devices that show up only after user input, like crypto devices. */
29686440 256
d15d0333 257 _cleanup_free_ char *node = NULL, *unit = NULL, *timeout = NULL;
29686440
ZJS
258 usec_t u;
259 int r;
29686440 260
0004f698
ZJS
261 r = fstab_filter_options(opts, "comment=systemd.device-timeout\0"
262 "x-systemd.device-timeout\0",
ff0c31bc 263 NULL, &timeout, NULL, filtered);
924f6503
ZJS
264 if (r < 0) {
265 log_warning_errno(r, "Failed to parse fstab options, ignoring: %m");
266 return 0;
267 }
268 if (r == 0)
269 return 0;
b3208b66 270
0004f698 271 r = parse_sec_fix_0(timeout, &u);
29686440 272 if (r < 0) {
7410616c 273 log_warning("Failed to parse timeout for %s, ignoring: %s", where, timeout);
29686440
ZJS
274 return 0;
275 }
276
277 node = fstab_node_to_udev_node(what);
278 if (!node)
279 return log_oom();
c67bd1f7
N
280 if (!is_device_path(node)) {
281 log_warning("x-systemd.device-timeout ignored for %s", what);
282 return 0;
283 }
29686440 284
7410616c
LP
285 r = unit_name_from_path(node, ".device", &unit);
286 if (r < 0)
287 return log_error_errno(r, "Failed to make unit name from path: %m");
29686440 288
8eea8687 289 return write_drop_in_format(dir, unit, 50, "device-timeout",
7cecc563
ZJS
290 "# Automatically generated by %s\n"
291 "# from supplied options \"%s\"\n\n"
acd53eaa
LP
292 "[Unit]\n"
293 "JobRunningTimeoutSec=%s",
294 program_invocation_short_name,
7cecc563 295 opts,
acd53eaa 296 timeout);
29686440 297}
7163e1ca 298
4195077a
MK
299int generator_write_device_deps(
300 const char *dir,
301 const char *what,
302 const char *where,
303 const char *opts) {
304
305 /* fstab records that specify _netdev option should apply the network
306 * ordering on the actual device depending on network connection. If we
307 * are not mounting real device (NFS, CIFS), we rely on _netdev effect
308 * on the mount unit itself. */
309
310 _cleanup_free_ char *node = NULL, *unit = NULL;
311 int r;
312
ad8f1b0f
FB
313 if (fstab_is_extrinsic(where, opts))
314 return 0;
315
4195077a
MK
316 if (!fstab_test_option(opts, "_netdev\0"))
317 return 0;
318
319 node = fstab_node_to_udev_node(what);
320 if (!node)
321 return log_oom();
322
323 /* Nothing to apply dependencies to. */
324 if (!is_device_path(node))
325 return 0;
326
327 r = unit_name_from_path(node, ".device", &unit);
328 if (r < 0)
da495a03
ZJS
329 return log_error_errno(r, "Failed to make unit name from path \"%s\": %m",
330 node);
4195077a
MK
331
332 /* See mount_add_default_dependencies for explanation why we create such
333 * dependencies. */
334 return write_drop_in_format(dir, unit, 50, "netdev-dependencies",
335 "# Automatically generated by %s\n\n"
336 "[Unit]\n"
337 "After=" SPECIAL_NETWORK_ONLINE_TARGET " " SPECIAL_NETWORK_TARGET "\n"
338 "Wants=" SPECIAL_NETWORK_ONLINE_TARGET "\n",
339 program_invocation_short_name);
340}
341
7163e1ca
DD
342int generator_write_initrd_root_device_deps(const char *dir, const char *what) {
343 _cleanup_free_ char *unit = NULL;
344 int r;
345
346 r = unit_name_from_path(what, ".device", &unit);
347 if (r < 0)
da495a03
ZJS
348 return log_error_errno(r, "Failed to make unit name from path \"%s\": %m",
349 what);
7163e1ca
DD
350
351 return write_drop_in_format(dir, SPECIAL_INITRD_ROOT_DEVICE_TARGET, 50, "root-device",
352 "# Automatically generated by %s\n\n"
acd53eaa
LP
353 "[Unit]\n"
354 "Requires=%s\n"
355 "After=%s",
356 program_invocation_short_name,
357 unit,
358 unit);
7163e1ca 359}
da495a03
ZJS
360
361int generator_hook_up_mkswap(
362 const char *dir,
363 const char *what) {
364
365 _cleanup_free_ char *node = NULL, *unit = NULL, *escaped = NULL, *where_unit = NULL;
8e7e4a73 366 _cleanup_free_ char *unit_file = NULL;
da495a03 367 _cleanup_fclose_ FILE *f = NULL;
da495a03
ZJS
368 int r;
369
370 node = fstab_node_to_udev_node(what);
371 if (!node)
372 return log_oom();
373
374 /* Nothing to work on. */
baaa35ad
ZJS
375 if (!is_device_path(node))
376 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
377 "Cannot format something that is not a device node: %s",
378 node);
da495a03
ZJS
379
380 r = unit_name_from_path_instance("systemd-mkswap", node, ".service", &unit);
381 if (r < 0)
382 return log_error_errno(r, "Failed to make unit instance name from path \"%s\": %m",
383 node);
384
8e7e4a73
LP
385 unit_file = path_join(dir, unit);
386 if (!unit_file)
387 return log_oom();
388
da495a03
ZJS
389 log_debug("Creating %s", unit_file);
390
391 escaped = cescape(node);
392 if (!escaped)
393 return log_oom();
394
395 r = unit_name_from_path(what, ".swap", &where_unit);
396 if (r < 0)
397 return log_error_errno(r, "Failed to make unit name from path \"%s\": %m",
398 what);
399
400 f = fopen(unit_file, "wxe");
401 if (!f)
402 return log_error_errno(errno, "Failed to create unit file %s: %m",
403 unit_file);
404
405 fprintf(f,
406 "# Automatically generated by %s\n\n"
407 "[Unit]\n"
408 "Description=Make Swap on %%f\n"
409 "Documentation=man:systemd-mkswap@.service(8)\n"
410 "DefaultDependencies=no\n"
411 "BindsTo=%%i.device\n"
ff9bf8d0 412 "Conflicts=shutdown.target\n"
da495a03 413 "After=%%i.device\n"
ff9bf8d0 414 "Before=shutdown.target %s\n"
da495a03
ZJS
415 "\n"
416 "[Service]\n"
417 "Type=oneshot\n"
418 "RemainAfterExit=yes\n"
419 "ExecStart="SYSTEMD_MAKEFS_PATH " swap %s\n"
420 "TimeoutSec=0\n",
421 program_invocation_short_name,
422 where_unit,
423 escaped);
424
425 r = fflush_and_check(f);
426 if (r < 0)
427 return log_error_errno(r, "Failed to write unit file %s: %m", unit_file);
428
429 return generator_add_symlink(dir, where_unit, "requires", unit);
430}
431
432int generator_hook_up_mkfs(
433 const char *dir,
434 const char *what,
435 const char *where,
436 const char *type) {
437
8e7e4a73 438 _cleanup_free_ char *node = NULL, *unit = NULL, *unit_file = NULL, *escaped = NULL, *where_unit = NULL;
da495a03 439 _cleanup_fclose_ FILE *f = NULL;
da495a03
ZJS
440 int r;
441
442 node = fstab_node_to_udev_node(what);
443 if (!node)
444 return log_oom();
445
446 /* Nothing to work on. */
baaa35ad
ZJS
447 if (!is_device_path(node))
448 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
449 "Cannot format something that is not a device node: %s",
450 node);
da495a03 451
baaa35ad
ZJS
452 if (!type || streq(type, "auto"))
453 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
454 "Cannot format partition %s, filesystem type is not specified",
455 node);
da495a03 456
804f8e17 457 r = unit_name_from_path_instance("systemd-makefs", node, ".service", &unit);
da495a03
ZJS
458 if (r < 0)
459 return log_error_errno(r, "Failed to make unit instance name from path \"%s\": %m",
460 node);
461
8e7e4a73
LP
462 unit_file = path_join(dir, unit);
463 if (!unit_file)
464 return log_oom();
465
da495a03
ZJS
466 log_debug("Creating %s", unit_file);
467
468 escaped = cescape(node);
469 if (!escaped)
470 return log_oom();
471
472 r = unit_name_from_path(where, ".mount", &where_unit);
473 if (r < 0)
474 return log_error_errno(r, "Failed to make unit name from path \"%s\": %m",
475 where);
476
477 f = fopen(unit_file, "wxe");
478 if (!f)
479 return log_error_errno(errno, "Failed to create unit file %s: %m",
480 unit_file);
481
482 fprintf(f,
483 "# Automatically generated by %s\n\n"
484 "[Unit]\n"
485 "Description=Make File System on %%f\n"
804f8e17 486 "Documentation=man:systemd-makefs@.service(8)\n"
da495a03
ZJS
487 "DefaultDependencies=no\n"
488 "BindsTo=%%i.device\n"
ff9bf8d0 489 "Conflicts=shutdown.target\n"
da495a03
ZJS
490 "After=%%i.device\n"
491 /* fsck might or might not be used, so let's be safe and order
492 * ourselves before both systemd-fsck@.service and the mount unit. */
ff9bf8d0 493 "Before=shutdown.target systemd-fsck@%%i.service %s\n"
da495a03
ZJS
494 "\n"
495 "[Service]\n"
496 "Type=oneshot\n"
497 "RemainAfterExit=yes\n"
498 "ExecStart="SYSTEMD_MAKEFS_PATH " %s %s\n"
499 "TimeoutSec=0\n",
500 program_invocation_short_name,
501 where_unit,
502 type,
503 escaped);
504 // XXX: what about local-fs-pre.target?
505
506 r = fflush_and_check(f);
507 if (r < 0)
508 return log_error_errno(r, "Failed to write unit file %s: %m", unit_file);
509
510 return generator_add_symlink(dir, where_unit, "requires", unit);
511}
7f2806d5
ZJS
512
513int generator_hook_up_growfs(
514 const char *dir,
515 const char *where,
516 const char *target) {
517
8e7e4a73 518 _cleanup_free_ char *unit = NULL, *escaped = NULL, *where_unit = NULL, *unit_file = NULL;
7f2806d5 519 _cleanup_fclose_ FILE *f = NULL;
7f2806d5
ZJS
520 int r;
521
400c1e8f
LP
522 assert(dir);
523 assert(where);
524
7f2806d5
ZJS
525 escaped = cescape(where);
526 if (!escaped)
527 return log_oom();
528
529 r = unit_name_from_path_instance("systemd-growfs", where, ".service", &unit);
530 if (r < 0)
531 return log_error_errno(r, "Failed to make unit instance name from path \"%s\": %m",
532 where);
533
534 r = unit_name_from_path(where, ".mount", &where_unit);
535 if (r < 0)
536 return log_error_errno(r, "Failed to make unit name from path \"%s\": %m",
537 where);
538
8e7e4a73
LP
539 unit_file = path_join(dir, unit);
540 if (!unit_file)
541 return log_oom();
542
7f2806d5
ZJS
543 log_debug("Creating %s", unit_file);
544
545 f = fopen(unit_file, "wxe");
546 if (!f)
547 return log_error_errno(errno, "Failed to create unit file %s: %m",
548 unit_file);
549
550 fprintf(f,
551 "# Automatically generated by %s\n\n"
552 "[Unit]\n"
553 "Description=Grow File System on %%f\n"
554 "Documentation=man:systemd-growfs@.service(8)\n"
555 "DefaultDependencies=no\n"
556 "BindsTo=%%i.mount\n"
ff9bf8d0 557 "Conflicts=shutdown.target\n"
7b45d6b6 558 "After=systemd-repart.service %%i.mount\n"
400c1e8f 559 "Before=shutdown.target%s%s\n",
18e6e863 560 program_invocation_short_name,
400c1e8f
LP
561 target ? " " : "",
562 strempty(target));
18e6e863
LP
563
564 if (empty_or_root(where)) /* Make sure the root fs is actually writable before we resize it */
565 fprintf(f,
566 "After=systemd-remount-fs.service\n");
567
568 fprintf(f,
7f2806d5
ZJS
569 "\n"
570 "[Service]\n"
571 "Type=oneshot\n"
572 "RemainAfterExit=yes\n"
573 "ExecStart="SYSTEMD_GROWFS_PATH " %s\n"
574 "TimeoutSec=0\n",
7f2806d5
ZJS
575 escaped);
576
577 return generator_add_symlink(dir, where_unit, "wants", unit);
578}
afe44c8f 579
9b69569d
ZJS
580int generator_enable_remount_fs_service(const char *dir) {
581 /* Pull in systemd-remount-fs.service */
582 return generator_add_symlink(dir, SPECIAL_LOCAL_FS_TARGET, "wants",
835cf75a 583 SYSTEM_DATA_UNIT_DIR "/" SPECIAL_REMOUNT_FS_SERVICE);
9b69569d
ZJS
584}
585
a7e88558
LP
586int generator_write_blockdev_dependency(
587 FILE *f,
588 const char *what) {
589
590 _cleanup_free_ char *escaped = NULL;
591 int r;
592
593 assert(f);
594 assert(what);
595
596 if (!path_startswith(what, "/dev/"))
597 return 0;
598
599 r = unit_name_path_escape(what, &escaped);
600 if (r < 0)
601 return log_error_errno(r, "Failed to escape device node path %s: %m", what);
602
603 fprintf(f,
604 "After=blockdev@%s.target\n",
605 escaped);
606
607 return 0;
608}
609
610int generator_write_cryptsetup_unit_section(
611 FILE *f,
612 const char *source) {
613
614 assert(f);
615
616 fprintf(f,
617 "[Unit]\n"
618 "Description=Cryptography Setup for %%I\n"
619 "Documentation=man:crypttab(5) man:systemd-cryptsetup-generator(8) man:systemd-cryptsetup@.service(8)\n");
620
621 if (source)
622 fprintf(f, "SourcePath=%s\n", source);
623
624 fprintf(f,
625 "DefaultDependencies=no\n"
626 "IgnoreOnIsolate=true\n"
239952e8 627 "After=cryptsetup-pre.target systemd-udevd-kernel.socket\n"
a7e88558
LP
628 "Before=blockdev@dev-mapper-%%i.target\n"
629 "Wants=blockdev@dev-mapper-%%i.target\n");
630
631 return 0;
632}
633
634int generator_write_cryptsetup_service_section(
635 FILE *f,
636 const char *name,
637 const char *what,
b7de9651 638 const char *key_file,
a7e88558
LP
639 const char *options) {
640
b7de9651 641 _cleanup_free_ char *name_escaped = NULL, *what_escaped = NULL, *key_file_escaped = NULL, *options_escaped = NULL;
a7e88558
LP
642
643 assert(f);
644 assert(name);
645 assert(what);
646
647 name_escaped = specifier_escape(name);
648 if (!name_escaped)
649 return log_oom();
650
651 what_escaped = specifier_escape(what);
652 if (!what_escaped)
653 return log_oom();
654
b7de9651
JJ
655 if (key_file) {
656 key_file_escaped = specifier_escape(key_file);
657 if (!key_file_escaped)
a7e88558
LP
658 return log_oom();
659 }
660
661 if (options) {
662 options_escaped = specifier_escape(options);
663 if (!options_escaped)
664 return log_oom();
665 }
666
667 fprintf(f,
668 "\n"
669 "[Service]\n"
670 "Type=oneshot\n"
671 "RemainAfterExit=yes\n"
672 "TimeoutSec=0\n" /* The binary handles timeouts on its own */
673 "KeyringMode=shared\n" /* Make sure we can share cached keys among instances */
674 "OOMScoreAdjust=500\n" /* Unlocking can allocate a lot of memory if Argon2 is used */
675 "ExecStart=" SYSTEMD_CRYPTSETUP_PATH " attach '%s' '%s' '%s' '%s'\n"
676 "ExecStop=" SYSTEMD_CRYPTSETUP_PATH " detach '%s'\n",
b7de9651 677 name_escaped, what_escaped, strempty(key_file_escaped), strempty(options_escaped),
a7e88558
LP
678 name_escaped);
679
680 return 0;
681}
682
08b04ec7
GP
683int generator_write_veritysetup_unit_section(
684 FILE *f,
685 const char *source) {
686
687 assert(f);
688
689 fprintf(f,
690 "[Unit]\n"
691 "Description=Integrity Protection Setup for %%I\n"
692 "Documentation=man:veritytab(5) man:systemd-veritysetup-generator(8) man:systemd-veritysetup@.service(8)\n");
693
694 if (source)
695 fprintf(f, "SourcePath=%s\n", source);
696
697 fprintf(f,
698 "DefaultDependencies=no\n"
699 "IgnoreOnIsolate=true\n"
700 "After=cryptsetup-pre.target systemd-udevd-kernel.socket\n"
701 "Before=blockdev@dev-mapper-%%i.target\n"
702 "Wants=blockdev@dev-mapper-%%i.target\n");
703
704 return 0;
705}
706
707int generator_write_veritysetup_service_section(
708 FILE *f,
709 const char *name,
710 const char *data_what,
711 const char *hash_what,
712 const char *roothash,
713 const char *options) {
714
47237e0e 715 _cleanup_free_ char *name_escaped = NULL, *data_what_escaped = NULL, *hash_what_escaped = NULL,
08b04ec7
GP
716 *roothash_escaped = NULL, *options_escaped = NULL;
717
718 assert(f);
719 assert(name);
720 assert(data_what);
721 assert(hash_what);
722
723 name_escaped = specifier_escape(name);
724 if (!name_escaped)
725 return log_oom();
726
727 data_what_escaped = specifier_escape(data_what);
728 if (!data_what_escaped)
729 return log_oom();
730
731 hash_what_escaped = specifier_escape(hash_what);
732 if (!hash_what_escaped)
733 return log_oom();
734
735 roothash_escaped = specifier_escape(roothash);
736 if (!roothash_escaped)
737 return log_oom();
738
739 if (options) {
740 options_escaped = specifier_escape(options);
741 if (!options_escaped)
742 return log_oom();
743 }
744
745 fprintf(f,
746 "\n"
747 "[Service]\n"
748 "Type=oneshot\n"
749 "RemainAfterExit=yes\n"
750 "ExecStart=" SYSTEMD_VERITYSETUP_PATH " attach '%s' '%s' '%s' '%s' '%s'\n"
751 "ExecStop=" SYSTEMD_VERITYSETUP_PATH " detach '%s'\n",
752 name_escaped, data_what_escaped, hash_what_escaped, roothash_escaped, strempty(options_escaped),
753 name_escaped);
754
755 return 0;
756}
757
afe44c8f 758void log_setup_generator(void) {
911017f0
ZJS
759 if (invoked_by_systemd()) {
760 /* Disable talking to syslog/journal (i.e. the two IPC-based loggers) if we run in system context. */
761 if (cg_pid_get_owner_uid(0, NULL) == -ENXIO /* not running in a per-user slice */)
762 log_set_prohibit_ipc(true);
763
764 /* This effectively means: journal for per-user generators, kmsg otherwise */
765 log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
766 }
dee29aeb 767
dee29aeb
LP
768 log_parse_environment();
769 (void) log_open();
afe44c8f 770}