remove an unused #include statement that is causing compile issues on osx
[oweals/openwrt.git] / tools / mkimage / src / mkimage.c
1 /*
2  * (C) Copyright 2000-2004
3  * DENX Software Engineering
4  * Wolfgang Denk, wd@denx.de
5  * All rights reserved.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License as
9  * published by the Free Software Foundation; either version 2 of
10  * the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
20  * MA 02111-1307 USA
21  */
22 #ifdef __APPLE__
23 #define __FreeBSD__ 10
24 #endif
25
26 #include <errno.h>
27 #include <fcntl.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #ifndef __WIN32__
32 #include <netinet/in.h>         /* for host / network byte order conversions    */
33 #endif
34 #include <sys/mman.h>
35 #include <sys/stat.h>
36 #include <time.h>
37 #include <unistd.h>
38
39 #if defined(__BEOS__) || defined(__NetBSD__) || defined(__APPLE__)
40 #include <inttypes.h>
41 #include <sys/types.h>
42 #endif
43 #ifdef __WIN32__
44 typedef unsigned int __u32;
45
46 #define SWAP_LONG(x) \
47         ((__u32)( \
48                 (((__u32)(x) & (__u32)0x000000ffUL) << 24) | \
49                 (((__u32)(x) & (__u32)0x0000ff00UL) <<  8) | \
50                 (((__u32)(x) & (__u32)0x00ff0000UL) >>  8) | \
51                 (((__u32)(x) & (__u32)0xff000000UL) >> 24) ))
52 typedef         unsigned char   uint8_t;
53 typedef         unsigned short  uint16_t;
54 typedef         unsigned int    uint32_t;
55
56 #define     ntohl(a)    SWAP_LONG(a)
57 #define     htonl(a)    SWAP_LONG(a)
58 #endif  /* __WIN32__ */
59
60 #ifndef O_BINARY                /* should be define'd on __WIN32__ */
61 #define O_BINARY        0
62 #endif
63
64 #include "image.h"
65
66 extern int errno;
67
68 #ifndef MAP_FAILED
69 #define MAP_FAILED (-1)
70 #endif
71
72 char *cmdname;
73
74 extern unsigned long crc32 (unsigned long crc, const char *buf, unsigned int len);
75
76 typedef struct table_entry {
77         int     val;            /* as defined in image.h        */
78         char    *sname;         /* short (input) name           */
79         char    *lname;         /* long (output) name           */
80 } table_entry_t;
81
82 table_entry_t arch_name[] = {
83     {   IH_CPU_INVALID,         NULL,           "Invalid CPU",  },
84     {   IH_CPU_ALPHA,           "alpha",        "Alpha",        },
85     {   IH_CPU_ARM,             "arm",          "ARM",          },
86     {   IH_CPU_I386,            "x86",          "Intel x86",    },
87     {   IH_CPU_IA64,            "ia64",         "IA64",         },
88     {   IH_CPU_M68K,            "m68k",         "MC68000",      },
89     {   IH_CPU_MICROBLAZE,      "microblaze",   "MicroBlaze",   },
90     {   IH_CPU_MIPS,            "mips",         "MIPS",         },
91     {   IH_CPU_MIPS64,          "mips64",       "MIPS 64 Bit",  },
92     {   IH_CPU_NIOS,            "nios",         "NIOS",         },
93     {   IH_CPU_NIOS2,           "nios2",        "NIOS II",      },
94     {   IH_CPU_PPC,             "ppc",          "PowerPC",      },
95     {   IH_CPU_S390,            "s390",         "IBM S390",     },
96     {   IH_CPU_SH,              "sh",           "SuperH",       },
97     {   IH_CPU_SPARC,           "sparc",        "SPARC",        },
98     {   IH_CPU_SPARC64,         "sparc64",      "SPARC 64 Bit", },
99     {   IH_CPU_BLACKFIN,        "blackfin",     "Blackfin",     },
100     {   IH_CPU_AVR32,           "avr32",        "AVR32",        },
101     {   -1,                     "",             "",             },
102 };
103
104 table_entry_t os_name[] = {
105     {   IH_OS_INVALID,  NULL,           "Invalid OS",           },
106     {   IH_OS_4_4BSD,   "4_4bsd",       "4_4BSD",               },
107     {   IH_OS_ARTOS,    "artos",        "ARTOS",                },
108     {   IH_OS_DELL,     "dell",         "Dell",                 },
109     {   IH_OS_ESIX,     "esix",         "Esix",                 },
110     {   IH_OS_FREEBSD,  "freebsd",      "FreeBSD",              },
111     {   IH_OS_IRIX,     "irix",         "Irix",                 },
112     {   IH_OS_LINUX,    "linux",        "Linux",                },
113     {   IH_OS_LYNXOS,   "lynxos",       "LynxOS",               },
114     {   IH_OS_NCR,      "ncr",          "NCR",                  },
115     {   IH_OS_NETBSD,   "netbsd",       "NetBSD",               },
116     {   IH_OS_OPENBSD,  "openbsd",      "OpenBSD",              },
117     {   IH_OS_PSOS,     "psos",         "pSOS",                 },
118     {   IH_OS_QNX,      "qnx",          "QNX",                  },
119     {   IH_OS_RTEMS,    "rtems",        "RTEMS",                },
120     {   IH_OS_SCO,      "sco",          "SCO",                  },
121     {   IH_OS_SOLARIS,  "solaris",      "Solaris",              },
122     {   IH_OS_SVR4,     "svr4",         "SVR4",                 },
123     {   IH_OS_U_BOOT,   "u-boot",       "U-Boot",               },
124     {   IH_OS_VXWORKS,  "vxworks",      "VxWorks",              },
125     {   -1,             "",             "",                     },
126 };
127
128 table_entry_t type_name[] = {
129     {   IH_TYPE_INVALID,    NULL,         "Invalid Image",      },
130     {   IH_TYPE_FILESYSTEM, "filesystem", "Filesystem Image",   },
131     {   IH_TYPE_FIRMWARE,   "firmware",   "Firmware",           },
132     {   IH_TYPE_KERNEL,     "kernel",     "Kernel Image",       },
133     {   IH_TYPE_MULTI,      "multi",      "Multi-File Image",   },
134     {   IH_TYPE_RAMDISK,    "ramdisk",    "RAMDisk Image",      },
135     {   IH_TYPE_SCRIPT,     "script",     "Script",             },
136     {   IH_TYPE_STANDALONE, "standalone", "Standalone Program", },
137     {   IH_TYPE_FLATDT,     "flat_dt",    "Flat Device Tree",   },
138     {   -1,                 "",           "",                   },
139 };
140
141 table_entry_t comp_name[] = {
142     {   IH_COMP_NONE,   "none",         "uncompressed",         },
143     {   IH_COMP_BZIP2,  "bzip2",        "bzip2 compressed",     },
144     {   IH_COMP_GZIP,   "gzip",         "gzip compressed",      },
145     {   IH_COMP_LZMA,   "lzma",         "lzma compressed",      },
146     {   -1,             "",             "",                     },
147 };
148
149 static  void    copy_file (int, const char *, int);
150 static  void    usage   (void);
151 static  void    print_header (image_header_t *);
152 static  void    print_type (image_header_t *);
153 static  char    *put_table_entry (table_entry_t *, char *, int);
154 static  char    *put_arch (int);
155 static  char    *put_type (int);
156 static  char    *put_os   (int);
157 static  char    *put_comp (int);
158 static  int     get_table_entry (table_entry_t *, char *, char *);
159 static  int     get_arch(char *);
160 static  int     get_comp(char *);
161 static  int     get_os  (char *);
162 static  int     get_type(char *);
163
164
165 char    *datafile;
166 char    *imagefile;
167
168 int dflag    = 0;
169 int eflag    = 0;
170 int lflag    = 0;
171 int vflag    = 0;
172 int xflag    = 0;
173 int opt_os   = IH_OS_LINUX;
174 int opt_arch = IH_CPU_PPC;
175 int opt_type = IH_TYPE_KERNEL;
176 int opt_comp = IH_COMP_GZIP;
177
178 image_header_t header;
179 image_header_t *hdr = &header;
180
181 int
182 main (int argc, char **argv)
183 {
184         int ifd;
185         uint32_t checksum;
186         uint32_t addr;
187         uint32_t ep;
188         struct stat sbuf;
189         unsigned char *ptr;
190         char *name = "";
191
192         cmdname = *argv;
193
194         addr = ep = 0;
195
196         while (--argc > 0 && **++argv == '-') {
197                 while (*++*argv) {
198                         switch (**argv) {
199                         case 'l':
200                                 lflag = 1;
201                                 break;
202                         case 'A':
203                                 if ((--argc <= 0) ||
204                                     (opt_arch = get_arch(*++argv)) < 0)
205                                         usage ();
206                                 goto NXTARG;
207                         case 'C':
208                                 if ((--argc <= 0) ||
209                                     (opt_comp = get_comp(*++argv)) < 0)
210                                         usage ();
211                                 goto NXTARG;
212                         case 'O':
213                                 if ((--argc <= 0) ||
214                                     (opt_os = get_os(*++argv)) < 0)
215                                         usage ();
216                                 goto NXTARG;
217                         case 'T':
218                                 if ((--argc <= 0) ||
219                                     (opt_type = get_type(*++argv)) < 0)
220                                         usage ();
221                                 goto NXTARG;
222
223                         case 'a':
224                                 if (--argc <= 0)
225                                         usage ();
226                                 addr = strtoul (*++argv, (char **)&ptr, 16);
227                                 if (*ptr) {
228                                         fprintf (stderr,
229                                                 "%s: invalid load address %s\n",
230                                                 cmdname, *argv);
231                                         exit (EXIT_FAILURE);
232                                 }
233                                 goto NXTARG;
234                         case 'd':
235                                 if (--argc <= 0)
236                                         usage ();
237                                 datafile = *++argv;
238                                 dflag = 1;
239                                 goto NXTARG;
240                         case 'e':
241                                 if (--argc <= 0)
242                                         usage ();
243                                 ep = strtoul (*++argv, (char **)&ptr, 16);
244                                 if (*ptr) {
245                                         fprintf (stderr,
246                                                 "%s: invalid entry point %s\n",
247                                                 cmdname, *argv);
248                                         exit (EXIT_FAILURE);
249                                 }
250                                 eflag = 1;
251                                 goto NXTARG;
252                         case 'n':
253                                 if (--argc <= 0)
254                                         usage ();
255                                 name = *++argv;
256                                 goto NXTARG;
257                         case 'v':
258                                 vflag++;
259                                 break;
260                         case 'x':
261                                 xflag++;
262                                 break;
263                         default:
264                                 usage ();
265                         }
266                 }
267 NXTARG:         ;
268         }
269
270         if ((argc != 1) || ((lflag ^ dflag) == 0))
271                 usage();
272
273         if (!eflag) {
274                 ep = addr;
275                 /* If XIP, entry point must be after the U-Boot header */
276                 if (xflag)
277                         ep += sizeof(image_header_t);
278         }
279
280         /*
281          * If XIP, ensure the entry point is equal to the load address plus
282          * the size of the U-Boot header.
283          */
284         if (xflag) {
285                 if (ep != addr + sizeof(image_header_t)) {
286                         fprintf (stderr,
287                                 "%s: For XIP, the entry point must be the load addr + %lu\n",
288                                 cmdname,
289                                 (unsigned long)sizeof(image_header_t));
290                         exit (EXIT_FAILURE);
291                 }
292         }
293
294         imagefile = *argv;
295
296         if (lflag) {
297                 ifd = open(imagefile, O_RDONLY|O_BINARY);
298         } else {
299                 ifd = open(imagefile, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, 0666);
300         }
301
302         if (ifd < 0) {
303                 fprintf (stderr, "%s: Can't open %s: %s\n",
304                         cmdname, imagefile, strerror(errno));
305                 exit (EXIT_FAILURE);
306         }
307
308         if (lflag) {
309                 int len;
310                 char *data;
311                 /*
312                  * list header information of existing image
313                  */
314                 if (fstat(ifd, &sbuf) < 0) {
315                         fprintf (stderr, "%s: Can't stat %s: %s\n",
316                                 cmdname, imagefile, strerror(errno));
317                         exit (EXIT_FAILURE);
318                 }
319
320                 if ((unsigned)sbuf.st_size < sizeof(image_header_t)) {
321                         fprintf (stderr,
322                                 "%s: Bad size: \"%s\" is no valid image\n",
323                                 cmdname, imagefile);
324                         exit (EXIT_FAILURE);
325                 }
326
327                 ptr = (unsigned char *)mmap(0, sbuf.st_size,
328                                             PROT_READ, MAP_SHARED, ifd, 0);
329                 if ((caddr_t)ptr == (caddr_t)-1) {
330                         fprintf (stderr, "%s: Can't read %s: %s\n",
331                                 cmdname, imagefile, strerror(errno));
332                         exit (EXIT_FAILURE);
333                 }
334
335                 /*
336                  * create copy of header so that we can blank out the
337                  * checksum field for checking - this can't be done
338                  * on the PROT_READ mapped data.
339                  */
340                 memcpy (hdr, ptr, sizeof(image_header_t));
341
342                 if (ntohl(hdr->ih_magic) != IH_MAGIC) {
343                         fprintf (stderr,
344                                 "%s: Bad Magic Number: \"%s\" is no valid image\n",
345                                 cmdname, imagefile);
346                         exit (EXIT_FAILURE);
347                 }
348
349                 data = (char *)hdr;
350                 len  = sizeof(image_header_t);
351
352                 checksum = ntohl(hdr->ih_hcrc);
353                 hdr->ih_hcrc = htonl(0);        /* clear for re-calculation */
354
355                 if (crc32 (0, data, len) != checksum) {
356                         fprintf (stderr,
357                                 "%s: ERROR: \"%s\" has bad header checksum!\n",
358                                 cmdname, imagefile);
359                         exit (EXIT_FAILURE);
360                 }
361
362                 data = (char *)(ptr + sizeof(image_header_t));
363                 len  = sbuf.st_size - sizeof(image_header_t) ;
364
365                 if (crc32 (0, data, len) != ntohl(hdr->ih_dcrc)) {
366                         fprintf (stderr,
367                                 "%s: ERROR: \"%s\" has corrupted data!\n",
368                                 cmdname, imagefile);
369                         exit (EXIT_FAILURE);
370                 }
371
372                 /* for multi-file images we need the data part, too */
373                 print_header ((image_header_t *)ptr);
374
375                 (void) munmap((void *)ptr, sbuf.st_size);
376                 (void) close (ifd);
377
378                 exit (EXIT_SUCCESS);
379         }
380
381         /*
382          * Must be -w then:
383          *
384          * write dummy header, to be fixed later
385          */
386         memset (hdr, 0, sizeof(image_header_t));
387
388         if (write(ifd, hdr, sizeof(image_header_t)) != sizeof(image_header_t)) {
389                 fprintf (stderr, "%s: Write error on %s: %s\n",
390                         cmdname, imagefile, strerror(errno));
391                 exit (EXIT_FAILURE);
392         }
393
394         if (opt_type == IH_TYPE_MULTI || opt_type == IH_TYPE_SCRIPT) {
395                 char *file = datafile;
396                 uint32_t size;
397
398                 for (;;) {
399                         char *sep = NULL;
400
401                         if (file) {
402                                 if ((sep = strchr(file, ':')) != NULL) {
403                                         *sep = '\0';
404                                 }
405
406                                 if (stat (file, &sbuf) < 0) {
407                                         fprintf (stderr, "%s: Can't stat %s: %s\n",
408                                                 cmdname, file, strerror(errno));
409                                         exit (EXIT_FAILURE);
410                                 }
411                                 size = htonl(sbuf.st_size);
412                         } else {
413                                 size = 0;
414                         }
415
416                         if (write(ifd, (char *)&size, sizeof(size)) != sizeof(size)) {
417                                 fprintf (stderr, "%s: Write error on %s: %s\n",
418                                         cmdname, imagefile, strerror(errno));
419                                 exit (EXIT_FAILURE);
420                         }
421
422                         if (!file) {
423                                 break;
424                         }
425
426                         if (sep) {
427                                 *sep = ':';
428                                 file = sep + 1;
429                         } else {
430                                 file = NULL;
431                         }
432                 }
433
434                 file = datafile;
435
436                 for (;;) {
437                         char *sep = strchr(file, ':');
438                         if (sep) {
439                                 *sep = '\0';
440                                 copy_file (ifd, file, 1);
441                                 *sep++ = ':';
442                                 file = sep;
443                         } else {
444                                 copy_file (ifd, file, 0);
445                                 break;
446                         }
447                 }
448         } else {
449                 copy_file (ifd, datafile, 0);
450         }
451
452         /* We're a bit of paranoid */
453 #if defined(_POSIX_SYNCHRONIZED_IO) && !defined(__sun__) && !defined(__FreeBSD__)
454         (void) fdatasync (ifd);
455 #else
456         (void) fsync (ifd);
457 #endif
458
459         if (fstat(ifd, &sbuf) < 0) {
460                 fprintf (stderr, "%s: Can't stat %s: %s\n",
461                         cmdname, imagefile, strerror(errno));
462                 exit (EXIT_FAILURE);
463         }
464
465         ptr = (unsigned char *)mmap(0, sbuf.st_size,
466                                     PROT_READ|PROT_WRITE, MAP_SHARED, ifd, 0);
467         if (ptr == (unsigned char *)MAP_FAILED) {
468                 fprintf (stderr, "%s: Can't map %s: %s\n",
469                         cmdname, imagefile, strerror(errno));
470                 exit (EXIT_FAILURE);
471         }
472
473         hdr = (image_header_t *)ptr;
474
475         checksum = crc32 (0,
476                           (const char *)(ptr + sizeof(image_header_t)),
477                           sbuf.st_size - sizeof(image_header_t)
478                          );
479
480         /* Build new header */
481         hdr->ih_magic = htonl(IH_MAGIC);
482         hdr->ih_time  = htonl(sbuf.st_mtime);
483         hdr->ih_size  = htonl(sbuf.st_size - sizeof(image_header_t));
484         hdr->ih_load  = htonl(addr);
485         hdr->ih_ep    = htonl(ep);
486         hdr->ih_dcrc  = htonl(checksum);
487         hdr->ih_os    = opt_os;
488         hdr->ih_arch  = opt_arch;
489         hdr->ih_type  = opt_type;
490         hdr->ih_comp  = opt_comp;
491
492         strncpy((char *)hdr->ih_name, name, IH_NMLEN);
493
494         checksum = crc32(0,(const char *)hdr,sizeof(image_header_t));
495
496         hdr->ih_hcrc = htonl(checksum);
497
498         print_header (hdr);
499
500         (void) munmap((void *)ptr, sbuf.st_size);
501
502         /* We're a bit of paranoid */
503 #if defined(_POSIX_SYNCHRONIZED_IO) && !defined(__sun__) && !defined(__FreeBSD__)
504         (void) fdatasync (ifd);
505 #else
506         (void) fsync (ifd);
507 #endif
508
509         if (close(ifd)) {
510                 fprintf (stderr, "%s: Write error on %s: %s\n",
511                         cmdname, imagefile, strerror(errno));
512                 exit (EXIT_FAILURE);
513         }
514
515         exit (EXIT_SUCCESS);
516 }
517
518 static void
519 copy_file (int ifd, const char *datafile, int pad)
520 {
521         int dfd;
522         struct stat sbuf;
523         unsigned char *ptr;
524         int tail;
525         int zero = 0;
526         int offset = 0;
527         int size;
528
529         if (vflag) {
530                 fprintf (stderr, "Adding Image %s\n", datafile);
531         }
532
533         if ((dfd = open(datafile, O_RDONLY|O_BINARY)) < 0) {
534                 fprintf (stderr, "%s: Can't open %s: %s\n",
535                         cmdname, datafile, strerror(errno));
536                 exit (EXIT_FAILURE);
537         }
538
539         if (fstat(dfd, &sbuf) < 0) {
540                 fprintf (stderr, "%s: Can't stat %s: %s\n",
541                         cmdname, datafile, strerror(errno));
542                 exit (EXIT_FAILURE);
543         }
544
545         ptr = (unsigned char *)mmap(0, sbuf.st_size,
546                                     PROT_READ, MAP_SHARED, dfd, 0);
547         if (ptr == (unsigned char *)MAP_FAILED) {
548                 fprintf (stderr, "%s: Can't read %s: %s\n",
549                         cmdname, datafile, strerror(errno));
550                 exit (EXIT_FAILURE);
551         }
552
553         if (xflag) {
554                 unsigned char *p = NULL;
555                 /*
556                  * XIP: do not append the image_header_t at the
557                  * beginning of the file, but consume the space
558                  * reserved for it.
559                  */
560
561                 if ((unsigned)sbuf.st_size < sizeof(image_header_t)) {
562                         fprintf (stderr,
563                                 "%s: Bad size: \"%s\" is too small for XIP\n",
564                                 cmdname, datafile);
565                         exit (EXIT_FAILURE);
566                 }
567
568                 for (p=ptr; p < ptr+sizeof(image_header_t); p++) {
569                         if ( *p != 0xff ) {
570                                 fprintf (stderr,
571                                         "%s: Bad file: \"%s\" has invalid buffer for XIP\n",
572                                         cmdname, datafile);
573                                 exit (EXIT_FAILURE);
574                         }
575                 }
576
577                 offset = sizeof(image_header_t);
578         }
579
580         size = sbuf.st_size - offset;
581         if (write(ifd, ptr + offset, size) != size) {
582                 fprintf (stderr, "%s: Write error on %s: %s\n",
583                         cmdname, imagefile, strerror(errno));
584                 exit (EXIT_FAILURE);
585         }
586
587         if (pad && ((tail = size % 4) != 0)) {
588
589                 if (write(ifd, (char *)&zero, 4-tail) != 4-tail) {
590                         fprintf (stderr, "%s: Write error on %s: %s\n",
591                                 cmdname, imagefile, strerror(errno));
592                         exit (EXIT_FAILURE);
593                 }
594         }
595
596         (void) munmap((void *)ptr, sbuf.st_size);
597         (void) close (dfd);
598 }
599
600 void
601 usage ()
602 {
603         fprintf (stderr, "Usage: %s -l image\n"
604                          "          -l ==> list image header information\n"
605                          "       %s [-x] -A arch -O os -T type -C comp "
606                          "-a addr -e ep -n name -d data_file[:data_file...] image\n",
607                 cmdname, cmdname);
608         fprintf (stderr, "          -A ==> set architecture to 'arch'\n"
609                          "          -O ==> set operating system to 'os'\n"
610                          "          -T ==> set image type to 'type'\n"
611                          "          -C ==> set compression type 'comp'\n"
612                          "          -a ==> set load address to 'addr' (hex)\n"
613                          "          -e ==> set entry point to 'ep' (hex)\n"
614                          "          -n ==> set image name to 'name'\n"
615                          "          -d ==> use image data from 'datafile'\n"
616                          "          -x ==> set XIP (execute in place)\n"
617                 );
618         exit (EXIT_FAILURE);
619 }
620
621 static void
622 print_header (image_header_t *hdr)
623 {
624         time_t timestamp;
625         uint32_t size;
626
627         timestamp = (time_t)ntohl(hdr->ih_time);
628         size = ntohl(hdr->ih_size);
629
630         printf ("Image Name:   %.*s\n", IH_NMLEN, hdr->ih_name);
631         printf ("Created:      %s", ctime(&timestamp));
632         printf ("Image Type:   "); print_type(hdr);
633         printf ("Data Size:    %d Bytes = %.2f kB = %.2f MB\n",
634                 size, (double)size / 1.024e3, (double)size / 1.048576e6 );
635         printf ("Load Address: 0x%08X\n", ntohl(hdr->ih_load));
636         printf ("Entry Point:  0x%08X\n", ntohl(hdr->ih_ep));
637
638         if (hdr->ih_type == IH_TYPE_MULTI || hdr->ih_type == IH_TYPE_SCRIPT) {
639                 int i, ptrs;
640                 uint32_t pos;
641                 uint32_t *len_ptr = (uint32_t *) (
642                                         (unsigned long)hdr + sizeof(image_header_t)
643                                 );
644
645                 /* determine number of images first (to calculate image offsets) */
646                 for (i=0; len_ptr[i]; ++i)      /* null pointer terminates list */
647                         ;
648                 ptrs = i;               /* null pointer terminates list */
649
650                 pos = sizeof(image_header_t) + ptrs * sizeof(long);
651                 printf ("Contents:\n");
652                 for (i=0; len_ptr[i]; ++i) {
653                         size = ntohl(len_ptr[i]);
654
655                         printf ("   Image %d: %8d Bytes = %4d kB = %d MB\n",
656                                 i, size, size>>10, size>>20);
657                         if (hdr->ih_type == IH_TYPE_SCRIPT && i > 0) {
658                                 /*
659                                  * the user may need to know offsets
660                                  * if planning to do something with
661                                  * multiple files
662                                  */
663                                 printf ("    Offset = %08X\n", pos);
664                         }
665                         /* copy_file() will pad the first files to even word align */
666                         size += 3;
667                         size &= ~3;
668                         pos += size;
669                 }
670         }
671 }
672
673
674 static void
675 print_type (image_header_t *hdr)
676 {
677         printf ("%s %s %s (%s)\n",
678                 put_arch (hdr->ih_arch),
679                 put_os   (hdr->ih_os  ),
680                 put_type (hdr->ih_type),
681                 put_comp (hdr->ih_comp)
682         );
683 }
684
685 static char *put_arch (int arch)
686 {
687         return (put_table_entry(arch_name, "Unknown Architecture", arch));
688 }
689
690 static char *put_os (int os)
691 {
692         return (put_table_entry(os_name, "Unknown OS", os));
693 }
694
695 static char *put_type (int type)
696 {
697         return (put_table_entry(type_name, "Unknown Image", type));
698 }
699
700 static char *put_comp (int comp)
701 {
702         return (put_table_entry(comp_name, "Unknown Compression", comp));
703 }
704
705 static char *put_table_entry (table_entry_t *table, char *msg, int type)
706 {
707         for (; table->val>=0; ++table) {
708                 if (table->val == type)
709                         return (table->lname);
710         }
711         return (msg);
712 }
713
714 static int get_arch(char *name)
715 {
716         return (get_table_entry(arch_name, "CPU", name));
717 }
718
719
720 static int get_comp(char *name)
721 {
722         return (get_table_entry(comp_name, "Compression", name));
723 }
724
725
726 static int get_os (char *name)
727 {
728         return (get_table_entry(os_name, "OS", name));
729 }
730
731
732 static int get_type(char *name)
733 {
734         return (get_table_entry(type_name, "Image", name));
735 }
736
737 static int get_table_entry (table_entry_t *table, char *msg, char *name)
738 {
739         table_entry_t *t;
740         int first = 1;
741
742         for (t=table; t->val>=0; ++t) {
743                 if (t->sname && strcasecmp(t->sname, name)==0)
744                         return (t->val);
745         }
746         fprintf (stderr, "\nInvalid %s Type - valid names are", msg);
747         for (t=table; t->val>=0; ++t) {
748                 if (t->sname == NULL)
749                         continue;
750                 fprintf (stderr, "%c %s", (first) ? ':' : ',', t->sname);
751                 first = 0;
752         }
753         fprintf (stderr, "\n");
754         return (-1);
755 }