mtd: add fixwrgg command
[openwrt/openwrt.git] / package / system / mtd / src / mtd.c
1 /*
2 * mtd - simple memory technology device manipulation tool
3 *
4 * Copyright (C) 2005 Waldemar Brodkorb <wbx@dass-it.de>,
5 * Copyright (C) 2005-2009 Felix Fietkau <nbd@nbd.name>
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License v2
9 * as published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 *
20 *
21 * The code is based on the linux-mtd examples.
22 */
23
24 #define _GNU_SOURCE
25 #include <byteswap.h>
26 #include <endian.h>
27 #include <limits.h>
28 #include <unistd.h>
29 #include <stdlib.h>
30 #include <stdio.h>
31 #include <stdint.h>
32 #include <signal.h>
33 #include <sys/ioctl.h>
34 #include <sys/syscall.h>
35 #include <fcntl.h>
36 #include <errno.h>
37 #include <time.h>
38 #include <string.h>
39 #include <sys/ioctl.h>
40 #include <sys/types.h>
41 #include <sys/param.h>
42 #include <sys/mount.h>
43 #include <sys/stat.h>
44 #include <sys/reboot.h>
45 #include <linux/reboot.h>
46 #include <mtd/mtd-user.h>
47 #include "fis.h"
48 #include "mtd.h"
49
50 #include <libubox/md5.h>
51
52 #define MAX_ARGS 8
53 #define JFFS2_DEFAULT_DIR "" /* directory name without /, empty means root dir */
54
55 #define TRX_MAGIC 0x48445230 /* "HDR0" */
56 #define SEAMA_MAGIC 0x5ea3a417
57 #define WRGG03_MAGIC 0x20080321
58
59 #if !defined(__BYTE_ORDER)
60 #error "Unknown byte order"
61 #endif
62
63 #if __BYTE_ORDER == __BIG_ENDIAN
64 #define cpu_to_be32(x) (x)
65 #define be32_to_cpu(x) (x)
66 #define le32_to_cpu(x) bswap_32(x)
67 #elif __BYTE_ORDER == __LITTLE_ENDIAN
68 #define cpu_to_be32(x) bswap_32(x)
69 #define be32_to_cpu(x) bswap_32(x)
70 #define le32_to_cpu(x) (x)
71 #else
72 #error "Unsupported endianness"
73 #endif
74
75 enum mtd_image_format {
76 MTD_IMAGE_FORMAT_UNKNOWN,
77 MTD_IMAGE_FORMAT_TRX,
78 MTD_IMAGE_FORMAT_SEAMA,
79 MTD_IMAGE_FORMAT_WRGG03,
80 };
81
82 static char *buf = NULL;
83 static char *imagefile = NULL;
84 static enum mtd_image_format imageformat = MTD_IMAGE_FORMAT_UNKNOWN;
85 static char *jffs2file = NULL, *jffs2dir = JFFS2_DEFAULT_DIR;
86 static int buflen = 0;
87 int quiet;
88 int no_erase;
89 int mtdsize = 0;
90 int erasesize = 0;
91 int jffs2_skip_bytes=0;
92 int mtdtype = 0;
93
94 int mtd_open(const char *mtd, bool block)
95 {
96 FILE *fp;
97 char dev[PATH_MAX];
98 int i;
99 int ret;
100 int flags = O_RDWR | O_SYNC;
101 char name[PATH_MAX];
102
103 snprintf(name, sizeof(name), "\"%s\"", mtd);
104 if ((fp = fopen("/proc/mtd", "r"))) {
105 while (fgets(dev, sizeof(dev), fp)) {
106 if (sscanf(dev, "mtd%d:", &i) && strstr(dev, name)) {
107 snprintf(dev, sizeof(dev), "/dev/mtd%s/%d", (block ? "block" : ""), i);
108 if ((ret=open(dev, flags))<0) {
109 snprintf(dev, sizeof(dev), "/dev/mtd%s%d", (block ? "block" : ""), i);
110 ret=open(dev, flags);
111 }
112 fclose(fp);
113 return ret;
114 }
115 }
116 fclose(fp);
117 }
118
119 return open(mtd, flags);
120 }
121
122 int mtd_check_open(const char *mtd)
123 {
124 struct mtd_info_user mtdInfo;
125 int fd;
126
127 fd = mtd_open(mtd, false);
128 if(fd < 0) {
129 fprintf(stderr, "Could not open mtd device: %s\n", mtd);
130 return -1;
131 }
132
133 if(ioctl(fd, MEMGETINFO, &mtdInfo)) {
134 fprintf(stderr, "Could not get MTD device info from %s\n", mtd);
135 close(fd);
136 return -1;
137 }
138 mtdsize = mtdInfo.size;
139 erasesize = mtdInfo.erasesize;
140 mtdtype = mtdInfo.type;
141
142 return fd;
143 }
144
145 int mtd_block_is_bad(int fd, int offset)
146 {
147 int r = 0;
148 loff_t o = offset;
149
150 if (mtdtype == MTD_NANDFLASH)
151 {
152 r = ioctl(fd, MEMGETBADBLOCK, &o);
153 if (r < 0)
154 {
155 fprintf(stderr, "Failed to get erase block status\n");
156 exit(1);
157 }
158 }
159 return r;
160 }
161
162 int mtd_erase_block(int fd, int offset)
163 {
164 struct erase_info_user mtdEraseInfo;
165
166 mtdEraseInfo.start = offset;
167 mtdEraseInfo.length = erasesize;
168 ioctl(fd, MEMUNLOCK, &mtdEraseInfo);
169 if (ioctl (fd, MEMERASE, &mtdEraseInfo) < 0)
170 return -1;
171
172 return 0;
173 }
174
175 int mtd_write_buffer(int fd, const char *buf, int offset, int length)
176 {
177 lseek(fd, offset, SEEK_SET);
178 write(fd, buf, length);
179 return 0;
180 }
181
182 static int
183 image_check(int imagefd, const char *mtd)
184 {
185 uint32_t magic;
186 int ret = 1;
187 int bufread;
188
189 while (buflen < sizeof(magic)) {
190 bufread = read(imagefd, buf + buflen, sizeof(magic) - buflen);
191 if (bufread < 1)
192 break;
193
194 buflen += bufread;
195 }
196
197 if (buflen < sizeof(magic)) {
198 fprintf(stdout, "Could not get image magic\n");
199 return 0;
200 }
201
202 magic = ((uint32_t *)buf)[0];
203
204 if (be32_to_cpu(magic) == TRX_MAGIC)
205 imageformat = MTD_IMAGE_FORMAT_TRX;
206 else if (be32_to_cpu(magic) == SEAMA_MAGIC)
207 imageformat = MTD_IMAGE_FORMAT_SEAMA;
208 else if (le32_to_cpu(magic) == WRGG03_MAGIC)
209 imageformat = MTD_IMAGE_FORMAT_WRGG03;
210
211 switch (imageformat) {
212 case MTD_IMAGE_FORMAT_TRX:
213 if (trx_check)
214 ret = trx_check(imagefd, mtd, buf, &buflen);
215 break;
216 case MTD_IMAGE_FORMAT_SEAMA:
217 break;
218 case MTD_IMAGE_FORMAT_WRGG03:
219 break;
220 default:
221 #ifdef target_brcm
222 if (!strcmp(mtd, "firmware"))
223 ret = 0;
224 #endif
225 break;
226 }
227
228 return ret;
229 }
230
231 static int mtd_check(const char *mtd)
232 {
233 char *next = NULL;
234 char *str = NULL;
235 int fd;
236
237 if (strchr(mtd, ':')) {
238 str = strdup(mtd);
239 mtd = str;
240 }
241
242 do {
243 next = strchr(mtd, ':');
244 if (next) {
245 *next = 0;
246 next++;
247 }
248
249 fd = mtd_check_open(mtd);
250 if (fd < 0)
251 return 0;
252
253 if (!buf)
254 buf = malloc(erasesize);
255
256 close(fd);
257 mtd = next;
258 } while (next);
259
260 if (str)
261 free(str);
262
263 return 1;
264 }
265
266 static int
267 mtd_unlock(const char *mtd)
268 {
269 struct erase_info_user mtdLockInfo;
270 char *next = NULL;
271 char *str = NULL;
272 int fd;
273
274 if (strchr(mtd, ':')) {
275 str = strdup(mtd);
276 mtd = str;
277 }
278
279 do {
280 next = strchr(mtd, ':');
281 if (next) {
282 *next = 0;
283 next++;
284 }
285
286 fd = mtd_check_open(mtd);
287 if(fd < 0) {
288 fprintf(stderr, "Could not open mtd device: %s\n", mtd);
289 exit(1);
290 }
291
292 if (quiet < 2)
293 fprintf(stderr, "Unlocking %s ...\n", mtd);
294
295 mtdLockInfo.start = 0;
296 mtdLockInfo.length = mtdsize;
297 ioctl(fd, MEMUNLOCK, &mtdLockInfo);
298 close(fd);
299 mtd = next;
300 } while (next);
301
302 if (str)
303 free(str);
304
305 return 0;
306 }
307
308 static int
309 mtd_erase(const char *mtd)
310 {
311 int fd;
312 struct erase_info_user mtdEraseInfo;
313
314 if (quiet < 2)
315 fprintf(stderr, "Erasing %s ...\n", mtd);
316
317 fd = mtd_check_open(mtd);
318 if(fd < 0) {
319 fprintf(stderr, "Could not open mtd device: %s\n", mtd);
320 exit(1);
321 }
322
323 mtdEraseInfo.length = erasesize;
324
325 for (mtdEraseInfo.start = 0;
326 mtdEraseInfo.start < mtdsize;
327 mtdEraseInfo.start += erasesize) {
328 if (mtd_block_is_bad(fd, mtdEraseInfo.start)) {
329 if (!quiet)
330 fprintf(stderr, "\nSkipping bad block at 0x%x ", mtdEraseInfo.start);
331 } else {
332 ioctl(fd, MEMUNLOCK, &mtdEraseInfo);
333 if(ioctl(fd, MEMERASE, &mtdEraseInfo))
334 fprintf(stderr, "Failed to erase block on %s at 0x%x\n", mtd, mtdEraseInfo.start);
335 }
336 }
337
338 close(fd);
339 return 0;
340
341 }
342
343 static int
344 mtd_dump(const char *mtd, int part_offset, int size)
345 {
346 int ret = 0, offset = 0;
347 int fd;
348 char *buf;
349
350 if (quiet < 2)
351 fprintf(stderr, "Dumping %s ...\n", mtd);
352
353 fd = mtd_check_open(mtd);
354 if(fd < 0) {
355 fprintf(stderr, "Could not open mtd device: %s\n", mtd);
356 return -1;
357 }
358
359 if (!size)
360 size = mtdsize;
361
362 if (part_offset)
363 lseek(fd, part_offset, SEEK_SET);
364
365 buf = malloc(erasesize);
366 if (!buf)
367 return -1;
368
369 do {
370 int len = (size > erasesize) ? (erasesize) : (size);
371 int rlen = read(fd, buf, len);
372
373 if (rlen < 0) {
374 if (errno == EINTR)
375 continue;
376 ret = -1;
377 goto out;
378 }
379 if (!rlen || rlen != len)
380 break;
381 if (mtd_block_is_bad(fd, offset)) {
382 fprintf(stderr, "skipping bad block at 0x%08x\n", offset);
383 } else {
384 size -= rlen;
385 write(1, buf, rlen);
386 }
387 offset += rlen;
388 } while (size > 0);
389
390 out:
391 close(fd);
392 return ret;
393 }
394
395 static int
396 mtd_verify(const char *mtd, char *file)
397 {
398 uint32_t f_md5[4], m_md5[4];
399 struct stat s;
400 md5_ctx_t ctx;
401 int ret = 0;
402 int fd;
403
404 if (quiet < 2)
405 fprintf(stderr, "Verifying %s against %s ...\n", mtd, file);
406
407 if (stat(file, &s) || md5sum(file, f_md5) < 0) {
408 fprintf(stderr, "Failed to hash %s\n", file);
409 return -1;
410 }
411
412 fd = mtd_check_open(mtd);
413 if(fd < 0) {
414 fprintf(stderr, "Could not open mtd device: %s\n", mtd);
415 return -1;
416 }
417
418 md5_begin(&ctx);
419 do {
420 char buf[256];
421 int len = (s.st_size > sizeof(buf)) ? (sizeof(buf)) : (s.st_size);
422 int rlen = read(fd, buf, len);
423
424 if (rlen < 0) {
425 if (errno == EINTR)
426 continue;
427 ret = -1;
428 goto out;
429 }
430 if (!rlen)
431 break;
432 md5_hash(buf, rlen, &ctx);
433 s.st_size -= rlen;
434 } while (s.st_size > 0);
435
436 md5_end(m_md5, &ctx);
437
438 fprintf(stderr, "%08x%08x%08x%08x - %s\n", m_md5[0], m_md5[1], m_md5[2], m_md5[3], mtd);
439 fprintf(stderr, "%08x%08x%08x%08x - %s\n", f_md5[0], f_md5[1], f_md5[2], f_md5[3], file);
440
441 ret = memcmp(f_md5, m_md5, sizeof(m_md5));
442 if (!ret)
443 fprintf(stderr, "Success\n");
444 else
445 fprintf(stderr, "Failed\n");
446
447 out:
448 close(fd);
449 return ret;
450 }
451
452 static void
453 indicate_writing(const char *mtd)
454 {
455 if (quiet < 2)
456 fprintf(stderr, "\nWriting from %s to %s ... ", imagefile, mtd);
457
458 if (!quiet)
459 fprintf(stderr, " [ ]");
460 }
461
462 static int
463 mtd_write(int imagefd, const char *mtd, char *fis_layout, size_t part_offset)
464 {
465 char *next = NULL;
466 char *str = NULL;
467 int fd, result;
468 ssize_t r, w, e;
469 ssize_t skip = 0;
470 uint32_t offset = 0;
471 int jffs2_replaced = 0;
472 int skip_bad_blocks = 0;
473
474 #ifdef FIS_SUPPORT
475 static struct fis_part new_parts[MAX_ARGS];
476 static struct fis_part old_parts[MAX_ARGS];
477 int n_new = 0, n_old = 0;
478
479 if (fis_layout) {
480 const char *tmp = mtd;
481 char *word, *brkt;
482 int ret;
483
484 memset(&old_parts, 0, sizeof(old_parts));
485 memset(&new_parts, 0, sizeof(new_parts));
486
487 do {
488 next = strchr(tmp, ':');
489 if (!next)
490 next = (char *) tmp + strlen(tmp);
491
492 memcpy(old_parts[n_old].name, tmp, next - tmp);
493
494 n_old++;
495 tmp = next + 1;
496 } while(*next);
497
498 for (word = strtok_r(fis_layout, ",", &brkt);
499 word;
500 word = strtok_r(NULL, ",", &brkt)) {
501
502 tmp = strtok(word, ":");
503 strncpy((char *) new_parts[n_new].name, tmp, sizeof(new_parts[n_new].name) - 1);
504
505 tmp = strtok(NULL, ":");
506 if (!tmp)
507 goto next;
508
509 new_parts[n_new].size = strtoul(tmp, NULL, 0);
510
511 tmp = strtok(NULL, ":");
512 if (!tmp)
513 goto next;
514
515 new_parts[n_new].loadaddr = strtoul(tmp, NULL, 16);
516 next:
517 n_new++;
518 }
519 ret = fis_validate(old_parts, n_old, new_parts, n_new);
520 if (ret < 0) {
521 fprintf(stderr, "Failed to validate the new FIS partition table\n");
522 exit(1);
523 }
524 if (ret == 0)
525 fis_layout = NULL;
526 }
527 #endif
528
529 if (strchr(mtd, ':')) {
530 str = strdup(mtd);
531 mtd = str;
532 }
533
534 r = 0;
535
536 resume:
537 next = strchr(mtd, ':');
538 if (next) {
539 *next = 0;
540 next++;
541 }
542
543 fd = mtd_check_open(mtd);
544 if(fd < 0) {
545 fprintf(stderr, "Could not open mtd device: %s\n", mtd);
546 exit(1);
547 }
548 if (part_offset > 0) {
549 fprintf(stderr, "Seeking on mtd device '%s' to: %zu\n", mtd, part_offset);
550 lseek(fd, part_offset, SEEK_SET);
551 }
552
553 indicate_writing(mtd);
554
555 w = e = 0;
556 for (;;) {
557 /* buffer may contain data already (from trx check or last mtd partition write attempt) */
558 while (buflen < erasesize) {
559 r = read(imagefd, buf + buflen, erasesize - buflen);
560 if (r < 0) {
561 if ((errno == EINTR) || (errno == EAGAIN))
562 continue;
563 else {
564 perror("read");
565 break;
566 }
567 }
568
569 if (r == 0)
570 break;
571
572 buflen += r;
573 }
574
575 if (buflen == 0)
576 break;
577
578 if (buflen < erasesize) {
579 /* Pad block to eraseblock size */
580 memset(&buf[buflen], 0xff, erasesize - buflen);
581 buflen = erasesize;
582 }
583
584 if (skip > 0) {
585 skip -= buflen;
586 buflen = 0;
587 if (skip <= 0)
588 indicate_writing(mtd);
589
590 continue;
591 }
592
593 if (jffs2file && w >= jffs2_skip_bytes) {
594 if (memcmp(buf, JFFS2_EOF, sizeof(JFFS2_EOF) - 1) == 0) {
595 if (!quiet)
596 fprintf(stderr, "\b\b\b ");
597 if (quiet < 2)
598 fprintf(stderr, "\nAppending jffs2 data from %s to %s..\n.", jffs2file, mtd);
599 /* got an EOF marker - this is the place to add some jffs2 data */
600 skip = mtd_replace_jffs2(mtd, fd, e, jffs2file);
601 jffs2_replaced = 1;
602
603 /* don't add it again */
604 jffs2file = NULL;
605
606 w += skip;
607 e += skip;
608 skip -= buflen;
609 buflen = 0;
610 offset = 0;
611 continue;
612 }
613 /* no EOF marker, make sure we figure out the last inode number
614 * before appending some data */
615 mtd_parse_jffs2data(buf, jffs2dir);
616 }
617
618 /* need to erase the next block before writing data to it */
619 if(!no_erase)
620 {
621 while (w + buflen > e - skip_bad_blocks) {
622 if (!quiet)
623 fprintf(stderr, "\b\b\b[e]");
624
625 if (mtd_block_is_bad(fd, e)) {
626 if (!quiet)
627 fprintf(stderr, "\nSkipping bad block at 0x%08zx ", e);
628
629 skip_bad_blocks += erasesize;
630 e += erasesize;
631
632 // Move the file pointer along over the bad block.
633 lseek(fd, erasesize, SEEK_CUR);
634 continue;
635 }
636
637 if (mtd_erase_block(fd, e) < 0) {
638 if (next) {
639 if (w < e) {
640 write(fd, buf + offset, e - w);
641 offset = e - w;
642 }
643 w = 0;
644 e = 0;
645 close(fd);
646 mtd = next;
647 fprintf(stderr, "\b\b\b \n");
648 goto resume;
649 } else {
650 fprintf(stderr, "Failed to erase block\n");
651 exit(1);
652 }
653 }
654
655 /* erase the chunk */
656 e += erasesize;
657 }
658 }
659
660 if (!quiet)
661 fprintf(stderr, "\b\b\b[w]");
662
663 if ((result = write(fd, buf + offset, buflen)) < buflen) {
664 if (result < 0) {
665 fprintf(stderr, "Error writing image.\n");
666 exit(1);
667 } else {
668 fprintf(stderr, "Insufficient space.\n");
669 exit(1);
670 }
671 }
672 w += buflen;
673
674 buflen = 0;
675 offset = 0;
676 }
677
678 if (jffs2_replaced) {
679 switch (imageformat) {
680 case MTD_IMAGE_FORMAT_TRX:
681 if (trx_fixup)
682 trx_fixup(fd, mtd);
683 break;
684 case MTD_IMAGE_FORMAT_SEAMA:
685 if (mtd_fixseama)
686 mtd_fixseama(mtd, 0, 0);
687 break;
688 case MTD_IMAGE_FORMAT_WRGG03:
689 if (mtd_fixwrgg)
690 mtd_fixwrgg(mtd, 0, 0);
691 break;
692 default:
693 break;
694 }
695 }
696
697 if (!quiet)
698 fprintf(stderr, "\b\b\b\b ");
699
700 if (quiet < 2)
701 fprintf(stderr, "\n");
702
703 #ifdef FIS_SUPPORT
704 if (fis_layout) {
705 if (fis_remap(old_parts, n_old, new_parts, n_new) < 0)
706 fprintf(stderr, "Failed to update the FIS partition table\n");
707 }
708 #endif
709
710 close(fd);
711 return 0;
712 }
713
714 static void usage(void)
715 {
716 fprintf(stderr, "Usage: mtd [<options> ...] <command> [<arguments> ...] <device>[:<device>...]\n\n"
717 "The device is in the format of mtdX (eg: mtd4) or its label.\n"
718 "mtd recognizes these commands:\n"
719 " unlock unlock the device\n"
720 " refresh refresh mtd partition\n"
721 " erase erase all data on device\n"
722 " verify <imagefile>|- verify <imagefile> (use - for stdin) to device\n"
723 " write <imagefile>|- write <imagefile> (use - for stdin) to device\n"
724 " jffs2write <file> append <file> to the jffs2 partition on the device\n");
725 if (mtd_resetbc) {
726 fprintf(stderr,
727 " resetbc <device> reset the uboot boot counter\n");
728 }
729 if (mtd_fixtrx) {
730 fprintf(stderr,
731 " fixtrx fix the checksum in a trx header on first boot\n");
732 }
733 if (mtd_fixseama) {
734 fprintf(stderr,
735 " fixseama fix the checksum in a seama header on first boot\n");
736 }
737 if (mtd_fixwrgg) {
738 fprintf(stderr,
739 " fixwrgg fix the checksum in a wrgg header on first boot\n");
740 }
741 fprintf(stderr,
742 "Following options are available:\n"
743 " -q quiet mode (once: no [w] on writing,\n"
744 " twice: no status messages)\n"
745 " -n write without first erasing the blocks\n"
746 " -r reboot after successful command\n"
747 " -f force write without trx checks\n"
748 " -e <device> erase <device> before executing the command\n"
749 " -d <name> directory for jffs2write, defaults to \"tmp\"\n"
750 " -j <name> integrate <file> into jffs2 data when writing an image\n"
751 " -s <number> skip the first n bytes when appending data to the jffs2 partiton, defaults to \"0\"\n"
752 " -p <number> write beginning at partition offset\n"
753 " -l <length> the length of data that we want to dump\n");
754 if (mtd_fixtrx) {
755 fprintf(stderr,
756 " -o offset offset of the image header in the partition(for fixtrx)\n");
757 }
758 if (mtd_fixtrx || mtd_fixseama || mtd_fixwrgg) {
759 fprintf(stderr,
760 " -c datasize amount of data to be used for checksum calculation (for fixtrx / fixseama / fixwrgg)\n");
761 }
762 fprintf(stderr,
763 #ifdef FIS_SUPPORT
764 " -F <part>[:<size>[:<entrypoint>]][,<part>...]\n"
765 " alter the fis partition table to create new partitions replacing\n"
766 " the partitions provided as argument to the write command\n"
767 " (only valid together with the write command)\n"
768 #endif
769 "\n"
770 "Example: To write linux.trx to mtd4 labeled as linux and reboot afterwards\n"
771 " mtd -r write linux.trx linux\n\n");
772 exit(1);
773 }
774
775 static void do_reboot(void)
776 {
777 fprintf(stderr, "Rebooting ...\n");
778 fflush(stderr);
779
780 /* try regular reboot method first */
781 system("/sbin/reboot");
782 sleep(2);
783
784 /* if we're still alive at this point, force the kernel to reboot */
785 syscall(SYS_reboot,LINUX_REBOOT_MAGIC1,LINUX_REBOOT_MAGIC2,LINUX_REBOOT_CMD_RESTART,NULL);
786 }
787
788 int main (int argc, char **argv)
789 {
790 int ch, i, boot, imagefd = 0, force, unlocked;
791 char *erase[MAX_ARGS], *device = NULL;
792 char *fis_layout = NULL;
793 size_t offset = 0, data_size = 0, part_offset = 0, dump_len = 0;
794 enum {
795 CMD_ERASE,
796 CMD_WRITE,
797 CMD_UNLOCK,
798 CMD_JFFS2WRITE,
799 CMD_FIXTRX,
800 CMD_FIXSEAMA,
801 CMD_FIXWRGG,
802 CMD_VERIFY,
803 CMD_DUMP,
804 CMD_RESETBC,
805 } cmd = -1;
806
807 erase[0] = NULL;
808 boot = 0;
809 force = 0;
810 buflen = 0;
811 quiet = 0;
812 no_erase = 0;
813
814 while ((ch = getopt(argc, argv,
815 #ifdef FIS_SUPPORT
816 "F:"
817 #endif
818 "frnqe:d:s:j:p:o:c:l:")) != -1)
819 switch (ch) {
820 case 'f':
821 force = 1;
822 break;
823 case 'r':
824 boot = 1;
825 break;
826 case 'n':
827 no_erase = 1;
828 break;
829 case 'j':
830 jffs2file = optarg;
831 break;
832 case 's':
833 errno = 0;
834 jffs2_skip_bytes = strtoul(optarg, 0, 0);
835 if (errno) {
836 fprintf(stderr, "-s: illegal numeric string\n");
837 usage();
838 }
839 break;
840 case 'q':
841 quiet++;
842 break;
843 case 'e':
844 i = 0;
845 while ((erase[i] != NULL) && ((i + 1) < MAX_ARGS))
846 i++;
847
848 erase[i++] = optarg;
849 erase[i] = NULL;
850 break;
851 case 'd':
852 jffs2dir = optarg;
853 break;
854 case 'p':
855 errno = 0;
856 part_offset = strtoul(optarg, 0, 0);
857 if (errno) {
858 fprintf(stderr, "-p: illegal numeric string\n");
859 usage();
860 }
861 break;
862 case 'l':
863 errno = 0;
864 dump_len = strtoul(optarg, 0, 0);
865 if (errno) {
866 fprintf(stderr, "-l: illegal numeric string\n");
867 usage();
868 }
869 break;
870 case 'o':
871 errno = 0;
872 offset = strtoul(optarg, 0, 0);
873 if (errno) {
874 fprintf(stderr, "-o: illegal numeric string\n");
875 usage();
876 }
877 break;
878 case 'c':
879 errno = 0;
880 data_size = strtoul(optarg, 0, 0);
881 if (errno) {
882 fprintf(stderr, "-c: illegal numeric string\n");
883 usage();
884 }
885 break;
886 #ifdef FIS_SUPPORT
887 case 'F':
888 fis_layout = optarg;
889 break;
890 #endif
891 case '?':
892 default:
893 usage();
894 }
895 argc -= optind;
896 argv += optind;
897
898 if (argc < 2)
899 usage();
900
901 if ((strcmp(argv[0], "unlock") == 0) && (argc == 2)) {
902 cmd = CMD_UNLOCK;
903 device = argv[1];
904 } else if ((strcmp(argv[0], "erase") == 0) && (argc == 2)) {
905 cmd = CMD_ERASE;
906 device = argv[1];
907 } else if (((strcmp(argv[0], "resetbc") == 0) && (argc == 2)) && mtd_resetbc) {
908 cmd = CMD_RESETBC;
909 device = argv[1];
910 } else if (((strcmp(argv[0], "fixtrx") == 0) && (argc == 2)) && mtd_fixtrx) {
911 cmd = CMD_FIXTRX;
912 device = argv[1];
913 } else if (((strcmp(argv[0], "fixseama") == 0) && (argc == 2)) && mtd_fixseama) {
914 cmd = CMD_FIXSEAMA;
915 device = argv[1];
916 } else if (((strcmp(argv[0], "fixwrgg") == 0) && (argc == 2)) && mtd_fixwrgg) {
917 cmd = CMD_FIXWRGG;
918 device = argv[1];
919 } else if ((strcmp(argv[0], "verify") == 0) && (argc == 3)) {
920 cmd = CMD_VERIFY;
921 imagefile = argv[1];
922 device = argv[2];
923 } else if ((strcmp(argv[0], "dump") == 0) && (argc == 2)) {
924 cmd = CMD_DUMP;
925 device = argv[1];
926 } else if ((strcmp(argv[0], "write") == 0) && (argc == 3)) {
927 cmd = CMD_WRITE;
928 device = argv[2];
929
930 if (strcmp(argv[1], "-") == 0) {
931 imagefile = "<stdin>";
932 imagefd = 0;
933 } else {
934 imagefile = argv[1];
935 if ((imagefd = open(argv[1], O_RDONLY)) < 0) {
936 fprintf(stderr, "Couldn't open image file: %s!\n", imagefile);
937 exit(1);
938 }
939 }
940
941 if (!mtd_check(device)) {
942 fprintf(stderr, "Can't open device for writing!\n");
943 exit(1);
944 }
945 /* check trx file before erasing or writing anything */
946 if (!image_check(imagefd, device) && !force) {
947 fprintf(stderr, "Image check failed.\n");
948 exit(1);
949 }
950 } else if ((strcmp(argv[0], "jffs2write") == 0) && (argc == 3)) {
951 cmd = CMD_JFFS2WRITE;
952 device = argv[2];
953
954 imagefile = argv[1];
955 if (!mtd_check(device)) {
956 fprintf(stderr, "Can't open device for writing!\n");
957 exit(1);
958 }
959 } else {
960 usage();
961 }
962
963 sync();
964
965 i = 0;
966 unlocked = 0;
967 while (erase[i] != NULL) {
968 mtd_unlock(erase[i]);
969 mtd_erase(erase[i]);
970 if (strcmp(erase[i], device) == 0)
971 unlocked = 1;
972 i++;
973 }
974
975 switch (cmd) {
976 case CMD_UNLOCK:
977 if (!unlocked)
978 mtd_unlock(device);
979 break;
980 case CMD_VERIFY:
981 mtd_verify(device, imagefile);
982 break;
983 case CMD_DUMP:
984 mtd_dump(device, offset, dump_len);
985 break;
986 case CMD_ERASE:
987 if (!unlocked)
988 mtd_unlock(device);
989 mtd_erase(device);
990 break;
991 case CMD_WRITE:
992 if (!unlocked)
993 mtd_unlock(device);
994 mtd_write(imagefd, device, fis_layout, part_offset);
995 break;
996 case CMD_JFFS2WRITE:
997 if (!unlocked)
998 mtd_unlock(device);
999 mtd_write_jffs2(device, imagefile, jffs2dir);
1000 break;
1001 case CMD_FIXTRX:
1002 if (mtd_fixtrx) {
1003 mtd_fixtrx(device, offset, data_size);
1004 }
1005 break;
1006 case CMD_RESETBC:
1007 if (mtd_resetbc) {
1008 mtd_resetbc(device);
1009 }
1010 break;
1011 case CMD_FIXSEAMA:
1012 if (mtd_fixseama)
1013 mtd_fixseama(device, 0, data_size);
1014 break;
1015 case CMD_FIXWRGG:
1016 if (mtd_fixwrgg)
1017 mtd_fixwrgg(device, 0, data_size);
1018 break;
1019 }
1020
1021 sync();
1022
1023 if (boot)
1024 do_reboot();
1025
1026 return 0;
1027 }