Merge branch 'vendor/OPENSSL'
[dragonfly.git] / sbin / disklabel64 / disklabel64.c
1 /*
2  * Copyright (c) 2007 The DragonFly Project.  All rights reserved.
3  * 
4  * This code is derived from software contributed to The DragonFly Project
5  * by Matthew Dillon <dillon@backplane.com>
6  * 
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  * 3. Neither the name of The DragonFly Project nor the names of its
18  *    contributors may be used to endorse or promote products derived
19  *    from this software without specific, prior written permission.
20  * 
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34 /*
35  * Copyright (c) 1987, 1993
36  *      The Regents of the University of California.  All rights reserved.
37  *
38  * This code is derived from software contributed to Berkeley by
39  * Symmetric Computer Systems.
40  *
41  * Redistribution and use in source and binary forms, with or without
42  * modification, are permitted provided that the following conditions
43  * are met:
44  * 1. Redistributions of source code must retain the above copyright
45  *    notice, this list of conditions and the following disclaimer.
46  * 2. Redistributions in binary form must reproduce the above copyright
47  *    notice, this list of conditions and the following disclaimer in the
48  *    documentation and/or other materials provided with the distribution.
49  * 3. Neither the name of the University nor the names of its contributors
50  *    may be used to endorse or promote products derived from this software
51  *    without specific prior written permission.
52  *
53  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
54  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
55  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
56  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
57  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
58  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
59  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
60  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
61  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
62  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
63  * SUCH DAMAGE.
64  *
65  * @(#)disklabel.c      1.2 (Symmetric) 11/28/85
66  * @(#)disklabel.c      8.2 (Berkeley) 1/7/94
67  * $FreeBSD: src/sbin/disklabel/disklabel.c,v 1.28.2.15 2003/01/24 16:18:16 des Exp $
68  */
69
70 #include <sys/param.h>
71 #include <sys/file.h>
72 #include <sys/stat.h>
73 #include <sys/wait.h>
74 #define DKTYPENAMES
75 #include <sys/disklabel64.h>
76 #include <sys/diskslice.h>
77 #include <sys/diskmbr.h>
78 #include <sys/dtype.h>
79 #include <sys/sysctl.h>
80 #include <disktab.h>
81 #include <fstab.h>
82
83 #include <vfs/ufs/dinode.h>
84 #include <vfs/ufs/fs.h>
85
86 #include <unistd.h>
87 #include <string.h>
88 #include <stdio.h>
89 #include <stdlib.h>
90 #include <signal.h>
91 #include <stdarg.h>
92 #include <stddef.h>
93 #include <ctype.h>
94 #include <err.h>
95 #include <errno.h>
96 #include <uuid.h>
97 #include "pathnames.h"
98
99 extern uint32_t crc32(const void *buf, size_t size);
100
101 /*
102  * Disklabel64: read and write 64 bit disklabels.
103  * The label is usually placed on one of the first sectors of the disk.
104  * Many machines also place a bootstrap in the same area,
105  * in which case the label is embedded in the bootstrap.
106  * The bootstrap source must leave space at the proper offset
107  * for the label on such machines.
108  */
109
110 #define LABELSIZE       ((sizeof(struct disklabel64) + 4095) & ~4095)
111 #define BOOTSIZE        32768
112
113 /* FIX!  These are too low, but are traditional */
114 #define DEFAULT_NEWFS_BLOCK  8192U
115 #define DEFAULT_NEWFS_FRAG   1024U
116 #define DEFAULT_NEWFS_CPG    16U
117
118 #define BIG_NEWFS_BLOCK  16384U
119 #define BIG_NEWFS_FRAG   2048U
120 #define BIG_NEWFS_CPG    64U
121
122 void    makelabel(const char *, const char *, struct disklabel64 *);
123 int     writelabel(int, struct disklabel64 *);
124 void    l_perror(const char *);
125 struct disklabel64 *readlabel(int);
126 struct disklabel64 *makebootarea(int);
127 void    display(FILE *, const struct disklabel64 *);
128 int     edit(struct disklabel64 *, int);
129 int     editit(void);
130 char    *skip(char *);
131 char    *word(char *);
132 int     getasciilabel(FILE *, struct disklabel64 *);
133 int     getasciipartspec(char *, struct disklabel64 *, int, int, uint32_t);
134 int     getasciipartuuid(char *, struct disklabel64 *, int, int, uint32_t);
135 int     checklabel(struct disklabel64 *);
136 void    Warning(const char *, ...) __printflike(1, 2);
137 void    usage(void);
138 struct disklabel64 *getvirginlabel(void);
139
140 #define DEFEDITOR       _PATH_VI
141 #define streq(a,b)      (strcmp(a,b) == 0)
142
143 char    *dkname;
144 char    *specname;
145 char    tmpfil[] = PATH_TMPFILE;
146
147 struct  disklabel64 lab;
148
149 #define MAX_PART ('z')
150 #define MAX_NUM_PARTS (1 + MAX_PART - 'a')
151 char    part_size_type[MAX_NUM_PARTS];
152 char    part_offset_type[MAX_NUM_PARTS];
153 int     part_set[MAX_NUM_PARTS];
154
155 int     installboot;    /* non-zero if we should install a boot program */
156 int     boot1size;
157 int     boot1lsize;
158 int     boot2size;
159 char    *boot1buf;
160 char    *boot2buf;
161 char    *boot1path;
162 char    *boot2path;
163
164 enum    {
165         UNSPEC, EDIT, NOWRITE, READ, RESTORE, WRITE, WRITEABLE, WRITEBOOT
166 } op = UNSPEC;
167
168 int     rflag;
169 int     Vflag;
170 int     disable_write;   /* set to disable writing to disk label */
171 u_int32_t slice_start_lba;
172
173 #ifdef DEBUG
174 int     debug;
175 #define OPTIONS "BNRWb:denrs:Vw"
176 #else
177 #define OPTIONS "BNRWb:enrs:Vw"
178 #endif
179
180 int
181 main(int argc, char *argv[])
182 {
183         struct disklabel64 *lp;
184         FILE *t;
185         int ch, f = 0, flag, error = 0;
186         char *name = NULL;
187
188         while ((ch = getopt(argc, argv, OPTIONS)) != -1)
189                 switch (ch) {
190                         case 'B':
191                                 ++installboot;
192                                 break;
193                         case 'b':
194                                 boot1path = optarg;
195                                 break;
196
197                         case 's':
198                                 boot2path = optarg;
199                                 break;
200                         case 'N':
201                                 if (op != UNSPEC)
202                                         usage();
203                                 op = NOWRITE;
204                                 break;
205                         case 'n':
206                                 disable_write = 1;
207                                 break;
208                         case 'R':
209                                 if (op != UNSPEC)
210                                         usage();
211                                 op = RESTORE;
212                                 break;
213                         case 'W':
214                                 if (op != UNSPEC)
215                                         usage();
216                                 op = WRITEABLE;
217                                 break;
218                         case 'e':
219                                 if (op != UNSPEC)
220                                         usage();
221                                 op = EDIT;
222                                 break;
223                         case 'V':
224                                 ++Vflag;
225                                 break;
226                         case 'r':
227                                 ++rflag;
228                                 break;
229                         case 'w':
230                                 if (op != UNSPEC)
231                                         usage();
232                                 op = WRITE;
233                                 break;
234 #ifdef DEBUG
235                         case 'd':
236                                 debug++;
237                                 break;
238 #endif
239                         case '?':
240                         default:
241                                 usage();
242                 }
243         argc -= optind;
244         argv += optind;
245         if (installboot) {
246                 rflag++;
247                 if (op == UNSPEC)
248                         op = WRITEBOOT;
249         } else {
250                 if (op == UNSPEC)
251                         op = READ;
252                 boot1path = NULL;
253                 boot2path = NULL;
254         }
255         if (argc < 1)
256                 usage();
257
258         dkname = getdevpath(argv[0], 0);
259         specname = dkname;
260         f = open(specname, op == READ ? O_RDONLY : O_RDWR);
261         if (f < 0)
262                 err(4, "%s", specname);
263
264         switch(op) {
265
266         case UNSPEC:
267                 break;
268
269         case EDIT:
270                 if (argc != 1)
271                         usage();
272                 lp = readlabel(f);
273                 error = edit(lp, f);
274                 break;
275
276         case NOWRITE:
277                 flag = 0;
278                 if (ioctl(f, DIOCWLABEL, (char *)&flag) < 0)
279                         err(4, "ioctl DIOCWLABEL");
280                 break;
281
282         case READ:
283                 if (argc != 1)
284                         usage();
285                 lp = readlabel(f);
286                 display(stdout, lp);
287                 error = checklabel(lp);
288                 break;
289
290         case RESTORE:
291                 if (installboot && argc == 3) {
292                         makelabel(argv[2], 0, &lab);
293                         argc--;
294
295                         /*
296                          * We only called makelabel() for its side effect
297                          * of setting the bootstrap file names.  Discard
298                          * all changes to `lab' so that all values in the
299                          * final label come from the ASCII label.
300                          */
301                         bzero((char *)&lab, sizeof(lab));
302                 }
303                 if (argc != 2)
304                         usage();
305                 if (!(t = fopen(argv[1], "r")))
306                         err(4, "%s", argv[1]);
307                 if (!getasciilabel(t, &lab))
308                         exit(1);
309                 lp = makebootarea(f);
310                 bcopy(&lab.d_magic, &lp->d_magic,
311                       sizeof(lab) - offsetof(struct disklabel64, d_magic));
312                 error = writelabel(f, lp);
313                 break;
314
315         case WRITE:
316                 if (argc == 3) {
317                         name = argv[2];
318                         argc--;
319                 }
320                 if (argc != 2)
321                         usage();
322                 makelabel(argv[1], name, &lab);
323                 lp = makebootarea(f);
324                 bcopy(&lab.d_magic, &lp->d_magic,
325                       sizeof(lab) - offsetof(struct disklabel64, d_magic));
326                 if (checklabel(lp) == 0)
327                         error = writelabel(f, lp);
328                 break;
329
330         case WRITEABLE:
331                 flag = 1;
332                 if (ioctl(f, DIOCWLABEL, (char *)&flag) < 0)
333                         err(4, "ioctl DIOCWLABEL");
334                 break;
335
336         case WRITEBOOT:
337         {
338                 struct disklabel64 tlab;
339
340                 lp = readlabel(f);
341                 tlab = *lp;
342                 if (argc == 2)
343                         makelabel(argv[1], 0, &lab);
344                 lp = makebootarea(f);
345                 bcopy(&tlab.d_magic, &lp->d_magic,
346                       sizeof(tlab) - offsetof(struct disklabel64, d_magic));
347                 if (checklabel(lp) == 0)
348                         error = writelabel(f, lp);
349                 break;
350         }
351         }
352         exit(error);
353 }
354
355 /*
356  * Construct a prototype disklabel from /etc/disktab.  As a side
357  * effect, set the names of the primary and secondary boot files
358  * if specified.
359  */
360 void
361 makelabel(const char *type, const char *name, struct disklabel64 *lp)
362 {
363         struct disklabel64 *dp;
364
365         if (strcmp(type, "auto") == 0)
366                 dp = getvirginlabel();
367         else
368                 dp = NULL;
369         if (dp == NULL)
370                 errx(1, "%s: unknown disk type", type);
371         *lp = *dp;
372
373         /*
374          * NOTE: boot control files may no longer be specified in disktab.
375          */
376         if (name)
377                 strncpy(lp->d_packname, name, sizeof(lp->d_packname));
378 }
379
380 int
381 writelabel(int f, struct disklabel64 *lp)
382 {
383         struct disklabel64 *blp;
384         int flag;
385         int r;
386         size_t lpsize;
387         size_t lpcrcsize;
388
389         lpsize = offsetof(struct disklabel64, d_partitions[lp->d_npartitions]);
390         lpcrcsize = lpsize - offsetof(struct disklabel64, d_magic);
391
392         if (disable_write) {
393                 Warning("write to disk label suppressed - label was as follows:");
394                 display(stdout, lp);
395                 return (0);
396         } else {
397                 lp->d_magic = DISKMAGIC64;
398                 lp->d_crc = 0;
399                 lp->d_crc = crc32(&lp->d_magic, lpcrcsize);
400                 if (rflag) {
401                         /*
402                          * Make sure the boot area is not too large
403                          */
404                         if (boot2buf) {
405                                 int lpbsize = (int)(lp->d_pbase - lp->d_bbase);
406                                 if (lp->d_pbase == 0) {
407                                         errx(1, "no space was set aside in "
408                                                 "the disklabel for boot2!");
409                                 }
410                                 if (boot2size > lpbsize) {
411                                         errx(1, "label did not reserve enough "
412                                                 "space for boot!  %d/%d",
413                                              boot2size, lpbsize);
414                                 }
415                         }
416
417                         /*
418                          * First set the kernel disk label,
419                          * then write a label to the raw disk.
420                          * If the SDINFO ioctl fails because it is
421                          * unimplemented, keep going; otherwise, the kernel
422                          * consistency checks may prevent us from changing
423                          * the current (in-core) label.
424                          */
425                         if (ioctl(f, DIOCSDINFO64, lp) < 0 &&
426                                 errno != ENODEV && errno != ENOTTY) {
427                                 l_perror("ioctl DIOCSDINFO");
428                                 return (1);
429                         }
430                         lseek(f, (off_t)0, SEEK_SET);
431
432                         /*
433                          * The disklabel embeds areas which we may not
434                          * have wanted to change.  Merge those areas in
435                          * from disk.
436                          */
437                         blp = makebootarea(f);
438                         if (blp != lp) {
439                                 bcopy(&lp->d_magic, &blp->d_magic,
440                                       sizeof(*lp) -
441                                       offsetof(struct disklabel64, d_magic));
442                         }
443                         
444                         /*
445                          * write enable label sector before write
446                          * (if necessary), disable after writing.
447                          */
448                         flag = 1;
449                         if (ioctl(f, DIOCWLABEL, &flag) < 0)
450                                 warn("ioctl DIOCWLABEL");
451
452                         r = write(f, boot1buf, boot1lsize);
453                         if (r != (ssize_t)boot1lsize) {
454                                 warn("write");
455                                 return (1);
456                         }
457                         /*
458                          * Output the remainder of the disklabel
459                          */
460                         if (boot2buf) {
461                                 lseek(f, lp->d_bbase, 0);
462                                 r = write(f, boot2buf, boot2size);
463                                 if (r != boot2size) {
464                                         warn("write");
465                                         return(1);
466                                 }
467                         }
468                         flag = 0;
469                         ioctl(f, DIOCWLABEL, &flag);
470                 } else if (ioctl(f, DIOCWDINFO64, lp) < 0) {
471                         l_perror("ioctl DIOCWDINFO64");
472                         return (1);
473                 }
474         }
475         return (0);
476 }
477
478 void
479 l_perror(const char *s)
480 {
481         switch (errno) {
482
483         case ESRCH:
484                 warnx("%s: no disk label on disk;", s);
485                 fprintf(stderr, "add \"-r\" to install initial label\n");
486                 break;
487
488         case EINVAL:
489                 warnx("%s: label magic number or checksum is wrong!", s);
490                 fprintf(stderr, "(disklabel or kernel is out of date?)\n");
491                 break;
492
493         case EBUSY:
494                 warnx("%s: open partition would move or shrink", s);
495                 break;
496
497         case ENOATTR:
498                 warnx("%s: the disk already has a label of a different type,\n"
499                       "probably a 32 bit disklabel.  It must be cleaned out "
500                       "first.\n", s);
501                 break;
502
503         default:
504                 warn(NULL);
505                 break;
506         }
507 }
508
509 /*
510  * Fetch disklabel for disk.
511  * Use ioctl to get label unless -r flag is given.
512  */
513 struct disklabel64 *
514 readlabel(int f)
515 {
516         struct disklabel64 *lp;
517         u_int32_t savecrc;
518         size_t lpcrcsize;
519
520         if (rflag) {
521                 /*
522                  * Allocate space for the label.  The boot1 code, if any,
523                  * is embedded in the label.  The label overlaps the boot1
524                  * code.
525                  */
526                 lp = makebootarea(f);
527                 lpcrcsize = offsetof(struct disklabel64,
528                                      d_partitions[lp->d_npartitions]) -
529                             offsetof(struct disklabel64, d_magic);
530                 savecrc = lp->d_crc;
531                 lp->d_crc = 0;
532                 if (lp->d_magic != DISKMAGIC64)
533                         errx(1, "bad pack magic number");
534                 if (lp->d_npartitions > MAXPARTITIONS64 ||
535                     savecrc != crc32(&lp->d_magic, lpcrcsize)
536                 ) {
537                         errx(1, "corrupted disklabel64");
538                 }
539                 lp->d_crc = savecrc;
540         } else {
541                 /*
542                  * Just use a static structure to hold the label.  Note
543                  * that DIOCSDINFO64 does not overwrite the boot1 area
544                  * even though it is part of the disklabel64 structure.
545                  */
546                 lp = &lab;
547                 if (Vflag) {
548                         if (ioctl(f, DIOCGDVIRGIN64, lp) < 0) {
549                                 l_perror("ioctl DIOCGDVIRGIN64");
550                                 exit(4);
551                         }
552                 } else {
553                         if (ioctl(f, DIOCGDINFO64, lp) < 0) {
554                                 l_perror("ioctl DIOCGDINFO64");
555                                 exit(4);
556                         }
557                 }
558         }
559         return (lp);
560 }
561
562 /*
563  * Construct a boot area for boot1 and boot2 and return the location of
564  * the label within the area.  The caller will overwrite the label so
565  * we don't actually have to read it.
566  */
567 struct disklabel64 *
568 makebootarea(int f)
569 {
570         struct disklabel64 *lp;
571         struct partinfo info;
572         u_int32_t secsize;
573         struct stat st;
574         int fd;
575         int r;
576
577         if (ioctl(f, DIOCGPART, &info) == 0)
578                 secsize = info.media_blksize;
579         else
580                 secsize = 512;
581
582         if (boot1buf == NULL) {
583                 size_t rsize;
584
585                 rsize = (sizeof(struct disklabel64) + secsize - 1) &
586                         ~(secsize - 1);
587                 boot1size = offsetof(struct disklabel64, d_magic);
588                 boot1lsize = rsize;
589                 boot1buf = malloc(rsize);
590                 bzero(boot1buf, rsize);
591                 r = read(f, boot1buf, rsize);
592                 if (r != (int)rsize)
593                         err(4, "%s", specname);
594         }
595         lp = (void *)boot1buf;
596
597         if (installboot == 0)
598                 return(lp);
599
600         if (boot2buf == NULL) {
601                 boot2size = 32768;
602                 boot2buf = malloc(boot2size);
603                 bzero(boot2buf, boot2size);
604         }
605
606         /*
607          * If installing the boot code, read it into the appropriate portions
608          * of the buffer(s)
609          */
610         if (boot1path == NULL)
611                 asprintf(&boot1path, "%s/boot1_64", _PATH_BOOTDIR);
612         if (boot2path == NULL)
613                 asprintf(&boot2path, "%s/boot2_64", _PATH_BOOTDIR);
614
615         if ((fd = open(boot1path, O_RDONLY)) < 0)
616                 err(4, "%s", boot1path);
617         if (fstat(fd, &st) < 0)
618                 err(4, "%s", boot1path);
619         if (st.st_size > boot1size)
620                 err(4, "%s must be exactly %d bytes!", boot1path, boot1size);
621         if (read(fd, boot1buf, boot1size) != boot1size)
622                 err(4, "%s must be exactly %d bytes!", boot1path, boot1size);
623         close(fd);
624
625         if ((fd = open(boot2path, O_RDONLY)) < 0)
626                 err(4, "%s", boot2path);
627         if (fstat(fd, &st) < 0)
628                 err(4, "%s", boot2path);
629         if (st.st_size > boot2size)
630                 err(4, "%s must be <= %d bytes!", boot2path, boot2size);
631         if ((r = read(fd, boot2buf, boot2size)) < 1)
632                 err(4, "%s is empty!", boot2path);
633         boot2size = (r + secsize - 1) & ~(secsize - 1);
634         close(fd);
635
636         /*
637          * XXX dangerously dedicated support goes here XXX
638          */
639         return (lp);
640 }
641
642 void
643 display(FILE *f, const struct disklabel64 *lp)
644 {
645         const struct partition64 *pp;
646         char *str;
647         unsigned int part;
648         int didany;
649         uint32_t blksize;
650
651         /*
652          * Use a human readable block size if possible.  This is for
653          * display and editing purposes only.
654          */
655         if (lp->d_align > 1024)
656                 blksize = 1024;
657         else
658                 blksize = lp->d_align;
659
660         fprintf(f, "# %s:\n", specname);
661         fprintf(f, "#\n");
662         fprintf(f, "# Informational fields calculated from the above\n");
663         fprintf(f, "# All byte equivalent offsets must be aligned\n");
664         fprintf(f, "#\n");
665         fprintf(f, "# boot space: %10ju bytes\n",
666                 (intmax_t)(lp->d_pbase - lp->d_bbase));
667         fprintf(f, "# data space: %10ju blocks\t# %6.2f MB (%ju bytes)\n",
668                         (intmax_t)(lp->d_pstop - lp->d_pbase) / blksize,
669                         (double)(lp->d_pstop - lp->d_pbase) / 1024.0 / 1024.0,
670                         (intmax_t)(lp->d_pstop - lp->d_pbase));
671         fprintf(f, "#\n");
672         fprintf(f, "# NOTE: If the partition data base looks odd it may be\n");
673         fprintf(f, "#       physically aligned instead of slice-aligned\n");
674         fprintf(f, "#\n");
675
676         uuid_to_string(&lp->d_stor_uuid, &str, NULL);
677         fprintf(f, "diskid: %s\n", str ? str : "<unknown>");
678         free(str);
679
680         fprintf(f, "label: %.*s\n", (int)sizeof(lp->d_packname),
681                 lp->d_packname);
682         fprintf(f, "boot2 data base:      0x%012jx\n", (intmax_t)lp->d_bbase);
683         fprintf(f, "partitions data base: 0x%012jx\n", (intmax_t)lp->d_pbase);
684         fprintf(f, "partitions data stop: 0x%012jx\n", (intmax_t)lp->d_pstop);
685         fprintf(f, "backup label:         0x%012jx\n", (intmax_t)lp->d_abase);
686         fprintf(f, "total size:           0x%012jx\t# %6.2f MB\n",
687                 (intmax_t)lp->d_total_size,
688                 (double)lp->d_total_size / 1024.0 / 1024.0);
689         fprintf(f, "alignment: %u\n", lp->d_align);
690         fprintf(f, "display block size: %u\t# for partition display only\n",
691                 blksize);
692
693         fprintf(f, "\n");
694         fprintf(f, "%u partitions:\n", lp->d_npartitions);
695         fprintf(f, "#          size     offset    fstype   fsuuid\n");
696         didany = 0;
697         for (part = 0; part < lp->d_npartitions; part++) {
698                 pp = &lp->d_partitions[part];
699                 const u_long onemeg = 1024 * 1024;
700
701                 if (pp->p_bsize == 0)
702                         continue;
703                 didany = 1;
704                 fprintf(f, "  %c: ", 'a' + part);
705
706                 if (pp->p_bsize % lp->d_align)
707                     fprintf(f, "%10s  ", "ILLEGAL");
708                 else
709                     fprintf(f, "%10ju ", (intmax_t)pp->p_bsize / blksize);
710
711                 if ((pp->p_boffset - lp->d_pbase) % lp->d_align)
712                     fprintf(f, "%10s  ", "ILLEGAL");
713                 else
714                     fprintf(f, "%10ju  ",
715                             (intmax_t)(pp->p_boffset - lp->d_pbase) / blksize);
716
717                 if (pp->p_fstype < FSMAXTYPES)
718                         fprintf(f, "%8.8s", fstypenames[pp->p_fstype]);
719                 else
720                         fprintf(f, "%8d", pp->p_fstype);
721                 fprintf(f, "\t# %11.3fMB", (double)pp->p_bsize / onemeg);
722                 fprintf(f, "\n");
723         }
724         for (part = 0; part < lp->d_npartitions; part++) {
725                 pp = &lp->d_partitions[part];
726
727                 if (pp->p_bsize == 0)
728                         continue;
729
730                 if (uuid_is_nil(&lp->d_stor_uuid, NULL) == 0) {
731                         fprintf(f, "  %c-stor_uuid: ", 'a' + part);
732                         str = NULL;
733                         uuid_to_string(&pp->p_stor_uuid, &str, NULL);
734                         if (str) {
735                                 fprintf(f, "%s", str);
736                                 free(str);
737                         }
738                         fprintf(f, "\n");
739                 }
740         }
741         if (didany == 0) {
742                 fprintf(f, "# EXAMPLE\n");
743                 fprintf(f, "#a:          4g          0    4.2BSD\n");
744                 fprintf(f, "#a:          *           *    4.2BSD\n");
745
746         }
747         fflush(f);
748 }
749
750 int
751 edit(struct disklabel64 *lp, int f)
752 {
753         int c, fd;
754         struct disklabel64 label;
755         FILE *fp;
756
757         if ((fd = mkstemp(tmpfil)) == -1 ||
758             (fp = fdopen(fd, "w")) == NULL) {
759                 warnx("can't create %s", tmpfil);
760                 return (1);
761         }
762         display(fp, lp);
763         fclose(fp);
764         for (;;) {
765                 if (!editit())
766                         break;
767                 fp = fopen(tmpfil, "r");
768                 if (fp == NULL) {
769                         warnx("can't reopen %s for reading", tmpfil);
770                         break;
771                 }
772                 bzero((char *)&label, sizeof(label));
773                 if (getasciilabel(fp, &label)) {
774                         *lp = label;
775                         if (writelabel(f, lp) == 0) {
776                                 fclose(fp);
777                                 unlink(tmpfil);
778                                 return (0);
779                         }
780                 }
781                 fclose(fp);
782                 printf("re-edit the label? [y]: "); fflush(stdout);
783                 c = getchar();
784                 if (c != EOF && c != (int)'\n')
785                         while (getchar() != (int)'\n')
786                                 ;
787                 if  (c == (int)'n')
788                         break;
789         }
790         unlink(tmpfil);
791         return (1);
792 }
793
794 int
795 editit(void)
796 {
797         int pid, xpid;
798         int status, omask;
799         const char *ed;
800
801         omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP));
802         while ((pid = fork()) < 0) {
803                 if (errno == EPROCLIM) {
804                         warnx("you have too many processes");
805                         return(0);
806                 }
807                 if (errno != EAGAIN) {
808                         warn("fork");
809                         return(0);
810                 }
811                 sleep(1);
812         }
813         if (pid == 0) {
814                 sigsetmask(omask);
815                 setgid(getgid());
816                 setuid(getuid());
817                 if ((ed = getenv("EDITOR")) == NULL)
818                         ed = DEFEDITOR;
819                 execlp(ed, ed, tmpfil, NULL);
820                 err(1, "%s", ed);
821         }
822         while ((xpid = wait(&status)) >= 0)
823                 if (xpid == pid)
824                         break;
825         sigsetmask(omask);
826         return(!status);
827 }
828
829 char *
830 skip(char *cp)
831 {
832
833         while (*cp != '\0' && isspace(*cp))
834                 cp++;
835         if (*cp == '\0' || *cp == '#')
836                 return (NULL);
837         return (cp);
838 }
839
840 char *
841 word(char *cp)
842 {
843         char c;
844
845         while (*cp != '\0' && !isspace(*cp) && *cp != '#')
846                 cp++;
847         if ((c = *cp) != '\0') {
848                 *cp++ = '\0';
849                 if (c != '#')
850                         return (skip(cp));
851         }
852         return (NULL);
853 }
854
855 /*
856  * Read an ascii label in from fd f,
857  * in the same format as that put out by display(),
858  * and fill in lp.
859  */
860 int
861 getasciilabel(FILE *f, struct disklabel64 *lp)
862 {
863         char *cp;
864         u_int part;
865         char *tp, line[BUFSIZ];
866         u_long v;
867         uint32_t blksize = 0;
868         uint64_t vv;
869         int lineno = 0, errors = 0;
870         char empty[] = "";
871
872         bzero(&part_set, sizeof(part_set));
873         bzero(&part_size_type, sizeof(part_size_type));
874         bzero(&part_offset_type, sizeof(part_offset_type));
875         while (fgets(line, sizeof(line) - 1, f)) {
876                 lineno++;
877                 if ((cp = strchr(line,'\n')) != NULL)
878                         *cp = '\0';
879                 cp = skip(line);
880                 if (cp == NULL)
881                         continue;
882                 tp = strchr(cp, ':');
883                 if (tp == NULL) {
884                         fprintf(stderr, "line %d: syntax error\n", lineno);
885                         errors++;
886                         continue;
887                 }
888                 *tp++ = '\0', tp = skip(tp);
889                 if (sscanf(cp, "%lu partitions", &v) == 1) {
890                         if (v == 0 || v > MAXPARTITIONS64) {
891                                 fprintf(stderr,
892                                     "line %d: bad # of partitions\n", lineno);
893                                 lp->d_npartitions = MAXPARTITIONS64;
894                                 errors++;
895                         } else
896                                 lp->d_npartitions = v;
897                         continue;
898                 }
899                 if (tp == NULL)
900                         tp = empty;
901
902                 if (streq(cp, "diskid")) {
903                         uint32_t status = 0;
904                         uuid_from_string(tp, &lp->d_stor_uuid, &status);
905                         if (status != uuid_s_ok) {
906                                 fprintf(stderr,
907                                     "line %d: %s: illegal UUID\n",
908                                     lineno, tp);
909                                 errors++;
910                         }
911                         continue;
912                 }
913                 if (streq(cp, "label")) {
914                         strncpy(lp->d_packname, tp, sizeof (lp->d_packname));
915                         continue;
916                 }
917
918                 if (streq(cp, "alignment")) {
919                         v = strtoul(tp, NULL, 0);
920                         if (v <= 0 || (v & DEV_BMASK) != 0 || v > 1024*1024) {
921                                 fprintf(stderr,
922                                     "line %d: %s: bad alignment\n",
923                                     lineno, tp);
924                                 errors++;
925                         } else {
926                                 lp->d_align = v;
927                         }
928                         continue;
929                 }
930                 if (streq(cp, "total size")) {
931                         vv = strtoull(tp, NULL, 0);
932                         if (vv == 0 || vv == (uint64_t)-1) {
933                                 fprintf(stderr, "line %d: %s: bad %s\n",
934                                     lineno, tp, cp);
935                                 errors++;
936                         } else {
937                                 lp->d_total_size = vv;
938                         }
939                         continue;
940                 }
941                 if (streq(cp, "boot2 data base")) {
942                         vv = strtoull(tp, NULL, 0);
943                         if (vv == 0 || vv == (uint64_t)-1) {
944                                 fprintf(stderr, "line %d: %s: bad %s\n",
945                                     lineno, tp, cp);
946                                 errors++;
947                         } else {
948                                 lp->d_bbase = vv;
949                         }
950                         continue;
951                 }
952                 if (streq(cp, "partitions data base")) {
953                         vv = strtoull(tp, NULL, 0);
954                         if (vv == 0 || vv == (uint64_t)-1) {
955                                 fprintf(stderr, "line %d: %s: bad %s\n",
956                                     lineno, tp, cp);
957                                 errors++;
958                         } else {
959                                 lp->d_pbase = vv;
960                         }
961                         continue;
962                 }
963                 if (streq(cp, "partitions data stop")) {
964                         vv = strtoull(tp, NULL, 0);
965                         if (vv == 0 || vv == (uint64_t)-1) {
966                                 fprintf(stderr, "line %d: %s: bad %s\n",
967                                     lineno, tp, cp);
968                                 errors++;
969                         } else {
970                                 lp->d_pstop = vv;
971                         }
972                         continue;
973                 }
974                 if (streq(cp, "backup label")) {
975                         vv = strtoull(tp, NULL, 0);
976                         if (vv == 0 || vv == (uint64_t)-1) {
977                                 fprintf(stderr, "line %d: %s: bad %s\n",
978                                     lineno, tp, cp);
979                                 errors++;
980                         } else {
981                                 lp->d_abase = vv;
982                         }
983                         continue;
984                 }
985                 if (streq(cp, "display block size")) {
986                         v = strtoul(tp, NULL, 0);
987                         if (v <= 0 || (v & DEV_BMASK) != 0 || v > 1024*1024) {
988                                 fprintf(stderr,
989                                     "line %d: %s: bad alignment\n",
990                                     lineno, tp);
991                                 errors++;
992                         } else {
993                                 blksize = v;
994                         }
995                         continue;
996                 }
997
998                 /* the ':' was removed above */
999
1000                 /*
1001                  * Handle main partition data, e.g. a:, b:, etc.
1002                  */
1003                 if (*cp < 'a' || *cp > MAX_PART) {
1004                         fprintf(stderr,
1005                             "line %d: %s: Unknown disklabel field\n", lineno,
1006                             cp);
1007                         errors++;
1008                         continue;
1009                 }
1010
1011                 /* Process a partition specification line. */
1012                 part = *cp - 'a';
1013                 if (part >= lp->d_npartitions) {
1014                         fprintf(stderr,
1015                             "line %d: partition name out of range a-%c: %s\n",
1016                             lineno, 'a' + lp->d_npartitions - 1, cp);
1017                         errors++;
1018                         continue;
1019                 }
1020
1021                 if (blksize == 0) {
1022                         fprintf(stderr, "block size to use for partition "
1023                                         "display was not specified!\n");
1024                         errors++;
1025                         continue;
1026                 }
1027
1028                 if (strcmp(cp + 1, "-stor_uuid") == 0) {
1029                         if (getasciipartuuid(tp, lp, part, lineno, blksize)) {
1030                                 errors++;
1031                                 break;
1032                         }
1033                         continue;
1034                 } else if (cp[1] == 0) {
1035                         part_set[part] = 1;
1036                         if (getasciipartspec(tp, lp, part, lineno, blksize)) {
1037                                 errors++;
1038                                 break;
1039                         }
1040                         continue;
1041                 }
1042                 fprintf(stderr, "line %d: %s: Unknown disklabel field\n",
1043                         lineno, cp);
1044                 errors++;
1045                 continue;
1046         }
1047         errors += checklabel(lp);
1048         return (errors == 0);
1049 }
1050
1051 static
1052 int
1053 parse_field_val(char **tp, char **cp, u_int64_t *vv, int lineno)
1054 {
1055         char *tmp;
1056
1057         if (*tp == NULL || **tp == 0) {
1058                 fprintf(stderr, "line %d: too few numeric fields\n", lineno);
1059                 return(-1);
1060         }
1061         *cp = *tp;
1062         *tp = word(*cp);
1063         *vv = strtoull(*cp, &tmp, 0);
1064         if (*vv == ULLONG_MAX) {
1065                 fprintf(stderr, "line %d: illegal number\n", lineno);
1066                 return(-1);
1067         }
1068         if (tmp)
1069                 return(*tmp);
1070         else
1071                 return(0);
1072 }
1073
1074 /*
1075  * Read a partition line into partition `part' in the specified disklabel.
1076  * Return 0 on success, 1 on failure.
1077  */
1078 int
1079 getasciipartspec(char *tp, struct disklabel64 *lp, int part,
1080                  int lineno, uint32_t blksize)
1081 {
1082         struct partition64 *pp;
1083         char *cp;
1084         const char **cpp;
1085         int r;
1086         u_long v;
1087         uint64_t vv;
1088         uint64_t mpx;
1089
1090         pp = &lp->d_partitions[part];
1091         cp = NULL;
1092
1093         /*
1094          * size
1095          */
1096         r = parse_field_val(&tp, &cp, &vv, lineno);
1097         if (r < 0)
1098                 return (1);
1099
1100         mpx = 1;
1101         switch(r) {
1102         case 0:
1103                 mpx = blksize;
1104                 break;
1105         case '%':
1106                 /* mpx = 1; */
1107                 break;
1108         case '*':
1109                 mpx = 0;
1110                 break;
1111         case 't':
1112         case 'T':
1113                 mpx *= 1024ULL;
1114                 /* fall through */
1115         case 'g':
1116         case 'G':
1117                 mpx *= 1024ULL;
1118                 /* fall through */
1119         case 'm':
1120         case 'M':
1121                 mpx *= 1024ULL;
1122                 /* fall through */
1123         case 'k':
1124         case 'K':
1125                 mpx *= 1024ULL;
1126                 r = 0;                  /* eat the suffix */
1127                 break;
1128         default:
1129                 Warning("unknown size specifier '%c' (*/%%/K/M/G/T are valid)",
1130                         r);
1131                 return(1);
1132         }
1133
1134         part_size_type[part] = r;
1135         if (vv == 0 && r != '*') {
1136                 fprintf(stderr,
1137                     "line %d: %s: bad partition size (0)\n", lineno, cp);
1138                 return (1);
1139         }
1140         pp->p_bsize = vv * mpx;
1141
1142         /*
1143          * offset
1144          */
1145         r = parse_field_val(&tp, &cp, &vv, lineno);
1146         if (r < 0)
1147                 return (1);
1148         part_offset_type[part] = r;
1149         switch(r) {
1150         case '*':
1151                 pp->p_boffset = 0;
1152                 break;
1153         case 0:
1154                 pp->p_boffset = vv * blksize + lp->d_pbase;
1155                 break;
1156         default:
1157                 fprintf(stderr,
1158                     "line %d: %s: bad suffix on partition offset (%c)\n",
1159                     lineno, cp, r);
1160                 return (1);
1161         }
1162
1163         /*
1164          * fstype
1165          */
1166         if (tp == NULL) {
1167                 fprintf(stderr,
1168                     "line %d: no filesystem type was specified\n", lineno);
1169                 return(1);
1170         }
1171         cp = tp;
1172         tp = word(cp);
1173         for (cpp = fstypenames; cpp < &fstypenames[FSMAXTYPES]; cpp++) {
1174                 if (*cpp && strcasecmp(*cpp, cp) == 0)
1175                         break;
1176         }
1177         if (*cpp != NULL) {
1178                 pp->p_fstype = cpp - fstypenames;
1179         } else {
1180                 if (isdigit(*cp))
1181                         v = strtoul(cp, NULL, 0);
1182                 else
1183                         v = FSMAXTYPES;
1184                 if (v >= FSMAXTYPES) {
1185                         fprintf(stderr,
1186                             "line %d: Warning, unknown filesystem type %s\n",
1187                             lineno, cp);
1188                         v = FS_UNUSED;
1189                 }
1190                 pp->p_fstype = v;
1191         }
1192
1193         cp = tp;
1194         if (tp) {
1195                 fprintf(stderr, "line %d: Warning, extra data on line\n",
1196                         lineno);
1197         }
1198         return(0);
1199 }
1200
1201 int
1202 getasciipartuuid(char *tp, struct disklabel64 *lp, int part,
1203                  int lineno, uint32_t blksize __unused)
1204 {
1205         struct partition64 *pp;
1206         uint32_t status;
1207         char *cp;
1208
1209         pp = &lp->d_partitions[part];
1210
1211         cp = tp;
1212         tp = word(cp);
1213         uuid_from_string(cp, &pp->p_stor_uuid, &status);
1214         if (status != uuid_s_ok) {
1215                 fprintf(stderr, "line %d: Illegal storage uuid specification\n",
1216                         lineno);
1217                 return(1);
1218         }
1219         return(0);
1220 }
1221
1222 /*
1223  * Check disklabel for errors and fill in
1224  * derived fields according to supplied values.
1225  */
1226 int
1227 checklabel(struct disklabel64 *lp)
1228 {
1229         struct partition64 *pp;
1230         int errors = 0;
1231         char part;
1232         u_int64_t total_size;
1233         u_int64_t current_offset;
1234         u_long total_percent;
1235         int seen_default_offset;
1236         int hog_part;
1237         int i, j;
1238         struct partition64 *pp2;
1239         u_int64_t off;
1240
1241         if (lp->d_align < 512 ||
1242             (lp->d_align ^ (lp->d_align - 1)) != lp->d_align * 2 - 1) {
1243                 Warning("Illegal alignment specified: %u\n", lp->d_align);
1244                 return (1);
1245         }
1246         if (lp->d_npartitions > MAXPARTITIONS64) {
1247                 Warning("number of partitions (%u) > MAXPARTITIONS (%d)",
1248                         lp->d_npartitions, MAXPARTITIONS64);
1249                 return (1);
1250         }
1251         off = offsetof(struct disklabel64, d_partitions[lp->d_npartitions]);
1252         off = (off + lp->d_align - 1) & ~(int64_t)(lp->d_align - 1);
1253
1254         if (lp->d_bbase < off || lp->d_bbase % lp->d_align) {
1255                 Warning("illegal boot2 data base ");
1256                 return (1);
1257         }
1258
1259         /*
1260          * pbase can be unaligned slice-relative but will be
1261          * aligned physically.
1262          */
1263         if (lp->d_pbase < lp->d_bbase) {
1264                 Warning("illegal partition data base");
1265                 return (1);
1266         }
1267         if (lp->d_pstop < lp->d_pbase) {
1268                 Warning("illegal partition data stop");
1269                 return (1);
1270         }
1271         if (lp->d_pstop > lp->d_total_size) {
1272                 printf("%012jx\n%012jx\n",
1273                         (intmax_t)lp->d_pstop, (intmax_t)lp->d_total_size);
1274                 Warning("disklabel control info is beyond the total size");
1275                 return (1);
1276         }
1277         if (lp->d_abase &&
1278             (lp->d_abase < lp->d_pstop ||
1279              lp->d_abase > lp->d_total_size - off)) {
1280                 Warning("illegal backup label location");
1281                 return (1);
1282         }
1283
1284         /* first allocate space to the partitions, then offsets */
1285         total_size = 0;         /* in bytes */
1286         total_percent = 0;      /* in percent */
1287         hog_part = -1;
1288         /* find all fixed partitions */
1289         for (i = 0; i < (int)lp->d_npartitions; i++) {
1290                 pp = &lp->d_partitions[i];
1291                 if (part_set[i]) {
1292                         if (part_size_type[i] == '*') {
1293                                 if (part_offset_type[i] != '*') {
1294                                         if (total_size < pp->p_boffset)
1295                                                 total_size = pp->p_boffset;
1296                                 }
1297                                 if (hog_part != -1) {
1298                                         Warning("Too many '*' partitions (%c and %c)",
1299                                             hog_part + 'a',i + 'a');
1300                                 } else {
1301                                         hog_part = i;
1302                                 }
1303                         } else {
1304                                 off_t size;
1305
1306                                 size = pp->p_bsize;
1307                                 if (part_size_type[i] == '%') {
1308                                         /* 
1309                                          * don't count %'s yet
1310                                          */
1311                                         total_percent += size;
1312                                 } else {
1313                                         /*
1314                                          * Value has already been converted
1315                                          * to bytes.
1316                                          */
1317                                         if (size % lp->d_align != 0) {
1318                                                 Warning("partition %c's size is not properly aligned",
1319                                                         i + 'a');
1320                                         }
1321                                         total_size += size;
1322                                 }
1323                         }
1324                 }
1325         }
1326         /* handle % partitions - note %'s don't need to add up to 100! */
1327         if (total_percent != 0) {
1328                 int64_t free_space;
1329                 int64_t space_left;
1330
1331                 free_space = (int64_t)(lp->d_pstop - lp->d_pbase - total_size);
1332                 free_space &= ~(u_int64_t)(lp->d_align - 1);
1333
1334                 space_left = free_space;
1335                 if (total_percent > 100) {
1336                         fprintf(stderr,"total percentage %lu is greater than 100\n",
1337                             total_percent);
1338                         errors++;
1339                 }
1340
1341                 if (free_space > 0) {
1342                         for (i = 0; i < (int)lp->d_npartitions; i++) {
1343                                 pp = &lp->d_partitions[i];
1344                                 if (part_set[i] && part_size_type[i] == '%') {
1345                                         /* careful of overflows! and integer roundoff */
1346                                         pp->p_bsize = ((double)pp->p_bsize/100) * free_space;
1347                                         pp->p_bsize = (pp->p_bsize + lp->d_align - 1) & ~(u_int64_t)(lp->d_align - 1);
1348                                         if ((int64_t)pp->p_bsize > space_left)
1349                                                 pp->p_bsize = (u_int64_t)space_left;
1350                                         total_size += pp->p_bsize;
1351                                         space_left -= pp->p_bsize;
1352                                 }
1353                         }
1354                 } else {
1355                         fprintf(stderr, "%jd bytes available to give to "
1356                                         "'*' and '%%' partitions\n",
1357                                 (intmax_t)free_space);
1358                         errors++;
1359                         /* fix?  set all % partitions to size 0? */
1360                 }
1361         }
1362         /* give anything remaining to the hog partition */
1363         if (hog_part != -1) {
1364                 off = lp->d_pstop - lp->d_pbase - total_size;
1365                 off &= ~(u_int64_t)(lp->d_align - 1);
1366                 lp->d_partitions[hog_part].p_bsize = off;
1367                 total_size = lp->d_pstop - lp->d_pbase;
1368         }
1369
1370         /* Now set the offsets for each partition */
1371         current_offset = lp->d_pbase;
1372         seen_default_offset = 0;
1373         for (i = 0; i < (int)lp->d_npartitions; i++) {
1374                 part = 'a' + i;
1375                 pp = &lp->d_partitions[i];
1376                 if (pp->p_bsize == 0)
1377                         continue;
1378                 if (part_set[i]) {
1379                         if (part_offset_type[i] == '*') {
1380                                 pp->p_boffset = current_offset;
1381                                 seen_default_offset = 1;
1382                         } else {
1383                                 /* allow them to be out of order for old-style tables */
1384                                 if (pp->p_boffset < current_offset && 
1385                                     seen_default_offset &&
1386                                     pp->p_fstype != FS_VINUM) {
1387                                         fprintf(stderr,
1388 "Offset 0x%012jx for partition %c overlaps previous partition which ends at 0x%012jx\n",
1389                                             (intmax_t)pp->p_boffset,
1390                                             i + 'a',
1391                                             (intmax_t)current_offset);
1392                                         fprintf(stderr,
1393 "Labels with any *'s for offset must be in ascending order by sector\n");
1394                                         errors++;
1395                                 } else if (pp->p_boffset != current_offset &&
1396                                            seen_default_offset) {
1397                                         /* 
1398                                          * this may give unneeded warnings if 
1399                                          * partitions are out-of-order
1400                                          */
1401                                         Warning(
1402 "Offset 0x%012jx for partition %c doesn't match expected value 0x%012jx",
1403                                             pp->p_boffset, i + 'a',
1404                                             (intmax_t)current_offset);
1405                                 }
1406                         }
1407                         current_offset = pp->p_boffset + pp->p_bsize; 
1408                 }
1409         }
1410
1411         for (i = 0; i < (int)lp->d_npartitions; i++) {
1412                 part = 'a' + i;
1413                 pp = &lp->d_partitions[i];
1414                 if (pp->p_bsize == 0 && pp->p_boffset != 0)
1415                         Warning("partition %c: size 0, but offset 0x%012jx",
1416                                 part, (intmax_t)pp->p_boffset);
1417                 if (pp->p_bsize == 0) {
1418                         pp->p_boffset = 0;
1419                         continue;
1420                 }
1421                 if (uuid_is_nil(&pp->p_stor_uuid, NULL))
1422                         uuid_create(&pp->p_stor_uuid, NULL);
1423
1424                 if (pp->p_boffset < lp->d_pbase) {
1425                         fprintf(stderr,
1426                             "partition %c: offset out of bounds (%jd)\n",
1427                             part, (intmax_t)(pp->p_boffset - lp->d_pbase));
1428                         errors++;
1429                 }
1430                 if (pp->p_boffset > lp->d_pstop) {
1431                         fprintf(stderr,
1432                             "partition %c: offset out of bounds (%jd)\n",
1433                             part, (intmax_t)(pp->p_boffset - lp->d_pbase));
1434                         errors++;
1435                 }
1436                 if (pp->p_boffset + pp->p_bsize > lp->d_pstop) {
1437                         fprintf(stderr,
1438                             "partition %c: size out of bounds (%jd)\n",
1439                             part, (intmax_t)(pp->p_boffset - lp->d_pbase));
1440                         errors++;
1441                 }
1442
1443                 /* check for overlaps */
1444                 /* this will check for all possible overlaps once and only once */
1445                 for (j = 0; j < i; j++) {
1446                         pp2 = &lp->d_partitions[j];
1447                         if (pp->p_fstype != FS_VINUM &&
1448                             pp2->p_fstype != FS_VINUM &&
1449                             part_set[i] && part_set[j]) {
1450                                 if (pp2->p_boffset < pp->p_boffset + pp->p_bsize &&
1451                                     (pp2->p_boffset + pp2->p_bsize > pp->p_boffset ||
1452                                         pp2->p_boffset >= pp->p_boffset)) {
1453                                         fprintf(stderr,"partitions %c and %c overlap!\n",
1454                                             j + 'a', i + 'a');
1455                                         errors++;
1456                                 }
1457                         }
1458                 }
1459         }
1460         for (; i < (int)lp->d_npartitions; i++) {
1461                 part = 'a' + i;
1462                 pp = &lp->d_partitions[i];
1463                 if (pp->p_bsize || pp->p_boffset)
1464                         Warning("unused partition %c: size 0x%012jx "
1465                                 "offset 0x%012jx",
1466                                 'a' + i, (intmax_t)pp->p_bsize,
1467                                 (intmax_t)pp->p_boffset);
1468         }
1469         return (errors);
1470 }
1471
1472 /*
1473  * When operating on a "virgin" disk, try getting an initial label
1474  * from the associated device driver.  This might work for all device
1475  * drivers that are able to fetch some initial device parameters
1476  * without even having access to a (BSD) disklabel, like SCSI disks,
1477  * most IDE drives, or vn devices.
1478  *
1479  * The device name must be given in its "canonical" form.
1480  */
1481 static struct disklabel64 dlab;
1482
1483 struct disklabel64 *
1484 getvirginlabel(void)
1485 {
1486         struct disklabel64 *dl = &dlab;
1487         int f;
1488
1489         if ((f = open(dkname, O_RDONLY)) == -1) {
1490                 warn("cannot open %s", dkname);
1491                 return (NULL);
1492         }
1493
1494         /*
1495          * Try to use the new get-virgin-label ioctl.  If it fails,
1496          * fallback to the old get-disk-info ioctl.
1497          */
1498         if (ioctl(f, DIOCGDVIRGIN64, dl) < 0) {
1499                 l_perror("ioctl DIOCGDVIRGIN64");
1500                 close(f);
1501                 return (NULL);
1502         }
1503         close(f);
1504         return (dl);
1505 }
1506
1507 /*VARARGS1*/
1508 void
1509 Warning(const char *fmt, ...)
1510 {
1511         va_list ap;
1512
1513         fprintf(stderr, "Warning, ");
1514         va_start(ap, fmt);
1515         vfprintf(stderr, fmt, ap);
1516         fprintf(stderr, "\n");
1517         va_end(ap);
1518 }
1519
1520 void
1521 usage(void)
1522 {
1523         fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
1524                 "usage: disklabel64 [-r] disk",
1525                 "\t\t(to read label)",
1526                 "       disklabel64 -w [-r] [-n] disk type [packid]",
1527                 "\t\t(to write label with existing boot program)",
1528                 "       disklabel64 -e [-r] [-n] disk",
1529                 "\t\t(to edit label)",
1530                 "       disklabel64 -R [-r] [-n] disk protofile",
1531                 "\t\t(to restore label with existing boot program)",
1532                 "       disklabel64 -B [-n] [-b boot1 -s boot2] disk [type]",
1533                 "\t\t(to install boot program with existing label)",
1534                 "       disklabel64 -w -B [-n] [-b boot1 -s boot2] disk type [packid]",
1535                 "\t\t(to write label and boot program)",
1536                 "       disklabel64 -R -B [-n] [-b boot1 -s boot2] disk protofile [type]",
1537                 "\t\t(to restore label and boot program)",
1538                 "       disklabel64 [-NW] disk",
1539                 "\t\t(to write disable/enable label)");
1540         exit(1);
1541 }