mkwrggimg.c 5.6 KB

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