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 } 1042