1 /* $NetBSD: installboot.c,v 1.14 2008/01/12 09:54:30 tsutsui Exp $ */
4 * Copyright (c) 1998 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
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 #include <sys/param.h>
33 #include <sys/cdefs.h>
34 #include <sys/mount.h>
37 #include <sys/statvfs.h>
38 #include <ufs/ufs/dinode.h>
39 #include <ufs/ufs/dir.h>
40 #include <ufs/ffs/fs.h>
48 #include <sys/disklabel.h>
52 int verbose
, nowrite
, hflag
;
53 char *boot
, *proto
, *dev
;
56 #define X_BLOCK_SIZE 0
57 #define X_BLOCK_COUNT 1
58 #define X_BLOCK_TABLE 2
71 int *block_size_p
; /* block size var. in prototype image */
72 int *block_count_p
; /* block count var. in prototype image */
74 int32_t *block_table
; /* block number array in prototype image */
75 int maxblocknum
; /* size of this array */
78 char *loadprotoblocks(char *, size_t *);
79 int loadblocknums(char *, int);
80 static void devread(int, void *, daddr_t
, size_t, char *);
81 static void usage(void);
82 int main(int, char *[]);
90 "usage: installboot [-n] [-v] [-h] <boot> <proto> <device>\n");
95 main(int argc
, char *argv
[])
102 while ((c
= getopt(argc
, argv
, "vnh")) != -1) {
105 /* Don't strip a.out header */
109 /* Do not actually write the bootblock to disk */
121 if (argc
- optind
< 3) {
126 proto
= argv
[optind
+ 1];
127 dev
= argv
[optind
+ 2];
130 printf("boot: %s\n", boot
);
131 printf("proto: %s\n", proto
);
132 printf("device: %s\n", dev
);
135 /* Load proto blocks into core */
136 if ((protostore
= loadprotoblocks(proto
, &protosize
)) == NULL
)
139 /* XXX - Paranoia: Make sure size is aligned! */
140 if (protosize
& (DEV_BSIZE
- 1))
141 err(1, "proto bootblock bad size=%d", protosize
);
143 /* Open and check raw disk device */
144 if ((devfd
= open(dev
, O_RDONLY
, 0)) < 0)
145 err(1, "open: %s", dev
);
147 /* Extract and load block numbers */
148 if (loadblocknums(boot
, devfd
) != 0)
156 /* Write patched proto bootblocks into the superblock */
157 if (protosize
> SBLOCKSIZE
- DEV_BSIZE
)
158 errx(1, "proto bootblocks too big");
160 /* The primary bootblock needs to be written to the raw partition */
161 dev
[strlen(dev
) - 1] = 'a' + RAW_PART
;
163 if ((devfd
= open(dev
, O_RDWR
, 0)) < 0)
164 err(1, "open: %s", dev
);
166 if (lseek(devfd
, DEV_BSIZE
, SEEK_SET
) != DEV_BSIZE
)
167 err(1, "lseek bootstrap");
169 /* Sync filesystems (to clean in-memory superblock?) */
172 if (write(devfd
, protostore
, protosize
) != protosize
)
173 err(1, "write bootstrap");
179 loadprotoblocks(char *fname
, size_t *size
)
182 u_long marks
[MARK_MAX
], bp
, offs
;
186 /* Locate block number array in proto file */
187 if (nlist(fname
, nl
) != 0) {
188 warnx("nlist: %s: symbols not found", fname
);
192 marks
[MARK_START
] = 0;
193 if ((fd
= loadfile(fname
, marks
, COUNT_TEXT
|COUNT_DATA
)) == -1)
197 *size
= roundup(marks
[MARK_END
] - marks
[MARK_START
], DEV_BSIZE
);
198 bp
= (u_long
)malloc(*size
);
200 offs
= marks
[MARK_START
];
201 marks
[MARK_START
] = bp
- offs
;
203 if ((fd
= loadfile(fname
, marks
, LOAD_TEXT
|LOAD_DATA
)) == -1)
207 /* Calculate the symbols' locations within the proto file */
208 block_size_p
= (int *)(bp
+ (nl
[X_BLOCK_SIZE
].n_value
- offs
));
209 block_count_p
= (int *)(bp
+ (nl
[X_BLOCK_COUNT
].n_value
- offs
));
211 block_table
= (int32_t *)(bp
+ (nl
[X_BLOCK_TABLE
].n_value
- offs
));
212 maxblocknum
= *block_count_p
;
215 printf("%s: entry point %#lx\n", fname
, marks
[MARK_ENTRY
]);
216 printf("proto bootblock size %d\n", *size
);
217 printf("room for %d filesystem blocks at %#lx\n",
218 maxblocknum
, nl
[X_BLOCK_TABLE
].n_value
);
229 devread(int fd
, void *buf
, daddr_t blk
, size_t size
, char *msg
)
232 if (lseek(fd
, dbtob(blk
), SEEK_SET
) != dbtob(blk
))
233 err(1, "%s: devread: lseek", msg
);
235 if (read(fd
, buf
, size
) != size
)
236 err(1, "%s: devread: read", msg
);
239 static char sblock
[SBLOCKSIZE
];
242 loadblocknums(char *boot
, int devfd
)
246 struct statvfs statvfsbuf
;
250 struct ufs1_dinode
*ip
;
254 * Open 2nd-level boot program and record the block numbers
255 * it occupies on the filesystem represented by `devfd'.
258 /* Make sure the (probably new) boot file is on disk. */
261 if ((fd
= open(boot
, O_RDONLY
)) < 0)
262 err(1, "open: %s", boot
);
264 if (fstatvfs(fd
, &statvfsbuf
) != 0)
265 err(1, "statfs: %s", boot
);
267 if (strncmp(statvfsbuf
.f_fstypename
, "ffs",
268 sizeof(statvfsbuf
.f_fstypename
)) &&
269 strncmp(statvfsbuf
.f_fstypename
, "ufs",
270 sizeof(statvfsbuf
.f_fstypename
))) {
271 errx(1, "%s: must be on an FFS filesystem", boot
);
275 err(1, "fsync: %s", boot
);
277 if (fstat(fd
, &statbuf
) != 0)
278 err(1, "fstat: %s", boot
);
282 /* Read superblock */
283 devread(devfd
, sblock
, (daddr_t
)(BBSIZE
/ DEV_BSIZE
),
284 SBLOCKSIZE
, "superblock");
285 fs
= (struct fs
*)sblock
;
287 /* Sanity-check super-block. */
288 if (fs
->fs_magic
!= FS_UFS1_MAGIC
)
289 errx(1, "Bad magic number in superblock, must be UFS1");
290 if (fs
->fs_inopb
<= 0)
291 err(1, "Bad inopb=%d in superblock", fs
->fs_inopb
);
294 if ((buf
= malloc(fs
->fs_bsize
)) == NULL
)
295 errx(1, "No memory for filesystem block");
297 blk
= fsbtodb(fs
, ino_to_fsba(fs
, statbuf
.st_ino
));
298 devread(devfd
, buf
, blk
, fs
->fs_bsize
, "inode");
299 ip
= (struct ufs1_dinode
*)(buf
) + ino_to_fsbo(fs
, statbuf
.st_ino
);
302 * Have the inode. Figure out how many blocks we need.
304 ndb
= howmany(ip
->di_size
, fs
->fs_bsize
);
305 if (ndb
> maxblocknum
)
306 errx(1, "Too many blocks");
307 *block_count_p
= ndb
;
308 *block_size_p
= fs
->fs_bsize
;
310 printf("Will load %d blocks of size %d each.\n",
314 * Get the block numbers; we don't handle fragments
317 for (i
= 0; i
< NDADDR
&& *ap
&& ndb
; i
++, ap
++, ndb
--) {
318 blk
= fsbtodb(fs
, *ap
);
320 printf("%d: %d\n", i
, blk
);
321 block_table
[i
] = blk
;
327 * Just one level of indirections; there isn't much room
328 * for more in the 1st-level bootblocks anyway.
330 blk
= fsbtodb(fs
, ip
->di_ib
[0]);
331 devread(devfd
, buf
, blk
, fs
->fs_bsize
, "indirect block");
334 for (; i
< NINDIR(fs
) && *ap
&& ndb
; i
++, ap
++, ndb
--) {
335 blk
= fsbtodb(fs
, *ap
);
337 printf("%d: %d\n", i
, blk
);
338 block_table
[i
] = blk
;