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