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