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