Home | History | Annotate | Line # | Download | only in installboot
bbinfo.c revision 1.11.18.1
      1  1.11.18.1     yamt /*	$NetBSD: bbinfo.c,v 1.11.18.1 2008/05/18 12:36:18 yamt Exp $ */
      2        1.1    lukem 
      3        1.1    lukem /*-
      4        1.1    lukem  * Copyright (c) 1998, 2002 The NetBSD Foundation, Inc.
      5        1.1    lukem  * All rights reserved.
      6        1.1    lukem  *
      7        1.1    lukem  * This code is derived from software contributed to The NetBSD Foundation
      8        1.1    lukem  * by Matt Fredette, Paul Kranenburg, and Luke Mewburn.
      9        1.1    lukem  *
     10        1.1    lukem  * Redistribution and use in source and binary forms, with or without
     11        1.1    lukem  * modification, are permitted provided that the following conditions
     12        1.1    lukem  * are met:
     13        1.1    lukem  * 1. Redistributions of source code must retain the above copyright
     14        1.1    lukem  *    notice, this list of conditions and the following disclaimer.
     15        1.1    lukem  * 2. Redistributions in binary form must reproduce the above copyright
     16        1.1    lukem  *    notice, this list of conditions and the following disclaimer in the
     17        1.1    lukem  *    documentation and/or other materials provided with the distribution.
     18        1.1    lukem  *
     19        1.1    lukem  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20        1.1    lukem  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21        1.1    lukem  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22        1.1    lukem  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23        1.1    lukem  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24        1.1    lukem  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25        1.1    lukem  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26        1.1    lukem  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27        1.1    lukem  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28        1.1    lukem  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29        1.1    lukem  * POSSIBILITY OF SUCH DAMAGE.
     30        1.1    lukem  */
     31        1.1    lukem 
     32        1.9    lukem #if HAVE_NBTOOL_CONFIG_H
     33        1.9    lukem #include "nbtool_config.h"
     34        1.9    lukem #endif
     35        1.9    lukem 
     36        1.1    lukem #include <sys/cdefs.h>
     37        1.9    lukem #if !defined(__lint)
     38  1.11.18.1     yamt __RCSID("$NetBSD: bbinfo.c,v 1.11.18.1 2008/05/18 12:36:18 yamt Exp $");
     39        1.1    lukem #endif	/* !__lint */
     40        1.1    lukem 
     41        1.1    lukem #include <sys/param.h>
     42  1.11.18.1     yamt #ifndef HAVE_NBTOOL_CONFIG_H
     43  1.11.18.1     yamt #include <sys/ioctl.h>
     44  1.11.18.1     yamt #include <sys/dkio.h>
     45  1.11.18.1     yamt #include <errno.h>
     46  1.11.18.1     yamt #endif
     47        1.1    lukem 
     48        1.1    lukem #include <assert.h>
     49        1.1    lukem #include <err.h>
     50        1.1    lukem #include <stddef.h>
     51        1.1    lukem #include <stdio.h>
     52        1.1    lukem #include <stdlib.h>
     53        1.1    lukem #include <string.h>
     54        1.1    lukem #include <unistd.h>
     55        1.1    lukem 
     56        1.1    lukem #include "installboot.h"
     57        1.1    lukem 
     58        1.1    lukem int
     59        1.5    lukem shared_bbinfo_clearboot(ib_params *params, struct bbinfo_params *bbparams,
     60        1.5    lukem 	int (*callback)(ib_params *, struct bbinfo_params *, uint8_t *))
     61        1.1    lukem {
     62        1.5    lukem 	uint8_t	*bb;
     63        1.1    lukem 	ssize_t	rv;
     64        1.1    lukem 	int	retval;
     65        1.1    lukem 
     66        1.1    lukem 	assert(params != NULL);
     67        1.1    lukem 	assert(params->fsfd != -1);
     68        1.1    lukem 	assert(params->filesystem != NULL);
     69        1.1    lukem 	assert(bbparams != NULL);
     70        1.1    lukem 	assert((strlen(bbparams->magic) + 1) == 32);
     71        1.1    lukem 
     72        1.1    lukem 	retval = 0;
     73        1.1    lukem 	if ((bb = malloc(bbparams->maxsize)) == NULL) {
     74        1.4    lukem 		warn("Allocating %lu bytes for bbinfo",
     75        1.1    lukem 		    (unsigned long) bbparams->maxsize);
     76        1.1    lukem 		goto done;
     77        1.1    lukem 	}
     78        1.1    lukem 
     79        1.3    lukem 		/* First check that it _could_ exist here */
     80        1.1    lukem 	rv = pread(params->fsfd, bb, bbparams->maxsize, bbparams->offset);
     81        1.1    lukem 	if (rv == -1) {
     82        1.1    lukem 		warn("Reading `%s'", params->filesystem);
     83        1.1    lukem 		goto done;
     84        1.1    lukem 	} else if (rv != bbparams->maxsize) {
     85        1.1    lukem 		warnx("Reading `%s': short read", params->filesystem);
     86        1.1    lukem 		goto done;
     87        1.1    lukem 	}
     88        1.1    lukem 
     89        1.5    lukem 		/* Now clear out (past the header offset) */
     90        1.5    lukem 	memset(bb + bbparams->headeroffset, 0,
     91        1.5    lukem 	    bbparams->maxsize - bbparams->headeroffset);
     92        1.5    lukem 	if (callback != NULL && ! (*callback)(params, bbparams, bb))
     93        1.5    lukem 		goto done;
     94        1.1    lukem 
     95        1.1    lukem 	if (params->flags & IB_VERBOSE)
     96        1.1    lukem 		printf("%slearing boot block\n",
     97        1.1    lukem 		    (params->flags & IB_NOWRITE) ? "Not c" : "C");
     98        1.1    lukem 	if (params->flags & IB_NOWRITE) {
     99        1.1    lukem 		retval = 1;
    100        1.1    lukem 		goto done;
    101        1.1    lukem 	}
    102        1.1    lukem 
    103        1.1    lukem 	rv = pwrite(params->fsfd, bb, bbparams->maxsize, bbparams->offset);
    104  1.11.18.1     yamt #ifdef DIOCWLABEL
    105  1.11.18.1     yamt 	if (rv == -1 && errno == EROFS) {
    106  1.11.18.1     yamt 		/*
    107  1.11.18.1     yamt 		 * The first sector might be protected by
    108  1.11.18.1     yamt 		 * bounds_check_with_label(9)
    109  1.11.18.1     yamt 		 */
    110  1.11.18.1     yamt 		int enable;
    111  1.11.18.1     yamt 
    112  1.11.18.1     yamt 		enable = 1;
    113  1.11.18.1     yamt 		rv = ioctl(params->fsfd, DIOCWLABEL, &enable);
    114  1.11.18.1     yamt 		if (rv != 0) {
    115  1.11.18.1     yamt 			warn("Cannot enable writes to the label sector");
    116  1.11.18.1     yamt 			goto done;
    117  1.11.18.1     yamt 		}
    118  1.11.18.1     yamt 
    119  1.11.18.1     yamt 		rv = pwrite(params->fsfd, bb, bbparams->maxsize,
    120  1.11.18.1     yamt 		    bbparams->offset);
    121  1.11.18.1     yamt 
    122  1.11.18.1     yamt 		/* Reset write-protect. */
    123  1.11.18.1     yamt 		enable = 0;
    124  1.11.18.1     yamt 		(void)ioctl(params->fsfd, DIOCWLABEL, &enable);
    125  1.11.18.1     yamt 	}
    126  1.11.18.1     yamt #endif
    127        1.1    lukem 	if (rv == -1) {
    128        1.1    lukem 		warn("Writing `%s'", params->filesystem);
    129        1.1    lukem 		goto done;
    130        1.1    lukem 	} else if (rv != bbparams->maxsize) {
    131        1.1    lukem 		warnx("Writing `%s': short write", params->filesystem);
    132        1.1    lukem 		goto done;
    133        1.1    lukem 	} else
    134        1.1    lukem 		retval = 1;
    135        1.1    lukem 
    136        1.1    lukem  done:
    137        1.1    lukem 	if (bb != NULL)
    138        1.1    lukem 		free(bb);
    139        1.1    lukem 	return (retval);
    140        1.1    lukem }
    141        1.1    lukem 
    142        1.1    lukem int
    143        1.1    lukem shared_bbinfo_setboot(ib_params *params, struct bbinfo_params *bbparams,
    144        1.5    lukem 	int (*callback)(ib_params *, struct bbinfo_params *, uint8_t *))
    145        1.1    lukem {
    146        1.5    lukem 	uint8_t		*bb;
    147        1.1    lukem 	int		retval;
    148        1.1    lukem 	ssize_t		rv;
    149        1.1    lukem 	size_t		bbi;
    150        1.1    lukem 	struct shared_bbinfo	*bbinfop;	/* bbinfo in prototype image */
    151        1.1    lukem 	uint32_t	maxblk, nblk, blk_i;
    152        1.1    lukem 	ib_block	*blocks;
    153        1.1    lukem 
    154        1.1    lukem 	assert(params != NULL);
    155        1.1    lukem 	assert(params->fsfd != -1);
    156        1.1    lukem 	assert(params->filesystem != NULL);
    157        1.1    lukem 	assert(params->fstype != NULL);
    158        1.1    lukem 	assert(params->s1fd != -1);
    159        1.1    lukem 	assert(params->stage1 != NULL);
    160        1.1    lukem 	assert(bbparams != NULL);
    161        1.1    lukem 	assert((strlen(bbparams->magic) + 1) == 32);
    162        1.1    lukem 
    163       1.11       he 	bbinfop = NULL;		/* XXXGCC -Wuninitialized [sparc64] */
    164        1.1    lukem 	retval = 0;
    165        1.1    lukem 	blocks = NULL;
    166        1.1    lukem 	if ((bb = malloc(bbparams->maxsize)) == NULL) {
    167        1.4    lukem 		warn("Allocating %lu bytes for bbinfo",
    168        1.1    lukem 		    (unsigned long) bbparams->maxsize);
    169        1.1    lukem 		goto done;
    170        1.1    lukem 	}
    171        1.1    lukem 
    172        1.1    lukem 	if (params->stage2 == NULL) {
    173        1.1    lukem 		warnx("Name of secondary bootstrap not provided");
    174        1.1    lukem 		goto done;
    175        1.1    lukem 	}
    176        1.1    lukem 
    177        1.1    lukem 	if (params->s1stat.st_size >
    178        1.1    lukem 	    bbparams->maxsize - bbparams->headeroffset) {
    179        1.1    lukem 		warnx("`%s' cannot be larger than %lu bytes",
    180        1.1    lukem 		    params->stage1, (unsigned long)(bbparams->maxsize -
    181        1.1    lukem 			bbparams->headeroffset));
    182        1.1    lukem 		goto done;
    183        1.1    lukem 	}
    184        1.1    lukem 
    185        1.1    lukem 	memset(bb, 0, bbparams->maxsize);
    186        1.1    lukem 	rv = read(params->s1fd, bb + bbparams->headeroffset,
    187        1.1    lukem 	    bbparams->maxsize - bbparams->headeroffset);
    188        1.1    lukem 	if (rv == -1) {
    189        1.1    lukem 		warn("Reading `%s'", params->stage1);
    190        1.1    lukem 		goto done;
    191        1.1    lukem 	}
    192        1.1    lukem 
    193        1.3    lukem 		/*
    194        1.3    lukem 		 * Quick sanity check that the bootstrap given
    195        1.3    lukem 		 * is *not* an ELF executable.
    196        1.3    lukem 		 */
    197        1.1    lukem 	if (memcmp(bb + bbparams->headeroffset + 1, "ELF", strlen("ELF"))
    198        1.1    lukem 	    == 0) {
    199        1.4    lukem 		warnx("`%s' is an ELF executable; need raw binary",
    200        1.1    lukem 		    params->stage1);
    201        1.1    lukem 		goto done;
    202        1.1    lukem 	}
    203        1.1    lukem 
    204        1.5    lukem #define HOSTTOTARGET32(x) ((bbparams->endian == BBINFO_LITTLE_ENDIAN) \
    205        1.6  tsutsui 			    ? htole32((x)) : htobe32((x)))
    206        1.6  tsutsui #define TARGET32TOHOST(x) ((bbparams->endian == BBINFO_LITTLE_ENDIAN) \
    207        1.5    lukem 			    ? le32toh((x)) : be32toh((x)))
    208        1.1    lukem 
    209        1.3    lukem 		/* Look for the bbinfo structure. */
    210       1.10      chs 	bbinfop = NULL;
    211        1.1    lukem 	for (bbi = 0; bbi < bbparams->maxsize; bbi += sizeof(uint32_t)) {
    212        1.5    lukem 		bbinfop = (void *) (bb + bbparams->headeroffset + bbi);
    213        1.1    lukem 		if (memcmp(bbinfop->bbi_magic, bbparams->magic,
    214        1.1    lukem 			    sizeof(bbinfop->bbi_magic)) == 0)
    215        1.1    lukem 			break;
    216        1.1    lukem 	}
    217        1.1    lukem 	if (bbi >= bbparams->maxsize) {
    218        1.4    lukem 		warnx("%s bbinfo structure not found in `%s'",
    219        1.1    lukem 		    params->machine->name, params->stage1);
    220        1.1    lukem 		goto done;
    221        1.1    lukem 	}
    222        1.6  tsutsui 	maxblk = TARGET32TOHOST(bbinfop->bbi_block_count);
    223        1.1    lukem 	if (maxblk == 0 || maxblk > (bbparams->maxsize / sizeof(uint32_t))) {
    224        1.1    lukem 		warnx("%s bbinfo structure in `%s' has preposterous size `%u'",
    225        1.1    lukem 		    params->machine->name, params->stage1, maxblk);
    226        1.1    lukem 		goto done;
    227        1.1    lukem 	}
    228        1.1    lukem 
    229        1.3    lukem 		/* Allocate space for our block list. */
    230        1.1    lukem 	blocks = malloc(sizeof(*blocks) * maxblk);
    231        1.1    lukem 	if (blocks == NULL) {
    232        1.4    lukem 		warn("Allocating %lu bytes",
    233        1.4    lukem 		    (unsigned long)sizeof(*blocks) * maxblk);
    234        1.1    lukem 		goto done;
    235        1.1    lukem 	}
    236        1.1    lukem 
    237        1.1    lukem 	if (S_ISREG(params->fsstat.st_mode)) {
    238        1.1    lukem 		if (fsync(params->fsfd) == -1)
    239        1.1    lukem 			warn("Synchronising file system `%s'",
    240        1.1    lukem 			    params->filesystem);
    241        1.1    lukem 	} else {
    242        1.1    lukem 		/* Ensure the secondary bootstrap is on disk. */
    243        1.1    lukem 		sync();
    244        1.1    lukem 	}
    245        1.1    lukem 
    246        1.3    lukem 		/* Collect the blocks for the secondary bootstrap. */
    247        1.1    lukem 	nblk = maxblk;
    248        1.1    lukem 	if (! params->fstype->findstage2(params, &nblk, blocks))
    249        1.1    lukem 		goto done;
    250        1.1    lukem 	if (nblk == 0) {
    251        1.1    lukem 		warnx("Secondary bootstrap `%s' is empty",
    252        1.4    lukem 		    params->stage2);
    253        1.1    lukem 		goto done;
    254        1.1    lukem 	}
    255        1.1    lukem 
    256        1.3    lukem 		/* Save those blocks in the primary bootstrap. */
    257        1.1    lukem 	bbinfop->bbi_block_count = HOSTTOTARGET32(nblk);
    258        1.1    lukem 	bbinfop->bbi_block_size = HOSTTOTARGET32(blocks[0].blocksize);
    259        1.1    lukem 	for (blk_i = 0; blk_i < nblk; blk_i++) {
    260        1.4    lukem 		bbinfop->bbi_block_table[blk_i] =
    261        1.1    lukem 		    HOSTTOTARGET32(blocks[blk_i].block);
    262        1.1    lukem 		if (blocks[blk_i].blocksize < blocks[0].blocksize &&
    263        1.1    lukem 		    blk_i + 1 != nblk) {
    264        1.4    lukem 			warnx("Secondary bootstrap `%s' blocks do not have "
    265        1.1    lukem 			    "a uniform size", params->stage2);
    266        1.1    lukem 			goto done;
    267        1.1    lukem 		}
    268        1.1    lukem 	}
    269        1.2    lukem 	if (callback != NULL && ! (*callback)(params, bbparams, bb))
    270        1.1    lukem 		goto done;
    271        1.1    lukem 
    272        1.1    lukem 	if (params->flags & IB_VERBOSE) {
    273        1.1    lukem 		printf("Bootstrap start sector: %u\n",
    274        1.1    lukem 		    bbparams->offset / bbparams->blocksize);
    275        1.1    lukem 		printf("Bootstrap byte count:   %u\n", (unsigned)rv);
    276        1.1    lukem 		printf("Bootstrap block table:  "
    277        1.1    lukem 			"%u entries of %u bytes available, %u used:",
    278        1.1    lukem 		    maxblk, blocks[0].blocksize, nblk);
    279        1.1    lukem 		for (blk_i = 0; blk_i < nblk; blk_i++)
    280        1.7     fvdl 			printf(" %llu",
    281        1.7     fvdl 			    (unsigned long long)blocks[blk_i].block);
    282        1.1    lukem 		printf("\n%sriting bootstrap\n",
    283        1.1    lukem 		    (params->flags & IB_NOWRITE) ? "Not w" : "W");
    284        1.1    lukem 	}
    285        1.1    lukem 	if (params->flags & IB_NOWRITE) {
    286        1.1    lukem 		retval = 1;
    287        1.1    lukem 		goto done;
    288        1.1    lukem 	}
    289        1.1    lukem 
    290        1.1    lukem 	rv = pwrite(params->fsfd, bb, bbparams->maxsize, bbparams->offset);
    291  1.11.18.1     yamt #ifdef DIOCWLABEL
    292  1.11.18.1     yamt 	if (rv == -1 && errno == EROFS) {
    293  1.11.18.1     yamt 		/*
    294  1.11.18.1     yamt 		 * The first sector might be protected by
    295  1.11.18.1     yamt 		 * bounds_check_with_label(9)
    296  1.11.18.1     yamt 		 */
    297  1.11.18.1     yamt 		int enable;
    298  1.11.18.1     yamt 
    299  1.11.18.1     yamt 		enable = 1;
    300  1.11.18.1     yamt 		rv = ioctl(params->fsfd, DIOCWLABEL, &enable);
    301  1.11.18.1     yamt 		if (rv != 0) {
    302  1.11.18.1     yamt 			warn("Cannot enable writes to the label sector");
    303  1.11.18.1     yamt 			goto done;
    304  1.11.18.1     yamt 		}
    305  1.11.18.1     yamt 
    306  1.11.18.1     yamt 		rv = pwrite(params->fsfd, bb, bbparams->maxsize,
    307  1.11.18.1     yamt 		    bbparams->offset);
    308  1.11.18.1     yamt 
    309  1.11.18.1     yamt 		/* Reset write-protect. */
    310  1.11.18.1     yamt 		enable = 0;
    311  1.11.18.1     yamt 		(void)ioctl(params->fsfd, DIOCWLABEL, &enable);
    312  1.11.18.1     yamt 	}
    313  1.11.18.1     yamt #endif
    314        1.1    lukem 	if (rv == -1) {
    315        1.1    lukem 		warn("Writing `%s'", params->filesystem);
    316        1.1    lukem 		goto done;
    317        1.1    lukem 	} else if (rv != bbparams->maxsize) {
    318        1.1    lukem 		warnx("Writing `%s': short write", params->filesystem);
    319        1.1    lukem 		goto done;
    320        1.1    lukem 	} else {
    321        1.1    lukem 		retval = 1;
    322        1.1    lukem 	}
    323        1.1    lukem 
    324        1.1    lukem  done:
    325        1.1    lukem 	if (blocks != NULL)
    326        1.4    lukem 		free(blocks);
    327        1.1    lukem 	if (bb != NULL)
    328        1.4    lukem 		free(bb);
    329        1.1    lukem 	return (retval);
    330        1.1    lukem }
    331