OpenWrt – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | #include <stdio.h> |
2 | #include <stdint.h> |
||
3 | #include <stdlib.h> |
||
4 | #include <unistd.h> |
||
5 | #include <libgen.h> |
||
6 | #include <stdarg.h> |
||
7 | #include <getopt.h> |
||
8 | #include <string.h> |
||
9 | #include <errno.h> |
||
10 | |||
11 | #include <netinet/in.h> // htonl |
||
12 | |||
13 | // Usage: mkdapimg [-p] [-m <model>] -s <sig> -i <input> -o <output> |
||
14 | // |
||
15 | // e.g.: mkdapimg -s RT3052-AP-DAP1350-3 -i sysupgrade.bin -o factory.bin |
||
16 | // |
||
17 | // If the model string <model> is not given, we will assume that |
||
18 | // the leading characters upto the first "-" is the model. |
||
19 | // |
||
20 | // The "-p" (patch) option is used to patch the exisiting image with the |
||
21 | // specified model and signature. |
||
22 | // The "-x" (fix) option will recalculate the payload size and checksum |
||
23 | // during the patch mode operation. |
||
24 | |||
25 | // The img_hdr_struct was taken from the D-Link SDK: |
||
26 | // DAP-1350_A1_FW1.11NA_GPL/GPL_Source_Code/Uboot/DAP-1350/httpd/header.h |
||
27 | |||
28 | #define MAX_MODEL_NAME_LEN 20 |
||
29 | #define MAX_SIG_LEN 30 |
||
30 | #define MAX_REGION_LEN 4 |
||
31 | #define MAX_VERSION_LEN 12 |
||
32 | |||
33 | struct img_hdr_struct { |
||
34 | uint32_t checksum; |
||
35 | char model[MAX_MODEL_NAME_LEN]; |
||
36 | char sig[MAX_SIG_LEN]; |
||
37 | uint8_t partition; |
||
38 | uint8_t hdr_len; |
||
39 | uint8_t rsv1; |
||
40 | uint8_t rsv2; |
||
41 | uint32_t flash_byte_cnt; |
||
42 | } imghdr ; |
||
43 | |||
44 | char *progname; |
||
45 | |||
46 | void |
||
47 | perrexit(int code, char *msg) |
||
48 | { |
||
49 | fprintf(stderr, "%s: %s: %s\n", progname, msg, strerror(errno)); |
||
50 | exit(code); |
||
51 | } |
||
52 | |||
53 | void |
||
54 | usage() |
||
55 | { |
||
56 | fprintf(stderr, "usage: %s [-p] [-m model] [-r region] [-v version] -s signature -i input -o output\n", progname); |
||
57 | exit(1); |
||
58 | } |
||
59 | |||
60 | int |
||
61 | main(int ac, char *av[]) |
||
62 | { |
||
63 | char model[MAX_MODEL_NAME_LEN+1]; |
||
64 | char signature[MAX_SIG_LEN+1]; |
||
65 | char region[MAX_REGION_LEN+1]; |
||
66 | char version[MAX_VERSION_LEN+1]; |
||
67 | int patchmode = 0; |
||
68 | int fixmode = 0; |
||
69 | int have_regionversion = 0; |
||
70 | |||
71 | FILE *ifile, *ofile; |
||
72 | int c; |
||
73 | uint32_t cksum; |
||
74 | uint32_t bcnt; |
||
75 | |||
76 | progname = basename(av[0]); |
||
77 | memset(model, 0, sizeof(model)); |
||
78 | memset(signature, 0, sizeof(signature)); |
||
79 | memset(region, 0, sizeof(region)); |
||
80 | memset(version, 0, sizeof(version)); |
||
81 | |||
82 | while ( 1 ) { |
||
83 | int c; |
||
84 | |||
85 | c = getopt(ac, av, "pxm:r:v:s:i:o:"); |
||
86 | if (c == -1) |
||
87 | break; |
||
88 | |||
89 | switch (c) { |
||
90 | case 'p': |
||
91 | patchmode = 1; |
||
92 | break; |
||
93 | case 'x': |
||
94 | fixmode = 1; |
||
95 | break; |
||
96 | case 'm': |
||
97 | if (strlen(optarg) > MAX_MODEL_NAME_LEN) { |
||
98 | fprintf(stderr, "%s: model name exceeds %d chars\n", |
||
99 | progname, MAX_MODEL_NAME_LEN); |
||
100 | exit(1); |
||
101 | } |
||
102 | strcpy(model, optarg); |
||
103 | break; |
||
104 | case 'r': |
||
105 | if (strlen(optarg) > MAX_REGION_LEN) { |
||
106 | fprintf(stderr, "%s: region exceeds %d chars\n", |
||
107 | progname, MAX_REGION_LEN); |
||
108 | exit(1); |
||
109 | } |
||
110 | have_regionversion = 1; |
||
111 | strcpy(region, optarg); |
||
112 | break; |
||
113 | case 'v': |
||
114 | if (strlen(optarg) > MAX_VERSION_LEN) { |
||
115 | fprintf(stderr, "%s: version exceeds %d chars\n", |
||
116 | progname, MAX_VERSION_LEN); |
||
117 | exit(1); |
||
118 | } |
||
119 | have_regionversion = 1; |
||
120 | strcpy(version, optarg); |
||
121 | break; |
||
122 | case 's': |
||
123 | if (strlen(optarg) > MAX_SIG_LEN) { |
||
124 | fprintf(stderr, "%s: signature exceeds %d chars\n", |
||
125 | progname, MAX_SIG_LEN); |
||
126 | exit(1); |
||
127 | } |
||
128 | strcpy(signature, optarg); |
||
129 | break; |
||
130 | case 'i': |
||
131 | if ((ifile = fopen(optarg, "r")) == NULL) |
||
132 | perrexit(1, optarg); |
||
133 | break; |
||
134 | case 'o': |
||
135 | if ((ofile = fopen(optarg, "w")) == NULL) |
||
136 | perrexit(1, optarg); |
||
137 | break; |
||
138 | default: |
||
139 | usage(); |
||
140 | } |
||
141 | } |
||
142 | |||
143 | if (signature[0] == 0 || ifile == NULL || ofile == NULL) { |
||
144 | usage(); |
||
145 | } |
||
146 | |||
147 | if (model[0] == 0) { |
||
148 | char *p = strchr(signature, '-'); |
||
149 | if (p == NULL) { |
||
150 | fprintf(stderr, "%s: model name unknown\n", progname); |
||
151 | exit(1); |
||
152 | } |
||
153 | if (p - signature > MAX_MODEL_NAME_LEN) { |
||
154 | *p = 0; |
||
155 | fprintf(stderr, "%s: auto model name failed, string %s too long\n", progname, signature); |
||
156 | exit(1); |
||
157 | } |
||
158 | strncpy(model, signature, p - signature); |
||
159 | } |
||
160 | |||
161 | if (patchmode) { |
||
162 | if (fread(&imghdr, sizeof(imghdr), 1, ifile) < 0) |
||
163 | perrexit(2, "fread on input"); |
||
164 | } |
||
165 | |||
166 | for (bcnt = 0, cksum = 0 ; (c = fgetc(ifile)) != EOF ; bcnt++) |
||
167 | cksum += c & 0xff; |
||
168 | |||
169 | if (fseek(ifile, patchmode ? sizeof(imghdr) : 0, SEEK_SET) < 0) |
||
170 | perrexit(2, "fseek on input"); |
||
171 | |||
172 | if (patchmode == 0) { |
||
173 | // Fill in the header |
||
174 | memset(&imghdr, 0, sizeof(imghdr)); |
||
175 | imghdr.checksum = htonl(cksum); |
||
176 | imghdr.partition = 0 ; // don't care? |
||
177 | imghdr.hdr_len = sizeof(imghdr); |
||
178 | if (have_regionversion) { |
||
179 | imghdr.hdr_len += MAX_REGION_LEN; |
||
180 | imghdr.hdr_len += MAX_VERSION_LEN; |
||
181 | } |
||
182 | imghdr.flash_byte_cnt = htonl(bcnt); |
||
183 | } else { |
||
184 | if (ntohl(imghdr.checksum) != cksum) { |
||
185 | fprintf(stderr, "%s: patch mode, checksum mismatch\n", |
||
186 | progname); |
||
187 | if (fixmode) { |
||
188 | fprintf(stderr, "%s: fixing\n", progname); |
||
189 | imghdr.checksum = htonl(cksum); |
||
190 | } else |
||
191 | exit(3); |
||
192 | } else if (ntohl(imghdr.flash_byte_cnt) != bcnt) { |
||
193 | fprintf(stderr, "%s: patch mode, size mismatch\n", |
||
194 | progname); |
||
195 | if (fixmode) { |
||
196 | fprintf(stderr, "%s: fixing\n", progname); |
||
197 | imghdr.flash_byte_cnt = htonl(bcnt); |
||
198 | } else |
||
199 | exit(3); |
||
200 | } |
||
201 | } |
||
202 | |||
203 | strncpy(imghdr.model, model, MAX_MODEL_NAME_LEN); |
||
204 | strncpy(imghdr.sig, signature, MAX_SIG_LEN); |
||
205 | |||
206 | if (fwrite(&imghdr, sizeof(imghdr), 1, ofile) < 0) |
||
207 | perrexit(2, "fwrite header on output"); |
||
208 | if (have_regionversion) { |
||
209 | if (fwrite(®ion, MAX_REGION_LEN, 1, ofile) < 0) |
||
210 | perrexit(2, "fwrite header on output"); |
||
211 | if (fwrite(&version, MAX_VERSION_LEN, 1, ofile) < 0) |
||
212 | perrexit(2, "fwrite header on output"); |
||
213 | } |
||
214 | |||
215 | while ((c = fgetc(ifile)) != EOF) { |
||
216 | if (fputc(c, ofile) == EOF) |
||
217 | perrexit(2, "fputc on output"); |
||
218 | } |
||
219 | |||
220 | if (ferror(ifile)) |
||
221 | perrexit(2, "fgetc on input"); |
||
222 | |||
223 | |||
224 | fclose(ofile); |
||
225 | fclose(ifile); |
||
226 | } |