1 /* SPDX-License-Identifier: LGPL-2.1+ */
6 #include "alloc-util.h"
11 #include "fstab-util.h"
12 #include "generator.h"
16 #include "path-util.h"
18 #include "specifier.h"
19 #include "string-util.h"
20 #include "time-util.h"
21 #include "unit-name.h"
24 int generator_open_unit_file(
34 unit
= prefix_roota(dest
, name
);
36 r
= fopen_unlocked(unit
, "wxe", &f
);
38 if (source
&& r
== -EEXIST
)
39 return log_error_errno(r
,
40 "Failed to create unit file %s, as it already exists. Duplicate entry in %s?",
43 return log_error_errno(r
,
44 "Failed to create unit file %s: %m",
49 "# Automatically generated by %s\n\n",
50 program_invocation_short_name
);
56 int generator_add_symlink(const char *dir
, const char *dst
, const char *dep_type
, const char *src
) {
57 /* Adds a symlink from <dst>.<dep_type>/ to <src> (if src is absolute)
58 * or ../<src> (otherwise). */
60 const char *from
, *to
;
62 from
= path_is_absolute(src
) ? src
: strjoina("../", src
);
63 to
= strjoina(dir
, "/", dst
, ".", dep_type
, "/", basename(src
));
65 mkdir_parents_label(to
, 0755);
66 if (symlink(from
, to
) < 0)
68 return log_error_errno(errno
, "Failed to create symlink \"%s\": %m", to
);
73 static int write_fsck_sysroot_service(const char *dir
, const char *what
) {
74 _cleanup_free_
char *device
= NULL
, *escaped
= NULL
, *escaped2
= NULL
;
75 _cleanup_fclose_
FILE *f
= NULL
;
79 escaped
= specifier_escape(what
);
83 escaped2
= cescape(escaped
);
87 unit
= strjoina(dir
, "/"SPECIAL_FSCK_ROOT_SERVICE
);
88 log_debug("Creating %s", unit
);
90 r
= unit_name_from_path(what
, ".device", &device
);
92 return log_error_errno(r
, "Failed to convert device \"%s\" to unit name: %m", what
);
94 f
= fopen(unit
, "wxe");
96 return log_error_errno(errno
, "Failed to create unit file %s: %m", unit
);
99 "# Automatically generated by %1$s\n\n"
101 "Description=File System Check on %2$s\n"
102 "Documentation=man:systemd-fsck-root.service(8)\n"
103 "DefaultDependencies=no\n"
105 "Conflicts=shutdown.target\n"
106 "After=initrd-root-device.target local-fs-pre.target %3$s\n"
107 "Before=shutdown.target\n"
111 "RemainAfterExit=yes\n"
112 "ExecStart=" SYSTEMD_FSCK_PATH
" %4$s\n"
114 program_invocation_short_name
,
119 r
= fflush_and_check(f
);
121 return log_error_errno(r
, "Failed to write unit file %s: %m", unit
);
126 int generator_write_fsck_deps(
131 const char *fstype
) {
140 if (!is_device_path(what
)) {
141 log_warning("Checking was requested for \"%s\", but it is not a device.", what
);
145 if (!isempty(fstype
) && !streq(fstype
, "auto")) {
146 r
= fsck_exists(fstype
);
148 log_warning_errno(r
, "Checking was requested for %s, but couldn't detect if fsck.%s may be used, proceeding: %m", what
, fstype
);
150 /* treat missing check as essentially OK */
151 log_debug("Checking was requested for %s, but fsck.%s does not exist.", what
, fstype
);
156 if (path_equal(where
, "/")) {
159 lnk
= strjoina(dir
, "/" SPECIAL_LOCAL_FS_TARGET
".wants/" SPECIAL_FSCK_ROOT_SERVICE
);
161 (void) mkdir_parents(lnk
, 0755);
162 if (symlink(SYSTEM_DATA_UNIT_PATH
"/" SPECIAL_FSCK_ROOT_SERVICE
, lnk
) < 0)
163 return log_error_errno(errno
, "Failed to create symlink %s: %m", lnk
);
166 _cleanup_free_
char *_fsck
= NULL
;
167 const char *fsck
, *dep
;
169 if (in_initrd() && path_equal(where
, "/sysroot")) {
170 r
= write_fsck_sysroot_service(dir
, what
);
174 fsck
= SPECIAL_FSCK_ROOT_SERVICE
;
177 /* When this is /usr, then let's add a Wants= dependency, otherwise a Requires=
178 * dependency. Why? We can't possibly unmount /usr during shutdown, but if we have a
179 * Requires= from /usr onto a fsck@.service unit and that unit is shut down, then
180 * we'd have to unmount /usr too. */
182 dep
= !in_initrd() && path_equal(where
, "/usr") ? "Wants" : "Requires";
184 r
= unit_name_from_path_instance("systemd-fsck", what
, ".service", &_fsck
);
186 return log_error_errno(r
, "Failed to create fsck service name: %m");
200 int generator_write_timeouts(
207 /* Configure how long we wait for a device that backs a mount point or a
208 * swap partition to show up. This is useful to support endless device timeouts
209 * for devices that show up only after user input, like crypto devices. */
211 _cleanup_free_
char *node
= NULL
, *unit
= NULL
, *timeout
= NULL
;
215 r
= fstab_filter_options(opts
, "comment=systemd.device-timeout\0"
216 "x-systemd.device-timeout\0",
217 NULL
, &timeout
, filtered
);
221 r
= parse_sec_fix_0(timeout
, &u
);
223 log_warning("Failed to parse timeout for %s, ignoring: %s", where
, timeout
);
227 node
= fstab_node_to_udev_node(what
);
230 if (!is_device_path(node
)) {
231 log_warning("x-systemd.device-timeout ignored for %s", what
);
235 r
= unit_name_from_path(node
, ".device", &unit
);
237 return log_error_errno(r
, "Failed to make unit name from path: %m");
239 return write_drop_in_format(dir
, unit
, 50, "device-timeout",
240 "# Automatically generated by %s\n"
241 "# from supplied options \"%s\"\n\n"
243 "JobRunningTimeoutSec=%s",
244 program_invocation_short_name
,
249 int generator_write_device_deps(
255 /* fstab records that specify _netdev option should apply the network
256 * ordering on the actual device depending on network connection. If we
257 * are not mounting real device (NFS, CIFS), we rely on _netdev effect
258 * on the mount unit itself. */
260 _cleanup_free_
char *node
= NULL
, *unit
= NULL
;
263 if (fstab_is_extrinsic(where
, opts
))
266 if (!fstab_test_option(opts
, "_netdev\0"))
269 node
= fstab_node_to_udev_node(what
);
273 /* Nothing to apply dependencies to. */
274 if (!is_device_path(node
))
277 r
= unit_name_from_path(node
, ".device", &unit
);
279 return log_error_errno(r
, "Failed to make unit name from path \"%s\": %m",
282 /* See mount_add_default_dependencies for explanation why we create such
284 return write_drop_in_format(dir
, unit
, 50, "netdev-dependencies",
285 "# Automatically generated by %s\n\n"
287 "After=" SPECIAL_NETWORK_ONLINE_TARGET
" " SPECIAL_NETWORK_TARGET
"\n"
288 "Wants=" SPECIAL_NETWORK_ONLINE_TARGET
"\n",
289 program_invocation_short_name
);
292 int generator_write_initrd_root_device_deps(const char *dir
, const char *what
) {
293 _cleanup_free_
char *unit
= NULL
;
296 r
= unit_name_from_path(what
, ".device", &unit
);
298 return log_error_errno(r
, "Failed to make unit name from path \"%s\": %m",
301 return write_drop_in_format(dir
, SPECIAL_INITRD_ROOT_DEVICE_TARGET
, 50, "root-device",
302 "# Automatically generated by %s\n\n"
306 program_invocation_short_name
,
311 int generator_hook_up_mkswap(
315 _cleanup_free_
char *node
= NULL
, *unit
= NULL
, *escaped
= NULL
, *where_unit
= NULL
;
316 _cleanup_fclose_
FILE *f
= NULL
;
317 const char *unit_file
;
320 node
= fstab_node_to_udev_node(what
);
324 /* Nothing to work on. */
325 if (!is_device_path(node
))
326 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
327 "Cannot format something that is not a device node: %s",
330 r
= unit_name_from_path_instance("systemd-mkswap", node
, ".service", &unit
);
332 return log_error_errno(r
, "Failed to make unit instance name from path \"%s\": %m",
335 unit_file
= prefix_roota(dir
, unit
);
336 log_debug("Creating %s", unit_file
);
338 escaped
= cescape(node
);
342 r
= unit_name_from_path(what
, ".swap", &where_unit
);
344 return log_error_errno(r
, "Failed to make unit name from path \"%s\": %m",
347 f
= fopen(unit_file
, "wxe");
349 return log_error_errno(errno
, "Failed to create unit file %s: %m",
353 "# Automatically generated by %s\n\n"
355 "Description=Make Swap on %%f\n"
356 "Documentation=man:systemd-mkswap@.service(8)\n"
357 "DefaultDependencies=no\n"
358 "BindsTo=%%i.device\n"
359 "Conflicts=shutdown.target\n"
361 "Before=shutdown.target %s\n"
365 "RemainAfterExit=yes\n"
366 "ExecStart="SYSTEMD_MAKEFS_PATH
" swap %s\n"
368 program_invocation_short_name
,
372 r
= fflush_and_check(f
);
374 return log_error_errno(r
, "Failed to write unit file %s: %m", unit_file
);
376 return generator_add_symlink(dir
, where_unit
, "requires", unit
);
379 int generator_hook_up_mkfs(
385 _cleanup_free_
char *node
= NULL
, *unit
= NULL
, *escaped
= NULL
, *where_unit
= NULL
;
386 _cleanup_fclose_
FILE *f
= NULL
;
387 const char *unit_file
;
390 node
= fstab_node_to_udev_node(what
);
394 /* Nothing to work on. */
395 if (!is_device_path(node
))
396 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
397 "Cannot format something that is not a device node: %s",
400 if (!type
|| streq(type
, "auto"))
401 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
402 "Cannot format partition %s, filesystem type is not specified",
405 r
= unit_name_from_path_instance("systemd-makefs", node
, ".service", &unit
);
407 return log_error_errno(r
, "Failed to make unit instance name from path \"%s\": %m",
410 unit_file
= prefix_roota(dir
, unit
);
411 log_debug("Creating %s", unit_file
);
413 escaped
= cescape(node
);
417 r
= unit_name_from_path(where
, ".mount", &where_unit
);
419 return log_error_errno(r
, "Failed to make unit name from path \"%s\": %m",
422 f
= fopen(unit_file
, "wxe");
424 return log_error_errno(errno
, "Failed to create unit file %s: %m",
428 "# Automatically generated by %s\n\n"
430 "Description=Make File System on %%f\n"
431 "Documentation=man:systemd-makefs@.service(8)\n"
432 "DefaultDependencies=no\n"
433 "BindsTo=%%i.device\n"
434 "Conflicts=shutdown.target\n"
436 /* fsck might or might not be used, so let's be safe and order
437 * ourselves before both systemd-fsck@.service and the mount unit. */
438 "Before=shutdown.target systemd-fsck@%%i.service %s\n"
442 "RemainAfterExit=yes\n"
443 "ExecStart="SYSTEMD_MAKEFS_PATH
" %s %s\n"
445 program_invocation_short_name
,
449 // XXX: what about local-fs-pre.target?
451 r
= fflush_and_check(f
);
453 return log_error_errno(r
, "Failed to write unit file %s: %m", unit_file
);
455 return generator_add_symlink(dir
, where_unit
, "requires", unit
);
458 int generator_hook_up_growfs(
461 const char *target
) {
463 _cleanup_free_
char *unit
= NULL
, *escaped
= NULL
, *where_unit
= NULL
;
464 _cleanup_fclose_
FILE *f
= NULL
;
465 const char *unit_file
;
468 escaped
= cescape(where
);
472 r
= unit_name_from_path_instance("systemd-growfs", where
, ".service", &unit
);
474 return log_error_errno(r
, "Failed to make unit instance name from path \"%s\": %m",
477 r
= unit_name_from_path(where
, ".mount", &where_unit
);
479 return log_error_errno(r
, "Failed to make unit name from path \"%s\": %m",
482 unit_file
= prefix_roota(dir
, unit
);
483 log_debug("Creating %s", unit_file
);
485 f
= fopen(unit_file
, "wxe");
487 return log_error_errno(errno
, "Failed to create unit file %s: %m",
491 "# Automatically generated by %s\n\n"
493 "Description=Grow File System on %%f\n"
494 "Documentation=man:systemd-growfs@.service(8)\n"
495 "DefaultDependencies=no\n"
496 "BindsTo=%%i.mount\n"
497 "Conflicts=shutdown.target\n"
499 "Before=shutdown.target %s\n",
500 program_invocation_short_name
,
503 if (empty_or_root(where
)) /* Make sure the root fs is actually writable before we resize it */
505 "After=systemd-remount-fs.service\n");
511 "RemainAfterExit=yes\n"
512 "ExecStart="SYSTEMD_GROWFS_PATH
" %s\n"
516 return generator_add_symlink(dir
, where_unit
, "wants", unit
);
519 int generator_enable_remount_fs_service(const char *dir
) {
520 /* Pull in systemd-remount-fs.service */
521 return generator_add_symlink(dir
, SPECIAL_LOCAL_FS_TARGET
, "wants",
522 SYSTEM_DATA_UNIT_PATH
"/" SPECIAL_REMOUNT_FS_SERVICE
);
525 int generator_write_blockdev_dependency(
529 _cleanup_free_
char *escaped
= NULL
;
535 if (!path_startswith(what
, "/dev/"))
538 r
= unit_name_path_escape(what
, &escaped
);
540 return log_error_errno(r
, "Failed to escape device node path %s: %m", what
);
543 "After=blockdev@%s.target\n",
549 int generator_write_cryptsetup_unit_section(
551 const char *source
) {
557 "Description=Cryptography Setup for %%I\n"
558 "Documentation=man:crypttab(5) man:systemd-cryptsetup-generator(8) man:systemd-cryptsetup@.service(8)\n");
561 fprintf(f
, "SourcePath=%s\n", source
);
564 "DefaultDependencies=no\n"
565 "IgnoreOnIsolate=true\n"
566 "After=cryptsetup-pre.target\n"
567 "Before=blockdev@dev-mapper-%%i.target\n"
568 "Wants=blockdev@dev-mapper-%%i.target\n");
573 int generator_write_cryptsetup_service_section(
577 const char *password
,
578 const char *options
) {
580 _cleanup_free_
char *name_escaped
= NULL
, *what_escaped
= NULL
, *password_escaped
= NULL
, *options_escaped
= NULL
;
586 name_escaped
= specifier_escape(name
);
590 what_escaped
= specifier_escape(what
);
595 password_escaped
= specifier_escape(password
);
596 if (!password_escaped
)
601 options_escaped
= specifier_escape(options
);
602 if (!options_escaped
)
610 "RemainAfterExit=yes\n"
611 "TimeoutSec=0\n" /* The binary handles timeouts on its own */
612 "KeyringMode=shared\n" /* Make sure we can share cached keys among instances */
613 "OOMScoreAdjust=500\n" /* Unlocking can allocate a lot of memory if Argon2 is used */
614 "ExecStart=" SYSTEMD_CRYPTSETUP_PATH
" attach '%s' '%s' '%s' '%s'\n"
615 "ExecStop=" SYSTEMD_CRYPTSETUP_PATH
" detach '%s'\n",
616 name_escaped
, what_escaped
, strempty(password_escaped
), strempty(options_escaped
),
622 void log_setup_generator(void) {
623 log_set_prohibit_ipc(true);