1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
6 #include "alloc-util.h"
7 #include "cgroup-util.h"
12 #include "fstab-util.h"
13 #include "generator.h"
16 #include "mkdir-label.h"
17 #include "path-util.h"
19 #include "specifier.h"
20 #include "string-util.h"
21 #include "time-util.h"
22 #include "unit-name.h"
25 int generator_open_unit_file(
35 unit
= prefix_roota(dest
, name
);
37 r
= fopen_unlocked(unit
, "wxe", &f
);
39 if (source
&& r
== -EEXIST
)
40 return log_error_errno(r
,
41 "Failed to create unit file %s, as it already exists. Duplicate entry in %s?",
44 return log_error_errno(r
,
45 "Failed to create unit file %s: %m",
50 "# Automatically generated by %s\n\n",
51 program_invocation_short_name
);
57 int generator_add_symlink(const char *dir
, const char *dst
, const char *dep_type
, const char *src
) {
58 /* Adds a symlink from <dst>.<dep_type>/ to <src> (if src is absolute)
59 * or ../<src> (otherwise). */
61 const char *from
, *to
;
63 from
= path_is_absolute(src
) ? src
: strjoina("../", src
);
64 to
= strjoina(dir
, "/", dst
, ".", dep_type
, "/", basename(src
));
66 (void) mkdir_parents_label(to
, 0755);
67 if (symlink(from
, to
) < 0)
69 return log_error_errno(errno
, "Failed to create symlink \"%s\": %m", to
);
74 static int write_fsck_sysroot_service(
75 const char *unit
, /* Either SPECIAL_FSCK_ROOT_SERVICE or SPECIAL_FSCK_USR_SERVICE */
78 const char *extra_after
) {
80 _cleanup_free_
char *device
= NULL
, *escaped
= NULL
, *escaped2
= NULL
;
81 _cleanup_fclose_
FILE *f
= NULL
;
85 /* Writes out special versions of systemd-root-fsck.service and systemd-usr-fsck.service for use in
86 * the initrd. The regular statically shipped versions of these unit files use / and /usr for as
87 * paths, which doesn't match what we need for the initrd (where the dirs are /sysroot +
88 * /sysusr/usr), hence we overwrite those versions here. */
90 escaped
= specifier_escape(what
);
94 escaped2
= cescape(escaped
);
98 fn
= strjoina(dir
, "/", unit
);
99 log_debug("Creating %s", fn
);
101 r
= unit_name_from_path(what
, ".device", &device
);
103 return log_error_errno(r
, "Failed to convert device \"%s\" to unit name: %m", what
);
105 f
= fopen(fn
, "wxe");
107 return log_error_errno(errno
, "Failed to create unit file %s: %m", fn
);
110 "# Automatically generated by %1$s\n\n"
112 "Description=File System Check on %2$s\n"
113 "Documentation=man:%3$s(8)\n"
114 "DefaultDependencies=no\n"
116 "Conflicts=shutdown.target\n"
117 "After=%5$s%6$slocal-fs-pre.target %4$s\n"
118 "Before=shutdown.target\n"
122 "RemainAfterExit=yes\n"
123 "ExecStart=" SYSTEMD_FSCK_PATH
" %7$s\n"
125 program_invocation_short_name
,
129 strempty(extra_after
),
130 isempty(extra_after
) ? "" : " ",
133 r
= fflush_and_check(f
);
135 return log_error_errno(r
, "Failed to write unit file %s: %m", fn
);
140 int generator_write_fsck_deps(
145 const char *fstype
) {
154 /* Let's do an early exit if we are invoked for the root and /usr/ trees in the initrd, to avoid
155 * generating confusing log messages */
156 if (in_initrd() && PATH_IN_SET(where
, "/", "/usr")) {
157 log_debug("Skipping fsck for %s in initrd.", where
);
161 if (!is_device_path(what
)) {
162 log_warning("Checking was requested for \"%s\", but it is not a device.", what
);
166 if (!isempty(fstype
) && !streq(fstype
, "auto")) {
167 r
= fsck_exists(fstype
);
169 log_warning_errno(r
, "Checking was requested for %s, but couldn't detect if fsck.%s may be used, proceeding: %m", what
, fstype
);
171 /* treat missing check as essentially OK */
172 log_debug("Checking was requested for %s, but fsck.%s does not exist.", what
, fstype
);
177 if (path_equal(where
, "/")) {
180 /* We support running the fsck instance for the root fs while it is already mounted, for
181 * compatibility with non-initrd boots. It's ugly, but it is how it is. Since – unlike for
182 * regular file systems – this means the ordering is reversed (i.e. mount *before* fsck) we
183 * have a separate fsck unit for this, independent of systemd-fsck@.service. */
185 lnk
= strjoina(dir
, "/" SPECIAL_LOCAL_FS_TARGET
".wants/" SPECIAL_FSCK_ROOT_SERVICE
);
187 (void) mkdir_parents(lnk
, 0755);
188 if (symlink(SYSTEM_DATA_UNIT_DIR
"/" SPECIAL_FSCK_ROOT_SERVICE
, lnk
) < 0)
189 return log_error_errno(errno
, "Failed to create symlink %s: %m", lnk
);
192 _cleanup_free_
char *_fsck
= NULL
;
193 const char *fsck
, *dep
;
195 if (in_initrd() && path_equal(where
, "/sysroot")) {
196 r
= write_fsck_sysroot_service(SPECIAL_FSCK_ROOT_SERVICE
, dir
, what
, SPECIAL_INITRD_ROOT_DEVICE_TARGET
);
200 fsck
= SPECIAL_FSCK_ROOT_SERVICE
;
203 } else if (in_initrd() && path_equal(where
, "/sysusr/usr")) {
204 r
= write_fsck_sysroot_service(SPECIAL_FSCK_USR_SERVICE
, dir
, what
, NULL
);
208 fsck
= SPECIAL_FSCK_USR_SERVICE
;
211 /* When this is /usr, then let's add a Wants= dependency, otherwise a Requires=
212 * dependency. Why? We can't possibly unmount /usr during shutdown, but if we have a
213 * Requires= from /usr onto a fsck@.service unit and that unit is shut down, then
214 * we'd have to unmount /usr too. */
216 dep
= path_equal(where
, "/usr") ? "Wants" : "Requires";
218 r
= unit_name_from_path_instance("systemd-fsck", what
, ".service", &_fsck
);
220 return log_error_errno(r
, "Failed to create fsck service name: %m");
234 int generator_write_timeouts(
241 /* Configure how long we wait for a device that backs a mount point or a
242 * swap partition to show up. This is useful to support endless device timeouts
243 * for devices that show up only after user input, like crypto devices. */
245 _cleanup_free_
char *node
= NULL
, *unit
= NULL
, *timeout
= NULL
;
249 r
= fstab_filter_options(opts
, "comment=systemd.device-timeout\0"
250 "x-systemd.device-timeout\0",
251 NULL
, &timeout
, NULL
, filtered
);
253 log_warning_errno(r
, "Failed to parse fstab options, ignoring: %m");
259 r
= parse_sec_fix_0(timeout
, &u
);
261 log_warning("Failed to parse timeout for %s, ignoring: %s", where
, timeout
);
265 node
= fstab_node_to_udev_node(what
);
268 if (!is_device_path(node
)) {
269 log_warning("x-systemd.device-timeout ignored for %s", what
);
273 r
= unit_name_from_path(node
, ".device", &unit
);
275 return log_error_errno(r
, "Failed to make unit name from path: %m");
277 return write_drop_in_format(dir
, unit
, 50, "device-timeout",
278 "# Automatically generated by %s\n"
279 "# from supplied options \"%s\"\n\n"
281 "JobRunningTimeoutSec=%s",
282 program_invocation_short_name
,
287 int generator_write_device_deps(
293 /* fstab records that specify _netdev option should apply the network
294 * ordering on the actual device depending on network connection. If we
295 * are not mounting real device (NFS, CIFS), we rely on _netdev effect
296 * on the mount unit itself. */
298 _cleanup_free_
char *node
= NULL
, *unit
= NULL
;
301 if (fstab_is_extrinsic(where
, opts
))
304 if (!fstab_test_option(opts
, "_netdev\0"))
307 node
= fstab_node_to_udev_node(what
);
311 /* Nothing to apply dependencies to. */
312 if (!is_device_path(node
))
315 r
= unit_name_from_path(node
, ".device", &unit
);
317 return log_error_errno(r
, "Failed to make unit name from path \"%s\": %m",
320 /* See mount_add_default_dependencies for explanation why we create such
322 return write_drop_in_format(dir
, unit
, 50, "netdev-dependencies",
323 "# Automatically generated by %s\n\n"
325 "After=" SPECIAL_NETWORK_ONLINE_TARGET
" " SPECIAL_NETWORK_TARGET
"\n"
326 "Wants=" SPECIAL_NETWORK_ONLINE_TARGET
"\n",
327 program_invocation_short_name
);
330 int generator_write_initrd_root_device_deps(const char *dir
, const char *what
) {
331 _cleanup_free_
char *unit
= NULL
;
334 r
= unit_name_from_path(what
, ".device", &unit
);
336 return log_error_errno(r
, "Failed to make unit name from path \"%s\": %m",
339 return write_drop_in_format(dir
, SPECIAL_INITRD_ROOT_DEVICE_TARGET
, 50, "root-device",
340 "# Automatically generated by %s\n\n"
344 program_invocation_short_name
,
349 int generator_hook_up_mkswap(
353 _cleanup_free_
char *node
= NULL
, *unit
= NULL
, *escaped
= NULL
, *where_unit
= NULL
;
354 _cleanup_fclose_
FILE *f
= NULL
;
355 const char *unit_file
;
358 node
= fstab_node_to_udev_node(what
);
362 /* Nothing to work on. */
363 if (!is_device_path(node
))
364 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
365 "Cannot format something that is not a device node: %s",
368 r
= unit_name_from_path_instance("systemd-mkswap", node
, ".service", &unit
);
370 return log_error_errno(r
, "Failed to make unit instance name from path \"%s\": %m",
373 unit_file
= prefix_roota(dir
, unit
);
374 log_debug("Creating %s", unit_file
);
376 escaped
= cescape(node
);
380 r
= unit_name_from_path(what
, ".swap", &where_unit
);
382 return log_error_errno(r
, "Failed to make unit name from path \"%s\": %m",
385 f
= fopen(unit_file
, "wxe");
387 return log_error_errno(errno
, "Failed to create unit file %s: %m",
391 "# Automatically generated by %s\n\n"
393 "Description=Make Swap on %%f\n"
394 "Documentation=man:systemd-mkswap@.service(8)\n"
395 "DefaultDependencies=no\n"
396 "BindsTo=%%i.device\n"
397 "Conflicts=shutdown.target\n"
399 "Before=shutdown.target %s\n"
403 "RemainAfterExit=yes\n"
404 "ExecStart="SYSTEMD_MAKEFS_PATH
" swap %s\n"
406 program_invocation_short_name
,
410 r
= fflush_and_check(f
);
412 return log_error_errno(r
, "Failed to write unit file %s: %m", unit_file
);
414 return generator_add_symlink(dir
, where_unit
, "requires", unit
);
417 int generator_hook_up_mkfs(
423 _cleanup_free_
char *node
= NULL
, *unit
= NULL
, *escaped
= NULL
, *where_unit
= NULL
;
424 _cleanup_fclose_
FILE *f
= NULL
;
425 const char *unit_file
;
428 node
= fstab_node_to_udev_node(what
);
432 /* Nothing to work on. */
433 if (!is_device_path(node
))
434 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
435 "Cannot format something that is not a device node: %s",
438 if (!type
|| streq(type
, "auto"))
439 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
440 "Cannot format partition %s, filesystem type is not specified",
443 r
= unit_name_from_path_instance("systemd-makefs", node
, ".service", &unit
);
445 return log_error_errno(r
, "Failed to make unit instance name from path \"%s\": %m",
448 unit_file
= prefix_roota(dir
, unit
);
449 log_debug("Creating %s", unit_file
);
451 escaped
= cescape(node
);
455 r
= unit_name_from_path(where
, ".mount", &where_unit
);
457 return log_error_errno(r
, "Failed to make unit name from path \"%s\": %m",
460 f
= fopen(unit_file
, "wxe");
462 return log_error_errno(errno
, "Failed to create unit file %s: %m",
466 "# Automatically generated by %s\n\n"
468 "Description=Make File System on %%f\n"
469 "Documentation=man:systemd-makefs@.service(8)\n"
470 "DefaultDependencies=no\n"
471 "BindsTo=%%i.device\n"
472 "Conflicts=shutdown.target\n"
474 /* fsck might or might not be used, so let's be safe and order
475 * ourselves before both systemd-fsck@.service and the mount unit. */
476 "Before=shutdown.target systemd-fsck@%%i.service %s\n"
480 "RemainAfterExit=yes\n"
481 "ExecStart="SYSTEMD_MAKEFS_PATH
" %s %s\n"
483 program_invocation_short_name
,
487 // XXX: what about local-fs-pre.target?
489 r
= fflush_and_check(f
);
491 return log_error_errno(r
, "Failed to write unit file %s: %m", unit_file
);
493 return generator_add_symlink(dir
, where_unit
, "requires", unit
);
496 int generator_hook_up_growfs(
499 const char *target
) {
501 _cleanup_free_
char *unit
= NULL
, *escaped
= NULL
, *where_unit
= NULL
;
502 _cleanup_fclose_
FILE *f
= NULL
;
503 const char *unit_file
;
509 escaped
= cescape(where
);
513 r
= unit_name_from_path_instance("systemd-growfs", where
, ".service", &unit
);
515 return log_error_errno(r
, "Failed to make unit instance name from path \"%s\": %m",
518 r
= unit_name_from_path(where
, ".mount", &where_unit
);
520 return log_error_errno(r
, "Failed to make unit name from path \"%s\": %m",
523 unit_file
= prefix_roota(dir
, unit
);
524 log_debug("Creating %s", unit_file
);
526 f
= fopen(unit_file
, "wxe");
528 return log_error_errno(errno
, "Failed to create unit file %s: %m",
532 "# Automatically generated by %s\n\n"
534 "Description=Grow File System on %%f\n"
535 "Documentation=man:systemd-growfs@.service(8)\n"
536 "DefaultDependencies=no\n"
537 "BindsTo=%%i.mount\n"
538 "Conflicts=shutdown.target\n"
540 "Before=shutdown.target%s%s\n",
541 program_invocation_short_name
,
545 if (empty_or_root(where
)) /* Make sure the root fs is actually writable before we resize it */
547 "After=systemd-remount-fs.service\n");
553 "RemainAfterExit=yes\n"
554 "ExecStart="SYSTEMD_GROWFS_PATH
" %s\n"
558 return generator_add_symlink(dir
, where_unit
, "wants", unit
);
561 int generator_enable_remount_fs_service(const char *dir
) {
562 /* Pull in systemd-remount-fs.service */
563 return generator_add_symlink(dir
, SPECIAL_LOCAL_FS_TARGET
, "wants",
564 SYSTEM_DATA_UNIT_DIR
"/" SPECIAL_REMOUNT_FS_SERVICE
);
567 int generator_write_blockdev_dependency(
571 _cleanup_free_
char *escaped
= NULL
;
577 if (!path_startswith(what
, "/dev/"))
580 r
= unit_name_path_escape(what
, &escaped
);
582 return log_error_errno(r
, "Failed to escape device node path %s: %m", what
);
585 "After=blockdev@%s.target\n",
591 int generator_write_cryptsetup_unit_section(
593 const char *source
) {
599 "Description=Cryptography Setup for %%I\n"
600 "Documentation=man:crypttab(5) man:systemd-cryptsetup-generator(8) man:systemd-cryptsetup@.service(8)\n");
603 fprintf(f
, "SourcePath=%s\n", source
);
606 "DefaultDependencies=no\n"
607 "IgnoreOnIsolate=true\n"
608 "After=cryptsetup-pre.target systemd-udevd-kernel.socket\n"
609 "Before=blockdev@dev-mapper-%%i.target\n"
610 "Wants=blockdev@dev-mapper-%%i.target\n");
615 int generator_write_cryptsetup_service_section(
619 const char *password
,
620 const char *options
) {
622 _cleanup_free_
char *name_escaped
= NULL
, *what_escaped
= NULL
, *password_escaped
= NULL
, *options_escaped
= NULL
;
628 name_escaped
= specifier_escape(name
);
632 what_escaped
= specifier_escape(what
);
637 password_escaped
= specifier_escape(password
);
638 if (!password_escaped
)
643 options_escaped
= specifier_escape(options
);
644 if (!options_escaped
)
652 "RemainAfterExit=yes\n"
653 "TimeoutSec=0\n" /* The binary handles timeouts on its own */
654 "KeyringMode=shared\n" /* Make sure we can share cached keys among instances */
655 "OOMScoreAdjust=500\n" /* Unlocking can allocate a lot of memory if Argon2 is used */
656 "ExecStart=" SYSTEMD_CRYPTSETUP_PATH
" attach '%s' '%s' '%s' '%s'\n"
657 "ExecStop=" SYSTEMD_CRYPTSETUP_PATH
" detach '%s'\n",
658 name_escaped
, what_escaped
, strempty(password_escaped
), strempty(options_escaped
),
664 int generator_write_veritysetup_unit_section(
666 const char *source
) {
672 "Description=Integrity Protection Setup for %%I\n"
673 "Documentation=man:veritytab(5) man:systemd-veritysetup-generator(8) man:systemd-veritysetup@.service(8)\n");
676 fprintf(f
, "SourcePath=%s\n", source
);
679 "DefaultDependencies=no\n"
680 "IgnoreOnIsolate=true\n"
681 "After=cryptsetup-pre.target systemd-udevd-kernel.socket\n"
682 "Before=blockdev@dev-mapper-%%i.target\n"
683 "Wants=blockdev@dev-mapper-%%i.target\n");
688 int generator_write_veritysetup_service_section(
691 const char *data_what
,
692 const char *hash_what
,
693 const char *roothash
,
694 const char *options
) {
696 _cleanup_free_
char *name_escaped
= NULL
, *data_what_escaped
= NULL
, *hash_what_escaped
= NULL
,
697 *roothash_escaped
= NULL
, *options_escaped
= NULL
;
704 name_escaped
= specifier_escape(name
);
708 data_what_escaped
= specifier_escape(data_what
);
709 if (!data_what_escaped
)
712 hash_what_escaped
= specifier_escape(hash_what
);
713 if (!hash_what_escaped
)
716 roothash_escaped
= specifier_escape(roothash
);
717 if (!roothash_escaped
)
721 options_escaped
= specifier_escape(options
);
722 if (!options_escaped
)
730 "RemainAfterExit=yes\n"
731 "ExecStart=" SYSTEMD_VERITYSETUP_PATH
" attach '%s' '%s' '%s' '%s' '%s'\n"
732 "ExecStop=" SYSTEMD_VERITYSETUP_PATH
" detach '%s'\n",
733 name_escaped
, data_what_escaped
, hash_what_escaped
, roothash_escaped
, strempty(options_escaped
),
739 void log_setup_generator(void) {
740 /* Disable talking to syslog/journal (i.e. the two IPC-based loggers) if we run in system context. */
741 if (cg_pid_get_owner_uid(0, NULL
) == -ENXIO
/* not running in a per-user slice */)
742 log_set_prohibit_ipc(true);
744 log_set_target(LOG_TARGET_JOURNAL_OR_KMSG
); /* This effectively means: journal for per-user generators, kmsg otherwise */
745 log_parse_environment();