package/mtd: (enhancement) add option to prevent erase when writing to flash. (closes...
[openwrt.git] / package / 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 #include <limits.h>
25 #include <unistd.h>
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <stdint.h>
29 #include <signal.h>
30 #include <sys/ioctl.h>
31 #include <sys/syscall.h>
32 #include <fcntl.h>
33 #include <errno.h>
34 #include <error.h>
35 #include <time.h>
36 #include <string.h>
37 #include <sys/ioctl.h>
38 #include <sys/types.h>
39 #include <sys/param.h>
40 #include <sys/mount.h>
41 #include <sys/stat.h>
42 #include <sys/reboot.h>
43 #include <linux/reboot.h>
44 #include "mtd-api.h"
45 #include "fis.h"
46 #include "mtd.h"
47 #include "crc32.h"
48
49 #define MAX_ARGS 8
50 #define JFFS2_DEFAULT_DIR       "" /* directory name without /, empty means root dir */
51
52 #if __BYTE_ORDER == __BIG_ENDIAN
53 #define STORE32_LE(X)           ((((X) & 0x000000FF) << 24) | (((X) & 0x0000FF00) << 8) | (((X) & 0x00FF0000) >> 8) | (((X) & 0xFF000000) >> 24))
54 #elif __BYTE_ORDER == __LITTLE_ENDIAN
55 #define STORE32_LE(X)           (X)
56 #else
57 #error unkown endianness!
58 #endif
59
60 ssize_t pread(int fd, void *buf, size_t count, off_t offset);
61 ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset);
62
63 #define TRX_MAGIC       0x30524448      /* "HDR0" */
64 struct trx_header {
65         uint32_t magic;         /* "HDR0" */
66         uint32_t len;           /* Length of file including header */
67         uint32_t crc32;         /* 32-bit CRC from flag_version to end of file */
68         uint32_t flag_version;  /* 0:15 flags, 16:31 version */
69         uint32_t offsets[3];    /* Offsets of partitions from start of header */
70 };
71
72 static char *buf = NULL;
73 static char *imagefile = NULL;
74 static char *jffs2file = NULL, *jffs2dir = JFFS2_DEFAULT_DIR;
75 static int buflen = 0;
76 int quiet;
77 int no_erase;
78 int mtdsize = 0;
79 int erasesize = 0;
80
81 int mtd_open(const char *mtd, bool block)
82 {
83         FILE *fp;
84         char dev[PATH_MAX];
85         int i;
86         int ret;
87         int flags = O_RDWR | O_SYNC;
88
89         if ((fp = fopen("/proc/mtd", "r"))) {
90                 while (fgets(dev, sizeof(dev), fp)) {
91                         if (sscanf(dev, "mtd%d:", &i) && strstr(dev, mtd)) {
92                                 snprintf(dev, sizeof(dev), "/dev/mtd%s/%d", (block ? "block" : ""), i);
93                                 if ((ret=open(dev, flags))<0) {
94                                         snprintf(dev, sizeof(dev), "/dev/mtd%s%d", (block ? "block" : ""), i);
95                                         ret=open(dev, flags);
96                                 }
97                                 fclose(fp);
98                                 return ret;
99                         }
100                 }
101                 fclose(fp);
102         }
103
104         return open(mtd, flags);
105 }
106
107 int mtd_check_open(const char *mtd)
108 {
109         struct mtd_info_user mtdInfo;
110         int fd;
111
112         fd = mtd_open(mtd, false);
113         if(fd < 0) {
114                 fprintf(stderr, "Could not open mtd device: %s\n", mtd);
115                 return -1;
116         }
117
118         if(ioctl(fd, MEMGETINFO, &mtdInfo)) {
119                 fprintf(stderr, "Could not get MTD device info from %s\n", mtd);
120                 close(fd);
121                 return -1;
122         }
123         mtdsize = mtdInfo.size;
124         erasesize = mtdInfo.erasesize;
125
126         return fd;
127 }
128
129 int mtd_erase_block(int fd, int offset)
130 {
131         struct erase_info_user mtdEraseInfo;
132
133         mtdEraseInfo.start = offset;
134         mtdEraseInfo.length = erasesize;
135         ioctl(fd, MEMUNLOCK, &mtdEraseInfo);
136         if (ioctl (fd, MEMERASE, &mtdEraseInfo) < 0)
137                 return -1;
138
139         return 0;
140 }
141
142 int mtd_write_buffer(int fd, const char *buf, int offset, int length)
143 {
144         lseek(fd, offset, SEEK_SET);
145         write(fd, buf, length);
146         return 0;
147 }
148
149
150 static int
151 image_check(int imagefd, const char *mtd)
152 {
153         int ret = 1;
154 #ifdef target_brcm
155         ret = trx_check(imagefd, mtd, buf, &buflen);
156 #endif
157         return ret;
158 }
159
160 static int mtd_check(const char *mtd)
161 {
162         char *next = NULL;
163         char *str = NULL;
164         int fd;
165
166         if (strchr(mtd, ':')) {
167                 str = strdup(mtd);
168                 mtd = str;
169         }
170
171         do {
172                 next = strchr(mtd, ':');
173                 if (next) {
174                         *next = 0;
175                         next++;
176                 }
177
178                 fd = mtd_check_open(mtd);
179                 if (fd < 0)
180                         return 0;
181
182                 if (!buf)
183                         buf = malloc(erasesize);
184
185                 close(fd);
186                 mtd = next;
187         } while (next);
188
189         if (str)
190                 free(str);
191
192         return 1;
193 }
194
195 static int
196 mtd_unlock(const char *mtd)
197 {
198         struct erase_info_user mtdLockInfo;
199         char *next = NULL;
200         char *str = NULL;
201         int fd;
202
203         if (strchr(mtd, ':')) {
204                 str = strdup(mtd);
205                 mtd = str;
206         }
207
208         do {
209                 next = strchr(mtd, ':');
210                 if (next) {
211                         *next = 0;
212                         next++;
213                 }
214
215                 fd = mtd_check_open(mtd);
216                 if(fd < 0) {
217                         fprintf(stderr, "Could not open mtd device: %s\n", mtd);
218                         exit(1);
219                 }
220
221                 if (quiet < 2)
222                         fprintf(stderr, "Unlocking %s ...\n", mtd);
223
224                 mtdLockInfo.start = 0;
225                 mtdLockInfo.length = mtdsize;
226                 ioctl(fd, MEMUNLOCK, &mtdLockInfo);
227                 close(fd);
228                 mtd = next;
229         } while (next);
230
231         if (str)
232                 free(str);
233
234         return 0;
235 }
236
237 static int
238 mtd_erase(const char *mtd)
239 {
240         int fd;
241         struct erase_info_user mtdEraseInfo;
242
243         if (quiet < 2)
244                 fprintf(stderr, "Erasing %s ...\n", mtd);
245
246         fd = mtd_check_open(mtd);
247         if(fd < 0) {
248                 fprintf(stderr, "Could not open mtd device: %s\n", mtd);
249                 exit(1);
250         }
251
252         mtdEraseInfo.length = erasesize;
253
254         for (mtdEraseInfo.start = 0;
255                  mtdEraseInfo.start < mtdsize;
256                  mtdEraseInfo.start += erasesize) {
257
258                 ioctl(fd, MEMUNLOCK, &mtdEraseInfo);
259                 if(ioctl(fd, MEMERASE, &mtdEraseInfo))
260                         fprintf(stderr, "Failed to erase block on %s at 0x%x\n", mtd, mtdEraseInfo.start);
261         }
262
263         close(fd);
264         return 0;
265
266 }
267
268 static int
269 mtd_fixtrx(const char *mtd, size_t offset)
270 {
271         int fd;
272         struct trx_header *trx;
273         char *buf;
274         ssize_t res;
275         size_t block_offset;
276
277         if (quiet < 2)
278                 fprintf(stderr, "Trying to fix trx header in %s at 0x%x...\n", mtd, offset);
279
280         block_offset = offset & ~(erasesize - 1);
281         offset -= block_offset;
282
283         fd = mtd_check_open(mtd);
284         if(fd < 0) {
285                 fprintf(stderr, "Could not open mtd device: %s\n", mtd);
286                 exit(1);
287         }
288
289         if (block_offset + erasesize > mtdsize) {
290                 fprintf(stderr, "Offset too large, device size 0x%x\n", mtdsize);
291                 exit(1);
292         }
293
294         buf = malloc(erasesize);
295         if (!buf) {
296                 perror("malloc");
297                 exit(1);
298         }
299
300         res = pread(fd, buf, erasesize, block_offset);
301         if (res != erasesize) {
302                 perror("pread");
303                 exit(1);
304         }
305
306         trx = (struct trx_header *) (buf + offset);
307         if (trx->magic != STORE32_LE(0x30524448)) {
308                 fprintf(stderr, "No trx magic found\n");
309                 exit(1);
310         }
311
312         if (trx->len == STORE32_LE(erasesize - offset)) {
313                 if (quiet < 2)
314                         fprintf(stderr, "Header already fixed, exiting\n");
315                 close(fd);
316                 return 0;
317         }
318
319         trx->len = STORE32_LE(erasesize - offset);
320
321         trx->crc32 = STORE32_LE(crc32buf((char*) &trx->flag_version, erasesize - offset - 3*4));
322         if (mtd_erase_block(fd, block_offset)) {
323                 fprintf(stderr, "Can't erease block at 0x%x (%s)\n", block_offset, strerror(errno));
324                 exit(1);
325         }
326
327         if (quiet < 2)
328                 fprintf(stderr, "New crc32: 0x%x, rewriting block\n", trx->crc32);
329
330         if (pwrite(fd, buf, erasesize, block_offset) != erasesize) {
331                 fprintf(stderr, "Error writing block (%s)\n", strerror(errno));
332                 exit(1);
333         }
334
335         if (quiet < 2)
336                 fprintf(stderr, "Done.\n");
337
338         close (fd);
339         sync();
340         return 0;
341
342 }
343
344 static int
345 mtd_refresh(const char *mtd)
346 {
347         int fd;
348
349         if (quiet < 2)
350                 fprintf(stderr, "Refreshing mtd partition %s ... ", mtd);
351
352         fd = mtd_check_open(mtd);
353         if(fd < 0) {
354                 fprintf(stderr, "Could not open mtd device: %s\n", mtd);
355                 exit(1);
356         }
357
358         if (ioctl(fd, MTDREFRESH, NULL)) {
359                 fprintf(stderr, "Failed to refresh the MTD device\n");
360                 close(fd);
361                 exit(1);
362         }
363         close(fd);
364
365         if (quiet < 2)
366                 fprintf(stderr, "\n");
367
368         return 0;
369 }
370
371 static void
372 indicate_writing(const char *mtd)
373 {
374         if (quiet < 2)
375                 fprintf(stderr, "\nWriting from %s to %s ... ", imagefile, mtd);
376
377         if (!quiet)
378                 fprintf(stderr, " [ ]");
379 }
380
381 static int
382 mtd_write(int imagefd, const char *mtd, char *fis_layout)
383 {
384         char *next = NULL;
385         char *str = NULL;
386         int fd, result;
387         ssize_t r, w, e;
388         ssize_t skip = 0;
389         uint32_t offset = 0;
390
391 #ifdef FIS_SUPPORT
392         static struct fis_part new_parts[MAX_ARGS];
393         static struct fis_part old_parts[MAX_ARGS];
394         int n_new = 0, n_old = 0;
395
396         if (fis_layout) {
397                 const char *tmp = mtd;
398                 char *word, *brkt;
399                 int ret;
400
401                 memset(&old_parts, 0, sizeof(old_parts));
402                 memset(&new_parts, 0, sizeof(new_parts));
403
404                 do {
405                         next = strchr(tmp, ':');
406                         if (!next)
407                                 next = (char *) tmp + strlen(tmp);
408
409                         memcpy(old_parts[n_old].name, tmp, next - tmp);
410
411                         n_old++;
412                         tmp = next + 1;
413                 } while(*next);
414
415                 for (word = strtok_r(fis_layout, ",", &brkt);
416                      word;
417                          word = strtok_r(NULL, ",", &brkt)) {
418
419                         tmp = strtok(word, ":");
420                         strncpy((char *) new_parts[n_new].name, tmp, sizeof(new_parts[n_new].name) - 1);
421
422                         tmp = strtok(NULL, ":");
423                         if (!tmp)
424                                 goto next;
425
426                         new_parts[n_new].size = strtoul(tmp, NULL, 0);
427
428                         tmp = strtok(NULL, ":");
429                         if (!tmp)
430                                 goto next;
431
432                         new_parts[n_new].loadaddr = strtoul(tmp, NULL, 16);
433 next:
434                         n_new++;
435                 }
436                 ret = fis_validate(old_parts, n_old, new_parts, n_new);
437                 if (ret < 0) {
438                         fprintf(stderr, "Failed to validate the new FIS partition table\n");
439                         exit(1);
440                 }
441                 if (ret == 0)
442                         fis_layout = NULL;
443         }
444 #endif
445
446         if (strchr(mtd, ':')) {
447                 str = strdup(mtd);
448                 mtd = str;
449         }
450
451         r = 0;
452
453 resume:
454         next = strchr(mtd, ':');
455         if (next) {
456                 *next = 0;
457                 next++;
458         }
459
460         fd = mtd_check_open(mtd);
461         if(fd < 0) {
462                 fprintf(stderr, "Could not open mtd device: %s\n", mtd);
463                 exit(1);
464         }
465
466         indicate_writing(mtd);
467
468         w = e = 0;
469         for (;;) {
470                 /* buffer may contain data already (from trx check or last mtd partition write attempt) */
471                 while (buflen < erasesize) {
472                         r = read(imagefd, buf + buflen, erasesize - buflen);
473                         if (r < 0) {
474                                 if ((errno == EINTR) || (errno == EAGAIN))
475                                         continue;
476                                 else {
477                                         perror("read");
478                                         break;
479                                 }
480                         }
481
482                         if (r == 0)
483                                 break;
484
485                         buflen += r;
486                 }
487
488                 if (buflen == 0)
489                         break;
490
491                 if (skip > 0) {
492                         skip -= buflen;
493                         buflen = 0;
494                         if (skip <= 0)
495                                 indicate_writing(mtd);
496
497                         continue;
498                 }
499
500                 if (jffs2file) {
501                         if (memcmp(buf, JFFS2_EOF, sizeof(JFFS2_EOF) - 1) == 0) {
502                                 if (!quiet)
503                                         fprintf(stderr, "\b\b\b   ");
504                                 if (quiet < 2)
505                                         fprintf(stderr, "\nAppending jffs2 data from %s to %s...", jffs2file, mtd);
506                                 /* got an EOF marker - this is the place to add some jffs2 data */
507                                 skip = mtd_replace_jffs2(mtd, fd, e, jffs2file);
508
509                                 w += skip;
510                                 e += skip;
511                                 skip -= buflen;
512                                 buflen = 0;
513                                 offset = 0;
514                                 continue;
515                         }
516                         /* no EOF marker, make sure we figure out the last inode number
517                          * before appending some data */
518                         mtd_parse_jffs2data(buf, jffs2dir);
519                 }
520
521                 /* need to erase the next block before writing data to it */
522     if(no_erase)
523     {
524                 while (w + buflen > e) {
525                         if (!quiet)
526                                 fprintf(stderr, "\b\b\b[e]");
527
528
529                         if (mtd_erase_block(fd, e) < 0) {
530                                 if (next) {
531                                         if (w < e) {
532                                                 write(fd, buf + offset, e - w);
533                                                 offset = e - w;
534                                         }
535                                         w = 0;
536                                         e = 0;
537                                         close(fd);
538                                         mtd = next;
539                                         fprintf(stderr, "\b\b\b   \n");
540                                         goto resume;
541                                 } else {
542                                         fprintf(stderr, "Failed to erase block\n");
543                                         exit(1);
544                                 }
545                         }
546
547                         /* erase the chunk */
548                         e += erasesize;
549                 }
550     }
551
552                 if (!quiet)
553                         fprintf(stderr, "\b\b\b[w]");
554
555                 if ((result = write(fd, buf + offset, buflen)) < buflen) {
556                         if (result < 0) {
557                                 fprintf(stderr, "Error writing image.\n");
558                                 exit(1);
559                         } else {
560                                 fprintf(stderr, "Insufficient space.\n");
561                                 exit(1);
562                         }
563                 }
564                 w += buflen;
565
566                 buflen = 0;
567                 offset = 0;
568         }
569
570         if (!quiet)
571                 fprintf(stderr, "\b\b\b\b    ");
572
573 done:
574         if (quiet < 2)
575                 fprintf(stderr, "\n");
576
577 #ifdef FIS_SUPPORT
578         if (fis_layout) {
579                 if (fis_remap(old_parts, n_old, new_parts, n_new) < 0)
580                         fprintf(stderr, "Failed to update the FIS partition table\n");
581         }
582 #endif
583
584         close(fd);
585         return 0;
586 }
587
588 static void usage(void)
589 {
590         fprintf(stderr, "Usage: mtd [<options> ...] <command> [<arguments> ...] <device>[:<device>...]\n\n"
591         "The device is in the format of mtdX (eg: mtd4) or its label.\n"
592         "mtd recognizes these commands:\n"
593         "        unlock                  unlock the device\n"
594         "        refresh                 refresh mtd partition\n"
595         "        erase                   erase all data on device\n"
596         "        write <imagefile>|-     write <imagefile> (use - for stdin) to device\n"
597         "        jffs2write <file>       append <file> to the jffs2 partition on the device\n"
598         "        fixtrx                  fix the checksum in a trx header on first boot\n"
599         "Following options are available:\n"
600         "        -q                      quiet mode (once: no [w] on writing,\n"
601         "                                           twice: no status messages)\n"
602         "        -n                      write without first erasing the blocks\n"
603         "        -r                      reboot after successful command\n"
604         "        -f                      force write without trx checks\n"
605         "        -e <device>             erase <device> before executing the command\n"
606         "        -d <name>               directory for jffs2write, defaults to \"tmp\"\n"
607         "        -j <name>               integrate <file> into jffs2 data when writing an image\n"
608         "        -o offset               offset of the trx header in the partition (for fixtrx)\n"
609 #ifdef FIS_SUPPORT
610         "        -F <part>[:<size>[:<entrypoint>]][,<part>...]\n"
611         "                                alter the fis partition table to create new partitions replacing\n"
612         "                                the partitions provided as argument to the write command\n"
613         "                                (only valid together with the write command)\n"
614 #endif
615         "\n"
616         "Example: To write linux.trx to mtd4 labeled as linux and reboot afterwards\n"
617         "         mtd -r write linux.trx linux\n\n");
618         exit(1);
619 }
620
621 static void do_reboot(void)
622 {
623         fprintf(stderr, "Rebooting ...\n");
624         fflush(stderr);
625
626         /* try regular reboot method first */
627         system("/sbin/reboot");
628         sleep(2);
629
630         /* if we're still alive at this point, force the kernel to reboot */
631         syscall(SYS_reboot,LINUX_REBOOT_MAGIC1,LINUX_REBOOT_MAGIC2,LINUX_REBOOT_CMD_RESTART,NULL);
632 }
633
634 int main (int argc, char **argv)
635 {
636         int ch, i, boot, imagefd = 0, force, unlocked;
637         char *erase[MAX_ARGS], *device = NULL;
638         char *fis_layout = NULL;
639         size_t offset = 0;
640         enum {
641                 CMD_ERASE,
642                 CMD_WRITE,
643                 CMD_UNLOCK,
644                 CMD_REFRESH,
645                 CMD_JFFS2WRITE,
646                 CMD_FIXTRX,
647         } cmd = -1;
648
649         erase[0] = NULL;
650         boot = 0;
651         force = 0;
652         buflen = 0;
653         quiet = 0;
654   no_erase = 0;
655
656         while ((ch = getopt(argc, argv,
657 #ifdef FIS_SUPPORT
658                         "F:"
659 #endif
660                         "frnqe:d:j:o:")) != -1)
661                 switch (ch) {
662                         case 'f':
663                                 force = 1;
664                                 break;
665                         case 'r':
666                                 boot = 1;
667                                 break;
668       case 'n':
669         no_erase = 1;
670         break;
671                         case 'j':
672                                 jffs2file = optarg;
673                                 break;
674                         case 'q':
675                                 quiet++;
676                                 break;
677                         case 'e':
678                                 i = 0;
679                                 while ((erase[i] != NULL) && ((i + 1) < MAX_ARGS))
680                                         i++;
681
682                                 erase[i++] = optarg;
683                                 erase[i] = NULL;
684                                 break;
685                         case 'd':
686                                 jffs2dir = optarg;
687                                 break;
688                         case 'o':
689                                 errno = 0;
690                                 offset = strtoul(optarg, 0, 0);
691                                 if (errno) {
692                                         fprintf(stderr, "-o: illegal numeric string\n");
693                                         usage();
694                                 }
695                                 break;
696 #ifdef FIS_SUPPORT
697                         case 'F':
698                                 fis_layout = optarg;
699                                 break;
700 #endif
701                         case '?':
702                         default:
703                                 usage();
704                 }
705         argc -= optind;
706         argv += optind;
707
708         if (argc < 2)
709                 usage();
710
711         if ((strcmp(argv[0], "unlock") == 0) && (argc == 2)) {
712                 cmd = CMD_UNLOCK;
713                 device = argv[1];
714         } else if ((strcmp(argv[0], "refresh") == 0) && (argc == 2)) {
715                 cmd = CMD_REFRESH;
716                 device = argv[1];
717         } else if ((strcmp(argv[0], "erase") == 0) && (argc == 2)) {
718                 cmd = CMD_ERASE;
719                 device = argv[1];
720         } else if ((strcmp(argv[0], "fixtrx") == 0) && (argc == 2)) {
721                 cmd = CMD_FIXTRX;
722                 device = argv[1];
723         } else if ((strcmp(argv[0], "write") == 0) && (argc == 3)) {
724                 cmd = CMD_WRITE;
725                 device = argv[2];
726
727                 if (strcmp(argv[1], "-") == 0) {
728                         imagefile = "<stdin>";
729                         imagefd = 0;
730                 } else {
731                         imagefile = argv[1];
732                         if ((imagefd = open(argv[1], O_RDONLY)) < 0) {
733                                 fprintf(stderr, "Couldn't open image file: %s!\n", imagefile);
734                                 exit(1);
735                         }
736                 }
737
738                 if (!mtd_check(device)) {
739                         fprintf(stderr, "Can't open device for writing!\n");
740                         exit(1);
741                 }
742                 /* check trx file before erasing or writing anything */
743                 if (!image_check(imagefd, device) && !force) {
744                         fprintf(stderr, "Image check failed.\n");
745                         exit(1);
746                 }
747         } else if ((strcmp(argv[0], "jffs2write") == 0) && (argc == 3)) {
748                 cmd = CMD_JFFS2WRITE;
749                 device = argv[2];
750
751                 imagefile = argv[1];
752                 if (!mtd_check(device)) {
753                         fprintf(stderr, "Can't open device for writing!\n");
754                         exit(1);
755                 }
756         } else {
757                 usage();
758         }
759
760         sync();
761
762         i = 0;
763         unlocked = 0;
764         while (erase[i] != NULL) {
765                 mtd_unlock(erase[i]);
766                 mtd_erase(erase[i]);
767                 if (strcmp(erase[i], device) == 0)
768                         unlocked = 1;
769                 i++;
770         }
771
772         switch (cmd) {
773                 case CMD_UNLOCK:
774                         if (!unlocked)
775                                 mtd_unlock(device);
776                         break;
777                 case CMD_ERASE:
778                         if (!unlocked)
779                                 mtd_unlock(device);
780                         mtd_erase(device);
781                         break;
782                 case CMD_WRITE:
783                         if (!unlocked)
784                                 mtd_unlock(device);
785                         mtd_write(imagefd, device, fis_layout);
786                         break;
787                 case CMD_JFFS2WRITE:
788                         if (!unlocked)
789                                 mtd_unlock(device);
790                         mtd_write_jffs2(device, imagefile, jffs2dir);
791                         break;
792                 case CMD_REFRESH:
793                         mtd_refresh(device);
794                         break;
795                 case CMD_FIXTRX:
796                         mtd_fixtrx(device, offset);
797                         break;
798         }
799
800         sync();
801
802         if (boot)
803                 do_reboot();
804
805         return 0;
806 }