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