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