]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/cryptsetup-generator.c
cryptsetup: minimal cryptsetup unit generator
[thirdparty/systemd.git] / src / 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
9 under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 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 General Public License for more details.
17
18 You should have received a copy of the GNU 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
30const char *arg_dest = "/tmp";
31
32static bool has_option(const char *haystack, const char *needle) {
33 const char *f = haystack;
34 size_t l;
35
36 l = strlen(needle);
37
38 while ((f = strstr(f, needle))) {
39
40 if (f > haystack && f[-1] != ',') {
41 f++;
42 continue;
43 }
44
45 if (f[l] != 0 && f[l] == ',') {
46 f++;
47 continue;
48 }
49
50 return true;
51 }
52
53 return false;
54}
55
56static int create_disk(
57 const char *name,
58 const char *device,
59 const char *password,
60 const char *options) {
61
62 char *p = NULL, *n = NULL, *d = NULL, *u = NULL, *from = NULL, *to = NULL;
63 int r;
64 FILE *f = NULL;
65
66 assert(name);
67 assert(device);
68
69 if (!(n = unit_name_build_escape("cryptsetup", name, ".service"))) {
70 r = -ENOMEM;
71 log_error("Failed to allocate unit name.");
72 goto fail;
73 }
74
75 if (asprintf(&p, "%s/%s", arg_dest, n) < 0) {
76 r = -ENOMEM;
77 log_error("Failed to allocate unit file name.");
78 goto fail;
79 }
80
81 if (!(u = fstab_node_to_udev_node(device))) {
82 r = -ENOMEM;
83 log_error("Failed to allocate device node.");
84 goto fail;
85 }
86
87 if (!(d = unit_name_from_path(u, ".device"))) {
88 r = -ENOMEM;
89 log_error("Failed to allocate device name.");
90 goto fail;
91 }
92
93 if (!(f = fopen(p, "wxe"))) {
94 r = -errno;
95 log_error("Failed to create unit file: %m");
96 goto fail;
97 }
98
99 fprintf(f,
100 "[Unit]\n"
101 "Description=Cryptography Setup for %%f\n"
102 "DefaultDependencies=no\n"
103 "BindTo=%s\n"
104 "After=systemd-readahead-collect.service systemd-readahead-replay.service %s\n"
105 "Before=dev-mapper-%%f.device shutdown.target\n",
106 d, d);
107
108 if (password && (streq(password, "/dev/urandom") ||
109 streq(password, "/dev/random") ||
110 streq(password, "/dev/hw_random")))
111 fprintf(f,
112 "After=systemd-random-seed-load.service\n");
113
114 fprintf(f,
115 "\n[Service]\n"
116 "Type=oneshot\n"
117 "RemainAfterExit=yes\n"
118 "ExecStart=" SYSTEMD_CRYPTSETUP_PATH " %s '%s' '%s' '%s' '%s'\n"
119 "ExecStop=" SYSTEMD_CRYPTSETUP_PATH " remove '%s'\n",
120 options && has_option(options, "swap") ? "format" : "create",
121 name, u, strempty(password), strempty(options),
122 name);
123
124 if (options && has_option(options, "tmp"))
125 fprintf(f,
126 "ExecStartPost=/sbin/mke2fs '%s'",
127 u);
128
129 if (options && has_option(options, "swap"))
130 fprintf(f,
131 "ExecStartPost=/sbin/mkswap '%s'",
132 u);
133
134 fflush(f);
135
136 if (ferror(f)) {
137 r = -errno;
138 log_error("Failed to write file: %m");
139 goto fail;
140 }
141
142 if (!options || !has_option(options, "noauto")) {
143
144 if (asprintf(&to, "%s/%s.wants/%s", arg_dest, d, n) < 0) {
145 r = -ENOMEM;
146 goto fail;
147 }
148
149 if (asprintf(&from, "../%s", n) < 0) {
150 r = -ENOMEM;
151 goto fail;
152 }
153
154 mkdir_parents(to, 0755);
155
156 if (symlink(from, to) < 0) {
157 log_error("Failed to create symlink '%s' to '%s': %m", from, to);
158 r = -errno;
159 goto fail;
160 }
161 }
162
163 r = 0;
164
165fail:
166 free(p);
167 free(n);
168 free(d);
169
170 free(from);
171 free(to);
172
173 if (f)
174 fclose(f);
175
176 return r;
177}
178
179int main(int argc, char *argv[]) {
180 FILE *f;
181 int r = EXIT_SUCCESS;
182 unsigned n = 0;
183
184 if (argc > 2) {
185 log_error("This program takes one or no arguments.");
186 return EXIT_FAILURE;
187 }
188
189 arg_dest = argv[1];
190
191 log_set_target(LOG_TARGET_SYSLOG_OR_KMSG);
192 log_parse_environment();
193 log_open();
194
195 if (!(f = fopen("/etc/crypttab", "re"))) {
196
197 if (errno == ENOENT)
198 r = EXIT_SUCCESS;
199 else {
200 r = EXIT_FAILURE;
201 log_error("Failed to open /etc/crypttab: %m");
202 }
203
204 goto finish;
205 }
206
207 for (;;) {
208 char line[LINE_MAX], *l;
209 char *name = NULL, *device = NULL, *password = NULL, *options = NULL;
210 int k;
211
212 if (!(fgets(line, sizeof(line), f)))
213 break;
214
215 n++;
216
217 l = strstrip(line);
218 if (*l == '#' || *l == 0)
219 continue;
220
221 if ((k = sscanf(l, "%ms %ms %ms %ms", &name, &device, &password, &options)) < 2 || k > 4) {
222 log_error("Failed to parse /etc/crypttab:%u, ignoring.", n);
223 r = EXIT_FAILURE;
224 goto next;
225 }
226
227 if (create_disk(name, device, password, options) < 0)
228 r = EXIT_FAILURE;
229
230 next:
231 free(name);
232 free(device);
233 free(password);
234 free(options);
235 }
236
237finish:
238 return r;
239}