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