xref: /netbsd-src/sys/arch/mipsco/stand/installboot/installboot.c (revision 8ad876315594405ea173955673484dd778e09a3d)
1*8ad87631Schristos /*	$NetBSD: installboot.c,v 1.10 2016/01/21 16:58:36 christos Exp $	*/
27378a103Swdk 
37378a103Swdk /*
47378a103Swdk  * Copyright (c) 2000 The NetBSD Foundation, Inc.
57378a103Swdk  * All rights reserved.
67378a103Swdk  *
77378a103Swdk  * This code is derived from software contributed to The NetBSD Foundation
87378a103Swdk  * by Wayne Knowles
97378a103Swdk  *
107378a103Swdk  * Redistribution and use in source and binary forms, with or without
117378a103Swdk  * modification, are permitted provided that the following conditions
127378a103Swdk  * are met:
137378a103Swdk  * 1. Redistributions of source code must retain the above copyright
147378a103Swdk  *    notice, this list of conditions and the following disclaimer.
157378a103Swdk  * 2. Redistributions in binary form must reproduce the above copyright
167378a103Swdk  *    notice, this list of conditions and the following disclaimer in the
177378a103Swdk  *    documentation and/or other materials provided with the distribution.
187378a103Swdk  *
197378a103Swdk  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
207378a103Swdk  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
217378a103Swdk  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
227378a103Swdk  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
237378a103Swdk  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
247378a103Swdk  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
257378a103Swdk  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
267378a103Swdk  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
277378a103Swdk  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
287378a103Swdk  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
297378a103Swdk  * POSSIBILITY OF SUCH DAMAGE.
307378a103Swdk  */
317378a103Swdk 
327378a103Swdk #include <assert.h>
337378a103Swdk #include <err.h>
347378a103Swdk #include <fcntl.h>
357378a103Swdk #include <stdlib.h>
367378a103Swdk #include <stdio.h>
377378a103Swdk #include <string.h>
387378a103Swdk #include <unistd.h>
397378a103Swdk 
407378a103Swdk #include <sys/param.h>
417378a103Swdk #include <sys/stat.h>
427378a103Swdk #include <sys/disklabel.h>
437378a103Swdk 
447378a103Swdk 
457378a103Swdk #define	VERBOSE(msg)	if (verbose)				\
467378a103Swdk 				fprintf(stderr, msg)
477378a103Swdk #define	FATAL(a1,a2)	errx(EXIT_FAILURE, a1, a2)
487378a103Swdk #define	FATALIO(a1,a2)	err(EXIT_FAILURE, a1, a2)
497378a103Swdk 
507378a103Swdk #define BOOTBLOCK_NUMBER	2
517378a103Swdk #define	BOOTBLOCK_OFFSET	BOOTBLOCK_NUMBER*DEV_BSIZE
527378a103Swdk #define	DEFAULT_BOOTFILE	"boot"
537378a103Swdk 
5402cdf4d2Sdsl static void	usage(void);
5502cdf4d2Sdsl static void	do_list(const char *);
5602cdf4d2Sdsl static void	do_remove(const char *, const char *);
5702cdf4d2Sdsl static void	do_install(const char *, const char *, const char *);
5802cdf4d2Sdsl static int	mipsvh_cksum(struct mips_volheader *);
5902cdf4d2Sdsl static void	read_volheader(const char *, struct mips_volheader *);
6002cdf4d2Sdsl static void	write_volheader(const char *, struct mips_volheader *);
6102cdf4d2Sdsl static struct mips_voldir *voldir_findfile(struct mips_volheader *,
6202cdf4d2Sdsl 						const char *, int);
637378a103Swdk 
647378a103Swdk int verbose, nowrite;
657378a103Swdk 
667378a103Swdk static void
usage(void)67df7f595eScegger usage(void)
687378a103Swdk {
697378a103Swdk 
707378a103Swdk 	fprintf(stderr, "usage:\n");
71c2bdafabScgd 	fprintf(stderr, "\t%s [-nv] disk bootstrap [name]\n", getprogname());
72c2bdafabScgd 	fprintf(stderr, "\t%s -r [-nv] disk [name]\n", getprogname());
73c2bdafabScgd 	fprintf(stderr, "\t%s -l [-nv] disk\n", getprogname());
747378a103Swdk 	exit(EXIT_FAILURE);
757378a103Swdk }
767378a103Swdk 
777378a103Swdk int
main(int argc,char * argv[])787378a103Swdk main(int argc, char *argv[])
797378a103Swdk {
807378a103Swdk 	const char *disk;
817378a103Swdk 	int c, rflag, lflag;
827378a103Swdk 
837378a103Swdk 	rflag = lflag = verbose = nowrite = 0;
847378a103Swdk 
857378a103Swdk 	while ((c = getopt(argc, argv, "lnrv")) != -1) {
867378a103Swdk 		switch (c) {
877378a103Swdk 		case 'l':
887378a103Swdk 			/* List volume directory contents */
897378a103Swdk 			lflag = 1;
907378a103Swdk 			break;
917378a103Swdk 		case 'n':
927378a103Swdk 			/* Disable write of boot sectors */
937378a103Swdk 			nowrite = 1;
947378a103Swdk 			break;
957378a103Swdk 		case 'r':
967378a103Swdk 			/* Clear any existing boot block */
977378a103Swdk 			rflag = 1;
987378a103Swdk 			break;
997378a103Swdk 		case 'v':
1007378a103Swdk 			/* Verbose output */
1017378a103Swdk 			verbose = 1;
1027378a103Swdk 			break;
1037378a103Swdk 		default:
1047378a103Swdk 			usage();
1057378a103Swdk 		}
1067378a103Swdk 	}
1077378a103Swdk 
1087378a103Swdk 	argc -= optind;
1097378a103Swdk 	argv += optind;
1107378a103Swdk 
1117378a103Swdk 	if ((lflag && rflag) || argc < 1 || (lflag && argc != 1) ||
1127378a103Swdk 	    (rflag && argc > 3) || argc > 4)
1137378a103Swdk 		usage();
1147378a103Swdk 
1157378a103Swdk 	disk = argv[0];
1167378a103Swdk 
1177378a103Swdk 	if (lflag)
1187378a103Swdk 		do_list(disk);
1197378a103Swdk 	else if (rflag)
1207378a103Swdk 		do_remove(disk, argc==2?argv[1]:DEFAULT_BOOTFILE);
1217378a103Swdk 	else
1227378a103Swdk 		do_install(disk, argv[1], argc==3?argv[2]:DEFAULT_BOOTFILE);
1237378a103Swdk 
1247378a103Swdk 	exit(EXIT_SUCCESS);
1257378a103Swdk }
1267378a103Swdk 
1277378a103Swdk static void
do_list(const char * disk)128454af1c0Sdsl do_list(const char *disk)
1297378a103Swdk {
1307378a103Swdk 	struct mips_volheader vh;
1317378a103Swdk 	struct mips_voldir *vdp;
1327378a103Swdk 	int i;
1337378a103Swdk 
1347378a103Swdk 	read_volheader(disk, &vh);
1357378a103Swdk 
1367378a103Swdk 	printf("Slot\t  LBN\tLength\tFilename\n");
1377378a103Swdk 	printf("------------------------------------------\n");
1387378a103Swdk 	for (i=0, vdp=vh.vh_voldir; i<MIPS_NVOLDIR; i++, vdp++)
1397378a103Swdk 		if (vdp->vd_len)
1407378a103Swdk 			printf("%2d:\t%5d\t%6d\t%s\n", i, vdp->vd_lba,
1417378a103Swdk 			       vdp->vd_len, vdp->vd_name);
1427378a103Swdk }
1437378a103Swdk 
1447378a103Swdk static void
do_remove(const char * disk,const char * filename)145454af1c0Sdsl do_remove(const char *disk, const char *filename)
1467378a103Swdk {
1477378a103Swdk 	struct mips_volheader vh;
1487378a103Swdk 	struct mips_voldir *vdp;
1497378a103Swdk 
1507378a103Swdk 	read_volheader(disk, &vh);
1517378a103Swdk 	vdp = voldir_findfile(&vh, filename, 0);
1527378a103Swdk 	if (vdp == NULL)
1537378a103Swdk 		FATAL("%s: file not found", disk);
1547378a103Swdk 
155fa993060Swdk 	memset(vdp, 0, sizeof(*vdp));
1567378a103Swdk 
1577378a103Swdk 	/* Update volume header */
1587378a103Swdk 	write_volheader(disk, &vh);
1597378a103Swdk }
1607378a103Swdk 
1617378a103Swdk static void
do_install(const char * disk,const char * bootstrap,const char * bootname)162454af1c0Sdsl do_install(const char *disk, const char *bootstrap, const char *bootname)
1637378a103Swdk {
1647378a103Swdk 	struct stat bootstrapsb;
1657378a103Swdk 	struct mips_volheader vh;
1667378a103Swdk 	struct mips_voldir *vdp;
1677378a103Swdk 	int fd;
1687378a103Swdk 	char *boot_code;
1697378a103Swdk 	size_t boot_size;
1707378a103Swdk 	ssize_t len;
1717378a103Swdk 
1727378a103Swdk 	/* Open the input file and check it out */
1737378a103Swdk 	if ((fd = open(bootstrap, O_RDONLY)) == -1)
1747378a103Swdk 		FATALIO("open %s", bootstrap);
1757378a103Swdk 	if (fstat(fd, &bootstrapsb) == -1)
1767378a103Swdk 		FATALIO("fstat %s", bootstrap);
1777378a103Swdk 	if (!S_ISREG(bootstrapsb.st_mode))
1787378a103Swdk 		FATAL("%s must be a regular file", bootstrap);
1797378a103Swdk 
1807378a103Swdk 	boot_size = roundup(bootstrapsb.st_size, DEV_BSIZE);
1817378a103Swdk 
1827378a103Swdk 	if (boot_size > 8192-1024)
1837378a103Swdk 		FATAL("bootstrap program too large (%d bytes)", boot_size);
1847378a103Swdk 
1857378a103Swdk 	boot_code = malloc(boot_size);
1867378a103Swdk 	if (boot_code == NULL)
1877378a103Swdk 		FATAL("malloc %d bytes failed", boot_size);
188fa993060Swdk 	memset(boot_code, 0, boot_size);
1897378a103Swdk 
1907378a103Swdk 	/* read the file into the buffer */
1917378a103Swdk 	len = read(fd, boot_code, bootstrapsb.st_size);
1927378a103Swdk 	if (len == -1)
1937378a103Swdk 		FATALIO("read %s", bootstrap);
1947378a103Swdk 	else if (len != bootstrapsb.st_size)
1957378a103Swdk 		FATAL("read %s: short read", bootstrap);
1967378a103Swdk 	(void)close(fd);
1977378a103Swdk 
1987378a103Swdk 	read_volheader(disk, &vh);
1997378a103Swdk 
2007378a103Swdk 	vdp = voldir_findfile(&vh, bootname, 1);
2017378a103Swdk 	if (vdp == NULL)
2027378a103Swdk 		FATAL("%s: volume directory full", disk);
2037378a103Swdk 
2047378a103Swdk 	strcpy(vdp->vd_name, bootname);
2057378a103Swdk 	vdp->vd_lba = BOOTBLOCK_NUMBER;
2067378a103Swdk 	vdp->vd_len = bootstrapsb.st_size;
2077378a103Swdk 
2087378a103Swdk 	if (nowrite) {
2097378a103Swdk 	    if (verbose)
2107378a103Swdk 		    fprintf(stderr, "not writing\n");
211*8ad87631Schristos 	    free(boot_code);
2127378a103Swdk 	    return;
2137378a103Swdk 	}
2147378a103Swdk 
2157378a103Swdk 	if (verbose)
2167378a103Swdk 		fprintf(stderr, "writing bootstrap (%d bytes at logical block %d)\n",
2177378a103Swdk 			boot_size, 2);
2187378a103Swdk 
2197378a103Swdk 	/* Write bootstrap */
2207378a103Swdk 	if ((fd = open(disk, O_WRONLY)) == -1)
2217378a103Swdk 		FATALIO("open %s", bootstrap);
2227378a103Swdk 	len = pwrite(fd, boot_code, boot_size, BOOTBLOCK_OFFSET);
223d05665daSchristos 	free(boot_code);
2247378a103Swdk 	if (len == -1)
2257378a103Swdk 		FATAL("write %s", disk);
2267378a103Swdk 	if (len != boot_size)
2277378a103Swdk 		FATAL("write %s: short write", disk);
2287378a103Swdk 	(void) close(fd);
2297378a103Swdk 
2307378a103Swdk 	/* Update volume header */
2317378a103Swdk 	write_volheader(disk, &vh);
2327378a103Swdk }
2337378a103Swdk 
2347378a103Swdk static void
read_volheader(const char * disk,struct mips_volheader * vhp)235454af1c0Sdsl read_volheader(const char *disk, struct mips_volheader *vhp)
2367378a103Swdk {
2377378a103Swdk 	int vfd;
2387378a103Swdk 	ssize_t len;
2397378a103Swdk 
2407378a103Swdk 	if ((vfd = open(disk, O_RDONLY)) == -1)
2417378a103Swdk 		FATALIO("open %s", disk);
2427378a103Swdk 
2437378a103Swdk 	len = pread(vfd, vhp, sizeof(*vhp), MIPS_VHSECTOR*DEV_BSIZE);
2447378a103Swdk 
2457378a103Swdk 	(void) close(vfd);
2467378a103Swdk 
2477378a103Swdk 	if (len == -1)
2487378a103Swdk 		FATALIO("read %s", disk);
2497378a103Swdk 	if (len != sizeof(*vhp))
2507378a103Swdk 		FATAL("read %s: short read", disk);
2517378a103Swdk 
2527378a103Swdk 	/* Check volume header magic */
2537378a103Swdk 	if (vhp->vh_magic != MIPS_VHMAGIC)
2547378a103Swdk 		FATAL("%s: no volume header", disk);
2557378a103Swdk 
2567378a103Swdk 	/* check volume header checksum */
2577378a103Swdk 	if (mipsvh_cksum(vhp))
2587378a103Swdk 		FATAL("%s: volume header corrupted", disk);
2597378a103Swdk }
2607378a103Swdk 
2617378a103Swdk static void
write_volheader(const char * disk,struct mips_volheader * vhp)262454af1c0Sdsl write_volheader(const char *disk, struct mips_volheader *vhp)
2637378a103Swdk {
2647378a103Swdk 	int vfd;
2657378a103Swdk 	ssize_t len;
2667378a103Swdk 
2677378a103Swdk 	/* update volume header checksum */
2687378a103Swdk 	vhp->vh_cksum = 0;
2697378a103Swdk 	vhp->vh_cksum = -mipsvh_cksum(vhp);
2707378a103Swdk 
2717378a103Swdk 	if ((vfd = open(disk, O_WRONLY)) == -1)
2727378a103Swdk 		FATALIO("open %s", disk);
2737378a103Swdk 
2747378a103Swdk 	if (verbose)
2757378a103Swdk 		fprintf(stderr, "%s: writing volume header\n", disk);
2767378a103Swdk 
2777378a103Swdk 	len = pwrite(vfd, vhp, sizeof(*vhp), MIPS_VHSECTOR*512); /* XXX */
2787378a103Swdk 	if (len == -1)
2797378a103Swdk 		FATALIO("write %s", disk);
2807378a103Swdk 	if (len != sizeof(*vhp))
2817378a103Swdk 		FATAL("write %s: short write", disk);
2827378a103Swdk 
2837378a103Swdk 	(void) close(vfd);
2847378a103Swdk }
2857378a103Swdk 
2867378a103Swdk /*
2877378a103Swdk  * Compute checksum for MIPS disk volume header
2887378a103Swdk  *
2897378a103Swdk  * Mips volume header checksum is the 32bit 2's complement sum
2907378a103Swdk  * of the entire volume header structure
2917378a103Swdk  */
2927378a103Swdk int
mipsvh_cksum(struct mips_volheader * vhp)293454af1c0Sdsl mipsvh_cksum(struct mips_volheader *vhp)
2947378a103Swdk {
2957378a103Swdk 	int i, *ptr;
2967378a103Swdk 	int cksum = 0;
2977378a103Swdk 
2987378a103Swdk 	ptr = (int *)vhp;
2997378a103Swdk 	i = sizeof(*vhp) / sizeof(*ptr);
3007378a103Swdk 	while (i--)
3017378a103Swdk 		cksum += *ptr++;
3027378a103Swdk 	return cksum;
3037378a103Swdk }
3047378a103Swdk 
3057378a103Swdk 
3067378a103Swdk /*
3077378a103Swdk  * Locate the volume directory slot that matches a filename
3087378a103Swdk  *
3097378a103Swdk  * If the file entry cannot be found and create is non-zero the next
3107378a103Swdk  * empty slot is returned, otherwise return NULL
3117378a103Swdk  */
3127378a103Swdk static struct mips_voldir *
voldir_findfile(struct mips_volheader * vhp,const char * file,int create)31382357f6dSdsl voldir_findfile(struct mips_volheader *vhp, const char *file, int create)
31482357f6dSdsl 	/* create:		 return unused entry if not found */
3157378a103Swdk {
3167378a103Swdk 	struct mips_voldir *vdp = vhp->vh_voldir;
3177378a103Swdk 	int i;
3187378a103Swdk 
3197378a103Swdk 	for (i=0; i<MIPS_NVOLDIR; i++, vdp++) {
3207378a103Swdk 		if (strcmp(vdp->vd_name, file) == 0)
3217378a103Swdk 			return vdp;
3227378a103Swdk 	}
3237378a103Swdk 	if (create) {
3247378a103Swdk 		vdp = vhp->vh_voldir;
3257378a103Swdk 		for (i=0; i<MIPS_NVOLDIR; i++, vdp++)
3267378a103Swdk 			if (vdp->vd_len == 0)
3277378a103Swdk 				return vdp;
3287378a103Swdk 	}
3297378a103Swdk 	return NULL;
3307378a103Swdk }
331