xref: /illumos-gate/usr/src/cmd/fmthard/fmthard.c (revision 06e1a714)
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 #pragma ident	"%Z%%M%	%I%	%E% SMI"
32 
33 /*
34  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
35  * Use is subject to license terms.
36  */
37 
38 /*
39  * Sun Microsystems version of fmthard:
40  *
41  * Supports the following arguments:
42  *
43  *	-i		Writes VTOC to stdout, rather than disk
44  *	-q		Quick check: exit code 0 if VTOC ok
45  *	-d <data>	Incremental changes to the VTOC
46  *	-n <vname>	Change volume name to <vname>
47  *	-s <file>	Read VTOC information from <file>, or stdin ("-")
48  *	-u <state>	Reboot after writing VTOC, according to <state>:
49  *				boot: AD_BOOT (standard reboot)
50  *				firm: AD_IBOOT (interactive reboot)
51  *
52  * Note that fmthard cannot write a VTOC on an unlabeled disk.
53  * You must use format or SunInstall for this purpose.
54  * (NOTE: the above restriction only applies on Sparc systems).
55  *
56  * The primary motivation for fmthard is to duplicate the
57  * partitioning from disk to disk:
58  *
59  *	prtvtoc /dev/rdsk/c0t0d0s2 | fmthard -s - /dev/rdsk/c0t1d0s2
60  */
61 
62 #include <stdio.h>
63 #include <fcntl.h>
64 #include <errno.h>
65 #include <string.h>
66 #include <stdlib.h>
67 #include <unistd.h>
68 #include <sys/types.h>
69 #include <sys/param.h>
70 #include <sys/stat.h>
71 #include <sys/uadmin.h>
72 #include <sys/open.h>
73 #include <sys/vtoc.h>
74 #include <sys/dkio.h>
75 #include <sys/isa_defs.h>
76 #include <sys/efi_partition.h>
77 
78 #if defined(_SUNOS_VTOC_16)
79 #include <sys/dklabel.h>
80 #endif
81 
82 #include <sys/sysmacros.h>
83 
84 #ifndef	SECSIZE
85 #define	SECSIZE			DEV_BSIZE
86 #endif	/* SECSIZE */
87 
88 
89 /*
90  * External functions.
91  */
92 extern	int	read_vtoc(int, struct vtoc *);
93 extern	int	write_vtoc(int, struct vtoc *);
94 
95 /*
96  * Internal functions.
97  */
98 extern	int	main(int, char **);
99 static	void	display(struct dk_geom *, struct vtoc *, char *);
100 static	void	display64(struct dk_gpt *,  char *);
101 static	void	insert(char *, struct vtoc *);
102 static	void	insert64(char *, struct dk_gpt *);
103 static	void	load(FILE *, struct dk_geom *, struct vtoc *);
104 static	void	load64(FILE *, int fd, struct dk_gpt **);
105 static	void	usage(void);
106 static	void	validate(struct dk_geom *, struct vtoc *);
107 static	void	validate64(struct dk_gpt *);
108 static	int	vread(int, struct vtoc *, char *);
109 static	void	vread64(int, struct dk_gpt **, char *);
110 static	void	vwrite(int, struct vtoc *, char *);
111 static	void	vwrite64(int, struct dk_gpt *, char *);
112 
113 /*
114  * Static variables.
115  */
116 static char	*delta;		/* Incremental update */
117 static short	eflag;		/* force write of an EFI label */
118 static short	iflag;		/* Prints VTOC w/o updating */
119 static short	qflag;		/* Check for a formatted disk */
120 static short	uflag;		/* Exit to firmware after writing  */
121 				/* new vtoc and reboot. Used during */
122 				/* installation of core floppies */
123 static diskaddr_t	lastlba = 0;	/* last LBA on 64-bit VTOC */
124 
125 #if defined(sparc)
126 static char	*uboot = "boot";
127 
128 #elif defined(i386)
129 /* use installgrub(1M) to install boot blocks */
130 static char *uboot = "";
131 #else
132 #error No platform defined.
133 #endif	/* various platform-specific definitions */
134 
135 static char	*ufirm = "firm";
136 #if defined(_SUNOS_VTOC_16)
137 static int		sectsiz;
138 static struct vtoc	disk_vtoc;
139 #endif	/* defined(_SUNOS_VTOC_16) */
140 
141 int
142 main(int argc, char **argv)
143 {
144 	int		fd;
145 	int		c;
146 	char		*dfile;
147 	char		*vname;
148 	struct stat	statbuf;
149 #if defined(_SUNOS_VTOC_8)
150 	struct vtoc	disk_vtoc;
151 #endif	/* defined(_SUNOS_VTOC_8) */
152 	struct dk_gpt	*disk_efi;
153 	struct dk_geom	disk_geom;
154 	int		n;
155 
156 
157 	disk_efi = NULL;
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) || qflag)) {
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 		(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  */
378 static void
379 display(struct dk_geom *geom, struct vtoc *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", SECSIZE);
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		%ld		%ld\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  */
428 static void
429 display64(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  */
469 static void
470 insert(char *data, struct vtoc *vtoc)
471 {
472 	int	part;
473 	int	tag;
474 	uint_t	flag;
475 	daddr_t	start;
476 	long	size;
477 
478 	if (sscanf(data, "%d:%d:%x:%ld:%ld",
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  */
500 static void
501 insert64(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  */
531 static void
532 load(FILE *fp, struct dk_geom *geom, struct vtoc *vtoc)
533 {
534 	int	part;
535 	int	tag;
536 	uint_t	flag;
537 	daddr_t	start;
538 	long	size;
539 	char	line[256];
540 	int	i;
541 	long	nblks;
542 	long	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 = 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 %ld %ld",
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  */
599 static void
600 load64(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 
676 static void
677 usage()
678 {
679 	(void) fprintf(stderr,
680 #if defined(sparc)
681 "Usage:	fmthard [ -i ] [ -n volumename ] [ -s datafile ] [ -d arguments] \
682 raw-device\n");
683 
684 #elif defined(i386)
685 "Usage:	fmthard [ -i ] [ -S ] [-I geom_file]  \
686 -n volumename | -s datafile  [ -d arguments] raw-device\n");
687 
688 #else
689 #error No platform defined.
690 #endif
691 	exit(2);
692 }
693 
694 /*
695  * validate()
696  *
697  * Validate the new VTOC.
698  */
699 static void
700 validate(struct dk_geom *geom, struct vtoc *vtoc)
701 {
702 	int	i;
703 	int	j;
704 	long	fullsz;
705 	long	endsect;
706 	daddr_t	istart;
707 	daddr_t	jstart;
708 	long	isize;
709 	long	jsize;
710 	long	nblks;
711 
712 	nblks = geom->dkg_nsect * geom->dkg_nhead;
713 
714 	fullsz = geom->dkg_ncyl * geom->dkg_nsect * geom->dkg_nhead;
715 
716 #if defined(_SUNOS_VTOC_16)
717 	/* make the vtoc look sane - ha ha */
718 	vtoc->v_version = V_VERSION;
719 	vtoc->v_sanity = VTOC_SANE;
720 	vtoc->v_nparts = V_NUMPAR;
721 	if (sectsiz == 0)
722 		sectsiz = SECSIZE;
723 	if (vtoc->v_sectorsz == 0)
724 		vtoc->v_sectorsz = sectsiz;
725 #endif				/* defined(_SUNOS_VTOC_16) */
726 
727 	for (i = 0; i < V_NUMPAR; i++) {
728 		if (vtoc->v_part[i].p_tag == V_BACKUP) {
729 			if (vtoc->v_part[i].p_size != fullsz) {
730 				(void) fprintf(stderr, "\
731 fmthard: Partition %d specifies the full disk and is not equal\n\
732 full size of disk.  The full disk capacity is %lu sectors.\n", i, fullsz);
733 #if defined(sparc)
734 			exit(1);
735 #endif
736 			}
737 		}
738 		if (vtoc->v_part[i].p_size == 0)
739 			continue;	/* Undefined partition */
740 		if ((vtoc->v_part[i].p_start % nblks) ||
741 				(vtoc->v_part[i].p_size % nblks)) {
742 			(void) fprintf(stderr, "\
743 fmthard: Partition %d not aligned on cylinder boundary \n", i);
744 				exit(1);
745 		}
746 		if (vtoc->v_part[i].p_start > fullsz ||
747 			vtoc->v_part[i].p_start +
748 				vtoc->v_part[i].p_size > fullsz) {
749 			(void) fprintf(stderr, "\
750 fmthard: Partition %d specified as %lu sectors starting at %lu\n\
751 \tdoes not fit. The full disk contains %lu sectors.\n",
752 				i, vtoc->v_part[i].p_size,
753 				vtoc->v_part[i].p_start, fullsz);
754 #if defined(sparc)
755 			exit(1);
756 #endif
757 		}
758 
759 		if (vtoc->v_part[i].p_tag != V_BACKUP &&
760 		    vtoc->v_part[i].p_size != fullsz) {
761 			for (j = 0; j < V_NUMPAR; j++) {
762 				if (vtoc->v_part[j].p_tag == V_BACKUP)
763 					continue;
764 				if (vtoc->v_part[j].p_size == fullsz)
765 					continue;
766 				isize = vtoc->v_part[i].p_size;
767 				jsize = vtoc->v_part[j].p_size;
768 				istart = vtoc->v_part[i].p_start;
769 				jstart = vtoc->v_part[j].p_start;
770 				if ((i != j) &&
771 				    (isize != 0) && (jsize != 0)) {
772 					endsect = jstart + jsize -1;
773 					if ((jstart <= istart) &&
774 						(istart <= endsect)) {
775 						(void) fprintf(stderr, "\
776 fmthard: Partition %d overlaps partition %d. Overlap is allowed\n\
777 \tonly on partition on the full disk partition).\n",
778 						    i, j);
779 #if defined(sparc)
780 						exit(1);
781 #endif
782 					}
783 				}
784 			}
785 		}
786 	}
787 }
788 
789 /*
790  * validate64()
791  *
792  * Validate the new VTOC.
793  */
794 static void
795 validate64(struct dk_gpt *efi)
796 {
797 	int		i;
798 	int		j;
799 	int		resv_part = 0;
800 	diskaddr_t	endsect;
801 	diskaddr_t	fullsz;
802 	diskaddr_t		istart;
803 	diskaddr_t		jstart;
804 	diskaddr_t		isize;
805 	diskaddr_t		jsize;
806 
807 	fullsz = lastlba + 1;
808 
809 	for (i = 0; i < efi->efi_nparts; i++) {
810 		if (efi->efi_parts[i].p_size == 0)
811 			continue;	/* Undefined partition */
812 		if (efi->efi_parts[i].p_tag == V_RESERVED)
813 			resv_part++;
814 		if (efi->efi_parts[i].p_start > fullsz ||
815 			efi->efi_parts[i].p_start +
816 				efi->efi_parts[i].p_size > fullsz) {
817 			(void) fprintf(stderr, "\
818 fmthard: Partition %d specified as %lld sectors starting at %lld\n\
819 \tdoes not fit. The full disk contains %lld sectors.\n",
820 				i, efi->efi_parts[i].p_size,
821 				efi->efi_parts[i].p_start, fullsz);
822 			exit(1);
823 		}
824 
825 		if (efi->efi_parts[i].p_tag != V_BACKUP &&
826 		    efi->efi_parts[i].p_size != fullsz) {
827 			for (j = 0; j < V_NUMPAR; j++) {
828 				if (efi->efi_parts[j].p_size == fullsz)
829 					continue;
830 				isize = efi->efi_parts[i].p_size;
831 				jsize = efi->efi_parts[j].p_size;
832 				istart = efi->efi_parts[i].p_start;
833 				jstart = efi->efi_parts[j].p_start;
834 				if ((i != j) &&
835 				    (isize != 0) && (jsize != 0)) {
836 					endsect = jstart + jsize - 1;
837 					if ((jstart <= istart) &&
838 						(istart <= endsect)) {
839 						(void) fprintf(stderr, "\
840 fmthard: Partition %d overlaps partition %d. Overlap is allowed\n\
841 \tonly on partition on the full disk partition).\n",
842 						    i, j);
843 #if defined(sparc)
844 						exit(1);
845 #endif
846 					}
847 				}
848 			}
849 		}
850 	}
851 	if (resv_part != 1) {
852 		(void) fprintf(stderr,
853 		    "expected one reserved partition, but found %d\n",
854 		    resv_part);
855 		exit(1);
856 	}
857 }
858 
859 
860 /*
861  * Read the VTOC
862  */
863 int
864 vread(int fd, struct vtoc *vtoc, char *devname)
865 {
866 	int	i;
867 
868 	if ((i = read_vtoc(fd, vtoc)) < 0) {
869 		if (i == VT_ENOTSUP) {
870 			return (1);
871 		}
872 		if (i == VT_EINVAL) {
873 			(void) fprintf(stderr, "%s: Invalid VTOC\n",
874 				devname);
875 		} else {
876 			(void) fprintf(stderr, "%s: Cannot read VTOC\n",
877 				devname);
878 		}
879 		exit(1);
880 	}
881 	return (0);
882 }
883 
884 void
885 vread64(int fd, struct dk_gpt **efi_hdr, char *devname)
886 {
887 	int i;
888 
889 	if ((i = efi_alloc_and_read(fd, efi_hdr)) < 0) {
890 		if (i == VT_EINVAL)
891 			(void) fprintf(stderr,
892 				"%s: this disk must be labeled first\n",
893 				devname);
894 		else
895 			(void) fprintf(stderr,
896 				"%s: read_efi failed %d\n",
897 				devname, i);
898 		exit(1);
899 	}
900 	lastlba = (*efi_hdr)->efi_last_u_lba;
901 }
902 
903 /*
904  * Write the VTOC
905  */
906 void
907 vwrite(int fd, struct vtoc *vtoc, char *devname)
908 {
909 	int	i;
910 
911 	if ((i = write_vtoc(fd, vtoc)) != 0) {
912 		if (i == VT_EINVAL) {
913 			(void) fprintf(stderr,
914 			"%s: invalid entry exists in vtoc\n",
915 				devname);
916 		} else {
917 			(void) fprintf(stderr, "%s: Cannot write VTOC\n",
918 				devname);
919 		}
920 		exit(1);
921 	}
922 }
923 
924 /*
925  * Write the VTOC
926  */
927 void
928 vwrite64(int fd, struct dk_gpt *efi, char *devname)
929 {
930 	int	i;
931 
932 	if ((i = efi_write(fd, efi)) != 0) {
933 		if (i == VT_EINVAL) {
934 			(void) fprintf(stderr,
935 			"%s: invalid entry exists in vtoc\n",
936 				devname);
937 		} else {
938 			(void) fprintf(stderr, "%s: Cannot write EFI\n",
939 				devname);
940 		}
941 		exit(1);
942 	}
943 }
944