1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
22/*	  All Rights Reserved  	*/
23
24
25/*
26 *
27 *	Portions of this source code were provided by International
28 *	Computers Limited (ICL) under a development agreement with AT&T.
29 */
30
31/*
32 * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
33 * Use is subject to license terms.
34 */
35
36/*
37 * Sun Microsystems version of fmthard:
38 *
39 * Supports the following arguments:
40 *
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)
49 *
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).
53 *
54 * The primary motivation for fmthard is to duplicate the
55 * partitioning from disk to disk:
56 *
57 *	prtvtoc /dev/rdsk/c0t0d0s2 | fmthard -s - /dev/rdsk/c0t1d0s2
58 */
59
60#include <stdio.h>
61#include <fcntl.h>
62#include <errno.h>
63#include <string.h>
64#include <stdlib.h>
65#include <unistd.h>
66#include <sys/types.h>
67#include <sys/param.h>
68#include <sys/int_limits.h>
69#include <sys/stat.h>
70#include <sys/uadmin.h>
71#include <sys/open.h>
72#include <sys/vtoc.h>
73#include <sys/dkio.h>
74#include <sys/isa_defs.h>
75#include <sys/efi_partition.h>
76
77#if defined(_SUNOS_VTOC_16)
78#include <sys/dklabel.h>
79#endif
80
81#include <sys/sysmacros.h>
82
83#ifndef	SECSIZE
84#define	SECSIZE			DEV_BSIZE
85#endif	/* SECSIZE */
86
87/*
88 * Internal functions.
89 */
90extern	int	main(int, char **);
91static	void	display(struct dk_geom *, struct extvtoc *, char *);
92static	void	display64(struct dk_gpt *,  char *);
93static	void	insert(char *, struct extvtoc *);
94static	void	insert64(char *, struct dk_gpt *);
95static	void	load(FILE *, struct dk_geom *, struct extvtoc *);
96static	void	load64(FILE *, int fd, struct dk_gpt **);
97static	void	usage(void);
98static	void	validate(struct dk_geom *, struct extvtoc *);
99static	void	validate64(struct dk_gpt *);
100static	int	vread(int, struct extvtoc *, char *);
101static	void	vread64(int, struct dk_gpt **, char *);
102static	void	vwrite(int, struct extvtoc *, char *);
103static	void	vwrite64(int, struct dk_gpt *, char *);
104
105/*
106 * Static variables.
107 */
108static char	*delta;		/* Incremental update */
109static short	eflag;		/* force write of an EFI label */
110static short	iflag;		/* Prints VTOC w/o updating */
111static short	qflag;		/* Check for a formatted disk */
112static short	uflag;		/* Exit to firmware after writing  */
113				/* new vtoc and reboot. Used during */
114				/* installation of core floppies */
115static diskaddr_t	lastlba = 0;	/* last LBA on 64-bit VTOC */
116
117#if defined(sparc)
118static char	*uboot = "boot";
119
120#elif defined(i386)
121/* use installgrub(1M) to install boot blocks */
122static char *uboot = "";
123#else
124#error No platform defined.
125#endif	/* various platform-specific definitions */
126
127static char	*ufirm = "firm";
128static int		sectsiz;
129#if defined(_SUNOS_VTOC_16)
130static struct extvtoc	disk_vtoc;
131#endif	/* defined(_SUNOS_VTOC_16) */
132
133int
134main(int argc, char **argv)
135{
136	int		fd;
137	int		c;
138	char		*dfile;
139	char		*vname;
140	struct stat	statbuf;
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;
147	int		n;
148
149
150	disk_efi = NULL;
151	dfile = NULL;
152	vname = NULL;
153#if defined(sparc)
154	while ((c = getopt(argc, argv, "ed:u:in:qs:")) != EOF)
155
156#elif defined(i386)
157	while ((c = getopt(argc, argv, "ed:u:in:qb:p:s:")) != EOF)
158
159#else
160#error No platform defined.
161#endif
162		switch (c) {
163#if defined(i386)
164		case 'p':
165		case 'b':
166			(void) fprintf(stderr,
167			    "fmthard: -p and -b no longer supported."
168			    " Use installgrub(1M) to install boot blocks\n");
169			break;
170#endif	/* defined(i386) */
171
172		case 'd':
173			delta = optarg;
174			break;
175		case 'e':
176			++eflag;
177			break;
178		case 'i':
179			++iflag;
180			break;
181		case 'n':
182			vname = optarg;
183			break;
184		case 'q':
185			++qflag;
186			break;
187		case 's':
188			dfile = optarg;
189			break;
190		case 'u':
191			if (strcmp(uboot, optarg) == 0)
192				++uflag;
193			else if (strcmp(ufirm, optarg) == 0)
194				uflag = 2;
195
196			break;
197		default:
198			usage();
199		}
200
201
202	if (argc - optind != 1)
203		usage();
204
205	if (stat(argv[optind], (struct stat *)&statbuf) == -1) {
206		(void) fprintf(stderr,
207		    "fmthard:  Cannot stat device %s\n",
208		    argv[optind]);
209		exit(1);
210	}
211
212	if ((statbuf.st_mode & S_IFMT) != S_IFCHR) {
213		(void) fprintf(stderr,
214		    "fmthard:  %s must be a raw device.\n",
215		    argv[optind]);
216		exit(1);
217	}
218
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));
222		exit(1);
223	}
224
225	if (ioctl(fd, DKIOCGMEDIAINFO, &minfo) == 0) {
226		sectsiz = minfo.dki_lbsize;
227	}
228
229	if (sectsiz == 0) {
230		sectsiz = SECSIZE;
231	}
232
233	/*
234	 * Get the geometry information for this disk from the driver
235	 */
236	if (!eflag && ioctl(fd, DKIOCGGEOM, &disk_geom)) {
237#ifdef DEBUG
238		perror("DKIOCGGEOM failed");
239#endif /* DEBUG */
240		if (errno == ENOTSUP) {
241			/* disk has EFI labels */
242			eflag++;
243		} else {
244			(void) fprintf(stderr,
245			    "%s: Cannot get disk geometry\n", argv[optind]);
246			(void) close(fd);
247			exit(1);
248		}
249	}
250
251	/*
252	 * Read the vtoc on the disk
253	 */
254	if (!eflag) {
255		if (vread(fd, &disk_vtoc, argv[optind]) == 1)
256			eflag++;
257	}
258	if (eflag && ((dfile == NULL) || qflag)) {
259		vread64(fd, &disk_efi, argv[optind]);
260	}
261
262	/*
263	 * Quick check for valid disk: 0 if ok, 1 if not
264	 */
265	if (qflag) {
266		(void) close(fd);
267		if (!eflag) {
268			exit(disk_vtoc.v_sanity == VTOC_SANE ? 0 : 1);
269		} else {
270			exit(disk_efi->efi_version <= EFI_VERSION102 ? 0 : 1);
271		}
272	}
273
274	/*
275	 * Incremental changes to the VTOC
276	 */
277	if (delta) {
278		if (!eflag) {
279			insert(delta, &disk_vtoc);
280			validate(&disk_geom, &disk_vtoc);
281			vwrite(fd, &disk_vtoc, argv[optind]);
282		} else {
283			insert64(delta, disk_efi);
284			validate64(disk_efi);
285			vwrite64(fd, disk_efi, argv[optind]);
286		}
287		(void) close(fd);
288		exit(0);
289	}
290
291	if (!dfile && !vname)
292		usage();
293
294	/*
295	 * Read new VTOC from stdin or data file
296	 */
297	if (dfile) {
298		if (strcmp(dfile, "-") == 0) {
299			if (!eflag)
300				load(stdin, &disk_geom, &disk_vtoc);
301			else
302				load64(stdin, fd, &disk_efi);
303		} else {
304			FILE *fp;
305			if ((fp = fopen(dfile, "r")) == NULL) {
306				(void) fprintf(stderr, "Cannot open file %s\n",
307				    dfile);
308				(void) close(fd);
309				exit(1);
310			}
311			if (!eflag)
312				load(fp, &disk_geom, &disk_vtoc);
313			else
314				load64(fp, fd, &disk_efi);
315			(void) fclose(fp);
316		}
317	}
318
319	/*
320	 * Print the modified VTOC, rather than updating the disk
321	 */
322	if (iflag) {
323		if (!eflag)
324			display(&disk_geom, &disk_vtoc, argv[optind]);
325		else
326			display64(disk_efi, argv[optind]);
327		(void) close(fd);
328		exit(0);
329	}
330
331	if (vname) {
332		n = MIN(strlen(vname) + 1, LEN_DKL_VVOL);
333		if (!eflag) {
334			(void) memcpy(disk_vtoc.v_volume, vname, n);
335		} else {
336			for (c = 0; c < disk_efi->efi_nparts; c++) {
337				if (disk_efi->efi_parts[c].p_tag ==
338				    V_RESERVED) {
339				(void) memcpy(&disk_efi->efi_parts[c].p_name,
340				    vname, n);
341				}
342			}
343		}
344
345	}
346	/*
347	 * Write the new VTOC on the disk
348	 */
349	if (!eflag) {
350		validate(&disk_geom, &disk_vtoc);
351		vwrite(fd, &disk_vtoc, argv[optind]);
352	} else {
353		validate64(disk_efi);
354		vwrite64(fd, disk_efi, argv[optind]);
355	}
356
357	/*
358	 * Shut system down after writing a new vtoc to disk
359	 * This is used during installation of core floppies.
360	 */
361	if (uflag == 1)
362		(void) uadmin(A_REBOOT, AD_BOOT, 0);
363	else if (uflag == 2)
364		(void) uadmin(A_REBOOT, AD_IBOOT, 0);
365
366	(void) printf("fmthard:  New volume table of contents now in place.\n");
367
368	return (0);
369}
370
371
372
373/*
374 * display ()
375 *
376 * display contents of VTOC without writing it to disk
377 */
378static void
379display(struct dk_geom *geom, struct extvtoc *vtoc, char *device)
380{
381	int	i;
382	int	c;
383
384	/*
385	 * Print out the VTOC
386	 */
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)
392				break;
393			(void) printf("%c", c);
394		}
395		(void) printf("\n");
396	}
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");
409	(void) printf(
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)
413			(void) printf(
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);
419	}
420	exit(0);
421}
422
423/*
424 * display64 ()
425 *
426 * display64 contents of EFI partition without writing it to disk
427 */
428static void
429display64(struct dk_gpt *efi, char *device)
430{
431	int	i;
432
433	/*
434	 * Print out the VTOC
435	 */
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");
449	(void) printf(
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)
453			(void) printf(
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);
459	}
460	exit(0);
461}
462
463
464/*
465 * insert()
466 *
467 * Insert a change into the VTOC.
468 */
469static void
470insert(char *data, struct extvtoc *vtoc)
471{
472	int		part;
473	int		tag;
474	uint_t		flag;
475	diskaddr_t	start;
476	uint64_t	size;
477
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);
481		exit(1);
482	}
483	if (part >= V_NUMPAR) {
484		(void) fprintf(stderr,
485		    "Error in data \"%s\": No such partition %x\n",
486		    data, part);
487		exit(1);
488	}
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;
493}
494
495/*
496 * insert64()
497 *
498 * Insert a change into the VTOC.
499 */
500static void
501insert64(char *data, struct dk_gpt *efi)
502{
503	int		part;
504	int		tag;
505	uint_t		flag;
506	diskaddr_t	start;
507	diskaddr_t	size;
508
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);
512		exit(1);
513	}
514	if (part >= efi->efi_nparts) {
515		(void) fprintf(stderr,
516		    "Error in data \"%s\": No such partition %x\n",
517		    data, part);
518		exit(1);
519	}
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;
524}
525
526/*
527 * load()
528 *
529 * Load VTOC information from a datafile.
530 */
531static void
532load(FILE *fp, struct dk_geom *geom, struct extvtoc *vtoc)
533{
534	int		part;
535	int		tag;
536	uint_t		flag;
537	diskaddr_t	start;
538	uint64_t	size;
539	char		line[256];
540	int		i;
541	uint64_t	nblks;
542	uint64_t	fullsz;
543
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;
549	}
550	/*
551	 * initialize partition 2, by convention it corresponds to whole
552	 * disk. It will be overwritten, if specified in the input datafile
553	 */
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;
559
560	nblks = geom->dkg_nsect * geom->dkg_nhead;
561
562	while (fgets(line, sizeof (line) - 1, fp)) {
563		if (line[0] == '\0' || line[0] == '\n' || line[0] == '*')
564			continue;
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",
569			    line);
570			exit(1);
571		}
572		if (part >= V_NUMPAR) {
573			(void) fprintf(stderr,
574			    "No such partition %x: \"%s\"\n",
575			    part, line);
576			exit(1);
577		}
578		if (!eflag && ((start % nblks) != 0 || (size % nblks) != 0)) {
579			(void) fprintf(stderr,
580"Partition %d not aligned on cylinder boundary: \"%s\"\n",
581			    part, line);
582			exit(1);
583		}
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;
588	}
589	for (part = 0; part < V_NUMPAR; part++) {
590		vtoc->timestamp[part] = (time_t)0;
591	}
592}
593
594/*
595 * load64()
596 *
597 * Load VTOC information from a datafile.
598 */
599static void
600load64(FILE *fp, int fd, struct dk_gpt **efi)
601{
602	int	part;
603	int	tag;
604	uint_t	flag;
605	diskaddr_t	start;
606	diskaddr_t	size;
607	int	nlines = 0;
608	char	line[256];
609	int	i;
610	uint_t	max_part = 0;
611	char	**mem = NULL;
612
613	while (fgets(line, sizeof (line) - 1, fp)) {
614		if (line[0] == '\0' || line[0] == '\n' || line[0] == '*')
615			continue;
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",
620			    line);
621			exit(1);
622		}
623		mem = realloc(mem, sizeof (*mem) * (nlines + 1));
624		if (mem == NULL) {
625			(void) fprintf(stderr, "realloc failed\n");
626			exit(1);
627		}
628		mem[nlines] = strdup(line);
629		if (mem[nlines] == NULL) {
630			(void) fprintf(stderr, "strdup failed\n");
631			exit(1);
632		}
633		nlines++;
634		if (part > max_part)
635			max_part = part;
636	}
637	max_part++;
638
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);
642		exit(1);
643	}
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;
649	}
650	lastlba = (*efi)->efi_last_u_lba;
651
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",
656			    line);
657			exit(1);
658		}
659		free(mem[i]);
660		if (part >= (*efi)->efi_nparts) {
661			(void) fprintf(stderr,
662			    "No such partition %x: \"%s\"\n",
663			    part, line);
664			exit(1);
665		}
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;
670	}
671	(*efi)->efi_nparts = max_part;
672	free(mem);
673}
674
675
676static void
677usage()
678{
679#if defined(sparc)
680	(void) fprintf(stderr,
681"Usage:	fmthard [ -i ] [ -n volumename ] [ -s datafile ] [ -d arguments] \
682raw-device\n");
683
684#elif defined(i386)
685	(void) fprintf(stderr,
686"Usage:	fmthard [ -i ] [ -S ] [-I geom_file]  \
687-n volumename | -s datafile  [ -d arguments] raw-device\n");
688
689#else
690#error No platform defined.
691#endif
692	exit(2);
693}
694
695/*
696 * validate()
697 *
698 * Validate the new VTOC.
699 */
700static void
701validate(struct dk_geom *geom, struct extvtoc *vtoc)
702{
703	int		i;
704	int		j;
705	uint64_t	fullsz;
706	diskaddr_t	endsect;
707	diskaddr_t	istart;
708	diskaddr_t	jstart;
709	uint64_t	isize;
710	uint64_t	jsize;
711	uint64_t	nblks;
712
713	nblks = geom->dkg_nsect * geom->dkg_nhead;
714
715	fullsz = (uint64_t)geom->dkg_ncyl * geom->dkg_nsect * geom->dkg_nhead;
716
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) */
725
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, "\
730fmthard: Partition %d specifies the full disk and is not equal\n\
731full size of disk.  The full disk capacity is %llu sectors.\n", i, fullsz);
732#if defined(sparc)
733			exit(1);
734#endif
735			}
736		}
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, "\
742fmthard: Partition %d not aligned on cylinder boundary \n", i);
743				exit(1);
744		}
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, "\
749fmthard: 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);
753#if defined(sparc)
754			exit(1);
755#endif
756		}
757
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)
762					continue;
763				if (vtoc->v_part[j].p_size == fullsz)
764					continue;
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;
769				if ((i != j) &&
770				    (isize != 0) && (jsize != 0)) {
771					endsect = jstart + jsize -1;
772					if ((jstart <= istart) &&
773					    (istart <= endsect)) {
774						(void) fprintf(stderr, "\
775fmthard: Partition %d overlaps partition %d. Overlap is allowed\n\
776\tonly on partition on the full disk partition).\n",
777						    i, j);
778#if defined(sparc)
779						exit(1);
780#endif
781					}
782				}
783			}
784		}
785	}
786}
787
788/*
789 * validate64()
790 *
791 * Validate the new VTOC.
792 */
793static void
794validate64(struct dk_gpt *efi)
795{
796	int		i;
797	int		j;
798	int		resv_part = 0;
799	diskaddr_t	endsect;
800	diskaddr_t	fullsz;
801	diskaddr_t		istart;
802	diskaddr_t		jstart;
803	diskaddr_t		isize;
804	diskaddr_t		jsize;
805
806	fullsz = lastlba + 1;
807
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)
812			resv_part++;
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, "\
817fmthard: 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);
821			exit(1);
822		}
823
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)
828					continue;
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;
833				if ((i != j) &&
834				    (isize != 0) && (jsize != 0)) {
835					endsect = jstart + jsize - 1;
836					if ((jstart <= istart) &&
837					    (istart <= endsect)) {
838						(void) fprintf(stderr, "\
839fmthard: Partition %d overlaps partition %d. Overlap is allowed\n\
840\tonly on partition on the full disk partition).\n",
841						    i, j);
842#if defined(sparc)
843						exit(1);
844#endif
845					}
846				}
847			}
848		}
849	}
850	if (resv_part != 1) {
851		(void) fprintf(stderr,
852		    "expected one reserved partition, but found %d\n",
853		    resv_part);
854		exit(1);
855	}
856}
857
858
859/*
860 * Read the VTOC
861 */
862int
863vread(int fd, struct extvtoc *vtoc, char *devname)
864{
865	int	i;
866
867	if ((i = read_extvtoc(fd, vtoc)) < 0) {
868		if (i == VT_ENOTSUP) {
869			return (1);
870		}
871		if (i == VT_EINVAL) {
872			(void) fprintf(stderr, "%s: Invalid VTOC\n",
873			    devname);
874		} else {
875			(void) fprintf(stderr, "%s: Cannot read VTOC\n",
876			    devname);
877		}
878		exit(1);
879	}
880	return (0);
881}
882
883void
884vread64(int fd, struct dk_gpt **efi_hdr, char *devname)
885{
886	int i;
887
888	if ((i = efi_alloc_and_read(fd, efi_hdr)) < 0) {
889		if (i == VT_EINVAL)
890			(void) fprintf(stderr,
891			    "%s: this disk must be labeled first\n",
892			    devname);
893		else
894			(void) fprintf(stderr,
895			    "%s: read_efi failed %d\n",
896			    devname, i);
897		exit(1);
898	}
899	lastlba = (*efi_hdr)->efi_last_u_lba;
900}
901
902/*
903 * Write the VTOC
904 */
905void
906vwrite(int fd, struct extvtoc *vtoc, char *devname)
907{
908	int	i;
909
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",
914			    devname);
915		} else {
916			(void) fprintf(stderr, "%s: Cannot write VTOC\n",
917			    devname);
918		}
919		exit(1);
920	}
921}
922
923/*
924 * Write the VTOC
925 */
926void
927vwrite64(int fd, struct dk_gpt *efi, char *devname)
928{
929	int	i;
930
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",
935			    devname);
936		} else {
937			(void) fprintf(stderr, "%s: Cannot write EFI\n",
938			    devname);
939		}
940		exit(1);
941	}
942}
943