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