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