xref: /illumos-gate/usr/src/cmd/fmthard/fmthard.c (revision c85864d8472aaccb47ceb468ebd9b3a85b66d161)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
22 /*	  All Rights Reserved  	*/
23 
24 
25 /*
26  *
27  *	Portions of this source code were provided by International
28  *	Computers Limited (ICL) under a development agreement with AT&T.
29  */
30 
31 /*
32  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
33  * Use is subject to license terms.
34  */
35 
36 /*
37  * 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 static int		sectsiz;
129 #if defined(_SUNOS_VTOC_16)
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 	struct dk_minfo	minfo;
147 	int		n;
148 
149 
150 	disk_efi = NULL;
151 	dfile = NULL;
152 	vname = NULL;
153 #if defined(sparc)
154 	while ((c = getopt(argc, argv, "ed:u:in:qs:")) != EOF)
155 
156 #elif defined(i386)
157 	while ((c = getopt(argc, argv, "ed:u:in:qb:p:s:")) != EOF)
158 
159 #else
160 #error No platform defined.
161 #endif
162 		switch (c) {
163 #if defined(i386)
164 		case 'p':
165 		case 'b':
166 			(void) fprintf(stderr,
167 			    "fmthard: -p and -b no longer supported."
168 			    " Use installgrub(1M) to install boot blocks\n");
169 			break;
170 #endif	/* defined(i386) */
171 
172 		case 'd':
173 			delta = optarg;
174 			break;
175 		case 'e':
176 			++eflag;
177 			break;
178 		case 'i':
179 			++iflag;
180 			break;
181 		case 'n':
182 			vname = optarg;
183 			break;
184 		case 'q':
185 			++qflag;
186 			break;
187 		case 's':
188 			dfile = optarg;
189 			break;
190 		case 'u':
191 			if (strcmp(uboot, optarg) == 0)
192 				++uflag;
193 			else if (strcmp(ufirm, optarg) == 0)
194 				uflag = 2;
195 
196 			break;
197 		default:
198 			usage();
199 		}
200 
201 
202 	if (argc - optind != 1)
203 		usage();
204 
205 	if (stat(argv[optind], (struct stat *)&statbuf) == -1) {
206 		(void) fprintf(stderr,
207 		    "fmthard:  Cannot stat device %s\n",
208 		    argv[optind]);
209 		exit(1);
210 	}
211 
212 	if ((statbuf.st_mode & S_IFMT) != S_IFCHR) {
213 		(void) fprintf(stderr,
214 		    "fmthard:  %s must be a raw device.\n",
215 		    argv[optind]);
216 		exit(1);
217 	}
218 
219 	if ((fd = open(argv[optind], O_RDWR|O_NDELAY)) < 0) {
220 		(void) fprintf(stderr, "fmthard:  Cannot open device %s - %s\n",
221 		    argv[optind], strerror(errno));
222 		exit(1);
223 	}
224 
225 	if (ioctl(fd, DKIOCGMEDIAINFO, &minfo) == 0) {
226 		sectsiz = minfo.dki_lbsize;
227 	}
228 
229 	if (sectsiz == 0) {
230 		sectsiz = SECSIZE;
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 	 * 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 extvtoc *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", sectsiz);
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		%llu		%llu\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 extvtoc *vtoc)
471 {
472 	int		part;
473 	int		tag;
474 	uint_t		flag;
475 	diskaddr_t	start;
476 	uint64_t	size;
477 
478 	if (sscanf(data, "%d:%d:%x:%llu:%llu",
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 extvtoc *vtoc)
533 {
534 	int		part;
535 	int		tag;
536 	uint_t		flag;
537 	diskaddr_t	start;
538 	uint64_t	size;
539 	char		line[256];
540 	int		i;
541 	uint64_t	nblks;
542 	uint64_t	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 = (uint64_t)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 %llu %llu",
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 #if defined(sparc)
680 	(void) fprintf(stderr,
681 "Usage:	fmthard [ -i ] [ -n volumename ] [ -s datafile ] [ -d arguments] \
682 raw-device\n");
683 
684 #elif defined(i386)
685 	(void) fprintf(stderr,
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 extvtoc *vtoc)
702 {
703 	int		i;
704 	int		j;
705 	uint64_t	fullsz;
706 	diskaddr_t	endsect;
707 	diskaddr_t	istart;
708 	diskaddr_t	jstart;
709 	uint64_t	isize;
710 	uint64_t	jsize;
711 	uint64_t	nblks;
712 
713 	nblks = geom->dkg_nsect * geom->dkg_nhead;
714 
715 	fullsz = (uint64_t)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 (vtoc->v_sectorsz == 0)
723 		vtoc->v_sectorsz = sectsiz;
724 #endif				/* defined(_SUNOS_VTOC_16) */
725 
726 	for (i = 0; i < V_NUMPAR; i++) {
727 		if (vtoc->v_part[i].p_tag == V_BACKUP) {
728 			if (vtoc->v_part[i].p_size != fullsz) {
729 				(void) fprintf(stderr, "\
730 fmthard: Partition %d specifies the full disk and is not equal\n\
731 full size of disk.  The full disk capacity is %llu sectors.\n", i, fullsz);
732 #if defined(sparc)
733 			exit(1);
734 #endif
735 			}
736 		}
737 		if (vtoc->v_part[i].p_size == 0)
738 			continue;	/* Undefined partition */
739 		if ((vtoc->v_part[i].p_start % nblks) ||
740 		    (vtoc->v_part[i].p_size % nblks)) {
741 			(void) fprintf(stderr, "\
742 fmthard: Partition %d not aligned on cylinder boundary \n", i);
743 				exit(1);
744 		}
745 		if (vtoc->v_part[i].p_start > fullsz ||
746 		    vtoc->v_part[i].p_start +
747 		    vtoc->v_part[i].p_size > fullsz) {
748 			(void) fprintf(stderr, "\
749 fmthard: Partition %d specified as %llu sectors starting at %llu\n\
750 \tdoes not fit. The full disk contains %llu sectors.\n",
751 			    i, vtoc->v_part[i].p_size,
752 			    vtoc->v_part[i].p_start, fullsz);
753 #if defined(sparc)
754 			exit(1);
755 #endif
756 		}
757 
758 		if (vtoc->v_part[i].p_tag != V_BACKUP &&
759 		    vtoc->v_part[i].p_size != fullsz) {
760 			for (j = 0; j < V_NUMPAR; j++) {
761 				if (vtoc->v_part[j].p_tag == V_BACKUP)
762 					continue;
763 				if (vtoc->v_part[j].p_size == fullsz)
764 					continue;
765 				isize = vtoc->v_part[i].p_size;
766 				jsize = vtoc->v_part[j].p_size;
767 				istart = vtoc->v_part[i].p_start;
768 				jstart = vtoc->v_part[j].p_start;
769 				if ((i != j) &&
770 				    (isize != 0) && (jsize != 0)) {
771 					endsect = jstart + jsize -1;
772 					if ((jstart <= istart) &&
773 					    (istart <= endsect)) {
774 						(void) fprintf(stderr, "\
775 fmthard: Partition %d overlaps partition %d. Overlap is allowed\n\
776 \tonly on partition on the full disk partition).\n",
777 						    i, j);
778 #if defined(sparc)
779 						exit(1);
780 #endif
781 					}
782 				}
783 			}
784 		}
785 	}
786 }
787 
788 /*
789  * validate64()
790  *
791  * Validate the new VTOC.
792  */
793 static void
794 validate64(struct dk_gpt *efi)
795 {
796 	int		i;
797 	int		j;
798 	int		resv_part = 0;
799 	diskaddr_t	endsect;
800 	diskaddr_t	fullsz;
801 	diskaddr_t		istart;
802 	diskaddr_t		jstart;
803 	diskaddr_t		isize;
804 	diskaddr_t		jsize;
805 
806 	fullsz = lastlba + 1;
807 
808 	for (i = 0; i < efi->efi_nparts; i++) {
809 		if (efi->efi_parts[i].p_size == 0)
810 			continue;	/* Undefined partition */
811 		if (efi->efi_parts[i].p_tag == V_RESERVED)
812 			resv_part++;
813 		if (efi->efi_parts[i].p_start > fullsz ||
814 		    efi->efi_parts[i].p_start +
815 		    efi->efi_parts[i].p_size > fullsz) {
816 			(void) fprintf(stderr, "\
817 fmthard: Partition %d specified as %lld sectors starting at %lld\n\
818 \tdoes not fit. The full disk contains %lld sectors.\n",
819 			    i, efi->efi_parts[i].p_size,
820 			    efi->efi_parts[i].p_start, fullsz);
821 			exit(1);
822 		}
823 
824 		if (efi->efi_parts[i].p_tag != V_BACKUP &&
825 		    efi->efi_parts[i].p_size != fullsz) {
826 			for (j = 0; j < efi->efi_nparts; j++) {
827 				if (efi->efi_parts[j].p_size == fullsz)
828 					continue;
829 				isize = efi->efi_parts[i].p_size;
830 				jsize = efi->efi_parts[j].p_size;
831 				istart = efi->efi_parts[i].p_start;
832 				jstart = efi->efi_parts[j].p_start;
833 				if ((i != j) &&
834 				    (isize != 0) && (jsize != 0)) {
835 					endsect = jstart + jsize - 1;
836 					if ((jstart <= istart) &&
837 					    (istart <= endsect)) {
838 						(void) fprintf(stderr, "\
839 fmthard: Partition %d overlaps partition %d. Overlap is allowed\n\
840 \tonly on partition on the full disk partition).\n",
841 						    i, j);
842 #if defined(sparc)
843 						exit(1);
844 #endif
845 					}
846 				}
847 			}
848 		}
849 	}
850 	if (resv_part != 1) {
851 		(void) fprintf(stderr,
852 		    "expected one reserved partition, but found %d\n",
853 		    resv_part);
854 		exit(1);
855 	}
856 }
857 
858 
859 /*
860  * Read the VTOC
861  */
862 int
863 vread(int fd, struct extvtoc *vtoc, char *devname)
864 {
865 	int	i;
866 
867 	if ((i = read_extvtoc(fd, vtoc)) < 0) {
868 		if (i == VT_ENOTSUP) {
869 			return (1);
870 		}
871 		if (i == VT_EINVAL) {
872 			(void) fprintf(stderr, "%s: Invalid VTOC\n",
873 			    devname);
874 		} else {
875 			(void) fprintf(stderr, "%s: Cannot read VTOC\n",
876 			    devname);
877 		}
878 		exit(1);
879 	}
880 	return (0);
881 }
882 
883 void
884 vread64(int fd, struct dk_gpt **efi_hdr, char *devname)
885 {
886 	int i;
887 
888 	if ((i = efi_alloc_and_read(fd, efi_hdr)) < 0) {
889 		if (i == VT_EINVAL)
890 			(void) fprintf(stderr,
891 			    "%s: this disk must be labeled first\n",
892 			    devname);
893 		else
894 			(void) fprintf(stderr,
895 			    "%s: read_efi failed %d\n",
896 			    devname, i);
897 		exit(1);
898 	}
899 	lastlba = (*efi_hdr)->efi_last_u_lba;
900 }
901 
902 /*
903  * Write the VTOC
904  */
905 void
906 vwrite(int fd, struct extvtoc *vtoc, char *devname)
907 {
908 	int	i;
909 
910 	if ((i = write_extvtoc(fd, vtoc)) != 0) {
911 		if (i == VT_EINVAL) {
912 			(void) fprintf(stderr,
913 			"%s: invalid entry exists in vtoc\n",
914 			    devname);
915 		} else {
916 			(void) fprintf(stderr, "%s: Cannot write VTOC\n",
917 			    devname);
918 		}
919 		exit(1);
920 	}
921 }
922 
923 /*
924  * Write the VTOC
925  */
926 void
927 vwrite64(int fd, struct dk_gpt *efi, char *devname)
928 {
929 	int	i;
930 
931 	if ((i = efi_write(fd, efi)) != 0) {
932 		if (i == VT_EINVAL) {
933 			(void) fprintf(stderr,
934 			"%s: invalid entry exists in vtoc\n",
935 			    devname);
936 		} else {
937 			(void) fprintf(stderr, "%s: Cannot write EFI\n",
938 			    devname);
939 		}
940 		exit(1);
941 	}
942 }
943