mtd: add missing breaks in a switch
[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@openwrt.org>
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);
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 fprintf(stderr,
742 #ifdef FIS_SUPPORT
743 " -F <part>[:<size>[:<entrypoint>]][,<part>...]\n"
744 " alter the fis partition table to create new partitions replacing\n"
745 " the partitions provided as argument to the write command\n"
746 " (only valid together with the write command)\n"
747 #endif
748 "\n"
749 "Example: To write linux.trx to mtd4 labeled as linux and reboot afterwards\n"
750 " mtd -r write linux.trx linux\n\n");
751 exit(1);
752 }
753
754 static void do_reboot(void)
755 {
756 fprintf(stderr, "Rebooting ...\n");
757 fflush(stderr);
758
759 /* try regular reboot method first */
760 system("/sbin/reboot");
761 sleep(2);
762
763 /* if we're still alive at this point, force the kernel to reboot */
764 syscall(SYS_reboot,LINUX_REBOOT_MAGIC1,LINUX_REBOOT_MAGIC2,LINUX_REBOOT_CMD_RESTART,NULL);
765 }
766
767 int main (int argc, char **argv)
768 {
769 int ch, i, boot, imagefd = 0, force, unlocked;
770 char *erase[MAX_ARGS], *device = NULL;
771 char *fis_layout = NULL;
772 size_t offset = 0, part_offset = 0, dump_len = 0;
773 enum {
774 CMD_ERASE,
775 CMD_WRITE,
776 CMD_UNLOCK,
777 CMD_JFFS2WRITE,
778 CMD_FIXTRX,
779 CMD_FIXSEAMA,
780 CMD_VERIFY,
781 CMD_DUMP,
782 CMD_RESETBC,
783 } cmd = -1;
784
785 erase[0] = NULL;
786 boot = 0;
787 force = 0;
788 buflen = 0;
789 quiet = 0;
790 no_erase = 0;
791
792 while ((ch = getopt(argc, argv,
793 #ifdef FIS_SUPPORT
794 "F:"
795 #endif
796 "frnqe:d:s:j:p:o:l:")) != -1)
797 switch (ch) {
798 case 'f':
799 force = 1;
800 break;
801 case 'r':
802 boot = 1;
803 break;
804 case 'n':
805 no_erase = 1;
806 break;
807 case 'j':
808 jffs2file = optarg;
809 break;
810 case 's':
811 errno = 0;
812 jffs2_skip_bytes = strtoul(optarg, 0, 0);
813 if (errno) {
814 fprintf(stderr, "-s: illegal numeric string\n");
815 usage();
816 }
817 break;
818 case 'q':
819 quiet++;
820 break;
821 case 'e':
822 i = 0;
823 while ((erase[i] != NULL) && ((i + 1) < MAX_ARGS))
824 i++;
825
826 erase[i++] = optarg;
827 erase[i] = NULL;
828 break;
829 case 'd':
830 jffs2dir = optarg;
831 break;
832 case 'p':
833 errno = 0;
834 part_offset = strtoul(optarg, 0, 0);
835 if (errno) {
836 fprintf(stderr, "-p: illegal numeric string\n");
837 usage();
838 }
839 break;
840 case 'l':
841 errno = 0;
842 dump_len = strtoul(optarg, 0, 0);
843 if (errno) {
844 fprintf(stderr, "-l: illegal numeric string\n");
845 usage();
846 }
847 break;
848 case 'o':
849 errno = 0;
850 offset = strtoul(optarg, 0, 0);
851 if (errno) {
852 fprintf(stderr, "-o: illegal numeric string\n");
853 usage();
854 }
855 break;
856 #ifdef FIS_SUPPORT
857 case 'F':
858 fis_layout = optarg;
859 break;
860 #endif
861 case '?':
862 default:
863 usage();
864 }
865 argc -= optind;
866 argv += optind;
867
868 if (argc < 2)
869 usage();
870
871 if ((strcmp(argv[0], "unlock") == 0) && (argc == 2)) {
872 cmd = CMD_UNLOCK;
873 device = argv[1];
874 } else if ((strcmp(argv[0], "erase") == 0) && (argc == 2)) {
875 cmd = CMD_ERASE;
876 device = argv[1];
877 } else if (((strcmp(argv[0], "resetbc") == 0) && (argc == 2)) && mtd_resetbc) {
878 cmd = CMD_RESETBC;
879 device = argv[1];
880 } else if (((strcmp(argv[0], "fixtrx") == 0) && (argc == 2)) && mtd_fixtrx) {
881 cmd = CMD_FIXTRX;
882 device = argv[1];
883 } else if (((strcmp(argv[0], "fixseama") == 0) && (argc == 2)) && mtd_fixseama) {
884 cmd = CMD_FIXSEAMA;
885 device = argv[1];
886 } else if ((strcmp(argv[0], "verify") == 0) && (argc == 3)) {
887 cmd = CMD_VERIFY;
888 imagefile = argv[1];
889 device = argv[2];
890 } else if ((strcmp(argv[0], "dump") == 0) && (argc == 2)) {
891 cmd = CMD_DUMP;
892 device = argv[1];
893 } else if ((strcmp(argv[0], "write") == 0) && (argc == 3)) {
894 cmd = CMD_WRITE;
895 device = argv[2];
896
897 if (strcmp(argv[1], "-") == 0) {
898 imagefile = "<stdin>";
899 imagefd = 0;
900 } else {
901 imagefile = argv[1];
902 if ((imagefd = open(argv[1], O_RDONLY)) < 0) {
903 fprintf(stderr, "Couldn't open image file: %s!\n", imagefile);
904 exit(1);
905 }
906 }
907
908 if (!mtd_check(device)) {
909 fprintf(stderr, "Can't open device for writing!\n");
910 exit(1);
911 }
912 /* check trx file before erasing or writing anything */
913 if (!image_check(imagefd, device) && !force) {
914 fprintf(stderr, "Image check failed.\n");
915 exit(1);
916 }
917 } else if ((strcmp(argv[0], "jffs2write") == 0) && (argc == 3)) {
918 cmd = CMD_JFFS2WRITE;
919 device = argv[2];
920
921 imagefile = argv[1];
922 if (!mtd_check(device)) {
923 fprintf(stderr, "Can't open device for writing!\n");
924 exit(1);
925 }
926 } else {
927 usage();
928 }
929
930 sync();
931
932 i = 0;
933 unlocked = 0;
934 while (erase[i] != NULL) {
935 mtd_unlock(erase[i]);
936 mtd_erase(erase[i]);
937 if (strcmp(erase[i], device) == 0)
938 unlocked = 1;
939 i++;
940 }
941
942 switch (cmd) {
943 case CMD_UNLOCK:
944 if (!unlocked)
945 mtd_unlock(device);
946 break;
947 case CMD_VERIFY:
948 mtd_verify(device, imagefile);
949 break;
950 case CMD_DUMP:
951 mtd_dump(device, offset, dump_len);
952 break;
953 case CMD_ERASE:
954 if (!unlocked)
955 mtd_unlock(device);
956 mtd_erase(device);
957 break;
958 case CMD_WRITE:
959 if (!unlocked)
960 mtd_unlock(device);
961 mtd_write(imagefd, device, fis_layout, part_offset);
962 break;
963 case CMD_JFFS2WRITE:
964 if (!unlocked)
965 mtd_unlock(device);
966 mtd_write_jffs2(device, imagefile, jffs2dir);
967 break;
968 case CMD_FIXTRX:
969 if (mtd_fixtrx) {
970 mtd_fixtrx(device, offset);
971 }
972 break;
973 case CMD_RESETBC:
974 if (mtd_resetbc) {
975 mtd_resetbc(device);
976 }
977 break;
978 case CMD_FIXSEAMA:
979 if (mtd_fixseama)
980 mtd_fixseama(device, 0);
981 break;
982 }
983
984 sync();
985
986 if (boot)
987 do_reboot();
988
989 return 0;
990 }