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