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