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