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