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