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