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