OpenWrt – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | /* |
2 | * Copyright (C) 2011 Vasilis Tsiligiannis <b_tsiligiannis@silverton.gr> |
||
3 | * |
||
4 | * This program is free software; you can redistribute it and/or |
||
5 | * modify it under the terms of the GNU General Public License as |
||
6 | * published by the Free Software Foundation; either version 2 of the |
||
7 | * License, or (at your option) any later version. |
||
8 | * |
||
9 | */ |
||
10 | |||
11 | #include <stdio.h> |
||
12 | #include <stdlib.h> |
||
13 | #include <string.h> |
||
14 | #include <libgen.h> |
||
15 | #include <getopt.h> |
||
16 | #include <errno.h> |
||
17 | #include <sys/stat.h> |
||
18 | #include <endian.h> /* for __BYTE_ORDER */ |
||
19 | |||
20 | #define FALSE 0 |
||
21 | #define TRUE 1 |
||
22 | |||
23 | #if (__BYTE_ORDER == __LITTLE_ENDIAN) |
||
24 | # define HOST_TO_LE16(x) (x) |
||
25 | # define HOST_TO_LE32(x) (x) |
||
26 | # define HOST_TO_BE16(x) bswap_16(x) |
||
27 | # define HOST_TO_BE32(x) bswap_32(x) |
||
28 | #else |
||
29 | # define HOST_TO_LE16(x) bswap_16(x) |
||
30 | # define HOST_TO_LE32(x) bswap_32(x) |
||
31 | # define HOST_TO_BE16(x) (x) |
||
32 | # define HOST_TO_BE32(x) (x) |
||
33 | #endif |
||
34 | |||
35 | struct header |
||
36 | { |
||
37 | unsigned char sign[4]; |
||
38 | unsigned int start; |
||
39 | unsigned int flash; |
||
40 | unsigned char model[4]; |
||
41 | unsigned int size; |
||
42 | } __attribute__ ((packed)); |
||
43 | |||
44 | struct finfo |
||
45 | { |
||
46 | char *name; |
||
47 | off_t size; |
||
48 | }; |
||
49 | |||
50 | struct buf |
||
51 | { |
||
52 | char *start; |
||
53 | size_t size; |
||
54 | }; |
||
55 | |||
56 | static char *progname; |
||
57 | static int force_be = FALSE; |
||
58 | |||
59 | static void usage(int status) |
||
60 | { |
||
61 | FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout; |
||
62 | |||
63 | fprintf(stream, "Usage: %s [OPTIONS...]\n", progname); |
||
64 | fprintf(stream, |
||
65 | "\n" |
||
66 | "Options:\n" |
||
67 | " -s <sig> set image signature to <sig>\n" |
||
68 | " -m <model> set model to <model>\n" |
||
69 | " -i <file> read input from file <file>\n" |
||
70 | " -o <file> write output to file <file>\n" |
||
71 | " -f <flash> set flash address to <flash>\n" |
||
72 | " -S <start> set start address to <start>\n" |
||
73 | " -b big-endianness mode\n"); |
||
74 | |||
75 | exit(status); |
||
76 | } |
||
77 | |||
78 | static int strtou32(char *arg, unsigned int *val) |
||
79 | { |
||
80 | char *endptr = NULL; |
||
81 | |||
82 | errno = 0; |
||
83 | *val = strtoul(arg, &endptr, 0); |
||
84 | if (errno || (endptr == arg) || (*endptr && (endptr != NULL))) { |
||
85 | return EXIT_SUCCESS; |
||
86 | } |
||
87 | |||
88 | return EXIT_FAILURE; |
||
89 | } |
||
90 | |||
91 | static unsigned short fwcsum (struct buf *buf) { |
||
92 | int i; |
||
93 | unsigned short ret = 0; |
||
94 | |||
95 | for (i = 0; i < buf->size / 2; i++) { |
||
96 | if (force_be == FALSE) |
||
97 | ret -= ((unsigned short *) buf->start)[i]; |
||
98 | else |
||
99 | ret -= HOST_TO_BE16(((unsigned short *) buf->start)[i]); |
||
100 | } |
||
101 | |||
102 | return ret; |
||
103 | } |
||
104 | |||
105 | static int fwread(struct finfo *finfo, struct buf *buf) |
||
106 | { |
||
107 | FILE *f; |
||
108 | |||
109 | f = fopen(finfo->name, "r"); |
||
110 | if (!f) { |
||
111 | fprintf(stderr, "could not open \"%s\" for reading\n", finfo->name); |
||
112 | usage(EXIT_FAILURE); |
||
113 | } |
||
114 | |||
115 | buf->size = fread(buf->start, 1, finfo->size, f); |
||
116 | if (buf->size != finfo->size) { |
||
117 | fprintf(stderr, "unable to read from file \"%s\"\n", finfo->name); |
||
118 | usage(EXIT_FAILURE); |
||
119 | } |
||
120 | |||
121 | fclose(f); |
||
122 | |||
123 | return EXIT_SUCCESS; |
||
124 | } |
||
125 | |||
126 | static int fwwrite(struct finfo *finfo, struct buf *buf) |
||
127 | { |
||
128 | FILE *f; |
||
129 | |||
130 | f = fopen(finfo->name, "w"); |
||
131 | if (!f) { |
||
132 | fprintf(stderr, "could not open \"%s\" for writing\n", finfo->name); |
||
133 | usage(EXIT_FAILURE); |
||
134 | } |
||
135 | |||
136 | buf->size = fwrite(buf->start, 1, finfo->size, f); |
||
137 | if (buf->size != finfo->size) { |
||
138 | fprintf(stderr, "unable to write to file \"%s\"\n", finfo->name); |
||
139 | usage(EXIT_FAILURE); |
||
140 | } |
||
141 | |||
142 | fclose(f); |
||
143 | |||
144 | return EXIT_SUCCESS; |
||
145 | } |
||
146 | |||
147 | int main(int argc, char **argv) |
||
148 | { |
||
149 | struct stat st; |
||
150 | struct header header; |
||
151 | struct buf ibuf, obuf; |
||
152 | struct finfo ifinfo, ofinfo; |
||
153 | unsigned short csum; |
||
154 | int c; |
||
155 | |||
156 | ifinfo.name = ofinfo.name = NULL; |
||
157 | header.flash = header.size = header.start = 0; |
||
158 | progname = basename(argv[0]); |
||
159 | |||
160 | while((c = getopt(argc, argv, "i:o:m:s:f:S:h:b")) != -1) { |
||
161 | switch (c) { |
||
162 | case 'i': |
||
163 | ifinfo.name = optarg; |
||
164 | break; |
||
165 | case 'o': |
||
166 | ofinfo.name = optarg; |
||
167 | break; |
||
168 | case 'm': |
||
169 | if (strlen(optarg) != 4) { |
||
170 | fprintf(stderr, "model must be 4 characters long\n"); |
||
171 | usage(EXIT_FAILURE); |
||
172 | } |
||
173 | memcpy(header.model, optarg, 4); |
||
174 | break; |
||
175 | case 's': |
||
176 | if (strlen(optarg) != 4) { |
||
177 | fprintf(stderr, "signature must be 4 characters long\n"); |
||
178 | usage(EXIT_FAILURE); |
||
179 | } |
||
180 | memcpy(header.sign, optarg, 4); |
||
181 | break; |
||
182 | case 'h': |
||
183 | usage(EXIT_SUCCESS); |
||
184 | break; |
||
185 | case 'f': |
||
186 | if (!strtou32(optarg, &header.flash)) { |
||
187 | fprintf(stderr, "invalid flash address specified\n"); |
||
188 | usage(EXIT_FAILURE); |
||
189 | } |
||
190 | break; |
||
191 | case 'S': |
||
192 | if (!strtou32(optarg, &header.start)) { |
||
193 | fprintf(stderr, "invalid start address specified\n"); |
||
194 | usage(EXIT_FAILURE); |
||
195 | } |
||
196 | break; |
||
197 | case 'b': |
||
198 | force_be = TRUE; |
||
199 | break; |
||
200 | default: |
||
201 | usage(EXIT_FAILURE); |
||
202 | break; |
||
203 | } |
||
204 | } |
||
205 | |||
206 | if (ifinfo.name == NULL) { |
||
207 | fprintf(stderr, "no input file specified\n"); |
||
208 | usage(EXIT_FAILURE); |
||
209 | } |
||
210 | |||
211 | if (ofinfo.name == NULL) { |
||
212 | fprintf(stderr, "no output file specified\n"); |
||
213 | usage(EXIT_FAILURE); |
||
214 | } |
||
215 | |||
216 | if (stat(ifinfo.name, &st)) { |
||
217 | fprintf(stderr, "stat failed on %s\n", ifinfo.name); |
||
218 | usage(EXIT_FAILURE); |
||
219 | } |
||
220 | |||
221 | if (header.sign == NULL) { |
||
222 | fprintf(stderr, "no signature specified\n"); |
||
223 | usage(EXIT_FAILURE); |
||
224 | } |
||
225 | |||
226 | if (header.model == NULL) { |
||
227 | fprintf(stderr, "no model specified\n"); |
||
228 | usage(EXIT_FAILURE); |
||
229 | } |
||
230 | |||
231 | if (!header.flash) { |
||
232 | fprintf(stderr, "no flash address specified\n"); |
||
233 | usage(EXIT_FAILURE); |
||
234 | } |
||
235 | |||
236 | if (!header.start) { |
||
237 | fprintf(stderr, "no start address specified\n"); |
||
238 | usage(EXIT_FAILURE); |
||
239 | } |
||
240 | |||
241 | ifinfo.size = st.st_size; |
||
242 | |||
243 | obuf.size = ifinfo.size + sizeof(struct header) + sizeof(unsigned short); |
||
244 | if (obuf.size % sizeof(unsigned short)) |
||
245 | obuf.size++; |
||
246 | |||
247 | obuf.start = malloc(obuf.size); |
||
248 | if (!obuf.start) { |
||
249 | fprintf(stderr, "no memory for buffer\n"); |
||
250 | usage(EXIT_FAILURE); |
||
251 | } |
||
252 | memset(obuf.start, 0, obuf.size); |
||
253 | |||
254 | ibuf.size = ifinfo.size; |
||
255 | ibuf.start = obuf.start + sizeof(struct header); |
||
256 | |||
257 | if (fwread(&ifinfo, &ibuf)) |
||
258 | usage(EXIT_FAILURE); |
||
259 | |||
260 | if (force_be == FALSE) { |
||
261 | header.flash = HOST_TO_LE32(header.flash); |
||
262 | header.size = HOST_TO_LE32(obuf.size - sizeof(struct header)); |
||
263 | header.start = HOST_TO_LE32(header.start); |
||
264 | } else { |
||
265 | header.flash = HOST_TO_BE32(header.flash); |
||
266 | header.size = HOST_TO_BE32(obuf.size - sizeof(struct header)); |
||
267 | header.start = HOST_TO_BE32(header.start); |
||
268 | } |
||
269 | |||
270 | memcpy (obuf.start, &header, sizeof(struct header)); |
||
271 | |||
272 | if (force_be == FALSE) |
||
273 | csum = HOST_TO_LE16(fwcsum(&ibuf)); |
||
274 | else |
||
275 | csum = HOST_TO_BE16(fwcsum(&ibuf)); |
||
276 | |||
277 | memcpy(obuf.start + obuf.size - sizeof(unsigned short), |
||
278 | &csum, sizeof(unsigned short)); |
||
279 | |||
280 | ofinfo.size = obuf.size; |
||
281 | |||
282 | if (fwwrite(&ofinfo, &obuf)) |
||
283 | usage(EXIT_FAILURE); |
||
284 | |||
285 | return EXIT_SUCCESS; |
||
286 | } |