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