+/* SPDX-License-Identifier: LGPL-2.1+ */
/***
This file is part of systemd.
#include "parse-util.h"
#include "path-util.h"
#include "proc-cmdline.h"
+#include "specifier.h"
#include "string-util.h"
#include "strv.h"
#include "unit-name.h"
const char *password,
const char *options) {
- _cleanup_free_ char *p = NULL, *n = NULL, *d = NULL, *u = NULL, *to = NULL, *e = NULL,
- *filtered = NULL;
+ _cleanup_free_ char *p = NULL, *n = NULL, *d = NULL, *u = NULL, *e = NULL,
+ *filtered = NULL, *u_escaped = NULL, *password_escaped = NULL, *filtered_escaped = NULL, *name_escaped = NULL;
_cleanup_fclose_ FILE *f = NULL;
- bool noauto, nofail, tmp, swap;
- char *from;
+ const char *dmname;
+ bool noauto, nofail, tmp, swap, netdev;
int r;
assert(name);
nofail = fstab_test_yes_no_option(options, "nofail\0" "fail\0");
tmp = fstab_test_option(options, "tmp\0");
swap = fstab_test_option(options, "swap\0");
+ netdev = fstab_test_option(options, "_netdev\0");
if (tmp && swap) {
log_error("Device '%s' cannot be both 'tmp' and 'swap'. Ignoring.", name);
return -EINVAL;
}
+ name_escaped = specifier_escape(name);
+ if (!name_escaped)
+ return log_oom();
+
e = unit_name_escape(name);
if (!e)
return log_oom();
if (!u)
return log_oom();
+ u_escaped = specifier_escape(u);
+ if (!u_escaped)
+ return log_oom();
+
r = unit_name_from_path(u, ".device", &d);
if (r < 0)
return log_error_errno(r, "Failed to generate unit name: %m");
+ password_escaped = specifier_escape(password);
+ if (!password_escaped)
+ return log_oom();
+
f = fopen(p, "wxe");
if (!f)
return log_error_errno(errno, "Failed to create unit file %s: %m", p);
- fputs("# Automatically generated by systemd-cryptsetup-generator\n\n"
- "[Unit]\n"
- "Description=Cryptography Setup for %I\n"
- "Documentation=man:crypttab(5) man:systemd-cryptsetup-generator(8) man:systemd-cryptsetup@.service(8)\n"
- "SourcePath=/etc/crypttab\n"
- "DefaultDependencies=no\n"
- "Conflicts=umount.target\n"
- "BindsTo=dev-mapper-%i.device\n"
- "IgnoreOnIsolate=true\n"
- "After=cryptsetup-pre.target\n",
- f);
+ fprintf(f,
+ "# Automatically generated by systemd-cryptsetup-generator\n\n"
+ "[Unit]\n"
+ "Description=Cryptography Setup for %%I\n"
+ "Documentation=man:crypttab(5) man:systemd-cryptsetup-generator(8) man:systemd-cryptsetup@.service(8)\n"
+ "SourcePath=/etc/crypttab\n"
+ "DefaultDependencies=no\n"
+ "Conflicts=umount.target\n"
+ "IgnoreOnIsolate=true\n"
+ "After=%s\n",
+ netdev ? "remote-fs-pre.target" : "cryptsetup-pre.target");
if (!nofail)
fprintf(f,
- "Before=cryptsetup.target\n");
+ "Before=%s\n",
+ netdev ? "remote-cryptsetup.target" : "cryptsetup.target");
if (password) {
if (STR_IN_SET(password, "/dev/urandom", "/dev/random", "/dev/hw_random"))
- fputs("After=systemd-random-seed.service\n", f);
- else if (!streq(password, "-") && !streq(password, "none")) {
+ fputs_unlocked("After=systemd-random-seed.service\n", f);
+ else if (!STR_IN_SET(password, "-", "none")) {
_cleanup_free_ char *uu;
uu = fstab_node_to_udev_node(password);
if (!path_equal(uu, "/dev/null")) {
- if (is_device_path(uu)) {
+ if (path_startswith(uu, "/dev/")) {
_cleanup_free_ char *dd = NULL;
r = unit_name_from_path(uu, ".device", &dd);
fprintf(f, "After=%1$s\nRequires=%1$s\n", dd);
} else
- fprintf(f, "RequiresMountsFor=%s\n", password);
+ fprintf(f, "RequiresMountsFor=%s\n", password_escaped);
}
}
}
- if (is_device_path(u))
+ if (path_startswith(u, "/dev/")) {
fprintf(f,
"BindsTo=%s\n"
"After=%s\n"
"Before=umount.target\n",
d, d);
- else
+
+ if (swap)
+ fputs_unlocked("Before=dev-mapper-%i.swap\n",
+ f);
+ } else
fprintf(f,
"RequiresMountsFor=%s\n",
- u);
+ u_escaped);
+
r = generator_write_timeouts(arg_dest, device, name, options, &filtered);
if (r < 0)
return r;
+ 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 */
"ExecStart=" SYSTEMD_CRYPTSETUP_PATH " attach '%s' '%s' '%s' '%s'\n"
"ExecStop=" SYSTEMD_CRYPTSETUP_PATH " detach '%s'\n",
- name, u, strempty(password), strempty(filtered),
- name);
+ name_escaped, u_escaped, strempty(password_escaped), strempty(filtered_escaped),
+ name_escaped);
if (tmp)
fprintf(f,
"ExecStartPost=/sbin/mke2fs '/dev/mapper/%s'\n",
- name);
+ name_escaped);
if (swap)
fprintf(f,
"ExecStartPost=/sbin/mkswap '/dev/mapper/%s'\n",
- name);
+ name_escaped);
r = fflush_and_check(f);
if (r < 0)
return log_error_errno(r, "Failed to write file %s: %m", p);
- from = strjoina("../", n);
-
if (!noauto) {
+ r = generator_add_symlink(arg_dest, d, "wants", n);
+ if (r < 0)
+ return r;
- to = strjoin(arg_dest, "/", d, ".wants/", n);
- if (!to)
- return log_oom();
-
- mkdir_parents_label(to, 0755);
- if (symlink(from, to) < 0)
- return log_error_errno(errno, "Failed to create symlink %s: %m", to);
-
- free(to);
- if (!nofail)
- to = strjoin(arg_dest, "/cryptsetup.target.requires/", n);
- else
- to = strjoin(arg_dest, "/cryptsetup.target.wants/", n);
- if (!to)
- return log_oom();
-
- mkdir_parents_label(to, 0755);
- if (symlink(from, to) < 0)
- return log_error_errno(errno, "Failed to create symlink %s: %m", to);
+ r = generator_add_symlink(arg_dest,
+ netdev ? "remote-cryptsetup.target" : "cryptsetup.target",
+ nofail ? "wants" : "requires", n);
+ if (r < 0)
+ return r;
}
- free(to);
- to = strjoin(arg_dest, "/dev-mapper-", e, ".device.requires/", n);
- if (!to)
- return log_oom();
-
- mkdir_parents_label(to, 0755);
- if (symlink(from, to) < 0)
- return log_error_errno(errno, "Failed to create symlink %s: %m", to);
+ dmname = strjoina("dev-mapper-", e, ".device");
+ r = generator_add_symlink(arg_dest, dmname, "requires", n);
+ if (r < 0)
+ return r;
if (!noauto && !nofail) {
- _cleanup_free_ char *dmname;
- dmname = strjoin("dev-mapper-", e, ".device");
- if (!dmname)
- return log_oom();
-
r = write_drop_in(arg_dest, dmname, 90, "device-timeout",
"# Automatically generated by systemd-cryptsetup-generator \n\n"
"[Unit]\nJobTimeoutSec=0");
return 0;
}
-static void free_arg_disks(void) {
- crypto_device *d;
-
- while ((d = hashmap_steal_first(arg_disks))) {
- free(d->uuid);
- free(d->keyfile);
- free(d->name);
- free(d->options);
- free(d);
- }
-
- hashmap_free(arg_disks);
+static void crypt_device_free(crypto_device *d) {
+ free(d->uuid);
+ free(d->keyfile);
+ free(d->name);
+ free(d->options);
+ free(d);
}
static crypto_device *get_crypto_device(const char *uuid) {
d->create = arg_whitelist = true;
- free(d->name);
- d->name = uuid_value;
- uuid_value = NULL;
+ free_and_replace(d->name, uuid_value);
} else
log_warning("Failed to parse luks name switch %s. Ignoring.", value);
}
crypttab_line++;
l = strstrip(line);
- if (*l == '#' || *l == 0)
+ if (IN_SET(*l, 0, '#'))
continue;
k = sscanf(l, "%ms %ms %ms %ms", &name, &device, &keyfile, &options);
r = 0;
finish:
- free_arg_disks();
+ hashmap_free_with_destructor(arg_disks, crypt_device_free);
free(arg_default_options);
free(arg_default_keyfile);