devno = MAKEBOOTDEV(major(devno), 0, 0, minor(devno), 0);
devno = MAKEBOOTDEV(major(devno), 0, 0, DISKUNIT(devno), 0);
char		*loadprotoblocks __P((char *, long *));int		loadblocknums __P((char *, int, struct disklabel *));static void	devread __P((int, void *, daddr_t, size_t, char *));static void	usage __P((void));static int	record_block	__P((u_int8_t *, daddr_t, u_int, struct disklabel *));static voidusage(){	fprintf(stderr, "usage: %s [-n] [-v] [-s <spt>] [-h <tpc>] "		"<boot> <proto> <device>\n", __progname);	exit(1);}intmain(argc, argv)	int argc;	char *argv[];{	int	c;	int	devfd;	char	*protostore;	long	protosize;	struct stat sb;	struct disklabel dl;	struct dos_mbr mbr;	struct dos_partition *dp;	off_t startoff = 0;	int mib[4], size;	dev_t devno;	bios_diskinfo_t di;	nsectors = nheads = -1;	while ((c = getopt(argc, argv, "vnh:s:")) != EOF) {		switch (c) {		case 'h':			nheads = atoi(optarg);			userspec = 1;			break;		case 's':			nsectors = atoi(optarg);			userspec = 1;			break;		case 'n':			/* Do not actually write the bootblock to disk */			nowrite = 1;			break;		case 'v':			/* Chat */			verbose = 1;			break;		default:			usage();		}	}	if (argc - optind < 3) {		usage();	}	boot = argv[optind];	proto = argv[optind + 1];	realdev = dev = argv[optind + 2];	/* Open and check raw disk device */	if ((devfd = opendev(dev, (nowrite? O_RDONLY:O_RDWR),			     OPENDEV_PART, &realdev)) < 0)		err(1, "open: %s", realdev);	if (verbose) {		fprintf(stderr, "boot: %s\n", boot);		fprintf(stderr, "proto: %s\n", proto);		fprintf(stderr, "device: %s\n", realdev);	}	if (ioctl(devfd, DIOCGDINFO, &dl) != 0)		err(1, "disklabel: %s", realdev);	/* check disklabel */	if (dl.d_magic != DISKMAGIC)		err(1, "bad disklabel magic=%0x8x", dl.d_magic);	/* warn on unknown disklabel types */	if (dl.d_type == 0)		warnx("disklabel type unknown");	/* Load proto blocks into core */	if ((protostore = loadprotoblocks(proto, &protosize)) == NULL)		exit(1);	/* XXX - Paranoia: Make sure size is aligned! */	if (protosize & (DEV_BSIZE - 1))		err(1, "proto bootblock bad size=%ld", protosize);	/* Write patched proto bootblocks into the superblock */	if (protosize > SBSIZE - DEV_BSIZE)		errx(1, "proto bootblocks too big");	if (fstat(devfd, &sb) < 0)		err(1, "stat: %s", realdev);	if (!S_ISCHR(sb.st_mode))		errx(1, "%s: Not a character device", realdev);	if (nheads == -1 || nsectors == -1) {		mib[0] = CTL_MACHDEP;		mib[1] = CPU_CHR2BLK;		mib[2] = sb.st_rdev;		size = sizeof(devno);		if(sysctl(mib, 3, &devno, &size, NULL, 0) < 0)			err(1, "mapping device number");		devno = MAKEBOOTDEV(major(devno), 0, 0, minor(devno), 0);		mib[0] = CTL_MACHDEP;		mib[1] = CPU_BIOS;		mib[2] = BIOS_DISKINFO;		mib[3] = devno;		size = sizeof(di);		if(sysctl(mib, 4, &di, &size, NULL, 0) < 0)			errx(1, "Unable to get BIOS geometry, "				"must specify -h and -s");		nheads = di.bios_heads;		nsectors = di.bios_sectors;	}	/* Extract and load block numbers */	if (loadblocknums(boot, devfd, &dl) != 0)		exit(1);	/* Sync filesystems (to clean in-memory superblock?) */	sync(); sleep(1);	if (dl.d_type != 0 && dl.d_type != DTYPE_FLOPPY &&	    dl.d_type != DTYPE_VND) {		if (lseek(devfd, (off_t)DOSBBSECTOR, SEEK_SET) < 0 ||		    read(devfd, &mbr, sizeof(mbr)) < sizeof(mbr))			err(4, "can't read master boot record");		if (mbr.dmbr_sign != DOSMBR_SIGNATURE)			errx(1, "broken MBR");		/* Find OpenBSD partition. */		for (dp = mbr.dmbr_parts; dp < &mbr.dmbr_parts[NDOSPART]; dp++) {			if (dp->dp_size && dp->dp_typ == DOSPTYP_OPENBSD) {				startoff = dp->dp_start * dl.d_secsize;				fprintf(stderr, "using MBR partition %d: "					"type %d (0x%02x) offset %d (0x%x)\n",					dp - mbr.dmbr_parts,					dp->dp_typ, dp->dp_typ,					dp->dp_start, dp->dp_start);				break;			}		}		/* don't check for old part number, that is ;-p */		if (dp >= &mbr.dmbr_parts[NDOSPART])			errx(1, "no OpenBSD partition");	}	if (!nowrite) {		if (lseek(devfd, startoff, SEEK_SET) < 0 ||		    write(devfd, protostore, protosize) != protosize)			err(1, "write bootstrap");	}	(void)close(devfd);	return 0;}char *loadprotoblocks(fname, size)	char *fname;	long *size;{	int	fd;	size_t	tdsize;		/* text+data size */	char	*bp;	struct	nlist *nlp;	struct	exec eh;	fd = -1;	bp = NULL;	/* Locate block number array in proto file */	if (nlist(fname, nl) != 0) {		warnx("nlist: %s: symbols not found", fname);		return NULL;	}	/* Validate symbol types (global data). */	for (nlp = nl; nlp->n_un.n_name; nlp++) {		if (nlp->n_type != (N_TEXT | N_EXT)) {			warnx("nlist: %s: wrong type", nlp->n_un.n_name);			return NULL;		}	}	if ((fd = open(fname, O_RDONLY)) < 0) {		warn("open: %s", fname);		return NULL;	}	if (read(fd, &eh, sizeof(eh)) != sizeof(eh)) {		warn("read: %s", fname);		goto bad;	}	if (N_GETMAGIC(eh) != OMAGIC) {		warn("bad magic: 0x%lx", eh.a_midmag);		goto bad;	}	/*	 * We have to include the exec header in the beginning of	 * the buffer, and leave extra space at the end in case	 * the actual write to disk wants to skip the header.	 */	tdsize = eh.a_text + eh.a_data;	/*	 * Allocate extra space here because the caller may copy	 * the boot block starting at the end of the exec header.	 * This prevents reading beyond the end of the buffer.	 */	if ((bp = calloc(tdsize, 1)) == NULL) {		warnx("malloc: %s: no memory", fname);		goto bad;	}	/* Read the rest of the file. */	if (read(fd, bp, tdsize) != tdsize) {		warn("read: %s", fname);		goto bad;	}	*size = tdsize;	/* not aligned to DEV_BSIZE */	/* Calculate the symbols' locations within the proto file */	block_count_p = (u_int8_t *) (bp + nl[X_BLOCK_COUNT].n_value);	block_table_p = (u_int8_t *) (bp + nl[X_BLOCK_TABLE].n_value);	maxblocknum = *block_count_p;	if (verbose) {		fprintf(stderr, "%s: entry point %#lx\n", fname, eh.a_entry);		fprintf(stderr, "proto bootblock size %ld\n", *size);		fprintf(stderr, "room for %d filesystem blocks at %#lx\n",			maxblocknum, nl[X_BLOCK_TABLE].n_value);	}	close(fd);	return bp; bad:	if (bp)		free(bp);	if (fd >= 0)		close(fd);	return NULL;}