1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 Copyright 2014 Lennart Poettering
10 #include "alloc-util.h"
15 #include "fstab-util.h"
16 #include "generator.h"
20 #include "path-util.h"
22 #include "specifier.h"
23 #include "string-util.h"
24 #include "time-util.h"
25 #include "unit-name.h"
28 int generator_open_unit_file(
37 unit
= strjoina(dest
, "/", name
);
39 f
= fopen(unit
, "wxe");
41 if (source
&& errno
== EEXIST
)
42 return log_error_errno(errno
,
43 "Failed to create unit file %s, as it already exists. Duplicate entry in %s?",
46 return log_error_errno(errno
,
47 "Failed to create unit file %s: %m",
51 (void) __fsetlocking(f
, FSETLOCKING_BYCALLER
);
54 "# Automatically generated by %s\n\n",
55 program_invocation_short_name
);
61 int generator_add_symlink(const char *root
, const char *dst
, const char *dep_type
, const char *src
) {
62 /* Adds a symlink from <dst>.<dep_type>.d/ to ../<src> */
64 const char *from
, *to
;
66 from
= strjoina("../", src
);
67 to
= strjoina(root
, "/", dst
, ".", dep_type
, "/", src
);
69 mkdir_parents_label(to
, 0755);
70 if (symlink(from
, to
) < 0)
72 return log_error_errno(errno
, "Failed to create symlink \"%s\": %m", to
);
77 static int write_fsck_sysroot_service(const char *dir
, const char *what
) {
78 _cleanup_free_
char *device
= NULL
, *escaped
= NULL
, *escaped2
= NULL
;
79 _cleanup_fclose_
FILE *f
= NULL
;
83 escaped
= specifier_escape(what
);
87 escaped2
= cescape(escaped
);
91 unit
= strjoina(dir
, "/systemd-fsck-root.service");
92 log_debug("Creating %s", unit
);
94 r
= unit_name_from_path(what
, ".device", &device
);
96 return log_error_errno(r
, "Failed to convert device \"%s\" to unit name: %m", what
);
98 f
= fopen(unit
, "wxe");
100 return log_error_errno(errno
, "Failed to create unit file %s: %m", unit
);
103 "# Automatically generated by %1$s\n\n"
105 "Description=File System Check on %2$s\n"
106 "Documentation=man:systemd-fsck-root.service(8)\n"
107 "DefaultDependencies=no\n"
109 "After=initrd-root-device.target local-fs-pre.target %3$s\n"
110 "Before=shutdown.target\n"
114 "RemainAfterExit=yes\n"
115 "ExecStart=" SYSTEMD_FSCK_PATH
" %4$s\n"
117 program_invocation_short_name
,
122 r
= fflush_and_check(f
);
124 return log_error_errno(r
, "Failed to write unit file %s: %m", unit
);
129 int generator_write_fsck_deps(
134 const char *fstype
) {
143 if (!is_device_path(what
)) {
144 log_warning("Checking was requested for \"%s\", but it is not a device.", what
);
148 if (!isempty(fstype
) && !streq(fstype
, "auto")) {
149 r
= fsck_exists(fstype
);
151 log_warning_errno(r
, "Checking was requested for %s, but couldn't detect if fsck.%s may be used, proceeding: %m", what
, fstype
);
153 /* treat missing check as essentially OK */
154 log_debug("Checking was requested for %s, but fsck.%s does not exist.", what
, fstype
);
159 if (path_equal(where
, "/")) {
162 lnk
= strjoina(dir
, "/" SPECIAL_LOCAL_FS_TARGET
".wants/systemd-fsck-root.service");
164 mkdir_parents(lnk
, 0755);
165 if (symlink(SYSTEM_DATA_UNIT_PATH
"/systemd-fsck-root.service", lnk
) < 0)
166 return log_error_errno(errno
, "Failed to create symlink %s: %m", lnk
);
169 _cleanup_free_
char *_fsck
= NULL
;
172 if (in_initrd() && path_equal(where
, "/sysroot")) {
173 r
= write_fsck_sysroot_service(dir
, what
);
177 fsck
= "systemd-fsck-root.service";
179 r
= unit_name_from_path_instance("systemd-fsck", what
, ".service", &_fsck
);
181 return log_error_errno(r
, "Failed to create fsck service name: %m");
195 int generator_write_timeouts(
202 /* Allow configuration how long we wait for a device that
203 * backs a mount point to show up. This is useful to support
204 * endless device timeouts for devices that show up only after
205 * user input, like crypto devices. */
207 _cleanup_free_
char *node
= NULL
, *unit
= NULL
, *timeout
= NULL
;
211 r
= fstab_filter_options(opts
, "comment=systemd.device-timeout\0"
212 "x-systemd.device-timeout\0",
213 NULL
, &timeout
, filtered
);
217 r
= parse_sec_fix_0(timeout
, &u
);
219 log_warning("Failed to parse timeout for %s, ignoring: %s", where
, timeout
);
223 node
= fstab_node_to_udev_node(what
);
226 if (!is_device_path(node
)) {
227 log_warning("x-systemd.device-timeout ignored for %s", what
);
231 r
= unit_name_from_path(node
, ".device", &unit
);
233 return log_error_errno(r
, "Failed to make unit name from path: %m");
235 return write_drop_in_format(dir
, unit
, 50, "device-timeout",
236 "# Automatically generated by %s\n\n"
238 "JobRunningTimeoutSec=%s",
239 program_invocation_short_name
,
243 int generator_write_device_deps(
249 /* fstab records that specify _netdev option should apply the network
250 * ordering on the actual device depending on network connection. If we
251 * are not mounting real device (NFS, CIFS), we rely on _netdev effect
252 * on the mount unit itself. */
254 _cleanup_free_
char *node
= NULL
, *unit
= NULL
;
257 if (!fstab_test_option(opts
, "_netdev\0"))
260 node
= fstab_node_to_udev_node(what
);
264 /* Nothing to apply dependencies to. */
265 if (!is_device_path(node
))
268 r
= unit_name_from_path(node
, ".device", &unit
);
270 return log_error_errno(r
, "Failed to make unit name from path \"%s\": %m",
273 /* See mount_add_default_dependencies for explanation why we create such
275 return write_drop_in_format(dir
, unit
, 50, "netdev-dependencies",
276 "# Automatically generated by %s\n\n"
278 "After=" SPECIAL_NETWORK_ONLINE_TARGET
" " SPECIAL_NETWORK_TARGET
"\n"
279 "Wants=" SPECIAL_NETWORK_ONLINE_TARGET
"\n",
280 program_invocation_short_name
);
283 int generator_write_initrd_root_device_deps(const char *dir
, const char *what
) {
284 _cleanup_free_
char *unit
= NULL
;
287 r
= unit_name_from_path(what
, ".device", &unit
);
289 return log_error_errno(r
, "Failed to make unit name from path \"%s\": %m",
292 return write_drop_in_format(dir
, SPECIAL_INITRD_ROOT_DEVICE_TARGET
, 50, "root-device",
293 "# Automatically generated by %s\n\n"
297 program_invocation_short_name
,
302 int generator_hook_up_mkswap(
306 _cleanup_free_
char *node
= NULL
, *unit
= NULL
, *escaped
= NULL
, *where_unit
= NULL
;
307 _cleanup_fclose_
FILE *f
= NULL
;
308 const char *unit_file
;
311 node
= fstab_node_to_udev_node(what
);
315 /* Nothing to work on. */
316 if (!is_device_path(node
)) {
317 log_error("Cannot format something that is not a device node: %s", node
);
321 r
= unit_name_from_path_instance("systemd-mkswap", node
, ".service", &unit
);
323 return log_error_errno(r
, "Failed to make unit instance name from path \"%s\": %m",
326 unit_file
= strjoina(dir
, "/", unit
);
327 log_debug("Creating %s", unit_file
);
329 escaped
= cescape(node
);
333 r
= unit_name_from_path(what
, ".swap", &where_unit
);
335 return log_error_errno(r
, "Failed to make unit name from path \"%s\": %m",
338 f
= fopen(unit_file
, "wxe");
340 return log_error_errno(errno
, "Failed to create unit file %s: %m",
344 "# Automatically generated by %s\n\n"
346 "Description=Make Swap on %%f\n"
347 "Documentation=man:systemd-mkswap@.service(8)\n"
348 "DefaultDependencies=no\n"
349 "BindsTo=%%i.device\n"
352 "Before=shutdown.target\n"
356 "RemainAfterExit=yes\n"
357 "ExecStart="SYSTEMD_MAKEFS_PATH
" swap %s\n"
359 program_invocation_short_name
,
363 r
= fflush_and_check(f
);
365 return log_error_errno(r
, "Failed to write unit file %s: %m", unit_file
);
367 return generator_add_symlink(dir
, where_unit
, "requires", unit
);
370 int generator_hook_up_mkfs(
376 _cleanup_free_
char *node
= NULL
, *unit
= NULL
, *escaped
= NULL
, *where_unit
= NULL
;
377 _cleanup_fclose_
FILE *f
= NULL
;
378 const char *unit_file
;
381 node
= fstab_node_to_udev_node(what
);
385 /* Nothing to work on. */
386 if (!is_device_path(node
)) {
387 log_error("Cannot format something that is not a device node: %s", node
);
391 if (!type
|| streq(type
, "auto")) {
392 log_error("Cannot format partition %s, filesystem type is not specified", node
);
396 r
= unit_name_from_path_instance("systemd-mkfs", node
, ".service", &unit
);
398 return log_error_errno(r
, "Failed to make unit instance name from path \"%s\": %m",
401 unit_file
= strjoina(dir
, "/", unit
);
402 log_debug("Creating %s", unit_file
);
404 escaped
= cescape(node
);
408 r
= unit_name_from_path(where
, ".mount", &where_unit
);
410 return log_error_errno(r
, "Failed to make unit name from path \"%s\": %m",
413 f
= fopen(unit_file
, "wxe");
415 return log_error_errno(errno
, "Failed to create unit file %s: %m",
419 "# Automatically generated by %s\n\n"
421 "Description=Make File System on %%f\n"
422 "Documentation=man:systemd-mkfs@.service(8)\n"
423 "DefaultDependencies=no\n"
424 "BindsTo=%%i.device\n"
426 /* fsck might or might not be used, so let's be safe and order
427 * ourselves before both systemd-fsck@.service and the mount unit. */
428 "Before=systemd-fsck@%%i.service\n"
430 "Before=shutdown.target\n"
434 "RemainAfterExit=yes\n"
435 "ExecStart="SYSTEMD_MAKEFS_PATH
" %s %s\n"
437 program_invocation_short_name
,
441 // XXX: what about local-fs-pre.target?
443 r
= fflush_and_check(f
);
445 return log_error_errno(r
, "Failed to write unit file %s: %m", unit_file
);
447 return generator_add_symlink(dir
, where_unit
, "requires", unit
);
450 int generator_hook_up_growfs(
453 const char *target
) {
455 _cleanup_free_
char *unit
= NULL
, *escaped
= NULL
, *where_unit
= NULL
;
456 _cleanup_fclose_
FILE *f
= NULL
;
457 const char *unit_file
;
460 escaped
= cescape(where
);
464 r
= unit_name_from_path_instance("systemd-growfs", where
, ".service", &unit
);
466 return log_error_errno(r
, "Failed to make unit instance name from path \"%s\": %m",
469 r
= unit_name_from_path(where
, ".mount", &where_unit
);
471 return log_error_errno(r
, "Failed to make unit name from path \"%s\": %m",
474 unit_file
= strjoina(dir
, "/", unit
);
475 log_debug("Creating %s", unit_file
);
477 f
= fopen(unit_file
, "wxe");
479 return log_error_errno(errno
, "Failed to create unit file %s: %m",
483 "# Automatically generated by %s\n\n"
485 "Description=Grow File System on %%f\n"
486 "Documentation=man:systemd-growfs@.service(8)\n"
487 "DefaultDependencies=no\n"
488 "BindsTo=%%i.mount\n"
490 "Before=shutdown.target\n"
495 "RemainAfterExit=yes\n"
496 "ExecStart="SYSTEMD_GROWFS_PATH
" %s\n"
498 program_invocation_short_name
,
502 return generator_add_symlink(dir
, where_unit
, "wants", unit
);