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