]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/cryptsetup/cryptsetup-generator.c
core/socket: log errors when starting socket for this socket
[thirdparty/systemd.git] / src / cryptsetup / cryptsetup-generator.c
CommitLineData
e23a0ce8
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2010 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
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
e23a0ce8
LP
11 (at your option) any later version.
12
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
5430f7f2 16 Lesser General Public License for more details.
e23a0ce8 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
e23a0ce8
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <string.h>
23#include <errno.h>
24#include <unistd.h>
25
26#include "log.h"
27#include "util.h"
28#include "unit-name.h"
49e942b2 29#include "mkdir.h"
66a78c2b
LP
30#include "virt.h"
31#include "strv.h"
a860325e 32#include "fileio.h"
e23a0ce8 33
66a78c2b
LP
34static const char *arg_dest = "/tmp";
35static bool arg_enabled = true;
36static bool arg_read_crypttab = true;
e23a0ce8
LP
37
38static bool has_option(const char *haystack, const char *needle) {
39 const char *f = haystack;
40 size_t l;
41
f653f683
LP
42 assert(needle);
43
44 if (!haystack)
45 return false;
46
e23a0ce8
LP
47 l = strlen(needle);
48
49 while ((f = strstr(f, needle))) {
50
51 if (f > haystack && f[-1] != ',') {
52 f++;
53 continue;
54 }
55
aae5220d 56 if (f[l] != 0 && f[l] != ',') {
e23a0ce8
LP
57 f++;
58 continue;
59 }
60
61 return true;
62 }
63
64 return false;
65}
66
67static int create_disk(
68 const char *name,
69 const char *device,
70 const char *password,
71 const char *options) {
72
24a988e9
HH
73 char _cleanup_free_ *p = NULL, *n = NULL, *d = NULL, *u = NULL, *from = NULL, *to = NULL, *e = NULL;
74 FILE _cleanup_fclose_ *f = NULL;
155da457 75 bool noauto, nofail;
e23a0ce8
LP
76
77 assert(name);
78 assert(device);
79
155da457
LP
80 noauto = has_option(options, "noauto");
81 nofail = has_option(options, "nofail");
82
35eb6b12 83 n = unit_name_from_path_instance("systemd-cryptsetup", name, ".service");
24a988e9
HH
84 if (!n)
85 return log_oom();
e23a0ce8 86
b7def684 87 p = strjoin(arg_dest, "/", n, NULL);
24a988e9
HH
88 if (!p)
89 return log_oom();
e23a0ce8 90
f7f21d33 91 u = fstab_node_to_udev_node(device);
24a988e9
HH
92 if (!u)
93 return log_oom();
e23a0ce8 94
f7f21d33 95 d = unit_name_from_path(u, ".device");
24a988e9
HH
96 if (!d)
97 return log_oom();
e23a0ce8 98
f7f21d33
LP
99 f = fopen(p, "wxe");
100 if (!f) {
1cda32b8 101 log_error("Failed to create unit file %s: %m", p);
24a988e9 102 return -errno;
e23a0ce8
LP
103 }
104
105 fprintf(f,
6b1dc2bd 106 "# Automatically generated by systemd-cryptsetup-generator\n\n"
e23a0ce8 107 "[Unit]\n"
a4477e68 108 "Description=Cryptography Setup for %%I\n"
1c732700 109 "Documentation=man:systemd-cryptsetup@.service(8) man:crypttab(5)\n"
1b64d026 110 "SourcePath=/etc/crypttab\n"
155da457 111 "Conflicts=umount.target\n"
e23a0ce8 112 "DefaultDependencies=no\n"
7f2cddae 113 "BindsTo=%s dev-mapper-%%i.device\n"
e23a0ce8 114 "After=systemd-readahead-collect.service systemd-readahead-replay.service %s\n"
87e75fdd 115 "Before=umount.target\n",
e23a0ce8
LP
116 d, d);
117
155da457
LP
118 if (!nofail)
119 fprintf(f,
120 "Before=cryptsetup.target\n");
121
e23a0ce8
LP
122 if (password && (streq(password, "/dev/urandom") ||
123 streq(password, "/dev/random") ||
124 streq(password, "/dev/hw_random")))
1b64d026 125 fputs("After=systemd-random-seed-load.service\n", f);
87e75fdd 126 else
1b64d026 127 fputs("Before=local-fs.target\n", f);
e23a0ce8
LP
128
129 fprintf(f,
130 "\n[Service]\n"
131 "Type=oneshot\n"
132 "RemainAfterExit=yes\n"
90724929 133 "TimeoutSec=0\n" /* the binary handles timeouts anyway */
260ab287 134 "ExecStart=" SYSTEMD_CRYPTSETUP_PATH " attach '%s' '%s' '%s' '%s'\n"
7f4e0805 135 "ExecStop=" SYSTEMD_CRYPTSETUP_PATH " detach '%s'\n",
e23a0ce8
LP
136 name, u, strempty(password), strempty(options),
137 name);
138
f653f683 139 if (has_option(options, "tmp"))
e23a0ce8 140 fprintf(f,
50109038 141 "ExecStartPost=/sbin/mke2fs '/dev/mapper/%s'\n",
1d3399e6 142 name);
e23a0ce8 143
f653f683 144 if (has_option(options, "swap"))
e23a0ce8 145 fprintf(f,
50109038 146 "ExecStartPost=/sbin/mkswap '/dev/mapper/%s'\n",
1d3399e6 147 name);
e23a0ce8
LP
148
149 fflush(f);
150
151 if (ferror(f)) {
1cda32b8 152 log_error("Failed to write file %s: %m", p);
24a988e9 153 return -errno;
e23a0ce8
LP
154 }
155
24a988e9
HH
156 if (asprintf(&from, "../%s", n) < 0)
157 return log_oom();
74715b82 158
155da457 159 if (!noauto) {
e23a0ce8 160
b7def684 161 to = strjoin(arg_dest, "/", d, ".wants/", n, NULL);
24a988e9
HH
162 if (!to)
163 return log_oom();
e23a0ce8 164
d2e54fae 165 mkdir_parents_label(to, 0755);
e23a0ce8
LP
166 if (symlink(from, to) < 0) {
167 log_error("Failed to create symlink '%s' to '%s': %m", from, to);
24a988e9 168 return -errno;
e23a0ce8 169 }
2f8cd170
LP
170
171 free(to);
155da457 172 if (!nofail)
b7def684 173 to = strjoin(arg_dest, "/cryptsetup.target.requires/", n, NULL);
155da457 174 else
b7def684 175 to = strjoin(arg_dest, "/cryptsetup.target.wants/", n, NULL);
24a988e9
HH
176 if (!to)
177 return log_oom();
2f8cd170 178
d2e54fae 179 mkdir_parents_label(to, 0755);
155da457
LP
180 if (symlink(from, to) < 0) {
181 log_error("Failed to create symlink '%s' to '%s': %m", from, to);
24a988e9 182 return -errno;
2f8cd170 183 }
f7f21d33 184 }
74715b82
LP
185
186 e = unit_name_escape(name);
608d41f3
LP
187 if (!e)
188 return log_oom();
189
190 free(to);
b7def684 191 to = strjoin(arg_dest, "/dev-mapper-", e, ".device.requires/", n, NULL);
24a988e9
HH
192 if (!to)
193 return log_oom();
74715b82 194
d2e54fae 195 mkdir_parents_label(to, 0755);
74715b82
LP
196 if (symlink(from, to) < 0) {
197 log_error("Failed to create symlink '%s' to '%s': %m", from, to);
24a988e9 198 return -errno;
74715b82
LP
199 }
200
24a988e9 201 return 0;
e23a0ce8
LP
202}
203
24a988e9
HH
204static int parse_proc_cmdline(char ***arg_proc_cmdline_disks) {
205 char _cleanup_free_ *line = NULL;
206 char *w = NULL, *state = NULL;
66a78c2b
LP
207 int r;
208 size_t l;
209
210 if (detect_container(NULL) > 0)
211 return 0;
212
213 r = read_one_line_file("/proc/cmdline", &line);
214 if (r < 0) {
215 log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(-r));
216 return 0;
217 }
218
219 FOREACH_WORD_QUOTED(w, l, line, state) {
24a988e9 220 char _cleanup_free_ *word = NULL;
66a78c2b
LP
221
222 word = strndup(w, l);
24a988e9
HH
223 if (!word)
224 return log_oom();
66a78c2b
LP
225
226 if (startswith(word, "luks=")) {
227 r = parse_boolean(word + 5);
228 if (r < 0)
229 log_warning("Failed to parse luks switch %s. Ignoring.", word + 5);
230 else
231 arg_enabled = r;
232
233 } else if (startswith(word, "rd.luks=")) {
234
235 if (in_initrd()) {
236 r = parse_boolean(word + 8);
237 if (r < 0)
238 log_warning("Failed to parse luks switch %s. Ignoring.", word + 8);
239 else
240 arg_enabled = r;
241 }
242
243 } else if (startswith(word, "luks.crypttab=")) {
244 r = parse_boolean(word + 14);
245 if (r < 0)
246 log_warning("Failed to parse luks crypttab switch %s. Ignoring.", word + 14);
247 else
248 arg_read_crypttab = r;
249
250 } else if (startswith(word, "rd.luks.crypttab=")) {
251
252 if (in_initrd()) {
253 r = parse_boolean(word + 17);
254 if (r < 0)
255 log_warning("Failed to parse luks crypttab switch %s. Ignoring.", word + 17);
256 else
257 arg_read_crypttab = r;
258 }
259
260 } else if (startswith(word, "luks.uuid=")) {
e32530cb 261 if (strv_extend(arg_proc_cmdline_disks, word + 10) < 0)
24a988e9
HH
262 return log_oom();
263
66a78c2b
LP
264 } else if (startswith(word, "rd.luks.uuid=")) {
265
266 if (in_initrd()) {
e32530cb 267 if (strv_extend(arg_proc_cmdline_disks, word + 13) < 0)
24a988e9 268 return log_oom();
66a78c2b
LP
269 }
270
271 } else if (startswith(word, "luks.") ||
272 (in_initrd() && startswith(word, "rd.luks."))) {
273
274 log_warning("Unknown kernel switch %s. Ignoring.", word);
275 }
66a78c2b
LP
276 }
277
24a988e9 278 strv_uniq(*arg_proc_cmdline_disks);
66a78c2b 279
24a988e9 280 return 0;
66a78c2b
LP
281}
282
e23a0ce8 283int main(int argc, char *argv[]) {
24a988e9 284 FILE _cleanup_fclose_ *f = NULL;
e23a0ce8 285 unsigned n = 0;
24a988e9 286 int r = EXIT_SUCCESS;
66a78c2b 287 char **i;
24a988e9
HH
288 char _cleanup_strv_free_ **arg_proc_cmdline_disks_done = NULL;
289 char _cleanup_strv_free_ **arg_proc_cmdline_disks = NULL;
e23a0ce8 290
07719a21
LP
291 if (argc > 1 && argc != 4) {
292 log_error("This program takes three or no arguments.");
e23a0ce8
LP
293 return EXIT_FAILURE;
294 }
295
2a796654
LP
296 if (argc > 1)
297 arg_dest = argv[1];
e23a0ce8 298
a6903061 299 log_set_target(LOG_TARGET_SAFE);
e23a0ce8
LP
300 log_parse_environment();
301 log_open();
302
4c12626c
LP
303 umask(0022);
304
24a988e9 305 if (parse_proc_cmdline(&arg_proc_cmdline_disks) < 0)
66a78c2b
LP
306 return EXIT_FAILURE;
307
24a988e9
HH
308 if (!arg_enabled)
309 return EXIT_SUCCESS;
66a78c2b 310
e2cb60fa
HH
311 if (arg_read_crypttab) {
312 f = fopen("/etc/crypttab", "re");
66a78c2b 313
e2cb60fa
HH
314 if (!f) {
315 if (errno == ENOENT)
316 r = EXIT_SUCCESS;
317 else {
318 r = EXIT_FAILURE;
319 log_error("Failed to open /etc/crypttab: %m");
320 }
24a988e9 321 } else for (;;) {
e2cb60fa 322 char line[LINE_MAX], *l;
24a988e9 323 char _cleanup_free_ *name = NULL, *device = NULL, *password = NULL, *options = NULL;
e2cb60fa 324 int k;
66a78c2b 325
e2cb60fa
HH
326 if (!fgets(line, sizeof(line), f))
327 break;
66a78c2b 328
e2cb60fa 329 n++;
66a78c2b 330
e2cb60fa
HH
331 l = strstrip(line);
332 if (*l == '#' || *l == 0)
333 continue;
e23a0ce8 334
e2cb60fa
HH
335 k = sscanf(l, "%ms %ms %ms %ms", &name, &device, &password, &options);
336 if (k < 2 || k > 4) {
337 log_error("Failed to parse /etc/crypttab:%u, ignoring.", n);
338 r = EXIT_FAILURE;
24a988e9 339 continue;
e2cb60fa 340 }
e23a0ce8 341
e2cb60fa
HH
342 if (arg_proc_cmdline_disks) {
343 /*
344 If luks UUIDs are specified on the kernel command line, use them as a filter
345 for /etc/crypttab and only generate units for those.
346 */
347 STRV_FOREACH(i, arg_proc_cmdline_disks) {
24a988e9 348 char _cleanup_free_ *proc_device = NULL, *proc_name = NULL;
e2cb60fa
HH
349 const char *p = *i;
350
351 if (startswith(p, "luks-"))
352 p += 5;
353
354 proc_name = strappend("luks-", p);
355 proc_device = strappend("UUID=", p);
356
24a988e9
HH
357 if (!proc_name || !proc_device)
358 return log_oom();
359
e2cb60fa 360 if (streq(proc_device, device) || streq(proc_name, name)) {
e2cb60fa
HH
361 if (create_disk(name, device, password, options) < 0)
362 r = EXIT_FAILURE;
363
e32530cb 364 if (strv_extend(&arg_proc_cmdline_disks_done, p) < 0)
24a988e9 365 return log_oom();
e2cb60fa 366 }
e2cb60fa
HH
367 }
368 } else {
369 if (create_disk(name, device, password, options) < 0)
370 r = EXIT_FAILURE;
371 }
e2cb60fa 372 }
e23a0ce8
LP
373 }
374
e2cb60fa
HH
375 STRV_FOREACH(i, arg_proc_cmdline_disks) {
376 /*
377 Generate units for those UUIDs, which were specified
378 on the kernel command line and not yet written.
379 */
e23a0ce8 380
24a988e9 381 char _cleanup_free_ *name = NULL, *device = NULL;
e2cb60fa 382 const char *p = *i;
e23a0ce8 383
e2cb60fa
HH
384 if (startswith(p, "luks-"))
385 p += 5;
e23a0ce8 386
e2cb60fa 387 if (strv_contains(arg_proc_cmdline_disks_done, p))
e23a0ce8
LP
388 continue;
389
e2cb60fa
HH
390 name = strappend("luks-", p);
391 device = strappend("UUID=", p);
392
24a988e9
HH
393 if (!name || !device)
394 return log_oom();
e23a0ce8 395
e2cb60fa 396 if (create_disk(name, device, NULL, "timeout=0") < 0)
e23a0ce8 397 r = EXIT_FAILURE;
e23a0ce8
LP
398 }
399
e23a0ce8
LP
400 return r;
401}