xref: /illumos-gate/usr/src/cmd/fmthard/fmthard.c (revision cc6c5292fa8a241fe50604cf6a918edfbf7cd7d2)
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 	dfile = NULL;
159 	vname = NULL;
160 #if defined(sparc)
161 	while ((c = getopt(argc, argv, "ed:u:in:qs:")) != EOF)
162 
163 #elif defined(i386)
164 	while ((c = getopt(argc, argv, "ed:u:in:qb:p:s:")) != EOF)
165 
166 #else
167 #error No platform defined.
168 #endif
169 		switch (c) {
170 #if defined(i386)
171 		case 'p':
172 		case 'b':
173 			(void) fprintf(stderr,
174 			    "fmthard: -p and -b no longer supported."
175 			    " Use installgrub(1M) to install boot blocks\n");
176 			break;
177 #endif	/* defined(i386) */
178 
179 		case 'd':
180 			delta = optarg;
181 			break;
182 		case 'e':
183 			++eflag;
184 			break;
185 		case 'i':
186 			++iflag;
187 			break;
188 		case 'n':
189 			vname = optarg;
190 			break;
191 		case 'q':
192 			++qflag;
193 			break;
194 		case 's':
195 			dfile = optarg;
196 			break;
197 		case 'u':
198 			if (strcmp(uboot, optarg) == 0)
199 				++uflag;
200 			else if (strcmp(ufirm, optarg) == 0)
201 				uflag = 2;
202 
203 			break;
204 		default:
205 			usage();
206 		}
207 
208 
209 	if (argc - optind != 1)
210 		usage();
211 
212 	if (stat(argv[optind], (struct stat *)&statbuf) == -1) {
213 		(void) fprintf(stderr,
214 			"fmthard:  Cannot stat device %s\n",
215 			argv[optind]);
216 		exit(1);
217 	}
218 
219 	if ((statbuf.st_mode & S_IFMT) != S_IFCHR) {
220 		(void) fprintf(stderr,
221 			"fmthard:  %s must be a raw device.\n",
222 			argv[optind]);
223 		exit(1);
224 	}
225 
226 	if ((fd = open(argv[optind], O_RDWR|O_NDELAY)) < 0) {
227 		(void) fprintf(stderr, "fmthard:  Cannot open device %s - %s\n",
228 			argv[optind], strerror(errno));
229 		exit(1);
230 	}
231 
232 	/*
233 	 * Get the geometry information for this disk from the driver
234 	 */
235 	if (!eflag && ioctl(fd, DKIOCGGEOM, &disk_geom)) {
236 #ifdef DEBUG
237 		perror("DKIOCGGEOM failed");
238 #endif /* DEBUG */
239 		if (errno == ENOTSUP) {
240 			/* disk has EFI labels */
241 			eflag++;
242 		} else {
243 			(void) fprintf(stderr,
244 				"%s: Cannot get disk geometry\n", argv[optind]);
245 			(void) close(fd);
246 			exit(1);
247 		}
248 	}
249 
250 	/*
251 	 * Read the vtoc on the disk
252 	 */
253 	if (!eflag) {
254 		if (vread(fd, &disk_vtoc, argv[optind]) == 1)
255 			eflag++;
256 	}
257 	if (eflag && (dfile == NULL)) {
258 		vread64(fd, &disk_efi, argv[optind]);
259 	}
260 
261 	/*
262 	 * Quick check for valid disk: 0 if ok, 1 if not
263 	 */
264 	if (qflag) {
265 		(void) close(fd);
266 		if (!eflag) {
267 			exit(disk_vtoc.v_sanity == VTOC_SANE ? 0 : 1);
268 		} else {
269 			exit(disk_efi->efi_version <= EFI_VERSION102 ? 0 : 1);
270 		}
271 	}
272 
273 	/*
274 	 * Incremental changes to the VTOC
275 	 */
276 	if (delta) {
277 		if (!eflag) {
278 			insert(delta, &disk_vtoc);
279 			validate(&disk_geom, &disk_vtoc);
280 			vwrite(fd, &disk_vtoc, argv[optind]);
281 		} else {
282 			insert64(delta, disk_efi);
283 			validate64(disk_efi);
284 			vwrite64(fd, disk_efi, argv[optind]);
285 		}
286 		(void) close(fd);
287 		exit(0);
288 	}
289 
290 	if (!dfile && !vname)
291 		usage();
292 
293 	/*
294 	 * Read new VTOC from stdin or data file
295 	 */
296 	if (dfile) {
297 		if (strcmp(dfile, "-") == 0) {
298 			if (!eflag)
299 				load(stdin, &disk_geom, &disk_vtoc);
300 			else
301 				load64(stdin, fd, &disk_efi);
302 		} else {
303 			FILE *fp;
304 			if ((fp = fopen(dfile, "r")) == NULL) {
305 				(void) fprintf(stderr, "Cannot open file %s\n",
306 					dfile);
307 				(void) close(fd);
308 				exit(1);
309 			}
310 			if (!eflag)
311 				load(fp, &disk_geom, &disk_vtoc);
312 			else
313 				load64(fp, fd, &disk_efi);
314 			(void) fclose(fp);
315 		}
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 		uadmin(A_REBOOT, AD_BOOT, 0);
363 	else if (uflag == 2)
364 		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 	/*NOTREACHED*/
370 }
371 
372 
373 
374 /*
375  * display ()
376  *
377  * display contents of VTOC without writing it to disk
378  */
379 static void
380 display(struct dk_geom *geom, struct vtoc *vtoc, char *device)
381 {
382 	int	i;
383 	int	c;
384 
385 	/*
386 	 * Print out the VTOC
387 	 */
388 	(void) printf("* %s default partition map\n", device);
389 	if (*vtoc->v_volume) {
390 		(void) printf("* Volume Name:  ");
391 		for (i = 0; i < LEN_DKL_VVOL; i++) {
392 			if ((c = vtoc->v_volume[i]) == 0)
393 				break;
394 			(void) printf("%c", c);
395 		}
396 		(void) printf("\n");
397 	}
398 	(void) printf("*\n");
399 	(void) printf("* Dimensions:\n");
400 	(void) printf("*     %d bytes/sector\n", SECSIZE);
401 	(void) printf("*      %d sectors/track\n", geom->dkg_nsect);
402 	(void) printf("*       %d tracks/cylinder\n", geom->dkg_nhead);
403 	(void) printf("*     %d cylinders\n", geom->dkg_pcyl);
404 	(void) printf("*     %d accessible cylinders\n", geom->dkg_ncyl);
405 	(void) printf("*\n");
406 	(void) printf("* Flags:\n");
407 	(void) printf("*   1:  unmountable\n");
408 	(void) printf("*  10:  read-only\n");
409 	(void) printf("*\n");
410 	(void) printf(
411 "\n* Partition    Tag     Flag	    First Sector    Sector Count\n");
412 	for (i = 0; i < V_NUMPAR; i++) {
413 		if (vtoc->v_part[i].p_size > 0)
414 			(void) printf(
415 "    %d		%d	0%x		%ld		%ld\n",
416 				i, vtoc->v_part[i].p_tag,
417 				vtoc->v_part[i].p_flag,
418 				vtoc->v_part[i].p_start,
419 				vtoc->v_part[i].p_size);
420 	}
421 	exit(0);
422 }
423 
424 /*
425  * display64 ()
426  *
427  * display64 contents of EFI partition without writing it to disk
428  */
429 static void
430 display64(struct dk_gpt *efi, char *device)
431 {
432 	int	i;
433 
434 	/*
435 	 * Print out the VTOC
436 	 */
437 	(void) printf("* %s default partition map\n", device);
438 	(void) printf("*\n");
439 	(void) printf("* Dimensions:\n");
440 	(void) printf("*     %d bytes/sector\n", efi->efi_lbasize);
441 	(void) printf("*     N/A sectors/track\n");
442 	(void) printf("*     N/A tracks/cylinder\n");
443 	(void) printf("*     N/A cylinders\n");
444 	(void) printf("*     N/A accessible cylinders\n");
445 	(void) printf("*\n");
446 	(void) printf("* Flags:\n");
447 	(void) printf("*   1:  unmountable\n");
448 	(void) printf("*  10:  read-only\n");
449 	(void) printf("*\n");
450 	(void) printf(
451 "\n* Partition    Tag     Flag	    First Sector    Sector Count\n");
452 	for (i = 0; i < efi->efi_nparts; i++) {
453 		if (efi->efi_parts[i].p_size > 0)
454 			(void) printf(
455 "    %d		%d	0%x		%8lld	%8lld\n",
456 				i, efi->efi_parts[i].p_tag,
457 				efi->efi_parts[i].p_flag,
458 				efi->efi_parts[i].p_start,
459 				efi->efi_parts[i].p_size);
460 	}
461 	exit(0);
462 }
463 
464 
465 /*
466  * insert()
467  *
468  * Insert a change into the VTOC.
469  */
470 static void
471 insert(char *data, struct vtoc *vtoc)
472 {
473 	int	part;
474 	int	tag;
475 	uint_t	flag;
476 	daddr_t	start;
477 	long	size;
478 
479 	if (sscanf(data, "%d:%d:%x:%ld:%ld",
480 	    &part, &tag, &flag, &start, &size) != 5) {
481 		(void) fprintf(stderr, "Delta syntax error on \"%s\"\n", data);
482 		exit(1);
483 	}
484 	if (part >= V_NUMPAR) {
485 		(void) fprintf(stderr,
486 			"Error in data \"%s\": No such partition %x\n",
487 			data, part);
488 		exit(1);
489 	}
490 	vtoc->v_part[part].p_tag = (ushort_t)tag;
491 	vtoc->v_part[part].p_flag = (ushort_t)flag;
492 	vtoc->v_part[part].p_start = start;
493 	vtoc->v_part[part].p_size = size;
494 }
495 
496 /*
497  * insert64()
498  *
499  * Insert a change into the VTOC.
500  */
501 static void
502 insert64(char *data, struct dk_gpt *efi)
503 {
504 	int		part;
505 	int		tag;
506 	uint_t		flag;
507 	diskaddr_t	start;
508 	diskaddr_t	size;
509 
510 	if (sscanf(data, "%d:%d:%x:%lld:%lld",
511 	    &part, &tag, &flag, &start, &size) != 5) {
512 		(void) fprintf(stderr, "Delta syntax error on \"%s\"\n", data);
513 		exit(1);
514 	}
515 	if (part >= efi->efi_nparts) {
516 		(void) fprintf(stderr,
517 			"Error in data \"%s\": No such partition %x\n",
518 			data, part);
519 		exit(1);
520 	}
521 	efi->efi_parts[part].p_tag = (ushort_t)tag;
522 	efi->efi_parts[part].p_flag = (ushort_t)flag;
523 	efi->efi_parts[part].p_start = start;
524 	efi->efi_parts[part].p_size = size;
525 }
526 
527 /*
528  * load()
529  *
530  * Load VTOC information from a datafile.
531  */
532 static void
533 load(FILE *fp, struct dk_geom *geom, struct vtoc *vtoc)
534 {
535 	int	part;
536 	int	tag;
537 	uint_t	flag;
538 	daddr_t	start;
539 	long	size;
540 	char	line[256];
541 	int	i;
542 	long	nblks;
543 	long	fullsz;
544 
545 	for (i = 0; i < V_NUMPAR; ++i) {
546 		vtoc->v_part[i].p_tag = 0;
547 		vtoc->v_part[i].p_flag = V_UNMNT;
548 		vtoc->v_part[i].p_start = 0;
549 		vtoc->v_part[i].p_size = 0;
550 	}
551 	/*
552 	 * initialize partition 2, by convention it corresponds to whole
553 	 * disk. It will be overwritten, if specified in the input datafile
554 	 */
555 	fullsz = geom->dkg_ncyl * geom->dkg_nsect * geom->dkg_nhead;
556 	vtoc->v_part[2].p_tag = V_BACKUP;
557 	vtoc->v_part[2].p_flag = V_UNMNT;
558 	vtoc->v_part[2].p_start = 0;
559 	vtoc->v_part[2].p_size = fullsz;
560 
561 	nblks = geom->dkg_nsect * geom->dkg_nhead;
562 
563 	while (fgets(line, sizeof (line) - 1, fp)) {
564 		if (line[0] == '\0' || line[0] == '\n' || line[0] == '*')
565 			continue;
566 		line[strlen(line) - 1] = '\0';
567 		if (sscanf(line, "%d %d %x %ld %ld",
568 		    &part, &tag, &flag, &start, &size) != 5) {
569 			(void) fprintf(stderr, "Syntax error: \"%s\"\n",
570 				line);
571 			exit(1);
572 		}
573 		if (part >= V_NUMPAR) {
574 			(void) fprintf(stderr,
575 				"No such partition %x: \"%s\"\n",
576 				part, line);
577 			exit(1);
578 		}
579 		if (!eflag && ((start % nblks) != 0 || (size % nblks) != 0)) {
580 			(void) fprintf(stderr,
581 "Partition %d not aligned on cylinder boundary: \"%s\"\n",
582 					part, line);
583 			exit(1);
584 		}
585 		vtoc->v_part[part].p_tag = (ushort_t)tag;
586 		vtoc->v_part[part].p_flag = (ushort_t)flag;
587 		vtoc->v_part[part].p_start = start;
588 		vtoc->v_part[part].p_size = size;
589 	}
590 	for (part = 0; part < V_NUMPAR; part++) {
591 		vtoc->timestamp[part] = (time_t)0;
592 	}
593 }
594 
595 /*
596  * load64()
597  *
598  * Load VTOC information from a datafile.
599  */
600 static void
601 load64(FILE *fp, int fd, struct dk_gpt **efi)
602 {
603 	int	part;
604 	int	tag;
605 	uint_t	flag;
606 	diskaddr_t	start;
607 	diskaddr_t	size;
608 	int	nlines = 0;
609 	char	line[256];
610 	int	i;
611 	uint_t	max_part = 0;
612 	char	**mem = NULL;
613 
614 	while (fgets(line, sizeof (line) - 1, fp)) {
615 		if (line[0] == '\0' || line[0] == '\n' || line[0] == '*')
616 			continue;
617 		line[strlen(line) - 1] = '\0';
618 		if (sscanf(line, "%d %d %x %lld %lld",
619 		    &part, &tag, &flag, &start, &size) != 5) {
620 			(void) fprintf(stderr, "Syntax error: \"%s\"\n",
621 				line);
622 			exit(1);
623 		}
624 		mem = realloc(mem, sizeof (*mem) * (nlines + 1));
625 		if (mem == NULL) {
626 			(void) fprintf(stderr, "realloc failed\n");
627 			exit(1);
628 		}
629 		mem[nlines] = strdup(line);
630 		if (mem[nlines] == NULL) {
631 			(void) fprintf(stderr, "strdup failed\n");
632 			exit(1);
633 		}
634 		nlines++;
635 		if (part > max_part)
636 		    max_part = part;
637 	}
638 	max_part++;
639 
640 	if ((i = efi_alloc_and_init(fd, max_part, efi)) < 0) {
641 		(void) fprintf(stderr,
642 				"efi_alloc_and_init failed: %d\n", i);
643 		exit(1);
644 	}
645 	for (i = 0; i < (*efi)->efi_nparts; ++i) {
646 		(*efi)->efi_parts[i].p_tag = V_UNASSIGNED;
647 		(*efi)->efi_parts[i].p_flag = V_UNMNT;
648 		(*efi)->efi_parts[i].p_start = 0;
649 		(*efi)->efi_parts[i].p_size = 0;
650 	}
651 	lastlba = (*efi)->efi_last_u_lba;
652 
653 	for (i = 0; i < nlines; i++) {
654 		if (sscanf(mem[i], "%d %d %x %lld %lld",
655 		    &part, &tag, &flag, &start, &size) != 5) {
656 			(void) fprintf(stderr, "Syntax error: \"%s\"\n",
657 				line);
658 			exit(1);
659 		}
660 		free(mem[i]);
661 		if (part >= (*efi)->efi_nparts) {
662 			(void) fprintf(stderr,
663 				"No such partition %x: \"%s\"\n",
664 				part, line);
665 			exit(1);
666 		}
667 		(*efi)->efi_parts[part].p_tag = (ushort_t)tag;
668 		(*efi)->efi_parts[part].p_flag = (ushort_t)flag;
669 		(*efi)->efi_parts[part].p_start = start;
670 		(*efi)->efi_parts[part].p_size = size;
671 	}
672 	(*efi)->efi_nparts = max_part;
673 	free(mem);
674 }
675 
676 
677 static void
678 usage()
679 {
680 	(void) fprintf(stderr,
681 #if defined(sparc)
682 "Usage:	fmthard [ -i ] [ -n volumename ] [ -s datafile ] [ -d arguments] \
683 raw-device\n");
684 
685 #elif defined(i386)
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  */
700 static void
701 validate(struct dk_geom *geom, struct vtoc *vtoc)
702 {
703 	int	i;
704 	int	j;
705 	long	fullsz;
706 	long	endsect;
707 	daddr_t	istart;
708 	daddr_t	jstart;
709 	long	isize;
710 	long	jsize;
711 	long	nblks;
712 
713 	nblks = geom->dkg_nsect * geom->dkg_nhead;
714 
715 	fullsz = 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 (sectsiz == 0)
723 		sectsiz = SECSIZE;
724 	if (vtoc->v_sectorsz == 0)
725 		vtoc->v_sectorsz = sectsiz;
726 #endif				/* defined(_SUNOS_VTOC_16) */
727 
728 	for (i = 0; i < V_NUMPAR; i++) {
729 		if (vtoc->v_part[i].p_tag == V_BACKUP) {
730 			if (vtoc->v_part[i].p_size != fullsz) {
731 				(void) fprintf(stderr, "\
732 fmthard: Partition %d specifies the full disk and is not equal\n\
733 full size of disk.  The full disk capacity is %lu sectors.\n", i, fullsz);
734 #if defined(sparc)
735 			exit(1);
736 #endif
737 			}
738 		}
739 		if (vtoc->v_part[i].p_size == 0)
740 			continue;	/* Undefined partition */
741 		if ((vtoc->v_part[i].p_start % nblks) ||
742 				(vtoc->v_part[i].p_size % nblks)) {
743 			(void) fprintf(stderr, "\
744 fmthard: Partition %d not aligned on cylinder boundary \n", i);
745 				exit(1);
746 		}
747 		if (vtoc->v_part[i].p_start > fullsz ||
748 			vtoc->v_part[i].p_start +
749 				vtoc->v_part[i].p_size > fullsz) {
750 			(void) fprintf(stderr, "\
751 fmthard: Partition %d specified as %lu sectors starting at %lu\n\
752 \tdoes not fit. The full disk contains %lu sectors.\n",
753 				i, vtoc->v_part[i].p_size,
754 				vtoc->v_part[i].p_start, fullsz);
755 #if defined(sparc)
756 			exit(1);
757 #endif
758 		}
759 
760 		if (vtoc->v_part[i].p_tag != V_BACKUP &&
761 		    vtoc->v_part[i].p_size != fullsz) {
762 			for (j = 0; j < V_NUMPAR; j++) {
763 				if (vtoc->v_part[j].p_tag == V_BACKUP)
764 					continue;
765 				if (vtoc->v_part[j].p_size == fullsz)
766 					continue;
767 				isize = vtoc->v_part[i].p_size;
768 				jsize = vtoc->v_part[j].p_size;
769 				istart = vtoc->v_part[i].p_start;
770 				jstart = vtoc->v_part[j].p_start;
771 				if ((i != j) &&
772 				    (isize != 0) && (jsize != 0)) {
773 					endsect = jstart + jsize -1;
774 					if ((jstart <= istart) &&
775 						(istart <= endsect)) {
776 						(void) fprintf(stderr, "\
777 fmthard: Partition %d overlaps partition %d. Overlap is allowed\n\
778 \tonly on partition on the full disk partition).\n",
779 						    i, j);
780 #if defined(sparc)
781 						exit(1);
782 #endif
783 					}
784 				}
785 			}
786 		}
787 	}
788 }
789 
790 /*
791  * validate64()
792  *
793  * Validate the new VTOC.
794  */
795 static void
796 validate64(struct dk_gpt *efi)
797 {
798 	int		i;
799 	int		j;
800 	int		resv_part = 0;
801 	diskaddr_t	endsect;
802 	diskaddr_t	fullsz;
803 	diskaddr_t		istart;
804 	diskaddr_t		jstart;
805 	diskaddr_t		isize;
806 	diskaddr_t		jsize;
807 
808 	fullsz = lastlba + 1;
809 
810 	for (i = 0; i < efi->efi_nparts; i++) {
811 		if (efi->efi_parts[i].p_size == 0)
812 			continue;	/* Undefined partition */
813 		if (efi->efi_parts[i].p_tag == V_RESERVED)
814 			resv_part++;
815 		if (efi->efi_parts[i].p_start > fullsz ||
816 			efi->efi_parts[i].p_start +
817 				efi->efi_parts[i].p_size > fullsz) {
818 			(void) fprintf(stderr, "\
819 fmthard: Partition %d specified as %lld sectors starting at %lld\n\
820 \tdoes not fit. The full disk contains %lld sectors.\n",
821 				i, efi->efi_parts[i].p_size,
822 				efi->efi_parts[i].p_start, fullsz);
823 			exit(1);
824 		}
825 
826 		if (efi->efi_parts[i].p_tag != V_BACKUP &&
827 		    efi->efi_parts[i].p_size != fullsz) {
828 			for (j = 0; j < V_NUMPAR; j++) {
829 				if (efi->efi_parts[j].p_size == fullsz)
830 					continue;
831 				isize = efi->efi_parts[i].p_size;
832 				jsize = efi->efi_parts[j].p_size;
833 				istart = efi->efi_parts[i].p_start;
834 				jstart = efi->efi_parts[j].p_start;
835 				if ((i != j) &&
836 				    (isize != 0) && (jsize != 0)) {
837 					endsect = jstart + jsize - 1;
838 					if ((jstart <= istart) &&
839 						(istart <= endsect)) {
840 						(void) fprintf(stderr, "\
841 fmthard: Partition %d overlaps partition %d. Overlap is allowed\n\
842 \tonly on partition on the full disk partition).\n",
843 						    i, j);
844 #if defined(sparc)
845 						exit(1);
846 #endif
847 					}
848 				}
849 			}
850 		}
851 	}
852 	if (resv_part != 1) {
853 		(void) fprintf(stderr,
854 		    "expected one reserved partition, but found %d\n",
855 		    resv_part);
856 		exit(1);
857 	}
858 }
859 
860 
861 /*
862  * Read the VTOC
863  */
864 int
865 vread(int fd, struct vtoc *vtoc, char *devname)
866 {
867 	int	i;
868 
869 	if ((i = read_vtoc(fd, vtoc)) < 0) {
870 		if (i == VT_ENOTSUP) {
871 			return (1);
872 		}
873 		if (i == VT_EINVAL) {
874 			(void) fprintf(stderr, "%s: Invalid VTOC\n",
875 				devname);
876 		} else {
877 			(void) fprintf(stderr, "%s: Cannot read VTOC\n",
878 				devname);
879 		}
880 		exit(1);
881 	}
882 	return (0);
883 }
884 
885 void
886 vread64(int fd, struct dk_gpt **efi_hdr, char *devname)
887 {
888 	int i;
889 
890 	if ((i = efi_alloc_and_read(fd, efi_hdr)) < 0) {
891 		if (i == VT_EINVAL)
892 			(void) fprintf(stderr,
893 				"%s: this disk must be labeled first\n",
894 				devname);
895 		else
896 			(void) fprintf(stderr,
897 				"%s: read_efi failed %d\n",
898 				devname, i);
899 		exit(1);
900 	}
901 	lastlba = (*efi_hdr)->efi_last_u_lba;
902 }
903 
904 /*
905  * Write the VTOC
906  */
907 void
908 vwrite(int fd, struct vtoc *vtoc, char *devname)
909 {
910 	int	i;
911 
912 	if ((i = write_vtoc(fd, vtoc)) != 0) {
913 		if (i == VT_EINVAL) {
914 			(void) fprintf(stderr,
915 			"%s: invalid entry exists in vtoc\n",
916 				devname);
917 		} else {
918 			(void) fprintf(stderr, "%s: Cannot write VTOC\n",
919 				devname);
920 		}
921 		exit(1);
922 	}
923 }
924 
925 /*
926  * Write the VTOC
927  */
928 void
929 vwrite64(int fd, struct dk_gpt *efi, char *devname)
930 {
931 	int	i;
932 
933 	if ((i = efi_write(fd, efi)) != 0) {
934 		if (i == VT_EINVAL) {
935 			(void) fprintf(stderr,
936 			"%s: invalid entry exists in vtoc\n",
937 				devname);
938 		} else {
939 			(void) fprintf(stderr, "%s: Cannot write EFI\n",
940 				devname);
941 		}
942 		exit(1);
943 	}
944 }
945