Root/tools/firmware-utils/src/mkcasfw.c

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

Archive Download this file



interactive