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         nvlist_free(media_attrs);
 720         nvlist_free(slice_attrs);
 721 
 722         if (slices)
 723                 dm_free_descriptors(slices);
 724         if (media)
 725                 dm_free_descriptors(media);
 726         if (slice)
 727                 dm_free_descriptor(slice);
 728 
 729         return (ret);
 730 }
 731 
 732 /*
 733  * Get the full list of swap entries.  Returns -1 on error, or >= 0 to
 734  * indicate the number of entries in the list.  Callers are responsible
 735  * for calling dm_free_swapentries() to deallocate memory.  If this
 736  * returns 0, the swaptbl_t still needs to be freed.
 737  */
 738 int
 739 dm_get_swapentries(swaptbl_t **stp, int *errp)
 740 {
 741         int count, i;
 742         swaptbl_t *tbl;
 743         char *ptr;
 744 
 745         *stp = NULL;
 746 
 747         /* get number of swap entries */
 748         if ((count = swapctl(SC_GETNSWP, NULL)) < 0) {
 749                 *errp = errno;
 750                 return (-1);
 751         }
 752 
 753         if (count == 0) {
 754                 return (0);
 755         }
 756 
 757         /* allocate space */
 758         tbl = calloc(1, sizeof (int) + count * sizeof (swapent_t));
 759         if (tbl == NULL) {
 760                 *errp = ENOMEM;
 761                 return (-1);
 762         }
 763 
 764         ptr = calloc(1, count * MAXPATHLEN);
 765         if (ptr == NULL) {
 766                 *errp = ENOMEM;
 767                 free(tbl);
 768                 return (-1);
 769         }
 770 
 771         /* set up pointers to the pathnames */
 772         tbl->swt_n = count;
 773         for (i = 0; i < count; i++) {
 774                 tbl->swt_ent[i].ste_path = ptr;
 775                 ptr += MAXPATHLEN;
 776         }
 777 
 778         /* get list of swap paths */
 779         count = swapctl(SC_LIST, tbl);
 780         if (count < 0) {
 781                 *errp = errno;
 782                 free(ptr);
 783                 free(tbl);
 784                 return (-1);
 785         }
 786 
 787         *stp = tbl;
 788         return (count);
 789 }
 790 
 791 /* ARGSUSED */
 792 void
 793 dm_free_swapentries(swaptbl_t *stp)
 794 {
 795         ASSERT(stp != NULL);
 796 
 797         free(stp->swt_ent[0].ste_path);
 798         free(stp);
 799 }
 800 
 801 /*
 802  * Check a slice to see if it's being used by swap.
 803  */
 804 int
 805 dm_inuse_swap(const char *dev_name, int *errp)
 806 {
 807         int count;
 808         int found;
 809         swaptbl_t *tbl = NULL;
 810 
 811         *errp = 0;
 812 
 813         count = dm_get_swapentries(&tbl, errp);
 814         if (count < 0 || *errp) {
 815                 if (tbl)
 816                         dm_free_swapentries(tbl);
 817                 return (-1);
 818         }
 819 
 820         /* if there are no swap entries, we're done */
 821         if (!count) {
 822                 return (0);
 823         }
 824 
 825         ASSERT(tbl != NULL);
 826 
 827         found = 0;
 828         while (count--) {
 829                 if (strcmp(dev_name, tbl->swt_ent[count].ste_path) == 0) {
 830                         found = 1;
 831                         break;
 832                 }
 833         }
 834 
 835         dm_free_swapentries(tbl);
 836         return (found);
 837 }
 838 
 839 /*
 840  * Returns 'in use' details, if found, about a specific dev_name,
 841  * based on the caller(who). It is important to note that it is possible
 842  * for there to be more than one 'in use' statistic regarding a dev_name.
 843  * The **msg parameter returns a list of 'in use' details. This message
 844  * is formatted via gettext().
 845  */
 846 int
 847 dm_inuse(char *dev_name, char **msg, dm_who_type_t who, int *errp)
 848 {
 849         nvlist_t *dev_stats = NULL;
 850         char *by, *data;
 851         nvpair_t *nvwhat = NULL;
 852         nvpair_t *nvdesc = NULL;
 853         int     found = 0;
 854         int     err;
 855         char    *dname = NULL;
 856 
 857         *errp = 0;
 858         *msg = NULL;
 859 
 860         /*
 861          * If the user doesn't want to do in use checking, return.
 862          */
 863 
 864         if (NOINUSE_SET)
 865                 return (0);
 866 
 867         dname = getfullblkname(dev_name);
 868         /*
 869          * If we cannot find the block name, we cannot check the device
 870          * for in use statistics. So, return found, which is == 0.
 871          */
 872         if (dname == NULL || *dname == '\0') {
 873                 return (found);
 874         }
 875 
 876         /*
 877          * Slice stats for swap devices are only returned if mounted
 878          * (e.g. /tmp).  Other devices or files being used for swap
 879          * are ignored, so we add a special check here to use swapctl(2)
 880          * to perform in-use checking.
 881          */
 882         if (ANY_ZPOOL_USE(who) && (err = dm_inuse_swap(dname, errp))) {
 883 
 884                 /* on error, dm_inuse_swap sets errp */
 885                 if (err < 0) {
 886                         free(dname);
 887                         return (err);
 888                 }
 889 
 890                 /* simulate a mounted swap device */
 891                 (void) build_usage_string(dname, DM_USE_MOUNT, "swap", msg,
 892                     &found, errp);
 893 
 894                 /* if this fails, dm_get_usage_string changed */
 895                 ASSERT(found == 1);
 896 
 897                 free(dname);
 898                 return (found);
 899         }
 900 
 901         dm_get_slice_stats(dname, &dev_stats, errp);
 902         if (dev_stats == NULL) {
 903                 /*
 904                  * If there is an error, but it isn't a no device found error
 905                  * return the error as recorded. Otherwise, with a full
 906                  * block name, we might not be able to get the slice
 907                  * associated, and will get an ENODEV error. For example,
 908                  * an SVM metadevice will return a value from getfullblkname()
 909                  * but libdiskmgt won't be able to find this device for
 910                  * statistics gathering. This is expected and we should not
 911                  * report errnoneous errors.
 912                  */
 913                 if (*errp) {
 914                         if (*errp == ENODEV) {
 915                                 *errp = 0;
 916                         }
 917                 }
 918                 free(dname);
 919                 return (found);
 920         }
 921 
 922         for (;;) {
 923 
 924                 nvwhat = nvlist_next_nvpair(dev_stats, nvdesc);
 925                 nvdesc = nvlist_next_nvpair(dev_stats, nvwhat);
 926 
 927                 /*
 928                  * End of the list found.
 929                  */
 930                 if (nvwhat == NULL || nvdesc == NULL) {
 931                         break;
 932                 }
 933                 /*
 934                  * Otherwise, we check to see if this client(who) cares
 935                  * about this in use scenario
 936                  */
 937 
 938                 ASSERT(strcmp(nvpair_name(nvwhat), DM_USED_BY) == 0);
 939                 ASSERT(strcmp(nvpair_name(nvdesc), DM_USED_NAME) == 0);
 940                 /*
 941                  * If we error getting the string value continue on
 942                  * to the next pair(if there is one)
 943                  */
 944                 if (nvpair_value_string(nvwhat, &by)) {
 945                         continue;
 946                 }
 947                 if (nvpair_value_string(nvdesc, &data)) {
 948                         continue;
 949                 }
 950 
 951                 switch (who) {
 952                         case DM_WHO_MKFS:
 953                                 /*
 954                                  * mkfs is not in use for these cases.
 955                                  * All others are in use.
 956                                  */
 957                                 if (strcmp(by, DM_USE_LU) == 0 ||
 958                                     strcmp(by, DM_USE_FS) == 0 ||
 959                                     strcmp(by, DM_USE_EXPORTED_ZPOOL) == 0) {
 960                                         break;
 961                                 }
 962                                 if (build_usage_string(dname,
 963                                     by, data, msg, &found, errp) != 0) {
 964                                         if (*errp) {
 965                                                 goto out;
 966                                         }
 967                                 }
 968                                 break;
 969                         case DM_WHO_SWAP:
 970                                 /*
 971                                  * Not in use for this.
 972                                  */
 973                                 if (strcmp(by, DM_USE_DUMP) == 0 ||
 974                                     strcmp(by, DM_USE_FS) == 0 ||
 975                                     strcmp(by, DM_USE_EXPORTED_ZPOOL) == 0) {
 976                                         break;
 977                                 }
 978                                 if (strcmp(by, DM_USE_LU) == 0 &&
 979                                     strcmp(data, "-") == 0) {
 980                                         break;
 981                                 }
 982                                 if (strcmp(by, DM_USE_VFSTAB) == 0 &&
 983                                     strcmp(data, "") == 0) {
 984                                         break;
 985                                 }
 986                                 if (build_usage_string(dname,
 987                                     by, data, msg, &found, errp) != 0) {
 988                                         if (*errp) {
 989                                                 goto out;
 990                                         }
 991                                 }
 992                                 break;
 993                         case DM_WHO_DUMP:
 994                                 /*
 995                                  * Not in use for this.
 996                                  */
 997                                 if ((strcmp(by, DM_USE_MOUNT) == 0 &&
 998                                     strcmp(data, "swap") == 0) ||
 999                                     strcmp(by, DM_USE_DUMP) == 0 ||
1000                                     strcmp(by, DM_USE_FS) == 0 ||
1001                                     strcmp(by, DM_USE_EXPORTED_ZPOOL) == 0) {
1002                                         break;
1003                                 }
1004                                 if (build_usage_string(dname,
1005                                     by, data, msg, &found, errp)) {
1006                                         if (*errp) {
1007                                                 goto out;
1008                                         }
1009                                 }
1010                                 break;
1011 
1012                         case DM_WHO_FORMAT:
1013                                 if (strcmp(by, DM_USE_FS) == 0 ||
1014                                     strcmp(by, DM_USE_EXPORTED_ZPOOL) == 0)
1015                                         break;
1016                                 if (build_usage_string(dname,
1017                                     by, data, msg, &found, errp) != 0) {
1018                                         if (*errp) {
1019                                                 goto out;
1020                                         }
1021                                 }
1022                                 break;
1023 
1024                         case DM_WHO_ZPOOL_FORCE:
1025                                 if (strcmp(by, DM_USE_FS) == 0 ||
1026                                     strcmp(by, DM_USE_EXPORTED_ZPOOL) == 0)
1027                                         break;
1028                                 /* FALLTHROUGH */
1029                         case DM_WHO_ZPOOL:
1030                                 if (build_usage_string(dname,
1031                                     by, data, msg, &found, errp) != 0) {
1032                                         if (*errp)
1033                                                 goto out;
1034                                 }
1035                                 break;
1036 
1037                         case DM_WHO_ZPOOL_SPARE:
1038                                 if (strcmp(by, DM_USE_SPARE_ZPOOL) != 0) {
1039                                         if (build_usage_string(dname, by,
1040                                             data, msg, &found, errp) != 0) {
1041                                                 if (*errp)
1042                                                         goto out;
1043                                         }
1044                                 }
1045                                 break;
1046 
1047                         default:
1048                                 /*
1049                                  * nothing found in use for this client
1050                                  * of libdiskmgt. Default is 'not in use'.
1051                                  */
1052                                 break;
1053                 }
1054         }
1055 out:
1056         if (dname != NULL)
1057                 free(dname);
1058         nvlist_free(dev_stats);
1059 
1060         return (found);
1061 }
1062 
1063 void
1064 dm_get_usage_string(char *what, char *how, char **usage_string)
1065 {
1066 
1067 
1068         if (usage_string == NULL || what == NULL) {
1069                 return;
1070         }
1071         *usage_string = NULL;
1072 
1073         if (strcmp(what, DM_USE_MOUNT) == 0) {
1074                 if (strcmp(how, "swap") == 0) {
1075                         *usage_string = dgettext(TEXT_DOMAIN,
1076                             "%s is currently used by swap. Please see swap(1M)."
1077                             "\n");
1078                 } else {
1079                         *usage_string = dgettext(TEXT_DOMAIN,
1080                             "%s is currently mounted on %s."
1081                             " Please see umount(1M).\n");
1082                 }
1083         } else if (strcmp(what, DM_USE_VFSTAB) == 0) {
1084                 *usage_string = dgettext(TEXT_DOMAIN,
1085                     "%s is normally mounted on %s according to /etc/vfstab. "
1086                     "Please remove this entry to use this device.\n");
1087         } else if (strcmp(what, DM_USE_FS) == 0) {
1088                 *usage_string = dgettext(TEXT_DOMAIN,
1089                     "%s contains a %s filesystem.\n");
1090         } else if (strcmp(what, DM_USE_SVM) == 0) {
1091                 if (strcmp(how, "mdb") == 0) {
1092                         *usage_string = dgettext(TEXT_DOMAIN,
1093                             "%s contains an SVM %s. Please see "
1094                             "metadb(1M).\n");
1095                 } else {
1096                         *usage_string = dgettext(TEXT_DOMAIN,
1097                             "%s is part of SVM volume %s. "
1098                             "Please see metaclear(1M).\n");
1099                 }
1100         } else if (strcmp(what, DM_USE_VXVM) == 0) {
1101                 *usage_string = dgettext(TEXT_DOMAIN,
1102                     "%s is part of VxVM volume %s.\n");
1103         } else if (strcmp(what, DM_USE_LU) == 0) {
1104                 *usage_string = dgettext(TEXT_DOMAIN,
1105                     "%s is in use for live upgrade %s. Please see ludelete(1M)."
1106                     "\n");
1107         } else if (strcmp(what, DM_USE_DUMP) == 0) {
1108                 *usage_string = dgettext(TEXT_DOMAIN,
1109                     "%s is in use by %s. Please see dumpadm(1M)."
1110                     "\n");
1111         } else if (strcmp(what, DM_USE_EXPORTED_ZPOOL) == 0) {
1112                 *usage_string = dgettext(TEXT_DOMAIN,
1113                     "%s is part of exported or potentially active ZFS pool %s. "
1114                     "Please see zpool(1M).\n");
1115         } else if (strcmp(what, DM_USE_ACTIVE_ZPOOL) == 0) {
1116                 *usage_string = dgettext(TEXT_DOMAIN,
1117                     "%s is part of active ZFS pool %s. Please see zpool(1M)."
1118                     "\n");
1119         } else if (strcmp(what, DM_USE_SPARE_ZPOOL) == 0) {
1120                 *usage_string = dgettext(TEXT_DOMAIN,
1121                     "%s is reserved as a hot spare for ZFS pool %s.  Please "
1122                     "see zpool(1M).\n");
1123         } else if (strcmp(what, DM_USE_L2CACHE_ZPOOL) == 0) {
1124                 *usage_string = dgettext(TEXT_DOMAIN,
1125                     "%s is in use as a cache device for ZFS pool %s.  "
1126                     "Please see zpool(1M).\n");
1127         }
1128 }
1129 void
1130 libdiskmgt_add_str(nvlist_t *attrs, char *name, char *val, int *errp)
1131 {
1132         if (*errp == 0) {
1133                 *errp = nvlist_add_string(attrs, name, val);
1134         }
1135 }
1136 
1137 descriptor_t **
1138 libdiskmgt_empty_desc_array(int *errp)
1139 {
1140         descriptor_t    **empty;
1141 
1142         empty = (descriptor_t **)calloc(1, sizeof (descriptor_t *));
1143         if (empty == NULL) {
1144                 *errp = ENOMEM;
1145                 return (NULL);
1146         }
1147         empty[0] = NULL;
1148 
1149         *errp = 0;
1150         return (empty);
1151 }
1152 
1153 void
1154 libdiskmgt_init_debug()
1155 {
1156         char    *valp;
1157 
1158         if ((valp = getenv(DM_DEBUG)) != NULL) {
1159                 dm_debug = atoi(valp);
1160         }
1161 }
1162 
1163 int
1164 libdiskmgt_str_eq(char *nm1, char *nm2)
1165 {
1166         if (nm1 == NULL) {
1167                 if (dm_debug) {
1168                         (void) fprintf(stderr, "WARNING: str_eq nm1 NULL\n");
1169                 }
1170 
1171                 if (nm2 == NULL) {
1172                         return (1);
1173                 } else {
1174                         return (0);
1175                 }
1176         }
1177 
1178         /* nm1 != NULL */
1179 
1180         if (nm2 == NULL) {
1181                 if (dm_debug) {
1182                         (void) fprintf(stderr, "WARNING: str_eq nm2 NULL\n");
1183                 }
1184                 return (0);
1185         }
1186 
1187         if (strcmp(nm1, nm2) == 0) {
1188                 return (1);
1189         }
1190 
1191         return (0);
1192 }
1193 
1194 /*ARGSUSED*/
1195 static descriptor_t **
1196 desc_array_to_ptr_array(dm_descriptor_t *descs, int *errp)
1197 {
1198 #ifdef _LP64
1199         return ((descriptor_t **)descs);
1200 #else
1201         /* convert the 64 bit descriptors to 32 bit ptrs */
1202         int     cnt;
1203         int     i;
1204         descriptor_t **da;
1205 
1206         for (cnt = 0; descs[cnt]; cnt++)
1207                 ;
1208 
1209         da = (descriptor_t **)calloc(cnt + 1, sizeof (descriptor_t *));
1210         if (da == NULL) {
1211                 *errp = ENOMEM;
1212                 return (NULL);
1213         }
1214 
1215         for (i = 0; descs[i]; i++) {
1216                 da[i] = (descriptor_t *)(uintptr_t)descs[i];
1217         }
1218         *errp = 0;
1219         free(descs);
1220 
1221         return (da);
1222 #endif
1223 }
1224 
1225 /*ARGSUSED*/
1226 static dm_descriptor_t *
1227 ptr_array_to_desc_array(descriptor_t **ptrs, int *errp)
1228 {
1229 #ifdef _LP64
1230         return ((dm_descriptor_t *)ptrs);
1231 #else
1232         /* convert the 32 bit ptrs to the 64 bit descriptors */
1233         int     cnt;
1234         int     i;
1235         dm_descriptor_t *da;
1236 
1237         if (*errp != 0 || ptrs == NULL) {
1238                 return (NULL);
1239         }
1240 
1241         for (cnt = 0; ptrs[cnt]; cnt++)
1242                 ;
1243 
1244         da = (dm_descriptor_t *)calloc(cnt + 1, sizeof (dm_descriptor_t));
1245         if (da == NULL) {
1246                 *errp = ENOMEM;
1247                 return (NULL);
1248         }
1249 
1250         for (i = 0; ptrs[i]; i++) {
1251                 da[i] = (uintptr_t)ptrs[i];
1252         }
1253         *errp = 0;
1254         free(ptrs);
1255 
1256         return (da);
1257 #endif
1258 }
1259 /*
1260  * Build the usage string for the in use data. Return the build string in
1261  * the msg parameter. This function takes care of reallocing all the memory
1262  * for this usage string. Usage string is returned already formatted for
1263  * localization.
1264  */
1265 static int
1266 build_usage_string(char *dname, char *by, char *data, char **msg,
1267     int *found, int *errp)
1268 {
1269         int     len0;
1270         int     len1;
1271         char    *use;
1272         char    *p;
1273 
1274         *errp = 0;
1275 
1276         dm_get_usage_string(by, data, &use);
1277         if (!use) {
1278                 return (-1);
1279         }
1280 
1281         if (*msg)
1282                 len0 = strlen(*msg);
1283         else
1284                 len0 = 0;
1285         /* LINTED */
1286         len1 = snprintf(NULL, 0, use, dname, data);
1287 
1288         /*
1289          * If multiple in use details they
1290          * are listed 1 per line for ease of
1291          * reading. dm_find_usage_string
1292          * formats these appropriately.
1293          */
1294         if ((p = realloc(*msg, len0 + len1 + 1)) == NULL) {
1295                 *errp = errno;
1296                 free(*msg);
1297                 return (-1);
1298         }
1299         *msg = p;
1300 
1301         /* LINTED */
1302         (void) snprintf(*msg + len0, len1 + 1, use, dname, data);
1303         (*found)++;
1304         return (0);
1305 }