xref: /dragonfly/lib/libdm/dm_task.c (revision 98b7ab4073679d0c13f2cf1e6ad42b6aaa2086c6)
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 <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 
47 struct dm_task {
48           int                           task_type;
49           int                           was_enoent;
50           prop_dictionary_t   dict;
51           void                          *data_buffer;
52 };
53 
54 struct dm_cmd {
55           int                 task_type;
56           const char          *dm_cmd;
57           uint32_t  cmd_version[3];
58 };
59 
60 struct 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 
_stderr_log(int level,const char * file,int line,const char * fmt,...)84 static 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 
116 static dm_error_func_t dm_log = _stderr_log;
117 
118 struct dm_task *
dm_task_create(int task_type)119 dm_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 
201 err:
202           if (dmt->dict != NULL)
203                     prop_object_release(dmt->dict);
204           if (dmt)
205                     free(dmt);
206 
207           return NULL;
208 }
209 
210 
211 void
dm_task_destroy(struct dm_task * dmt)212 dm_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 
227 int
dm_task_run(struct dm_task * dmt)228 dm_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 
306 unroll:
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 
325 err:
326           if (fd >= 0)
327                     close(fd);
328 
329           if (dmt_internal)
330                     dm_task_destroy(dmt_internal);
331 
332           return 0;
333 }
334 
335 int
dm_task_set_name(struct dm_task * dmt,const char * name)336 dm_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 
343 const char *
dm_task_get_name(struct dm_task * dmt)344 dm_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 
353 int
dm_task_set_newname(struct dm_task * dmt,const char * newname)354 dm_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 
360 int
dm_task_set_major(struct dm_task * dmt __unused,int major __unused)361 dm_task_set_major(struct dm_task *dmt __unused, int major __unused)
362 {
363           return 1;
364 }
365 
366 int
dm_task_set_minor(struct dm_task * dmt,int minor)367 dm_task_set_minor(struct dm_task *dmt, int minor)
368 {
369           return prop_dictionary_set_int32(dmt->dict, DM_IOCTL_MINOR, minor);
370 }
371 
372 int
dm_task_get_minor(struct dm_task * dmt)373 dm_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 
382 int
dm_task_set_uuid(struct dm_task * dmt,const char * uuid)383 dm_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 
389 const char *
dm_task_get_uuid(struct dm_task * dmt)390 dm_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 
399 int
dm_task_add_target(struct dm_task * dmt,uint64_t start,size_t size,const char * target,const char * params)400 dm_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 
432 err:
433           prop_object_release(target_dict);
434           return 0;
435 }
436 
437 int
dm_task_set_sector(struct dm_task * dmt,uint64_t sector)438 dm_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 
444 int
dm_task_set_message(struct dm_task * dmt,const char * msg)445 dm_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 
450 int
dm_task_set_ro(struct dm_task * dmt)451 dm_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 
461 int
dm_task_no_open_count(struct dm_task * dmt __unused)462 dm_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 
471 int
dm_task_query_inactive_table(struct dm_task * dmt)472 dm_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 
482 int
dm_task_set_read_ahead(struct dm_task * dmt __unused,uint32_t read_ahead __unused)483 dm_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 
490 int
dm_task_get_read_ahead(struct dm_task * dmt __unused,uint32_t * read_ahead)491 dm_task_get_read_ahead(struct dm_task *dmt __unused, uint32_t *read_ahead)
492 {
493           *read_ahead = 0;
494 
495           return 1;
496 }
497 
498 int
dm_task_secure_data(struct dm_task * dmt)499 dm_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 
510 int
dm_task_get_info(struct dm_task * dmt,struct dm_info * dmi)511 dm_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 
548 int
dm_task_get_driver_version(struct dm_task * dmt,char * ver,size_t ver_sz)549 dm_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 
571 struct dm_deps *
dm_task_get_deps(struct dm_task * dmt)572 dm_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 
610 struct dm_versions *
dm_task_get_versions(struct dm_task * dmt)611 dm_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 
659 struct dm_names *
dm_task_get_names(struct dm_task * dmt)660 dm_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 
708 int
dm_task_update_nodes(void)709 dm_task_update_nodes(void)
710 {
711 
712           /* nothing else needed */
713           return 1;
714 }
715 
716 void *
dm_get_next_target(struct dm_task * dmt,void * cur,uint64_t * startp,uint64_t * lengthp,char ** target_type,char ** params)717 dm_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 
771 err:
772           if (iter != NULL)
773                     prop_object_iterator_release(iter);
774 
775           return NULL;
776 }
777 
778 uint32_t
dm_get_major(void)779 dm_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 
789 int
dm_is_dm_major(uint32_t major)790 dm_is_dm_major(uint32_t major)
791 {
792           return (major == dm_get_major());
793 }
794 
795 const char *
dm_dir(void)796 dm_dir(void)
797 {
798           return "/dev/mapper";
799 }
800 
801 void
dm_udev_set_sync_support(int sync_udev __unused)802 dm_udev_set_sync_support(int sync_udev __unused)
803 {
804           return;
805 }
806 
807 int
dm_task_set_cookie(struct dm_task * dmt __unused,uint32_t * cookie __unused,uint16_t udev_flags __unused)808 dm_task_set_cookie(struct dm_task *dmt __unused, uint32_t *cookie __unused,
809     uint16_t udev_flags __unused)
810 {
811           return 1;
812 }
813 
814 int
dm_udev_wait(uint32_t cookie __unused)815 dm_udev_wait(uint32_t cookie __unused)
816 {
817           return 1;
818 }
819 
820 void
dm_lib_release(void)821 dm_lib_release(void)
822 {
823           return;
824 }
825 
826 int
dm_log_init(dm_error_func_t fn)827 dm_log_init(dm_error_func_t fn)
828 {
829           if (fn)
830                     dm_log = fn;
831           return 1;
832 }
833 
834 int
dm_log_init_verbose(int verbose __unused)835 dm_log_init_verbose(int verbose __unused)
836 {
837           return 1;
838 }
839 
840 /* XXX: unused in kernel */
841 int
dm_task_set_uid(struct dm_task * dmt,uid_t uid)842 dm_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 
848 int
dm_task_set_gid(struct dm_task * dmt,gid_t gid)849 dm_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 
855 int
dm_task_set_mode(struct dm_task * dmt,mode_t mode)856 dm_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 
862 int
dm_task_no_flush(struct dm_task * dmt __unused)863 dm_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 
873 int
dm_task_skip_lockfs(struct dm_task * dmt __unused)874 dm_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 
dm_task_set_geometry(struct dm_task * dmt __unused,const char * cylinders __unused,const char * heads __unused,const char * sectors __unused,const char * start __unused)884 int 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 /*****************************************************************************/
894 void *
dm_get_next_version(struct dm_task * dmt,void * cur,const char ** target_type,uint32_t * target_ver)895 dm_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 
942 err:
943           if (iter != NULL)
944                     prop_object_iterator_release(iter);
945 
946           return NULL;
947 }
948 
949 void *
dm_get_next_dep(struct dm_task * dmt,void * cur,uint64_t * dep)950 dm_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 
986 err:
987           if (iter != NULL)
988                     prop_object_iterator_release(iter);
989 
990           return NULL;
991 }
992 
993 void *
dm_get_next_name(struct dm_task * dmt,void * cur,const char ** name,uint64_t * dev)994 dm_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 
1034 err:
1035           if (iter != NULL)
1036                     prop_object_iterator_release(iter);
1037 
1038           return NULL;
1039 
1040 }
1041