Home | History | Annotate | Line # | Download | only in installboot
installboot.c revision 1.1.2.2
      1 /*	$NetBSD: installboot.c,v 1.1.2.2 2000/11/20 20:14:14 bouyer 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 	extern char *__progname;
     77 
     78 	fprintf(stderr, "usage:\n");
     79 	fprintf(stderr, "\t%s [-nv] disk bootstrap [name]\n", __progname);
     80 	fprintf(stderr, "\t%s -r [-nv] disk [name]\n", __progname);
     81 	fprintf(stderr, "\t%s -l [-nv] disk\n", __progname);
     82 	exit(EXIT_FAILURE);
     83 }
     84 
     85 int
     86 main(int argc, char *argv[])
     87 {
     88 	const char *disk;
     89 	int c, rflag, lflag;
     90 
     91 	rflag = lflag = verbose = nowrite = 0;
     92 
     93 	while ((c = getopt(argc, argv, "lnrv")) != -1) {
     94 		switch (c) {
     95 		case 'l':
     96 			/* List volume directory contents */
     97 			lflag = 1;
     98 			break;
     99 		case 'n':
    100 			/* Disable write of boot sectors */
    101 			nowrite = 1;
    102 			break;
    103 		case 'r':
    104 			/* Clear any existing boot block */
    105 			rflag = 1;
    106 			break;
    107 		case 'v':
    108 			/* Verbose output */
    109 			verbose = 1;
    110 			break;
    111 		default:
    112 			usage();
    113 		}
    114 	}
    115 
    116 	argc -= optind;
    117 	argv += optind;
    118 
    119 	if ((lflag && rflag) || argc < 1 || (lflag && argc != 1) ||
    120 	    (rflag && argc > 3) || argc > 4)
    121 		usage();
    122 
    123 	disk = argv[0];
    124 
    125 	if (lflag)
    126 		do_list(disk);
    127 	else if (rflag)
    128 		do_remove(disk, argc==2?argv[1]:DEFAULT_BOOTFILE);
    129 	else
    130 		do_install(disk, argv[1], argc==3?argv[2]:DEFAULT_BOOTFILE);
    131 
    132 	exit(EXIT_SUCCESS);
    133 }
    134 
    135 static void
    136 do_list(disk)
    137 	const char *disk;
    138 {
    139 	struct mips_volheader vh;
    140 	struct mips_voldir *vdp;
    141 	int i;
    142 
    143 	read_volheader(disk, &vh);
    144 
    145 	printf("Slot\t  LBN\tLength\tFilename\n");
    146 	printf("------------------------------------------\n");
    147 	for (i=0, vdp=vh.vh_voldir; i<MIPS_NVOLDIR; i++, vdp++)
    148 		if (vdp->vd_len)
    149 			printf("%2d:\t%5d\t%6d\t%s\n", i, vdp->vd_lba,
    150 			       vdp->vd_len, vdp->vd_name);
    151 }
    152 
    153 static void
    154 do_remove(disk, filename)
    155 	const char *disk;
    156 	const char *filename;
    157 {
    158 	struct mips_volheader vh;
    159 	struct mips_voldir *vdp;
    160 
    161 	read_volheader(disk, &vh);
    162 	vdp = voldir_findfile(&vh, filename, 0);
    163 	if (vdp == NULL)
    164 		FATAL("%s: file not found", disk);
    165 
    166 	bzero(vdp, sizeof(*vdp));
    167 
    168 	/* Update volume header */
    169 	write_volheader(disk, &vh);
    170 }
    171 
    172 static void
    173 do_install(disk, bootstrap, bootname)
    174 	const char *disk;
    175 	const char *bootstrap;
    176 	const char *bootname;
    177 {
    178 	struct stat bootstrapsb;
    179 	struct mips_volheader vh;
    180 	struct mips_voldir *vdp;
    181 	int fd;
    182 	char *boot_code;
    183 	size_t boot_size;
    184 	ssize_t len;
    185 
    186 	/* Open the input file and check it out */
    187 	if ((fd = open(bootstrap, O_RDONLY)) == -1)
    188 		FATALIO("open %s", bootstrap);
    189 	if (fstat(fd, &bootstrapsb) == -1)
    190 		FATALIO("fstat %s", bootstrap);
    191 	if (!S_ISREG(bootstrapsb.st_mode))
    192 		FATAL("%s must be a regular file", bootstrap);
    193 
    194 	boot_size = roundup(bootstrapsb.st_size, DEV_BSIZE);
    195 
    196 	if (boot_size > 8192-1024)
    197 		FATAL("bootstrap program too large (%d bytes)", boot_size);
    198 
    199 	boot_code = malloc(boot_size);
    200 	if (boot_code == NULL)
    201 		FATAL("malloc %d bytes failed", boot_size);
    202 	bzero(boot_code, boot_size);
    203 
    204 	/* read the file into the buffer */
    205 	len = read(fd, boot_code, bootstrapsb.st_size);
    206 	if (len == -1)
    207 		FATALIO("read %s", bootstrap);
    208 	else if (len != bootstrapsb.st_size)
    209 		FATAL("read %s: short read", bootstrap);
    210 	(void)close(fd);
    211 
    212 	read_volheader(disk, &vh);
    213 
    214 	vdp = voldir_findfile(&vh, bootname, 1);
    215 	if (vdp == NULL)
    216 		FATAL("%s: volume directory full", disk);
    217 
    218 	strcpy(vdp->vd_name, bootname);
    219 	vdp->vd_lba = BOOTBLOCK_NUMBER;
    220 	vdp->vd_len = bootstrapsb.st_size;
    221 
    222 	if (nowrite) {
    223 	    if (verbose)
    224 		    fprintf(stderr, "not writing\n");
    225 	    return;
    226 	}
    227 
    228 	if (verbose)
    229 		fprintf(stderr, "writing bootstrap (%d bytes at logical block %d)\n",
    230 			boot_size, 2);
    231 
    232 	/* Write bootstrap */
    233 	if ((fd = open(disk, O_WRONLY)) == -1)
    234 		FATALIO("open %s", bootstrap);
    235 	len = pwrite(fd, boot_code, boot_size, BOOTBLOCK_OFFSET);
    236 	if (len == -1)
    237 		FATAL("write %s", disk);
    238 	if (len != boot_size)
    239 		FATAL("write %s: short write", disk);
    240 	(void) close(fd);
    241 
    242 	/* Update volume header */
    243 	write_volheader(disk, &vh);
    244 }
    245 
    246 static void
    247 read_volheader(disk, vhp)
    248      const char *disk;
    249      struct mips_volheader *vhp;
    250 {
    251 	int vfd;
    252 	ssize_t len;
    253 
    254 	if ((vfd = open(disk, O_RDONLY)) == -1)
    255 		FATALIO("open %s", disk);
    256 
    257 	len = pread(vfd, vhp, sizeof(*vhp), MIPS_VHSECTOR*DEV_BSIZE);
    258 
    259 	(void) close(vfd);
    260 
    261 	if (len == -1)
    262 		FATALIO("read %s", disk);
    263 	if (len != sizeof(*vhp))
    264 		FATAL("read %s: short read", disk);
    265 
    266 	/* Check volume header magic */
    267 	if (vhp->vh_magic != MIPS_VHMAGIC)
    268 		FATAL("%s: no volume header", disk);
    269 
    270 	/* check volume header checksum */
    271 	if (mipsvh_cksum(vhp))
    272 		FATAL("%s: volume header corrupted", disk);
    273 }
    274 
    275 static void
    276 write_volheader(disk, vhp)
    277 	const char *disk;
    278 	struct mips_volheader *vhp;
    279 {
    280 	int vfd;
    281 	ssize_t len;
    282 
    283 	/* update volume header checksum */
    284 	vhp->vh_cksum = 0;
    285 	vhp->vh_cksum = -mipsvh_cksum(vhp);
    286 
    287 	if ((vfd = open(disk, O_WRONLY)) == -1)
    288 		FATALIO("open %s", disk);
    289 
    290 	if (verbose)
    291 		fprintf(stderr, "%s: writing volume header\n", disk);
    292 
    293 	len = pwrite(vfd, vhp, sizeof(*vhp), MIPS_VHSECTOR*512); /* XXX */
    294 	if (len == -1)
    295 		FATALIO("write %s", disk);
    296 	if (len != sizeof(*vhp))
    297 		FATAL("write %s: short write", disk);
    298 
    299 	(void) close(vfd);
    300 }
    301 
    302 /*
    303  * Compute checksum for MIPS disk volume header
    304  *
    305  * Mips volume header checksum is the 32bit 2's complement sum
    306  * of the entire volume header structure
    307  */
    308 int
    309 mipsvh_cksum(vhp)
    310 	struct mips_volheader *vhp;
    311 {
    312 	int i, *ptr;
    313 	int cksum = 0;
    314 
    315 	ptr = (int *)vhp;
    316 	i = sizeof(*vhp) / sizeof(*ptr);
    317 	while (i--)
    318 		cksum += *ptr++;
    319 	return cksum;
    320 }
    321 
    322 
    323 /*
    324  * Locate the volume directory slot that matches a filename
    325  *
    326  * If the file entry cannot be found and create is non-zero the next
    327  * empty slot is returned, otherwise return NULL
    328  */
    329 static struct mips_voldir *
    330 voldir_findfile(vhp, file, create)
    331 	struct mips_volheader *vhp;
    332 	const char *file;
    333 	int create;		/* return unused entry if not found */
    334 {
    335 	struct mips_voldir *vdp = vhp->vh_voldir;
    336 	int i;
    337 
    338 	for (i=0; i<MIPS_NVOLDIR; i++, vdp++) {
    339 		if (strcmp(vdp->vd_name, file) == 0)
    340 			return vdp;
    341 	}
    342 	if (create) {
    343 		vdp = vhp->vh_voldir;
    344 		for (i=0; i<MIPS_NVOLDIR; i++, vdp++)
    345 			if (vdp->vd_len == 0)
    346 				return vdp;
    347 	}
    348 	return NULL;
    349 }
    350