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 (c) 1993, 2010, Oracle and/or its affiliates. All rights reserved.
  23  * Copyright 2012 Milan Jurik. All rights reserved.
  24  * Copyright 2014 Toomas Soome <tsoome@me.com>
  25  * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
  26  */
  27 
  28 /*
  29  * This file contains functions that implement the command menu commands.
  30  */
  31 
  32 #include "global.h"
  33 #include <time.h>
  34 #include <sys/time.h>
  35 #include <sys/resource.h>
  36 #include <sys/wait.h>
  37 #include <strings.h>
  38 #include <signal.h>
  39 #include <stdlib.h>
  40 #include <string.h>
  41 
  42 #if defined(sparc)
  43 #include <sys/hdio.h>
  44 #endif /* defined(sparc) */
  45 
  46 #include "main.h"
  47 #include "analyze.h"
  48 #include "menu.h"
  49 #include "menu_command.h"
  50 #include "menu_defect.h"
  51 #include "menu_partition.h"
  52 #include "param.h"
  53 #include "misc.h"
  54 #include "label.h"
  55 #include "startup.h"
  56 #include "partition.h"
  57 #include "prompts.h"
  58 #include "checkdev.h"
  59 #include "io.h"
  60 #include "ctlr_scsi.h"
  61 #include "auto_sense.h"
  62 #include "modify_partition.h"
  63 
  64 
  65 extern  struct menu_item menu_partition[];
  66 extern  struct menu_item menu_analyze[];
  67 extern  struct menu_item menu_defect[];
  68 
  69 /*
  70  * Choices for the p_tag vtoc field
  71  */
  72 slist_t ptag_choices[] = {
  73         { "unassigned", "",     V_UNASSIGNED    },
  74         { "boot",       "",     V_BOOT          },
  75         { "root",       "",     V_ROOT          },
  76         { "swap",       "",     V_SWAP          },
  77         { "usr",        "",     V_USR           },
  78         { "backup",     "",     V_BACKUP        },
  79         { "stand",      "",     V_STAND         },
  80         { "var",        "",     V_VAR           },
  81         { "home",       "",     V_HOME          },
  82         { "alternates", "",     V_ALTSCTR       },
  83         { "reserved",   "",     V_RESERVED      },
  84         { "system",     "",     V_SYSTEM        },
  85         { "BIOS_boot",  "",     V_BIOS_BOOT     },
  86         { NULL }
  87 };
  88 
  89 
  90 /*
  91  * Choices for the p_flag vtoc field
  92  */
  93 slist_t pflag_choices[] = {
  94         { "wm", "read-write, mountable",        0               },
  95         { "wu", "read-write, unmountable",      V_UNMNT         },
  96         { "rm", "read-only, mountable",         V_RONLY         },
  97         { "ru", "read-only, unmountable",       V_RONLY|V_UNMNT },
  98         { NULL }
  99 };
 100 
 101 
 102 /*
 103  * This routine implements the 'disk' command.  It allows the user to
 104  * select a disk to be current.  The list of choices is the list of
 105  * disks that were found at startup time.
 106  */
 107 int
 108 c_disk()
 109 {
 110         struct disk_info        *disk;
 111         u_ioparam_t             ioparam;
 112         int                     i;
 113         int                     ndisks = 0;
 114         int                     blind_select = 0;
 115         int                     deflt;
 116         int                     index;
 117         int                     *defltptr = NULL;
 118         int                     more = 0;
 119         int                     more_quit = 0;
 120         int                     one_line = 0;
 121         int                     tty_lines;
 122 
 123 /*
 124  * This buffer holds the check() prompt that verifies we've got the right
 125  * disk when performing a blind selection.  The size should be sufficient
 126  * to hold the prompt string, plus 256 characters for the disk name -
 127  * way more than should ever be necessary.  See the #define in misc.h.
 128  */
 129         char                    chk_buf[BLIND_SELECT_VER_PROMPT];
 130 
 131         if (istokenpresent()) {
 132                 /*
 133                  * disk number to be selected is already in the
 134                  * input stream .
 135                  */
 136                 TOKEN token, cleantoken;
 137 
 138                 /*
 139                  * Get the disk number the user has given.
 140                  */
 141                 i = 0;
 142                 for (disk = disk_list; disk != NULL; disk = disk->disk_next) {
 143                         i++;
 144                 }
 145 
 146                 ioparam.io_bounds.lower = 0;
 147                 ioparam.io_bounds.upper = i - 1;
 148                 (void) gettoken(token);
 149                 clean_token(cleantoken, token);
 150 
 151                 /*
 152                  * Convert the token into an integer.
 153                  */
 154                 if (geti(cleantoken, &index, (int *)NULL))
 155                         return (0);
 156 
 157                 /*
 158                  * Check to be sure it is within the legal bounds.
 159                  */
 160                 if ((index < 0) || (index >= i)) {
 161                         err_print("`%d' is out of range.\n", index);
 162                         return (0);
 163                 }
 164                 goto checkdisk;
 165         }
 166 
 167         fmt_print("\n\nAVAILABLE DISK SELECTIONS:\n");
 168 
 169         i = 0;
 170         if ((option_f == (char *)NULL) && isatty(0) == 1 && isatty(1) == 1) {
 171                 /*
 172                  * We have a real terminal for std input and output, enable
 173                  * more style of output for disk selection list.
 174                  */
 175                 more = 1;
 176                 tty_lines = get_tty_lines();
 177                 enter_critical();
 178                 echo_off();
 179                 charmode_on();
 180                 exit_critical();
 181         }
 182 
 183         /*
 184          * Loop through the list of found disks.
 185          */
 186         for (disk = disk_list; disk != NULL; disk = disk->disk_next) {
 187                 /*
 188                  * If using more output, account 2 lines for each disk.
 189                  */
 190                 if (more && !more_quit && i && (one_line ||
 191                     ((2 * i + 1) % (tty_lines - 2) <= 1))) {
 192                         int     c;
 193 
 194                         /*
 195                          * Get the next character.
 196                          */
 197                         fmt_print("- hit space for more or s to select - ");
 198                         c = getchar();
 199                         fmt_print("\015");
 200                         one_line = 0;
 201                         /*
 202                          * Handle display one line command
 203                          * (return key)
 204                          */
 205                         if (c == '\012') {
 206                                 one_line++;
 207                         }
 208                         /* Handle Quit command */
 209                         if (c == 'q') {
 210                                 fmt_print(
 211                                 "                       \015");
 212                                 more_quit++;
 213                         }
 214                         /* Handle ^D command */
 215                         if (c == '\004')
 216                                 fullabort();
 217                         /* or get on with the show */
 218                         if (c == 's' || c == 'S') {
 219                                 fmt_print("%80s\n", " ");
 220                                 break;
 221                         }
 222                 }
 223                 /*
 224                  * If this is the current disk, mark it as
 225                  * the default.
 226                  */
 227                 if (cur_disk == disk) {
 228                         deflt = i;
 229                         defltptr = &deflt;
 230                 }
 231                 if (!more || !more_quit)
 232                         pr_diskline(disk, i);
 233                 i++;
 234         }
 235         if (more) {
 236                 enter_critical();
 237                 charmode_off();
 238                 echo_on();
 239                 exit_critical();
 240         }
 241 
 242         /*
 243          * Determine total number of disks, and ask the user which disk he
 244          * would like to make current.
 245          */
 246 
 247         for (disk = disk_list; disk != NULL; disk = disk->disk_next) {
 248                 ndisks++;
 249         }
 250 
 251         ioparam.io_bounds.lower = 0;
 252         ioparam.io_bounds.upper = ndisks - 1;
 253         index = input(FIO_INT, "Specify disk (enter its number)", ':',
 254             &ioparam, defltptr, DATA_INPUT);
 255 
 256         if (index >= i) {
 257                 blind_select = 1;
 258         }
 259 
 260         /*
 261          * Find the disk chosen.  Search through controllers/disks
 262          * in the same original order, so we match what the user
 263          * chose.
 264          */
 265 checkdisk:
 266         i = 0;
 267         for (disk = disk_list; disk != NULL; disk = disk->disk_next) {
 268                 if (i == index)
 269                         goto found;
 270                 i++;
 271         }
 272         /*
 273          * Should never happen.
 274          */
 275         impossible("no disk found");
 276 
 277 found:
 278         if (blind_select) {
 279                 (void) snprintf(chk_buf, sizeof (chk_buf),
 280 "Disk %s selected - is this the desired disk? ", disk->disk_name);
 281                 if (check(chk_buf)) {
 282                         return (-1);
 283                 }
 284         }
 285 
 286         /*
 287          * Update the state.  We lock out interrupts so the state can't
 288          * get half-updated.
 289          */
 290 
 291         enter_critical();
 292         init_globals(disk);
 293         exit_critical();
 294 
 295         /*
 296          * If type unknown and interactive, ask user to specify type.
 297          * Also, set partition table (best guess) too.
 298          */
 299         if (!option_f && ncyl == 0 && nhead == 0 && nsect == 0 &&
 300             (disk->label_type != L_TYPE_EFI)) {
 301                 (void) c_type();
 302         }
 303 
 304         /*
 305          * Get the Solaris Fdisk Partition information
 306          */
 307         if (nhead != 0 && nsect != 0)
 308                 (void) copy_solaris_part(&cur_disk->fdisk_part);
 309 
 310         if ((cur_disk->label_type == L_TYPE_EFI) &&
 311             (cur_disk->disk_parts->etoc->efi_flags &
 312             EFI_GPT_PRIMARY_CORRUPT)) {
 313                 err_print("Reading the primary EFI GPT label ");
 314                 err_print("failed.  Using backup label.\n");
 315                 err_print("Use the 'backup' command to restore ");
 316                 err_print("the primary label.\n");
 317         }
 318 
 319 #if defined(_SUNOS_VTOC_16)
 320         /*
 321          * If there is no fdisk solaris partition.
 322          */
 323         if (cur_disk->fdisk_part.numsect == 0) {
 324                 err_print("No Solaris fdisk partition found.\n");
 325                 goto exit;
 326         }
 327 #endif /* defined(_SUNOS_VTOC_16) */
 328 
 329         /*
 330          * If the label of the disk is marked dirty,
 331          * see if they'd like to label the disk now.
 332          */
 333         if (cur_disk->disk_flags & DSK_LABEL_DIRTY) {
 334                 if (check("Disk not labeled.  Label it now") == 0) {
 335                         if (write_label()) {
 336                                 err_print("Write label failed\n");
 337                         } else {
 338                                 cur_disk->disk_flags &= ~DSK_LABEL_DIRTY;
 339                         }
 340                 }
 341         }
 342 exit:
 343         return (0);
 344 }
 345 
 346 /*
 347  * This routine implements the 'type' command.  It allows the user to
 348  * specify the type of the current disk.  It should be necessary only
 349  * if the disk was not labelled or was somehow labelled incorrectly.
 350  * The list of legal types for the disk comes from information that was
 351  * in the data file.
 352  */
 353 int
 354 c_type()
 355 {
 356         struct disk_type        *type, *tptr, *oldtype;
 357         u_ioparam_t             ioparam;
 358         int                     i, index, deflt, *defltptr = NULL;
 359         struct disk_type        disk_type;
 360         struct disk_type        *d = &disk_type;
 361         int                     first_disk;
 362         int                     auto_conf_choice;
 363         int                     other_choice;
 364         struct dk_label         label;
 365         struct efi_info         efi_info;
 366         uint64_t                maxLBA;
 367         char                    volname[LEN_DKL_VVOL];
 368         int                     volinit = 0;
 369 
 370         /*
 371          * There must be a current disk.
 372          */
 373         if (cur_disk == NULL) {
 374                 err_print("Current Disk is not set.\n");
 375                 return (-1);
 376         }
 377         oldtype = cur_disk->disk_type;
 378         type = cur_ctype->ctype_dlist;
 379         /*
 380          * Print out the list of choices.
 381          */
 382         fmt_print("\n\nAVAILABLE DRIVE TYPES:\n");
 383         first_disk = 0;
 384         if (cur_ctype->ctype_ctype == DKC_SCSI_CCS) {
 385                 auto_conf_choice = 0;
 386                 fmt_print("        %d. Auto configure\n", first_disk++);
 387         } else {
 388                 auto_conf_choice = -1;
 389         }
 390 
 391         i = first_disk;
 392         for (tptr = type; tptr != NULL; tptr = tptr->dtype_next) {
 393                 /*
 394                  * If we pass the current type, mark it to be the default.
 395                  */
 396                 if (cur_dtype == tptr) {
 397                         deflt = i;
 398                         defltptr = &deflt;
 399                 }
 400                 if (cur_disk->label_type == L_TYPE_EFI) {
 401                         continue;
 402                 }
 403                 if (tptr->dtype_asciilabel)
 404                         fmt_print("        %d. %s\n", i++,
 405                             tptr->dtype_asciilabel);
 406         }
 407         other_choice = i;
 408         fmt_print("        %d. other\n", i);
 409         ioparam.io_bounds.lower = 0;
 410         ioparam.io_bounds.upper = i;
 411         /*
 412          * Ask the user which type the disk is.
 413          */
 414         index = input(FIO_INT, "Specify disk type (enter its number)", ':',
 415             &ioparam, defltptr, DATA_INPUT);
 416         /*
 417          * Find the type s/he chose.
 418          */
 419         if (index == auto_conf_choice) {
 420                 float                   scaled;
 421                 diskaddr_t              nblks;
 422                 int                     nparts;
 423 
 424                 /*
 425                  * User chose "auto configure".
 426                  */
 427                 (void) strcpy(x86_devname, cur_disk->disk_name);
 428                 switch (cur_disk->label_type) {
 429                 case L_TYPE_SOLARIS:
 430                         if ((tptr = auto_sense(cur_file, 1, &label)) == NULL) {
 431                                 err_print("Auto configure failed\n");
 432                                 return (-1);
 433                         }
 434                         fmt_print("%s: configured with capacity of ",
 435                             cur_disk->disk_name);
 436                         nblks = (diskaddr_t)tptr->dtype_ncyl *
 437                             tptr->dtype_nhead * tptr->dtype_nsect;
 438                         scaled = bn2mb(nblks);
 439                         if (scaled > 1024.0) {
 440                                 fmt_print("%1.2fGB\n", scaled/1024.0);
 441                         } else {
 442                                 fmt_print("%1.2fMB\n", scaled);
 443                         }
 444                         fmt_print("<%s cyl %d alt %d hd %d sec %d>\n",
 445                             tptr->dtype_asciilabel, tptr->dtype_ncyl,
 446                             tptr->dtype_acyl, tptr->dtype_nhead,
 447                             tptr->dtype_nsect);
 448                         break;
 449                 case L_TYPE_EFI:
 450                         if ((tptr = auto_efi_sense(cur_file, &efi_info))
 451                             == NULL) {
 452                                 err_print("Auto configure failed\n");
 453                                 return (-1);
 454                         }
 455                         fmt_print("%s: configured with capacity of ",
 456                             cur_disk->disk_name);
 457                         scaled = bn2mb(efi_info.capacity);
 458                         if (scaled > 1024.0) {
 459                                 fmt_print("%1.2fGB\n", scaled/1024.0);
 460                         } else {
 461                                 fmt_print("%1.2fMB\n", scaled);
 462                         }
 463                         cur_blksz = efi_info.e_parts->efi_lbasize;
 464                         print_efi_string(efi_info.vendor, efi_info.product,
 465                             efi_info.revision, efi_info.capacity);
 466                         fmt_print("\n");
 467                         for (nparts = 0; nparts < cur_parts->etoc->efi_nparts;
 468                             nparts++) {
 469                                 if (cur_parts->etoc->efi_parts[nparts].p_tag ==
 470                                     V_RESERVED) {
 471                                         if (cur_parts->etoc->efi_parts[nparts].
 472                                             p_name) {
 473                                                 (void) strcpy(volname,
 474                                                     cur_parts->etoc->efi_parts
 475                                                     [nparts].p_name);
 476                                                 volinit = 1;
 477                                         }
 478                                         break;
 479                                 }
 480                         }
 481                         enter_critical();
 482                         if (delete_disk_type(cur_disk->disk_type) != 0) {
 483                                 fmt_print("Autoconfiguration failed.\n");
 484                                 return (-1);
 485                         }
 486                         cur_disk->disk_type = tptr;
 487                         cur_disk->disk_parts = tptr->dtype_plist;
 488                         init_globals(cur_disk);
 489                         exit_critical();
 490                         if (volinit) {
 491                                 for (nparts = 0; nparts <
 492                                     cur_parts->etoc->efi_nparts; nparts++) {
 493                                 if (cur_parts->etoc->efi_parts[nparts].p_tag ==
 494                                     V_RESERVED) {
 495                                 (void) strcpy(
 496                                     cur_parts->etoc->efi_parts[nparts].p_name,
 497                                     volname);
 498                                 (void) strlcpy(cur_disk->v_volume, volname,
 499                                     LEN_DKL_VVOL);
 500                                 break;
 501                                 }
 502                                 }
 503                         }
 504                         return (0);
 505                 default:
 506                         /* Should never happen */
 507                         return (-1);
 508                 }
 509         } else if ((index == other_choice) && (cur_label == L_TYPE_SOLARIS)) {
 510                 /*
 511                  * User chose "other".
 512                  * Get the standard information on the new type.
 513                  * Put all information in a tmp structure, in
 514                  * case user aborts.
 515                  */
 516                 bzero((char *)d, sizeof (struct disk_type));
 517 
 518                 d->dtype_ncyl = get_ncyl();
 519                 d->dtype_acyl = get_acyl(d->dtype_ncyl);
 520                 d->dtype_pcyl = get_pcyl(d->dtype_ncyl, d->dtype_acyl);
 521                 d->dtype_nhead = get_nhead();
 522                 d->dtype_phead = get_phead(d->dtype_nhead, &d->dtype_options);
 523                 d->dtype_nsect = get_nsect();
 524                 d->dtype_psect = get_psect(&d->dtype_options);
 525                 d->dtype_bpt = get_bpt(d->dtype_nsect, &d->dtype_options);
 526                 d->dtype_rpm = get_rpm();
 527                 d->dtype_fmt_time = get_fmt_time(&d->dtype_options);
 528                 d->dtype_cyl_skew = get_cyl_skew(&d->dtype_options);
 529                 d->dtype_trk_skew = get_trk_skew(&d->dtype_options);
 530                 d->dtype_trks_zone = get_trks_zone(&d->dtype_options);
 531                 d->dtype_atrks = get_atrks(&d->dtype_options);
 532                 d->dtype_asect = get_asect(&d->dtype_options);
 533                 d->dtype_cache = get_cache(&d->dtype_options);
 534                 d->dtype_threshold = get_threshold(&d->dtype_options);
 535                 d->dtype_prefetch_min = get_min_prefetch(&d->dtype_options);
 536                 d->dtype_prefetch_max = get_max_prefetch(d->dtype_prefetch_min,
 537                     &d->dtype_options);
 538                 d->dtype_bps = get_bps();
 539 #if defined(sparc)
 540                 d->dtype_dr_type = 0;
 541 #endif /* defined(sparc) */
 542 
 543                 d->dtype_asciilabel = get_asciilabel();
 544                 /*
 545                  * Add the new type to the list of possible types for
 546                  * this controller.  We lock out interrupts so the lists
 547                  * can't get munged.  We put off actually allocating the
 548                  * structure till here in case the user wanted to
 549                  * interrupt while still inputting information.
 550                  */
 551                 enter_critical();
 552                 tptr = (struct disk_type *)zalloc(sizeof (struct disk_type));
 553                 if (type == NULL)
 554                         cur_ctype->ctype_dlist = tptr;
 555                 else {
 556                         while (type->dtype_next != NULL)
 557                                 type = type->dtype_next;
 558                         type->dtype_next = tptr;
 559                 }
 560                 bcopy((char *)d, (char *)tptr, sizeof (disk_type));
 561                 tptr->dtype_next = NULL;
 562                 /*
 563                  * the new disk type does not have any defined
 564                  * partition table . Hence copy the current partition
 565                  * table if possible else create a default
 566                  * paritition table.
 567                  */
 568                 new_partitiontable(tptr, oldtype);
 569         } else if ((index == other_choice) && (cur_label == L_TYPE_EFI)) {
 570                 maxLBA = get_mlba();
 571                 cur_parts->etoc->efi_last_lba = maxLBA;
 572                 cur_parts->etoc->efi_last_u_lba = maxLBA - 34;
 573                 for (i = 0; i < cur_parts->etoc->efi_nparts; i++) {
 574                         cur_parts->etoc->efi_parts[i].p_start = 0;
 575                         cur_parts->etoc->efi_parts[i].p_size = 0;
 576                         cur_parts->etoc->efi_parts[i].p_tag = V_UNASSIGNED;
 577                 }
 578                 cur_parts->etoc->efi_parts[8].p_start =
 579                     maxLBA - 34 - (1024 * 16);
 580                 cur_parts->etoc->efi_parts[8].p_size = (1024 * 16);
 581                 cur_parts->etoc->efi_parts[8].p_tag = V_RESERVED;
 582                 if (write_label()) {
 583                         err_print("Write label failed\n");
 584                 } else {
 585                         cur_disk->disk_flags &= ~DSK_LABEL_DIRTY;
 586                 }
 587                 return (0);
 588         } else {
 589                 /*
 590                  * User picked an existing disk type.
 591                  */
 592                 i = first_disk;
 593                 tptr = type;
 594                 while (i < index) {
 595                         if (tptr->dtype_asciilabel) {
 596                                 i++;
 597                         }
 598                         tptr = tptr->dtype_next;
 599                 }
 600                 if ((tptr->dtype_asciilabel == NULL) &&
 601                     (tptr->dtype_next != NULL)) {
 602                         while (tptr->dtype_asciilabel == NULL) {
 603                                 tptr = tptr->dtype_next;
 604                         }
 605                 }
 606         }
 607         /*
 608          * Check for mounted file systems in the format zone.
 609          * One potential problem with this would be that check()
 610          * always returns 'yes' when running out of a file.  However,
 611          * it is actually ok because we don't let the program get
 612          * started if there are mounted file systems and we are
 613          * running from a file.
 614          */
 615         if ((tptr != oldtype) &&
 616             checkmount((diskaddr_t)-1, (diskaddr_t)-1)) {
 617                 err_print(
 618                     "Cannot set disk type while it has mounted "
 619                     "partitions.\n\n");
 620                 return (-1);
 621         }
 622         /*
 623          * check for partitions being used for swapping in format zone
 624          */
 625         if ((tptr != oldtype) &&
 626             checkswap((diskaddr_t)-1, (diskaddr_t)-1)) {
 627                 err_print("Cannot set disk type while its partition are "
 628                 "currently being used for swapping.\n");
 629                 return (-1);
 630         }
 631 
 632         /*
 633          * Check for partitions being used in SVM, VxVM or LU devices
 634          */
 635 
 636         if ((tptr != oldtype) &&
 637             checkdevinuse(cur_disk->disk_name, (diskaddr_t)-1,
 638             (diskaddr_t)-1, 0, 0)) {
 639                 err_print("Cannot set disk type while its "
 640                     "partitions are currently in use.\n");
 641                 return (-1);
 642         }
 643         /*
 644          * If the type selected is different from the previous type,
 645          * mark the disk as not labelled and reload the current
 646          * partition info.  This is not essential but probably the
 647          * right thing to do, since the size of the disk has probably
 648          * changed.
 649          */
 650         enter_critical();
 651         if (tptr != oldtype) {
 652                 cur_disk->disk_type = tptr;
 653                 cur_disk->disk_parts = NULL;
 654                 cur_disk->disk_flags &= ~DSK_LABEL;
 655         }
 656         /*
 657          * Initialize the state of the current disk.
 658          */
 659         init_globals(cur_disk);
 660         (void) get_partition();
 661         exit_critical();
 662 
 663         /*
 664          * If the label of the disk is marked dirty,
 665          * see if they'd like to label the disk now.
 666          */
 667         if (cur_disk->disk_flags & DSK_LABEL_DIRTY) {
 668                 if (check("Disk not labeled.  Label it now") == 0) {
 669                         if (write_label()) {
 670                                 err_print("Write label failed\n");
 671                         } else {
 672                                 cur_disk->disk_flags &= ~DSK_LABEL_DIRTY;
 673                         }
 674                 }
 675         }
 676 
 677         return (0);
 678 }
 679 
 680 /*
 681  * This routine implements the 'partition' command.  It simply runs
 682  * the partition menu.
 683  */
 684 int
 685 c_partition()
 686 {
 687 
 688         /*
 689          * There must be a current disk type and a current disk
 690          */
 691         if (cur_dtype == NULL) {
 692                 err_print("Current Disk Type is not set.\n");
 693                 return (-1);
 694         }
 695         /*
 696          * Check for a valid fdisk table entry for Solaris
 697          */
 698         if (!good_fdisk()) {
 699                 return (-1);
 700         }
 701 
 702         cur_menu++;
 703         last_menu = cur_menu;
 704 
 705 #ifdef  not
 706         /*
 707          * If there is no current partition table, make one.  This is
 708          * so the commands within the menu never have to check for
 709          * a non-existent table.
 710          */
 711         if (cur_parts == NULL)
 712                 err_print("making partition.\n");
 713                 make_partition();
 714 #endif  /* not */
 715 
 716         /*
 717          * Run the menu.
 718          */
 719         run_menu(menu_partition, "PARTITION", "partition", 0);
 720         cur_menu--;
 721         return (0);
 722 }
 723 
 724 /*
 725  * This routine implements the 'current' command.  It describes the
 726  * current disk.
 727  */
 728 int
 729 c_current()
 730 {
 731 
 732         /*
 733          * If there is no current disk, say so.  Note that this is
 734          * not an error since it is a legitimate response to the inquiry.
 735          */
 736         if (cur_disk == NULL) {
 737                 fmt_print("No Current Disk.\n");
 738                 return (0);
 739         }
 740         /*
 741          * Print out the info we have on the current disk.
 742          */
 743         fmt_print("Current Disk = %s", cur_disk->disk_name);
 744         if (chk_volname(cur_disk)) {
 745                 fmt_print(": ");
 746                 print_volname(cur_disk);
 747         }
 748         fmt_print("\n");
 749         if (cur_disk->devfs_name != NULL) {
 750                 if (cur_dtype == NULL) {
 751                         fmt_print("<type unknown>\n");
 752                 } else if (cur_label == L_TYPE_SOLARIS) {
 753                         fmt_print("<%s cyl %d alt %d hd %d sec %d>\n",
 754                             cur_dtype->dtype_asciilabel, ncyl,
 755                             acyl, nhead, nsect);
 756                 } else if (cur_label == L_TYPE_EFI) {
 757                         print_efi_string(cur_dtype->vendor,
 758                             cur_dtype->product, cur_dtype->revision,
 759                             cur_dtype->capacity);
 760                         fmt_print("\n");
 761                 }
 762                 fmt_print("%s\n", cur_disk->devfs_name);
 763         } else {
 764                 fmt_print("%s%d: <", cur_ctlr->ctlr_dname,
 765                     cur_disk->disk_dkinfo.dki_unit);
 766                 if (cur_dtype == NULL) {
 767                         fmt_print("type unknown");
 768                 } else if (cur_label == L_TYPE_SOLARIS) {
 769                         fmt_print("%s cyl %d alt %d hd %d sec %d",
 770                             cur_dtype->dtype_asciilabel, ncyl,
 771                             acyl, nhead, nsect);
 772                 } else if (cur_label == L_TYPE_EFI) {
 773                         print_efi_string(cur_dtype->vendor,
 774                             cur_dtype->product, cur_dtype->revision,
 775                             cur_dtype->capacity);
 776                         fmt_print("\n");
 777                 }
 778                 fmt_print(">\n");
 779         }
 780         fmt_print("\n");
 781         return (0);
 782 }
 783 /*
 784  * This routine implements the 'format' command.  It allows the user
 785  * to format and verify any portion of the disk.
 786  */
 787 int
 788 c_format()
 789 {
 790         diskaddr_t              start, end;
 791         time_t                  clock;
 792         int                     format_time, format_tracks, format_cyls;
 793         int                     format_interval;
 794         diskaddr_t              deflt;
 795         int                     status;
 796         u_ioparam_t             ioparam;
 797         struct scsi_inquiry     *inq;
 798         char    rawbuf[MAX_MODE_SENSE_SIZE];
 799         struct scsi_capacity_16 capacity;
 800         struct vpd_hdr  *vpdhdr;
 801         uint8_t protect;
 802         uint8_t pagecode;
 803         uint8_t spt;
 804         uint8_t p_type;
 805         uint8_t prot_flag[NUM_PROT_TYPE] = {1, 0, 0, 0};
 806         int     i;
 807         char    *prot_descriptor[NUM_PROT_TYPE] = {
 808             "Protection Information is disabled.",
 809             "Protection Information is enabled.",
 810             "Protection Information is enabled.",
 811             "Protection Information is enabled.", };
 812 
 813         /*
 814          * There must be a current disk type and a current disk
 815          */
 816         if (cur_dtype == NULL) {
 817                 err_print("Current Disk Type is not set.\n");
 818                 return (-1);
 819         }
 820 
 821         /*
 822          * There must be a format routine in cur_ops structure to have
 823          *  this routine work.
 824          */
 825         if (cur_ops->op_format == NULL) {
 826                 err_print(
 827 "Cannot format this drive. Please use your Manufacturer supplied formatting "
 828 "utility.\n");
 829                 return (-1);
 830         }
 831 
 832         /*
 833          * There must be a current defect list.  Except for
 834          * unformatted SCSI disks.  For them the defect list
 835          * can only be retrieved after formatting the disk.
 836          */
 837         if ((cur_ctype->ctype_flags & CF_SCSI) && !EMBEDDED_SCSI &&
 838             (cur_ctype->ctype_flags & CF_DEFECTS) &&
 839             ! (cur_flags & DISK_FORMATTED)) {
 840                 cur_list.flags |= LIST_RELOAD;
 841 
 842         } else if (cur_list.list == NULL && !EMBEDDED_SCSI) {
 843                 err_print("Current Defect List must be initialized.\n");
 844                 return (-1);
 845         }
 846         /*
 847          * Ask for the bounds of the format.  We always use the whole
 848          * disk as the default, since that is the most likely case.
 849          * Note, for disks which must be formatted accross the whole disk,
 850          * don't bother the user.
 851          */
 852         ioparam.io_bounds.lower = start = 0;
 853         if (cur_label == L_TYPE_SOLARIS) {
 854                 if (cur_ctype->ctype_flags & CF_SCSI) {
 855                         ioparam.io_bounds.upper = end = datasects() - 1;
 856                 } else {
 857                         ioparam.io_bounds.upper = end = physsects() - 1;
 858                 }
 859         } else {
 860                 ioparam.io_bounds.upper = end = cur_parts->etoc->efi_last_lba;
 861         }
 862 
 863         if (! (cur_ctlr->ctlr_flags & DKI_FMTVOL)) {
 864                 deflt = ioparam.io_bounds.lower;
 865                 start = input(FIO_BN,
 866                     "Enter starting block number", ':',
 867                     &ioparam, (int *)&deflt, DATA_INPUT);
 868                 ioparam.io_bounds.lower = start;
 869                 deflt = ioparam.io_bounds.upper;
 870                 end = input(FIO_BN,
 871                     "Enter ending block number", ':',
 872                     &ioparam, (int *)&deflt, DATA_INPUT);
 873         }
 874         /*
 875          * Some disks can format tracks.  Make sure the whole track is
 876          * specified for them.
 877          */
 878         if (cur_ctlr->ctlr_flags & DKI_FMTTRK) {
 879                 if (bn2s(start) != 0 ||
 880                     bn2s(end) != sectors(bn2h(end)) - 1) {
 881                         err_print("Controller requires formatting of ");
 882                         err_print("entire tracks.\n");
 883                         return (-1);
 884                 }
 885         }
 886         /*
 887          * Check for mounted file systems in the format zone, and if we
 888          * find any, make sure they are really serious.  One potential
 889          * problem with this would be that check() always returns 'yes'
 890          * when running out of a file.  However, it is actually ok
 891          * because we don't let the program get started if there are
 892          * mounted file systems and we are running from a file.
 893          */
 894         if (checkmount(start, end)) {
 895                 err_print(
 896                 "Cannot format disk while it has mounted partitions.\n\n");
 897                 return (-1);
 898         }
 899         /*
 900          * check for partitions being used for swapping in format zone
 901          */
 902         if (checkswap(start, end)) {
 903                 err_print("Cannot format disk while its partition are \
 904 currently being used for swapping.\n");
 905                 return (-1);
 906         }
 907         /*
 908          * Check for partitions being used in SVM, VxVM or LU devices
 909          * in this format zone
 910          */
 911         if (checkdevinuse(cur_disk->disk_name, start, end, 0, 0)) {
 912                 err_print("Cannot format disk while its partitions "
 913                     "are currently in use.\n");
 914                 return (-1);
 915         }
 916 
 917         if (cur_disk->disk_lbasize != DEV_BSIZE) {
 918                 fmt_print("Current disk sector size is %d Byte, format\n"
 919                     "will change the sector size to 512 Byte. ",
 920                     cur_disk->disk_lbasize);
 921                 if (check("Continue")) {
 922                         return (-1);
 923                 }
 924         }
 925 
 926         /*
 927          * set the default protection type
 928          */
 929         prot_type = PROT_TYPE_0;
 930 
 931         /*
 932          * Check if the protect information of this disk is enabled
 933          */
 934         if (uscsi_inquiry(cur_file, rawbuf, sizeof (rawbuf))) {
 935                 err_print("Inquiry failed\n");
 936                 return (-1);
 937         }
 938         inq = (struct scsi_inquiry *)rawbuf;
 939         protect = inq->inq_protect;
 940         if (protect == 0) {
 941                 fmt_print("The protection information is not enabled\n");
 942                 fmt_print(
 943                     "The disk will be formatted with protection type 0\n");
 944         } else {
 945                 (void) memset(rawbuf, 0, MAX_MODE_SENSE_SIZE);
 946                 if (uscsi_inquiry_page_86h(cur_file, rawbuf, sizeof (rawbuf))) {
 947                         err_print("Inquiry with page 86h failed\n");
 948                         return (-1);
 949                 }
 950                 vpdhdr = (struct vpd_hdr *)rawbuf;
 951                 pagecode = vpdhdr->page_code;
 952                 if (pagecode != 0x86) {
 953                         err_print("Inquiry with page 86h failed\n");
 954                         return (-1);
 955                 }
 956                 spt = (rawbuf[4] << 2) >> 5;
 957                 fmt_print("This disk can support protection types:\n");
 958 
 959                 switch (spt) {
 960                 case 0:
 961                         prot_flag[1] = 1;
 962                         break;
 963                 case 1:
 964                         prot_flag[1] = 1;
 965                         prot_flag[2] = 1;
 966                         break;
 967                 case 2:
 968                         prot_flag[2] = 1;
 969                         break;
 970                 case 3:
 971                         prot_flag[1] = 1;
 972                         prot_flag[3] = 1;
 973                         break;
 974                 case 4:
 975                         prot_flag[3] = 1;
 976                         break;
 977                 case 5:
 978                         prot_flag[2] = 1;
 979                         prot_flag[3] = 1;
 980                         break;
 981                 case 7:
 982                         prot_flag[1] = 1;
 983                         prot_flag[2] = 1;
 984                         prot_flag[3] = 1;
 985                         break;
 986                 default:
 987                         err_print(
 988                             "Invalid supported protection types\n");
 989                         return (-1);
 990                 }
 991                 for (i = 0; i < NUM_PROT_TYPE; i++) {
 992                         if (prot_flag[i] == 1) {
 993                                 fmt_print("[%d] TYPE_%d : ", i, i);
 994                                 fmt_print("%s\n", prot_descriptor[i]);
 995                         }
 996                 }
 997 
 998                 /*
 999                  * Get the current protection type
1000                  */
1001                 if (uscsi_read_capacity_16(cur_file, &capacity)) {
1002                         err_print("Read capacity_16 failed\n");
1003                         return (-1);
1004                 }
1005                 p_type = get_cur_protection_type(&capacity);
1006                 fmt_print("\nThe disk is currently formatted with TYPE_%d.\n",
1007                     p_type);
1008 
1009                 /*
1010                  * Ask user what protection type to use
1011                  */
1012                 ioparam.io_bounds.lower = PROT_TYPE_0;
1013                 ioparam.io_bounds.upper = PROT_TYPE_3;
1014                 prot_type = input(FIO_INT, "Specify the New Protection Type",
1015                     ':', &ioparam, NULL, DATA_INPUT);
1016                 /*
1017                  * if get a unsupported protection type, then use the
1018                  * current type: p_type.
1019                  */
1020                 if (prot_flag[prot_type] == 0) {
1021                         fmt_print("Unsupported protection type.\n");
1022                         prot_type = p_type;
1023                 }
1024                 fmt_print("The disk will be formatted to type %d\n", prot_type);
1025         }
1026 
1027         if (SCSI && (format_time = scsi_format_time()) > 0) {
1028                 fmt_print(
1029                     "\nReady to format.  Formatting cannot be interrupted\n"
1030                     "and takes %d minutes (estimated). ", format_time);
1031 
1032         } else if (cur_dtype->dtype_options & SUP_FMTTIME) {
1033                 /*
1034                  * Formatting time is (2 * time of 1 spin * number of
1035                  * tracks) + (step rate * number of cylinders) rounded
1036                  * up to the nearest minute.  Note, a 10% fudge factor
1037                  * is thrown in for insurance.
1038                  */
1039                 if (cur_dtype->dtype_fmt_time == 0)
1040                         cur_dtype->dtype_fmt_time = 2;
1041 
1042                 format_tracks = ((end-start) / cur_dtype->dtype_nsect) + 1;
1043                 format_cyls = format_tracks / cur_dtype->dtype_nhead;
1044                 format_tracks = format_tracks * cur_dtype->dtype_fmt_time;
1045 
1046                 /*
1047                  * ms.
1048                  */
1049                 format_time = ((60000 / cur_dtype->dtype_rpm) +1) *
1050                     format_tracks + format_cyls * 7;
1051                 /*
1052                  * 20% done tick (sec)
1053                  */
1054                 format_interval = format_time / 5000;
1055                 /*
1056                  * min.
1057                  */
1058                 format_time = (format_time + 59999) / 60000;
1059 
1060                 /*
1061                  * Check format time values and make adjustments
1062                  * to prevent sleeping too long (forever?) or
1063                  * too short.
1064                  */
1065                 if (format_time <= 1) {
1066                         /*
1067                          * Format time is less than 1 min..
1068                          */
1069                         format_time = 1;
1070                 }
1071 
1072                 if (format_interval < 11) {
1073                         /* Format time is less than 1 minute. */
1074                         if (format_interval < 2)
1075                                 format_interval = 2;    /* failsafe */
1076                         format_interval = 10;
1077                 } else {
1078                         /* Format time is greater than 1 minute. */
1079                         format_interval -= 10;
1080                 }
1081 
1082                 fmt_print(
1083                     "Ready to format.  Formatting cannot be interrupted\n"
1084                     "and takes %d minutes (estimated). ", format_time);
1085         } else {
1086                 fmt_print(
1087                     "Ready to format.  Formatting cannot be interrupted.\n");
1088         }
1089         if (check("Continue")) {
1090                 return (-1);
1091         }
1092 
1093         /*
1094          * Print the time so that the user will know when format started.
1095          * Lock out interrupts.  This could be a problem, since it could
1096          * cause the user to sit for quite awhile with no control, but we
1097          * don't have any other good way of keeping his gun from going off.
1098          */
1099         clock = time((time_t *)0);
1100         fmt_print("Beginning format. The current time is %s\n",
1101             ctime(&clock));
1102         enter_critical();
1103         /*
1104          * Mark the defect list dirty so it will be rewritten when we are
1105          * done.  It is possible to qualify this so it doesn't always
1106          * get rewritten, but it's not worth the trouble.
1107          * Note: no defect lists for embedded scsi drives.
1108          */
1109         if (!EMBEDDED_SCSI) {
1110                 cur_list.flags |= LIST_DIRTY;
1111         }
1112         /*
1113          * If we are formatting over any of the labels, mark the label
1114          * dirty so it will be rewritten.
1115          */
1116         if (cur_disk->label_type == L_TYPE_SOLARIS) {
1117                 if (start < totalsects() && end >= datasects()) {
1118                         if (cur_disk->disk_flags & DSK_LABEL)
1119                                 cur_flags |= LABEL_DIRTY;
1120                 }
1121         } else if (cur_disk->label_type == L_TYPE_EFI) {
1122                 if (start < 34) {
1123                         if (cur_disk->disk_flags & DSK_LABEL)
1124                                 cur_flags |= LABEL_DIRTY;
1125                 }
1126         }
1127         if (start == 0) {
1128                 cur_flags |= LABEL_DIRTY;
1129         }
1130         /*
1131          * Do the format. bugid 1009138 removed the use of fork to
1132          * background the format and print a tick.
1133          */
1134 
1135         status = (*cur_ops->op_format)(start, end, &cur_list);
1136         if (status) {
1137                 exit_critical();
1138                 err_print("failed\n");
1139                 return (-1);
1140         }
1141         fmt_print("done\n");
1142         if (option_msg && diag_msg) {
1143                 clock = time((time_t *)0);
1144                 fmt_print("The current time is %s\n", ctime(&clock));
1145         }
1146         cur_flags |= DISK_FORMATTED;
1147         /*
1148          * If the defect list or label is dirty, write them out again.
1149          * Note, for SCSI we have to wait til now to load defect list
1150          * since we can't access it until after formatting a virgin disk.
1151          */
1152         /* enter_critical(); */
1153         if (cur_list.flags & LIST_RELOAD) {
1154                 assert(!EMBEDDED_SCSI);
1155                 if (*cur_ops->op_ex_man == NULL ||
1156                     (*cur_ops->op_ex_man)(&cur_list)) {
1157                         err_print("Warning: unable to reload defect list\n");
1158                         cur_list.flags &= ~LIST_DIRTY;
1159                         return (-1);
1160                 }
1161                 cur_list.flags |= LIST_DIRTY;
1162         }
1163 
1164         if (cur_list.flags & LIST_DIRTY) {
1165                 assert(!EMBEDDED_SCSI);
1166                 write_deflist(&cur_list);
1167                 cur_list.flags = 0;
1168         }
1169         if (cur_flags & LABEL_DIRTY) {
1170                 (void) write_label();
1171                 cur_flags &= ~LABEL_DIRTY;
1172         }
1173         /*
1174          * Come up for air, since the verify step does not need to
1175          * be atomic (it does it's own lockouts when necessary).
1176          */
1177         exit_critical();
1178         /*
1179          * If we are supposed to verify, we do the 'write' test over
1180          * the format zone.  The rest of the analysis parameters are
1181          * left the way they were.
1182          */
1183         if (scan_auto) {
1184                 scan_entire = 0;
1185                 scan_lower = start;
1186                 scan_upper = end;
1187                 fmt_print("\nVerifying media...");
1188                 status = do_scan(SCAN_PATTERN, F_SILENT);
1189         }
1190         /*
1191          * If the defect list or label is dirty, write them out again.
1192          */
1193         if (cur_list.flags & LIST_DIRTY) {
1194                 assert(!EMBEDDED_SCSI);
1195                 cur_list.flags = 0;
1196                 write_deflist(&cur_list);
1197         }
1198         if (cur_flags & LABEL_DIRTY) {
1199                 cur_flags &= ~LABEL_DIRTY;
1200                 (void) write_label();
1201         }
1202         return (status);
1203 }
1204 
1205 /*
1206  * This routine implements the 'repair' command.  It allows the user
1207  * to reallocate sectors on the disk that have gone bad.
1208  */
1209 int
1210 c_repair()
1211 {
1212         diskaddr_t      bn;
1213         int             status;
1214         u_ioparam_t     ioparam;
1215         char            *buf;
1216         int             buf_is_good;
1217         int             block_has_error;
1218         int             i;
1219 
1220         /*
1221          * There must be a current disk type (and therefore a current disk).
1222          */
1223         if (cur_dtype == NULL) {
1224                 err_print("Current Disk Type is not set.\n");
1225                 return (-1);
1226         }
1227         /*
1228          * The current disk must be formatted for repair to work.
1229          */
1230         if (!(cur_flags & DISK_FORMATTED)) {
1231                 err_print("Current Disk is unformatted.\n");
1232                 return (-1);
1233         }
1234         /*
1235          * Check for a valid fdisk table entry for Solaris
1236          */
1237         if (!good_fdisk()) {
1238                 return (-1);
1239         }
1240         /*
1241          * Repair is an optional command for controllers, so it may
1242          * not be supported.
1243          */
1244         if (cur_ops->op_repair == NULL) {
1245                 err_print("Controller does not support repairing.\n");
1246                 err_print("or disk supports automatic defect management.\n");
1247                 return (-1);
1248         }
1249         /*
1250          * There must be a defect list for non-embedded scsi devices,
1251          * since we will add to it.
1252          */
1253         if (!EMBEDDED_SCSI && cur_list.list == NULL) {
1254                 err_print("Current Defect List must be initialized.\n");
1255                 return (-1);
1256         }
1257         /*
1258          * Ask the user which sector has gone bad.
1259          */
1260         ioparam.io_bounds.lower = 0;
1261         if (cur_disk->label_type == L_TYPE_SOLARIS) {
1262                 ioparam.io_bounds.upper = physsects() - 1;
1263         } else {
1264                 ioparam.io_bounds.upper = cur_parts->etoc->efi_last_lba;
1265         }
1266         bn = input(FIO_BN,
1267             "Enter absolute block number of defect", ':',
1268             &ioparam, (int *)NULL, DATA_INPUT);
1269         /*
1270          * Check to see if there is a mounted file system over the
1271          * specified sector.  If there is, make sure the user is
1272          * really serious.
1273          */
1274         if (checkmount(bn, bn)) {
1275                 if (check("Repair is in a mounted partition, continue"))
1276                         return (-1);
1277         }
1278         /*
1279          * check for partitions being used for swapping in format zone
1280          */
1281         if (checkswap(bn, bn)) {
1282                 if (check("Repair is in a partition which is currently \
1283 being used for swapping.\ncontinue"))
1284                 return (-1);
1285         }
1286 
1287         if (checkdevinuse(cur_disk->disk_name, bn, bn, 0, 0)) {
1288                 if (check("Repair is in a partition which is currently "
1289                     "in use.\ncontinue"))
1290                         return (-1);
1291         }
1292 
1293         buf = zalloc((cur_disk->disk_lbasize == 0) ?
1294             SECSIZE : cur_disk->disk_lbasize);
1295 
1296         /*
1297          * Try to read the sector before repairing it.  If we can
1298          * get good data out of it, we can write that data back
1299          * after the repair.  If the sector looks ok, ask the
1300          * user to confirm the repair, since it doesn't appear
1301          * necessary.  Try reading the block several times to
1302          * see if we can read it consistently.
1303          *
1304          * First, let's see if the block appears to have problems...
1305          */
1306         block_has_error = 1;
1307         for (i = 0; i < 5; i++) {
1308                 status = (*cur_ops->op_rdwr)(DIR_READ, cur_file, bn,
1309                     1, buf, (F_SILENT | F_ALLERRS), NULL);
1310                 if (status)
1311                         break;          /* one of the tries failed */
1312         }
1313         if (status == 0) {
1314                 block_has_error = 0;
1315                 if (check("\
1316 This block doesn't appear to be bad.  Repair it anyway")) {
1317                         free(buf);
1318                         return (0);
1319                 }
1320         }
1321         /*
1322          * Last chance...
1323          */
1324         if (check("Ready to repair defect, continue")) {
1325                 free(buf);
1326                 return (-1);
1327         }
1328         /*
1329          * We're committed to repairing it.  Try to get any good
1330          * data out of the block if possible.  Note that we do
1331          * not set the F_ALLERRS flag.
1332          */
1333         buf_is_good = 0;
1334         for (i = 0; i < 5; i++) {
1335                 status = (*cur_ops->op_rdwr)(DIR_READ, cur_file, bn,
1336                     1, buf, F_SILENT, NULL);
1337                 if (status == 0) {
1338                         buf_is_good = 1;
1339                         break;
1340                 }
1341         }
1342         /*
1343          * Lock out interrupts so the disk can't get out of sync with
1344          * the defect list.
1345          */
1346         enter_critical();
1347 
1348         fmt_print("Repairing ");
1349         if (block_has_error) {
1350                 fmt_print("%s error on ", buf_is_good ? "soft" : "hard");
1351         }
1352         fmt_print("block %llu (", bn);
1353         pr_dblock(fmt_print, bn);
1354         fmt_print(")...");
1355         /*
1356          * Do the repair.
1357          */
1358         status = (*cur_ops->op_repair)(bn, F_NORMAL);
1359         if (status) {
1360                 fmt_print("failed.\n\n");
1361         } else {
1362                 /*
1363                  * The repair worked.  Write the old data to the new
1364                  * block if we were able to read it, otherwise
1365                  * zero out the new block.  If it looks like the
1366                  * new block is bad, let the user know that, too.
1367                  * Should we attempt auto-repair in this case?
1368                  */
1369                 fmt_print("ok.\n");
1370                 if (!buf_is_good) {
1371                         bzero(buf, cur_disk->disk_lbasize);
1372                 }
1373                 status = (*cur_ops->op_rdwr)(DIR_WRITE, cur_file, bn,
1374                     1, buf, (F_SILENT | F_ALLERRS), NULL);
1375                 if (status == 0) {
1376                         status = (*cur_ops->op_rdwr)(DIR_READ, cur_file,
1377                             bn, 1, buf, (F_SILENT | F_ALLERRS), NULL);
1378                 }
1379                 if (status) {
1380                         fmt_print("The new block %llu (", bn);
1381                         pr_dblock(fmt_print, bn);
1382                         fmt_print(") also appears defective.\n");
1383                 }
1384                 fmt_print("\n");
1385                 /*
1386                  * Add the bad sector to the defect list, write out
1387                  * the defect list, and kill off the working list so
1388                  * it will get synced up with the current defect list
1389                  * next time we need it.
1390                  *
1391                  * For embedded scsi, we don't require a defect list.
1392                  * However, if we have one, add the defect if the
1393                  * list includes the grown list.  If not, kill it
1394                  * to force a resync if we need the list later.
1395                  */
1396                 if (EMBEDDED_SCSI) {
1397                         if (cur_list.list != NULL) {
1398                                 if (cur_list.flags & LIST_PGLIST) {
1399                                         add_ldef(bn, &cur_list);
1400                                 } else {
1401                                         kill_deflist(&cur_list);
1402                                 }
1403                         }
1404                 } else if (cur_ctype->ctype_flags & CF_WLIST) {
1405                         kill_deflist(&cur_list);
1406                         if (*cur_ops->op_ex_cur != NULL) {
1407                                 (*cur_ops->op_ex_cur)(&cur_list);
1408                                 fmt_print("Current list updated\n");
1409                         }
1410                 } else {
1411                         add_ldef(bn, &cur_list);
1412                         write_deflist(&cur_list);
1413                 }
1414                 kill_deflist(&work_list);
1415         }
1416         exit_critical();
1417         free(buf);
1418 
1419         /*
1420          * Return status.
1421          */
1422         return (status);
1423 }
1424 
1425 /*
1426  * This routine implements the 'show' command.  It translates a disk
1427  * block given in any format into decimal, hexadecimal, and
1428  * cylinder/head/sector format.
1429  */
1430 int
1431 c_show()
1432 {
1433         u_ioparam_t     ioparam;
1434         diskaddr_t      bn;
1435 
1436         /*
1437          * There must be a current disk type, so we will know the geometry.
1438          */
1439         if (cur_dtype == NULL) {
1440                 err_print("Current Disk Type is not set.\n");
1441                 return (-1);
1442         }
1443         /*
1444          * Ask the user for a disk block.
1445          */
1446         ioparam.io_bounds.lower = 0;
1447         if (cur_disk->label_type == L_TYPE_SOLARIS) {
1448                 ioparam.io_bounds.upper = physsects() - 1;
1449         } else {
1450                 ioparam.io_bounds.upper = cur_parts->etoc->efi_last_lba;
1451         }
1452         bn = input(FIO_BN, "Enter a disk block", ':',
1453             &ioparam, (int *)NULL, DATA_INPUT);
1454         /*
1455          * Echo it back.
1456          */
1457         fmt_print("Disk block = %lld = 0x%llx = (", bn, bn);
1458         pr_dblock(fmt_print, bn);
1459         fmt_print(")\n\n");
1460         return (0);
1461 }
1462 
1463 /*
1464  * This routine implements the 'label' command.  It writes the
1465  * primary and backup labels onto the current disk.
1466  */
1467 int
1468 c_label()
1469 {
1470         int                     status;
1471         int                     deflt, *defltptr = NULL;
1472 
1473         /*
1474          * There must be a current disk type (and therefore a current disk).
1475          */
1476         if (cur_dtype == NULL) {
1477                 err_print("Current Disk Type is not set.\n");
1478                 return (-1);
1479         }
1480         /*
1481          * The current disk must be formatted to label it.
1482          */
1483         if (!(cur_flags & DISK_FORMATTED)) {
1484                 err_print("Current Disk is unformatted.\n");
1485                 return (-1);
1486         }
1487         /*
1488          * Check for a valid fdisk table entry for Solaris
1489          */
1490         if (!good_fdisk()) {
1491                 return (-1);
1492         }
1493         /*
1494          * Check to see if there are any mounted file systems anywhere
1495          * on the current disk.  If so, refuse to label the disk, but
1496          * only if the partitions would change for the mounted partitions.
1497          *
1498          */
1499         if (checkmount((diskaddr_t)-1, (diskaddr_t)-1)) {
1500                 /* Bleagh, too descriptive */
1501                 if (check_label_with_mount()) {
1502                         err_print("Cannot label disk while it has "
1503                             "mounted partitions.\n\n");
1504                         return (-1);
1505                 }
1506         }
1507 
1508         /*
1509          * check to see if there any partitions being used for swapping
1510          * on the current disk.  If so, refuse to label the disk, but
1511          * only if the partitions would change for the mounted partitions.
1512          */
1513         if (checkswap((diskaddr_t)-1, (diskaddr_t)-1)) {
1514                 if (check_label_with_swap()) {
1515                         err_print("Cannot label disk while its "
1516                             "partitions are currently being used for "
1517                             "swapping.\n");
1518                         return (-1);
1519                 }
1520         }
1521 
1522         /*
1523          * Check to see if any partitions used for svm, vxvm or live upgrade
1524          * are on the disk. If so, refuse to label the disk, but only
1525          * if we are trying to shrink a partition in use.
1526          */
1527         if (checkdevinuse(cur_disk->disk_name, (diskaddr_t)-1,
1528             (diskaddr_t)-1, 0, 1)) {
1529                 err_print("Cannot label disk when "
1530                     "partitions are in use as described.\n");
1531                 return (-1);
1532         }
1533 
1534         /*
1535          * If there is not a current partition map, warn the user we
1536          * are going to use the default.  The default is the first
1537          * partition map we encountered in the data file.  If there is
1538          * no default we give up.
1539          */
1540         if (cur_parts == NULL) {
1541                 fmt_print("Current Partition Table is not set, "
1542                     "using default.\n");
1543                 cur_disk->disk_parts = cur_parts = cur_dtype->dtype_plist;
1544                 if (cur_parts == NULL) {
1545                         err_print("No default available, cannot label.\n");
1546                         return (-1);
1547                 }
1548         }
1549         /*
1550          * If expert (-e) mode, then ask user if they wish
1551          * to change the current solaris label into an EFI one
1552          */
1553         if (expert_mode) {
1554 #if defined(_SUNOS_VTOC_8)
1555                 int             i;
1556 #endif
1557                 int             choice;
1558                 u_ioparam_t             ioparam;
1559                 struct extvtoc  vtoc;
1560                 struct dk_label label;
1561                 struct dk_gpt   *vtoc64;
1562                 struct efi_info efinfo;
1563                 struct disk_type        *dptr;
1564 
1565                 /* Ask user what label to use */
1566                 fmt_print("[0] SMI Label\n");
1567                 fmt_print("[1] EFI Label\n");
1568                 ioparam.io_bounds.lower = 0;
1569                 ioparam.io_bounds.upper = 1;
1570                 if ((cur_label == L_TYPE_SOLARIS) &&
1571                     (cur_disk->fdisk_part.systid != EFI_PMBR))
1572                         deflt = L_TYPE_SOLARIS;
1573                 else
1574                         deflt = L_TYPE_EFI;
1575                 defltptr = &deflt;
1576                 choice = input(FIO_INT, "Specify Label type", ':',
1577                     &ioparam, defltptr, DATA_INPUT);
1578                 if ((choice == L_TYPE_SOLARIS) &&
1579                     (cur_label == L_TYPE_SOLARIS) &&
1580                     (cur_disk->fdisk_part.systid != EFI_PMBR)) {
1581                         goto expert_end;
1582                 } else if ((choice == L_TYPE_EFI) &&
1583                     (cur_label == L_TYPE_EFI)) {
1584                         goto expert_end;
1585                 }
1586                 switch (choice) {
1587                 case L_TYPE_SOLARIS:
1588                 /*
1589                  * EFI label to SMI label
1590                  */
1591                 if (cur_dtype->capacity > INFINITY) {
1592                         fmt_print("Warning: SMI labels only support up to "
1593                             "2 TB.\n");
1594                 }
1595 
1596                 if (cur_disk->fdisk_part.systid == EFI_PMBR) {
1597                         fmt_print("Warning: This disk has an EFI label. "
1598                             "Changing to SMI label will erase all\n"
1599                             "current partitions.\n");
1600                         if (check("Continue"))
1601                         return (-1);
1602 #if defined(_FIRMWARE_NEEDS_FDISK)
1603                         fmt_print("You must use fdisk to delete the current "
1604                             "EFI partition and create a new\n"
1605                             "Solaris partition before you can convert the "
1606                             "label.\n");
1607                         return (-1);
1608 #endif
1609                 }
1610 
1611 #if defined(_FIRMWARE_NEEDS_FDISK)
1612                 if (!(((cur_disk->fdisk_part.systid != SUNIXOS) ||
1613                     (cur_disk->fdisk_part.systid != SUNIXOS2)) &&
1614                     (cur_disk->fdisk_part.numsect > 0))) {
1615                         fmt_print("You must use fdisk to create a Solaris "
1616                             "partition before you can convert the label.\n");
1617                         return (-1);
1618                 }
1619 #endif
1620 
1621                 (void) memset((char *)&label, 0, sizeof (struct dk_label));
1622 
1623                 (void) strcpy(x86_devname, cur_disk->disk_name);
1624                 if (cur_ctype->ctype_ctype == DKC_DIRECT)
1625                         dptr = auto_direct_get_geom_label(cur_file,  &label);
1626                 else
1627                         dptr = auto_sense(cur_file, 1, &label);
1628                 if (dptr == NULL) {
1629                         fmt_print("Autoconfiguration failed.\n");
1630                         return (-1);
1631                 }
1632 
1633                 pcyl = label.dkl_pcyl;
1634                 ncyl = label.dkl_ncyl;
1635                 acyl = label.dkl_acyl;
1636                 nhead = label.dkl_nhead;
1637                 nsect = label.dkl_nsect;
1638 
1639                 if (delete_disk_type(cur_disk->disk_type) == 0) {
1640                         cur_label = L_TYPE_SOLARIS;
1641                         cur_disk->label_type = L_TYPE_SOLARIS;
1642                         cur_disk->disk_type = dptr;
1643                         cur_disk->disk_parts = dptr->dtype_plist;
1644                         cur_dtype = dptr;
1645                         cur_parts = dptr->dtype_plist;
1646 
1647                         if (status = write_label())
1648                                 err_print("Label failed.\n");
1649                         else
1650                                 cur_disk->disk_flags &= ~DSK_LABEL_DIRTY;
1651 
1652                         return (status);
1653                 } else {
1654                         err_print("Label failed.\n");
1655                         return (-1);
1656                 }
1657 
1658 
1659                 case L_TYPE_EFI:
1660                 /*
1661                  * SMI label to EFI label
1662                  */
1663 
1664                 if ((cur_disk->fdisk_part.systid == SUNIXOS) ||
1665                     (cur_disk->fdisk_part.systid == SUNIXOS2)) {
1666                         fmt_print("Warning: This disk has an SMI label. "
1667                             "Changing to EFI label will erase all\ncurrent "
1668                             "partitions.\n");
1669                         if (check("Continue")) {
1670                                 return (-1);
1671                         }
1672                 }
1673 
1674                 if (get_disk_info(cur_file, &efinfo, cur_disk) != 0) {
1675                         return (-1);
1676                 }
1677                 (void) memset((char *)&label, 0, sizeof (struct dk_label));
1678                 label.dkl_pcyl = pcyl;
1679                 label.dkl_ncyl = ncyl;
1680                 label.dkl_acyl = acyl;
1681 #if defined(_SUNOS_VTOC_16)
1682                 label.dkl_bcyl = bcyl;
1683 #endif                  /* defined(_SUNOC_VTOC_16) */
1684                 label.dkl_nhead = nhead;
1685                 label.dkl_nsect = nsect;
1686 #if defined(_SUNOS_VTOC_8)
1687                 for (i = 0; i < NDKMAP; i++) {
1688                         label.dkl_map[i] = cur_parts->pinfo_map[i];
1689                 }
1690 #endif                  /* defined(_SUNOS_VTOC_8) */
1691                 label.dkl_magic = DKL_MAGIC;
1692                 label.dkl_vtoc = cur_parts->vtoc;
1693                 if (label_to_vtoc(&vtoc, &label) == -1) {
1694                         return (-1);
1695                 }
1696                 if (SMI_vtoc_to_EFI(cur_file, &vtoc64) == -1) {
1697                         return (-1);
1698                 }
1699                 if (efi_write(cur_file, vtoc64) != 0) {
1700                         err_check(vtoc64);
1701                         err_print("Warning: error writing EFI.\n");
1702                         return (-1);
1703                 } else {
1704                         cur_disk->disk_flags &= ~DSK_LABEL_DIRTY;
1705                 }
1706                 /*
1707                  * copy over the EFI vtoc onto the SMI vtoc and return
1708                  * okay.
1709                  */
1710                 dptr = auto_efi_sense(cur_file, &efinfo);
1711                 if (dptr == NULL) {
1712                         fmt_print("Autoconfiguration failed.\n");
1713                         return (-1);
1714                 }
1715 
1716                 cur_label = L_TYPE_EFI;
1717                 cur_disk->label_type = L_TYPE_EFI;
1718                 cur_disk->disk_type = dptr;
1719                 cur_disk->disk_parts = dptr->dtype_plist;
1720                 cur_dtype = dptr;
1721                 cur_parts = dptr->dtype_plist;
1722                 cur_parts->etoc = vtoc64;
1723 
1724                 ncyl = pcyl = nsect = psect = acyl = phead = 0;
1725 
1726                 /*
1727                  * Get the Solais Fdisk Partition information.
1728                  */
1729                 (void) copy_solaris_part(&cur_disk->fdisk_part);
1730 
1731                 return (0);
1732                 }
1733         }
1734 
1735 expert_end:
1736         /*
1737          * Make sure the user is serious.
1738          */
1739         if (check("Ready to label disk, continue")) {
1740                 return (-1);
1741         }
1742         /*
1743          * Write the labels out (this will also notify unix) and
1744          * return status.
1745          */
1746         fmt_print("\n");
1747         if (status = write_label())
1748                 err_print("Label failed.\n");
1749         return (status);
1750 }
1751 
1752 /*
1753  * This routine implements the 'analyze' command.  It simply runs
1754  * the analyze menu.
1755  */
1756 int
1757 c_analyze()
1758 {
1759 
1760         /*
1761          * There must be a current disk type (and therefor a current disk).
1762          */
1763         if (cur_dtype == NULL) {
1764                 err_print("Current Disk Type is not set.\n");
1765                 return (-1);
1766         }
1767         cur_menu++;
1768         last_menu = cur_menu;
1769 
1770         /*
1771          * Run the menu.
1772          */
1773         run_menu(menu_analyze, "ANALYZE", "analyze", 0);
1774         cur_menu--;
1775         return (0);
1776 }
1777 
1778 /*
1779  * This routine implements the 'defect' command.  It simply runs
1780  * the defect menu.
1781  */
1782 int
1783 c_defect()
1784 {
1785         int     i;
1786 
1787         /*
1788          * There must be a current disk type (and therefor a current disk).
1789          */
1790         if (cur_dtype == NULL) {
1791                 err_print("Current Disk Type is not set.\n");
1792                 return (-1);
1793         }
1794 
1795         /*
1796          * Check for the defect management and list management ops and
1797          * display appropriate message.
1798          */
1799         if ((cur_ops->op_ex_man == NULL) && (cur_ops->op_ex_cur == NULL) &&
1800             (cur_ops->op_create == NULL) && (cur_ops->op_wr_cur == NULL)) {
1801                 err_print("Controller does not support defect management\n");
1802                 err_print("or disk supports automatic defect management.\n");
1803                 return (-1);
1804         }
1805         cur_menu++;
1806         last_menu = cur_menu;
1807 
1808         /*
1809          * Lock out interrupt while we manipulate the defect lists.
1810          */
1811         enter_critical();
1812         /*
1813          * If the working list is null but there is a current list,
1814          * update the working list to be a copy of the current list.
1815          */
1816         if ((work_list.list == NULL) && (cur_list.list != NULL)) {
1817                 work_list.header = cur_list.header;
1818                 work_list.list = (struct defect_entry *)zalloc(
1819                     deflist_size(cur_blksz, work_list.header.count) *
1820                     cur_blksz);
1821                 for (i = 0; i < work_list.header.count; i++)
1822                         *(work_list.list + i) = *(cur_list.list + i);
1823                 work_list.flags = cur_list.flags & LIST_PGLIST;
1824         }
1825         exit_critical();
1826         /*
1827          * Run the menu.
1828          */
1829         run_menu(menu_defect, "DEFECT", "defect", 0);
1830         cur_menu--;
1831 
1832         /*
1833          * If the user has modified the working list but not committed
1834          * it, warn him that he is probably making a mistake.
1835          */
1836         if (work_list.flags & LIST_DIRTY) {
1837                 if (!EMBEDDED_SCSI) {
1838                         err_print(
1839                 "Warning: working defect list modified; but not committed.\n");
1840                         if (!check(
1841                 "Do you wish to commit changes to current defect list"))
1842                         (void) do_commit();
1843                 }
1844         }
1845         return (0);
1846 }
1847 
1848 /*
1849  * This routine implements the 'backup' command.  It allows the user
1850  * to search for backup labels on the current disk.  This is useful
1851  * if the primary label was lost and the user wishes to recover the
1852  * partition information for the disk. The disk is relabeled and
1853  * the current defect list is written out if a backup label is found.
1854  */
1855 int
1856 c_backup()
1857 {
1858         struct  dk_label label;
1859         struct  disk_type *dtype;
1860         struct  partition_info *parts, *plist;
1861         diskaddr_t      bn;
1862         int     sec, head, i;
1863         char    *buf;
1864 
1865         /*
1866          * There must be a current disk type (and therefore a current disk).
1867          */
1868         if (cur_dtype == NULL) {
1869                 err_print("Current Disk Type is not set.\n");
1870                 return (-1);
1871         }
1872         /*
1873          * The disk must be formatted to read backup labels.
1874          */
1875         if (!(cur_flags & DISK_FORMATTED)) {
1876                 err_print("Current Disk is unformatted.\n");
1877                 return (-1);
1878         }
1879         /*
1880          * Check for a valid fdisk table entry for Solaris
1881          */
1882         if (!good_fdisk()) {
1883                 return (-1);
1884         }
1885         /*
1886          * If we found a primary label on this disk, make sure
1887          * the user is serious.
1888          */
1889         if (cur_disk->label_type == L_TYPE_EFI) {
1890                 if (((cur_disk->disk_parts->etoc->efi_flags &
1891                     EFI_GPT_PRIMARY_CORRUPT) == 0) &&
1892                     check("Disk has a primary label, still continue"))
1893                         return (-1);
1894                 fmt_print("Restoring primary label.\n");
1895                 if (write_label()) {
1896                         err_print("Failed\n");
1897                         return (-1);
1898                 }
1899                 return (0);
1900         } else if (((cur_disk->disk_flags & (DSK_LABEL | DSK_LABEL_DIRTY)) ==
1901             DSK_LABEL) &&
1902             (check("Disk has a primary label, still continue"))) {
1903                 return (-1);
1904         }
1905 
1906         buf = zalloc(cur_blksz);
1907         fmt_print("Searching for backup labels...");
1908         (void) fflush(stdout);
1909 
1910         /*
1911          * Some disks have the backup labels in a strange place.
1912          */
1913         if (cur_ctype->ctype_flags & CF_BLABEL)
1914                 head = 2;
1915         else
1916                 head = nhead - 1;
1917         /*
1918          * Loop through each copy of the backup label.
1919          */
1920         for (sec = 1; ((sec < BAD_LISTCNT * 2 + 1) && (sec < nsect));
1921             sec += 2) {
1922                 bn = chs2bn(ncyl + acyl - 1, head, sec) + solaris_offset;
1923                 /*
1924                  * Attempt to read it.
1925                  */
1926                 if ((*cur_ops->op_rdwr)(DIR_READ, cur_file, bn,
1927                     1, buf, F_NORMAL, NULL)) {
1928                         continue;
1929                 }
1930 
1931                 (void *) memcpy((char *)&label, buf, sizeof (struct dk_label));
1932 
1933                 /*
1934                  * Verify that it is a reasonable label.
1935                  */
1936                 if (!checklabel(&label))
1937                         continue;
1938                 if (trim_id(label.dkl_asciilabel))
1939                         continue;
1940                 /*
1941                  * Lock out interrupts while we manipulate lists.
1942                  */
1943                 enter_critical();
1944                 fmt_print("found.\n");
1945                 /*
1946                  * Find out which disk type the backup label claims.
1947                  */
1948                 for (dtype = cur_ctype->ctype_dlist; dtype != NULL;
1949                     dtype = dtype->dtype_next)
1950                         if (dtype_match(&label, dtype))
1951                                 break;
1952                 /*
1953                  * If it disagrees with our current type, something
1954                  * real bad is happening.
1955                  */
1956                 if (dtype != cur_dtype) {
1957                         if (dtype == NULL) {
1958                                 fmt_print("\
1959 Unknown disk type in backup label\n");
1960                                 exit_critical();
1961                                 free(buf);
1962                                 return (-1);
1963                         }
1964                         fmt_print("Backup label claims different type:\n");
1965                         fmt_print("    <%s cyl %d alt %d hd %d sec %d>\n",
1966                             label.dkl_asciilabel, label.dkl_ncyl,
1967                             label.dkl_acyl, label.dkl_nhead,
1968                             label.dkl_nsect);
1969                         if (check("Continue")) {
1970                                 exit_critical();
1971                                 free(buf);
1972                                 return (-1);
1973                         }
1974                         cur_dtype = dtype;
1975                 }
1976                 /*
1977                  * Try to match the partition map with a known map.
1978                  */
1979                 for (parts = dtype->dtype_plist; parts != NULL;
1980                     parts = parts->pinfo_next)
1981                         if (parts_match(&label, parts))
1982                                 break;
1983                 /*
1984                  * If we couldn't match it, allocate space for a new one,
1985                  * fill in the info, and add it to the list.  The name
1986                  * for the new map is derived from the disk name.
1987                  */
1988                 if (parts == NULL) {
1989                         parts = (struct partition_info *)
1990                             zalloc(sizeof (struct partition_info));
1991                         plist = dtype->dtype_plist;
1992                         if (plist == NULL)
1993                                 dtype->dtype_plist = parts;
1994                         else {
1995                                 while (plist->pinfo_next != NULL)
1996                                         plist = plist->pinfo_next;
1997                                 plist->pinfo_next = parts;
1998                         }
1999                         parts->pinfo_name = alloc_string("original");
2000                         for (i = 0; i < NDKMAP; i++)
2001 
2002 #if defined(_SUNOS_VTOC_8)
2003                                 parts->pinfo_map[i] = label.dkl_map[i];
2004 
2005 #elif defined(_SUNOS_VTOC_16)
2006                                 parts->pinfo_map[i].dkl_cylno  =
2007                                     label.dkl_vtoc.v_part[i].p_start / spc();
2008                                 parts->pinfo_map[i].dkl_nblk =
2009                                     label.dkl_vtoc.v_part[i].p_size;
2010 #else
2011 #error No VTOC layout defined.
2012 #endif /* defined(_SUNOS_VTOC_8) */
2013                         parts->vtoc = label.dkl_vtoc;
2014                 }
2015                 /*
2016                  * We now have a partition map.  Make it the current map.
2017                  */
2018                 cur_disk->disk_parts = cur_parts = parts;
2019                 exit_critical();
2020                 /*
2021                  * Rewrite the labels and defect lists, as appropriate.
2022                  */
2023                 if (EMBEDDED_SCSI) {
2024                         fmt_print("Restoring primary label.\n");
2025                         if (write_label()) {
2026                                 free(buf);
2027                                 return (-1);
2028                         }
2029                 } else {
2030                         fmt_print("Restoring primary label and defect list.\n");
2031                         if (write_label()) {
2032                                 free(buf);
2033                                 return (-1);
2034                         }
2035                         if (cur_list.list != NULL)
2036                                 write_deflist(&cur_list);
2037                 }
2038                 fmt_print("\n");
2039                 free(buf);
2040                 return (0);
2041         }
2042         /*
2043          * If we didn't find any backup labels, say so.
2044          */
2045         fmt_print("not found.\n\n");
2046         free(buf);
2047         return (0);
2048 }
2049 
2050 /*
2051  * This routine is called by c_verify() for an EFI labeled disk
2052  */
2053 static int
2054 c_verify_efi()
2055 {
2056         struct efi_info efi_info;
2057         struct  partition_info  tmp_pinfo;
2058         int status;
2059 
2060         status = read_efi_label(cur_file, &efi_info, cur_disk);
2061         if (status != 0) {
2062                 err_print("Warning: Could not read label.\n");
2063                 return (-1);
2064         }
2065         if (cur_parts->etoc->efi_flags & EFI_GPT_PRIMARY_CORRUPT) {
2066                 err_print("Reading the primary EFI GPT label ");
2067                 err_print("failed.  Using backup label.\n");
2068                 err_print("Use the 'backup' command to restore ");
2069                 err_print("the primary label.\n");
2070         }
2071         tmp_pinfo.etoc = efi_info.e_parts;
2072         fmt_print("\n");
2073         if (cur_parts->etoc->efi_parts[8].p_name) {
2074                 fmt_print("Volume name = <%8s>\n",
2075                     cur_parts->etoc->efi_parts[8].p_name);
2076         } else {
2077                 fmt_print("Volume name = <        >\n");
2078         }
2079         fmt_print("ascii name  = ");
2080         print_efi_string(efi_info.vendor, efi_info.product,
2081             efi_info.revision, efi_info.capacity);
2082         fmt_print("\n");
2083 
2084         fmt_print("bytes/sector =  %d\n", cur_blksz);
2085         fmt_print("sectors = %llu\n", cur_parts->etoc->efi_last_lba);
2086         fmt_print("accessible sectors = %llu\n",
2087             cur_parts->etoc->efi_last_u_lba);
2088 
2089         print_map(&tmp_pinfo);
2090 
2091         free(efi_info.vendor);
2092         free(efi_info.product);
2093         free(efi_info.revision);
2094         return (0);
2095 }
2096 
2097 /*
2098  * This routine implements the 'verify' command.  It allows the user
2099  * to read the labels on the current disk.
2100  */
2101 int
2102 c_verify()
2103 {
2104         struct  dk_label p_label, b_label, *label;
2105         struct  partition_info tmp_pinfo;
2106         diskaddr_t      bn;
2107         int     sec, head, i, status;
2108         int     p_label_bad = 0;
2109         int     b_label_bad = 0;
2110         int     p_label_found = 0;
2111         int     b_label_found = 0;
2112         char    id_str[128];
2113         char    *buf;
2114 
2115         /*
2116          * There must be a current disk type (and therefore a current disk).
2117          */
2118         if (cur_dtype == NULL) {
2119                 err_print("Current Disk Type is not set.\n");
2120                 return (-1);
2121         }
2122         /*
2123          * The disk must be formatted to read labels.
2124          */
2125         if (!(cur_flags & DISK_FORMATTED)) {
2126                 err_print("Current Disk is unformatted.\n");
2127                 return (-1);
2128         }
2129         /*
2130          * Check for a valid fdisk table entry for Solaris
2131          */
2132         if (!good_fdisk()) {
2133                 return (-1);
2134         }
2135         /*
2136          * Branch off here if the disk is EFI labelled.
2137          */
2138         if (cur_label == L_TYPE_EFI) {
2139                 return (c_verify_efi());
2140         }
2141         /*
2142          * Attempt to read the primary label.
2143          */
2144         status = read_label(cur_file, &p_label);
2145         if (status == -1) {
2146                 err_print("Warning: Could not read primary label.\n");
2147                 p_label_bad = 1;
2148         } else {
2149                 /*
2150                  * Verify that it is a reasonable label.
2151                  */
2152                 /*
2153                  * Save complete ascii string for printing later.
2154                  */
2155                 (void) strncpy(id_str, p_label.dkl_asciilabel, 128);
2156 
2157                 if ((!checklabel((struct dk_label *)&p_label)) ||
2158                     (trim_id(p_label.dkl_asciilabel))) {
2159                         err_print("\
2160 Warning: Primary label appears to be corrupt.\n");
2161                         p_label_bad = 1;
2162                 } else {
2163                         p_label_found = 1;
2164                         /*
2165                          * Make sure it matches current label
2166                          */
2167                         if ((!dtype_match(&p_label, cur_dtype)) ||
2168                             (!parts_match(&p_label, cur_parts))) {
2169                                 err_print("\
2170 Warning: Primary label on disk appears to be different from\ncurrent label.\n");
2171                                 p_label_bad = 1;
2172                         }
2173                 }
2174         }
2175 
2176         /*
2177          * Read backup labels.
2178          * Some disks have the backup labels in a strange place.
2179          */
2180         if (cur_ctype->ctype_flags & CF_BLABEL)
2181                 head = 2;
2182         else
2183                 head = nhead - 1;
2184 
2185         buf = zalloc(cur_blksz);
2186         /*
2187          * Loop through each copy of the backup label.
2188          */
2189         for (sec = 1; ((sec < BAD_LISTCNT * 2 + 1) && (sec < nsect));
2190             sec += 2) {
2191                 bn = chs2bn(ncyl + acyl - 1, head, sec) + solaris_offset;
2192                 /*
2193                  * Attempt to read it.
2194                  */
2195                 if ((*cur_ops->op_rdwr)(DIR_READ, cur_file, bn,
2196                     1, buf, F_NORMAL, NULL))
2197                         continue;
2198 
2199                 (void *) memcpy((char *)&b_label, buf,
2200                     sizeof (struct dk_label));
2201 
2202                 /*
2203                  * Verify that it is a reasonable label.
2204                  */
2205                 if (!checklabel(&b_label))
2206                         continue;
2207 
2208                 /*
2209                  * Save complete label only if no primary label exists
2210                  */
2211                 if (!p_label_found)
2212                         (void) strncpy(id_str, b_label.dkl_asciilabel, 128);
2213 
2214                 if (trim_id(b_label.dkl_asciilabel))
2215                         continue;
2216                 b_label_found = 1;
2217                 /*
2218                  * Compare against primary label
2219                  */
2220                 if (p_label_found) {
2221                         if ((strcmp(b_label.dkl_asciilabel,
2222                             p_label.dkl_asciilabel) != 0) ||
2223                             (b_label.dkl_ncyl != p_label.dkl_ncyl) ||
2224                             (b_label.dkl_acyl != p_label.dkl_acyl) ||
2225                             (b_label.dkl_nhead != p_label.dkl_nhead) ||
2226                             (b_label.dkl_nsect != p_label.dkl_nsect)) {
2227                                 b_label_bad = 1;
2228                         } else {
2229                                 for (i = 0; i < NDKMAP; i++) {
2230 #if defined(_SUNOS_VTOC_8)
2231                                         if ((b_label.dkl_map[i].dkl_cylno !=
2232                                             p_label.dkl_map[i].dkl_cylno) ||
2233                                             (b_label.dkl_map[i].dkl_nblk !=
2234                                             p_label.dkl_map[i].dkl_nblk)) {
2235                                                 b_label_bad = 1;
2236                                                 break;
2237                                         }
2238 
2239 #elif defined(_SUNOS_VTOC_16)
2240                                         if ((b_label.dkl_vtoc.v_part[i].p_tag !=
2241                                             p_label.dkl_vtoc.v_part[i].p_tag) ||
2242                                             (b_label.dkl_vtoc.v_part[i].p_flag
2243                                             != p_label.dkl_vtoc.v_part[i].
2244                                             p_flag) ||
2245                                             (b_label.dkl_vtoc.v_part[i].p_start
2246                                             != p_label.dkl_vtoc.v_part[i].
2247                                             p_start) ||
2248                                             (b_label.dkl_vtoc.v_part[i].p_size
2249                                             != p_label.dkl_vtoc.v_part[i].
2250                                             p_size)) {
2251                                                 b_label_bad = 1;
2252                                                 break;
2253                                         }
2254 #else
2255 #error No VTOC layout defined.
2256 #endif /* defined(_SUNOS_VTOC_8) */
2257                                 }
2258                         }
2259                 }
2260                 if (b_label_bad)
2261                         err_print(
2262 "Warning: Primary and backup labels do not match.\n");
2263                 break;
2264         }
2265         /*
2266          * If we didn't find any backup labels, say so.
2267          */
2268         if (!b_label_found)
2269                 err_print("Warning: Could not read backup labels.\n");
2270 
2271         if ((!b_label_found) || (p_label_bad) || (b_label_bad))
2272                 err_print("\n\
2273 Warning: Check the current partitioning and 'label' the disk or use the\n\
2274 \t 'backup' command.\n");
2275 
2276         /*
2277          * Print label information.
2278          */
2279         if (p_label_found) {
2280                 fmt_print("\nPrimary label contents:\n");
2281                 label = &p_label;
2282         } else if (b_label_found) {
2283                 fmt_print("\nBackup label contents:\n");
2284                 label = &b_label;
2285         } else {
2286                 free(buf);
2287                 return (0);
2288         }
2289 
2290         /*
2291          * Must put info into partition_info struct for
2292          * for print routine.
2293          */
2294         bzero(&tmp_pinfo, sizeof (struct partition_info));
2295         for (i = 0; i < NDKMAP; i++) {
2296 
2297 #if defined(_SUNOS_VTOC_8)
2298                 tmp_pinfo.pinfo_map[i] = label->dkl_map[i];
2299 
2300 #elif defined(_SUNOS_VTOC_16)
2301                 tmp_pinfo.pinfo_map[i].dkl_cylno =
2302                     label->dkl_vtoc.v_part[i].p_start / spc();
2303                 tmp_pinfo.pinfo_map[i].dkl_nblk =
2304                     label->dkl_vtoc.v_part[i].p_size;
2305 #else
2306 #error No VTOC layout defined.
2307 #endif /* defined(_SUNOS_VTOC_8) */
2308         }
2309         tmp_pinfo.vtoc = label->dkl_vtoc;
2310 
2311         fmt_print("\n");
2312         fmt_print("Volume name = <%8s>\n", label->dkl_vtoc.v_volume);
2313         fmt_print("ascii name  = <%s>\n", id_str);
2314         fmt_print("pcyl        = %4d\n", label->dkl_pcyl);
2315         fmt_print("ncyl        = %4d\n", label->dkl_ncyl);
2316         fmt_print("acyl        = %4d\n", label->dkl_acyl);
2317 
2318 #if defined(_SUNOS_VTOC_16)
2319         fmt_print("bcyl        = %4d\n", label->dkl_bcyl);
2320 #endif /* defined(_SUNOS_VTOC_16) */
2321 
2322         fmt_print("nhead       = %4d\n", label->dkl_nhead);
2323         fmt_print("nsect       = %4d\n", label->dkl_nsect);
2324 
2325         print_map(&tmp_pinfo);
2326         free(buf);
2327         return (0);
2328 }
2329 
2330 
2331 /*
2332  * This command implements the inquiry command, for embedded SCSI
2333  * disks only, which issues a SCSI inquiry command, and
2334  * displays the resulting vendor, product id and revision level.
2335  */
2336 int
2337 c_inquiry()
2338 {
2339         char                    inqbuf[255];
2340         struct scsi_inquiry     *inq;
2341 
2342         assert(SCSI);
2343 
2344         inq = (struct scsi_inquiry *)inqbuf;
2345 
2346         if (uscsi_inquiry(cur_file, inqbuf, sizeof (inqbuf))) {
2347                 err_print("Failed\n");
2348                 return (-1);
2349         } else {
2350                 fmt_print("Vendor:   ");
2351                 print_buf(inq->inq_vid, sizeof (inq->inq_vid));
2352                 fmt_print("\nProduct:  ");
2353                 print_buf(inq->inq_pid, sizeof (inq->inq_pid));
2354                 fmt_print("\nRevision: ");
2355                 print_buf(inq->inq_revision, sizeof (inq->inq_revision));
2356                 fmt_print("\n");
2357         }
2358 
2359         return (0);
2360 }
2361 
2362 
2363 /*
2364  * This routine allows the user to set the 8-character
2365  * volume name in the vtoc.  It then writes both the
2366  * primary and backup labels onto the current disk.
2367  */
2368 int
2369 c_volname()
2370 {
2371         int      status;
2372         char    *prompt;
2373         union {
2374                 int     xfoo;
2375                 char    defvolname[LEN_DKL_VVOL+1];
2376         } x;
2377         char    s1[MAXPATHLEN], nclean[MAXPATHLEN];
2378         char    *volname;
2379 
2380 
2381         /*
2382          * There must be a current disk type (and therefore a current disk).
2383          */
2384         if (cur_dtype == NULL) {
2385                 err_print("Current Disk Type is not set.\n");
2386                 return (-1);
2387         }
2388         /*
2389          * The current disk must be formatted to label it.
2390          */
2391         if (!(cur_flags & DISK_FORMATTED)) {
2392                 err_print("Current Disk is unformatted.\n");
2393                 return (-1);
2394         }
2395         /*
2396          * Check for a valid fdisk table entry for Solaris
2397          */
2398         if (!good_fdisk()) {
2399                 return (-1);
2400         }
2401         /*
2402          * The current disk must be formatted to label it.
2403          */
2404         if (cur_parts == NULL) {
2405         err_print(
2406 "Please select a partition map for the disk first.\n");
2407         return (-1);
2408         }
2409 
2410         /*
2411          * Check to see if there are any mounted file systems anywhere
2412          * on the current disk.  If so, refuse to label the disk, but
2413          * only if the partitions would change for the mounted partitions.
2414          *
2415          */
2416         if (checkmount((diskaddr_t)-1, (diskaddr_t)-1)) {
2417                 /* Bleagh, too descriptive */
2418                 if (check_label_with_mount()) {
2419                         err_print(
2420 "Cannot label disk while it has mounted partitions.\n\n");
2421                         return (-1);
2422                 }
2423         }
2424 
2425         /*
2426          * Check to see if there are partitions being used for swapping
2427          * on the current disk.  If so, refuse to label the disk, but
2428          * only if the partitions would change for the swap partitions.
2429          *
2430          */
2431         if (checkswap((diskaddr_t)-1, (diskaddr_t)-1)) {
2432                 /* Bleagh, too descriptive */
2433                 if (check_label_with_swap()) {
2434                         err_print(
2435 "Cannot label disk while its partitions are currently \
2436 being used for swapping.\n\n");
2437                         return (-1);
2438                 }
2439         }
2440 
2441         /*
2442          * Check to see if any partitions used for svm, vxvm, ZFS zpool
2443          * or live upgrade are on the disk. If so, refuse to label the
2444          * disk, but only if we are trying to shrink a partition in
2445          * use.
2446          */
2447         if (checkdevinuse(cur_disk->disk_name, (diskaddr_t)-1,
2448             (diskaddr_t)-1, 0, 1)) {
2449                 err_print("Cannot label disk while its partitions "
2450                     "are in use as described.\n");
2451                 return (-1);
2452         }
2453 
2454         /*
2455          * Prompt for the disk volume name.
2456          */
2457         prompt = "Enter 8-character volume name (remember quotes)";
2458         bzero(x.defvolname, LEN_DKL_VVOL+1);
2459         bcopy(cur_disk->v_volume, x.defvolname, LEN_DKL_VVOL);
2460         /*
2461          *  Get the input using "get_inputline" since
2462          *  input would never return null string.
2463          */
2464         fmt_print("%s[\"%s\"]:", prompt, x.defvolname);
2465 
2466         /*
2467          * Get input from the user.
2468          */
2469         get_inputline(nclean, MAXPATHLEN);
2470         clean_token(s1, nclean);
2471         /*
2472          * check for return.
2473          */
2474         if (s1[0] == 0) {
2475                 volname = x.defvolname;
2476         } else {
2477                 /*
2478                  * remove the " mark from volname.
2479                  */
2480                 if (s1[0] == '"') {
2481                         int i = 1;
2482                         volname = &s1[1];
2483                         while (s1[i] != '"' && s1[i] != '\0')
2484                                 i++;
2485                         s1[i] = '\0';
2486                         clean_token(nclean, volname);
2487                         volname = nclean;
2488                 } else {
2489                         (void) sscanf(&s1[0], "%1024s", nclean);
2490                         volname = nclean;
2491                 };
2492         }
2493         /*
2494          * Make sure the user is serious.
2495          */
2496         if (check("Ready to label disk, continue")) {
2497                 fmt_print("\n");
2498                 return (-1);
2499         }
2500         /*
2501          * Use the volume name chosen above
2502          */
2503         bzero(cur_disk->v_volume, LEN_DKL_VVOL);
2504         bcopy(volname, cur_disk->v_volume, min((int)strlen(volname),
2505             LEN_DKL_VVOL));
2506         if (cur_label == L_TYPE_EFI) {
2507                 bzero(cur_parts->etoc->efi_parts[8].p_name, LEN_DKL_VVOL);
2508                 bcopy(volname, cur_parts->etoc->efi_parts[8].p_name,
2509                     LEN_DKL_VVOL);
2510         }
2511         /*
2512          * Write the labels out (this will also notify unix) and
2513          * return status.
2514          */
2515         fmt_print("\n");
2516         if (status = write_label())
2517                 err_print("Label failed.\n");
2518         return (status);
2519 }