]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/cryptsetup/cryptsetup-generator.c
use "Out of memory." consistantly (or with "\n")
[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"
e23a0ce8 32
66a78c2b
LP
33static const char *arg_dest = "/tmp";
34static bool arg_enabled = true;
35static bool arg_read_crypttab = true;
36static char **arg_proc_cmdline_disks = NULL;
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
74715b82 73 char *p = NULL, *n = NULL, *d = NULL, *u = NULL, *from = NULL, *to = NULL, *e = NULL;
e23a0ce8
LP
74 int r;
75 FILE *f = NULL;
155da457 76 bool noauto, nofail;
e23a0ce8
LP
77
78 assert(name);
79 assert(device);
80
155da457
LP
81 noauto = has_option(options, "noauto");
82 nofail = has_option(options, "nofail");
83
35eb6b12 84 n = unit_name_from_path_instance("systemd-cryptsetup", name, ".service");
f7f21d33 85 if (!n) {
e23a0ce8
LP
86 r = -ENOMEM;
87 log_error("Failed to allocate unit name.");
88 goto fail;
89 }
90
b7def684 91 p = strjoin(arg_dest, "/", n, NULL);
f7f21d33 92 if (!p) {
e23a0ce8
LP
93 r = -ENOMEM;
94 log_error("Failed to allocate unit file name.");
95 goto fail;
96 }
97
f7f21d33
LP
98 u = fstab_node_to_udev_node(device);
99 if (!u) {
e23a0ce8
LP
100 r = -ENOMEM;
101 log_error("Failed to allocate device node.");
102 goto fail;
103 }
104
f7f21d33
LP
105 d = unit_name_from_path(u, ".device");
106 if (!d) {
e23a0ce8
LP
107 r = -ENOMEM;
108 log_error("Failed to allocate device name.");
109 goto fail;
110 }
111
f7f21d33
LP
112 f = fopen(p, "wxe");
113 if (!f) {
e23a0ce8
LP
114 r = -errno;
115 log_error("Failed to create unit file: %m");
116 goto fail;
117 }
118
119 fprintf(f,
6b1dc2bd 120 "# Automatically generated by systemd-cryptsetup-generator\n\n"
e23a0ce8 121 "[Unit]\n"
a4477e68 122 "Description=Cryptography Setup for %%I\n"
1c732700 123 "Documentation=man:systemd-cryptsetup@.service(8) man:crypttab(5)\n"
1b64d026 124 "SourcePath=/etc/crypttab\n"
155da457 125 "Conflicts=umount.target\n"
e23a0ce8 126 "DefaultDependencies=no\n"
7f2cddae 127 "BindsTo=%s dev-mapper-%%i.device\n"
e23a0ce8 128 "After=systemd-readahead-collect.service systemd-readahead-replay.service %s\n"
87e75fdd 129 "Before=umount.target\n",
e23a0ce8
LP
130 d, d);
131
155da457
LP
132 if (!nofail)
133 fprintf(f,
134 "Before=cryptsetup.target\n");
135
e23a0ce8
LP
136 if (password && (streq(password, "/dev/urandom") ||
137 streq(password, "/dev/random") ||
138 streq(password, "/dev/hw_random")))
1b64d026 139 fputs("After=systemd-random-seed-load.service\n", f);
87e75fdd 140 else
1b64d026 141 fputs("Before=local-fs.target\n", f);
e23a0ce8
LP
142
143 fprintf(f,
144 "\n[Service]\n"
145 "Type=oneshot\n"
146 "RemainAfterExit=yes\n"
90724929 147 "TimeoutSec=0\n" /* the binary handles timeouts anyway */
260ab287 148 "ExecStart=" SYSTEMD_CRYPTSETUP_PATH " attach '%s' '%s' '%s' '%s'\n"
7f4e0805 149 "ExecStop=" SYSTEMD_CRYPTSETUP_PATH " detach '%s'\n",
e23a0ce8
LP
150 name, u, strempty(password), strempty(options),
151 name);
152
f653f683 153 if (has_option(options, "tmp"))
e23a0ce8 154 fprintf(f,
50109038 155 "ExecStartPost=/sbin/mke2fs '/dev/mapper/%s'\n",
1d3399e6 156 name);
e23a0ce8 157
f653f683 158 if (has_option(options, "swap"))
e23a0ce8 159 fprintf(f,
50109038 160 "ExecStartPost=/sbin/mkswap '/dev/mapper/%s'\n",
1d3399e6 161 name);
e23a0ce8
LP
162
163 fflush(f);
164
165 if (ferror(f)) {
166 r = -errno;
167 log_error("Failed to write file: %m");
168 goto fail;
169 }
170
74715b82
LP
171 if (asprintf(&from, "../%s", n) < 0) {
172 r = -ENOMEM;
173 goto fail;
174 }
175
155da457 176 if (!noauto) {
e23a0ce8 177
b7def684 178 to = strjoin(arg_dest, "/", d, ".wants/", n, NULL);
f7f21d33 179 if (!to) {
e23a0ce8
LP
180 r = -ENOMEM;
181 goto fail;
182 }
183
d2e54fae 184 mkdir_parents_label(to, 0755);
e23a0ce8
LP
185 if (symlink(from, to) < 0) {
186 log_error("Failed to create symlink '%s' to '%s': %m", from, to);
187 r = -errno;
188 goto fail;
189 }
2f8cd170
LP
190
191 free(to);
2f8cd170 192
155da457 193 if (!nofail)
b7def684 194 to = strjoin(arg_dest, "/cryptsetup.target.requires/", n, NULL);
155da457 195 else
b7def684 196 to = strjoin(arg_dest, "/cryptsetup.target.wants/", n, NULL);
155da457
LP
197 if (!to) {
198 r = -ENOMEM;
199 goto fail;
200 }
2f8cd170 201
d2e54fae 202 mkdir_parents_label(to, 0755);
155da457
LP
203 if (symlink(from, to) < 0) {
204 log_error("Failed to create symlink '%s' to '%s': %m", from, to);
205 r = -errno;
206 goto fail;
2f8cd170 207 }
e23a0ce8 208
f7f21d33
LP
209 free(to);
210 to = NULL;
211 }
74715b82
LP
212
213 e = unit_name_escape(name);
b7def684 214 to = strjoin(arg_dest, "/dev-mapper-", e, ".device.requires/", n, NULL);
f7f21d33 215 if (!to) {
74715b82
LP
216 r = -ENOMEM;
217 goto fail;
218 }
219
d2e54fae 220 mkdir_parents_label(to, 0755);
74715b82
LP
221 if (symlink(from, to) < 0) {
222 log_error("Failed to create symlink '%s' to '%s': %m", from, to);
223 r = -errno;
224 goto fail;
225 }
226
e23a0ce8
LP
227 r = 0;
228
229fail:
230 free(p);
231 free(n);
232 free(d);
74715b82 233 free(e);
e23a0ce8
LP
234
235 free(from);
236 free(to);
237
238 if (f)
239 fclose(f);
240
241 return r;
242}
243
66a78c2b
LP
244static int parse_proc_cmdline(void) {
245 char *line, *w, *state;
246 int r;
247 size_t l;
248
249 if (detect_container(NULL) > 0)
250 return 0;
251
252 r = read_one_line_file("/proc/cmdline", &line);
253 if (r < 0) {
254 log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(-r));
255 return 0;
256 }
257
258 FOREACH_WORD_QUOTED(w, l, line, state) {
259 char *word;
260
261 word = strndup(w, l);
262 if (!word) {
263 r = -ENOMEM;
264 goto finish;
265 }
266
267 if (startswith(word, "luks=")) {
268 r = parse_boolean(word + 5);
269 if (r < 0)
270 log_warning("Failed to parse luks switch %s. Ignoring.", word + 5);
271 else
272 arg_enabled = r;
273
274 } else if (startswith(word, "rd.luks=")) {
275
276 if (in_initrd()) {
277 r = parse_boolean(word + 8);
278 if (r < 0)
279 log_warning("Failed to parse luks switch %s. Ignoring.", word + 8);
280 else
281 arg_enabled = r;
282 }
283
284 } else if (startswith(word, "luks.crypttab=")) {
285 r = parse_boolean(word + 14);
286 if (r < 0)
287 log_warning("Failed to parse luks crypttab switch %s. Ignoring.", word + 14);
288 else
289 arg_read_crypttab = r;
290
291 } else if (startswith(word, "rd.luks.crypttab=")) {
292
293 if (in_initrd()) {
294 r = parse_boolean(word + 17);
295 if (r < 0)
296 log_warning("Failed to parse luks crypttab switch %s. Ignoring.", word + 17);
297 else
298 arg_read_crypttab = r;
299 }
300
301 } else if (startswith(word, "luks.uuid=")) {
302 char **t;
303
304 t = strv_append(arg_proc_cmdline_disks, word + 10);
305 if (!t) {
669241a0 306 log_error("Out of memory.");
66a78c2b
LP
307 r = -ENOMEM;
308 goto finish;
309 }
310 strv_free(arg_proc_cmdline_disks);
311 arg_proc_cmdline_disks = t;
312
313 } else if (startswith(word, "rd.luks.uuid=")) {
314
315 if (in_initrd()) {
316 char **t;
317
318 t = strv_append(arg_proc_cmdline_disks, word + 13);
319 if (!t) {
669241a0 320 log_error("Out of memory.");
66a78c2b
LP
321 r = -ENOMEM;
322 goto finish;
323 }
324 strv_free(arg_proc_cmdline_disks);
325 arg_proc_cmdline_disks = t;
326 }
327
328 } else if (startswith(word, "luks.") ||
329 (in_initrd() && startswith(word, "rd.luks."))) {
330
331 log_warning("Unknown kernel switch %s. Ignoring.", word);
332 }
333
334 free(word);
335 }
336
337 r = 0;
338
339finish:
340 free(line);
341 return r;
342}
343
e23a0ce8 344int main(int argc, char *argv[]) {
66a78c2b 345 FILE *f = NULL;
e23a0ce8
LP
346 int r = EXIT_SUCCESS;
347 unsigned n = 0;
66a78c2b 348 char **i;
e23a0ce8 349
07719a21
LP
350 if (argc > 1 && argc != 4) {
351 log_error("This program takes three or no arguments.");
e23a0ce8
LP
352 return EXIT_FAILURE;
353 }
354
2a796654
LP
355 if (argc > 1)
356 arg_dest = argv[1];
e23a0ce8 357
a6903061 358 log_set_target(LOG_TARGET_SAFE);
e23a0ce8
LP
359 log_parse_environment();
360 log_open();
361
4c12626c
LP
362 umask(0022);
363
66a78c2b
LP
364 if (parse_proc_cmdline() < 0)
365 return EXIT_FAILURE;
366
367 if (!arg_enabled) {
368 r = EXIT_SUCCESS;
369 goto finish;
370 }
371
372 STRV_FOREACH(i, arg_proc_cmdline_disks) {
373 char *name, *device;
374 const char *p = *i;
375
376 if (startswith(p, "luks-"))
377 p += 5;
378
379 name = strappend("luks-", *i);
380 device = strappend("UUID=", *i);
381
382 if (!name || !device) {
669241a0 383 log_error("Out of memory.");
66a78c2b
LP
384 r = EXIT_FAILURE;
385 free(name);
386 free(device);
387 goto finish;
388 }
389
390 if (create_disk(name, device, NULL, NULL) < 0)
391 r = EXIT_FAILURE;
392
393 free(name);
394 free(device);
395 }
396
397 if (!arg_read_crypttab)
398 return r;
399
f7f21d33
LP
400 f = fopen("/etc/crypttab", "re");
401 if (!f) {
e23a0ce8
LP
402
403 if (errno == ENOENT)
404 r = EXIT_SUCCESS;
405 else {
406 r = EXIT_FAILURE;
407 log_error("Failed to open /etc/crypttab: %m");
408 }
409
410 goto finish;
411 }
412
413 for (;;) {
414 char line[LINE_MAX], *l;
415 char *name = NULL, *device = NULL, *password = NULL, *options = NULL;
416 int k;
417
f7f21d33 418 if (!fgets(line, sizeof(line), f))
e23a0ce8
LP
419 break;
420
421 n++;
422
423 l = strstrip(line);
424 if (*l == '#' || *l == 0)
425 continue;
426
f7f21d33
LP
427 k = sscanf(l, "%ms %ms %ms %ms", &name, &device, &password, &options);
428 if (k < 2 || k > 4) {
e23a0ce8
LP
429 log_error("Failed to parse /etc/crypttab:%u, ignoring.", n);
430 r = EXIT_FAILURE;
431 goto next;
432 }
433
434 if (create_disk(name, device, password, options) < 0)
435 r = EXIT_FAILURE;
436
437 next:
438 free(name);
439 free(device);
440 free(password);
441 free(options);
442 }
443
444finish:
66a78c2b
LP
445 if (f)
446 fclose(f);
447
448 strv_free(arg_proc_cmdline_disks);
449
e23a0ce8
LP
450 return r;
451}