1/* $NetBSD: mdsetimage.c,v 1.2 2010/11/06 16:03:23 uebayasi Exp $ */
2/* from: NetBSD: mdsetimage.c,v 1.15 2001/03/21 23:46:48 cgd Exp $ */
3
4/*
5 * Copyright (c) 1996, 2002 Christopher G. Demetriou
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. The name of the author may not be used to endorse or promote products
17 *    derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 *
30 * <<Id: LICENSE_GC,v 1.1 2001/10/01 23:24:05 cgd Exp>>
31 */
32
33#if HAVE_NBTOOL_CONFIG_H
34#include "nbtool_config.h"
35#endif
36
37#include <sys/cdefs.h>
38#if !defined(lint)
39__COPYRIGHT("@(#) Copyright (c) 1996\
40 Christopher G. Demetriou.  All rights reserved.");
41__RCSID("$NetBSD: mdsetimage.c,v 1.2 2010/11/06 16:03:23 uebayasi Exp $");
42#endif /* not lint */
43
44#include <sys/types.h>
45#include <sys/mman.h>
46#include <sys/stat.h>
47
48#include <err.h>
49#include <fcntl.h>
50#include <limits.h>
51#include <stdio.h>
52#include <stdlib.h>
53#include <unistd.h>
54#include <string.h>
55
56#include <bfd.h>
57
58struct symbols {
59	char *name;
60	size_t offset;
61};
62#define	X_MD_ROOT_IMAGE	0
63#define	X_MD_ROOT_SIZE	1
64
65#define	CHUNKSIZE	(64 * 1024)
66
67int		main(int, char *[]);
68static void	usage(void) __attribute__((noreturn));
69static int	find_md_root(bfd *, struct symbols symbols[]);
70
71int	verbose;
72int	extract;
73int	setsize;
74
75static const char *progname;
76#undef setprogname
77#define	setprogname(x)	(void)(progname = (x))
78#undef getprogname
79#define	getprogname()	(progname)
80
81int
82main(int argc, char *argv[])
83{
84	int ch, kfd, fsfd, rv;
85	struct stat ksb, fssb;
86	size_t md_root_offset, md_root_size_offset;
87	u_int32_t md_root_size;
88	const char *kfile, *fsfile;
89	char *mappedkfile;
90	char *bfdname = NULL;
91	bfd *abfd;
92	ssize_t left_to_copy;
93	struct symbols md_root_symbols[3] = { { 0 } };
94
95	md_root_symbols[X_MD_ROOT_IMAGE].name = "_md_root_image";
96	md_root_symbols[X_MD_ROOT_SIZE].name = "_md_root_size";
97
98	setprogname(argv[0]);
99
100	while ((ch = getopt(argc, argv, "I:S:b:svx")) != -1)
101		switch (ch) {
102		case 'I':
103			md_root_symbols[X_MD_ROOT_IMAGE].name = optarg;
104			break;
105		case 'S':
106			md_root_symbols[X_MD_ROOT_SIZE].name = optarg;
107			break;
108		case 'b':
109			bfdname = optarg;
110			break;
111		case 's':
112			setsize = 1;
113			break;
114		case 'v':
115			verbose = 1;
116			break;
117		case 'x':
118			extract = 1;
119			break;
120		case '?':
121		default:
122			usage();
123	}
124	argc -= optind;
125	argv += optind;
126
127	if (argc != 2)
128		usage();
129	kfile = argv[0];
130	fsfile = argv[1];
131
132	if (extract) {
133		if ((kfd = open(kfile, O_RDONLY, 0))  == -1)
134			err(1, "open %s", kfile);
135	} else {
136		if ((kfd = open(kfile, O_RDWR, 0))  == -1)
137			err(1, "open %s", kfile);
138	}
139
140	bfd_init();
141	if ((abfd = bfd_fdopenr(kfile, bfdname, kfd)) == NULL) {
142		bfd_perror("open");
143		exit(1);
144	}
145	if (!bfd_check_format(abfd, bfd_object)) {
146		bfd_perror("check format");
147		exit(1);
148	}
149
150	if (find_md_root(abfd, md_root_symbols) != 0)
151		errx(1, "could not find symbols in %s", kfile);
152	if (verbose)
153		fprintf(stderr, "got symbols from %s\n", kfile);
154
155	if (fstat(kfd, &ksb) == -1)
156		err(1, "fstat %s", kfile);
157	if (ksb.st_size != (size_t)ksb.st_size)
158		errx(1, "%s too big to map", kfile);
159
160	if ((mappedkfile = mmap(NULL, ksb.st_size, PROT_READ,
161	    MAP_FILE | MAP_PRIVATE, kfd, 0)) == (caddr_t)-1)
162		err(1, "mmap %s", kfile);
163	if (verbose)
164		fprintf(stderr, "mapped %s\n", kfile);
165
166	md_root_offset = md_root_symbols[X_MD_ROOT_IMAGE].offset;
167	md_root_size_offset = md_root_symbols[X_MD_ROOT_SIZE].offset;
168	md_root_size = bfd_get_32(abfd, &mappedkfile[md_root_size_offset]);
169
170	munmap(mappedkfile, ksb.st_size);
171
172	if (extract) {
173		if ((fsfd = open(fsfile, O_WRONLY|O_CREAT, 0777)) == -1)
174			err(1, "open %s", fsfile);
175		left_to_copy = md_root_size;
176	} else {
177		if ((fsfd = open(fsfile, O_RDONLY, 0)) == -1)
178			err(1, "open %s", fsfile);
179		if (fstat(fsfd, &fssb) == -1)
180			err(1, "fstat %s", fsfile);
181		if (fssb.st_size != (size_t)fssb.st_size)
182			errx(1, "fs image is too big");
183		if (fssb.st_size > md_root_size)
184			errx(1, "fs image (%lld bytes) too big for buffer (%lu bytes)",
185			    (long long)fssb.st_size, (unsigned long)md_root_size);
186		left_to_copy = fssb.st_size;
187	}
188
189	if (verbose)
190		fprintf(stderr, "copying image %s %s %s\n", fsfile,
191		    (extract ? "from" : "into"), kfile);
192
193	if (lseek(kfd, md_root_offset, SEEK_SET) != md_root_offset)
194		err(1, "seek %s", kfile);
195	while (left_to_copy > 0) {
196		char buf[CHUNKSIZE];
197		ssize_t todo;
198		int rfd;
199		int wfd;
200		const char *rfile;
201		const char *wfile;
202		if (extract) {
203			rfd = kfd;
204			rfile = kfile;
205			wfd = fsfd;
206			wfile = fsfile;
207		} else {
208			rfd = fsfd;
209			rfile = fsfile;
210			wfd = kfd;
211			wfile = kfile;
212		}
213
214		todo = (left_to_copy > CHUNKSIZE) ? CHUNKSIZE : left_to_copy;
215		if ((rv = read(rfd, buf, todo)) != todo) {
216			if (rv == -1)
217				err(1, "read %s", rfile);
218			else
219				errx(1, "unexpected EOF reading %s", rfile);
220		}
221		if ((rv = write(wfd, buf, todo)) != todo) {
222			if (rv == -1)
223				err(1, "write %s", wfile);
224			else
225				errx(1, "short write writing %s", wfile);
226		}
227		left_to_copy -= todo;
228	}
229	if (verbose)
230		fprintf(stderr, "done copying image\n");
231	if (setsize && !extract) {
232		char buf[sizeof(uint32_t)];
233
234		if (verbose)
235			fprintf(stderr, "setting md_root_size to %llu\n",
236			    (unsigned long long) fssb.st_size);
237		if (lseek(kfd, md_root_size_offset, SEEK_SET) !=
238		    md_root_size_offset)
239			err(1, "seek %s", kfile);
240		bfd_put_32(abfd, fssb.st_size, buf);
241		if (write(kfd, buf, sizeof(buf)) != sizeof(buf))
242			err(1, "write %s", kfile);
243	}
244
245	close(fsfd);
246	close(kfd);
247
248	if (verbose)
249		fprintf(stderr, "exiting\n");
250
251	bfd_close_all_done(abfd);
252	exit(0);
253}
254
255static void
256usage(void)
257{
258	const char **list;
259
260	fprintf(stderr,
261	    "usage: %s [-svx] [-b bfdname] kernel image\n",
262	    getprogname());
263	fprintf(stderr, "supported targets:");
264	for (list = bfd_target_list(); *list != NULL; list++)
265		fprintf(stderr, " %s", *list);
266	fprintf(stderr, "\n");
267	exit(1);
268}
269
270static int
271find_md_root(bfd *abfd, struct symbols symbols[])
272{
273	long i;
274	long storage_needed;
275	long number_of_symbols;
276	asymbol **symbol_table = NULL;
277	struct symbols *s;
278
279	storage_needed = bfd_get_symtab_upper_bound(abfd);
280	if (storage_needed <= 0)
281		return (1);
282
283	symbol_table = (asymbol **)malloc(storage_needed);
284	if (symbol_table == NULL)
285		return (1);
286
287	number_of_symbols = bfd_canonicalize_symtab(abfd, symbol_table);
288	if (number_of_symbols <= 0) {
289		free(symbol_table);
290		return (1);
291	}
292
293	for (i = 0; i < number_of_symbols; i++) {
294		for (s = symbols; s->name != NULL; s++) {
295			const char *sym = symbol_table[i]->name;
296
297			/*
298			 * match symbol prefix '_' or ''.
299			 */
300			if (!strcmp(s->name, sym) ||
301			    !strcmp(s->name + 1, sym)) {
302				s->offset =
303				    (size_t)(symbol_table[i]->section->filepos
304				    + symbol_table[i]->value);
305			}
306		}
307	}
308
309	free(symbol_table);
310
311	for (s = symbols; s->name != NULL; s++) {
312		if (s->offset == 0)
313			return (1);
314	}
315
316	return (0);
317}
318