[tools] revert changeset 15081 seems to break Alice box devices
[openwrt.git] / tools / firmware-utils / src / mkcasfw.c
1 /*
2  *  $Id$
3  *
4  *  Copyright (C) 2007 OpenWrt.org
5  *  Copyright (C) 2007 Gabor Juhos <juhosg at openwrt.org>
6  *
7  *  This program is free software; you can redistribute it and/or modify it
8  *  under the terms of the GNU General Public License version 2 as published
9  *  by the Free Software Foundation.
10  *
11  */
12
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <stdint.h>
16 #include <string.h>
17 #include <unistd.h>     /* for unlink() */
18 #include <libgen.h>
19 #include <getopt.h>     /* for getopt() */
20 #include <stdarg.h>
21 #include <errno.h>
22 #include <sys/stat.h>
23 #include <endian.h>     /* for __BYTE_ORDER */
24 #if defined(__CYGWIN__)
25 #  include <byteswap.h>
26 #endif
27
28 #if (__BYTE_ORDER == __LITTLE_ENDIAN)
29 #  define HOST_TO_LE16(x)       (x)
30 #  define HOST_TO_LE32(x)       (x)
31 #  define LE16_TO_HOST(x)       (x)
32 #  define LE32_TO_HOST(x)       (x)
33 #else
34 #  define HOST_TO_LE16(x)       bswap_16(x)
35 #  define HOST_TO_LE32(x)       bswap_32(x)
36 #  define LE16_TO_HOST(x)       bswap_16(x)
37 #  define LE32_TO_HOST(x)       bswap_32(x)
38 #endif
39
40 #define MAX_NUM_BLOCKS  2
41 #define MAX_ARG_COUNT   32
42 #define MAX_ARG_LEN     1024
43 #define FILE_BUF_LEN    (16*1024)
44 #define DEFAULT_PADC    0xFF
45
46 #define DEFAULT_BLOCK_ALIGN     0x10000U
47
48 #define CSUM_TYPE_NONE  0
49 #define CSUM_TYPE_8     1
50 #define CSUM_TYPE_16    2
51 #define CSUM_TYPE_32    3
52
53 struct csum_state{
54         int     size;
55         uint32_t val;
56         uint32_t tmp;
57         int     odd;
58 };
59
60 struct image_desc {
61         int             need_file;
62         char            *file_name;     /* name of the file */
63         uint32_t        file_size;      /* length of the file */
64
65         uint32_t        csum;
66         uint32_t        out_size;
67         uint8_t         padc;
68 };
69
70 struct fwhdr_nfs {
71         uint32_t        type;
72         uint32_t        kernel_offs;
73         uint32_t        kernel_size;
74         uint32_t        fs_offs;
75         uint32_t        fs_size;
76         uint32_t        kernel_csum;
77         uint32_t        fs_csum;
78         uint32_t        id;
79 } __attribute__ ((packed));
80
81 struct fwhdr_cas {
82         uint32_t        type;
83         uint32_t        kernel_offs;
84         uint32_t        kernel_size;
85         uint32_t        id;
86         uint32_t        kernel_csum;
87         uint32_t        magic1;
88         uint32_t        magic2;
89         uint32_t        magic3;
90 } __attribute__ ((packed));
91
92 union file_hdr {
93         struct fwhdr_cas cas;
94         struct fwhdr_nfs nfs;
95 };
96
97 struct board_info {
98         char            *model;
99         char            *name;
100         int             header_type;
101         uint32_t        id;
102         uint32_t        max_kernel_size;
103         uint32_t        max_fs_size;
104 };
105
106 #define HEADER_TYPE_NFS         0
107 #define HEADER_TYPE_CAS         1
108
109 #define KERNEL_SIZE_CAS         (61*64*1024)
110 #define KERNEL_SIZE_NFS         (52*64*1024)
111 #define FS_SIZE_NFS             (9*64*1024)
112
113 #define CAS_MAGIC1      0x5241AA55
114 #define CAS_MAGIC2      0x524F4741
115 #define CAS_MAGIC3      0xD3F22D4E
116
117 /* Cellvision/SparkLAN products */
118 #define MODEL_CAS_630           0x01000000
119 #define MODEL_CAS_630W          0x01000000
120 #define MODEL_CAS_670           0x01000000
121 #define MODEL_CAS_670W          0x01000000
122 #define MODEL_NFS_101U          0x01000000
123 #define MODEL_NFS_101WU         0x01000003
124 #define MODEL_NFS_202U          0x01000001
125 #define MODEL_NFS_202WU         0x01000002
126
127 /* Corega products */
128 #define MODEL_CG_NSADP          0x01000020 /* NFS-101U */
129 #define MODEL_CG_NSADPCR        0x01000021 /* NFS-202U */
130
131 /* D-Link products */
132 #define MODEL_DCS_950           0x01010102 /* CAS-630 */
133 #define MODEL_DCS_950G          0x01020102 /* CAS-630W */
134 #define MODEL_DNS_120           0x01000030 /* NFS-101U */
135 #define MODEL_DNS_G120          0x01000032 /* NFS-101WU */
136
137 /* Digitus products */
138 #define MODEL_DN_16021          MODEL_CAS_630
139 #define MODEL_DN_16022          MODEL_CAS_630W
140 #define MODEL_DN_16030          MODEL_CAS_670
141 #define MODEL_DN_16031          MODEL_CAS_670W
142 #define MODEL_DN_7013           MODEL_NFS_101U
143
144 /* Lobos products */
145 #define MODEL_LB_SS01TXU        0x00000000
146
147 /* Neu-Fusion products */
148
149 /* Ovislink products */
150 #define MODEL_MU_5000FS         0x01000040 /* NFS-101U */
151 #define MODEL_WL_5420CAM        0x020B0101 /* CAS-630W? */
152 #define MODEL_WL_5460CAM        0x020B0001 /* CAS-670W */
153
154 /* Repotec products */
155
156 /* Sitecom products */
157 #define MODEL_LN_350            /* unknown */
158 #define MODEL_LN_403            0x01020402
159 #define MODEL_WL_401            0x01010402
160
161 /* Surecom products */
162 #define MODEL_EP_4001_MM        0x01030A02 /* CAS-630 */
163 #define MODEL_EP_4002_MM        0x01020A02 /* CAS-630W */
164 #define MODEL_EP_4011_MM        0x01010A02 /* CAS-670 */
165 #define MODEL_EP_4012_MM        0x01000A02 /* CAS-670W */
166 #define MODEL_EP_9812_U         /* unknown */
167
168 /* Trendnet products */
169 #define MODEL_TN_U100           0x01000081 /* NFS-101U */
170 #define MODEL_TN_U200           0x01000082 /* NFS-202U */
171
172 /*
173  * Globals
174  */
175 char *progname;
176 char *ofname;
177 int verblevel;
178 int keep_invalid_images;
179 int invalid_causes_error = 1;
180 union file_hdr header;
181
182 struct image_desc kernel_image;
183 struct image_desc fs_image;
184
185 struct board_info *board = NULL;
186
187 #define BOARD(m, n, i, ks, fs, h) {             \
188                 .model = (m),                   \
189                 .name = (n),                    \
190                 .id = (i),                      \
191                 .max_kernel_size = (ks),        \
192                 .max_fs_size = (fs),            \
193                 .header_type = (h)              \
194         }
195
196 #define BOARD_CAS(m,n,i) \
197                 BOARD(m, n, i, KERNEL_SIZE_CAS, 0, HEADER_TYPE_CAS)
198 #define BOARD_NFS(m,n,i) \
199                 BOARD(m, n, i, KERNEL_SIZE_NFS, FS_SIZE_NFS, HEADER_TYPE_NFS)
200
201 static struct board_info boards[] = {
202         /* Cellvision/Sparklan products */
203         BOARD_CAS("CAS-630", "Cellvision CAS-630", MODEL_CAS_630),
204         BOARD_CAS("CAS-630W", "Cellvision CAS-630W", MODEL_CAS_630W),
205         BOARD_CAS("CAS-670", "Cellvision CAS-670", MODEL_CAS_670),
206         BOARD_CAS("CAS-670W", "Cellvision CAS-670W", MODEL_CAS_670W),
207         BOARD_NFS("NFS-101U", "Cellvision NFS-101U", MODEL_NFS_101U),
208         BOARD_NFS("NFS-101WU", "Cellvision NFS-101WU", MODEL_NFS_101WU),
209         BOARD_NFS("NFS-202U", "Cellvision NFS-202U", MODEL_NFS_202U),
210         BOARD_NFS("NFS-202WU", "Cellvision NFS-202WU", MODEL_NFS_202WU),
211
212         /* Corega products */
213         BOARD_NFS("CG-NSADP", "Corega CG-NSADP", MODEL_CG_NSADP),
214         BOARD_NFS("CG-NSADPCR", "Corega CG-NSADPCR", MODEL_CG_NSADPCR),
215
216         /* D-Link products */
217         BOARD_CAS("DCS-950", "D-Link DCS-950", MODEL_DCS_950),
218         BOARD_CAS("DCS-950G", "D-Link DCS-950G", MODEL_DCS_950G),
219         BOARD_NFS("DNS-120", "D-Link DNS-120", MODEL_DNS_120),
220         BOARD_NFS("DNS-G120", "D-Link DNS-G120", MODEL_DNS_G120),
221
222         /* Digitus products */
223         BOARD_NFS("DN-7013", "Digitus DN-7013", MODEL_DN_7013),
224
225         /* Lobos products */
226         BOARD_NFS("LB-SS01TXU", "Lobos LB-SS01TXU", MODEL_LB_SS01TXU),
227
228         /* Ovislink products */
229         BOARD_NFS("MU-5000FS", "Ovislink MU-5000FS", MODEL_MU_5000FS),
230         BOARD_CAS("WL-5420CAM", "Ovislink WL-5420 CAM", MODEL_WL_5420CAM),
231         BOARD_CAS("WL-5460CAM", "Ovislink WL-5460 CAM", MODEL_WL_5460CAM),
232
233         /* Sitecom products */
234         BOARD_CAS("LN-403", "Sitecom LN-403", MODEL_LN_403),
235         BOARD_CAS("WL-401", "Sitecom WL-401", MODEL_WL_401),
236
237         /* Surecom products */
238         BOARD_CAS("EP-4001-MM", "Surecom EP-4001-MM", MODEL_EP_4001_MM),
239         BOARD_CAS("EP-4002-MM", "Surecom EP-4002-MM", MODEL_EP_4002_MM),
240         BOARD_CAS("EP-4011-MM", "Surecom EP-4011-MM", MODEL_EP_4011_MM),
241         BOARD_CAS("EP-4012-MM", "Surecom EP-4012-MM", MODEL_EP_4012_MM),
242
243         /* TrendNET products */
244         BOARD_NFS("TN-U100", "TrendNET TN-U100", MODEL_TN_U100),
245         BOARD_NFS("TN-U200", "TrendNET TN-U200", MODEL_TN_U200),
246
247         {.model = NULL}
248 };
249
250 /*
251  * Message macros
252  */
253 #define ERR(fmt, ...) do { \
254         fflush(0); \
255         fprintf(stderr, "[%s] *** error: " fmt "\n", \
256                         progname, ## __VA_ARGS__ ); \
257 } while (0)
258
259 #define ERRS(fmt, ...) do { \
260         int save = errno; \
261         fflush(0); \
262         fprintf(stderr, "[%s] *** error: " fmt "\n", \
263                         progname, ## __VA_ARGS__, strerror(save)); \
264 } while (0)
265
266 #define WARN(fmt, ...) do { \
267         fprintf(stderr, "[%s] *** warning: " fmt "\n", \
268                         progname, ## __VA_ARGS__ ); \
269 } while (0)
270
271 #define DBG(lev, fmt, ...) do { \
272         if (verblevel < lev) \
273                 break;\
274         fprintf(stderr, "[%s] " fmt "\n", progname, ## __VA_ARGS__ ); \
275 } while (0)
276
277 #define ERR_FATAL               -1
278 #define ERR_INVALID_IMAGE       -2
279
280 void
281 usage(int status)
282 {
283         FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
284         struct board_info *board;
285
286         fprintf(stream, "Usage: %s [OPTIONS...] <file>\n", progname);
287         fprintf(stream,
288 "\n"
289 "Options:\n"
290 "  -B <board>      create image for the board specified with <board>.\n"
291 "                  valid <board> values:\n"
292         );
293         for (board = boards; board->model != NULL; board++){
294                 fprintf(stream,
295 "                  %-12s: %s\n",
296                  board->model, board->name);
297         };
298         fprintf(stream,
299 "  -d              don't throw error on invalid images\n"
300 "  -k              keep invalid images\n"
301 "  -K <file>       add kernel to the image\n"
302 "  -C <file>       add custom filesystem to the image\n"
303 "  -h              show this screen\n"
304 "Parameters:\n"
305 "  <file>          write output to the file <file>\n"
306         );
307
308         exit(status);
309 }
310
311 static inline uint32_t align(uint32_t base, uint32_t alignment)
312 {
313         uint32_t ret;
314
315         if (alignment) {
316                 ret = (base + alignment - 1);
317                 ret &= ~(alignment-1);
318         } else {
319                 ret = base;
320         }
321
322         return ret;
323 }
324
325 /*
326  * argument parsing
327  */
328 int
329 str2u32(char *arg, uint32_t *val)
330 {
331         char *err = NULL;
332         uint32_t t;
333
334         errno=0;
335         t = strtoul(arg, &err, 0);
336         if (errno || (err==arg) || ((err != NULL) && *err)) {
337                 return -1;
338         }
339
340         *val = t;
341         return 0;
342 }
343
344
345 int
346 str2u16(char *arg, uint16_t *val)
347 {
348         char *err = NULL;
349         uint32_t t;
350
351         errno=0;
352         t = strtoul(arg, &err, 0);
353         if (errno || (err==arg) || ((err != NULL) && *err) || (t >= 0x10000)) {
354                 return -1;
355         }
356
357         *val = t & 0xFFFF;
358         return 0;
359 }
360
361 int
362 str2u8(char *arg, uint8_t *val)
363 {
364         char *err = NULL;
365         uint32_t t;
366
367         errno=0;
368         t = strtoul(arg, &err, 0);
369         if (errno || (err==arg) || ((err != NULL) && *err) || (t >= 0x100)) {
370                 return -1;
371         }
372
373         *val = t & 0xFF;
374         return 0;
375 }
376
377 int
378 parse_arg(char *arg, char *buf, char *argv[])
379 {
380         int res = 0;
381         size_t argl;
382         char *tok;
383         char **ap = &buf;
384         int i;
385
386         memset(argv, 0, MAX_ARG_COUNT * sizeof(void *));
387
388         if ((arg == NULL)) {
389                 /* no arguments */
390                 return 0;
391         }
392
393         argl = strlen(arg);
394         if (argl == 0) {
395                 /* no arguments */
396                 return 0;
397         }
398
399         if (argl >= MAX_ARG_LEN) {
400                 /* argument is too long */
401                 argl = MAX_ARG_LEN-1;
402         }
403
404         memcpy(buf, arg, argl);
405         buf[argl] = '\0';
406
407         for (i = 0; i < MAX_ARG_COUNT; i++) {
408                 tok = strsep(ap, ":");
409                 if (tok == NULL) {
410                         break;
411                 }
412 #if 0
413                 else if (tok[0] == '\0') {
414                         break;
415                 }
416 #endif
417                 argv[i] = tok;
418                 res++;
419         }
420
421         return res;
422 }
423
424
425 int
426 required_arg(char c, char *arg)
427 {
428         if (arg == NULL || *arg != '-')
429                 return 0;
430
431         ERR("option -%c requires an argument\n", c);
432         return ERR_FATAL;
433 }
434
435
436 int
437 is_empty_arg(char *arg)
438 {
439         int ret = 1;
440         if (arg != NULL) {
441                 if (*arg) ret = 0;
442         };
443         return ret;
444 }
445
446
447 void
448 csum8_update(uint8_t *p, uint32_t len, struct csum_state *css)
449 {
450         for ( ; len > 0; len --) {
451                 css->val += *p++;
452         }
453 }
454
455
456 uint16_t
457 csum8_get(struct csum_state *css)
458 {
459         uint8_t t;
460
461         t = css->val;
462         return ~t + 1;
463 }
464
465
466 void
467 csum16_update(uint8_t *p, uint32_t len, struct csum_state *css)
468 {
469         uint16_t t;
470
471         if (css->odd) {
472                 t = css->tmp + (p[0]<<8);
473                 css->val += LE16_TO_HOST(t);
474                 css->odd = 0;
475                 len--;
476                 p++;
477         }
478
479         for ( ; len > 1; len -= 2, p +=2 ) {
480                 t = p[0] + (p[1] << 8);
481                 css->val += LE16_TO_HOST(t);
482         }
483
484         if (len == 1) {
485                 css->tmp = p[0];
486                 css->odd = 1;
487         }
488 }
489
490
491 uint16_t
492 csum16_get(struct csum_state *css)
493 {
494         char pad = 0;
495
496         csum16_update(&pad, 1, css);
497         return ~css->val + 1;
498 }
499
500 void
501 csum32_update(uint8_t *p, uint32_t len, struct csum_state *css)
502 {
503         uint32_t t;
504
505         for ( ; len > 3; len -= 4, p += 4 ) {
506                 t = p[0] + (p[1] << 8) + (p[2] << 16) + (p[3] << 24);
507                 css->val ^= t;
508         }
509 }
510
511 uint32_t
512 csum32_get(struct csum_state *css)
513 {
514         return css->val;
515 }
516
517
518 void
519 csum_init(struct csum_state *css, int size)
520 {
521         css->val = 0;
522         css->tmp = 0;
523         css->odd = 0;
524         css->size = size;
525 }
526
527 void
528 csum_update(uint8_t *p, uint32_t len, struct csum_state *css)
529 {
530         switch (css->size) {
531         case CSUM_TYPE_8:
532                 csum8_update(p,len,css);
533                 break;
534         case CSUM_TYPE_16:
535                 csum16_update(p,len,css);
536                 break;
537         case CSUM_TYPE_32:
538                 csum32_update(p,len,css);
539                 break;
540         }
541 }
542
543
544 uint32_t
545 csum_get(struct csum_state *css)
546 {
547         uint32_t ret;
548
549         switch (css->size) {
550         case CSUM_TYPE_8:
551                 ret = csum8_get(css);
552                 break;
553         case CSUM_TYPE_16:
554                 ret = csum16_get(css);
555                 break;
556         case CSUM_TYPE_32:
557                 ret = csum32_get(css);
558         }
559
560         return ret;
561 }
562
563
564 /*
565  * routines to write data to the output file
566  */
567 int
568 write_out_data(FILE *outfile, uint8_t *data, size_t len,
569                 struct csum_state *css)
570 {
571         errno = 0;
572
573         fwrite(data, len, 1, outfile);
574         if (errno) {
575                 ERRS("unable to write output file");
576                 return ERR_FATAL;
577         }
578
579         if (css) {
580                 csum_update(data, len, css);
581         }
582
583         return 0;
584 }
585
586
587 int
588 write_out_padding(FILE *outfile, size_t len, uint8_t padc,
589                  struct csum_state *css)
590 {
591         uint8_t buf[512];
592         size_t buflen = sizeof(buf);
593         int err;
594
595         memset(buf, padc, buflen);
596         while (len > 0) {
597                 if (len < buflen)
598                         buflen = len;
599
600                 err = write_out_data(outfile, buf, buflen, css);
601                 if (err)
602                         return err;
603
604                 len -= buflen;
605         }
606
607         return 0;
608 }
609
610
611 int
612 image_stat_file(struct image_desc *desc)
613 {
614         struct stat st;
615         int err;
616
617         if (desc->file_name == NULL)
618                 return 0;
619
620         err = stat(desc->file_name, &st);
621         if (err){
622                 ERRS("stat failed on %s", desc->file_name);
623                 return ERR_FATAL;
624         }
625
626         if (st.st_size > desc->out_size) {
627                 WARN("file %s is too big, will be truncated to %d bytes\n",
628                         desc->file_name, desc->out_size);
629                 desc->file_size = desc->out_size;
630                 return ERR_INVALID_IMAGE;
631         }
632
633
634         desc->file_size = st.st_size;
635         desc->out_size = align(desc->file_size,1);
636         return 0;
637 }
638
639
640 int
641 image_writeout_file(FILE *outfile, struct image_desc *desc,
642                         struct csum_state *css)
643 {
644         char buf[FILE_BUF_LEN];
645         size_t buflen = sizeof(buf);
646         FILE *f;
647         size_t len;
648         int res;
649
650         if (desc->file_name == NULL)
651                 return 0;
652
653         if (desc->file_size == 0)
654                 return 0;
655
656         errno = 0;
657         f = fopen(desc->file_name,"r");
658         if (errno) {
659                 ERRS("unable to open file: %s", desc->file_name);
660                 return ERR_FATAL;
661         }
662
663         len = desc->file_size;
664         while (len > 0) {
665                 if (len < buflen)
666                         buflen = len;
667
668                 /* read data from source file */
669                 errno = 0;
670                 fread(buf, buflen, 1, f);
671                 if (errno != 0) {
672                         ERRS("unable to read from file: %s", desc->file_name);
673                         res = ERR_FATAL;
674                         break;
675                 }
676
677                 res = write_out_data(outfile, buf, buflen, css);
678                 if (res)
679                         break;
680
681                 len -= buflen;
682         }
683
684         fclose(f);
685         return res;
686 }
687
688
689 int
690 image_writeout(FILE *outfile, struct image_desc *desc)
691 {
692         int res;
693         struct csum_state css;
694         size_t padlen;
695
696         res = 0;
697
698         if (!desc->file_size)
699                 return 0;
700
701         DBG(2, "writing image, file=%s, file_size=%d\n",
702                 desc->file_name, desc->file_size);
703
704         csum_init(&css, CSUM_TYPE_32);
705
706         res = image_writeout_file(outfile, desc, &css);
707         if (res)
708                 return res;
709
710         /* write padding data if neccesary */
711         padlen = desc->out_size - desc->file_size;
712         DBG(1,"padding desc, length=%d", padlen);
713         res = write_out_padding(outfile, padlen, desc->padc, &css);
714
715         desc->csum = csum_get(&css);
716
717         return res;
718 }
719
720
721 int
722 write_out_header(FILE *outfile)
723 {
724         union file_hdr tmp;
725         int res;
726
727         errno = 0;
728         if (fseek(outfile, 0, SEEK_SET) != 0) {
729                 ERRS("fseek failed on output file");
730                 return ERR_FATAL;
731         }
732
733         switch (board->header_type) {
734         case HEADER_TYPE_CAS:
735                 tmp.cas.type = HOST_TO_LE32(header.cas.type);
736                 tmp.cas.id = HOST_TO_LE32(header.cas.id);
737                 tmp.cas.kernel_offs = HOST_TO_LE32(sizeof(tmp.cas));
738                 tmp.cas.kernel_size = HOST_TO_LE32(kernel_image.out_size);
739                 tmp.cas.kernel_csum = HOST_TO_LE32(kernel_image.csum);
740                 tmp.cas.magic1 = HOST_TO_LE32(CAS_MAGIC1);
741                 tmp.cas.magic2 = HOST_TO_LE32(CAS_MAGIC2);
742                 tmp.cas.magic3 = HOST_TO_LE32(CAS_MAGIC3);
743                 res = write_out_data(outfile, (uint8_t *)&tmp.cas,
744                                         sizeof(tmp.cas), NULL);
745                 break;
746         case HEADER_TYPE_NFS:
747                 tmp.nfs.type = HOST_TO_LE32(header.nfs.type);
748                 tmp.nfs.id = HOST_TO_LE32(header.nfs.id);
749                 tmp.nfs.kernel_offs = HOST_TO_LE32(sizeof(tmp.nfs));
750                 tmp.nfs.kernel_size = HOST_TO_LE32(kernel_image.out_size);
751                 tmp.nfs.kernel_csum = HOST_TO_LE32(kernel_image.csum);
752                 tmp.nfs.fs_offs = HOST_TO_LE32(sizeof(tmp.nfs)
753                                         + kernel_image.out_size);
754                 tmp.nfs.fs_size = HOST_TO_LE32(fs_image.out_size);
755                 tmp.nfs.fs_csum = HOST_TO_LE32(fs_image.csum);
756                 res = write_out_data(outfile, (uint8_t *)&tmp.nfs,
757                                         sizeof(tmp.nfs), NULL);
758                 break;
759         }
760
761         return res;
762 }
763
764 int
765 write_out_images(FILE *outfile)
766 {
767         struct image_desc *desc;
768         int i, res;
769
770         res = image_writeout(outfile, &kernel_image);
771         if (res)
772                 return res;
773
774         res = image_writeout(outfile, &fs_image);
775         if (res)
776                 return res;
777
778         return 0;
779 }
780
781
782 struct board_info *
783 find_board(char *model)
784 {
785         struct board_info *ret;
786         struct board_info *board;
787
788         ret = NULL;
789         for (board = boards; board->model != NULL; board++){
790                 if (strcasecmp(model, board->model) == 0) {
791                         ret = board;
792                         break;
793                 }
794         };
795
796         return ret;
797 }
798
799
800 int
801 parse_opt_board(char ch, char *arg)
802 {
803
804         DBG(1,"parsing board option: -%c %s", ch, arg);
805
806         if (board != NULL) {
807                 ERR("only one board option allowed");
808                 return ERR_FATAL;
809         }
810
811         if (required_arg(ch, arg))
812                 return ERR_FATAL;
813
814         board = find_board(arg);
815         if (board == NULL){
816                 ERR("invalid/unknown board specified: %s", arg);
817                 return ERR_FATAL;
818         }
819
820         switch (board->header_type) {
821         case HEADER_TYPE_CAS:
822                 header.cas.type = HEADER_TYPE_CAS;
823                 header.cas.id = board->id;
824                 break;
825         case HEADER_TYPE_NFS:
826                 header.nfs.type = HEADER_TYPE_NFS;
827                 header.nfs.id = board->id;
828                 break;
829         default:
830                 ERR("internal error, unknown header type\n");
831                 return ERR_FATAL;
832         }
833
834         return 0;
835 }
836
837
838 int
839 parse_opt_image(char ch, char *arg)
840 {
841         char buf[MAX_ARG_LEN];
842         char *argv[MAX_ARG_COUNT];
843         int argc;
844         char *p;
845         struct image_desc *desc = NULL;
846         int i;
847
848         switch (ch) {
849         case 'K':
850                 if (kernel_image.file_name) {
851                         WARN("only one kernel option allowed");
852                         break;
853                 }
854                 desc = &kernel_image;
855                 break;
856         case 'F':
857                 if (fs_image.file_name) {
858                         WARN("only one fs option allowed");
859                         break;
860                 }
861                 desc = &fs_image;
862                 break;
863         }
864
865         if (!desc)
866                 return ERR_FATAL;
867
868         argc = parse_arg(arg, buf, argv);
869
870         i = 0;
871         p = argv[i++];
872         if (!is_empty_arg(p)) {
873                 desc->file_name = strdup(p);
874                 if (desc->file_name == NULL) {
875                         ERR("not enough memory");
876                         return ERR_FATAL;
877                 }
878         } else {
879                 ERR("no file specified for option %c", ch);
880                 return ERR_FATAL;
881         }
882
883         return 0;
884 }
885
886
887 int
888 process_images(void)
889 {
890         struct image_desc *desc;
891         uint32_t offs = 0;
892         int i;
893         int res;
894
895         kernel_image.out_size = board->max_kernel_size;
896         kernel_image.padc = DEFAULT_PADC;
897         res = image_stat_file(&kernel_image);
898         if (res)
899                 return res;
900
901         if (!fs_image.file_name)
902                 return 0;
903
904         fs_image.out_size = board->max_fs_size;
905         fs_image.padc = DEFAULT_PADC;
906         res = image_stat_file(&fs_image);
907         if (res)
908                 return res;
909
910         return 0;
911 }
912
913
914 int
915 main(int argc, char *argv[])
916 {
917         int optinvalid = 0;   /* flag for invalid option */
918         int c;
919         int res = ERR_FATAL;
920
921         FILE *outfile;
922
923         progname=basename(argv[0]);
924
925         opterr = 0;  /* could not print standard getopt error messages */
926         while ( 1 ) {
927                 optinvalid = 0;
928
929                 c = getopt(argc, argv, "B:C:dhK:r:vw:x:");
930                 if (c == -1)
931                         break;
932
933                 switch (c) {
934                 case 'B':
935                         optinvalid = parse_opt_board(c,optarg);
936                         break;
937                 case 'd':
938                         invalid_causes_error = 0;
939                         break;
940                 case 'C':
941                 case 'K':
942                         optinvalid = parse_opt_image(c,optarg);
943                         break;
944                 case 'k':
945                         keep_invalid_images = 1;
946                         break;
947                 case 'v':
948                         verblevel++;
949                         break;
950                 case 'h':
951                         usage(EXIT_SUCCESS);
952                         break;
953                 default:
954                         optinvalid = 1;
955                         break;
956                 }
957                 if (optinvalid != 0 ){
958                         ERR("invalid option: -%c", optopt);
959                         goto out;
960                 }
961         }
962
963         if (board == NULL) {
964                 ERR("no board specified");
965                 goto out;
966         }
967
968         if (optind == argc) {
969                 ERR("no output file specified");
970                 goto out;
971         }
972
973         ofname = argv[optind++];
974
975         if (optind < argc) {
976                 ERR("invalid option: %s", argv[optind]);
977                 goto out;
978         }
979
980         res = process_images();
981         if (res == ERR_FATAL)
982                 goto out;
983
984         if (res == ERR_INVALID_IMAGE) {
985                 if (invalid_causes_error)
986                         res = ERR_FATAL;
987
988                 if (keep_invalid_images == 0) {
989                         WARN("generation of invalid images disabled", ofname);
990                         goto out;
991                 }
992
993                 WARN("generating invalid image", ofname);
994         }
995
996         outfile = fopen(ofname, "w");
997         if (outfile == NULL) {
998                 ERRS("could not open \"%s\" for writing", ofname);
999                 res = ERR_FATAL;
1000                 goto out;
1001         }
1002
1003         if (write_out_header(outfile) != 0) {
1004                 res = ERR_FATAL;
1005                 goto out_flush;
1006         }
1007
1008         if (write_out_images(outfile) != 0) {
1009                 res = ERR_FATAL;
1010                 goto out_flush;
1011         }
1012
1013         if (write_out_header(outfile) != 0) {
1014                 res = ERR_FATAL;
1015                 goto out_flush;
1016         }
1017
1018         DBG(1,"Image file %s completed.", ofname);
1019
1020 out_flush:
1021         fflush(outfile);
1022         fclose(outfile);
1023         if (res == ERR_FATAL) {
1024                 unlink(ofname);
1025         }
1026 out:
1027         if (res == ERR_FATAL)
1028                 return EXIT_FAILURE;
1029
1030         return EXIT_SUCCESS;
1031 }