summaryrefslogtreecommitdiff
path: root/usr/src/cmd/fmthard
diff options
context:
space:
mode:
authorstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
committerstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
commit7c478bd95313f5f23a4c958a745db2134aa03244 (patch)
treec871e58545497667cbb4b0a4f2daf204743e1fe7 /usr/src/cmd/fmthard
downloadillumos-joyent-7c478bd95313f5f23a4c958a745db2134aa03244.tar.gz
OpenSolaris Launch
Diffstat (limited to 'usr/src/cmd/fmthard')
-rw-r--r--usr/src/cmd/fmthard/Makefile56
-rw-r--r--usr/src/cmd/fmthard/fmthard.c952
2 files changed, 1008 insertions, 0 deletions
diff --git a/usr/src/cmd/fmthard/Makefile b/usr/src/cmd/fmthard/Makefile
new file mode 100644
index 0000000000..2b077b99f4
--- /dev/null
+++ b/usr/src/cmd/fmthard/Makefile
@@ -0,0 +1,56 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# cmd/fmthard/Makefile
+#
+
+PROG= fmthard
+
+include ../Makefile.cmd
+
+RELUSRSBIN= ../usr/sbin
+ROOTSYMLINK= $(ROOTETC)/$(PROG)
+OWNER= root
+GROUP= sys
+LDLIBS += -ladm -lefi
+lint := LINTFLAGS = -u -erroff=E_BAD_FORMAT_ARG_TYPE2
+
+.KEEP_STATE:
+
+all: $(PROG)
+
+install: all $(ROOTUSRSBINPROG) $(ROOTSYMLINK)
+
+$(ROOTSYMLINK):
+ -$(RM) $@; $(SYMLINK) $(RELUSRSBIN)/$(PROG) $@
+
+clean:
+
+lint: lint_PROG
+
+include ../Makefile.targ
+
diff --git a/usr/src/cmd/fmthard/fmthard.c b/usr/src/cmd/fmthard/fmthard.c
new file mode 100644
index 0000000000..92d44338d8
--- /dev/null
+++ b/usr/src/cmd/fmthard/fmthard.c
@@ -0,0 +1,952 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+/*
+ *
+ * Portions of this source code were provided by International
+ * Computers Limited (ICL) under a development agreement with AT&T.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Sun Microsystems version of fmthard:
+ *
+ * Supports the following arguments:
+ *
+ * -i Writes VTOC to stdout, rather than disk
+ * -q Quick check: exit code 0 if VTOC ok
+ * -d <data> Incremental changes to the VTOC
+ * -n <vname> Change volume name to <vname>
+ * -s <file> Read VTOC information from <file>, or stdin ("-")
+ * -u <state> Reboot after writing VTOC, according to <state>:
+ * boot: AD_BOOT (standard reboot)
+ * firm: AD_IBOOT (interactive reboot)
+ *
+ * Note that fmthard cannot write a VTOC on an unlabeled disk.
+ * You must use format or SunInstall for this purpose.
+ * (NOTE: the above restriction only applies on Sparc systems).
+ *
+ * The primary motivation for fmthard is to duplicate the
+ * partitioning from disk to disk:
+ *
+ * prtvtoc /dev/rdsk/c0t0d0s2 | fmthard -s - /dev/rdsk/c0t1d0s2
+ */
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/uadmin.h>
+#include <sys/open.h>
+#include <sys/vtoc.h>
+#include <sys/dkio.h>
+#include <sys/isa_defs.h>
+#include <sys/efi_partition.h>
+
+#if defined(_SUNOS_VTOC_16)
+#include <sys/dklabel.h>
+#endif
+
+#include <sys/sysmacros.h>
+
+#ifndef SECSIZE
+#define SECSIZE DEV_BSIZE
+#endif /* SECSIZE */
+
+
+/*
+ * External functions.
+ */
+extern int read_vtoc(int, struct vtoc *);
+extern int write_vtoc(int, struct vtoc *);
+
+/*
+ * Externals
+ */
+extern char *optarg;
+extern int optind;
+extern int errno;
+extern char *sys_errlist[];
+
+/*
+ * Internal functions.
+ */
+extern int main(int, char **);
+static void display(struct dk_geom *, struct vtoc *, char *);
+static void display64(struct dk_gpt *, char *);
+static void insert(char *, struct vtoc *);
+static void insert64(char *, struct dk_gpt *);
+static void load(FILE *, struct dk_geom *, struct vtoc *);
+static void load64(FILE *, int fd, struct dk_gpt **);
+static void usage(void);
+static void validate(struct dk_geom *, struct vtoc *);
+static void validate64(struct dk_gpt *);
+static int vread(int, struct vtoc *, char *);
+static void vread64(int, struct dk_gpt **, char *);
+static void vwrite(int, struct vtoc *, char *);
+static void vwrite64(int, struct dk_gpt *, char *);
+
+/*
+ * Static variables.
+ */
+static char *delta; /* Incremental update */
+static short eflag; /* force write of an EFI label */
+static short iflag; /* Prints VTOC w/o updating */
+static short qflag; /* Check for a formatted disk */
+static short uflag; /* Exit to firmware after writing */
+ /* new vtoc and reboot. Used during */
+ /* installation of core floppies */
+static diskaddr_t lastlba = 0; /* last LBA on 64-bit VTOC */
+
+#if defined(sparc)
+static char *uboot = "boot";
+
+#elif defined(i386)
+/* use installgrub(1M) to install boot blocks */
+static char *uboot = "";
+#else
+#error No platform defined.
+#endif /* various platform-specific definitions */
+
+static char *ufirm = "firm";
+#if defined(_SUNOS_VTOC_16)
+static int sectsiz;
+static struct vtoc disk_vtoc;
+#endif /* defined(_SUNOS_VTOC_16) */
+
+int
+main(int argc, char **argv)
+{
+ int fd;
+ int c;
+ char *dfile;
+ char *vname;
+ struct stat statbuf;
+#if defined(_SUNOS_VTOC_8)
+ struct vtoc disk_vtoc;
+#endif /* defined(_SUNOS_VTOC_8) */
+ struct dk_gpt *disk_efi;
+ struct dk_geom disk_geom;
+ int n;
+
+
+ dfile = NULL;
+ vname = NULL;
+#if defined(sparc)
+ while ((c = getopt(argc, argv, "ed:u:in:qs:")) != EOF)
+
+#elif defined(i386)
+ while ((c = getopt(argc, argv, "ed:u:in:qb:p:s:")) != EOF)
+
+#else
+#error No platform defined.
+#endif
+ switch (c) {
+#if defined(i386)
+ case 'p':
+ case 'b':
+ (void) fprintf(stderr,
+ "fmthard: -p and -b no longer supported."
+ " Use installgrub(1M) to install boot blocks\n");
+ break;
+#endif /* defined(i386) */
+
+ case 'd':
+ delta = optarg;
+ break;
+ case 'e':
+ ++eflag;
+ break;
+ case 'i':
+ ++iflag;
+ break;
+ case 'n':
+ vname = optarg;
+ break;
+ case 'q':
+ ++qflag;
+ break;
+ case 's':
+ dfile = optarg;
+ break;
+ case 'u':
+ if (strcmp(uboot, optarg) == 0)
+ ++uflag;
+ else if (strcmp(ufirm, optarg) == 0)
+ uflag = 2;
+
+ break;
+ default:
+ usage();
+ }
+
+
+ if (argc - optind != 1)
+ usage();
+
+ if (stat(argv[optind], (struct stat *)&statbuf) == -1) {
+ (void) fprintf(stderr,
+ "fmthard: Cannot stat device %s\n",
+ argv[optind]);
+ exit(1);
+ }
+
+ if ((statbuf.st_mode & S_IFMT) != S_IFCHR) {
+ (void) fprintf(stderr,
+ "fmthard: %s must be a raw device.\n",
+ argv[optind]);
+ exit(1);
+ }
+
+ if ((fd = open(argv[optind], O_RDWR|O_NDELAY)) < 0) {
+ (void) fprintf(stderr, "fmthard: Cannot open device %s - %s\n",
+ argv[optind], sys_errlist[errno]);
+ exit(1);
+ }
+
+ /*
+ * Get the geometry information for this disk from the driver
+ */
+ if (!eflag && ioctl(fd, DKIOCGGEOM, &disk_geom)) {
+#ifdef DEBUG
+ perror("DKIOCGGEOM failed");
+#endif /* DEBUG */
+ if (errno == ENOTSUP) {
+ /* disk has EFI labels */
+ eflag++;
+ } else {
+ (void) fprintf(stderr,
+ "%s: Cannot get disk geometry\n", argv[optind]);
+ (void) close(fd);
+ exit(1);
+ }
+ }
+
+ /*
+ * Read the vtoc on the disk
+ */
+ if (!eflag) {
+ if (vread(fd, &disk_vtoc, argv[optind]) == 1)
+ eflag++;
+ }
+ if (eflag && (dfile == NULL)) {
+ vread64(fd, &disk_efi, argv[optind]);
+ }
+
+ /*
+ * Quick check for valid disk: 0 if ok, 1 if not
+ */
+ if (qflag) {
+ (void) close(fd);
+ if (!eflag) {
+ exit(disk_vtoc.v_sanity == VTOC_SANE ? 0 : 1);
+ } else {
+ exit(disk_efi->efi_version <= EFI_VERSION102 ? 0 : 1);
+ }
+ }
+
+ /*
+ * Incremental changes to the VTOC
+ */
+ if (delta) {
+ if (!eflag) {
+ insert(delta, &disk_vtoc);
+ validate(&disk_geom, &disk_vtoc);
+ vwrite(fd, &disk_vtoc, argv[optind]);
+ } else {
+ insert64(delta, disk_efi);
+ validate64(disk_efi);
+ vwrite64(fd, disk_efi, argv[optind]);
+ }
+ (void) close(fd);
+ exit(0);
+ }
+
+ if (!dfile && !vname)
+ usage();
+
+ /*
+ * Read new VTOC from stdin or data file
+ */
+ if (dfile) {
+ if (strcmp(dfile, "-") == 0) {
+ if (!eflag)
+ load(stdin, &disk_geom, &disk_vtoc);
+ else
+ load64(stdin, fd, &disk_efi);
+ } else {
+ FILE *fp;
+ if ((fp = fopen(dfile, "r")) == NULL) {
+ (void) fprintf(stderr, "Cannot open file %s\n",
+ dfile);
+ (void) close(fd);
+ exit(1);
+ }
+ if (!eflag)
+ load(fp, &disk_geom, &disk_vtoc);
+ else
+ load64(fp, fd, &disk_efi);
+ (void) fclose(fp);
+ }
+ }
+
+
+ /*
+ * Print the modified VTOC, rather than updating the disk
+ */
+ if (iflag) {
+ if (!eflag)
+ display(&disk_geom, &disk_vtoc, argv[optind]);
+ else
+ display64(disk_efi, argv[optind]);
+ (void) close(fd);
+ exit(0);
+ }
+
+ if (vname) {
+ n = MIN(strlen(vname) + 1, LEN_DKL_VVOL);
+ if (!eflag) {
+ (void) memcpy(disk_vtoc.v_volume, vname, n);
+ } else {
+ for (c = 0; c < disk_efi->efi_nparts; c++) {
+ if (disk_efi->efi_parts[c].p_tag ==
+ V_RESERVED) {
+ (void) memcpy(&disk_efi->efi_parts[c].p_name,
+ vname, n);
+ }
+ }
+ }
+
+ }
+ /*
+ * Write the new VTOC on the disk
+ */
+ if (!eflag) {
+ validate(&disk_geom, &disk_vtoc);
+ vwrite(fd, &disk_vtoc, argv[optind]);
+ } else {
+ validate64(disk_efi);
+ vwrite64(fd, disk_efi, argv[optind]);
+ }
+
+ /*
+ * Shut system down after writing a new vtoc to disk
+ * This is used during installation of core floppies.
+ */
+ if (uflag == 1)
+ uadmin(A_REBOOT, AD_BOOT, 0);
+ else if (uflag == 2)
+ uadmin(A_REBOOT, AD_IBOOT, 0);
+
+ (void) printf("fmthard: New volume table of contents now in place.\n");
+
+ return (0);
+ /*NOTREACHED*/
+}
+
+
+
+/*
+ * display ()
+ *
+ * display contents of VTOC without writing it to disk
+ */
+static void
+display(struct dk_geom *geom, struct vtoc *vtoc, char *device)
+{
+ int i;
+ int c;
+
+ /*
+ * Print out the VTOC
+ */
+ (void) printf("* %s default partition map\n", device);
+ if (*vtoc->v_volume) {
+ (void) printf("* Volume Name: ");
+ for (i = 0; i < LEN_DKL_VVOL; i++) {
+ if ((c = vtoc->v_volume[i]) == 0)
+ break;
+ (void) printf("%c", c);
+ }
+ (void) printf("\n");
+ }
+ (void) printf("*\n");
+ (void) printf("* Dimensions:\n");
+ (void) printf("* %d bytes/sector\n", SECSIZE);
+ (void) printf("* %d sectors/track\n", geom->dkg_nsect);
+ (void) printf("* %d tracks/cylinder\n", geom->dkg_nhead);
+ (void) printf("* %d cylinders\n", geom->dkg_pcyl);
+ (void) printf("* %d accessible cylinders\n", geom->dkg_ncyl);
+ (void) printf("*\n");
+ (void) printf("* Flags:\n");
+ (void) printf("* 1: unmountable\n");
+ (void) printf("* 10: read-only\n");
+ (void) printf("*\n");
+ (void) printf(
+"\n* Partition Tag Flag First Sector Sector Count\n");
+ for (i = 0; i < V_NUMPAR; i++) {
+ if (vtoc->v_part[i].p_size > 0)
+ (void) printf(
+" %d %d 0%x %ld %ld\n",
+ i, vtoc->v_part[i].p_tag,
+ vtoc->v_part[i].p_flag,
+ vtoc->v_part[i].p_start,
+ vtoc->v_part[i].p_size);
+ }
+ exit(0);
+}
+
+/*
+ * display64 ()
+ *
+ * display64 contents of EFI partition without writing it to disk
+ */
+static void
+display64(struct dk_gpt *efi, char *device)
+{
+ int i;
+
+ /*
+ * Print out the VTOC
+ */
+ (void) printf("* %s default partition map\n", device);
+ (void) printf("*\n");
+ (void) printf("* Dimensions:\n");
+ (void) printf("* %d bytes/sector\n", efi->efi_lbasize);
+ (void) printf("* N/A sectors/track\n");
+ (void) printf("* N/A tracks/cylinder\n");
+ (void) printf("* N/A cylinders\n");
+ (void) printf("* N/A accessible cylinders\n");
+ (void) printf("*\n");
+ (void) printf("* Flags:\n");
+ (void) printf("* 1: unmountable\n");
+ (void) printf("* 10: read-only\n");
+ (void) printf("*\n");
+ (void) printf(
+"\n* Partition Tag Flag First Sector Sector Count\n");
+ for (i = 0; i < efi->efi_nparts; i++) {
+ if (efi->efi_parts[i].p_size > 0)
+ (void) printf(
+" %d %d 0%x %8lld %8lld\n",
+ i, efi->efi_parts[i].p_tag,
+ efi->efi_parts[i].p_flag,
+ efi->efi_parts[i].p_start,
+ efi->efi_parts[i].p_size);
+ }
+ exit(0);
+}
+
+
+/*
+ * insert()
+ *
+ * Insert a change into the VTOC.
+ */
+static void
+insert(char *data, struct vtoc *vtoc)
+{
+ int part;
+ int tag;
+ uint_t flag;
+ daddr_t start;
+ long size;
+
+ if (sscanf(data, "%d:%d:%x:%ld:%ld",
+ &part, &tag, &flag, &start, &size) != 5) {
+ (void) fprintf(stderr, "Delta syntax error on \"%s\"\n", data);
+ exit(1);
+ }
+ if (part >= V_NUMPAR) {
+ (void) fprintf(stderr,
+ "Error in data \"%s\": No such partition %x\n",
+ data, part);
+ exit(1);
+ }
+ vtoc->v_part[part].p_tag = (ushort_t)tag;
+ vtoc->v_part[part].p_flag = (ushort_t)flag;
+ vtoc->v_part[part].p_start = start;
+ vtoc->v_part[part].p_size = size;
+}
+
+/*
+ * insert64()
+ *
+ * Insert a change into the VTOC.
+ */
+static void
+insert64(char *data, struct dk_gpt *efi)
+{
+ int part;
+ int tag;
+ uint_t flag;
+ diskaddr_t start;
+ diskaddr_t size;
+
+ if (sscanf(data, "%d:%d:%x:%lld:%lld",
+ &part, &tag, &flag, &start, &size) != 5) {
+ (void) fprintf(stderr, "Delta syntax error on \"%s\"\n", data);
+ exit(1);
+ }
+ if (part >= efi->efi_nparts) {
+ (void) fprintf(stderr,
+ "Error in data \"%s\": No such partition %x\n",
+ data, part);
+ exit(1);
+ }
+ efi->efi_parts[part].p_tag = (ushort_t)tag;
+ efi->efi_parts[part].p_flag = (ushort_t)flag;
+ efi->efi_parts[part].p_start = start;
+ efi->efi_parts[part].p_size = size;
+}
+
+/*
+ * load()
+ *
+ * Load VTOC information from a datafile.
+ */
+static void
+load(FILE *fp, struct dk_geom *geom, struct vtoc *vtoc)
+{
+ int part;
+ int tag;
+ uint_t flag;
+ daddr_t start;
+ long size;
+ char line[256];
+ int i;
+ long nblks;
+ long fullsz;
+
+ for (i = 0; i < V_NUMPAR; ++i) {
+ vtoc->v_part[i].p_tag = 0;
+ vtoc->v_part[i].p_flag = V_UNMNT;
+ vtoc->v_part[i].p_start = 0;
+ vtoc->v_part[i].p_size = 0;
+ }
+ /*
+ * initialize partition 2, by convention it corresponds to whole
+ * disk. It will be overwritten, if specified in the input datafile
+ */
+ fullsz = geom->dkg_ncyl * geom->dkg_nsect * geom->dkg_nhead;
+ vtoc->v_part[2].p_tag = V_BACKUP;
+ vtoc->v_part[2].p_flag = V_UNMNT;
+ vtoc->v_part[2].p_start = 0;
+ vtoc->v_part[2].p_size = fullsz;
+
+ nblks = geom->dkg_nsect * geom->dkg_nhead;
+
+ while (fgets(line, sizeof (line) - 1, fp)) {
+ if (line[0] == '\0' || line[0] == '\n' || line[0] == '*')
+ continue;
+ line[strlen(line) - 1] = '\0';
+ if (sscanf(line, "%d %d %x %ld %ld",
+ &part, &tag, &flag, &start, &size) != 5) {
+ (void) fprintf(stderr, "Syntax error: \"%s\"\n",
+ line);
+ exit(1);
+ }
+ if (part >= V_NUMPAR) {
+ (void) fprintf(stderr,
+ "No such partition %x: \"%s\"\n",
+ part, line);
+ exit(1);
+ }
+ if (!eflag && ((start % nblks) != 0 || (size % nblks) != 0)) {
+ (void) fprintf(stderr,
+"Partition %d not aligned on cylinder boundary: \"%s\"\n",
+ part, line);
+ exit(1);
+ }
+ vtoc->v_part[part].p_tag = (ushort_t)tag;
+ vtoc->v_part[part].p_flag = (ushort_t)flag;
+ vtoc->v_part[part].p_start = start;
+ vtoc->v_part[part].p_size = size;
+ }
+ for (part = 0; part < V_NUMPAR; part++) {
+ vtoc->timestamp[part] = (time_t)0;
+ }
+}
+
+/*
+ * load64()
+ *
+ * Load VTOC information from a datafile.
+ */
+static void
+load64(FILE *fp, int fd, struct dk_gpt **efi)
+{
+ int part;
+ int tag;
+ uint_t flag;
+ diskaddr_t start;
+ diskaddr_t size;
+ int nlines = 0;
+ char line[256];
+ int i;
+ uint_t max_part = 0;
+ char **mem = NULL;
+
+ while (fgets(line, sizeof (line) - 1, fp)) {
+ if (line[0] == '\0' || line[0] == '\n' || line[0] == '*')
+ continue;
+ line[strlen(line) - 1] = '\0';
+ if (sscanf(line, "%d %d %x %lld %lld",
+ &part, &tag, &flag, &start, &size) != 5) {
+ (void) fprintf(stderr, "Syntax error: \"%s\"\n",
+ line);
+ exit(1);
+ }
+ mem = realloc(mem, sizeof (*mem) * (nlines + 1));
+ if (mem == NULL) {
+ (void) fprintf(stderr, "realloc failed\n");
+ exit(1);
+ }
+ mem[nlines] = strdup(line);
+ if (mem[nlines] == NULL) {
+ (void) fprintf(stderr, "strdup failed\n");
+ exit(1);
+ }
+ nlines++;
+ if (part > max_part)
+ max_part = part;
+ }
+ max_part++;
+
+ if ((i = efi_alloc_and_init(fd, max_part, efi)) < 0) {
+ (void) fprintf(stderr,
+ "efi_alloc_and_init failed: %d\n", i);
+ exit(1);
+ }
+ for (i = 0; i < (*efi)->efi_nparts; ++i) {
+ (*efi)->efi_parts[i].p_tag = V_UNASSIGNED;
+ (*efi)->efi_parts[i].p_flag = V_UNMNT;
+ (*efi)->efi_parts[i].p_start = 0;
+ (*efi)->efi_parts[i].p_size = 0;
+ }
+ lastlba = (*efi)->efi_last_u_lba;
+
+ for (i = 0; i < nlines; i++) {
+ if (sscanf(mem[i], "%d %d %x %lld %lld",
+ &part, &tag, &flag, &start, &size) != 5) {
+ (void) fprintf(stderr, "Syntax error: \"%s\"\n",
+ line);
+ exit(1);
+ }
+ free(mem[i]);
+ if (part >= (*efi)->efi_nparts) {
+ (void) fprintf(stderr,
+ "No such partition %x: \"%s\"\n",
+ part, line);
+ exit(1);
+ }
+ (*efi)->efi_parts[part].p_tag = (ushort_t)tag;
+ (*efi)->efi_parts[part].p_flag = (ushort_t)flag;
+ (*efi)->efi_parts[part].p_start = start;
+ (*efi)->efi_parts[part].p_size = size;
+ }
+ (*efi)->efi_nparts = max_part;
+ free(mem);
+}
+
+
+static void
+usage()
+{
+ (void) fprintf(stderr,
+#if defined(sparc)
+"Usage: fmthard [ -i ] [ -n volumename ] [ -s datafile ] [ -d arguments] \
+raw-device\n");
+
+#elif defined(i386)
+"Usage: fmthard [ -i ] [ -S ] [-I geom_file] \
+-n volumename | -s datafile [ -d arguments] raw-device\n");
+
+#else
+#error No platform defined.
+#endif
+ exit(2);
+}
+
+/*
+ * validate()
+ *
+ * Validate the new VTOC.
+ */
+static void
+validate(struct dk_geom *geom, struct vtoc *vtoc)
+{
+ int i;
+ int j;
+ long fullsz;
+ long endsect;
+ daddr_t istart;
+ daddr_t jstart;
+ long isize;
+ long jsize;
+ long nblks;
+
+ nblks = geom->dkg_nsect * geom->dkg_nhead;
+
+ fullsz = geom->dkg_ncyl * geom->dkg_nsect * geom->dkg_nhead;
+
+#if defined(_SUNOS_VTOC_16)
+ /* make the vtoc look sane - ha ha */
+ vtoc->v_version = V_VERSION;
+ vtoc->v_sanity = VTOC_SANE;
+ vtoc->v_nparts = V_NUMPAR;
+ if (sectsiz == 0)
+ sectsiz = SECSIZE;
+ if (vtoc->v_sectorsz == 0)
+ vtoc->v_sectorsz = sectsiz;
+#endif /* defined(_SUNOS_VTOC_16) */
+
+ for (i = 0; i < V_NUMPAR; i++) {
+ if (vtoc->v_part[i].p_tag == V_BACKUP) {
+ if (vtoc->v_part[i].p_size != fullsz) {
+ (void) fprintf(stderr, "\
+fmthard: Partition %d specifies the full disk and is not equal\n\
+full size of disk. The full disk capacity is %lu sectors.\n", i, fullsz);
+#if defined(sparc)
+ exit(1);
+#endif
+ }
+ }
+ if (vtoc->v_part[i].p_size == 0)
+ continue; /* Undefined partition */
+ if ((vtoc->v_part[i].p_start % nblks) ||
+ (vtoc->v_part[i].p_size % nblks)) {
+ (void) fprintf(stderr, "\
+fmthard: Partition %d not aligned on cylinder boundary \n", i);
+ exit(1);
+ }
+ if (vtoc->v_part[i].p_start > fullsz ||
+ vtoc->v_part[i].p_start +
+ vtoc->v_part[i].p_size > fullsz) {
+ (void) fprintf(stderr, "\
+fmthard: Partition %d specified as %lu sectors starting at %lu\n\
+\tdoes not fit. The full disk contains %lu sectors.\n",
+ i, vtoc->v_part[i].p_size,
+ vtoc->v_part[i].p_start, fullsz);
+#if defined(sparc)
+ exit(1);
+#endif
+ }
+
+ if (vtoc->v_part[i].p_tag != V_BACKUP &&
+ vtoc->v_part[i].p_size != fullsz) {
+ for (j = 0; j < V_NUMPAR; j++) {
+ if (vtoc->v_part[j].p_tag == V_BACKUP)
+ continue;
+ if (vtoc->v_part[j].p_size == fullsz)
+ continue;
+ isize = vtoc->v_part[i].p_size;
+ jsize = vtoc->v_part[j].p_size;
+ istart = vtoc->v_part[i].p_start;
+ jstart = vtoc->v_part[j].p_start;
+ if ((i != j) &&
+ (isize != 0) && (jsize != 0)) {
+ endsect = jstart + jsize -1;
+ if ((jstart <= istart) &&
+ (istart <= endsect)) {
+ (void) fprintf(stderr, "\
+fmthard: Partition %d overlaps partition %d. Overlap is allowed\n\
+\tonly on partition on the full disk partition).\n",
+ i, j);
+#if defined(sparc)
+ exit(1);
+#endif
+ }
+ }
+ }
+ }
+ }
+}
+
+/*
+ * validate64()
+ *
+ * Validate the new VTOC.
+ */
+static void
+validate64(struct dk_gpt *efi)
+{
+ int i;
+ int j;
+ int resv_part = 0;
+ diskaddr_t endsect;
+ diskaddr_t fullsz;
+ diskaddr_t istart;
+ diskaddr_t jstart;
+ diskaddr_t isize;
+ diskaddr_t jsize;
+
+ fullsz = lastlba + 1;
+
+ for (i = 0; i < efi->efi_nparts; i++) {
+ if (efi->efi_parts[i].p_size == 0)
+ continue; /* Undefined partition */
+ if (efi->efi_parts[i].p_tag == V_RESERVED)
+ resv_part++;
+ if (efi->efi_parts[i].p_start > fullsz ||
+ efi->efi_parts[i].p_start +
+ efi->efi_parts[i].p_size > fullsz) {
+ (void) fprintf(stderr, "\
+fmthard: Partition %d specified as %lld sectors starting at %lld\n\
+\tdoes not fit. The full disk contains %lld sectors.\n",
+ i, efi->efi_parts[i].p_size,
+ efi->efi_parts[i].p_start, fullsz);
+ exit(1);
+ }
+
+ if (efi->efi_parts[i].p_tag != V_BACKUP &&
+ efi->efi_parts[i].p_size != fullsz) {
+ for (j = 0; j < V_NUMPAR; j++) {
+ if (efi->efi_parts[j].p_size == fullsz)
+ continue;
+ isize = efi->efi_parts[i].p_size;
+ jsize = efi->efi_parts[j].p_size;
+ istart = efi->efi_parts[i].p_start;
+ jstart = efi->efi_parts[j].p_start;
+ if ((i != j) &&
+ (isize != 0) && (jsize != 0)) {
+ endsect = jstart + jsize - 1;
+ if ((jstart <= istart) &&
+ (istart <= endsect)) {
+ (void) fprintf(stderr, "\
+fmthard: Partition %d overlaps partition %d. Overlap is allowed\n\
+\tonly on partition on the full disk partition).\n",
+ i, j);
+#if defined(sparc)
+ exit(1);
+#endif
+ }
+ }
+ }
+ }
+ }
+ if (resv_part != 1) {
+ (void) fprintf(stderr,
+ "expected one reserved partition, but found %d\n",
+ resv_part);
+ exit(1);
+ }
+}
+
+
+/*
+ * Read the VTOC
+ */
+int
+vread(int fd, struct vtoc *vtoc, char *devname)
+{
+ int i;
+
+ if ((i = read_vtoc(fd, vtoc)) < 0) {
+ if (i == VT_ENOTSUP) {
+ return (1);
+ }
+ if (i == VT_EINVAL) {
+ (void) fprintf(stderr, "%s: Invalid VTOC\n",
+ devname);
+ } else {
+ (void) fprintf(stderr, "%s: Cannot read VTOC\n",
+ devname);
+ }
+ exit(1);
+ }
+ return (0);
+}
+
+void
+vread64(int fd, struct dk_gpt **efi_hdr, char *devname)
+{
+ int i;
+
+ if ((i = efi_alloc_and_read(fd, efi_hdr)) < 0) {
+ if (i == VT_EINVAL)
+ (void) fprintf(stderr,
+ "%s: this disk must be labeled first\n",
+ devname);
+ else
+ (void) fprintf(stderr,
+ "%s: read_efi failed %d\n",
+ devname, i);
+ exit(1);
+ }
+ lastlba = (*efi_hdr)->efi_last_u_lba;
+}
+
+/*
+ * Write the VTOC
+ */
+void
+vwrite(int fd, struct vtoc *vtoc, char *devname)
+{
+ int i;
+
+ if ((i = write_vtoc(fd, vtoc)) != 0) {
+ if (i == VT_EINVAL) {
+ (void) fprintf(stderr,
+ "%s: invalid entry exists in vtoc\n",
+ devname);
+ } else {
+ (void) fprintf(stderr, "%s: Cannot write VTOC\n",
+ devname);
+ }
+ exit(1);
+ }
+}
+
+/*
+ * Write the VTOC
+ */
+void
+vwrite64(int fd, struct dk_gpt *efi, char *devname)
+{
+ int i;
+
+ if ((i = efi_write(fd, efi)) != 0) {
+ if (i == VT_EINVAL) {
+ (void) fprintf(stderr,
+ "%s: invalid entry exists in vtoc\n",
+ devname);
+ } else {
+ (void) fprintf(stderr, "%s: Cannot write EFI\n",
+ devname);
+ }
+ exit(1);
+ }
+}