1/*
2 * Copyright (c) 2010 The NetBSD Foundation, Inc.
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 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#include <sys/types.h>
31#include <sys/param.h>
32#include <sys/ioctl.h>
33
34#include <errno.h>
35#include <fcntl.h>
36#include <stdio.h>
37#include <stdlib.h>
38#include <string.h>
39#include <unistd.h>
40
41#include <prop/proplib.h>
42
43#include <dev/dm/netbsd-dm.h>
44
45#include "dm.h"
46
47/*
48 * Libdm library works like interface between device-mapper driver and
49 * NetBSD userspace. For start it uses same set of commands like linux
50 * libdevmapper, but in later stage if we introduce NetBSD device-mapper
51 * extensions we don't need to change libdevmapper.
52 *
53 * LIBDM basically creates one proplib dictionary with everything what is
54 * needed to work with device-mapper devices.
55 *
56 * Basic element of libdm is libdm_task which contains version and command
57 * string with another dictionary cmd.
58 */
59
60struct libdm_cmd {
61	prop_array_t ldm_cmd;
62};
63
64struct libdm_iter {
65	prop_object_iterator_t ldm_obji;
66};
67
68struct libdm_task {
69	prop_dictionary_t ldm_task;
70};
71
72struct libdm_table {
73	prop_dictionary_t ldm_tbl;
74};
75
76struct libdm_target {
77	prop_dictionary_t ldm_trgt;
78};
79
80struct libdm_dev {
81	prop_dictionary_t ldm_dev;
82};
83
84struct cmd_version cmd_ver[] = {
85	{"version", {4, 0, 0}},
86	{"targets", {4, 0, 0}},
87	{"create", {4, 0, 0}},
88	{"info",   {4, 0, 0}},
89	{"mknodes",{4, 0, 0}},
90	{"names",  {4, 0, 0}},
91	{"suspend",{4, 0, 0}},
92	{"remove", {4, 0, 0}},
93	{"rename", {4, 0, 0}},
94	{"resume", {4, 0, 0}},
95	{"clear",  {4, 0, 0}},
96	{"deps",   {4, 0, 0}},
97	{"reload", {4, 0, 0}},
98	{"status", {4, 0, 0}},
99	{"table",  {4, 0, 0}},
100	/* NetBSD device-mapper command extension goes here */
101	{NULL, {0, 0, 0}}
102};
103
104/* /dev/mapper/control managing routines */
105static int libdm_control_open(const char *);
106static int libdm_control_close(int);
107
108static int
109libdm_control_open(const char *path)
110{
111	int fd;
112#ifdef RUMP_ACTION
113	if ((fd = rump_sys_open(path, O_RDWR)) < 0)
114		return -1;
115#else
116	if ((fd = open(path, O_RDWR)) < 0)
117		return -1;
118#endif
119	return fd;
120}
121
122static int
123libdm_control_close(int fd)
124{
125
126#ifdef RUMP_ACTION
127	return rump_sys_close(fd);
128#else
129	return close(fd);
130#endif
131}
132
133/* Destroy iterator for arrays such as version strings, cmd_data. */
134void
135libdm_iter_destroy(libdm_iter_t libdm_iter)
136{
137
138	prop_object_iterator_release(libdm_iter->ldm_obji);
139	free(libdm_iter);
140}
141
142/*
143 * Issue ioctl call to kernel, releasing both dictionaries is
144 * left on callers.
145 */
146int
147libdm_task_run(libdm_task_t libdm_task)
148{
149	prop_dictionary_t dict;
150	int libdm_control_fd = -1;
151	int error;
152#ifdef RUMP_ACTION
153	struct plistref prefp;
154#endif
155	error = 0;
156
157	if (libdm_task == NULL)
158		return ENOENT;
159
160	if ((libdm_control_fd = libdm_control_open(DM_DEVICE_PATH)) < 0)
161		return errno;
162#ifdef RUMP_ACTION
163	prop_dictionary_externalize_to_pref(libdm_task->ldm_task,
164	    &prefp);
165
166	error = rump_sys_ioctl(libdm_control_fd, NETBSD_DM_IOCTL, &prefp);
167	if (error < 0) {
168		libdm_task_destroy(libdm_task);
169		libdm_task = NULL;
170		libdm_control_close(libdm_control_fd);
171
172		return error;
173	}
174	dict = prop_dictionary_internalize(prefp.pref_plist);
175#else
176	prop_dictionary_externalize_to_file(libdm_task->ldm_task, "/tmp/libdm_in");
177	error = prop_dictionary_sendrecv_ioctl(libdm_task->ldm_task,
178	    libdm_control_fd, NETBSD_DM_IOCTL, &dict);
179	if ( error != 0) {
180		libdm_task_destroy(libdm_task);
181		libdm_task = NULL;
182		libdm_control_close(libdm_control_fd);
183		return error;
184	}
185	prop_dictionary_externalize_to_file(dict, "/tmp/libdm_out");
186#endif
187
188	libdm_control_close(libdm_control_fd);
189	prop_object_retain(dict);
190	prop_object_release(libdm_task->ldm_task);
191	libdm_task->ldm_task = dict;
192
193	return EXIT_SUCCESS;
194}
195
196
197/* Create libdm General task structure */
198libdm_task_t
199libdm_task_create(const char *command)
200{
201	libdm_task_t task;
202	size_t i,len,slen;
203	prop_array_t ver;
204
205	task = NULL;
206
207	task = malloc(sizeof(*task));
208	if (task == NULL)
209		return NULL;
210
211	if ((task->ldm_task = prop_dictionary_create()) == NULL) {
212		free(task);
213		return NULL;
214	}
215
216	if ((prop_dictionary_set_cstring(task->ldm_task, DM_IOCTL_COMMAND,
217		    command)) == false) {
218		prop_object_release(task->ldm_task);
219		free(task);
220		return NULL;
221	}
222
223	len = strlen(command);
224
225	for (i = 0; cmd_ver[i].cmd != NULL; i++) {
226		slen = strlen(cmd_ver[i].cmd);
227
228		if (len != slen)
229			continue;
230
231		if ((strncmp(command, cmd_ver[i].cmd, slen)) == 0) {
232			ver = prop_array_create();
233			prop_array_add_uint32(ver, cmd_ver[i].version[0]);
234			prop_array_add_uint32(ver, cmd_ver[i].version[1]);
235			prop_array_add_uint32(ver, cmd_ver[i].version[2]);
236
237			prop_dictionary_set(task->ldm_task, DM_IOCTL_VERSION,
238			    ver);
239
240			prop_object_release(ver);
241			break;
242		}
243	}
244
245	return task;
246}
247
248void
249libdm_task_destroy(libdm_task_t libdm_task)
250{
251
252	if (libdm_task != NULL)
253		prop_object_release(libdm_task->ldm_task);
254	free(libdm_task);
255}
256
257/* Set device name */
258int
259libdm_task_set_name(const char *name, libdm_task_t libdm_task)
260{
261
262	if ((prop_dictionary_set_cstring(libdm_task->ldm_task,
263		    DM_IOCTL_NAME, name)) == false)
264		return ENOENT;
265
266	return 0;
267}
268
269/* Set device name */
270char *
271libdm_task_get_name(libdm_task_t libdm_task)
272{
273	char *name;
274
275	if (!prop_dictionary_get_cstring_nocopy(libdm_task->ldm_task,
276	    DM_IOCTL_NAME, (const char **)&name))
277		return NULL;
278
279	return name;
280}
281
282/* Set device uuid */
283int
284libdm_task_set_uuid(const char *uuid, libdm_task_t libdm_task)
285{
286
287	if ((prop_dictionary_set_cstring(libdm_task->ldm_task,
288	    DM_IOCTL_UUID, uuid)) == false)
289		return ENOENT;
290
291	return 0;
292}
293
294/* Set device name */
295char *
296libdm_task_get_uuid(libdm_task_t libdm_task)
297{
298	char *uuid;
299
300	if (!prop_dictionary_get_cstring_nocopy(libdm_task->ldm_task,
301	    DM_IOCTL_UUID, (const char **)&uuid))
302		return NULL;
303
304	return uuid;
305}
306
307/* Get command name */
308char *
309libdm_task_get_command(libdm_task_t libdm_task)
310{
311	char *command;
312
313	if (!prop_dictionary_get_cstring_nocopy(libdm_task->ldm_task,
314	    DM_IOCTL_COMMAND, (const char **)&command))
315		return NULL;
316
317	return command;
318}
319
320int32_t
321libdm_task_get_cmd_version(libdm_task_t libdm_task, uint32_t *ver, size_t size)
322{
323	prop_array_t prop_ver;
324	size_t i;
325
326	prop_ver = prop_dictionary_get(libdm_task->ldm_task,
327	    DM_IOCTL_VERSION);
328
329	i = prop_array_count(prop_ver);
330
331	if (i > size)
332		return -i;
333
334	for (i = 0; i < size; i++)
335		prop_array_get_uint32(prop_ver, i, &ver[i]);
336
337	return i;
338}
339
340/* Select device minor number. */
341int
342libdm_task_set_minor(uint32_t minor, libdm_task_t libdm_task)
343{
344
345	if ((prop_dictionary_set_uint32(libdm_task->ldm_task,
346	    DM_IOCTL_MINOR, minor)) == false)
347		return ENOENT;
348
349	return 0;
350}
351
352/* Select device minor number. */
353uint32_t
354libdm_task_get_minor(libdm_task_t libdm_task)
355{
356	uint32_t minor;
357
358	minor = 0;
359
360	(void)prop_dictionary_get_uint32(libdm_task->ldm_task,
361	    DM_IOCTL_MINOR, &minor);
362
363	return minor;
364}
365
366/* Set/Del DM_SUSPEND_FLAG for caller. */
367void
368libdm_task_set_suspend_flag(libdm_task_t libdm_task)
369{
370	uint32_t flags;
371
372	flags = 0;
373
374	(void)prop_dictionary_get_uint32(libdm_task->ldm_task,
375	    DM_IOCTL_FLAGS, &flags);
376
377	flags |= DM_SUSPEND_FLAG;
378
379	(void)prop_dictionary_set_uint32(libdm_task->ldm_task,
380	    DM_IOCTL_FLAGS, flags);
381}
382
383void
384libdm_task_del_suspend_flag(libdm_task_t libdm_task)
385{
386	uint32_t flags;
387
388	(void)prop_dictionary_get_uint32(libdm_task->ldm_task,
389	    DM_IOCTL_FLAGS, &flags);
390
391	flags &= ~DM_SUSPEND_FLAG;
392
393	(void)prop_dictionary_set_uint32(libdm_task->ldm_task,
394	    DM_IOCTL_FLAGS, flags);
395}
396
397/* Set/Del DM_STATUS_FLAG for caller. */
398void
399libdm_task_set_status_flag(libdm_task_t libdm_task)
400{
401	uint32_t flags;
402
403	flags = 0;
404
405	(void)prop_dictionary_get_uint32(libdm_task->ldm_task,
406	    DM_IOCTL_FLAGS, &flags);
407
408	flags |= DM_STATUS_TABLE_FLAG;
409
410	(void)prop_dictionary_set_uint32(libdm_task->ldm_task,
411	    DM_IOCTL_FLAGS, flags);
412}
413
414void
415libdm_task_del_status_flag(libdm_task_t libdm_task)
416{
417	uint32_t flags;
418
419	(void)prop_dictionary_get_uint32(libdm_task->ldm_task,
420	    DM_IOCTL_FLAGS, &flags);
421
422	flags &= ~DM_STATUS_TABLE_FLAG;
423
424	(void)prop_dictionary_set_uint32(libdm_task->ldm_task,
425	    DM_IOCTL_FLAGS, flags);
426}
427
428/* Set/Del DM_EXISTS_FLAG for caller. */
429void
430libdm_task_set_exists_flag(libdm_task_t libdm_task)
431{
432	uint32_t flags;
433
434	flags = 0;
435
436	(void)prop_dictionary_get_uint32(libdm_task->ldm_task,
437	    DM_IOCTL_FLAGS, &flags);
438
439	flags |= DM_EXISTS_FLAG;
440
441	(void)prop_dictionary_set_uint32(libdm_task->ldm_task,
442	    DM_IOCTL_FLAGS, flags);
443}
444
445void
446libdm_task_del_exists_flag(libdm_task_t libdm_task)
447{
448	uint32_t flags;
449
450	(void)prop_dictionary_get_uint32(libdm_task->ldm_task,
451	    DM_IOCTL_FLAGS, &flags);
452
453	flags &= ~DM_EXISTS_FLAG;
454
455	(void)prop_dictionary_set_uint32(libdm_task->ldm_task,
456	    DM_IOCTL_FLAGS, flags);
457}
458
459/* Set flags used by LVM this is shortcut and should not be used
460   by anyone else. */
461void
462libdm_task_set_flags(libdm_task_t libdm_task, uint32_t flags)
463{
464
465	(void)prop_dictionary_set_uint32(libdm_task->ldm_task,
466	    DM_IOCTL_FLAGS, flags);
467}
468
469/* Get ioctl protocol status flags. */
470uint32_t
471libdm_task_get_flags(libdm_task_t libdm_task)
472{
473	uint32_t flags;
474
475	(void)prop_dictionary_get_uint32(libdm_task->ldm_task,
476	    DM_IOCTL_FLAGS, &flags);
477
478	return flags;
479}
480
481/* Set ioctl protocol status flags. */
482uint32_t
483libdm_task_get_target_num(libdm_task_t libdm_task)
484{
485	uint32_t count;
486
487	(void)prop_dictionary_get_uint32(libdm_task->ldm_task,
488	    DM_IOCTL_TARGET_COUNT, &count);
489
490	return count;
491}
492
493int32_t
494libdm_task_get_open_num(libdm_task_t libdm_task)
495{
496	int32_t count;
497
498	(void)prop_dictionary_get_int32(libdm_task->ldm_task,
499	    DM_IOCTL_OPEN, &count);
500
501	return count;
502}
503
504uint32_t
505libdm_task_get_event_num(libdm_task_t libdm_task)
506{
507	uint32_t event;
508
509	(void)prop_dictionary_get_uint32(libdm_task->ldm_task,
510	    DM_IOCTL_EVENT, &event);
511
512	return event;
513}
514
515/* Set cmd_data dictionary entry to task struct. */
516int
517libdm_task_set_cmd(libdm_cmd_t libdm_cmd, libdm_task_t libdm_task)
518{
519
520	if ((prop_dictionary_set(libdm_task->ldm_task,
521	    DM_IOCTL_CMD_DATA, libdm_cmd->ldm_cmd)) == false)
522		return ENOENT;
523
524	return 0;
525}
526
527/* Get cmd_data dictionary entry from task struct */
528libdm_cmd_t
529libdm_task_get_cmd(libdm_task_t libdm_task)
530{
531	libdm_cmd_t cmd;
532
533	cmd = malloc(sizeof(*cmd));
534
535	cmd->ldm_cmd = prop_dictionary_get(libdm_task->ldm_task,
536	    DM_IOCTL_CMD_DATA);
537
538	if (cmd->ldm_cmd == NULL) {
539		free(cmd);
540		return NULL;
541	}
542
543	/* Get a reference prop_dictionary_get will not get it */
544	prop_object_retain(cmd->ldm_cmd);
545
546	return cmd;
547}
548
549/* Command functions
550 *
551 * Functions for creation, destroing, set, get of command area of
552 * ioctl dictionary.
553 */
554libdm_cmd_t
555libdm_cmd_create(void)
556{
557	libdm_cmd_t cmd;
558
559	cmd = malloc(sizeof(*cmd));
560	if (cmd == NULL)
561		return NULL;
562
563	cmd->ldm_cmd =  prop_array_create();
564
565	return cmd;
566}
567
568void
569libdm_cmd_destroy(libdm_cmd_t libdm_cmd)
570{
571
572	prop_object_release(libdm_cmd->ldm_cmd);
573	free(libdm_cmd);
574}
575
576/* Create iterator object for caller this can be used to
577   iterate through all members of cmd array. */
578libdm_iter_t
579libdm_cmd_iter_create(libdm_cmd_t libdm_cmd)
580{
581
582	libdm_iter_t iter;
583
584	iter = malloc(sizeof(*iter));
585	if (iter == NULL)
586		return NULL;
587
588	iter->ldm_obji = prop_array_iterator(libdm_cmd->ldm_cmd);
589
590	return iter;
591}
592
593int
594libdm_cmd_set_table(libdm_table_t libdm_table, libdm_cmd_t libdm_cmd)
595{
596
597	return prop_array_add(libdm_cmd->ldm_cmd,
598	    libdm_table->ldm_tbl);
599}
600
601
602libdm_target_t
603libdm_cmd_get_target(libdm_iter_t iter)
604{
605	libdm_target_t trgt;
606
607	trgt = malloc(sizeof(*trgt));
608	if (trgt == NULL)
609		return NULL;
610
611	trgt->ldm_trgt = prop_object_iterator_next(iter->ldm_obji);
612	if (trgt->ldm_trgt == NULL) {
613		free(trgt);
614		return NULL;
615	}
616
617	return trgt;
618}
619
620libdm_table_t
621libdm_cmd_get_table(libdm_iter_t iter)
622{
623	libdm_table_t tbl;
624
625	tbl = malloc(sizeof(*tbl));
626	if (tbl == NULL)
627		return NULL;
628
629	tbl->ldm_tbl = prop_object_iterator_next(iter->ldm_obji);
630	if (tbl->ldm_tbl == NULL) {
631		free(tbl);
632		return NULL;
633	}
634
635	return tbl;
636}
637
638libdm_dev_t
639libdm_cmd_get_dev(libdm_iter_t iter)
640{
641	libdm_dev_t dev;
642
643	dev = malloc(sizeof(*dev));
644	if (dev == NULL)
645		return NULL;
646
647	dev->ldm_dev = prop_object_iterator_next(iter->ldm_obji);
648	if (dev->ldm_dev == NULL) {
649		free(dev);
650		return NULL;
651	}
652
653	return dev;
654}
655
656/*
657 * Deps manipulation routines
658 */
659uint64_t
660libdm_cmd_get_deps(libdm_iter_t libdm_iter)
661{
662	prop_object_t obj;
663	uint64_t deps;
664
665	obj = prop_object_iterator_next(libdm_iter->ldm_obji);
666	deps = prop_number_unsigned_integer_value(obj);
667
668	if (obj != NULL)
669		prop_object_release(obj);
670
671	return deps;
672}
673
674/*
675 * Table manipulation routines
676 */
677libdm_table_t
678libdm_table_create(void)
679{
680	libdm_table_t table;
681
682	table = malloc(sizeof(*table));
683	if (table == NULL)
684		return NULL;
685
686	table->ldm_tbl = prop_dictionary_create();
687
688	return table;
689}
690
691void
692libdm_table_destroy(libdm_table_t libdm_table)
693{
694
695	prop_object_release(libdm_table->ldm_tbl);
696	free(libdm_table);
697}
698
699int
700libdm_table_set_start(uint64_t start, libdm_table_t libdm_table)
701{
702
703	if (libdm_table == NULL)
704		return ENOENT;
705
706	return prop_dictionary_set_uint64(libdm_table->ldm_tbl,
707	    DM_TABLE_START, start);
708}
709
710uint64_t
711libdm_table_get_start(libdm_table_t libdm_table)
712{
713	uint64_t start;
714
715	if (libdm_table == NULL)
716		return ENOENT;
717
718	(void)prop_dictionary_get_uint64(libdm_table->ldm_tbl, DM_TABLE_START,
719	    &start);
720
721	return start;
722}
723
724int
725libdm_table_set_length(uint64_t length, libdm_table_t libdm_table)
726{
727
728	if (libdm_table == NULL)
729		return ENOENT;
730
731	return prop_dictionary_set_uint64(libdm_table->ldm_tbl,
732	    DM_TABLE_LENGTH, length);
733}
734
735uint64_t
736libdm_table_get_length(libdm_table_t libdm_table)
737{
738	uint64_t length;
739
740	if (libdm_table == NULL)
741		return ENOENT;
742
743	prop_dictionary_get_uint64(libdm_table->ldm_tbl, DM_TABLE_LENGTH,
744	    &length);
745
746	return length;
747}
748
749int
750libdm_table_set_target(const char *name, libdm_table_t libdm_table)
751{
752
753	if (libdm_table == NULL)
754		return ENOENT;
755
756	return prop_dictionary_set_cstring(libdm_table->ldm_tbl, DM_TABLE_TYPE, name);
757}
758
759char *
760libdm_table_get_target(libdm_table_t libdm_table)
761{
762	char *target;
763
764	if (!prop_dictionary_get_cstring_nocopy(libdm_table->ldm_tbl, DM_TABLE_TYPE,
765	    (const char **)&target))
766		return NULL;
767
768	return target;
769}
770
771int
772libdm_table_set_params(const char *params, libdm_table_t  libdm_table)
773{
774
775	if (libdm_table == NULL)
776		return ENOENT;
777
778	return prop_dictionary_set_cstring(libdm_table->ldm_tbl,
779	    DM_TABLE_PARAMS, params);
780}
781
782/*
783 * Get table params string from libdm_table_t
784 * returned char * is dynamically allocated caller should free it.
785 */
786char *
787libdm_table_get_params(libdm_table_t  libdm_table)
788{
789	char *params;
790
791	if (!prop_dictionary_get_cstring_nocopy(libdm_table->ldm_tbl, DM_TABLE_PARAMS,
792	    (const char **)&params))
793		return NULL;
794
795	return params;
796}
797
798int32_t
799libdm_table_get_status(libdm_table_t libdm_table)
800{
801	int32_t status;
802
803	(void)prop_dictionary_get_int32(libdm_table->ldm_tbl, DM_TABLE_STAT,
804	    &status);
805
806	return status;
807}
808
809/*
810 * Target manipulation routines
811 */
812void
813libdm_target_destroy(libdm_target_t libdm_target)
814{
815
816	prop_object_release(libdm_target->ldm_trgt);
817	free(libdm_target);
818}
819
820char *
821libdm_target_get_name(libdm_target_t libdm_target)
822{
823	char *name;
824
825	if (!prop_dictionary_get_cstring_nocopy(libdm_target->ldm_trgt,
826	    DM_TARGETS_NAME, (const char **)&name))
827		return NULL;
828
829	return name;
830}
831
832int32_t
833libdm_target_get_version(libdm_target_t libdm_target, uint32_t *ver, size_t size)
834{
835	prop_array_t prop_ver;
836	size_t i;
837
838	prop_ver = prop_dictionary_get(libdm_target->ldm_trgt,
839	    DM_TARGETS_VERSION);
840
841	i = prop_array_count(prop_ver);
842
843	if (i > size)
844		return -i;
845
846	for (i = 0; i < size; i++)
847		prop_array_get_uint32(prop_ver, i, &ver[i]);
848
849	return i;
850}
851
852
853/*
854 * Dev manipulation routines
855 */
856void
857libdm_dev_destroy(libdm_dev_t libdm_dev)
858{
859
860	prop_object_release(libdm_dev->ldm_dev);
861	free(libdm_dev);
862}
863
864char *
865libdm_dev_get_name(libdm_dev_t libdm_dev)
866{
867	char *name;
868
869	if (!prop_dictionary_get_cstring_nocopy(libdm_dev->ldm_dev,
870	    DM_DEV_NAME, (const char **)&name))
871		return NULL;
872
873	return name;
874}
875
876uint32_t
877libdm_dev_get_minor(libdm_dev_t libdm_dev)
878{
879	uint32_t dev;
880
881	(void)prop_dictionary_get_uint32(libdm_dev->ldm_dev, DM_DEV_DEV,
882	    &dev);
883
884	return dev;
885}
886
887int
888libdm_dev_set_newname(const char *newname, libdm_cmd_t libdm_cmd)
889{
890
891	if (newname == NULL)
892		return ENOENT;
893
894	return prop_array_set_cstring(libdm_cmd->ldm_cmd, 0, newname);
895}
896