]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/cryptsetup/cryptsetup-generator.c
relicense to LGPLv2.1 (with exceptions)
[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"
e23a0ce8
LP
30
31const char *arg_dest = "/tmp";
32
33static bool has_option(const char *haystack, const char *needle) {
34 const char *f = haystack;
35 size_t l;
36
f653f683
LP
37 assert(needle);
38
39 if (!haystack)
40 return false;
41
e23a0ce8
LP
42 l = strlen(needle);
43
44 while ((f = strstr(f, needle))) {
45
46 if (f > haystack && f[-1] != ',') {
47 f++;
48 continue;
49 }
50
aae5220d 51 if (f[l] != 0 && f[l] != ',') {
e23a0ce8
LP
52 f++;
53 continue;
54 }
55
56 return true;
57 }
58
59 return false;
60}
61
62static int create_disk(
63 const char *name,
64 const char *device,
65 const char *password,
66 const char *options) {
67
74715b82 68 char *p = NULL, *n = NULL, *d = NULL, *u = NULL, *from = NULL, *to = NULL, *e = NULL;
e23a0ce8
LP
69 int r;
70 FILE *f = NULL;
155da457 71 bool noauto, nofail;
e23a0ce8
LP
72
73 assert(name);
74 assert(device);
75
155da457
LP
76 noauto = has_option(options, "noauto");
77 nofail = has_option(options, "nofail");
78
e23a0ce8
LP
79 if (!(n = unit_name_build_escape("cryptsetup", name, ".service"))) {
80 r = -ENOMEM;
81 log_error("Failed to allocate unit name.");
82 goto fail;
83 }
84
85 if (asprintf(&p, "%s/%s", arg_dest, n) < 0) {
86 r = -ENOMEM;
87 log_error("Failed to allocate unit file name.");
88 goto fail;
89 }
90
91 if (!(u = fstab_node_to_udev_node(device))) {
92 r = -ENOMEM;
93 log_error("Failed to allocate device node.");
94 goto fail;
95 }
96
97 if (!(d = unit_name_from_path(u, ".device"))) {
98 r = -ENOMEM;
99 log_error("Failed to allocate device name.");
100 goto fail;
101 }
102
103 if (!(f = fopen(p, "wxe"))) {
104 r = -errno;
105 log_error("Failed to create unit file: %m");
106 goto fail;
107 }
108
109 fprintf(f,
110 "[Unit]\n"
a4477e68 111 "Description=Cryptography Setup for %%I\n"
155da457 112 "Conflicts=umount.target\n"
e23a0ce8 113 "DefaultDependencies=no\n"
49d50c55 114 "BindTo=%s dev-mapper-%%i.device\n"
e23a0ce8 115 "After=systemd-readahead-collect.service systemd-readahead-replay.service %s\n"
87e75fdd 116 "Before=umount.target\n",
e23a0ce8
LP
117 d, d);
118
155da457
LP
119 if (!nofail)
120 fprintf(f,
121 "Before=cryptsetup.target\n");
122
e23a0ce8
LP
123 if (password && (streq(password, "/dev/urandom") ||
124 streq(password, "/dev/random") ||
125 streq(password, "/dev/hw_random")))
126 fprintf(f,
127 "After=systemd-random-seed-load.service\n");
87e75fdd
TG
128 else
129 fprintf(f,
130 "Before=local-fs.target\n");
e23a0ce8
LP
131
132 fprintf(f,
133 "\n[Service]\n"
134 "Type=oneshot\n"
135 "RemainAfterExit=yes\n"
90724929 136 "TimeoutSec=0\n" /* the binary handles timeouts anyway */
260ab287 137 "ExecStart=" SYSTEMD_CRYPTSETUP_PATH " attach '%s' '%s' '%s' '%s'\n"
7f4e0805 138 "ExecStop=" SYSTEMD_CRYPTSETUP_PATH " detach '%s'\n",
e23a0ce8
LP
139 name, u, strempty(password), strempty(options),
140 name);
141
f653f683 142 if (has_option(options, "tmp"))
e23a0ce8 143 fprintf(f,
50109038 144 "ExecStartPost=/sbin/mke2fs '/dev/mapper/%s'\n",
1d3399e6 145 name);
e23a0ce8 146
f653f683 147 if (has_option(options, "swap"))
e23a0ce8 148 fprintf(f,
50109038 149 "ExecStartPost=/sbin/mkswap '/dev/mapper/%s'\n",
1d3399e6 150 name);
e23a0ce8
LP
151
152 fflush(f);
153
154 if (ferror(f)) {
155 r = -errno;
156 log_error("Failed to write file: %m");
157 goto fail;
158 }
159
74715b82
LP
160 if (asprintf(&from, "../%s", n) < 0) {
161 r = -ENOMEM;
162 goto fail;
163 }
164
155da457 165 if (!noauto) {
e23a0ce8
LP
166
167 if (asprintf(&to, "%s/%s.wants/%s", arg_dest, d, n) < 0) {
168 r = -ENOMEM;
169 goto fail;
170 }
171
e23a0ce8
LP
172 mkdir_parents(to, 0755);
173
174 if (symlink(from, to) < 0) {
175 log_error("Failed to create symlink '%s' to '%s': %m", from, to);
176 r = -errno;
177 goto fail;
178 }
2f8cd170
LP
179
180 free(to);
181 to = NULL;
182
155da457
LP
183 if (!nofail)
184 asprintf(&to, "%s/cryptsetup.target.requires/%s", arg_dest, n);
185 else
186 asprintf(&to, "%s/cryptsetup.target.wants/%s", arg_dest, n);
2f8cd170 187
155da457
LP
188 if (!to) {
189 r = -ENOMEM;
190 goto fail;
191 }
2f8cd170 192
155da457 193 mkdir_parents(to, 0755);
2f8cd170 194
155da457
LP
195 if (symlink(from, to) < 0) {
196 log_error("Failed to create symlink '%s' to '%s': %m", from, to);
197 r = -errno;
198 goto fail;
2f8cd170 199 }
e23a0ce8
LP
200 }
201
74715b82
LP
202 free(to);
203 to = NULL;
204
205 e = unit_name_escape(name);
8c4dd542 206 if (asprintf(&to, "%s/dev-mapper-%s.device.requires/%s", arg_dest, e, n) < 0) {
74715b82
LP
207 r = -ENOMEM;
208 goto fail;
209 }
210
211 mkdir_parents(to, 0755);
212
213 if (symlink(from, to) < 0) {
214 log_error("Failed to create symlink '%s' to '%s': %m", from, to);
215 r = -errno;
216 goto fail;
217 }
218
e23a0ce8
LP
219 r = 0;
220
221fail:
222 free(p);
223 free(n);
224 free(d);
74715b82 225 free(e);
e23a0ce8
LP
226
227 free(from);
228 free(to);
229
230 if (f)
231 fclose(f);
232
233 return r;
234}
235
236int main(int argc, char *argv[]) {
237 FILE *f;
238 int r = EXIT_SUCCESS;
239 unsigned n = 0;
240
241 if (argc > 2) {
242 log_error("This program takes one or no arguments.");
243 return EXIT_FAILURE;
244 }
245
2a796654
LP
246 if (argc > 1)
247 arg_dest = argv[1];
e23a0ce8 248
4cfa2c99 249 log_set_target(LOG_TARGET_AUTO);
e23a0ce8
LP
250 log_parse_environment();
251 log_open();
252
4c12626c
LP
253 umask(0022);
254
e23a0ce8
LP
255 if (!(f = fopen("/etc/crypttab", "re"))) {
256
257 if (errno == ENOENT)
258 r = EXIT_SUCCESS;
259 else {
260 r = EXIT_FAILURE;
261 log_error("Failed to open /etc/crypttab: %m");
262 }
263
264 goto finish;
265 }
266
267 for (;;) {
268 char line[LINE_MAX], *l;
269 char *name = NULL, *device = NULL, *password = NULL, *options = NULL;
270 int k;
271
272 if (!(fgets(line, sizeof(line), f)))
273 break;
274
275 n++;
276
277 l = strstrip(line);
278 if (*l == '#' || *l == 0)
279 continue;
280
281 if ((k = sscanf(l, "%ms %ms %ms %ms", &name, &device, &password, &options)) < 2 || k > 4) {
282 log_error("Failed to parse /etc/crypttab:%u, ignoring.", n);
283 r = EXIT_FAILURE;
284 goto next;
285 }
286
287 if (create_disk(name, device, password, options) < 0)
288 r = EXIT_FAILURE;
289
290 next:
291 free(name);
292 free(device);
293 free(password);
294 free(options);
295 }
296
297finish:
298 return r;
299}