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"
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 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(const char *dir
, const char *what
) {
75 _cleanup_free_
char *device
= NULL
, *escaped
= NULL
, *escaped2
= NULL
;
76 _cleanup_fclose_
FILE *f
= NULL
;
80 escaped
= specifier_escape(what
);
84 escaped2
= cescape(escaped
);
88 unit
= strjoina(dir
, "/"SPECIAL_FSCK_ROOT_SERVICE
);
89 log_debug("Creating %s", unit
);
91 r
= unit_name_from_path(what
, ".device", &device
);
93 return log_error_errno(r
, "Failed to convert device \"%s\" to unit name: %m", what
);
95 f
= fopen(unit
, "wxe");
97 return log_error_errno(errno
, "Failed to create unit file %s: %m", unit
);
100 "# Automatically generated by %1$s\n\n"
102 "Description=File System Check on %2$s\n"
103 "Documentation=man:systemd-fsck-root.service(8)\n"
104 "DefaultDependencies=no\n"
106 "Conflicts=shutdown.target\n"
107 "After=initrd-root-device.target local-fs-pre.target %3$s\n"
108 "Before=shutdown.target\n"
112 "RemainAfterExit=yes\n"
113 "ExecStart=" SYSTEMD_FSCK_PATH
" %4$s\n"
115 program_invocation_short_name
,
120 r
= fflush_and_check(f
);
122 return log_error_errno(r
, "Failed to write unit file %s: %m", unit
);
127 int generator_write_fsck_deps(
132 const char *fstype
) {
141 if (!is_device_path(what
)) {
142 log_warning("Checking was requested for \"%s\", but it is not a device.", what
);
146 if (!isempty(fstype
) && !streq(fstype
, "auto")) {
147 r
= fsck_exists(fstype
);
149 log_warning_errno(r
, "Checking was requested for %s, but couldn't detect if fsck.%s may be used, proceeding: %m", what
, fstype
);
151 /* treat missing check as essentially OK */
152 log_debug("Checking was requested for %s, but fsck.%s does not exist.", what
, fstype
);
157 if (path_equal(where
, "/")) {
160 lnk
= strjoina(dir
, "/" SPECIAL_LOCAL_FS_TARGET
".wants/" SPECIAL_FSCK_ROOT_SERVICE
);
162 (void) mkdir_parents(lnk
, 0755);
163 if (symlink(SYSTEM_DATA_UNIT_PATH
"/" SPECIAL_FSCK_ROOT_SERVICE
, lnk
) < 0)
164 return log_error_errno(errno
, "Failed to create symlink %s: %m", lnk
);
167 _cleanup_free_
char *_fsck
= NULL
;
168 const char *fsck
, *dep
;
170 if (in_initrd() && path_equal(where
, "/sysroot")) {
171 r
= write_fsck_sysroot_service(dir
, what
);
175 fsck
= SPECIAL_FSCK_ROOT_SERVICE
;
178 /* When this is /usr, then let's add a Wants= dependency, otherwise a Requires=
179 * dependency. Why? We can't possibly unmount /usr during shutdown, but if we have a
180 * Requires= from /usr onto a fsck@.service unit and that unit is shut down, then
181 * we'd have to unmount /usr too. */
183 dep
= !in_initrd() && path_equal(where
, "/usr") ? "Wants" : "Requires";
185 r
= unit_name_from_path_instance("systemd-fsck", what
, ".service", &_fsck
);
187 return log_error_errno(r
, "Failed to create fsck service name: %m");
201 int generator_write_timeouts(
208 /* Configure how long we wait for a device that backs a mount point or a
209 * swap partition to show up. This is useful to support endless device timeouts
210 * for devices that show up only after user input, like crypto devices. */
212 _cleanup_free_
char *node
= NULL
, *unit
= NULL
, *timeout
= NULL
;
216 r
= fstab_filter_options(opts
, "comment=systemd.device-timeout\0"
217 "x-systemd.device-timeout\0",
218 NULL
, &timeout
, filtered
);
222 r
= parse_sec_fix_0(timeout
, &u
);
224 log_warning("Failed to parse timeout for %s, ignoring: %s", where
, timeout
);
228 node
= fstab_node_to_udev_node(what
);
231 if (!is_device_path(node
)) {
232 log_warning("x-systemd.device-timeout ignored for %s", what
);
236 r
= unit_name_from_path(node
, ".device", &unit
);
238 return log_error_errno(r
, "Failed to make unit name from path: %m");
240 return write_drop_in_format(dir
, unit
, 50, "device-timeout",
241 "# Automatically generated by %s\n"
242 "# from supplied options \"%s\"\n\n"
244 "JobRunningTimeoutSec=%s",
245 program_invocation_short_name
,
250 int generator_write_device_deps(
256 /* fstab records that specify _netdev option should apply the network
257 * ordering on the actual device depending on network connection. If we
258 * are not mounting real device (NFS, CIFS), we rely on _netdev effect
259 * on the mount unit itself. */
261 _cleanup_free_
char *node
= NULL
, *unit
= NULL
;
264 if (fstab_is_extrinsic(where
, opts
))
267 if (!fstab_test_option(opts
, "_netdev\0"))
270 node
= fstab_node_to_udev_node(what
);
274 /* Nothing to apply dependencies to. */
275 if (!is_device_path(node
))
278 r
= unit_name_from_path(node
, ".device", &unit
);
280 return log_error_errno(r
, "Failed to make unit name from path \"%s\": %m",
283 /* See mount_add_default_dependencies for explanation why we create such
285 return write_drop_in_format(dir
, unit
, 50, "netdev-dependencies",
286 "# Automatically generated by %s\n\n"
288 "After=" SPECIAL_NETWORK_ONLINE_TARGET
" " SPECIAL_NETWORK_TARGET
"\n"
289 "Wants=" SPECIAL_NETWORK_ONLINE_TARGET
"\n",
290 program_invocation_short_name
);
293 int generator_write_initrd_root_device_deps(const char *dir
, const char *what
) {
294 _cleanup_free_
char *unit
= NULL
;
297 r
= unit_name_from_path(what
, ".device", &unit
);
299 return log_error_errno(r
, "Failed to make unit name from path \"%s\": %m",
302 return write_drop_in_format(dir
, SPECIAL_INITRD_ROOT_DEVICE_TARGET
, 50, "root-device",
303 "# Automatically generated by %s\n\n"
307 program_invocation_short_name
,
312 int generator_hook_up_mkswap(
316 _cleanup_free_
char *node
= NULL
, *unit
= NULL
, *escaped
= NULL
, *where_unit
= NULL
;
317 _cleanup_fclose_
FILE *f
= NULL
;
318 const char *unit_file
;
321 node
= fstab_node_to_udev_node(what
);
325 /* Nothing to work on. */
326 if (!is_device_path(node
))
327 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
328 "Cannot format something that is not a device node: %s",
331 r
= unit_name_from_path_instance("systemd-mkswap", node
, ".service", &unit
);
333 return log_error_errno(r
, "Failed to make unit instance name from path \"%s\": %m",
336 unit_file
= prefix_roota(dir
, unit
);
337 log_debug("Creating %s", unit_file
);
339 escaped
= cescape(node
);
343 r
= unit_name_from_path(what
, ".swap", &where_unit
);
345 return log_error_errno(r
, "Failed to make unit name from path \"%s\": %m",
348 f
= fopen(unit_file
, "wxe");
350 return log_error_errno(errno
, "Failed to create unit file %s: %m",
354 "# Automatically generated by %s\n\n"
356 "Description=Make Swap on %%f\n"
357 "Documentation=man:systemd-mkswap@.service(8)\n"
358 "DefaultDependencies=no\n"
359 "BindsTo=%%i.device\n"
360 "Conflicts=shutdown.target\n"
362 "Before=shutdown.target %s\n"
366 "RemainAfterExit=yes\n"
367 "ExecStart="SYSTEMD_MAKEFS_PATH
" swap %s\n"
369 program_invocation_short_name
,
373 r
= fflush_and_check(f
);
375 return log_error_errno(r
, "Failed to write unit file %s: %m", unit_file
);
377 return generator_add_symlink(dir
, where_unit
, "requires", unit
);
380 int generator_hook_up_mkfs(
386 _cleanup_free_
char *node
= NULL
, *unit
= NULL
, *escaped
= NULL
, *where_unit
= NULL
;
387 _cleanup_fclose_
FILE *f
= NULL
;
388 const char *unit_file
;
391 node
= fstab_node_to_udev_node(what
);
395 /* Nothing to work on. */
396 if (!is_device_path(node
))
397 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
398 "Cannot format something that is not a device node: %s",
401 if (!type
|| streq(type
, "auto"))
402 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
403 "Cannot format partition %s, filesystem type is not specified",
406 r
= unit_name_from_path_instance("systemd-makefs", node
, ".service", &unit
);
408 return log_error_errno(r
, "Failed to make unit instance name from path \"%s\": %m",
411 unit_file
= prefix_roota(dir
, unit
);
412 log_debug("Creating %s", unit_file
);
414 escaped
= cescape(node
);
418 r
= unit_name_from_path(where
, ".mount", &where_unit
);
420 return log_error_errno(r
, "Failed to make unit name from path \"%s\": %m",
423 f
= fopen(unit_file
, "wxe");
425 return log_error_errno(errno
, "Failed to create unit file %s: %m",
429 "# Automatically generated by %s\n\n"
431 "Description=Make File System on %%f\n"
432 "Documentation=man:systemd-makefs@.service(8)\n"
433 "DefaultDependencies=no\n"
434 "BindsTo=%%i.device\n"
435 "Conflicts=shutdown.target\n"
437 /* fsck might or might not be used, so let's be safe and order
438 * ourselves before both systemd-fsck@.service and the mount unit. */
439 "Before=shutdown.target systemd-fsck@%%i.service %s\n"
443 "RemainAfterExit=yes\n"
444 "ExecStart="SYSTEMD_MAKEFS_PATH
" %s %s\n"
446 program_invocation_short_name
,
450 // XXX: what about local-fs-pre.target?
452 r
= fflush_and_check(f
);
454 return log_error_errno(r
, "Failed to write unit file %s: %m", unit_file
);
456 return generator_add_symlink(dir
, where_unit
, "requires", unit
);
459 int generator_hook_up_growfs(
462 const char *target
) {
464 _cleanup_free_
char *unit
= NULL
, *escaped
= NULL
, *where_unit
= NULL
;
465 _cleanup_fclose_
FILE *f
= NULL
;
466 const char *unit_file
;
469 escaped
= cescape(where
);
473 r
= unit_name_from_path_instance("systemd-growfs", where
, ".service", &unit
);
475 return log_error_errno(r
, "Failed to make unit instance name from path \"%s\": %m",
478 r
= unit_name_from_path(where
, ".mount", &where_unit
);
480 return log_error_errno(r
, "Failed to make unit name from path \"%s\": %m",
483 unit_file
= prefix_roota(dir
, unit
);
484 log_debug("Creating %s", unit_file
);
486 f
= fopen(unit_file
, "wxe");
488 return log_error_errno(errno
, "Failed to create unit file %s: %m",
492 "# Automatically generated by %s\n\n"
494 "Description=Grow File System on %%f\n"
495 "Documentation=man:systemd-growfs@.service(8)\n"
496 "DefaultDependencies=no\n"
497 "BindsTo=%%i.mount\n"
498 "Conflicts=shutdown.target\n"
500 "Before=shutdown.target %s\n",
501 program_invocation_short_name
,
504 if (empty_or_root(where
)) /* Make sure the root fs is actually writable before we resize it */
506 "After=systemd-remount-fs.service\n");
512 "RemainAfterExit=yes\n"
513 "ExecStart="SYSTEMD_GROWFS_PATH
" %s\n"
517 return generator_add_symlink(dir
, where_unit
, "wants", unit
);
520 int generator_enable_remount_fs_service(const char *dir
) {
521 /* Pull in systemd-remount-fs.service */
522 return generator_add_symlink(dir
, SPECIAL_LOCAL_FS_TARGET
, "wants",
523 SYSTEM_DATA_UNIT_PATH
"/" SPECIAL_REMOUNT_FS_SERVICE
);
526 int generator_write_blockdev_dependency(
530 _cleanup_free_
char *escaped
= NULL
;
536 if (!path_startswith(what
, "/dev/"))
539 r
= unit_name_path_escape(what
, &escaped
);
541 return log_error_errno(r
, "Failed to escape device node path %s: %m", what
);
544 "After=blockdev@%s.target\n",
550 int generator_write_cryptsetup_unit_section(
552 const char *source
) {
558 "Description=Cryptography Setup for %%I\n"
559 "Documentation=man:crypttab(5) man:systemd-cryptsetup-generator(8) man:systemd-cryptsetup@.service(8)\n");
562 fprintf(f
, "SourcePath=%s\n", source
);
565 "DefaultDependencies=no\n"
566 "IgnoreOnIsolate=true\n"
567 "After=cryptsetup-pre.target systemd-udevd-kernel.socket\n"
568 "Before=blockdev@dev-mapper-%%i.target\n"
569 "Wants=blockdev@dev-mapper-%%i.target\n");
574 int generator_write_cryptsetup_service_section(
578 const char *password
,
579 const char *options
) {
581 _cleanup_free_
char *name_escaped
= NULL
, *what_escaped
= NULL
, *password_escaped
= NULL
, *options_escaped
= NULL
;
587 name_escaped
= specifier_escape(name
);
591 what_escaped
= specifier_escape(what
);
596 password_escaped
= specifier_escape(password
);
597 if (!password_escaped
)
602 options_escaped
= specifier_escape(options
);
603 if (!options_escaped
)
611 "RemainAfterExit=yes\n"
612 "TimeoutSec=0\n" /* The binary handles timeouts on its own */
613 "KeyringMode=shared\n" /* Make sure we can share cached keys among instances */
614 "OOMScoreAdjust=500\n" /* Unlocking can allocate a lot of memory if Argon2 is used */
615 "ExecStart=" SYSTEMD_CRYPTSETUP_PATH
" attach '%s' '%s' '%s' '%s'\n"
616 "ExecStop=" SYSTEMD_CRYPTSETUP_PATH
" detach '%s'\n",
617 name_escaped
, what_escaped
, strempty(password_escaped
), strempty(options_escaped
),
623 int generator_write_veritysetup_unit_section(
625 const char *source
) {
631 "Description=Integrity Protection Setup for %%I\n"
632 "Documentation=man:veritytab(5) man:systemd-veritysetup-generator(8) man:systemd-veritysetup@.service(8)\n");
635 fprintf(f
, "SourcePath=%s\n", source
);
638 "DefaultDependencies=no\n"
639 "IgnoreOnIsolate=true\n"
640 "After=cryptsetup-pre.target systemd-udevd-kernel.socket\n"
641 "Before=blockdev@dev-mapper-%%i.target\n"
642 "Wants=blockdev@dev-mapper-%%i.target\n");
647 int generator_write_veritysetup_service_section(
650 const char *data_what
,
651 const char *hash_what
,
652 const char *roothash
,
653 const char *options
) {
655 _cleanup_free_
char *name_escaped
= NULL
, *data_what_escaped
= NULL
, *hash_what_escaped
= NULL
,
656 *roothash_escaped
= NULL
, *options_escaped
= NULL
;
663 name_escaped
= specifier_escape(name
);
667 data_what_escaped
= specifier_escape(data_what
);
668 if (!data_what_escaped
)
671 hash_what_escaped
= specifier_escape(hash_what
);
672 if (!hash_what_escaped
)
675 roothash_escaped
= specifier_escape(roothash
);
676 if (!roothash_escaped
)
680 options_escaped
= specifier_escape(options
);
681 if (!options_escaped
)
689 "RemainAfterExit=yes\n"
690 "ExecStart=" SYSTEMD_VERITYSETUP_PATH
" attach '%s' '%s' '%s' '%s' '%s'\n"
691 "ExecStop=" SYSTEMD_VERITYSETUP_PATH
" detach '%s'\n",
692 name_escaped
, data_what_escaped
, hash_what_escaped
, roothash_escaped
, strempty(options_escaped
),
698 void log_setup_generator(void) {
699 /* Disable talking to syslog/journal (i.e. the two IPC-based loggers) if we run in system context. */
700 if (cg_pid_get_owner_uid(0, NULL
) == -ENXIO
/* not running in a per-user slice */)
701 log_set_prohibit_ipc(true);
703 log_set_target(LOG_TARGET_JOURNAL_OR_KMSG
); /* This effectively means: journal for per-user generators, kmsg otherwise */
704 log_parse_environment();