1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
28 #include "unit-name.h"
33 static const char *arg_dest = "/tmp";
34 static bool arg_enabled = true;
35 static bool arg_read_crypttab = true;
37 static bool has_option(const char *haystack, const char *needle) {
38 const char *f = haystack;
48 while ((f = strstr(f, needle))) {
50 if (f > haystack && f[-1] != ',') {
55 if (f[l] != 0 && f[l] != ',') {
66 static int create_disk(
70 const char *options) {
72 _cleanup_free_ char *p = NULL, *n = NULL, *d = NULL, *u = NULL, *from = NULL, *to = NULL, *e = NULL;
73 _cleanup_fclose_ FILE *f = NULL;
74 bool noauto, nofail, tmp, swap;
79 noauto = has_option(options, "noauto");
80 nofail = has_option(options, "nofail");
81 tmp = has_option(options, "tmp");
82 swap = has_option(options, "swap");
85 log_error("Device '%s' cannot be both 'tmp' and 'swap'. Ignoring.", name);
89 n = unit_name_from_path_instance("systemd-cryptsetup", name, ".service");
93 p = strjoin(arg_dest, "/", n, NULL);
97 u = fstab_node_to_udev_node(device);
101 d = unit_name_from_path(u, ".device");
107 log_error("Failed to create unit file %s: %m", p);
112 "# Automatically generated by systemd-cryptsetup-generator\n\n"
114 "Description=Cryptography Setup for %I\n"
115 "Documentation=man:systemd-cryptsetup@.service(8) man:crypttab(5)\n"
116 "SourcePath=/etc/crypttab\n"
117 "Conflicts=umount.target\n"
118 "DefaultDependencies=no\n"
119 "BindsTo=dev-mapper-%i.device\n"
120 "IgnoreOnIsolate=true\n"
121 "After=systemd-readahead-collect.service systemd-readahead-replay.service\n",
126 "Before=cryptsetup.target\n");
129 if (streq(password, "/dev/urandom") ||
130 streq(password, "/dev/random") ||
131 streq(password, "/dev/hw_random"))
132 fputs("After=systemd-random-seed.service\n", f);
134 else if (!streq(password, "-") && !streq(password, "none")) {
135 _cleanup_free_ char *uu = fstab_node_to_udev_node(password);
139 if (is_device_path(uu)) {
140 _cleanup_free_ char *dd = unit_name_from_path(uu, ".device");
144 fprintf(f, "After=%1$s\nRequires=%1$s\n", dd);
146 fprintf(f, "RequiresMountsFor=%s\n", password);
150 if (is_device_path(u))
154 "Before=umount.target\n",
158 "RequiresMountsFor=%s\n",
164 "RemainAfterExit=yes\n"
165 "TimeoutSec=0\n" /* the binary handles timeouts anyway */
166 "ExecStart=" SYSTEMD_CRYPTSETUP_PATH " attach '%s' '%s' '%s' '%s'\n"
167 "ExecStop=" SYSTEMD_CRYPTSETUP_PATH " detach '%s'\n",
168 name, u, strempty(password), strempty(options),
173 "ExecStartPost=/sbin/mke2fs '/dev/mapper/%s'\n",
178 "ExecStartPost=/sbin/mkswap '/dev/mapper/%s'\n",
184 log_error("Failed to write file %s: %m", p);
188 if (asprintf(&from, "../%s", n) < 0)
193 to = strjoin(arg_dest, "/", d, ".wants/", n, NULL);
197 mkdir_parents_label(to, 0755);
198 if (symlink(from, to) < 0) {
199 log_error("Failed to create symlink %s: %m", to);
205 to = strjoin(arg_dest, "/cryptsetup.target.requires/", n, NULL);
207 to = strjoin(arg_dest, "/cryptsetup.target.wants/", n, NULL);
211 mkdir_parents_label(to, 0755);
212 if (symlink(from, to) < 0) {
213 log_error("Failed to create symlink %s: %m", to);
218 e = unit_name_escape(name);
223 to = strjoin(arg_dest, "/dev-mapper-", e, ".device.requires/", n, NULL);
227 mkdir_parents_label(to, 0755);
228 if (symlink(from, to) < 0) {
229 log_error("Failed to create symlink %s: %m", to);
233 if (!noauto && !nofail) {
236 p = strjoin(arg_dest, "/dev-mapper-", e, ".device.d/50-job-timeout-sec-0.conf", NULL);
240 mkdir_parents_label(p, 0755);
242 r = write_string_file(p,
243 "# Automatically generated by systemd-cryptsetup-generator\n\n"
245 "JobTimeoutSec=0\n"); /* the binary handles timeouts anyway */
253 static int parse_proc_cmdline(
254 char ***arg_proc_cmdline_disks,
255 char ***arg_proc_cmdline_options,
256 char **arg_proc_cmdline_keyfile) {
258 _cleanup_free_ char *line = NULL;
259 char *w = NULL, *state = NULL;
263 r = proc_cmdline(&line);
265 log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(-r));
269 FOREACH_WORD_QUOTED(w, l, line, state) {
270 _cleanup_free_ char *word = NULL;
272 word = strndup(w, l);
276 if (startswith(word, "luks=")) {
277 r = parse_boolean(word + 5);
279 log_warning("Failed to parse luks switch %s. Ignoring.", word + 5);
283 } else if (startswith(word, "rd.luks=")) {
286 r = parse_boolean(word + 8);
288 log_warning("Failed to parse luks switch %s. Ignoring.", word + 8);
293 } else if (startswith(word, "luks.crypttab=")) {
294 r = parse_boolean(word + 14);
296 log_warning("Failed to parse luks crypttab switch %s. Ignoring.", word + 14);
298 arg_read_crypttab = r;
300 } else if (startswith(word, "rd.luks.crypttab=")) {
303 r = parse_boolean(word + 17);
305 log_warning("Failed to parse luks crypttab switch %s. Ignoring.", word + 17);
307 arg_read_crypttab = r;
310 } else if (startswith(word, "luks.uuid=")) {
311 if (strv_extend(arg_proc_cmdline_disks, word + 10) < 0)
314 } else if (startswith(word, "rd.luks.uuid=")) {
317 if (strv_extend(arg_proc_cmdline_disks, word + 13) < 0)
321 } else if (startswith(word, "luks.options=")) {
322 if (strv_extend(arg_proc_cmdline_options, word + 13) < 0)
325 } else if (startswith(word, "rd.luks.options=")) {
328 if (strv_extend(arg_proc_cmdline_options, word + 16) < 0)
332 } else if (startswith(word, "luks.key=")) {
333 if (*arg_proc_cmdline_keyfile)
334 free(*arg_proc_cmdline_keyfile);
335 *arg_proc_cmdline_keyfile = strdup(word + 9);
336 if (!*arg_proc_cmdline_keyfile)
339 } else if (startswith(word, "rd.luks.key=")) {
342 if (*arg_proc_cmdline_keyfile)
343 free(*arg_proc_cmdline_keyfile);
344 *arg_proc_cmdline_keyfile = strdup(word + 12);
345 if (!*arg_proc_cmdline_keyfile)
349 } else if (startswith(word, "luks.") ||
350 (in_initrd() && startswith(word, "rd.luks."))) {
352 log_warning("Unknown kernel switch %s. Ignoring.", word);
356 strv_uniq(*arg_proc_cmdline_disks);
361 int main(int argc, char *argv[]) {
362 _cleanup_strv_free_ char **arg_proc_cmdline_disks_done = NULL;
363 _cleanup_strv_free_ char **arg_proc_cmdline_disks = NULL;
364 _cleanup_strv_free_ char **arg_proc_cmdline_options = NULL;
365 _cleanup_free_ char *arg_proc_cmdline_keyfile = NULL;
366 _cleanup_fclose_ FILE *f = NULL;
368 int r = EXIT_SUCCESS;
371 if (argc > 1 && argc != 4) {
372 log_error("This program takes three or no arguments.");
379 log_set_target(LOG_TARGET_SAFE);
380 log_parse_environment();
385 if (parse_proc_cmdline(&arg_proc_cmdline_disks, &arg_proc_cmdline_options, &arg_proc_cmdline_keyfile) < 0)
391 if (arg_read_crypttab) {
394 f = fopen("/etc/crypttab", "re");
400 log_error("Failed to open /etc/crypttab: %m");
406 if (fstat(fileno(f), &st) < 0) {
407 log_error("Failed to stat /etc/crypttab: %m");
412 /* If we readd support for specifying passphrases
413 * directly in crypttabe we should upgrade the warning
414 * below, though possibly only if a passphrase is
415 * specified directly. */
416 if (st.st_mode & 0005)
417 log_debug("/etc/crypttab is world-readable. This is usually not a good idea.");
420 char line[LINE_MAX], *l;
421 _cleanup_free_ char *name = NULL, *device = NULL, *password = NULL, *options = NULL;
424 if (!fgets(line, sizeof(line), f))
430 if (*l == '#' || *l == 0)
433 k = sscanf(l, "%ms %ms %ms %ms", &name, &device, &password, &options);
434 if (k < 2 || k > 4) {
435 log_error("Failed to parse /etc/crypttab:%u, ignoring.", n);
440 if (arg_proc_cmdline_options) {
442 If options are specified on the kernel commandline, let them override
443 the ones from crypttab.
445 STRV_FOREACH(i, arg_proc_cmdline_options) {
446 _cleanup_free_ char *proc_uuid = NULL, *proc_options = NULL;
449 k = sscanf(p, "%m[0-9a-fA-F-]=%ms", &proc_uuid, &proc_options);
450 if (k == 2 && streq(proc_uuid, device + 5)) {
460 if (arg_proc_cmdline_disks) {
462 If luks UUIDs are specified on the kernel command line, use them as a filter
463 for /etc/crypttab and only generate units for those.
465 STRV_FOREACH(i, arg_proc_cmdline_disks) {
466 _cleanup_free_ char *proc_device = NULL, *proc_name = NULL;
469 if (startswith(p, "luks-"))
472 proc_name = strappend("luks-", p);
473 proc_device = strappend("UUID=", p);
475 if (!proc_name || !proc_device)
478 if (streq(proc_device, device) || streq(proc_name, name)) {
479 if (create_disk(name, device, password, options) < 0)
482 if (strv_extend(&arg_proc_cmdline_disks_done, p) < 0)
487 if (create_disk(name, device, password, options) < 0)
494 STRV_FOREACH(i, arg_proc_cmdline_disks) {
496 Generate units for those UUIDs, which were specified
497 on the kernel command line and not yet written.
500 _cleanup_free_ char *name = NULL, *device = NULL, *options = NULL;
503 if (startswith(p, "luks-"))
506 if (strv_contains(arg_proc_cmdline_disks_done, p))
509 name = strappend("luks-", p);
510 device = strappend("UUID=", p);
512 if (!name || !device)
515 if (arg_proc_cmdline_options) {
517 If options are specified on the kernel commandline, use them.
521 STRV_FOREACH(j, arg_proc_cmdline_options) {
522 _cleanup_free_ char *proc_uuid = NULL, *proc_options = NULL;
526 k = sscanf(s, "%m[0-9a-fA-F-]=%ms", &proc_uuid, &proc_options);
528 if (streq(proc_uuid, device + 5)) {
531 options = strdup(proc_options);
535 } else if (!options) {
537 Fall back to options without a specified UUID
547 options = strdup("timeout=0");
552 if (create_disk(name, device, arg_proc_cmdline_keyfile, options) < 0)