• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/firmware-utils/src/mkcameofw.c

  1 // SPDX-License-Identifier: GPL-2.0-only
  2 /*
  3  * Copyright (C) 2012 Gabor Juhos <juhosg@openwrt.org>
  4  */
  5 
  6 #include <stdio.h>
  7 #include <stdlib.h>
  8 #include <stdint.h>
  9 #include <string.h>
 10 #include <unistd.h>     /* for unlink() */
 11 #include <libgen.h>
 12 #include <getopt.h>     /* for getopt() */
 13 #include <stdarg.h>
 14 #include <errno.h>
 15 #include <sys/stat.h>
 16 
 17 #include <arpa/inet.h>
 18 #include <netinet/in.h>
 19 
 20 #define MAX_MODEL_LEN           20
 21 #define MAX_SIGNATURE_LEN       30
 22 #define MAX_REGION_LEN          4
 23 #define MAX_VERSION_LEN         12
 24 
 25 #define FIELD_SIZEOF(t, f) (sizeof(((t*)0)->f))
 26 
 27 struct file_info {
 28         char            *file_name;     /* name of the file */
 29         uint32_t        file_size;      /* length of the file */
 30         uint32_t        write_size;
 31 };
 32 
 33 struct img_header {
 34         uint32_t        checksum;
 35         uint32_t        image_size;
 36         uint32_t        kernel_size;
 37         char            model[MAX_MODEL_LEN];
 38         char            signature[MAX_SIGNATURE_LEN];
 39         char            region[MAX_REGION_LEN];
 40         char            version[MAX_VERSION_LEN];
 41         unsigned char   header_len;
 42         unsigned char   is_tgz;
 43         unsigned char   pad[4];
 44 } __attribute__ ((packed));
 45 
 46 /*
 47  * Globals
 48  */
 49 static char *ofname;
 50 static char *progname;
 51 
 52 static char *model;
 53 static char *signature;
 54 static char *region = "DEF";
 55 static char *version;
 56 static struct file_info kernel_info;
 57 static struct file_info rootfs_info;
 58 static uint32_t kernel_size;
 59 static uint32_t image_size;
 60 static int combined;
 61 
 62 /*
 63  * Message macros
 64  */
 65 #define ERR(fmt, ...) do { \
 66         fflush(0); \
 67         fprintf(stderr, "[%s] *** error: " fmt "\n", \
 68                         progname, ## __VA_ARGS__ ); \
 69 } while (0)
 70 
 71 #define ERRS(fmt, ...) do { \
 72         int save = errno; \
 73         fflush(0); \
 74         fprintf(stderr, "[%s] *** error: " fmt " (%s)\n", \
 75                         progname, ## __VA_ARGS__, strerror(save)); \
 76 } while (0)
 77 
 78 #define DBG(fmt, ...) do { \
 79         fprintf(stderr, "[%s] " fmt "\n", progname, ## __VA_ARGS__ ); \
 80 } while (0)
 81 
 82 static void usage(int status)
 83 {
 84         FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
 85 
 86         fprintf(stream, "Usage: %s [OPTIONS...]\n", progname);
 87         fprintf(stream,
 88 "\n"
 89 "Options:\n"
 90 "  -k <file>       read kernel image from the file <file>\n"
 91 "  -c              use the kernel image as a combined image\n"
 92 "  -M <model>      set model to <model>\n"
 93 "  -o <file>       write output to the file <file>\n"
 94 "  -r <file>       read rootfs image from the file <file>\n"
 95 "  -S <signature>  set image signature to <signature>\n"
 96 "  -R <region>     set image region to <region>\n"
 97 "  -V <version>    set image version to <version>\n"
 98 "  -I <size>       set image size to <size>\n"
 99 "  -K <size>       set kernel size to <size>\n"
100 "  -h              show this screen\n"
101         );
102 
103         exit(status);
104 }
105 
106 int
107 str2u32(char *arg, uint32_t *val)
108 {
109         char *err = NULL;
110         uint32_t t;
111 
112         errno=0;
113         t = strtoul(arg, &err, 0);
114         if (errno || (err==arg) || ((err != NULL) && *err)) {
115                 return -1;
116         }
117 
118         *val = t;
119         return 0;
120 }
121 
122 static int get_file_stat(struct file_info *fdata)
123 {
124         struct stat st;
125         int res;
126 
127         if (fdata->file_name == NULL)
128                 return 0;
129 
130         res = stat(fdata->file_name, &st);
131         if (res){
132                 ERRS("stat failed on %s", fdata->file_name);
133                 return res;
134         }
135 
136         fdata->file_size = st.st_size;
137         fdata->write_size = fdata->file_size;
138         return 0;
139 }
140 
141 static int read_to_buf(struct file_info *fdata, char *buf)
142 {
143         FILE *f;
144         int ret = EXIT_FAILURE;
145 
146         f = fopen(fdata->file_name, "r");
147         if (f == NULL) {
148                 ERRS("could not open \"%s\" for reading", fdata->file_name);
149                 goto out;
150         }
151 
152         errno = 0;
153         fread(buf, fdata->file_size, 1, f);
154         if (errno != 0) {
155                 ERRS("unable to read from file \"%s\"", fdata->file_name);
156                 goto out_close;
157         }
158 
159         ret = EXIT_SUCCESS;
160 
161 out_close:
162         fclose(f);
163 out:
164         return ret;
165 }
166 
167 static int check_options(void)
168 {
169         int ret;
170 
171 #define CHKSTR(_name, _msg)                             \
172         do {                                            \
173                 if (_name == NULL) {                    \
174                         ERR("no %s specified", _msg);   \
175                         return -1;                      \
176                 }                                       \
177         } while (0)
178 
179 #define CHKSTRLEN(_name, _msg)                                  \
180         do {                                                    \
181                 int field_len;                                  \
182                 CHKSTR(_name, _msg);                            \
183                 field_len = FIELD_SIZEOF(struct img_header, _name) - 1; \
184                 if (strlen(_name) > field_len) {                \
185                         ERR("%s is too long, max length is %d", \
186                             _msg, field_len);                   \
187                         return -1;                              \
188                 }                                               \
189         } while (0)
190 
191         CHKSTRLEN(model, "model");
192         CHKSTRLEN(signature, "signature");
193         CHKSTRLEN(region, "region");
194         CHKSTRLEN(version, "version");
195         CHKSTR(ofname, "output file");
196         CHKSTR(kernel_info.file_name, "kernel image");
197 
198         ret = get_file_stat(&kernel_info);
199         if (ret)
200                 return ret;
201 
202         if (combined) {
203                 if (!kernel_size) {
204                         ERR("kernel size must be specified for combined images");
205                         return -1;                              \
206                 }
207 
208                 if (!image_size)
209                         image_size = kernel_info.file_size;
210 
211                 if (kernel_info.file_size > image_size) {
212                         ERR("kernel image is too big");
213                         return -1;
214                 }
215 
216                 kernel_info.write_size = image_size;
217         } else {
218                 CHKSTR(rootfs_info.file_name, "rootfs image");
219 
220                 ret = get_file_stat(&rootfs_info);
221                 if (ret)
222                         return ret;
223 
224                 if (kernel_size) {
225                         /* override kernel size */
226                         kernel_info.write_size = kernel_size;
227                 }
228 
229                 if (image_size) {
230                         if (image_size < kernel_info.write_size)
231                                 kernel_info.write_size = image_size;
232 
233                         /* override rootfs size */
234                         rootfs_info.write_size = image_size - kernel_info.write_size;
235                 }
236 
237                 if (kernel_info.file_size > kernel_info.write_size) {
238                         ERR("kernel image is too big");
239                         return -1;
240                 }
241 
242                 if (rootfs_info.file_size > rootfs_info.write_size) {
243                         ERR("rootfs image is too big");
244                         return -1;
245                 }
246         }
247 
248         return 0;
249 }
250 
251 static int write_fw(char *data, int len)
252 {
253         FILE *f;
254         int ret = EXIT_FAILURE;
255 
256         f = fopen(ofname, "w");
257         if (f == NULL) {
258                 ERRS("could not open \"%s\" for writing", ofname);
259                 goto out;
260         }
261 
262         errno = 0;
263         fwrite(data, len, 1, f);
264         if (errno) {
265                 ERRS("unable to write output file");
266                 goto out_flush;
267         }
268 
269         DBG("firmware file \"%s\" completed", ofname);
270 
271         ret = EXIT_SUCCESS;
272 
273 out_flush:
274         fflush(f);
275         fclose(f);
276         if (ret != EXIT_SUCCESS) {
277                 unlink(ofname);
278         }
279 out:
280         return ret;
281 }
282 
283 static uint32_t get_csum(unsigned char *p, uint32_t len)
284 {
285         uint32_t csum = 0;
286 
287         while (len--)
288                 csum += *p++;
289 
290         return csum;
291 }
292 
293 static int build_fw(void)
294 {
295         int buflen;
296         char *buf;
297         char *p;
298         uint32_t csum;
299         struct img_header *hdr;
300         int ret = EXIT_FAILURE;
301 
302         buflen = sizeof(struct img_header) +
303                  kernel_info.write_size + rootfs_info.write_size;
304 
305         buf = malloc(buflen);
306         if (!buf) {
307                 ERR("no memory for buffer\n");
308                 goto out;
309         }
310 
311         memset(buf, 0, buflen);
312 
313         p = buf + sizeof(struct img_header);
314 
315         /* read kernel data */
316         ret = read_to_buf(&kernel_info, p);
317         if (ret)
318                 goto out_free_buf;
319 
320         if (!combined) {
321                 p += kernel_info.write_size;
322 
323                 /* read rootfs data */
324                 ret = read_to_buf(&rootfs_info, p);
325                 if (ret)
326                         goto out_free_buf;
327         }
328 
329         csum = get_csum((unsigned char *)(buf + sizeof(struct img_header)),
330                         buflen - sizeof(struct img_header));
331 
332         /* fill firmware header */
333         hdr = (struct img_header *) buf;
334 
335         hdr->checksum = htonl(csum);
336         hdr->image_size = htonl(buflen - sizeof(struct img_header));
337         if (!combined)
338                 hdr->kernel_size = htonl(kernel_info.write_size);
339         else
340                 hdr->kernel_size = htonl(kernel_size);
341         hdr->header_len = sizeof(struct img_header);
342         strncpy(hdr->model, model, sizeof(hdr->model));
343         strncpy(hdr->signature, signature, sizeof(hdr->signature));
344         strncpy(hdr->version, version, sizeof(hdr->version));
345         strncpy(hdr->region, region, sizeof(hdr->region));
346 
347         ret = write_fw(buf, buflen);
348         if (ret)
349                 goto out_free_buf;
350 
351         ret = EXIT_SUCCESS;
352 
353 out_free_buf:
354         free(buf);
355 out:
356         return ret;
357 }
358 
359 int main(int argc, char *argv[])
360 {
361         int ret = EXIT_FAILURE;
362 
363         progname = basename(argv[0]);
364 
365         while (1) {
366                 int c;
367 
368                 c = getopt(argc, argv, "M:S:V:R:k:K:I:r:o:hc");
369                 if (c == -1)
370                         break;
371 
372                 switch (c) {
373                 case 'M':
374                         model = optarg;
375                         break;
376                 case 'S':
377                         signature = optarg;
378                         break;
379                 case 'V':
380                         version = optarg;
381                         break;
382                 case 'R':
383                         region = optarg;
384                         break;
385                 case 'k':
386                         kernel_info.file_name = optarg;
387                         break;
388                 case 'K':
389                         if (str2u32(optarg, &kernel_size)) {
390                                 ERR("%s is invalid '%s'",
391                                     "kernel size", optarg);
392                                 goto out;
393                         }
394                         break;
395                 case 'I':
396                         if (str2u32(optarg, &image_size)) {
397                                 ERR("%s is invalid '%s'",
398                                     "image size", optarg);
399                                 goto out;
400                         }
401                         break;
402                 case 'r':
403                         rootfs_info.file_name = optarg;
404                         break;
405                 case 'c':
406                         combined = 1;
407                         break;
408                 case 'o':
409                         ofname = optarg;
410                         break;
411                 case 'h':
412                         usage(EXIT_SUCCESS);
413                         break;
414                 default:
415                         usage(EXIT_FAILURE);
416                         break;
417                 }
418         }
419 
420         ret = check_options();
421         if (ret)
422                 goto out;
423 
424         ret = build_fw();
425 
426 out:
427         return ret;
428 }
429 
430 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt