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]
21 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
22 /* All Rights Reserved */
27 * Portions of this source code were provided by International
28 * Computers Limited (ICL) under a development agreement with AT&T.
32 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
33 * Use is subject to license terms.
37 * Sun Microsystems version of fmthard:
39 * Supports the following arguments:
41 * -i Writes VTOC to stdout, rather than disk
42 * -q Quick check: exit code 0 if VTOC ok
43 * -d <data> Incremental changes to the VTOC
44 * -n <vname> Change volume name to <vname>
45 * -s <file> Read VTOC information from <file>, or stdin ("-")
46 * -u <state> Reboot after writing VTOC, according to <state>:
47 * boot: AD_BOOT (standard reboot)
48 * firm: AD_IBOOT (interactive reboot)
50 * Note that fmthard cannot write a VTOC on an unlabeled disk.
51 * You must use format or SunInstall for this purpose.
52 * (NOTE: the above restriction only applies on Sparc systems).
54 * The primary motivation for fmthard is to duplicate the
55 * partitioning from disk to disk:
57 * prtvtoc /dev/rdsk/c0t0d0s2 | fmthard -s - /dev/rdsk/c0t1d0s2
66 #include <sys/types.h>
67 #include <sys/param.h>
68 #include <sys/int_limits.h>
70 #include <sys/uadmin.h>
74 #include <sys/isa_defs.h>
75 #include <sys/efi_partition.h>
77 #if defined(_SUNOS_VTOC_16)
78 #include <sys/dklabel.h>
81 #include <sys/sysmacros.h>
84 #define SECSIZE DEV_BSIZE
90 extern int main(int, char **);
91 static void display(struct dk_geom
*, struct extvtoc
*, char *);
92 static void display64(struct dk_gpt
*, char *);
93 static void insert(char *, struct extvtoc
*);
94 static void insert64(char *, struct dk_gpt
*);
95 static void load(FILE *, struct dk_geom
*, struct extvtoc
*);
96 static void load64(FILE *, int fd
, struct dk_gpt
**);
97 static void usage(void);
98 static void validate(struct dk_geom
*, struct extvtoc
*);
99 static void validate64(struct dk_gpt
*);
100 static int vread(int, struct extvtoc
*, char *);
101 static void vread64(int, struct dk_gpt
**, char *);
102 static void vwrite(int, struct extvtoc
*, char *);
103 static void vwrite64(int, struct dk_gpt
*, char *);
108 static char *delta
; /* Incremental update */
109 static short eflag
; /* force write of an EFI label */
110 static short iflag
; /* Prints VTOC w/o updating */
111 static short qflag
; /* Check for a formatted disk */
112 static short uflag
; /* Exit to firmware after writing */
113 /* new vtoc and reboot. Used during */
114 /* installation of core floppies */
115 static diskaddr_t lastlba
= 0; /* last LBA on 64-bit VTOC */
118 static char *uboot
= "boot";
121 /* use installboot(1M) to install boot blocks */
122 static char *uboot
= "";
124 #error No platform defined.
125 #endif /* various platform-specific definitions */
127 static char *ufirm
= "firm";
129 #if defined(_SUNOS_VTOC_16)
130 static struct extvtoc disk_vtoc
;
131 #endif /* defined(_SUNOS_VTOC_16) */
134 main(int argc
, char **argv
)
141 #if defined(_SUNOS_VTOC_8)
142 struct extvtoc disk_vtoc
;
143 #endif /* defined(_SUNOS_VTOC_8) */
144 struct dk_gpt
*disk_efi
;
145 struct dk_geom disk_geom
;
146 struct dk_minfo minfo
;
154 while ((c
= getopt(argc
, argv
, "ed:u:in:qs:")) != EOF
)
157 while ((c
= getopt(argc
, argv
, "ed:u:in:qb:p:s:")) != EOF
)
160 #error No platform defined.
166 (void) fprintf(stderr
,
167 "fmthard: -p and -b no longer supported."
168 " Use installboot(1M) to install boot blocks\n");
170 #endif /* defined(i386) */
191 if (strcmp(uboot
, optarg
) == 0)
193 else if (strcmp(ufirm
, optarg
) == 0)
202 if (argc
- optind
!= 1)
205 if (stat(argv
[optind
], (struct stat
*)&statbuf
) == -1) {
206 (void) fprintf(stderr
,
207 "fmthard: Cannot stat device %s\n",
212 if ((statbuf
.st_mode
& S_IFMT
) != S_IFCHR
) {
213 (void) fprintf(stderr
,
214 "fmthard: %s must be a raw device.\n",
219 if ((fd
= open(argv
[optind
], O_RDWR
|O_NDELAY
)) < 0) {
220 (void) fprintf(stderr
, "fmthard: Cannot open device %s - %s\n",
221 argv
[optind
], strerror(errno
));
225 if (ioctl(fd
, DKIOCGMEDIAINFO
, &minfo
) == 0) {
226 sectsiz
= minfo
.dki_lbsize
;
234 * Get the geometry information for this disk from the driver
236 if (!eflag
&& ioctl(fd
, DKIOCGGEOM
, &disk_geom
)) {
238 perror("DKIOCGGEOM failed");
240 if (errno
== ENOTSUP
) {
241 /* disk has EFI labels */
244 (void) fprintf(stderr
,
245 "%s: Cannot get disk geometry\n", argv
[optind
]);
252 * Read the vtoc on the disk
255 if (vread(fd
, &disk_vtoc
, argv
[optind
]) == 1)
258 if (eflag
&& ((dfile
== NULL
) || qflag
)) {
259 vread64(fd
, &disk_efi
, argv
[optind
]);
263 * Quick check for valid disk: 0 if ok, 1 if not
268 exit(disk_vtoc
.v_sanity
== VTOC_SANE
? 0 : 1);
270 exit(disk_efi
->efi_version
<= EFI_VERSION102
? 0 : 1);
275 * Incremental changes to the VTOC
279 insert(delta
, &disk_vtoc
);
280 validate(&disk_geom
, &disk_vtoc
);
281 vwrite(fd
, &disk_vtoc
, argv
[optind
]);
283 insert64(delta
, disk_efi
);
284 validate64(disk_efi
);
285 vwrite64(fd
, disk_efi
, argv
[optind
]);
291 if (!dfile
&& !vname
)
295 * Read new VTOC from stdin or data file
298 if (strcmp(dfile
, "-") == 0) {
300 load(stdin
, &disk_geom
, &disk_vtoc
);
302 load64(stdin
, fd
, &disk_efi
);
305 if ((fp
= fopen(dfile
, "r")) == NULL
) {
306 (void) fprintf(stderr
, "Cannot open file %s\n",
312 load(fp
, &disk_geom
, &disk_vtoc
);
314 load64(fp
, fd
, &disk_efi
);
320 * Print the modified VTOC, rather than updating the disk
324 display(&disk_geom
, &disk_vtoc
, argv
[optind
]);
326 display64(disk_efi
, argv
[optind
]);
332 n
= MIN(strlen(vname
) + 1, LEN_DKL_VVOL
);
334 (void) memcpy(disk_vtoc
.v_volume
, vname
, n
);
336 for (c
= 0; c
< disk_efi
->efi_nparts
; c
++) {
337 if (disk_efi
->efi_parts
[c
].p_tag
==
339 (void) memcpy(&disk_efi
->efi_parts
[c
].p_name
,
347 * Write the new VTOC on the disk
350 validate(&disk_geom
, &disk_vtoc
);
351 vwrite(fd
, &disk_vtoc
, argv
[optind
]);
353 validate64(disk_efi
);
354 vwrite64(fd
, disk_efi
, argv
[optind
]);
358 * Shut system down after writing a new vtoc to disk
359 * This is used during installation of core floppies.
362 (void) uadmin(A_REBOOT
, AD_BOOT
, 0);
364 (void) uadmin(A_REBOOT
, AD_IBOOT
, 0);
366 (void) printf("fmthard: New volume table of contents now in place.\n");
376 * display contents of VTOC without writing it to disk
379 display(struct dk_geom
*geom
, struct extvtoc
*vtoc
, char *device
)
387 (void) printf("* %s default partition map\n", device
);
388 if (*vtoc
->v_volume
) {
389 (void) printf("* Volume Name: ");
390 for (i
= 0; i
< LEN_DKL_VVOL
; i
++) {
391 if ((c
= vtoc
->v_volume
[i
]) == 0)
393 (void) printf("%c", c
);
397 (void) printf("*\n");
398 (void) printf("* Dimensions:\n");
399 (void) printf("* %d bytes/sector\n", sectsiz
);
400 (void) printf("* %d sectors/track\n", geom
->dkg_nsect
);
401 (void) printf("* %d tracks/cylinder\n", geom
->dkg_nhead
);
402 (void) printf("* %d cylinders\n", geom
->dkg_pcyl
);
403 (void) printf("* %d accessible cylinders\n", geom
->dkg_ncyl
);
404 (void) printf("*\n");
405 (void) printf("* Flags:\n");
406 (void) printf("* 1: unmountable\n");
407 (void) printf("* 10: read-only\n");
408 (void) printf("*\n");
410 "\n* Partition Tag Flag First Sector Sector Count\n");
411 for (i
= 0; i
< V_NUMPAR
; i
++) {
412 if (vtoc
->v_part
[i
].p_size
> 0)
414 " %d %d 0%x %llu %llu\n",
415 i
, vtoc
->v_part
[i
].p_tag
,
416 vtoc
->v_part
[i
].p_flag
,
417 vtoc
->v_part
[i
].p_start
,
418 vtoc
->v_part
[i
].p_size
);
426 * display64 contents of EFI partition without writing it to disk
429 display64(struct dk_gpt
*efi
, char *device
)
436 (void) printf("* %s default partition map\n", device
);
437 (void) printf("*\n");
438 (void) printf("* Dimensions:\n");
439 (void) printf("* %d bytes/sector\n", efi
->efi_lbasize
);
440 (void) printf("* N/A sectors/track\n");
441 (void) printf("* N/A tracks/cylinder\n");
442 (void) printf("* N/A cylinders\n");
443 (void) printf("* N/A accessible cylinders\n");
444 (void) printf("*\n");
445 (void) printf("* Flags:\n");
446 (void) printf("* 1: unmountable\n");
447 (void) printf("* 10: read-only\n");
448 (void) printf("*\n");
450 "\n* Partition Tag Flag First Sector Sector Count\n");
451 for (i
= 0; i
< efi
->efi_nparts
; i
++) {
452 if (efi
->efi_parts
[i
].p_size
> 0)
454 " %d %d 0%x %8lld %8lld\n",
455 i
, efi
->efi_parts
[i
].p_tag
,
456 efi
->efi_parts
[i
].p_flag
,
457 efi
->efi_parts
[i
].p_start
,
458 efi
->efi_parts
[i
].p_size
);
467 * Insert a change into the VTOC.
470 insert(char *data
, struct extvtoc
*vtoc
)
478 if (sscanf(data
, "%d:%d:%x:%llu:%llu",
479 &part
, &tag
, &flag
, &start
, &size
) != 5) {
480 (void) fprintf(stderr
, "Delta syntax error on \"%s\"\n", data
);
483 if (part
>= V_NUMPAR
) {
484 (void) fprintf(stderr
,
485 "Error in data \"%s\": No such partition %x\n",
489 vtoc
->v_part
[part
].p_tag
= (ushort_t
)tag
;
490 vtoc
->v_part
[part
].p_flag
= (ushort_t
)flag
;
491 vtoc
->v_part
[part
].p_start
= start
;
492 vtoc
->v_part
[part
].p_size
= size
;
498 * Insert a change into the VTOC.
501 insert64(char *data
, struct dk_gpt
*efi
)
509 if (sscanf(data
, "%d:%d:%x:%lld:%lld",
510 &part
, &tag
, &flag
, &start
, &size
) != 5) {
511 (void) fprintf(stderr
, "Delta syntax error on \"%s\"\n", data
);
514 if (part
>= efi
->efi_nparts
) {
515 (void) fprintf(stderr
,
516 "Error in data \"%s\": No such partition %x\n",
520 efi
->efi_parts
[part
].p_tag
= (ushort_t
)tag
;
521 efi
->efi_parts
[part
].p_flag
= (ushort_t
)flag
;
522 efi
->efi_parts
[part
].p_start
= start
;
523 efi
->efi_parts
[part
].p_size
= size
;
529 * Load VTOC information from a datafile.
532 load(FILE *fp
, struct dk_geom
*geom
, struct extvtoc
*vtoc
)
544 for (i
= 0; i
< V_NUMPAR
; ++i
) {
545 vtoc
->v_part
[i
].p_tag
= 0;
546 vtoc
->v_part
[i
].p_flag
= V_UNMNT
;
547 vtoc
->v_part
[i
].p_start
= 0;
548 vtoc
->v_part
[i
].p_size
= 0;
551 * initialize partition 2, by convention it corresponds to whole
552 * disk. It will be overwritten, if specified in the input datafile
554 fullsz
= (uint64_t)geom
->dkg_ncyl
* geom
->dkg_nsect
* geom
->dkg_nhead
;
555 vtoc
->v_part
[2].p_tag
= V_BACKUP
;
556 vtoc
->v_part
[2].p_flag
= V_UNMNT
;
557 vtoc
->v_part
[2].p_start
= 0;
558 vtoc
->v_part
[2].p_size
= fullsz
;
560 nblks
= geom
->dkg_nsect
* geom
->dkg_nhead
;
562 while (fgets(line
, sizeof (line
) - 1, fp
)) {
563 if (line
[0] == '\0' || line
[0] == '\n' || line
[0] == '*')
565 line
[strlen(line
) - 1] = '\0';
566 if (sscanf(line
, "%d %d %x %llu %llu",
567 &part
, &tag
, &flag
, &start
, &size
) != 5) {
568 (void) fprintf(stderr
, "Syntax error: \"%s\"\n",
572 if (part
>= V_NUMPAR
) {
573 (void) fprintf(stderr
,
574 "No such partition %x: \"%s\"\n",
578 if (!eflag
&& ((start
% nblks
) != 0 || (size
% nblks
) != 0)) {
579 (void) fprintf(stderr
,
580 "Partition %d not aligned on cylinder boundary: \"%s\"\n",
584 vtoc
->v_part
[part
].p_tag
= (ushort_t
)tag
;
585 vtoc
->v_part
[part
].p_flag
= (ushort_t
)flag
;
586 vtoc
->v_part
[part
].p_start
= start
;
587 vtoc
->v_part
[part
].p_size
= size
;
589 for (part
= 0; part
< V_NUMPAR
; part
++) {
590 vtoc
->timestamp
[part
] = (time_t)0;
597 * Load VTOC information from a datafile.
600 load64(FILE *fp
, int fd
, struct dk_gpt
**efi
)
613 while (fgets(line
, sizeof (line
) - 1, fp
)) {
614 if (line
[0] == '\0' || line
[0] == '\n' || line
[0] == '*')
616 line
[strlen(line
) - 1] = '\0';
617 if (sscanf(line
, "%d %d %x %lld %lld",
618 &part
, &tag
, &flag
, &start
, &size
) != 5) {
619 (void) fprintf(stderr
, "Syntax error: \"%s\"\n",
623 mem
= reallocarray(mem
, nlines
+ 1, sizeof (*mem
));
625 (void) fprintf(stderr
, "realloc failed\n");
628 mem
[nlines
] = strdup(line
);
629 if (mem
[nlines
] == NULL
) {
630 (void) fprintf(stderr
, "strdup failed\n");
639 if ((i
= efi_alloc_and_init(fd
, max_part
, efi
)) < 0) {
640 (void) fprintf(stderr
,
641 "efi_alloc_and_init failed: %d\n", i
);
644 for (i
= 0; i
< (*efi
)->efi_nparts
; ++i
) {
645 (*efi
)->efi_parts
[i
].p_tag
= V_UNASSIGNED
;
646 (*efi
)->efi_parts
[i
].p_flag
= V_UNMNT
;
647 (*efi
)->efi_parts
[i
].p_start
= 0;
648 (*efi
)->efi_parts
[i
].p_size
= 0;
650 lastlba
= (*efi
)->efi_last_u_lba
;
652 for (i
= 0; i
< nlines
; i
++) {
653 if (sscanf(mem
[i
], "%d %d %x %lld %lld",
654 &part
, &tag
, &flag
, &start
, &size
) != 5) {
655 (void) fprintf(stderr
, "Syntax error: \"%s\"\n",
660 if (part
>= (*efi
)->efi_nparts
) {
661 (void) fprintf(stderr
,
662 "No such partition %x: \"%s\"\n",
666 (*efi
)->efi_parts
[part
].p_tag
= (ushort_t
)tag
;
667 (*efi
)->efi_parts
[part
].p_flag
= (ushort_t
)flag
;
668 (*efi
)->efi_parts
[part
].p_start
= start
;
669 (*efi
)->efi_parts
[part
].p_size
= size
;
671 (*efi
)->efi_nparts
= max_part
;
680 (void) fprintf(stderr
,
681 "Usage: fmthard [ -i ] [ -n volumename ] [ -s datafile ] [ -d arguments] \
685 (void) fprintf(stderr
,
686 "Usage: fmthard [ -i ] [ -S ] [-I geom_file] \
687 -n volumename | -s datafile [ -d arguments] raw-device\n");
690 #error No platform defined.
698 * Validate the new VTOC.
701 validate(struct dk_geom
*geom
, struct extvtoc
*vtoc
)
713 nblks
= geom
->dkg_nsect
* geom
->dkg_nhead
;
715 fullsz
= (uint64_t)geom
->dkg_ncyl
* geom
->dkg_nsect
* geom
->dkg_nhead
;
717 #if defined(_SUNOS_VTOC_16)
718 /* make the vtoc look sane - ha ha */
719 vtoc
->v_version
= V_VERSION
;
720 vtoc
->v_sanity
= VTOC_SANE
;
721 vtoc
->v_nparts
= V_NUMPAR
;
722 if (vtoc
->v_sectorsz
== 0)
723 vtoc
->v_sectorsz
= sectsiz
;
724 #endif /* defined(_SUNOS_VTOC_16) */
726 for (i
= 0; i
< V_NUMPAR
; i
++) {
727 if (vtoc
->v_part
[i
].p_tag
== V_BACKUP
) {
728 if (vtoc
->v_part
[i
].p_size
!= fullsz
) {
729 (void) fprintf(stderr
, "\
730 fmthard: Partition %d specifies the full disk and is not equal\n\
731 full size of disk. The full disk capacity is %llu sectors.\n", i
, fullsz
);
737 if (vtoc
->v_part
[i
].p_size
== 0)
738 continue; /* Undefined partition */
739 if ((vtoc
->v_part
[i
].p_start
% nblks
) ||
740 (vtoc
->v_part
[i
].p_size
% nblks
)) {
741 (void) fprintf(stderr
, "\
742 fmthard: Partition %d not aligned on cylinder boundary \n", i
);
745 if (vtoc
->v_part
[i
].p_start
> fullsz
||
746 vtoc
->v_part
[i
].p_start
+
747 vtoc
->v_part
[i
].p_size
> fullsz
) {
748 (void) fprintf(stderr
, "\
749 fmthard: Partition %d specified as %llu sectors starting at %llu\n\
750 \tdoes not fit. The full disk contains %llu sectors.\n",
751 i
, vtoc
->v_part
[i
].p_size
,
752 vtoc
->v_part
[i
].p_start
, fullsz
);
758 if (vtoc
->v_part
[i
].p_tag
!= V_BACKUP
&&
759 vtoc
->v_part
[i
].p_size
!= fullsz
) {
760 for (j
= 0; j
< V_NUMPAR
; j
++) {
761 if (vtoc
->v_part
[j
].p_tag
== V_BACKUP
)
763 if (vtoc
->v_part
[j
].p_size
== fullsz
)
765 isize
= vtoc
->v_part
[i
].p_size
;
766 jsize
= vtoc
->v_part
[j
].p_size
;
767 istart
= vtoc
->v_part
[i
].p_start
;
768 jstart
= vtoc
->v_part
[j
].p_start
;
770 (isize
!= 0) && (jsize
!= 0)) {
771 endsect
= jstart
+ jsize
-1;
772 if ((jstart
<= istart
) &&
773 (istart
<= endsect
)) {
774 (void) fprintf(stderr
, "\
775 fmthard: Partition %d overlaps partition %d. Overlap is allowed\n\
776 \tonly on partition on the full disk partition).\n",
791 * Validate the new VTOC.
794 validate64(struct dk_gpt
*efi
)
806 fullsz
= lastlba
+ 1;
808 for (i
= 0; i
< efi
->efi_nparts
; i
++) {
809 if (efi
->efi_parts
[i
].p_size
== 0)
810 continue; /* Undefined partition */
811 if (efi
->efi_parts
[i
].p_tag
== V_RESERVED
)
813 if (efi
->efi_parts
[i
].p_start
> fullsz
||
814 efi
->efi_parts
[i
].p_start
+
815 efi
->efi_parts
[i
].p_size
> fullsz
) {
816 (void) fprintf(stderr
, "\
817 fmthard: Partition %d specified as %lld sectors starting at %lld\n\
818 \tdoes not fit. The full disk contains %lld sectors.\n",
819 i
, efi
->efi_parts
[i
].p_size
,
820 efi
->efi_parts
[i
].p_start
, fullsz
);
824 if (efi
->efi_parts
[i
].p_tag
!= V_BACKUP
&&
825 efi
->efi_parts
[i
].p_size
!= fullsz
) {
826 for (j
= 0; j
< efi
->efi_nparts
; j
++) {
827 if (efi
->efi_parts
[j
].p_size
== fullsz
)
829 isize
= efi
->efi_parts
[i
].p_size
;
830 jsize
= efi
->efi_parts
[j
].p_size
;
831 istart
= efi
->efi_parts
[i
].p_start
;
832 jstart
= efi
->efi_parts
[j
].p_start
;
834 (isize
!= 0) && (jsize
!= 0)) {
835 endsect
= jstart
+ jsize
- 1;
836 if ((jstart
<= istart
) &&
837 (istart
<= endsect
)) {
838 (void) fprintf(stderr
, "\
839 fmthard: Partition %d overlaps partition %d. Overlap is allowed\n\
840 \tonly on partition on the full disk partition).\n",
850 if (resv_part
!= 1) {
851 (void) fprintf(stderr
,
852 "expected one reserved partition, but found %d\n",
863 vread(int fd
, struct extvtoc
*vtoc
, char *devname
)
867 if ((i
= read_extvtoc(fd
, vtoc
)) < 0) {
868 if (i
== VT_ENOTSUP
) {
871 if (i
== VT_EINVAL
) {
872 (void) fprintf(stderr
, "%s: Invalid VTOC\n",
875 (void) fprintf(stderr
, "%s: Cannot read VTOC\n",
884 vread64(int fd
, struct dk_gpt
**efi_hdr
, char *devname
)
888 if ((i
= efi_alloc_and_read(fd
, efi_hdr
)) < 0) {
890 (void) fprintf(stderr
,
891 "%s: this disk must be labeled first\n",
894 (void) fprintf(stderr
,
895 "%s: read_efi failed %d\n",
899 lastlba
= (*efi_hdr
)->efi_last_u_lba
;
906 vwrite(int fd
, struct extvtoc
*vtoc
, char *devname
)
910 if ((i
= write_extvtoc(fd
, vtoc
)) != 0) {
911 if (i
== VT_EINVAL
) {
912 (void) fprintf(stderr
,
913 "%s: invalid entry exists in vtoc\n",
916 (void) fprintf(stderr
, "%s: Cannot write VTOC\n",
927 vwrite64(int fd
, struct dk_gpt
*efi
, char *devname
)
931 if ((i
= efi_write(fd
, efi
)) != 0) {
932 if (i
== VT_EINVAL
) {
933 (void) fprintf(stderr
,
934 "%s: invalid entry exists in vtoc\n",
937 (void) fprintf(stderr
, "%s: Cannot write EFI\n",