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