OpenBSD-4.6/usr.sbin/mksuncd/mksuncd.c

Compare this file to the similar file:
Show the results in this format:

/*	$OpenBSD: mksuncd.c,v 1.1 2008/08/22 15:48:32 deraadt Exp $	*/

/*
 * Copyright (c) 2001 Jason L. Wright (jason@thought.net)
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

/*
 * WARNING! WARNING!
 * This program is not type safe (it assumes sparc type sizes) and not
 * endian safe (assumes sparc endianness).
 * WARNING! WARNING!
 */

/*
 * Copyright (c) 1992, 1993
 *	The Regents of the University of California.  All rights reserved.
 *
 * This software was developed by the Computer Systems Engineering group
 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
 * contributed to Berkeley.
 *
 * All advertising materials mentioning features or use of this software
 * must display the following acknowledgement:
 *	This product includes software developed by the University of
 *	California, Lawrence Berkeley Laboratory.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 *	@(#)sun_disklabel.h	8.1 (Berkeley) 6/11/93
 */

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <err.h>
#include <string.h>

/*
 * SunOS disk label layout (only relevant portions discovered here).
 * JLW XXX should get these definitions from elsewhere, oh well.
 */

#define	SUN_DKMAGIC	55998

/* partition info */
struct sun_dkpart {
	int	sdkp_cyloffset;		/* starting cylinder */
	int	sdkp_nsectors;		/* number of sectors */
};

struct sun_disklabel {			/* total size = 512 bytes */
	char	sl_text[128];
	char	sl_xxx1[292];
#define sl_bsdlabel	sl_xxx1		/* Embedded OpenBSD label */
	u_short sl_rpm;			/* rotational speed */
	u_short	sl_pcylinders;		/* number of physical cyls */
#define	sl_pcyl	 sl_pcylinders		/* XXX: old sun3 */
	u_short sl_sparespercyl;	/* spare sectors per cylinder */
	char	sl_xxx3[4];
	u_short sl_interleave;		/* interleave factor */
	u_short	sl_ncylinders;		/* data cylinders */
	u_short	sl_acylinders;		/* alternate cylinders */
	u_short	sl_ntracks;		/* tracks per cylinder */
	u_short	sl_nsectors;		/* sectors per track */
	char	sl_xxx4[4];
	struct sun_dkpart sl_part[8];	/* partition layout */
	u_short	sl_magic;		/* == SUN_DKMAGIC */
	u_short	sl_cksum;		/* xor checksum of all shorts */
};

int expand_file(int, off_t);
void usage(void);
int adjust_base(int, struct sun_disklabel *);
int get_label(int, struct sun_disklabel *);
int append_osfile(int, int);
off_t cylindersize(int, struct sun_disklabel *);
int adjust_label(int, struct sun_disklabel *, int, off_t, off_t);

int
expand_file(int f, off_t len)
{
	char buf[1024];
	off_t i;

	if (lseek(f, 0, SEEK_END) == -1)
		return (-1);
	bzero(buf, sizeof(buf));
	while (len) {
		i = (sizeof(buf) < len) ? sizeof(buf) : len;
		if (write(f, buf, i) != i)
			return (-1);
		len -= i;
	}
	return (0);
}

void
usage(void)
{
	fprintf(stderr, "setpart partition baseimage bootimage\n");
}

/*
 * Adjust size of base to meet a cylinder boundary.
 */
int
adjust_base(int f, struct sun_disklabel *slp)
{
	struct stat st;
	off_t sz;

	if (lseek(f, 0, SEEK_END) == -1)
		err(1, "lseek");

	if (fstat(f, &st) == -1)
		err(1, "fstat");

	sz = ((off_t)slp->sl_nsectors) *
	    ((off_t)slp->sl_ntracks) * ((off_t)512);

	if ((st.st_size % sz) != 0) {
		if (expand_file(f, sz - (st.st_size % sz)))
			err(1, "expand_file");
	}

	return (0);
}

int
get_label(int f, struct sun_disklabel *slp)
{
	int r;

	if (lseek(f, 0, SEEK_SET) == -1)
		err(1, "lseek");

	r = read(f, slp, sizeof(*slp));
	if (r == -1)
		err(1, "read");
	if (r != sizeof(*slp))
		errx(1, "short read");

	if (slp->sl_ntracks == 0 || slp->sl_ncylinders == 0 ||
	    slp->sl_nsectors == 0)
		errx(1, "bogus disklabel");

	return (0);
}

int
main(int argc, char **argv)
{
	struct sun_disklabel sl;
	int part, bf, of;
	off_t cylstart, cylsize;

	if (argc != 4) {
		usage();
		return (1);
	}

	if (argv[1] == NULL || strlen(argv[1]) != 1 ||
	    (argv[1][0] < 'a' || argv[1][0] > 'h')) {
		usage();
		return (1);
	}
	part = argv[1][0] - 'a';

	if (argv[2] == NULL || argv[3] == NULL) {
		usage();
		return (1);
	}

	bf = open(argv[2], O_RDWR);
	if (bf == -1)
		err(1, "open");

	of = open(argv[3], O_RDONLY);
	if (of == -1)
		err(1, "open");

	if (get_label(bf, &sl))
		return (1);

	if (adjust_base(bf, &sl))
		return (1);

	cylstart = cylindersize(bf, &sl);
	cylsize = cylindersize(of, &sl);

	if (append_osfile(bf, of))
		return (1);

	if (adjust_base(bf, &sl))
		return (1);

	if (adjust_label(bf, &sl, part, cylstart, cylsize))
		return (1);

	close(bf);
	close(of);

	return (0);
}

/*
 * Put our entry into the disklabel, recompute label checksum, and
 * write it back to the disk.
 */
int
adjust_label(int f, struct sun_disklabel *slp, int part, off_t start, off_t size)
{
	u_short sum = 0, *sp;
	int i;

	if (start > 65535)
		errx(1, "start too large! %lld", (long long)start);
	if (part < 0 || part > 8)
		errx(1, "invalid partition: %d", part);
	slp->sl_part[part].sdkp_cyloffset = start;
	slp->sl_part[part].sdkp_nsectors =
	    size * slp->sl_nsectors * slp->sl_ntracks;

	slp->sl_cksum = 0;
	sp = (u_short *)slp;
	for (i = 0; i < sizeof(*slp)/sizeof(u_short); i++) {
		sum ^= *sp;
		sp++;
	}
	slp->sl_cksum = sum;

	if (lseek(f, 0, SEEK_SET) == -1)
		return (-1);

	i = write(f, slp, sizeof(*slp));
	if (i < 0)
		err(1, "write modified label");
	if (i != sizeof(*slp))
		errx(1, "short write modified label");
	return (0);
}

int
append_osfile(int outf, int inf)
{
	char buf[512];
	int r, len;

	while (1) {
		len = read(inf, buf, sizeof(buf));
		if (len < 0)
			err(1, "read osfile");
		if (len == 0)
			return (0);

		r = write(outf, buf, len);
		if (r < 0)
			err(1, "write basefile");
		if (r != len)
			errx(1, "short write basefile");
	}
}

off_t
cylindersize(int f, struct sun_disklabel *slp)
{
	struct stat st;
	off_t sz, r;

	if (fstat(f, &st) == -1)
		err(1, "fstat");

	sz = ((off_t)slp->sl_nsectors) *
	    ((off_t)slp->sl_ntracks) * ((off_t)512);

	r = st.st_size / sz;

	if ((st.st_size % sz) == 0)
		return (r);
	return (r + 1);
}