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