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