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