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
main(int argc,char * argv[])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
usage(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