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