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