Move all the code related to handling the current 32 bit disklabel
[dragonfly.git] / sbin / disklabel / disklabel.c
1 /*
2  * Copyright (c) 1987, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Symmetric Computer Systems.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
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 the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *      This product includes software developed by the University of
19  *      California, Berkeley and its contributors.
20  * 4. Neither the name of the University nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  *
36  * @(#) Copyright (c) 1987, 1993 The Regents of the University of California.  All rights reserved.
37  * @(#)disklabel.c      1.2 (Symmetric) 11/28/85
38  * @(#)disklabel.c      8.2 (Berkeley) 1/7/94
39  * $FreeBSD: src/sbin/disklabel/disklabel.c,v 1.28.2.15 2003/01/24 16:18:16 des Exp $
40  * $DragonFly: src/sbin/disklabel/disklabel.c,v 1.21 2007/06/18 05:13:38 dillon Exp $
41  */
42
43 #include <sys/param.h>
44 #include <sys/file.h>
45 #include <sys/stat.h>
46 #include <sys/wait.h>
47 #define DKTYPENAMES
48 #include <sys/disklabel32.h>
49 #include <sys/disklabel64.h>
50 #include <sys/diskslice.h>
51 #include <sys/diskmbr.h>
52 #include <sys/dtype.h>
53 #include <sys/sysctl.h>
54 #include <disktab.h>
55
56 #include <vfs/ufs/dinode.h>
57 #include <vfs/ufs/fs.h>
58
59 #include <unistd.h>
60 #include <string.h>
61 #include <stdio.h>
62 #include <stdlib.h>
63 #include <signal.h>
64 #include <stdarg.h>
65 #include <ctype.h>
66 #include <err.h>
67 #include <errno.h>
68 #include <disktab.h>
69 #include "pathnames.h"
70
71 /*
72  * Disklabel: read and write disklabels.
73  * The label is usually placed on one of the first sectors of the disk.
74  * Many machines also place a bootstrap in the same area,
75  * in which case the label is embedded in the bootstrap.
76  * The bootstrap source must leave space at the proper offset
77  * for the label on such machines.
78  */
79
80 #ifndef BBSIZE
81 #define BBSIZE  8192                    /* size of boot area, with label */
82 #endif
83
84 /* FIX!  These are too low, but are traditional */
85 #define DEFAULT_NEWFS_BLOCK  8192U
86 #define DEFAULT_NEWFS_FRAG   1024U
87 #define DEFAULT_NEWFS_CPG    16U
88
89 #define BIG_NEWFS_BLOCK  16384U
90 #define BIG_NEWFS_FRAG   2048U
91 #define BIG_NEWFS_CPG    64U
92
93 #define NUMBOOT 2
94
95 void    makelabel(const char *, const char *, struct disklabel32 *);
96 int     writelabel(int, const char *, struct disklabel32 *);
97 void    l_perror(const char *);
98 struct disklabel32 *readlabel(int);
99 struct disklabel32 *makebootarea(char *, struct disklabel32 *, int);
100 void    display(FILE *, const struct disklabel32 *);
101 int     edit(struct disklabel32 *, int);
102 int     editit(void);
103 char    *skip(char *);
104 char    *word(char *);
105 int     getasciilabel(FILE *, struct disklabel32 *);
106 int     getasciipartspec(char *, struct disklabel32 *, int, int);
107 int     checklabel(struct disklabel32 *);
108 void    setbootflag(struct disklabel32 *);
109 void    Warning(const char *, ...) __printflike(1, 2);
110 void    usage(void);
111 int     checkoldboot(int, const char *);
112 const char *fixlabel(int, struct disklabel32 *, int);
113 struct disklabel32 *getvirginlabel(void);
114 struct disklabel32 *getdisklabelfromdisktab(const char *name);
115
116 #define DEFEDITOR       _PATH_VI
117 #define streq(a,b)      (strcmp(a,b) == 0)
118
119 char    *dkname;
120 char    *specname;
121 char    tmpfil[] = PATH_TMPFILE;
122
123 char    namebuf[BBSIZE], *np = namebuf;
124 struct  disklabel32 lab;
125 char    bootarea[BBSIZE];
126
127 #define MAX_PART ('z')
128 #define MAX_NUM_PARTS (1 + MAX_PART - 'a')
129 char    part_size_type[MAX_NUM_PARTS];
130 char    part_offset_type[MAX_NUM_PARTS];
131 int     part_set[MAX_NUM_PARTS];
132
133 #if NUMBOOT > 0
134 int     installboot;    /* non-zero if we should install a boot program */
135 char    *bootbuf;       /* pointer to buffer with remainder of boot prog */
136 int     bootsize;       /* size of remaining boot program */
137 char    *xxboot;        /* primary boot */
138 char    *bootxx;        /* secondary boot */
139 char    boot0[MAXPATHLEN];
140 char    boot1[MAXPATHLEN];
141 #endif
142
143 enum    {
144         UNSPEC, EDIT, NOWRITE, READ, RESTORE, WRITE, WRITEABLE, WRITEBOOT
145 } op = UNSPEC;
146
147 int     rflag;
148 int     disable_write;   /* set to disable writing to disk label */
149 int     forceflag;
150 u_int32_t slice_start_lba;
151
152 #ifdef DEBUG
153 int     debug;
154 #define OPTIONS "BNRWb:def:nrs:w"
155 #else
156 #define OPTIONS "BNRWb:ef:nrs:w"
157 #endif
158
159 int
160 main(int argc, char *argv[])
161 {
162         struct disklabel32 *lp;
163         FILE *t;
164         int ch, f = 0, flag, error = 0;
165         char *name = 0;
166
167         while ((ch = getopt(argc, argv, OPTIONS)) != -1)
168                 switch (ch) {
169 #if NUMBOOT > 0
170                         case 'B':
171                                 ++installboot;
172                                 break;
173                         case 'b':
174                                 xxboot = optarg;
175                                 break;
176
177                         case 'f':
178                                 forceflag = 1;
179                                 slice_start_lba = strtoul(optarg, NULL, 0);
180                                 break;
181 #if NUMBOOT > 1
182                         case 's':
183                                 bootxx = optarg;
184                                 break;
185 #endif
186 #endif
187                         case 'N':
188                                 if (op != UNSPEC)
189                                         usage();
190                                 op = NOWRITE;
191                                 break;
192                         case 'n':
193                                 disable_write = 1;
194                                 break;
195                         case 'R':
196                                 if (op != UNSPEC)
197                                         usage();
198                                 op = RESTORE;
199                                 break;
200                         case 'W':
201                                 if (op != UNSPEC)
202                                         usage();
203                                 op = WRITEABLE;
204                                 break;
205                         case 'e':
206                                 if (op != UNSPEC)
207                                         usage();
208                                 op = EDIT;
209                                 break;
210                         case 'r':
211                                 ++rflag;
212                                 break;
213                         case 'w':
214                                 if (op != UNSPEC)
215                                         usage();
216                                 op = WRITE;
217                                 break;
218 #ifdef DEBUG
219                         case 'd':
220                                 debug++;
221                                 break;
222 #endif
223                         case '?':
224                         default:
225                                 usage();
226                 }
227         argc -= optind;
228         argv += optind;
229 #if NUMBOOT > 0
230         if (installboot) {
231                 rflag++;
232                 if (op == UNSPEC)
233                         op = WRITEBOOT;
234         } else {
235                 if (op == UNSPEC)
236                         op = READ;
237                 xxboot = bootxx = 0;
238         }
239 #else
240         if (op == UNSPEC)
241                 op = READ;
242 #endif
243         if (argc < 1)
244                 usage();
245
246         dkname = argv[0];
247         if (dkname[0] != '/') {
248                 sprintf(np, "%s%s", _PATH_DEV, dkname);
249                 specname = np;
250                 np += strlen(specname) + 1;
251         } else {
252                 specname = dkname;
253         }
254         f = open(specname, op == READ ? O_RDONLY : O_RDWR);
255         if (f < 0 && errno == ENOENT && dkname[0] != '/') {
256                 sprintf(specname, "%s%s", _PATH_DEV, dkname);
257                 np = namebuf + strlen(specname) + 1;
258                 f = open(specname, op == READ ? O_RDONLY : O_RDWR);
259         }
260         if (f < 0)
261                 err(4, "%s", specname);
262
263         switch(op) {
264
265         case UNSPEC:
266                 break;
267
268         case EDIT:
269                 if (argc != 1)
270                         usage();
271                 lp = readlabel(f);
272                 error = edit(lp, f);
273                 break;
274
275         case NOWRITE:
276                 flag = 0;
277                 if (ioctl(f, DIOCWLABEL, (char *)&flag) < 0)
278                         err(4, "ioctl DIOCWLABEL");
279                 break;
280
281         case READ:
282                 if (argc != 1)
283                         usage();
284                 lp = readlabel(f);
285                 display(stdout, lp);
286                 error = checklabel(lp);
287                 if (checkoldboot(f, NULL))
288                         warnx("Warning, old bootblocks detected, install new bootblocks & reinstall the disklabel");
289                 break;
290
291         case RESTORE:
292 #if NUMBOOT > 0
293                 if (installboot && argc == 3) {
294                         makelabel(argv[2], 0, &lab);
295                         argc--;
296
297                         /*
298                          * We only called makelabel() for its side effect
299                          * of setting the bootstrap file names.  Discard
300                          * all changes to `lab' so that all values in the
301                          * final label come from the ASCII label.
302                          */
303                         bzero((char *)&lab, sizeof(lab));
304                 }
305 #endif
306                 if (argc != 2)
307                         usage();
308                 if (!(t = fopen(argv[1], "r")))
309                         err(4, "%s", argv[1]);
310                 if (!getasciilabel(t, &lab))
311                         exit(1);
312                 lp = makebootarea(bootarea, &lab, f);
313                 *lp = lab;
314                 error = writelabel(f, bootarea, lp);
315                 break;
316
317         case WRITE:
318                 if (argc == 3) {
319                         name = argv[2];
320                         argc--;
321                 }
322                 if (argc != 2)
323                         usage();
324                 makelabel(argv[1], name, &lab);
325                 lp = makebootarea(bootarea, &lab, f);
326                 *lp = lab;
327                 if (checklabel(lp) == 0)
328                         error = writelabel(f, bootarea, lp);
329                 break;
330
331         case WRITEABLE:
332                 flag = 1;
333                 if (ioctl(f, DIOCWLABEL, (char *)&flag) < 0)
334                         err(4, "ioctl DIOCWLABEL");
335                 break;
336
337 #if NUMBOOT > 0
338         case WRITEBOOT:
339         {
340                 struct disklabel32 tlab;
341
342                 lp = readlabel(f);
343                 tlab = *lp;
344                 if (argc == 2)
345                         makelabel(argv[1], 0, &lab);
346                 lp = makebootarea(bootarea, &lab, f);
347                 *lp = tlab;
348                 if (checklabel(lp) == 0)
349                         error = writelabel(f, bootarea, lp);
350                 break;
351         }
352 #endif
353         }
354         exit(error);
355 }
356
357 /*
358  * Construct a prototype disklabel from /etc/disktab.  As a side
359  * effect, set the names of the primary and secondary boot files
360  * if specified.
361  */
362 void
363 makelabel(const char *type, const char *name, struct disklabel32 *lp)
364 {
365         struct disklabel32 *dp;
366
367         if (strcmp(type, "auto") == 0)
368                 dp = getvirginlabel();
369         else
370                 dp = getdisklabelfromdisktab(type);
371         if (dp == NULL)
372                 errx(1, "%s: unknown disk type", type);
373         *lp = *dp;
374
375         /*
376          * NOTE: boot control files may no longer be specified in disktab.
377          */
378         if (name)
379                 strncpy(lp->d_packname, name, sizeof(lp->d_packname));
380 }
381
382 int
383 writelabel(int f, const char *boot, struct disklabel32 *lp)
384 {
385         const char *msg;
386         int flag;
387         int r;
388
389         if (disable_write) {
390                 Warning("write to disk label supressed - label was as follows:");
391                 display(stdout, lp);
392                 return (0);
393         } else {
394                 /* make sure we are not overwriting our boot code */
395                 if (checkoldboot(f, boot))
396                         errx(4, "Will not overwrite old bootblocks w/ label, install new boot blocks first!");
397                 setbootflag(lp);
398                 lp->d_magic = DISKMAGIC32;
399                 lp->d_magic2 = DISKMAGIC32;
400                 lp->d_checksum = 0;
401                 lp->d_checksum = dkcksum32(lp);
402                 if (rflag) {
403                         /*
404                          * First set the kernel disk label,
405                          * then write a label to the raw disk.
406                          * If the SDINFO ioctl fails because it is unimplemented,
407                          * keep going; otherwise, the kernel consistency checks
408                          * may prevent us from changing the current (in-core)
409                          * label.
410                          */
411                         if (ioctl(f, DIOCSDINFO32, lp) < 0 &&
412                                 errno != ENODEV && errno != ENOTTY) {
413                                 l_perror("ioctl DIOCSDINFO");
414                                 return (1);
415                         }
416                         lseek(f, (off_t)0, SEEK_SET);
417                         
418                         /*
419                          * write enable label sector before write
420                          * (if necessary), disable after writing.
421                          */
422                         flag = 1;
423                         if (ioctl(f, DIOCWLABEL, &flag) < 0)
424                                 warn("ioctl DIOCWLABEL");
425                         msg = fixlabel(f, lp, 1);
426                         if (msg) {
427                                 warn(msg);
428                                 return (1);
429                         }
430                         r = write(f, boot, lp->d_bbsize);
431                         fixlabel(f, lp, 0);
432                         if (r != ((ssize_t)lp->d_bbsize)) {
433                                 warn("write");
434                                 return (1);
435                         }
436 #if NUMBOOT > 0
437                         /*
438                          * Output the remainder of the disklabel
439                          */
440                         if (bootbuf) {
441                                 fixlabel(f, lp, 1);
442                                 r = write(f, bootbuf, bootsize);
443                                 fixlabel(f, lp, 0);
444                                 if (r != bootsize) {
445                                         warn("write");
446                                         return(1);
447                                 }
448                         }
449 #endif
450                         flag = 0;
451                         ioctl(f, DIOCWLABEL, &flag);
452                 } else if (ioctl(f, DIOCWDINFO32, lp) < 0) {
453                         l_perror("ioctl DIOCWDINFO");
454                         return (1);
455                 }
456         }
457         return (0);
458 }
459
460 void
461 l_perror(const char *s)
462 {
463         switch (errno) {
464
465         case ESRCH:
466                 warnx("%s: no disk label on disk;", s);
467                 fprintf(stderr, "add \"-r\" to install initial label\n");
468                 break;
469
470         case EINVAL:
471                 warnx("%s: label magic number or checksum is wrong!", s);
472                 fprintf(stderr, "(disklabel or kernel is out of date?)\n");
473                 break;
474
475         case EBUSY:
476                 warnx("%s: open partition would move or shrink", s);
477                 break;
478
479         case EXDEV:
480                 warnx("%s: '%c' partition must start at beginning of disk",
481                     s, 'a' + RAW_PART);
482                 break;
483
484         default:
485                 warn((char *)NULL);
486                 break;
487         }
488 }
489
490 /*
491  * Fetch disklabel for disk.
492  * Use ioctl to get label unless -r flag is given.
493  */
494 struct disklabel32 *
495 readlabel(int f)
496 {
497         const char *msg;
498         struct disklabel32 *lp;
499         int r;
500
501         if (rflag) {
502                 r = read(f, bootarea, BBSIZE);
503                 if (r < BBSIZE)
504                         err(4, "%s", specname);
505                 for (lp = (struct disklabel32 *)bootarea;
506                     lp <= (struct disklabel32 *)(bootarea + BBSIZE - sizeof(*lp));
507                     lp = (struct disklabel32 *)((char *)lp + 16)) {
508                         if (lp->d_magic == DISKMAGIC32 &&
509                             lp->d_magic2 == DISKMAGIC32)
510                                 break;
511                 }
512                 if (lp > (struct disklabel32 *)(bootarea+BBSIZE-sizeof(*lp)) ||
513                     lp->d_magic != DISKMAGIC32 || lp->d_magic2 != DISKMAGIC32 ||
514                     dkcksum32(lp) != 0) {
515                         errx(1, "bad pack magic number (label is damaged, "
516                                 "or pack is unlabeled)");
517                 }
518                 if ((msg = fixlabel(f, lp, 0)) != NULL)
519                         errx(1, msg);
520         } else {
521                 lp = &lab;
522                 if (ioctl(f, DIOCGDINFO32, lp) < 0)
523                         err(4, "ioctl DIOCGDINFO");
524         }
525         return (lp);
526 }
527
528 /*
529  * Construct a bootarea (d_bbsize bytes) in the specified buffer ``boot''
530  * Returns a pointer to the disklabel portion of the bootarea.
531  */
532 struct disklabel32 *
533 makebootarea(char *boot, struct disklabel32 *dp, int f)
534 {
535         struct disklabel32 *lp;
536         char *p;
537         int b;
538 #if NUMBOOT > 0
539         char *dkbasename;
540         struct stat sb;
541 #endif
542 #ifdef __i386__
543         char *tmpbuf;
544         unsigned int i, found;
545 #endif
546
547         /* XXX */
548         if (dp->d_secsize == 0) {
549                 dp->d_secsize = DEV_BSIZE;
550                 dp->d_bbsize = BBSIZE;
551         }
552         lp = (struct disklabel32 *)
553                 (boot + (LABELSECTOR32 * dp->d_secsize) + LABELOFFSET32);
554         bzero((char *)lp, sizeof *lp);
555 #if NUMBOOT > 0
556         /*
557          * If we are not installing a boot program but we are installing a
558          * label on disk then we must read the current bootarea so we don't
559          * clobber the existing boot.
560          */
561         if (!installboot) {
562                 if (rflag) {
563                         if (read(f, boot, BBSIZE) < BBSIZE)
564                                 err(4, "%s", specname);
565                         bzero((char *)lp, sizeof *lp);
566                 }
567                 return (lp);
568         }
569         /*
570          * We are installing a boot program.  Determine the name(s) and
571          * read them into the appropriate places in the boot area.
572          */
573         if (!xxboot || !bootxx) {
574                 dkbasename = np;
575                 if ((p = strrchr(dkname, '/')) == NULL)
576                         p = dkname;
577                 else
578                         p++;
579                 while (*p && !isdigit(*p))
580                         *np++ = *p++;
581                 *np++ = '\0';
582
583                 if (!xxboot) {
584                         sprintf(boot0, "%s/boot1", _PATH_BOOTDIR);
585                         xxboot = boot0;
586                 }
587 #if NUMBOOT > 1
588                 if (!bootxx) {
589                         sprintf(boot1, "%s/boot2", _PATH_BOOTDIR);
590                         bootxx = boot1;
591                 }
592 #endif
593         }
594 #ifdef DEBUG
595         if (debug)
596                 fprintf(stderr, "bootstraps: xxboot = %s, bootxx = %s\n",
597                         xxboot, bootxx ? bootxx : "NONE");
598 #endif
599
600         /*
601          * Strange rules:
602          * 1. One-piece bootstrap (hp300/hp800)
603          *      up to d_bbsize bytes of ``xxboot'' go in bootarea, the rest
604          *      is remembered and written later following the bootarea.
605          * 2. Two-piece bootstraps (vax/i386?/mips?)
606          *      up to d_secsize bytes of ``xxboot'' go in first d_secsize
607          *      bytes of bootarea, remaining d_bbsize-d_secsize filled
608          *      from ``bootxx''.
609          */
610         b = open(xxboot, O_RDONLY);
611         if (b < 0)
612                 err(4, "%s", xxboot);
613 #if NUMBOOT > 1
614 #ifdef __i386__
615         /*
616          * XXX Botch alert.
617          * The i386 has the so-called fdisk table embedded into the
618          * primary bootstrap.  We take care to not clobber it, but
619          * only if it does already contain some data.  (Otherwise,
620          * the xxboot provides a template.)
621          */
622         if ((tmpbuf = (char *)malloc((int)dp->d_secsize)) == 0)
623                 err(4, "%s", xxboot);
624         memcpy((void *)tmpbuf, (void *)boot, (int)dp->d_secsize);
625 #endif /* i386 */
626         if (read(b, boot, (int)dp->d_secsize) < 0)
627                 err(4, "%s", xxboot);
628         close(b);
629 #ifdef __i386__
630         for (i = DOSPARTOFF, found = 0;
631              !found && i < DOSPARTOFF + NDOSPART*sizeof(struct dos_partition);
632              i++)
633                 found = tmpbuf[i] != 0;
634         if (found)
635                 memcpy((void *)&boot[DOSPARTOFF],
636                        (void *)&tmpbuf[DOSPARTOFF],
637                        NDOSPART * sizeof(struct dos_partition));
638         free(tmpbuf);
639 #endif /* i386 */
640         b = open(bootxx, O_RDONLY);
641         if (b < 0)
642                 err(4, "%s", bootxx);
643         if (fstat(b, &sb) != 0)
644                 err(4, "%s", bootxx);
645         if (dp->d_secsize + sb.st_size > dp->d_bbsize)
646                 errx(4, "%s too large", bootxx);
647         if (read(b, &boot[dp->d_secsize],
648                  (int)(dp->d_bbsize-dp->d_secsize)) < 0)
649                 err(4, "%s", bootxx);
650 #else /* !(NUMBOOT > 1) */
651         if (read(b, boot, (int)dp->d_bbsize) < 0)
652                 err(4, "%s", xxboot);
653         if (fstat(b, &sb) != 0)
654                 err(4, "%s", xxboot);
655         bootsize = (int)sb.st_size - dp->d_bbsize;
656         if (bootsize > 0) {
657                 /* XXX assume d_secsize is a power of two */
658                 bootsize = (bootsize + dp->d_secsize-1) & ~(dp->d_secsize-1);
659                 bootbuf = (char *)malloc((size_t)bootsize);
660                 if (bootbuf == 0)
661                         err(4, "%s", xxboot);
662                 if (read(b, bootbuf, bootsize) < 0) {
663                         free(bootbuf);
664                         err(4, "%s", xxboot);
665                 }
666         }
667 #endif /* NUMBOOT > 1 */
668         close(b);
669 #endif /* NUMBOOT > 0 */
670         /*
671          * Make sure no part of the bootstrap is written in the area
672          * reserved for the label.
673          */
674         for (p = (char *)lp; p < (char *)lp + sizeof(struct disklabel32); p++)
675                 if (*p)
676                         errx(2, "bootstrap doesn't leave room for disk label");
677         return (lp);
678 }
679
680 void
681 display(FILE *f, const struct disklabel32 *lp)
682 {
683         int i, j;
684         const struct partition32 *pp;
685
686         fprintf(f, "# %s:\n", specname);
687         if (lp->d_type < DKMAXTYPES)
688                 fprintf(f, "type: %s\n", dktypenames[lp->d_type]);
689         else
690                 fprintf(f, "type: %u\n", lp->d_type);
691         fprintf(f, "disk: %.*s\n", (int)sizeof(lp->d_typename),
692                 lp->d_typename);
693         fprintf(f, "label: %.*s\n", (int)sizeof(lp->d_packname),
694                 lp->d_packname);
695         fprintf(f, "flags:");
696         fprintf(f, "\n");
697         fprintf(f, "bytes/sector: %lu\n", (u_long)lp->d_secsize);
698         fprintf(f, "sectors/track: %lu\n", (u_long)lp->d_nsectors);
699         fprintf(f, "tracks/cylinder: %lu\n", (u_long)lp->d_ntracks);
700         fprintf(f, "sectors/cylinder: %lu\n", (u_long)lp->d_secpercyl);
701         fprintf(f, "cylinders: %lu\n", (u_long)lp->d_ncylinders);
702         fprintf(f, "sectors/unit: %lu\n", (u_long)lp->d_secperunit);
703         fprintf(f, "rpm: %u\n", lp->d_rpm);
704         fprintf(f, "interleave: %u\n", lp->d_interleave);
705         fprintf(f, "trackskew: %u\n", lp->d_trackskew);
706         fprintf(f, "cylinderskew: %u\n", lp->d_cylskew);
707         fprintf(f, "headswitch: %lu\t\t# milliseconds\n",
708             (u_long)lp->d_headswitch);
709         fprintf(f, "track-to-track seek: %ld\t# milliseconds\n",
710             (u_long)lp->d_trkseek);
711         fprintf(f, "drivedata: ");
712         for (i = NDDATA32 - 1; i >= 0; i--) {
713                 if (lp->d_drivedata[i])
714                         break;
715         }
716         if (i < 0)
717                 i = 0;
718         for (j = 0; j <= i; j++)
719                 fprintf(f, "%lu ", (u_long)lp->d_drivedata[j]);
720         fprintf(f, "\n\n%u partitions:\n", lp->d_npartitions);
721         fprintf(f,
722             "#          size     offset    fstype   \n");
723         pp = lp->d_partitions;
724         for (i = 0; i < lp->d_npartitions; i++, pp++) {
725                 if (pp->p_size) {
726                         u_long onemeg = 1024 * 1024 / lp->d_secsize;
727                         fprintf(f, "  %c: ", 'a' + i);
728
729                         fprintf(f, "%10lu ", (u_long)pp->p_size);
730                         fprintf(f, "%10lu  ", (u_long)pp->p_offset);
731                         if (pp->p_fstype < FSMAXTYPES)
732                                 fprintf(f, "%8.8s", fstypenames[pp->p_fstype]);
733                         else
734                                 fprintf(f, "%8d", pp->p_fstype);
735
736                         fprintf(f, "\t# %11.3fM", (double)pp->p_size / onemeg);
737                         fprintf(f, "\n");
738                 }
739         }
740         fflush(f);
741 }
742
743 int
744 edit(struct disklabel32 *lp, int f)
745 {
746         int c, fd;
747         struct disklabel32 label;
748         FILE *fp;
749
750         if ((fd = mkstemp(tmpfil)) == -1 ||
751             (fp = fdopen(fd, "w")) == NULL) {
752                 warnx("can't create %s", tmpfil);
753                 return (1);
754         }
755         display(fp, lp);
756         fclose(fp);
757         for (;;) {
758                 if (!editit())
759                         break;
760                 fp = fopen(tmpfil, "r");
761                 if (fp == NULL) {
762                         warnx("can't reopen %s for reading", tmpfil);
763                         break;
764                 }
765                 bzero((char *)&label, sizeof(label));
766                 if (getasciilabel(fp, &label)) {
767                         *lp = label;
768                         if (writelabel(f, bootarea, lp) == 0) {
769                                 fclose(fp);
770                                 unlink(tmpfil);
771                                 return (0);
772                         }
773                 }
774                 fclose(fp);
775                 printf("re-edit the label? [y]: "); fflush(stdout);
776                 c = getchar();
777                 if (c != EOF && c != (int)'\n')
778                         while (getchar() != (int)'\n')
779                                 ;
780                 if  (c == (int)'n')
781                         break;
782         }
783         unlink(tmpfil);
784         return (1);
785 }
786
787 int
788 editit(void)
789 {
790         int pid, xpid;
791         int status, omask;
792         const char *ed;
793
794         omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP));
795         while ((pid = fork()) < 0) {
796                 if (errno == EPROCLIM) {
797                         warnx("you have too many processes");
798                         return(0);
799                 }
800                 if (errno != EAGAIN) {
801                         warn("fork");
802                         return(0);
803                 }
804                 sleep(1);
805         }
806         if (pid == 0) {
807                 sigsetmask(omask);
808                 setgid(getgid());
809                 setuid(getuid());
810                 if ((ed = getenv("EDITOR")) == (char *)0)
811                         ed = DEFEDITOR;
812                 execlp(ed, ed, tmpfil, (char *)0);
813                 err(1, "%s", ed);
814         }
815         while ((xpid = wait(&status)) >= 0)
816                 if (xpid == pid)
817                         break;
818         sigsetmask(omask);
819         return(!status);
820 }
821
822 char *
823 skip(char *cp)
824 {
825
826         while (*cp != '\0' && isspace(*cp))
827                 cp++;
828         if (*cp == '\0' || *cp == '#')
829                 return (NULL);
830         return (cp);
831 }
832
833 char *
834 word(char *cp)
835 {
836         char c;
837
838         while (*cp != '\0' && !isspace(*cp) && *cp != '#')
839                 cp++;
840         if ((c = *cp) != '\0') {
841                 *cp++ = '\0';
842                 if (c != '#')
843                         return (skip(cp));
844         }
845         return (NULL);
846 }
847
848 /*
849  * Read an ascii label in from fd f,
850  * in the same format as that put out by display(),
851  * and fill in lp.
852  */
853 int
854 getasciilabel(FILE *f, struct disklabel32 *lp)
855 {
856         char *cp;
857         const char **cpp;
858         u_int part;
859         char *tp, line[BUFSIZ];
860         u_long v;
861         int lineno = 0, errors = 0;
862         int i;
863         char empty[] = "";
864         char unknown[] = "unknown";
865
866         bzero(&part_set, sizeof(part_set));
867         bzero(&part_size_type, sizeof(part_size_type));
868         bzero(&part_offset_type, sizeof(part_offset_type));
869         lp->d_bbsize = BBSIZE;                          /* XXX */
870         lp->d_sbsize = SBSIZE;                          /* XXX */
871         while (fgets(line, sizeof(line) - 1, f)) {
872                 lineno++;
873                 if ((cp = strchr(line,'\n')) != 0)
874                         *cp = '\0';
875                 cp = skip(line);
876                 if (cp == NULL)
877                         continue;
878                 tp = strchr(cp, ':');
879                 if (tp == NULL) {
880                         fprintf(stderr, "line %d: syntax error\n", lineno);
881                         errors++;
882                         continue;
883                 }
884                 *tp++ = '\0', tp = skip(tp);
885                 if (streq(cp, "type")) {
886                         if (tp == NULL)
887                                 tp = unknown;
888                         cpp = dktypenames;
889                         for (; cpp < &dktypenames[DKMAXTYPES]; cpp++) {
890                                 if (*cpp && streq(*cpp, tp)) {
891                                         lp->d_type = cpp - dktypenames;
892                                         break;
893                                 }
894                         }
895                         if (cpp < &dktypenames[DKMAXTYPES])
896                                 continue;
897                         v = strtoul(tp, NULL, 10);
898                         if (v >= DKMAXTYPES) {
899                                 fprintf(stderr, "line %d:%s %lu\n", lineno,
900                                     "Warning, unknown disk type", v);
901                         }
902                         lp->d_type = v;
903                         continue;
904                 }
905                 if (streq(cp, "flags")) {
906                         for (v = 0; (cp = tp) && *cp != '\0';) {
907                                 tp = word(cp);
908                                 if (streq(cp, "removeable"))
909                                         v |= 0; /* obsolete */
910                                 else if (streq(cp, "ecc"))
911                                         v |= 0; /* obsolete */
912                                 else if (streq(cp, "badsect"))
913                                         v |= 0; /* obsolete */
914                                 else {
915                                         fprintf(stderr,
916                                             "line %d: %s: bad flag\n",
917                                             lineno, cp);
918                                         errors++;
919                                 }
920                         }
921                         lp->d_flags = v;
922                         continue;
923                 }
924                 if (streq(cp, "drivedata")) {
925                         for (i = 0; (cp = tp) && *cp != '\0' && i < NDDATA32;) {
926                                 lp->d_drivedata[i++] = strtoul(cp, NULL, 10);
927                                 tp = word(cp);
928                         }
929                         continue;
930                 }
931                 if (sscanf(cp, "%lu partitions", &v) == 1) {
932                         if (v == 0 || v > MAXPARTITIONS32) {
933                                 fprintf(stderr,
934                                     "line %d: bad # of partitions\n", lineno);
935                                 lp->d_npartitions = MAXPARTITIONS32;
936                                 errors++;
937                         } else
938                                 lp->d_npartitions = v;
939                         continue;
940                 }
941                 if (tp == NULL)
942                         tp = empty;
943                 if (streq(cp, "disk")) {
944                         strncpy(lp->d_typename, tp, sizeof (lp->d_typename));
945                         continue;
946                 }
947                 if (streq(cp, "label")) {
948                         strncpy(lp->d_packname, tp, sizeof (lp->d_packname));
949                         continue;
950                 }
951                 if (streq(cp, "bytes/sector")) {
952                         v = strtoul(tp, NULL, 10);
953                         if (v == 0 || (v % DEV_BSIZE) != 0) {
954                                 fprintf(stderr,
955                                     "line %d: %s: bad sector size\n",
956                                     lineno, tp);
957                                 errors++;
958                         } else
959                                 lp->d_secsize = v;
960                         continue;
961                 }
962                 if (streq(cp, "sectors/track")) {
963                         v = strtoul(tp, NULL, 10);
964 #if (ULONG_MAX != 0xffffffffUL)
965                         if (v == 0 || v > 0xffffffff) {
966 #else
967                         if (v == 0) {
968 #endif
969                                 fprintf(stderr, "line %d: %s: bad %s\n",
970                                     lineno, tp, cp);
971                                 errors++;
972                         } else
973                                 lp->d_nsectors = v;
974                         continue;
975                 }
976                 if (streq(cp, "sectors/cylinder")) {
977                         v = strtoul(tp, NULL, 10);
978                         if (v == 0) {
979                                 fprintf(stderr, "line %d: %s: bad %s\n",
980                                     lineno, tp, cp);
981                                 errors++;
982                         } else
983                                 lp->d_secpercyl = v;
984                         continue;
985                 }
986                 if (streq(cp, "tracks/cylinder")) {
987                         v = strtoul(tp, NULL, 10);
988                         if (v == 0) {
989                                 fprintf(stderr, "line %d: %s: bad %s\n",
990                                     lineno, tp, cp);
991                                 errors++;
992                         } else
993                                 lp->d_ntracks = v;
994                         continue;
995                 }
996                 if (streq(cp, "cylinders")) {
997                         v = strtoul(tp, NULL, 10);
998                         if (v == 0) {
999                                 fprintf(stderr, "line %d: %s: bad %s\n",
1000                                     lineno, tp, cp);
1001                                 errors++;
1002                         } else
1003                                 lp->d_ncylinders = v;
1004                         continue;
1005                 }
1006                 if (streq(cp, "sectors/unit")) {
1007                         v = strtoul(tp, NULL, 10);
1008                         if (v == 0) {
1009                                 fprintf(stderr, "line %d: %s: bad %s\n",
1010                                     lineno, tp, cp);
1011                                 errors++;
1012                         } else
1013                                 lp->d_secperunit = v;
1014                         continue;
1015                 }
1016                 if (streq(cp, "rpm")) {
1017                         v = strtoul(tp, NULL, 10);
1018                         if (v == 0 || v > USHRT_MAX) {
1019                                 fprintf(stderr, "line %d: %s: bad %s\n",
1020                                     lineno, tp, cp);
1021                                 errors++;
1022                         } else
1023                                 lp->d_rpm = v;
1024                         continue;
1025                 }
1026                 if (streq(cp, "interleave")) {
1027                         v = strtoul(tp, NULL, 10);
1028                         if (v == 0 || v > USHRT_MAX) {
1029                                 fprintf(stderr, "line %d: %s: bad %s\n",
1030                                     lineno, tp, cp);
1031                                 errors++;
1032                         } else
1033                                 lp->d_interleave = v;
1034                         continue;
1035                 }
1036                 if (streq(cp, "trackskew")) {
1037                         v = strtoul(tp, NULL, 10);
1038                         if (v > USHRT_MAX) {
1039                                 fprintf(stderr, "line %d: %s: bad %s\n",
1040                                     lineno, tp, cp);
1041                                 errors++;
1042                         } else
1043                                 lp->d_trackskew = v;
1044                         continue;
1045                 }
1046                 if (streq(cp, "cylinderskew")) {
1047                         v = strtoul(tp, NULL, 10);
1048                         if (v > USHRT_MAX) {
1049                                 fprintf(stderr, "line %d: %s: bad %s\n",
1050                                     lineno, tp, cp);
1051                                 errors++;
1052                         } else
1053                                 lp->d_cylskew = v;
1054                         continue;
1055                 }
1056                 if (streq(cp, "headswitch")) {
1057                         v = strtoul(tp, NULL, 10);
1058                         lp->d_headswitch = v;
1059                         continue;
1060                 }
1061                 if (streq(cp, "track-to-track seek")) {
1062                         v = strtoul(tp, NULL, 10);
1063                         lp->d_trkseek = v;
1064                         continue;
1065                 }
1066                 /* the ':' was removed above */
1067                 if (*cp < 'a' || *cp > MAX_PART || cp[1] != '\0') {
1068                         fprintf(stderr,
1069                             "line %d: %s: Unknown disklabel field\n", lineno,
1070                             cp);
1071                         errors++;
1072                         continue;
1073                 }
1074
1075                 /* Process a partition specification line. */
1076                 part = *cp - 'a';
1077                 if (part >= lp->d_npartitions) {
1078                         fprintf(stderr,
1079                             "line %d: partition name out of range a-%c: %s\n",
1080                             lineno, 'a' + lp->d_npartitions - 1, cp);
1081                         errors++;
1082                         continue;
1083                 }
1084                 part_set[part] = 1;
1085
1086                 if (getasciipartspec(tp, lp, part, lineno) != 0) {
1087                         errors++;
1088                         break;
1089                 }
1090         }
1091         errors += checklabel(lp);
1092         return (errors == 0);
1093 }
1094
1095 #define NXTNUM(n) do { \
1096         if (tp == NULL) { \
1097                 fprintf(stderr, "line %d: too few numeric fields\n", lineno); \
1098                 return (1); \
1099         } else { \
1100                 cp = tp, tp = word(cp); \
1101                 (n) = strtoul(cp, NULL, 10); \
1102         } \
1103 } while (0)
1104
1105 /* retain 1 character following number */
1106 #define NXTWORD(w,n) do { \
1107         if (tp == NULL) { \
1108                 fprintf(stderr, "line %d: too few numeric fields\n", lineno); \
1109                 return (1); \
1110         } else { \
1111                 char *tmp; \
1112                 cp = tp, tp = word(cp); \
1113                 (n) = strtoul(cp, &tmp, 10); \
1114                 if (tmp) (w) = *tmp; \
1115         } \
1116 } while (0)
1117
1118 /*
1119  * Read a partition line into partition `part' in the specified disklabel.
1120  * Return 0 on success, 1 on failure.
1121  */
1122 int
1123 getasciipartspec(char *tp, struct disklabel32 *lp, int part, int lineno)
1124 {
1125         struct partition32 *pp;
1126         char *cp;
1127         const char **cpp;
1128         u_long v;
1129
1130         pp = &lp->d_partitions[part];
1131         cp = NULL;
1132
1133         /*
1134          * size
1135          */
1136         v = 0;
1137         NXTWORD(part_size_type[part],v);
1138         if (v == 0 && part_size_type[part] != '*') {
1139                 fprintf(stderr,
1140                     "line %d: %s: bad partition size\n", lineno, cp);
1141                 return (1);
1142         }
1143         pp->p_size = v;
1144
1145         /*
1146          * offset
1147          */
1148         v = 0;
1149         NXTWORD(part_offset_type[part],v);
1150         if (v == 0 && part_offset_type[part] != '*' &&
1151             part_offset_type[part] != '\0') {
1152                 fprintf(stderr,
1153                     "line %d: %s: bad partition offset\n", lineno, cp);
1154                 return (1);
1155         }
1156         pp->p_offset = v;
1157
1158         /*
1159          * fstype
1160          */
1161         cp = tp;
1162         tp = word(cp);
1163         for (cpp = fstypenames; cpp < &fstypenames[FSMAXTYPES]; cpp++)
1164                 if (*cpp && streq(*cpp, cp))
1165                         break;
1166         if (*cpp != NULL) {
1167                 pp->p_fstype = cpp - fstypenames;
1168         } else {
1169                 if (isdigit(*cp))
1170                         v = strtoul(cp, NULL, 10);
1171                 else
1172                         v = FSMAXTYPES;
1173                 if (v >= FSMAXTYPES) {
1174                         fprintf(stderr,
1175                             "line %d: Warning, unknown filesystem type %s\n",
1176                             lineno, cp);
1177                         v = FS_UNUSED;
1178                 }
1179                 pp->p_fstype = v;
1180         }
1181
1182         pp->p_fsize = 0;
1183         pp->p_frag = 0;
1184         pp->p_cpg = 0;
1185
1186         cp = tp;
1187         if (tp) {
1188                 fprintf(stderr, "line %d: Warning, fragment, block, "
1189                                 "and bps/cpg fields are no\n"
1190                                 "longer supported and must be specified "
1191                                 "via newfs options instead.\n",
1192                         lineno);
1193         }
1194         return(0);
1195 }
1196
1197 /*
1198  * Check disklabel for errors and fill in
1199  * derived fields according to supplied values.
1200  */
1201 int
1202 checklabel(struct disklabel32 *lp)
1203 {
1204         struct partition32 *pp;
1205         int i, errors = 0;
1206         char part;
1207         u_long total_size, total_percent, current_offset;
1208         int seen_default_offset;
1209         int hog_part;
1210         int j;
1211         struct partition32 *pp2;
1212
1213         if (lp->d_secsize == 0) {
1214                 fprintf(stderr, "sector size 0\n");
1215                 return (1);
1216         }
1217         if (lp->d_nsectors == 0) {
1218                 fprintf(stderr, "sectors/track 0\n");
1219                 return (1);
1220         }
1221         if (lp->d_ntracks == 0) {
1222                 fprintf(stderr, "tracks/cylinder 0\n");
1223                 return (1);
1224         }
1225         if  (lp->d_ncylinders == 0) {
1226                 fprintf(stderr, "cylinders/unit 0\n");
1227                 errors++;
1228         }
1229         if (lp->d_rpm == 0)
1230                 Warning("revolutions/minute 0");
1231         if (lp->d_secpercyl == 0)
1232                 lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks;
1233         if (lp->d_secperunit == 0)
1234                 lp->d_secperunit = lp->d_secpercyl * lp->d_ncylinders;
1235         if (lp->d_bbsize == 0) {
1236                 fprintf(stderr, "boot block size 0\n");
1237                 errors++;
1238         } else if (lp->d_bbsize % lp->d_secsize)
1239                 Warning("boot block size %% sector-size != 0");
1240         if (lp->d_sbsize == 0) {
1241                 fprintf(stderr, "super block size 0\n");
1242                 errors++;
1243         } else if (lp->d_sbsize % lp->d_secsize)
1244                 Warning("super block size %% sector-size != 0");
1245         if (lp->d_npartitions > MAXPARTITIONS32)
1246                 Warning("number of partitions (%lu) > MAXPARTITIONS (%d)",
1247                     (u_long)lp->d_npartitions, MAXPARTITIONS32);
1248
1249         /* first allocate space to the partitions, then offsets */
1250         total_size = 0; /* in sectors */
1251         total_percent = 0; /* in percent */
1252         hog_part = -1;
1253         /* find all fixed partitions */
1254         for (i = 0; i < lp->d_npartitions; i++) {
1255                 pp = &lp->d_partitions[i];
1256                 if (part_set[i]) {
1257                         if (part_size_type[i] == '*') {
1258                                 if (i == RAW_PART) {
1259                                         pp->p_size = lp->d_secperunit;
1260                                 } else {
1261                                         if (hog_part != -1)
1262                                                 Warning("Too many '*' partitions (%c and %c)",
1263                                                     hog_part + 'a',i + 'a');
1264                                         else
1265                                                 hog_part = i;
1266                                 }
1267                         } else {
1268                                 off_t size;
1269
1270                                 size = pp->p_size;
1271                                 switch (part_size_type[i]) {
1272                                 case '%':
1273                                         total_percent += size;
1274                                         break;
1275                                 case 'k':
1276                                 case 'K':
1277                                         size *= 1024ULL;
1278                                         break;
1279                                 case 'm':
1280                                 case 'M':
1281                                         size *= 1024ULL * 1024ULL;
1282                                         break;
1283                                 case 'g':
1284                                 case 'G':
1285                                         size *= 1024ULL * 1024ULL * 1024ULL;
1286                                         break;
1287                                 case '\0':
1288                                         break;
1289                                 default:
1290                                         Warning("unknown size specifier '%c' (K/M/G are valid)",part_size_type[i]);
1291                                         break;
1292                                 }
1293                                 /* don't count %'s yet */
1294                                 if (part_size_type[i] != '%') {
1295                                         /*
1296                                          * for all not in sectors, convert to
1297                                          * sectors
1298                                          */
1299                                         if (part_size_type[i] != '\0') {
1300                                                 if (size % lp->d_secsize != 0)
1301                                                         Warning("partition %c not an integer number of sectors",
1302                                                             i + 'a');
1303                                                 size /= lp->d_secsize;
1304                                                 pp->p_size = size;
1305                                         }
1306                                         /* else already in sectors */
1307                                         if (i != RAW_PART)
1308                                                 total_size += size;
1309                                 }
1310                         }
1311                 }
1312         }
1313         /* handle % partitions - note %'s don't need to add up to 100! */
1314         if (total_percent != 0) {
1315                 long free_space = lp->d_secperunit - total_size;
1316                 if (total_percent > 100) {
1317                         fprintf(stderr,"total percentage %lu is greater than 100\n",
1318                             total_percent);
1319                         errors++;
1320                 }
1321
1322                 if (free_space > 0) {
1323                         for (i = 0; i < lp->d_npartitions; i++) {
1324                                 pp = &lp->d_partitions[i];
1325                                 if (part_set[i] && part_size_type[i] == '%') {
1326                                         /* careful of overflows! and integer roundoff */
1327                                         pp->p_size = ((double)pp->p_size/100) * free_space;
1328                                         total_size += pp->p_size;
1329
1330                                         /* FIX we can lose a sector or so due to roundoff per
1331                                            partition.  A more complex algorithm could avoid that */
1332                                 }
1333                         }
1334                 } else {
1335                         fprintf(stderr,
1336                             "%ld sectors available to give to '*' and '%%' partitions\n",
1337                             free_space);
1338                         errors++;
1339                         /* fix?  set all % partitions to size 0? */
1340                 }
1341         }
1342         /* give anything remaining to the hog partition */
1343         if (hog_part != -1) {
1344                 lp->d_partitions[hog_part].p_size = lp->d_secperunit - total_size;
1345                 total_size = lp->d_secperunit;
1346         }
1347
1348         /* Now set the offsets for each partition */
1349         current_offset = 0; /* in sectors */
1350         seen_default_offset = 0;
1351         for (i = 0; i < lp->d_npartitions; i++) {
1352                 part = 'a' + i;
1353                 pp = &lp->d_partitions[i];
1354                 if (part_set[i]) {
1355                         if (part_offset_type[i] == '*') {
1356                                 if (i == RAW_PART) {
1357                                         pp->p_offset = 0;
1358                                 } else {
1359                                         pp->p_offset = current_offset;
1360                                         seen_default_offset = 1;
1361                                 }
1362                         } else {
1363                                 /* allow them to be out of order for old-style tables */
1364                                 if (pp->p_offset < current_offset && 
1365                                     seen_default_offset && i != RAW_PART &&
1366                                     pp->p_fstype != FS_VINUM) {
1367                                         fprintf(stderr,
1368 "Offset %ld for partition %c overlaps previous partition which ends at %lu\n",
1369                                             (long)pp->p_offset,i+'a',current_offset);
1370                                         fprintf(stderr,
1371 "Labels with any *'s for offset must be in ascending order by sector\n");
1372                                         errors++;
1373                                 } else if (pp->p_offset != current_offset &&
1374                                     i != RAW_PART && seen_default_offset) {
1375                                         /* 
1376                                          * this may give unneeded warnings if 
1377                                          * partitions are out-of-order
1378                                          */
1379                                         Warning(
1380 "Offset %ld for partition %c doesn't match expected value %ld",
1381                                             (long)pp->p_offset, i + 'a', current_offset);
1382                                 }
1383                         }
1384                         if (i != RAW_PART)
1385                                 current_offset = pp->p_offset + pp->p_size; 
1386                 }
1387         }
1388
1389         for (i = 0; i < lp->d_npartitions; i++) {
1390                 part = 'a' + i;
1391                 pp = &lp->d_partitions[i];
1392                 if (pp->p_size == 0 && pp->p_offset != 0)
1393                         Warning("partition %c: size 0, but offset %lu",
1394                             part, (u_long)pp->p_offset);
1395 #ifdef notdef
1396                 if (pp->p_size % lp->d_secpercyl)
1397                         Warning("partition %c: size %% cylinder-size != 0",
1398                             part);
1399                 if (pp->p_offset % lp->d_secpercyl)
1400                         Warning("partition %c: offset %% cylinder-size != 0",
1401                             part);
1402 #endif
1403                 if (pp->p_offset > lp->d_secperunit) {
1404                         fprintf(stderr,
1405                             "partition %c: offset past end of unit\n", part);
1406                         errors++;
1407                 }
1408                 if (pp->p_offset + pp->p_size > lp->d_secperunit) {
1409                         fprintf(stderr,
1410                         "partition %c: partition extends past end of unit\n",
1411                             part);
1412                         errors++;
1413                 }
1414                 if (i == RAW_PART)
1415                 {
1416                         if (pp->p_fstype != FS_UNUSED)
1417                                 Warning("partition %c is not marked as unused!",part);
1418                         if (pp->p_offset != 0)
1419                                 Warning("partition %c doesn't start at 0!",part);
1420                         if (pp->p_size != lp->d_secperunit)
1421                                 Warning("partition %c doesn't cover the whole unit!",part);
1422
1423                         if ((pp->p_fstype != FS_UNUSED) || (pp->p_offset != 0) ||
1424                             (pp->p_size != lp->d_secperunit)) {
1425                                 Warning("An incorrect partition %c may cause problems for "
1426                                     "standard system utilities",part);
1427                         }
1428                 }
1429
1430                 /* check for overlaps */
1431                 /* this will check for all possible overlaps once and only once */
1432                 for (j = 0; j < i; j++) {
1433                         pp2 = &lp->d_partitions[j];
1434                         if (j != RAW_PART && i != RAW_PART &&   
1435                             pp->p_fstype != FS_VINUM &&
1436                             pp2->p_fstype != FS_VINUM &&
1437                             part_set[i] && part_set[j]) {
1438                                 if (pp2->p_offset < pp->p_offset + pp->p_size &&
1439                                     (pp2->p_offset + pp2->p_size > pp->p_offset ||
1440                                         pp2->p_offset >= pp->p_offset)) {
1441                                         fprintf(stderr,"partitions %c and %c overlap!\n",
1442                                             j + 'a', i + 'a');
1443                                         errors++;
1444                                 }
1445                         }
1446                 }
1447         }
1448         for (; i < 8 || i < lp->d_npartitions; i++) {
1449                 part = 'a' + i;
1450                 pp = &lp->d_partitions[i];
1451                 if (pp->p_size || pp->p_offset)
1452                         Warning("unused partition %c: size %d offset %lu",
1453                             'a' + i, pp->p_size, (u_long)pp->p_offset);
1454         }
1455         return (errors);
1456 }
1457
1458 /*
1459  * When operating on a "virgin" disk, try getting an initial label
1460  * from the associated device driver.  This might work for all device
1461  * drivers that are able to fetch some initial device parameters
1462  * without even having access to a (BSD) disklabel, like SCSI disks,
1463  * most IDE drives, or vn devices.
1464  *
1465  * The device name must be given in its "canonical" form.
1466  */
1467 static struct disklabel32 dlab;
1468
1469 struct disklabel32 *
1470 getvirginlabel(void)
1471 {
1472         struct disklabel32 *dl = &dlab;
1473         char nambuf[BBSIZE];
1474         int f;
1475
1476         if (dkname[0] == '/') {
1477                 warnx("\"auto\" requires the usage of a canonical disk name");
1478                 return (NULL);
1479         }
1480         snprintf(nambuf, BBSIZE, "%s%s", _PATH_DEV, dkname);
1481         if ((f = open(nambuf, O_RDONLY)) == -1) {
1482                 warn("cannot open %s", nambuf);
1483                 return (NULL);
1484         }
1485
1486         /*
1487          * Try to use the new get-virgin-label ioctl.  If it fails,
1488          * fallback to the old get-disdk-info ioctl.
1489          */
1490         if (ioctl(f, DIOCGDVIRGIN32, dl) < 0) {
1491                 if (ioctl(f, DIOCGDINFO32, dl) < 0) {
1492                         warn("ioctl DIOCGDINFO");
1493                         close(f);
1494                         return (NULL);
1495                 }
1496         }
1497         close(f);
1498         return (dl);
1499 }
1500
1501 struct disklabel32 *
1502 getdisklabelfromdisktab(const char *name)
1503 {
1504         struct disktab *dt;
1505         struct disklabel32 *dl = &dlab;
1506         int i;
1507
1508         if ((dt = getdisktabbyname(name)) == NULL)
1509                 return(NULL);
1510         dl->d_magic = DISKMAGIC32;
1511         dl->d_type = dt->d_typeid;
1512         dl->d_subtype = 0;
1513         dl->d_secsize = dt->d_media_blksize;
1514         dl->d_nsectors = dt->d_secpertrack;
1515         dl->d_ntracks = dt->d_nheads;
1516         dl->d_ncylinders = dt->d_ncylinders;
1517         dl->d_secpercyl = dt->d_secpercyl;
1518         dl->d_secperunit = dt->d_media_blocks;
1519         dl->d_rpm = dt->d_rpm;
1520         dl->d_interleave = dt->d_interleave;
1521         dl->d_trackskew = dt->d_trackskew;
1522         dl->d_cylskew = dt->d_cylskew;
1523         dl->d_headswitch = dt->d_headswitch;
1524         dl->d_trkseek = dt->d_trkseek;
1525         dl->d_magic2 = DISKMAGIC32;
1526         dl->d_npartitions = dt->d_npartitions;
1527         dl->d_bbsize = dt->d_bbsize;
1528         dl->d_sbsize = dt->d_sbsize;
1529         for (i = 0; i < dt->d_npartitions; ++i) {
1530                 struct partition32 *dlp = &dl->d_partitions[i];
1531                 struct dt_partition *dtp = &dt->d_partitions[i];
1532
1533                 dlp->p_size     = dtp->p_size;
1534                 dlp->p_offset   = dtp->p_offset;
1535                 dlp->p_fsize    = dtp->p_fsize;
1536                 dlp->p_fstype   = dtp->p_fstype;
1537                 dlp->p_frag     = dtp->p_fsize;
1538         }
1539         return(dl);
1540 }
1541
1542 /*
1543  * If we are installing a boot program that doesn't fit in d_bbsize
1544  * we need to mark those partitions that the boot overflows into.
1545  * This allows newfs to prevent creation of a filesystem where it might
1546  * clobber bootstrap code.
1547  */
1548 void
1549 setbootflag(struct disklabel32 *lp)
1550 {
1551         struct partition32 *pp;
1552         int i, errors = 0;
1553         char part;
1554         u_long boffset;
1555
1556         if (bootbuf == 0)
1557                 return;
1558         boffset = bootsize / lp->d_secsize;
1559         for (i = 0; i < lp->d_npartitions; i++) {
1560                 part = 'a' + i;
1561                 pp = &lp->d_partitions[i];
1562                 if (pp->p_size == 0)
1563                         continue;
1564                 if (boffset <= pp->p_offset) {
1565                         if (pp->p_fstype == FS_BOOT)
1566                                 pp->p_fstype = FS_UNUSED;
1567                 } else if (pp->p_fstype != FS_BOOT) {
1568                         if (pp->p_fstype != FS_UNUSED) {
1569                                 fprintf(stderr,
1570                                         "boot overlaps used partition %c\n",
1571                                         part);
1572                                 errors++;
1573                         } else {
1574                                 pp->p_fstype = FS_BOOT;
1575                                 Warning("boot overlaps partition %c, %s",
1576                                         part, "marked as FS_BOOT");
1577                         }
1578                 }
1579         }
1580         if (errors)
1581                 errx(4, "cannot install boot program");
1582 }
1583
1584 /*VARARGS1*/
1585 void
1586 Warning(const char *fmt, ...)
1587 {
1588         va_list ap;
1589
1590         fprintf(stderr, "Warning, ");
1591         va_start(ap, fmt);
1592         vfprintf(stderr, fmt, ap);
1593         fprintf(stderr, "\n");
1594         va_end(ap);
1595 }
1596
1597 /*
1598  * Check to see if the bootblocks are in the wrong place.  FBsd5 bootblocks
1599  * and earlier DFly bb's are packed against the old disklabel and a new
1600  * disklabel would blow them up.  This is a hack that should be removed
1601  * in 2006 sometime (if ever).
1602  */
1603
1604 int
1605 checkoldboot(int f, const char *bootbuffer)
1606 {
1607         char buf[BBSIZE];
1608
1609         if (bootbuffer && strncmp(bootbuffer + 0x402, "BTX", 3) == 0)
1610                 return(0);
1611         lseek(f, (off_t)0, SEEK_SET);
1612         if (read(f, buf, sizeof(buf)) != sizeof(buf))
1613                 return(0);
1614         if (strncmp(buf + 0x402, "BTX", 3) == 0)  /* new location */
1615                 return(0);
1616         if (strncmp(buf + 0x316, "BTX", 3) == 0)  /* old location */
1617                 return(1);
1618         return(0);
1619 }
1620
1621 /*
1622  * Traditional 32 bit disklabels actually use absolute sector numbers on
1623  * disk, NOT slice relative sector numbres.   The OS hides this from us
1624  * when we use DIOC ioctls to access the label, but newer versions of
1625  * Dragonfly no longer adjusts the disklabel when snooping reads or writes
1626  * so we have to figure it out ourselves.
1627  */
1628 const char *
1629 fixlabel(int f, struct disklabel32 *lp, int writeadj)
1630 {
1631         const char *msg = NULL;
1632         struct partinfo info;
1633         struct partition32 *pp;
1634         u_int64_t start;
1635         u_int64_t end;
1636         u_int64_t offset;
1637         int part;
1638         int rev;
1639         int rev_len = sizeof(rev);
1640
1641         if (sysctlbyname("kern.osrevision", &rev, &rev_len, NULL, 0) < 0) {
1642                 errx(1, "Cannot use raw mode on non-DragonFly systems\n");
1643         }
1644         if (rev < 200701) {
1645                 warnx("Warning running new disklabel on old DragonFly systems,\n"
1646                       "assuming the disk layer will fixup the label.\n");
1647                 sleep(3);
1648                 return(NULL);
1649         }
1650
1651         pp = &lp->d_partitions[RAW_PART];
1652
1653         if (forceflag) {
1654                 info.media_offset = slice_start_lba * lp->d_secsize;
1655                 info.media_blocks = pp->p_size;
1656                 info.media_blksize = lp->d_secsize;
1657         } else if (ioctl(f, DIOCGPART, &info) < 0) {
1658                 msg = "Unable to extract the slice starting LBA, "
1659                       "you must use the -f <slice_start_lba> option\n"
1660                       "to specify it manually, or perhaps try without "
1661                       "using -r and let the kernel deal with it\n";
1662                 return(msg);
1663         }
1664
1665         if (lp->d_magic != DISKMAGIC32 || lp->d_magic2 != DISKMAGIC32)
1666                 return ("fixlabel: invalid magic");
1667         if (dkcksum32(lp) != 0)
1668                 return ("fixlabel: invalid checksum");
1669
1670         /*
1671          * What a mess.  For ages old backwards compatibility the disklabel
1672          * on-disk stores absolute offsets instead of slice-relative offsets.
1673          * So fix it up when reading, writing, or snooping.
1674          *
1675          * The in-core label is always slice-relative.
1676          */
1677         if (writeadj) {
1678                 /*
1679                  * incore -> disk
1680                  */
1681                 start = 0;
1682                 offset = info.media_offset / info.media_blksize;
1683         } else {
1684                 /*
1685                  * disk -> incore
1686                  */
1687                 start = info.media_offset / info.media_blksize;
1688                 offset = -info.media_offset / info.media_blksize;
1689         }
1690         if (pp->p_offset != start)
1691                 return ("fixlabel: raw partition offset != slice offset");
1692         if (pp->p_size != info.media_blocks) {
1693                 if (pp->p_size > info.media_blocks)
1694                         return ("fixlabel: raw partition size > slice size");
1695         }
1696         end = start + info.media_blocks;
1697         if (start > end)
1698                 return ("fixlabel: slice wraps");
1699         if (lp->d_secpercyl <= 0)
1700                 return ("fixlabel: d_secpercyl <= 0");
1701         pp -= RAW_PART;
1702         for (part = 0; part < lp->d_npartitions; part++, pp++) {
1703                 if (pp->p_offset != 0 || pp->p_size != 0) {
1704                         if (pp->p_offset < start
1705                             || pp->p_offset + pp->p_size > end
1706                             || pp->p_offset + pp->p_size < pp->p_offset) {
1707                                 /* XXX else silently discard junk. */
1708                                 bzero(pp, sizeof *pp);
1709                         } else {
1710                                 pp->p_offset += offset;
1711                         }
1712                 }
1713         }
1714         lp->d_checksum = 0;
1715         lp->d_checksum = dkcksum32(lp);
1716         return (NULL);
1717 }
1718
1719 void
1720 usage(void)
1721 {
1722 #if NUMBOOT > 0
1723         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",
1724                 "usage: disklabel [-r] disk",
1725                 "\t\t(to read label)",
1726                 "       disklabel -w [-r] [-n] disk type [ packid ]",
1727                 "\t\t(to write label with existing boot program)",
1728                 "       disklabel -e [-r] [-n] disk",
1729                 "\t\t(to edit label)",
1730                 "       disklabel -R [-r] [-n] disk protofile",
1731                 "\t\t(to restore label with existing boot program)",
1732 #if NUMBOOT > 1
1733                 "       disklabel -B [-n] [ -b boot1 [ -s boot2 ] ] disk [ type ]",
1734                 "\t\t(to install boot program with existing label)",
1735                 "       disklabel -w -B [-n] [ -b boot1 [ -s boot2 ] ] disk type [ packid ]",
1736                 "\t\t(to write label and boot program)",
1737                 "       disklabel -R -B [-n] [ -b boot1 [ -s boot2 ] ] disk protofile [ type ]",
1738                 "\t\t(to restore label and boot program)",
1739 #else
1740                 "       disklabel -B [-n] [ -b bootprog ] disk [ type ]",
1741                 "\t\t(to install boot program with existing on-disk label)",
1742                 "       disklabel -w -B [-n] [ -b bootprog ] disk type [ packid ]",
1743                 "\t\t(to write label and install boot program)",
1744                 "       disklabel -R -B [-n] [ -b bootprog ] disk protofile [ type ]",
1745                 "\t\t(to restore label and install boot program)",
1746 #endif
1747                 "       disklabel [-NW] disk",
1748                 "\t\t(to write disable/enable label)");
1749 #else
1750         fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
1751                 "usage: disklabel [-r] disk", "(to read label)",
1752                 "       disklabel -w [-r] [-n] disk type [ packid ]",
1753                 "\t\t(to write label)",
1754                 "       disklabel -e [-r] [-n] disk",
1755                 "\t\t(to edit label)",
1756                 "       disklabel -R [-r] [-n] disk protofile",
1757                 "\t\t(to restore label)",
1758                 "       disklabel [-NW] disk",
1759                 "\t\t(to write disable/enable label)");
1760 #endif
1761         exit(1);
1762 }