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