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