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