Systemd/src/cryptsetup/cryptsetup-generator.c
Ondrej Kozina a8574d0055 cryptsetup-generator: add detached LUKS header support
Adds support for LUKS detached header device on kernel
command line. It's introduced via extension to existing
luks.options 'header=' argument beyond colon (see examples
below). If LUKS header device is specified it's expected
to contain filesystem with LUKS header image on a path
specified in the first part of header specification.

The second parameter 'luks.data' specifies LUKS data device
supposed to be paired with detached LUKS header (note that
encrypted LUKS data device with detached header is unrecognisable
by standard blkid probe).

This adds support for LUKS encrypted rootfs partition with
detached header. It can also be used for initializing online LUKS2
encryption of data device.

Examples:
    luks.data=<luks_uuid>=/dev/sdz
    luks.data=<luks_uuid>=/dev/vg/lv
    luks.data=<luks_uuid>=/dev/mapper/lv
    luks.data=<luks_uuid>=PARTUUID=<part_uuid>
    luks.data=<luks_uuid>=PARTLABEL=<part_uuid>

    luks.options=<luks_uuid>=header=/header/path:UUID=<fs_uuid>
    luks.options=<luks_uuid>=header=/header/path:PARTUUID=<part_uuid>
    luks.options=<luks_uuid>=header=/header/path:PARTLABEL=<part_label>
    luks.options=<luks_uuid>=header=/header/path:LABEL=<fs_label>
    luks.options=<luks_uuid>=header=/header/path:/dev/sdx
    luks.options=<luks_uuid>=header=/header/path:/dev/vg/lv

The '/header/path' is considered to be relative location within
filesystem residing on the header device specified beyond colon
character
2020-09-25 17:01:36 +02:00

911 lines
30 KiB
C

