Root/tools/firmware-utils/src/buffalo-tag.c

1/*
2 * Copyright (C) 2009-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 <libgen.h>
15#include <getopt.h> /* for getopt() */
16#include <netinet/in.h>
17
18#include "buffalo-lib.h"
19
20#define ERR(fmt, ...) do { \
21    fflush(0); \
22    fprintf(stderr, "[%s] *** error: " fmt "\n", \
23            progname, ## __VA_ARGS__ ); \
24} while (0)
25
26static char *region_table[] = {
27    "JP", "US", "EU", "AP", "TW", "KR"
28};
29
30#define MAX_INPUT_FILES 2
31
32static char *progname;
33static char *ifname[MAX_INPUT_FILES];
34static ssize_t fsize[MAX_INPUT_FILES];
35static int num_files;
36static char *ofname;
37static char *product;
38static char *brand;
39static char *language;
40static char *hwver;
41static char *platform;
42static int flag;
43static char *major;
44static char *minor = "1.01";
45static int skipcrc;
46static uint32_t base1;
47static uint32_t base2;
48static char *region_code;
49static uint32_t region_mask;
50static int num_regions;
51
52void usage(int status)
53{
54    FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
55
56    fprintf(stream, "Usage: %s [OPTIONS...]\n", progname);
57    fprintf(stream,
58"\n"
59"Options:\n"
60" -a <platform> set platform to <platform>\n"
61" -b <brand> set brand to <brand>\n"
62" -c <base1>\n"
63" -d <base2>\n"
64" -f <flag> set flag to <flag>\n"
65" -i <file> read input from the file <file>\n"
66" -l <language> set language to <language>\n"
67" -m <version> set minor version to <version>\n"
68" -o <file> write output to the file <file>\n"
69" -p <product> set product to <product>\n"
70" -r <region> set image region to <region>\n"
71" valid regions: JP, US, EU, AP, TW, KR, M_\n"
72" -s skip CRC calculation\n"
73" -v <version> set major version to <version>\n"
74" -w <version> set harwdware version to <version>\n"
75" -h show this screen\n"
76    );
77
78    exit(status);
79}
80
81static int check_params(void)
82{
83
84#define CHECKSTR(_var, _name, _len) do { \
85    if ((_var) == NULL) { \
86        ERR("no %s specified", (_name)); \
87        return -1; \
88    } \
89    if ((_len) > 0 && \
90        strlen((_var)) > ((_len) - 1)) { \
91        ERR("%s is too long", (_name)); \
92        return -1; \
93    } \
94} while (0)
95
96    if (num_files == 0)
97        ERR("no input files specified");
98
99    CHECKSTR(ofname, "output file", 0);
100    CHECKSTR(brand, "brand", TAG_BRAND_LEN);
101    CHECKSTR(product, "product", TAG_PRODUCT_LEN);
102    CHECKSTR(platform, "platform", TAG_PLATFORM_LEN);
103    CHECKSTR(major, "major version", TAG_VERSION_LEN);
104    CHECKSTR(minor, "minor version", TAG_VERSION_LEN);
105    CHECKSTR(language, "language", TAG_LANGUAGE_LEN);
106
107    if (hwver)
108        CHECKSTR(hwver, "hardware version", 2);
109
110    if (num_regions == 0) {
111        ERR("no region code specified");
112        return -1;
113    }
114
115    return 0;
116
117#undef CHECKSTR
118}
119
120static int process_region(char *reg)
121{
122    int i;
123
124    if (strlen(reg) != 2) {
125        ERR("invalid region code '%s'", reg);
126        return -1;
127    }
128
129    if (strcmp(reg, "M_") == 0) {
130        region_code = reg;
131        region_mask |= ~0;
132        num_regions = 32;
133        return 0;
134    }
135
136    for (i = 0; i < ARRAY_SIZE(region_table); i++)
137        if (strcmp(reg, region_table[i]) == 0) {
138            region_code = reg;
139            region_mask |= 1 << i;
140            num_regions++;
141            return 0;
142        }
143
144    ERR("unknown region code '%s'", reg);
145    return -1;
146}
147
148static int process_ifname(char *name)
149{
150    if (num_files >= ARRAY_SIZE(ifname)) {
151        ERR("too many input files specified");
152        return -1;
153    }
154
155    ifname[num_files++] = name;
156    return 0;
157}
158
159static void fixup_tag(unsigned char *buf, ssize_t buflen)
160{
161    struct buffalo_tag *tag = (struct buffalo_tag *) buf;
162
163    memset(tag, '\0', sizeof(*tag));
164
165    memcpy(tag->brand, brand, strlen(brand));
166    memcpy(tag->product, product, strlen(product));
167    memcpy(tag->platform, platform, strlen(platform));
168    memcpy(tag->ver_major, major, strlen(major));
169    memcpy(tag->ver_minor, minor, strlen(minor));
170    memcpy(tag->language, language, strlen(language));
171
172    if (num_regions > 1) {
173        tag->region_code[0] = 'M';
174        tag->region_code[1] = '_';
175        tag->region_mask = htonl(region_mask);
176    } else {
177        memcpy(tag->region_code, region_code, 2);
178    }
179
180    tag->len = htonl(buflen);
181    tag->data_len = htonl(fsize[0]);
182    tag->base1 = htonl(base1);
183    tag->base2 = htonl(base2);
184    tag->flag = flag;
185
186    if (hwver) {
187        memcpy(tag->hwv, "hwv", 3);
188        memcpy(tag->hwv_val, hwver, strlen(hwver));
189    }
190
191    if (!skipcrc)
192        tag->crc = htonl(buffalo_crc(buf, buflen));
193}
194
195static void fixup_tag2(unsigned char *buf, ssize_t buflen)
196{
197    struct buffalo_tag2 *tag = (struct buffalo_tag2 *) buf;
198
199    memset(tag, '\0', sizeof(*tag));
200
201    memcpy(tag->brand, brand, strlen(brand));
202    memcpy(tag->product, product, strlen(product));
203    memcpy(tag->platform, platform, strlen(platform));
204    memcpy(tag->ver_major, major, strlen(major));
205    memcpy(tag->ver_minor, minor, strlen(minor));
206    memcpy(tag->language, language, strlen(language));
207
208    if (num_regions > 1) {
209        tag->region_code[0] = 'M';
210        tag->region_code[1] = '_';
211        tag->region_mask = htonl(region_mask);
212    } else {
213        memcpy(tag->region_code, region_code, 2);
214    }
215
216    tag->total_len = htonl(buflen);
217    tag->len1 = htonl(fsize[0]);
218    tag->len2 = htonl(fsize[1]);
219    tag->flag = flag;
220
221    if (hwver) {
222        memcpy(tag->hwv, "hwv", 3);
223        memcpy(tag->hwv_val, hwver, strlen(hwver));
224    }
225
226    if (!skipcrc)
227        tag->crc = htonl(buffalo_crc(buf, buflen));
228}
229
230static int tag_file(void)
231{
232    unsigned char *buf;
233    ssize_t offset;
234    ssize_t hdrlen;
235    ssize_t buflen;
236    int err;
237    int ret = -1;
238    int i;
239
240    if (num_files == 1)
241        hdrlen = sizeof(struct buffalo_tag);
242    else
243        hdrlen = sizeof(struct buffalo_tag2);
244
245    buflen = hdrlen;
246
247    for (i = 0; i < num_files; i++) {
248        fsize[i] = get_file_size(ifname[i]);
249        if (fsize[i] < 0) {
250            ERR("unable to get size of '%s'", ifname[i]);
251            goto out;
252        }
253        buflen += fsize[i];
254    }
255
256    buf = malloc(buflen);
257    if (!buf) {
258        ERR("no memory for buffer\n");
259        goto out;
260    }
261
262    offset = hdrlen;
263    for (i = 0; i < num_files; i++) {
264        err = read_file_to_buf(ifname[i], buf + offset, fsize[i]);
265        if (err) {
266            ERR("unable to read from file '%s'", ifname[i]);
267            goto free_buf;
268        }
269
270        offset += fsize[i];
271    }
272
273    if (num_files == 1)
274        fixup_tag(buf, buflen);
275    else
276        fixup_tag2(buf, buflen);
277
278    err = write_buf_to_file(ofname, buf, buflen);
279    if (err) {
280        ERR("unable to write to file '%s'", ofname);
281        goto free_buf;
282    }
283
284    ret = 0;
285
286free_buf:
287    free(buf);
288out:
289    return ret;
290}
291
292int main(int argc, char *argv[])
293{
294    int res = EXIT_FAILURE;
295    int err;
296
297    progname = basename(argv[0]);
298
299    while ( 1 ) {
300        int c;
301
302        c = getopt(argc, argv, "a:b:c:d:f:hi:l:m:o:p:r:sv:w:");
303        if (c == -1)
304            break;
305
306        switch (c) {
307        case 'a':
308            platform = optarg;
309            break;
310        case 'b':
311            brand = optarg;
312            break;
313        case 'c':
314            base1 = strtoul(optarg, NULL, 16);
315            break;
316        case 'd':
317            base2 = strtoul(optarg, NULL, 16);
318            break;
319        case 'f':
320            flag = strtoul(optarg, NULL, 2);
321            break;
322        case 'i':
323            err = process_ifname(optarg);
324            if (err)
325                goto out;
326            break;
327        case 'l':
328            language = optarg;
329            break;
330        case 'm':
331            minor = optarg;
332            break;
333        case 'o':
334            ofname = optarg;
335            break;
336        case 'p':
337            product = optarg;
338            break;
339        case 'r':
340            err = process_region(optarg);
341            if (err)
342                goto out;
343            break;
344        case 's':
345            skipcrc = 1;
346            break;
347        case 'v':
348            major = optarg;
349            break;
350        case 'w':
351            hwver = optarg;
352            break;
353        case 'h':
354            usage(EXIT_SUCCESS);
355            break;
356        default:
357            usage(EXIT_FAILURE);
358            break;
359        }
360    }
361
362    err = check_params();
363    if (err)
364        goto out;
365
366    err = tag_file();
367    if (err)
368        goto out;
369
370    res = EXIT_SUCCESS;
371
372out:
373    return res;
374}
375

Archive Download this file



interactive