libdm - add dummy dm_udev_set_sync_support()
[dragonfly.git] / lib / libdm / dm_task.c
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 }