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 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 *errp = 0; 747 *msg = NULL; 748 749 /* 750 * If the user doesn't want to do in use checking, return. 751 */ 752 753 if (NOINUSE_SET) 754 return (0); 755 756 dname = getfullblkname(dev_name); 757 /* 758 * If we cannot find the block name, we cannot check the device 759 * for in use statistics. So, return found, which is == 0. 760 */ 761 if (dname == NULL || *dname == '\0') { 762 return (found); 763 } 764 765 dm_get_slice_stats(dname, &dev_stats, errp); 766 if (dev_stats == NULL) { 767 /* 768 * If there is an error, but it isn't a no device found error 769 * return the error as recorded. Otherwise, with a full 770 * block name, we might not be able to get the slice 771 * associated, and will get an ENODEV error. For example, 772 * an SVM metadevice will return a value from getfullblkname() 773 * but libdiskmgt won't be able to find this device for 774 * statistics gathering. This is expected and we should not 775 * report errnoneous errors. 776 */ 777 if (*errp) { 778 if (*errp == ENODEV) { 779 *errp = 0; 780 } 781 } 782 free(dname); 783 return (found); 784 } 785 786 for (;;) { 787 788 nvwhat = nvlist_next_nvpair(dev_stats, nvdesc); 789 nvdesc = nvlist_next_nvpair(dev_stats, nvwhat); 790 791 /* 792 * End of the list found. 793 */ 794 if (nvwhat == NULL || nvdesc == NULL) { 795 break; 796 } 797 /* 798 * Otherwise, we check to see if this client(who) cares 799 * about this in use scenario 800 */ 801 802 ASSERT(strcmp(nvpair_name(nvwhat), DM_USED_BY) == 0); 803 ASSERT(strcmp(nvpair_name(nvdesc), DM_USED_NAME) == 0); 804 /* 805 * If we error getting the string value continue on 806 * to the next pair(if there is one) 807 */ 808 if (nvpair_value_string(nvwhat, &by)) { 809 continue; 810 } 811 if (nvpair_value_string(nvdesc, &data)) { 812 continue; 813 } 814 815 switch (who) { 816 case DM_WHO_MKFS: 817 /* 818 * mkfs is not in use for these cases. 819 * All others are in use. 820 */ 821 if (strcmp(by, DM_USE_LU) == 0 || 822 strcmp(by, DM_USE_FS) == 0 || 823 strcmp(by, DM_USE_EXPORTED_ZPOOL) == 0) { 824 break; 825 } 826 if (build_usage_string(dname, 827 by, data, msg, &found, errp) != 0) { 828 if (*errp) { 829 goto out; 830 } 831 } 832 break; 833 case DM_WHO_SWAP: 834 /* 835 * Not in use for this. 836 */ 837 if (strcmp(by, DM_USE_DUMP) == 0 || 838 strcmp(by, DM_USE_FS) == 0 || 839 strcmp(by, DM_USE_EXPORTED_ZPOOL) == 0) { 840 break; 841 } 842 843 if (build_usage_string(dname, 844 by, data, msg, &found, errp) != 0) { 845 if (*errp) { 846 goto out; 847 } 848 } 849 break; 850 case DM_WHO_DUMP: 851 /* 852 * Not in use for this. 853 */ 854 if ((strcmp(by, DM_USE_MOUNT) == 0 && 855 strcmp(data, "swap") == 0) || 856 strcmp(by, DM_USE_DUMP) == 0 || 857 strcmp(by, DM_USE_FS) == 0 || 858 strcmp(by, DM_USE_EXPORTED_ZPOOL) == 0) { 859 break; 860 } 861 if (build_usage_string(dname, 862 by, data, msg, &found, errp)) { 863 if (*errp) { 864 goto out; 865 } 866 } 867 break; 868 869 case DM_WHO_FORMAT: 870 if (strcmp(by, DM_USE_FS) == 0 || 871 strcmp(by, DM_USE_EXPORTED_ZPOOL) == 0) 872 break; 873 if (build_usage_string(dname, 874 by, data, msg, &found, errp) != 0) { 875 if (*errp) { 876 goto out; 877 } 878 } 879 break; 880 881 case DM_WHO_ZPOOL_FORCE: 882 if (strcmp(by, DM_USE_FS) == 0 || 883 strcmp(by, DM_USE_EXPORTED_ZPOOL) == 0) 884 break; 885 /* FALLTHROUGH */ 886 case DM_WHO_ZPOOL: 887 if (build_usage_string(dname, 888 by, data, msg, &found, errp) != 0) { 889 if (*errp) 890 goto out; 891 } 892 break; 893 894 case DM_WHO_ZPOOL_SPARE: 895 if (strcmp(by, DM_USE_SPARE_ZPOOL) != 0) { 896 if (build_usage_string(dname, by, 897 data, msg, &found, errp) != 0) { 898 if (*errp) 899 goto out; 900 } 901 } 902 break; 903 904 default: 905 /* 906 * nothing found in use for this client 907 * of libdiskmgt. Default is 'not in use'. 908 */ 909 break; 910 } 911 } 912 out: 913 if (dname != NULL) 914 free(dname); 915 if (dev_stats != NULL) 916 nvlist_free(dev_stats); 917 918 return (found); 919 } 920 921 void 922 dm_get_usage_string(char *what, char *how, char **usage_string) 923 { 924 925 926 if (usage_string == NULL || what == NULL) { 927 return; 928 } 929 *usage_string = NULL; 930 931 if (strcmp(what, DM_USE_MOUNT) == 0) { 932 if (strcmp(how, "swap") == 0) { 933 *usage_string = dgettext(TEXT_DOMAIN, 934 "%s is currently used by swap. Please see swap(1M)." 935 "\n"); 936 } else { 937 *usage_string = dgettext(TEXT_DOMAIN, 938 "%s is currently mounted on %s." 939 " Please see umount(1M).\n"); 940 } 941 } else if (strcmp(what, DM_USE_VFSTAB) == 0) { 942 *usage_string = dgettext(TEXT_DOMAIN, 943 "%s is normally mounted on %s according to /etc/vfstab. " 944 "Please remove this entry to use this device.\n"); 945 } else if (strcmp(what, DM_USE_FS) == 0) { 946 *usage_string = dgettext(TEXT_DOMAIN, 947 "%s contains a %s filesystem.\n"); 948 } else if (strcmp(what, DM_USE_SVM) == 0) { 949 if (strcmp(how, "mdb") == 0) { 950 *usage_string = dgettext(TEXT_DOMAIN, 951 "%s contains an SVM %s. Please see " 952 "metadb(1M).\n"); 953 } else { 954 *usage_string = dgettext(TEXT_DOMAIN, 955 "%s is part of SVM volume %s. " 956 "Please see metaclear(1M).\n"); 957 } 958 } else if (strcmp(what, DM_USE_VXVM) == 0) { 959 *usage_string = dgettext(TEXT_DOMAIN, 960 "%s is part of VxVM volume %s.\n"); 961 } else if (strcmp(what, DM_USE_LU) == 0) { 962 *usage_string = dgettext(TEXT_DOMAIN, 963 "%s is in use for live upgrade %s. Please see ludelete(1M)." 964 "\n"); 965 } else if (strcmp(what, DM_USE_DUMP) == 0) { 966 *usage_string = dgettext(TEXT_DOMAIN, 967 "%s is in use by %s. Please see dumpadm(1M)." 968 "\n"); 969 } else if (strcmp(what, DM_USE_EXPORTED_ZPOOL) == 0) { 970 *usage_string = dgettext(TEXT_DOMAIN, 971 "%s is part of exported or potentially active ZFS pool %s. " 972 "Please see zpool(1M).\n"); 973 } else if (strcmp(what, DM_USE_ACTIVE_ZPOOL) == 0) { 974 *usage_string = dgettext(TEXT_DOMAIN, 975 "%s is part of active ZFS pool %s. Please see zpool(1M)." 976 "\n"); 977 } else if (strcmp(what, DM_USE_SPARE_ZPOOL) == 0) { 978 *usage_string = dgettext(TEXT_DOMAIN, 979 "%s is reserved as a hot spare for ZFS pool %s. Please " 980 "see zpool(1M).\n"); 981 } 982 } 983 void 984 libdiskmgt_add_str(nvlist_t *attrs, char *name, char *val, int *errp) 985 { 986 if (*errp == 0) { 987 *errp = nvlist_add_string(attrs, name, val); 988 } 989 } 990 991 descriptor_t ** 992 libdiskmgt_empty_desc_array(int *errp) 993 { 994 descriptor_t **empty; 995 996 empty = (descriptor_t **)calloc(1, sizeof (descriptor_t *)); 997 if (empty == NULL) { 998 *errp = ENOMEM; 999 return (NULL); 1000 } 1001 empty[0] = NULL; 1002 1003 *errp = 0; 1004 return (empty); 1005 } 1006 1007 void 1008 libdiskmgt_init_debug() 1009 { 1010 char *valp; 1011 1012 if ((valp = getenv(DM_DEBUG)) != NULL) { 1013 dm_debug = atoi(valp); 1014 } 1015 } 1016 1017 int 1018 libdiskmgt_str_eq(char *nm1, char *nm2) 1019 { 1020 if (nm1 == NULL) { 1021 if (dm_debug) { 1022 (void) fprintf(stderr, "WARNING: str_eq nm1 NULL\n"); 1023 } 1024 1025 if (nm2 == NULL) { 1026 return (1); 1027 } else { 1028 return (0); 1029 } 1030 } 1031 1032 /* nm1 != NULL */ 1033 1034 if (nm2 == NULL) { 1035 if (dm_debug) { 1036 (void) fprintf(stderr, "WARNING: str_eq nm2 NULL\n"); 1037 } 1038 return (0); 1039 } 1040 1041 if (strcmp(nm1, nm2) == 0) { 1042 return (1); 1043 } 1044 1045 return (0); 1046 } 1047 1048 /*ARGSUSED*/ 1049 static descriptor_t ** 1050 desc_array_to_ptr_array(dm_descriptor_t *descs, int *errp) 1051 { 1052 #ifdef _LP64 1053 return ((descriptor_t **)descs); 1054 #else 1055 /* convert the 64 bit descriptors to 32 bit ptrs */ 1056 int cnt; 1057 int i; 1058 descriptor_t **da; 1059 1060 for (cnt = 0; descs[cnt]; cnt++); 1061 1062 da = (descriptor_t **)calloc(cnt + 1, sizeof (descriptor_t *)); 1063 if (da == NULL) { 1064 *errp = ENOMEM; 1065 return (NULL); 1066 } 1067 1068 for (i = 0; descs[i]; i++) { 1069 da[i] = (descriptor_t *)(uintptr_t)descs[i]; 1070 } 1071 *errp = 0; 1072 free(descs); 1073 1074 return (da); 1075 #endif 1076 } 1077 1078 /*ARGSUSED*/ 1079 static dm_descriptor_t * 1080 ptr_array_to_desc_array(descriptor_t **ptrs, int *errp) 1081 { 1082 #ifdef _LP64 1083 return ((dm_descriptor_t *)ptrs); 1084 #else 1085 /* convert the 32 bit ptrs to the 64 bit descriptors */ 1086 int cnt; 1087 int i; 1088 dm_descriptor_t *da; 1089 1090 if (*errp != 0 || ptrs == NULL) { 1091 return (NULL); 1092 } 1093 1094 for (cnt = 0; ptrs[cnt]; cnt++); 1095 1096 da = (dm_descriptor_t *)calloc(cnt + 1, sizeof (dm_descriptor_t)); 1097 if (da == NULL) { 1098 *errp = ENOMEM; 1099 return (NULL); 1100 } 1101 1102 for (i = 0; ptrs[i]; i++) { 1103 da[i] = (uintptr_t)ptrs[i]; 1104 } 1105 *errp = 0; 1106 free(ptrs); 1107 1108 return (da); 1109 #endif 1110 } 1111 /* 1112 * Build the usage string for the in use data. Return the build string in 1113 * the msg parameter. This function takes care of reallocing all the memory 1114 * for this usage string. Usage string is returned already formatted for 1115 * localization. 1116 */ 1117 static int 1118 build_usage_string(char *dname, char *by, char *data, char **msg, 1119 int *found, int *errp) 1120 { 1121 int len0; 1122 int len1; 1123 char *use; 1124 char *p; 1125 1126 *errp = 0; 1127 1128 dm_get_usage_string(by, data, &use); 1129 if (!use) { 1130 return (-1); 1131 } 1132 1133 if (*msg) 1134 len0 = strlen(*msg); 1135 else 1136 len0 = 0; 1137 /* LINTED */ 1138 len1 = snprintf(NULL, 0, use, dname, data); 1139 1140 /* 1141 * If multiple in use details they 1142 * are listed 1 per line for ease of 1143 * reading. dm_find_usage_string 1144 * formats these appropriately. 1145 */ 1146 if ((p = realloc(*msg, len0 + len1 + 1)) == NULL) { 1147 *errp = errno; 1148 free(*msg); 1149 return (-1); 1150 } 1151 *msg = p; 1152 1153 /* LINTED */ 1154 (void) snprintf(*msg + len0, len1 + 1, use, dname, data); 1155 (*found)++; 1156 return (0); 1157 } 1158