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.
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.
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]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
28 * This file contains the functions for parsing a slice file
32 #include <sys/types.h>
42 #include <sys/fcntl.h>
43 #include <sys/param.h>
47 #include <priv_utils.h>
50 extern void my_perror(char *err_string
);
52 static int32_t last_token_type
= 0;
53 #define spc() (last_token_type)
57 * This global is used to store the current line # in the
58 * data file. It must be global because the I/O routines
59 * are allowed to side effect it to keep track of backslashed
63 static int32_t data_lineno
; /* current line # in data file */
65 #define CHG_MODE_UNDEFINED (-1) /* undefined value */
66 #define CHG_MODE_SET 0 /* set bits by or'ing */
67 #define CHG_MODE_CLR 1 /* clr bits by and'ing */
68 #define CHG_MODE_ABS 2 /* set absolute value */
71 #define TOKEN_SIZE 36 /* max length of a token */
72 typedef char TOKEN
[TOKEN_SIZE
+1]; /* token type */
73 #define DATA_INPUT 0 /* 2 modes of input */
75 #define WILD_STRING "$" /* wildcard character */
76 #define COMMENT_CHAR '#' /* comment character */
79 * List of strings with arbitrary matching values
81 typedef struct slist
{
87 static slist_t ptag_choices
[] = {
88 { "unassigned", "", V_UNASSIGNED
},
89 { "boot", "", V_BOOT
},
90 { "root", "", V_ROOT
},
91 { "swap", "", V_SWAP
},
93 { "backup", "", V_BACKUP
},
94 { "stand", "", V_STAND
},
96 { "home", "", V_HOME
},
97 { "alternates", "", V_ALTSCTR
},
103 * Choices for the p_flag vtoc field
105 static slist_t pflag_choices
[] = {
106 { "wm", "read-write, mountable", 0 },
107 { "wu", "read-write, unmountable", V_UNMNT
},
108 { "rm", "read-only, mountable", V_RONLY
},
109 { "ru", "read-only, unmountable", V_RONLY
|V_UNMNT
},
114 * The definitions are the token types that the data file parser recognizes.
116 #define SUP_EOF -1 /* eof token */
117 #define SUP_STRING 0 /* string token */
118 #define SUP_EQL 1 /* equals token */
119 #define SUP_COMMA 2 /* comma token */
120 #define SUP_COLON 3 /* colon token */
121 #define SUP_EOL 4 /* newline token */
122 #define SUP_OR 5 /* vertical bar */
123 #define SUP_AND 6 /* ampersand */
124 #define SUP_TILDE 7 /* tilde */
128 * Prototypes for ANSI C compilers
130 static int32_t sup_prxfile(char *file_name
, struct extvtoc
*vt
);
131 static int32_t sup_setpart(struct extvtoc
*vt
);
132 static void sup_pushchar(int32_t c
);
133 static void clean_token(char *cleantoken
, char *token
);
134 static void clean_token(char *cleantoken
, char *token
);
135 static int32_t sup_inputchar();
136 static int32_t sup_gettoken(char *buf
);
137 static int32_t sup_get_token(char *buf
);
138 static int32_t find_value(slist_t
*slist
, char *str
, int32_t *value
);
139 static int32_t check_vtoc_sanity(smedia_handle_t
, int32_t fd
,
141 static uint64_t str2sector(char *str
);
142 static int32_t strcnt(char *s1
, char *s2
);
143 static int32_t get_fdisk(smedia_handle_t
, int32_t fd
, int32_t offset
,
144 struct fdisk_info
*fdisk
);
145 static void erase(smedia_handle_t handle
, diskaddr_t offset
, diskaddr_t size
);
148 extern uint64_t my_atoll(char *ptr
);
149 extern smmedium_prop_t med_info
;
151 static FILE *data_file
;
154 sup_prxfile(char *file_name
, struct extvtoc
*vt
)
156 int32_t status
, ret_val
;
161 * Open the data file. Return 0 if unable to do so.
163 data_file
= fopen(file_name
, "r");
164 if (data_file
== NULL
) {
165 PERROR("Open failed");
169 * Step through the data file a meta-line at a time. There are
170 * typically several backslashed newlines in each meta-line,
171 * so data_lineno will be getting side effected along the way.
179 status
= sup_gettoken(token
);
181 * If we hit the end of the data file, we're done.
183 if (status
== SUP_EOF
)
186 * If the line starts with some key character, it's an error.
188 if (status
!= SUP_STRING
) {
189 (void) fprintf(stderr
,
190 gettext("Expecting keyword, found '%s'"),
192 (void) fprintf(stderr
,
193 gettext("Line no %d\n"), data_lineno
);
197 * Clean up the token and see which keyword it is. Call
198 * the appropriate routine to process the rest of the line.
200 clean_token(cleaned
, token
);
201 if (strcmp(cleaned
, "slices") == 0) {
202 ret_val
= sup_setpart(vt
);
203 (void) fclose(data_file
);
206 (void) fprintf(stderr
, gettext("Unknown keyword '%s'"),
208 (void) fprintf(stderr
,
209 gettext("Line no %d\n"), data_lineno
);
210 (void) fclose(data_file
);
215 * Close the data file.
217 (void) fclose(data_file
);
219 (void) fprintf(stderr
,
220 gettext("Unexpected end of file (line no %d)\n"), data_lineno
);
225 sup_gettoken(char *buf
)
228 * Skip end of lines and blank lines.
230 while ((last_token_type
= sup_get_token(buf
)) == SUP_EOL
)
232 return (last_token_type
);
236 sup_get_token(char *buf
)
239 int32_t c
, quoted
= 0;
242 * Was an end of file detected last try?
245 if (feof(data_file
)) {
250 * Zero out the returned token buffer
253 bzero(buf
, TOKEN_SIZE
+ 1);
256 * Strip off leading white-space.
258 while (isspace(c
= sup_inputchar()))
262 * Only white spaces and then end of file?
265 if (feof(data_file
)) {
270 * Read in characters until we hit unquoted white-space.
272 for (; !isspace(c
) || quoted
; c
= sup_inputchar()) {
275 * If we hit eof, check if we have anything in buffer.
276 * if we have, return STRING, next time we will return EOF
277 * else, return EOF here...should not happen.
279 if (feof(data_file
)) {
288 * If we hit a double quote, change the state of quoting.
295 * If we hit a newline, that delimits a token.
300 * If we hit any nonquoted special delimiters, that delimits
303 if (!quoted
&& (c
== '=' || c
== ',' || c
== ':' ||
304 c
== '#' || c
== '|' || c
== '&' || c
== '~'))
307 * Store the character if there's room left.
309 if (ptr
- buf
< TOKEN_SIZE
)
313 * If we stored characters in the buffer, then we inputted a string.
314 * Push the delimiter back into the pipe and return the string.
321 * We didn't input a string, so we must have inputted a known delimiter.
322 * store the delimiter in the buffer, so it will get returned.
326 * Switch on the delimiter. Return the appropriate value for each one.
345 * For comments, we flush out the rest of the line and return
348 while ((c
= sup_inputchar()) != '\n' && !feof(data_file
))
355 * Shouldn't ever get here.
367 * Input the character.
371 * If it's not a backslash, return it.
375 * It was a backslash. Get the next character.
382 * If it was a newline, update the line counter and get the next
389 * Return the character.
395 sup_pushchar(int32_t c
)
398 (void) ungetc(c
, data_file
);
404 clean_token(char *cleantoken
, char *token
)
409 * Strip off leading white-space.
411 for (ptr
= token
; isspace(*ptr
) && (ptr
<=
412 (token
+ strlen(token
) - 1)); ptr
++)
416 * Copy it into the clean buffer.
418 (void) strcpy(cleantoken
, ptr
);
420 * Strip off trailing white-space.
422 for (ptr
= cleantoken
+ strlen(cleantoken
) - 1;
423 isspace(*ptr
) && (ptr
>= cleantoken
); ptr
--) {
429 sup_setpart(struct extvtoc
*vt
)
431 TOKEN token
, cleaned
, ident
;
432 int32_t i
, index
, status
;
434 ushort_t vtoc_tag
= 0xFFFF;
435 ushort_t vtoc_flag
= 0xFFFF;
438 * Pull in some grammar.
441 status
= sup_gettoken(token
);
443 if (status
!= SUP_COLON
) {
444 (void) fprintf(stderr
,
445 gettext("Expecting ':', found '%s'"), token
);
446 (void) fprintf(stderr
,
447 gettext("Line no %d\n"), data_lineno
);
452 status
= sup_gettoken(token
);
453 if (status
!= SUP_STRING
) {
454 (void) fprintf(stderr
,
455 gettext("Expecting string, found '%s'"), token
);
456 (void) fprintf(stderr
,
457 gettext("Line no %d\n"), data_lineno
);
460 clean_token(ident
, token
);
462 * Here's the index of the partition we're dealing with
464 index
= (int32_t)my_atoll(ident
);
465 if ((index
< 0) || (index
>= NDKMAP
)) {
466 (void) fprintf(stderr
,
467 gettext("Unknown partition %d"), index
);
468 (void) fprintf(stderr
,
469 gettext("Line no %d\n"), data_lineno
);
473 * Check for floppy and PCMCIA_MEM cards.
474 * for floppy, the partition no. can be 0 1 2.
475 * for PCMCIA, the partition no. can be 2
477 if (med_info
.sm_media_type
== SM_FLOPPY
) {
478 if ((index
< 0) || (index
> 2)) {
479 (void) fprintf(stderr
, gettext(
480 "Floppy can have partitions 0 1 and 2\n"));
484 if (med_info
.sm_media_type
== SM_PCMCIA_MEM
) {
486 (void) fprintf(stderr
, gettext(
487 "PCMCIA Memory cards can have partition 2 only.\n"));
492 DPRINTF1("\n Partition %d: ", index
);
494 status
= sup_gettoken(token
);
495 if (status
!= SUP_EQL
) {
496 (void) fprintf(stderr
,
497 gettext("Expecting '=', found '%s'"), token
);
498 (void) fprintf(stderr
,
499 gettext("Line no %d\n"), data_lineno
);
505 status
= sup_gettoken(token
);
507 * If we hit a key character, it's an error.
509 if (status
!= SUP_STRING
) {
510 (void) fprintf(stderr
,
511 gettext("Expecting value, found '%s'"), token
);
512 (void) fprintf(stderr
,
513 gettext("Line no %d\n"), data_lineno
);
516 clean_token(cleaned
, token
);
518 * <tag> may be one of: boot, root, swap, etc.
519 * <flag> consists of two characters:
520 * W (writable) or R (read-only)
521 * M (mountable) or U (unmountable)
523 * Start with the defaults assigned above:
527 * All other attributes have a pair of numeric values.
528 * Convert the first value to a number. This value
529 * is the starting cylinder number of the partition.
532 /* Check for valid partition, e.g. > 8 or 16 */
533 val1
= str2sector(cleaned
);
535 (void) fprintf(stderr
,
536 gettext("Invalid partition beggining %s \n"),
538 (void) fprintf(stderr
,
539 gettext("Line no %d\n"), data_lineno
);
542 DPRINTF1(" begins %s", cleaned
);
544 * Pull in some grammar.
546 status
= sup_gettoken(token
);
547 if (status
!= SUP_COMMA
) {
548 (void) fprintf(stderr
,
549 gettext("Expecting ', ', found '%s'"), token
);
550 (void) fprintf(stderr
,
551 gettext("Line no %d\n"), data_lineno
);
555 * Pull in the second value.
557 status
= sup_gettoken(token
);
558 if (status
!= SUP_STRING
) {
559 (void) fprintf(stderr
,
560 gettext("Expecting value, found '%s'"), token
);
561 (void) fprintf(stderr
,
562 gettext("Line no %d\n"), data_lineno
);
565 clean_token(cleaned
, token
);
567 val2
= str2sector(cleaned
);
569 (void) fprintf(stderr
,
570 gettext("Invalid partition size %s \n"),
572 (void) fprintf(stderr
,
573 gettext("Line no %d\n"), data_lineno
);
575 DPRINTF1(" ends %s ", cleaned
);
578 * Pull in some grammar.
580 status
= sup_gettoken(token
);
582 if (status
== SUP_COMMA
) {
584 status
= sup_gettoken(token
);
585 if (status
!= SUP_STRING
) {
586 (void) fprintf(stderr
,
587 gettext("Expecting value, found '%s'"),
589 (void) fprintf(stderr
,
590 gettext("Line no %d\n"), data_lineno
);
593 clean_token(cleaned
, token
);
594 if (find_value(pflag_choices
, cleaned
, &i
) == 1) {
596 * Found valid tag. Use it and advance parser
598 DPRINTF1(" flag = %s", cleaned
);
599 vtoc_flag
= (ushort_t
)i
;
600 status
= sup_gettoken(token
);
601 } else if (find_value(ptag_choices
, cleaned
, &i
) == 1) {
602 DPRINTF1(" tag = %s", cleaned
);
603 vtoc_tag
= (ushort_t
)i
;
604 status
= sup_gettoken(token
);
605 if (status
== SUP_COMMA
) {
606 (void) fprintf(stderr
,
607 gettext("Expecting : got %s\n"),
609 (void) fprintf(stderr
,
610 gettext("Line no %d\n"),
615 (void) fprintf(stderr
,
616 gettext("Invalid flag or tag\n"));
617 (void) fprintf(stderr
,
618 gettext("Line no %d\n"), data_lineno
);
623 if (status
== SUP_COMMA
) {
624 /* Can be tag only */
626 status
= sup_gettoken(token
);
627 if (status
!= SUP_STRING
) {
628 (void) fprintf(stderr
,
629 gettext("Expecting value"
632 (void) fprintf(stderr
,
633 gettext("Line no %d\n"),
638 clean_token(cleaned
, token
);
639 if (find_value(ptag_choices
,
641 DPRINTF1(" tag = %s", cleaned
);
642 vtoc_tag
= (ushort_t
)i
;
644 status
= sup_gettoken(token
);
649 * Fill in the appropriate map entry with the values.
651 vt
->v_part
[index
].p_start
= val1
;
652 vt
->v_part
[index
].p_size
= val2
;
653 if (vtoc_tag
!= 0xFFFF) {
654 vt
->v_part
[index
].p_tag
= vtoc_tag
;
657 if (vtoc_flag
!= 0xFFFF) {
658 vt
->v_part
[index
].p_flag
= vtoc_flag
;
661 if (status
== SUP_EOF
) {
662 DPRINTF("\nEnd of file\n");
665 if (status
!= SUP_COLON
) {
666 (void) fprintf(stderr
,
667 gettext("Expecting ':', found '%s'"), token
);
668 (void) fprintf(stderr
,
669 gettext("Line no %d\n"), data_lineno
);
678 find_value(slist_t
*slist
, char *match_str
, int32_t *match_value
)
683 int32_t match_length
;
688 match_length
= strlen(match_str
);
690 for (; slist
->str
!= NULL
; slist
++) {
692 * See how many characters of the token match
694 i
= strcnt(match_str
, slist
->str
);
696 * If it's not the whole token, then it's not a match.
698 if (i
< match_length
) {
702 * If it ties with another input, remember that.
707 * If it matches the most so far, record that.
710 *match_value
= slist
->value
;
720 strcnt(char *s1
, char *s2
)
724 while ((*s1
!= '\0') && (*s1
++ == *s2
++))
730 str2sector(char *str
)
732 int32_t mul_factor
= 1;
733 char *s1
, *s2
, *base
;
734 uint64_t num_sectors
;
737 base
= s2
= (char *)malloc(strlen(str
) + 1);
739 PERROR("Malloc failed");
748 if ((*s1
!= 'x') && ((*s1
< 'A') || (*s1
> 'F')) &&
749 ((*s1
< 'a') || (*s1
> 'f')) && ((*s1
< '0') ||
752 mul_factor
= 1024*1024*1024;
754 } else if (*s1
== 'M') {
755 mul_factor
= 1024*1024;
757 } else if (*s1
== 'K') {
761 if ((*s1
!= 'B') || (*(++s1
) != NULL
)) {
762 (void) fprintf(stderr
,
763 gettext("Extra chars at the end\n"));
775 size
= my_atoll(base
);
776 if ((!mul_factor
) || (size
== -1)) {
780 num_sectors
= size
* (uint64_t)mul_factor
/512;
783 return (num_sectors
);
788 valid_slice_file(smedia_handle_t handle
, int32_t fd
, char *file_name
,
793 if (stat(file_name
, &status
)) {
797 (void) memset(vt
, 0, sizeof (*vt
));
798 /* Set default tag and flag */
800 vt
->v_part
[0].p_tag
= V_ROOT
;
801 vt
->v_part
[1].p_tag
= V_SWAP
;
802 vt
->v_part
[2].p_tag
= V_BACKUP
;
803 vt
->v_part
[6].p_tag
= V_USR
;
805 vt
->v_part
[1].p_flag
= V_UNMNT
; /* Unmountable */
806 vt
->v_part
[2].p_flag
= V_UNMNT
; /* Unmountable */
809 ret_val
= sup_prxfile(file_name
, vt
);
816 for (i
= 0; i
< 8; i
++) {
817 DPRINTF1("\npart %d\n", i
);
818 DPRINTF1("\t start %llu", vt
->v_part
[i
].p_start
);
819 DPRINTF1("\t size %llu ", vt
->v_part
[i
].p_size
);
820 DPRINTF1("\t tag %d", vt
->v_part
[i
].p_tag
);
821 DPRINTF1("\t flag %d", vt
->v_part
[i
].p_flag
);
825 if (check_vtoc_sanity(handle
, fd
, vt
) < 0) {
831 for (i
= 0; i
< 8; i
++) {
832 DPRINTF1("\npart %d\n", i
);
833 DPRINTF1("\t start %llu", vt
->v_part
[i
].p_start
);
834 DPRINTF1("\t size %llu ", vt
->v_part
[i
].p_size
);
835 DPRINTF1("\t tag %d", vt
->v_part
[i
].p_tag
);
836 DPRINTF1("\t flag %d", vt
->v_part
[i
].p_flag
);
843 #define SWAP(a, b) {diskaddr_t tmp; tmp = (a); (a) = (b); (b) = tmp; }
846 * On x86 Solaris, the partitioning is done in two levels, fdisk and Solaris
847 * VTOC. Where as, on sparc solaris, it is only VTOC. On floppy and PCMCIA
848 * also it is assumed to be only VTOC, no fdisk.
850 * On sparc, the back up slice can cover the whole medium. But on x86
851 * (SCSI/ATAPI disks), the backup slice can cover the solaris partition
853 * Following table describes how is it handled
855 * SCSI/ATAPI, floppy, pcmcia : don't check for fdisk.
856 * DKIOCGGEOM is sufficient.
857 * x86 : floppy, pcmcia : Don't check for fdisk. DKIOCGGEOM is sufficient.
858 * SCSI/ATAPI : Check for fdisk.
859 * if not present, assume that the solaris
860 * partition covers 100% of the medium
861 * (minus one cylinder).
864 * check for active solaris partition.
865 * if not found, take the first solaris
867 * If there are no solaris partitions, its an error, stop.
871 check_vtoc_sanity(smedia_handle_t handle
, int32_t fd
, struct extvtoc
*vt
)
876 int32_t num_backup
= 0;
877 diskaddr_t backup_size
= 0;
884 int32_t min_slice
, num_slices
;
885 diskaddr_t media_size
;
887 int sparc_style
= 0; /* sparc_style handling ? */
888 struct fdisk_info fdisk
;
896 if ((med_info
.sm_media_type
== SM_FLOPPY
) ||
897 (med_info
.sm_media_type
== SM_PCMCIA_MEM
) ||
898 (med_info
.sm_media_type
== SM_PCMCIA_ATA
) ||
899 (med_info
.sm_media_type
== SM_SCSI_FLOPPY
)) {
904 DPRINTF("sparc style true\n");
905 if (ioctl(fd
, DKIOCGGEOM
, &dkg
) < 0) {
906 PERROR("DKIOCGGEOM Failed");
909 media_size
= (diskaddr_t
)dkg
.dkg_ncyl
* dkg
.dkg_nhead
*
911 cyl_size
= dkg
.dkg_nhead
* dkg
.dkg_nsect
;
916 * Try to get the fdisk information if available.
918 if (get_fdisk(handle
, fd
, 0, &fdisk
) >= 0) {
919 /* fdisk table on disk */
921 for (i
= 0; i
< FD_NUMPART
; i
++) {
922 if (fdisk
.part
[i
].systid
== SUNIXOS
||
923 fdisk
.part
[i
].systid
== SUNIXOS2
) {
924 if (sol_part
== 0xFF)
927 if (fdisk
.part
[i
].bootid
== ACTIVE
)
931 if (sol_part
== 0xFF) {
932 /* No Solaris partition */
934 (void) fprintf(stderr
, gettext("No FDISK \
935 Solaris partition found!\n"));
939 (void) fprintf(stderr
, gettext("Multiple FDISK \
940 Solaris partitions found.\n"));
941 media_size
= (diskaddr_t
)fdisk
.part
[sol_part
].numsect
;
943 DPRINTF1("sol_part %d\n", sol_part
);
944 DPRINTF1("media_size %llu\n", media_size
);
946 DPRINTF("Didn't get fdisk\n");
948 * No fdisk partition available. Assume a 100% Solaris.
950 * Try getting disk geometry.
952 if (ioctl(fd
, DKIOCGGEOM
, &dkg
) < 0)
953 if (ioctl(fd
, DKIOCG_PHYGEOM
, &dkg
) < 0) {
954 DPRINTF("DKIOCG_PHYGEOM ioctl failed");
957 /* On x86 platform 1 cylinder is used for fdisk table */
958 dkg
.dkg_ncyl
= dkg
.dkg_ncyl
- 1;
959 media_size
= (diskaddr_t
)dkg
.dkg_ncyl
* dkg
.dkg_nhead
*
965 DPRINTF1("Ncyl %d\n", dkg
.dkg_ncyl
);
966 DPRINTF1("nhead %d\n", dkg
.dkg_nhead
);
967 DPRINTF1("nsect %d\n", dkg
.dkg_nsect
);
970 if (media_size
== 0) {
971 media_size
= (uint32_t)med_info
.sm_capacity
;
974 (void) memset(&part
, 0, sizeof (part
));
975 for (i
= 0, j
= 0; i
< NDKMAP
; i
++) {
976 if (vt
->v_part
[i
].p_tag
== V_BACKUP
) {
977 if (vt
->v_part
[i
].p_start
!= 0) {
978 (void) fprintf(stderr
,
980 "Backup slice should start at sector 0\n"));
983 backup_size
= vt
->v_part
[i
].p_size
;
987 if (vt
->v_part
[i
].p_size
) {
990 if (vt
->v_part
[i
].p_start
% cyl_size
) {
991 (void) fprintf(stderr
,
993 "Slice %d does not start on cylinder boundary\n"), i
);
994 (void) fprintf(stderr
,
996 "Cylinder size %d 512 byte sectors\n"), cyl_size
);
1000 part
[j
].start
= vt
->v_part
[i
].p_start
;
1001 part
[j
].end
= vt
->v_part
[i
].p_start
+
1002 vt
->v_part
[i
].p_size
-1;
1007 if (num_backup
> 1) {
1008 (void) fprintf(stderr
,
1009 gettext("Maximum one backup slice is allowed\n"));
1010 (void) smedia_release_handle(handle
);
1016 for (i
= 0; i
< num_slices
; i
++) {
1017 min_val
= part
[i
].start
;
1019 for (j
= i
+1; j
< num_slices
; j
++) {
1020 if (part
[j
].start
< min_val
) {
1021 min_val
= part
[j
].start
;
1025 if (min_slice
!= i
) {
1026 SWAP(part
[i
].start
, part
[min_slice
].start
)
1027 SWAP(part
[i
].end
, part
[min_slice
].end
)
1028 SWAP(part
[i
].num
, part
[min_slice
].num
)
1033 for (i
= 0; i
< num_slices
; i
++) {
1034 DPRINTF4("\n %d (%d) : %llu, %llu", i
, part
[i
].num
,
1035 part
[i
].start
, part
[i
].end
);
1039 if (backup_size
> media_size
) {
1041 (void) fprintf(stderr
,
1043 "Backup slice extends beyond size of media\n"));
1044 (void) fprintf(stderr
,
1045 gettext("media size : %llu sectors \n"),
1049 (void) fprintf(stderr
,
1050 gettext("Backup slice extends beyond size of FDISK \
1051 Solaris partition\n"));
1052 (void) fprintf(stderr
,
1054 "FDISK Solaris partition size : %llu sectors \n"),
1061 * If we have only backup slice return success here.
1063 if (num_slices
== 0)
1067 if (part
[num_slices
- 1].end
> backup_size
) {
1068 (void) fprintf(stderr
,
1069 gettext("Slice %d extends beyond backup slice.\n"),
1070 part
[num_slices
-1].num
);
1074 if (part
[num_slices
- 1].end
> media_size
) {
1076 (void) fprintf(stderr
,
1078 "Slice %d extends beyond media size\n"),
1079 part
[num_slices
-1].num
);
1080 (void) fprintf(stderr
,
1081 gettext("media size : %llu sectors \n"),
1084 (void) fprintf(stderr
,
1085 gettext("Slice %d extends beyond FDISK"
1086 " Solaris partition size\n"),
1087 part
[num_slices
-1].num
);
1088 (void) fprintf(stderr
, gettext(
1089 "FDISK Solaris partition size : %llu "
1090 "sectors \n"), media_size
);
1098 for (i
= 0; i
< num_slices
; i
++) {
1101 if (part
[i
].start
<= part
[i
-1].end
) {
1102 (void) fprintf(stderr
,
1103 gettext("Overlap between slices %d and %d\n"),
1104 part
[i
-1].num
, part
[i
].num
);
1105 (void) smedia_release_handle(handle
);
1116 get_fdisk(smedia_handle_t handle
, int32_t fd
, int32_t offset
,
1117 struct fdisk_info
*fdisk
)
1119 struct mboot
*boot_sec
;
1125 /* Read the master boot program */
1127 buf
= (char *)malloc(med_info
.sm_blocksize
);
1129 PERROR("malloc failed");
1133 ret
= ioctl(fd
, DKIOCGMBOOT
, buf
);
1135 if (errno
!= ENOTTY
) {
1136 PERROR("DKIOCGMBOOT ioctl failed");
1140 /* Turn on privileges. */
1141 (void) __priv_bracket(PRIV_ON
);
1143 ret
= smedia_raw_read(handle
,
1144 (diskaddr_t
)offset
/med_info
.sm_blocksize
,
1145 buf
, med_info
.sm_blocksize
);
1147 /* Turn off privileges. */
1148 (void) __priv_bracket(PRIV_OFF
);
1152 if (ret
!= med_info
.sm_blocksize
) {
1153 if (errno
== ENOTSUP
) {
1155 if (lseek(fd
, offset
, SEEK_SET
)) {
1156 PERROR("Seek failed:");
1161 /* Turn on privileges. */
1162 (void) __priv_bracket(PRIV_ON
);
1164 ret
= read(fd
, buf
, sizeof (struct mboot
));
1166 /* Turn off privileges. */
1167 (void) __priv_bracket(PRIV_OFF
);
1169 if (ret
!= sizeof (struct mboot
)) {
1170 PERROR("Could not read "
1171 "master boot record");
1176 PERROR("Could not read master boot record");
1182 /* LINTED pointer cast may result in improper alignment */
1183 boot_sec
= (struct mboot
*)buf
;
1185 /* Is this really a master boot record? */
1186 if (les(boot_sec
->signature
) != MBB_MAGIC
) {
1187 DPRINTF("fdisk: Invalid master boot file \n");
1188 DPRINTF2("Bad magic number: is %x, should be %x.\n",
1189 les(boot_sec
->signature
), MBB_MAGIC
);
1194 for (i
= 0; i
< FD_NUMPART
; i
++) {
1195 DPRINTF1("part %d\n", i
);
1196 /* LINTED pointer cast may result in improper alignment */
1197 part
= (struct ipart
*)&boot_sec
->parts
[i
*
1198 sizeof (struct ipart
)];
1199 fdisk
->part
[i
].bootid
= part
->bootid
;
1200 if (part
->bootid
&& (part
->bootid
!= ACTIVE
)) {
1201 /* Hmmm...not a valid fdisk! */
1204 fdisk
->part
[i
].systid
= part
->systid
;
1206 /* To avoid the misalign access in sparc */
1208 fdisk
->part
[i
].relsect
= lel(GET_32(&(part
->relsect
)));
1209 fdisk
->part
[i
].numsect
= lel(GET_32(&(part
->numsect
)));
1211 DPRINTF1("\tboot id 0x%x\n", part
->bootid
);
1212 DPRINTF1("\tsystem id 0x%x\n", part
->systid
);
1213 DPRINTF1("\trel sector 0x%x\n", fdisk
->part
[i
].relsect
);
1214 DPRINTF1("\tnum sector 0x%x\n", fdisk
->part
[i
].numsect
);
1222 * wrrite_defualt_label(int32_t fd)
1223 * fd = file descriptor for the device.
1226 * Create a vtoc partition with
1227 * slice 0 = slice 2 = medium capacity.
1228 * The cyl, head, sect (CHS) values are computed as done in sd
1230 * nhead = 64, nsect = 32
1232 * nhead = 255, nsect = 63
1235 * Create a fdisk partition,
1236 * partition 0 covers the full medium, the partition
1237 * type is set to Solaris.
1238 * Then create solaris vtoc. The algorithm is same as sparc solaris.
1239 * But the capacity is reduced by 1 cyl, to leave space for fdisk table.
1245 write_default_label(smedia_handle_t handle
, int32_t fd
)
1248 struct extvtoc v_toc
;
1249 uint32_t nhead
, numcyl
, nsect
;
1250 diskaddr_t capacity
;
1252 char asciilabel
[LEN_DKL_ASCII
];
1253 char asciilabel2
[LEN_DKL_ASCII
] = "DEFAULT\0";
1257 DPRINTF("Writing default vtoc\n");
1258 (void) memset(&v_toc
, 0, sizeof (v_toc
));
1261 v_toc
.v_nparts
= V_NUMPAR
;
1262 v_toc
.v_sanity
= VTOC_SANE
;
1263 v_toc
.v_version
= V_VERSION
;
1264 v_toc
.v_sectorsz
= DEV_BSIZE
;
1267 * For the head, cyl and number of sector per track,
1268 * if the capacity <= 1GB, head = 64, sect = 32.
1269 * else head = 255, sect 63
1270 * NOTE: the capacity should be equal to C*H*S values.
1271 * This will cause some truncation of size due to
1274 if ((uint32_t)med_info
.sm_capacity
<= 0x200000) {
1282 numcyl
= (uint32_t)med_info
.sm_capacity
/ (nhead
* nsect
);
1283 capacity
= (diskaddr_t
)nhead
* nsect
* numcyl
;
1285 v_toc
.v_part
[0].p_start
= 0;
1286 v_toc
.v_part
[0].p_size
= capacity
;
1287 v_toc
.v_part
[0].p_tag
= V_ROOT
;
1288 v_toc
.v_part
[0].p_flag
= 0; /* Mountable */
1290 v_toc
.v_part
[2].p_start
= 0;
1291 v_toc
.v_part
[2].p_size
= capacity
;
1292 v_toc
.v_part
[2].p_tag
= V_BACKUP
;
1293 v_toc
.v_part
[2].p_flag
= V_UNMNT
;
1295 /* Create asciilabel for compatibility with format utility */
1296 (void) snprintf(asciilabel
, sizeof (asciilabel
),
1297 "%s cyl %d alt %d hd %d sec %d",
1298 asciilabel2
, numcyl
, acyl
, nhead
, nsect
);
1299 (void) memcpy(v_toc
.v_asciilabel
, asciilabel
,
1304 /* Turn on privileges. */
1305 (void) __priv_bracket(PRIV_ON
);
1307 ret
= write_extvtoc(fd
, &v_toc
);
1309 /* Turn off privileges. */
1310 (void) __priv_bracket(PRIV_OFF
);
1313 PERROR("write VTOC failed");
1314 DPRINTF1("Errno = %d\n", errno
);
1322 write_default_label(smedia_handle_t handle
, int32_t fd
)
1327 struct extvtoc v_toc
;
1330 struct mboot boot_code
; /* Buffer for master boot record */
1331 struct ipart parts
[FD_NUMPART
];
1332 uint32_t numcyl
, nhead
, nsect
;
1335 diskaddr_t capacity
;
1337 size_t bytes_written
;
1338 char asciilabel
[LEN_DKL_ASCII
];
1339 char asciilabel2
[LEN_DKL_ASCII
] = "DEFAULT\0";
1342 DPRINTF("Writing default fdisk table and vtoc\n");
1343 (void) memset(&v_toc
, 0, sizeof (v_toc
));
1345 * Try getting disk geometry.
1347 if (ioctl(fd
, DKIOCGGEOM
, &dkg
) < 0)
1348 if (ioctl(fd
, DKIOCG_PHYGEOM
, &dkg
) < 0) {
1350 DPRINTF("DKIOCG_PHYGEOM ioctl failed");
1354 tmp_fd
= open("/usr/lib/fs/ufs/mboot", O_RDONLY
);
1359 if (read(tmp_fd
, &boot_code
, sizeof (struct mboot
))
1360 != sizeof (struct mboot
)) {
1361 (void) close(tmp_fd
);
1365 blocksize
= med_info
.sm_blocksize
;
1366 fdisk_buf
= (char *)malloc(blocksize
);
1367 if (fdisk_buf
== NULL
) {
1368 DPRINTF("malloc for fdisk_buf failed\n");
1372 (void) memset(&parts
, 0, sizeof (parts
));
1374 for (i
= 0; i
< FD_NUMPART
; i
++) {
1375 parts
[i
].systid
= UNUSED
;
1376 parts
[i
].numsect
= lel(UNUSED
);
1377 parts
[i
].relsect
= lel(UNUSED
);
1378 parts
[i
].bootid
= 0;
1381 numcyl
= dkg
.dkg_ncyl
;
1382 nhead
= dkg
.dkg_nhead
;
1383 nsect
= dkg
.dkg_nsect
;
1385 parts
[0].bootid
= ACTIVE
;
1386 parts
[0].begsect
= 1;
1390 parts
[0].relsect
= lel(nhead
* nsect
);
1391 parts
[0].numsect
= lel(((diskaddr_t
)numcyl
* nhead
* nsect
));
1392 parts
[0].systid
= SUNIXOS2
; /* Solaris */
1393 parts
[0].beghead
= 0;
1394 parts
[0].begcyl
= 1;
1395 parts
[0].endhead
= nhead
- 1;
1396 parts
[0].endsect
= (nsect
& 0x3f) |
1397 (char)((unixend
>> 2) & 0x00c0);
1398 parts
[0].endcyl
= (char)(unixend
& 0x00ff);
1400 (void) memcpy(&(boot_code
.parts
), parts
, sizeof (parts
));
1401 (void) memcpy(fdisk_buf
, &boot_code
, sizeof (boot_code
));
1403 /* Turn on privileges. */
1404 (void) __priv_bracket(PRIV_ON
);
1406 ret
= ioctl(fd
, DKIOCSMBOOT
, fdisk_buf
);
1408 /* Turn off privileges. */
1409 (void) __priv_bracket(PRIV_OFF
);
1412 if (errno
!= ENOTTY
) {
1413 PERROR("DKIOCSMBOOT ioctl Failed");
1417 /* Turn on privileges. */
1418 (void) __priv_bracket(PRIV_ON
);
1420 bytes_written
= smedia_raw_write(handle
, (diskaddr_t
)0,
1421 fdisk_buf
, blocksize
);
1423 /* Turn off privileges. */
1424 (void) __priv_bracket(PRIV_OFF
);
1428 if (bytes_written
!= blocksize
) {
1429 if (errno
== ENOTSUP
) {
1431 /* Turn on privileges. */
1432 (void) __priv_bracket(PRIV_ON
);
1434 ret
= write(fd
, fdisk_buf
, blocksize
);
1436 /* Turn off privileges. */
1437 (void) __priv_bracket(PRIV_OFF
);
1439 if (ret
!= blocksize
) {
1447 capacity
= (diskaddr_t
)(numcyl
- 1) * nhead
* nsect
;
1449 v_toc
.v_nparts
= V_NUMPAR
;
1450 v_toc
.v_sanity
= VTOC_SANE
;
1451 v_toc
.v_version
= V_VERSION
;
1452 v_toc
.v_sectorsz
= DEV_BSIZE
;
1454 v_toc
.v_part
[0].p_start
= 0;
1455 v_toc
.v_part
[0].p_size
= capacity
;
1456 v_toc
.v_part
[0].p_tag
= V_ROOT
;
1457 v_toc
.v_part
[0].p_flag
= 0; /* Mountable */
1459 v_toc
.v_part
[2].p_start
= 0;
1460 v_toc
.v_part
[2].p_size
= capacity
;
1461 v_toc
.v_part
[2].p_tag
= V_BACKUP
;
1462 v_toc
.v_part
[2].p_flag
= V_UNMNT
;
1464 /* Create asciilabel for compatibility with format utility */
1465 (void) snprintf(asciilabel
, sizeof (asciilabel
),
1466 "%s cyl %d alt %d hd %d sec %d",
1467 asciilabel2
, numcyl
, acyl
, nhead
, nsect
);
1468 (void) memcpy(v_toc
.v_asciilabel
, asciilabel
,
1474 /* Turn on privileges. */
1475 (void) __priv_bracket(PRIV_ON
);
1477 ret
= write_extvtoc(fd
, &v_toc
);
1479 /* Turn off privileges. */
1480 (void) __priv_bracket(PRIV_OFF
);
1483 PERROR("write VTOC failed");
1484 DPRINTF1("Errno = %d\n", errno
);
1490 #error One of sparc or i386 must be defined!
1496 * void overwrite_metadata(int32_t fd, smedia_handle_t handle)
1498 * purpose : quick format does not erase the data on Iomega
1499 * zip/jaz media. So, the meta data on the disk should be erased.
1501 * If there is a valid fdisk table,
1502 * erase first 64K of each partition.
1503 * If there is a valid vtoc,
1504 * erase first 64k of each slice.
1505 * Then erase the 0th sector (the home for vtoc and fdisk) of the disk.
1506 * Note that teh vtoc on x86 resides in one of the fdisk partition.
1507 * So delay the erasing of the solaris partition until the vtoc is read.
1511 overwrite_metadata(int32_t fd
, smedia_handle_t handle
)
1514 struct fdisk_info fdisk
;
1515 diskaddr_t sol_offset
= 0;
1517 struct extvtoc t_vtoc
;
1519 diskaddr_t sol_size
= 0;
1523 /* Get fdisk info. */
1524 if (get_fdisk(handle
, fd
, 0, &fdisk
) >= 0) {
1525 /* Got a valid fdisk */
1526 for (i
= 0; i
< FD_NUMPART
; i
++) {
1528 if (fdisk
.part
[i
].numsect
== 0)
1530 if ((fdisk
.part
[i
].systid
== UNUSED
) ||
1531 (fdisk
.part
[i
].systid
== 0))
1534 if (fdisk
.part
[i
].systid
== SUNIXOS
||
1535 fdisk
.part
[i
].systid
== SUNIXOS2
) {
1537 sol_offset
= fdisk
.part
[i
].relsect
;
1538 sol_size
= fdisk
.part
[i
].numsect
;
1539 if (fdisk
.part
[i
].bootid
== ACTIVE
)
1542 } else if ((fdisk
.part
[i
].bootid
== ACTIVE
) &&
1544 erase(handle
, sol_offset
, sol_size
);
1545 sol_offset
= fdisk
.part
[i
].relsect
;
1546 sol_size
= fdisk
.part
[i
].numsect
;
1552 erase(handle
, (diskaddr_t
)fdisk
.part
[i
].relsect
,
1553 (diskaddr_t
)fdisk
.part
[i
].numsect
);
1557 (void) memset(&t_vtoc
, 0, sizeof (t_vtoc
));
1560 /* fdisk x86 Solaris partition */
1561 /* VTOC location in solaris partition is DK_LABEL_LOC */
1563 /* Turn on privileges. */
1564 (void) __priv_bracket(PRIV_ON
);
1566 ret
= read_extvtoc(fd
, &t_vtoc
);
1568 /* Turn off privileges. */
1569 (void) __priv_bracket(PRIV_OFF
);
1572 /* No valid vtoc, erase fdisk table. */
1573 erase(handle
, (diskaddr_t
)0, (diskaddr_t
)1);
1577 /* Sparc Solaris or x86 solaris with faked fdisk */
1579 /* Turn on privileges */
1580 (void) __priv_bracket(PRIV_ON
);
1582 ret
= read_extvtoc(fd
, &t_vtoc
);
1584 /* Turn off privileges. */
1585 (void) __priv_bracket(PRIV_OFF
);
1588 /* No valid vtoc, erase from 0th sector */
1589 erase(handle
, (diskaddr_t
)0,
1590 (uint32_t)med_info
.sm_capacity
);
1595 for (i
= 0; i
< V_NUMPAR
; i
++) {
1596 if (t_vtoc
.v_part
[i
].p_size
!= 0) {
1597 erase(handle
, sol_offset
+ t_vtoc
.v_part
[i
].p_start
,
1598 t_vtoc
.v_part
[i
].p_size
);
1600 * To make the udfs not recognise the partition we will
1601 * erase sectors 256, (p_size-256) and psize.
1604 sol_offset
+ t_vtoc
.v_part
[i
].p_start
+ 256,
1607 (sol_offset
+ t_vtoc
.v_part
[i
].p_start
+
1608 t_vtoc
.v_part
[i
].p_size
- 256),
1611 (sol_offset
+ t_vtoc
.v_part
[i
].p_start
+
1612 t_vtoc
.v_part
[i
].p_size
- 1),
1618 * If x86 fdisk solaris partition, erase the vtoc also.
1619 * for sparc, the erasing 0the sector erases vtoc.
1622 erase(handle
, sol_offset
, (diskaddr_t
)DK_LABEL_LOC
+ 2);
1626 * erase the 0th sector, it is not guaranteed to be
1627 * erased in the above sequence.
1630 erase(handle
, (diskaddr_t
)0, (diskaddr_t
)1);
1634 * void erase(smedia_handle_t handle, uint32_t offset, uint32_t size)
1636 * Initialize the media with '0' from offset 'offset' upto 'size'
1637 * or 128 blocks(64k), whichever is smaller.
1641 erase(smedia_handle_t handle
, diskaddr_t offset
, diskaddr_t size
)
1644 diskaddr_t nblocks
= size
;
1648 nblocks
= (nblocks
< 128) ? nblocks
: 128;
1649 buf
= (char *)malloc(nblocks
* med_info
.sm_blocksize
);
1651 PERROR("malloc failed");
1654 (void) memset(buf
, 0, (size_t)nblocks
* med_info
.sm_blocksize
);
1656 /* Turn on privileges. */
1657 (void) __priv_bracket(PRIV_ON
);
1659 ret
= smedia_raw_write(handle
, offset
, buf
,
1660 (size_t)nblocks
* med_info
.sm_blocksize
);
1662 /* Turn off privileges. */
1663 (void) __priv_bracket(PRIV_OFF
);
1665 if (ret
!= (nblocks
* med_info
.sm_blocksize
))
1666 PERROR("error in writing\n");