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