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