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_simple(int task, const char *name);
43 static int dm_init(void)
45 dm_log_init(set_dm_error);
46 if (!_dm_simple(DM_DEVICE_LIST_VERSIONS, "test")) {
47 set_error("Cannot communicate with device-mapper. Is the dm_mod module loaded?");
51 return 1; /* unsafe memory */
54 static void dm_exit(void)
60 static void flush_dm_workqueue(void)
63 * Unfortunately this is the only way to trigger libdevmapper's
64 * update_nodes function
70 static char *__lookup_dev(char *path, dev_t dev)
79 path[PATH_MAX - 1] = '\0';
80 ptr = path + strlen(path);
83 space = PATH_MAX - (ptr - path);
89 while((entry = readdir(dir))) {
90 if (entry->d_name[0] == '.' &&
91 (entry->d_name[1] == '\0' || (entry->d_name[1] == '.' &&
92 entry->d_name[2] == '\0')))
95 strncpy(ptr, entry->d_name, space);
96 if (lstat(path, &st) < 0)
99 if (S_ISDIR(st.st_mode)) {
100 result = __lookup_dev(path, dev);
103 } else if (S_ISBLK(st.st_mode)) {
104 if (st.st_rdev == dev) {
105 result = strdup(path);
116 static char *lookup_dev(const char *dev)
118 uint32_t major, minor;
119 char buf[PATH_MAX + 1];
121 if (sscanf(dev, "%" PRIu32 ":%" PRIu32, &major, &minor) != 2)
124 strncpy(buf, DEVICE_DIR, PATH_MAX);
125 buf[PATH_MAX] = '\0';
127 return __lookup_dev(buf, makedev(major, minor));
130 static char *get_params(struct crypt_options *options, const char *key)
136 hexkey = safe_alloc(options->key_size * 2 + 1);
138 set_error("Memory allocation problem");
142 for(i = 0; i < options->key_size; i++)
143 sprintf(&hexkey[i * 2], "%02x", (unsigned char)key[i]);
145 params = safe_alloc(strlen(hexkey) + strlen(options->cipher) +
146 strlen(options->device) + 64);
148 set_error("Memory allocation problem");
152 sprintf(params, "%s %s %" PRIu64 " %s %" PRIu64,
153 options->cipher, hexkey, options->skip,
154 options->device, options->offset);
162 static int dm_create_device(int reload, struct crypt_options *options,
165 struct dm_task *dmt = NULL;
166 struct dm_task *dmt_query = NULL;
171 params = get_params(options, key);
174 if (!(dmt = dm_task_create(reload ? DM_DEVICE_RELOAD
175 : DM_DEVICE_CREATE)))
177 if (!dm_task_set_name(dmt, options->name))
179 if (options->flags & CRYPT_FLAG_READONLY && !dm_task_set_ro(dmt))
181 if (!dm_task_add_target(dmt, 0, options->size, CRYPT_TARGET, params))
183 if (!dm_task_run(dmt))
187 dm_task_destroy(dmt);
188 if (!(dmt = dm_task_create(DM_DEVICE_RESUME)))
190 if (!dm_task_set_name(dmt, options->name))
192 if (!dm_task_run(dmt))
196 if (!dm_task_get_info(dmt, &dmi))
199 options->flags |= CRYPT_FLAG_READONLY;
201 /* run udevsettle to avoid a race in libdevmapper causing busy dm devices */
207 if (r < 0 && !reload) {
208 char *error = (char *)get_error();
210 error = strdup(error);
212 dm_task_destroy(dmt);
214 if (!(dmt = dm_task_create(DM_DEVICE_REMOVE)))
215 goto out_restore_error;
216 if (!dm_task_set_name(dmt, options->name))
217 goto out_restore_error;
218 if (!dm_task_run(dmt))
219 goto out_restore_error;
222 set_error("%s", error);
231 dm_task_destroy(dmt);
233 dm_task_destroy(dmt_query);
234 flush_dm_workqueue();
238 static int dm_query_device(int details, struct crypt_options *options,
243 uint64_t start, length;
244 char *target_type, *params;
248 if (!(dmt = dm_task_create(details ? DM_DEVICE_TABLE
249 : DM_DEVICE_STATUS)))
251 if (!dm_task_set_name(dmt, options->name))
254 if (!dm_task_run(dmt))
258 if (!dm_task_get_info(dmt, &dmi))
266 next = dm_get_next_target(dmt, next, &start, &length,
267 &target_type, ¶ms);
268 if (!target_type || strcmp(target_type, CRYPT_TARGET) != 0 ||
272 options->hash = NULL;
273 options->cipher = NULL;
276 options->size = length;
278 char *cipher, *key_, *device;
281 set_error("Invalid dm table");
283 cipher = strsep(¶ms, " ");
284 key_ = strsep(¶ms, " ");
288 val64 = strtoull(params, ¶ms, 10);
292 options->skip = val64;
294 device = strsep(¶ms, " ");
298 val64 = strtoull(params, ¶ms, 10);
301 options->offset = val64;
303 options->cipher = strdup(cipher);
304 options->key_size = strlen(key_) / 2;
310 *key = safe_alloc(options->key_size);
312 set_error("Out of memory");
318 for(i = 0; i < options->key_size; i++) {
319 memcpy(buffer, &key_[i * 2], 2);
320 (*key)[i] = strtoul(buffer, &endp, 16);
321 if (endp != &buffer[2]) {
328 memset(key_, 0, strlen(key_));
329 options->device = lookup_dev(device);
334 r = (dmi.open_count > 0);
338 dm_task_destroy(dmt);
341 options->flags |= CRYPT_FLAG_FREE_DEVICE;
343 options->flags |= CRYPT_FLAG_FREE_CIPHER;
344 options->flags &= ~CRYPT_FLAG_READONLY;
346 options->flags |= CRYPT_FLAG_READONLY;
348 if (options->device) {
349 free((char *)options->device);
350 options->device = NULL;
351 options->flags &= ~CRYPT_FLAG_FREE_DEVICE;
353 if (options->cipher) {
354 free((char *)options->cipher);
355 options->cipher = NULL;
356 options->flags &= ~CRYPT_FLAG_FREE_CIPHER;
362 static int dm_remove_device(struct crypt_options *options)
367 if (!(dmt = dm_task_create(DM_DEVICE_REMOVE)))
369 if (!dm_task_set_name(dmt, options->name))
371 if (!dm_task_run(dmt))
378 dm_task_destroy(dmt);
379 flush_dm_workqueue();
384 static const char *dm_get_dir(void)
389 struct setup_backend setup_libdevmapper_backend = {
393 .create = dm_create_device,
394 .status = dm_query_device,
395 .remove = dm_remove_device,