if_bge: Support more chipsets
[dragonfly.git] / lib / libdm / dm_task.c
CommitLineData
0cdd1155
AH
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
48struct dm_task {
49 int task_type;
50 int was_enoent;
51 prop_dictionary_t dict;
52 void *data_buffer;
53};
54
55struct dm_cmd {
56 int task_type;
57 const char *dm_cmd;
58 uint32_t cmd_version[3];
59};
60
61struct 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
85static 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
117static dm_error_func_t dm_log = _stderr_log;
118
119struct dm_task *
120dm_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
202err:
203 if (dmt->dict != NULL)
204 prop_object_release(dmt->dict);
205 if (dmt)
206 free(dmt);
207
208 return NULL;
209}
210
211
212void
213dm_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
228int
229dm_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
307unroll:
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
326err:
327 if (fd >= 0)
328 close(fd);
329
330 if (dmt_internal)
331 dm_task_destroy(dmt_internal);
332
333 return 0;
334}
335
336int
337dm_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
344const char *
345dm_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
354int
355dm_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
361int
362dm_task_set_major(struct dm_task *dmt __unused, int major __unused)
363{
364 return 1;
365}
366
367int
368dm_task_set_minor(struct dm_task *dmt, int minor)
369{
370 return prop_dictionary_set_int32(dmt->dict, DM_IOCTL_MINOR, minor);
371}
372
373int
374dm_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
383int
384dm_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
390const char *
391dm_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
400int
401dm_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
433err:
434 prop_object_release(target_dict);
435 return 0;
436}
437
438int
439dm_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
445int
446dm_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
451int
452dm_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
462int
463dm_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
472int
473dm_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
483int
484dm_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
491int
492dm_task_get_read_ahead(struct dm_task *dmt __unused, uint32_t *read_ahead)
493{
494 *read_ahead = 0;
495
496 return 1;
497}
498
499int
500dm_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
511int
512dm_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
549int
550dm_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
572struct dm_deps *
573dm_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
611struct dm_versions *
612dm_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
660struct dm_names *
661dm_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
709int
710dm_task_update_nodes(void)
711{
712
713 /* nothing else needed */
714 return 1;
715}
716
717void *
718dm_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
772err:
773 if (iter != NULL)
774 prop_object_iterator_release(iter);
775
776 return NULL;
777}
778
779uint32_t
780dm_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
790int
791dm_is_dm_major(uint32_t major)
792{
793 return (major == dm_get_major());
794}
795
796const char *
797dm_dir(void)
798{
799 return "/dev/mapper";
800}
801
802int
803dm_task_set_cookie(struct dm_task *dmt __unused, uint32_t *cookie __unused,
804 uint16_t udev_flags __unused)
805{
806 return 1;
807}
808
809int
810dm_udev_wait(uint32_t cookie __unused)
811{
812 return 1;
813}
814
815void
816dm_lib_release(void)
817{
818 return;
819}
820
821int
822dm_log_init(dm_error_func_t fn)
823{
824 if (fn)
825 dm_log = fn;
826 return 1;
827}
828
829int
830dm_log_init_verbose(int verbose __unused)
831{
832 return 1;
833}
834
835/* XXX: unused in kernel */
836int
837dm_task_set_uid(struct dm_task *dmt, uid_t uid)
838{
839 return prop_dictionary_set_uint32(dmt->dict, DM_DEV_UID,
840 (uint32_t)uid);
841}
842
843int
844dm_task_set_gid(struct dm_task *dmt, gid_t gid)
845{
846 return prop_dictionary_set_uint32(dmt->dict, DM_DEV_GID,
847 (uint32_t)gid);
848}
849
850int
851dm_task_set_mode(struct dm_task *dmt, mode_t mode)
852{
853 return prop_dictionary_set_uint32(dmt->dict, DM_DEV_MODE,
854 (uint32_t)mode);
855}
856
857int
858dm_task_no_flush(struct dm_task *dmt __unused)
859{
860 uint32_t flags = 0;
861
862 prop_dictionary_get_uint32(dmt->dict, DM_IOCTL_FLAGS, &flags);
863 flags |= DM_NOFLUSH_FLAG;
864
865 return prop_dictionary_set_uint32(dmt->dict, DM_IOCTL_FLAGS, flags);
866}
867
868int
869dm_task_skip_lockfs(struct dm_task *dmt __unused)
870{
871 uint32_t flags = 0;
872
873 prop_dictionary_get_uint32(dmt->dict, DM_IOCTL_FLAGS, &flags);
874 flags |= DM_SKIP_LOCKFS_FLAG;
875
876 return prop_dictionary_set_uint32(dmt->dict, DM_IOCTL_FLAGS, flags);
877}
878
879int dm_task_set_geometry(struct dm_task *dmt __unused,
880 const char *cylinders __unused, const char *heads __unused,
881 const char *sectors __unused, const char *start __unused)
882{
883 return 1;
884}
885
886/*****************************************************************************/
887/********************** DragonFly-specific extensions ************************/
888/*****************************************************************************/
889void *
890dm_get_next_version(struct dm_task *dmt, void *cur, const char **target_type,
891 uint32_t *target_ver)
892{
893 prop_object_iterator_t iter;
894 prop_dictionary_t target_dict;
895 prop_array_t pa, pa_ver;
896 unsigned int count;
897 int j;
898
899 if ((pa = prop_dictionary_get(dmt->dict, DM_IOCTL_CMD_DATA)) == NULL)
900 return NULL;
901
902 count = prop_array_count(pa);
903
904 if (cur == NULL) {
905 if ((iter = prop_array_iterator(pa)) == NULL)
906 return NULL;
907 } else {
908 iter = (prop_object_iterator_t)cur;
909 }
910
911 /* Get the next target dict */
912 if ((target_dict = prop_object_iterator_next(iter)) == NULL) {
913 /* If there are no more target dicts, release the iterator */
914 goto err;
915 }
916
917 if (!prop_dictionary_get_cstring_nocopy(target_dict, DM_TARGETS_NAME,
918 target_type))
919 goto err;
920
921 if ((pa_ver = prop_dictionary_get(target_dict, DM_TARGETS_VERSION))
922 == NULL)
923 goto err;
924
925 for (j = 0; j < 3; j++) {
926 if (!prop_array_get_uint32(pa_ver, j, &target_ver[j]))
927 goto err;
928 }
929
930 /* If we are at the last element, make sure we return NULL */
931 if (target_dict == prop_array_get(pa, count-1))
932 goto err;
933
934 return (void *)iter;
935 /* NOT REACHED */
936
937err:
938 if (iter != NULL)
939 prop_object_iterator_release(iter);
940
941 return NULL;
942}
943
944void *
945dm_get_next_dep(struct dm_task *dmt, void *cur, uint64_t *dep)
946{
947 prop_object_iterator_t iter;
948 prop_object_t po;
949 prop_array_t pa;
950 unsigned int count;
951
952 *dep = 0;
953
954 if ((pa = prop_dictionary_get(dmt->dict, DM_IOCTL_CMD_DATA)) == NULL)
955 return NULL;
956
957 count = prop_array_count(pa);
958
959 if (cur == NULL) {
960 if ((iter = prop_array_iterator(pa)) == NULL)
961 return NULL;
962 } else {
963 iter = (prop_object_iterator_t)cur;
964 }
965
966 /* Get the next target dict */
967 if ((po = prop_object_iterator_next(iter)) == NULL) {
968 /* If there are no more target dicts, release the iterator */
969 goto err;
970 }
971
972 *dep = prop_number_unsigned_integer_value(po);
973
974 /* If we are at the last element, make sure we return NULL */
975 if (po == prop_array_get(pa, count-1))
976 goto err;
977
978 return (void *)iter;
979 /* NOT REACHED */
980
981err:
982 if (iter != NULL)
983 prop_object_iterator_release(iter);
984
985 return NULL;
986}
987
988void *
989dm_get_next_name(struct dm_task *dmt, void *cur, const char **name,
990 uint64_t *dev)
991{
992 prop_object_iterator_t iter;
993 prop_dictionary_t devs_dict;
994 prop_array_t pa;
995 unsigned int count;
996
997 if ((pa = prop_dictionary_get(dmt->dict, DM_IOCTL_CMD_DATA)) == NULL)
998 return NULL;
999
1000 count = prop_array_count(pa);
1001
1002
1003 if (cur == NULL) {
1004 if ((iter = prop_array_iterator(pa)) == NULL)
1005 return NULL;
1006 } else {
1007 iter = (prop_object_iterator_t)cur;
1008 }
1009
1010 /* Get the next dev dict */
1011 if ((devs_dict = prop_object_iterator_next(iter)) == NULL) {
1012 /* If there are no more dev dicts, release the iterator */
1013 goto err;
1014 }
1015
1016 if (!prop_dictionary_get_cstring_nocopy(devs_dict, DM_DEV_NAME, name))
1017 goto err;
1018
1019 if (!prop_dictionary_get_uint64(devs_dict, DM_DEV_DEV, dev))
1020 goto err;
1021
1022 /* If we are at the last element, make sure we return NULL */
1023 if (devs_dict == prop_array_get(pa, count-1))
1024 goto err;
1025
1026 return (void *)iter;
1027 /* NOT REACHED */
1028
1029err:
1030 if (iter != NULL)
1031 prop_object_iterator_release(iter);
1032
1033 return NULL;
1034
1035}