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