cryptsetup-generator.c revision 66aaf85e178492c27f699d9c94c84a98466a1435
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen This file is part of systemd.
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen Copyright 2010 Lennart Poettering
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen systemd is free software; you can redistribute it and/or modify it
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen under the terms of the GNU Lesser General Public License as published by
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen the Free Software Foundation; either version 2.1 of the License, or
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen (at your option) any later version.
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen systemd is distributed in the hope that it will be useful, but
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen WITHOUT ANY WARRANTY; without even the implied warranty of
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen Lesser General Public License for more details.
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen You should have received a copy of the GNU Lesser General Public License
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen along with systemd; If not, see <http://www.gnu.org/licenses/>.
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersenstatic bool arg_enabled = true;
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersenstatic bool arg_read_crypttab = true;
3aeb37bc4f32b5edc334f2ac7c5d3c7b0a121328Tom Gundersenstatic bool has_option(const char *haystack, const char *needle) {
c6f7c917a1b494d4455800823472227463f87438Tom Gundersen const char *f = haystack;
a501033335ed402c8f7e86fe41a15531ba69abd7Tom Gundersen return false;
2ad8416dd057e7e3185169609ca3006e7649f576Zbigniew Jędrzejewski-Szmek if (f[l] != 0 && f[l] != ',') {
5b9d4dc05560ddda89e48b6b39365824b15e1300Tom Gundersen return false;
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen const char *options) {
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen _cleanup_free_ char *p = NULL, *n = NULL, *d = NULL, *u = NULL, *to = NULL, *e = NULL;
977085794d2996320e345433403de75f662b0622Tom Gundersen log_error("Device '%s' cannot be both 'tmp' and 'swap'. Ignoring.", name);
847a8a5fed4d265dfa659917515c6f9bd1b8d5c4Tom Gundersen n = unit_name_build("systemd-cryptsetup", e, ".service");
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen log_error("Failed to create unit file %s: %m", p);
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen "# Automatically generated by systemd-cryptsetup-generator\n\n"
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen "Description=Cryptography Setup for %I\n"
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen "Documentation=man:crypttab(5) man:systemd-cryptsetup-generator(8) man:systemd-cryptsetup@.service(8)\n"
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen "SourcePath=/etc/crypttab\n"
d2df0d0ed3a88e491405b403e6022e6619750130Tom Gundersen "DefaultDependencies=no\n"
edf029b7fd9a5853a87d3ca99aac2922bb8a277eTom Gundersen "Conflicts=umount.target\n"
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen "BindsTo=dev-mapper-%i.device\n"
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen "IgnoreOnIsolate=true\n"
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen "After=systemd-readahead-collect.service systemd-readahead-replay.service\n",
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen "Before=cryptsetup.target\n");
43b3a5ef61859f06cdbaf26765cab8e1adac4296Tom Gundersen if (STR_IN_SET(password, "/dev/urandom", "/dev/random", "/dev/hw_random"))
43b3a5ef61859f06cdbaf26765cab8e1adac4296Tom Gundersen fputs("After=systemd-random-seed.service\n", f);
43b3a5ef61859f06cdbaf26765cab8e1adac4296Tom Gundersen else if (!streq(password, "-") && !streq(password, "none")) {
6e37cd2f4af8928d905203108a4331e375d7127cThomas Hindoe Paaboel Andersen dd = unit_name_from_path(uu, ".device");
187dc6e554f2d5b4b5a3bee72c73ff5df6418aa6Thomas Hindoe Paaboel Andersen fprintf(f, "After=%1$s\nRequires=%1$s\n", dd);
6916ec29afd488d91e7e0fcbcc2e006b4e5f28dfTom Gundersen fprintf(f, "RequiresMountsFor=%s\n", password);
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen "BindsTo=%s\n"
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen "Before=umount.target\n",
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen "RequiresMountsFor=%s\n",
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen "\n[Service]\n"
5fde13d748749f0e06e2e6cdd15f0980a79ea82cTom Gundersen "Type=oneshot\n"
5fde13d748749f0e06e2e6cdd15f0980a79ea82cTom Gundersen "RemainAfterExit=yes\n"
5fde13d748749f0e06e2e6cdd15f0980a79ea82cTom Gundersen "TimeoutSec=0\n" /* the binary handles timeouts anyway */
5fde13d748749f0e06e2e6cdd15f0980a79ea82cTom Gundersen "ExecStart=" SYSTEMD_CRYPTSETUP_PATH " attach '%s' '%s' '%s' '%s'\n"
e9f3d2d508bfd9fb5b54e82994bda365a71eb864Zbigniew Jędrzejewski-Szmek "ExecStop=" SYSTEMD_CRYPTSETUP_PATH " detach '%s'\n",
e9f3d2d508bfd9fb5b54e82994bda365a71eb864Zbigniew Jędrzejewski-Szmek name, u, strempty(password), strempty(options),
36f822c4bd077f9121757e24b6516e5c7ada63b5Zbigniew Jędrzejewski-Szmek "ExecStartPost=/sbin/mke2fs '/dev/mapper/%s'\n",
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen "ExecStartPost=/sbin/mkswap '/dev/mapper/%s'\n",
74df0fca09b3c31ed19e14ba80f996fdff772417Lennart Poettering to = strjoin(arg_dest, "/", d, ".wants/", n, NULL);
ff83aac3647e21f31ac5e2b575ec1285dc585f6bTom Gundersen log_error("Failed to create symlink %s: %m", to);
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen to = strjoin(arg_dest, "/cryptsetup.target.requires/", n, NULL);
edf029b7fd9a5853a87d3ca99aac2922bb8a277eTom Gundersen to = strjoin(arg_dest, "/cryptsetup.target.wants/", n, NULL);
f61942250a43a123580d7bbe5d7873dc5118ed97Tom Gundersen log_error("Failed to create symlink %s: %m", to);
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen to = strjoin(arg_dest, "/dev-mapper-", e, ".device.requires/", n, NULL);
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen log_error("Failed to create symlink %s: %m", to);
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen p = strjoin(arg_dest, "/dev-mapper-", e, ".device.d/50-job-timeout-sec-0.conf", NULL);
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen "# Automatically generated by systemd-cryptsetup-generator\n\n"
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen "JobTimeoutSec=0\n"); /* the binary handles timeouts anyway */
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen log_error("Failed to write device drop-in: %s", strerror(-r));
bf175aafd20c9ef974709ef12c5acf836121af33Tom Gundersenstatic int parse_proc_cmdline_item(const char *key, const char *value) {
be32eb9b7fbcb22e4b648086d644135e38279633Tom Gundersen if (STR_IN_SET(key, "luks", "rd.luks") && value) {
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen log_warning("Failed to parse luks switch %s. Ignoring.", value);
be32eb9b7fbcb22e4b648086d644135e38279633Tom Gundersen } else if (STR_IN_SET(key, "luks.crypttab", "rd.luks.crypttab") && value) {
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen log_warning("Failed to parse luks crypttab switch %s. Ignoring.", value);
f1ac700248f231b7bdac2aafe8c35650efddb89fTom Gundersen } else if (STR_IN_SET(key, "luks.uuid", "rd.luks.uuid") && value) {
f1ac700248f231b7bdac2aafe8c35650efddb89fTom Gundersen } else if (STR_IN_SET(key, "luks.options", "rd.luks.options") && value) {
16b9b87aeee9353b5b8dae6089a69752422a5b09Tom Gundersen } else if (STR_IN_SET(key, "luks.key", "rd.luks.key") && value) {
9bf3b53533cdc9b95c921b71da755401f223f765Lennart Poettering } else if (startswith(key, "luks.") || startswith(key, "rd.luks."))
16b9b87aeee9353b5b8dae6089a69752422a5b09Tom Gundersen log_warning("Unknown kernel switch %s. Ignoring.", key);
9bf3b53533cdc9b95c921b71da755401f223f765Lennart Poettering unsigned n = 0;
16b9b87aeee9353b5b8dae6089a69752422a5b09Tom Gundersen log_error("This program takes three or no arguments.");
3e137a1b9a0eac2bf43d493d3302c3c959b6ccdbTom Gundersen if (parse_proc_cmdline(parse_proc_cmdline_item) < 0)
3e137a1b9a0eac2bf43d493d3302c3c959b6ccdbTom Gundersen log_error("Failed to open /etc/crypttab: %m");
43b3a5ef61859f06cdbaf26765cab8e1adac4296Tom Gundersen log_error("Failed to stat /etc/crypttab: %m");
43b3a5ef61859f06cdbaf26765cab8e1adac4296Tom Gundersen /* If we readd support for specifying passphrases
f61942250a43a123580d7bbe5d7873dc5118ed97Tom Gundersen * directly in crypttabe we should upgrade the warning
5fde13d748749f0e06e2e6cdd15f0980a79ea82cTom Gundersen * below, though possibly only if a passphrase is
daeb71a36a98834664e4d95773a3629b746f4db8Tom Gundersen * specified directly. */
5fde13d748749f0e06e2e6cdd15f0980a79ea82cTom Gundersen log_debug("/etc/crypttab is world-readable. This is usually not a good idea.");
5fde13d748749f0e06e2e6cdd15f0980a79ea82cTom Gundersen _cleanup_free_ char *name = NULL, *device = NULL, *password = NULL, *options = NULL;
5fde13d748749f0e06e2e6cdd15f0980a79ea82cTom Gundersen if (*l == '#' || *l == 0)
5fde13d748749f0e06e2e6cdd15f0980a79ea82cTom Gundersen k = sscanf(l, "%ms %ms %ms %ms", &name, &device, &password, &options);
5fde13d748749f0e06e2e6cdd15f0980a79ea82cTom Gundersen log_error("Failed to parse /etc/crypttab:%u, ignoring.", n);
3e137a1b9a0eac2bf43d493d3302c3c959b6ccdbTom Gundersen If options are specified on the kernel commandline, let them override
3e137a1b9a0eac2bf43d493d3302c3c959b6ccdbTom Gundersen the ones from crypttab.
3e137a1b9a0eac2bf43d493d3302c3c959b6ccdbTom Gundersen _cleanup_free_ char *proc_uuid = NULL, *proc_options = NULL;
daeb71a36a98834664e4d95773a3629b746f4db8Tom Gundersen const char *p = *i;
5fde13d748749f0e06e2e6cdd15f0980a79ea82cTom Gundersen k = sscanf(p, "%m[0-9a-fA-F-]=%ms", &proc_uuid, &proc_options);
a669ea9860900d5cdebbc4cb9aaea72db7e28a02Tom Gundersen If luks UUIDs are specified on the kernel command line, use them as a filter
a669ea9860900d5cdebbc4cb9aaea72db7e28a02Tom Gundersen for /etc/crypttab and only generate units for those.
5fde13d748749f0e06e2e6cdd15f0980a79ea82cTom Gundersen _cleanup_free_ char *proc_device = NULL, *proc_name = NULL;
16b9b87aeee9353b5b8dae6089a69752422a5b09Tom Gundersen const char *p = *i;
af6f0d422c521374ee6a2dd92df5935a5a476ae5Tom Gundersen if (streq(proc_device, device) || streq(proc_name, name)) {
be32eb9b7fbcb22e4b648086d644135e38279633Tom Gundersen if (create_disk(name, device, password, options) < 0)
847a8a5fed4d265dfa659917515c6f9bd1b8d5c4Tom Gundersen } else if (create_disk(name, device, password, options) < 0)
847a8a5fed4d265dfa659917515c6f9bd1b8d5c4Tom Gundersen Generate units for those UUIDs, which were specified
847a8a5fed4d265dfa659917515c6f9bd1b8d5c4Tom Gundersen on the kernel command line and not yet written.
be32eb9b7fbcb22e4b648086d644135e38279633Tom Gundersen _cleanup_free_ char *name = NULL, *device = NULL, *options = NULL;
be32eb9b7fbcb22e4b648086d644135e38279633Tom Gundersen const char *p = *i;
if (arg_options) {
} else if (!options) {
if (!options) {
log_oom();
goto cleanup;
if (!options) {
if (!options) {
log_oom();
goto cleanup;
goto cleanup;