xref: /illumos-gate/usr/src/cmd/fmthard/fmthard.c (revision 7f7322febbcfe774b7270abc3b191c094bfcc517)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
23 /*	  All Rights Reserved  	*/
24 
25 
26 /*
27  *
28  *	Portions of this source code were provided by International
29  *	Computers Limited (ICL) under a development agreement with AT&T.
30  */
31 
32 #pragma ident	"%Z%%M%	%I%	%E% SMI"
33 
34 /*
35  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
36  * Use is subject to license terms.
37  */
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/stat.h>
72 #include <sys/uadmin.h>
73 #include <sys/open.h>
74 #include <sys/vtoc.h>
75 #include <sys/dkio.h>
76 #include <sys/isa_defs.h>
77 #include <sys/efi_partition.h>
78 
79 #if defined(_SUNOS_VTOC_16)
80 #include <sys/dklabel.h>
81 #endif
82 
83 #include <sys/sysmacros.h>
84 
85 #ifndef	SECSIZE
86 #define	SECSIZE			DEV_BSIZE
87 #endif	/* SECSIZE */
88 
89 
90 /*
91  * External functions.
92  */
93 extern	int	read_vtoc(int, struct vtoc *);
94 extern	int	write_vtoc(int, struct vtoc *);
95 
96 /*
97  * Internal functions.
98  */
99 extern	int	main(int, char **);
100 static	void	display(struct dk_geom *, struct vtoc *, char *);
101 static	void	display64(struct dk_gpt *,  char *);
102 static	void	insert(char *, struct vtoc *);
103 static	void	insert64(char *, struct dk_gpt *);
104 static	void	load(FILE *, struct dk_geom *, struct vtoc *);
105 static	void	load64(FILE *, int fd, struct dk_gpt **);
106 static	void	usage(void);
107 static	void	validate(struct dk_geom *, struct vtoc *);
108 static	void	validate64(struct dk_gpt *);
109 static	int	vread(int, struct vtoc *, char *);
110 static	void	vread64(int, struct dk_gpt **, char *);
111 static	void	vwrite(int, struct vtoc *, char *);
112 static	void	vwrite64(int, struct dk_gpt *, char *);
113 
114 /*
115  * Static variables.
116  */
117 static char	*delta;		/* Incremental update */
118 static short	eflag;		/* force write of an EFI label */
119 static short	iflag;		/* Prints VTOC w/o updating */
120 static short	qflag;		/* Check for a formatted disk */
121 static short	uflag;		/* Exit to firmware after writing  */
122 				/* new vtoc and reboot. Used during */
123 				/* installation of core floppies */
124 static diskaddr_t	lastlba = 0;	/* last LBA on 64-bit VTOC */
125 
126 #if defined(sparc)
127 static char	*uboot = "boot";
128 
129 #elif defined(i386)
130 /* use installgrub(1M) to install boot blocks */
131 static char *uboot = "";
132 #else
133 #error No platform defined.
134 #endif	/* various platform-specific definitions */
135 
136 static char	*ufirm = "firm";
137 #if defined(_SUNOS_VTOC_16)
138 static int		sectsiz;
139 static struct vtoc	disk_vtoc;
140 #endif	/* defined(_SUNOS_VTOC_16) */
141 
142 int
143 main(int argc, char **argv)
144 {
145 	int		fd;
146 	int		c;
147 	char		*dfile;
148 	char		*vname;
149 	struct stat	statbuf;
150 #if defined(_SUNOS_VTOC_8)
151 	struct vtoc	disk_vtoc;
152 #endif	/* defined(_SUNOS_VTOC_8) */
153 	struct dk_gpt	*disk_efi;
154 	struct dk_geom	disk_geom;
155 	int		n;
156 
157 
158 	disk_efi = NULL;
159 	dfile = NULL;
160 	vname = NULL;
161 #if defined(sparc)
162 	while ((c = getopt(argc, argv, "ed:u:in:qs:")) != EOF)
163 
164 #elif defined(i386)
165 	while ((c = getopt(argc, argv, "ed:u:in:qb:p:s:")) != EOF)
166 
167 #else
168 #error No platform defined.
169 #endif
170 		switch (c) {
171 #if defined(i386)
172 		case 'p':
173 		case 'b':
174 			(void) fprintf(stderr,
175 			    "fmthard: -p and -b no longer supported."
176 			    " Use installgrub(1M) to install boot blocks\n");
177 			break;
178 #endif	/* defined(i386) */
179 
180 		case 'd':
181 			delta = optarg;
182 			break;
183 		case 'e':
184 			++eflag;
185 			break;
186 		case 'i':
187 			++iflag;
188 			break;
189 		case 'n':
190 			vname = optarg;
191 			break;
192 		case 'q':
193 			++qflag;
194 			break;
195 		case 's':
196 			dfile = optarg;
197 			break;
198 		case 'u':
199 			if (strcmp(uboot, optarg) == 0)
200 				++uflag;
201 			else if (strcmp(ufirm, optarg) == 0)
202 				uflag = 2;
203 
204 			break;
205 		default:
206 			usage();
207 		}
208 
209 
210 	if (argc - optind != 1)
211 		usage();
212 
213 	if (stat(argv[optind], (struct stat *)&statbuf) == -1) {
214 		(void) fprintf(stderr,
215 			"fmthard:  Cannot stat device %s\n",
216 			argv[optind]);
217 		exit(1);
218 	}
219 
220 	if ((statbuf.st_mode & S_IFMT) != S_IFCHR) {
221 		(void) fprintf(stderr,
222 			"fmthard:  %s must be a raw device.\n",
223 			argv[optind]);
224 		exit(1);
225 	}
226 
227 	if ((fd = open(argv[optind], O_RDWR|O_NDELAY)) < 0) {
228 		(void) fprintf(stderr, "fmthard:  Cannot open device %s - %s\n",
229 			argv[optind], strerror(errno));
230 		exit(1);
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 	/*
321 	 * Print the modified VTOC, rather than updating the disk
322 	 */
323 	if (iflag) {
324 		if (!eflag)
325 			display(&disk_geom, &disk_vtoc, argv[optind]);
326 		else
327 			display64(disk_efi, argv[optind]);
328 		(void) close(fd);
329 		exit(0);
330 	}
331 
332 	if (vname) {
333 		n = MIN(strlen(vname) + 1, LEN_DKL_VVOL);
334 		if (!eflag) {
335 			(void) memcpy(disk_vtoc.v_volume, vname, n);
336 		} else {
337 			for (c = 0; c < disk_efi->efi_nparts; c++) {
338 			    if (disk_efi->efi_parts[c].p_tag ==
339 				    V_RESERVED) {
340 				(void) memcpy(&disk_efi->efi_parts[c].p_name,
341 					    vname, n);
342 				}
343 			}
344 		}
345 
346 	}
347 	/*
348 	 * Write the new VTOC on the disk
349 	 */
350 	if (!eflag) {
351 		validate(&disk_geom, &disk_vtoc);
352 		vwrite(fd, &disk_vtoc, argv[optind]);
353 	} else {
354 		validate64(disk_efi);
355 		vwrite64(fd, disk_efi, argv[optind]);
356 	}
357 
358 	/*
359 	 * Shut system down after writing a new vtoc to disk
360 	 * This is used during installation of core floppies.
361 	 */
362 	if (uflag == 1)
363 		uadmin(A_REBOOT, AD_BOOT, 0);
364 	else if (uflag == 2)
365 		uadmin(A_REBOOT, AD_IBOOT, 0);
366 
367 	(void) printf("fmthard:  New volume table of contents now in place.\n");
368 
369 	return (0);
370 	/*NOTREACHED*/
371 }
372 
373 
374 
375 /*
376  * display ()
377  *
378  * display contents of VTOC without writing it to disk
379  */
380 static void
381 display(struct dk_geom *geom, struct vtoc *vtoc, char *device)
382 {
383 	int	i;
384 	int	c;
385 
386 	/*
387 	 * Print out the VTOC
388 	 */
389 	(void) printf("* %s default partition map\n", device);
390 	if (*vtoc->v_volume) {
391 		(void) printf("* Volume Name:  ");
392 		for (i = 0; i < LEN_DKL_VVOL; i++) {
393 			if ((c = vtoc->v_volume[i]) == 0)
394 				break;
395 			(void) printf("%c", c);
396 		}
397 		(void) printf("\n");
398 	}
399 	(void) printf("*\n");
400 	(void) printf("* Dimensions:\n");
401 	(void) printf("*     %d bytes/sector\n", SECSIZE);
402 	(void) printf("*      %d sectors/track\n", geom->dkg_nsect);
403 	(void) printf("*       %d tracks/cylinder\n", geom->dkg_nhead);
404 	(void) printf("*     %d cylinders\n", geom->dkg_pcyl);
405 	(void) printf("*     %d accessible cylinders\n", geom->dkg_ncyl);
406 	(void) printf("*\n");
407 	(void) printf("* Flags:\n");
408 	(void) printf("*   1:  unmountable\n");
409 	(void) printf("*  10:  read-only\n");
410 	(void) printf("*\n");
411 	(void) printf(
412 "\n* Partition    Tag     Flag	    First Sector    Sector Count\n");
413 	for (i = 0; i < V_NUMPAR; i++) {
414 		if (vtoc->v_part[i].p_size > 0)
415 			(void) printf(
416 "    %d		%d	0%x		%ld		%ld\n",
417 				i, vtoc->v_part[i].p_tag,
418 				vtoc->v_part[i].p_flag,
419 				vtoc->v_part[i].p_start,
420 				vtoc->v_part[i].p_size);
421 	}
422 	exit(0);
423 }
424 
425 /*
426  * display64 ()
427  *
428  * display64 contents of EFI partition without writing it to disk
429  */
430 static void
431 display64(struct dk_gpt *efi, char *device)
432 {
433 	int	i;
434 
435 	/*
436 	 * Print out the VTOC
437 	 */
438 	(void) printf("* %s default partition map\n", device);
439 	(void) printf("*\n");
440 	(void) printf("* Dimensions:\n");
441 	(void) printf("*     %d bytes/sector\n", efi->efi_lbasize);
442 	(void) printf("*     N/A sectors/track\n");
443 	(void) printf("*     N/A tracks/cylinder\n");
444 	(void) printf("*     N/A cylinders\n");
445 	(void) printf("*     N/A accessible cylinders\n");
446 	(void) printf("*\n");
447 	(void) printf("* Flags:\n");
448 	(void) printf("*   1:  unmountable\n");
449 	(void) printf("*  10:  read-only\n");
450 	(void) printf("*\n");
451 	(void) printf(
452 "\n* Partition    Tag     Flag	    First Sector    Sector Count\n");
453 	for (i = 0; i < efi->efi_nparts; i++) {
454 		if (efi->efi_parts[i].p_size > 0)
455 			(void) printf(
456 "    %d		%d	0%x		%8lld	%8lld\n",
457 				i, efi->efi_parts[i].p_tag,
458 				efi->efi_parts[i].p_flag,
459 				efi->efi_parts[i].p_start,
460 				efi->efi_parts[i].p_size);
461 	}
462 	exit(0);
463 }
464 
465 
466 /*
467  * insert()
468  *
469  * Insert a change into the VTOC.
470  */
471 static void
472 insert(char *data, struct vtoc *vtoc)
473 {
474 	int	part;
475 	int	tag;
476 	uint_t	flag;
477 	daddr_t	start;
478 	long	size;
479 
480 	if (sscanf(data, "%d:%d:%x:%ld:%ld",
481 	    &part, &tag, &flag, &start, &size) != 5) {
482 		(void) fprintf(stderr, "Delta syntax error on \"%s\"\n", data);
483 		exit(1);
484 	}
485 	if (part >= V_NUMPAR) {
486 		(void) fprintf(stderr,
487 			"Error in data \"%s\": No such partition %x\n",
488 			data, part);
489 		exit(1);
490 	}
491 	vtoc->v_part[part].p_tag = (ushort_t)tag;
492 	vtoc->v_part[part].p_flag = (ushort_t)flag;
493 	vtoc->v_part[part].p_start = start;
494 	vtoc->v_part[part].p_size = size;
495 }
496 
497 /*
498  * insert64()
499  *
500  * Insert a change into the VTOC.
501  */
502 static void
503 insert64(char *data, struct dk_gpt *efi)
504 {
505 	int		part;
506 	int		tag;
507 	uint_t		flag;
508 	diskaddr_t	start;
509 	diskaddr_t	size;
510 
511 	if (sscanf(data, "%d:%d:%x:%lld:%lld",
512 	    &part, &tag, &flag, &start, &size) != 5) {
513 		(void) fprintf(stderr, "Delta syntax error on \"%s\"\n", data);
514 		exit(1);
515 	}
516 	if (part >= efi->efi_nparts) {
517 		(void) fprintf(stderr,
518 			"Error in data \"%s\": No such partition %x\n",
519 			data, part);
520 		exit(1);
521 	}
522 	efi->efi_parts[part].p_tag = (ushort_t)tag;
523 	efi->efi_parts[part].p_flag = (ushort_t)flag;
524 	efi->efi_parts[part].p_start = start;
525 	efi->efi_parts[part].p_size = size;
526 }
527 
528 /*
529  * load()
530  *
531  * Load VTOC information from a datafile.
532  */
533 static void
534 load(FILE *fp, struct dk_geom *geom, struct vtoc *vtoc)
535 {
536 	int	part;
537 	int	tag;
538 	uint_t	flag;
539 	daddr_t	start;
540 	long	size;
541 	char	line[256];
542 	int	i;
543 	long	nblks;
544 	long	fullsz;
545 
546 	for (i = 0; i < V_NUMPAR; ++i) {
547 		vtoc->v_part[i].p_tag = 0;
548 		vtoc->v_part[i].p_flag = V_UNMNT;
549 		vtoc->v_part[i].p_start = 0;
550 		vtoc->v_part[i].p_size = 0;
551 	}
552 	/*
553 	 * initialize partition 2, by convention it corresponds to whole
554 	 * disk. It will be overwritten, if specified in the input datafile
555 	 */
556 	fullsz = geom->dkg_ncyl * geom->dkg_nsect * geom->dkg_nhead;
557 	vtoc->v_part[2].p_tag = V_BACKUP;
558 	vtoc->v_part[2].p_flag = V_UNMNT;
559 	vtoc->v_part[2].p_start = 0;
560 	vtoc->v_part[2].p_size = fullsz;
561 
562 	nblks = geom->dkg_nsect * geom->dkg_nhead;
563 
564 	while (fgets(line, sizeof (line) - 1, fp)) {
565 		if (line[0] == '\0' || line[0] == '\n' || line[0] == '*')
566 			continue;
567 		line[strlen(line) - 1] = '\0';
568 		if (sscanf(line, "%d %d %x %ld %ld",
569 		    &part, &tag, &flag, &start, &size) != 5) {
570 			(void) fprintf(stderr, "Syntax error: \"%s\"\n",
571 				line);
572 			exit(1);
573 		}
574 		if (part >= V_NUMPAR) {
575 			(void) fprintf(stderr,
576 				"No such partition %x: \"%s\"\n",
577 				part, line);
578 			exit(1);
579 		}
580 		if (!eflag && ((start % nblks) != 0 || (size % nblks) != 0)) {
581 			(void) fprintf(stderr,
582 "Partition %d not aligned on cylinder boundary: \"%s\"\n",
583 					part, line);
584 			exit(1);
585 		}
586 		vtoc->v_part[part].p_tag = (ushort_t)tag;
587 		vtoc->v_part[part].p_flag = (ushort_t)flag;
588 		vtoc->v_part[part].p_start = start;
589 		vtoc->v_part[part].p_size = size;
590 	}
591 	for (part = 0; part < V_NUMPAR; part++) {
592 		vtoc->timestamp[part] = (time_t)0;
593 	}
594 }
595 
596 /*
597  * load64()
598  *
599  * Load VTOC information from a datafile.
600  */
601 static void
602 load64(FILE *fp, int fd, struct dk_gpt **efi)
603 {
604 	int	part;
605 	int	tag;
606 	uint_t	flag;
607 	diskaddr_t	start;
608 	diskaddr_t	size;
609 	int	nlines = 0;
610 	char	line[256];
611 	int	i;
612 	uint_t	max_part = 0;
613 	char	**mem = NULL;
614 
615 	while (fgets(line, sizeof (line) - 1, fp)) {
616 		if (line[0] == '\0' || line[0] == '\n' || line[0] == '*')
617 			continue;
618 		line[strlen(line) - 1] = '\0';
619 		if (sscanf(line, "%d %d %x %lld %lld",
620 		    &part, &tag, &flag, &start, &size) != 5) {
621 			(void) fprintf(stderr, "Syntax error: \"%s\"\n",
622 				line);
623 			exit(1);
624 		}
625 		mem = realloc(mem, sizeof (*mem) * (nlines + 1));
626 		if (mem == NULL) {
627 			(void) fprintf(stderr, "realloc failed\n");
628 			exit(1);
629 		}
630 		mem[nlines] = strdup(line);
631 		if (mem[nlines] == NULL) {
632 			(void) fprintf(stderr, "strdup failed\n");
633 			exit(1);
634 		}
635 		nlines++;
636 		if (part > max_part)
637 		    max_part = part;
638 	}
639 	max_part++;
640 
641 	if ((i = efi_alloc_and_init(fd, max_part, efi)) < 0) {
642 		(void) fprintf(stderr,
643 				"efi_alloc_and_init failed: %d\n", i);
644 		exit(1);
645 	}
646 	for (i = 0; i < (*efi)->efi_nparts; ++i) {
647 		(*efi)->efi_parts[i].p_tag = V_UNASSIGNED;
648 		(*efi)->efi_parts[i].p_flag = V_UNMNT;
649 		(*efi)->efi_parts[i].p_start = 0;
650 		(*efi)->efi_parts[i].p_size = 0;
651 	}
652 	lastlba = (*efi)->efi_last_u_lba;
653 
654 	for (i = 0; i < nlines; i++) {
655 		if (sscanf(mem[i], "%d %d %x %lld %lld",
656 		    &part, &tag, &flag, &start, &size) != 5) {
657 			(void) fprintf(stderr, "Syntax error: \"%s\"\n",
658 				line);
659 			exit(1);
660 		}
661 		free(mem[i]);
662 		if (part >= (*efi)->efi_nparts) {
663 			(void) fprintf(stderr,
664 				"No such partition %x: \"%s\"\n",
665 				part, line);
666 			exit(1);
667 		}
668 		(*efi)->efi_parts[part].p_tag = (ushort_t)tag;
669 		(*efi)->efi_parts[part].p_flag = (ushort_t)flag;
670 		(*efi)->efi_parts[part].p_start = start;
671 		(*efi)->efi_parts[part].p_size = size;
672 	}
673 	(*efi)->efi_nparts = max_part;
674 	free(mem);
675 }
676 
677 
678 static void
679 usage()
680 {
681 	(void) fprintf(stderr,
682 #if defined(sparc)
683 "Usage:	fmthard [ -i ] [ -n volumename ] [ -s datafile ] [ -d arguments] \
684 raw-device\n");
685 
686 #elif defined(i386)
687 "Usage:	fmthard [ -i ] [ -S ] [-I geom_file]  \
688 -n volumename | -s datafile  [ -d arguments] raw-device\n");
689 
690 #else
691 #error No platform defined.
692 #endif
693 	exit(2);
694 }
695 
696 /*
697  * validate()
698  *
699  * Validate the new VTOC.
700  */
701 static void
702 validate(struct dk_geom *geom, struct vtoc *vtoc)
703 {
704 	int	i;
705 	int	j;
706 	long	fullsz;
707 	long	endsect;
708 	daddr_t	istart;
709 	daddr_t	jstart;
710 	long	isize;
711 	long	jsize;
712 	long	nblks;
713 
714 	nblks = geom->dkg_nsect * geom->dkg_nhead;
715 
716 	fullsz = geom->dkg_ncyl * geom->dkg_nsect * geom->dkg_nhead;
717 
718 #if defined(_SUNOS_VTOC_16)
719 	/* make the vtoc look sane - ha ha */
720 	vtoc->v_version = V_VERSION;
721 	vtoc->v_sanity = VTOC_SANE;
722 	vtoc->v_nparts = V_NUMPAR;
723 	if (sectsiz == 0)
724 		sectsiz = SECSIZE;
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 %lu 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 %lu sectors starting at %lu\n\
753 \tdoes not fit. The full disk contains %lu 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 < V_NUMPAR; 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 vtoc *vtoc, char *devname)
867 {
868 	int	i;
869 
870 	if ((i = read_vtoc(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 vtoc *vtoc, char *devname)
910 {
911 	int	i;
912 
913 	if ((i = write_vtoc(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