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