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