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

1/*
2 * Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 2 as published
6 * by the Free Software Foundation.
7 *
8 */
9
10#include <stdio.h>
11#include <stdlib.h>
12#include <stdint.h>
13#include <string.h>
14#include <unistd.h>
15#include <libgen.h>
16#include <getopt.h>
17#include <stdarg.h>
18#include <errno.h>
19#include <sys/stat.h>
20
21#include "md5.h"
22
23#define ERR(fmt, ...) do { \
24    fflush(0); \
25    fprintf(stderr, "[%s] *** error: " fmt "\n", \
26            progname, ## __VA_ARGS__ ); \
27} while (0)
28
29#define ERRS(fmt, ...) do { \
30    int save = errno; \
31    fflush(0); \
32    fprintf(stderr, "[%s] *** error: " fmt ", %s\n", \
33            progname, ## __VA_ARGS__, strerror(save)); \
34} while (0)
35
36#define WRG_MAGIC 0x20040220
37
38struct wrg_header {
39    char signature[32];
40    uint32_t magic1;
41    uint32_t magic2;
42    uint32_t size;
43    uint32_t offset;
44    char devname[32];
45    char digest[16];
46} __attribute__ ((packed));
47
48static char *progname;
49static char *ifname;
50static char *ofname;
51static char *signature;
52static char *dev_name;
53static uint32_t offset;
54static int big_endian;
55
56void usage(int status)
57{
58    FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
59
60    fprintf(stream, "Usage: %s [OPTIONS...]\n", progname);
61    fprintf(stream,
62"\n"
63"Options:\n"
64" -b create image in big endian format\n"
65" -i <file> read input from the file <file>\n"
66" -d <name> set device name to <name>\n"
67" -o <file> write output to the file <file>\n"
68" -O <offset> set offset to <offset>\n"
69" -s <sig> set image signature to <sig>\n"
70" -h show this screen\n"
71    );
72
73    exit(status);
74}
75
76static void put_u32(void *data, uint32_t val)
77{
78    unsigned char *p = data;
79
80    if (big_endian) {
81        p[0] = (val >> 24) & 0xff;
82        p[1] = (val >> 16) & 0xff;
83        p[2] = (val >> 8) & 0xff;
84        p[3] = val & 0xff;
85    } else {
86        p[3] = (val >> 24) & 0xff;
87        p[2] = (val >> 16) & 0xff;
88        p[1] = (val >> 8) & 0xff;
89        p[0] = val & 0xff;
90    }
91}
92
93static void get_digest(struct wrg_header *header, char *data, int size)
94{
95    MD5_CTX ctx;
96
97    MD5_Init(&ctx);
98
99    MD5_Update(&ctx, (char *)&header->offset, sizeof(header->offset));
100    MD5_Update(&ctx, (char *)&header->devname, sizeof(header->devname));
101    MD5_Update(&ctx, data, size);
102
103    MD5_Final(header->digest, &ctx);
104}
105
106int main(int argc, char *argv[])
107{
108    struct wrg_header *header;
109    char *buf;
110    struct stat st;
111    int buflen;
112    int err;
113    int res = EXIT_FAILURE;
114
115    FILE *outfile, *infile;
116
117    progname = basename(argv[0]);
118
119    while ( 1 ) {
120        int c;
121
122        c = getopt(argc, argv, "bd:i:o:s:O:h");
123        if (c == -1)
124            break;
125
126        switch (c) {
127        case 'b':
128            big_endian = 1;
129            break;
130        case 'd':
131            dev_name = optarg;
132            break;
133        case 'i':
134            ifname = optarg;
135            break;
136        case 'o':
137            ofname = optarg;
138            break;
139        case 's':
140            signature = optarg;
141            break;
142        case 'O':
143            offset = strtoul(optarg, NULL, 0);
144            break;
145        case 'h':
146            usage(EXIT_SUCCESS);
147            break;
148
149        default:
150            usage(EXIT_FAILURE);
151            break;
152        }
153    }
154
155    if (signature == NULL) {
156        ERR("no signature specified");
157        goto err;
158    }
159
160    if (ifname == NULL) {
161        ERR("no input file specified");
162        goto err;
163    }
164
165    if (ofname == NULL) {
166        ERR("no output file specified");
167        goto err;
168    }
169
170    if (dev_name == NULL) {
171        ERR("no device name specified");
172        goto err;
173    }
174
175    err = stat(ifname, &st);
176    if (err){
177        ERRS("stat failed on %s", ifname);
178        goto err;
179    }
180
181    buflen = st.st_size + sizeof(struct wrg_header);
182    buf = malloc(buflen);
183    if (!buf) {
184        ERR("no memory for buffer\n");
185        goto err;
186    }
187
188    infile = fopen(ifname, "r");
189    if (infile == NULL) {
190        ERRS("could not open \"%s\" for reading", ifname);
191        goto err_free;
192    }
193
194    errno = 0;
195    fread(buf + sizeof(struct wrg_header), st.st_size, 1, infile);
196    if (errno != 0) {
197        ERRS("unable to read from file %s", ifname);
198        goto close_in;
199    }
200
201    header = (struct wrg_header *) buf;
202    memset(header, '\0', sizeof(struct wrg_header));
203
204    strncpy(header->signature, signature, sizeof(header->signature));
205    strncpy(header->devname, dev_name, sizeof(header->signature));
206    put_u32(&header->magic1, WRG_MAGIC);
207    put_u32(&header->magic2, WRG_MAGIC);
208    put_u32(&header->size, st.st_size);
209    put_u32(&header->offset, offset);
210
211    get_digest(header, buf + sizeof(struct wrg_header), st.st_size);
212
213    outfile = fopen(ofname, "w");
214    if (outfile == NULL) {
215        ERRS("could not open \"%s\" for writing", ofname);
216        goto close_in;
217    }
218
219    errno = 0;
220    fwrite(buf, buflen, 1, outfile);
221    if (errno) {
222        ERRS("unable to write to file %s", ofname);
223        goto close_out;
224    }
225
226    fflush(outfile);
227
228    res = EXIT_SUCCESS;
229
230close_out:
231    fclose(outfile);
232    if (res != EXIT_SUCCESS)
233        unlink(ofname);
234close_in:
235    fclose(infile);
236err_free:
237    free(buf);
238err:
239    return res;
240}
241

Archive Download this file



interactive