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 (getenv("NOINUSE_CHECK") != NULL) { 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 *errp = 0; 575 *msg = NULL; 576 577 dname = getfullblkname(dev_name); 578 /* 579 * If we cannot find the block name, we cannot check the device 580 * for in use statistics. So, return found, which is == 0. 581 */ 582 if (dname == NULL || *dname == '\0') { 583 return (found); 584 } 585 586 dm_get_slice_stats(dname, &dev_stats, errp); 587 if (dev_stats == NULL) { 588 /* 589 * If there is an error, but it isn't a no device found error 590 * return the error as recorded. Otherwise, with a full 591 * block name, we might not be able to get the slice 592 * associated, and will get an ENODEV error. For example, 593 * an SVM metadevice will return a value from getfullblkname() 594 * but libdiskmgt won't be able to find this device for 595 * statistics gathering. This is expected and we should not 596 * report errnoneous errors. 597 */ 598 if (*errp) { 599 if (*errp == ENODEV) { 600 *errp = 0; 601 } 602 } 603 free(dname); 604 return (found); 605 } 606 607 for (;;) { 608 609 nvwhat = nvlist_next_nvpair(dev_stats, nvdesc); 610 nvdesc = nvlist_next_nvpair(dev_stats, nvwhat); 611 612 /* 613 * End of the list found. 614 */ 615 if (nvwhat == NULL || nvdesc == NULL) { 616 break; 617 } 618 /* 619 * Otherwise, we check to see if this client(who) cares 620 * about this in use scenario 621 */ 622 623 ASSERT(strcmp(nvpair_name(nvwhat), DM_USED_BY) == 0); 624 ASSERT(strcmp(nvpair_name(nvdesc), DM_USED_NAME) == 0); 625 /* 626 * If we error getting the string value continue on 627 * to the next pair(if there is one) 628 */ 629 if (nvpair_value_string(nvwhat, &by)) { 630 continue; 631 } 632 if (nvpair_value_string(nvdesc, &data)) { 633 continue; 634 } 635 636 switch (who) { 637 case DM_WHO_MKFS: 638 /* 639 * mkfs is not in use for these cases. 640 * All others are in use. 641 */ 642 if (strcmp(by, DM_USE_LU) == 0 || 643 strcmp(by, DM_USE_FS) == 0) { 644 break; 645 } 646 if (build_usage_string(dname, 647 by, data, msg, &found, errp) != 0) { 648 if (*errp) { 649 goto out; 650 } 651 } 652 break; 653 case DM_WHO_SWAP: 654 /* 655 * Not in use for this. 656 */ 657 if (strcmp(by, DM_USE_DUMP) == 0 || 658 strcmp(by, DM_USE_FS) == 0) { 659 break; 660 } 661 662 if (build_usage_string(dname, 663 by, data, msg, &found, errp) != 0) { 664 if (*errp) { 665 goto out; 666 } 667 } 668 break; 669 case DM_WHO_DUMP: 670 /* 671 * Not in use for this. 672 */ 673 if ((strcmp(by, DM_USE_MOUNT) == 0 && 674 strcmp(data, "swap") == 0) || 675 strcmp(by, DM_USE_DUMP) == 0 || 676 strcmp(by, DM_USE_FS) == 0) { 677 break; 678 } 679 if (build_usage_string(dname, 680 by, data, msg, &found, errp)) { 681 if (*errp) { 682 goto out; 683 } 684 } 685 break; 686 687 case DM_WHO_FORMAT: 688 if (strcmp(by, DM_USE_FS) == 0) 689 break; 690 if (build_usage_string(dname, 691 by, data, msg, &found, errp) != 0) { 692 if (*errp) { 693 goto out; 694 } 695 } 696 break; 697 default: 698 /* 699 * nothing found in use for this client 700 * of libdiskmgt. Default is 'not in use'. 701 */ 702 break; 703 } 704 } 705 out: 706 if (dname != NULL) 707 free(dname); 708 if (dev_stats != NULL) 709 nvlist_free(dev_stats); 710 711 return (found); 712 } 713 714 void 715 dm_get_usage_string(char *what, char *how, char **usage_string) 716 { 717 718 719 if (usage_string == NULL || what == NULL) { 720 return; 721 } 722 *usage_string = NULL; 723 724 if (strcmp(what, DM_USE_MOUNT) == 0) { 725 if (strcmp(how, "swap") == 0) { 726 *usage_string = dgettext(TEXT_DOMAIN, 727 "%s is currently used by swap. Please see swap(1M)." 728 "\n"); 729 } else { 730 *usage_string = dgettext(TEXT_DOMAIN, 731 "%s is currently mounted on %s." 732 " Please see umount(1M).\n"); 733 } 734 } else if (strcmp(what, DM_USE_VFSTAB) == 0) { 735 *usage_string = dgettext(TEXT_DOMAIN, 736 "%s is normally mounted on %s according to /etc/vfstab. " 737 "Please remove this entry to use this device.\n"); 738 } else if (strcmp(what, DM_USE_FS) == 0) { 739 *usage_string = dgettext(TEXT_DOMAIN, 740 "Warning: %s contains a %s filesystem.\n"); 741 } else if (strcmp(what, DM_USE_SVM) == 0) { 742 if (strcmp(how, "mdb") == 0) { 743 *usage_string = dgettext(TEXT_DOMAIN, 744 "%s contains an SVM %s. Please see " 745 "metadb(1M).\n"); 746 } else { 747 *usage_string = dgettext(TEXT_DOMAIN, 748 "%s is part of SVM volume %s. " 749 "Please see metaclear(1M).\n"); 750 } 751 } else if (strcmp(what, DM_USE_VXVM) == 0) { 752 *usage_string = dgettext(TEXT_DOMAIN, 753 "%s is part of VxVM volume %s.\n"); 754 } else if (strcmp(what, DM_USE_LU) == 0) { 755 *usage_string = dgettext(TEXT_DOMAIN, 756 "%s is in use for live upgrade %s. Please see ludelete(1M)." 757 "\n"); 758 } else if (strcmp(what, DM_USE_DUMP) == 0) { 759 *usage_string = dgettext(TEXT_DOMAIN, 760 "%s is in use by %s. Please see dumpadm(1M)." 761 "\n"); 762 } else if (strcmp(what, DM_USE_ZPOOL) == 0) { 763 *usage_string = dgettext(TEXT_DOMAIN, 764 "%s is in use by zpool %s. Please see zpool(1M)." 765 "\n"); 766 } 767 } 768 void 769 libdiskmgt_add_str(nvlist_t *attrs, char *name, char *val, int *errp) 770 { 771 if (*errp == 0) { 772 *errp = nvlist_add_string(attrs, name, val); 773 } 774 } 775 776 descriptor_t ** 777 libdiskmgt_empty_desc_array(int *errp) 778 { 779 descriptor_t **empty; 780 781 empty = (descriptor_t **)calloc(1, sizeof (descriptor_t *)); 782 if (empty == NULL) { 783 *errp = ENOMEM; 784 return (NULL); 785 } 786 empty[0] = NULL; 787 788 *errp = 0; 789 return (empty); 790 } 791 792 void 793 libdiskmgt_init_debug() 794 { 795 char *valp; 796 797 if ((valp = getenv(DM_DEBUG)) != NULL) { 798 dm_debug = atoi(valp); 799 } 800 } 801 802 int 803 libdiskmgt_str_eq(char *nm1, char *nm2) 804 { 805 if (nm1 == NULL) { 806 if (dm_debug) { 807 (void) fprintf(stderr, "WARNING: str_eq nm1 NULL\n"); 808 } 809 810 if (nm2 == NULL) { 811 return (1); 812 } else { 813 return (0); 814 } 815 } 816 817 /* nm1 != NULL */ 818 819 if (nm2 == NULL) { 820 if (dm_debug) { 821 (void) fprintf(stderr, "WARNING: str_eq nm2 NULL\n"); 822 } 823 return (0); 824 } 825 826 if (strcmp(nm1, nm2) == 0) { 827 return (1); 828 } 829 830 return (0); 831 } 832 833 /*ARGSUSED*/ 834 static descriptor_t ** 835 desc_array_to_ptr_array(dm_descriptor_t *descs, int *errp) 836 { 837 #ifdef _LP64 838 return ((descriptor_t **)descs); 839 #else 840 /* convert the 64 bit descriptors to 32 bit ptrs */ 841 int cnt; 842 int i; 843 descriptor_t **da; 844 845 for (cnt = 0; descs[cnt]; cnt++); 846 847 da = (descriptor_t **)calloc(cnt + 1, sizeof (descriptor_t *)); 848 if (da == NULL) { 849 *errp = ENOMEM; 850 return (NULL); 851 } 852 853 for (i = 0; descs[i]; i++) { 854 da[i] = (descriptor_t *)(uintptr_t)descs[i]; 855 } 856 *errp = 0; 857 free(descs); 858 859 return (da); 860 #endif 861 } 862 863 /*ARGSUSED*/ 864 static dm_descriptor_t * 865 ptr_array_to_desc_array(descriptor_t **ptrs, int *errp) 866 { 867 #ifdef _LP64 868 return ((dm_descriptor_t *)ptrs); 869 #else 870 /* convert the 32 bit ptrs to the 64 bit descriptors */ 871 int cnt; 872 int i; 873 dm_descriptor_t *da; 874 875 if (*errp != 0 || ptrs == NULL) { 876 return (NULL); 877 } 878 879 for (cnt = 0; ptrs[cnt]; cnt++); 880 881 da = (dm_descriptor_t *)calloc(cnt + 1, sizeof (dm_descriptor_t)); 882 if (da == NULL) { 883 *errp = ENOMEM; 884 return (NULL); 885 } 886 887 for (i = 0; ptrs[i]; i++) { 888 da[i] = (uintptr_t)ptrs[i]; 889 } 890 *errp = 0; 891 free(ptrs); 892 893 return (da); 894 #endif 895 } 896 /* 897 * Build the usage string for the in use data. Return the build string in 898 * the msg parameter. This function takes care of reallocing all the memory 899 * for this usage string. Usage string is returned already formatted for 900 * localization. 901 */ 902 static int 903 build_usage_string(char *dname, char *by, char *data, char **msg, 904 int *found, int *errp) 905 { 906 int len0; 907 int len1; 908 char *use; 909 char *p; 910 911 *errp = 0; 912 913 dm_get_usage_string(by, data, &use); 914 if (!use) { 915 return (-1); 916 } 917 918 if (*msg) 919 len0 = strlen(*msg); 920 else 921 len0 = 0; 922 /* LINTED */ 923 len1 = snprintf(NULL, 0, use, dname, data); 924 925 /* 926 * If multiple in use details they 927 * are listed 1 per line for ease of 928 * reading. dm_find_usage_string 929 * formats these appropriately. 930 */ 931 if ((p = realloc(*msg, len0 + len1 + 1)) == NULL) { 932 *errp = errno; 933 free(*msg); 934 return (-1); 935 } 936 *msg = p; 937 938 /* LINTED */ 939 (void) snprintf(*msg + len0, len1 + 1, use, dname, data); 940 (*found)++; 941 return (0); 942 } 943