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