mkimage: fix argument parsing on BSD systems
[oweals/u-boot.git] / tools / mkimage.c
1 /*
2  * (C) Copyright 2008 Semihalf
3  *
4  * (C) Copyright 2000-2009
5  * DENX Software Engineering
6  * Wolfgang Denk, wd@denx.de
7  *
8  * SPDX-License-Identifier:     GPL-2.0+
9  */
10
11 #include "mkimage.h"
12 #include <image.h>
13 #include <version.h>
14
15 static void copy_file(int, const char *, int);
16
17 /* parameters initialized by core will be used by the image type code */
18 static struct image_tool_params params = {
19         .os = IH_OS_LINUX,
20         .arch = IH_ARCH_PPC,
21         .type = IH_TYPE_KERNEL,
22         .comp = IH_COMP_GZIP,
23         .dtc = MKIMAGE_DEFAULT_DTC_OPTIONS,
24         .imagename = "",
25         .imagename2 = "",
26 };
27
28 static int h_compare_image_name(const void *vtype1, const void *vtype2)
29 {
30         const int *type1 = vtype1;
31         const int *type2 = vtype2;
32         const char *name1 = genimg_get_type_short_name(*type1);
33         const char *name2 = genimg_get_type_short_name(*type2);
34
35         return strcmp(name1, name2);
36 }
37
38 /* Show all image types supported by mkimage */
39 static void show_image_types(void)
40 {
41         struct image_type_params *tparams;
42         int order[IH_TYPE_COUNT];
43         int count;
44         int type;
45         int i;
46
47         /* Sort the names in order of short name for easier reading */
48         memset(order, '\0', sizeof(order));
49         for (count = 0, type = 0; type < IH_TYPE_COUNT; type++) {
50                 tparams = imagetool_get_type(type);
51                 if (tparams)
52                         order[count++] = type;
53         }
54         qsort(order, count, sizeof(int), h_compare_image_name);
55
56         fprintf(stderr, "\nInvalid image type. Supported image types:\n");
57         for (i = 0; i < count; i++) {
58                 type = order[i];
59                 tparams = imagetool_get_type(type);
60                 if (tparams) {
61                         fprintf(stderr, "\t%-15s  %s\n",
62                                 genimg_get_type_short_name(type),
63                                 genimg_get_type_name(type));
64                 }
65         }
66         fprintf(stderr, "\n");
67 }
68
69 static void usage(const char *msg)
70 {
71         fprintf(stderr, "Error: %s\n", msg);
72         fprintf(stderr, "Usage: %s -l image\n"
73                          "          -l ==> list image header information\n",
74                 params.cmdname);
75         fprintf(stderr,
76                 "       %s [-x] -A arch -O os -T type -C comp -a addr -e ep -n name -d data_file[:data_file...] image\n"
77                 "          -A ==> set architecture to 'arch'\n"
78                 "          -O ==> set operating system to 'os'\n"
79                 "          -T ==> set image type to 'type'\n"
80                 "          -C ==> set compression type 'comp'\n"
81                 "          -a ==> set load address to 'addr' (hex)\n"
82                 "          -e ==> set entry point to 'ep' (hex)\n"
83                 "          -n ==> set image name to 'name'\n"
84                 "          -d ==> use image data from 'datafile'\n"
85                 "          -x ==> set XIP (execute in place)\n",
86                 params.cmdname);
87         fprintf(stderr,
88                 "       %s [-D dtc_options] [-f fit-image.its|-f auto|-F] [-b <dtb> [-b <dtb>]] fit-image\n"
89                 "           <dtb> file is used with -f auto, it may occour multiple times.\n",
90                 params.cmdname);
91         fprintf(stderr,
92                 "          -D => set all options for device tree compiler\n"
93                 "          -f => input filename for FIT source\n");
94 #ifdef CONFIG_FIT_SIGNATURE
95         fprintf(stderr,
96                 "Signing / verified boot options: [-k keydir] [-K dtb] [ -c <comment>] [-r]\n"
97                 "          -k => set directory containing private keys\n"
98                 "          -K => write public keys to this .dtb file\n"
99                 "          -c => add comment in signature node\n"
100                 "          -F => re-sign existing FIT image\n"
101                 "          -r => mark keys used as 'required' in dtb\n");
102 #else
103         fprintf(stderr,
104                 "Signing / verified boot not supported (CONFIG_FIT_SIGNATURE undefined)\n");
105 #endif
106         fprintf(stderr, "       %s -V ==> print version information and exit\n",
107                 params.cmdname);
108         fprintf(stderr, "Use -T to see a list of available image types\n");
109
110         exit(EXIT_FAILURE);
111 }
112
113 static int add_content(int type, const char *fname)
114 {
115         struct content_info *cont;
116
117         cont = calloc(1, sizeof(*cont));
118         if (!cont)
119                 return -1;
120         cont->type = type;
121         cont->fname = fname;
122         if (params.content_tail)
123                 params.content_tail->next = cont;
124         else
125                 params.content_head = cont;
126         params.content_tail = cont;
127
128         return 0;
129 }
130
131 static void process_args(int argc, char **argv)
132 {
133         char *ptr;
134         int type = IH_TYPE_INVALID;
135         char *datafile = NULL;
136         int expecting;
137         int opt;
138
139         expecting = IH_TYPE_COUNT;      /* Unknown */
140         while ((opt = getopt(argc, argv,
141                              "a:A:b:cC:d:D:e:Ef:Fk:K:ln:O:rR:sT:vVx")) != -1) {
142                 switch (opt) {
143                 case 'a':
144                         params.addr = strtoull(optarg, &ptr, 16);
145                         if (*ptr) {
146                                 fprintf(stderr, "%s: invalid load address %s\n",
147                                         params.cmdname, optarg);
148                                 exit(EXIT_FAILURE);
149                         }
150                         break;
151                 case 'A':
152                         params.arch = genimg_get_arch_id(optarg);
153                         if (params.arch < 0)
154                                 usage("Invalid architecture");
155                         break;
156                 case 'b':
157                         expecting = IH_TYPE_FLATDT;
158                         if (add_content(expecting, optarg)) {
159                                 fprintf(stderr,
160                                         "%s: Out of memory adding content '%s'",
161                                         params.cmdname, optarg);
162                                 exit(EXIT_FAILURE);
163                         }
164                         break;
165                 case 'c':
166                         params.comment = optarg;
167                         break;
168                 case 'C':
169                         params.comp = genimg_get_comp_id(optarg);
170                         if (params.comp < 0)
171                                 usage("Invalid compression type");
172                         break;
173                 case 'd':
174                         params.datafile = optarg;
175                         params.dflag = 1;
176                         break;
177                 case 'D':
178                         params.dtc = optarg;
179                         break;
180                 case 'e':
181                         params.ep = strtoull(optarg, &ptr, 16);
182                         if (*ptr) {
183                                 fprintf(stderr, "%s: invalid entry point %s\n",
184                                         params.cmdname, optarg);
185                                 exit(EXIT_FAILURE);
186                         }
187                         params.eflag = 1;
188                         break;
189                 case 'E':
190                         params.external_data = true;
191                         break;
192                 case 'f':
193                         datafile = optarg;
194                         params.auto_its = !strcmp(datafile, "auto");
195                         /* no break */
196                 case 'F':
197                         /*
198                          * The flattened image tree (FIT) format
199                          * requires a flattened device tree image type
200                          */
201                         params.fit_image_type = params.type;
202                         params.type = IH_TYPE_FLATDT;
203                         params.fflag = 1;
204                         break;
205                 case 'k':
206                         params.keydir = optarg;
207                         break;
208                 case 'K':
209                         params.keydest = optarg;
210                         break;
211                 case 'l':
212                         params.lflag = 1;
213                         break;
214                 case 'n':
215                         params.imagename = optarg;
216                         break;
217                 case 'O':
218                         params.os = genimg_get_os_id(optarg);
219                         if (params.os < 0)
220                                 usage("Invalid operating system");
221                         break;
222                 case 'r':
223                         params.require_keys = 1;
224                         break;
225                 case 'R':
226                         /*
227                          * This entry is for the second configuration
228                          * file, if only one is not enough.
229                          */
230                         params.imagename2 = optarg;
231                         break;
232                 case 's':
233                         params.skipcpy = 1;
234                         break;
235                 case 'T':
236                         type = genimg_get_type_id(optarg);
237                         if (type < 0) {
238                                 show_image_types();
239                                 usage("Invalid image type");
240                         }
241                         expecting = type;
242                         break;
243                 case 'v':
244                         params.vflag++;
245                         break;
246                 case 'V':
247                         printf("mkimage version %s\n", PLAIN_VERSION);
248                         exit(EXIT_SUCCESS);
249                 case 'x':
250                         params.xflag++;
251                         break;
252                 default:
253                         usage("Invalid option");
254                 }
255         }
256
257         if (optind < argc && expecting == type)
258                 params.imagefile = argv[optind];
259
260         /*
261          * For auto-generated FIT images we need to know the image type to put
262          * in the FIT, which is separate from the file's image type (which
263          * will always be IH_TYPE_FLATDT in this case).
264          */
265         if (params.type == IH_TYPE_FLATDT) {
266                 params.fit_image_type = type;
267                 if (!params.auto_its)
268                         params.datafile = datafile;
269         } else if (type != IH_TYPE_INVALID) {
270                 params.type = type;
271         }
272
273         if (!params.imagefile)
274                 usage("Missing output filename");
275 }
276
277
278 int main(int argc, char **argv)
279 {
280         int ifd = -1;
281         struct stat sbuf;
282         char *ptr;
283         int retval = 0;
284         struct image_type_params *tparams = NULL;
285         int pad_len = 0;
286         int dfd;
287
288         params.cmdname = *argv;
289         params.addr = 0;
290         params.ep = 0;
291
292         process_args(argc, argv);
293
294         /* set tparams as per input type_id */
295         tparams = imagetool_get_type(params.type);
296         if (tparams == NULL) {
297                 fprintf (stderr, "%s: unsupported type %s\n",
298                         params.cmdname, genimg_get_type_name(params.type));
299                 exit (EXIT_FAILURE);
300         }
301
302         /*
303          * check the passed arguments parameters meets the requirements
304          * as per image type to be generated/listed
305          */
306         if (tparams->check_params)
307                 if (tparams->check_params (&params))
308                         usage("Bad parameters for image type");
309
310         if (!params.eflag) {
311                 params.ep = params.addr;
312                 /* If XIP, entry point must be after the U-Boot header */
313                 if (params.xflag)
314                         params.ep += tparams->header_size;
315         }
316
317         if (params.fflag){
318                 if (tparams->fflag_handle)
319                         /*
320                          * in some cases, some additional processing needs
321                          * to be done if fflag is defined
322                          *
323                          * For ex. fit_handle_file for Fit file support
324                          */
325                         retval = tparams->fflag_handle(&params);
326
327                 if (retval != EXIT_SUCCESS)
328                         exit (retval);
329         }
330
331         if (params.lflag || params.fflag) {
332                 ifd = open (params.imagefile, O_RDONLY|O_BINARY);
333         } else {
334                 ifd = open (params.imagefile,
335                         O_RDWR|O_CREAT|O_TRUNC|O_BINARY, 0666);
336         }
337
338         if (ifd < 0) {
339                 fprintf (stderr, "%s: Can't open %s: %s\n",
340                         params.cmdname, params.imagefile,
341                         strerror(errno));
342                 exit (EXIT_FAILURE);
343         }
344
345         if (params.lflag || params.fflag) {
346                 /*
347                  * list header information of existing image
348                  */
349                 if (fstat(ifd, &sbuf) < 0) {
350                         fprintf (stderr, "%s: Can't stat %s: %s\n",
351                                 params.cmdname, params.imagefile,
352                                 strerror(errno));
353                         exit (EXIT_FAILURE);
354                 }
355
356                 if ((unsigned)sbuf.st_size < tparams->header_size) {
357                         fprintf (stderr,
358                                 "%s: Bad size: \"%s\" is not valid image\n",
359                                 params.cmdname, params.imagefile);
360                         exit (EXIT_FAILURE);
361                 }
362
363                 ptr = mmap(0, sbuf.st_size, PROT_READ, MAP_SHARED, ifd, 0);
364                 if (ptr == MAP_FAILED) {
365                         fprintf (stderr, "%s: Can't read %s: %s\n",
366                                 params.cmdname, params.imagefile,
367                                 strerror(errno));
368                         exit (EXIT_FAILURE);
369                 }
370
371                 /*
372                  * scan through mkimage registry for all supported image types
373                  * and verify the input image file header for match
374                  * Print the image information for matched image type
375                  * Returns the error code if not matched
376                  */
377                 retval = imagetool_verify_print_header(ptr, &sbuf,
378                                 tparams, &params);
379
380                 (void) munmap((void *)ptr, sbuf.st_size);
381                 (void) close (ifd);
382
383                 exit (retval);
384         }
385
386         if ((params.type != IH_TYPE_MULTI) && (params.type != IH_TYPE_SCRIPT)) {
387                 dfd = open(params.datafile, O_RDONLY | O_BINARY);
388                 if (dfd < 0) {
389                         fprintf(stderr, "%s: Can't open %s: %s\n",
390                                 params.cmdname, params.datafile,
391                                 strerror(errno));
392                         exit(EXIT_FAILURE);
393                 }
394
395                 if (fstat(dfd, &sbuf) < 0) {
396                         fprintf(stderr, "%s: Can't stat %s: %s\n",
397                                 params.cmdname, params.datafile,
398                                 strerror(errno));
399                         exit(EXIT_FAILURE);
400                 }
401
402                 params.file_size = sbuf.st_size + tparams->header_size;
403                 close(dfd);
404         }
405
406         /*
407          * In case there an header with a variable
408          * length will be added, the corresponding
409          * function is called. This is responsible to
410          * allocate memory for the header itself.
411          */
412         if (tparams->vrec_header)
413                 pad_len = tparams->vrec_header(&params, tparams);
414         else
415                 memset(tparams->hdr, 0, tparams->header_size);
416
417         if (write(ifd, tparams->hdr, tparams->header_size)
418                                         != tparams->header_size) {
419                 fprintf (stderr, "%s: Write error on %s: %s\n",
420                         params.cmdname, params.imagefile, strerror(errno));
421                 exit (EXIT_FAILURE);
422         }
423
424         if (!params.skipcpy) {
425                 if (params.type == IH_TYPE_MULTI ||
426                     params.type == IH_TYPE_SCRIPT) {
427                         char *file = params.datafile;
428                         uint32_t size;
429
430                         for (;;) {
431                                 char *sep = NULL;
432
433                                 if (file) {
434                                         if ((sep = strchr(file, ':')) != NULL) {
435                                                 *sep = '\0';
436                                         }
437
438                                         if (stat (file, &sbuf) < 0) {
439                                                 fprintf (stderr, "%s: Can't stat %s: %s\n",
440                                                          params.cmdname, file, strerror(errno));
441                                                 exit (EXIT_FAILURE);
442                                         }
443                                         size = cpu_to_uimage (sbuf.st_size);
444                                 } else {
445                                         size = 0;
446                                 }
447
448                                 if (write(ifd, (char *)&size, sizeof(size)) != sizeof(size)) {
449                                         fprintf (stderr, "%s: Write error on %s: %s\n",
450                                                  params.cmdname, params.imagefile,
451                                                  strerror(errno));
452                                         exit (EXIT_FAILURE);
453                                 }
454
455                                 if (!file) {
456                                         break;
457                                 }
458
459                                 if (sep) {
460                                         *sep = ':';
461                                         file = sep + 1;
462                                 } else {
463                                         file = NULL;
464                                 }
465                         }
466
467                         file = params.datafile;
468
469                         for (;;) {
470                                 char *sep = strchr(file, ':');
471                                 if (sep) {
472                                         *sep = '\0';
473                                         copy_file (ifd, file, 1);
474                                         *sep++ = ':';
475                                         file = sep;
476                                 } else {
477                                         copy_file (ifd, file, 0);
478                                         break;
479                                 }
480                         }
481                 } else if (params.type == IH_TYPE_PBLIMAGE) {
482                         /* PBL has special Image format, implements its' own */
483                         pbl_load_uboot(ifd, &params);
484                 } else {
485                         copy_file(ifd, params.datafile, pad_len);
486                 }
487         }
488
489         /* We're a bit of paranoid */
490 #if defined(_POSIX_SYNCHRONIZED_IO) && \
491    !defined(__sun__) && \
492    !defined(__FreeBSD__) && \
493    !defined(__OpenBSD__) && \
494    !defined(__APPLE__)
495         (void) fdatasync (ifd);
496 #else
497         (void) fsync (ifd);
498 #endif
499
500         if (fstat(ifd, &sbuf) < 0) {
501                 fprintf (stderr, "%s: Can't stat %s: %s\n",
502                         params.cmdname, params.imagefile, strerror(errno));
503                 exit (EXIT_FAILURE);
504         }
505         params.file_size = sbuf.st_size;
506
507         ptr = mmap(0, sbuf.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, ifd, 0);
508         if (ptr == MAP_FAILED) {
509                 fprintf (stderr, "%s: Can't map %s: %s\n",
510                         params.cmdname, params.imagefile, strerror(errno));
511                 exit (EXIT_FAILURE);
512         }
513
514         /* Setup the image header as per input image type*/
515         if (tparams->set_header)
516                 tparams->set_header (ptr, &sbuf, ifd, &params);
517         else {
518                 fprintf (stderr, "%s: Can't set header for %s: %s\n",
519                         params.cmdname, tparams->name, strerror(errno));
520                 exit (EXIT_FAILURE);
521         }
522
523         /* Print the image information by processing image header */
524         if (tparams->print_header)
525                 tparams->print_header (ptr);
526         else {
527                 fprintf (stderr, "%s: Can't print header for %s: %s\n",
528                         params.cmdname, tparams->name, strerror(errno));
529                 exit (EXIT_FAILURE);
530         }
531
532         (void) munmap((void *)ptr, sbuf.st_size);
533
534         /* We're a bit of paranoid */
535 #if defined(_POSIX_SYNCHRONIZED_IO) && \
536    !defined(__sun__) && \
537    !defined(__FreeBSD__) && \
538    !defined(__OpenBSD__) && \
539    !defined(__APPLE__)
540         (void) fdatasync (ifd);
541 #else
542         (void) fsync (ifd);
543 #endif
544
545         if (close(ifd)) {
546                 fprintf (stderr, "%s: Write error on %s: %s\n",
547                         params.cmdname, params.imagefile, strerror(errno));
548                 exit (EXIT_FAILURE);
549         }
550
551         exit (EXIT_SUCCESS);
552 }
553
554 static void
555 copy_file (int ifd, const char *datafile, int pad)
556 {
557         int dfd;
558         struct stat sbuf;
559         unsigned char *ptr;
560         int tail;
561         int zero = 0;
562         uint8_t zeros[4096];
563         int offset = 0;
564         int size;
565         struct image_type_params *tparams = imagetool_get_type(params.type);
566
567         memset(zeros, 0, sizeof(zeros));
568
569         if (params.vflag) {
570                 fprintf (stderr, "Adding Image %s\n", datafile);
571         }
572
573         if ((dfd = open(datafile, O_RDONLY|O_BINARY)) < 0) {
574                 fprintf (stderr, "%s: Can't open %s: %s\n",
575                         params.cmdname, datafile, strerror(errno));
576                 exit (EXIT_FAILURE);
577         }
578
579         if (fstat(dfd, &sbuf) < 0) {
580                 fprintf (stderr, "%s: Can't stat %s: %s\n",
581                         params.cmdname, datafile, strerror(errno));
582                 exit (EXIT_FAILURE);
583         }
584
585         ptr = mmap(0, sbuf.st_size, PROT_READ, MAP_SHARED, dfd, 0);
586         if (ptr == MAP_FAILED) {
587                 fprintf (stderr, "%s: Can't read %s: %s\n",
588                         params.cmdname, datafile, strerror(errno));
589                 exit (EXIT_FAILURE);
590         }
591
592         if (params.xflag) {
593                 unsigned char *p = NULL;
594                 /*
595                  * XIP: do not append the image_header_t at the
596                  * beginning of the file, but consume the space
597                  * reserved for it.
598                  */
599
600                 if ((unsigned)sbuf.st_size < tparams->header_size) {
601                         fprintf (stderr,
602                                 "%s: Bad size: \"%s\" is too small for XIP\n",
603                                 params.cmdname, datafile);
604                         exit (EXIT_FAILURE);
605                 }
606
607                 for (p = ptr; p < ptr + tparams->header_size; p++) {
608                         if ( *p != 0xff ) {
609                                 fprintf (stderr,
610                                         "%s: Bad file: \"%s\" has invalid buffer for XIP\n",
611                                         params.cmdname, datafile);
612                                 exit (EXIT_FAILURE);
613                         }
614                 }
615
616                 offset = tparams->header_size;
617         }
618
619         size = sbuf.st_size - offset;
620         if (write(ifd, ptr + offset, size) != size) {
621                 fprintf (stderr, "%s: Write error on %s: %s\n",
622                         params.cmdname, params.imagefile, strerror(errno));
623                 exit (EXIT_FAILURE);
624         }
625
626         tail = size % 4;
627         if ((pad == 1) && (tail != 0)) {
628
629                 if (write(ifd, (char *)&zero, 4-tail) != 4-tail) {
630                         fprintf (stderr, "%s: Write error on %s: %s\n",
631                                 params.cmdname, params.imagefile,
632                                 strerror(errno));
633                         exit (EXIT_FAILURE);
634                 }
635         } else if (pad > 1) {
636                 while (pad > 0) {
637                         int todo = sizeof(zeros);
638
639                         if (todo > pad)
640                                 todo = pad;
641                         if (write(ifd, (char *)&zeros, todo) != todo) {
642                                 fprintf(stderr, "%s: Write error on %s: %s\n",
643                                         params.cmdname, params.imagefile,
644                                         strerror(errno));
645                                 exit(EXIT_FAILURE);
646                         }
647                         pad -= todo;
648                 }
649         }
650
651         (void) munmap((void *)ptr, sbuf.st_size);
652         (void) close (dfd);
653 }