Home | History | Annotate | Line # | Download | only in installboot
installboot.c revision 1.2
      1 /*	$NetBSD: installboot.c,v 1.2 2001/02/20 23:59:10 cgd Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 2000 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Wayne Knowles
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  * 3. All advertising materials mentioning features or use of this software
     19  *    must display the following acknowledgement:
     20  *        This product includes software developed by the NetBSD
     21  *        Foundation, Inc. and its contributors.
     22  * 4. Neither the name of The NetBSD Foundation nor the names of its
     23  *    contributors may be used to endorse or promote products derived
     24  *    from this software without specific prior written permission.
     25  *
     26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     36  * POSSIBILITY OF SUCH DAMAGE.
     37  */
     38 
     39 #include <assert.h>
     40 #include <err.h>
     41 #include <fcntl.h>
     42 #include <stdlib.h>
     43 #include <stdio.h>
     44 #include <string.h>
     45 #include <unistd.h>
     46 
     47 #include <sys/param.h>
     48 #include <sys/stat.h>
     49 #include <sys/disklabel.h>
     50 
     51 
     52 #define	VERBOSE(msg)	if (verbose)				\
     53 				fprintf(stderr, msg)
     54 #define	FATAL(a1,a2)	errx(EXIT_FAILURE, a1, a2)
     55 #define	FATALIO(a1,a2)	err(EXIT_FAILURE, a1, a2)
     56 
     57 #define BOOTBLOCK_NUMBER	2
     58 #define	BOOTBLOCK_OFFSET	BOOTBLOCK_NUMBER*DEV_BSIZE
     59 #define	DEFAULT_BOOTFILE	"boot"
     60 
     61 static void	usage __P((void));
     62 static void	do_list __P((const char *));
     63 static void	do_remove __P((const char *, const char *));
     64 static void	do_install __P((const char *, const char *, const char *));
     65 static int	mipsvh_cksum __P((struct mips_volheader *));
     66 static void	read_volheader __P((const char *, struct mips_volheader *));
     67 static void	write_volheader __P((const char *, struct mips_volheader *));
     68 static struct mips_voldir *voldir_findfile __P((struct mips_volheader *,
     69 						const char *, int));
     70 
     71 int verbose, nowrite;
     72 
     73 static void
     74 usage()
     75 {
     76 
     77 	fprintf(stderr, "usage:\n");
     78 	fprintf(stderr, "\t%s [-nv] disk bootstrap [name]\n", getprogname());
     79 	fprintf(stderr, "\t%s -r [-nv] disk [name]\n", getprogname());
     80 	fprintf(stderr, "\t%s -l [-nv] disk\n", getprogname());
     81 	exit(EXIT_FAILURE);
     82 }
     83 
     84 int
     85 main(int argc, char *argv[])
     86 {
     87 	const char *disk;
     88 	int c, rflag, lflag;
     89 
     90 	rflag = lflag = verbose = nowrite = 0;
     91 
     92 	while ((c = getopt(argc, argv, "lnrv")) != -1) {
     93 		switch (c) {
     94 		case 'l':
     95 			/* List volume directory contents */
     96 			lflag = 1;
     97 			break;
     98 		case 'n':
     99 			/* Disable write of boot sectors */
    100 			nowrite = 1;
    101 			break;
    102 		case 'r':
    103 			/* Clear any existing boot block */
    104 			rflag = 1;
    105 			break;
    106 		case 'v':
    107 			/* Verbose output */
    108 			verbose = 1;
    109 			break;
    110 		default:
    111 			usage();
    112 		}
    113 	}
    114 
    115 	argc -= optind;
    116 	argv += optind;
    117 
    118 	if ((lflag && rflag) || argc < 1 || (lflag && argc != 1) ||
    119 	    (rflag && argc > 3) || argc > 4)
    120 		usage();
    121 
    122 	disk = argv[0];
    123 
    124 	if (lflag)
    125 		do_list(disk);
    126 	else if (rflag)
    127 		do_remove(disk, argc==2?argv[1]:DEFAULT_BOOTFILE);
    128 	else
    129 		do_install(disk, argv[1], argc==3?argv[2]:DEFAULT_BOOTFILE);
    130 
    131 	exit(EXIT_SUCCESS);
    132 }
    133 
    134 static void
    135 do_list(disk)
    136 	const char *disk;
    137 {
    138 	struct mips_volheader vh;
    139 	struct mips_voldir *vdp;
    140 	int i;
    141 
    142 	read_volheader(disk, &vh);
    143 
    144 	printf("Slot\t  LBN\tLength\tFilename\n");
    145 	printf("------------------------------------------\n");
    146 	for (i=0, vdp=vh.vh_voldir; i<MIPS_NVOLDIR; i++, vdp++)
    147 		if (vdp->vd_len)
    148 			printf("%2d:\t%5d\t%6d\t%s\n", i, vdp->vd_lba,
    149 			       vdp->vd_len, vdp->vd_name);
    150 }
    151 
    152 static void
    153 do_remove(disk, filename)
    154 	const char *disk;
    155 	const char *filename;
    156 {
    157 	struct mips_volheader vh;
    158 	struct mips_voldir *vdp;
    159 
    160 	read_volheader(disk, &vh);
    161 	vdp = voldir_findfile(&vh, filename, 0);
    162 	if (vdp == NULL)
    163 		FATAL("%s: file not found", disk);
    164 
    165 	bzero(vdp, sizeof(*vdp));
    166 
    167 	/* Update volume header */
    168 	write_volheader(disk, &vh);
    169 }
    170 
    171 static void
    172 do_install(disk, bootstrap, bootname)
    173 	const char *disk;
    174 	const char *bootstrap;
    175 	const char *bootname;
    176 {
    177 	struct stat bootstrapsb;
    178 	struct mips_volheader vh;
    179 	struct mips_voldir *vdp;
    180 	int fd;
    181 	char *boot_code;
    182 	size_t boot_size;
    183 	ssize_t len;
    184 
    185 	/* Open the input file and check it out */
    186 	if ((fd = open(bootstrap, O_RDONLY)) == -1)
    187 		FATALIO("open %s", bootstrap);
    188 	if (fstat(fd, &bootstrapsb) == -1)
    189 		FATALIO("fstat %s", bootstrap);
    190 	if (!S_ISREG(bootstrapsb.st_mode))
    191 		FATAL("%s must be a regular file", bootstrap);
    192 
    193 	boot_size = roundup(bootstrapsb.st_size, DEV_BSIZE);
    194 
    195 	if (boot_size > 8192-1024)
    196 		FATAL("bootstrap program too large (%d bytes)", boot_size);
    197 
    198 	boot_code = malloc(boot_size);
    199 	if (boot_code == NULL)
    200 		FATAL("malloc %d bytes failed", boot_size);
    201 	bzero(boot_code, boot_size);
    202 
    203 	/* read the file into the buffer */
    204 	len = read(fd, boot_code, bootstrapsb.st_size);
    205 	if (len == -1)
    206 		FATALIO("read %s", bootstrap);
    207 	else if (len != bootstrapsb.st_size)
    208 		FATAL("read %s: short read", bootstrap);
    209 	(void)close(fd);
    210 
    211 	read_volheader(disk, &vh);
    212 
    213 	vdp = voldir_findfile(&vh, bootname, 1);
    214 	if (vdp == NULL)
    215 		FATAL("%s: volume directory full", disk);
    216 
    217 	strcpy(vdp->vd_name, bootname);
    218 	vdp->vd_lba = BOOTBLOCK_NUMBER;
    219 	vdp->vd_len = bootstrapsb.st_size;
    220 
    221 	if (nowrite) {
    222 	    if (verbose)
    223 		    fprintf(stderr, "not writing\n");
    224 	    return;
    225 	}
    226 
    227 	if (verbose)
    228 		fprintf(stderr, "writing bootstrap (%d bytes at logical block %d)\n",
    229 			boot_size, 2);
    230 
    231 	/* Write bootstrap */
    232 	if ((fd = open(disk, O_WRONLY)) == -1)
    233 		FATALIO("open %s", bootstrap);
    234 	len = pwrite(fd, boot_code, boot_size, BOOTBLOCK_OFFSET);
    235 	if (len == -1)
    236 		FATAL("write %s", disk);
    237 	if (len != boot_size)
    238 		FATAL("write %s: short write", disk);
    239 	(void) close(fd);
    240 
    241 	/* Update volume header */
    242 	write_volheader(disk, &vh);
    243 }
    244 
    245 static void
    246 read_volheader(disk, vhp)
    247      const char *disk;
    248      struct mips_volheader *vhp;
    249 {
    250 	int vfd;
    251 	ssize_t len;
    252 
    253 	if ((vfd = open(disk, O_RDONLY)) == -1)
    254 		FATALIO("open %s", disk);
    255 
    256 	len = pread(vfd, vhp, sizeof(*vhp), MIPS_VHSECTOR*DEV_BSIZE);
    257 
    258 	(void) close(vfd);
    259 
    260 	if (len == -1)
    261 		FATALIO("read %s", disk);
    262 	if (len != sizeof(*vhp))
    263 		FATAL("read %s: short read", disk);
    264 
    265 	/* Check volume header magic */
    266 	if (vhp->vh_magic != MIPS_VHMAGIC)
    267 		FATAL("%s: no volume header", disk);
    268 
    269 	/* check volume header checksum */
    270 	if (mipsvh_cksum(vhp))
    271 		FATAL("%s: volume header corrupted", disk);
    272 }
    273 
    274 static void
    275 write_volheader(disk, vhp)
    276 	const char *disk;
    277 	struct mips_volheader *vhp;
    278 {
    279 	int vfd;
    280 	ssize_t len;
    281 
    282 	/* update volume header checksum */
    283 	vhp->vh_cksum = 0;
    284 	vhp->vh_cksum = -mipsvh_cksum(vhp);
    285 
    286 	if ((vfd = open(disk, O_WRONLY)) == -1)
    287 		FATALIO("open %s", disk);
    288 
    289 	if (verbose)
    290 		fprintf(stderr, "%s: writing volume header\n", disk);
    291 
    292 	len = pwrite(vfd, vhp, sizeof(*vhp), MIPS_VHSECTOR*512); /* XXX */
    293 	if (len == -1)
    294 		FATALIO("write %s", disk);
    295 	if (len != sizeof(*vhp))
    296 		FATAL("write %s: short write", disk);
    297 
    298 	(void) close(vfd);
    299 }
    300 
    301 /*
    302  * Compute checksum for MIPS disk volume header
    303  *
    304  * Mips volume header checksum is the 32bit 2's complement sum
    305  * of the entire volume header structure
    306  */
    307 int
    308 mipsvh_cksum(vhp)
    309 	struct mips_volheader *vhp;
    310 {
    311 	int i, *ptr;
    312 	int cksum = 0;
    313 
    314 	ptr = (int *)vhp;
    315 	i = sizeof(*vhp) / sizeof(*ptr);
    316 	while (i--)
    317 		cksum += *ptr++;
    318 	return cksum;
    319 }
    320 
    321 
    322 /*
    323  * Locate the volume directory slot that matches a filename
    324  *
    325  * If the file entry cannot be found and create is non-zero the next
    326  * empty slot is returned, otherwise return NULL
    327  */
    328 static struct mips_voldir *
    329 voldir_findfile(vhp, file, create)
    330 	struct mips_volheader *vhp;
    331 	const char *file;
    332 	int create;		/* return unused entry if not found */
    333 {
    334 	struct mips_voldir *vdp = vhp->vh_voldir;
    335 	int i;
    336 
    337 	for (i=0; i<MIPS_NVOLDIR; i++, vdp++) {
    338 		if (strcmp(vdp->vd_name, file) == 0)
    339 			return vdp;
    340 	}
    341 	if (create) {
    342 		vdp = vhp->vh_voldir;
    343 		for (i=0; i<MIPS_NVOLDIR; i++, vdp++)
    344 			if (vdp->vd_len == 0)
    345 				return vdp;
    346 	}
    347 	return NULL;
    348 }
    349