]> CyberLeo.Net >> Repos - FreeBSD/releng/8.2.git/blob - sbin/bsdlabel/bsdlabel.c
MFS r217050: Make minidumps work on i386/XEN.
[FreeBSD/releng/8.2.git] / sbin / bsdlabel / bsdlabel.c
1 /*
2  * Copyright (c) 1994, 1995 Gordon W. Ross
3  * Copyright (c) 1994 Theo de Raadt
4  * All rights reserved.
5  * Copyright (c) 1987, 1993
6  *      The Regents of the University of California.  All rights reserved.
7  *
8  * This code is derived from software contributed to Berkeley by
9  * Symmetric Computer Systems.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. All advertising materials mentioning features or use of this software
20  *    must display the following acknowledgement:
21  *      This product includes software developed by the University of
22  *      California, Berkeley and its contributors.
23  *      This product includes software developed by Theo de Raadt.
24  * 4. Neither the name of the University nor the names of its contributors
25  *    may be used to endorse or promote products derived from this software
26  *    without specific prior written permission.
27  *
28  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38  * SUCH DAMAGE.
39  *
40  *      from: $NetBSD: disksubr.c,v 1.13 2000/12/17 22:39:18 pk $
41  */
42
43 #if 0
44 #ifndef lint
45 static const char copyright[] =
46 "@(#) Copyright (c) 1987, 1993\n\
47         The Regents of the University of California.  All rights reserved.\n";
48 #endif /* not lint */
49
50 #ifndef lint
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 /* not lint */
54 #endif
55 #include <sys/cdefs.h>
56 __FBSDID("$FreeBSD$");
57
58 #include <sys/param.h>
59 #include <stdint.h>
60 #include <sys/file.h>
61 #include <sys/stat.h>
62 #include <sys/wait.h>
63 #include <sys/disk.h>
64 #define DKTYPENAMES
65 #define FSTYPENAMES
66 #define MAXPARTITIONS   26
67 #include <sys/disklabel.h>
68
69 #include <unistd.h>
70 #include <string.h>
71 #include <stdio.h>
72 #include <libgeom.h>
73 #include <stdlib.h>
74 #include <signal.h>
75 #include <stdarg.h>
76 #include <ctype.h>
77 #include <err.h>
78 #include <errno.h>
79
80 #include "pathnames.h"
81
82 static void     makelabel(const char *, struct disklabel *);
83 static int      geom_bsd_available(void);
84 static int      writelabel(void);
85 static int      readlabel(int flag);
86 static void     display(FILE *, const struct disklabel *);
87 static int      edit(void);
88 static int      editit(void);
89 static void     fixlabel(struct disklabel *);
90 static char     *skip(char *);
91 static char     *word(char *);
92 static int      getasciilabel(FILE *, struct disklabel *);
93 static int      getasciipartspec(char *, struct disklabel *, int, int);
94 static int      checklabel(struct disklabel *);
95 static void     usage(void);
96 static struct disklabel *getvirginlabel(void);
97
98 #define DEFEDITOR       _PATH_VI
99 #define DEFPARTITIONS   8
100
101 static char     *specname;
102 static char     *pname;
103 static char     tmpfil[] = PATH_TMPFILE;
104
105 static struct   disklabel lab;
106 static u_char   bootarea[BBSIZE];
107 static off_t    mediasize;
108 static u_int    secsize;
109 static char     blank[] = "";
110 static char     unknown[] = "unknown";
111
112 #define MAX_PART ('z')
113 #define MAX_NUM_PARTS (1 + MAX_PART - 'a')
114 static char    part_size_type[MAX_NUM_PARTS];
115 static char    part_offset_type[MAX_NUM_PARTS];
116 static int     part_set[MAX_NUM_PARTS];
117
118 static int      installboot;    /* non-zero if we should install a boot program */
119 static int      allfields;      /* present all fields in edit */
120 static char const *xxboot;      /* primary boot */
121
122 static uint32_t lba_offset;
123 #ifndef LABELSECTOR
124 #define LABELSECTOR -1
125 #endif
126 #ifndef LABELOFFSET
127 #define LABELOFFSET -1
128 #endif
129 static int labelsoffset = LABELSECTOR;
130 static int labeloffset = LABELOFFSET;
131 static int bbsize = BBSIZE;
132 static int alphacksum =
133 #if defined(__alpha__)
134         1;
135 #else
136         0;
137 #endif
138
139 enum    {
140         UNSPEC, EDIT, READ, RESTORE, WRITE, WRITEBOOT
141 } op = UNSPEC;
142
143
144 static int      disable_write;   /* set to disable writing to disk label */
145 static int      is_file;        /* work on a file (abs. pathname), "-f" opt. */
146
147 int
148 main(int argc, char *argv[])
149 {
150         FILE *t;
151         int ch, error, fd;
152         const char *name;
153         
154         error = 0;
155         name = NULL;
156
157         while ((ch = getopt(argc, argv, "ABb:efm:nRrw")) != -1)
158                 switch (ch) {
159                         case 'A':
160                                 allfields = 1;
161                                 break;
162                         case 'B':
163                                 ++installboot;
164                                 break;
165                         case 'b':
166                                 xxboot = optarg;
167                                 break;
168                         case 'f':
169                                 is_file=1;
170                                 break;
171                         case 'm':
172                                 if (!strcmp(optarg, "i386") ||
173                                     !strcmp(optarg, "amd64") ||
174                                     !strcmp(optarg, "ia64") ||
175                                     !strcmp(optarg, "pc98")) {
176                                         labelsoffset = 1;
177                                         labeloffset = 0;
178                                         bbsize = 8192;
179                                         alphacksum = 0;
180                                 } else if (!strcmp(optarg, "alpha")) {
181                                         labelsoffset = 0;
182                                         labeloffset = 64;
183                                         bbsize = 8192;
184                                         alphacksum = 1;
185                                 } else {
186                                         errx(1, "Unsupported architecture");
187                                 }
188                                 break;
189                         case 'n':
190                                 disable_write = 1;
191                                 break;
192                         case 'R':
193                                 if (op != UNSPEC)
194                                         usage();
195                                 op = RESTORE;
196                                 break;
197                         case 'e':
198                                 if (op != UNSPEC)
199                                         usage();
200                                 op = EDIT;
201                                 break;
202                         case 'r':
203                                 /*
204                                  * We accept and ignode -r for compatibility with
205                                  * historically disklabel usage.
206                                  */
207                                 break;
208                         case 'w':
209                                 if (op != UNSPEC)
210                                         usage();
211                                 op = WRITE;
212                                 break;
213                         case '?':
214                         default:
215                                 usage();
216                 }
217         argc -= optind;
218         argv += optind;
219
220         if (argc < 1)
221                 usage();
222         if (labelsoffset < 0 || labeloffset < 0)
223                 errx(1, "a -m <architecture> option must be specified");
224
225         /* Figure out the names of the thing we're working on */
226         if (is_file) {
227                 specname = argv[0];
228         } else {
229                 specname = g_device_path(argv[0]);
230                 if (specname == NULL) {
231                         warn("unable to get correct path for %s", argv[0]);
232                         return(1);
233                 }
234                 fd = open(specname, O_RDONLY);
235                 if (fd < 0) {
236                         warn("error opening %s", specname);
237                         return(1);
238                 }
239                 pname = g_providername(fd);
240                 if (pname == NULL) {
241                         warn("error getting providername for %s", specname);
242                         close(fd);
243                         return(1);
244                 }
245                 close(fd);
246         }
247
248         if (installboot && op == UNSPEC)
249                 op = WRITEBOOT;
250         else if (op == UNSPEC)
251                 op = READ;
252
253         switch(op) {
254
255         case UNSPEC:
256                 break;
257
258         case EDIT:
259                 if (argc != 1)
260                         usage();
261                 readlabel(1);
262                 fixlabel(&lab);
263                 error = edit();
264                 break;
265
266         case READ:
267                 if (argc != 1)
268                         usage();
269                 readlabel(1);
270                 display(stdout, NULL);
271                 error = checklabel(NULL);
272                 break;
273
274         case RESTORE:
275                 if (argc != 2)
276                         usage();
277                 if (!(t = fopen(argv[1], "r")))
278                         err(4, "fopen %s", argv[1]);
279                 readlabel(0);
280                 if (!getasciilabel(t, &lab))
281                         exit(1);
282                 error = writelabel();
283                 break;
284
285         case WRITE:
286                 if (argc == 2)
287                         name = argv[1];
288                 else if (argc == 1)
289                         name = "auto";
290                 else
291                         usage();
292                 readlabel(0);
293                 makelabel(name, &lab);
294                 fixlabel(&lab);
295                 if (checklabel(NULL) == 0)
296                         error = writelabel();
297                 break;
298
299         case WRITEBOOT:
300
301                 readlabel(1);
302                 fixlabel(&lab);
303                 if (argc == 2)
304                         makelabel(argv[1], &lab);
305                 if (checklabel(NULL) == 0)
306                         error = writelabel();
307                 break;
308         }
309         exit(error);
310 }
311
312 static void
313 fixlabel(struct disklabel *lp)
314 {
315         struct partition *dp;
316         int i;
317
318         for (i = 0; i < lp->d_npartitions; i++) {
319                 if (i == RAW_PART)
320                         continue;
321                 if (lp->d_partitions[i].p_size)
322                         return;
323         }
324
325         dp = &lp->d_partitions[0];
326         dp->p_offset = BBSIZE / secsize;
327         dp->p_size = lp->d_secperunit - dp->p_offset;
328 }
329
330 /*
331  * Construct a prototype disklabel from /etc/disktab.
332  */
333 static void
334 makelabel(const char *type, struct disklabel *lp)
335 {
336         struct disklabel *dp;
337
338         if (strcmp(type, "auto") == 0)
339                 dp = getvirginlabel();
340         else
341                 dp = getdiskbyname(type);
342         if (dp == NULL)
343                 errx(1, "%s: unknown disk type", type);
344         *lp = *dp;
345         bzero(lp->d_packname, sizeof(lp->d_packname));
346 }
347
348 static void
349 readboot(void)
350 {
351         int fd;
352         struct stat st;
353         uint64_t *p;
354
355         if (xxboot == NULL)
356                 xxboot = "/boot/boot";
357         fd = open(xxboot, O_RDONLY);
358         if (fd < 0)
359                 err(1, "cannot open %s", xxboot);
360         fstat(fd, &st);
361         if (alphacksum && st.st_size <= BBSIZE - 512) {
362                 if (read(fd, bootarea + 512, st.st_size) != st.st_size)
363                         err(1, "read error %s", xxboot);
364
365                 /*
366                  * Set the location and length so SRM can find the
367                  * boot blocks.
368                  */
369                 p = (uint64_t *)bootarea;
370                 p[60] = (st.st_size + secsize - 1) / secsize;
371                 p[61] = 1;
372                 p[62] = 0;
373                 return;
374         } else if ((!alphacksum) && st.st_size <= BBSIZE) {
375                 if (read(fd, bootarea, st.st_size) != st.st_size)
376                         err(1, "read error %s", xxboot);
377                 return;
378         }
379         errx(1, "boot code %s is wrong size", xxboot);
380 }
381
382 static int
383 geom_bsd_available(void)
384 {
385         struct gclass *class;
386         struct gmesh mesh;
387         int error;
388
389         error = geom_gettree(&mesh);
390         if (error != 0)
391                 errc(1, error, "Cannot get GEOM tree");
392
393         LIST_FOREACH(class, &mesh.lg_class, lg_class) {
394                 if (strcmp(class->lg_name, "BSD") == 0) {
395                         geom_deletetree(&mesh);
396                         return (1);
397                 }
398         }
399
400         geom_deletetree(&mesh);
401
402         return (0);
403 }
404
405 static int
406 writelabel(void)
407 {
408         uint64_t *p, sum;
409         int i, fd, serrno;
410         struct gctl_req *grq;
411         char const *errstr;
412         struct disklabel *lp = &lab;
413
414         if (disable_write) {
415                 warnx("write to disk label supressed - label was as follows:");
416                 display(stdout, NULL);
417                 return (0);
418         }
419
420         lp->d_magic = DISKMAGIC;
421         lp->d_magic2 = DISKMAGIC;
422         lp->d_checksum = 0;
423         lp->d_checksum = dkcksum(lp);
424         if (installboot)
425                 readboot();
426         for (i = 0; i < lab.d_npartitions; i++)
427                 if (lab.d_partitions[i].p_size)
428                         lab.d_partitions[i].p_offset += lba_offset;
429         bsd_disklabel_le_enc(bootarea + labeloffset + labelsoffset * secsize,
430             lp);
431         if (alphacksum) {
432                 /* Generate the bootblock checksum for the SRM console.  */
433                 for (p = (uint64_t *)bootarea, i = 0, sum = 0; i < 63; i++)
434                         sum += p[i];
435                 p[63] = sum;
436         }
437
438         fd = open(specname, O_RDWR);
439         if (fd < 0) {
440                 if (is_file) {
441                         warn("cannot open file %s for writing label", specname);
442                         return(1);
443                 } else
444                         serrno = errno;
445
446                 /* Give up if GEOM_BSD is not available. */
447                 if (geom_bsd_available() == 0) {
448                         warnc(serrno, "%s", specname);
449                         return (1);
450                 }
451
452                 grq = gctl_get_handle();
453                 gctl_ro_param(grq, "verb", -1, "write label");
454                 gctl_ro_param(grq, "class", -1, "BSD");
455                 gctl_ro_param(grq, "geom", -1, pname);
456                 gctl_ro_param(grq, "label", 148+16*8,
457                         bootarea + labeloffset + labelsoffset * secsize);
458                 errstr = gctl_issue(grq);
459                 if (errstr != NULL) {
460                         warnx("%s", errstr);
461                         gctl_free(grq);
462                         return(1);
463                 }
464                 gctl_free(grq);
465                 if (installboot) {
466                         grq = gctl_get_handle();
467                         gctl_ro_param(grq, "verb", -1, "write bootcode");
468                         gctl_ro_param(grq, "class", -1, "BSD");
469                         gctl_ro_param(grq, "geom", -1, pname);
470                         gctl_ro_param(grq, "bootcode", BBSIZE, bootarea);
471                         errstr = gctl_issue(grq);
472                         if (errstr != NULL) {
473                                 warnx("%s", errstr);
474                                 gctl_free(grq);
475                                 return (1);
476                         }
477                         gctl_free(grq);
478                 }
479         } else {
480                 if (write(fd, bootarea, bbsize) != bbsize) {
481                         warn("write %s", specname);
482                         close (fd);
483                         return (1);
484                 }
485                 close (fd);
486         }
487         return (0);
488 }
489
490 static void
491 get_file_parms(int f)
492 {
493         int i;
494         struct stat sb;
495
496         if (fstat(f, &sb) != 0)
497                 err(4, "fstat failed");
498         i = sb.st_mode & S_IFMT;
499         if (i != S_IFREG && i != S_IFLNK)
500                 errx(4, "%s is not a valid file or link", specname);
501         secsize = DEV_BSIZE;
502         mediasize = sb.st_size;
503 }
504
505 /*
506  * Fetch disklabel for disk.
507  */
508 static int
509 readlabel(int flag)
510 {
511         ssize_t nbytes;
512         uint32_t lba;
513         int f, i;
514         int error;
515
516         f = open(specname, O_RDONLY);
517         if (f < 0)
518                 err(1, specname);
519         if (is_file)
520                 get_file_parms(f);
521         else {
522                 mediasize = g_mediasize(f);
523                 secsize = g_sectorsize(f);
524                 if (secsize < 0 || mediasize < 0)
525                         err(4, "cannot get disk geometry");
526         }
527         if (mediasize > (off_t)0xffffffff * secsize)
528                 errx(1,
529                     "disks with more than 2^32-1 sectors are not supported");
530         (void)lseek(f, (off_t)0, SEEK_SET);
531         nbytes = read(f, bootarea, BBSIZE);
532         if (nbytes == -1)
533                 err(4, "%s read", specname);
534         if (nbytes != BBSIZE)
535                 errx(4, "couldn't read %d bytes from %s", BBSIZE, specname);
536         close (f);
537         error = bsd_disklabel_le_dec(
538             bootarea + (labeloffset + labelsoffset * secsize),
539             &lab, MAXPARTITIONS);
540         if (flag && error)
541                 errx(1, "%s: no valid label found", specname);
542
543         if (is_file)
544                 return(0);
545
546         /*
547          * Compensate for absolute block addressing by finding the
548          * smallest partition offset and if the offset of the 'c'
549          * partition is equal to that, subtract it from all offsets.
550          */
551         lba = ~0;
552         for (i = 0; i < lab.d_npartitions; i++) {
553                 if (lab.d_partitions[i].p_size)
554                         lba = MIN(lba, lab.d_partitions[i].p_offset);
555         }
556         if (lba != 0 && lab.d_partitions[RAW_PART].p_offset == lba) {
557                 for (i = 0; i < lab.d_npartitions; i++) {
558                         if (lab.d_partitions[i].p_size)
559                                 lab.d_partitions[i].p_offset -= lba;
560                 }
561                 /*
562                  * Save the offset so that we can write the label
563                  * back with absolute block addresses.
564                  */
565                 lba_offset = lba;
566         }
567         return (error);
568 }
569
570
571 static void
572 display(FILE *f, const struct disklabel *lp)
573 {
574         int i, j;
575         const struct partition *pp;
576
577         if (lp == NULL)
578                 lp = &lab;
579
580         fprintf(f, "# %s:\n", specname);
581         if (allfields) {
582                 if (lp->d_type < DKMAXTYPES)
583                         fprintf(f, "type: %s\n", dktypenames[lp->d_type]);
584                 else
585                         fprintf(f, "type: %u\n", lp->d_type);
586                 fprintf(f, "disk: %.*s\n", (int)sizeof(lp->d_typename),
587                         lp->d_typename);
588                 fprintf(f, "label: %.*s\n", (int)sizeof(lp->d_packname),
589                         lp->d_packname);
590                 fprintf(f, "flags:");
591                 if (lp->d_flags & D_REMOVABLE)
592                         fprintf(f, " removeable");
593                 if (lp->d_flags & D_ECC)
594                         fprintf(f, " ecc");
595                 if (lp->d_flags & D_BADSECT)
596                         fprintf(f, " badsect");
597                 fprintf(f, "\n");
598                 fprintf(f, "bytes/sector: %lu\n", (u_long)lp->d_secsize);
599                 fprintf(f, "sectors/track: %lu\n", (u_long)lp->d_nsectors);
600                 fprintf(f, "tracks/cylinder: %lu\n", (u_long)lp->d_ntracks);
601                 fprintf(f, "sectors/cylinder: %lu\n", (u_long)lp->d_secpercyl);
602                 fprintf(f, "cylinders: %lu\n", (u_long)lp->d_ncylinders);
603                 fprintf(f, "sectors/unit: %lu\n", (u_long)lp->d_secperunit);
604                 fprintf(f, "rpm: %u\n", lp->d_rpm);
605                 fprintf(f, "interleave: %u\n", lp->d_interleave);
606                 fprintf(f, "trackskew: %u\n", lp->d_trackskew);
607                 fprintf(f, "cylinderskew: %u\n", lp->d_cylskew);
608                 fprintf(f, "headswitch: %lu\t\t# milliseconds\n",
609                     (u_long)lp->d_headswitch);
610                 fprintf(f, "track-to-track seek: %ld\t# milliseconds\n",
611                     (u_long)lp->d_trkseek);
612                 fprintf(f, "drivedata: ");
613                 for (i = NDDATA - 1; i >= 0; i--)
614                         if (lp->d_drivedata[i])
615                                 break;
616                 if (i < 0)
617                         i = 0;
618                 for (j = 0; j <= i; j++)
619                         fprintf(f, "%lu ", (u_long)lp->d_drivedata[j]);
620                 fprintf(f, "\n\n");
621         }
622         fprintf(f, "%u partitions:\n", lp->d_npartitions);
623         fprintf(f,
624             "#        size   offset    fstype   [fsize bsize bps/cpg]\n");
625         pp = lp->d_partitions;
626         for (i = 0; i < lp->d_npartitions; i++, pp++) {
627                 if (pp->p_size) {
628                         fprintf(f, "  %c: %8lu %8lu  ", 'a' + i,
629                            (u_long)pp->p_size, (u_long)pp->p_offset);
630                         if (pp->p_fstype < FSMAXTYPES)
631                                 fprintf(f, "%8.8s", fstypenames[pp->p_fstype]);
632                         else
633                                 fprintf(f, "%8d", pp->p_fstype);
634                         switch (pp->p_fstype) {
635
636                         case FS_UNUSED:                         /* XXX */
637                                 fprintf(f, "    %5lu %5lu %5.5s ",
638                                     (u_long)pp->p_fsize,
639                                     (u_long)(pp->p_fsize * pp->p_frag), "");
640                                 break;
641
642                         case FS_BSDFFS:
643                                 fprintf(f, "    %5lu %5lu %5u ",
644                                     (u_long)pp->p_fsize,
645                                     (u_long)(pp->p_fsize * pp->p_frag),
646                                     pp->p_cpg);
647                                 break;
648
649                         case FS_BSDLFS:
650                                 fprintf(f, "    %5lu %5lu %5d",
651                                     (u_long)pp->p_fsize,
652                                     (u_long)(pp->p_fsize * pp->p_frag),
653                                     pp->p_cpg);
654                                 break;
655
656                         default:
657                                 fprintf(f, "%20.20s", "");
658                                 break;
659                         }
660                         if (i == RAW_PART) {
661                                 fprintf(f, "  # \"raw\" part, don't edit");
662                         }
663                         fprintf(f, "\n");
664                 }
665         }
666         fflush(f);
667 }
668
669 static int
670 edit(void)
671 {
672         int c, fd;
673         struct disklabel label;
674         FILE *fp;
675
676         if ((fd = mkstemp(tmpfil)) == -1 ||
677             (fp = fdopen(fd, "w")) == NULL) {
678                 warnx("can't create %s", tmpfil);
679                 return (1);
680         }
681         display(fp, NULL);
682         fclose(fp);
683         for (;;) {
684                 if (!editit())
685                         break;
686                 fp = fopen(tmpfil, "r");
687                 if (fp == NULL) {
688                         warnx("can't reopen %s for reading", tmpfil);
689                         break;
690                 }
691                 bzero((char *)&label, sizeof(label));
692                 c = getasciilabel(fp, &label);
693                 fclose(fp);
694                 if (c) {
695                         lab = label;
696                         if (writelabel() == 0) {
697                                 (void) unlink(tmpfil);
698                                 return (0);
699                         }
700                 }
701                 printf("re-edit the label? [y]: ");
702                 fflush(stdout);
703                 c = getchar();
704                 if (c != EOF && c != (int)'\n')
705                         while (getchar() != (int)'\n')
706                                 ;
707                 if  (c == (int)'n')
708                         break;
709         }
710         (void) unlink(tmpfil);
711         return (1);
712 }
713
714 static int
715 editit(void)
716 {
717         int pid, xpid;
718         int locstat, omask;
719         const char *ed;
720
721         omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP));
722         while ((pid = fork()) < 0) {
723                 if (errno == EPROCLIM) {
724                         warnx("you have too many processes");
725                         return(0);
726                 }
727                 if (errno != EAGAIN) {
728                         warn("fork");
729                         return(0);
730                 }
731                 sleep(1);
732         }
733         if (pid == 0) {
734                 sigsetmask(omask);
735                 setgid(getgid());
736                 setuid(getuid());
737                 if ((ed = getenv("EDITOR")) == (char *)0)
738                         ed = DEFEDITOR;
739                 execlp(ed, ed, tmpfil, (char *)0);
740                 err(1, "%s", ed);
741         }
742         while ((xpid = wait(&locstat)) >= 0)
743                 if (xpid == pid)
744                         break;
745         sigsetmask(omask);
746         return(!locstat);
747 }
748
749 static char *
750 skip(char *cp)
751 {
752
753         while (*cp != '\0' && isspace(*cp))
754                 cp++;
755         if (*cp == '\0' || *cp == '#')
756                 return (NULL);
757         return (cp);
758 }
759
760 static char *
761 word(char *cp)
762 {
763         char c;
764
765         while (*cp != '\0' && !isspace(*cp) && *cp != '#')
766                 cp++;
767         if ((c = *cp) != '\0') {
768                 *cp++ = '\0';
769                 if (c != '#')
770                         return (skip(cp));
771         }
772         return (NULL);
773 }
774
775 /*
776  * Read an ascii label in from fd f,
777  * in the same format as that put out by display(),
778  * and fill in lp.
779  */
780 static int
781 getasciilabel(FILE *f, struct disklabel *lp)
782 {
783         char *cp, *endp;
784         const char **cpp;
785         u_int part;
786         char *tp, line[BUFSIZ];
787         u_long v;
788         int lineno = 0, errors = 0;
789         int i;
790
791         makelabel("auto", lp);
792         bzero(&part_set, sizeof(part_set));
793         bzero(&part_size_type, sizeof(part_size_type));
794         bzero(&part_offset_type, sizeof(part_offset_type));
795         lp->d_bbsize = BBSIZE;                          /* XXX */
796         lp->d_sbsize = 0;                               /* XXX */
797         while (fgets(line, sizeof(line) - 1, f)) {
798                 lineno++;
799                 if ((cp = index(line,'\n')) != 0)
800                         *cp = '\0';
801                 cp = skip(line);
802                 if (cp == NULL)
803                         continue;
804                 tp = index(cp, ':');
805                 if (tp == NULL) {
806                         fprintf(stderr, "line %d: syntax error\n", lineno);
807                         errors++;
808                         continue;
809                 }
810                 *tp++ = '\0', tp = skip(tp);
811                 if (!strcmp(cp, "type")) {
812                         if (tp == NULL)
813                                 tp = unknown;
814                         cpp = dktypenames;
815                         for (; cpp < &dktypenames[DKMAXTYPES]; cpp++)
816                                 if (*cpp && !strcmp(*cpp, tp)) {
817                                         lp->d_type = cpp - dktypenames;
818                                         break;
819                                 }
820                         if (cpp < &dktypenames[DKMAXTYPES])
821                                 continue;
822                         errno = 0;
823                         v = strtoul(tp, &endp, 10);
824                         if (errno != 0 || *endp != '\0')
825                                 v = DKMAXTYPES;
826                         if (v >= DKMAXTYPES)
827                                 fprintf(stderr, "line %d:%s %lu\n", lineno,
828                                     "Warning, unknown disk type", v);
829                         else
830                                 lp->d_type = v;
831                         continue;
832                 }
833                 if (!strcmp(cp, "flags")) {
834                         for (v = 0; (cp = tp) && *cp != '\0';) {
835                                 tp = word(cp);
836                                 if (!strcmp(cp, "removeable"))
837                                         v |= D_REMOVABLE;
838                                 else if (!strcmp(cp, "ecc"))
839                                         v |= D_ECC;
840                                 else if (!strcmp(cp, "badsect"))
841                                         v |= D_BADSECT;
842                                 else {
843                                         fprintf(stderr,
844                                             "line %d: %s: bad flag\n",
845                                             lineno, cp);
846                                         errors++;
847                                 }
848                         }
849                         lp->d_flags = v;
850                         continue;
851                 }
852                 if (!strcmp(cp, "drivedata")) {
853                         for (i = 0; (cp = tp) && *cp != '\0' && i < NDDATA;) {
854                                 lp->d_drivedata[i++] = strtoul(cp, NULL, 10);
855                                 tp = word(cp);
856                         }
857                         continue;
858                 }
859                 if (sscanf(cp, "%lu partitions", &v) == 1) {
860                         if (v == 0 || v > MAXPARTITIONS) {
861                                 fprintf(stderr,
862                                     "line %d: bad # of partitions\n", lineno);
863                                 lp->d_npartitions = MAXPARTITIONS;
864                                 errors++;
865                         } else
866                                 lp->d_npartitions = v;
867                         continue;
868                 }
869                 if (tp == NULL)
870                         tp = blank;
871                 if (!strcmp(cp, "disk")) {
872                         strncpy(lp->d_typename, tp, sizeof (lp->d_typename));
873                         continue;
874                 }
875                 if (!strcmp(cp, "label")) {
876                         strncpy(lp->d_packname, tp, sizeof (lp->d_packname));
877                         continue;
878                 }
879                 if (!strcmp(cp, "bytes/sector")) {
880                         v = strtoul(tp, NULL, 10);
881                         if (v == 0 || (v % DEV_BSIZE) != 0) {
882                                 fprintf(stderr,
883                                     "line %d: %s: bad sector size\n",
884                                     lineno, tp);
885                                 errors++;
886                         } else
887                                 lp->d_secsize = v;
888                         continue;
889                 }
890                 if (!strcmp(cp, "sectors/track")) {
891                         v = strtoul(tp, NULL, 10);
892 #if (ULONG_MAX != 0xffffffffUL)
893                         if (v == 0 || v > 0xffffffff)
894 #else
895                         if (v == 0)
896 #endif
897                         {
898                                 fprintf(stderr, "line %d: %s: bad %s\n",
899                                     lineno, tp, cp);
900                                 errors++;
901                         } else
902                                 lp->d_nsectors = v;
903                         continue;
904                 }
905                 if (!strcmp(cp, "sectors/cylinder")) {
906                         v = strtoul(tp, NULL, 10);
907                         if (v == 0) {
908                                 fprintf(stderr, "line %d: %s: bad %s\n",
909                                     lineno, tp, cp);
910                                 errors++;
911                         } else
912                                 lp->d_secpercyl = v;
913                         continue;
914                 }
915                 if (!strcmp(cp, "tracks/cylinder")) {
916                         v = strtoul(tp, NULL, 10);
917                         if (v == 0) {
918                                 fprintf(stderr, "line %d: %s: bad %s\n",
919                                     lineno, tp, cp);
920                                 errors++;
921                         } else
922                                 lp->d_ntracks = v;
923                         continue;
924                 }
925                 if (!strcmp(cp, "cylinders")) {
926                         v = strtoul(tp, NULL, 10);
927                         if (v == 0) {
928                                 fprintf(stderr, "line %d: %s: bad %s\n",
929                                     lineno, tp, cp);
930                                 errors++;
931                         } else
932                                 lp->d_ncylinders = v;
933                         continue;
934                 }
935                 if (!strcmp(cp, "sectors/unit")) {
936                         v = strtoul(tp, NULL, 10);
937                         if (v == 0) {
938                                 fprintf(stderr, "line %d: %s: bad %s\n",
939                                     lineno, tp, cp);
940                                 errors++;
941                         } else
942                                 lp->d_secperunit = v;
943                         continue;
944                 }
945                 if (!strcmp(cp, "rpm")) {
946                         v = strtoul(tp, NULL, 10);
947                         if (v == 0 || v > USHRT_MAX) {
948                                 fprintf(stderr, "line %d: %s: bad %s\n",
949                                     lineno, tp, cp);
950                                 errors++;
951                         } else
952                                 lp->d_rpm = v;
953                         continue;
954                 }
955                 if (!strcmp(cp, "interleave")) {
956                         v = strtoul(tp, NULL, 10);
957                         if (v == 0 || v > USHRT_MAX) {
958                                 fprintf(stderr, "line %d: %s: bad %s\n",
959                                     lineno, tp, cp);
960                                 errors++;
961                         } else
962                                 lp->d_interleave = v;
963                         continue;
964                 }
965                 if (!strcmp(cp, "trackskew")) {
966                         v = strtoul(tp, NULL, 10);
967                         if (v > USHRT_MAX) {
968                                 fprintf(stderr, "line %d: %s: bad %s\n",
969                                     lineno, tp, cp);
970                                 errors++;
971                         } else
972                                 lp->d_trackskew = v;
973                         continue;
974                 }
975                 if (!strcmp(cp, "cylinderskew")) {
976                         v = strtoul(tp, NULL, 10);
977                         if (v > USHRT_MAX) {
978                                 fprintf(stderr, "line %d: %s: bad %s\n",
979                                     lineno, tp, cp);
980                                 errors++;
981                         } else
982                                 lp->d_cylskew = v;
983                         continue;
984                 }
985                 if (!strcmp(cp, "headswitch")) {
986                         v = strtoul(tp, NULL, 10);
987                         lp->d_headswitch = v;
988                         continue;
989                 }
990                 if (!strcmp(cp, "track-to-track seek")) {
991                         v = strtoul(tp, NULL, 10);
992                         lp->d_trkseek = v;
993                         continue;
994                 }
995                 /* the ':' was removed above */
996                 if (*cp < 'a' || *cp > MAX_PART || cp[1] != '\0') {
997                         fprintf(stderr,
998                             "line %d: %s: Unknown disklabel field\n", lineno,
999                             cp);
1000                         errors++;
1001                         continue;
1002                 }
1003
1004                 /* Process a partition specification line. */
1005                 part = *cp - 'a';
1006                 if (part >= lp->d_npartitions) {
1007                         fprintf(stderr,
1008                             "line %d: partition name out of range a-%c: %s\n",
1009                             lineno, 'a' + lp->d_npartitions - 1, cp);
1010                         errors++;
1011                         continue;
1012                 }
1013                 part_set[part] = 1;
1014
1015                 if (getasciipartspec(tp, lp, part, lineno) != 0) {
1016                         errors++;
1017                         break;
1018                 }
1019         }
1020         errors += checklabel(lp);
1021         return (errors == 0);
1022 }
1023
1024 #define NXTNUM(n) do { \
1025         if (tp == NULL) { \
1026                 fprintf(stderr, "line %d: too few numeric fields\n", lineno); \
1027                 return (1); \
1028         } else { \
1029                 cp = tp, tp = word(cp); \
1030                 (n) = strtoul(cp, NULL, 10); \
1031         } \
1032 } while (0)
1033
1034 /* retain 1 character following number */
1035 #define NXTWORD(w,n) do { \
1036         if (tp == NULL) { \
1037                 fprintf(stderr, "line %d: too few numeric fields\n", lineno); \
1038                 return (1); \
1039         } else { \
1040                 char *tmp; \
1041                 cp = tp, tp = word(cp); \
1042                 (n) = strtoul(cp, &tmp, 10); \
1043                 if (tmp) (w) = *tmp; \
1044         } \
1045 } while (0)
1046
1047 /*
1048  * Read a partition line into partition `part' in the specified disklabel.
1049  * Return 0 on success, 1 on failure.
1050  */
1051 static int
1052 getasciipartspec(char *tp, struct disklabel *lp, int part, int lineno)
1053 {
1054         struct partition *pp;
1055         char *cp, *endp;
1056         const char **cpp;
1057         u_long v;
1058
1059         pp = &lp->d_partitions[part];
1060         cp = NULL;
1061
1062         v = 0;
1063         NXTWORD(part_size_type[part],v);
1064         if (v == 0 && part_size_type[part] != '*') {
1065                 fprintf(stderr,
1066                     "line %d: %s: bad partition size\n", lineno, cp);
1067                 return (1);
1068         }
1069         pp->p_size = v;
1070
1071         v = 0;
1072         NXTWORD(part_offset_type[part],v);
1073         if (v == 0 && part_offset_type[part] != '*' &&
1074             part_offset_type[part] != '\0') {
1075                 fprintf(stderr,
1076                     "line %d: %s: bad partition offset\n", lineno, cp);
1077                 return (1);
1078         }
1079         pp->p_offset = v;
1080         if (tp == NULL) {
1081                 fprintf(stderr, "line %d: missing file system type\n", lineno);
1082                 return (1);
1083         }
1084         cp = tp, tp = word(cp);
1085         for (cpp = fstypenames; cpp < &fstypenames[FSMAXTYPES]; cpp++)
1086                 if (*cpp && !strcmp(*cpp, cp))
1087                         break;
1088         if (*cpp != NULL) {
1089                 pp->p_fstype = cpp - fstypenames;
1090         } else {
1091                 if (isdigit(*cp)) {
1092                         errno = 0;
1093                         v = strtoul(cp, &endp, 10);
1094                         if (errno != 0 || *endp != '\0')
1095                                 v = FSMAXTYPES;
1096                 } else
1097                         v = FSMAXTYPES;
1098                 if (v >= FSMAXTYPES) {
1099                         fprintf(stderr,
1100                             "line %d: Warning, unknown file system type %s\n",
1101                             lineno, cp);
1102                         v = FS_UNUSED;
1103                 }
1104                 pp->p_fstype = v;
1105         }
1106
1107         switch (pp->p_fstype) {
1108         case FS_UNUSED:
1109         case FS_BSDFFS:
1110         case FS_BSDLFS:
1111                 /* accept defaults for fsize/frag/cpg */
1112                 if (tp) {
1113                         NXTNUM(pp->p_fsize);
1114                         if (pp->p_fsize == 0)
1115                                 break;
1116                         NXTNUM(v);
1117                         pp->p_frag = v / pp->p_fsize;
1118                         if (tp != NULL)
1119                                 NXTNUM(pp->p_cpg);
1120                 }
1121                 /* else default to 0's */
1122                 break;
1123         default:
1124                 break;
1125         }
1126         return (0);
1127 }
1128
1129 /*
1130  * Check disklabel for errors and fill in
1131  * derived fields according to supplied values.
1132  */
1133 static int
1134 checklabel(struct disklabel *lp)
1135 {
1136         struct partition *pp;
1137         int i, errors = 0;
1138         char part;
1139         u_long base_offset, needed, total_size, total_percent, current_offset;
1140         long free_space;
1141         int seen_default_offset;
1142         int hog_part;
1143         int j;
1144         struct partition *pp2;
1145
1146         if (lp == NULL)
1147                 lp = &lab;
1148
1149         if (allfields) {
1150
1151                 if (lp->d_secsize == 0) {
1152                         fprintf(stderr, "sector size 0\n");
1153                         return (1);
1154                 }
1155                 if (lp->d_nsectors == 0) {
1156                         fprintf(stderr, "sectors/track 0\n");
1157                         return (1);
1158                 }
1159                 if (lp->d_ntracks == 0) {
1160                         fprintf(stderr, "tracks/cylinder 0\n");
1161                         return (1);
1162                 }
1163                 if  (lp->d_ncylinders == 0) {
1164                         fprintf(stderr, "cylinders/unit 0\n");
1165                         errors++;
1166                 }
1167                 if (lp->d_rpm == 0)
1168                         warnx("revolutions/minute 0");
1169                 if (lp->d_secpercyl == 0)
1170                         lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks;
1171                 if (lp->d_secperunit == 0)
1172                         lp->d_secperunit = lp->d_secpercyl * lp->d_ncylinders;
1173                 if (lp->d_bbsize == 0) {
1174                         fprintf(stderr, "boot block size 0\n");
1175                         errors++;
1176                 } else if (lp->d_bbsize % lp->d_secsize)
1177                         warnx("boot block size %% sector-size != 0");
1178                 if (lp->d_npartitions > MAXPARTITIONS)
1179                         warnx("number of partitions (%lu) > MAXPARTITIONS (%d)",
1180                             (u_long)lp->d_npartitions, MAXPARTITIONS);
1181         } else {
1182                 struct disklabel *vl;
1183
1184                 vl = getvirginlabel();
1185                 lp->d_secsize = vl->d_secsize;
1186                 lp->d_nsectors = vl->d_nsectors;
1187                 lp->d_ntracks = vl->d_ntracks;
1188                 lp->d_ncylinders = vl->d_ncylinders;
1189                 lp->d_rpm = vl->d_rpm;
1190                 lp->d_interleave = vl->d_interleave;
1191                 lp->d_secpercyl = vl->d_secpercyl;
1192                 lp->d_secperunit = vl->d_secperunit;
1193                 lp->d_bbsize = vl->d_bbsize;
1194                 lp->d_npartitions = vl->d_npartitions;
1195         }
1196
1197
1198         /* first allocate space to the partitions, then offsets */
1199         total_size = 0; /* in sectors */
1200         total_percent = 0; /* in percent */
1201         hog_part = -1;
1202         /* find all fixed partitions */
1203         for (i = 0; i < lp->d_npartitions; i++) {
1204                 pp = &lp->d_partitions[i];
1205                 if (part_set[i]) {
1206                         if (part_size_type[i] == '*') {
1207                                 if (i == RAW_PART) {
1208                                         pp->p_size = lp->d_secperunit;
1209                                 } else {
1210                                         if (hog_part != -1)
1211                                                 warnx("Too many '*' partitions (%c and %c)",
1212                                                     hog_part + 'a',i + 'a');
1213                                         else
1214                                                 hog_part = i;
1215                                 }
1216                         } else {
1217                                 off_t size;
1218
1219                                 size = pp->p_size;
1220                                 switch (part_size_type[i]) {
1221                                 case '%':
1222                                         total_percent += size;
1223                                         break;
1224                                 case 't':
1225                                 case 'T':
1226                                         size *= 1024ULL;
1227                                         /* FALLTHROUGH */
1228                                 case 'g':
1229                                 case 'G':
1230                                         size *= 1024ULL;
1231                                         /* FALLTHROUGH */
1232                                 case 'm':
1233                                 case 'M':
1234                                         size *= 1024ULL;
1235                                         /* FALLTHROUGH */
1236                                 case 'k':
1237                                 case 'K':
1238                                         size *= 1024ULL;
1239                                         break;
1240                                 case '\0':
1241                                         break;
1242                                 default:
1243                                         warnx("unknown multiplier suffix '%c' for partition %c (should be K, M, G or T)",
1244                                             part_size_type[i], i + 'a');
1245                                         break;
1246                                 }
1247                                 /* don't count %'s yet */
1248                                 if (part_size_type[i] != '%') {
1249                                         /*
1250                                          * for all not in sectors, convert to
1251                                          * sectors
1252                                          */
1253                                         if (part_size_type[i] != '\0') {
1254                                                 if (size % lp->d_secsize != 0)
1255                                                         warnx("partition %c not an integer number of sectors",
1256                                                             i + 'a');
1257                                                 size /= lp->d_secsize;
1258                                                 pp->p_size = size;
1259                                         }
1260                                         /* else already in sectors */
1261                                         if (i != RAW_PART)
1262                                                 total_size += size;
1263                                 }
1264                         }
1265                 }
1266         }
1267
1268         /* Find out the total free space, excluding the boot block area. */
1269         base_offset = BBSIZE / secsize;
1270         free_space = 0;
1271         for (i = 0; i < lp->d_npartitions; i++) {
1272                 pp = &lp->d_partitions[i];
1273                 if (!part_set[i] || i == RAW_PART ||
1274                     part_size_type[i] == '%' || part_size_type[i] == '*')
1275                         continue;
1276                 if (pp->p_offset > base_offset)
1277                         free_space += pp->p_offset - base_offset;
1278                 if (pp->p_offset + pp->p_size > base_offset)
1279                         base_offset = pp->p_offset + pp->p_size;
1280         }
1281         if (base_offset < lp->d_secperunit)
1282                 free_space += lp->d_secperunit - base_offset;
1283
1284         /* handle % partitions - note %'s don't need to add up to 100! */
1285         if (total_percent != 0) {
1286                 if (total_percent > 100) {
1287                         fprintf(stderr,"total percentage %lu is greater than 100\n",
1288                             total_percent);
1289                         errors++;
1290                 }
1291
1292                 if (free_space > 0) {
1293                         for (i = 0; i < lp->d_npartitions; i++) {
1294                                 pp = &lp->d_partitions[i];
1295                                 if (part_set[i] && part_size_type[i] == '%') {
1296                                         /* careful of overflows! and integer roundoff */
1297                                         pp->p_size = ((double)pp->p_size/100) * free_space;
1298                                         total_size += pp->p_size;
1299
1300                                         /* FIX we can lose a sector or so due to roundoff per
1301                                            partition.  A more complex algorithm could avoid that */
1302                                 }
1303                         }
1304                 } else {
1305                         fprintf(stderr,
1306                             "%ld sectors available to give to '*' and '%%' partitions\n",
1307                             free_space);
1308                         errors++;
1309                         /* fix?  set all % partitions to size 0? */
1310                 }
1311         }
1312         /* give anything remaining to the hog partition */
1313         if (hog_part != -1) {
1314                 /*
1315                  * Find the range of offsets usable by '*' partitions around
1316                  * the hog partition and how much space they need.
1317                  */
1318                 needed = 0;
1319                 base_offset = BBSIZE / secsize;
1320                 for (i = hog_part - 1; i >= 0; i--) {
1321                         pp = &lp->d_partitions[i];
1322                         if (!part_set[i] || i == RAW_PART)
1323                                 continue;
1324                         if (part_offset_type[i] == '*') {
1325                                 needed += pp->p_size;
1326                                 continue;
1327                         }
1328                         base_offset = pp->p_offset + pp->p_size;
1329                         break;
1330                 }
1331                 current_offset = lp->d_secperunit;
1332                 for (i = lp->d_npartitions - 1; i > hog_part; i--) {
1333                         pp = &lp->d_partitions[i];
1334                         if (!part_set[i] || i == RAW_PART)
1335                                 continue;
1336                         if (part_offset_type[i] == '*') {
1337                                 needed += pp->p_size;
1338                                 continue;
1339                         }
1340                         current_offset = pp->p_offset;
1341                 }
1342
1343                 if (current_offset - base_offset <= needed) {
1344                         fprintf(stderr, "Cannot find space for partition %c\n",
1345                             hog_part + 'a');
1346                         fprintf(stderr,
1347                             "Need more than %lu sectors between %lu and %lu\n",
1348                             needed, base_offset, current_offset);
1349                         errors++;
1350                         lp->d_partitions[hog_part].p_size = 0;
1351                 } else {
1352                         lp->d_partitions[hog_part].p_size = current_offset -
1353                             base_offset - needed;
1354                         total_size += lp->d_partitions[hog_part].p_size;
1355                 }
1356         }
1357
1358         /* Now set the offsets for each partition */
1359         current_offset = BBSIZE / secsize; /* in sectors */
1360         seen_default_offset = 0;
1361         for (i = 0; i < lp->d_npartitions; i++) {
1362                 part = 'a' + i;
1363                 pp = &lp->d_partitions[i];
1364                 if (part_set[i]) {
1365                         if (part_offset_type[i] == '*') {
1366                                 if (i == RAW_PART) {
1367                                         pp->p_offset = 0;
1368                                 } else {
1369                                         pp->p_offset = current_offset;
1370                                         seen_default_offset = 1;
1371                                 }
1372                         } else {
1373                                 /* allow them to be out of order for old-style tables */
1374                                 if (pp->p_offset < current_offset &&
1375                                     seen_default_offset && i != RAW_PART &&
1376                                     pp->p_fstype != FS_VINUM) {
1377                                         fprintf(stderr,
1378 "Offset %ld for partition %c overlaps previous partition which ends at %lu\n",
1379                                             (long)pp->p_offset,i+'a',current_offset);
1380                                         fprintf(stderr,
1381 "Labels with any *'s for offset must be in ascending order by sector\n");
1382                                         errors++;
1383                                 } else if (pp->p_offset != current_offset &&
1384                                     i != RAW_PART && seen_default_offset) {
1385                                         /*
1386                                          * this may give unneeded warnings if
1387                                          * partitions are out-of-order
1388                                          */
1389                                         warnx(
1390 "Offset %ld for partition %c doesn't match expected value %ld",
1391                                             (long)pp->p_offset, i + 'a', current_offset);
1392                                 }
1393                         }
1394                         if (i != RAW_PART)
1395                                 current_offset = pp->p_offset + pp->p_size;
1396                 }
1397         }
1398
1399         for (i = 0; i < lp->d_npartitions; i++) {
1400                 part = 'a' + i;
1401                 pp = &lp->d_partitions[i];
1402                 if (pp->p_size == 0 && pp->p_offset != 0)
1403                         warnx("partition %c: size 0, but offset %lu",
1404                             part, (u_long)pp->p_offset);
1405 #ifdef notdef
1406                 if (pp->p_size % lp->d_secpercyl)
1407                         warnx("partition %c: size %% cylinder-size != 0",
1408                             part);
1409                 if (pp->p_offset % lp->d_secpercyl)
1410                         warnx("partition %c: offset %% cylinder-size != 0",
1411                             part);
1412 #endif
1413                 if (pp->p_offset > lp->d_secperunit) {
1414                         fprintf(stderr,
1415                             "partition %c: offset past end of unit\n", part);
1416                         errors++;
1417                 }
1418                 if (pp->p_offset + pp->p_size > lp->d_secperunit) {
1419                         fprintf(stderr,
1420                         "partition %c: partition extends past end of unit\n",
1421                             part);
1422                         errors++;
1423                 }
1424                 if (i == RAW_PART) {
1425                         if (pp->p_fstype != FS_UNUSED)
1426                                 warnx("partition %c is not marked as unused!",part);
1427                         if (pp->p_offset != 0)
1428                                 warnx("partition %c doesn't start at 0!",part);
1429                         if (pp->p_size != lp->d_secperunit)
1430                                 warnx("partition %c doesn't cover the whole unit!",part);
1431
1432                         if ((pp->p_fstype != FS_UNUSED) || (pp->p_offset != 0) ||
1433                             (pp->p_size != lp->d_secperunit)) {
1434                                 warnx("An incorrect partition %c may cause problems for "
1435                                     "standard system utilities",part);
1436                         }
1437                 }
1438
1439                 /* check for overlaps */
1440                 /* this will check for all possible overlaps once and only once */
1441                 for (j = 0; j < i; j++) {
1442                         pp2 = &lp->d_partitions[j];
1443                         if (j != RAW_PART && i != RAW_PART &&
1444                             pp->p_fstype != FS_VINUM &&
1445                             pp2->p_fstype != FS_VINUM &&
1446                             part_set[i] && part_set[j]) {
1447                                 if (pp2->p_offset < pp->p_offset + pp->p_size &&
1448                                     (pp2->p_offset + pp2->p_size > pp->p_offset ||
1449                                         pp2->p_offset >= pp->p_offset)) {
1450                                         fprintf(stderr,"partitions %c and %c overlap!\n",
1451                                             j + 'a', i + 'a');
1452                                         errors++;
1453                                 }
1454                         }
1455                 }
1456         }
1457         for (; i < lp->d_npartitions; i++) {
1458                 part = 'a' + i;
1459                 pp = &lp->d_partitions[i];
1460                 if (pp->p_size || pp->p_offset)
1461                         warnx("unused partition %c: size %d offset %lu",
1462                             'a' + i, pp->p_size, (u_long)pp->p_offset);
1463         }
1464         return (errors);
1465 }
1466
1467 /*
1468  * When operating on a "virgin" disk, try getting an initial label
1469  * from the associated device driver.  This might work for all device
1470  * drivers that are able to fetch some initial device parameters
1471  * without even having access to a (BSD) disklabel, like SCSI disks,
1472  * most IDE drives, or vn devices.
1473  *
1474  * The device name must be given in its "canonical" form.
1475  */
1476 static struct disklabel *
1477 getvirginlabel(void)
1478 {
1479         static struct disklabel loclab;
1480         struct partition *dp;
1481         int f;
1482         u_int u;
1483
1484         if ((f = open(specname, O_RDONLY)) == -1) {
1485                 warn("cannot open %s", specname);
1486                 return (NULL);
1487         }
1488
1489         if (is_file)
1490                 get_file_parms(f);
1491         else {
1492                 mediasize = g_mediasize(f);
1493                 secsize = g_sectorsize(f);
1494                 if (secsize < 0 || mediasize < 0) {
1495                         close (f);
1496                         return (NULL);
1497                 }
1498         }
1499         memset(&loclab, 0, sizeof loclab);
1500         loclab.d_magic = DISKMAGIC;
1501         loclab.d_magic2 = DISKMAGIC;
1502         loclab.d_secsize = secsize;
1503         loclab.d_secperunit = mediasize / secsize;
1504
1505         /*
1506          * Nobody in these enligthened days uses the CHS geometry for
1507          * anything, but nontheless try to get it right.  If we fail
1508          * to get any good ideas from the device, construct something
1509          * which is IBM-PC friendly.
1510          */
1511         if (ioctl(f, DIOCGFWSECTORS, &u) == 0)
1512                 loclab.d_nsectors = u;
1513         else
1514                 loclab.d_nsectors = 63;
1515         if (ioctl(f, DIOCGFWHEADS, &u) == 0)
1516                 loclab.d_ntracks = u;
1517         else if (loclab.d_secperunit <= 63*1*1024)
1518                 loclab.d_ntracks = 1;
1519         else if (loclab.d_secperunit <= 63*16*1024)
1520                 loclab.d_ntracks = 16;
1521         else
1522                 loclab.d_ntracks = 255;
1523         loclab.d_secpercyl = loclab.d_ntracks * loclab.d_nsectors;
1524         loclab.d_ncylinders = loclab.d_secperunit / loclab.d_secpercyl;
1525         loclab.d_npartitions = DEFPARTITIONS;
1526
1527         /* Various (unneeded) compat stuff */
1528         loclab.d_rpm = 3600;
1529         loclab.d_bbsize = BBSIZE;
1530         loclab.d_interleave = 1;
1531         strncpy(loclab.d_typename, "amnesiac",
1532             sizeof(loclab.d_typename));
1533
1534         dp = &loclab.d_partitions[RAW_PART];
1535         dp->p_size = loclab.d_secperunit;
1536         loclab.d_checksum = dkcksum(&loclab);
1537         close (f);
1538         return (&loclab);
1539 }
1540
1541 static void
1542 usage(void)
1543 {
1544
1545         fprintf(stderr,
1546         "%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",
1547         "usage: bsdlabel disk",
1548         "\t\t(to read label)",
1549         "       bsdlabel -w [-n] [-m machine] disk [type]",
1550         "\t\t(to write label with existing boot program)",
1551         "       bsdlabel -e [-n] [-m machine] disk",
1552         "\t\t(to edit label)",
1553         "       bsdlabel -R [-n] [-m machine] disk protofile",
1554         "\t\t(to restore label with existing boot program)",
1555         "       bsdlabel -B [-b boot] [-m machine] disk",
1556         "\t\t(to install boot program with existing on-disk label)",
1557         "       bsdlabel -w -B [-n] [-b boot] [-m machine] disk [type]",
1558         "\t\t(to write label and install boot program)",
1559         "       bsdlabel -R -B [-n] [-b boot] [-m machine] disk protofile",
1560                 "\t\t(to restore label and install boot program)"
1561         );
1562         exit(1);
1563 }