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