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 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 * 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 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 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 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 * 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 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 361 dm_task_set_major(struct dm_task *dmt __unused, int major __unused) 362 { 363 return 1; 364 } 365 366 int 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 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 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 * 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 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 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 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 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 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 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 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 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 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 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 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 * 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 * 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 * 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 709 dm_task_update_nodes(void) 710 { 711 712 /* nothing else needed */ 713 return 1; 714 } 715 716 void * 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 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 790 dm_is_dm_major(uint32_t major) 791 { 792 return (major == dm_get_major()); 793 } 794 795 const char * 796 dm_dir(void) 797 { 798 return "/dev/mapper"; 799 } 800 801 void 802 dm_udev_set_sync_support(int sync_udev __unused) 803 { 804 return; 805 } 806 807 int 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 815 dm_udev_wait(uint32_t cookie __unused) 816 { 817 return 1; 818 } 819 820 void 821 dm_lib_release(void) 822 { 823 return; 824 } 825 826 int 827 dm_log_init(dm_error_func_t fn) 828 { 829 if (fn) 830 dm_log = fn; 831 return 1; 832 } 833 834 int 835 dm_log_init_verbose(int verbose __unused) 836 { 837 return 1; 838 } 839 840 /* XXX: unused in kernel */ 841 int 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 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 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 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 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 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 * 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 * 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 * 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