2 * Copyright (c) 2004, 2005 Christophe Varoqui
8 #include <libdevmapper.h>
11 #include <sys/sysmacros.h>
12 #include "devmapper.h"
14 #define _UUID_PREFIX "part"
15 #define UUID_PREFIX _UUID_PREFIX "%d-"
16 #define _UUID_PREFIX_LEN (sizeof(_UUID_PREFIX) - 1)
17 #define MAX_PREFIX_LEN (_UUID_PREFIX_LEN + 4)
18 #define PARAMS_SIZE 1024
20 int dm_prereq(char * str, int x, int y, int z)
24 struct dm_versions *target;
25 struct dm_versions *last_target;
27 if (!(dmt = dm_task_create(DM_DEVICE_LIST_VERSIONS)))
30 dm_task_no_open_count(dmt);
32 if (!dm_task_run(dmt))
35 target = dm_task_get_versions(dmt);
37 /* Fetch targets and print 'em */
41 if (!strncmp(str, target->name, strlen(str)) &&
42 /* dummy prereq on multipath version */
43 target->version[0] >= x &&
44 target->version[1] >= y &&
45 target->version[2] >= z
49 target = (void *) target + target->next;
50 } while (last_target != target);
57 int dm_simplecmd(int task, const char *name, int no_flush, uint16_t udev_flags)
60 int udev_wait_flag = (task == DM_DEVICE_RESUME ||
61 task == DM_DEVICE_REMOVE);
62 #ifdef LIBDM_API_COOKIE
67 if (!(dmt = dm_task_create(task)))
70 if (!dm_task_set_name(dmt, name))
73 dm_task_no_open_count(dmt);
74 dm_task_skip_lockfs(dmt);
77 dm_task_no_flush(dmt);
79 #ifdef LIBDM_API_COOKIE
81 udev_flags |= DM_UDEV_DISABLE_LIBRARY_FALLBACK;
82 if (udev_wait_flag && !dm_task_set_cookie(dmt, &cookie, udev_flags))
86 #ifdef LIBDM_API_COOKIE
96 strip_slash (char * device)
100 while (*(p++) != 0x0) {
107 static int format_partname(char *buf, size_t bufsiz,
108 const char *mapname, const char *delim, int part)
110 if (snprintf(buf, bufsiz, "%s%s%d", mapname, delim, part) >= bufsiz)
116 static char *make_prefixed_uuid(int part, const char *uuid)
119 int len = MAX_PREFIX_LEN + strlen(uuid) + 1;
121 prefixed_uuid = malloc(len);
122 if (!prefixed_uuid) {
123 fprintf(stderr, "cannot create prefixed uuid : %s\n",
127 snprintf(prefixed_uuid, len, UUID_PREFIX "%s", part, uuid);
128 return prefixed_uuid;
131 int dm_addmap(int task, const char *name, const char *target,
132 const char *params, uint64_t size, int ro, const char *uuid,
133 int part, mode_t mode, uid_t uid, gid_t gid)
137 char *prefixed_uuid = NULL;
138 #ifdef LIBDM_API_COOKIE
140 uint16_t udev_flags = 0;
143 if (!(dmt = dm_task_create (task)))
146 if (!dm_task_set_name (dmt, name))
149 if (!dm_task_add_target (dmt, 0, size, target, params))
152 if (ro && !dm_task_set_ro (dmt))
155 if (task == DM_DEVICE_CREATE && uuid) {
156 prefixed_uuid = make_prefixed_uuid(part, uuid);
157 if (prefixed_uuid == NULL)
159 if (!dm_task_set_uuid(dmt, prefixed_uuid))
163 if (!dm_task_set_mode(dmt, mode))
165 if (!dm_task_set_uid(dmt, uid))
167 if (!dm_task_set_gid(dmt, gid))
170 dm_task_no_open_count(dmt);
172 #ifdef LIBDM_API_COOKIE
174 udev_flags = DM_UDEV_DISABLE_LIBRARY_FALLBACK;
175 if (task == DM_DEVICE_CREATE &&
176 !dm_task_set_cookie(dmt, &cookie, udev_flags))
179 r = dm_task_run (dmt);
180 #ifdef LIBDM_API_COOKIE
181 if (task == DM_DEVICE_CREATE)
182 dm_udev_wait(cookie);
185 dm_task_destroy (dmt);
191 static int dm_map_present(char *str, char **uuid)
201 if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
204 if (!dm_task_set_name(dmt, str))
207 dm_task_no_open_count(dmt);
209 if (!dm_task_run(dmt))
212 if (!dm_task_get_info(dmt, &info))
220 uuidtmp = dm_task_get_uuid(dmt);
221 if (uuidtmp && strlen(uuidtmp))
222 *uuid = strdup(uuidtmp);
225 dm_task_destroy(dmt);
229 static int dm_rename (const char *old, const char *new)
233 uint16_t udev_flags = DM_UDEV_DISABLE_LIBRARY_FALLBACK;
236 dmt = dm_task_create(DM_DEVICE_RENAME);
240 if (!dm_task_set_name(dmt, old) ||
241 !dm_task_set_newname(dmt, new) ||
242 !dm_task_no_open_count(dmt) ||
243 !dm_task_set_cookie(dmt, &cookie, udev_flags))
246 r = dm_task_run(dmt);
247 dm_udev_wait(cookie);
250 dm_task_destroy(dmt);
254 static const char *dm_find_uuid(const char *uuid)
257 const char *name = NULL, *tmp;
259 if ((dmt = dm_task_create(DM_DEVICE_INFO)) == NULL)
262 if (!dm_task_set_uuid(dmt, uuid) ||
266 tmp = dm_task_get_name(dmt);
267 if (tmp != NULL && *tmp != '\0')
271 dm_task_destroy(dmt);
276 dm_mapname(int major, int minor)
279 char *mapname = NULL;
282 if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
285 dm_task_no_open_count(dmt);
286 dm_task_set_major(dmt, major);
287 dm_task_set_minor(dmt, minor);
289 if (!dm_task_run(dmt))
292 map = dm_task_get_name(dmt);
293 if (map && strlen(map))
294 mapname = strdup(map);
297 dm_task_destroy(dmt);
304 * Return the device number of the first dependend device
305 * for a given target.
307 dev_t dm_get_first_dep(char *devname)
310 struct dm_deps *dm_deps;
313 if ((dmt = dm_task_create(DM_DEVICE_DEPS)) == NULL) {
316 if (!dm_task_set_name(dmt, devname)) {
319 if (!dm_task_run(dmt)) {
322 if ((dm_deps = dm_task_get_deps(dmt)) == NULL) {
325 if (dm_deps->count > 0) {
326 ret = dm_deps->device[0];
329 dm_task_destroy(dmt);
335 dm_mapuuid(const char *mapname)
341 if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
344 if (!dm_task_set_name(dmt, mapname))
346 dm_task_no_open_count(dmt);
348 if (!dm_task_run(dmt))
351 tmp = dm_task_get_uuid(dmt);
355 dm_task_destroy(dmt);
360 dm_devn (const char * mapname, int *major, int *minor)
366 if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
369 if (!dm_task_set_name(dmt, mapname))
372 if (!dm_task_run(dmt))
375 if (!dm_task_get_info(dmt, &info) || info.exists == 0)
383 dm_task_destroy(dmt);
388 dm_get_map(const char *mapname, char * outparams)
392 uint64_t start, length;
393 char *target_type = NULL;
396 if (!(dmt = dm_task_create(DM_DEVICE_TABLE)))
399 if (!dm_task_set_name(dmt, mapname))
401 dm_task_no_open_count(dmt);
403 if (!dm_task_run(dmt))
406 /* Fetch 1st target */
407 dm_get_next_target(dmt, NULL, &start, &length,
408 &target_type, ¶ms);
410 if (snprintf(outparams, PARAMS_SIZE, "%s", params) <= PARAMS_SIZE)
413 dm_task_destroy(dmt);
418 dm_get_opencount (const char * mapname)
424 if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
427 if (!dm_task_set_name(dmt, mapname))
430 if (!dm_task_run(dmt))
433 if (!dm_task_get_info(dmt, &info))
441 dm_task_destroy(dmt);
452 dm_type(const char * name, char * type)
456 uint64_t start, length;
457 char *target_type = NULL;
460 if (!(dmt = dm_task_create(DM_DEVICE_TABLE)))
463 if (!dm_task_set_name(dmt, name))
466 dm_task_no_open_count(dmt);
468 if (!dm_task_run(dmt))
471 /* Fetch 1st target */
472 if (dm_get_next_target(dmt, NULL, &start, &length,
473 &target_type, ¶ms) != NULL)
474 /* more than one target */
476 else if (!target_type)
478 else if (!strcmp(target_type, type))
482 dm_task_destroy(dmt);
488 * 0 : if both uuids end with same suffix which starts with UUID_PREFIX
492 dm_compare_uuid(const char *mapuuid, const char *partname)
497 partuuid = dm_mapuuid(partname);
501 if (!strncmp(partuuid, _UUID_PREFIX, _UUID_PREFIX_LEN)) {
502 char *p = partuuid + _UUID_PREFIX_LEN;
503 /* skip partition number */
506 if (p != partuuid + _UUID_PREFIX_LEN && *p == '-' &&
507 !strcmp(mapuuid, p + 1))
519 do_foreach_partmaps (const char * mapname, const char *uuid,
521 int (*partmap_func)(const char *, void *),
525 struct dm_names *names;
526 struct remove_data *rd = data;
528 char params[PARAMS_SIZE];
534 if (!(dmt = dm_task_create(DM_DEVICE_LIST)))
537 dm_task_no_open_count(dmt);
539 if (!dm_task_run(dmt))
542 if (!(names = dm_task_get_names(dmt)))
546 r = 0; /* this is perfectly valid */
550 if (dm_devn(mapname, &major, &minor) ||
551 (major != major(devt) || minor != minor(devt)))
553 * The latter could happen if a dm device "/dev/mapper/loop0"
554 * exits while kpartx is called on "/dev/loop0".
558 sprintf(dev_t, "%d:%d", major(devt), minor(devt));
563 if (is_dmdev && !strcmp(names->name, mapname))
567 * skip if we cannot fetch the map table from the kernel
569 if (dm_get_map(names->name, ¶ms[0]))
573 * skip if the table does not map over the multipath map
575 if (!strstr(params, dev_t))
579 * skip if devmap target is not "linear"
581 if (dm_type(names->name, "linear") != 1) {
583 printf("%s: is not a linear target. Not removing\n",
589 * skip if uuids don't match
591 if (uuid && dm_compare_uuid(uuid, names->name)) {
593 printf("%s: is not a kpartx partition. Not removing\n",
598 if (partmap_func(names->name, data) != 0)
602 names = (void *) names + next;
607 dm_task_destroy (dmt);
612 remove_partmap(const char *name, void *data)
614 struct remove_data *rd = (struct remove_data *)data;
617 if (dm_get_opencount(name)) {
619 printf("%s is in use. Not removing", name);
622 if (!dm_simplecmd(DM_DEVICE_REMOVE, name, 0, 0)) {
624 printf("%s: failed to remove\n", name);
626 } else if (rd->verbose)
627 printf("del devmap : %s\n", name);
632 dm_remove_partmaps (char * mapname, char *uuid, dev_t devt, int verbose)
634 struct remove_data rd = { verbose };
635 return do_foreach_partmaps(mapname, uuid, devt, remove_partmap, &rd);
638 int dm_find_part(const char *parent, const char *delim, int part,
639 const char *parent_uuid,
640 char *name, size_t namesiz, char **part_uuid, int verbose)
643 char params[PARAMS_SIZE];
649 if (!format_partname(name, namesiz, parent, delim, part)) {
651 fprintf(stderr, "partname too small\n");
655 r = dm_map_present(name, part_uuid);
656 if (r == 1 || parent_uuid == NULL || *parent_uuid == '\0')
659 uuid = make_prefixed_uuid(part, parent_uuid);
663 tmp = dm_find_uuid(uuid);
667 /* Sanity check on partition, see dm_foreach_partmaps */
668 if (dm_type(tmp, "linear") != 1)
672 * Try nondm uuid first. That way we avoid confusing
673 * a device name with a device mapper name.
675 if (!nondm_parse_uuid(parent_uuid, &major, &minor) &&
676 dm_devn(parent, &major, &minor))
678 snprintf(dev_t, sizeof(dev_t), "%d:%d", major, minor);
680 if (dm_get_map(tmp, params))
683 if (!strstr(params, dev_t))
687 fprintf(stderr, "found map %s for uuid %s, renaming to %s\n",
690 r = dm_rename(tmp, name);
694 fprintf(stderr, "renaming %s->%s failed\n", tmp, name);
702 char *nondm_create_uuid(dev_t devt)
704 #define NONDM_UUID_BUFLEN (34 + sizeof(NONDM_UUID_PREFIX) + \
705 sizeof(NONDM_UUID_SUFFIX))
706 static char uuid_buf[NONDM_UUID_BUFLEN];
707 snprintf(uuid_buf, sizeof(uuid_buf), "%s_%u:%u_%s",
708 NONDM_UUID_PREFIX, major(devt), minor(devt),
710 uuid_buf[NONDM_UUID_BUFLEN-1] = '\0';
714 int nondm_parse_uuid(const char *uuid, int *major, int *minor)
720 if (strncmp(uuid, NONDM_UUID_PREFIX "_", sizeof(NONDM_UUID_PREFIX)))
722 p = uuid + sizeof(NONDM_UUID_PREFIX);
723 ma = strtoul(p, &e, 10);
724 if (e == p || *e != ':')
727 mi = strtoul(p, &e, 10);
728 if (e == p || *e != '_')
731 if (strcmp(p, NONDM_UUID_SUFFIX))