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