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