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