ubi_tools: a bit smaller applet resolution code
[oweals/busybox.git] / miscutils / flash_eraseall.c
1 /* vi: set sw=4 ts=4: */
2 /* eraseall.c -- erase the whole of a MTD device
3  *
4  * Ported to busybox from mtd-utils.
5  *
6  * Copyright (C) 2000 Arcom Control System Ltd
7  *
8  * Renamed to flash_eraseall.c
9  *
10  * Licensed under GPLv2 or later, see file LICENSE in this source tree.
11  */
12 //config:config FLASH_ERASEALL
13 //config:       bool "flash_eraseall (5.5 kb)"
14 //config:       default n  # doesn't build on Ubuntu 8.04
15 //config:       help
16 //config:       The flash_eraseall binary from mtd-utils as of git head c4c6a59eb.
17 //config:       This utility is used to erase the whole MTD device.
18
19 //applet:IF_FLASH_ERASEALL(APPLET(flash_eraseall, BB_DIR_USR_SBIN, BB_SUID_DROP))
20
21 //kbuild:lib-$(CONFIG_FLASH_ERASEALL) += flash_eraseall.o
22
23 //usage:#define flash_eraseall_trivial_usage
24 //usage:       "[-jNq] MTD_DEVICE"
25 //usage:#define flash_eraseall_full_usage "\n\n"
26 //usage:       "Erase an MTD device\n"
27 //usage:     "\n        -j      Format the device for jffs2"
28 //usage:     "\n        -N      Don't skip bad blocks"
29 //usage:     "\n        -q      Don't display progress messages"
30
31 #include "libbb.h"
32 #include <mtd/mtd-user.h>
33 #include <linux/jffs2.h>
34
35 #define OPTION_J  (1 << 0)
36 #define OPTION_N  (1 << 1)
37 #define OPTION_Q  (1 << 2)
38 #define IS_NAND   (1 << 3)
39
40 /* mtd/jffs2-user.h used to have this atrocity:
41 extern int target_endian;
42
43 #define t16(x) ({ __u16 __b = (x); (target_endian==__BYTE_ORDER)?__b:bswap_16(__b); })
44 #define t32(x) ({ __u32 __b = (x); (target_endian==__BYTE_ORDER)?__b:bswap_32(__b); })
45
46 #define cpu_to_je16(x) ((jint16_t){t16(x)})
47 #define cpu_to_je32(x) ((jint32_t){t32(x)})
48 #define cpu_to_jemode(x) ((jmode_t){t32(x)})
49
50 #define je16_to_cpu(x) (t16((x).v16))
51 #define je32_to_cpu(x) (t32((x).v32))
52 #define jemode_to_cpu(x) (t32((x).m))
53
54 but mtd/jffs2-user.h is gone now (at least 2.6.31.6 does not have it anymore)
55 */
56
57 /* We always use native endianness */
58 #undef cpu_to_je16
59 #undef cpu_to_je32
60 #define cpu_to_je16(v) ((jint16_t){(v)})
61 #define cpu_to_je32(v) ((jint32_t){(v)})
62
63 static void show_progress(mtd_info_t *meminfo, erase_info_t *erase)
64 {
65         printf("\rErasing %u Kibyte @ %x - %2u%% complete.",
66                 (unsigned)meminfo->erasesize / 1024,
67                 erase->start,
68                 (unsigned) ((unsigned long long) erase->start * 100 / meminfo->size)
69         );
70         fflush_all();
71 }
72
73 int flash_eraseall_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
74 int flash_eraseall_main(int argc UNUSED_PARAM, char **argv)
75 {
76         struct jffs2_unknown_node cleanmarker;
77         mtd_info_t meminfo;
78         int fd, clmpos, clmlen;
79         erase_info_t erase;
80         struct stat st;
81         unsigned int flags;
82         char *mtd_name;
83
84         opt_complementary = "=1";
85         flags = getopt32(argv, "jNq");
86
87         mtd_name = argv[optind];
88         fd = xopen(mtd_name, O_RDWR);
89         fstat(fd, &st);
90         if (!S_ISCHR(st.st_mode))
91                 bb_error_msg_and_die("%s: not a char device", mtd_name);
92
93         xioctl(fd, MEMGETINFO, &meminfo);
94         erase.length = meminfo.erasesize;
95         if (meminfo.type == MTD_NANDFLASH)
96                 flags |= IS_NAND;
97
98         clmpos = 0;
99         clmlen = 8;
100         if (flags & OPTION_J) {
101                 uint32_t *crc32_table;
102
103                 crc32_table = crc32_filltable(NULL, 0);
104
105                 cleanmarker.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
106                 cleanmarker.nodetype = cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER);
107                 if (!(flags & IS_NAND))
108                         cleanmarker.totlen = cpu_to_je32(sizeof(struct jffs2_unknown_node));
109                 else {
110                         struct nand_oobinfo oobinfo;
111
112                         xioctl(fd, MEMGETOOBSEL, &oobinfo);
113
114                         /* Check for autoplacement */
115                         if (oobinfo.useecc == MTD_NANDECC_AUTOPLACE) {
116                                 /* Get the position of the free bytes */
117                                 clmpos = oobinfo.oobfree[0][0];
118                                 clmlen = oobinfo.oobfree[0][1];
119                                 if (clmlen > 8)
120                                         clmlen = 8;
121                                 if (clmlen == 0)
122                                         bb_error_msg_and_die("autoplacement selected and no empty space in oob");
123                         } else {
124                                 /* Legacy mode */
125                                 switch (meminfo.oobsize) {
126                                 case 8:
127                                         clmpos = 6;
128                                         clmlen = 2;
129                                         break;
130                                 case 16:
131                                         clmpos = 8;
132                                         /*clmlen = 8;*/
133                                         break;
134                                 case 64:
135                                         clmpos = 16;
136                                         /*clmlen = 8;*/
137                                         break;
138                                 }
139                         }
140                         cleanmarker.totlen = cpu_to_je32(8);
141                 }
142
143                 cleanmarker.hdr_crc = cpu_to_je32(
144                         crc32_block_endian0(0, &cleanmarker, sizeof(struct jffs2_unknown_node) - 4, crc32_table)
145                 );
146         }
147
148         /* Don't want to destroy progress indicator by bb_error_msg's */
149         applet_name = xasprintf("\n%s: %s", applet_name, mtd_name);
150
151         for (erase.start = 0; erase.start < meminfo.size;
152              erase.start += meminfo.erasesize) {
153                 if (!(flags & OPTION_N)) {
154                         int ret;
155                         loff_t offset = erase.start;
156
157                         ret = ioctl(fd, MEMGETBADBLOCK, &offset);
158                         if (ret > 0) {
159                                 if (!(flags & OPTION_Q))
160                                         printf("\nSkipping bad block at 0x%08x\n", erase.start);
161                                 continue;
162                         }
163                         if (ret < 0) {
164                                 /* Black block table is not available on certain flash
165                                  * types e.g. NOR
166                                  */
167                                 if (errno == EOPNOTSUPP) {
168                                         flags |= OPTION_N;
169                                         if (flags & IS_NAND)
170                                                 bb_error_msg_and_die("bad block check not available");
171                                 } else {
172                                         bb_perror_msg_and_die("MEMGETBADBLOCK error");
173                                 }
174                         }
175                 }
176
177                 if (!(flags & OPTION_Q))
178                         show_progress(&meminfo, &erase);
179
180                 xioctl(fd, MEMERASE, &erase);
181
182                 /* format for JFFS2 ? */
183                 if (!(flags & OPTION_J))
184                         continue;
185
186                 /* write cleanmarker */
187                 if (flags & IS_NAND) {
188                         struct mtd_oob_buf oob;
189
190                         oob.ptr = (unsigned char *) &cleanmarker;
191                         oob.start = erase.start + clmpos;
192                         oob.length = clmlen;
193                         xioctl(fd, MEMWRITEOOB, &oob);
194                 } else {
195                         xlseek(fd, erase.start, SEEK_SET);
196                         /* if (lseek(fd, erase.start, SEEK_SET) < 0) {
197                                 bb_perror_msg("MTD %s failure", "seek");
198                                 continue;
199                         } */
200                         xwrite(fd, &cleanmarker, sizeof(cleanmarker));
201                         /* if (write(fd, &cleanmarker, sizeof(cleanmarker)) != sizeof(cleanmarker)) {
202                                 bb_perror_msg("MTD %s failure", "write");
203                                 continue;
204                         } */
205                 }
206                 if (!(flags & OPTION_Q))
207                         printf(" Cleanmarker written at %x.", erase.start);
208         }
209         if (!(flags & OPTION_Q)) {
210                 show_progress(&meminfo, &erase);
211                 bb_putchar('\n');
212         }
213
214         if (ENABLE_FEATURE_CLEAN_UP)
215                 close(fd);
216         return EXIT_SUCCESS;
217 }