1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <fcntl.h> 30 #include <libdevinfo.h> 31 #include <stdio.h> 32 #include <sys/sunddi.h> 33 #include <sys/types.h> 34 #include <unistd.h> 35 #include <stdlib.h> 36 #include <string.h> 37 #include <libintl.h> 38 #include <locale.h> 39 #include <sys/debug.h> 40 41 #include "libdiskmgt.h" 42 #include "disks_private.h" 43 #include "partition.h" 44 45 extern char *getfullblkname(); 46 47 48 extern dm_desc_type_t drive_assoc_types[]; 49 extern dm_desc_type_t bus_assoc_types[]; 50 extern dm_desc_type_t controller_assoc_types[]; 51 extern dm_desc_type_t media_assoc_types[]; 52 extern dm_desc_type_t slice_assoc_types[]; 53 extern dm_desc_type_t partition_assoc_types[]; 54 extern dm_desc_type_t path_assoc_types[]; 55 extern dm_desc_type_t alias_assoc_types[]; 56 57 58 static dm_descriptor_t *ptr_array_to_desc_array(descriptor_t **ptrs, int *errp); 59 static descriptor_t **desc_array_to_ptr_array(dm_descriptor_t *da, int *errp); 60 static int build_usage_string(char *dname, char *by, char *data, char **use, 61 int *found, int *errp); 62 63 void 64 dm_free_descriptor(dm_descriptor_t desc) 65 { 66 descriptor_t *dp; 67 68 if (desc == NULL) { 69 return; 70 } 71 dp = (descriptor_t *)(uintptr_t)desc; 72 73 cache_wlock(); 74 cache_free_descriptor(dp); 75 cache_unlock(); 76 } 77 78 void 79 dm_free_descriptors(dm_descriptor_t *desc_list) 80 { 81 descriptor_t **dp; 82 int error; 83 84 if (desc_list == NULL) { 85 return; 86 } 87 dp = desc_array_to_ptr_array(desc_list, &error); 88 if (error != 0) { 89 free(desc_list); 90 return; 91 } 92 93 cache_wlock(); 94 cache_free_descriptors(dp); 95 cache_unlock(); 96 } 97 98 /*ARGSUSED*/ 99 void 100 dm_free_name(char *name) 101 { 102 free(name); 103 } 104 105 dm_descriptor_t * 106 dm_get_associated_descriptors(dm_descriptor_t desc, dm_desc_type_t type, 107 int *errp) 108 { 109 descriptor_t **descs = NULL; 110 descriptor_t *dp; 111 112 113 dp = (descriptor_t *)(uintptr_t)desc; 114 115 cache_wlock(); 116 117 if (!cache_is_valid_desc(dp)) { 118 cache_unlock(); 119 *errp = EBADF; 120 return (NULL); 121 } 122 123 /* verify that the descriptor is still valid */ 124 if (dp->p.generic == NULL) { 125 cache_unlock(); 126 *errp = ENODEV; 127 return (NULL); 128 } 129 130 switch (dp->type) { 131 case DM_DRIVE: 132 descs = drive_get_assoc_descriptors(dp, type, errp); 133 break; 134 case DM_BUS: 135 descs = bus_get_assoc_descriptors(dp, type, errp); 136 break; 137 case DM_CONTROLLER: 138 descs = controller_get_assoc_descriptors(dp, type, errp); 139 break; 140 case DM_MEDIA: 141 descs = media_get_assoc_descriptors(dp, type, errp); 142 break; 143 case DM_SLICE: 144 descs = slice_get_assoc_descriptors(dp, type, errp); 145 break; 146 case DM_PARTITION: 147 descs = partition_get_assoc_descriptors(dp, type, errp); 148 break; 149 case DM_PATH: 150 descs = path_get_assoc_descriptors(dp, type, errp); 151 break; 152 case DM_ALIAS: 153 descs = alias_get_assoc_descriptors(dp, type, errp); 154 break; 155 default: 156 *errp = EINVAL; 157 break; 158 } 159 160 cache_unlock(); 161 162 return (ptr_array_to_desc_array(descs, errp)); 163 } 164 165 dm_desc_type_t * 166 dm_get_associated_types(dm_desc_type_t type) 167 { 168 switch (type) { 169 case DM_DRIVE: 170 return (drive_assoc_types); 171 case DM_BUS: 172 return (bus_assoc_types); 173 case DM_CONTROLLER: 174 return (controller_assoc_types); 175 case DM_MEDIA: 176 return (media_assoc_types); 177 case DM_SLICE: 178 return (slice_assoc_types); 179 case DM_PARTITION: 180 return (partition_assoc_types); 181 case DM_PATH: 182 return (path_assoc_types); 183 case DM_ALIAS: 184 return (alias_assoc_types); 185 } 186 187 return (NULL); 188 } 189 190 nvlist_t * 191 dm_get_attributes(dm_descriptor_t desc, int *errp) 192 { 193 descriptor_t *dp; 194 nvlist_t *attrs = NULL; 195 196 197 dp = (descriptor_t *)(uintptr_t)desc; 198 199 cache_rlock(); 200 201 if (!cache_is_valid_desc(dp)) { 202 cache_unlock(); 203 *errp = EBADF; 204 return (NULL); 205 } 206 207 /* verify that the descriptor is still valid */ 208 if (dp->p.generic == NULL) { 209 cache_unlock(); 210 *errp = ENODEV; 211 return (NULL); 212 } 213 214 switch (dp->type) { 215 case DM_DRIVE: 216 attrs = drive_get_attributes(dp, errp); 217 break; 218 case DM_BUS: 219 attrs = bus_get_attributes(dp, errp); 220 break; 221 case DM_CONTROLLER: 222 attrs = controller_get_attributes(dp, errp); 223 break; 224 case DM_MEDIA: 225 attrs = media_get_attributes(dp, errp); 226 break; 227 case DM_SLICE: 228 attrs = slice_get_attributes(dp, errp); 229 break; 230 case DM_PARTITION: 231 attrs = partition_get_attributes(dp, errp); 232 break; 233 case DM_PATH: 234 attrs = path_get_attributes(dp, errp); 235 break; 236 case DM_ALIAS: 237 attrs = alias_get_attributes(dp, errp); 238 break; 239 default: 240 *errp = EINVAL; 241 break; 242 } 243 244 cache_unlock(); 245 246 return (attrs); 247 } 248 249 dm_descriptor_t 250 dm_get_descriptor_by_name(dm_desc_type_t desc_type, char *name, int *errp) 251 { 252 dm_descriptor_t desc = NULL; 253 254 255 cache_wlock(); 256 257 switch (desc_type) { 258 case DM_DRIVE: 259 desc = (uintptr_t)drive_get_descriptor_by_name(name, errp); 260 break; 261 case DM_BUS: 262 desc = (uintptr_t)bus_get_descriptor_by_name(name, errp); 263 break; 264 case DM_CONTROLLER: 265 desc = (uintptr_t)controller_get_descriptor_by_name(name, 266 errp); 267 break; 268 case DM_MEDIA: 269 desc = (uintptr_t)media_get_descriptor_by_name(name, errp); 270 break; 271 case DM_SLICE: 272 desc = (uintptr_t)slice_get_descriptor_by_name(name, errp); 273 break; 274 case DM_PARTITION: 275 desc = (uintptr_t)partition_get_descriptor_by_name(name, 276 errp); 277 break; 278 case DM_PATH: 279 desc = (uintptr_t)path_get_descriptor_by_name(name, errp); 280 break; 281 case DM_ALIAS: 282 desc = (uintptr_t)alias_get_descriptor_by_name(name, errp); 283 break; 284 default: 285 *errp = EINVAL; 286 break; 287 } 288 289 cache_unlock(); 290 291 return (desc); 292 } 293 294 dm_descriptor_t * 295 dm_get_descriptors(dm_desc_type_t type, int filter[], int *errp) 296 { 297 descriptor_t **descs = NULL; 298 299 300 cache_wlock(); 301 302 switch (type) { 303 case DM_DRIVE: 304 descs = drive_get_descriptors(filter, errp); 305 break; 306 case DM_BUS: 307 descs = bus_get_descriptors(filter, errp); 308 break; 309 case DM_CONTROLLER: 310 descs = controller_get_descriptors(filter, errp); 311 break; 312 case DM_MEDIA: 313 descs = media_get_descriptors(filter, errp); 314 break; 315 case DM_SLICE: 316 descs = slice_get_descriptors(filter, errp); 317 break; 318 case DM_PARTITION: 319 descs = partition_get_descriptors(filter, errp); 320 break; 321 case DM_PATH: 322 descs = path_get_descriptors(filter, errp); 323 break; 324 case DM_ALIAS: 325 descs = alias_get_descriptors(filter, errp); 326 break; 327 default: 328 *errp = EINVAL; 329 break; 330 } 331 332 cache_unlock(); 333 334 return (ptr_array_to_desc_array(descs, errp)); 335 } 336 337 char * 338 dm_get_name(dm_descriptor_t desc, int *errp) 339 { 340 descriptor_t *dp; 341 char *nm = NULL; 342 char *name = NULL; 343 344 dp = (descriptor_t *)(uintptr_t)desc; 345 346 cache_rlock(); 347 348 if (!cache_is_valid_desc(dp)) { 349 cache_unlock(); 350 *errp = EBADF; 351 return (NULL); 352 } 353 354 /* verify that the descriptor is still valid */ 355 if (dp->p.generic == NULL) { 356 cache_unlock(); 357 *errp = ENODEV; 358 return (NULL); 359 } 360 361 switch (dp->type) { 362 case DM_DRIVE: 363 nm = (drive_get_name(dp)); 364 break; 365 case DM_BUS: 366 nm = (bus_get_name(dp)); 367 break; 368 case DM_CONTROLLER: 369 nm = (controller_get_name(dp)); 370 break; 371 case DM_MEDIA: 372 nm = (media_get_name(dp)); 373 break; 374 case DM_SLICE: 375 nm = (slice_get_name(dp)); 376 break; 377 case DM_PARTITION: 378 nm = (partition_get_name(dp)); 379 break; 380 case DM_PATH: 381 nm = (path_get_name(dp)); 382 break; 383 case DM_ALIAS: 384 nm = (alias_get_name(dp)); 385 break; 386 } 387 388 cache_unlock(); 389 390 *errp = 0; 391 if (nm != NULL) { 392 name = strdup(nm); 393 if (name == NULL) { 394 *errp = ENOMEM; 395 return (NULL); 396 } 397 return (name); 398 } 399 return (NULL); 400 } 401 402 nvlist_t * 403 dm_get_stats(dm_descriptor_t desc, int stat_type, int *errp) 404 { 405 descriptor_t *dp; 406 nvlist_t *stats = NULL; 407 408 409 dp = (descriptor_t *)(uintptr_t)desc; 410 411 cache_rlock(); 412 413 if (!cache_is_valid_desc(dp)) { 414 cache_unlock(); 415 *errp = EBADF; 416 return (NULL); 417 } 418 419 /* verify that the descriptor is still valid */ 420 if (dp->p.generic == NULL) { 421 cache_unlock(); 422 *errp = ENODEV; 423 return (NULL); 424 } 425 426 switch (dp->type) { 427 case DM_DRIVE: 428 stats = drive_get_stats(dp, stat_type, errp); 429 break; 430 case DM_BUS: 431 stats = bus_get_stats(dp, stat_type, errp); 432 break; 433 case DM_CONTROLLER: 434 stats = controller_get_stats(dp, stat_type, errp); 435 break; 436 case DM_MEDIA: 437 stats = media_get_stats(dp, stat_type, errp); 438 break; 439 case DM_SLICE: 440 if (stat_type == DM_SLICE_STAT_USE) { 441 /* 442 * If NOINUSE_CHECK is set, we do not perform 443 * the in use checking if the user has set stat_type 444 * DM_SLICE_STAT_USE 445 */ 446 if (NOINUSE_SET) { 447 stats = NULL; 448 break; 449 } 450 } 451 stats = slice_get_stats(dp, stat_type, errp); 452 break; 453 case DM_PARTITION: 454 stats = partition_get_stats(dp, stat_type, errp); 455 break; 456 case DM_PATH: 457 stats = path_get_stats(dp, stat_type, errp); 458 break; 459 case DM_ALIAS: 460 stats = alias_get_stats(dp, stat_type, errp); 461 break; 462 default: 463 *errp = EINVAL; 464 break; 465 } 466 467 cache_unlock(); 468 469 return (stats); 470 } 471 472 dm_desc_type_t 473 dm_get_type(dm_descriptor_t desc) 474 { 475 descriptor_t *dp; 476 477 dp = (descriptor_t *)(uintptr_t)desc; 478 479 cache_rlock(); 480 481 if (!cache_is_valid_desc(dp)) { 482 cache_unlock(); 483 return (-1); 484 } 485 486 cache_unlock(); 487 488 return (dp->type); 489 } 490 /* 491 * Returns, via slices paramater, a dm_descriptor_t list of 492 * slices for the named disk drive. 493 */ 494 void 495 dm_get_slices(char *drive, dm_descriptor_t **slices, int *errp) 496 { 497 dm_descriptor_t alias; 498 dm_descriptor_t *media; 499 dm_descriptor_t *disk; 500 501 *slices = NULL; 502 *errp = 0; 503 504 if (drive == NULL) { 505 return; 506 } 507 508 alias = dm_get_descriptor_by_name(DM_ALIAS, drive, errp); 509 510 /* 511 * Errors must be handled by the caller. The dm_descriptor_t * 512 * values will be NULL if an error occured in these calls. 513 */ 514 515 if (alias != NULL) { 516 disk = dm_get_associated_descriptors(alias, DM_DRIVE, errp); 517 dm_free_descriptor(alias); 518 if (disk != NULL) { 519 media = dm_get_associated_descriptors(*disk, 520 DM_MEDIA, errp); 521 dm_free_descriptors(disk); 522 if (media != NULL) { 523 *slices = dm_get_associated_descriptors(*media, 524 DM_SLICE, errp); 525 dm_free_descriptors(media); 526 } 527 } 528 } 529 } 530 /* 531 * Convenience function to get slice stats 532 */ 533 void 534 dm_get_slice_stats(char *slice, nvlist_t **dev_stats, int *errp) 535 { 536 dm_descriptor_t devp; 537 538 *dev_stats = NULL; 539 *errp = 0; 540 541 if (slice == NULL) { 542 return; 543 } 544 545 /* 546 * Errors must be handled by the caller. The dm_descriptor_t * 547 * values will be NULL if an error occured in these calls. 548 */ 549 devp = dm_get_descriptor_by_name(DM_SLICE, slice, errp); 550 if (devp != NULL) { 551 *dev_stats = dm_get_stats(devp, DM_SLICE_STAT_USE, 552 errp); 553 dm_free_descriptor(devp); 554 } 555 } 556 557 /* 558 * Returns 'in use' details, if found, about a specific dev_name, 559 * based on the caller(who). It is important to note that it is possible 560 * for there to be more than one 'in use' statistic regarding a dev_name. 561 * The **msg parameter returns a list of 'in use' details. This message 562 * is formatted via gettext(). 563 */ 564 int 565 dm_inuse(char *dev_name, char **msg, dm_who_type_t who, int *errp) 566 { 567 nvlist_t *dev_stats = NULL; 568 char *by, *data; 569 nvpair_t *nvwhat = NULL; 570 nvpair_t *nvdesc = NULL; 571 int found = 0; 572 char *dname = NULL; 573 574 575 *errp = 0; 576 *msg = NULL; 577 578 /* 579 * If the user doesn't want to do in use checking, return. 580 */ 581 582 if (NOINUSE_SET) 583 return (0); 584 585 dname = getfullblkname(dev_name); 586 /* 587 * If we cannot find the block name, we cannot check the device 588 * for in use statistics. So, return found, which is == 0. 589 */ 590 if (dname == NULL || *dname == '\0') { 591 return (found); 592 } 593 594 dm_get_slice_stats(dname, &dev_stats, errp); 595 if (dev_stats == NULL) { 596 /* 597 * If there is an error, but it isn't a no device found error 598 * return the error as recorded. Otherwise, with a full 599 * block name, we might not be able to get the slice 600 * associated, and will get an ENODEV error. For example, 601 * an SVM metadevice will return a value from getfullblkname() 602 * but libdiskmgt won't be able to find this device for 603 * statistics gathering. This is expected and we should not 604 * report errnoneous errors. 605 */ 606 if (*errp) { 607 if (*errp == ENODEV) { 608 *errp = 0; 609 } 610 } 611 free(dname); 612 return (found); 613 } 614 615 for (;;) { 616 617 nvwhat = nvlist_next_nvpair(dev_stats, nvdesc); 618 nvdesc = nvlist_next_nvpair(dev_stats, nvwhat); 619 620 /* 621 * End of the list found. 622 */ 623 if (nvwhat == NULL || nvdesc == NULL) { 624 break; 625 } 626 /* 627 * Otherwise, we check to see if this client(who) cares 628 * about this in use scenario 629 */ 630 631 ASSERT(strcmp(nvpair_name(nvwhat), DM_USED_BY) == 0); 632 ASSERT(strcmp(nvpair_name(nvdesc), DM_USED_NAME) == 0); 633 /* 634 * If we error getting the string value continue on 635 * to the next pair(if there is one) 636 */ 637 if (nvpair_value_string(nvwhat, &by)) { 638 continue; 639 } 640 if (nvpair_value_string(nvdesc, &data)) { 641 continue; 642 } 643 644 switch (who) { 645 case DM_WHO_MKFS: 646 /* 647 * mkfs is not in use for these cases. 648 * All others are in use. 649 */ 650 if (strcmp(by, DM_USE_LU) == 0 || 651 strcmp(by, DM_USE_FS) == 0) { 652 break; 653 } 654 if (build_usage_string(dname, 655 by, data, msg, &found, errp) != 0) { 656 if (*errp) { 657 goto out; 658 } 659 } 660 break; 661 case DM_WHO_SWAP: 662 /* 663 * Not in use for this. 664 */ 665 if (strcmp(by, DM_USE_DUMP) == 0 || 666 strcmp(by, DM_USE_FS) == 0) { 667 break; 668 } 669 670 if (build_usage_string(dname, 671 by, data, msg, &found, errp) != 0) { 672 if (*errp) { 673 goto out; 674 } 675 } 676 break; 677 case DM_WHO_DUMP: 678 /* 679 * Not in use for this. 680 */ 681 if ((strcmp(by, DM_USE_MOUNT) == 0 && 682 strcmp(data, "swap") == 0) || 683 strcmp(by, DM_USE_DUMP) == 0 || 684 strcmp(by, DM_USE_FS) == 0) { 685 break; 686 } 687 if (build_usage_string(dname, 688 by, data, msg, &found, errp)) { 689 if (*errp) { 690 goto out; 691 } 692 } 693 break; 694 695 case DM_WHO_FORMAT: 696 if (strcmp(by, DM_USE_FS) == 0) 697 break; 698 if (build_usage_string(dname, 699 by, data, msg, &found, errp) != 0) { 700 if (*errp) { 701 goto out; 702 } 703 } 704 break; 705 default: 706 /* 707 * nothing found in use for this client 708 * of libdiskmgt. Default is 'not in use'. 709 */ 710 break; 711 } 712 } 713 out: 714 if (dname != NULL) 715 free(dname); 716 if (dev_stats != NULL) 717 nvlist_free(dev_stats); 718 719 return (found); 720 } 721 722 void 723 dm_get_usage_string(char *what, char *how, char **usage_string) 724 { 725 726 727 if (usage_string == NULL || what == NULL) { 728 return; 729 } 730 *usage_string = NULL; 731 732 if (strcmp(what, DM_USE_MOUNT) == 0) { 733 if (strcmp(how, "swap") == 0) { 734 *usage_string = dgettext(TEXT_DOMAIN, 735 "%s is currently used by swap. Please see swap(1M)." 736 "\n"); 737 } else { 738 *usage_string = dgettext(TEXT_DOMAIN, 739 "%s is currently mounted on %s." 740 " Please see umount(1M).\n"); 741 } 742 } else if (strcmp(what, DM_USE_VFSTAB) == 0) { 743 *usage_string = dgettext(TEXT_DOMAIN, 744 "%s is normally mounted on %s according to /etc/vfstab. " 745 "Please remove this entry to use this device.\n"); 746 } else if (strcmp(what, DM_USE_FS) == 0) { 747 *usage_string = dgettext(TEXT_DOMAIN, 748 "Warning: %s contains a %s filesystem.\n"); 749 } else if (strcmp(what, DM_USE_SVM) == 0) { 750 if (strcmp(how, "mdb") == 0) { 751 *usage_string = dgettext(TEXT_DOMAIN, 752 "%s contains an SVM %s. Please see " 753 "metadb(1M).\n"); 754 } else { 755 *usage_string = dgettext(TEXT_DOMAIN, 756 "%s is part of SVM volume %s. " 757 "Please see metaclear(1M).\n"); 758 } 759 } else if (strcmp(what, DM_USE_VXVM) == 0) { 760 *usage_string = dgettext(TEXT_DOMAIN, 761 "%s is part of VxVM volume %s.\n"); 762 } else if (strcmp(what, DM_USE_LU) == 0) { 763 *usage_string = dgettext(TEXT_DOMAIN, 764 "%s is in use for live upgrade %s. Please see ludelete(1M)." 765 "\n"); 766 } else if (strcmp(what, DM_USE_DUMP) == 0) { 767 *usage_string = dgettext(TEXT_DOMAIN, 768 "%s is in use by %s. Please see dumpadm(1M)." 769 "\n"); 770 } else if (strcmp(what, DM_USE_ZPOOL) == 0) { 771 *usage_string = dgettext(TEXT_DOMAIN, 772 "%s is in use by zpool %s. Please see zpool(1M)." 773 "\n"); 774 } 775 } 776 void 777 libdiskmgt_add_str(nvlist_t *attrs, char *name, char *val, int *errp) 778 { 779 if (*errp == 0) { 780 *errp = nvlist_add_string(attrs, name, val); 781 } 782 } 783 784 descriptor_t ** 785 libdiskmgt_empty_desc_array(int *errp) 786 { 787 descriptor_t **empty; 788 789 empty = (descriptor_t **)calloc(1, sizeof (descriptor_t *)); 790 if (empty == NULL) { 791 *errp = ENOMEM; 792 return (NULL); 793 } 794 empty[0] = NULL; 795 796 *errp = 0; 797 return (empty); 798 } 799 800 void 801 libdiskmgt_init_debug() 802 { 803 char *valp; 804 805 if ((valp = getenv(DM_DEBUG)) != NULL) { 806 dm_debug = atoi(valp); 807 } 808 } 809 810 int 811 libdiskmgt_str_eq(char *nm1, char *nm2) 812 { 813 if (nm1 == NULL) { 814 if (dm_debug) { 815 (void) fprintf(stderr, "WARNING: str_eq nm1 NULL\n"); 816 } 817 818 if (nm2 == NULL) { 819 return (1); 820 } else { 821 return (0); 822 } 823 } 824 825 /* nm1 != NULL */ 826 827 if (nm2 == NULL) { 828 if (dm_debug) { 829 (void) fprintf(stderr, "WARNING: str_eq nm2 NULL\n"); 830 } 831 return (0); 832 } 833 834 if (strcmp(nm1, nm2) == 0) { 835 return (1); 836 } 837 838 return (0); 839 } 840 841 /*ARGSUSED*/ 842 static descriptor_t ** 843 desc_array_to_ptr_array(dm_descriptor_t *descs, int *errp) 844 { 845 #ifdef _LP64 846 return ((descriptor_t **)descs); 847 #else 848 /* convert the 64 bit descriptors to 32 bit ptrs */ 849 int cnt; 850 int i; 851 descriptor_t **da; 852 853 for (cnt = 0; descs[cnt]; cnt++); 854 855 da = (descriptor_t **)calloc(cnt + 1, sizeof (descriptor_t *)); 856 if (da == NULL) { 857 *errp = ENOMEM; 858 return (NULL); 859 } 860 861 for (i = 0; descs[i]; i++) { 862 da[i] = (descriptor_t *)(uintptr_t)descs[i]; 863 } 864 *errp = 0; 865 free(descs); 866 867 return (da); 868 #endif 869 } 870 871 /*ARGSUSED*/ 872 static dm_descriptor_t * 873 ptr_array_to_desc_array(descriptor_t **ptrs, int *errp) 874 { 875 #ifdef _LP64 876 return ((dm_descriptor_t *)ptrs); 877 #else 878 /* convert the 32 bit ptrs to the 64 bit descriptors */ 879 int cnt; 880 int i; 881 dm_descriptor_t *da; 882 883 if (*errp != 0 || ptrs == NULL) { 884 return (NULL); 885 } 886 887 for (cnt = 0; ptrs[cnt]; cnt++); 888 889 da = (dm_descriptor_t *)calloc(cnt + 1, sizeof (dm_descriptor_t)); 890 if (da == NULL) { 891 *errp = ENOMEM; 892 return (NULL); 893 } 894 895 for (i = 0; ptrs[i]; i++) { 896 da[i] = (uintptr_t)ptrs[i]; 897 } 898 *errp = 0; 899 free(ptrs); 900 901 return (da); 902 #endif 903 } 904 /* 905 * Build the usage string for the in use data. Return the build string in 906 * the msg parameter. This function takes care of reallocing all the memory 907 * for this usage string. Usage string is returned already formatted for 908 * localization. 909 */ 910 static int 911 build_usage_string(char *dname, char *by, char *data, char **msg, 912 int *found, int *errp) 913 { 914 int len0; 915 int len1; 916 char *use; 917 char *p; 918 919 *errp = 0; 920 921 dm_get_usage_string(by, data, &use); 922 if (!use) { 923 return (-1); 924 } 925 926 if (*msg) 927 len0 = strlen(*msg); 928 else 929 len0 = 0; 930 /* LINTED */ 931 len1 = snprintf(NULL, 0, use, dname, data); 932 933 /* 934 * If multiple in use details they 935 * are listed 1 per line for ease of 936 * reading. dm_find_usage_string 937 * formats these appropriately. 938 */ 939 if ((p = realloc(*msg, len0 + len1 + 1)) == NULL) { 940 *errp = errno; 941 free(*msg); 942 return (-1); 943 } 944 *msg = p; 945 946 /* LINTED */ 947 (void) snprintf(*msg + len0, len1 + 1, use, dname, data); 948 (*found)++; 949 return (0); 950 } 951