2 * Copyright (C) 2001 Sistina Software (UK) Limited.
4 * This file is released under the LGPL.
7 #include "libdm-targets.h"
8 #include "libdm-common.h"
15 #include <sys/param.h>
19 #include <linux/dm-ioctl.h>
20 #include <linux/kdev_t.h>
22 #define DEV_DIR "/dev/"
24 static char _dm_dir[PATH_MAX] = DEV_DIR DM_DIR;
26 static int _verbose = 0;
29 * Library users can provide their own logging
32 static void _default_log(int level, const char *file, int line,
37 if (level > _LOG_WARN && !_verbose)
42 if (level < _LOG_WARN)
43 vfprintf(stderr, f, ap);
49 if (level < _LOG_WARN)
50 fprintf(stderr, "\n");
52 fprintf(stdout, "\n");
55 dm_log_fn _log = _default_log;
57 void dm_log_init(dm_log_fn fn)
62 void dm_log_init_verbose(int level)
67 static void _build_dev_path(char *buffer, size_t len, const char *dev_name)
69 /* If there's a /, assume caller knows what they're doing */
70 if (strchr(dev_name, '/'))
71 snprintf(buffer, len, "%s", dev_name);
73 snprintf(buffer, len, "%s/%s", _dm_dir, dev_name);
76 int dm_get_library_version(char *version, size_t size)
78 strncpy(version, DM_LIB_VERSION, size);
82 struct dm_task *dm_task_create(int type)
84 struct dm_task *dmt = malloc(sizeof(*dmt));
86 if (!dm_check_version())
90 log_error("dm_task_create: malloc(%d) failed", sizeof(*dmt));
94 memset(dmt, 0, sizeof(*dmt));
103 int dm_task_set_name(struct dm_task *dmt, const char *name)
107 struct stat st1, st2;
111 dmt->dev_name = NULL;
114 /* If path was supplied, remove it if it points to the same device
115 * as its last component.
117 if ((pos = strrchr(name, '/'))) {
118 snprintf(path, sizeof(path), "%s/%s", _dm_dir, pos + 1);
120 if (stat(name, &st1) || stat(path, &st2) ||
121 !(st1.st_dev == st2.st_dev)) {
122 log_error("dm_task_set_name: Device %s not found",
130 if (!(dmt->dev_name = strdup(name))) {
131 log_error("dm_task_set_name: strdup(%s) failed", name);
138 int dm_task_set_uuid(struct dm_task *dmt, const char *uuid)
145 if (!(dmt->uuid = strdup(uuid))) {
146 log_error("dm_task_set_uuid: strdup(%s) failed", uuid);
153 int dm_task_set_major(struct dm_task *dmt, int major)
156 log_debug("Setting major: %d", dmt->major);
161 int dm_task_set_minor(struct dm_task *dmt, int minor)
164 log_debug("Setting minor: %d", dmt->minor);
169 int dm_task_add_target(struct dm_task *dmt, uint64_t start, uint64_t size,
170 const char *ttype, const char *params)
172 struct target *t = create_target(start, size, ttype, params);
178 dmt->head = dmt->tail = t;
187 static int _add_dev_node(const char *dev_name, uint32_t major, uint32_t minor)
191 dev_t dev = MKDEV(major, minor);
193 _build_dev_path(path, sizeof(path), dev_name);
195 if (stat(path, &info) >= 0) {
196 if (!S_ISBLK(info.st_mode)) {
197 log_error("A non-block device file at '%s' "
198 "is already present", path);
202 if (info.st_rdev == dev)
205 if (unlink(path) < 0) {
206 log_error("Unable to unlink device node for '%s'",
212 if (mknod(path, S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP, dev) < 0) {
213 log_error("Unable to make device node for '%s'", dev_name);
220 static int _rename_dev_node(const char *old_name, const char *new_name)
222 char oldpath[PATH_MAX];
223 char newpath[PATH_MAX];
226 _build_dev_path(oldpath, sizeof(oldpath), old_name);
227 _build_dev_path(newpath, sizeof(newpath), new_name);
229 if (stat(newpath, &info) == 0) {
230 if (!S_ISBLK(info.st_mode)) {
231 log_error("A non-block device file at '%s' "
232 "is already present", newpath);
236 if (unlink(newpath) < 0) {
237 if (errno == EPERM) {
238 /* devfs, entry has already been renamed */
241 log_error("Unable to unlink device node for '%s'",
247 if (rename(oldpath, newpath) < 0) {
248 log_error("Unable to rename device node from '%s' to '%s'",
256 static int _rm_dev_node(const char *dev_name)
261 _build_dev_path(path, sizeof(path), dev_name);
263 if (stat(path, &info) < 0)
266 if (unlink(path) < 0) {
267 log_error("Unable to unlink device node for '%s'", dev_name);
280 static int _do_node_op(node_op_t type, const char *dev_name, uint32_t major,
281 uint32_t minor, const char *old_name)
285 return _add_dev_node(dev_name, major, minor);
287 return _rm_dev_node(dev_name);
289 return _rename_dev_node(old_name, dev_name);
295 static LIST_INIT(_node_ops);
297 struct node_op_parms {
307 static void _store_str(char **pos, char **ptr, const char *str)
311 *pos += strlen(*ptr) + 1;
314 static int _stack_node_op(node_op_t type, const char *dev_name, uint32_t major,
315 uint32_t minor, const char *old_name)
317 struct node_op_parms *nop;
318 size_t len = strlen(dev_name) + strlen(old_name) + 2;
321 if (!(nop = malloc(sizeof(*nop) + len))) {
322 log_error("Insufficient memory to stack mknod operation");
331 _store_str(&pos, &nop->dev_name, dev_name);
332 _store_str(&pos, &nop->old_name, old_name);
334 list_add(&_node_ops, &nop->list);
339 static void _pop_node_ops(void)
341 struct list *noph, *nopht;
342 struct node_op_parms *nop;
344 list_iterate_safe(noph, nopht, &_node_ops) {
345 nop = list_item(noph, struct node_op_parms);
346 _do_node_op(nop->type, nop->dev_name, nop->major, nop->minor,
348 list_del(&nop->list);
353 int add_dev_node(const char *dev_name, uint32_t major, uint32_t minor)
355 return _stack_node_op(NODE_ADD, dev_name, major, minor, "");
358 int rename_dev_node(const char *old_name, const char *new_name)
360 return _stack_node_op(NODE_RENAME, new_name, 0, 0, old_name);
363 int rm_dev_node(const char *dev_name)
365 return _stack_node_op(NODE_DEL, dev_name, 0, 0, "");
368 void update_devs(void)
373 int dm_set_dev_dir(const char *dir)
375 snprintf(_dm_dir, sizeof(_dm_dir), "%s%s", dir, DM_DIR);
379 const char *dm_dir(void)