]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sbin/disklabel/disklabel.c
This commit was generated by cvs2svn to compensate for changes in r48907,
[FreeBSD/FreeBSD.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
37 #ifndef lint
38 static const char copyright[] =
39 "@(#) Copyright (c) 1987, 1993\n\
40         The Regents of the University of California.  All rights reserved.\n";
41 #endif /* not lint */
42
43 #ifndef lint
44 #if 0
45 static char sccsid[] = "@(#)disklabel.c 8.2 (Berkeley) 1/7/94";
46 /* from static char sccsid[] = "@(#)disklabel.c 1.2 (Symmetric) 11/28/85"; */
47 #endif
48 static const char rcsid[] =
49         "$Id: disklabel.c,v 1.23 1998/10/23 18:57:39 bde Exp $";
50 #endif /* not lint */
51
52 #include <sys/param.h>
53 #include <sys/errno.h>
54 #include <sys/file.h>
55 #include <sys/stat.h>
56 #include <sys/wait.h>
57 #define DKTYPENAMES
58 #include <sys/disklabel.h>
59 #include <ufs/ffs/fs.h>
60 #include <unistd.h>
61 #include <string.h>
62 #include <stdio.h>
63 #include <stdlib.h>
64 #include <signal.h>
65 #include <stdarg.h>
66 #include <ctype.h>
67 #include <err.h>
68 #include "pathnames.h"
69
70 /*
71  * Disklabel: read and write disklabels.
72  * The label is usually placed on one of the first sectors of the disk.
73  * Many machines also place a bootstrap in the same area,
74  * in which case the label is embedded in the bootstrap.
75  * The bootstrap source must leave space at the proper offset
76  * for the label on such machines.
77  */
78
79 #ifndef BBSIZE
80 #define BBSIZE  8192                    /* size of boot area, with label */
81 #endif
82
83 #ifdef tahoe
84 #define NUMBOOT 0
85 #else
86 #if defined(__alpha__) || defined(hp300) || defined(hp800)
87 #define NUMBOOT 1
88 #else
89 #define NUMBOOT 2
90 #endif
91 #endif
92
93 void    makelabel       __P((char *, char *, struct disklabel *));
94 int     writelabel      __P((int, char *, struct disklabel *));
95 void    l_perror        __P((char *));
96 struct disklabel * readlabel __P((int));
97 struct disklabel * makebootarea __P((char *, struct disklabel *, int));
98 void    display         __P((FILE *, struct disklabel *));
99 int     edit            __P((struct disklabel *, int));
100 int     editit          __P((void));
101 char *  skip            __P((char *));
102 char *  word            __P((char *));
103 int     getasciilabel   __P((FILE *, struct disklabel *));
104 int     checklabel      __P((struct disklabel *));
105 void    setbootflag     __P((struct disklabel *));
106 void    Warning         (char *, ...);
107 void    usage           __P((void));
108 extern  u_short dkcksum __P((struct disklabel *));
109 struct disklabel * getvirginlabel __P((void));
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_TMP;
117
118 char    namebuf[BBSIZE], *np = namebuf;
119 struct  disklabel lab;
120 struct  disklabel *readlabel(), *makebootarea();
121 char    bootarea[BBSIZE];
122
123 #if NUMBOOT > 0
124 int     installboot;    /* non-zero if we should install a boot program */
125 char    *bootbuf;       /* pointer to buffer with remainder of boot prog */
126 int     bootsize;       /* size of remaining boot program */
127 char    *xxboot;        /* primary boot */
128 char    *bootxx;        /* secondary boot */
129 char    boot0[MAXPATHLEN];
130 char    boot1[MAXPATHLEN];
131 #endif
132
133 enum    {
134         UNSPEC, EDIT, NOWRITE, READ, RESTORE, WRITE, WRITEABLE, WRITEBOOT
135 } op = UNSPEC;
136
137 int     rflag;
138
139 #ifdef DEBUG
140 int     debug;
141 #define OPTIONS "BNRWb:ders:w"
142 #else
143 #define OPTIONS "BNRWb:ers:w"
144 #endif
145
146 int
147 main(argc, argv)
148         int argc;
149         char *argv[];
150 {
151         register struct disklabel *lp;
152         FILE *t;
153         int ch, f, flag, error = 0;
154         char *name = 0;
155
156         while ((ch = getopt(argc, argv, OPTIONS)) != -1)
157                 switch (ch) {
158 #if NUMBOOT > 0
159                         case 'B':
160                                 ++installboot;
161                                 break;
162                         case 'b':
163                                 xxboot = optarg;
164                                 break;
165 #if NUMBOOT > 1
166                         case 's':
167                                 bootxx = optarg;
168                                 break;
169 #endif
170 #endif
171                         case 'N':
172                                 if (op != UNSPEC)
173                                         usage();
174                                 op = NOWRITE;
175                                 break;
176                         case 'R':
177                                 if (op != UNSPEC)
178                                         usage();
179                                 op = RESTORE;
180                                 break;
181                         case 'W':
182                                 if (op != UNSPEC)
183                                         usage();
184                                 op = WRITEABLE;
185                                 break;
186                         case 'e':
187                                 if (op != UNSPEC)
188                                         usage();
189                                 op = EDIT;
190                                 break;
191                         case 'r':
192                                 ++rflag;
193                                 break;
194                         case 'w':
195                                 if (op != UNSPEC)
196                                         usage();
197                                 op = WRITE;
198                                 break;
199 #ifdef DEBUG
200                         case 'd':
201                                 debug++;
202                                 break;
203 #endif
204                         case '?':
205                         default:
206                                 usage();
207                 }
208         argc -= optind;
209         argv += optind;
210 #if NUMBOOT > 0
211         if (installboot) {
212                 rflag++;
213                 if (op == UNSPEC)
214                         op = WRITEBOOT;
215         } else {
216                 if (op == UNSPEC)
217                         op = READ;
218                 xxboot = bootxx = 0;
219         }
220 #else
221         if (op == UNSPEC)
222                 op = READ;
223 #endif
224         if (argc < 1)
225                 usage();
226
227         dkname = argv[0];
228         if (dkname[0] != '/') {
229                 (void)sprintf(np, "%sr%s%c", _PATH_DEV, dkname, 'a' + RAW_PART);
230                 specname = np;
231                 np += strlen(specname) + 1;
232         } else
233                 specname = dkname;
234         f = open(specname, op == READ ? O_RDONLY : O_RDWR);
235         if (f < 0 && errno == ENOENT && dkname[0] != '/') {
236                 (void)sprintf(specname, "%sr%s", _PATH_DEV, dkname);
237                 np = namebuf + strlen(specname) + 1;
238                 f = open(specname, op == READ ? O_RDONLY : O_RDWR);
239         }
240         if (f < 0)
241                 err(4, "%s", specname);
242
243         switch(op) {
244
245         case EDIT:
246                 if (argc != 1)
247                         usage();
248                 lp = readlabel(f);
249                 error = edit(lp, f);
250                 break;
251
252         case NOWRITE:
253                 flag = 0;
254                 if (ioctl(f, DIOCWLABEL, (char *)&flag) < 0)
255                         err(4, "ioctl DIOCWLABEL");
256                 break;
257
258         case READ:
259                 if (argc != 1)
260                         usage();
261                 lp = readlabel(f);
262                 display(stdout, lp);
263                 error = checklabel(lp);
264                 break;
265
266         case RESTORE:
267 #if NUMBOOT > 0
268                 if (installboot && argc == 3) {
269                         makelabel(argv[2], 0, &lab);
270                         argc--;
271
272                         /*
273                          * We only called makelabel() for its side effect
274                          * of setting the bootstrap file names.  Discard
275                          * all changes to `lab' so that all values in the
276                          * final label come from the ASCII label.
277                          */
278                         bzero((char *)&lab, sizeof(lab));
279                 }
280 #endif
281                 if (argc != 2)
282                         usage();
283                 if (!(t = fopen(argv[1], "r")))
284                         err(4, "%s", argv[1]);
285                 if (!getasciilabel(t, &lab))
286                         exit(1);
287                 lp = makebootarea(bootarea, &lab, f);
288                 *lp = lab;
289                 error = writelabel(f, bootarea, lp);
290                 break;
291
292         case WRITE:
293                 if (argc == 3) {
294                         name = argv[2];
295                         argc--;
296                 }
297                 if (argc != 2)
298                         usage();
299                 makelabel(argv[1], name, &lab);
300                 lp = makebootarea(bootarea, &lab, f);
301                 *lp = lab;
302                 if (checklabel(lp) == 0)
303                         error = writelabel(f, bootarea, lp);
304                 break;
305
306         case WRITEABLE:
307                 flag = 1;
308                 if (ioctl(f, DIOCWLABEL, (char *)&flag) < 0)
309                         err(4, "ioctl DIOCWLABEL");
310                 break;
311
312 #if NUMBOOT > 0
313         case WRITEBOOT:
314         {
315                 struct disklabel tlab;
316
317                 lp = readlabel(f);
318                 tlab = *lp;
319                 if (argc == 2)
320                         makelabel(argv[1], 0, &lab);
321                 lp = makebootarea(bootarea, &lab, f);
322                 *lp = tlab;
323                 if (checklabel(lp) == 0)
324                         error = writelabel(f, bootarea, lp);
325                 break;
326         }
327 #endif
328         }
329         exit(error);
330 }
331
332 /*
333  * Construct a prototype disklabel from /etc/disktab.  As a side
334  * effect, set the names of the primary and secondary boot files
335  * if specified.
336  */
337 void
338 makelabel(type, name, lp)
339         char *type, *name;
340         register struct disklabel *lp;
341 {
342         register struct disklabel *dp;
343
344         if (strcmp(type, "auto") == 0)
345                 dp = getvirginlabel();
346         else
347                 dp = getdiskbyname(type);
348         if (dp == NULL)
349                 errx(1, "%s: unknown disk type", type);
350         *lp = *dp;
351 #if NUMBOOT > 0
352         /*
353          * Set bootstrap name(s).
354          * 1. If set from command line, use those,
355          * 2. otherwise, check if disktab specifies them (b0 or b1),
356          * 3. otherwise, makebootarea() will choose ones based on the name
357          *    of the disk special file. E.g. /dev/ra0 -> raboot, bootra
358          */
359         if (!xxboot && lp->d_boot0) {
360                 if (*lp->d_boot0 != '/')
361                         (void)sprintf(boot0, "%s/%s",
362                                       _PATH_BOOTDIR, lp->d_boot0);
363                 else
364                         (void)strcpy(boot0, lp->d_boot0);
365                 xxboot = boot0;
366         }
367 #if NUMBOOT > 1
368         if (!bootxx && lp->d_boot1) {
369                 if (*lp->d_boot1 != '/')
370                         (void)sprintf(boot1, "%s/%s",
371                                       _PATH_BOOTDIR, lp->d_boot1);
372                 else
373                         (void)strcpy(boot1, lp->d_boot1);
374                 bootxx = boot1;
375         }
376 #endif
377 #endif
378         /* d_packname is union d_boot[01], so zero */
379         bzero(lp->d_packname, sizeof(lp->d_packname));
380         if (name)
381                 (void)strncpy(lp->d_packname, name, sizeof(lp->d_packname));
382 }
383
384 int
385 writelabel(f, boot, lp)
386         int f;
387         char *boot;
388         register struct disklabel *lp;
389 {
390         int flag;
391 #ifdef __alpha__
392         u_long *p, sum;
393         int i;
394 #endif
395 #ifdef vax
396         register int i;
397 #endif
398
399         setbootflag(lp);
400         lp->d_magic = DISKMAGIC;
401         lp->d_magic2 = DISKMAGIC;
402         lp->d_checksum = 0;
403         lp->d_checksum = dkcksum(lp);
404         if (rflag) {
405                 /*
406                  * First set the kernel disk label,
407                  * then write a label to the raw disk.
408                  * If the SDINFO ioctl fails because it is unimplemented,
409                  * keep going; otherwise, the kernel consistency checks
410                  * may prevent us from changing the current (in-core)
411                  * label.
412                  */
413                 if (ioctl(f, DIOCSDINFO, lp) < 0 &&
414                     errno != ENODEV && errno != ENOTTY) {
415                         l_perror("ioctl DIOCSDINFO");
416                         return (1);
417                 }
418                 (void)lseek(f, (off_t)0, SEEK_SET);
419
420 #ifdef __alpha__
421                 /*
422                  * Generate the bootblock checksum for the SRM console.
423                  */
424                 for (p = (u_long *)boot, i = 0, sum = 0; i < 63; i++)
425                         sum += p[i];
426                 p[63] = sum;
427 #endif
428
429                 /*
430                  * write enable label sector before write (if necessary),
431                  * disable after writing.
432                  */
433                 flag = 1;
434                 if (ioctl(f, DIOCWLABEL, &flag) < 0)
435                         warn("ioctl DIOCWLABEL");
436                 if (write(f, boot, lp->d_bbsize) != lp->d_bbsize) {
437                         warn("write");
438                         return (1);
439                 }
440 #if NUMBOOT > 0
441                 /*
442                  * Output the remainder of the disklabel
443                  */
444                 if (bootbuf && write(f, bootbuf, bootsize) != bootsize) {
445                         warn("write");
446                         return(1);
447                 }
448 #endif
449                 flag = 0;
450                 (void) ioctl(f, DIOCWLABEL, &flag);
451         } else if (ioctl(f, DIOCWDINFO, lp) < 0) {
452                 l_perror("ioctl DIOCWDINFO");
453                 return (1);
454         }
455 #ifdef vax
456         if (lp->d_type == DTYPE_SMD && lp->d_flags & D_BADSECT) {
457                 daddr_t alt;
458
459                 alt = lp->d_ncylinders * lp->d_secpercyl - lp->d_nsectors;
460                 for (i = 1; i < 11 && i < lp->d_nsectors; i += 2) {
461                         (void)lseek(f, (off_t)((alt + i) * lp->d_secsize),
462                             SEEK_SET);
463                         if (write(f, boot, lp->d_secsize) < lp->d_secsize)
464                                 warn("alternate label %d write", i/2);
465                 }
466         }
467 #endif
468         return (0);
469 }
470
471 void
472 l_perror(s)
473         char *s;
474 {
475         switch (errno) {
476
477         case ESRCH:
478                 warnx("%s: no disk label on disk;", s);
479                 fprintf(stderr,
480                     "use \"disklabel -r\" to install initial label\n");
481                 break;
482
483         case EINVAL:
484                 warnx("%s: label magic number or checksum is wrong!", s);
485                 fprintf(stderr, "(disklabel or kernel is out of date?)\n");
486                 break;
487
488         case EBUSY:
489                 warnx("%s: open partition would move or shrink", s);
490                 break;
491
492         case EXDEV:
493                 warnx("%s: '%c' partition must start at beginning of disk",
494                     s, 'a' + RAW_PART);
495                 break;
496
497         default:
498                 warn((char *)NULL);
499                 break;
500         }
501 }
502
503 /*
504  * Fetch disklabel for disk.
505  * Use ioctl to get label unless -r flag is given.
506  */
507 struct disklabel *
508 readlabel(f)
509         int f;
510 {
511         register struct disklabel *lp;
512
513         if (rflag) {
514                 if (read(f, bootarea, BBSIZE) < BBSIZE)
515                         err(4, "%s", specname);
516                 for (lp = (struct disklabel *)bootarea;
517                     lp <= (struct disklabel *)(bootarea + BBSIZE - sizeof(*lp));
518                     lp = (struct disklabel *)((char *)lp + 16))
519                         if (lp->d_magic == DISKMAGIC &&
520                             lp->d_magic2 == DISKMAGIC)
521                                 break;
522                 if (lp > (struct disklabel *)(bootarea+BBSIZE-sizeof(*lp)) ||
523                     lp->d_magic != DISKMAGIC || lp->d_magic2 != DISKMAGIC ||
524                     dkcksum(lp) != 0)
525                         errx(1,
526             "bad pack magic number (label is damaged, or pack is unlabeled)");
527         } else {
528                 lp = &lab;
529                 if (ioctl(f, DIOCGDINFO, lp) < 0)
530                         err(4, "ioctl DIOCGDINFO");
531         }
532         return (lp);
533 }
534
535 /*
536  * Construct a bootarea (d_bbsize bytes) in the specified buffer ``boot''
537  * Returns a pointer to the disklabel portion of the bootarea.
538  */
539 struct disklabel *
540 makebootarea(boot, dp, f)
541         char *boot;
542         register struct disklabel *dp;
543         int f;
544 {
545         struct disklabel *lp;
546         register char *p;
547         int b;
548 #if NUMBOOT > 0
549         char *dkbasename;
550         struct stat sb;
551 #endif
552 #ifdef __alpha__
553         u_long *bootinfo;
554         int n;
555 #endif
556 #ifdef __i386__
557         char *tmpbuf;
558         int i, found;
559 #endif
560
561         /* XXX */
562         if (dp->d_secsize == 0) {
563                 dp->d_secsize = DEV_BSIZE;
564                 dp->d_bbsize = BBSIZE;
565         }
566         lp = (struct disklabel *)
567                 (boot + (LABELSECTOR * dp->d_secsize) + LABELOFFSET);
568         bzero((char *)lp, sizeof *lp);
569 #if NUMBOOT > 0
570         /*
571          * If we are not installing a boot program but we are installing a
572          * label on disk then we must read the current bootarea so we don't
573          * clobber the existing boot.
574          */
575         if (!installboot) {
576                 if (rflag) {
577                         if (read(f, boot, BBSIZE) < BBSIZE)
578                                 err(4, "%s", specname);
579                         bzero((char *)lp, sizeof *lp);
580                 }
581                 return (lp);
582         }
583         /*
584          * We are installing a boot program.  Determine the name(s) and
585          * read them into the appropriate places in the boot area.
586          */
587         if (!xxboot || !bootxx) {
588                 dkbasename = np;
589                 if ((p = rindex(dkname, '/')) == NULL)
590                         p = dkname;
591                 else
592                         p++;
593                 while (*p && !isdigit(*p))
594                         *np++ = *p++;
595                 *np++ = '\0';
596
597                 if (!xxboot) {
598                         (void)sprintf(boot0, "%s/boot1", _PATH_BOOTDIR);
599                         xxboot = boot0;
600                 }
601 #if NUMBOOT > 1
602                 if (!bootxx) {
603                         (void)sprintf(boot1, "%s/boot2", _PATH_BOOTDIR);
604                         bootxx = boot1;
605                 }
606 #endif
607         }
608 #ifdef DEBUG
609         if (debug)
610                 fprintf(stderr, "bootstraps: xxboot = %s, bootxx = %s\n",
611                         xxboot, bootxx ? bootxx : "NONE");
612 #endif
613
614         /*
615          * Strange rules:
616          * 1. One-piece bootstrap (hp300/hp800)
617          *      up to d_bbsize bytes of ``xxboot'' go in bootarea, the rest
618          *      is remembered and written later following the bootarea.
619          * 2. Two-piece bootstraps (vax/i386?/mips?)
620          *      up to d_secsize bytes of ``xxboot'' go in first d_secsize
621          *      bytes of bootarea, remaining d_bbsize-d_secsize filled
622          *      from ``bootxx''.
623          */
624         b = open(xxboot, O_RDONLY);
625         if (b < 0)
626                 err(4, "%s", xxboot);
627 #if NUMBOOT > 1
628 #ifdef __i386__
629         /*
630          * XXX Botch alert.
631          * The i386 has the so-called fdisk table embedded into the
632          * primary bootstrap.  We take care to not clobber it, but
633          * only if it does already contain some data.  (Otherwise,
634          * the xxboot provides a template.)
635          */
636         if ((tmpbuf = (char *)malloc((int)dp->d_secsize)) == 0)
637                 err(4, "%s", xxboot);
638         memcpy((void *)tmpbuf, (void *)boot, (int)dp->d_secsize);
639 #endif /* i386 */
640         if (read(b, boot, (int)dp->d_secsize) < 0)
641                 err(4, "%s", xxboot);
642         (void)close(b);
643 #ifdef __i386__
644         for (i = DOSPARTOFF, found = 0;
645              !found && i < DOSPARTOFF + NDOSPART*sizeof(struct dos_partition);
646              i++)
647                 found = tmpbuf[i] != 0;
648         if (found)
649                 memcpy((void *)&boot[DOSPARTOFF],
650                        (void *)&tmpbuf[DOSPARTOFF],
651                        NDOSPART * sizeof(struct dos_partition));
652         free(tmpbuf);
653 #endif /* i386 */
654         b = open(bootxx, O_RDONLY);
655         if (b < 0)
656                 err(4, "%s", bootxx);
657         if (fstat(b, &sb) != 0)
658                 err(4, "%s", bootxx);
659         if (dp->d_secsize + sb.st_size > dp->d_bbsize)
660                 errx(4, "%s too large", bootxx);
661         if (read(b, &boot[dp->d_secsize],
662                  (int)(dp->d_bbsize-dp->d_secsize)) < 0)
663                 err(4, "%s", bootxx);
664 #else /* !(NUMBOOT > 1) */
665 #ifdef __alpha__
666         /*
667          * On the alpha, the primary bootstrap starts at the
668          * second sector of the boot area.  The first sector
669          * contains the label and must be edited to contain the
670          * size and location of the primary bootstrap.
671          */
672         n = read(b, boot + dp->d_secsize, (int)dp->d_bbsize);
673         if (n < 0)
674                 err(4, "%s", xxboot);
675         bootinfo = (u_long *)(boot + 480);
676         bootinfo[0] = (n + dp->d_secsize - 1) / dp->d_secsize;
677         bootinfo[1] = 1;        /* start at sector 1 */
678         bootinfo[2] = 0;        /* flags (must be zero) */
679 #else /* !__alpha__ */
680         if (read(b, boot, (int)dp->d_bbsize) < 0)
681                 err(4, "%s", xxboot);
682 #endif /* __alpha__ */
683         if (fstat(b, &sb) != 0)
684                 err(4, "%s", xxboot);
685         bootsize = (int)sb.st_size - dp->d_bbsize;
686         if (bootsize > 0) {
687                 /* XXX assume d_secsize is a power of two */
688                 bootsize = (bootsize + dp->d_secsize-1) & ~(dp->d_secsize-1);
689                 bootbuf = (char *)malloc((size_t)bootsize);
690                 if (bootbuf == 0)
691                         err(4, "%s", xxboot);
692                 if (read(b, bootbuf, bootsize) < 0) {
693                         free(bootbuf);
694                         err(4, "%s", xxboot);
695                 }
696         }
697 #endif /* NUMBOOT > 1 */
698         (void)close(b);
699 #endif /* NUMBOOT > 0 */
700         /*
701          * Make sure no part of the bootstrap is written in the area
702          * reserved for the label.
703          */
704         for (p = (char *)lp; p < (char *)lp + sizeof(struct disklabel); p++)
705                 if (*p)
706                         errx(2, "bootstrap doesn't leave room for disk label");
707         return (lp);
708 }
709
710 void
711 display(f, lp)
712         FILE *f;
713         register struct disklabel *lp;
714 {
715         register int i, j;
716         register struct partition *pp;
717
718         fprintf(f, "# %s:\n", specname);
719         if ((unsigned) lp->d_type < DKMAXTYPES)
720                 fprintf(f, "type: %s\n", dktypenames[lp->d_type]);
721         else
722                 fprintf(f, "type: %u\n", lp->d_type);
723         fprintf(f, "disk: %.*s\n", (int)sizeof(lp->d_typename),
724                 lp->d_typename);
725         fprintf(f, "label: %.*s\n", (int)sizeof(lp->d_packname),
726                 lp->d_packname);
727         fprintf(f, "flags:");
728         if (lp->d_flags & D_REMOVABLE)
729                 fprintf(f, " removeable");
730         if (lp->d_flags & D_ECC)
731                 fprintf(f, " ecc");
732         if (lp->d_flags & D_BADSECT)
733                 fprintf(f, " badsect");
734         fprintf(f, "\n");
735         fprintf(f, "bytes/sector: %lu\n", (u_long)lp->d_secsize);
736         fprintf(f, "sectors/track: %lu\n", (u_long)lp->d_nsectors);
737         fprintf(f, "tracks/cylinder: %lu\n", (u_long)lp->d_ntracks);
738         fprintf(f, "sectors/cylinder: %lu\n", (u_long)lp->d_secpercyl);
739         fprintf(f, "cylinders: %lu\n", (u_long)lp->d_ncylinders);
740         fprintf(f, "sectors/unit: %lu\n", (u_long)lp->d_secperunit);
741         fprintf(f, "rpm: %u\n", lp->d_rpm);
742         fprintf(f, "interleave: %u\n", lp->d_interleave);
743         fprintf(f, "trackskew: %u\n", lp->d_trackskew);
744         fprintf(f, "cylinderskew: %u\n", lp->d_cylskew);
745         fprintf(f, "headswitch: %lu\t\t# milliseconds\n",
746             (u_long)lp->d_headswitch);
747         fprintf(f, "track-to-track seek: %ld\t# milliseconds\n",
748             (u_long)lp->d_trkseek);
749         fprintf(f, "drivedata: ");
750         for (i = NDDATA - 1; i >= 0; i--)
751                 if (lp->d_drivedata[i])
752                         break;
753         if (i < 0)
754                 i = 0;
755         for (j = 0; j <= i; j++)
756                 fprintf(f, "%lu ", (u_long)lp->d_drivedata[j]);
757         fprintf(f, "\n\n%u partitions:\n", lp->d_npartitions);
758         fprintf(f,
759             "#        size   offset    fstype   [fsize bsize bps/cpg]\n");
760         pp = lp->d_partitions;
761         for (i = 0; i < lp->d_npartitions; i++, pp++) {
762                 if (pp->p_size) {
763                         fprintf(f, "  %c: %8lu %8lu  ", 'a' + i,
764                            (u_long)pp->p_size, (u_long)pp->p_offset);
765                         if ((unsigned) pp->p_fstype < FSMAXTYPES)
766                                 fprintf(f, "%8.8s", fstypenames[pp->p_fstype]);
767                         else
768                                 fprintf(f, "%8d", pp->p_fstype);
769                         switch (pp->p_fstype) {
770
771                         case FS_UNUSED:                         /* XXX */
772                                 fprintf(f, "    %5lu %5lu %5.5s ",
773                                     (u_long)pp->p_fsize,
774                                     (u_long)(pp->p_fsize * pp->p_frag), "");
775                                 break;
776
777                         case FS_BSDFFS:
778                                 fprintf(f, "    %5lu %5lu %5u ",
779                                     (u_long)pp->p_fsize,
780                                     (u_long)(pp->p_fsize * pp->p_frag),
781                                     pp->p_cpg);
782                                 break;
783
784                         case FS_BSDLFS:
785                                 fprintf(f, "    %5lu %5lu %5d",
786                                     (u_long)pp->p_fsize,
787                                     (u_long)(pp->p_fsize * pp->p_frag),
788                                     pp->p_cpg);
789                                 break;
790
791                         default:
792                                 fprintf(f, "%20.20s", "");
793                                 break;
794                         }
795                         fprintf(f, "\t# (Cyl. %4lu",
796                             (u_long)(pp->p_offset / lp->d_secpercyl));
797                         if (pp->p_offset % lp->d_secpercyl)
798                             putc('*', f);
799                         else
800                             putc(' ', f);
801                         fprintf(f, "- %lu",
802                             (u_long)((pp->p_offset + pp->p_size +
803                             lp->d_secpercyl - 1) /
804                             lp->d_secpercyl - 1));
805                         if (pp->p_size % lp->d_secpercyl)
806                             putc('*', f);
807                         fprintf(f, ")\n");
808                 }
809         }
810         fflush(f);
811 }
812
813 int
814 edit(lp, f)
815         struct disklabel *lp;
816         int f;
817 {
818         register int c, fd;
819         struct disklabel label;
820         FILE *fp;
821
822         if ((fd = mkstemp(tmpfil)) == -1 ||
823             (fp = fdopen(fd, "w")) == NULL) {
824                 warnx("can't create %s", tmpfil);
825                 return (1);
826         }
827         display(fp, lp);
828         fclose(fp);
829         for (;;) {
830                 if (!editit())
831                         break;
832                 fp = fopen(tmpfil, "r");
833                 if (fp == NULL) {
834                         warnx("can't reopen %s for reading", tmpfil);
835                         break;
836                 }
837                 bzero((char *)&label, sizeof(label));
838                 if (getasciilabel(fp, &label)) {
839                         *lp = label;
840                         if (writelabel(f, bootarea, lp) == 0) {
841                                 fclose(fp);
842                                 (void) unlink(tmpfil);
843                                 return (0);
844                         }
845                 }
846                 fclose(fp);
847                 printf("re-edit the label? [y]: "); fflush(stdout);
848                 c = getchar();
849                 if (c != EOF && c != (int)'\n')
850                         while (getchar() != (int)'\n')
851                                 ;
852                 if  (c == (int)'n')
853                         break;
854         }
855         (void) unlink(tmpfil);
856         return (1);
857 }
858
859 int
860 editit()
861 {
862         register int pid, xpid;
863         int stat, omask;
864         extern char *getenv();
865
866         omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP));
867         while ((pid = fork()) < 0) {
868                 extern int errno;
869
870                 if (errno == EPROCLIM) {
871                         warnx("you have too many processes");
872                         return(0);
873                 }
874                 if (errno != EAGAIN) {
875                         warn("fork");
876                         return(0);
877                 }
878                 sleep(1);
879         }
880         if (pid == 0) {
881                 register char *ed;
882
883                 sigsetmask(omask);
884                 setgid(getgid());
885                 setuid(getuid());
886                 if ((ed = getenv("EDITOR")) == (char *)0)
887                         ed = DEFEDITOR;
888                 execlp(ed, ed, tmpfil, 0);
889                 err(1, "%s", ed);
890         }
891         while ((xpid = wait(&stat)) >= 0)
892                 if (xpid == pid)
893                         break;
894         sigsetmask(omask);
895         return(!stat);
896 }
897
898 char *
899 skip(cp)
900         register char *cp;
901 {
902
903         while (*cp != '\0' && isspace(*cp))
904                 cp++;
905         if (*cp == '\0' || *cp == '#')
906                 return ((char *)NULL);
907         return (cp);
908 }
909
910 char *
911 word(cp)
912         register char *cp;
913 {
914         register char c;
915
916         while (*cp != '\0' && !isspace(*cp) && *cp != '#')
917                 cp++;
918         if ((c = *cp) != '\0') {
919                 *cp++ = '\0';
920                 if (c != '#')
921                         return (skip(cp));
922         }
923         return ((char *)NULL);
924 }
925
926 /*
927  * Read an ascii label in from fd f,
928  * in the same format as that put out by display(),
929  * and fill in lp.
930  */
931 int
932 getasciilabel(f, lp)
933         FILE    *f;
934         register struct disklabel *lp;
935 {
936         register char **cpp, *cp;
937         register struct partition *pp;
938         char *tp, *s, line[BUFSIZ];
939         int v, lineno = 0, errors = 0;
940
941         lp->d_bbsize = BBSIZE;                          /* XXX */
942         lp->d_sbsize = SBSIZE;                          /* XXX */
943         while (fgets(line, sizeof(line) - 1, f)) {
944                 lineno++;
945                 if ((cp = index(line,'\n')) != 0)
946                         *cp = '\0';
947                 cp = skip(line);
948                 if (cp == NULL)
949                         continue;
950                 tp = index(cp, ':');
951                 if (tp == NULL) {
952                         fprintf(stderr, "line %d: syntax error\n", lineno);
953                         errors++;
954                         continue;
955                 }
956                 *tp++ = '\0', tp = skip(tp);
957                 if (streq(cp, "type")) {
958                         if (tp == NULL)
959                                 tp = "unknown";
960                         cpp = dktypenames;
961                         for (; cpp < &dktypenames[DKMAXTYPES]; cpp++)
962                                 if ((s = *cpp) && streq(s, tp)) {
963                                         lp->d_type = cpp - dktypenames;
964                                         goto next;
965                                 }
966                         v = atoi(tp);
967                         if ((unsigned)v >= DKMAXTYPES)
968                                 fprintf(stderr, "line %d:%s %d\n", lineno,
969                                     "Warning, unknown disk type", v);
970                         lp->d_type = v;
971                         continue;
972                 }
973                 if (streq(cp, "flags")) {
974                         for (v = 0; (cp = tp) && *cp != '\0';) {
975                                 tp = word(cp);
976                                 if (streq(cp, "removeable"))
977                                         v |= D_REMOVABLE;
978                                 else if (streq(cp, "ecc"))
979                                         v |= D_ECC;
980                                 else if (streq(cp, "badsect"))
981                                         v |= D_BADSECT;
982                                 else {
983                                         fprintf(stderr,
984                                             "line %d: %s: bad flag\n",
985                                             lineno, cp);
986                                         errors++;
987                                 }
988                         }
989                         lp->d_flags = v;
990                         continue;
991                 }
992                 if (streq(cp, "drivedata")) {
993                         register int i;
994
995                         for (i = 0; (cp = tp) && *cp != '\0' && i < NDDATA;) {
996                                 lp->d_drivedata[i++] = atoi(cp);
997                                 tp = word(cp);
998                         }
999                         continue;
1000                 }
1001                 if (sscanf(cp, "%d partitions", &v) == 1) {
1002                         if (v == 0 || (unsigned)v > MAXPARTITIONS) {
1003                                 fprintf(stderr,
1004                                     "line %d: bad # of partitions\n", lineno);
1005                                 lp->d_npartitions = MAXPARTITIONS;
1006                                 errors++;
1007                         } else
1008                                 lp->d_npartitions = v;
1009                         continue;
1010                 }
1011                 if (tp == NULL)
1012                         tp = "";
1013                 if (streq(cp, "disk")) {
1014                         strncpy(lp->d_typename, tp, sizeof (lp->d_typename));
1015                         continue;
1016                 }
1017                 if (streq(cp, "label")) {
1018                         strncpy(lp->d_packname, tp, sizeof (lp->d_packname));
1019                         continue;
1020                 }
1021                 if (streq(cp, "bytes/sector")) {
1022                         v = atoi(tp);
1023                         if (v <= 0 || (v % DEV_BSIZE) != 0) {
1024                                 fprintf(stderr,
1025                                     "line %d: %s: bad sector size\n",
1026                                     lineno, tp);
1027                                 errors++;
1028                         } else
1029                                 lp->d_secsize = v;
1030                         continue;
1031                 }
1032                 if (streq(cp, "sectors/track")) {
1033                         v = atoi(tp);
1034                         if (v <= 0) {
1035                                 fprintf(stderr, "line %d: %s: bad %s\n",
1036                                     lineno, tp, cp);
1037                                 errors++;
1038                         } else
1039                                 lp->d_nsectors = v;
1040                         continue;
1041                 }
1042                 if (streq(cp, "sectors/cylinder")) {
1043                         v = atoi(tp);
1044                         if (v <= 0) {
1045                                 fprintf(stderr, "line %d: %s: bad %s\n",
1046                                     lineno, tp, cp);
1047                                 errors++;
1048                         } else
1049                                 lp->d_secpercyl = v;
1050                         continue;
1051                 }
1052                 if (streq(cp, "tracks/cylinder")) {
1053                         v = atoi(tp);
1054                         if (v <= 0) {
1055                                 fprintf(stderr, "line %d: %s: bad %s\n",
1056                                     lineno, tp, cp);
1057                                 errors++;
1058                         } else
1059                                 lp->d_ntracks = v;
1060                         continue;
1061                 }
1062                 if (streq(cp, "cylinders")) {
1063                         v = atoi(tp);
1064                         if (v <= 0) {
1065                                 fprintf(stderr, "line %d: %s: bad %s\n",
1066                                     lineno, tp, cp);
1067                                 errors++;
1068                         } else
1069                                 lp->d_ncylinders = v;
1070                         continue;
1071                 }
1072                 if (streq(cp, "sectors/unit")) {
1073                         v = atoi(tp);
1074                         if (v <= 0) {
1075                                 fprintf(stderr, "line %d: %s: bad %s\n",
1076                                     lineno, tp, cp);
1077                                 errors++;
1078                         } else
1079                                 lp->d_secperunit = v;
1080                         continue;
1081                 }
1082                 if (streq(cp, "rpm")) {
1083                         v = atoi(tp);
1084                         if (v <= 0) {
1085                                 fprintf(stderr, "line %d: %s: bad %s\n",
1086                                     lineno, tp, cp);
1087                                 errors++;
1088                         } else
1089                                 lp->d_rpm = v;
1090                         continue;
1091                 }
1092                 if (streq(cp, "interleave")) {
1093                         v = atoi(tp);
1094                         if (v <= 0) {
1095                                 fprintf(stderr, "line %d: %s: bad %s\n",
1096                                     lineno, tp, cp);
1097                                 errors++;
1098                         } else
1099                                 lp->d_interleave = v;
1100                         continue;
1101                 }
1102                 if (streq(cp, "trackskew")) {
1103                         v = atoi(tp);
1104                         if (v < 0) {
1105                                 fprintf(stderr, "line %d: %s: bad %s\n",
1106                                     lineno, tp, cp);
1107                                 errors++;
1108                         } else
1109                                 lp->d_trackskew = v;
1110                         continue;
1111                 }
1112                 if (streq(cp, "cylinderskew")) {
1113                         v = atoi(tp);
1114                         if (v < 0) {
1115                                 fprintf(stderr, "line %d: %s: bad %s\n",
1116                                     lineno, tp, cp);
1117                                 errors++;
1118                         } else
1119                                 lp->d_cylskew = v;
1120                         continue;
1121                 }
1122                 if (streq(cp, "headswitch")) {
1123                         v = atoi(tp);
1124                         if (v < 0) {
1125                                 fprintf(stderr, "line %d: %s: bad %s\n",
1126                                     lineno, tp, cp);
1127                                 errors++;
1128                         } else
1129                                 lp->d_headswitch = v;
1130                         continue;
1131                 }
1132                 if (streq(cp, "track-to-track seek")) {
1133                         v = atoi(tp);
1134                         if (v < 0) {
1135                                 fprintf(stderr, "line %d: %s: bad %s\n",
1136                                     lineno, tp, cp);
1137                                 errors++;
1138                         } else
1139                                 lp->d_trkseek = v;
1140                         continue;
1141                 }
1142                 if ('a' <= *cp && *cp <= 'z' && cp[1] == '\0') {
1143                         unsigned part = *cp - 'a';
1144
1145                         if (part > lp->d_npartitions) {
1146                                 fprintf(stderr,
1147                                     "line %d: bad partition name\n", lineno);
1148                                 errors++;
1149                                 continue;
1150                         }
1151                         pp = &lp->d_partitions[part];
1152 #define NXTNUM(n) { \
1153         if (tp == NULL) { \
1154                 fprintf(stderr, "line %d: too few numeric fields\n", lineno); \
1155                 errors++; \
1156                 break; \
1157         } else { \
1158                 cp = tp, tp = word(cp); \
1159                 if (tp == NULL) \
1160                         tp = cp; \
1161                 (n) = atoi(cp); \
1162         } \
1163      }
1164
1165                         NXTNUM(v);
1166                         if (v < 0) {
1167                                 fprintf(stderr,
1168                                     "line %d: %s: bad partition size\n",
1169                                     lineno, cp);
1170                                 errors++;
1171                         } else
1172                                 pp->p_size = v;
1173                         NXTNUM(v);
1174                         if (v < 0) {
1175                                 fprintf(stderr,
1176                                     "line %d: %s: bad partition offset\n",
1177                                     lineno, cp);
1178                                 errors++;
1179                         } else
1180                                 pp->p_offset = v;
1181                         cp = tp, tp = word(cp);
1182                         cpp = fstypenames;
1183                         for (; cpp < &fstypenames[FSMAXTYPES]; cpp++)
1184                                 if ((s = *cpp) && streq(s, cp)) {
1185                                         pp->p_fstype = cpp - fstypenames;
1186                                         goto gottype;
1187                                 }
1188                         if (isdigit(*cp))
1189                                 v = atoi(cp);
1190                         else
1191                                 v = FSMAXTYPES;
1192                         if ((unsigned)v >= FSMAXTYPES) {
1193                                 fprintf(stderr, "line %d: %s %s\n", lineno,
1194                                     "Warning, unknown filesystem type", cp);
1195                                 v = FS_UNUSED;
1196                         }
1197                         pp->p_fstype = v;
1198         gottype:
1199
1200                         switch (pp->p_fstype) {
1201
1202                         case FS_UNUSED:                         /* XXX */
1203                                 NXTNUM(pp->p_fsize);
1204                                 if (pp->p_fsize == 0)
1205                                         break;
1206                                 NXTNUM(v);
1207                                 pp->p_frag = v / pp->p_fsize;
1208                                 break;
1209
1210                         case FS_BSDFFS:
1211                                 NXTNUM(pp->p_fsize);
1212                                 if (pp->p_fsize == 0)
1213                                         break;
1214                                 NXTNUM(v);
1215                                 pp->p_frag = v / pp->p_fsize;
1216                                 NXTNUM(pp->p_cpg);
1217                                 break;
1218
1219                         case FS_BSDLFS:
1220                                 NXTNUM(pp->p_fsize);
1221                                 if (pp->p_fsize == 0)
1222                                         break;
1223                                 NXTNUM(v);
1224                                 pp->p_frag = v / pp->p_fsize;
1225                                 NXTNUM(pp->p_cpg);
1226                                 break;
1227
1228                         default:
1229                                 break;
1230                         }
1231                         continue;
1232                 }
1233                 fprintf(stderr, "line %d: %s: Unknown disklabel field\n",
1234                     lineno, cp);
1235                 errors++;
1236         next:
1237                 ;
1238         }
1239         errors += checklabel(lp);
1240         return (errors == 0);
1241 }
1242
1243 /*
1244  * Check disklabel for errors and fill in
1245  * derived fields according to supplied values.
1246  */
1247 int
1248 checklabel(lp)
1249         register struct disklabel *lp;
1250 {
1251         register struct partition *pp;
1252         int i, errors = 0;
1253         char part;
1254
1255         if (lp->d_secsize == 0) {
1256                 fprintf(stderr, "sector size 0\n");
1257                 return (1);
1258         }
1259         if (lp->d_nsectors == 0) {
1260                 fprintf(stderr, "sectors/track 0\n");
1261                 return (1);
1262         }
1263         if (lp->d_ntracks == 0) {
1264                 fprintf(stderr, "tracks/cylinder 0\n");
1265                 return (1);
1266         }
1267         if  (lp->d_ncylinders == 0) {
1268                 fprintf(stderr, "cylinders/unit 0\n");
1269                 errors++;
1270         }
1271         if (lp->d_rpm == 0)
1272                 Warning("revolutions/minute 0");
1273         if (lp->d_secpercyl == 0)
1274                 lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks;
1275         if (lp->d_secperunit == 0)
1276                 lp->d_secperunit = lp->d_secpercyl * lp->d_ncylinders;
1277         if (lp->d_bbsize == 0) {
1278                 fprintf(stderr, "boot block size 0\n");
1279                 errors++;
1280         } else if (lp->d_bbsize % lp->d_secsize)
1281                 Warning("boot block size %% sector-size != 0");
1282         if (lp->d_sbsize == 0) {
1283                 fprintf(stderr, "super block size 0\n");
1284                 errors++;
1285         } else if (lp->d_sbsize % lp->d_secsize)
1286                 Warning("super block size %% sector-size != 0");
1287         if (lp->d_npartitions > MAXPARTITIONS)
1288                 Warning("number of partitions (%lu) > MAXPARTITIONS (%d)",
1289                     (u_long)lp->d_npartitions, MAXPARTITIONS);
1290         for (i = 0; i < lp->d_npartitions; i++) {
1291                 part = 'a' + i;
1292                 pp = &lp->d_partitions[i];
1293                 if (pp->p_size == 0 && pp->p_offset != 0)
1294                         Warning("partition %c: size 0, but offset %lu",
1295                             part, (u_long)pp->p_offset);
1296 #ifdef notdef
1297                 if (pp->p_size % lp->d_secpercyl)
1298                         Warning("partition %c: size %% cylinder-size != 0",
1299                             part);
1300                 if (pp->p_offset % lp->d_secpercyl)
1301                         Warning("partition %c: offset %% cylinder-size != 0",
1302                             part);
1303 #endif
1304                 if (pp->p_offset > lp->d_secperunit) {
1305                         fprintf(stderr,
1306                             "partition %c: offset past end of unit\n", part);
1307                         errors++;
1308                 }
1309                 if (pp->p_offset + pp->p_size > lp->d_secperunit) {
1310                         fprintf(stderr,
1311                         "partition %c: partition extends past end of unit\n",
1312                             part);
1313                         errors++;
1314                 }
1315         }
1316         for (; i < MAXPARTITIONS; i++) {
1317                 part = 'a' + i;
1318                 pp = &lp->d_partitions[i];
1319                 if (pp->p_size || pp->p_offset)
1320                         Warning("unused partition %c: size %d offset %lu",
1321                             'a' + i, pp->p_size, (u_long)pp->p_offset);
1322         }
1323         return (errors);
1324 }
1325
1326 /*
1327  * When operating on a "virgin" disk, try getting an initial label
1328  * from the associated device driver.  This might work for all device
1329  * drivers that are able to fetch some initial device parameters
1330  * without even having access to a (BSD) disklabel, like SCSI disks,
1331  * most IDE drives, or vn devices.
1332  *
1333  * The device name must be given in its "canonical" form.
1334  */
1335 struct disklabel *
1336 getvirginlabel(void)
1337 {
1338         static struct disklabel lab;
1339         char namebuf[BBSIZE];
1340         int f;
1341
1342         if (dkname[0] == '/') {
1343                 warnx("\"auto\" requires the usage of a canonical disk name");
1344                 return (NULL);
1345         }
1346         (void)snprintf(namebuf, BBSIZE, "%sr%s", _PATH_DEV, dkname);
1347         if ((f = open(namebuf, O_RDONLY)) == -1) {
1348                 warn("cannot open %s", namebuf);
1349                 return (NULL);
1350         }
1351         if (ioctl(f, DIOCGDINFO, &lab) < 0) {
1352                 warn("ioctl DIOCGDINFO");
1353                 close(f);
1354                 return (NULL);
1355         }
1356         close(f);
1357         lab.d_boot0 = NULL;
1358         lab.d_boot1 = NULL;
1359         return (&lab);
1360 }
1361
1362 /*
1363  * If we are installing a boot program that doesn't fit in d_bbsize
1364  * we need to mark those partitions that the boot overflows into.
1365  * This allows newfs to prevent creation of a filesystem where it might
1366  * clobber bootstrap code.
1367  */
1368 void
1369 setbootflag(lp)
1370         register struct disklabel *lp;
1371 {
1372         register struct partition *pp;
1373         int i, errors = 0;
1374         char part;
1375         u_long boffset;
1376
1377         if (bootbuf == 0)
1378                 return;
1379         boffset = bootsize / lp->d_secsize;
1380         for (i = 0; i < lp->d_npartitions; i++) {
1381                 part = 'a' + i;
1382                 pp = &lp->d_partitions[i];
1383                 if (pp->p_size == 0)
1384                         continue;
1385                 if (boffset <= pp->p_offset) {
1386                         if (pp->p_fstype == FS_BOOT)
1387                                 pp->p_fstype = FS_UNUSED;
1388                 } else if (pp->p_fstype != FS_BOOT) {
1389                         if (pp->p_fstype != FS_UNUSED) {
1390                                 fprintf(stderr,
1391                                         "boot overlaps used partition %c\n",
1392                                         part);
1393                                 errors++;
1394                         } else {
1395                                 pp->p_fstype = FS_BOOT;
1396                                 Warning("boot overlaps partition %c, %s",
1397                                         part, "marked as FS_BOOT");
1398                         }
1399                 }
1400         }
1401         if (errors)
1402                 errx(4, "cannot install boot program");
1403 }
1404
1405 /*VARARGS1*/
1406 void
1407 Warning(char *fmt, ...)
1408 {
1409         va_list ap;
1410
1411         fprintf(stderr, "Warning, ");
1412         va_start(ap, fmt);
1413         vfprintf(stderr, fmt, ap);
1414         fprintf(stderr, "\n");
1415         va_end(ap);
1416 }
1417
1418 void
1419 usage()
1420 {
1421 #if NUMBOOT > 0
1422         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",
1423                 "usage: disklabel [-r] disk",
1424                 "\t\t(to read label)",
1425                 "       disklabel -w [-r] disk type [ packid ]",
1426                 "\t\t(to write label with existing boot program)",
1427                 "       disklabel -e [-r] disk",
1428                 "\t\t(to edit label)",
1429                 "       disklabel -R [-r] disk protofile",
1430                 "\t\t(to restore label with existing boot program)",
1431 #if NUMBOOT > 1
1432                 "       disklabel -B [ -b boot1 [ -s boot2 ] ] disk [ type ]",
1433                 "\t\t(to install boot program with existing label)",
1434                 "       disklabel -w -B [ -b boot1 [ -s boot2 ] ] disk type [ packid ]",
1435                 "\t\t(to write label and boot program)",
1436                 "       disklabel -R -B [ -b boot1 [ -s boot2 ] ] disk protofile [ type ]",
1437                 "\t\t(to restore label and boot program)",
1438 #else
1439                 "       disklabel -B [ -b bootprog ] disk [ type ]",
1440                 "\t\t(to install boot program with existing on-disk label)",
1441                 "       disklabel -w -B [ -b bootprog ] disk type [ packid ]",
1442                 "\t\t(to write label and install boot program)",
1443                 "       disklabel -R -B [ -b bootprog ] disk protofile [ type ]",
1444                 "\t\t(to restore label and install boot program)",
1445 #endif
1446                 "       disklabel [-NW] disk",
1447                 "\t\t(to write disable/enable label)");
1448 #else
1449         fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
1450                 "usage: disklabel [-r] disk", "(to read label)",
1451                 "       disklabel -w [-r] disk type [ packid ]",
1452                 "\t\t(to write label)",
1453                 "       disklabel -e [-r] disk",
1454                 "\t\t(to edit label)",
1455                 "       disklabel -R [-r] disk protofile",
1456                 "\t\t(to restore label)",
1457                 "       disklabel [-NW] disk",
1458                 "\t\t(to write disable/enable label)");
1459 #endif
1460         exit(1);
1461 }