OpenWrt – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | /* |
2 | * |
||
3 | * Copyright (C) 2007 OpenWrt.org |
||
4 | * Copyright (C) 2007 Gabor Juhos <juhosg at openwrt.org> |
||
5 | * |
||
6 | * This program is free software; you can redistribute it and/or modify it |
||
7 | * under the terms of the GNU General Public License version 2 as published |
||
8 | * by the Free Software Foundation. |
||
9 | * |
||
10 | */ |
||
11 | |||
12 | #include <stdio.h> |
||
13 | #include <stdlib.h> |
||
14 | #include <stdint.h> |
||
15 | #include <string.h> |
||
16 | #include <unistd.h> /* for unlink() */ |
||
17 | #include <libgen.h> |
||
18 | #include <getopt.h> /* for getopt() */ |
||
19 | #include <stdarg.h> |
||
20 | #include <errno.h> |
||
21 | #include <sys/stat.h> |
||
22 | #include <endian.h> /* for __BYTE_ORDER */ |
||
23 | #if defined(__CYGWIN__) |
||
24 | # include <byteswap.h> |
||
25 | #endif |
||
26 | |||
27 | #if (__BYTE_ORDER == __LITTLE_ENDIAN) |
||
28 | # define HOST_TO_LE16(x) (x) |
||
29 | # define HOST_TO_LE32(x) (x) |
||
30 | # define LE16_TO_HOST(x) (x) |
||
31 | # define LE32_TO_HOST(x) (x) |
||
32 | #else |
||
33 | # define HOST_TO_LE16(x) bswap_16(x) |
||
34 | # define HOST_TO_LE32(x) bswap_32(x) |
||
35 | # define LE16_TO_HOST(x) bswap_16(x) |
||
36 | # define LE32_TO_HOST(x) bswap_32(x) |
||
37 | #endif |
||
38 | |||
39 | #define MAX_NUM_BLOCKS 2 |
||
40 | #define MAX_ARG_COUNT 32 |
||
41 | #define MAX_ARG_LEN 1024 |
||
42 | #define FILE_BUF_LEN (16*1024) |
||
43 | #define DEFAULT_PADC 0xFF |
||
44 | |||
45 | #define DEFAULT_BLOCK_ALIGN 0x10000U |
||
46 | |||
47 | #define CSUM_TYPE_NONE 0 |
||
48 | #define CSUM_TYPE_8 1 |
||
49 | #define CSUM_TYPE_16 2 |
||
50 | #define CSUM_TYPE_32 3 |
||
51 | |||
52 | struct csum_state{ |
||
53 | int size; |
||
54 | uint32_t val; |
||
55 | uint32_t tmp; |
||
56 | int odd; |
||
57 | }; |
||
58 | |||
59 | struct image_desc { |
||
60 | int need_file; |
||
61 | char *file_name; /* name of the file */ |
||
62 | uint32_t file_size; /* length of the file */ |
||
63 | |||
64 | uint32_t csum; |
||
65 | uint32_t out_size; |
||
66 | uint8_t padc; |
||
67 | }; |
||
68 | |||
69 | struct fwhdr_nfs { |
||
70 | uint32_t type; |
||
71 | uint32_t kernel_offs; |
||
72 | uint32_t kernel_size; |
||
73 | uint32_t fs_offs; |
||
74 | uint32_t fs_size; |
||
75 | uint32_t kernel_csum; |
||
76 | uint32_t fs_csum; |
||
77 | uint32_t id; |
||
78 | } __attribute__ ((packed)); |
||
79 | |||
80 | struct fwhdr_cas { |
||
81 | uint32_t type; |
||
82 | uint32_t kernel_offs; |
||
83 | uint32_t kernel_size; |
||
84 | uint32_t id; |
||
85 | uint32_t kernel_csum; |
||
86 | uint32_t magic1; |
||
87 | uint32_t magic2; |
||
88 | uint32_t magic3; |
||
89 | } __attribute__ ((packed)); |
||
90 | |||
91 | union file_hdr { |
||
92 | struct fwhdr_cas cas; |
||
93 | struct fwhdr_nfs nfs; |
||
94 | }; |
||
95 | |||
96 | struct board_info { |
||
97 | char *model; |
||
98 | char *name; |
||
99 | int header_type; |
||
100 | uint32_t id; |
||
101 | uint32_t max_kernel_size; |
||
102 | uint32_t max_fs_size; |
||
103 | }; |
||
104 | |||
105 | #define HEADER_TYPE_NFS 0 |
||
106 | #define HEADER_TYPE_CAS 1 |
||
107 | |||
108 | #define KERNEL_SIZE_CAS (61*64*1024) |
||
109 | #define KERNEL_SIZE_NFS (52*64*1024) |
||
110 | #define FS_SIZE_NFS (9*64*1024) |
||
111 | |||
112 | #define CAS_MAGIC1 0x5241AA55 |
||
113 | #define CAS_MAGIC2 0x524F4741 |
||
114 | #define CAS_MAGIC3 0xD3F22D4E |
||
115 | |||
116 | /* Cellvision/SparkLAN products */ |
||
117 | #define MODEL_CAS_630 0x01000000 |
||
118 | #define MODEL_CAS_630W 0x01000000 |
||
119 | #define MODEL_CAS_670 0x01000000 |
||
120 | #define MODEL_CAS_670W 0x01000000 |
||
121 | #define MODEL_NFS_101U 0x01000000 |
||
122 | #define MODEL_NFS_101WU 0x01000003 |
||
123 | #define MODEL_NFS_202U 0x01000001 |
||
124 | #define MODEL_NFS_202WU 0x01000002 |
||
125 | |||
126 | /* Corega products */ |
||
127 | #define MODEL_CG_NSADP 0x01000020 /* NFS-101U */ |
||
128 | #define MODEL_CG_NSADPCR 0x01000021 /* NFS-202U */ |
||
129 | |||
130 | /* D-Link products */ |
||
131 | #define MODEL_DCS_950 0x01010102 /* CAS-630 */ |
||
132 | #define MODEL_DCS_950G 0x01020102 /* CAS-630W */ |
||
133 | #define MODEL_DNS_120 0x01000030 /* NFS-101U */ |
||
134 | #define MODEL_DNS_G120 0x01000032 /* NFS-101WU */ |
||
135 | |||
136 | /* Digitus products */ |
||
137 | #define MODEL_DN_16021 MODEL_CAS_630 |
||
138 | #define MODEL_DN_16022 MODEL_CAS_630W |
||
139 | #define MODEL_DN_16030 MODEL_CAS_670 |
||
140 | #define MODEL_DN_16031 MODEL_CAS_670W |
||
141 | #define MODEL_DN_7013 MODEL_NFS_101U |
||
142 | |||
143 | /* Lobos products */ |
||
144 | #define MODEL_LB_SS01TXU 0x00000000 |
||
145 | |||
146 | /* Neu-Fusion products */ |
||
147 | |||
148 | /* Ovislink products */ |
||
149 | #define MODEL_MU_5000FS 0x01000040 /* NFS-101U */ |
||
150 | #define MODEL_WL_5420CAM 0x020B0101 /* CAS-630W? */ |
||
151 | #define MODEL_WL_5460CAM 0x020B0001 /* CAS-670W */ |
||
152 | |||
153 | /* Repotec products */ |
||
154 | |||
155 | /* Sitecom products */ |
||
156 | #define MODEL_LN_350 /* unknown */ |
||
157 | #define MODEL_LN_403 0x01020402 |
||
158 | #define MODEL_WL_401 0x01010402 |
||
159 | |||
160 | /* Surecom products */ |
||
161 | #define MODEL_EP_4001_MM 0x01030A02 /* CAS-630 */ |
||
162 | #define MODEL_EP_4002_MM 0x01020A02 /* CAS-630W */ |
||
163 | #define MODEL_EP_4011_MM 0x01010A02 /* CAS-670 */ |
||
164 | #define MODEL_EP_4012_MM 0x01000A02 /* CAS-670W */ |
||
165 | #define MODEL_EP_9812_U /* unknown */ |
||
166 | |||
167 | /* Trendnet products */ |
||
168 | #define MODEL_TN_U100 0x01000081 /* NFS-101U */ |
||
169 | #define MODEL_TN_U200 0x01000082 /* NFS-202U */ |
||
170 | |||
171 | /* |
||
172 | * Globals |
||
173 | */ |
||
174 | char *progname; |
||
175 | char *ofname; |
||
176 | int verblevel; |
||
177 | int keep_invalid_images; |
||
178 | int invalid_causes_error = 1; |
||
179 | union file_hdr header; |
||
180 | |||
181 | struct image_desc kernel_image; |
||
182 | struct image_desc fs_image; |
||
183 | |||
184 | struct board_info *board = NULL; |
||
185 | |||
186 | #define BOARD(m, n, i, ks, fs, h) { \ |
||
187 | .model = (m), \ |
||
188 | .name = (n), \ |
||
189 | .id = (i), \ |
||
190 | .max_kernel_size = (ks), \ |
||
191 | .max_fs_size = (fs), \ |
||
192 | .header_type = (h) \ |
||
193 | } |
||
194 | |||
195 | #define BOARD_CAS(m,n,i) \ |
||
196 | BOARD(m, n, i, KERNEL_SIZE_CAS, 0, HEADER_TYPE_CAS) |
||
197 | #define BOARD_NFS(m,n,i) \ |
||
198 | BOARD(m, n, i, KERNEL_SIZE_NFS, FS_SIZE_NFS, HEADER_TYPE_NFS) |
||
199 | |||
200 | static struct board_info boards[] = { |
||
201 | /* Cellvision/Sparklan products */ |
||
202 | BOARD_CAS("CAS-630", "Cellvision CAS-630", MODEL_CAS_630), |
||
203 | BOARD_CAS("CAS-630W", "Cellvision CAS-630W", MODEL_CAS_630W), |
||
204 | BOARD_CAS("CAS-670", "Cellvision CAS-670", MODEL_CAS_670), |
||
205 | BOARD_CAS("CAS-670W", "Cellvision CAS-670W", MODEL_CAS_670W), |
||
206 | BOARD_NFS("NFS-101U", "Cellvision NFS-101U", MODEL_NFS_101U), |
||
207 | BOARD_NFS("NFS-101WU", "Cellvision NFS-101WU", MODEL_NFS_101WU), |
||
208 | BOARD_NFS("NFS-202U", "Cellvision NFS-202U", MODEL_NFS_202U), |
||
209 | BOARD_NFS("NFS-202WU", "Cellvision NFS-202WU", MODEL_NFS_202WU), |
||
210 | |||
211 | /* Corega products */ |
||
212 | BOARD_NFS("CG-NSADP", "Corega CG-NSADP", MODEL_CG_NSADP), |
||
213 | BOARD_NFS("CG-NSADPCR", "Corega CG-NSADPCR", MODEL_CG_NSADPCR), |
||
214 | |||
215 | /* D-Link products */ |
||
216 | BOARD_CAS("DCS-950", "D-Link DCS-950", MODEL_DCS_950), |
||
217 | BOARD_CAS("DCS-950G", "D-Link DCS-950G", MODEL_DCS_950G), |
||
218 | BOARD_NFS("DNS-120", "D-Link DNS-120", MODEL_DNS_120), |
||
219 | BOARD_NFS("DNS-G120", "D-Link DNS-G120", MODEL_DNS_G120), |
||
220 | |||
221 | /* Digitus products */ |
||
222 | BOARD_NFS("DN-7013", "Digitus DN-7013", MODEL_DN_7013), |
||
223 | |||
224 | /* Lobos products */ |
||
225 | BOARD_NFS("LB-SS01TXU", "Lobos LB-SS01TXU", MODEL_LB_SS01TXU), |
||
226 | |||
227 | /* Ovislink products */ |
||
228 | BOARD_NFS("MU-5000FS", "Ovislink MU-5000FS", MODEL_MU_5000FS), |
||
229 | BOARD_CAS("WL-5420CAM", "Ovislink WL-5420 CAM", MODEL_WL_5420CAM), |
||
230 | BOARD_CAS("WL-5460CAM", "Ovislink WL-5460 CAM", MODEL_WL_5460CAM), |
||
231 | |||
232 | /* Sitecom products */ |
||
233 | BOARD_CAS("LN-403", "Sitecom LN-403", MODEL_LN_403), |
||
234 | BOARD_CAS("WL-401", "Sitecom WL-401", MODEL_WL_401), |
||
235 | |||
236 | /* Surecom products */ |
||
237 | BOARD_CAS("EP-4001-MM", "Surecom EP-4001-MM", MODEL_EP_4001_MM), |
||
238 | BOARD_CAS("EP-4002-MM", "Surecom EP-4002-MM", MODEL_EP_4002_MM), |
||
239 | BOARD_CAS("EP-4011-MM", "Surecom EP-4011-MM", MODEL_EP_4011_MM), |
||
240 | BOARD_CAS("EP-4012-MM", "Surecom EP-4012-MM", MODEL_EP_4012_MM), |
||
241 | |||
242 | /* TrendNET products */ |
||
243 | BOARD_NFS("TN-U100", "TrendNET TN-U100", MODEL_TN_U100), |
||
244 | BOARD_NFS("TN-U200", "TrendNET TN-U200", MODEL_TN_U200), |
||
245 | |||
246 | {.model = NULL} |
||
247 | }; |
||
248 | |||
249 | /* |
||
250 | * Message macros |
||
251 | */ |
||
252 | #define ERR(fmt, ...) do { \ |
||
253 | fflush(0); \ |
||
254 | fprintf(stderr, "[%s] *** error: " fmt "\n", \ |
||
255 | progname, ## __VA_ARGS__ ); \ |
||
256 | } while (0) |
||
257 | |||
258 | #define ERRS(fmt, ...) do { \ |
||
259 | int save = errno; \ |
||
260 | fflush(0); \ |
||
261 | fprintf(stderr, "[%s] *** error: " fmt ": %s\n", \ |
||
262 | progname, ## __VA_ARGS__, strerror(save)); \ |
||
263 | } while (0) |
||
264 | |||
265 | #define WARN(fmt, ...) do { \ |
||
266 | fprintf(stderr, "[%s] *** warning: " fmt "\n", \ |
||
267 | progname, ## __VA_ARGS__ ); \ |
||
268 | } while (0) |
||
269 | |||
270 | #define DBG(lev, fmt, ...) do { \ |
||
271 | if (verblevel < lev) \ |
||
272 | break;\ |
||
273 | fprintf(stderr, "[%s] " fmt "\n", progname, ## __VA_ARGS__ ); \ |
||
274 | } while (0) |
||
275 | |||
276 | #define ERR_FATAL -1 |
||
277 | #define ERR_INVALID_IMAGE -2 |
||
278 | |||
279 | void |
||
280 | usage(int status) |
||
281 | { |
||
282 | FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout; |
||
283 | struct board_info *board; |
||
284 | |||
285 | fprintf(stream, "Usage: %s [OPTIONS...] <file>\n", progname); |
||
286 | fprintf(stream, |
||
287 | "\n" |
||
288 | "Options:\n" |
||
289 | " -B <board> create image for the board specified with <board>.\n" |
||
290 | " valid <board> values:\n" |
||
291 | ); |
||
292 | for (board = boards; board->model != NULL; board++){ |
||
293 | fprintf(stream, |
||
294 | " %-12s: %s\n", |
||
295 | board->model, board->name); |
||
296 | }; |
||
297 | fprintf(stream, |
||
298 | " -d don't throw error on invalid images\n" |
||
299 | " -k keep invalid images\n" |
||
300 | " -K <file> add kernel to the image\n" |
||
301 | " -C <file> add custom filesystem to the image\n" |
||
302 | " -h show this screen\n" |
||
303 | "Parameters:\n" |
||
304 | " <file> write output to the file <file>\n" |
||
305 | ); |
||
306 | |||
307 | exit(status); |
||
308 | } |
||
309 | |||
310 | static inline uint32_t align(uint32_t base, uint32_t alignment) |
||
311 | { |
||
312 | uint32_t ret; |
||
313 | |||
314 | if (alignment) { |
||
315 | ret = (base + alignment - 1); |
||
316 | ret &= ~(alignment-1); |
||
317 | } else { |
||
318 | ret = base; |
||
319 | } |
||
320 | |||
321 | return ret; |
||
322 | } |
||
323 | |||
324 | /* |
||
325 | * argument parsing |
||
326 | */ |
||
327 | int |
||
328 | str2u32(char *arg, uint32_t *val) |
||
329 | { |
||
330 | char *err = NULL; |
||
331 | uint32_t t; |
||
332 | |||
333 | errno=0; |
||
334 | t = strtoul(arg, &err, 0); |
||
335 | if (errno || (err==arg) || ((err != NULL) && *err)) { |
||
336 | return -1; |
||
337 | } |
||
338 | |||
339 | *val = t; |
||
340 | return 0; |
||
341 | } |
||
342 | |||
343 | |||
344 | int |
||
345 | str2u16(char *arg, uint16_t *val) |
||
346 | { |
||
347 | char *err = NULL; |
||
348 | uint32_t t; |
||
349 | |||
350 | errno=0; |
||
351 | t = strtoul(arg, &err, 0); |
||
352 | if (errno || (err==arg) || ((err != NULL) && *err) || (t >= 0x10000)) { |
||
353 | return -1; |
||
354 | } |
||
355 | |||
356 | *val = t & 0xFFFF; |
||
357 | return 0; |
||
358 | } |
||
359 | |||
360 | int |
||
361 | str2u8(char *arg, uint8_t *val) |
||
362 | { |
||
363 | char *err = NULL; |
||
364 | uint32_t t; |
||
365 | |||
366 | errno=0; |
||
367 | t = strtoul(arg, &err, 0); |
||
368 | if (errno || (err==arg) || ((err != NULL) && *err) || (t >= 0x100)) { |
||
369 | return -1; |
||
370 | } |
||
371 | |||
372 | *val = t & 0xFF; |
||
373 | return 0; |
||
374 | } |
||
375 | |||
376 | int |
||
377 | parse_arg(char *arg, char *buf, char *argv[]) |
||
378 | { |
||
379 | int res = 0; |
||
380 | size_t argl; |
||
381 | char *tok; |
||
382 | char **ap = &buf; |
||
383 | int i; |
||
384 | |||
385 | memset(argv, 0, MAX_ARG_COUNT * sizeof(void *)); |
||
386 | |||
387 | if ((arg == NULL)) { |
||
388 | /* no arguments */ |
||
389 | return 0; |
||
390 | } |
||
391 | |||
392 | argl = strlen(arg); |
||
393 | if (argl == 0) { |
||
394 | /* no arguments */ |
||
395 | return 0; |
||
396 | } |
||
397 | |||
398 | if (argl >= MAX_ARG_LEN) { |
||
399 | /* argument is too long */ |
||
400 | argl = MAX_ARG_LEN-1; |
||
401 | } |
||
402 | |||
403 | memcpy(buf, arg, argl); |
||
404 | buf[argl] = '\0'; |
||
405 | |||
406 | for (i = 0; i < MAX_ARG_COUNT; i++) { |
||
407 | tok = strsep(ap, ":"); |
||
408 | if (tok == NULL) { |
||
409 | break; |
||
410 | } |
||
411 | #if 0 |
||
412 | else if (tok[0] == '\0') { |
||
413 | break; |
||
414 | } |
||
415 | #endif |
||
416 | argv[i] = tok; |
||
417 | res++; |
||
418 | } |
||
419 | |||
420 | return res; |
||
421 | } |
||
422 | |||
423 | |||
424 | int |
||
425 | required_arg(char c, char *arg) |
||
426 | { |
||
427 | if (arg == NULL || *arg != '-') |
||
428 | return 0; |
||
429 | |||
430 | ERR("option -%c requires an argument\n", c); |
||
431 | return ERR_FATAL; |
||
432 | } |
||
433 | |||
434 | |||
435 | int |
||
436 | is_empty_arg(char *arg) |
||
437 | { |
||
438 | int ret = 1; |
||
439 | if (arg != NULL) { |
||
440 | if (*arg) ret = 0; |
||
441 | }; |
||
442 | return ret; |
||
443 | } |
||
444 | |||
445 | |||
446 | void |
||
447 | csum8_update(uint8_t *p, uint32_t len, struct csum_state *css) |
||
448 | { |
||
449 | for ( ; len > 0; len --) { |
||
450 | css->val += *p++; |
||
451 | } |
||
452 | } |
||
453 | |||
454 | |||
455 | uint16_t |
||
456 | csum8_get(struct csum_state *css) |
||
457 | { |
||
458 | uint8_t t; |
||
459 | |||
460 | t = css->val; |
||
461 | return ~t + 1; |
||
462 | } |
||
463 | |||
464 | |||
465 | void |
||
466 | csum16_update(uint8_t *p, uint32_t len, struct csum_state *css) |
||
467 | { |
||
468 | uint16_t t; |
||
469 | |||
470 | if (css->odd) { |
||
471 | t = css->tmp + (p[0]<<8); |
||
472 | css->val += LE16_TO_HOST(t); |
||
473 | css->odd = 0; |
||
474 | len--; |
||
475 | p++; |
||
476 | } |
||
477 | |||
478 | for ( ; len > 1; len -= 2, p +=2 ) { |
||
479 | t = p[0] + (p[1] << 8); |
||
480 | css->val += LE16_TO_HOST(t); |
||
481 | } |
||
482 | |||
483 | if (len == 1) { |
||
484 | css->tmp = p[0]; |
||
485 | css->odd = 1; |
||
486 | } |
||
487 | } |
||
488 | |||
489 | |||
490 | uint16_t |
||
491 | csum16_get(struct csum_state *css) |
||
492 | { |
||
493 | char pad = 0; |
||
494 | |||
495 | csum16_update(&pad, 1, css); |
||
496 | return ~css->val + 1; |
||
497 | } |
||
498 | |||
499 | void |
||
500 | csum32_update(uint8_t *p, uint32_t len, struct csum_state *css) |
||
501 | { |
||
502 | uint32_t t; |
||
503 | |||
504 | for ( ; len > 3; len -= 4, p += 4 ) { |
||
505 | t = p[0] + (p[1] << 8) + (p[2] << 16) + (p[3] << 24); |
||
506 | css->val ^= t; |
||
507 | } |
||
508 | } |
||
509 | |||
510 | uint32_t |
||
511 | csum32_get(struct csum_state *css) |
||
512 | { |
||
513 | return css->val; |
||
514 | } |
||
515 | |||
516 | |||
517 | void |
||
518 | csum_init(struct csum_state *css, int size) |
||
519 | { |
||
520 | css->val = 0; |
||
521 | css->tmp = 0; |
||
522 | css->odd = 0; |
||
523 | css->size = size; |
||
524 | } |
||
525 | |||
526 | void |
||
527 | csum_update(uint8_t *p, uint32_t len, struct csum_state *css) |
||
528 | { |
||
529 | switch (css->size) { |
||
530 | case CSUM_TYPE_8: |
||
531 | csum8_update(p,len,css); |
||
532 | break; |
||
533 | case CSUM_TYPE_16: |
||
534 | csum16_update(p,len,css); |
||
535 | break; |
||
536 | case CSUM_TYPE_32: |
||
537 | csum32_update(p,len,css); |
||
538 | break; |
||
539 | } |
||
540 | } |
||
541 | |||
542 | |||
543 | uint32_t |
||
544 | csum_get(struct csum_state *css) |
||
545 | { |
||
546 | uint32_t ret; |
||
547 | |||
548 | switch (css->size) { |
||
549 | case CSUM_TYPE_8: |
||
550 | ret = csum8_get(css); |
||
551 | break; |
||
552 | case CSUM_TYPE_16: |
||
553 | ret = csum16_get(css); |
||
554 | break; |
||
555 | case CSUM_TYPE_32: |
||
556 | ret = csum32_get(css); |
||
557 | } |
||
558 | |||
559 | return ret; |
||
560 | } |
||
561 | |||
562 | |||
563 | /* |
||
564 | * routines to write data to the output file |
||
565 | */ |
||
566 | int |
||
567 | write_out_data(FILE *outfile, uint8_t *data, size_t len, |
||
568 | struct csum_state *css) |
||
569 | { |
||
570 | errno = 0; |
||
571 | |||
572 | fwrite(data, len, 1, outfile); |
||
573 | if (errno) { |
||
574 | ERRS("unable to write output file"); |
||
575 | return ERR_FATAL; |
||
576 | } |
||
577 | |||
578 | if (css) { |
||
579 | csum_update(data, len, css); |
||
580 | } |
||
581 | |||
582 | return 0; |
||
583 | } |
||
584 | |||
585 | |||
586 | int |
||
587 | write_out_padding(FILE *outfile, size_t len, uint8_t padc, |
||
588 | struct csum_state *css) |
||
589 | { |
||
590 | uint8_t buf[512]; |
||
591 | size_t buflen = sizeof(buf); |
||
592 | int err; |
||
593 | |||
594 | memset(buf, padc, buflen); |
||
595 | while (len > 0) { |
||
596 | if (len < buflen) |
||
597 | buflen = len; |
||
598 | |||
599 | err = write_out_data(outfile, buf, buflen, css); |
||
600 | if (err) |
||
601 | return err; |
||
602 | |||
603 | len -= buflen; |
||
604 | } |
||
605 | |||
606 | return 0; |
||
607 | } |
||
608 | |||
609 | |||
610 | int |
||
611 | image_stat_file(struct image_desc *desc) |
||
612 | { |
||
613 | struct stat st; |
||
614 | int err; |
||
615 | |||
616 | if (desc->file_name == NULL) |
||
617 | return 0; |
||
618 | |||
619 | err = stat(desc->file_name, &st); |
||
620 | if (err){ |
||
621 | ERRS("stat failed on %s", desc->file_name); |
||
622 | return ERR_FATAL; |
||
623 | } |
||
624 | |||
625 | if (st.st_size > desc->out_size) { |
||
626 | WARN("file %s is too big, will be truncated to %d bytes\n", |
||
627 | desc->file_name, desc->out_size); |
||
628 | desc->file_size = desc->out_size; |
||
629 | return ERR_INVALID_IMAGE; |
||
630 | } |
||
631 | |||
632 | |||
633 | desc->file_size = st.st_size; |
||
634 | desc->out_size = align(desc->file_size,1); |
||
635 | return 0; |
||
636 | } |
||
637 | |||
638 | |||
639 | int |
||
640 | image_writeout_file(FILE *outfile, struct image_desc *desc, |
||
641 | struct csum_state *css) |
||
642 | { |
||
643 | char buf[FILE_BUF_LEN]; |
||
644 | size_t buflen = sizeof(buf); |
||
645 | FILE *f; |
||
646 | size_t len; |
||
647 | int res; |
||
648 | |||
649 | if (desc->file_name == NULL) |
||
650 | return 0; |
||
651 | |||
652 | if (desc->file_size == 0) |
||
653 | return 0; |
||
654 | |||
655 | errno = 0; |
||
656 | f = fopen(desc->file_name,"r"); |
||
657 | if (errno) { |
||
658 | ERRS("unable to open file: %s", desc->file_name); |
||
659 | return ERR_FATAL; |
||
660 | } |
||
661 | |||
662 | len = desc->file_size; |
||
663 | while (len > 0) { |
||
664 | if (len < buflen) |
||
665 | buflen = len; |
||
666 | |||
667 | /* read data from source file */ |
||
668 | errno = 0; |
||
669 | fread(buf, buflen, 1, f); |
||
670 | if (errno != 0) { |
||
671 | ERRS("unable to read from file: %s", desc->file_name); |
||
672 | res = ERR_FATAL; |
||
673 | break; |
||
674 | } |
||
675 | |||
676 | res = write_out_data(outfile, buf, buflen, css); |
||
677 | if (res) |
||
678 | break; |
||
679 | |||
680 | len -= buflen; |
||
681 | } |
||
682 | |||
683 | fclose(f); |
||
684 | return res; |
||
685 | } |
||
686 | |||
687 | |||
688 | int |
||
689 | image_writeout(FILE *outfile, struct image_desc *desc) |
||
690 | { |
||
691 | int res; |
||
692 | struct csum_state css; |
||
693 | size_t padlen; |
||
694 | |||
695 | res = 0; |
||
696 | |||
697 | if (!desc->file_size) |
||
698 | return 0; |
||
699 | |||
700 | DBG(2, "writing image, file=%s, file_size=%d\n", |
||
701 | desc->file_name, desc->file_size); |
||
702 | |||
703 | csum_init(&css, CSUM_TYPE_32); |
||
704 | |||
705 | res = image_writeout_file(outfile, desc, &css); |
||
706 | if (res) |
||
707 | return res; |
||
708 | |||
709 | /* write padding data if neccesary */ |
||
710 | padlen = desc->out_size - desc->file_size; |
||
711 | DBG(1,"padding desc, length=%zu", padlen); |
||
712 | res = write_out_padding(outfile, padlen, desc->padc, &css); |
||
713 | |||
714 | desc->csum = csum_get(&css); |
||
715 | |||
716 | return res; |
||
717 | } |
||
718 | |||
719 | |||
720 | int |
||
721 | write_out_header(FILE *outfile) |
||
722 | { |
||
723 | union file_hdr tmp; |
||
724 | int res; |
||
725 | |||
726 | errno = 0; |
||
727 | if (fseek(outfile, 0, SEEK_SET) != 0) { |
||
728 | ERRS("fseek failed on output file"); |
||
729 | return ERR_FATAL; |
||
730 | } |
||
731 | |||
732 | switch (board->header_type) { |
||
733 | case HEADER_TYPE_CAS: |
||
734 | tmp.cas.type = HOST_TO_LE32(header.cas.type); |
||
735 | tmp.cas.id = HOST_TO_LE32(header.cas.id); |
||
736 | tmp.cas.kernel_offs = HOST_TO_LE32(sizeof(tmp.cas)); |
||
737 | tmp.cas.kernel_size = HOST_TO_LE32(kernel_image.out_size); |
||
738 | tmp.cas.kernel_csum = HOST_TO_LE32(kernel_image.csum); |
||
739 | tmp.cas.magic1 = HOST_TO_LE32(CAS_MAGIC1); |
||
740 | tmp.cas.magic2 = HOST_TO_LE32(CAS_MAGIC2); |
||
741 | tmp.cas.magic3 = HOST_TO_LE32(CAS_MAGIC3); |
||
742 | res = write_out_data(outfile, (uint8_t *)&tmp.cas, |
||
743 | sizeof(tmp.cas), NULL); |
||
744 | break; |
||
745 | case HEADER_TYPE_NFS: |
||
746 | tmp.nfs.type = HOST_TO_LE32(header.nfs.type); |
||
747 | tmp.nfs.id = HOST_TO_LE32(header.nfs.id); |
||
748 | tmp.nfs.kernel_offs = HOST_TO_LE32(sizeof(tmp.nfs)); |
||
749 | tmp.nfs.kernel_size = HOST_TO_LE32(kernel_image.out_size); |
||
750 | tmp.nfs.kernel_csum = HOST_TO_LE32(kernel_image.csum); |
||
751 | tmp.nfs.fs_offs = HOST_TO_LE32(sizeof(tmp.nfs) |
||
752 | + kernel_image.out_size); |
||
753 | tmp.nfs.fs_size = HOST_TO_LE32(fs_image.out_size); |
||
754 | tmp.nfs.fs_csum = HOST_TO_LE32(fs_image.csum); |
||
755 | res = write_out_data(outfile, (uint8_t *)&tmp.nfs, |
||
756 | sizeof(tmp.nfs), NULL); |
||
757 | break; |
||
758 | } |
||
759 | |||
760 | return res; |
||
761 | } |
||
762 | |||
763 | int |
||
764 | write_out_images(FILE *outfile) |
||
765 | { |
||
766 | struct image_desc *desc; |
||
767 | int i, res; |
||
768 | |||
769 | res = image_writeout(outfile, &kernel_image); |
||
770 | if (res) |
||
771 | return res; |
||
772 | |||
773 | res = image_writeout(outfile, &fs_image); |
||
774 | if (res) |
||
775 | return res; |
||
776 | |||
777 | return 0; |
||
778 | } |
||
779 | |||
780 | |||
781 | struct board_info * |
||
782 | find_board(char *model) |
||
783 | { |
||
784 | struct board_info *ret; |
||
785 | struct board_info *board; |
||
786 | |||
787 | ret = NULL; |
||
788 | for (board = boards; board->model != NULL; board++){ |
||
789 | if (strcasecmp(model, board->model) == 0) { |
||
790 | ret = board; |
||
791 | break; |
||
792 | } |
||
793 | }; |
||
794 | |||
795 | return ret; |
||
796 | } |
||
797 | |||
798 | |||
799 | int |
||
800 | parse_opt_board(char ch, char *arg) |
||
801 | { |
||
802 | |||
803 | DBG(1,"parsing board option: -%c %s", ch, arg); |
||
804 | |||
805 | if (board != NULL) { |
||
806 | ERR("only one board option allowed"); |
||
807 | return ERR_FATAL; |
||
808 | } |
||
809 | |||
810 | if (required_arg(ch, arg)) |
||
811 | return ERR_FATAL; |
||
812 | |||
813 | board = find_board(arg); |
||
814 | if (board == NULL){ |
||
815 | ERR("invalid/unknown board specified: %s", arg); |
||
816 | return ERR_FATAL; |
||
817 | } |
||
818 | |||
819 | switch (board->header_type) { |
||
820 | case HEADER_TYPE_CAS: |
||
821 | header.cas.type = HEADER_TYPE_CAS; |
||
822 | header.cas.id = board->id; |
||
823 | break; |
||
824 | case HEADER_TYPE_NFS: |
||
825 | header.nfs.type = HEADER_TYPE_NFS; |
||
826 | header.nfs.id = board->id; |
||
827 | break; |
||
828 | default: |
||
829 | ERR("internal error, unknown header type\n"); |
||
830 | return ERR_FATAL; |
||
831 | } |
||
832 | |||
833 | return 0; |
||
834 | } |
||
835 | |||
836 | |||
837 | int |
||
838 | parse_opt_image(char ch, char *arg) |
||
839 | { |
||
840 | char buf[MAX_ARG_LEN]; |
||
841 | char *argv[MAX_ARG_COUNT]; |
||
842 | int argc; |
||
843 | char *p; |
||
844 | struct image_desc *desc = NULL; |
||
845 | int i; |
||
846 | |||
847 | switch (ch) { |
||
848 | case 'K': |
||
849 | if (kernel_image.file_name) { |
||
850 | WARN("only one kernel option allowed"); |
||
851 | break; |
||
852 | } |
||
853 | desc = &kernel_image; |
||
854 | break; |
||
855 | case 'F': |
||
856 | if (fs_image.file_name) { |
||
857 | WARN("only one fs option allowed"); |
||
858 | break; |
||
859 | } |
||
860 | desc = &fs_image; |
||
861 | break; |
||
862 | } |
||
863 | |||
864 | if (!desc) |
||
865 | return ERR_FATAL; |
||
866 | |||
867 | argc = parse_arg(arg, buf, argv); |
||
868 | |||
869 | i = 0; |
||
870 | p = argv[i++]; |
||
871 | if (!is_empty_arg(p)) { |
||
872 | desc->file_name = strdup(p); |
||
873 | if (desc->file_name == NULL) { |
||
874 | ERR("not enough memory"); |
||
875 | return ERR_FATAL; |
||
876 | } |
||
877 | } else { |
||
878 | ERR("no file specified for option %c", ch); |
||
879 | return ERR_FATAL; |
||
880 | } |
||
881 | |||
882 | return 0; |
||
883 | } |
||
884 | |||
885 | |||
886 | int |
||
887 | process_images(void) |
||
888 | { |
||
889 | struct image_desc *desc; |
||
890 | uint32_t offs = 0; |
||
891 | int i; |
||
892 | int res; |
||
893 | |||
894 | kernel_image.out_size = board->max_kernel_size; |
||
895 | kernel_image.padc = DEFAULT_PADC; |
||
896 | res = image_stat_file(&kernel_image); |
||
897 | if (res) |
||
898 | return res; |
||
899 | |||
900 | if (!fs_image.file_name) |
||
901 | return 0; |
||
902 | |||
903 | fs_image.out_size = board->max_fs_size; |
||
904 | fs_image.padc = DEFAULT_PADC; |
||
905 | res = image_stat_file(&fs_image); |
||
906 | if (res) |
||
907 | return res; |
||
908 | |||
909 | return 0; |
||
910 | } |
||
911 | |||
912 | |||
913 | int |
||
914 | main(int argc, char *argv[]) |
||
915 | { |
||
916 | int optinvalid = 0; /* flag for invalid option */ |
||
917 | int c; |
||
918 | int res = ERR_FATAL; |
||
919 | |||
920 | FILE *outfile; |
||
921 | |||
922 | progname=basename(argv[0]); |
||
923 | |||
924 | opterr = 0; /* could not print standard getopt error messages */ |
||
925 | while ( 1 ) { |
||
926 | optinvalid = 0; |
||
927 | |||
928 | c = getopt(argc, argv, "B:C:dhK:r:vw:x:"); |
||
929 | if (c == -1) |
||
930 | break; |
||
931 | |||
932 | switch (c) { |
||
933 | case 'B': |
||
934 | optinvalid = parse_opt_board(c,optarg); |
||
935 | break; |
||
936 | case 'd': |
||
937 | invalid_causes_error = 0; |
||
938 | break; |
||
939 | case 'C': |
||
940 | case 'K': |
||
941 | optinvalid = parse_opt_image(c,optarg); |
||
942 | break; |
||
943 | case 'k': |
||
944 | keep_invalid_images = 1; |
||
945 | break; |
||
946 | case 'v': |
||
947 | verblevel++; |
||
948 | break; |
||
949 | case 'h': |
||
950 | usage(EXIT_SUCCESS); |
||
951 | break; |
||
952 | default: |
||
953 | optinvalid = 1; |
||
954 | break; |
||
955 | } |
||
956 | if (optinvalid != 0 ){ |
||
957 | ERR("invalid option: -%c", optopt); |
||
958 | goto out; |
||
959 | } |
||
960 | } |
||
961 | |||
962 | if (board == NULL) { |
||
963 | ERR("no board specified"); |
||
964 | goto out; |
||
965 | } |
||
966 | |||
967 | if (optind == argc) { |
||
968 | ERR("no output file specified"); |
||
969 | goto out; |
||
970 | } |
||
971 | |||
972 | ofname = argv[optind++]; |
||
973 | |||
974 | if (optind < argc) { |
||
975 | ERR("invalid option: %s", argv[optind]); |
||
976 | goto out; |
||
977 | } |
||
978 | |||
979 | res = process_images(); |
||
980 | if (res == ERR_FATAL) |
||
981 | goto out; |
||
982 | |||
983 | if (res == ERR_INVALID_IMAGE) { |
||
984 | if (invalid_causes_error) |
||
985 | res = ERR_FATAL; |
||
986 | |||
987 | if (keep_invalid_images == 0) { |
||
988 | WARN("generation of invalid images \"%s\" disabled", ofname); |
||
989 | goto out; |
||
990 | } |
||
991 | |||
992 | WARN("generating invalid image: \"%s\"", ofname); |
||
993 | } |
||
994 | |||
995 | outfile = fopen(ofname, "w"); |
||
996 | if (outfile == NULL) { |
||
997 | ERRS("could not open \"%s\" for writing", ofname); |
||
998 | res = ERR_FATAL; |
||
999 | goto out; |
||
1000 | } |
||
1001 | |||
1002 | if (write_out_header(outfile) != 0) { |
||
1003 | res = ERR_FATAL; |
||
1004 | goto out_flush; |
||
1005 | } |
||
1006 | |||
1007 | if (write_out_images(outfile) != 0) { |
||
1008 | res = ERR_FATAL; |
||
1009 | goto out_flush; |
||
1010 | } |
||
1011 | |||
1012 | if (write_out_header(outfile) != 0) { |
||
1013 | res = ERR_FATAL; |
||
1014 | goto out_flush; |
||
1015 | } |
||
1016 | |||
1017 | DBG(1,"Image file %s completed.", ofname); |
||
1018 | |||
1019 | out_flush: |
||
1020 | fflush(outfile); |
||
1021 | fclose(outfile); |
||
1022 | if (res == ERR_FATAL) { |
||
1023 | unlink(ofname); |
||
1024 | } |
||
1025 | out: |
||
1026 | if (res == ERR_FATAL) |
||
1027 | return EXIT_FAILURE; |
||
1028 | |||
1029 | return EXIT_SUCCESS; |
||
1030 | } |