8 #include <sys/sysmacros.h>
12 #include <libdevmapper.h>
14 #include "libcryptsetup.h"
17 #define DEVICE_DIR "/dev"
19 #define CRYPT_TARGET "crypt"
21 #define UDEVSETTLE "/sbin/udevsettle"
23 static void run_udevsettle(void)
28 static void set_dm_error(int level, const char *file, int line,
41 static int dm_init(void)
43 dm_log_init(set_dm_error);
44 return 1; /* unsafe memory */
47 static void dm_exit(void)
53 static void flush_dm_workqueue(void)
56 * Unfortunately this is the only way to trigger libdevmapper's
57 * update_nodes function
63 static char *__lookup_dev(char *path, dev_t dev)
72 path[PATH_MAX - 1] = '\0';
73 ptr = path + strlen(path);
76 space = PATH_MAX - (ptr - path);
82 while((entry = readdir(dir))) {
83 if (entry->d_name[0] == '.' &&
84 (entry->d_name[1] == '\0' || (entry->d_name[1] == '.' &&
85 entry->d_name[2] == '\0')))
88 strncpy(ptr, entry->d_name, space);
89 if (lstat(path, &st) < 0)
92 if (S_ISDIR(st.st_mode)) {
93 result = __lookup_dev(path, dev);
96 } else if (S_ISBLK(st.st_mode)) {
97 if (st.st_rdev == dev) {
98 result = strdup(path);
109 static char *lookup_dev(const char *dev)
111 uint32_t major, minor;
112 char buf[PATH_MAX + 1];
114 if (sscanf(dev, "%" PRIu32 ":%" PRIu32, &major, &minor) != 2)
117 strncpy(buf, DEVICE_DIR, PATH_MAX);
118 buf[PATH_MAX] = '\0';
120 return __lookup_dev(buf, makedev(major, minor));
123 static char *get_params(struct crypt_options *options, const char *key)
129 hexkey = safe_alloc(options->key_size * 2 + 1);
131 set_error("Memory allocation problem");
135 for(i = 0; i < options->key_size; i++)
136 sprintf(&hexkey[i * 2], "%02x", (unsigned char)key[i]);
138 params = safe_alloc(strlen(hexkey) + strlen(options->cipher) +
139 strlen(options->device) + 64);
141 set_error("Memory allocation problem");
145 sprintf(params, "%s %s %" PRIu64 " %s %" PRIu64,
146 options->cipher, hexkey, options->skip,
147 options->device, options->offset);
155 static int dm_create_device(int reload, struct crypt_options *options,
158 struct dm_task *dmt = NULL;
159 struct dm_task *dmt_query = NULL;
164 params = get_params(options, key);
167 if (!(dmt = dm_task_create(reload ? DM_DEVICE_RELOAD
168 : DM_DEVICE_CREATE)))
170 if (!dm_task_set_name(dmt, options->name))
172 if (options->flags & CRYPT_FLAG_READONLY && !dm_task_set_ro(dmt))
174 if (!dm_task_add_target(dmt, 0, options->size, CRYPT_TARGET, params))
176 if (!dm_task_run(dmt))
180 dm_task_destroy(dmt);
181 if (!(dmt = dm_task_create(DM_DEVICE_RESUME)))
183 if (!dm_task_set_name(dmt, options->name))
185 if (!dm_task_run(dmt))
189 if (!dm_task_get_info(dmt, &dmi))
192 options->flags |= CRYPT_FLAG_READONLY;
194 /* run udevsettle to avoid a race in libdevmapper causing busy dm devices */
200 if (r < 0 && !reload) {
201 char *error = (char *)get_error();
203 error = strdup(error);
205 dm_task_destroy(dmt);
207 if (!(dmt = dm_task_create(DM_DEVICE_REMOVE)))
208 goto out_restore_error;
209 if (!dm_task_set_name(dmt, options->name))
210 goto out_restore_error;
211 if (!dm_task_run(dmt))
212 goto out_restore_error;
215 set_error("%s", error);
224 dm_task_destroy(dmt);
226 dm_task_destroy(dmt_query);
227 flush_dm_workqueue();
231 static int dm_query_device(int details, struct crypt_options *options,
236 uint64_t start, length;
237 char *target_type, *params;
241 if (!(dmt = dm_task_create(details ? DM_DEVICE_TABLE
242 : DM_DEVICE_STATUS)))
244 if (!dm_task_set_name(dmt, options->name))
247 if (!dm_task_run(dmt))
251 if (!dm_task_get_info(dmt, &dmi))
259 next = dm_get_next_target(dmt, next, &start, &length,
260 &target_type, ¶ms);
261 if (!target_type || strcmp(target_type, CRYPT_TARGET) != 0 ||
265 options->hash = NULL;
266 options->cipher = NULL;
269 options->size = length;
271 char *cipher, *key_, *device;
274 set_error("Invalid dm table");
276 cipher = strsep(¶ms, " ");
277 key_ = strsep(¶ms, " ");
281 val64 = strtoull(params, ¶ms, 10);
285 options->skip = val64;
287 device = strsep(¶ms, " ");
291 val64 = strtoull(params, ¶ms, 10);
294 options->offset = val64;
296 options->cipher = strdup(cipher);
297 options->key_size = strlen(key_) / 2;
303 *key = safe_alloc(options->key_size);
305 set_error("Out of memory");
311 for(i = 0; i < options->key_size; i++) {
312 memcpy(buffer, &key_[i * 2], 2);
313 (*key)[i] = strtoul(buffer, &endp, 16);
314 if (endp != &buffer[2]) {
321 memset(key_, 0, strlen(key_));
322 options->device = lookup_dev(device);
327 r = (dmi.open_count > 0);
331 dm_task_destroy(dmt);
334 options->flags |= CRYPT_FLAG_FREE_DEVICE;
336 options->flags |= CRYPT_FLAG_FREE_CIPHER;
337 options->flags &= ~CRYPT_FLAG_READONLY;
339 options->flags |= CRYPT_FLAG_READONLY;
341 if (options->device) {
342 free((char *)options->device);
343 options->device = NULL;
344 options->flags &= ~CRYPT_FLAG_FREE_DEVICE;
346 if (options->cipher) {
347 free((char *)options->cipher);
348 options->cipher = NULL;
349 options->flags &= ~CRYPT_FLAG_FREE_CIPHER;
355 static int dm_remove_device(struct crypt_options *options)
360 if (!(dmt = dm_task_create(DM_DEVICE_REMOVE)))
362 if (!dm_task_set_name(dmt, options->name))
364 if (!dm_task_run(dmt))
371 dm_task_destroy(dmt);
372 flush_dm_workqueue();
377 static const char *dm_get_dir(void)
382 struct setup_backend setup_libdevmapper_backend = {
386 .create = dm_create_device,
387 .status = dm_query_device,
388 .remove = dm_remove_device,