1/* 2 * Copyright (C) 2009 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> /* for unlink() */ 15#include <libgen.h> 16#include <getopt.h> /* for getopt() */ 17#include <stdarg.h> 18#include <errno.h> 19#include <sys/stat.h> 20 21#include "sha1.h" 22 23#if (__BYTE_ORDER == __BIG_ENDIAN) 24# define HOST_TO_BE32(x) (x) 25# define BE32_TO_HOST(x) (x) 26#else 27# define HOST_TO_BE32(x) bswap_32(x) 28# define BE32_TO_HOST(x) bswap_32(x) 29#endif 30 31 32struct planex_hdr { 33 uint8_t sha1sum[20]; 34 char version[8]; 35 uint8_t unk1[2]; 36 uint32_t datalen; 37} __attribute__ ((packed)); 38 39struct board_info { 40 char *id; 41 uint32_t seed; 42 uint8_t unk[2]; 43 uint32_t datalen; 44}; 45 46/* 47 * Globals 48 */ 49static char *ifname; 50static char *progname; 51static char *ofname; 52static char *version = "1.00.00"; 53 54static char *board_id; 55static struct board_info *board; 56 57static struct board_info boards[] = { 58 { 59 .id = "MZK-W04NU", 60 .seed = 2, 61 .unk = {0x04, 0x08}, 62 .datalen = 0x770000, 63 }, { 64 .id = "MZK-W300NH", 65 .seed = 4, 66 .unk = {0x00, 0x00}, 67 .datalen = 0x770000, 68 }, { 69 /* terminating entry */ 70 } 71}; 72 73/* 74 * Message macros 75 */ 76#define ERR(fmt, ...) do { \ 77 fflush(0); \ 78 fprintf(stderr, "[%s] *** error: " fmt "\n", \ 79 progname, ## __VA_ARGS__ ); \ 80} while (0) 81 82#define ERRS(fmt, ...) do { \ 83 int save = errno; \ 84 fflush(0); \ 85 fprintf(stderr, "[%s] *** error: " fmt "\n", \ 86 progname, ## __VA_ARGS__, strerror(save)); \ 87} while (0) 88 89static struct board_info *find_board(char *id) 90{ 91 struct board_info *ret; 92 struct board_info *board; 93 94 ret = NULL; 95 for (board = boards; board->id != NULL; board++){ 96 if (strcasecmp(id, board->id) == 0) { 97 ret = board; 98 break; 99 } 100 }; 101 102 return ret; 103} 104 105void usage(int status) 106{ 107 FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout; 108 struct board_info *board; 109 110 fprintf(stream, "Usage: %s [OPTIONS...]\n", progname); 111 fprintf(stream, 112"\n" 113"Options:\n" 114" -B <board> create image for the board specified with <board>\n" 115" -i <file> read input from the file <file>\n" 116" -o <file> write output to the file <file>\n" 117" -v <version> set image version to <version>\n" 118" -h show this screen\n" 119 ); 120 121 exit(status); 122} 123 124int main(int argc, char *argv[]) 125{ 126 int res = EXIT_FAILURE; 127 int buflen; 128 int err; 129 struct stat st; 130 char *buf; 131 struct planex_hdr *hdr; 132 sha1_context ctx; 133 uint32_t seed; 134 135 FILE *outfile, *infile; 136 137 progname = basename(argv[0]); 138 139 while ( 1 ) { 140 int c; 141 142 c = getopt(argc, argv, "B:i:o:v:h"); 143 if (c == -1) 144 break; 145 146 switch (c) { 147 case 'B': 148 board_id = optarg; 149 break; 150 case 'i': 151 ifname = optarg; 152 break; 153 case 'o': 154 ofname = optarg; 155 break; 156 case 'v': 157 version = optarg; 158 break; 159 case 'h': 160 usage(EXIT_SUCCESS); 161 break; 162 default: 163 usage(EXIT_FAILURE); 164 break; 165 } 166 } 167 168 if (board_id == NULL) { 169 ERR("no board specified"); 170 goto err; 171 } 172 173 board = find_board(board_id); 174 if (board == NULL) { 175 ERR("unknown board '%s'", board_id); 176 goto err; 177 }; 178 179 if (ifname == NULL) { 180 ERR("no input file specified"); 181 goto err; 182 } 183 184 if (ofname == NULL) { 185 ERR("no output file specified"); 186 goto err; 187 } 188 189 err = stat(ifname, &st); 190 if (err){ 191 ERRS("stat failed on %s", ifname); 192 goto err; 193 } 194 195 if (st.st_size > board->datalen) { 196 ERR("file '%s' is too big - max size: 0x%08X (exceeds %lu bytes)\n", 197 ifname, board->datalen, st.st_size - board->datalen); 198 goto err; 199 } 200 201 buflen = board->datalen + 0x10000; 202 buf = malloc(buflen); 203 if (!buf) { 204 ERR("no memory for buffer\n"); 205 goto err; 206 } 207 208 memset(buf, 0xff, buflen); 209 hdr = (struct planex_hdr *)buf; 210 211 hdr->datalen = HOST_TO_BE32(board->datalen); 212 hdr->unk1[0] = board->unk[0]; 213 hdr->unk1[1] = board->unk[1]; 214 215 snprintf(hdr->version, sizeof(hdr->version), "%s", version); 216 217 infile = fopen(ifname, "r"); 218 if (infile == NULL) { 219 ERRS("could not open \"%s\" for reading", ifname); 220 goto err_free; 221 } 222 223 errno = 0; 224 fread(buf + sizeof(*hdr), st.st_size, 1, infile); 225 if (errno != 0) { 226 ERRS("unable to read from file %s", ifname); 227 goto err_close_in; 228 } 229 230 seed = HOST_TO_BE32(board->seed); 231 sha1_starts(&ctx); 232 sha1_update(&ctx, (uchar *) &seed, sizeof(seed)); 233 sha1_update(&ctx, buf + sizeof(*hdr), board->datalen); 234 sha1_finish(&ctx, hdr->sha1sum); 235 236 outfile = fopen(ofname, "w"); 237 if (outfile == NULL) { 238 ERRS("could not open \"%s\" for writing", ofname); 239 goto err_close_in; 240 } 241 242 errno = 0; 243 fwrite(buf, buflen, 1, outfile); 244 if (errno) { 245 ERRS("unable to write to file %s", ofname); 246 goto err_close_out; 247 } 248 249 res = EXIT_SUCCESS; 250 251 out_flush: 252 fflush(outfile); 253 254 err_close_out: 255 fclose(outfile); 256 if (res != EXIT_SUCCESS) { 257 unlink(ofname); 258 } 259 260 err_close_in: 261 fclose(infile); 262 263 err_free: 264 free(buf); 265 266 err: 267 return res; 268} 269 270