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) 2012 Nexenta System Inc.
  23  *
  24  * Copyright (c) 2011 Gary Mills
  25  *
  26  * Copyright (c) 1993, 2010, Oracle and/or its affiliates. All rights reserved.
  27  */
  28 
  29 /*
  30  * This file contains the code to perform program startup.  This
  31  * includes reading the data file and the search for disks.
  32  */
  33 #include "global.h"
  34 
  35 #include <ctype.h>
  36 #include <stdlib.h>
  37 #include <unistd.h>
  38 #include <string.h>
  39 #include <strings.h>
  40 #include <fcntl.h>
  41 #include <errno.h>
  42 #include <memory.h>
  43 #include <dirent.h>
  44 #include <sys/fcntl.h>
  45 #include <sys/param.h>
  46 #include <sys/stat.h>
  47 
  48 #include "startup.h"
  49 #include "param.h"
  50 #include "label.h"
  51 #include "misc.h"
  52 #include "menu_command.h"
  53 #include "partition.h"
  54 #include "ctlr_scsi.h"
  55 
  56 #include "auto_sense.h"
  57 
  58 extern  struct  ctlr_type ctlr_types[];
  59 extern  int     nctypes;
  60 extern  struct  ctlr_ops        genericops;
  61 extern  long    strtol();
  62 
  63 extern  int     errno;
  64 
  65 #ifdef __STDC__
  66 
  67 /* Function prototypes for ANSI C Compilers */
  68 static void     usage(void);
  69 static int      sup_prxfile(void);
  70 static void     sup_setpath(void);
  71 static void     sup_setdtype(void);
  72 static int      sup_change_spec(struct disk_type *, char *);
  73 static void     sup_setpart(void);
  74 static void     search_for_logical_dev(char *devname);
  75 static void     add_device_to_disklist(char *devname, char *devpath);
  76 static int      disk_is_known(struct dk_cinfo *dkinfo);
  77 static void     datafile_error(char *errmsg, char *token);
  78 static void     search_duplicate_dtypes(void);
  79 static void     search_duplicate_pinfo(void);
  80 static void     check_dtypes_for_inconsistency(struct disk_type *dp1,
  81                 struct disk_type *dp2);
  82 static void     check_pinfo_for_inconsistency(struct partition_info *pp1,
  83                 struct partition_info *pp2);
  84 static uint_t   str2blks(char *str);
  85 static int      str2cyls(char *str);
  86 static struct   chg_list *new_chg_list(struct disk_type *);
  87 static char     *get_physical_name(char *);
  88 static void     sort_disk_list(void);
  89 static int      disk_name_compare(const void *, const void *);
  90 static void     make_controller_list(void);
  91 static void     check_for_duplicate_disknames(char *arglist[]);
  92 
  93 #else   /* __STDC__ */
  94 
  95 /* Function prototypes for non-ANSI C Compilers */
  96 static void     usage();
  97 static int      sup_prxfile();
  98 static void     sup_setpath();
  99 static void     sup_setdtype();
 100 static int      sup_change_spec();
 101 static void     sup_setpart();
 102 static void     search_for_logical_dev();
 103 static void     add_device_to_disklist();
 104 static int      disk_is_known();
 105 static void     datafile_error();
 106 static void     search_duplicate_dtypes();
 107 static void     search_duplicate_pinfo();
 108 static void     check_dtypes_for_inconsistency();
 109 static void     check_pinfo_for_inconsistency();
 110 static uint_t   str2blks();
 111 static int      str2cyls();
 112 static struct   chg_list *new_chg_list();
 113 static char     *get_physical_name();
 114 static void     sort_disk_list();
 115 static int      disk_name_compare();
 116 static void     make_controller_list();
 117 static void     check_for_duplicate_disknames();
 118 
 119 #endif  /* __STDC__ */
 120 
 121 #if defined(sparc)
 122 static char *other_ctlrs[] = {
 123         "ata"
 124         };
 125 #define OTHER_CTLRS 1
 126 
 127 #elif defined(i386)
 128 static char *other_ctlrs[] = {
 129         "ISP-80"
 130         };
 131 #define OTHER_CTLRS 2
 132 
 133 #else
 134 #error No Platform defined.
 135 #endif
 136 
 137 
 138 /*
 139  * This global is used to store the current line # in the data file.
 140  * It must be global because the I/O routines are allowed to side
 141  * effect it to keep track of backslashed newlines.
 142  */
 143 int     data_lineno;                    /* current line # in data file */
 144 
 145 /*
 146  * Search path as defined in the format.dat files
 147  */
 148 static char     **search_path = NULL;
 149 
 150 
 151 static int name_represents_wholedisk(char *name);
 152 
 153 static void get_disk_name(int fd, char *disk_name);
 154 
 155 /*
 156  * This routine digests the options on the command line.  It returns
 157  * the index into argv of the first string that is not an option.  If
 158  * there are none, it returns -1.
 159  */
 160 int
 161 do_options(int argc, char *argv[])
 162 {
 163         char    *ptr;
 164         int     i;
 165         int     next;
 166 
 167         /*
 168          * Default is no extended messages.  Can be enabled manually.
 169          */
 170         option_msg = 0;
 171         diag_msg = 0;
 172         expert_mode = 0;
 173         need_newline = 0;
 174         dev_expert = 0;
 175 
 176         /*
 177          * Loop through the argument list, incrementing each time by
 178          * an amount determined by the options found.
 179          */
 180         for (i = 1; i < argc; i = next) {
 181                 /*
 182                  * Start out assuming an increment of 1.
 183                  */
 184                 next = i + 1;
 185                 /*
 186                  * As soon as we hit a non-option, we're done.
 187                  */
 188                 if (*argv[i] != '-')
 189                         return (i);
 190                 /*
 191                  * Loop through all the characters in this option string.
 192                  */
 193                 for (ptr = argv[i] + 1; *ptr != '\0'; ptr++) {
 194                         /*
 195                          * Determine each option represented.  For options
 196                          * that use a second string, increase the increment
 197                          * of the main loop so they aren't re-interpreted.
 198                          */
 199                         switch (*ptr) {
 200                         case 's':
 201                         case 'S':
 202                                 option_s = 1;
 203                                 break;
 204                         case 'f':
 205                         case 'F':
 206                                 option_f = argv[next++];
 207                                 if (next > argc)
 208                                         goto badopt;
 209                                 break;
 210                         case 'l':
 211                         case 'L':
 212                                 option_l = argv[next++];
 213                                 if (next > argc)
 214                                         goto badopt;
 215                                 break;
 216                         case 'x':
 217                         case 'X':
 218                                 option_x = argv[next++];
 219                                 if (next > argc)
 220                                         goto badopt;
 221                                 break;
 222                         case 'd':
 223                         case 'D':
 224                                 option_d = argv[next++];
 225                                 if (next > argc)
 226                                         goto badopt;
 227                                 break;
 228                         case 't':
 229                         case 'T':
 230                                 option_t = argv[next++];
 231                                 if (next > argc)
 232                                         goto badopt;
 233                                 break;
 234                         case 'p':
 235                         case 'P':
 236                                 option_p = argv[next++];
 237                                 if (next > argc)
 238                                         goto badopt;
 239                                 break;
 240                         case 'm':
 241                                 option_msg = 1;
 242                                 break;
 243                         case 'M':
 244                                 option_msg = 1;
 245                                 diag_msg = 1;
 246                                 break;
 247                         case 'e':
 248                                 expert_mode = 1;
 249                                 break;
 250 #ifdef DEBUG
 251                         case 'z':
 252                                 dev_expert = 1;
 253                                 break;
 254 #endif
 255                         default:
 256 badopt:
 257                                 usage();
 258                                 break;
 259                         }
 260                 }
 261         }
 262         /*
 263          * All the command line strings were options.  Return that fact.
 264          */
 265         return (-1);
 266 }
 267 
 268 
 269 static void
 270 usage()
 271 {
 272         err_print("Usage:  format [-s][-d disk_name]");
 273         err_print("[-t disk_type][-p partition_name]\n");
 274         err_print("\t[-f cmd_file][-l log_file]");
 275         err_print("[-x data_file] [-m] [-M] [-e] disk_list\n");
 276         fullabort();
 277 }
 278 
 279 
 280 /*
 281  * This routine reads in and digests the data file.  The data file contains
 282  * definitions for the search path, known disk types, and known partition
 283  * maps.
 284  *
 285  * Note: for each file being processed, file_name is a pointer to that
 286  * file's name.  We are careful to make sure that file_name points to
 287  * globally-accessible data, not data on the stack, because each
 288  * disk/partition/controller definition now keeps a pointer to the
 289  * filename in which it was defined.  In the case of duplicate,
 290  * conflicting definitions, we can thus tell the user exactly where
 291  * the problem is occurring.
 292  */
 293 void
 294 sup_init()
 295 {
 296         int             nopened_files = 0;
 297         char            fname[MAXPATHLEN];
 298         char            *path;
 299         char            *p;
 300         struct stat     stbuf;
 301 
 302 
 303         /*
 304          * Create a singly-linked list of controller types so that we may
 305          * dynamically add unknown controllers to this for 3'rd
 306          * party disk support.
 307          */
 308 
 309         make_controller_list();
 310 
 311         /*
 312          * If a data file was specified on the command line, use it first
 313          * If the file cannot be opened, fail.  We want to guarantee
 314          * that, if the user explicitly names a file, they can
 315          * access it.
 316          *
 317          * option_x is already global, no need to dup it on the heap.
 318          */
 319         if (option_x) {
 320                 file_name = option_x;
 321                 if (sup_prxfile()) {
 322                         nopened_files++;
 323                 } else {
 324                         err_print("Unable to open data file '%s' - %s.\n",
 325                             file_name, strerror(errno));
 326                         fullabort();
 327                 }
 328         }
 329 
 330         /*
 331          * Now look for an environment variable FORMAT_PATH.
 332          * If found, we use it as a colon-separated list
 333          * of directories.  If no such environment variable
 334          * is defined, use a default path of "/etc".
 335          */
 336         path = getenv("FORMAT_PATH");
 337         if (path == NULL) {
 338                 path = "/etc";
 339         }
 340         /*
 341          * Traverse the path one file at a time.  Pick off
 342          * the file name, and append the name "format.dat"
 343          * at the end of the pathname.
 344          * Whatever string we construct, duplicate it on the
 345          * heap, so that file_name is globally accessible.
 346          */
 347         while (*path != 0) {
 348                 p = fname;
 349                 while (*path != 0 && *path != ':')
 350                         *p++ = *path++;
 351                 if (p == fname)
 352                         continue;
 353                 *p = 0;
 354                 if (*path == ':')
 355                         path++;
 356                 /*
 357                  * If the path we have so far is a directory,
 358                  * look for a format.dat file in that directory,
 359                  * otherwise try using the path name specified.
 360                  * This permits arbitrary file names in the
 361                  * path specification, if this proves useful.
 362                  */
 363                 if (stat(fname, &stbuf) == -1) {
 364                         err_print("Unable to access '%s' - %s.\n",
 365                             fname, strerror(errno));
 366                 } else {
 367                         if (S_ISDIR(stbuf.st_mode)) {
 368                                 if (*(p-1) != '/')
 369                                         *p++ = '/';
 370                                 (void) strcpy(p, "format.dat");
 371                         }
 372                         file_name = alloc_string(fname);
 373                         if (sup_prxfile()) {
 374                                 nopened_files++;
 375                         }
 376                 }
 377         }
 378 
 379         /*
 380          * Check for duplicate disk or partitions definitions
 381          * that are inconsistent - this would be very confusing.
 382          */
 383         search_duplicate_dtypes();
 384         search_duplicate_pinfo();
 385 }
 386 
 387 
 388 /*
 389  * Open and process a format data file.  Unfortunately, we use
 390  * globals: file_name for the file name, and data_file
 391  * for the descriptor.  Return true if able to open the file.
 392  */
 393 static int
 394 sup_prxfile()
 395 {
 396         int     status;
 397         TOKEN   token;
 398         TOKEN   cleaned;
 399 
 400         /*
 401          * Open the data file.  Return 0 if unable to do so.
 402          */
 403         data_file = fopen(file_name, "r");
 404         if (data_file == NULL) {
 405                 return (0);
 406         }
 407         /*
 408          * Step through the data file a meta-line at a time.  There are
 409          * typically several backslashed newlines in each meta-line,
 410          * so data_lineno will be getting side effected along the way.
 411          */
 412         data_lineno = 0;
 413         for (;;) {
 414                 data_lineno++;
 415                 /*
 416                  * Get the keyword.
 417                  */
 418                 status = sup_gettoken(token);
 419                 /*
 420                  * If we hit the end of the data file, we're done.
 421                  */
 422                 if (status == SUP_EOF)
 423                         break;
 424                 /*
 425                  * If the line is blank, skip it.
 426                  */
 427                 if (status == SUP_EOL)
 428                         continue;
 429                 /*
 430                  * If the line starts with some key character, it's an error.
 431                  */
 432                 if (status != SUP_STRING) {
 433                         datafile_error("Expecting keyword, found '%s'", token);
 434                         continue;
 435                 }
 436                 /*
 437                  * Clean up the token and see which keyword it is.  Call
 438                  * the appropriate routine to process the rest of the line.
 439                  */
 440                 clean_token(cleaned, token);
 441                 if (strcmp(cleaned, "search_path") == 0)
 442                         sup_setpath();
 443                 else if (strcmp(cleaned, "disk_type") == 0)
 444                         sup_setdtype();
 445                 else if (strcmp(cleaned, "partition") == 0)
 446                         sup_setpart();
 447                 else {
 448                         datafile_error("Unknown keyword '%s'", cleaned);
 449                 }
 450         }
 451         /*
 452          * Close the data file.
 453          */
 454         (void) fclose(data_file);
 455 
 456         return (1);
 457 }
 458 
 459 /*
 460  * This routine processes a 'search_path' line in the data file.  The
 461  * search path is a list of disk names that will be searched for by the
 462  * program.
 463  *
 464  * The static path_size and path_alloc are used to build up the
 465  * list of files comprising the search path.  The static definitions
 466  * enable supporting multiple search path definitions.
 467  */
 468 static void
 469 sup_setpath()
 470 {
 471         TOKEN           token;
 472         TOKEN           cleaned;
 473         int             status;
 474         static int      path_size;
 475         static int      path_alloc;
 476 
 477         /*
 478          * Pull in some grammar.
 479          */
 480         status = sup_gettoken(token);
 481         if (status != SUP_EQL) {
 482                 datafile_error("Expecting '=', found '%s'", token);
 483                 return;
 484         }
 485         /*
 486          * Loop through the entries.
 487          */
 488         for (;;) {
 489                 /*
 490                  * Pull in the disk name.
 491                  */
 492                 status = sup_gettoken(token);
 493                 /*
 494                  * If we hit end of line, we're done.
 495                  */
 496                 if (status == SUP_EOL)
 497                         break;
 498                 /*
 499                  * If we hit some key character, it's an error.
 500                  */
 501                 if (status != SUP_STRING) {
 502                         datafile_error("Expecting value, found '%s'", token);
 503                         break;
 504                 }
 505                 clean_token(cleaned, token);
 506                 /*
 507                  * Build the string into an argvlist.  This array
 508                  * is dynamically sized, as necessary, and terminated
 509                  * with a null.  Each name is alloc'ed on the heap,
 510                  * so no dangling references.
 511                  */
 512                 search_path = build_argvlist(search_path, &path_size,
 513                     &path_alloc, cleaned);
 514                 /*
 515                  * Pull in some grammar.
 516                  */
 517                 status = sup_gettoken(token);
 518                 if (status == SUP_EOL)
 519                         break;
 520                 if (status != SUP_COMMA) {
 521                         datafile_error("Expecting ', ', found '%s'", token);
 522                         break;
 523                 }
 524         }
 525 }
 526 
 527 /*
 528  * This routine processes a 'disk_type' line in the data file.  It defines
 529  * the physical attributes of a brand of disk when connected to a specific
 530  * controller type.
 531  */
 532 static void
 533 sup_setdtype()
 534 {
 535         TOKEN   token, cleaned, ident;
 536         int     val, status, i;
 537         ulong_t flags = 0;
 538         struct  disk_type *dtype, *type;
 539         struct  ctlr_type *ctype;
 540         char    *dtype_name, *ptr;
 541         struct  mctlr_list      *mlp;
 542 
 543         /*
 544          * Pull in some grammar.
 545          */
 546         status = sup_gettoken(token);
 547         if (status != SUP_EQL) {
 548                 datafile_error("Expecting '=', found '%s'", token);
 549                 return;
 550         }
 551         /*
 552          * Pull in the name of the disk type.
 553          */
 554         status = sup_gettoken(token);
 555         if (status != SUP_STRING) {
 556                 datafile_error("Expecting value, found '%s'", token);
 557                 return;
 558         }
 559         clean_token(cleaned, token);
 560         /*
 561          * Allocate space for the disk type and copy in the name.
 562          */
 563         dtype_name = (char *)zalloc(strlen(cleaned) + 1);
 564         (void) strcpy(dtype_name, cleaned);
 565         dtype = (struct disk_type *)zalloc(sizeof (struct disk_type));
 566         dtype->dtype_asciilabel = dtype_name;
 567         /*
 568          * Save the filename/linenumber where this disk was defined
 569          */
 570         dtype->dtype_filename = file_name;
 571         dtype->dtype_lineno = data_lineno;
 572         /*
 573          * Loop for each attribute.
 574          */
 575         for (;;) {
 576                 /*
 577                  * Pull in some grammar.
 578                  */
 579                 status = sup_gettoken(token);
 580                 /*
 581                  * If we hit end of line, we're done.
 582                  */
 583                 if (status == SUP_EOL)
 584                         break;
 585                 if (status != SUP_COLON) {
 586                         datafile_error("Expecting ':', found '%s'", token);
 587                         return;
 588                 }
 589                 /*
 590                  * Pull in the attribute.
 591                  */
 592                 status = sup_gettoken(token);
 593                 /*
 594                  * If we hit end of line, we're done.
 595                  */
 596                 if (status == SUP_EOL)
 597                         break;
 598                 /*
 599                  * If we hit a key character, it's an error.
 600                  */
 601                 if (status != SUP_STRING) {
 602                         datafile_error("Expecting keyword, found '%s'", token);
 603                         return;
 604                 }
 605                 clean_token(ident, token);
 606                 /*
 607                  * Check to see if we've got a change specification
 608                  * If so, this routine will parse the entire
 609                  * specification, so just restart at top of loop
 610                  */
 611                 if (sup_change_spec(dtype, ident)) {
 612                         continue;
 613                 }
 614                 /*
 615                  * Pull in more grammar.
 616                  */
 617                 status = sup_gettoken(token);
 618                 if (status != SUP_EQL) {
 619                         datafile_error("Expecting '=', found '%s'", token);
 620                         return;
 621                 }
 622                 /*
 623                  * Pull in the value of the attribute.
 624                  */
 625                 status = sup_gettoken(token);
 626                 if (status != SUP_STRING) {
 627                         datafile_error("Expecting value, found '%s'", token);
 628                         return;
 629                 }
 630                 clean_token(cleaned, token);
 631                 /*
 632                  * If the attribute defined the ctlr...
 633                  */
 634                 if (strcmp(ident, "ctlr") == 0) {
 635                         /*
 636                          * Match the value with a ctlr type.
 637                          */
 638                         mlp = controlp;
 639 
 640                         while (mlp != NULL) {
 641                                 if (strcmp(mlp->ctlr_type->ctype_name,
 642                                     cleaned) == 0)
 643                                         break;
 644                                 mlp = mlp->next;
 645                         }
 646                         /*
 647                          * If we couldn't match it, it's an error.
 648                          */
 649                         if (mlp == NULL) {
 650                                 for (i = 0; i < OTHER_CTLRS; i++) {
 651                                         if (strcmp(other_ctlrs[i], cleaned)
 652                                             == 0) {
 653                                                 datafile_error(NULL, NULL);
 654                                                 return;
 655                                         }
 656                                 }
 657                                 if (i == OTHER_CTLRS) {
 658                                         datafile_error(
 659                                             "Unknown controller '%s'",
 660                                             cleaned);
 661                                         return;
 662                                 }
 663                         }
 664                         /*
 665                          * Found a match.  Add this disk type to the list
 666                          * for the ctlr type if we can complete the
 667                          * disk specification correctly.
 668                          */
 669                         ctype = mlp->ctlr_type;
 670                         flags |= SUP_CTLR;
 671                         continue;
 672                 }
 673                 /*
 674                  * All other attributes require a numeric value.  Convert
 675                  * the value to a number.
 676                  */
 677                 val = (int)strtol(cleaned, &ptr, 0);
 678                 if (*ptr != '\0') {
 679                         datafile_error("Expecting an integer, found '%s'",
 680                             cleaned);
 681                         return;
 682                 }
 683                 /*
 684                  * Figure out which attribute it was and fill in the
 685                  * appropriate value.  Also note that the attribute
 686                  * has been defined.
 687                  */
 688                 if (strcmp(ident, "ncyl") == 0) {
 689                         dtype->dtype_ncyl = val;
 690                         flags |= SUP_NCYL;
 691                 } else if (strcmp(ident, "acyl") == 0) {
 692                         dtype->dtype_acyl = val;
 693                         flags |= SUP_ACYL;
 694                 } else if (strcmp(ident, "pcyl") == 0) {
 695                         dtype->dtype_pcyl = val;
 696                         flags |= SUP_PCYL;
 697                 } else if (strcmp(ident, "nhead") == 0) {
 698                         dtype->dtype_nhead = val;
 699                         flags |= SUP_NHEAD;
 700                 } else if (strcmp(ident, "nsect") == 0) {
 701                         dtype->dtype_nsect = val;
 702                         flags |= SUP_NSECT;
 703                 } else if (strcmp(ident, "rpm") == 0) {
 704                         dtype->dtype_rpm = val;
 705                         flags |= SUP_RPM;
 706                 } else if (strcmp(ident, "bpt") == 0) {
 707                         dtype->dtype_bpt = val;
 708                         flags |= SUP_BPT;
 709                 } else if (strcmp(ident, "bps") == 0) {
 710                         dtype->dtype_bps = val;
 711                         flags |= SUP_BPS;
 712                 } else if (strcmp(ident, "drive_type") == 0) {
 713                         dtype->dtype_dr_type = val;
 714                         flags |= SUP_DRTYPE;
 715                 } else if (strcmp(ident, "cache") == 0) {
 716                         dtype->dtype_cache = val;
 717                         flags |= SUP_CACHE;
 718                 } else if (strcmp(ident, "prefetch") == 0) {
 719                         dtype->dtype_threshold = val;
 720                         flags |= SUP_PREFETCH;
 721                 } else if (strcmp(ident, "read_retries") == 0) {
 722                         dtype->dtype_read_retries = val;
 723                         flags |= SUP_READ_RETRIES;
 724                 } else if (strcmp(ident, "write_retries") == 0) {
 725                         dtype->dtype_write_retries = val;
 726                         flags |= SUP_WRITE_RETRIES;
 727                 } else if (strcmp(ident, "min_prefetch") == 0) {
 728                         dtype->dtype_prefetch_min = val;
 729                         flags |= SUP_CACHE_MIN;
 730                 } else if (strcmp(ident, "max_prefetch") == 0) {
 731                         dtype->dtype_prefetch_max = val;
 732                         flags |= SUP_CACHE_MAX;
 733                 } else if (strcmp(ident, "trks_zone") == 0) {
 734                         dtype->dtype_trks_zone = val;
 735                         flags |= SUP_TRKS_ZONE;
 736                 } else if (strcmp(ident, "atrks") == 0) {
 737                         dtype->dtype_atrks = val;
 738                         flags |= SUP_ATRKS;
 739                 } else if (strcmp(ident, "asect") == 0) {
 740                         dtype->dtype_asect = val;
 741                         flags |= SUP_ASECT;
 742                 } else if (strcmp(ident, "psect") == 0) {
 743                         dtype->dtype_psect = val;
 744                         flags |= SUP_PSECT;
 745                 } else if (strcmp(ident, "phead") == 0) {
 746                         dtype->dtype_phead = val;
 747                         flags |= SUP_PHEAD;
 748                 } else if (strcmp(ident, "fmt_time") == 0) {
 749                         dtype->dtype_fmt_time = val;
 750                         flags |= SUP_FMTTIME;
 751                 } else if (strcmp(ident, "cyl_skew") == 0) {
 752                         dtype->dtype_cyl_skew = val;
 753                         flags |= SUP_CYLSKEW;
 754                 } else if (strcmp(ident, "trk_skew") == 0) {
 755                         dtype->dtype_trk_skew = val;
 756                         flags |= SUP_TRKSKEW;
 757                 } else {
 758                         datafile_error("Unknown keyword '%s'", ident);
 759                 }
 760         }
 761         /*
 762          * Check to be sure all the necessary attributes have been defined.
 763          * If any are missing, it's an error.  Also, log options for later
 764          * use by specific driver.
 765          */
 766         dtype->dtype_options = flags;
 767         if ((flags & SUP_MIN_DRIVE) != SUP_MIN_DRIVE) {
 768                 datafile_error("Incomplete specification", "");
 769                 return;
 770         }
 771         if ((!(ctype->ctype_flags & CF_SCSI)) && (!(flags & SUP_BPT)) &&
 772             (!(ctype->ctype_flags & CF_NOFORMAT))) {
 773                 datafile_error("Incomplete specification", "");
 774                 return;
 775         }
 776         if ((ctype->ctype_flags & CF_SMD_DEFS) && (!(flags & SUP_BPS))) {
 777                 datafile_error("Incomplete specification", "");
 778                 return;
 779         }
 780         /*
 781          * Add this disk type to the list for the ctlr type
 782          */
 783         assert(flags & SUP_CTLR);
 784         type = ctype->ctype_dlist;
 785         if (type == NULL) {
 786                 ctype->ctype_dlist = dtype;
 787         } else {
 788                 while (type->dtype_next != NULL)
 789                         type = type->dtype_next;
 790                 type->dtype_next = dtype;
 791         }
 792 }
 793 
 794 
 795 /*
 796  * Parse a SCSI mode page change specification.
 797  *
 798  * Return:
 799  *              0:  not change specification, continue parsing
 800  *              1:  was change specification, it was ok,
 801  *                  or we already handled the error.
 802  */
 803 static int
 804 sup_change_spec(struct disk_type *disk, char *id)
 805 {
 806         char            *p;
 807         char            *p2;
 808         int             pageno;
 809         int             byteno;
 810         int             mode;
 811         int             value;
 812         TOKEN           token;
 813         TOKEN           ident;
 814         struct chg_list *cp;
 815         int             tilde;
 816         int             i;
 817 
 818         /*
 819          * Syntax: p[<nn>|0x<xx>]
 820          */
 821         if (*id != 'p') {
 822                 return (0);
 823         }
 824         pageno = (int)strtol(id+1, &p2, 0);
 825         if (*p2 != 0) {
 826                 return (0);
 827         }
 828         /*
 829          * Once we get this far, we know we have the
 830          * beginnings of a change specification.
 831          * If there's a problem now, report the problem,
 832          * and return 1, so that the caller can restart
 833          * parsing at the next expression.
 834          */
 835         if (!scsi_supported_page(pageno)) {
 836                 datafile_error("Unsupported mode page '%s'", id);
 837                 return (1);
 838         }
 839         /*
 840          * Next token should be the byte offset
 841          */
 842         if (sup_gettoken(token) != SUP_STRING) {
 843                 datafile_error("Unexpected value '%s'", token);
 844                 return (1);
 845         }
 846         clean_token(ident, token);
 847 
 848         /*
 849          * Syntax: b[<nn>|0x<xx>]
 850          */
 851         p = ident;
 852         if (*p++ != 'b') {
 853                 datafile_error("Unknown keyword '%s'", ident);
 854                 return (1);
 855         }
 856         byteno = (int)strtol(p, &p2, 10);
 857         if (*p2 != 0) {
 858                 datafile_error("Unknown keyword '%s'", ident);
 859                 return (1);
 860         }
 861         if (byteno == 0 || byteno == 1) {
 862                 datafile_error("Unsupported byte offset '%s'", ident);
 863                 return (1);
 864         }
 865 
 866         /*
 867          * Get the operator for this expression
 868          */
 869         mode = CHG_MODE_UNDEFINED;
 870         switch (sup_gettoken(token)) {
 871         case SUP_EQL:
 872                 mode = CHG_MODE_ABS;
 873                 break;
 874         case SUP_OR:
 875                 if (sup_gettoken(token) == SUP_EQL)
 876                         mode = CHG_MODE_SET;
 877                 break;
 878         case SUP_AND:
 879                 if (sup_gettoken(token) == SUP_EQL)
 880                         mode = CHG_MODE_CLR;
 881                 break;
 882         }
 883         if (mode == CHG_MODE_UNDEFINED) {
 884                 datafile_error("Unexpected operator: '%s'", token);
 885                 return (1);
 886         }
 887 
 888         /*
 889          * Get right-hand of expression - accept optional tilde
 890          */
 891         tilde = 0;
 892         if ((i = sup_gettoken(token)) == SUP_TILDE) {
 893                 tilde = 1;
 894                 i = sup_gettoken(token);
 895         }
 896         if (i != SUP_STRING) {
 897                 datafile_error("Expecting value, found '%s'", token);
 898                 return (1);
 899         }
 900         clean_token(ident, token);
 901         value = (int)strtol(ident, &p, 0);
 902         if (*p != 0) {
 903                 datafile_error("Expecting value, found '%s'", token);
 904                 return (1);
 905         }
 906 
 907         /*
 908          * Apply the tilde operator, if found.
 909          * Constrain to a byte value.
 910          */
 911         if (tilde) {
 912                 value = ~value;
 913         }
 914         value &= 0xff;
 915 
 916         /*
 917          * We parsed a successful change specification expression.
 918          * Add it to the list for this disk type.
 919          */
 920         cp = new_chg_list(disk);
 921         cp->pageno = pageno;
 922         cp->byteno = byteno;
 923         cp->mode = mode;
 924         cp->value = value;
 925         return (1);
 926 }
 927 
 928 
 929 /*
 930  * This routine processes a 'partition' line in the data file.  It defines
 931  * a known partition map for a particular disk type on a particular
 932  * controller type.
 933  */
 934 static void
 935 sup_setpart()
 936 {
 937         TOKEN   token, cleaned, disk, ctlr, ident;
 938         struct  disk_type *dtype = NULL;
 939         struct  ctlr_type *ctype = NULL;
 940         struct  partition_info *pinfo, *parts;
 941         char    *pinfo_name;
 942         int     i, index, status, flags = 0;
 943         uint_t  val1, val2;
 944         ushort_t        vtoc_tag;
 945         ushort_t        vtoc_flag;
 946         struct  mctlr_list      *mlp;
 947 
 948         /*
 949          * Pull in some grammar.
 950          */
 951         status = sup_gettoken(token);
 952         if (status != SUP_EQL) {
 953                 datafile_error("Expecting '=', found '%s'", token);
 954                 return;
 955         }
 956         /*
 957          * Pull in the name of the map.
 958          */
 959         status = sup_gettoken(token);
 960         if (status != SUP_STRING) {
 961                 datafile_error("Expecting value, found '%s'", token);
 962                 return;
 963         }
 964         clean_token(cleaned, token);
 965         /*
 966          * Allocate space for the partition map and fill in the name.
 967          */
 968         pinfo_name = (char *)zalloc(strlen(cleaned) + 1);
 969         (void) strcpy(pinfo_name, cleaned);
 970         pinfo = (struct partition_info *)zalloc(sizeof (struct partition_info));
 971         pinfo->pinfo_name = pinfo_name;
 972         /*
 973          * Save the filename/linenumber where this partition was defined
 974          */
 975         pinfo->pinfo_filename = file_name;
 976         pinfo->pinfo_lineno = data_lineno;
 977 
 978         /*
 979          * Install default vtoc information into the new partition table
 980          */
 981         set_vtoc_defaults(pinfo);
 982 
 983         /*
 984          * Loop for each attribute in the line.
 985          */
 986         for (;;) {
 987                 /*
 988                  * Pull in some grammar.
 989                  */
 990                 status = sup_gettoken(token);
 991                 /*
 992                  * If we hit end of line, we're done.
 993                  */
 994                 if (status == SUP_EOL)
 995                         break;
 996                 if (status != SUP_COLON) {
 997                         datafile_error("Expecting ':', found '%s'", token);
 998                         return;
 999                 }
1000                 /*
1001                  * Pull in the attribute.
1002                  */
1003                 status = sup_gettoken(token);
1004                 /*
1005                  * If we hit end of line, we're done.
1006                  */
1007                 if (status == SUP_EOL)
1008                         break;
1009                 if (status != SUP_STRING) {
1010                         datafile_error("Expecting keyword, found '%s'", token);
1011                         return;
1012                 }
1013                 clean_token(ident, token);
1014                 /*
1015                  * Pull in more grammar.
1016                  */
1017                 status = sup_gettoken(token);
1018                 if (status != SUP_EQL) {
1019                         datafile_error("Expecting '=', found '%s'", token);
1020                         return;
1021                 }
1022                 /*
1023                  * Pull in the value of the attribute.
1024                  */
1025                 status = sup_gettoken(token);
1026                 /*
1027                  * If we hit a key character, it's an error.
1028                  */
1029                 if (status != SUP_STRING) {
1030                         datafile_error("Expecting value, found '%s'", token);
1031                         return;
1032                 }
1033                 clean_token(cleaned, token);
1034                 /*
1035                  * If the attribute is the ctlr, save the ctlr name and
1036                  * mark it defined.
1037                  */
1038                 if (strcmp(ident, "ctlr") == 0) {
1039                         (void) strcpy(ctlr, cleaned);
1040                         flags |= SUP_CTLR;
1041                         continue;
1042                 /*
1043                  * If the attribute is the disk, save the disk name and
1044                  * mark it defined.
1045                  */
1046                 } else if (strcmp(ident, "disk") == 0) {
1047                         (void) strcpy(disk, cleaned);
1048                         flags |= SUP_DISK;
1049                         continue;
1050                 }
1051                 /*
1052                  * If we now know both the controller name and the
1053                  * disk name, let's see if we can find the controller
1054                  * and disk type.  This will give us the geometry,
1055                  * which can permit us to accept partitions specs
1056                  * in cylinders or blocks.
1057                  */
1058                 if (((flags & (SUP_DISK|SUP_CTLR)) == (SUP_DISK|SUP_CTLR)) &&
1059                     dtype == NULL && ctype == NULL) {
1060                         /*
1061                          * Attempt to match the specified ctlr to a known type.
1062                          */
1063                         mlp = controlp;
1064 
1065                         while (mlp != NULL) {
1066                                 if (strcmp(mlp->ctlr_type->ctype_name,
1067                                     ctlr) == 0)
1068                                         break;
1069                                 mlp = mlp->next;
1070                         }
1071                         /*
1072                          * If no match is found, it's an error.
1073                          */
1074                         if (mlp == NULL) {
1075                                 for (i = 0; i < OTHER_CTLRS; i++) {
1076                                         if (strcmp(other_ctlrs[i], ctlr) == 0) {
1077                                                 datafile_error(NULL, NULL);
1078                                                 return;
1079                                         }
1080                                 }
1081                                 if (i == OTHER_CTLRS) {
1082                                         datafile_error(
1083                                             "Unknown controller '%s'", ctlr);
1084                                         return;
1085                                 }
1086                         }
1087                         ctype = mlp->ctlr_type;
1088                         /*
1089                          * Attempt to match the specified disk to a known type.
1090                          */
1091                         for (dtype = ctype->ctype_dlist; dtype != NULL;
1092                             dtype = dtype->dtype_next) {
1093                                 if (strcmp(dtype->dtype_asciilabel, disk) == 0)
1094                                         break;
1095                         }
1096                         /*
1097                          * If no match is found, it's an error.
1098                          */
1099                         if (dtype == NULL) {
1100                                 datafile_error("Unknown disk '%s'", disk);
1101                                 return;
1102                         }
1103                         /*
1104                          * Now that we know the disk type, set up the
1105                          * globals that let that magic macro "spc()"
1106                          * do it's thing.  Sorry that this is glued
1107                          * together so poorly...
1108                          */
1109                         nhead = dtype->dtype_nhead;
1110                         nsect = dtype->dtype_nsect;
1111                         acyl = dtype->dtype_acyl;
1112                         ncyl = dtype->dtype_ncyl;
1113                 }
1114                 /*
1115                  * By now, the disk and controller type must be defined
1116                  */
1117                 if (dtype == NULL || ctype == NULL) {
1118                         datafile_error("Incomplete specification", "");
1119                         return;
1120                 }
1121                 /*
1122                  * The rest of the attributes are all single letters.
1123                  * Make sure the specified attribute is a single letter.
1124                  */
1125                 if (strlen(ident) != 1) {
1126                         datafile_error("Unknown keyword '%s'", ident);
1127                         return;
1128                 }
1129                 /*
1130                  * Also make sure it is within the legal range of letters.
1131                  */
1132                 if (ident[0] < PARTITION_BASE || ident[0] > PARTITION_BASE+9) {
1133                         datafile_error("Unknown keyword '%s'", ident);
1134                         return;
1135                 }
1136                 /*
1137                  * Here's the index of the partition we're dealing with
1138                  */
1139                 index = ident[0] - PARTITION_BASE;
1140                 /*
1141                  * For SunOS 5.0, we support the additional syntax:
1142                  *      [<tag>, ] [<flag>, ] <start>, <end>
1143                  * instead of:
1144                  *      <start>, <end>
1145                  *
1146                  * <tag> may be one of: boot, root, swap, etc.
1147                  * <flag> consists of two characters:
1148                  *      W (writable) or R (read-only)
1149                  *      M (mountable) or U (unmountable)
1150                  *
1151                  * Start with the defaults assigned above:
1152                  */
1153                 vtoc_tag = pinfo->vtoc.v_part[index].p_tag;
1154                 vtoc_flag = pinfo->vtoc.v_part[index].p_flag;
1155 
1156                 /*
1157                  * First try to match token against possible tag values
1158                  */
1159                 if (find_value(ptag_choices, cleaned, &i) == 1) {
1160                         /*
1161                          * Found valid tag. Use it and advance parser
1162                          */
1163                         vtoc_tag = (ushort_t)i;
1164                         status = sup_gettoken(token);
1165                         if (status != SUP_COMMA) {
1166                                 datafile_error(
1167                                     "Expecting ', ', found '%s'", token);
1168                                 return;
1169                         }
1170                         status = sup_gettoken(token);
1171                         if (status != SUP_STRING) {
1172                                 datafile_error("Expecting value, found '%s'",
1173                                     token);
1174                                 return;
1175                         }
1176                         clean_token(cleaned, token);
1177                 }
1178 
1179                 /*
1180                  * Try to match token against possible flag values
1181                  */
1182                 if (find_value(pflag_choices, cleaned, &i) == 1) {
1183                         /*
1184                          * Found valid flag. Use it and advance parser
1185                          */
1186                         vtoc_flag = (ushort_t)i;
1187                         status = sup_gettoken(token);
1188                         if (status != SUP_COMMA) {
1189                                 datafile_error("Expecting ', ', found '%s'",
1190                                     token);
1191                                 return;
1192                         }
1193                         status = sup_gettoken(token);
1194                         if (status != SUP_STRING) {
1195                                 datafile_error("Expecting value, found '%s'",
1196                                     token);
1197                                 return;
1198                         }
1199                         clean_token(cleaned, token);
1200                 }
1201                 /*
1202                  * All other attributes have a pair of numeric values.
1203                  * Convert the first value to a number.  This value
1204                  * is the starting cylinder number of the partition.
1205                  */
1206                 val1 = str2cyls(cleaned);
1207                 if (val1 == (uint_t)(-1)) {
1208                         datafile_error("Expecting an integer, found '%s'",
1209                             cleaned);
1210                         return;
1211                 }
1212                 /*
1213                  * Pull in some grammar.
1214                  */
1215                 status = sup_gettoken(token);
1216                 if (status != SUP_COMMA) {
1217                         datafile_error("Expecting ', ', found '%s'", token);
1218                         return;
1219                 }
1220                 /*
1221                  * Pull in the second value.
1222                  */
1223                 status = sup_gettoken(token);
1224                 if (status != SUP_STRING) {
1225                         datafile_error("Expecting value, found '%s'", token);
1226                         return;
1227                 }
1228                 clean_token(cleaned, token);
1229                 /*
1230                  * Convert the second value to a number.  This value
1231                  * is the number of blocks composing the partition.
1232                  * If the token is terminated with a 'c', the units
1233                  * are cylinders, not blocks.  Also accept a 'b', if
1234                  * they choose to be so specific.
1235                  */
1236                 val2 = str2blks(cleaned);
1237                 if (val2 == (uint_t)(-1)) {
1238                         datafile_error("Expecting an integer, found '%s'",
1239                             cleaned);
1240                         return;
1241                 }
1242                 /*
1243                  * Fill in the appropriate map entry with the values.
1244                  */
1245                 pinfo->pinfo_map[index].dkl_cylno = val1;
1246                 pinfo->pinfo_map[index].dkl_nblk = val2;
1247                 pinfo->vtoc.v_part[index].p_tag = vtoc_tag;
1248                 pinfo->vtoc.v_part[index].p_flag = vtoc_flag;
1249 
1250 #if defined(_SUNOS_VTOC_16)
1251                 pinfo->vtoc.v_part[index].p_start = val1 * (nhead * nsect);
1252                 pinfo->vtoc.v_part[index].p_size = val2;
1253 
1254                 if (val2 == 0) {
1255                         pinfo->vtoc.v_part[index].p_tag = 0;
1256                         pinfo->vtoc.v_part[index].p_flag = 0;
1257                         pinfo->vtoc.v_part[index].p_start = 0;
1258                         pinfo->pinfo_map[index].dkl_cylno = 0;
1259                 }
1260 #endif /* defined(_SUNOS_VTOC_16) */
1261 
1262         }
1263         /*
1264          * Check to be sure that all necessary attributes were defined.
1265          */
1266         if ((flags & SUP_MIN_PART) != SUP_MIN_PART) {
1267                 datafile_error("Incomplete specification", "");
1268                 return;
1269         }
1270         /*
1271          * Add this partition map to the list of known maps for the
1272          * specified disk/ctlr.
1273          */
1274         parts = dtype->dtype_plist;
1275         if (parts == NULL)
1276                 dtype->dtype_plist = pinfo;
1277         else {
1278                 while (parts->pinfo_next != NULL)
1279                         parts = parts->pinfo_next;
1280                 parts->pinfo_next = pinfo;
1281         }
1282 }
1283 
1284 /*
1285  * Open the disk device - just a wrapper for open.
1286  */
1287 int
1288 open_disk(char *diskname, int flags)
1289 {
1290         return (open(diskname, flags));
1291 }
1292 
1293 /*
1294  * This routine performs the disk search during startup.  It looks for
1295  * all the disks in the search path, and creates a list of those that
1296  * are found.
1297  */
1298 void
1299 do_search(char *arglist[])
1300 {
1301         char                    **sp;
1302         DIR                     *dir;
1303         struct dirent           *dp;
1304         char                    s[MAXPATHLEN];
1305         char                    path[MAXPATHLEN];
1306         char                    curdir[MAXPATHLEN];
1307         char                    *directory = "/dev/rdsk";
1308         struct disk_info        *disk;
1309         int                     i;
1310 
1311         /*
1312          * Change directory to the device directory.  This
1313          * gives us the most efficient access to that directory.
1314          * Remember where we were, and return there when finished.
1315          */
1316         if (getcwd(curdir, sizeof (curdir)) == NULL) {
1317                 err_print("Cannot get current directory - %s\n",
1318                     strerror(errno));
1319                 fullabort();
1320         }
1321         if (chdir(directory) == -1) {
1322                 err_print("Cannot set directory to %s - %s\n",
1323                     directory, strerror(errno));
1324                 fullabort();
1325         }
1326 
1327         /*
1328          * If there were disks specified on the command line,
1329          * use those disks, and nothing but those disks.
1330          */
1331         if (arglist != NULL) {
1332                 check_for_duplicate_disknames(arglist);
1333                 for (; *arglist != NULL; arglist++) {
1334                         search_for_logical_dev(*arglist);
1335                 }
1336         } else {
1337                 /*
1338                  * If there were no disks specified on the command line,
1339                  * search for all disks attached to the system.
1340                  */
1341                 fmt_print("Searching for disks...");
1342                 (void) fflush(stdout);
1343                 need_newline = 1;
1344 
1345                 /*
1346                  * Find all disks specified in search_path definitions
1347                  * in whatever format.dat files were processed.
1348                  */
1349                 sp = search_path;
1350                 if (sp != NULL) {
1351                         while (*sp != NULL) {
1352                                 search_for_logical_dev(*sp++);
1353                         }
1354                 }
1355 
1356                 /*
1357                  * Open the device directory
1358                  */
1359                 if ((dir = opendir(".")) == NULL) {
1360                         err_print("Cannot open %s - %s\n",
1361                             directory, strerror(errno));
1362                         fullabort();
1363                 }
1364 
1365                 /*
1366                  * Now find all usable nodes in /dev/rdsk (or /dev, if 4.x)
1367                  * First find all nodes which do not conform to
1368                  * standard disk naming conventions.  This permits
1369                  * all user-defined names to override the default names.
1370                  */
1371                 while ((dp = readdir(dir)) != NULL) {
1372                         if (strcmp(dp->d_name, ".") == 0 ||
1373                             strcmp(dp->d_name, "..") == 0)
1374                                 continue;
1375                         if (!conventional_name(dp->d_name)) {
1376                                 if (!fdisk_physical_name(dp->d_name)) {
1377                                         /*
1378                                          * If non-conventional name represents
1379                                          * a link to non-s2 slice , ignore it.
1380                                          */
1381                                         if (!name_represents_wholedisk
1382                                             (dp->d_name)) {
1383                                                 (void) strcpy(path, directory);
1384                                                 (void) strcat(path, "/");
1385                                                 (void) strcat(path, dp->d_name);
1386                                                 add_device_to_disklist(
1387                                                     dp->d_name, path);
1388                                         }
1389                                 }
1390                         }
1391                 }
1392                 rewinddir(dir);
1393 
1394 
1395                 /*
1396                  * Now find all nodes corresponding to the standard
1397                  * device naming conventions.
1398                  */
1399                 while ((dp = readdir(dir)) != NULL) {
1400                         if (strcmp(dp->d_name, ".") == 0 ||
1401                             strcmp(dp->d_name, "..") == 0)
1402                                 continue;
1403                         if (whole_disk_name(dp->d_name)) {
1404                                 (void) strcpy(path, directory);
1405                                 (void) strcat(path, "/");
1406                                 (void) strcat(path, dp->d_name);
1407                                 canonicalize_name(s, dp->d_name);
1408                                 add_device_to_disklist(s, path);
1409                         }
1410                 }
1411                 /*
1412                  * Close the directory
1413                  */
1414                 if (closedir(dir) == -1) {
1415                         err_print("Cannot close directory %s - %s\n",
1416                             directory, strerror(errno));
1417                         fullabort();
1418                 }
1419 
1420                 need_newline = 0;
1421                 fmt_print("done\n");
1422         }
1423 
1424         /*
1425          * Return to whence we came
1426          */
1427         if (chdir(curdir) == -1) {
1428                 err_print("Cannot set directory to %s - %s\n",
1429                     curdir, strerror(errno));
1430                 fullabort();
1431         }
1432 
1433         /*
1434          * If we didn't find any disks, give up.
1435          */
1436         if (disk_list == NULL) {
1437                 if (geteuid() == 0) {
1438                         err_print("No disks found!\n");
1439                 } else {
1440                         err_print("No permission (or no disks found)!\n");
1441                 }
1442                 (void) fflush(stdout);
1443                 fullabort();
1444         }
1445 
1446         sort_disk_list();
1447 
1448         /*
1449          * Tell user the results of the auto-configure process
1450          */
1451         i = 0;
1452         for (disk = disk_list; disk != NULL; disk = disk->disk_next) {
1453                 float                   scaled;
1454                 diskaddr_t              nblks;
1455                 struct disk_type        *type;
1456                 if (disk->disk_flags & DSK_AUTO_CONFIG) {
1457                         if (i++ == 0) {
1458                                 fmt_print("\n");
1459                         }
1460                         fmt_print("%s: ", disk->disk_name);
1461                         if (disk->disk_flags & DSK_LABEL_DIRTY) {
1462                                 fmt_print("configured ");
1463                         } else {
1464                                 fmt_print("configured and labeled ");
1465                         }
1466                         type = disk->disk_type;
1467                         nblks = type->dtype_ncyl * type->dtype_nhead *
1468                             type->dtype_nsect;
1469                         if (disk->label_type == L_TYPE_SOLARIS)
1470                                 scaled = bn2mb(nblks);
1471                         else
1472                                 scaled = bn2mb(type->capacity);
1473                         fmt_print("with capacity of ");
1474                         if (scaled > 1024.0) {
1475                                 fmt_print("%1.2fGB\n", scaled/1024.0);
1476                         } else {
1477                                 fmt_print("%1.2fMB\n", scaled);
1478                         }
1479                 }
1480         }
1481 }
1482 
1483 
1484 /*
1485  * For a given "logical" disk name as specified in a format.dat
1486  * search path, try to find the device it actually refers to.
1487  * Since we are trying to maintain 4.x naming convention
1488  * compatibility in 5.0, this involves a little bit of work.
1489  * We also want to be able to function under 4.x, if needed.
1490  *
1491  * canonical:   standard name reference.  append a partition
1492  *      reference, and open that file in the device directory.
1493  *      examples:       SVR4:   c0t0d0
1494  *                      4.x:    sd0
1495  *
1496  * absolute:    begins with a '/', and is assumed to be an
1497  *      absolute pathname to some node.
1498  *
1499  * relative:    non-canonical, doesn't begin with a '/'.
1500  *      assumed to be the name of a file in the appropriate
1501  *      device directory.
1502  */
1503 static void
1504 search_for_logical_dev(char *devname)
1505 {
1506         char            path[MAXPATHLEN];
1507         char            *directory = "/dev/rdsk/";
1508         char            *partition = "s2";
1509 
1510         /*
1511          * If the name is an absolute path name, accept it as is
1512          */
1513         if (*devname == '/') {
1514                 (void) strcpy(path, devname);
1515         } else if (canonical_name(devname)) {
1516                 /*
1517                  * If canonical name, construct a standard path name.
1518                  */
1519                 (void) strcpy(path, directory);
1520                 (void) strcat(path, devname);
1521                 (void) strcat(path, partition);
1522         } else if (canonical4x_name(devname)) {
1523                 /*
1524                  * Check to see if it's a 4.x file name in the /dev
1525                  * directory on 5.0.  Here, we only accept the
1526                  * canonicalized form: sd0.
1527                  */
1528                 (void) strcpy(path, "/dev/r");
1529                 (void) strcat(path, devname);
1530                 (void) strcat(path, "c");
1531         } else {
1532                 /*
1533                  * If it's not a canonical name, then it may be a
1534                  * reference to an actual file name in the device
1535                  * directory itself.
1536                  */
1537                 (void) strcpy(path, directory);
1538                 (void) strcat(path, devname);
1539         }
1540 
1541         /* now add the device */
1542         add_device_to_disklist(devname, path);
1543 }
1544 
1545 /*
1546  * Get the disk name from the inquiry data
1547  */
1548 static void
1549 get_disk_name(int fd, char *disk_name)
1550 {
1551         struct scsi_inquiry     inquiry;
1552 
1553         if (uscsi_inquiry(fd, (char *)&inquiry, sizeof (inquiry))) {
1554                 if (option_msg)
1555                         err_print("\nInquiry failed - %s\n", strerror(errno));
1556                 (void) strcpy(disk_name, "Unknown-Unknown-0001");
1557                 return;
1558         }
1559 
1560         (void) get_generic_disk_name(disk_name, &inquiry);
1561 }
1562 
1563 /*
1564  * Add a device to the disk list, if it appears to be a disk,
1565  * and we haven't already found it under some other name.
1566  */
1567 static void
1568 add_device_to_disklist(char *devname, char *devpath)
1569 {
1570         struct disk_info        *search_disk;
1571         struct ctlr_info        *search_ctlr;
1572         struct disk_type        *search_dtype, *efi_disk;
1573         struct partition_info   *search_parts;
1574         struct disk_info        *dptr;
1575         struct ctlr_info        *cptr;
1576         struct disk_type        *type;
1577         struct partition_info   *parts;
1578         struct dk_label         search_label;
1579         struct dk_cinfo         dkinfo;
1580         struct stat             stbuf;
1581         struct ctlr_type        *ctlr, *tctlr;
1582         struct  mctlr_list      *mlp;
1583         struct  efi_info        efi_info;
1584         struct dk_minfo         mediainfo;
1585         int                     search_file;
1586         int                     status;
1587         int                     i;
1588         int                     access_flags = 0;
1589         char                    disk_name[MAXNAMELEN];
1590 
1591         /*
1592          * Attempt to open the disk.  If it fails, skip it.
1593          */
1594         if ((search_file = open_disk(devpath, O_RDWR | O_NDELAY)) < 0) {
1595                 return;
1596         }
1597         /*
1598          * Must be a character device
1599          */
1600         if (fstat(search_file, &stbuf) == -1 || !S_ISCHR(stbuf.st_mode)) {
1601                 (void) close(search_file);
1602                 return;
1603         }
1604         /*
1605          * Attempt to read the configuration info on the disk.
1606          * Again, if it fails, we assume the disk's not there.
1607          * Note we must close the file for the disk before we
1608          * continue.
1609          */
1610         if (ioctl(search_file, DKIOCINFO, &dkinfo) < 0) {
1611                 (void) close(search_file);
1612                 return;
1613         }
1614 
1615         /* If it is a removable media, skip it. */
1616 
1617         if (!expert_mode) {
1618                 int isremovable, ret;
1619                 ret = ioctl(search_file, DKIOCREMOVABLE, &isremovable);
1620                 if ((ret >= 0) && (isremovable != 0)) {
1621                         (void) close(search_file);
1622                         return;
1623                 }
1624         }
1625 
1626         if (ioctl(search_file, DKIOCGMEDIAINFO, &mediainfo) == -1) {
1627                 cur_blksz = DEV_BSIZE;
1628         } else {
1629                 cur_blksz = mediainfo.dki_lbsize;
1630         }
1631 
1632         /*
1633          * If the type of disk is one we don't know about,
1634          * add it to the list.
1635          */
1636         mlp = controlp;
1637 
1638         while (mlp != NULL) {
1639                 if (mlp->ctlr_type->ctype_ctype == dkinfo.dki_ctype) {
1640                         break;
1641                 }
1642                 mlp = mlp->next;
1643         }
1644 
1645         if (mlp == NULL) {
1646                 if (dkinfo.dki_ctype == DKC_CDROM) {
1647                         if (ioctl(search_file, DKIOCGMEDIAINFO,
1648                             &mediainfo) < 0) {
1649                                 mediainfo.dki_media_type = DK_UNKNOWN;
1650                         }
1651                 }
1652                 /*
1653                  * Skip CDROM devices, they are read only.
1654                  * But not devices like Iomega Rev Drive which
1655                  * identifies itself as a CDROM, but has a removable
1656                  * disk.
1657                  */
1658                 if ((dkinfo.dki_ctype == DKC_CDROM) &&
1659                     (mediainfo.dki_media_type != DK_REMOVABLE_DISK)) {
1660                         (void) close(search_file);
1661                         return;
1662                 }
1663                 /*
1664                  * create the new ctlr_type structure and fill it in.
1665                  */
1666                 tctlr = zalloc(sizeof (struct ctlr_type));
1667                 tctlr->ctype_ctype = dkinfo.dki_ctype;
1668                 tctlr->ctype_name = zalloc(DK_DEVLEN);
1669                 if (strlcpy(tctlr->ctype_name, dkinfo.dki_cname,
1670                     DK_DEVLEN) > DK_DEVLEN) {
1671                         /*
1672                          * DKIOCINFO returned a controller name longer
1673                          * than DK_DEVLEN bytes, which means more of the
1674                          * dk_cinfo structure may be corrupt.  We don't
1675                          * allow the user to perform any operations on
1676                          * the device in this case
1677                          */
1678                         err_print("\nError: Device %s: controller "
1679                             "name (%s)\nis invalid.  Device will not "
1680                             "be displayed.\n", devname, dkinfo.dki_cname);
1681                         (void) close(search_file);
1682                         destroy_data(tctlr->ctype_name);
1683                         destroy_data((char *)tctlr);
1684                         return;
1685                 } else {
1686                         tctlr->ctype_ops = zalloc(sizeof (struct ctlr_ops));
1687 
1688                         /*
1689                          * copy the generic disk ops structure into local copy.
1690                          */
1691                         *(tctlr->ctype_ops) = genericops;
1692 
1693                         tctlr->ctype_flags = CF_WLIST;
1694 
1695                         mlp = controlp;
1696 
1697                         while (mlp->next != NULL) {
1698                                 mlp = mlp->next;
1699                         }
1700 
1701                         mlp->next = zalloc(sizeof (struct mctlr_list));
1702                         mlp->next->ctlr_type = tctlr;
1703                 }
1704         }
1705 
1706         /*
1707          * Search through all disks known at this time, to
1708          * determine if we're already identified this disk.
1709          * If so, then there's no need to include it a
1710          * second time.  This permits the user-defined names
1711          * to supercede the standard conventional names.
1712          */
1713         if (disk_is_known(&dkinfo)) {
1714                 (void) close(search_file);
1715                 return;
1716         }
1717 #if defined(sparc)
1718         /*
1719          * Because opening id with FNDELAY always succeeds,
1720          * read the label early on to see whether the device
1721          * really exists.  A result of DSK_RESERVED
1722          * means the disk may be reserved.
1723          * In the future, it will be good
1724          * to move these into controller specific files and have a common
1725          * generic check for reserved disks here, including intel disks.
1726          */
1727         if (dkinfo.dki_ctype == DKC_SCSI_CCS) {
1728                 char    *first_sector;
1729 
1730                 first_sector = zalloc(cur_blksz);
1731                 i = scsi_rdwr(DIR_READ, search_file, (diskaddr_t)0,
1732                     1, first_sector, F_SILENT, NULL);
1733                 switch (i) {
1734                 case DSK_RESERVED:
1735                         access_flags |= DSK_RESERVED;
1736                         break;
1737                 case DSK_UNAVAILABLE:
1738                         access_flags |= DSK_UNAVAILABLE;
1739                         break;
1740                 default:
1741                         break;
1742                 }
1743                 free(first_sector);
1744         }
1745 #endif /* defined(sparc) */
1746 
1747         /*
1748          * The disk appears to be present.  Allocate space for the
1749          * disk structure and add it to the list of found disks.
1750          */
1751         search_disk = (struct disk_info *)zalloc(sizeof (struct disk_info));
1752         if (disk_list == NULL)
1753                 disk_list = search_disk;
1754         else {
1755                 for (dptr = disk_list; dptr->disk_next != NULL;
1756                     dptr = dptr->disk_next)
1757                         ;
1758                 dptr->disk_next = search_disk;
1759         }
1760         /*
1761          * Fill in some info from the ioctls.
1762          */
1763         search_disk->disk_dkinfo = dkinfo;
1764         if (is_efi_type(search_file)) {
1765                 search_disk->label_type = L_TYPE_EFI;
1766         } else {
1767                 search_disk->label_type = L_TYPE_SOLARIS;
1768         }
1769         /*
1770          * Remember the names of the disk
1771          */
1772         search_disk->disk_name = alloc_string(devname);
1773         search_disk->disk_path = alloc_string(devpath);
1774 
1775         /*
1776          * Remember the lba size of the disk
1777          */
1778         search_disk->disk_lbasize = cur_blksz;
1779 
1780         (void) strcpy(x86_devname, devname);
1781 
1782         /*
1783          * Determine if this device is linked to a physical name.
1784          */
1785         search_disk->devfs_name = get_physical_name(devpath);
1786 
1787         /*
1788          * Try to match the ctlr for this disk with a ctlr we
1789          * have already found.  A match is assumed if the ctlrs
1790          * are at the same address && ctypes agree
1791          */
1792         for (search_ctlr = ctlr_list; search_ctlr != NULL;
1793             search_ctlr = search_ctlr->ctlr_next)
1794                 if (search_ctlr->ctlr_addr == dkinfo.dki_addr &&
1795                     search_ctlr->ctlr_space == dkinfo.dki_space &&
1796                     search_ctlr->ctlr_ctype->ctype_ctype ==
1797                     dkinfo.dki_ctype)
1798                         break;
1799         /*
1800          * If no match was found, we need to identify this ctlr.
1801          */
1802         if (search_ctlr == NULL) {
1803                 /*
1804                  * Match the type of the ctlr to a known type.
1805                  */
1806                 mlp = controlp;
1807 
1808                 while (mlp != NULL) {
1809                         if (mlp->ctlr_type->ctype_ctype == dkinfo.dki_ctype)
1810                                 break;
1811                         mlp = mlp->next;
1812                 }
1813                 /*
1814                  * If no match was found, it's an error.
1815                  * Close the disk and report the error.
1816                  */
1817                 if (mlp == NULL) {
1818                         err_print("\nError: found disk attached to ");
1819                         err_print("unsupported controller type '%d'.\n",
1820                             dkinfo.dki_ctype);
1821                         (void) close(search_file);
1822                         return;
1823                 }
1824                 /*
1825                  * Allocate space for the ctlr structure and add it
1826                  * to the list of found ctlrs.
1827                  */
1828                 search_ctlr = (struct ctlr_info *)
1829                     zalloc(sizeof (struct ctlr_info));
1830                 search_ctlr->ctlr_ctype = mlp->ctlr_type;
1831                 if (ctlr_list == NULL)
1832                         ctlr_list = search_ctlr;
1833                 else {
1834                         for (cptr = ctlr_list; cptr->ctlr_next != NULL;
1835                             cptr = cptr->ctlr_next)
1836                                 ;
1837                         cptr->ctlr_next = search_ctlr;
1838                 }
1839                 /*
1840                  * Fill in info from the ioctl.
1841                  */
1842                 for (i = 0; i < DK_DEVLEN; i++) {
1843                         search_ctlr->ctlr_cname[i] = dkinfo.dki_cname[i];
1844                         search_ctlr->ctlr_dname[i] = dkinfo.dki_dname[i];
1845                 }
1846                 /*
1847                  * Make sure these can be used as simple strings
1848                  */
1849                 search_ctlr->ctlr_cname[i] = 0;
1850                 search_ctlr->ctlr_dname[i] = 0;
1851 
1852                 search_ctlr->ctlr_flags = dkinfo.dki_flags;
1853                 search_ctlr->ctlr_num = dkinfo.dki_cnum;
1854                 search_ctlr->ctlr_addr = dkinfo.dki_addr;
1855                 search_ctlr->ctlr_space = dkinfo.dki_space;
1856                 search_ctlr->ctlr_prio = dkinfo.dki_prio;
1857                 search_ctlr->ctlr_vec = dkinfo.dki_vec;
1858         }
1859         /*
1860          * By this point, we have a known ctlr.  Link the disk
1861          * to the ctlr.
1862          */
1863         search_disk->disk_ctlr = search_ctlr;
1864         if (access_flags & (DSK_RESERVED | DSK_UNAVAILABLE)) {
1865                 if (access_flags & DSK_RESERVED)
1866                         search_disk->disk_flags |= DSK_RESERVED;
1867                 else
1868                         search_disk->disk_flags |= DSK_UNAVAILABLE;
1869                 (void) close(search_file);
1870                 return;
1871         } else {
1872                 search_disk->disk_flags &= ~(DSK_RESERVED | DSK_UNAVAILABLE);
1873         }
1874 
1875         /*
1876          * Attempt to read the primary label.
1877          * (Note that this is really through the DKIOCGVTOC
1878          * ioctl, then converted from vtoc to label.)
1879          */
1880         if (search_disk->label_type == L_TYPE_SOLARIS) {
1881                 status = read_label(search_file, &search_label);
1882         } else {
1883                 status = read_efi_label(search_file, &efi_info);
1884         }
1885         /*
1886          * If reading the label failed, and this is a SCSI
1887          * disk, we can attempt to auto-sense the disk
1888          * Configuration.
1889          */
1890         ctlr = search_ctlr->ctlr_ctype;
1891         if ((status == -1) && (ctlr->ctype_ctype == DKC_SCSI_CCS)) {
1892                 if (option_msg && diag_msg) {
1893                         err_print("%s: attempting auto configuration\n",
1894                             search_disk->disk_name);
1895                 }
1896 
1897                 switch (search_disk->label_type) {
1898                 case (L_TYPE_SOLARIS):
1899                         if (auto_sense(search_file, 0, &search_label) != NULL) {
1900                         /*
1901                          * Auto config worked, so we now have
1902                          * a valid label for the disk.  Mark
1903                          * the disk as needing the label flushed.
1904                          */
1905                                 status = 0;
1906                                 search_disk->disk_flags |=
1907                                     (DSK_LABEL_DIRTY | DSK_AUTO_CONFIG);
1908                         }
1909                         break;
1910                 case (L_TYPE_EFI):
1911                         efi_disk = auto_efi_sense(search_file, &efi_info);
1912                         if (efi_disk != NULL) {
1913                                 /*
1914                                  * Auto config worked, so we now have
1915                                  * a valid label for the disk.
1916                                  */
1917                                 status = 0;
1918                                 search_disk->disk_flags |=
1919                                     (DSK_LABEL_DIRTY | DSK_AUTO_CONFIG);
1920                         }
1921                         break;
1922                 default:
1923                         /* Should never happen */
1924                         break;
1925                 }
1926         }
1927 
1928         /*
1929          * If we didn't successfully read the label, or the label
1930          * appears corrupt, just leave the disk as an unknown type.
1931          */
1932         if (status == -1) {
1933                 (void) close(search_file);
1934                 return;
1935         }
1936 
1937         if (search_disk->label_type == L_TYPE_SOLARIS) {
1938                 if (!checklabel(&search_label)) {
1939                         (void) close(search_file);
1940                         return;
1941                 }
1942                 if (trim_id(search_label.dkl_asciilabel)) {
1943                         (void) close(search_file);
1944                         return;
1945                 }
1946         }
1947         /*
1948          * The label looks ok.  Mark the disk as labeled.
1949          */
1950         search_disk->disk_flags |= DSK_LABEL;
1951 
1952         if (search_disk->label_type == L_TYPE_EFI) {
1953                 search_dtype = (struct disk_type *)
1954                     zalloc(sizeof (struct disk_type));
1955                 type = search_ctlr->ctlr_ctype->ctype_dlist;
1956                 if (type == NULL) {
1957                         search_ctlr->ctlr_ctype->ctype_dlist =
1958                             search_dtype;
1959                 } else {
1960                         while (type->dtype_next != NULL) {
1961                                 type = type->dtype_next;
1962                         }
1963                         type->dtype_next = search_dtype;
1964                 }
1965                 search_dtype->dtype_next = NULL;
1966 
1967                 (void) strlcpy(search_dtype->vendor, efi_info.vendor, 9);
1968                 (void) strlcpy(search_dtype->product, efi_info.product, 17);
1969                 (void) strlcpy(search_dtype->revision, efi_info.revision, 5);
1970                 search_dtype->capacity = efi_info.capacity;
1971                 search_disk->disk_type = search_dtype;
1972 
1973                 search_parts = (struct partition_info *)
1974                     zalloc(sizeof (struct partition_info));
1975                 search_dtype->dtype_plist = search_parts;
1976 
1977                 search_parts->pinfo_name = alloc_string("original");
1978                 search_parts->pinfo_next = NULL;
1979                 search_parts->etoc = efi_info.e_parts;
1980                 search_disk->disk_parts = search_parts;
1981 
1982                 /*
1983                  * Copy the volume name, if present
1984                  */
1985                 for (i = 0; i < search_parts->etoc->efi_nparts; i++) {
1986                         if (search_parts->etoc->efi_parts[i].p_tag ==
1987                             V_RESERVED) {
1988                                 if (search_parts->etoc->efi_parts[i].p_name) {
1989                                         bcopy(search_parts->etoc->efi_parts[i]
1990                                             .p_name, search_disk->v_volume,
1991                                             LEN_DKL_VVOL);
1992                                 } else {
1993                                         bzero(search_disk->v_volume,
1994                                             LEN_DKL_VVOL);
1995                                 }
1996                                 break;
1997                         }
1998                 }
1999                 (void) close(search_file);
2000                 return;
2001         }
2002 
2003         /*
2004          * Attempt to match the disk type in the label with a
2005          * known disk type.
2006          */
2007         for (search_dtype = search_ctlr->ctlr_ctype->ctype_dlist;
2008             search_dtype != NULL;
2009             search_dtype = search_dtype->dtype_next)
2010                 if (dtype_match(&search_label, search_dtype))
2011                         break;
2012         /*
2013          * If no match was found, we need to create a disk type
2014          * for this disk.
2015          */
2016         if (search_dtype == NULL) {
2017                 /*
2018                  * Allocate space for the disk type and add it
2019                  * to the list of disk types for this ctlr type.
2020                  */
2021                 search_dtype = (struct disk_type *)
2022                     zalloc(sizeof (struct disk_type));
2023                 type = search_ctlr->ctlr_ctype->ctype_dlist;
2024                 if (type == NULL)
2025                         search_ctlr->ctlr_ctype->ctype_dlist =
2026                             search_dtype;
2027                 else {
2028                         while (type->dtype_next != NULL)
2029                                 type = type->dtype_next;
2030                         type->dtype_next = search_dtype;
2031                 }
2032                 /*
2033                  * Fill in the drive info from the disk label.
2034                  */
2035                 search_dtype->dtype_next = NULL;
2036                 if (strncmp(search_label.dkl_asciilabel, "DEFAULT",
2037                     strlen("DEFAULT")) == 0) {
2038                         (void) get_disk_name(search_file, disk_name);
2039                         search_dtype->dtype_asciilabel = (char *)
2040                             zalloc(strlen(disk_name) + 1);
2041                         (void) strcpy(search_dtype->dtype_asciilabel,
2042                             disk_name);
2043                 } else {
2044                         search_dtype->dtype_asciilabel = (char *)
2045                             zalloc(strlen(search_label.dkl_asciilabel) + 1);
2046                         (void) strcpy(search_dtype->dtype_asciilabel,
2047                             search_label.dkl_asciilabel);
2048                 }
2049                 search_dtype->dtype_pcyl = search_label.dkl_pcyl;
2050                 search_dtype->dtype_ncyl = search_label.dkl_ncyl;
2051                 search_dtype->dtype_acyl = search_label.dkl_acyl;
2052                 search_dtype->dtype_nhead = search_label.dkl_nhead;
2053                 search_dtype->dtype_nsect = search_label.dkl_nsect;
2054                 search_dtype->dtype_rpm = search_label.dkl_rpm;
2055                 /*
2056                  * Mark the disk as needing specification of
2057                  * ctlr specific attributes.  This is necessary
2058                  * because the label doesn't contain these attributes,
2059                  * and they aren't known at this point.  They will
2060                  * be asked for if this disk is ever selected by
2061                  * the user.
2062                  * Note: for SCSI, we believe the label.
2063                  */
2064                 if ((search_ctlr->ctlr_ctype->ctype_ctype != DKC_SCSI_CCS) &&
2065                     (search_ctlr->ctlr_ctype->ctype_ctype != DKC_DIRECT) &&
2066                     (search_ctlr->ctlr_ctype->ctype_ctype != DKC_VBD) &&
2067                     (search_ctlr->ctlr_ctype->ctype_ctype != DKC_PCMCIA_ATA)) {
2068                         search_dtype->dtype_flags |= DT_NEED_SPEFS;
2069                 }
2070         }
2071         /*
2072          * By this time we have a known disk type.  Link the disk
2073          * to the disk type.
2074          */
2075         search_disk->disk_type = search_dtype;
2076 
2077         /*
2078          * Close the file for this disk
2079          */
2080         (void) close(search_file);
2081 
2082         /*
2083          * Attempt to match the partition map in the label with
2084          * a known partition map for this disk type.
2085          */
2086         for (search_parts = search_dtype->dtype_plist;
2087             search_parts != NULL;
2088             search_parts = search_parts->pinfo_next)
2089                 if (parts_match(&search_label, search_parts)) {
2090                         break;
2091                 }
2092         /*
2093          * If no match was made, we need to create a partition
2094          * map for this disk.
2095          */
2096         if (search_parts == NULL) {
2097                 /*
2098                  * Allocate space for the partition map and add
2099                  * it to the list of maps for this disk type.
2100                  */
2101                 search_parts = (struct partition_info *)
2102                     zalloc(sizeof (struct partition_info));
2103                 parts = search_dtype->dtype_plist;
2104                 if (parts == NULL)
2105                         search_dtype->dtype_plist = search_parts;
2106                 else {
2107                         while (parts->pinfo_next != NULL)
2108                                 parts = parts->pinfo_next;
2109                         parts->pinfo_next = search_parts;
2110                 }
2111                 search_parts->pinfo_next = NULL;
2112                 /*
2113                  * Fill in the name of the map with a name derived
2114                  * from the name of this disk.  This is necessary
2115                  * because the label contains no name for the
2116                  * partition map.
2117                  */
2118                 search_parts->pinfo_name = alloc_string("original");
2119                 /*
2120                  * Fill in the partition info from the disk label.
2121                  */
2122                 for (i = 0; i < NDKMAP; i++) {
2123 
2124 #if defined(_SUNOS_VTOC_8)
2125                         search_parts->pinfo_map[i] =
2126                             search_label.dkl_map[i];
2127 
2128 #elif defined(_SUNOS_VTOC_16)
2129                         search_parts->pinfo_map[i].dkl_cylno =
2130                             search_label.dkl_vtoc.v_part[i].p_start /
2131                             ((blkaddr32_t)(search_label.dkl_nhead *
2132                             search_label.dkl_nsect));
2133                         search_parts->pinfo_map[i].dkl_nblk =
2134                             search_label.dkl_vtoc.v_part[i].p_size;
2135 
2136 #else
2137 #error No VTOC format defined.
2138 #endif
2139                 }
2140         }
2141         /*
2142          * If the vtoc looks valid, copy the volume name and vtoc
2143          * info from the label.  Otherwise, install a default vtoc.
2144          * This permits vtoc info to automatically appear in the sun
2145          * label, without requiring an upgrade procedure.
2146          */
2147         if (search_label.dkl_vtoc.v_version == V_VERSION) {
2148                 bcopy(search_label.dkl_vtoc.v_volume,
2149                     search_disk->v_volume, LEN_DKL_VVOL);
2150                 search_parts->vtoc = search_label.dkl_vtoc;
2151         } else {
2152                 bzero(search_disk->v_volume, LEN_DKL_VVOL);
2153                 set_vtoc_defaults(search_parts);
2154         }
2155         /*
2156          * By this time we have a known partitition map.  Link the
2157          * disk to the partition map.
2158          */
2159         search_disk->disk_parts = search_parts;
2160 }
2161 
2162 
2163 /*
2164  * Search the disk list for a disk with the identical configuration.
2165  * Return true if one is found.
2166  */
2167 static int
2168 disk_is_known(struct dk_cinfo *dkinfo)
2169 {
2170         struct disk_info        *dp;
2171 
2172         dp = disk_list;
2173         while (dp != NULL) {
2174                 if (dp->disk_dkinfo.dki_ctype == dkinfo->dki_ctype &&
2175                     dp->disk_dkinfo.dki_cnum == dkinfo->dki_cnum &&
2176                     dp->disk_dkinfo.dki_unit == dkinfo->dki_unit &&
2177                     strcmp(dp->disk_dkinfo.dki_dname, dkinfo->dki_dname) == 0) {
2178                         return (1);
2179                 }
2180                 dp = dp->disk_next;
2181         }
2182         return (0);
2183 }
2184 
2185 
2186 /*
2187  * This routine checks to see if a given disk type matches the type
2188  * in the disk label.
2189  */
2190 int
2191 dtype_match(label, dtype)
2192         register struct dk_label *label;
2193         register struct disk_type *dtype;
2194 {
2195 
2196         if (dtype->dtype_asciilabel == NULL) {
2197             return (0);
2198         }
2199 
2200         /*
2201          * If the any of the physical characteristics are different, or
2202          * the name is different, it doesn't match.
2203          */
2204         if ((strcmp(label->dkl_asciilabel, dtype->dtype_asciilabel) != 0) ||
2205             (label->dkl_ncyl != dtype->dtype_ncyl) ||
2206             (label->dkl_acyl != dtype->dtype_acyl) ||
2207             (label->dkl_nhead != dtype->dtype_nhead) ||
2208             (label->dkl_nsect != dtype->dtype_nsect)) {
2209                 return (0);
2210         }
2211         /*
2212          * If those are all identical, assume it's a match.
2213          */
2214         return (1);
2215 }
2216 
2217 /*
2218  * This routine checks to see if a given partition map matches the map
2219  * in the disk label.
2220  */
2221 int
2222 parts_match(label, pinfo)
2223         register struct dk_label *label;
2224         register struct partition_info *pinfo;
2225 {
2226         int i;
2227 
2228         /*
2229          * If any of the partition entries is different, it doesn't match.
2230          */
2231         for (i = 0; i < NDKMAP; i++)
2232 
2233 #if defined(_SUNOS_VTOC_8)
2234                 if ((label->dkl_map[i].dkl_cylno !=
2235                     pinfo->pinfo_map[i].dkl_cylno) ||
2236                     (label->dkl_map[i].dkl_nblk !=
2237                     pinfo->pinfo_map[i].dkl_nblk))
2238 
2239 #elif defined(_SUNOS_VTOC_16)
2240                 if ((pinfo->pinfo_map[i].dkl_cylno !=
2241                     label->dkl_vtoc.v_part[i].p_start /
2242                     (label->dkl_nhead * label->dkl_nsect)) ||
2243                     (pinfo->pinfo_map[i].dkl_nblk !=
2244                     label->dkl_vtoc.v_part[i].p_size))
2245 #else
2246 #error No VTOC format defined.
2247 #endif
2248                         return (0);
2249         /*
2250          * Compare the vtoc information for a match
2251          * Do not require the volume name to be equal, for a match!
2252          */
2253         if (label->dkl_vtoc.v_version != pinfo->vtoc.v_version)
2254                 return (0);
2255         if (label->dkl_vtoc.v_nparts != pinfo->vtoc.v_nparts)
2256                 return (0);
2257         for (i = 0; i < NDKMAP; i++) {
2258                 if (label->dkl_vtoc.v_part[i].p_tag !=
2259                                 pinfo->vtoc.v_part[i].p_tag)
2260                         return (0);
2261                 if (label->dkl_vtoc.v_part[i].p_flag !=
2262                                 pinfo->vtoc.v_part[i].p_flag)
2263                         return (0);
2264         }
2265         /*
2266          * If they are all identical, it's a match.
2267          */
2268         return (1);
2269 }
2270 
2271 /*
2272  * This routine checks to see if the given disk name refers to the disk
2273  * in the given disk structure.
2274  */
2275 int
2276 diskname_match(char *name, struct disk_info *disk)
2277 {
2278         struct dk_cinfo         dkinfo;
2279         char                    s[MAXPATHLEN];
2280         int                     fd;
2281 
2282         /*
2283          * Match the name of the disk in the disk_info structure
2284          */
2285         if (strcmp(name, disk->disk_name) == 0) {
2286                 return (1);
2287         }
2288 
2289         /*
2290          * Check to see if it's a 4.x file name in the /dev
2291          * directory on 5.0.  Here, we only accept the
2292          * canonicalized form: sd0.
2293          */
2294         if (canonical4x_name(name) == 0) {
2295                 return (0);
2296         }
2297 
2298         (void) strcpy(s, "/dev/r");
2299         (void) strcat(s, name);
2300         (void) strcat(s, "c");
2301 
2302         if ((fd = open_disk(s, O_RDWR | O_NDELAY)) < 0) {
2303                 return (0);
2304         }
2305 
2306         if (ioctl(fd, DKIOCINFO, &dkinfo) < 0) {
2307                 (void) close(fd);
2308                 return (0);
2309         }
2310         (void) close(fd);
2311 
2312         if (disk->disk_dkinfo.dki_ctype == dkinfo.dki_ctype &&
2313             disk->disk_dkinfo.dki_cnum == dkinfo.dki_cnum &&
2314             disk->disk_dkinfo.dki_unit == dkinfo.dki_unit &&
2315             strcmp(disk->disk_dkinfo.dki_dname, dkinfo.dki_dname) == 0) {
2316                 return (1);
2317         }
2318         return (0);
2319 }
2320 
2321 
2322 static void
2323 datafile_error(char *errmsg, char *token)
2324 {
2325         int     token_type;
2326         TOKEN   token_buf;
2327 
2328         /*
2329          * Allow us to get by controllers that the other platforms don't
2330          * know about.
2331          */
2332         if (errmsg != NULL) {
2333                 err_print(errmsg, token);
2334                 err_print(" - %s (%d)\n", file_name, data_lineno);
2335         }
2336 
2337         /*
2338          * Re-sync the parsing at the beginning of the next line
2339          * unless of course we're already there.
2340          */
2341         if (last_token_type != SUP_EOF && last_token_type != SUP_EOL) {
2342                 do {
2343                         token_type = sup_gettoken(token_buf);
2344                 } while (token_type != SUP_EOF && token_type != SUP_EOL);
2345 
2346                 if (token_type == SUP_EOF) {
2347                         sup_pushtoken(token_buf, token_type);
2348                 }
2349         }
2350 }
2351 
2352 
2353 /*
2354  * Search through all defined disk types for duplicate entries
2355  * that are inconsistent with each other.  Disks with different
2356  * characteristics should be named differently.
2357  * Note that this function only checks for duplicate disks
2358  * for the same controller.  It's possible to have two disks with
2359  * the same name, but defined for different controllers.
2360  * That may or may not be a problem...
2361  */
2362 static void
2363 search_duplicate_dtypes()
2364 {
2365         struct disk_type        *dp1;
2366         struct disk_type        *dp2;
2367         struct mctlr_list       *mlp;
2368 
2369         mlp = controlp;
2370 
2371         while (mlp != NULL) {
2372                 dp1 = mlp->ctlr_type->ctype_dlist;
2373                 while (dp1 != NULL) {
2374                         dp2 = dp1->dtype_next;
2375                         while (dp2 != NULL) {
2376                                 check_dtypes_for_inconsistency(dp1, dp2);
2377                                 dp2 = dp2->dtype_next;
2378                         }
2379                         dp1 = dp1->dtype_next;
2380                 }
2381         mlp = mlp->next;
2382         }
2383 }
2384 
2385 
2386 /*
2387  * Search through all defined partition types for duplicate entries
2388  * that are inconsistent with each other.  Partitions with different
2389  * characteristics should be named differently.
2390  * Note that this function only checks for duplicate partitions
2391  * for the same disk.  It's possible to have two partitions with
2392  * the same name, but defined for different disks.
2393  * That may or may not be a problem...
2394  */
2395 static void
2396 search_duplicate_pinfo()
2397 {
2398         struct disk_type        *dp;
2399         struct partition_info   *pp1;
2400         struct partition_info   *pp2;
2401         struct mctlr_list       *mlp;
2402 
2403         mlp = controlp;
2404 
2405         while (mlp != NULL) {
2406                 dp = mlp->ctlr_type->ctype_dlist;
2407                 while (dp != NULL) {
2408                         pp1 = dp->dtype_plist;
2409                         while (pp1 != NULL) {
2410                                 pp2 = pp1->pinfo_next;
2411                                 while (pp2 != NULL) {
2412                                         check_pinfo_for_inconsistency(pp1, pp2);
2413                                         pp2 = pp2->pinfo_next;
2414                                 }
2415                                 pp1 = pp1->pinfo_next;
2416                         }
2417                         dp = dp->dtype_next;
2418                 }
2419         mlp = mlp->next;
2420         }
2421 }
2422 
2423 
2424 /*
2425  * Determine if two particular disk definitions are inconsistent.
2426  * Ie:  same name, but different characteristics.
2427  * If so, print an error message and abort.
2428  */
2429 static void
2430 check_dtypes_for_inconsistency(dp1, dp2)
2431         struct disk_type        *dp1;
2432         struct disk_type        *dp2;
2433 {
2434         int             i;
2435         int             result;
2436         struct chg_list *cp1;
2437         struct chg_list *cp2;
2438 
2439 
2440         /*
2441          * If the name's different, we're ok
2442          */
2443         if (strcmp(dp1->dtype_asciilabel, dp2->dtype_asciilabel) != 0) {
2444                 return;
2445         }
2446 
2447         /*
2448          * Compare all the disks' characteristics
2449          */
2450         result = 0;
2451         result |= (dp1->dtype_flags != dp2->dtype_flags);
2452         result |= (dp1->dtype_options != dp2->dtype_options);
2453         result |= (dp1->dtype_fmt_time != dp2->dtype_fmt_time);
2454         result |= (dp1->dtype_bpt != dp2->dtype_bpt);
2455         result |= (dp1->dtype_ncyl != dp2->dtype_ncyl);
2456         result |= (dp1->dtype_acyl != dp2->dtype_acyl);
2457         result |= (dp1->dtype_pcyl != dp2->dtype_pcyl);
2458         result |= (dp1->dtype_nhead != dp2->dtype_nhead);
2459         result |= (dp1->dtype_nsect != dp2->dtype_nsect);
2460         result |= (dp1->dtype_rpm != dp2->dtype_rpm);
2461         result |= (dp1->dtype_cyl_skew != dp2->dtype_cyl_skew);
2462         result |= (dp1->dtype_trk_skew != dp2->dtype_trk_skew);
2463         result |= (dp1->dtype_trks_zone != dp2->dtype_trks_zone);
2464         result |= (dp1->dtype_atrks != dp2->dtype_atrks);
2465         result |= (dp1->dtype_asect != dp2->dtype_asect);
2466         result |= (dp1->dtype_cache != dp2->dtype_cache);
2467         result |= (dp1->dtype_threshold != dp2->dtype_threshold);
2468         result |= (dp1->dtype_read_retries != dp2->dtype_read_retries);
2469         result |= (dp1->dtype_write_retries != dp2->dtype_write_retries);
2470         result |= (dp1->dtype_prefetch_min != dp2->dtype_prefetch_min);
2471         result |= (dp1->dtype_prefetch_max != dp2->dtype_prefetch_max);
2472         for (i = 0; i < NSPECIFICS; i++) {
2473                 result |= (dp1->dtype_specifics[i] != dp2->dtype_specifics[i]);
2474         }
2475 
2476         cp1 = dp1->dtype_chglist;
2477         cp2 = dp2->dtype_chglist;
2478         while (cp1 != NULL && cp2 != NULL) {
2479                 if (cp1 == NULL || cp2 == NULL) {
2480                         result = 1;
2481                         break;
2482                 }
2483                 result |= (cp1->pageno != cp2->pageno);
2484                 result |= (cp1->byteno != cp2->byteno);
2485                 result |= (cp1->mode != cp2->mode);
2486                 result |= (cp1->value != cp2->value);
2487                 cp1 = cp1->next;
2488                 cp2 = cp2->next;
2489         }
2490 
2491         if (result) {
2492                 err_print("Inconsistent definitions for disk type '%s'\n",
2493                         dp1->dtype_asciilabel);
2494                 if (dp1->dtype_filename != NULL &&
2495                                         dp2->dtype_filename != NULL) {
2496                         err_print("%s (%d) - %s (%d)\n",
2497                                 dp1->dtype_filename, dp1->dtype_lineno,
2498                                 dp2->dtype_filename, dp2->dtype_lineno);
2499                         }
2500                 fullabort();
2501         }
2502 }
2503 
2504 
2505 /*
2506  * Determine if two particular partition definitions are inconsistent.
2507  * Ie:  same name, but different characteristics.
2508  * If so, print an error message and abort.
2509  */
2510 static void
2511 check_pinfo_for_inconsistency(pp1, pp2)
2512         struct partition_info   *pp1;
2513         struct partition_info   *pp2;
2514 {
2515         int             i;
2516         int             result;
2517         struct dk_map32 *map1;
2518         struct dk_map32 *map2;
2519 
2520 #if defined(_SUNOS_VTOC_8)
2521         struct dk_map2  *vp1;
2522         struct dk_map2  *vp2;
2523 
2524 #elif defined(_SUNOS_VTOC_16)
2525         struct dkl_partition    *vp1;
2526         struct dkl_partition    *vp2;
2527 #else
2528 #error No VTOC layout defined.
2529 #endif /* defined(_SUNOS_VTOC_8) */
2530 
2531         /*
2532          * If the name's different, we're ok
2533          */
2534         if (strcmp(pp1->pinfo_name, pp2->pinfo_name) != 0) {
2535                 return;
2536         }
2537 
2538         /*
2539          * Compare all the partitions' characteristics
2540          */
2541         result = 0;
2542         map1 = pp1->pinfo_map;
2543         map2 = pp2->pinfo_map;
2544         for (i = 0; i < NDKMAP; i++, map1++, map2++) {
2545                 result |= (map1->dkl_cylno != map2->dkl_cylno);
2546                 result |= (map1->dkl_nblk != map2->dkl_nblk);
2547         }
2548 
2549         /*
2550          * Compare the significant portions of the vtoc information
2551          */
2552         vp1 = pp1->vtoc.v_part;
2553         vp2 = pp2->vtoc.v_part;
2554         for (i = 0; i < NDKMAP; i++, vp1++, vp2++) {
2555                 result |= (vp1->p_tag != vp2->p_tag);
2556                 result |= (vp1->p_flag != vp2->p_flag);
2557         }
2558 
2559         if (result) {
2560                 err_print("Inconsistent definitions for partition type '%s'\n",
2561                         pp1->pinfo_name);
2562                 if (pp1->pinfo_filename != NULL &&
2563                                         pp2->pinfo_filename != NULL) {
2564                         err_print("%s (%d) - %s (%d)\n",
2565                                 pp1->pinfo_filename, pp1->pinfo_lineno,
2566                                 pp2->pinfo_filename, pp2->pinfo_lineno);
2567                         }
2568                 fullabort();
2569         }
2570 }
2571 
2572 /*
2573  * Convert a string of digits into a block number.
2574  * The digits are assumed to be a block number unless the
2575  * the string is terminated by 'c', in which case it is
2576  * assumed to be in units of cylinders.  Accept a 'b'
2577  * to explictly specify blocks, for consistency.
2578  *
2579  * NB: uses the macro spc(), which requires that the
2580  * globals nhead/nsect/acyl be set up correctly.
2581  *
2582  * Returns -1 in the case of an error.
2583  */
2584 static uint_t
2585 str2blks(char *str)
2586 {
2587         int     blks;
2588         char    *p;
2589 
2590         blks = (int)strtol(str, &p, 0);
2591         /*
2592          * Check what terminated the conversion.
2593          */
2594         if (*p != 0) {
2595                 /*
2596                  * Units specifier of 'c': convert cylinders to blocks
2597                  */
2598                 if (*p == 'c') {
2599                         p++;
2600                         blks = blks * spc();
2601                 /*
2602                  * Ignore a 'b' specifier.
2603                  */
2604                 } else if (*p == 'b') {
2605                         p++;
2606                 }
2607                 /*
2608                  * Anthing left over is an error
2609                  */
2610                 if (*p != 0) {
2611                         blks = -1;
2612                 }
2613         }
2614 
2615         return (blks);
2616 }
2617 /*
2618  * Convert a string of digits into a cylinder number.
2619  * Accept a an optional 'c' specifier, for consistency.
2620  *
2621  * Returns -1 in the case of an error.
2622  */
2623 int
2624 str2cyls(char *str)
2625 {
2626         int     cyls;
2627         char    *p;
2628 
2629         cyls = (int)strtol(str, &p, 0);
2630         /*
2631          * Check what terminated the conversion.
2632          */
2633         if (*p != 0) {
2634                 /*
2635                  * Units specifier of 'c': accept it.
2636                  */
2637                 if (*p == 'c') {
2638                         p++;
2639                 }
2640                 /*
2641                  * Anthing left over is an error
2642                  */
2643                 if (*p != 0) {
2644                         cyls = -1;
2645                 }
2646         }
2647 
2648         return (cyls);
2649 }
2650 
2651 
2652 /*
2653  * Create a new chg_list structure, and append it onto the
2654  * end of the current chg_list under construction.  By
2655  * applying changes in the order in which listed in the
2656  * data file, the changes we make are deterministic.
2657  * Return a pointer to the new structure, so that the
2658  * caller can fill in the appropriate information.
2659  */
2660 static struct chg_list *
2661 new_chg_list(struct disk_type *disk)
2662 {
2663         struct chg_list         *cp;
2664         struct chg_list         *nc;
2665 
2666         nc = zalloc(sizeof (struct chg_list));
2667 
2668         if (disk->dtype_chglist == NULL) {
2669                 disk->dtype_chglist = nc;
2670         } else {
2671                 for (cp = disk->dtype_chglist; cp->next; cp = cp->next)
2672                         ;
2673                 cp->next = nc;
2674         }
2675         nc->next = NULL;
2676         return (nc);
2677 }
2678 
2679 
2680 /*
2681  * Follow symbolic links from the logical device name to
2682  * the /devfs physical device name.  To be complete, we
2683  * handle the case of multiple links.  This function
2684  * either returns NULL (no links, or some other error),
2685  * or the physical device name, alloc'ed on the heap.
2686  *
2687  * Note that the standard /devices prefix is stripped from
2688  * the final pathname, if present.  The trailing options
2689  * are also removed (":c, raw").
2690  */
2691 static char *
2692 get_physical_name(char *path)
2693 {
2694         struct stat     stbuf;
2695         int             i;
2696         int             level;
2697         char            *p;
2698         char            s[MAXPATHLEN];
2699         char            buf[MAXPATHLEN];
2700         char            dir[MAXPATHLEN];
2701         char            savedir[MAXPATHLEN];
2702         char            *result = NULL;
2703 
2704         if (getcwd(savedir, sizeof (savedir)) == NULL) {
2705                 err_print("getcwd() failed - %s\n", strerror(errno));
2706                 return (NULL);
2707         }
2708 
2709         (void) strcpy(s, path);
2710         if ((p = strrchr(s, '/')) != NULL) {
2711                 *p = 0;
2712         }
2713         if (s[0] == 0) {
2714                 (void) strcpy(s, "/");
2715         }
2716         if (chdir(s) == -1) {
2717                 err_print("cannot chdir() to %s - %s\n",
2718                     s, strerror(errno));
2719                 goto exit;
2720         }
2721 
2722         level = 0;
2723         (void) strcpy(s, path);
2724         for (;;) {
2725                 /*
2726                  * See if there's a real file out there.  If not,
2727                  * we have a dangling link and we ignore it.
2728                  */
2729                 if (stat(s, &stbuf) == -1) {
2730                         goto exit;
2731                 }
2732                 if (lstat(s, &stbuf) == -1) {
2733                         err_print("%s: lstat() failed - %s\n",
2734                             s, strerror(errno));
2735                         goto exit;
2736                 }
2737                 /*
2738                  * If the file is not a link, we're done one
2739                  * way or the other.  If there were links,
2740                  * return the full pathname of the resulting
2741                  * file.
2742                  */
2743                 if (!S_ISLNK(stbuf.st_mode)) {
2744                         if (level > 0) {
2745                                 /*
2746                                  * Strip trailing options from the
2747                                  * physical device name
2748                                  */
2749                                 if ((p = strrchr(s, ':')) != NULL) {
2750                                         *p = 0;
2751                                 }
2752                                 /*
2753                                  * Get the current directory, and
2754                                  * glue the pieces together.
2755                                  */
2756                                 if (getcwd(dir, sizeof (dir)) == NULL) {
2757                                         err_print("getcwd() failed - %s\n",
2758                                             strerror(errno));
2759                                         goto exit;
2760                                 }
2761                                 (void) strcat(dir, "/");
2762                                 (void) strcat(dir, s);
2763                                 /*
2764                                  * If we have the standard fixed
2765                                  * /devices prefix, remove it.
2766                                  */
2767                                 p = (strstr(dir, DEVFS_PREFIX) == dir) ?
2768                                     dir+strlen(DEVFS_PREFIX) : dir;
2769                                 result = alloc_string(p);
2770                         }
2771                         goto exit;
2772                 }
2773                 i = readlink(s, buf, sizeof (buf));
2774                 if (i == -1) {
2775                         err_print("%s: readlink() failed - %s\n",
2776                             s, strerror(errno));
2777                         goto exit;
2778                 }
2779                 level++;
2780                 buf[i] = 0;
2781 
2782                 /*
2783                  * Break up the pathname into the directory
2784                  * reference, if applicable and simple filename.
2785                  * chdir()'ing to the directory allows us to
2786                  * handle links with relative pathnames correctly.
2787                  */
2788                 (void) strcpy(dir, buf);
2789                 if ((p = strrchr(dir, '/')) != NULL) {
2790                         *p = 0;
2791                         if (chdir(dir) == -1) {
2792                                 err_print("cannot chdir() to %s - %s\n",
2793                                     dir, strerror(errno));
2794                                 goto exit;
2795                         }
2796                         (void) strcpy(s, p+1);
2797                 } else {
2798                         (void) strcpy(s, buf);
2799                 }
2800         }
2801 
2802 exit:
2803         if (chdir(savedir) == -1) {
2804                 err_print("cannot chdir() to %s - %s\n",
2805                     savedir, strerror(errno));
2806         }
2807 
2808         return (result);
2809 }
2810 
2811 
2812 static void
2813 sort_disk_list()
2814 {
2815         int                     n;
2816         struct disk_info        **disks;
2817         struct disk_info        *d;
2818         struct disk_info        **dp;
2819         struct disk_info        **dp2;
2820 
2821         /*
2822          * Count the number of disks in the list
2823          */
2824         n = 0;
2825         for (d = disk_list; d != NULL; d = d->disk_next) {
2826                 n++;
2827         }
2828         if (n == 0) {
2829                 return;
2830         }
2831 
2832         /*
2833          * Allocate a simple disk list array and fill it in
2834          */
2835         disks = (struct disk_info **)
2836             zalloc((n+1) * sizeof (struct disk_info *));
2837 
2838         dp = disks;
2839         for (d = disk_list; d != NULL; d = d->disk_next) {
2840                 *dp++ = d;
2841         }
2842         *dp = NULL;
2843 
2844         /*
2845          * Sort the disk list array
2846          */
2847         qsort((void *) disks, n, sizeof (struct disk_info *),
2848             disk_name_compare);
2849 
2850         /*
2851          * Rebuild the linked list disk list structure
2852          */
2853         dp = disks;
2854         disk_list = *dp;
2855         dp2 = dp + 1;
2856         do {
2857                 (*dp++)->disk_next = *dp2++;
2858         } while (*dp != NULL);
2859 
2860         /*
2861          * Clean up
2862          */
2863         (void) destroy_data((void *)disks);
2864 }
2865 
2866 
2867 /*
2868  * Compare two disk names
2869  */
2870 static int
2871 disk_name_compare(
2872         const void      *arg1,
2873         const void      *arg2)
2874 {
2875         char            *s1;
2876         char            *s2;
2877         int             n1;
2878         int             n2;
2879         char            *p1;
2880         char            *p2;
2881 
2882         s1 = (*((struct disk_info **)arg1))->disk_name;
2883         s2 = (*((struct disk_info **)arg2))->disk_name;
2884 
2885         for (;;) {
2886                 if (*s1 == 0 || *s2 == 0)
2887                         break;
2888                 if (isdigit(*s1) && isdigit(*s2)) {
2889                         n1 = strtol(s1, &p1, 10);
2890                         n2 = strtol(s2, &p2, 10);
2891                         if (n1 != n2) {
2892                                 return (n1 - n2);
2893                         }
2894                         s1 = p1;
2895                         s2 = p2;
2896                 } else if (*s1 != *s2) {
2897                         break;
2898                 } else {
2899                         s1++;
2900                         s2++;
2901                 }
2902         }
2903 
2904         return (*s1 - *s2);
2905 }
2906 
2907 static void
2908 make_controller_list()
2909 {
2910         int     x;
2911         struct  mctlr_list      *ctlrp;
2912 
2913         ctlrp = controlp;
2914 
2915         for (x = nctypes; x != 0; x--) {
2916                 ctlrp = zalloc(sizeof (struct mctlr_list));
2917                 ctlrp->next = controlp;
2918                 ctlrp->ctlr_type = &ctlr_types[x - 1];
2919                 controlp = ctlrp;
2920 
2921         }
2922 }
2923 
2924 static void
2925 check_for_duplicate_disknames(arglist)
2926 char *arglist[];
2927 {
2928         char                    *directory = "/dev/rdsk/";
2929         char                    **disklist;
2930         int                     len;
2931         char                    s[MAXPATHLEN], t[MAXPATHLEN];
2932         int                     diskno = 0;
2933         int                     i;
2934 
2935 
2936         len = strlen(directory);
2937         disklist = arglist;
2938         for (; *disklist != NULL; disklist++) {
2939                 if (strncmp(directory, *disklist, len) == 0) {
2940                         /* Disk is in conventional format */
2941                         canonicalize_name(s, *disklist);
2942                         /*
2943                          *  check if the disk is already present in
2944                          *  disk list.
2945                          */
2946                         for (i = 0; i < diskno; i++) {
2947                             canonicalize_name(t, arglist[i]);
2948                             if (strncmp(s, t, strlen(t)) == 0)
2949                                 break;
2950                         }
2951                         if (i != diskno)
2952                                 continue;
2953                 }
2954                 (void) strcpy(arglist[diskno], *disklist);
2955                 diskno++;
2956         }
2957         arglist[diskno] = NULL;
2958 }
2959 
2960 #define DISK_PREFIX     "/dev/rdsk/"
2961 
2962 /*
2963  * This Function checks if the non-conventional name is a a link to
2964  * one of the conventional whole disk name.
2965  */
2966 static int
2967 name_represents_wholedisk(char  *name)
2968 {
2969         char    symname[MAXPATHLEN];
2970         char    localname[MAXPATHLEN];
2971         char    *nameptr;
2972         ssize_t symname_size;
2973         size_t disk_prefix_len = strlen(DISK_PREFIX);
2974 
2975         if (strlcpy(localname, name, MAXPATHLEN) >= MAXPATHLEN)
2976                 return (1);     /* buffer overflow, reject this name */
2977 
2978         while ((symname_size = readlink(localname, symname, MAXPATHLEN - 1)) != -1) {
2979                 symname[symname_size] = '\0';
2980                 nameptr = symname;
2981                 if (strncmp(symname, DISK_PREFIX, disk_prefix_len) == 0)
2982                         nameptr += disk_prefix_len;
2983                 if (conventional_name(nameptr))
2984                         return (!whole_disk_name(nameptr));
2985                 (void) strcpy(localname, symname);
2986         }
2987         return (0);
2988 }