xref: /illumos-gate/usr/src/cmd/fmthard/fmthard.c (revision bc54f855)
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  * Copyright (c) 2018, Joyent, Inc.
38  */
39 /*
40  * Sun Microsystems version of fmthard:
41  *
42  * Supports the following arguments:
43  *
44  *	-i		Writes VTOC to stdout, rather than disk
45  *	-q		Quick check: exit code 0 if VTOC ok
46  *	-d <data>	Incremental changes to the VTOC
47  *	-n <vname>	Change volume name to <vname>
48  *	-s <file>	Read VTOC information from <file>, or stdin ("-")
49  *	-u <state>	Reboot after writing VTOC, according to <state>:
50  *				boot: AD_BOOT (standard reboot)
51  *				firm: AD_IBOOT (interactive reboot)
52  *
53  * Note that fmthard cannot write a VTOC on an unlabeled disk.
54  * You must use format or SunInstall for this purpose.
55  * (NOTE: the above restriction only applies on Sparc systems).
56  *
57  * The primary motivation for fmthard is to duplicate the
58  * partitioning from disk to disk:
59  *
60  *	prtvtoc /dev/rdsk/c0t0d0s2 | fmthard -s - /dev/rdsk/c0t1d0s2
61  */
62 
63 #include <stdio.h>
64 #include <fcntl.h>
65 #include <errno.h>
66 #include <string.h>
67 #include <stdlib.h>
68 #include <unistd.h>
69 #include <sys/types.h>
70 #include <sys/param.h>
71 #include <sys/int_limits.h>
72 #include <sys/stat.h>
73 #include <sys/uadmin.h>
74 #include <sys/open.h>
75 #include <sys/vtoc.h>
76 #include <sys/dkio.h>
77 #include <sys/isa_defs.h>
78 #include <sys/efi_partition.h>
79 
80 #if defined(_SUNOS_VTOC_16)
81 #include <sys/dklabel.h>
82 #endif
83 
84 #include <sys/sysmacros.h>
85 
86 #ifndef	SECSIZE
87 #define	SECSIZE			DEV_BSIZE
88 #endif	/* SECSIZE */
89 
90 /*
91  * Internal functions.
92  */
93 extern	int	main(int, char **);
94 static	void	display(struct dk_geom *, struct extvtoc *, char *);
95 static	void	display64(struct dk_gpt *,  char *);
96 static	void	insert(char *, struct extvtoc *);
97 static	void	insert64(char *, struct dk_gpt *);
98 static	void	load(FILE *, struct dk_geom *, struct extvtoc *);
99 static	void	load64(FILE *, int fd, struct dk_gpt **);
100 static	void	usage(void);
101 static	void	validate(struct dk_geom *, struct extvtoc *);
102 static	void	validate64(struct dk_gpt *);
103 static	int	vread(int, struct extvtoc *, char *);
104 static	void	vread64(int, struct dk_gpt **, char *);
105 static	void	vwrite(int, struct extvtoc *, char *);
106 static	void	vwrite64(int, struct dk_gpt *, char *);
107 
108 /*
109  * Static variables.
110  */
111 static char	*delta;		/* Incremental update */
112 static short	eflag;		/* force write of an EFI label */
113 static short	iflag;		/* Prints VTOC w/o updating */
114 static short	qflag;		/* Check for a formatted disk */
115 static short	uflag;		/* Exit to firmware after writing  */
116 				/* new vtoc and reboot. Used during */
117 				/* installation of core floppies */
118 static diskaddr_t	lastlba = 0;	/* last LBA on 64-bit VTOC */
119 
120 #if defined(sparc)
121 static char	*uboot = "boot";
122 
123 #elif defined(i386)
124 /* use installgrub(1M) to install boot blocks */
125 static char *uboot = "";
126 #else
127 #error No platform defined.
128 #endif	/* various platform-specific definitions */
129 
130 static char	*ufirm = "firm";
131 static int		sectsiz;
132 #if defined(_SUNOS_VTOC_16)
133 static struct extvtoc	disk_vtoc;
134 #endif	/* defined(_SUNOS_VTOC_16) */
135 
136 int
137 main(int argc, char **argv)
138 {
139 	int		fd;
140 	int		c;
141 	char		*dfile;
142 	char		*vname;
143 	struct stat	statbuf;
144 #if defined(_SUNOS_VTOC_8)
145 	struct extvtoc	disk_vtoc;
146 #endif	/* defined(_SUNOS_VTOC_8) */
147 	struct dk_gpt	*disk_efi;
148 	struct dk_geom	disk_geom;
149 	struct dk_minfo	minfo;
150 	int		n;
151 
152 
153 	disk_efi = NULL;
154 	dfile = NULL;
155 	vname = NULL;
156 #if defined(sparc)
157 	while ((c = getopt(argc, argv, "ed:u:in:qs:")) != EOF)
158 
159 #elif defined(i386)
160 	while ((c = getopt(argc, argv, "ed:u:in:qb:p:s:")) != EOF)
161 
162 #else
163 #error No platform defined.
164 #endif
165 		switch (c) {
166 #if defined(i386)
167 		case 'p':
168 		case 'b':
169 			(void) fprintf(stderr,
170 			    "fmthard: -p and -b no longer supported."
171 			    " Use installgrub(1M) to install boot blocks\n");
172 			break;
173 #endif	/* defined(i386) */
174 
175 		case 'd':
176 			delta = optarg;
177 			break;
178 		case 'e':
179 			++eflag;
180 			break;
181 		case 'i':
182 			++iflag;
183 			break;
184 		case 'n':
185 			vname = optarg;
186 			break;
187 		case 'q':
188 			++qflag;
189 			break;
190 		case 's':
191 			dfile = optarg;
192 			break;
193 		case 'u':
194 			if (strcmp(uboot, optarg) == 0)
195 				++uflag;
196 			else if (strcmp(ufirm, optarg) == 0)
197 				uflag = 2;
198 
199 			break;
200 		default:
201 			usage();
202 		}
203 
204 
205 	if (argc - optind != 1)
206 		usage();
207 
208 	if (stat(argv[optind], (struct stat *)&statbuf) == -1) {
209 		(void) fprintf(stderr,
210 		    "fmthard:  Cannot stat device %s\n",
211 		    argv[optind]);
212 		exit(1);
213 	}
214 
215 	if ((statbuf.st_mode & S_IFMT) != S_IFCHR) {
216 		(void) fprintf(stderr,
217 		    "fmthard:  %s must be a raw device.\n",
218 		    argv[optind]);
219 		exit(1);
220 	}
221 
222 	if ((fd = open(argv[optind], O_RDWR|O_NDELAY)) < 0) {
223 		(void) fprintf(stderr, "fmthard:  Cannot open device %s - %s\n",
224 		    argv[optind], strerror(errno));
225 		exit(1);
226 	}
227 
228 	if (ioctl(fd, DKIOCGMEDIAINFO, &minfo) == 0) {
229 		sectsiz = minfo.dki_lbsize;
230 	}
231 
232 	if (sectsiz == 0) {
233 		sectsiz = SECSIZE;
234 	}
235 
236 	/*
237 	 * Get the geometry information for this disk from the driver
238 	 */
239 	if (!eflag && ioctl(fd, DKIOCGGEOM, &disk_geom)) {
240 #ifdef DEBUG
241 		perror("DKIOCGGEOM failed");
242 #endif /* DEBUG */
243 		if (errno == ENOTSUP) {
244 			/* disk has EFI labels */
245 			eflag++;
246 		} else {
247 			(void) fprintf(stderr,
248 			    "%s: Cannot get disk geometry\n", argv[optind]);
249 			(void) close(fd);
250 			exit(1);
251 		}
252 	}
253 
254 	/*
255 	 * Read the vtoc on the disk
256 	 */
257 	if (!eflag) {
258 		if (vread(fd, &disk_vtoc, argv[optind]) == 1)
259 			eflag++;
260 	}
261 	if (eflag && ((dfile == NULL) || qflag)) {
262 		vread64(fd, &disk_efi, argv[optind]);
263 	}
264 
265 	/*
266 	 * Quick check for valid disk: 0 if ok, 1 if not
267 	 */
268 	if (qflag) {
269 		(void) close(fd);
270 		if (!eflag) {
271 			exit(disk_vtoc.v_sanity == VTOC_SANE ? 0 : 1);
272 		} else {
273 			exit(disk_efi->efi_version <= EFI_VERSION102 ? 0 : 1);
274 		}
275 	}
276 
277 	/*
278 	 * Incremental changes to the VTOC
279 	 */
280 	if (delta) {
281 		if (!eflag) {
282 			insert(delta, &disk_vtoc);
283 			validate(&disk_geom, &disk_vtoc);
284 			vwrite(fd, &disk_vtoc, argv[optind]);
285 		} else {
286 			insert64(delta, disk_efi);
287 			validate64(disk_efi);
288 			vwrite64(fd, disk_efi, argv[optind]);
289 		}
290 		(void) close(fd);
291 		exit(0);
292 	}
293 
294 	if (!dfile && !vname)
295 		usage();
296 
297 	/*
298 	 * Read new VTOC from stdin or data file
299 	 */
300 	if (dfile) {
301 		if (strcmp(dfile, "-") == 0) {
302 			if (!eflag)
303 				load(stdin, &disk_geom, &disk_vtoc);
304 			else
305 				load64(stdin, fd, &disk_efi);
306 		} else {
307 			FILE *fp;
308 			if ((fp = fopen(dfile, "r")) == NULL) {
309 				(void) fprintf(stderr, "Cannot open file %s\n",
310 				    dfile);
311 				(void) close(fd);
312 				exit(1);
313 			}
314 			if (!eflag)
315 				load(fp, &disk_geom, &disk_vtoc);
316 			else
317 				load64(fp, fd, &disk_efi);
318 			(void) fclose(fp);
319 		}
320 	}
321 
322 	/*
323 	 * Print the modified VTOC, rather than updating the disk
324 	 */
325 	if (iflag) {
326 		if (!eflag)
327 			display(&disk_geom, &disk_vtoc, argv[optind]);
328 		else
329 			display64(disk_efi, argv[optind]);
330 		(void) close(fd);
331 		exit(0);
332 	}
333 
334 	if (vname) {
335 		n = MIN(strlen(vname) + 1, LEN_DKL_VVOL);
336 		if (!eflag) {
337 			(void) memcpy(disk_vtoc.v_volume, vname, n);
338 		} else {
339 			for (c = 0; c < disk_efi->efi_nparts; c++) {
340 				if (disk_efi->efi_parts[c].p_tag ==
341 				    V_RESERVED) {
342 				(void) memcpy(&disk_efi->efi_parts[c].p_name,
343 				    vname, n);
344 				}
345 			}
346 		}
347 
348 	}
349 	/*
350 	 * Write the new VTOC on the disk
351 	 */
352 	if (!eflag) {
353 		validate(&disk_geom, &disk_vtoc);
354 		vwrite(fd, &disk_vtoc, argv[optind]);
355 	} else {
356 		validate64(disk_efi);
357 		vwrite64(fd, disk_efi, argv[optind]);
358 	}
359 
360 	/*
361 	 * Shut system down after writing a new vtoc to disk
362 	 * This is used during installation of core floppies.
363 	 */
364 	if (uflag == 1)
365 		(void) uadmin(A_REBOOT, AD_BOOT, 0);
366 	else if (uflag == 2)
367 		(void) uadmin(A_REBOOT, AD_IBOOT, 0);
368 
369 	(void) printf("fmthard:  New volume table of contents now in place.\n");
370 
371 	return (0);
372 }
373 
374 
375 
376 /*
377  * display ()
378  *
379  * display contents of VTOC without writing it to disk
380  */
381 static void
382 display(struct dk_geom *geom, struct extvtoc *vtoc, char *device)
383 {
384 	int	i;
385 	int	c;
386 
387 	/*
388 	 * Print out the VTOC
389 	 */
390 	(void) printf("* %s default partition map\n", device);
391 	if (*vtoc->v_volume) {
392 		(void) printf("* Volume Name:  ");
393 		for (i = 0; i < LEN_DKL_VVOL; i++) {
394 			if ((c = vtoc->v_volume[i]) == 0)
395 				break;
396 			(void) printf("%c", c);
397 		}
398 		(void) printf("\n");
399 	}
400 	(void) printf("*\n");
401 	(void) printf("* Dimensions:\n");
402 	(void) printf("*     %d bytes/sector\n", sectsiz);
403 	(void) printf("*      %d sectors/track\n", geom->dkg_nsect);
404 	(void) printf("*       %d tracks/cylinder\n", geom->dkg_nhead);
405 	(void) printf("*     %d cylinders\n", geom->dkg_pcyl);
406 	(void) printf("*     %d accessible cylinders\n", geom->dkg_ncyl);
407 	(void) printf("*\n");
408 	(void) printf("* Flags:\n");
409 	(void) printf("*   1:  unmountable\n");
410 	(void) printf("*  10:  read-only\n");
411 	(void) printf("*\n");
412 	(void) printf(
413 "\n* Partition    Tag     Flag	    First Sector    Sector Count\n");
414 	for (i = 0; i < V_NUMPAR; i++) {
415 		if (vtoc->v_part[i].p_size > 0)
416 			(void) printf(
417 "    %d		%d	0%x		%llu		%llu\n",
418 			    i, vtoc->v_part[i].p_tag,
419 			    vtoc->v_part[i].p_flag,
420 			    vtoc->v_part[i].p_start,
421 			    vtoc->v_part[i].p_size);
422 	}
423 	exit(0);
424 }
425 
426 /*
427  * display64 ()
428  *
429  * display64 contents of EFI partition without writing it to disk
430  */
431 static void
432 display64(struct dk_gpt *efi, char *device)
433 {
434 	int	i;
435 
436 	/*
437 	 * Print out the VTOC
438 	 */
439 	(void) printf("* %s default partition map\n", device);
440 	(void) printf("*\n");
441 	(void) printf("* Dimensions:\n");
442 	(void) printf("*     %d bytes/sector\n", efi->efi_lbasize);
443 	(void) printf("*     N/A sectors/track\n");
444 	(void) printf("*     N/A tracks/cylinder\n");
445 	(void) printf("*     N/A cylinders\n");
446 	(void) printf("*     N/A accessible cylinders\n");
447 	(void) printf("*\n");
448 	(void) printf("* Flags:\n");
449 	(void) printf("*   1:  unmountable\n");
450 	(void) printf("*  10:  read-only\n");
451 	(void) printf("*\n");
452 	(void) printf(
453 "\n* Partition    Tag     Flag	    First Sector    Sector Count\n");
454 	for (i = 0; i < efi->efi_nparts; i++) {
455 		if (efi->efi_parts[i].p_size > 0)
456 			(void) printf(
457 "    %d		%d	0%x		%8lld	%8lld\n",
458 			    i, efi->efi_parts[i].p_tag,
459 			    efi->efi_parts[i].p_flag,
460 			    efi->efi_parts[i].p_start,
461 			    efi->efi_parts[i].p_size);
462 	}
463 	exit(0);
464 }
465 
466 
467 /*
468  * insert()
469  *
470  * Insert a change into the VTOC.
471  */
472 static void
473 insert(char *data, struct extvtoc *vtoc)
474 {
475 	int		part;
476 	int		tag;
477 	uint_t		flag;
478 	diskaddr_t	start;
479 	uint64_t	size;
480 
481 	if (sscanf(data, "%d:%d:%x:%llu:%llu",
482 	    &part, &tag, &flag, &start, &size) != 5) {
483 		(void) fprintf(stderr, "Delta syntax error on \"%s\"\n", data);
484 		exit(1);
485 	}
486 	if (part >= V_NUMPAR) {
487 		(void) fprintf(stderr,
488 		    "Error in data \"%s\": No such partition %x\n",
489 		    data, part);
490 		exit(1);
491 	}
492 	vtoc->v_part[part].p_tag = (ushort_t)tag;
493 	vtoc->v_part[part].p_flag = (ushort_t)flag;
494 	vtoc->v_part[part].p_start = start;
495 	vtoc->v_part[part].p_size = size;
496 }
497 
498 /*
499  * insert64()
500  *
501  * Insert a change into the VTOC.
502  */
503 static void
504 insert64(char *data, struct dk_gpt *efi)
505 {
506 	int		part;
507 	int		tag;
508 	uint_t		flag;
509 	diskaddr_t	start;
510 	diskaddr_t	size;
511 
512 	if (sscanf(data, "%d:%d:%x:%lld:%lld",
513 	    &part, &tag, &flag, &start, &size) != 5) {
514 		(void) fprintf(stderr, "Delta syntax error on \"%s\"\n", data);
515 		exit(1);
516 	}
517 	if (part >= efi->efi_nparts) {
518 		(void) fprintf(stderr,
519 		    "Error in data \"%s\": No such partition %x\n",
520 		    data, part);
521 		exit(1);
522 	}
523 	efi->efi_parts[part].p_tag = (ushort_t)tag;
524 	efi->efi_parts[part].p_flag = (ushort_t)flag;
525 	efi->efi_parts[part].p_start = start;
526 	efi->efi_parts[part].p_size = size;
527 }
528 
529 /*
530  * load()
531  *
532  * Load VTOC information from a datafile.
533  */
534 static void
535 load(FILE *fp, struct dk_geom *geom, struct extvtoc *vtoc)
536 {
537 	int		part;
538 	int		tag;
539 	uint_t		flag;
540 	diskaddr_t	start;
541 	uint64_t	size;
542 	char		line[256];
543 	int		i;
544 	uint64_t	nblks;
545 	uint64_t	fullsz;
546 
547 	for (i = 0; i < V_NUMPAR; ++i) {
548 		vtoc->v_part[i].p_tag = 0;
549 		vtoc->v_part[i].p_flag = V_UNMNT;
550 		vtoc->v_part[i].p_start = 0;
551 		vtoc->v_part[i].p_size = 0;
552 	}
553 	/*
554 	 * initialize partition 2, by convention it corresponds to whole
555 	 * disk. It will be overwritten, if specified in the input datafile
556 	 */
557 	fullsz = (uint64_t)geom->dkg_ncyl * geom->dkg_nsect * geom->dkg_nhead;
558 	vtoc->v_part[2].p_tag = V_BACKUP;
559 	vtoc->v_part[2].p_flag = V_UNMNT;
560 	vtoc->v_part[2].p_start = 0;
561 	vtoc->v_part[2].p_size = fullsz;
562 
563 	nblks = geom->dkg_nsect * geom->dkg_nhead;
564 
565 	while (fgets(line, sizeof (line) - 1, fp)) {
566 		if (line[0] == '\0' || line[0] == '\n' || line[0] == '*')
567 			continue;
568 		line[strlen(line) - 1] = '\0';
569 		if (sscanf(line, "%d %d %x %llu %llu",
570 		    &part, &tag, &flag, &start, &size) != 5) {
571 			(void) fprintf(stderr, "Syntax error: \"%s\"\n",
572 			    line);
573 			exit(1);
574 		}
575 		if (part >= V_NUMPAR) {
576 			(void) fprintf(stderr,
577 			    "No such partition %x: \"%s\"\n",
578 			    part, line);
579 			exit(1);
580 		}
581 		if (!eflag && ((start % nblks) != 0 || (size % nblks) != 0)) {
582 			(void) fprintf(stderr,
583 "Partition %d not aligned on cylinder boundary: \"%s\"\n",
584 			    part, line);
585 			exit(1);
586 		}
587 		vtoc->v_part[part].p_tag = (ushort_t)tag;
588 		vtoc->v_part[part].p_flag = (ushort_t)flag;
589 		vtoc->v_part[part].p_start = start;
590 		vtoc->v_part[part].p_size = size;
591 	}
592 	for (part = 0; part < V_NUMPAR; part++) {
593 		vtoc->timestamp[part] = (time_t)0;
594 	}
595 }
596 
597 /*
598  * load64()
599  *
600  * Load VTOC information from a datafile.
601  */
602 static void
603 load64(FILE *fp, int fd, struct dk_gpt **efi)
604 {
605 	int	part;
606 	int	tag;
607 	uint_t	flag;
608 	diskaddr_t	start;
609 	diskaddr_t	size;
610 	int	nlines = 0;
611 	char	line[256];
612 	int	i;
613 	uint_t	max_part = 0;
614 	char	**mem = NULL;
615 
616 	while (fgets(line, sizeof (line) - 1, fp)) {
617 		if (line[0] == '\0' || line[0] == '\n' || line[0] == '*')
618 			continue;
619 		line[strlen(line) - 1] = '\0';
620 		if (sscanf(line, "%d %d %x %lld %lld",
621 		    &part, &tag, &flag, &start, &size) != 5) {
622 			(void) fprintf(stderr, "Syntax error: \"%s\"\n",
623 			    line);
624 			exit(1);
625 		}
626 		mem = realloc(mem, sizeof (*mem) * (nlines + 1));
627 		if (mem == NULL) {
628 			(void) fprintf(stderr, "realloc failed\n");
629 			exit(1);
630 		}
631 		mem[nlines] = strdup(line);
632 		if (mem[nlines] == NULL) {
633 			(void) fprintf(stderr, "strdup failed\n");
634 			exit(1);
635 		}
636 		nlines++;
637 		if (part > max_part)
638 			max_part = part;
639 	}
640 	max_part++;
641 
642 	if ((i = efi_alloc_and_init(fd, max_part, efi)) < 0) {
643 		(void) fprintf(stderr,
644 		    "efi_alloc_and_init failed: %d\n", i);
645 		exit(1);
646 	}
647 	for (i = 0; i < (*efi)->efi_nparts; ++i) {
648 		(*efi)->efi_parts[i].p_tag = V_UNASSIGNED;
649 		(*efi)->efi_parts[i].p_flag = V_UNMNT;
650 		(*efi)->efi_parts[i].p_start = 0;
651 		(*efi)->efi_parts[i].p_size = 0;
652 	}
653 	lastlba = (*efi)->efi_last_u_lba;
654 
655 	for (i = 0; i < nlines; i++) {
656 		if (sscanf(mem[i], "%d %d %x %lld %lld",
657 		    &part, &tag, &flag, &start, &size) != 5) {
658 			(void) fprintf(stderr, "Syntax error: \"%s\"\n",
659 			    line);
660 			exit(1);
661 		}
662 		free(mem[i]);
663 		if (part >= (*efi)->efi_nparts) {
664 			(void) fprintf(stderr,
665 			    "No such partition %x: \"%s\"\n",
666 			    part, line);
667 			exit(1);
668 		}
669 		(*efi)->efi_parts[part].p_tag = (ushort_t)tag;
670 		(*efi)->efi_parts[part].p_flag = (ushort_t)flag;
671 		(*efi)->efi_parts[part].p_start = start;
672 		(*efi)->efi_parts[part].p_size = size;
673 	}
674 	(*efi)->efi_nparts = max_part;
675 	free(mem);
676 }
677 
678 
679 static void
680 usage()
681 {
682 #if defined(sparc)
683 	(void) fprintf(stderr,
684 "Usage:	fmthard [ -i ] [ -n volumename ] [ -s datafile ] [ -d arguments] \
685 raw-device\n");
686 
687 #elif defined(i386)
688 	(void) fprintf(stderr,
689 "Usage:	fmthard [ -i ] [ -S ] [-I geom_file]  \
690 -n volumename | -s datafile  [ -d arguments] raw-device\n");
691 
692 #else
693 #error No platform defined.
694 #endif
695 	exit(2);
696 }
697 
698 /*
699  * validate()
700  *
701  * Validate the new VTOC.
702  */
703 static void
704 validate(struct dk_geom *geom, struct extvtoc *vtoc)
705 {
706 	int		i;
707 	int		j;
708 	uint64_t	fullsz;
709 	diskaddr_t	endsect;
710 	diskaddr_t	istart;
711 	diskaddr_t	jstart;
712 	uint64_t	isize;
713 	uint64_t	jsize;
714 	uint64_t	nblks;
715 
716 	nblks = geom->dkg_nsect * geom->dkg_nhead;
717 
718 	fullsz = (uint64_t)geom->dkg_ncyl * geom->dkg_nsect * geom->dkg_nhead;
719 
720 #if defined(_SUNOS_VTOC_16)
721 	/* make the vtoc look sane - ha ha */
722 	vtoc->v_version = V_VERSION;
723 	vtoc->v_sanity = VTOC_SANE;
724 	vtoc->v_nparts = V_NUMPAR;
725 	if (vtoc->v_sectorsz == 0)
726 		vtoc->v_sectorsz = sectsiz;
727 #endif				/* defined(_SUNOS_VTOC_16) */
728 
729 	for (i = 0; i < V_NUMPAR; i++) {
730 		if (vtoc->v_part[i].p_tag == V_BACKUP) {
731 			if (vtoc->v_part[i].p_size != fullsz) {
732 				(void) fprintf(stderr, "\
733 fmthard: Partition %d specifies the full disk and is not equal\n\
734 full size of disk.  The full disk capacity is %llu sectors.\n", i, fullsz);
735 #if defined(sparc)
736 			exit(1);
737 #endif
738 			}
739 		}
740 		if (vtoc->v_part[i].p_size == 0)
741 			continue;	/* Undefined partition */
742 		if ((vtoc->v_part[i].p_start % nblks) ||
743 		    (vtoc->v_part[i].p_size % nblks)) {
744 			(void) fprintf(stderr, "\
745 fmthard: Partition %d not aligned on cylinder boundary \n", i);
746 			exit(1);
747 		}
748 		if (vtoc->v_part[i].p_start > fullsz ||
749 		    vtoc->v_part[i].p_start +
750 		    vtoc->v_part[i].p_size > fullsz) {
751 			(void) fprintf(stderr, "\
752 fmthard: Partition %d specified as %llu sectors starting at %llu\n\
753 \tdoes not fit. The full disk contains %llu sectors.\n",
754 			    i, vtoc->v_part[i].p_size,
755 			    vtoc->v_part[i].p_start, fullsz);
756 #if defined(sparc)
757 			exit(1);
758 #endif
759 		}
760 
761 		if (vtoc->v_part[i].p_tag != V_BACKUP &&
762 		    vtoc->v_part[i].p_size != fullsz) {
763 			for (j = 0; j < V_NUMPAR; j++) {
764 				if (vtoc->v_part[j].p_tag == V_BACKUP)
765 					continue;
766 				if (vtoc->v_part[j].p_size == fullsz)
767 					continue;
768 				isize = vtoc->v_part[i].p_size;
769 				jsize = vtoc->v_part[j].p_size;
770 				istart = vtoc->v_part[i].p_start;
771 				jstart = vtoc->v_part[j].p_start;
772 				if ((i != j) &&
773 				    (isize != 0) && (jsize != 0)) {
774 					endsect = jstart + jsize -1;
775 					if ((jstart <= istart) &&
776 					    (istart <= endsect)) {
777 						(void) fprintf(stderr, "\
778 fmthard: Partition %d overlaps partition %d. Overlap is allowed\n\
779 \tonly on partition on the full disk partition).\n",
780 						    i, j);
781 #if defined(sparc)
782 						exit(1);
783 #endif
784 					}
785 				}
786 			}
787 		}
788 	}
789 }
790 
791 /*
792  * validate64()
793  *
794  * Validate the new VTOC.
795  */
796 static void
797 validate64(struct dk_gpt *efi)
798 {
799 	int		i;
800 	int		j;
801 	int		resv_part = 0;
802 	diskaddr_t	endsect;
803 	diskaddr_t	fullsz;
804 	diskaddr_t		istart;
805 	diskaddr_t		jstart;
806 	diskaddr_t		isize;
807 	diskaddr_t		jsize;
808 
809 	fullsz = lastlba + 1;
810 
811 	for (i = 0; i < efi->efi_nparts; i++) {
812 		if (efi->efi_parts[i].p_size == 0)
813 			continue;	/* Undefined partition */
814 		if (efi->efi_parts[i].p_tag == V_RESERVED)
815 			resv_part++;
816 		if (efi->efi_parts[i].p_start > fullsz ||
817 		    efi->efi_parts[i].p_start +
818 		    efi->efi_parts[i].p_size > fullsz) {
819 			(void) fprintf(stderr, "\
820 fmthard: Partition %d specified as %lld sectors starting at %lld\n\
821 \tdoes not fit. The full disk contains %lld sectors.\n",
822 			    i, efi->efi_parts[i].p_size,
823 			    efi->efi_parts[i].p_start, fullsz);
824 			exit(1);
825 		}
826 
827 		if (efi->efi_parts[i].p_tag != V_BACKUP &&
828 		    efi->efi_parts[i].p_size != fullsz) {
829 			for (j = 0; j < efi->efi_nparts; j++) {
830 				if (efi->efi_parts[j].p_size == fullsz)
831 					continue;
832 				isize = efi->efi_parts[i].p_size;
833 				jsize = efi->efi_parts[j].p_size;
834 				istart = efi->efi_parts[i].p_start;
835 				jstart = efi->efi_parts[j].p_start;
836 				if ((i != j) &&
837 				    (isize != 0) && (jsize != 0)) {
838 					endsect = jstart + jsize - 1;
839 					if ((jstart <= istart) &&
840 					    (istart <= endsect)) {
841 						(void) fprintf(stderr, "\
842 fmthard: Partition %d overlaps partition %d. Overlap is allowed\n\
843 \tonly on partition on the full disk partition).\n",
844 						    i, j);
845 #if defined(sparc)
846 						exit(1);
847 #endif
848 					}
849 				}
850 			}
851 		}
852 	}
853 	if (resv_part != 1) {
854 		(void) fprintf(stderr,
855 		    "expected one reserved partition, but found %d\n",
856 		    resv_part);
857 		exit(1);
858 	}
859 }
860 
861 
862 /*
863  * Read the VTOC
864  */
865 int
866 vread(int fd, struct extvtoc *vtoc, char *devname)
867 {
868 	int	i;
869 
870 	if ((i = read_extvtoc(fd, vtoc)) < 0) {
871 		if (i == VT_ENOTSUP) {
872 			return (1);
873 		}
874 		if (i == VT_EINVAL) {
875 			(void) fprintf(stderr, "%s: Invalid VTOC\n",
876 			    devname);
877 		} else {
878 			(void) fprintf(stderr, "%s: Cannot read VTOC\n",
879 			    devname);
880 		}
881 		exit(1);
882 	}
883 	return (0);
884 }
885 
886 void
887 vread64(int fd, struct dk_gpt **efi_hdr, char *devname)
888 {
889 	int i;
890 
891 	if ((i = efi_alloc_and_read(fd, efi_hdr)) < 0) {
892 		if (i == VT_EINVAL)
893 			(void) fprintf(stderr,
894 			    "%s: this disk must be labeled first\n",
895 			    devname);
896 		else
897 			(void) fprintf(stderr,
898 			    "%s: read_efi failed %d\n",
899 			    devname, i);
900 		exit(1);
901 	}
902 	lastlba = (*efi_hdr)->efi_last_u_lba;
903 }
904 
905 /*
906  * Write the VTOC
907  */
908 void
909 vwrite(int fd, struct extvtoc *vtoc, char *devname)
910 {
911 	int	i;
912 
913 	if ((i = write_extvtoc(fd, vtoc)) != 0) {
914 		if (i == VT_EINVAL) {
915 			(void) fprintf(stderr,
916 			"%s: invalid entry exists in vtoc\n",
917 			    devname);
918 		} else {
919 			(void) fprintf(stderr, "%s: Cannot write VTOC\n",
920 			    devname);
921 		}
922 		exit(1);
923 	}
924 }
925 
926 /*
927  * Write the VTOC
928  */
929 void
930 vwrite64(int fd, struct dk_gpt *efi, char *devname)
931 {
932 	int	i;
933 
934 	if ((i = efi_write(fd, efi)) != 0) {
935 		if (i == VT_EINVAL) {
936 			(void) fprintf(stderr,
937 			"%s: invalid entry exists in vtoc\n",
938 			    devname);
939 		} else {
940 			(void) fprintf(stderr, "%s: Cannot write EFI\n",
941 			    devname);
942 		}
943 		exit(1);
944 	}
945 }
946