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