OpenSolaris_b135/cmd/fmthard/fmthard.c

Compare this file to the similar file:
Show the results in this format:

/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (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.
 */

/*
 * Copyright 2009 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/int_limits.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 */

/*
 * Internal functions.
 */
extern	int	main(int, char **);
static	void	display(struct dk_geom *, struct extvtoc *, char *);
static	void	display64(struct dk_gpt *,  char *);
static	void	insert(char *, struct extvtoc *);
static	void	insert64(char *, struct dk_gpt *);
static	void	load(FILE *, struct dk_geom *, struct extvtoc *);
static	void	load64(FILE *, int fd, struct dk_gpt **);
static	void	usage(void);
static	void	validate(struct dk_geom *, struct extvtoc *);
static	void	validate64(struct dk_gpt *);
static	int	vread(int, struct extvtoc *, char *);
static	void	vread64(int, struct dk_gpt **, char *);
static	void	vwrite(int, struct extvtoc *, 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";
static int		sectsiz;
#if defined(_SUNOS_VTOC_16)
static struct extvtoc	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 extvtoc	disk_vtoc;
#endif	/* defined(_SUNOS_VTOC_8) */
	struct dk_gpt	*disk_efi;
	struct dk_geom	disk_geom;
	struct dk_minfo	minfo;
	int		n;


	disk_efi = NULL;
	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], strerror(errno));
		exit(1);
	}

	if (ioctl(fd, DKIOCGMEDIAINFO, &minfo) == 0) {
		sectsiz = minfo.dki_lbsize;
	}

	if (sectsiz == 0) {
		sectsiz = SECSIZE;
	}

	/*
	 * 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) || qflag)) {
		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)
		(void) uadmin(A_REBOOT, AD_BOOT, 0);
	else if (uflag == 2)
		(void) uadmin(A_REBOOT, AD_IBOOT, 0);

	(void) printf("fmthard:  New volume table of contents now in place.\n");

	return (0);
}



/*
 * display ()
 *
 * display contents of VTOC without writing it to disk
 */
static void
display(struct dk_geom *geom, struct extvtoc *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", sectsiz);
	(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		%llu		%llu\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 extvtoc *vtoc)
{
	int		part;
	int		tag;
	uint_t		flag;
	diskaddr_t	start;
	uint64_t	size;

	if (sscanf(data, "%d:%d:%x:%llu:%llu",
	    &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 extvtoc *vtoc)
{
	int		part;
	int		tag;
	uint_t		flag;
	diskaddr_t	start;
	uint64_t	size;
	char		line[256];
	int		i;
	uint64_t	nblks;
	uint64_t	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 = (uint64_t)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 %llu %llu",
		    &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()
{
#if defined(sparc)
	(void) fprintf(stderr,
"Usage:	fmthard [ -i ] [ -n volumename ] [ -s datafile ] [ -d arguments] \
raw-device\n");

#elif defined(i386)
	(void) fprintf(stderr,
"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 extvtoc *vtoc)
{
	int		i;
	int		j;
	uint64_t	fullsz;
	diskaddr_t	endsect;
	diskaddr_t	istart;
	diskaddr_t	jstart;
	uint64_t	isize;
	uint64_t	jsize;
	uint64_t	nblks;

	nblks = geom->dkg_nsect * geom->dkg_nhead;

	fullsz = (uint64_t)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 (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 %llu 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 %llu sectors starting at %llu\n\
\tdoes not fit. The full disk contains %llu 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 < efi->efi_nparts; 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 extvtoc *vtoc, char *devname)
{
	int	i;

	if ((i = read_extvtoc(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 extvtoc *vtoc, char *devname)
{
	int	i;

	if ((i = write_extvtoc(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);
	}
}