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