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