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 2009 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 if (ioctl(search_file, DKIOCGMEDIAINFO, &mediainfo) == -1) { 1611 cur_blksz = DEV_BSIZE; 1612 } else { 1613 cur_blksz = mediainfo.dki_lbsize; 1614 } 1615 1616 /* 1617 * If the type of disk is one we don't know about, 1618 * add it to the list. 1619 */ 1620 mlp = controlp; 1621 1622 while (mlp != NULL) { 1623 if (mlp->ctlr_type->ctype_ctype == dkinfo.dki_ctype && 1624 strcmp(mlp->ctlr_type->ctype_name, dkinfo.dki_cname) == 0) { 1625 break; 1626 } 1627 mlp = mlp->next; 1628 } 1629 1630 if (mlp == NULL) { 1631 if (dkinfo.dki_ctype == DKC_CDROM) { 1632 if (ioctl(search_file, DKIOCGMEDIAINFO, 1633 &mediainfo) < 0) { 1634 mediainfo.dki_media_type = DK_UNKNOWN; 1635 } 1636 } 1637 /* 1638 * Skip CDROM devices, they are read only. 1639 * But not devices like Iomega Rev Drive which 1640 * identifies itself as a CDROM, but has a removable 1641 * disk. 1642 * Also skip PCMCIA memory card device since 1643 * it is used as a pseudo floppy disk drive 1644 * at the present time (BugID 1201473) 1645 */ 1646 if (((dkinfo.dki_ctype == DKC_CDROM) && 1647 (mediainfo.dki_media_type != DK_REMOVABLE_DISK)) || 1648 (dkinfo.dki_ctype == DKC_PCMCIA_MEM)) { 1649 (void) close(search_file); 1650 return; 1651 } 1652 /* 1653 * create the new ctlr_type structure and fill it in. 1654 */ 1655 tctlr = zalloc(sizeof (struct ctlr_type)); 1656 tctlr->ctype_ctype = dkinfo.dki_ctype; 1657 tctlr->ctype_name = zalloc(DK_DEVLEN); 1658 if (strlcpy(tctlr->ctype_name, dkinfo.dki_cname, 1659 DK_DEVLEN) > DK_DEVLEN) { 1660 /* 1661 * DKIOCINFO returned a controller name longer 1662 * than DK_DEVLEN bytes, which means more of the 1663 * dk_cinfo structure may be corrupt. We don't 1664 * allow the user to perform any operations on 1665 * the device in this case 1666 */ 1667 err_print("\nError: Device %s: controller " 1668 "name (%s)\nis invalid. Device will not " 1669 "be displayed.\n", devname, dkinfo.dki_cname); 1670 (void) close(search_file); 1671 destroy_data(tctlr->ctype_name); 1672 destroy_data((char *)tctlr); 1673 return; 1674 } else { 1675 tctlr->ctype_ops = zalloc(sizeof (struct ctlr_ops)); 1676 1677 /* 1678 * copy the generic disk ops structure into local copy. 1679 */ 1680 *(tctlr->ctype_ops) = genericops; 1681 1682 tctlr->ctype_flags = CF_WLIST; 1683 1684 mlp = controlp; 1685 1686 while (mlp->next != NULL) { 1687 mlp = mlp->next; 1688 } 1689 1690 mlp->next = zalloc(sizeof (struct mctlr_list)); 1691 mlp->next->ctlr_type = tctlr; 1692 } 1693 } 1694 1695 /* 1696 * Search through all disks known at this time, to 1697 * determine if we're already identified this disk. 1698 * If so, then there's no need to include it a 1699 * second time. This permits the user-defined names 1700 * to supercede the standard conventional names. 1701 */ 1702 if (disk_is_known(&dkinfo)) { 1703 (void) close(search_file); 1704 return; 1705 } 1706 #if defined(sparc) 1707 /* 1708 * Because opening id with FNDELAY always succeeds, 1709 * read the label early on to see whether the device 1710 * really exists. A result of DSK_RESERVED 1711 * means the disk may be reserved. 1712 * In the future, it will be good 1713 * to move these into controller specific files and have a common 1714 * generic check for reserved disks here, including intel disks. 1715 */ 1716 if (dkinfo.dki_ctype == DKC_SCSI_CCS) { 1717 char *first_sector; 1718 1719 first_sector = zalloc(cur_blksz); 1720 i = scsi_rdwr(DIR_READ, search_file, (diskaddr_t)0, 1721 1, first_sector, F_SILENT, NULL); 1722 switch (i) { 1723 case DSK_RESERVED: 1724 access_flags |= DSK_RESERVED; 1725 break; 1726 case DSK_UNAVAILABLE: 1727 access_flags |= DSK_UNAVAILABLE; 1728 break; 1729 default: 1730 break; 1731 } 1732 free(first_sector); 1733 } 1734 #endif /* defined(sparc) */ 1735 1736 /* 1737 * The disk appears to be present. Allocate space for the 1738 * disk structure and add it to the list of found disks. 1739 */ 1740 search_disk = (struct disk_info *)zalloc(sizeof (struct disk_info)); 1741 if (disk_list == NULL) 1742 disk_list = search_disk; 1743 else { 1744 for (dptr = disk_list; dptr->disk_next != NULL; 1745 dptr = dptr->disk_next) 1746 ; 1747 dptr->disk_next = search_disk; 1748 } 1749 /* 1750 * Fill in some info from the ioctls. 1751 */ 1752 search_disk->disk_dkinfo = dkinfo; 1753 if (is_efi_type(search_file)) { 1754 search_disk->label_type = L_TYPE_EFI; 1755 } else { 1756 search_disk->label_type = L_TYPE_SOLARIS; 1757 } 1758 /* 1759 * Remember the names of the disk 1760 */ 1761 search_disk->disk_name = alloc_string(devname); 1762 search_disk->disk_path = alloc_string(devpath); 1763 1764 /* 1765 * Remember the lba size of the disk 1766 */ 1767 search_disk->disk_lbasize = cur_blksz; 1768 1769 (void) strcpy(x86_devname, devname); 1770 1771 /* 1772 * Determine if this device is linked to a physical name. 1773 */ 1774 search_disk->devfs_name = get_physical_name(devpath); 1775 1776 /* 1777 * Try to match the ctlr for this disk with a ctlr we 1778 * have already found. A match is assumed if the ctlrs 1779 * are at the same address && ctypes agree 1780 */ 1781 for (search_ctlr = ctlr_list; search_ctlr != NULL; 1782 search_ctlr = search_ctlr->ctlr_next) 1783 if (search_ctlr->ctlr_addr == dkinfo.dki_addr && 1784 search_ctlr->ctlr_space == dkinfo.dki_space && 1785 search_ctlr->ctlr_ctype->ctype_ctype == 1786 dkinfo.dki_ctype) 1787 break; 1788 /* 1789 * If no match was found, we need to identify this ctlr. 1790 */ 1791 if (search_ctlr == NULL) { 1792 /* 1793 * Match the type of the ctlr to a known type. 1794 */ 1795 mlp = controlp; 1796 1797 while (mlp != NULL) { 1798 if (mlp->ctlr_type->ctype_ctype == dkinfo.dki_ctype) 1799 break; 1800 mlp = mlp->next; 1801 } 1802 /* 1803 * If no match was found, it's an error. 1804 * Close the disk and report the error. 1805 */ 1806 if (mlp == NULL) { 1807 err_print("\nError: found disk attached to "); 1808 err_print("unsupported controller type '%d'.\n", 1809 dkinfo.dki_ctype); 1810 (void) close(search_file); 1811 return; 1812 } 1813 /* 1814 * Allocate space for the ctlr structure and add it 1815 * to the list of found ctlrs. 1816 */ 1817 search_ctlr = (struct ctlr_info *) 1818 zalloc(sizeof (struct ctlr_info)); 1819 search_ctlr->ctlr_ctype = mlp->ctlr_type; 1820 if (ctlr_list == NULL) 1821 ctlr_list = search_ctlr; 1822 else { 1823 for (cptr = ctlr_list; cptr->ctlr_next != NULL; 1824 cptr = cptr->ctlr_next) 1825 ; 1826 cptr->ctlr_next = search_ctlr; 1827 } 1828 /* 1829 * Fill in info from the ioctl. 1830 */ 1831 for (i = 0; i < DK_DEVLEN; i++) { 1832 search_ctlr->ctlr_cname[i] = dkinfo.dki_cname[i]; 1833 search_ctlr->ctlr_dname[i] = dkinfo.dki_dname[i]; 1834 } 1835 /* 1836 * Make sure these can be used as simple strings 1837 */ 1838 search_ctlr->ctlr_cname[i] = 0; 1839 search_ctlr->ctlr_dname[i] = 0; 1840 1841 search_ctlr->ctlr_flags = dkinfo.dki_flags; 1842 search_ctlr->ctlr_num = dkinfo.dki_cnum; 1843 search_ctlr->ctlr_addr = dkinfo.dki_addr; 1844 search_ctlr->ctlr_space = dkinfo.dki_space; 1845 search_ctlr->ctlr_prio = dkinfo.dki_prio; 1846 search_ctlr->ctlr_vec = dkinfo.dki_vec; 1847 } 1848 /* 1849 * By this point, we have a known ctlr. Link the disk 1850 * to the ctlr. 1851 */ 1852 search_disk->disk_ctlr = search_ctlr; 1853 if (access_flags & (DSK_RESERVED | DSK_UNAVAILABLE)) { 1854 if (access_flags & DSK_RESERVED) 1855 search_disk->disk_flags |= DSK_RESERVED; 1856 else 1857 search_disk->disk_flags |= DSK_UNAVAILABLE; 1858 (void) close(search_file); 1859 return; 1860 } else { 1861 search_disk->disk_flags &= ~(DSK_RESERVED | DSK_UNAVAILABLE); 1862 } 1863 1864 /* 1865 * Attempt to read the primary label. 1866 * (Note that this is really through the DKIOCGVTOC 1867 * ioctl, then converted from vtoc to label.) 1868 */ 1869 if (search_disk->label_type == L_TYPE_SOLARIS) { 1870 status = read_label(search_file, &search_label); 1871 } else { 1872 status = read_efi_label(search_file, &efi_info); 1873 } 1874 /* 1875 * If reading the label failed, and this is a SCSI 1876 * disk, we can attempt to auto-sense the disk 1877 * Configuration. 1878 */ 1879 ctlr = search_ctlr->ctlr_ctype; 1880 if ((status == -1) && (ctlr->ctype_ctype == DKC_SCSI_CCS)) { 1881 if (option_msg && diag_msg) { 1882 err_print("%s: attempting auto configuration\n", 1883 search_disk->disk_name); 1884 } 1885 1886 switch (search_disk->label_type) { 1887 case (L_TYPE_SOLARIS): 1888 if (auto_sense(search_file, 0, &search_label) != NULL) { 1889 /* 1890 * Auto config worked, so we now have 1891 * a valid label for the disk. Mark 1892 * the disk as needing the label flushed. 1893 */ 1894 status = 0; 1895 search_disk->disk_flags |= 1896 (DSK_LABEL_DIRTY | DSK_AUTO_CONFIG); 1897 } 1898 break; 1899 case (L_TYPE_EFI): 1900 efi_disk = auto_efi_sense(search_file, &efi_info); 1901 if (efi_disk != NULL) { 1902 /* 1903 * Auto config worked, so we now have 1904 * a valid label for the disk. 1905 */ 1906 status = 0; 1907 search_disk->disk_flags |= 1908 (DSK_LABEL_DIRTY | DSK_AUTO_CONFIG); 1909 } 1910 break; 1911 default: 1912 /* Should never happen */ 1913 break; 1914 } 1915 } 1916 /* 1917 * Close the file for this disk. 1918 */ 1919 (void) close(search_file); 1920 /* 1921 * If we didn't successfully read the label, or the label 1922 * appears corrupt, just leave the disk as an unknown type. 1923 */ 1924 if (status == -1) { 1925 return; 1926 } 1927 1928 if (search_disk->label_type == L_TYPE_SOLARIS) { 1929 if (!checklabel(&search_label)) { 1930 return; 1931 } 1932 if (trim_id(search_label.dkl_asciilabel)) { 1933 return; 1934 } 1935 } 1936 /* 1937 * The label looks ok. Mark the disk as labeled. 1938 */ 1939 search_disk->disk_flags |= DSK_LABEL; 1940 1941 if (search_disk->label_type == L_TYPE_EFI) { 1942 search_dtype = (struct disk_type *) 1943 zalloc(sizeof (struct disk_type)); 1944 type = search_ctlr->ctlr_ctype->ctype_dlist; 1945 if (type == NULL) { 1946 search_ctlr->ctlr_ctype->ctype_dlist = 1947 search_dtype; 1948 } else { 1949 while (type->dtype_next != NULL) { 1950 type = type->dtype_next; 1951 } 1952 type->dtype_next = search_dtype; 1953 } 1954 search_dtype->dtype_next = NULL; 1955 1956 (void) strlcpy(search_dtype->vendor, efi_info.vendor, 9); 1957 (void) strlcpy(search_dtype->product, efi_info.product, 17); 1958 (void) strlcpy(search_dtype->revision, efi_info.revision, 5); 1959 search_dtype->capacity = efi_info.capacity; 1960 search_disk->disk_type = search_dtype; 1961 1962 search_parts = (struct partition_info *) 1963 zalloc(sizeof (struct partition_info)); 1964 search_dtype->dtype_plist = search_parts; 1965 1966 search_parts->pinfo_name = alloc_string("original"); 1967 search_parts->pinfo_next = NULL; 1968 search_parts->etoc = efi_info.e_parts; 1969 search_disk->disk_parts = search_parts; 1970 1971 /* 1972 * Copy the volume name, if present 1973 */ 1974 for (i = 0; i < search_parts->etoc->efi_nparts; i++) { 1975 if (search_parts->etoc->efi_parts[i].p_tag == 1976 V_RESERVED) { 1977 if (search_parts->etoc->efi_parts[i].p_name) { 1978 bcopy(search_parts->etoc->efi_parts[i] 1979 .p_name, search_disk->v_volume, 1980 LEN_DKL_VVOL); 1981 } else { 1982 bzero(search_disk->v_volume, 1983 LEN_DKL_VVOL); 1984 } 1985 break; 1986 } 1987 } 1988 return; 1989 } 1990 1991 /* 1992 * Attempt to match the disk type in the label with a 1993 * known disk type. 1994 */ 1995 for (search_dtype = search_ctlr->ctlr_ctype->ctype_dlist; 1996 search_dtype != NULL; 1997 search_dtype = search_dtype->dtype_next) 1998 if (dtype_match(&search_label, search_dtype)) 1999 break; 2000 /* 2001 * If no match was found, we need to create a disk type 2002 * for this disk. 2003 */ 2004 if (search_dtype == NULL) { 2005 /* 2006 * Allocate space for the disk type and add it 2007 * to the list of disk types for this ctlr type. 2008 */ 2009 search_dtype = (struct disk_type *) 2010 zalloc(sizeof (struct disk_type)); 2011 type = search_ctlr->ctlr_ctype->ctype_dlist; 2012 if (type == NULL) 2013 search_ctlr->ctlr_ctype->ctype_dlist = 2014 search_dtype; 2015 else { 2016 while (type->dtype_next != NULL) 2017 type = type->dtype_next; 2018 type->dtype_next = search_dtype; 2019 } 2020 /* 2021 * Fill in the drive info from the disk label. 2022 */ 2023 search_dtype->dtype_next = NULL; 2024 search_dtype->dtype_asciilabel = (char *) 2025 zalloc(strlen(search_label.dkl_asciilabel) + 1); 2026 (void) strcpy(search_dtype->dtype_asciilabel, 2027 search_label.dkl_asciilabel); 2028 search_dtype->dtype_pcyl = search_label.dkl_pcyl; 2029 search_dtype->dtype_ncyl = search_label.dkl_ncyl; 2030 search_dtype->dtype_acyl = search_label.dkl_acyl; 2031 search_dtype->dtype_nhead = search_label.dkl_nhead; 2032 search_dtype->dtype_nsect = search_label.dkl_nsect; 2033 search_dtype->dtype_rpm = search_label.dkl_rpm; 2034 /* 2035 * Mark the disk as needing specification of 2036 * ctlr specific attributes. This is necessary 2037 * because the label doesn't contain these attributes, 2038 * and they aren't known at this point. They will 2039 * be asked for if this disk is ever selected by 2040 * the user. 2041 * Note: for SCSI, we believe the label. 2042 */ 2043 if ((search_ctlr->ctlr_ctype->ctype_ctype != DKC_SCSI_CCS) && 2044 (search_ctlr->ctlr_ctype->ctype_ctype != DKC_DIRECT) && 2045 (search_ctlr->ctlr_ctype->ctype_ctype != DKC_VBD) && 2046 (search_ctlr->ctlr_ctype->ctype_ctype != DKC_PCMCIA_ATA)) { 2047 search_dtype->dtype_flags |= DT_NEED_SPEFS; 2048 } 2049 } 2050 /* 2051 * By this time we have a known disk type. Link the disk 2052 * to the disk type. 2053 */ 2054 search_disk->disk_type = search_dtype; 2055 /* 2056 * Attempt to match the partition map in the label with 2057 * a known partition map for this disk type. 2058 */ 2059 for (search_parts = search_dtype->dtype_plist; 2060 search_parts != NULL; 2061 search_parts = search_parts->pinfo_next) 2062 if (parts_match(&search_label, search_parts)) { 2063 break; 2064 } 2065 /* 2066 * If no match was made, we need to create a partition 2067 * map for this disk. 2068 */ 2069 if (search_parts == NULL) { 2070 /* 2071 * Allocate space for the partition map and add 2072 * it to the list of maps for this disk type. 2073 */ 2074 search_parts = (struct partition_info *) 2075 zalloc(sizeof (struct partition_info)); 2076 parts = search_dtype->dtype_plist; 2077 if (parts == NULL) 2078 search_dtype->dtype_plist = search_parts; 2079 else { 2080 while (parts->pinfo_next != NULL) 2081 parts = parts->pinfo_next; 2082 parts->pinfo_next = search_parts; 2083 } 2084 search_parts->pinfo_next = NULL; 2085 /* 2086 * Fill in the name of the map with a name derived 2087 * from the name of this disk. This is necessary 2088 * because the label contains no name for the 2089 * partition map. 2090 */ 2091 search_parts->pinfo_name = alloc_string("original"); 2092 /* 2093 * Fill in the partition info from the disk label. 2094 */ 2095 for (i = 0; i < NDKMAP; i++) { 2096 2097 #if defined(_SUNOS_VTOC_8) 2098 search_parts->pinfo_map[i] = 2099 search_label.dkl_map[i]; 2100 2101 #elif defined(_SUNOS_VTOC_16) 2102 search_parts->pinfo_map[i].dkl_cylno = 2103 search_label.dkl_vtoc.v_part[i].p_start / 2104 ((blkaddr32_t)(search_label.dkl_nhead * 2105 search_label.dkl_nsect)); 2106 search_parts->pinfo_map[i].dkl_nblk = 2107 search_label.dkl_vtoc.v_part[i].p_size; 2108 2109 #else 2110 #error No VTOC format defined. 2111 #endif 2112 } 2113 } 2114 /* 2115 * If the vtoc looks valid, copy the volume name and vtoc 2116 * info from the label. Otherwise, install a default vtoc. 2117 * This permits vtoc info to automatically appear in the sun 2118 * label, without requiring an upgrade procedure. 2119 */ 2120 if (search_label.dkl_vtoc.v_version == V_VERSION) { 2121 bcopy(search_label.dkl_vtoc.v_volume, 2122 search_disk->v_volume, LEN_DKL_VVOL); 2123 search_parts->vtoc = search_label.dkl_vtoc; 2124 } else { 2125 bzero(search_disk->v_volume, LEN_DKL_VVOL); 2126 set_vtoc_defaults(search_parts); 2127 } 2128 /* 2129 * By this time we have a known partitition map. Link the 2130 * disk to the partition map. 2131 */ 2132 search_disk->disk_parts = search_parts; 2133 } 2134 2135 2136 /* 2137 * Search the disk list for a disk with the identical configuration. 2138 * Return true if one is found. 2139 */ 2140 static int 2141 disk_is_known(struct dk_cinfo *dkinfo) 2142 { 2143 struct disk_info *dp; 2144 2145 dp = disk_list; 2146 while (dp != NULL) { 2147 if (dp->disk_dkinfo.dki_ctype == dkinfo->dki_ctype && 2148 dp->disk_dkinfo.dki_cnum == dkinfo->dki_cnum && 2149 dp->disk_dkinfo.dki_unit == dkinfo->dki_unit && 2150 strcmp(dp->disk_dkinfo.dki_dname, dkinfo->dki_dname) == 0) { 2151 return (1); 2152 } 2153 dp = dp->disk_next; 2154 } 2155 return (0); 2156 } 2157 2158 2159 /* 2160 * This routine checks to see if a given disk type matches the type 2161 * in the disk label. 2162 */ 2163 int 2164 dtype_match(label, dtype) 2165 register struct dk_label *label; 2166 register struct disk_type *dtype; 2167 { 2168 2169 if (dtype->dtype_asciilabel == NULL) { 2170 return (0); 2171 } 2172 2173 /* 2174 * If the any of the physical characteristics are different, or 2175 * the name is different, it doesn't match. 2176 */ 2177 if ((strcmp(label->dkl_asciilabel, dtype->dtype_asciilabel) != 0) || 2178 (label->dkl_ncyl != dtype->dtype_ncyl) || 2179 (label->dkl_acyl != dtype->dtype_acyl) || 2180 (label->dkl_nhead != dtype->dtype_nhead) || 2181 (label->dkl_nsect != dtype->dtype_nsect)) { 2182 return (0); 2183 } 2184 /* 2185 * If those are all identical, assume it's a match. 2186 */ 2187 return (1); 2188 } 2189 2190 /* 2191 * This routine checks to see if a given partition map matches the map 2192 * in the disk label. 2193 */ 2194 int 2195 parts_match(label, pinfo) 2196 register struct dk_label *label; 2197 register struct partition_info *pinfo; 2198 { 2199 int i; 2200 2201 /* 2202 * If any of the partition entries is different, it doesn't match. 2203 */ 2204 for (i = 0; i < NDKMAP; i++) 2205 2206 #if defined(_SUNOS_VTOC_8) 2207 if ((label->dkl_map[i].dkl_cylno != 2208 pinfo->pinfo_map[i].dkl_cylno) || 2209 (label->dkl_map[i].dkl_nblk != 2210 pinfo->pinfo_map[i].dkl_nblk)) 2211 2212 #elif defined(_SUNOS_VTOC_16) 2213 if ((pinfo->pinfo_map[i].dkl_cylno != 2214 label->dkl_vtoc.v_part[i].p_start / 2215 (label->dkl_nhead * label->dkl_nsect)) || 2216 (pinfo->pinfo_map[i].dkl_nblk != 2217 label->dkl_vtoc.v_part[i].p_size)) 2218 #else 2219 #error No VTOC format defined. 2220 #endif 2221 return (0); 2222 /* 2223 * Compare the vtoc information for a match 2224 * Do not require the volume name to be equal, for a match! 2225 */ 2226 if (label->dkl_vtoc.v_version != pinfo->vtoc.v_version) 2227 return (0); 2228 if (label->dkl_vtoc.v_nparts != pinfo->vtoc.v_nparts) 2229 return (0); 2230 for (i = 0; i < NDKMAP; i++) { 2231 if (label->dkl_vtoc.v_part[i].p_tag != 2232 pinfo->vtoc.v_part[i].p_tag) 2233 return (0); 2234 if (label->dkl_vtoc.v_part[i].p_flag != 2235 pinfo->vtoc.v_part[i].p_flag) 2236 return (0); 2237 } 2238 /* 2239 * If they are all identical, it's a match. 2240 */ 2241 return (1); 2242 } 2243 2244 /* 2245 * This routine checks to see if the given disk name refers to the disk 2246 * in the given disk structure. 2247 */ 2248 int 2249 diskname_match(char *name, struct disk_info *disk) 2250 { 2251 struct dk_cinfo dkinfo; 2252 char s[MAXPATHLEN]; 2253 int fd; 2254 2255 /* 2256 * Match the name of the disk in the disk_info structure 2257 */ 2258 if (strcmp(name, disk->disk_name) == 0) { 2259 return (1); 2260 } 2261 2262 /* 2263 * Check to see if it's a 4.x file name in the /dev 2264 * directory on 5.0. Here, we only accept the 2265 * canonicalized form: sd0. 2266 */ 2267 if (canonical4x_name(name) == 0) { 2268 return (0); 2269 } 2270 2271 (void) strcpy(s, "/dev/r"); 2272 (void) strcat(s, name); 2273 (void) strcat(s, "c"); 2274 2275 if ((fd = open_disk(s, O_RDWR | O_NDELAY)) < 0) { 2276 return (0); 2277 } 2278 2279 if (ioctl(fd, DKIOCINFO, &dkinfo) < 0) { 2280 (void) close(fd); 2281 return (0); 2282 } 2283 (void) close(fd); 2284 2285 if (disk->disk_dkinfo.dki_ctype == dkinfo.dki_ctype && 2286 disk->disk_dkinfo.dki_cnum == dkinfo.dki_cnum && 2287 disk->disk_dkinfo.dki_unit == dkinfo.dki_unit && 2288 strcmp(disk->disk_dkinfo.dki_dname, dkinfo.dki_dname) == 0) { 2289 return (1); 2290 } 2291 return (0); 2292 } 2293 2294 2295 static void 2296 datafile_error(char *errmsg, char *token) 2297 { 2298 int token_type; 2299 TOKEN token_buf; 2300 2301 /* 2302 * Allow us to get by controllers that the other platforms don't 2303 * know about. 2304 */ 2305 if (errmsg != NULL) { 2306 err_print(errmsg, token); 2307 err_print(" - %s (%d)\n", file_name, data_lineno); 2308 } 2309 2310 /* 2311 * Re-sync the parsing at the beginning of the next line 2312 * unless of course we're already there. 2313 */ 2314 if (last_token_type != SUP_EOF && last_token_type != SUP_EOL) { 2315 do { 2316 token_type = sup_gettoken(token_buf); 2317 } while (token_type != SUP_EOF && token_type != SUP_EOL); 2318 2319 if (token_type == SUP_EOF) { 2320 sup_pushtoken(token_buf, token_type); 2321 } 2322 } 2323 } 2324 2325 2326 /* 2327 * Search through all defined disk types for duplicate entries 2328 * that are inconsistent with each other. Disks with different 2329 * characteristics should be named differently. 2330 * Note that this function only checks for duplicate disks 2331 * for the same controller. It's possible to have two disks with 2332 * the same name, but defined for different controllers. 2333 * That may or may not be a problem... 2334 */ 2335 static void 2336 search_duplicate_dtypes() 2337 { 2338 struct disk_type *dp1; 2339 struct disk_type *dp2; 2340 struct mctlr_list *mlp; 2341 2342 mlp = controlp; 2343 2344 while (mlp != NULL) { 2345 dp1 = mlp->ctlr_type->ctype_dlist; 2346 while (dp1 != NULL) { 2347 dp2 = dp1->dtype_next; 2348 while (dp2 != NULL) { 2349 check_dtypes_for_inconsistency(dp1, dp2); 2350 dp2 = dp2->dtype_next; 2351 } 2352 dp1 = dp1->dtype_next; 2353 } 2354 mlp = mlp->next; 2355 } 2356 } 2357 2358 2359 /* 2360 * Search through all defined partition types for duplicate entries 2361 * that are inconsistent with each other. Partitions with different 2362 * characteristics should be named differently. 2363 * Note that this function only checks for duplicate partitions 2364 * for the same disk. It's possible to have two partitions with 2365 * the same name, but defined for different disks. 2366 * That may or may not be a problem... 2367 */ 2368 static void 2369 search_duplicate_pinfo() 2370 { 2371 struct disk_type *dp; 2372 struct partition_info *pp1; 2373 struct partition_info *pp2; 2374 struct mctlr_list *mlp; 2375 2376 mlp = controlp; 2377 2378 while (mlp != NULL) { 2379 dp = mlp->ctlr_type->ctype_dlist; 2380 while (dp != NULL) { 2381 pp1 = dp->dtype_plist; 2382 while (pp1 != NULL) { 2383 pp2 = pp1->pinfo_next; 2384 while (pp2 != NULL) { 2385 check_pinfo_for_inconsistency(pp1, pp2); 2386 pp2 = pp2->pinfo_next; 2387 } 2388 pp1 = pp1->pinfo_next; 2389 } 2390 dp = dp->dtype_next; 2391 } 2392 mlp = mlp->next; 2393 } 2394 } 2395 2396 2397 /* 2398 * Determine if two particular disk definitions are inconsistent. 2399 * Ie: same name, but different characteristics. 2400 * If so, print an error message and abort. 2401 */ 2402 static void 2403 check_dtypes_for_inconsistency(dp1, dp2) 2404 struct disk_type *dp1; 2405 struct disk_type *dp2; 2406 { 2407 int i; 2408 int result; 2409 struct chg_list *cp1; 2410 struct chg_list *cp2; 2411 2412 2413 /* 2414 * If the name's different, we're ok 2415 */ 2416 if (strcmp(dp1->dtype_asciilabel, dp2->dtype_asciilabel) != 0) { 2417 return; 2418 } 2419 2420 /* 2421 * Compare all the disks' characteristics 2422 */ 2423 result = 0; 2424 result |= (dp1->dtype_flags != dp2->dtype_flags); 2425 result |= (dp1->dtype_options != dp2->dtype_options); 2426 result |= (dp1->dtype_fmt_time != dp2->dtype_fmt_time); 2427 result |= (dp1->dtype_bpt != dp2->dtype_bpt); 2428 result |= (dp1->dtype_ncyl != dp2->dtype_ncyl); 2429 result |= (dp1->dtype_acyl != dp2->dtype_acyl); 2430 result |= (dp1->dtype_pcyl != dp2->dtype_pcyl); 2431 result |= (dp1->dtype_nhead != dp2->dtype_nhead); 2432 result |= (dp1->dtype_nsect != dp2->dtype_nsect); 2433 result |= (dp1->dtype_rpm != dp2->dtype_rpm); 2434 result |= (dp1->dtype_cyl_skew != dp2->dtype_cyl_skew); 2435 result |= (dp1->dtype_trk_skew != dp2->dtype_trk_skew); 2436 result |= (dp1->dtype_trks_zone != dp2->dtype_trks_zone); 2437 result |= (dp1->dtype_atrks != dp2->dtype_atrks); 2438 result |= (dp1->dtype_asect != dp2->dtype_asect); 2439 result |= (dp1->dtype_cache != dp2->dtype_cache); 2440 result |= (dp1->dtype_threshold != dp2->dtype_threshold); 2441 result |= (dp1->dtype_read_retries != dp2->dtype_read_retries); 2442 result |= (dp1->dtype_write_retries != dp2->dtype_write_retries); 2443 result |= (dp1->dtype_prefetch_min != dp2->dtype_prefetch_min); 2444 result |= (dp1->dtype_prefetch_max != dp2->dtype_prefetch_max); 2445 for (i = 0; i < NSPECIFICS; i++) { 2446 result |= (dp1->dtype_specifics[i] != dp2->dtype_specifics[i]); 2447 } 2448 2449 cp1 = dp1->dtype_chglist; 2450 cp2 = dp2->dtype_chglist; 2451 while (cp1 != NULL && cp2 != NULL) { 2452 if (cp1 == NULL || cp2 == NULL) { 2453 result = 1; 2454 break; 2455 } 2456 result |= (cp1->pageno != cp2->pageno); 2457 result |= (cp1->byteno != cp2->byteno); 2458 result |= (cp1->mode != cp2->mode); 2459 result |= (cp1->value != cp2->value); 2460 cp1 = cp1->next; 2461 cp2 = cp2->next; 2462 } 2463 2464 if (result) { 2465 err_print("Inconsistent definitions for disk type '%s'\n", 2466 dp1->dtype_asciilabel); 2467 if (dp1->dtype_filename != NULL && 2468 dp2->dtype_filename != NULL) { 2469 err_print("%s (%d) - %s (%d)\n", 2470 dp1->dtype_filename, dp1->dtype_lineno, 2471 dp2->dtype_filename, dp2->dtype_lineno); 2472 } 2473 fullabort(); 2474 } 2475 } 2476 2477 2478 /* 2479 * Determine if two particular partition definitions are inconsistent. 2480 * Ie: same name, but different characteristics. 2481 * If so, print an error message and abort. 2482 */ 2483 static void 2484 check_pinfo_for_inconsistency(pp1, pp2) 2485 struct partition_info *pp1; 2486 struct partition_info *pp2; 2487 { 2488 int i; 2489 int result; 2490 struct dk_map32 *map1; 2491 struct dk_map32 *map2; 2492 2493 #if defined(_SUNOS_VTOC_8) 2494 struct dk_map2 *vp1; 2495 struct dk_map2 *vp2; 2496 2497 #elif defined(_SUNOS_VTOC_16) 2498 struct dkl_partition *vp1; 2499 struct dkl_partition *vp2; 2500 #else 2501 #error No VTOC layout defined. 2502 #endif /* defined(_SUNOS_VTOC_8) */ 2503 2504 /* 2505 * If the name's different, we're ok 2506 */ 2507 if (strcmp(pp1->pinfo_name, pp2->pinfo_name) != 0) { 2508 return; 2509 } 2510 2511 /* 2512 * Compare all the partitions' characteristics 2513 */ 2514 result = 0; 2515 map1 = pp1->pinfo_map; 2516 map2 = pp2->pinfo_map; 2517 for (i = 0; i < NDKMAP; i++, map1++, map2++) { 2518 result |= (map1->dkl_cylno != map2->dkl_cylno); 2519 result |= (map1->dkl_nblk != map2->dkl_nblk); 2520 } 2521 2522 /* 2523 * Compare the significant portions of the vtoc information 2524 */ 2525 vp1 = pp1->vtoc.v_part; 2526 vp2 = pp2->vtoc.v_part; 2527 for (i = 0; i < NDKMAP; i++, vp1++, vp2++) { 2528 result |= (vp1->p_tag != vp2->p_tag); 2529 result |= (vp1->p_flag != vp2->p_flag); 2530 } 2531 2532 if (result) { 2533 err_print("Inconsistent definitions for partition type '%s'\n", 2534 pp1->pinfo_name); 2535 if (pp1->pinfo_filename != NULL && 2536 pp2->pinfo_filename != NULL) { 2537 err_print("%s (%d) - %s (%d)\n", 2538 pp1->pinfo_filename, pp1->pinfo_lineno, 2539 pp2->pinfo_filename, pp2->pinfo_lineno); 2540 } 2541 fullabort(); 2542 } 2543 } 2544 2545 /* 2546 * Convert a string of digits into a block number. 2547 * The digits are assumed to be a block number unless the 2548 * the string is terminated by 'c', in which case it is 2549 * assumed to be in units of cylinders. Accept a 'b' 2550 * to explictly specify blocks, for consistency. 2551 * 2552 * NB: uses the macro spc(), which requires that the 2553 * globals nhead/nsect/acyl be set up correctly. 2554 * 2555 * Returns -1 in the case of an error. 2556 */ 2557 static uint_t 2558 str2blks(char *str) 2559 { 2560 int blks; 2561 char *p; 2562 2563 blks = (int)strtol(str, &p, 0); 2564 /* 2565 * Check what terminated the conversion. 2566 */ 2567 if (*p != 0) { 2568 /* 2569 * Units specifier of 'c': convert cylinders to blocks 2570 */ 2571 if (*p == 'c') { 2572 p++; 2573 blks = blks * spc(); 2574 /* 2575 * Ignore a 'b' specifier. 2576 */ 2577 } else if (*p == 'b') { 2578 p++; 2579 } 2580 /* 2581 * Anthing left over is an error 2582 */ 2583 if (*p != 0) { 2584 blks = -1; 2585 } 2586 } 2587 2588 return (blks); 2589 } 2590 /* 2591 * Convert a string of digits into a cylinder number. 2592 * Accept a an optional 'c' specifier, for consistency. 2593 * 2594 * Returns -1 in the case of an error. 2595 */ 2596 int 2597 str2cyls(char *str) 2598 { 2599 int cyls; 2600 char *p; 2601 2602 cyls = (int)strtol(str, &p, 0); 2603 /* 2604 * Check what terminated the conversion. 2605 */ 2606 if (*p != 0) { 2607 /* 2608 * Units specifier of 'c': accept it. 2609 */ 2610 if (*p == 'c') { 2611 p++; 2612 } 2613 /* 2614 * Anthing left over is an error 2615 */ 2616 if (*p != 0) { 2617 cyls = -1; 2618 } 2619 } 2620 2621 return (cyls); 2622 } 2623 2624 2625 /* 2626 * Create a new chg_list structure, and append it onto the 2627 * end of the current chg_list under construction. By 2628 * applying changes in the order in which listed in the 2629 * data file, the changes we make are deterministic. 2630 * Return a pointer to the new structure, so that the 2631 * caller can fill in the appropriate information. 2632 */ 2633 static struct chg_list * 2634 new_chg_list(struct disk_type *disk) 2635 { 2636 struct chg_list *cp; 2637 struct chg_list *nc; 2638 2639 nc = zalloc(sizeof (struct chg_list)); 2640 2641 if (disk->dtype_chglist == NULL) { 2642 disk->dtype_chglist = nc; 2643 } else { 2644 for (cp = disk->dtype_chglist; cp->next; cp = cp->next) 2645 ; 2646 cp->next = nc; 2647 } 2648 nc->next = NULL; 2649 return (nc); 2650 } 2651 2652 2653 /* 2654 * Follow symbolic links from the logical device name to 2655 * the /devfs physical device name. To be complete, we 2656 * handle the case of multiple links. This function 2657 * either returns NULL (no links, or some other error), 2658 * or the physical device name, alloc'ed on the heap. 2659 * 2660 * Note that the standard /devices prefix is stripped from 2661 * the final pathname, if present. The trailing options 2662 * are also removed (":c, raw"). 2663 */ 2664 static char * 2665 get_physical_name(char *path) 2666 { 2667 struct stat stbuf; 2668 int i; 2669 int level; 2670 char *p; 2671 char s[MAXPATHLEN]; 2672 char buf[MAXPATHLEN]; 2673 char dir[MAXPATHLEN]; 2674 char savedir[MAXPATHLEN]; 2675 char *result = NULL; 2676 2677 if (getcwd(savedir, sizeof (savedir)) == NULL) { 2678 err_print("getcwd() failed - %s\n", strerror(errno)); 2679 return (NULL); 2680 } 2681 2682 (void) strcpy(s, path); 2683 if ((p = strrchr(s, '/')) != NULL) { 2684 *p = 0; 2685 } 2686 if (s[0] == 0) { 2687 (void) strcpy(s, "/"); 2688 } 2689 if (chdir(s) == -1) { 2690 err_print("cannot chdir() to %s - %s\n", 2691 s, strerror(errno)); 2692 goto exit; 2693 } 2694 2695 level = 0; 2696 (void) strcpy(s, path); 2697 for (;;) { 2698 /* 2699 * See if there's a real file out there. If not, 2700 * we have a dangling link and we ignore it. 2701 */ 2702 if (stat(s, &stbuf) == -1) { 2703 goto exit; 2704 } 2705 if (lstat(s, &stbuf) == -1) { 2706 err_print("%s: lstat() failed - %s\n", 2707 s, strerror(errno)); 2708 goto exit; 2709 } 2710 /* 2711 * If the file is not a link, we're done one 2712 * way or the other. If there were links, 2713 * return the full pathname of the resulting 2714 * file. 2715 */ 2716 if (!S_ISLNK(stbuf.st_mode)) { 2717 if (level > 0) { 2718 /* 2719 * Strip trailing options from the 2720 * physical device name 2721 */ 2722 if ((p = strrchr(s, ':')) != NULL) { 2723 *p = 0; 2724 } 2725 /* 2726 * Get the current directory, and 2727 * glue the pieces together. 2728 */ 2729 if (getcwd(dir, sizeof (dir)) == NULL) { 2730 err_print("getcwd() failed - %s\n", 2731 strerror(errno)); 2732 goto exit; 2733 } 2734 (void) strcat(dir, "/"); 2735 (void) strcat(dir, s); 2736 /* 2737 * If we have the standard fixed 2738 * /devices prefix, remove it. 2739 */ 2740 p = (strstr(dir, DEVFS_PREFIX) == dir) ? 2741 dir+strlen(DEVFS_PREFIX) : dir; 2742 result = alloc_string(p); 2743 } 2744 goto exit; 2745 } 2746 i = readlink(s, buf, sizeof (buf)); 2747 if (i == -1) { 2748 err_print("%s: readlink() failed - %s\n", 2749 s, strerror(errno)); 2750 goto exit; 2751 } 2752 level++; 2753 buf[i] = 0; 2754 2755 /* 2756 * Break up the pathname into the directory 2757 * reference, if applicable and simple filename. 2758 * chdir()'ing to the directory allows us to 2759 * handle links with relative pathnames correctly. 2760 */ 2761 (void) strcpy(dir, buf); 2762 if ((p = strrchr(dir, '/')) != NULL) { 2763 *p = 0; 2764 if (chdir(dir) == -1) { 2765 err_print("cannot chdir() to %s - %s\n", 2766 dir, strerror(errno)); 2767 goto exit; 2768 } 2769 (void) strcpy(s, p+1); 2770 } else { 2771 (void) strcpy(s, buf); 2772 } 2773 } 2774 2775 exit: 2776 if (chdir(savedir) == -1) { 2777 err_print("cannot chdir() to %s - %s\n", 2778 savedir, strerror(errno)); 2779 } 2780 2781 return (result); 2782 } 2783 2784 2785 static void 2786 sort_disk_list() 2787 { 2788 int n; 2789 struct disk_info **disks; 2790 struct disk_info *d; 2791 struct disk_info **dp; 2792 struct disk_info **dp2; 2793 2794 /* 2795 * Count the number of disks in the list 2796 */ 2797 n = 0; 2798 for (d = disk_list; d != NULL; d = d->disk_next) { 2799 n++; 2800 } 2801 if (n == 0) { 2802 return; 2803 } 2804 2805 /* 2806 * Allocate a simple disk list array and fill it in 2807 */ 2808 disks = (struct disk_info **) 2809 zalloc((n+1) * sizeof (struct disk_info *)); 2810 2811 dp = disks; 2812 for (d = disk_list; d != NULL; d = d->disk_next) { 2813 *dp++ = d; 2814 } 2815 *dp = NULL; 2816 2817 /* 2818 * Sort the disk list array 2819 */ 2820 qsort((void *) disks, n, sizeof (struct disk_info *), 2821 disk_name_compare); 2822 2823 /* 2824 * Rebuild the linked list disk list structure 2825 */ 2826 dp = disks; 2827 disk_list = *dp; 2828 dp2 = dp + 1; 2829 do { 2830 (*dp++)->disk_next = *dp2++; 2831 } while (*dp != NULL); 2832 2833 /* 2834 * Clean up 2835 */ 2836 (void) destroy_data((void *)disks); 2837 } 2838 2839 2840 /* 2841 * Compare two disk names 2842 */ 2843 static int 2844 disk_name_compare( 2845 const void *arg1, 2846 const void *arg2) 2847 { 2848 char *s1; 2849 char *s2; 2850 int n1; 2851 int n2; 2852 char *p1; 2853 char *p2; 2854 2855 s1 = (*((struct disk_info **)arg1))->disk_name; 2856 s2 = (*((struct disk_info **)arg2))->disk_name; 2857 2858 for (;;) { 2859 if (*s1 == 0 || *s2 == 0) 2860 break; 2861 if (isdigit(*s1) && isdigit(*s2)) { 2862 n1 = strtol(s1, &p1, 10); 2863 n2 = strtol(s2, &p2, 10); 2864 if (n1 != n2) { 2865 return (n1 - n2); 2866 } 2867 s1 = p1; 2868 s2 = p2; 2869 } else if (*s1 != *s2) { 2870 break; 2871 } else { 2872 s1++; 2873 s2++; 2874 } 2875 } 2876 2877 return (*s1 - *s2); 2878 } 2879 2880 static void 2881 make_controller_list() 2882 { 2883 int x; 2884 struct mctlr_list *ctlrp; 2885 2886 ctlrp = controlp; 2887 2888 for (x = nctypes; x != 0; x--) { 2889 ctlrp = zalloc(sizeof (struct mctlr_list)); 2890 ctlrp->next = controlp; 2891 ctlrp->ctlr_type = &ctlr_types[x - 1]; 2892 controlp = ctlrp; 2893 2894 } 2895 } 2896 2897 static void 2898 check_for_duplicate_disknames(arglist) 2899 char *arglist[]; 2900 { 2901 char *directory = "/dev/rdsk/"; 2902 char **disklist; 2903 int len; 2904 char s[MAXPATHLEN], t[MAXPATHLEN]; 2905 int diskno = 0; 2906 int i; 2907 2908 2909 len = strlen(directory); 2910 disklist = arglist; 2911 for (; *disklist != NULL; disklist++) { 2912 if (strncmp(directory, *disklist, len) == 0) { 2913 /* Disk is in conventional format */ 2914 canonicalize_name(s, *disklist); 2915 /* 2916 * check if the disk is already present in 2917 * disk list. 2918 */ 2919 for (i = 0; i < diskno; i++) { 2920 canonicalize_name(t, arglist[i]); 2921 if (strncmp(s, t, strlen(t)) == 0) 2922 break; 2923 } 2924 if (i != diskno) 2925 continue; 2926 } 2927 (void) strcpy(arglist[diskno], *disklist); 2928 diskno++; 2929 } 2930 arglist[diskno] = NULL; 2931 } 2932 2933 #define DISK_PREFIX "/dev/rdsk/" 2934 2935 /* 2936 * This Function checks if the non-conventional name is a a link to 2937 * one of the conventional whole disk name. 2938 */ 2939 static int 2940 name_represents_wholedisk(name) 2941 char *name; 2942 { 2943 char symname[MAXPATHLEN]; 2944 char localname[MAXPATHLEN]; 2945 char *nameptr; 2946 2947 2948 (void) memset(symname, 0, MAXPATHLEN); 2949 (void) memset(localname, 0, MAXPATHLEN); 2950 (void) strcpy(localname, name); 2951 2952 while (readlink(localname, symname, MAXPATHLEN) != -1) { 2953 nameptr = symname; 2954 if (strncmp(symname, DISK_PREFIX, strlen(DISK_PREFIX)) == 0) 2955 nameptr += strlen(DISK_PREFIX); 2956 if (conventional_name(nameptr)) { 2957 if (whole_disk_name(nameptr)) 2958 return (0); 2959 else 2960 return (1); 2961 } 2962 (void) strcpy(localname, symname); 2963 (void) memset(symname, 0, MAXPATHLEN); 2964 } 2965 return (0); 2966 } 2967