const char *options) {
_cleanup_free_ char *n = NULL, *d = NULL, *u = NULL, *e = NULL,
- *keydev_mount = NULL, *keyfile_timeout_value = NULL, *password_escaped = NULL,
- *filtered = NULL, *u_escaped = NULL, *filtered_escaped = NULL, *name_escaped = NULL, *header_path = NULL;
+ *keydev_mount = NULL, *keyfile_timeout_value = NULL,
+ *filtered = NULL, *u_escaped = NULL, *name_escaped = NULL, *header_path = NULL, *password_buffer = NULL;
_cleanup_fclose_ FILE *f = NULL;
const char *dmname;
bool noauto, nofail, tmp, swap, netdev, attach_in_initrd;
if (r < 0)
return r;
- fprintf(f,
- "[Unit]\n"
- "Description=Cryptography Setup for %%I\n"
- "Documentation=man:crypttab(5) man:systemd-cryptsetup-generator(8) man:systemd-cryptsetup@.service(8)\n"
- "SourcePath=%s\n"
- "DefaultDependencies=no\n"
- "IgnoreOnIsolate=true\n"
- "After=cryptsetup-pre.target\n",
- arg_crypttab);
+ r = generator_write_cryptsetup_unit_section(f, arg_crypttab);
+ if (r < 0)
+ return r;
if (netdev)
fprintf(f, "After=remote-fs-pre.target\n");
if (!attach_in_initrd)
fprintf(f, "Conflicts=umount.target\n");
- if (password) {
- password_escaped = specifier_escape(password);
- if (!password_escaped)
- return log_oom();
- }
-
if (keydev) {
- _cleanup_free_ char *unit = NULL, *p = NULL;
+ _cleanup_free_ char *unit = NULL;
r = generate_keydev_mount(name, keydev, keyfile_timeout_value, keyfile_can_timeout > 0, &unit, &keydev_mount);
if (r < 0)
return log_error_errno(r, "Failed to generate keydev mount unit: %m");
- p = path_join(keydev_mount, password_escaped);
- if (!p)
+ password_buffer = path_join(keydev_mount, password);
+ if (!password_buffer)
return log_oom();
- free_and_replace(password_escaped, p);
+ password = password_buffer;
fprintf(f, "After=%s\n", unit);
if (keyfile_can_timeout > 0)
return r;
}
- if (path_startswith(u, "/dev/")) {
+ if (path_startswith(u, "/dev/"))
fprintf(f,
"BindsTo=%s\n"
"After=%s\n"
"Before=umount.target\n",
d, d);
-
- if (swap)
- fputs("Before=dev-mapper-%i.swap\n",
- f);
- } else
+ else
/* For loopback devices, add systemd-tmpfiles-setup-dev.service
dependency to ensure that loopback support is available in
the kernel (/dev/loop-control needs to exist) */
if (r < 0)
log_warning_errno(r, "Failed to write device timeout drop-in: %m");
- if (filtered) {
- filtered_escaped = specifier_escape(filtered);
- if (!filtered_escaped)
- return log_oom();
- }
-
- fprintf(f,
- "\n[Service]\n"
- "Type=oneshot\n"
- "RemainAfterExit=yes\n"
- "TimeoutSec=0\n" /* the binary handles timeouts anyway */
- "KeyringMode=shared\n" /* make sure we can share cached keys among instances */
- "OOMScoreAdjust=500\n" /* unlocking can allocate a lot of memory if Argon2 is used */
- "ExecStart=" SYSTEMD_CRYPTSETUP_PATH " attach '%s' '%s' '%s' '%s'\n"
- "ExecStop=" SYSTEMD_CRYPTSETUP_PATH " detach '%s'\n",
- name_escaped, u_escaped, strempty(password_escaped), strempty(filtered_escaped),
- name_escaped);
+ r = generator_write_cryptsetup_service_section(f, name, u, password, filtered);
+ if (r < 0)
+ return r;
if (tmp)
fprintf(f,
fprintf(f,
"[Unit]\n"
- "SourcePath=%s\n"
- "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n\n"
- "[Swap]\n",
+ "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n"
+ "SourcePath=%s\n",
fstab_path());
+ r = generator_write_blockdev_dependency(f, what);
+ if (r < 0)
+ return r;
+
+ fprintf(f,
+ "\n"
+ "[Swap]\n");
+
r = write_what(f, what);
if (r < 0)
return r;
fprintf(f,
"[Unit]\n"
- "SourcePath=%s\n"
- "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n",
+ "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n"
+ "SourcePath=%s\n",
source);
/* All mounts under /sysroot need to happen later, at initrd-fs.target time. IOW, it's not
return r;
}
- fprintf(f, "\n[Mount]\n");
+ r = generator_write_blockdev_dependency(f, what);
+ if (r < 0)
+ return r;
+
+ fprintf(f,
+ "\n"
+ "[Mount]\n");
+
if (original_where)
fprintf(f, "# Canonicalized from %s\n", original_where);
}
static int add_cryptsetup(const char *id, const char *what, bool rw, bool require, char **device) {
- _cleanup_free_ char *e = NULL, *n = NULL, *d = NULL, *id_escaped = NULL, *what_escaped = NULL;
+ _cleanup_free_ char *e = NULL, *n = NULL, *d = NULL;
_cleanup_fclose_ FILE *f = NULL;
- const char *p;
int r;
assert(id);
if (r < 0)
return log_error_errno(r, "Failed to generate unit name: %m");
- id_escaped = specifier_escape(id);
- if (!id_escaped)
- return log_oom();
-
- what_escaped = specifier_escape(what);
- if (!what_escaped)
- return log_oom();
+ r = generator_open_unit_file(arg_dest, NULL, n, &f);
+ if (r < 0)
+ return r;
- p = prefix_roota(arg_dest, n);
- f = fopen(p, "wxe");
- if (!f)
- return log_error_errno(errno, "Failed to create unit file %s: %m", p);
+ r = generator_write_cryptsetup_unit_section(f, NULL);
+ if (r < 0)
+ return r;
fprintf(f,
- "# Automatically generated by systemd-gpt-auto-generator\n\n"
- "[Unit]\n"
- "Description=Cryptography Setup for %%I\n"
- "Documentation=man:systemd-gpt-auto-generator(8) man:systemd-cryptsetup@.service(8)\n"
- "DefaultDependencies=no\n"
- "Conflicts=umount.target\n"
- "BindsTo=dev-mapper-%%i.device %s\n"
"Before=umount.target cryptsetup.target\n"
- "After=%s\n"
- "IgnoreOnIsolate=true\n"
- "[Service]\n"
- "Type=oneshot\n"
- "RemainAfterExit=yes\n"
- "TimeoutSec=0\n" /* the binary handles timeouts anyway */
- "KeyringMode=shared\n" /* make sure we can share cached keys among instances */
- "ExecStart=" SYSTEMD_CRYPTSETUP_PATH " attach '%s' '%s' '' '%s'\n"
- "ExecStop=" SYSTEMD_CRYPTSETUP_PATH " detach '%s'\n",
- d, d,
- id_escaped, what_escaped, rw ? "" : "read-only",
- id_escaped);
+ "Conflicts=umount.target\n"
+ "BindsTo=%s\n"
+ "After=%s\n",
+ d, d);
+
+ r = generator_write_cryptsetup_service_section(f, id, what, NULL, rw ? NULL : "read-only");
+ if (r < 0)
+ return r;
r = fflush_and_check(f);
if (r < 0)
- return log_error_errno(r, "Failed to write file %s: %m", p);
+ return log_error_errno(r, "Failed to write file %s: %m", n);
r = generator_add_symlink(arg_dest, d, "wants", n);
if (r < 0)
log_debug("Adding %s: %s fstype=%s", where, what, fstype ?: "(any)");
if (streq_ptr(fstype, "crypto_LUKS")) {
-
r = add_cryptsetup(id, what, rw, true, &crypto_what);
if (r < 0)
return r;
if (r < 0)
return r;
+ r = generator_write_blockdev_dependency(f, what);
+ if (r < 0)
+ return r;
+
fprintf(f,
"\n"
"[Mount]\n"
"# Automatically generated by systemd-gpt-auto-generator\n\n"
"[Unit]\n"
"Description=Swap Partition\n"
- "Documentation=man:systemd-gpt-auto-generator(8)\n\n"
+ "Documentation=man:systemd-gpt-auto-generator(8)\n");
+
+ r = generator_write_blockdev_dependency(f, path);
+ if (r < 0)
+ return r;
+
+ fprintf(f,
+ "\n"
"[Swap]\n"
"What=%s\n",
path);
SYSTEM_DATA_UNIT_PATH "/" SPECIAL_REMOUNT_FS_SERVICE);
}
+int generator_write_blockdev_dependency(
+ FILE *f,
+ const char *what) {
+
+ _cleanup_free_ char *escaped = NULL;
+ int r;
+
+ assert(f);
+ assert(what);
+
+ if (!path_startswith(what, "/dev/"))
+ return 0;
+
+ r = unit_name_path_escape(what, &escaped);
+ if (r < 0)
+ return log_error_errno(r, "Failed to escape device node path %s: %m", what);
+
+ fprintf(f,
+ "After=blockdev@%s.target\n",
+ escaped);
+
+ return 0;
+}
+
+int generator_write_cryptsetup_unit_section(
+ FILE *f,
+ const char *source) {
+
+ assert(f);
+
+ fprintf(f,
+ "[Unit]\n"
+ "Description=Cryptography Setup for %%I\n"
+ "Documentation=man:crypttab(5) man:systemd-cryptsetup-generator(8) man:systemd-cryptsetup@.service(8)\n");
+
+ if (source)
+ fprintf(f, "SourcePath=%s\n", source);
+
+ fprintf(f,
+ "DefaultDependencies=no\n"
+ "IgnoreOnIsolate=true\n"
+ "After=cryptsetup-pre.target\n"
+ "Before=blockdev@dev-mapper-%%i.target\n"
+ "Wants=blockdev@dev-mapper-%%i.target\n");
+
+ return 0;
+}
+
+int generator_write_cryptsetup_service_section(
+ FILE *f,
+ const char *name,
+ const char *what,
+ const char *password,
+ const char *options) {
+
+ _cleanup_free_ char *name_escaped = NULL, *what_escaped = NULL, *password_escaped = NULL, *options_escaped = NULL;
+
+ assert(f);
+ assert(name);
+ assert(what);
+
+ name_escaped = specifier_escape(name);
+ if (!name_escaped)
+ return log_oom();
+
+ what_escaped = specifier_escape(what);
+ if (!what_escaped)
+ return log_oom();
+
+ if (password) {
+ password_escaped = specifier_escape(password);
+ if (!password_escaped)
+ return log_oom();
+ }
+
+ if (options) {
+ options_escaped = specifier_escape(options);
+ if (!options_escaped)
+ return log_oom();
+ }
+
+ fprintf(f,
+ "\n"
+ "[Service]\n"
+ "Type=oneshot\n"
+ "RemainAfterExit=yes\n"
+ "TimeoutSec=0\n" /* The binary handles timeouts on its own */
+ "KeyringMode=shared\n" /* Make sure we can share cached keys among instances */
+ "OOMScoreAdjust=500\n" /* Unlocking can allocate a lot of memory if Argon2 is used */
+ "ExecStart=" SYSTEMD_CRYPTSETUP_PATH " attach '%s' '%s' '%s' '%s'\n"
+ "ExecStop=" SYSTEMD_CRYPTSETUP_PATH " detach '%s'\n",
+ name_escaped, what_escaped, strempty(password_escaped), strempty(options_escaped),
+ name_escaped);
+
+ return 0;
+}
+
void log_setup_generator(void) {
log_set_prohibit_ipc(true);
log_setup_service();
const char *opts,
char **filtered);
+int generator_write_blockdev_dependency(
+ FILE *f,
+ const char *what);
+
+int generator_write_cryptsetup_unit_section(
+ FILE *f,
+ const char *source);
+
+int generator_write_cryptsetup_service_section(
+ FILE *f,
+ const char *name,
+ const char *what,
+ const char *password,
+ const char *options);
+
int generator_write_device_deps(
const char *dir,
const char *what,
--- /dev/null
+# SPDX-License-Identifier: LGPL-2.1+
+#
+# This file is part of systemd.
+#
+# systemd is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+
+[Unit]
+Description=Block Device Preparation for %f
+Documentation=man:systemd.special(7)
+StopWhenUnneeded=yes
units = [
['basic.target', ''],
+ ['blockdev@.target', ''],
['bluetooth.target', ''],
['boot-complete.target', ''],
['cryptsetup-pre.target', 'HAVE_LIBCRYPTSETUP'],