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