1 /* $NetBSD: bbinfo.c,v 1.14 2009/04/05 11:55:39 lukem Exp $ */
4 * Copyright (c) 1998, 2002 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Matt Fredette, Paul Kranenburg, and Luke Mewburn.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
32 #if HAVE_NBTOOL_CONFIG_H
33 #include "nbtool_config.h"
36 #include <sys/cdefs.h>
38 __RCSID("$NetBSD: bbinfo.c,v 1.14 2009/04/05 11:55:39 lukem Exp $");
41 #include <sys/param.h>
42 #ifndef HAVE_NBTOOL_CONFIG_H
43 #include <sys/ioctl.h>
56 #include "installboot.h"
59 shared_bbinfo_clearboot(ib_params
*params
, struct bbinfo_params
*bbparams
,
60 int (*callback
)(ib_params
*, struct bbinfo_params
*, uint8_t *))
66 assert(params
!= NULL
);
67 assert(params
->fsfd
!= -1);
68 assert(params
->filesystem
!= NULL
);
69 assert(bbparams
!= NULL
);
70 assert((strlen(bbparams
->magic
) + 1) == 32);
73 if ((bb
= malloc(bbparams
->maxsize
)) == NULL
) {
74 warn("Allocating %lu bytes for bbinfo",
75 (unsigned long) bbparams
->maxsize
);
79 /* First check that it _could_ exist here */
80 rv
= pread(params
->fsfd
, bb
, bbparams
->maxsize
, bbparams
->offset
);
82 warn("Reading `%s'", params
->filesystem
);
84 } else if ((uint32_t)rv
!= bbparams
->maxsize
) {
85 warnx("Reading `%s': short read", params
->filesystem
);
89 /* Now clear out (past the header offset) */
90 memset(bb
+ bbparams
->headeroffset
, 0,
91 bbparams
->maxsize
- bbparams
->headeroffset
);
92 if (callback
!= NULL
&& ! (*callback
)(params
, bbparams
, bb
))
95 if (params
->flags
& IB_VERBOSE
)
96 printf("%slearing boot block\n",
97 (params
->flags
& IB_NOWRITE
) ? "Not c" : "C");
98 if (params
->flags
& IB_NOWRITE
) {
103 rv
= pwrite(params
->fsfd
, bb
, bbparams
->maxsize
, bbparams
->offset
);
105 if (rv
== -1 && errno
== EROFS
) {
107 * The first sector might be protected by
108 * bounds_check_with_label(9)
113 rv
= ioctl(params
->fsfd
, DIOCWLABEL
, &enable
);
115 warn("Cannot enable writes to the label sector");
119 rv
= pwrite(params
->fsfd
, bb
, bbparams
->maxsize
,
122 /* Reset write-protect. */
124 (void)ioctl(params
->fsfd
, DIOCWLABEL
, &enable
);
128 warn("Writing `%s'", params
->filesystem
);
130 } else if ((uint32_t)rv
!= bbparams
->maxsize
) {
131 warnx("Writing `%s': short write", params
->filesystem
);
143 shared_bbinfo_setboot(ib_params
*params
, struct bbinfo_params
*bbparams
,
144 int (*callback
)(ib_params
*, struct bbinfo_params
*, uint8_t *))
150 struct shared_bbinfo
*bbinfop
; /* bbinfo in prototype image */
151 uint32_t maxblk
, nblk
, blk_i
;
154 assert(params
!= NULL
);
155 assert(params
->fsfd
!= -1);
156 assert(params
->filesystem
!= NULL
);
157 assert(params
->fstype
!= NULL
);
158 assert(params
->s1fd
!= -1);
159 assert(params
->stage1
!= NULL
);
160 assert(bbparams
!= NULL
);
161 assert((strlen(bbparams
->magic
) + 1) == 32);
163 bbinfop
= NULL
; /* XXXGCC -Wuninitialized [sparc64] */
166 if ((bb
= malloc(bbparams
->maxsize
)) == NULL
) {
167 warn("Allocating %lu bytes for bbinfo",
168 (unsigned long) bbparams
->maxsize
);
172 if (params
->stage2
== NULL
) {
173 warnx("Name of secondary bootstrap not provided");
177 if (params
->s1stat
.st_size
>
178 bbparams
->maxsize
- bbparams
->headeroffset
) {
179 warnx("`%s' cannot be larger than %lu bytes",
180 params
->stage1
, (unsigned long)(bbparams
->maxsize
-
181 bbparams
->headeroffset
));
185 memset(bb
, 0, bbparams
->maxsize
);
186 rv
= read(params
->s1fd
, bb
+ bbparams
->headeroffset
,
187 bbparams
->maxsize
- bbparams
->headeroffset
);
189 warn("Reading `%s'", params
->stage1
);
194 * Quick sanity check that the bootstrap given
195 * is *not* an ELF executable.
197 if (memcmp(bb
+ bbparams
->headeroffset
+ 1, "ELF", strlen("ELF"))
199 warnx("`%s' is an ELF executable; need raw binary",
204 #define HOSTTOTARGET32(x) ((bbparams->endian == BBINFO_LITTLE_ENDIAN) \
205 ? (uint32_t)htole32((x)) : (uint32_t)htobe32((x)))
206 #define TARGET32TOHOST(x) ((bbparams->endian == BBINFO_LITTLE_ENDIAN) \
207 ? (uint32_t)le32toh((x)) : (uint32_t)be32toh((x)))
209 /* Look for the bbinfo structure. */
211 for (bbi
= 0; bbi
< bbparams
->maxsize
; bbi
+= sizeof(uint32_t)) {
212 bbinfop
= (void *) (bb
+ bbparams
->headeroffset
+ bbi
);
213 if (memcmp(bbinfop
->bbi_magic
, bbparams
->magic
,
214 sizeof(bbinfop
->bbi_magic
)) == 0)
217 if (bbi
>= bbparams
->maxsize
) {
218 warnx("%s bbinfo structure not found in `%s'",
219 params
->machine
->name
, params
->stage1
);
222 maxblk
= TARGET32TOHOST(bbinfop
->bbi_block_count
);
223 if (maxblk
== 0 || maxblk
> (bbparams
->maxsize
/ sizeof(uint32_t))) {
224 warnx("%s bbinfo structure in `%s' has preposterous size `%u'",
225 params
->machine
->name
, params
->stage1
, maxblk
);
229 /* Allocate space for our block list. */
230 blocks
= malloc(sizeof(*blocks
) * maxblk
);
231 if (blocks
== NULL
) {
232 warn("Allocating %lu bytes",
233 (unsigned long)sizeof(*blocks
) * maxblk
);
237 if (S_ISREG(params
->fsstat
.st_mode
)) {
238 if (fsync(params
->fsfd
) == -1)
239 warn("Synchronising file system `%s'",
242 /* Ensure the secondary bootstrap is on disk. */
246 /* Collect the blocks for the secondary bootstrap. */
248 if (! params
->fstype
->findstage2(params
, &nblk
, blocks
))
251 warnx("Secondary bootstrap `%s' is empty",
256 /* Save those blocks in the primary bootstrap. */
257 bbinfop
->bbi_block_count
= HOSTTOTARGET32(nblk
);
258 bbinfop
->bbi_block_size
= HOSTTOTARGET32(blocks
[0].blocksize
);
259 for (blk_i
= 0; blk_i
< nblk
; blk_i
++) {
260 bbinfop
->bbi_block_table
[blk_i
] =
261 HOSTTOTARGET32(blocks
[blk_i
].block
);
262 if (blocks
[blk_i
].blocksize
< blocks
[0].blocksize
&&
264 warnx("Secondary bootstrap `%s' blocks do not have "
265 "a uniform size", params
->stage2
);
269 if (callback
!= NULL
&& ! (*callback
)(params
, bbparams
, bb
))
272 if (params
->flags
& IB_VERBOSE
) {
273 printf("Bootstrap start sector: %u\n",
274 bbparams
->offset
/ bbparams
->blocksize
);
275 printf("Bootstrap byte count: %u\n", (unsigned)rv
);
276 printf("Bootstrap block table: "
277 "%u entries of %u bytes available, %u used:",
278 maxblk
, blocks
[0].blocksize
, nblk
);
279 for (blk_i
= 0; blk_i
< nblk
; blk_i
++)
281 (unsigned long long)blocks
[blk_i
].block
);
282 printf("\n%sriting bootstrap\n",
283 (params
->flags
& IB_NOWRITE
) ? "Not w" : "W");
285 if (params
->flags
& IB_NOWRITE
) {
290 rv
= pwrite(params
->fsfd
, bb
, bbparams
->maxsize
, bbparams
->offset
);
292 if (rv
== -1 && errno
== EROFS
) {
294 * The first sector might be protected by
295 * bounds_check_with_label(9)
300 rv
= ioctl(params
->fsfd
, DIOCWLABEL
, &enable
);
302 warn("Cannot enable writes to the label sector");
306 rv
= pwrite(params
->fsfd
, bb
, bbparams
->maxsize
,
309 /* Reset write-protect. */
311 (void)ioctl(params
->fsfd
, DIOCWLABEL
, &enable
);
315 warn("Writing `%s'", params
->filesystem
);
317 } else if ((uint32_t)rv
!= bbparams
->maxsize
) {
318 warnx("Writing `%s': short write", params
->filesystem
);