xref: /dragonfly/lib/libdm/dm_task.c (revision 9348a738)
1 /*
2  * Copyright (c) 2011 Alex Hornung <alex@alexhornung.com>.
3  * All rights reserved.
4  *
5  * This code is derived from software contributed to The NetBSD Foundation
6  * by Adam Hamsik.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in
16  *    the documentation and/or other materials provided with the
17  *    distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
23  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
25  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
29  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32 #include <sys/types.h>
33 #include <sys/param.h>
34 #include <sys/ioctl.h>
35 #include <sys/stat.h>
36 #include <machine/inttypes.h>
37 #include <dev/disk/dm/netbsd-dm.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <stdio.h>
41 #include <unistd.h>
42 #include <fcntl.h>
43 #include <errno.h>
44 
45 #include <libprop/proplib.h>
46 #include "libdm.h"
47 
48 struct dm_task {
49 	int			task_type;
50 	int			was_enoent;
51 	prop_dictionary_t	dict;
52 	void			*data_buffer;
53 };
54 
55 struct dm_cmd {
56 	int		task_type;
57 	const char	*dm_cmd;
58 	uint32_t	cmd_version[3];
59 };
60 
61 struct dm_cmd dm_cmds[] = {
62 	{ DM_DEVICE_REMOVE,		"remove",	{4, 0, 0} },
63 	{ DM_DEVICE_REMOVE_ALL,		"remove_all",	{4, 0, 0} },
64 	{ DM_DEVICE_CREATE,		"create",	{4, 0, 0} },
65 	{ DM_DEVICE_RELOAD,		"reload",	{4, 0, 0} },
66 	{ DM_DEVICE_RESUME,		"resume",	{4, 0, 0} },
67 	{ DM_DEVICE_SUSPEND,		"suspend",	{4, 0, 0} },
68 	{ DM_DEVICE_CLEAR,		"clear",	{4, 0, 0} },
69 	{ DM_DEVICE_LIST_VERSIONS,	"targets",	{4, 1, 0} },
70 	{ DM_DEVICE_STATUS,		"status",	{4, 0, 0} },
71 	{ DM_DEVICE_TABLE,		"table",	{4, 0, 0} },
72 	{ DM_DEVICE_INFO,		"info",		{4, 0, 0} },
73 	{ DM_DEVICE_DEPS,		"deps",		{4, 0, 0} },
74 	{ DM_DEVICE_VERSION,		"version",	{4, 0, 0} },
75 	{ DM_DEVICE_TARGET_MSG,		"message",	{4, 2, 0} },
76 	{ DM_DEVICE_RENAME,		"rename",	{4, 0, 0} },
77 	{ DM_DEVICE_LIST,		"names",	{4, 0, 0} },
78 	{ 0,				NULL,		{0, 0, 0} }
79 };
80 
81 #define _LOG_DEBUG	0
82 #define _LOG_WARN	5
83 #define _LOG_ERR	10
84 
85 static void _stderr_log(int level, const char *file,
86     int line, const char *fmt, ...)
87 {
88 	const char *prefix;
89 	__va_list ap;
90 
91 	switch (level) {
92 	case _LOG_DEBUG:
93 		prefix = "debug: ";
94 		break;
95 	case _LOG_WARN:
96 		prefix = "warning: ";
97 		break;
98 	case _LOG_ERR:
99 		prefix = "error: ";
100 		break;
101 	default:
102 		prefix = "";
103 	}
104 
105 	fprintf(stderr, "libdm %s:%d: ", file, line);
106 	fprintf(stderr, "%s", prefix);
107 
108 	__va_start(ap, fmt);
109 	vfprintf(stderr, fmt, ap);
110 	__va_end(ap);
111 
112 	fprintf(stderr, "\n");
113 
114 	return;
115 }
116 
117 static dm_error_func_t dm_log = _stderr_log;
118 
119 struct dm_task *
120 dm_task_create(int task_type)
121 {
122 	struct dm_task *dmt;
123 	struct dm_cmd *cmd = NULL;
124 	const char *task_cmd = NULL;
125 	prop_array_t pa;
126 	uint32_t flags = DM_EXISTS_FLAG;
127 	int i;
128 
129 	for (i = 0; dm_cmds[i].dm_cmd != NULL; i++) {
130 		if (dm_cmds[i].task_type == task_type) {
131 			cmd = &dm_cmds[i];
132 			task_cmd = dm_cmds[i].dm_cmd;
133 			break;
134 		}
135 	}
136 
137 	if (task_cmd == NULL)
138 		return NULL;
139 
140 	if (task_type == DM_DEVICE_TABLE)
141 		flags |= DM_STATUS_TABLE_FLAG;
142 
143 	if (task_type == DM_DEVICE_SUSPEND)
144 		flags |= DM_SUSPEND_FLAG;
145 
146 	if ((dmt = malloc(sizeof(*dmt))) == NULL)
147 		return NULL;
148 
149 	memset(dmt, 0, sizeof(*dmt));
150 
151 	dmt->task_type = task_type;
152 	dmt->was_enoent = 0;
153 
154 	if ((dmt->dict = prop_dictionary_create()) == NULL)
155 		goto err;
156 
157 	if ((pa = prop_array_create_with_capacity(3)) == NULL)
158 		goto err;
159 
160 	if (!prop_array_add_uint32(pa, cmd->cmd_version[0])) {
161 		prop_object_release(pa);
162 		goto err;
163 	}
164 
165 	if (!prop_array_add_uint32(pa, cmd->cmd_version[1])) {
166 		prop_object_release(pa);
167 		goto err;
168 	}
169 
170 	if (!prop_array_add_uint32(pa, cmd->cmd_version[2])) {
171 		prop_object_release(pa);
172 		goto err;
173 	}
174 
175 	if (!prop_dictionary_set(dmt->dict, DM_IOCTL_VERSION, pa)) {
176 		prop_object_release(pa);
177 		goto err;
178 	}
179 
180 	prop_object_release(pa);
181 
182 	if (!prop_dictionary_set_cstring(dmt->dict, DM_IOCTL_COMMAND,
183 	    task_cmd))
184 		goto err;
185 
186 	if (!prop_dictionary_set_uint32(dmt->dict, DM_IOCTL_FLAGS, flags))
187 		goto err;
188 
189 	if ((pa = prop_array_create_with_capacity(5)) == NULL)
190 		goto err;
191 
192 	if (!prop_dictionary_set(dmt->dict, DM_IOCTL_CMD_DATA, pa)) {
193 		prop_object_release(pa);
194 		goto err;
195 	}
196 
197 	prop_object_release(pa);
198 
199 	return dmt;
200 	/* NOT REACHED */
201 
202 err:
203 	if (dmt->dict != NULL)
204 		prop_object_release(dmt->dict);
205 	if (dmt)
206 		free(dmt);
207 
208 	return NULL;
209 }
210 
211 
212 void
213 dm_task_destroy(struct dm_task *dmt)
214 {
215 	if (dmt) {
216 		if (dmt->data_buffer)
217 			free(dmt->data_buffer);
218 
219 		if (dmt->dict) {
220 			prop_object_release(dmt->dict);
221 			dmt->dict = NULL;
222 		}
223 
224 		free(dmt);
225 	}
226 }
227 
228 int
229 dm_task_run(struct dm_task *dmt)
230 {
231 	struct dm_task *dmt_internal = NULL;
232 	prop_dictionary_t ret_pd = NULL;
233 	prop_array_t pa;
234 	int error;
235 	int fd;
236 	int need_unroll = 0;
237 
238 	if ((fd = open("/dev/mapper/control", O_RDWR)) < -1)
239 		goto err;
240 
241 	pa = prop_dictionary_get(dmt->dict, DM_IOCTL_CMD_DATA);
242 	if ((dmt->task_type == DM_DEVICE_CREATE) && (pa != NULL) &&
243 	    (prop_array_count(pa) > 0)) {
244 		/*
245 		 * Magic to separate a combined DM_DEVICE_CREATE+RELOAD int
246 		 * a DM_DEVICE_CREATE and a RELOAD with target table.
247 		 */
248 
249 		if ((dmt_internal = dm_task_create(DM_DEVICE_CREATE)) == NULL)
250 			goto err;
251 		if (!dm_task_set_name(dmt_internal, dm_task_get_name(dmt)))
252 			goto err;
253 		if (!dm_task_set_uuid(dmt_internal, dm_task_get_uuid(dmt)))
254 			goto err;
255 		if (!dm_task_run(dmt_internal))
256 			goto err;
257 		dm_task_destroy(dmt_internal);
258 		dmt_internal = NULL;
259 
260 		if (!prop_dictionary_set_cstring_nocopy(dmt->dict,
261 		    DM_IOCTL_COMMAND, "reload"))
262 			goto unroll;
263 		dmt->task_type = DM_DEVICE_RELOAD;
264 		if ((error = prop_dictionary_sendrecv_ioctl(dmt->dict, fd,
265 		    NETBSD_DM_IOCTL, &ret_pd)) != 0) {
266 			dm_log(_LOG_ERR, __FILE__, __LINE__, "ioctl failed: %d",
267 			    error);
268 			goto unroll;
269 		}
270 
271 		if (!prop_dictionary_set_cstring_nocopy(dmt->dict,
272 		    DM_IOCTL_COMMAND, "resume"))
273 			goto unroll;
274 		dmt->task_type = DM_DEVICE_RESUME;
275 		/* Remove superfluous stuff */
276 		prop_dictionary_remove(dmt->dict, DM_IOCTL_CMD_DATA);
277 
278 		need_unroll = 1;
279 	}
280 
281 	if ((error = prop_dictionary_sendrecv_ioctl(dmt->dict, fd,
282 	    NETBSD_DM_IOCTL, &ret_pd)) != 0) {
283 		if (((error == ENOENT) &&
284 		    ((dmt->task_type == DM_DEVICE_INFO) ||
285 		    (dmt->task_type == DM_DEVICE_STATUS)))) {
286 			dmt->was_enoent = 1;
287 			ret_pd = NULL;
288 		} else {
289 			dm_log(_LOG_ERR, __FILE__, __LINE__, "ioctl failed: %d",
290 			    error);
291 			if (need_unroll)
292 				goto unroll;
293 			else
294 				goto err;
295 		}
296 	}
297 
298 	if (ret_pd)
299 		prop_object_retain(ret_pd);
300 
301 	prop_object_release(dmt->dict);
302 	dmt->dict = ret_pd;
303 
304 	return 1;
305 	/* NOT REACHED */
306 
307 unroll:
308 	prop_dictionary_remove(dmt->dict, DM_IOCTL_CMD_DATA);
309 
310 	if (!prop_dictionary_set_cstring_nocopy(dmt->dict, DM_IOCTL_COMMAND,
311 	    "remove")) {
312 		dm_log(_LOG_ERR, __FILE__, __LINE__, "couldn't unroll changes "
313 		    "in dm_task_run");
314 		goto err;
315 	}
316 
317 	if ((error = prop_dictionary_sendrecv_ioctl(dmt->dict, fd,
318 	    NETBSD_DM_IOCTL, &ret_pd)) != 0) {
319 		dm_log(_LOG_ERR, __FILE__, __LINE__, "ioctl failed: %d",
320 		    error);
321 		goto unroll;
322 	}
323 	dmt->task_type = DM_DEVICE_REMOVE;
324 	dm_task_run(dmt);
325 
326 err:
327 	if (fd >= 0)
328 		close(fd);
329 
330 	if (dmt_internal)
331 		dm_task_destroy(dmt_internal);
332 
333 	return 0;
334 }
335 
336 int
337 dm_task_set_name(struct dm_task *dmt, const char *name)
338 {
339 	return prop_dictionary_set_cstring(dmt->dict, DM_IOCTL_NAME,
340 	    __DECONST(char *, name));
341 }
342 
343 
344 const char *
345 dm_task_get_name(struct dm_task *dmt)
346 {
347 	const char *name = NULL;
348 
349 	prop_dictionary_get_cstring_nocopy(dmt->dict, DM_IOCTL_NAME, &name);
350 
351 	return name;
352 }
353 
354 int
355 dm_task_set_newname(struct dm_task *dmt, const char *newname)
356 {
357 	return prop_dictionary_set_cstring(dmt->dict, DM_DEV_NEWNAME,
358 	    __DECONST(char *, newname));
359 }
360 
361 int
362 dm_task_set_major(struct dm_task *dmt __unused, int major __unused)
363 {
364 	return 1;
365 }
366 
367 int
368 dm_task_set_minor(struct dm_task *dmt, int minor)
369 {
370 	return prop_dictionary_set_int32(dmt->dict, DM_IOCTL_MINOR, minor);
371 }
372 
373 int
374 dm_task_get_minor(struct dm_task *dmt)
375 {
376 	int minor = 0;
377 
378 	minor = prop_dictionary_get_int32(dmt->dict, DM_IOCTL_MINOR, &minor);
379 
380 	return minor;
381 }
382 
383 int
384 dm_task_set_uuid(struct dm_task *dmt, const char *uuid)
385 {
386 	return prop_dictionary_set_cstring(dmt->dict, DM_IOCTL_UUID,
387 	    __DECONST(char *,uuid));
388 }
389 
390 const char *
391 dm_task_get_uuid(struct dm_task *dmt)
392 {
393 	const char *uuid = NULL;
394 
395 	prop_dictionary_get_cstring_nocopy(dmt->dict, DM_IOCTL_UUID, &uuid);
396 
397 	return uuid;
398 }
399 
400 int
401 dm_task_add_target(struct dm_task *dmt, uint64_t start, size_t size,
402     const char *target, const char *params)
403 {
404 	prop_dictionary_t target_dict = NULL;
405 	prop_array_t pa = NULL;
406 
407 	if ((pa = prop_dictionary_get(dmt->dict, DM_IOCTL_CMD_DATA)) == NULL)
408 		return 0;
409 
410 	if ((target_dict = prop_dictionary_create()) == NULL)
411 		return 0;
412 
413 	if (!prop_dictionary_set_uint64(target_dict, DM_TABLE_START, start))
414 		goto err;
415 
416 	if (!prop_dictionary_set_uint64(target_dict, DM_TABLE_LENGTH, size))
417 		goto err;
418 
419 	if (!prop_dictionary_set_cstring(target_dict, DM_TABLE_TYPE, target))
420 		goto err;
421 
422 	if (!prop_dictionary_set_cstring(target_dict, DM_TABLE_PARAMS, params))
423 		goto err;
424 
425 	if (!prop_array_add(pa, target_dict))
426 		goto err;
427 
428 	prop_object_release(target_dict);
429 
430 	return 1;
431 	/* NOT REACHED */
432 
433 err:
434 	prop_object_release(target_dict);
435 	return 0;
436 }
437 
438 int
439 dm_task_set_sector(struct dm_task *dmt, uint64_t sector)
440 {
441 	return prop_dictionary_set_uint64(dmt->dict, DM_MESSAGE_SECTOR,
442 	    sector);
443 }
444 
445 int
446 dm_task_set_message(struct dm_task *dmt, const char *msg)
447 {
448 	return prop_dictionary_set_cstring(dmt->dict, DM_MESSAGE_STR, msg);
449 }
450 
451 int
452 dm_task_set_ro(struct dm_task *dmt)
453 {
454 	uint32_t flags = 0;
455 
456 	prop_dictionary_get_uint32(dmt->dict, DM_IOCTL_FLAGS, &flags);
457 	flags |= DM_READONLY_FLAG;
458 
459 	return prop_dictionary_set_uint32(dmt->dict, DM_IOCTL_FLAGS, flags);
460 }
461 
462 int
463 dm_task_no_open_count(struct dm_task *dmt __unused)
464 {
465 	/*
466 	 * nothing else needed, since we don't have performance problems when
467 	 * getting the open count.
468 	 */
469 	return 1;
470 }
471 
472 int
473 dm_task_query_inactive_table(struct dm_task *dmt)
474 {
475 	uint32_t flags = 0;
476 
477 	prop_dictionary_get_uint32(dmt->dict, DM_IOCTL_FLAGS, &flags);
478 	flags |= DM_QUERY_INACTIVE_TABLE_FLAG;
479 
480 	return prop_dictionary_set_uint32(dmt->dict, DM_IOCTL_FLAGS, flags);
481 }
482 
483 int
484 dm_task_set_read_ahead(struct dm_task *dmt __unused,
485     uint32_t read_ahead __unused)
486 {
487 	/* We don't support readahead */
488 	return 1;
489 }
490 
491 int
492 dm_task_get_read_ahead(struct dm_task *dmt __unused, uint32_t *read_ahead)
493 {
494 	*read_ahead = 0;
495 
496 	return 1;
497 }
498 
499 int
500 dm_task_secure_data(struct dm_task *dmt)
501 {
502 	/* XXX: needs kernel support */
503 	uint32_t flags = 0;
504 
505 	prop_dictionary_get_uint32(dmt->dict, DM_IOCTL_FLAGS, &flags);
506 	flags |= DM_SECURE_DATA_FLAG;
507 
508 	return prop_dictionary_set_uint32(dmt->dict, DM_IOCTL_FLAGS, flags);
509 }
510 
511 int
512 dm_task_get_info(struct dm_task *dmt, struct dm_info *dmi)
513 {
514 	uint32_t flags = 0;
515 
516 	memset(dmi, 0, sizeof(struct dm_info));
517 
518 	/* Hack due to the way Linux dm works */
519 	if (dmt->was_enoent) {
520 		dmi->exists = 0;
521 		return 1;
522 		/* NOT REACHED */
523 	}
524 
525 	if (!prop_dictionary_get_uint32(dmt->dict, DM_IOCTL_FLAGS,
526 	    &flags))
527 		return 0;
528 
529 	prop_dictionary_get_int32(dmt->dict, DM_IOCTL_OPEN, &dmi->open_count);
530 
531 	prop_dictionary_get_uint32(dmt->dict, DM_IOCTL_TARGET_COUNT,
532 	    &dmi->target_count);
533 
534 	prop_dictionary_get_uint32(dmt->dict, DM_IOCTL_EVENT, &dmi->event_nr);
535 
536 	prop_dictionary_get_uint32(dmt->dict, DM_IOCTL_MINOR, &dmi->minor);
537 
538 	dmi->major = dm_get_major();
539 
540 	dmi->read_only = (flags & DM_READONLY_FLAG);
541 	dmi->exists = (flags & DM_EXISTS_FLAG);
542 	dmi->suspended = (flags & DM_SUSPEND_FLAG);
543 	dmi->live_table = (flags & DM_ACTIVE_PRESENT_FLAG);
544 	dmi->inactive_table = (flags & DM_INACTIVE_PRESENT_FLAG);
545 
546 	return 1;
547 }
548 
549 int
550 dm_task_get_driver_version(struct dm_task *dmt, char *ver, size_t ver_sz)
551 {
552 	prop_array_t pa_ver;
553 	uint32_t maj = 0, min = 0, patch = 0;
554 
555 	if ((pa_ver = prop_dictionary_get(dmt->dict, DM_IOCTL_VERSION)) == NULL)
556 		return 0;
557 
558 	if (!prop_array_get_uint32(pa_ver, 0, &maj))
559 		return 0;
560 
561 	if (!prop_array_get_uint32(pa_ver, 1, &min))
562 		return 0;
563 
564 	if (!prop_array_get_uint32(pa_ver, 2, &patch))
565 		return 0;
566 
567 	snprintf(ver, ver_sz, "%u.%u.%u", maj, min, patch);
568 
569 	return 1;
570 }
571 
572 struct dm_deps *
573 dm_task_get_deps(struct dm_task *dmt)
574 {
575 	prop_object_iterator_t iter;
576 	prop_array_t pa;
577 	prop_object_t po;
578 	struct dm_deps *deps;
579 
580 	unsigned int count;
581 	int i;
582 
583 	if ((pa = prop_dictionary_get(dmt->dict, DM_IOCTL_CMD_DATA)) == NULL)
584 		return NULL;
585 
586 	count = prop_array_count(pa);
587 
588 	if (dmt->data_buffer != NULL)
589 		free(dmt->data_buffer);
590 
591 	if ((dmt->data_buffer = malloc(sizeof(struct dm_deps) +
592 	    (count * sizeof(uint64_t)))) == NULL)
593 		return NULL;
594 
595 	if ((iter = prop_array_iterator(pa)) == NULL)
596 		return NULL;
597 
598 	deps = (struct dm_deps *)dmt->data_buffer;
599 	memset(deps, 0, sizeof(struct dm_deps) + (count * sizeof(uint64_t)));
600 	i = 0;
601 	while ((po = prop_object_iterator_next(iter)) != NULL)
602 		deps->deps[i++] = prop_number_unsigned_integer_value(po);
603 
604 	deps->count = (uint32_t)count;
605 
606 	prop_object_iterator_release(iter);
607 
608 	return deps;
609 }
610 
611 struct dm_versions *
612 dm_task_get_versions(struct dm_task *dmt)
613 {
614 	prop_object_iterator_t iter;
615 	prop_dictionary_t target_dict;
616 	prop_array_t pa, pa_ver;
617 	struct dm_versions *vers;
618 
619 	unsigned int count;
620 	int i, j;
621 
622 	if ((pa = prop_dictionary_get(dmt->dict, DM_IOCTL_CMD_DATA)) == NULL)
623 		return NULL;
624 
625 	count = prop_array_count(pa);
626 
627 	if (dmt->data_buffer != NULL)
628 		free(dmt->data_buffer);
629 
630 	if ((dmt->data_buffer = malloc(sizeof(struct dm_versions) * count))
631 	    == NULL)
632 		return NULL;
633 
634 	if ((iter = prop_array_iterator(pa)) == NULL)
635 		return NULL;
636 
637 	vers = (struct dm_versions *)dmt->data_buffer;
638 	memset(vers, 0, sizeof(struct dm_versions) * count);
639 	i = 0;
640 	while ((target_dict = prop_object_iterator_next(iter)) != NULL) {
641 		vers[i].next = sizeof(struct dm_versions);
642 		prop_dictionary_get_cstring_nocopy(target_dict,
643 		    DM_TARGETS_NAME, &vers[i].name);
644 
645 		pa_ver = prop_dictionary_get(target_dict, DM_TARGETS_VERSION);
646 		for (j = 0; j < 3; j++)
647 			prop_array_get_uint32(pa_ver, j, &vers[i].version[j]);
648 
649 		++i;
650 	}
651 
652 	/* Finish the array */
653 	vers[i-1].next = 0;
654 
655 	prop_object_iterator_release(iter);
656 
657 	return (struct dm_versions *)dmt->data_buffer;
658 }
659 
660 struct dm_names *
661 dm_task_get_names(struct dm_task *dmt)
662 {
663 	prop_object_iterator_t iter;
664 	prop_dictionary_t devs_dict;
665 	prop_array_t pa;
666 	struct dm_names *names;
667 
668 	unsigned int count;
669 	int i;
670 
671 	if ((pa = prop_dictionary_get(dmt->dict, DM_IOCTL_CMD_DATA)) == NULL)
672 		return NULL;
673 
674 	count = prop_array_count(pa);
675 
676 	if (dmt->data_buffer != NULL)
677 		free(dmt->data_buffer);
678 
679 	if ((dmt->data_buffer = malloc(sizeof(struct dm_names) * count))
680 	    == NULL)
681 		return NULL;
682 
683 	if ((iter = prop_array_iterator(pa)) == NULL)
684 		return NULL;
685 
686 	names = (struct dm_names *)dmt->data_buffer;
687 	memset(names, 0, sizeof(struct dm_names) * count);
688 	i = 0;
689 	while ((devs_dict = prop_object_iterator_next(iter)) != NULL) {
690 		names[i].next = sizeof(struct dm_names);
691 
692 		prop_dictionary_get_cstring_nocopy(devs_dict,
693 		    DM_DEV_NAME, &names[i].name);
694 
695 		prop_dictionary_get_uint64(devs_dict, DM_DEV_DEV,
696 		    &names[i].dev);
697 
698 		++i;
699 	}
700 
701 	/* Finish the array */
702 	names[i-1].next = 0;
703 
704 	prop_object_iterator_release(iter);
705 
706 	return (struct dm_names *)dmt->data_buffer;
707 }
708 
709 int
710 dm_task_update_nodes(void)
711 {
712 
713 	/* nothing else needed */
714 	return 1;
715 }
716 
717 void *
718 dm_get_next_target(struct dm_task *dmt, void *cur, uint64_t *startp,
719     uint64_t *lengthp, char **target_type, char **params)
720 {
721 	prop_object_iterator_t  iter;
722 	prop_dictionary_t target_dict;
723 	prop_array_t pa;
724 	uint64_t ulength;
725 	unsigned int count;
726 
727 	if ((pa = prop_dictionary_get(dmt->dict, DM_IOCTL_CMD_DATA)) == NULL)
728 		return NULL;
729 
730 	count = prop_array_count(pa);
731 
732 	if (cur == NULL) {
733 		if ((iter = prop_array_iterator(pa)) == NULL)
734 			return NULL;
735 	} else {
736 		iter = (prop_object_iterator_t)cur;
737 	}
738 
739 	/* Get the next target dict */
740 	if ((target_dict = prop_object_iterator_next(iter)) == NULL) {
741 		/* If there are no more target dicts, release the iterator */
742 		goto err;
743 	}
744 
745 	if (!prop_dictionary_get_cstring_nocopy(target_dict, DM_TABLE_TYPE,
746 	    (const char **)target_type))
747 		goto err;
748 
749 	/*
750 	 * Ugly __DECONST and (const char **) casts due to the linux prototype
751 	 * of this function.
752 	 */
753 	*params = __DECONST(char *, "");
754 	prop_dictionary_get_cstring_nocopy(target_dict, DM_TABLE_PARAMS,
755 	    (const char **)params);
756 
757 	if (!prop_dictionary_get_uint64(target_dict, DM_TABLE_START, startp))
758 		goto err;
759 
760 	if (!prop_dictionary_get_uint64(target_dict, DM_TABLE_LENGTH, &ulength))
761 		goto err;
762 
763 	*lengthp = (size_t)ulength;
764 
765 	/* If we are at the last element, make sure we return NULL */
766 	if (target_dict == prop_array_get(pa, count-1))
767 		goto err;
768 
769 	return (void *)iter;
770 	/* NOT REACHED */
771 
772 err:
773 	if (iter != NULL)
774 		prop_object_iterator_release(iter);
775 
776 	return NULL;
777 }
778 
779 uint32_t
780 dm_get_major(void)
781 {
782 	struct stat sb;
783 
784 	if (stat("/dev/mapper/control", &sb) < 0)
785 		return 0;
786 
787 	return (uint32_t)major(sb.st_dev);
788 }
789 
790 int
791 dm_is_dm_major(uint32_t major)
792 {
793 	return (major == dm_get_major());
794 }
795 
796 const char *
797 dm_dir(void)
798 {
799 	return "/dev/mapper";
800 }
801 
802 void
803 dm_udev_set_sync_support(int sync_udev __unused)
804 {
805 	return;
806 }
807 
808 int
809 dm_task_set_cookie(struct dm_task *dmt __unused, uint32_t *cookie __unused,
810     uint16_t udev_flags __unused)
811 {
812 	return 1;
813 }
814 
815 int
816 dm_udev_wait(uint32_t cookie __unused)
817 {
818 	return 1;
819 }
820 
821 void
822 dm_lib_release(void)
823 {
824 	return;
825 }
826 
827 int
828 dm_log_init(dm_error_func_t fn)
829 {
830 	if (fn)
831 		dm_log = fn;
832 	return 1;
833 }
834 
835 int
836 dm_log_init_verbose(int verbose __unused)
837 {
838 	return 1;
839 }
840 
841 /* XXX: unused in kernel */
842 int
843 dm_task_set_uid(struct dm_task *dmt, uid_t uid)
844 {
845 	return prop_dictionary_set_uint32(dmt->dict, DM_DEV_UID,
846 	    (uint32_t)uid);
847 }
848 
849 int
850 dm_task_set_gid(struct dm_task *dmt, gid_t gid)
851 {
852 	return prop_dictionary_set_uint32(dmt->dict, DM_DEV_GID,
853 	    (uint32_t)gid);
854 }
855 
856 int
857 dm_task_set_mode(struct dm_task *dmt, mode_t mode)
858 {
859 	return prop_dictionary_set_uint32(dmt->dict, DM_DEV_MODE,
860 	    (uint32_t)mode);
861 }
862 
863 int
864 dm_task_no_flush(struct dm_task *dmt __unused)
865 {
866 	uint32_t flags = 0;
867 
868 	prop_dictionary_get_uint32(dmt->dict, DM_IOCTL_FLAGS, &flags);
869 	flags |= DM_NOFLUSH_FLAG;
870 
871 	return prop_dictionary_set_uint32(dmt->dict, DM_IOCTL_FLAGS, flags);
872 }
873 
874 int
875 dm_task_skip_lockfs(struct dm_task *dmt __unused)
876 {
877 	uint32_t flags = 0;
878 
879 	prop_dictionary_get_uint32(dmt->dict, DM_IOCTL_FLAGS, &flags);
880 	flags |= DM_SKIP_LOCKFS_FLAG;
881 
882 	return prop_dictionary_set_uint32(dmt->dict, DM_IOCTL_FLAGS, flags);
883 }
884 
885 int dm_task_set_geometry(struct dm_task *dmt __unused,
886     const char *cylinders __unused, const char *heads __unused,
887     const char *sectors __unused, const char *start __unused)
888 {
889 	return 1;
890 }
891 
892 /*****************************************************************************/
893 /********************** DragonFly-specific extensions ************************/
894 /*****************************************************************************/
895 void *
896 dm_get_next_version(struct dm_task *dmt, void *cur, const char **target_type,
897     uint32_t *target_ver)
898 {
899 	prop_object_iterator_t iter;
900 	prop_dictionary_t target_dict;
901 	prop_array_t pa, pa_ver;
902 	unsigned int count;
903 	int j;
904 
905 	if ((pa = prop_dictionary_get(dmt->dict, DM_IOCTL_CMD_DATA)) == NULL)
906 		return NULL;
907 
908 	count = prop_array_count(pa);
909 
910 	if (cur == NULL) {
911 		if ((iter = prop_array_iterator(pa)) == NULL)
912 			return NULL;
913 	} else {
914 		iter = (prop_object_iterator_t)cur;
915 	}
916 
917 	/* Get the next target dict */
918 	if ((target_dict = prop_object_iterator_next(iter)) == NULL) {
919 		/* If there are no more target dicts, release the iterator */
920 		goto err;
921 	}
922 
923 	if (!prop_dictionary_get_cstring_nocopy(target_dict, DM_TARGETS_NAME,
924 	    target_type))
925 		goto err;
926 
927 	if ((pa_ver = prop_dictionary_get(target_dict, DM_TARGETS_VERSION))
928 	    == NULL)
929 		goto err;
930 
931 	for (j = 0; j < 3; j++) {
932 		if (!prop_array_get_uint32(pa_ver, j, &target_ver[j]))
933 			goto err;
934 	}
935 
936 	/* If we are at the last element, make sure we return NULL */
937 	if (target_dict == prop_array_get(pa, count-1))
938 		goto err;
939 
940 	return (void *)iter;
941 	/* NOT REACHED */
942 
943 err:
944 	if (iter != NULL)
945 		prop_object_iterator_release(iter);
946 
947 	return NULL;
948 }
949 
950 void *
951 dm_get_next_dep(struct dm_task *dmt, void *cur, uint64_t *dep)
952 {
953 	prop_object_iterator_t iter;
954 	prop_object_t po;
955 	prop_array_t pa;
956 	unsigned int count;
957 
958 	*dep = 0;
959 
960 	if ((pa = prop_dictionary_get(dmt->dict, DM_IOCTL_CMD_DATA)) == NULL)
961 		return NULL;
962 
963 	count = prop_array_count(pa);
964 
965 	if (cur == NULL) {
966 		if ((iter = prop_array_iterator(pa)) == NULL)
967 			return NULL;
968 	} else {
969 		iter = (prop_object_iterator_t)cur;
970 	}
971 
972 	/* Get the next target dict */
973 	if ((po = prop_object_iterator_next(iter)) == NULL) {
974 		/* If there are no more target dicts, release the iterator */
975 		goto err;
976 	}
977 
978 	*dep = prop_number_unsigned_integer_value(po);
979 
980 	/* If we are at the last element, make sure we return NULL */
981 	if (po == prop_array_get(pa, count-1))
982 		goto err;
983 
984 	return (void *)iter;
985 	/* NOT REACHED */
986 
987 err:
988 	if (iter != NULL)
989 		prop_object_iterator_release(iter);
990 
991 	return NULL;
992 }
993 
994 void *
995 dm_get_next_name(struct dm_task *dmt, void *cur, const char **name,
996     uint64_t *dev)
997 {
998 	prop_object_iterator_t iter;
999 	prop_dictionary_t devs_dict;
1000 	prop_array_t pa;
1001 	unsigned int count;
1002 
1003 	if ((pa = prop_dictionary_get(dmt->dict, DM_IOCTL_CMD_DATA)) == NULL)
1004 		return NULL;
1005 
1006 	count = prop_array_count(pa);
1007 
1008 
1009 	if (cur == NULL) {
1010 		if ((iter = prop_array_iterator(pa)) == NULL)
1011 			return NULL;
1012 	} else {
1013 		iter = (prop_object_iterator_t)cur;
1014 	}
1015 
1016 	/* Get the next dev dict */
1017 	if ((devs_dict = prop_object_iterator_next(iter)) == NULL) {
1018 		/* If there are no more dev dicts, release the iterator */
1019 		goto err;
1020 	}
1021 
1022 	if (!prop_dictionary_get_cstring_nocopy(devs_dict, DM_DEV_NAME, name))
1023 		goto err;
1024 
1025 	if (!prop_dictionary_get_uint64(devs_dict, DM_DEV_DEV, dev))
1026 		goto err;
1027 
1028 	/* If we are at the last element, make sure we return NULL */
1029 	if (devs_dict == prop_array_get(pa, count-1))
1030 		goto err;
1031 
1032 	return (void *)iter;
1033 	/* NOT REACHED */
1034 
1035 err:
1036 	if (iter != NULL)
1037 		prop_object_iterator_release(iter);
1038 
1039 	return NULL;
1040 
1041 }
1042