Merge from vendor branch GDB:
[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.25 2007/08/08 20:15:50 swildner 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 DIOCSDINFO32");
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 DIOCWDINFO32");
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         case ENOATTR:
485                 warnx("%s: the disk already has a label of a different type,\n"
486                       "probably a 64 bit disklabel.  It must be cleaned out "
487                       "first.\n", s);
488                 break;
489
490         default:
491                 warn((char *)NULL);
492                 break;
493         }
494 }
495
496 /*
497  * Fetch disklabel for disk.
498  * Use ioctl to get label unless -r flag is given.
499  */
500 struct disklabel32 *
501 readlabel(int f)
502 {
503         const char *msg;
504         struct disklabel32 *lp;
505         int r;
506
507         if (rflag) {
508                 r = read(f, bootarea, BBSIZE);
509                 if (r < BBSIZE)
510                         err(4, "%s", specname);
511                 for (lp = (struct disklabel32 *)bootarea;
512                     lp <= (struct disklabel32 *)(bootarea + BBSIZE - sizeof(*lp));
513                     lp = (struct disklabel32 *)((char *)lp + 16)) {
514                         if (lp->d_magic == DISKMAGIC32 &&
515                             lp->d_magic2 == DISKMAGIC32)
516                                 break;
517                 }
518                 if (lp > (struct disklabel32 *)(bootarea+BBSIZE-sizeof(*lp)) ||
519                     lp->d_magic != DISKMAGIC32 || lp->d_magic2 != DISKMAGIC32 ||
520                     dkcksum32(lp) != 0) {
521                         errx(1, "bad pack magic number (label is damaged, "
522                                 "or pack is unlabeled)");
523                 }
524                 if ((msg = fixlabel(f, lp, 0)) != NULL)
525                         errx(1, msg);
526         } else {
527                 lp = &lab;
528                 if (ioctl(f, DIOCGDINFO32, lp) < 0) {
529                         l_perror("ioctl DIOCGDINFO32");
530                         exit(4);
531                 }
532         }
533         return (lp);
534 }
535
536 /*
537  * Construct a bootarea (d_bbsize bytes) in the specified buffer ``boot''
538  * Returns a pointer to the disklabel portion of the bootarea.
539  */
540 struct disklabel32 *
541 makebootarea(char *boot, struct disklabel32 *dp, int f)
542 {
543         struct disklabel32 *lp;
544         char *p;
545         int b;
546 #if NUMBOOT > 0
547         char *dkbasename;
548         struct stat sb;
549 #endif
550 #ifdef __i386__
551         char *tmpbuf;
552         unsigned int i, found;
553 #endif
554
555         /* XXX */
556         if (dp->d_secsize == 0) {
557                 dp->d_secsize = DEV_BSIZE;
558                 dp->d_bbsize = BBSIZE;
559         }
560         lp = (struct disklabel32 *)
561                 (boot + (LABELSECTOR32 * dp->d_secsize) + LABELOFFSET32);
562         bzero((char *)lp, sizeof *lp);
563 #if NUMBOOT > 0
564         /*
565          * If we are not installing a boot program but we are installing a
566          * label on disk then we must read the current bootarea so we don't
567          * clobber the existing boot.
568          */
569         if (!installboot) {
570                 if (rflag) {
571                         if (read(f, boot, BBSIZE) < BBSIZE)
572                                 err(4, "%s", specname);
573                         bzero((char *)lp, sizeof *lp);
574                 }
575                 return (lp);
576         }
577         /*
578          * We are installing a boot program.  Determine the name(s) and
579          * read them into the appropriate places in the boot area.
580          */
581         if (!xxboot || !bootxx) {
582                 dkbasename = np;
583                 if ((p = strrchr(dkname, '/')) == NULL)
584                         p = dkname;
585                 else
586                         p++;
587                 while (*p && !isdigit(*p))
588                         *np++ = *p++;
589                 *np++ = '\0';
590
591                 if (!xxboot) {
592                         sprintf(boot0, "%s/boot1", _PATH_BOOTDIR);
593                         xxboot = boot0;
594                 }
595 #if NUMBOOT > 1
596                 if (!bootxx) {
597                         sprintf(boot1, "%s/boot2", _PATH_BOOTDIR);
598                         bootxx = boot1;
599                 }
600 #endif
601         }
602 #ifdef DEBUG
603         if (debug)
604                 fprintf(stderr, "bootstraps: xxboot = %s, bootxx = %s\n",
605                         xxboot, bootxx ? bootxx : "NONE");
606 #endif
607
608         /*
609          * Strange rules:
610          * 1. One-piece bootstrap (hp300/hp800)
611          *      up to d_bbsize bytes of ``xxboot'' go in bootarea, the rest
612          *      is remembered and written later following the bootarea.
613          * 2. Two-piece bootstraps (vax/i386?/mips?)
614          *      up to d_secsize bytes of ``xxboot'' go in first d_secsize
615          *      bytes of bootarea, remaining d_bbsize-d_secsize filled
616          *      from ``bootxx''.
617          */
618         b = open(xxboot, O_RDONLY);
619         if (b < 0)
620                 err(4, "%s", xxboot);
621 #if NUMBOOT > 1
622 #ifdef __i386__
623         /*
624          * XXX Botch alert.
625          * The i386 has the so-called fdisk table embedded into the
626          * primary bootstrap.  We take care to not clobber it, but
627          * only if it does already contain some data.  (Otherwise,
628          * the xxboot provides a template.)
629          */
630         if ((tmpbuf = (char *)malloc((int)dp->d_secsize)) == 0)
631                 err(4, "%s", xxboot);
632         memcpy((void *)tmpbuf, (void *)boot, (int)dp->d_secsize);
633 #endif /* i386 */
634         if (read(b, boot, (int)dp->d_secsize) < 0)
635                 err(4, "%s", xxboot);
636         close(b);
637 #ifdef __i386__
638         for (i = DOSPARTOFF, found = 0;
639              !found && i < DOSPARTOFF + NDOSPART*sizeof(struct dos_partition);
640              i++)
641                 found = tmpbuf[i] != 0;
642         if (found)
643                 memcpy((void *)&boot[DOSPARTOFF],
644                        (void *)&tmpbuf[DOSPARTOFF],
645                        NDOSPART * sizeof(struct dos_partition));
646         free(tmpbuf);
647 #endif /* i386 */
648         b = open(bootxx, O_RDONLY);
649         if (b < 0)
650                 err(4, "%s", bootxx);
651         if (fstat(b, &sb) != 0)
652                 err(4, "%s", bootxx);
653         if (dp->d_secsize + sb.st_size > dp->d_bbsize)
654                 errx(4, "%s too large", bootxx);
655         if (read(b, &boot[dp->d_secsize],
656                  (int)(dp->d_bbsize-dp->d_secsize)) < 0)
657                 err(4, "%s", bootxx);
658 #else /* !(NUMBOOT > 1) */
659         if (read(b, boot, (int)dp->d_bbsize) < 0)
660                 err(4, "%s", xxboot);
661         if (fstat(b, &sb) != 0)
662                 err(4, "%s", xxboot);
663         bootsize = (int)sb.st_size - dp->d_bbsize;
664         if (bootsize > 0) {
665                 /* XXX assume d_secsize is a power of two */
666                 bootsize = (bootsize + dp->d_secsize-1) & ~(dp->d_secsize-1);
667                 bootbuf = (char *)malloc((size_t)bootsize);
668                 if (bootbuf == 0)
669                         err(4, "%s", xxboot);
670                 if (read(b, bootbuf, bootsize) < 0) {
671                         free(bootbuf);
672                         err(4, "%s", xxboot);
673                 }
674         }
675 #endif /* NUMBOOT > 1 */
676         close(b);
677 #endif /* NUMBOOT > 0 */
678         /*
679          * Make sure no part of the bootstrap is written in the area
680          * reserved for the label.
681          */
682         for (p = (char *)lp; p < (char *)lp + sizeof(struct disklabel32); p++)
683                 if (*p)
684                         errx(2, "bootstrap doesn't leave room for disk label");
685         return (lp);
686 }
687
688 void
689 display(FILE *f, const struct disklabel32 *lp)
690 {
691         int i, j;
692         const struct partition32 *pp;
693
694         fprintf(f, "# %s:\n", specname);
695         if (lp->d_type < DKMAXTYPES)
696                 fprintf(f, "type: %s\n", dktypenames[lp->d_type]);
697         else
698                 fprintf(f, "type: %u\n", lp->d_type);
699         fprintf(f, "disk: %.*s\n", (int)sizeof(lp->d_typename),
700                 lp->d_typename);
701         fprintf(f, "label: %.*s\n", (int)sizeof(lp->d_packname),
702                 lp->d_packname);
703         fprintf(f, "flags:");
704         fprintf(f, "\n");
705         fprintf(f, "bytes/sector: %lu\n", (u_long)lp->d_secsize);
706         fprintf(f, "sectors/track: %lu\n", (u_long)lp->d_nsectors);
707         fprintf(f, "tracks/cylinder: %lu\n", (u_long)lp->d_ntracks);
708         fprintf(f, "sectors/cylinder: %lu\n", (u_long)lp->d_secpercyl);
709         fprintf(f, "cylinders: %lu\n", (u_long)lp->d_ncylinders);
710         fprintf(f, "sectors/unit: %lu\n", (u_long)lp->d_secperunit);
711         fprintf(f, "rpm: %u\n", lp->d_rpm);
712         fprintf(f, "interleave: %u\n", lp->d_interleave);
713         fprintf(f, "trackskew: %u\n", lp->d_trackskew);
714         fprintf(f, "cylinderskew: %u\n", lp->d_cylskew);
715         fprintf(f, "headswitch: %lu\t\t# milliseconds\n",
716             (u_long)lp->d_headswitch);
717         fprintf(f, "track-to-track seek: %ld\t# milliseconds\n",
718             (u_long)lp->d_trkseek);
719         fprintf(f, "drivedata: ");
720         for (i = NDDATA32 - 1; i >= 0; i--) {
721                 if (lp->d_drivedata[i])
722                         break;
723         }
724         if (i < 0)
725                 i = 0;
726         for (j = 0; j <= i; j++)
727                 fprintf(f, "%lu ", (u_long)lp->d_drivedata[j]);
728         fprintf(f, "\n\n%u partitions:\n", lp->d_npartitions);
729         fprintf(f,
730             "#          size     offset    fstype\n");
731         pp = lp->d_partitions;
732         for (i = 0; i < lp->d_npartitions; i++, pp++) {
733                 if (pp->p_size) {
734                         u_long onemeg = 1024 * 1024 / lp->d_secsize;
735                         fprintf(f, "  %c: ", 'a' + i);
736
737                         fprintf(f, "%10lu ", (u_long)pp->p_size);
738                         fprintf(f, "%10lu  ", (u_long)pp->p_offset);
739                         if (pp->p_fstype < FSMAXTYPES)
740                                 fprintf(f, "%8.8s", fstypenames[pp->p_fstype]);
741                         else
742                                 fprintf(f, "%8d", pp->p_fstype);
743
744                         fprintf(f, "\t# %11.3fM", (double)pp->p_size / onemeg);
745                         fprintf(f, "\n");
746                 }
747         }
748         fflush(f);
749 }
750
751 int
752 edit(struct disklabel32 *lp, int f)
753 {
754         int c, fd;
755         struct disklabel32 label;
756         FILE *fp;
757
758         if ((fd = mkstemp(tmpfil)) == -1 ||
759             (fp = fdopen(fd, "w")) == NULL) {
760                 warnx("can't create %s", tmpfil);
761                 return (1);
762         }
763         display(fp, lp);
764         fclose(fp);
765         for (;;) {
766                 if (!editit())
767                         break;
768                 fp = fopen(tmpfil, "r");
769                 if (fp == NULL) {
770                         warnx("can't reopen %s for reading", tmpfil);
771                         break;
772                 }
773                 bzero((char *)&label, sizeof(label));
774                 if (getasciilabel(fp, &label)) {
775                         *lp = label;
776                         if (writelabel(f, bootarea, lp) == 0) {
777                                 fclose(fp);
778                                 unlink(tmpfil);
779                                 return (0);
780                         }
781                 }
782                 fclose(fp);
783                 printf("re-edit the label? [y]: "); fflush(stdout);
784                 c = getchar();
785                 if (c != EOF && c != (int)'\n')
786                         while (getchar() != (int)'\n')
787                                 ;
788                 if  (c == (int)'n')
789                         break;
790         }
791         unlink(tmpfil);
792         return (1);
793 }
794
795 int
796 editit(void)
797 {
798         int pid, xpid;
799         int status, omask;
800         const char *ed;
801
802         omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP));
803         while ((pid = fork()) < 0) {
804                 if (errno == EPROCLIM) {
805                         warnx("you have too many processes");
806                         return(0);
807                 }
808                 if (errno != EAGAIN) {
809                         warn("fork");
810                         return(0);
811                 }
812                 sleep(1);
813         }
814         if (pid == 0) {
815                 sigsetmask(omask);
816                 setgid(getgid());
817                 setuid(getuid());
818                 if ((ed = getenv("EDITOR")) == (char *)0)
819                         ed = DEFEDITOR;
820                 execlp(ed, ed, tmpfil, (char *)0);
821                 err(1, "%s", ed);
822         }
823         while ((xpid = wait(&status)) >= 0)
824                 if (xpid == pid)
825                         break;
826         sigsetmask(omask);
827         return(!status);
828 }
829
830 char *
831 skip(char *cp)
832 {
833
834         while (*cp != '\0' && isspace(*cp))
835                 cp++;
836         if (*cp == '\0' || *cp == '#')
837                 return (NULL);
838         return (cp);
839 }
840
841 char *
842 word(char *cp)
843 {
844         char c;
845
846         while (*cp != '\0' && !isspace(*cp) && *cp != '#')
847                 cp++;
848         if ((c = *cp) != '\0') {
849                 *cp++ = '\0';
850                 if (c != '#')
851                         return (skip(cp));
852         }
853         return (NULL);
854 }
855
856 /*
857  * Read an ascii label in from fd f,
858  * in the same format as that put out by display(),
859  * and fill in lp.
860  */
861 int
862 getasciilabel(FILE *f, struct disklabel32 *lp)
863 {
864         char *cp;
865         const char **cpp;
866         u_int part;
867         char *tp, line[BUFSIZ];
868         u_long v;
869         int lineno = 0, errors = 0;
870         int i;
871         char empty[] = "";
872         char unknown[] = "unknown";
873
874         bzero(&part_set, sizeof(part_set));
875         bzero(&part_size_type, sizeof(part_size_type));
876         bzero(&part_offset_type, sizeof(part_offset_type));
877         lp->d_bbsize = BBSIZE;                          /* XXX */
878         lp->d_sbsize = SBSIZE;                          /* XXX */
879         while (fgets(line, sizeof(line) - 1, f)) {
880                 lineno++;
881                 if ((cp = strchr(line,'\n')) != 0)
882                         *cp = '\0';
883                 cp = skip(line);
884                 if (cp == NULL)
885                         continue;
886                 tp = strchr(cp, ':');
887                 if (tp == NULL) {
888                         fprintf(stderr, "line %d: syntax error\n", lineno);
889                         errors++;
890                         continue;
891                 }
892                 *tp++ = '\0', tp = skip(tp);
893                 if (streq(cp, "type")) {
894                         if (tp == NULL)
895                                 tp = unknown;
896                         cpp = dktypenames;
897                         for (; cpp < &dktypenames[DKMAXTYPES]; cpp++) {
898                                 if (*cpp && streq(*cpp, tp)) {
899                                         lp->d_type = cpp - dktypenames;
900                                         break;
901                                 }
902                         }
903                         if (cpp < &dktypenames[DKMAXTYPES])
904                                 continue;
905                         v = strtoul(tp, NULL, 10);
906                         if (v >= DKMAXTYPES) {
907                                 fprintf(stderr, "line %d:%s %lu\n", lineno,
908                                     "Warning, unknown disk type", v);
909                         }
910                         lp->d_type = v;
911                         continue;
912                 }
913                 if (streq(cp, "flags")) {
914                         for (v = 0; (cp = tp) && *cp != '\0';) {
915                                 tp = word(cp);
916                                 if (streq(cp, "removeable"))
917                                         v |= 0; /* obsolete */
918                                 else if (streq(cp, "ecc"))
919                                         v |= 0; /* obsolete */
920                                 else if (streq(cp, "badsect"))
921                                         v |= 0; /* obsolete */
922                                 else {
923                                         fprintf(stderr,
924                                             "line %d: %s: bad flag\n",
925                                             lineno, cp);
926                                         errors++;
927                                 }
928                         }
929                         lp->d_flags = v;
930                         continue;
931                 }
932                 if (streq(cp, "drivedata")) {
933                         for (i = 0; (cp = tp) && *cp != '\0' && i < NDDATA32;) {
934                                 lp->d_drivedata[i++] = strtoul(cp, NULL, 10);
935                                 tp = word(cp);
936                         }
937                         continue;
938                 }
939                 if (sscanf(cp, "%lu partitions", &v) == 1) {
940                         if (v == 0 || v > MAXPARTITIONS32) {
941                                 fprintf(stderr,
942                                     "line %d: bad # of partitions\n", lineno);
943                                 lp->d_npartitions = MAXPARTITIONS32;
944                                 errors++;
945                         } else
946                                 lp->d_npartitions = v;
947                         continue;
948                 }
949                 if (tp == NULL)
950                         tp = empty;
951                 if (streq(cp, "disk")) {
952                         strncpy(lp->d_typename, tp, sizeof (lp->d_typename));
953                         continue;
954                 }
955                 if (streq(cp, "label")) {
956                         strncpy(lp->d_packname, tp, sizeof (lp->d_packname));
957                         continue;
958                 }
959                 if (streq(cp, "bytes/sector")) {
960                         v = strtoul(tp, NULL, 10);
961                         if (v == 0 || (v % DEV_BSIZE) != 0) {
962                                 fprintf(stderr,
963                                     "line %d: %s: bad sector size\n",
964                                     lineno, tp);
965                                 errors++;
966                         } else
967                                 lp->d_secsize = v;
968                         continue;
969                 }
970                 if (streq(cp, "sectors/track")) {
971                         v = strtoul(tp, NULL, 10);
972 #if (ULONG_MAX != 0xffffffffUL)
973                         if (v == 0 || v > 0xffffffff) {
974 #else
975                         if (v == 0) {
976 #endif
977                                 fprintf(stderr, "line %d: %s: bad %s\n",
978                                     lineno, tp, cp);
979                                 errors++;
980                         } else
981                                 lp->d_nsectors = v;
982                         continue;
983                 }
984                 if (streq(cp, "sectors/cylinder")) {
985                         v = strtoul(tp, NULL, 10);
986                         if (v == 0) {
987                                 fprintf(stderr, "line %d: %s: bad %s\n",
988                                     lineno, tp, cp);
989                                 errors++;
990                         } else
991                                 lp->d_secpercyl = v;
992                         continue;
993                 }
994                 if (streq(cp, "tracks/cylinder")) {
995                         v = strtoul(tp, NULL, 10);
996                         if (v == 0) {
997                                 fprintf(stderr, "line %d: %s: bad %s\n",
998                                     lineno, tp, cp);
999                                 errors++;
1000                         } else
1001                                 lp->d_ntracks = v;
1002                         continue;
1003                 }
1004                 if (streq(cp, "cylinders")) {
1005                         v = strtoul(tp, NULL, 10);
1006                         if (v == 0) {
1007                                 fprintf(stderr, "line %d: %s: bad %s\n",
1008                                     lineno, tp, cp);
1009                                 errors++;
1010                         } else
1011                                 lp->d_ncylinders = v;
1012                         continue;
1013                 }
1014                 if (streq(cp, "sectors/unit")) {
1015                         v = strtoul(tp, NULL, 10);
1016                         if (v == 0) {
1017                                 fprintf(stderr, "line %d: %s: bad %s\n",
1018                                     lineno, tp, cp);
1019                                 errors++;
1020                         } else
1021                                 lp->d_secperunit = v;
1022                         continue;
1023                 }
1024                 if (streq(cp, "rpm")) {
1025                         v = strtoul(tp, NULL, 10);
1026                         if (v == 0 || v > USHRT_MAX) {
1027                                 fprintf(stderr, "line %d: %s: bad %s\n",
1028                                     lineno, tp, cp);
1029                                 errors++;
1030                         } else
1031                                 lp->d_rpm = v;
1032                         continue;
1033                 }
1034                 if (streq(cp, "interleave")) {
1035                         v = strtoul(tp, NULL, 10);
1036                         if (v == 0 || v > USHRT_MAX) {
1037                                 fprintf(stderr, "line %d: %s: bad %s\n",
1038                                     lineno, tp, cp);
1039                                 errors++;
1040                         } else
1041                                 lp->d_interleave = v;
1042                         continue;
1043                 }
1044                 if (streq(cp, "trackskew")) {
1045                         v = strtoul(tp, NULL, 10);
1046                         if (v > USHRT_MAX) {
1047                                 fprintf(stderr, "line %d: %s: bad %s\n",
1048                                     lineno, tp, cp);
1049                                 errors++;
1050                         } else
1051                                 lp->d_trackskew = v;
1052                         continue;
1053                 }
1054                 if (streq(cp, "cylinderskew")) {
1055                         v = strtoul(tp, NULL, 10);
1056                         if (v > USHRT_MAX) {
1057                                 fprintf(stderr, "line %d: %s: bad %s\n",
1058                                     lineno, tp, cp);
1059                                 errors++;
1060                         } else
1061                                 lp->d_cylskew = v;
1062                         continue;
1063                 }
1064                 if (streq(cp, "headswitch")) {
1065                         v = strtoul(tp, NULL, 10);
1066                         lp->d_headswitch = v;
1067                         continue;
1068                 }
1069                 if (streq(cp, "track-to-track seek")) {
1070                         v = strtoul(tp, NULL, 10);
1071                         lp->d_trkseek = v;
1072                         continue;
1073                 }
1074                 /* the ':' was removed above */
1075                 if (*cp < 'a' || *cp > MAX_PART || cp[1] != '\0') {
1076                         fprintf(stderr,
1077                             "line %d: %s: Unknown disklabel field\n", lineno,
1078                             cp);
1079                         errors++;
1080                         continue;
1081                 }
1082
1083                 /* Process a partition specification line. */
1084                 part = *cp - 'a';
1085                 if (part >= lp->d_npartitions) {
1086                         fprintf(stderr,
1087                             "line %d: partition name out of range a-%c: %s\n",
1088                             lineno, 'a' + lp->d_npartitions - 1, cp);
1089                         errors++;
1090                         continue;
1091                 }
1092                 part_set[part] = 1;
1093
1094                 if (getasciipartspec(tp, lp, part, lineno) != 0) {
1095                         errors++;
1096                         break;
1097                 }
1098         }
1099         errors += checklabel(lp);
1100         return (errors == 0);
1101 }
1102
1103 #define NXTNUM(n) do { \
1104         if (tp == NULL) { \
1105                 fprintf(stderr, "line %d: too few numeric fields\n", lineno); \
1106                 return (1); \
1107         } else { \
1108                 cp = tp, tp = word(cp); \
1109                 (n) = strtoul(cp, NULL, 10); \
1110         } \
1111 } while (0)
1112
1113 /* retain 1 character following number */
1114 #define NXTWORD(w,n) do { \
1115         if (tp == NULL) { \
1116                 fprintf(stderr, "line %d: too few numeric fields\n", lineno); \
1117                 return (1); \
1118         } else { \
1119                 char *tmp; \
1120                 cp = tp, tp = word(cp); \
1121                 (n) = strtoul(cp, &tmp, 10); \
1122                 if (tmp) (w) = *tmp; \
1123         } \
1124 } while (0)
1125
1126 /*
1127  * Read a partition line into partition `part' in the specified disklabel.
1128  * Return 0 on success, 1 on failure.
1129  */
1130 int
1131 getasciipartspec(char *tp, struct disklabel32 *lp, int part, int lineno)
1132 {
1133         struct partition32 *pp;
1134         char *cp;
1135         const char **cpp;
1136         u_long v;
1137
1138         pp = &lp->d_partitions[part];
1139         cp = NULL;
1140
1141         /*
1142          * size
1143          */
1144         v = 0;
1145         NXTWORD(part_size_type[part],v);
1146         if (v == 0 && part_size_type[part] != '*') {
1147                 fprintf(stderr,
1148                     "line %d: %s: bad partition size\n", lineno, cp);
1149                 return (1);
1150         }
1151         pp->p_size = v;
1152
1153         /*
1154          * offset
1155          */
1156         v = 0;
1157         NXTWORD(part_offset_type[part],v);
1158         if (v == 0 && part_offset_type[part] != '*' &&
1159             part_offset_type[part] != '\0') {
1160                 fprintf(stderr,
1161                     "line %d: %s: bad partition offset\n", lineno, cp);
1162                 return (1);
1163         }
1164         pp->p_offset = v;
1165
1166         /*
1167          * fstype
1168          */
1169         cp = tp;
1170         tp = word(cp);
1171         for (cpp = fstypenames; cpp < &fstypenames[FSMAXTYPES]; cpp++)
1172                 if (*cpp && streq(*cpp, cp))
1173                         break;
1174         if (*cpp != NULL) {
1175                 pp->p_fstype = cpp - fstypenames;
1176         } else {
1177                 if (isdigit(*cp))
1178                         v = strtoul(cp, NULL, 10);
1179                 else
1180                         v = FSMAXTYPES;
1181                 if (v >= FSMAXTYPES) {
1182                         fprintf(stderr,
1183                             "line %d: Warning, unknown filesystem type %s\n",
1184                             lineno, cp);
1185                         v = FS_UNUSED;
1186                 }
1187                 pp->p_fstype = v;
1188         }
1189
1190         pp->p_fsize = 0;
1191         pp->p_frag = 0;
1192         pp->p_cpg = 0;
1193
1194         cp = tp;
1195         if (tp) {
1196                 fprintf(stderr, "line %d: Warning, fragment, block, "
1197                                 "and bps/cpg fields are no\n"
1198                                 "longer supported and must be specified "
1199                                 "via newfs options instead.\n",
1200                         lineno);
1201         }
1202         return(0);
1203 }
1204
1205 /*
1206  * Check disklabel for errors and fill in
1207  * derived fields according to supplied values.
1208  */
1209 int
1210 checklabel(struct disklabel32 *lp)
1211 {
1212         struct partition32 *pp;
1213         int i, errors = 0;
1214         char part;
1215         u_long total_size, total_percent, current_offset;
1216         int seen_default_offset;
1217         int hog_part;
1218         int j;
1219         struct partition32 *pp2;
1220
1221         if (lp->d_secsize == 0) {
1222                 fprintf(stderr, "sector size 0\n");
1223                 return (1);
1224         }
1225         if (lp->d_nsectors == 0) {
1226                 fprintf(stderr, "sectors/track 0\n");
1227                 return (1);
1228         }
1229         if (lp->d_ntracks == 0) {
1230                 fprintf(stderr, "tracks/cylinder 0\n");
1231                 return (1);
1232         }
1233         if  (lp->d_ncylinders == 0) {
1234                 fprintf(stderr, "cylinders/unit 0\n");
1235                 errors++;
1236         }
1237         if (lp->d_rpm == 0)
1238                 Warning("revolutions/minute 0");
1239         if (lp->d_secpercyl == 0)
1240                 lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks;
1241         if (lp->d_secperunit == 0)
1242                 lp->d_secperunit = lp->d_secpercyl * lp->d_ncylinders;
1243         if (lp->d_bbsize == 0) {
1244                 fprintf(stderr, "boot block size 0\n");
1245                 errors++;
1246         } else if (lp->d_bbsize % lp->d_secsize)
1247                 Warning("boot block size %% sector-size != 0");
1248         if (lp->d_sbsize == 0) {
1249                 fprintf(stderr, "super block size 0\n");
1250                 errors++;
1251         } else if (lp->d_sbsize % lp->d_secsize)
1252                 Warning("super block size %% sector-size != 0");
1253         if (lp->d_npartitions > MAXPARTITIONS32)
1254                 Warning("number of partitions (%lu) > MAXPARTITIONS (%d)",
1255                     (u_long)lp->d_npartitions, MAXPARTITIONS32);
1256
1257         /* first allocate space to the partitions, then offsets */
1258         total_size = 0; /* in sectors */
1259         total_percent = 0; /* in percent */
1260         hog_part = -1;
1261         /* find all fixed partitions */
1262         for (i = 0; i < lp->d_npartitions; i++) {
1263                 pp = &lp->d_partitions[i];
1264                 if (part_set[i]) {
1265
1266                         if (part_size_type[i] == '*') {
1267                                 if (i == RAW_PART) {
1268                                         pp->p_size = lp->d_secperunit;
1269                                 } else {
1270                                         if (part_offset_type[i] != '*') {
1271                                                 if (total_size < pp->p_offset)
1272                                                         total_size = pp->p_offset;
1273                                         }
1274                                         if (hog_part != -1)
1275                                                 Warning("Too many '*' partitions (%c and %c)",
1276                                                     hog_part + 'a',i + 'a');
1277                                         else
1278                                                 hog_part = i;
1279                                 }
1280                         } else {
1281                                 off_t size;
1282
1283                                 size = pp->p_size;
1284                                 switch (part_size_type[i]) {
1285                                 case '%':
1286                                         total_percent += size;
1287                                         break;
1288                                 case 'k':
1289                                 case 'K':
1290                                         size *= 1024ULL;
1291                                         break;
1292                                 case 'm':
1293                                 case 'M':
1294                                         size *= 1024ULL * 1024ULL;
1295                                         break;
1296                                 case 'g':
1297                                 case 'G':
1298                                         size *= 1024ULL * 1024ULL * 1024ULL;
1299                                         break;
1300                                 case '\0':
1301                                         break;
1302                                 default:
1303                                         Warning("unknown size specifier '%c' (K/M/G are valid)",part_size_type[i]);
1304                                         break;
1305                                 }
1306                                 /* don't count %'s yet */
1307                                 if (part_size_type[i] != '%') {
1308                                         /*
1309                                          * for all not in sectors, convert to
1310                                          * sectors
1311                                          */
1312                                         if (part_size_type[i] != '\0') {
1313                                                 if (size % lp->d_secsize != 0)
1314                                                         Warning("partition %c not an integer number of sectors",
1315                                                             i + 'a');
1316                                                 size /= lp->d_secsize;
1317                                                 pp->p_size = size;
1318                                         }
1319                                         /* else already in sectors */
1320                                         if (i != RAW_PART)
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                 long free_space = lp->d_secperunit - total_size;
1329                 if (total_percent > 100) {
1330                         fprintf(stderr,"total percentage %lu is greater than 100\n",
1331                             total_percent);
1332                         errors++;
1333                 }
1334
1335                 if (free_space > 0) {
1336                         for (i = 0; i < lp->d_npartitions; i++) {
1337                                 pp = &lp->d_partitions[i];
1338                                 if (part_set[i] && part_size_type[i] == '%') {
1339                                         /* careful of overflows! and integer roundoff */
1340                                         pp->p_size = ((double)pp->p_size/100) * free_space;
1341                                         total_size += pp->p_size;
1342
1343                                         /* FIX we can lose a sector or so due to roundoff per
1344                                            partition.  A more complex algorithm could avoid that */
1345                                 }
1346                         }
1347                 } else {
1348                         fprintf(stderr,
1349                             "%ld sectors available to give to '*' and '%%' partitions\n",
1350                             free_space);
1351                         errors++;
1352                         /* fix?  set all % partitions to size 0? */
1353                 }
1354         }
1355         /* give anything remaining to the hog partition */
1356         if (hog_part != -1) {
1357                 lp->d_partitions[hog_part].p_size = lp->d_secperunit - total_size;
1358                 total_size = lp->d_secperunit;
1359         }
1360
1361         /* Now set the offsets for each partition */
1362         current_offset = 0; /* in sectors */
1363         seen_default_offset = 0;
1364         for (i = 0; i < lp->d_npartitions; i++) {
1365                 part = 'a' + i;
1366                 pp = &lp->d_partitions[i];
1367                 if (part_set[i]) {
1368                         if (part_offset_type[i] == '*') {
1369                                 if (i == RAW_PART) {
1370                                         pp->p_offset = 0;
1371                                 } else {
1372                                         pp->p_offset = current_offset;
1373                                         seen_default_offset = 1;
1374                                 }
1375                         } else {
1376                                 /* allow them to be out of order for old-style tables */
1377                                 if (pp->p_offset < current_offset && 
1378                                     seen_default_offset && i != RAW_PART &&
1379                                     pp->p_fstype != FS_VINUM) {
1380                                         fprintf(stderr,
1381 "Offset %ld for partition %c overlaps previous partition which ends at %lu\n",
1382                                             (long)pp->p_offset,i+'a',current_offset);
1383                                         fprintf(stderr,
1384 "Labels with any *'s for offset must be in ascending order by sector\n");
1385                                         errors++;
1386                                 } else if (pp->p_offset != current_offset &&
1387                                     i != RAW_PART && seen_default_offset) {
1388                                         /* 
1389                                          * this may give unneeded warnings if 
1390                                          * partitions are out-of-order
1391                                          */
1392                                         Warning(
1393 "Offset %ld for partition %c doesn't match expected value %ld",
1394                                             (long)pp->p_offset, i + 'a', current_offset);
1395                                 }
1396                         }
1397                         if (i != RAW_PART)
1398                                 current_offset = pp->p_offset + pp->p_size; 
1399                 }
1400         }
1401
1402         for (i = 0; i < lp->d_npartitions; i++) {
1403                 part = 'a' + i;
1404                 pp = &lp->d_partitions[i];
1405                 if (pp->p_size == 0 && pp->p_offset != 0)
1406                         Warning("partition %c: size 0, but offset %lu",
1407                             part, (u_long)pp->p_offset);
1408 #ifdef notdef
1409                 if (pp->p_size % lp->d_secpercyl)
1410                         Warning("partition %c: size %% cylinder-size != 0",
1411                             part);
1412                 if (pp->p_offset % lp->d_secpercyl)
1413                         Warning("partition %c: offset %% cylinder-size != 0",
1414                             part);
1415 #endif
1416                 if (pp->p_offset > lp->d_secperunit) {
1417                         fprintf(stderr,
1418                             "partition %c: offset past end of unit\n", part);
1419                         errors++;
1420                 }
1421                 if (pp->p_offset + pp->p_size > lp->d_secperunit) {
1422                         fprintf(stderr,
1423                         "partition %c: partition extends past end of unit\n",
1424                             part);
1425                         errors++;
1426                 }
1427                 if (i == RAW_PART)
1428                 {
1429                         if (pp->p_fstype != FS_UNUSED)
1430                                 Warning("partition %c is not marked as unused!",part);
1431                         if (pp->p_offset != 0)
1432                                 Warning("partition %c doesn't start at 0!",part);
1433                         if (pp->p_size != lp->d_secperunit)
1434                                 Warning("partition %c doesn't cover the whole unit!",part);
1435
1436                         if ((pp->p_fstype != FS_UNUSED) || (pp->p_offset != 0) ||
1437                             (pp->p_size != lp->d_secperunit)) {
1438                                 Warning("An incorrect partition %c may cause problems for "
1439                                     "standard system utilities",part);
1440                         }
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 (j != RAW_PART && i != RAW_PART &&   
1448                             pp->p_fstype != FS_VINUM &&
1449                             pp2->p_fstype != FS_VINUM &&
1450                             part_set[i] && part_set[j]) {
1451                                 if (pp2->p_offset < pp->p_offset + pp->p_size &&
1452                                     (pp2->p_offset + pp2->p_size > pp->p_offset ||
1453                                         pp2->p_offset >= pp->p_offset)) {
1454                                         fprintf(stderr,"partitions %c and %c overlap!\n",
1455                                             j + 'a', i + 'a');
1456                                         errors++;
1457                                 }
1458                         }
1459                 }
1460         }
1461         for (; i < 8 || i < lp->d_npartitions; i++) {
1462                 part = 'a' + i;
1463                 pp = &lp->d_partitions[i];
1464                 if (pp->p_size || pp->p_offset)
1465                         Warning("unused partition %c: size %d offset %lu",
1466                             'a' + i, pp->p_size, (u_long)pp->p_offset);
1467         }
1468         return (errors);
1469 }
1470
1471 /*
1472  * When operating on a "virgin" disk, try getting an initial label
1473  * from the associated device driver.  This might work for all device
1474  * drivers that are able to fetch some initial device parameters
1475  * without even having access to a (BSD) disklabel, like SCSI disks,
1476  * most IDE drives, or vn devices.
1477  *
1478  * The device name must be given in its "canonical" form.
1479  */
1480 static struct disklabel32 dlab;
1481
1482 struct disklabel32 *
1483 getvirginlabel(void)
1484 {
1485         struct partinfo info;
1486         struct disklabel32 *dl = &dlab;
1487         char nambuf[BBSIZE];
1488         int f;
1489
1490         if (dkname[0] == '/') {
1491                 warnx("\"auto\" requires the usage of a canonical disk name");
1492                 return (NULL);
1493         }
1494         snprintf(nambuf, BBSIZE, "%s%s", _PATH_DEV, dkname);
1495         if ((f = open(nambuf, O_RDONLY)) == -1) {
1496                 warn("cannot open %s", nambuf);
1497                 return (NULL);
1498         }
1499
1500         /*
1501          * Check to see if the media is too big for a 32 bit disklabel.
1502          */
1503         if (ioctl(f, DIOCGPART, &info) == 0) {
1504                  if (info.media_size >= 0x100000000ULL * 512) {
1505                         warnx("The media is too large for a 32 bit disklabel");
1506                         return (NULL);
1507                  }
1508         }
1509
1510         /*
1511          * Generate a virgin disklabel via ioctl
1512          */
1513         if (ioctl(f, DIOCGDVIRGIN32, dl) < 0) {
1514                 l_perror("ioctl DIOCGDVIRGIN32");
1515                 close(f);
1516                 return(NULL);
1517         }
1518         close(f);
1519         return (dl);
1520 }
1521
1522 struct disklabel32 *
1523 getdisklabelfromdisktab(const char *name)
1524 {
1525         struct disktab *dt;
1526         struct disklabel32 *dl = &dlab;
1527         int i;
1528
1529         if ((dt = getdisktabbyname(name)) == NULL)
1530                 return(NULL);
1531         dl->d_magic = DISKMAGIC32;
1532         dl->d_type = dt->d_typeid;
1533         dl->d_subtype = 0;
1534         dl->d_secsize = dt->d_media_blksize;
1535         dl->d_nsectors = dt->d_secpertrack;
1536         dl->d_ntracks = dt->d_nheads;
1537         dl->d_ncylinders = dt->d_ncylinders;
1538         dl->d_secpercyl = dt->d_secpercyl;
1539         dl->d_secperunit = dt->d_media_blocks;
1540         dl->d_rpm = dt->d_rpm;
1541         dl->d_interleave = dt->d_interleave;
1542         dl->d_trackskew = dt->d_trackskew;
1543         dl->d_cylskew = dt->d_cylskew;
1544         dl->d_headswitch = dt->d_headswitch;
1545         dl->d_trkseek = dt->d_trkseek;
1546         dl->d_magic2 = DISKMAGIC32;
1547         dl->d_npartitions = dt->d_npartitions;
1548         dl->d_bbsize = dt->d_bbsize;
1549         dl->d_sbsize = dt->d_sbsize;
1550         for (i = 0; i < dt->d_npartitions; ++i) {
1551                 struct partition32 *dlp = &dl->d_partitions[i];
1552                 struct dt_partition *dtp = &dt->d_partitions[i];
1553
1554                 dlp->p_size     = dtp->p_size;
1555                 dlp->p_offset   = dtp->p_offset;
1556                 dlp->p_fsize    = dtp->p_fsize;
1557                 dlp->p_fstype   = dtp->p_fstype;
1558                 dlp->p_frag     = dtp->p_fsize;
1559         }
1560         return(dl);
1561 }
1562
1563 /*
1564  * If we are installing a boot program that doesn't fit in d_bbsize
1565  * we need to mark those partitions that the boot overflows into.
1566  * This allows newfs to prevent creation of a filesystem where it might
1567  * clobber bootstrap code.
1568  */
1569 void
1570 setbootflag(struct disklabel32 *lp)
1571 {
1572         struct partition32 *pp;
1573         int i, errors = 0;
1574         char part;
1575         u_long boffset;
1576
1577         if (bootbuf == 0)
1578                 return;
1579         boffset = bootsize / lp->d_secsize;
1580         for (i = 0; i < lp->d_npartitions; i++) {
1581                 part = 'a' + i;
1582                 pp = &lp->d_partitions[i];
1583                 if (pp->p_size == 0)
1584                         continue;
1585                 if (boffset <= pp->p_offset) {
1586                         if (pp->p_fstype == FS_BOOT)
1587                                 pp->p_fstype = FS_UNUSED;
1588                 } else if (pp->p_fstype != FS_BOOT) {
1589                         if (pp->p_fstype != FS_UNUSED) {
1590                                 fprintf(stderr,
1591                                         "boot overlaps used partition %c\n",
1592                                         part);
1593                                 errors++;
1594                         } else {
1595                                 pp->p_fstype = FS_BOOT;
1596                                 Warning("boot overlaps partition %c, %s",
1597                                         part, "marked as FS_BOOT");
1598                         }
1599                 }
1600         }
1601         if (errors)
1602                 errx(4, "cannot install boot program");
1603 }
1604
1605 /*VARARGS1*/
1606 void
1607 Warning(const char *fmt, ...)
1608 {
1609         va_list ap;
1610
1611         fprintf(stderr, "Warning, ");
1612         va_start(ap, fmt);
1613         vfprintf(stderr, fmt, ap);
1614         fprintf(stderr, "\n");
1615         va_end(ap);
1616 }
1617
1618 /*
1619  * Check to see if the bootblocks are in the wrong place.  FBsd5 bootblocks
1620  * and earlier DFly bb's are packed against the old disklabel and a new
1621  * disklabel would blow them up.  This is a hack that should be removed
1622  * in 2006 sometime (if ever).
1623  */
1624
1625 int
1626 checkoldboot(int f, const char *bootbuffer)
1627 {
1628         char buf[BBSIZE];
1629
1630         if (bootbuffer && strncmp(bootbuffer + 0x402, "BTX", 3) == 0)
1631                 return(0);
1632         lseek(f, (off_t)0, SEEK_SET);
1633         if (read(f, buf, sizeof(buf)) != sizeof(buf))
1634                 return(0);
1635         if (strncmp(buf + 0x402, "BTX", 3) == 0)  /* new location */
1636                 return(0);
1637         if (strncmp(buf + 0x316, "BTX", 3) == 0)  /* old location */
1638                 return(1);
1639         return(0);
1640 }
1641
1642 /*
1643  * Traditional 32 bit disklabels actually use absolute sector numbers on
1644  * disk, NOT slice relative sector numbres.   The OS hides this from us
1645  * when we use DIOC ioctls to access the label, but newer versions of
1646  * Dragonfly no longer adjusts the disklabel when snooping reads or writes
1647  * so we have to figure it out ourselves.
1648  */
1649 const char *
1650 fixlabel(int f, struct disklabel32 *lp, int writeadj)
1651 {
1652         const char *msg = NULL;
1653         struct partinfo info;
1654         struct partition32 *pp;
1655         u_int64_t start;
1656         u_int64_t end;
1657         u_int64_t offset;
1658         int part;
1659         int rev;
1660         int rev_len = sizeof(rev);
1661
1662         if (sysctlbyname("kern.osrevision", &rev, &rev_len, NULL, 0) < 0) {
1663                 errx(1, "Cannot use raw mode on non-DragonFly systems\n");
1664         }
1665         if (rev < 200701) {
1666                 warnx("Warning running new disklabel on old DragonFly systems,\n"
1667                       "assuming the disk layer will fixup the label.\n");
1668                 sleep(3);
1669                 return(NULL);
1670         }
1671
1672         pp = &lp->d_partitions[RAW_PART];
1673
1674         if (forceflag) {
1675                 info.media_offset = slice_start_lba * lp->d_secsize;
1676                 info.media_blocks = pp->p_size;
1677                 info.media_blksize = lp->d_secsize;
1678         } else if (ioctl(f, DIOCGPART, &info) < 0) {
1679                 msg = "Unable to extract the slice starting LBA, "
1680                       "you must use the -f <slice_start_lba> option\n"
1681                       "to specify it manually, or perhaps try without "
1682                       "using -r and let the kernel deal with it\n";
1683                 return(msg);
1684         }
1685
1686         if (lp->d_magic != DISKMAGIC32 || lp->d_magic2 != DISKMAGIC32)
1687                 return ("fixlabel: invalid magic");
1688         if (dkcksum32(lp) != 0)
1689                 return ("fixlabel: invalid checksum");
1690
1691         /*
1692          * What a mess.  For ages old backwards compatibility the disklabel
1693          * on-disk stores absolute offsets instead of slice-relative offsets.
1694          * So fix it up when reading, writing, or snooping.
1695          *
1696          * The in-core label is always slice-relative.
1697          */
1698         if (writeadj) {
1699                 /*
1700                  * incore -> disk
1701                  */
1702                 start = 0;
1703                 offset = info.media_offset / info.media_blksize;
1704         } else {
1705                 /*
1706                  * disk -> incore
1707                  */
1708                 start = info.media_offset / info.media_blksize;
1709                 offset = -info.media_offset / info.media_blksize;
1710         }
1711         if (pp->p_offset != start)
1712                 return ("fixlabel: raw partition offset != slice offset");
1713         if (pp->p_size != info.media_blocks) {
1714                 if (pp->p_size > info.media_blocks)
1715                         return ("fixlabel: raw partition size > slice size");
1716         }
1717         end = start + info.media_blocks;
1718         if (start > end)
1719                 return ("fixlabel: slice wraps");
1720         if (lp->d_secpercyl <= 0)
1721                 return ("fixlabel: d_secpercyl <= 0");
1722         pp -= RAW_PART;
1723         for (part = 0; part < lp->d_npartitions; part++, pp++) {
1724                 if (pp->p_offset != 0 || pp->p_size != 0) {
1725                         if (pp->p_offset < start
1726                             || pp->p_offset + pp->p_size > end
1727                             || pp->p_offset + pp->p_size < pp->p_offset) {
1728                                 /* XXX else silently discard junk. */
1729                                 bzero(pp, sizeof *pp);
1730                         } else {
1731                                 pp->p_offset += offset;
1732                         }
1733                 }
1734         }
1735         lp->d_checksum = 0;
1736         lp->d_checksum = dkcksum32(lp);
1737         return (NULL);
1738 }
1739
1740 void
1741 usage(void)
1742 {
1743 #if NUMBOOT > 0
1744         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",
1745                 "usage: disklabel [-r] disk",
1746                 "\t\t(to read label)",
1747                 "       disklabel -w [-r] [-n] disk type [ packid ]",
1748                 "\t\t(to write label with existing boot program)",
1749                 "       disklabel -e [-r] [-n] disk",
1750                 "\t\t(to edit label)",
1751                 "       disklabel -R [-r] [-n] disk protofile",
1752                 "\t\t(to restore label with existing boot program)",
1753 #if NUMBOOT > 1
1754                 "       disklabel -B [-n] [ -b boot1 [ -s boot2 ] ] disk [ type ]",
1755                 "\t\t(to install boot program with existing label)",
1756                 "       disklabel -w -B [-n] [ -b boot1 [ -s boot2 ] ] disk type [ packid ]",
1757                 "\t\t(to write label and boot program)",
1758                 "       disklabel -R -B [-n] [ -b boot1 [ -s boot2 ] ] disk protofile [ type ]",
1759                 "\t\t(to restore label and boot program)",
1760 #else
1761                 "       disklabel -B [-n] [ -b bootprog ] disk [ type ]",
1762                 "\t\t(to install boot program with existing on-disk label)",
1763                 "       disklabel -w -B [-n] [ -b bootprog ] disk type [ packid ]",
1764                 "\t\t(to write label and install boot program)",
1765                 "       disklabel -R -B [-n] [ -b bootprog ] disk protofile [ type ]",
1766                 "\t\t(to restore label and install boot program)",
1767 #endif
1768                 "       disklabel [-NW] disk",
1769                 "\t\t(to write disable/enable label)");
1770 #else
1771         fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
1772                 "usage: disklabel [-r] disk", "(to read label)",
1773                 "       disklabel -w [-r] [-n] disk type [ packid ]",
1774                 "\t\t(to write label)",
1775                 "       disklabel -e [-r] [-n] disk",
1776                 "\t\t(to edit label)",
1777                 "       disklabel -R [-r] [-n] disk protofile",
1778                 "\t\t(to restore label)",
1779                 "       disklabel [-NW] disk",
1780                 "\t\t(to write disable/enable label)");
1781 #endif
1782         exit(1);
1783 }