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