xref: /netbsd-src/usr.sbin/mdsetimage/mdsetimage.c (revision 82d56013d7b633d116a93943de88e08335357a7c)
1 /*	$NetBSD: mdsetimage.c,v 1.25 2020/06/14 18:24:21 tsutsui Exp $	*/
2 
3 /*
4  * Copyright (c) 1996, 2002 Christopher G. Demetriou
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. The name of the author may not be used to endorse or promote products
16  *    derived from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  *
29  * <<Id: LICENSE_GC,v 1.1 2001/10/01 23:24:05 cgd Exp>>
30  */
31 
32 #if HAVE_NBTOOL_CONFIG_H
33 #include "nbtool_config.h"
34 #endif
35 
36 #include <sys/cdefs.h>
37 #if !defined(lint)
38 __COPYRIGHT("@(#) Copyright (c) 1996\
39  Christopher G. Demetriou.  All rights reserved.");
40 __RCSID("$NetBSD: mdsetimage.c,v 1.25 2020/06/14 18:24:21 tsutsui Exp $");
41 #endif /* not lint */
42 
43 #include <sys/types.h>
44 #include <sys/mman.h>
45 #include <sys/stat.h>
46 
47 #include <err.h>
48 #include <fcntl.h>
49 #include <limits.h>
50 #include <stdint.h>
51 #include <stdio.h>
52 #include <stdlib.h>
53 #include <unistd.h>
54 #include <string.h>
55 
56 #include "bin.h"
57 
58 #define	CHUNKSIZE	(64 * 1024)
59 
60 static void	usage(void) __attribute__((noreturn));
61 
62 int	verbose;
63 int	extract;
64 int	setsize;
65 
66 static const char *progname;
67 #undef setprogname
68 #define	setprogname(x)	(void)(progname = (x))
69 #undef getprogname
70 #define	getprogname()	(progname)
71 
72 int
73 main(int argc, char *argv[])
74 {
75 	int ch, kfd, fsfd, rv;
76 	struct stat ksb, fssb;
77 	size_t md_root_image_offset, md_root_size_offset;
78 	u_int32_t md_root_size_value;
79 	const char *kfile, *fsfile;
80 	char *mappedkfile;
81 	char *bfdname = NULL;
82 	void *bin;
83 	ssize_t left_to_copy;
84 	const char *md_root_image = "_md_root_image";
85 	const char *md_root_size = "_md_root_size";
86 	unsigned long text_start = ~0;
87 
88 	setprogname(argv[0]);
89 
90 	while ((ch = getopt(argc, argv, "I:S:b:svx")) != -1)
91 		switch (ch) {
92 		case 'I':
93 			md_root_image = optarg;
94 			break;
95 		case 'S':
96 			md_root_size = optarg;
97 			break;
98 		case 'T':
99 			text_start = strtoul(optarg, NULL, 0);
100 			break;
101 		case 'b':
102 			bfdname = optarg;
103 			break;
104 		case 's':
105 			setsize = 1;
106 			break;
107 		case 'v':
108 			verbose = 1;
109 			break;
110 		case 'x':
111 			extract = 1;
112 			break;
113 		case '?':
114 		default:
115 			usage();
116 	}
117 	argc -= optind;
118 	argv += optind;
119 
120 	if (argc != 2)
121 		usage();
122 	kfile = argv[0];
123 	fsfile = argv[1];
124 
125 	if (extract) {
126 		if ((kfd = open(kfile, O_RDONLY, 0))  == -1)
127 			err(1, "open %s", kfile);
128 	} else {
129 		if ((kfd = open(kfile, O_RDWR, 0))  == -1)
130 			err(1, "open %s", kfile);
131 	}
132 
133 	if (fstat(kfd, &ksb) == -1)
134 		err(1, "fstat %s", kfile);
135 	if ((uintmax_t)ksb.st_size != (size_t)ksb.st_size)
136 		errx(1, "%s too big to map", kfile);
137 
138 	if ((mappedkfile = mmap(NULL, ksb.st_size, PROT_READ,
139 	    MAP_FILE | MAP_PRIVATE, kfd, 0)) == (caddr_t)-1)
140 		err(1, "mmap %s", kfile);
141 	if (verbose)
142 		fprintf(stderr, "mapped %s\n", kfile);
143 
144 	bin = bin_open(kfd, kfile, bfdname);
145 
146 	if (bin_find_md_root(bin, mappedkfile, ksb.st_size, text_start,
147 	    md_root_image, md_root_size, &md_root_image_offset,
148 	    &md_root_size_offset, &md_root_size_value, verbose) != 0)
149 		errx(1, "could not find symbols in %s", kfile);
150 	if (verbose)
151 		fprintf(stderr, "got symbols from %s\n", kfile);
152 
153 	if (verbose)
154 		fprintf(stderr, "root @ %#zx/%u\n",
155 		    md_root_image_offset, md_root_size_value);
156 
157 	munmap(mappedkfile, ksb.st_size);
158 
159 	if (extract) {
160 		if ((fsfd = open(fsfile, O_WRONLY|O_CREAT, 0777)) == -1)
161 			err(1, "open %s", fsfile);
162 		left_to_copy = md_root_size_value;
163 	} else {
164 		if ((fsfd = open(fsfile, O_RDONLY, 0)) == -1)
165 			err(1, "open %s", fsfile);
166 		if (fstat(fsfd, &fssb) == -1)
167 			err(1, "fstat %s", fsfile);
168 		if ((uintmax_t)fssb.st_size != (size_t)fssb.st_size)
169 			errx(1, "fs image %s is too big", fsfile);
170 		if (fssb.st_size > md_root_size_value)
171 			errx(1, "fs image %s (%jd bytes) too big for buffer"
172 			    " (%u bytes)", fsfile, (intmax_t) fssb.st_size,
173 			    md_root_size_value);
174 		left_to_copy = fssb.st_size;
175 	}
176 
177 	if (verbose)
178 		fprintf(stderr, "copying image %s %s %s (%zd bytes)\n", fsfile,
179 		    (extract ? "from" : "into"), kfile, left_to_copy);
180 
181 	if (lseek(kfd, md_root_image_offset, SEEK_SET) !=
182 	    (off_t)md_root_image_offset)
183 		err(1, "seek %s", kfile);
184 	while (left_to_copy > 0) {
185 		char buf[CHUNKSIZE];
186 		ssize_t todo;
187 		int rfd;
188 		int wfd;
189 		const char *rfile;
190 		const char *wfile;
191 		if (extract) {
192 			rfd = kfd;
193 			rfile = kfile;
194 			wfd = fsfd;
195 			wfile = fsfile;
196 		} else {
197 			rfd = fsfd;
198 			rfile = fsfile;
199 			wfd = kfd;
200 			wfile = kfile;
201 		}
202 
203 		todo = (left_to_copy > CHUNKSIZE) ? CHUNKSIZE : left_to_copy;
204 		if ((rv = read(rfd, buf, todo)) != todo) {
205 			if (rv == -1)
206 				err(1, "read %s", rfile);
207 			else
208 				errx(1, "unexpected EOF reading %s", rfile);
209 		}
210 		if ((rv = write(wfd, buf, todo)) != todo) {
211 			if (rv == -1)
212 				err(1, "write %s", wfile);
213 			else
214 				errx(1, "short write writing %s", wfile);
215 		}
216 		left_to_copy -= todo;
217 	}
218 	if (verbose)
219 		fprintf(stderr, "done copying image\n");
220 	if (setsize && !extract) {
221 		char buf[sizeof(uint32_t)];
222 
223 		if (verbose)
224 			fprintf(stderr, "setting md_root_size to %jd\n",
225 			    (intmax_t) fssb.st_size);
226 		if (lseek(kfd, md_root_size_offset, SEEK_SET) !=
227 		    (off_t)md_root_size_offset)
228 			err(1, "seek %s", kfile);
229 		bin_put_32(bin, fssb.st_size, buf);
230 		if (write(kfd, buf, sizeof(buf)) != sizeof(buf))
231 			err(1, "write %s", kfile);
232 	}
233 
234 	close(fsfd);
235 	close(kfd);
236 
237 	if (verbose)
238 		fprintf(stderr, "exiting\n");
239 
240 	bin_close(bin);
241 	return 0;
242 }
243 
244 static void
245 usage(void)
246 {
247 	const char **list;
248 
249 	fprintf(stderr, "Usage: %s [-svx] [-b bfdname] [-I image_symbol] "
250 	    "[-S size_symbol] [-T address] kernel image\n", getprogname());
251 	fprintf(stderr, "Supported targets:");
252 	for (list = bin_supported_targets(); *list != NULL; list++)
253 		fprintf(stderr, " %s", *list);
254 	fprintf(stderr, "\n");
255 	exit(1);
256 }
257