/* SPDX-License-Identifier: LGPL-2.1+ */
#include <errno.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include "alloc-util.h"
#include "dropin.h"
#include "escape.h"
#include "fd-util.h"
#include "fileio.h"
#include "fstab-util.h"
#include "generator.h"
#include "hashmap.h"
#include "id128-util.h"
#include "log.h"
#include "mkdir.h"
#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"
#include "util.h"
typedef struct crypto_device {
char *uuid;
char *keyfile;
char *keydev;
char *headerdev;
char *datadev;
char *name;
char *options;
bool create;
} crypto_device;
static const char *arg_dest = NULL;
static bool arg_enabled = true;
static bool arg_read_crypttab = true;
static const char *arg_crypttab = NULL;
static const char *arg_runtime_directory = NULL;
static bool arg_allow_list = false;
static Hashmap *arg_disks = NULL;
static char *arg_default_options = NULL;
static char *arg_default_keyfile = NULL;
STATIC_DESTRUCTOR_REGISTER(arg_disks, hashmap_freep);
STATIC_DESTRUCTOR_REGISTER(arg_default_options, freep);
STATIC_DESTRUCTOR_REGISTER(arg_default_keyfile, freep);
static int split_locationspec(const char *locationspec, char **ret_file, char **ret_device) {
_cleanup_free_ char *file = NULL, *device = NULL;
const char *c;
assert(ret_file);
assert(ret_device);
if (!locationspec) {
*ret_file = *ret_device = NULL;
return 0;
}
c = strrchr(locationspec, ':');
if (c) {
/* The device part has to be either an absolute path to device node (/dev/something,
* /dev/foo/something, or even possibly /dev/foo/something:part), or a fstab device
* specification starting with LABEL= or similar. The file part has the same syntax.
*
* Let's try to guess if the second part looks like a device specification, or just part of a
* filename with a colon. fstab_node_to_udev_node() will convert the fstab device syntax to
* an absolute path. If we didn't get an absolute path, assume that it is just part of the
* first file argument. */
device = fstab_node_to_udev_node(c + 1);
if (!device)
return log_oom();
if (path_is_absolute(device))
file = strndup(locationspec, c-locationspec);
else {
log_debug("Location specification argument contains a colon, but \"%s\" doesn't look like a device specification.\n"
"Assuming that \"%s\" is a single device specification.",
c + 1, locationspec);
device = mfree(device);
c = NULL;
}
}
if (!c)
/* No device specified */
file = strdup(locationspec);
if (!file)
return log_oom();
*ret_file = TAKE_PTR(file);
*ret_device = TAKE_PTR(device);
return 0;
}
static int generate_device_mount(
const char *name,
const char *device,
const char *type_prefix, /* "keydev" or "headerdev" */
const char *device_timeout,
bool canfail,
bool readonly,
char **unit,
char **mount) {
_cleanup_free_ char *u = NULL, *where = NULL, *name_escaped = NULL, *device_unit = NULL;
_cleanup_fclose_ FILE *f = NULL;
int r;
usec_t timeout_us;
assert(name);
assert(device);
assert(unit);
assert(mount);
r = mkdir_parents(arg_runtime_directory, 0755);
if (r < 0)
return r;
r = mkdir(arg_runtime_directory, 0700);
if (r < 0 && errno != EEXIST)
return -errno;
name_escaped = cescape(name);
if (!name_escaped)
return -ENOMEM;
where = strjoin(arg_runtime_directory, "/", type_prefix, "-", name_escaped);
if (!where)
return -ENOMEM;
r = mkdir(where, 0700);
if (r < 0 && errno != EEXIST)
return -errno;
r = unit_name_from_path(where, ".mount", &u);
if (r < 0)
return r;
r = generator_open_unit_file(arg_dest, NULL, u, &f);
if (r < 0)
return r;
fprintf(f,
"[Unit]\n"
"DefaultDependencies=no\n\n"
"[Mount]\n"
"What=%s\n"
"Where=%s\n"
"Options=%s%s\n", device, where, readonly ? "ro" : "rw", canfail ? ",nofail" : "");
if (device_timeout) {
r = parse_sec_fix_0(device_timeout, &timeout_us);
if (r >= 0) {
r = unit_name_from_path(device, ".device", &device_unit);
if (r < 0)
return log_error_errno(r, "Failed to generate unit name: %m");
r = write_drop_in_format(arg_dest, device_unit, 90, "device-timeout",
"# Automatically generated by systemd-cryptsetup-generator \n\n"
"[Unit]\nJobRunningTimeoutSec=%s", device_timeout);
if (r < 0)
return log_error_errno(r, "Failed to write device drop-in: %m");
} else
log_warning_errno(r, "Failed to parse %s, ignoring: %m", device_timeout);
}
r = fflush_and_check(f);
if (r < 0)
return r;
*unit = TAKE_PTR(u);
*mount = TAKE_PTR(where);
return 0;
}
static int generate_device_umount(const char *name,
const char *device_mount,
const char *type_prefix, /* "keydev" or "headerdev" */
char **ret_umount_unit) {
_cleanup_fclose_ FILE *f = NULL;
_cleanup_free_ char *u = NULL, *name_escaped = NULL, *mount = NULL;
int r;
assert(name);
assert(ret_umount_unit);
name_escaped = cescape(name);
if (!name_escaped)
return -ENOMEM;
u = strjoin(type_prefix, "-", name_escaped, "-umount.service");
if (!u)
return -ENOMEM;
r = unit_name_from_path(device_mount, ".mount", &mount);
if (r < 0)
return r;
r = generator_open_unit_file(arg_dest, NULL, u, &f);
if (r < 0)
return r;
fprintf(f,
"[Unit]\n"
"DefaultDependencies=no\n"
"After=%s\n\n"
"[Service]\n"
"ExecStart=-" UMOUNT_PATH " %s\n\n", mount, device_mount);
r = fflush_and_check(f);
if (r < 0)
return r;
*ret_umount_unit = TAKE_PTR(u);
return 0;
}
static int print_dependencies(FILE *f, const char* device_path) {
int r;
if (STR_IN_SET(device_path, "-", "none"))
/* None, nothing to do */
return 0;
if (PATH_IN_SET(device_path,
"/dev/urandom",
"/dev/random",
"/dev/hw_random",
"/dev/hwrng")) {
/* RNG device, add random dep */
fputs("After=systemd-random-seed.service\n", f);
return 0;
}
_cleanup_free_ char *udev_node = fstab_node_to_udev_node(device_path);
if (!udev_node)
return log_oom();
if (path_equal(udev_node, "/dev/null"))
return 0;
if (path_startswith(udev_node, "/dev/")) {
/* We are dealing with a block device, add dependency for corresponding unit */
_cleanup_free_ char *unit = NULL;
r = unit_name_from_path(udev_node, ".device", &unit);
if (r < 0)
return log_error_errno(r, "Failed to generate unit name: %m");
fprintf(f,
"After=%1$s\n"
"Requires=%1$s\n", unit);
} else {
/* Regular file, add mount dependency */
_cleanup_free_ char *escaped_path = specifier_escape(device_path);
if (!escaped_path)
return log_oom();
fprintf(f, "RequiresMountsFor=%s\n", escaped_path);
}
return 0;
}
static int create_disk(
const char *name,
const char *device,
const char *password,
const char *keydev,
const char *headerdev,
const char *options,
const char *source) {
_cleanup_free_ char *n = NULL, *d = NULL, *u = NULL, *e = NULL,
*keydev_mount = NULL, *keyfile_timeout_value = NULL,
*filtered = NULL, *u_escaped = NULL, *name_escaped = NULL, *header_path = NULL, *password_buffer = NULL,
*tmp_fstype = NULL, *filtered_header = NULL, *headerdev_mount = NULL;
_cleanup_fclose_ FILE *f = NULL;
const char *dmname;
bool noauto, nofail, swap, netdev, attach_in_initrd;
int r, detached_header, keyfile_can_timeout, tmp;
assert(name);
assert(device);
noauto = fstab_test_yes_no_option(options, "noauto\0" "auto\0");
nofail = fstab_test_yes_no_option(options, "nofail\0" "fail\0");
swap = fstab_test_option(options, "swap\0");
netdev = fstab_test_option(options, "_netdev\0");
attach_in_initrd = fstab_test_option(options, "x-initrd.attach\0");
keyfile_can_timeout = fstab_filter_options(options, "keyfile-timeout\0", NULL, &keyfile_timeout_value, NULL);
if (keyfile_can_timeout < 0)
return log_error_errno(keyfile_can_timeout, "Failed to parse keyfile-timeout= option value: %m");
detached_header = fstab_filter_options(
options,
"header\0",
NULL,
&header_path,
headerdev ? &filtered_header : NULL);
if (detached_header < 0)
return log_error_errno(detached_header, "Failed to parse header= option value: %m");
tmp = fstab_filter_options(options, "tmp\0", NULL, &tmp_fstype, NULL);
if (tmp < 0)
return log_error_errno(tmp, "Failed to parse tmp= option value: %m");
if (tmp && swap)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Device '%s' cannot be both 'tmp' and 'swap'. Ignoring.",
name);
name_escaped = specifier_escape(name);
if (!name_escaped)
return log_oom();
e = unit_name_escape(name);
if (!e)
return log_oom();
u = fstab_node_to_udev_node(device);
if (!u)
return log_oom();
r = unit_name_build("systemd-cryptsetup", e, ".service", &n);
if (r < 0)
return log_error_errno(r, "Failed to generate unit name: %m");
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");
if (keydev && !password)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Key device is specified, but path to the password file is missing.");
r = generator_open_unit_file(arg_dest, NULL, n, &f);
if (r < 0)
return r;
r = generator_write_cryptsetup_unit_section(f, source);
if (r < 0)
return r;
if (netdev)
fprintf(f, "After=remote-fs-pre.target\n");
/* If initrd takes care of attaching the disk then it should also detach it during shutdown. */
if (!attach_in_initrd)
fprintf(f, "Conflicts=umount.target\n");
if (keydev) {
_cleanup_free_ char *unit = NULL, *umount_unit = NULL;
r = generate_device_mount(
name,
keydev,
"keydev",
keyfile_timeout_value,
/* canfail = */ keyfile_can_timeout > 0,
/* readonly= */ true,
&unit,
&keydev_mount);
if (r < 0)
return log_error_errno(r, "Failed to generate keydev mount unit: %m");
r = generate_device_umount(name, keydev_mount, "keydev", &umount_unit);
if (r < 0)
return log_error_errno(r, "Failed to generate keydev umount unit: %m");
password_buffer = path_join(keydev_mount, password);
if (!password_buffer)
return log_oom();
password = password_buffer;
fprintf(f, "After=%s\n", unit);
if (keyfile_can_timeout > 0)
fprintf(f, "Wants=%s\n", unit);
else
fprintf(f, "Requires=%s\n", unit);
if (umount_unit) {
fprintf(f,
"Wants=%s\n"
"Before=%s\n",
umount_unit,
umount_unit
);
}
}
if (headerdev) {
_cleanup_free_ char *unit = NULL, *umount_unit = NULL, *p = NULL;
r = generate_device_mount(
name,
headerdev,
"headerdev",
NULL,
/* canfail= */ false, /* header is always necessary */
/* readonly= */ false, /* LUKS2 recovery requires rw header access */
&unit,
&headerdev_mount);
if (r < 0)
return log_error_errno(r, "Failed to generate header device mount unit: %m");
r = generate_device_umount(name, headerdev_mount, "headerdev", &umount_unit);
if (r < 0)
return log_error_errno(r, "Failed to generate header device umount unit: %m");
p = path_join(headerdev_mount, header_path);
if (!p)
return log_oom();
free_and_replace(header_path, p);
if (isempty(filtered_header))
p = strjoin("header=", header_path);
else
p = strjoin(filtered_header, ",header=", header_path);
if (!p)
return log_oom();
free_and_replace(filtered_header, p);
options = filtered_header;
fprintf(f, "After=%s\n"
"Requires=%s\n", unit, unit);
if (umount_unit) {
fprintf(f,
"Wants=%s\n"
"Before=%s\n",
umount_unit,
umount_unit
);
}
}
if (!nofail)
fprintf(f,
"Before=%s\n",
netdev ? "remote-cryptsetup.target" : "cryptsetup.target");
if (password && !keydev) {
r = print_dependencies(f, password);
if (r < 0)
return r;
}
/* Check if a header option was specified */
if (detached_header > 0 && !headerdev) {
r = print_dependencies(f, header_path);
if (r < 0)
return r;
}
if (path_startswith(u, "/dev/"))
fprintf(f,
"BindsTo=%s\n"
"After=%s\n"
"Before=umount.target\n",
d, d);
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) */
fprintf(f,
"RequiresMountsFor=%s\n"
"Requires=systemd-tmpfiles-setup-dev.service\n"
"After=systemd-tmpfiles-setup-dev.service\n",
u_escaped);
r = generator_write_timeouts(arg_dest, device, name, options, &filtered);
if (r < 0)
log_warning_errno(r, "Failed to write device timeout drop-in: %m");
r = generator_write_cryptsetup_service_section(f, name, u, password, filtered);
if (r < 0)
return r;
if (tmp) {
_cleanup_free_ char *tmp_fstype_escaped = NULL;
if (tmp_fstype) {
tmp_fstype_escaped = specifier_escape(tmp_fstype);
if (!tmp_fstype_escaped)
return log_oom();
}
fprintf(f,
"ExecStartPost=" ROOTLIBEXECDIR "/systemd-makefs '%s' '/dev/mapper/%s'\n",
tmp_fstype_escaped ?: "ext4", name_escaped);
}
if (swap)
fprintf(f,
"ExecStartPost=" ROOTLIBEXECDIR "/systemd-makefs swap '/dev/mapper/%s'\n",
name_escaped);
r = fflush_and_check(f);
if (r < 0)
return log_error_errno(r, "Failed to write unit file %s: %m", n);
if (!noauto) {
r = generator_add_symlink(arg_dest,
netdev ? "remote-cryptsetup.target" : "cryptsetup.target",
nofail ? "wants" : "requires", n);
if (r < 0)
return r;
}
dmname = strjoina("dev-mapper-", e, ".device");
r = generator_add_symlink(arg_dest, dmname, "requires", n);
if (r < 0)
return r;
if (!noauto && !nofail) {
r = write_drop_in(arg_dest, dmname, 40, "device-timeout",
"# Automatically generated by systemd-cryptsetup-generator\n\n"
"[Unit]\nJobTimeoutSec=0");
if (r < 0)
log_warning_errno(r, "Failed to write device timeout drop-in: %m");
}
return 0;
}
static crypto_device* crypt_device_free(crypto_device *d) {
if (!d)
return NULL;
free(d->uuid);
free(d->keyfile);
free(d->keydev);
free(d->name);
free(d->options);
return mfree(d);
}
static crypto_device *get_crypto_device(const char *uuid) {
int r;
crypto_device *d;
assert(uuid);
d = hashmap_get(arg_disks, uuid);
if (!d) {
d = new0(struct crypto_device, 1);
if (!d)
return NULL;
d->uuid = strdup(uuid);
if (!d->uuid)
return mfree(d);
r = hashmap_put(arg_disks, d->uuid, d);
if (r < 0) {
free(d->uuid);
return mfree(d);
}
}
return d;
}
static bool warn_uuid_invalid(const char *uuid, const char *key) {
assert(key);
if (!id128_is_valid(uuid)) {
log_warning("Failed to parse %s= kernel command line switch. UUID is invalid, ignoring.", key);
return true;
}
return false;
}
static int filter_header_device(const char *options,
char **ret_headerdev,
char **ret_filtered_headerdev_options) {
int r;
_cleanup_free_ char *headerfile = NULL, *headerdev = NULL, *headerspec = NULL,
*filtered_headerdev = NULL, *filtered_headerspec = NULL;
assert(ret_headerdev);
assert(ret_filtered_headerdev_options);
r = fstab_filter_options(options, "header\0", NULL, &headerspec, &filtered_headerspec);
if (r < 0)
return log_error_errno(r, "Failed to parse header= option value: %m");
if (r > 0) {
r = split_locationspec(headerspec, &headerfile, &headerdev);
if (r < 0)
return r;
if (isempty(filtered_headerspec))
filtered_headerdev = strjoin("header=", headerfile);
else
filtered_headerdev = strjoin(filtered_headerspec, ",header=", headerfile);
if (!filtered_headerdev)
return log_oom();
} else
filtered_headerdev = TAKE_PTR(filtered_headerspec);
*ret_filtered_headerdev_options = TAKE_PTR(filtered_headerdev);
*ret_headerdev = TAKE_PTR(headerdev);
return 0;
}
static int parse_proc_cmdline_item(const char *key, const char *value, void *data) {
_cleanup_free_ char *uuid = NULL, *uuid_value = NULL;
crypto_device *d;
int r;
if (streq(key, "luks")) {
r = value ? parse_boolean(value) : 1;
if (r < 0)
log_warning("Failed to parse luks= kernel command line switch %s. Ignoring.", value);
else
arg_enabled = r;
} else if (streq(key, "luks.crypttab")) {
r = value ? parse_boolean(value) : 1;
if (r < 0)
log_warning("Failed to parse luks.crypttab= kernel command line switch %s. Ignoring.", value);
else
arg_read_crypttab = r;
} else if (streq(key, "luks.uuid")) {
if (proc_cmdline_value_missing(key, value))
return 0;
d = get_crypto_device(startswith(value, "luks-") ?: value);
if (!d)
return log_oom();
d->create = arg_allow_list = true;
} else if (streq(key, "luks.options")) {
_cleanup_free_ char *headerdev = NULL, *filtered_headerdev_options = NULL;
if (proc_cmdline_value_missing(key, value))
return 0;
r = sscanf(value, "%m[0-9a-fA-F-]=%ms", &uuid, &uuid_value);
if (r != 2)
return free_and_strdup(&arg_default_options, value) < 0 ? log_oom() : 0;
if (warn_uuid_invalid(uuid, key))
return 0;
d = get_crypto_device(uuid);
if (!d)
return log_oom();
r = filter_header_device(uuid_value, &headerdev, &filtered_headerdev_options);
if (r < 0)
return r;
free_and_replace(d->options, filtered_headerdev_options);
free_and_replace(d->headerdev, headerdev);
} else if (streq(key, "luks.key")) {
size_t n;
_cleanup_free_ char *keyfile = NULL, *keydev = NULL;
const char *keyspec;
if (proc_cmdline_value_missing(key, value))
return 0;
n = strspn(value, ALPHANUMERICAL "-");
if (value[n] != '=') {
if (free_and_strdup(&arg_default_keyfile, value) < 0)
return log_oom();
return 0;
}
uuid = strndup(value, n);
if (!uuid)
return log_oom();
if (warn_uuid_invalid(uuid, key))
return 0;
d = get_crypto_device(uuid);
if (!d)
return log_oom();
keyspec = value + n + 1;
r = split_locationspec(keyspec, &keyfile, &keydev);
if (r < 0)
return r;
free_and_replace(d->keyfile, keyfile);
free_and_replace(d->keydev, keydev);
} else if (streq(key, "luks.data")) {
size_t n;
_cleanup_free_ char *datadev = NULL;
if (proc_cmdline_value_missing(key, value))
return 0;
n = strspn(value, ALPHANUMERICAL "-");
if (value[n] != '=') {
log_warning("Failed to parse luks.data= kernel command line switch. UUID is invalid, ignoring.");
return 0;
}
uuid = strndup(value, n);
if (!uuid)
return log_oom();
if (warn_uuid_invalid(uuid, key))
return 0;
d = get_crypto_device(uuid);
if (!d)
return log_oom();
datadev = fstab_node_to_udev_node(value + n + 1);
if (!datadev)
return log_oom();
free_and_replace(d->datadev, datadev);
} else if (streq(key, "luks.name")) {
if (proc_cmdline_value_missing(key, value))
return 0;
r = sscanf(value, "%m[0-9a-fA-F-]=%ms", &uuid, &uuid_value);
if (r == 2) {
d = get_crypto_device(uuid);
if (!d)
return log_oom();
d->create = arg_allow_list = true;
free_and_replace(d->name, uuid_value);
} else
log_warning("Failed to parse luks name switch %s. Ignoring.", value);
}
return 0;
}
static int add_crypttab_devices(void) {
_cleanup_fclose_ FILE *f = NULL;
unsigned crypttab_line = 0;
struct stat st;
int r;
if (!arg_read_crypttab)
return 0;
r = fopen_unlocked(arg_crypttab, "re", &f);
if (r < 0) {
if (errno != ENOENT)
log_error_errno(errno, "Failed to open %s: %m", arg_crypttab);
return 0;
}
if (fstat(fileno(f), &st) < 0) {
log_error_errno(errno, "Failed to stat %s: %m", arg_crypttab);
return 0;
}
for (;;) {
_cleanup_free_ char *line = NULL, *name = NULL, *device = NULL, *keyspec = NULL, *options = NULL, *keyfile = NULL, *keydev = NULL;
crypto_device *d = NULL;
char *l, *uuid;
int k;
r = read_line(f, LONG_LINE_MAX, &line);
if (r < 0)
return log_error_errno(r, "Failed to read %s: %m", arg_crypttab);
if (r == 0)
break;
crypttab_line++;
l = strstrip(line);
if (IN_SET(l[0], 0, '#'))
continue;
k = sscanf(l, "%ms %ms %ms %ms", &name, &device, &keyspec, &options);
if (k < 2 || k > 4) {
log_error("Failed to parse %s:%u, ignoring.", arg_crypttab, crypttab_line);
continue;
}
uuid = startswith(device, "UUID=");
if (!uuid)
uuid = path_startswith(device, "/dev/disk/by-uuid/");
if (!uuid)
uuid = startswith(name, "luks-");
if (uuid)
d = hashmap_get(arg_disks, uuid);
if (arg_allow_list && !d) {
log_info("Not creating device '%s' because it was not specified on the kernel command line.", name);
continue;
}
r = split_locationspec(keyspec, &keyfile, &keydev);
if (r < 0)
return r;
r = create_disk(name, device, keyfile, keydev, d ? d->headerdev : NULL, (d && d->options) ? d->options : options, arg_crypttab);
if (r < 0)
return r;
if (d)
d->create = false;
}
return 0;
}
static int add_proc_cmdline_devices(void) {
int r;
crypto_device *d;
HASHMAP_FOREACH(d, arg_disks) {
_cleanup_free_ char *device = NULL;
if (!d->create)
continue;
if (!d->name) {
d->name = strjoin("luks-", d->uuid);
if (!d->name)
return log_oom();
}
device = strjoin("UUID=", d->uuid);
if (!device)
return log_oom();
r = create_disk(d->name,
d->datadev ?: device,
d->keyfile ?: arg_default_keyfile,
d->keydev,
d->headerdev,
d->options ?: arg_default_options,
"/proc/cmdline");
if (r < 0)
return r;
}
return 0;
}
DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(crypt_device_hash_ops, char, string_hash_func, string_compare_func,
crypto_device, crypt_device_free);
static int run(const char *dest, const char *dest_early, const char *dest_late) {
int r;
assert_se(arg_dest = dest);
arg_crypttab = getenv("SYSTEMD_CRYPTTAB") ?: "/etc/crypttab";
arg_runtime_directory = getenv("RUNTIME_DIRECTORY") ?: "/run/systemd/cryptsetup";
arg_disks = hashmap_new(&crypt_device_hash_ops);
if (!arg_disks)
return log_oom();
r = proc_cmdline_parse(parse_proc_cmdline_item, NULL, PROC_CMDLINE_STRIP_RD_PREFIX);
if (r < 0)
return log_warning_errno(r, "Failed to parse kernel command line: %m");
if (!arg_enabled)
return 0;
r = add_crypttab_devices();
if (r < 0)
return r;
r = add_proc_cmdline_devices();
if (r < 0)
return r;
return 0;
}
DEFINE_MAIN_GENERATOR_FUNCTION(run);