2 * Ported to busybox from mtd-utils.
4 * Licensed under GPLv2, see file LICENSE in this source tree.
6 //config:config UBIATTACH
7 //config: bool "ubiattach (4.5 kb)"
10 //config: Attach MTD device to an UBI device.
12 //config:config UBIDETACH
13 //config: bool "ubidetach (4.3 kb)"
16 //config: Detach MTD device from an UBI device.
18 //config:config UBIMKVOL
19 //config: bool "ubimkvol (5.5 kb)"
22 //config: Create a UBI volume.
24 //config:config UBIRMVOL
25 //config: bool "ubirmvol (5.1 kb)"
28 //config: Delete a UBI volume.
30 //config:config UBIRSVOL
31 //config: bool "ubirsvol (4.4 kb)"
34 //config: Resize a UBI volume.
36 //config:config UBIUPDATEVOL
37 //config: bool "ubiupdatevol (5.6 kb)"
40 //config: Update a UBI volume.
42 // APPLET_ODDNAME:name main location suid_type help
43 //applet:IF_UBIATTACH( APPLET_ODDNAME(ubiattach, ubi_tools, BB_DIR_USR_SBIN, BB_SUID_DROP, ubiattach))
44 //applet:IF_UBIDETACH( APPLET_ODDNAME(ubidetach, ubi_tools, BB_DIR_USR_SBIN, BB_SUID_DROP, ubidetach))
45 //applet:IF_UBIMKVOL( APPLET_ODDNAME(ubimkvol, ubi_tools, BB_DIR_USR_SBIN, BB_SUID_DROP, ubimkvol))
46 //applet:IF_UBIRMVOL( APPLET_ODDNAME(ubirmvol, ubi_tools, BB_DIR_USR_SBIN, BB_SUID_DROP, ubirmvol))
47 //applet:IF_UBIRSVOL( APPLET_ODDNAME(ubirsvol, ubi_tools, BB_DIR_USR_SBIN, BB_SUID_DROP, ubirsvol))
48 //applet:IF_UBIUPDATEVOL(APPLET_ODDNAME(ubiupdatevol, ubi_tools, BB_DIR_USR_SBIN, BB_SUID_DROP, ubiupdatevol))
49 /* not NOEXEC: if flash operation stalls, use less memory in "hung" process */
51 //kbuild:lib-$(CONFIG_UBIATTACH) += ubi_tools.o
52 //kbuild:lib-$(CONFIG_UBIDETACH) += ubi_tools.o
53 //kbuild:lib-$(CONFIG_UBIMKVOL) += ubi_tools.o
54 //kbuild:lib-$(CONFIG_UBIRMVOL) += ubi_tools.o
55 //kbuild:lib-$(CONFIG_UBIRSVOL) += ubi_tools.o
56 //kbuild:lib-$(CONFIG_UBIUPDATEVOL) += ubi_tools.o
59 /* Some versions of kernel have broken headers, need this hack */
61 # define __packed __attribute__((packed))
63 #include <mtd/ubi-user.h>
65 #define UBI_APPLET_CNT (0 \
71 + ENABLE_UBIUPDATEVOL \
74 #define do_attach (ENABLE_UBIATTACH && (UBI_APPLET_CNT == 1 || applet_name[4] == 't'))
75 #define do_detach (ENABLE_UBIDETACH && (UBI_APPLET_CNT == 1 || applet_name[4] == 'e'))
76 #define do_mkvol (ENABLE_UBIMKVOL && (UBI_APPLET_CNT == 1 || applet_name[4] == 'k'))
77 #define do_rmvol (ENABLE_UBIRMVOL && (UBI_APPLET_CNT == 1 || applet_name[4] == 'm'))
78 #define do_rsvol (ENABLE_UBIRSVOL && (UBI_APPLET_CNT == 1 || applet_name[4] == 's'))
79 #define do_update (ENABLE_UBIUPDATEVOL && (UBI_APPLET_CNT == 1 || applet_name[4] == 'p'))
81 static unsigned get_num_from_file(const char *path
, unsigned max
)
83 char buf
[sizeof(long long)*3];
84 unsigned long long num
;
86 if (open_read_close(path
, buf
, sizeof(buf
)) < 0)
87 bb_perror_msg_and_die("can't open '%s'", path
);
88 /* It can be \n terminated, xatoull won't work well */
89 if (sscanf(buf
, "%llu", &num
) != 1 || num
> max
)
90 bb_error_msg_and_die("number in '%s' is malformed or too large", path
);
94 /* To prevent malloc(1G) accidents */
95 #define MAX_SANE_ERASEBLOCK (16*1024*1024)
97 int ubi_tools_main(int argc
, char **argv
) MAIN_EXTERNALLY_VISIBLE
;
98 int ubi_tools_main(int argc UNUSED_PARAM
, char **argv
)
100 static const struct suffix_mult size_suffixes
[] ALIGN_SUFFIX
= {
102 { "MiB", 1024*1024 },
103 { "GiB", 1024*1024*1024 },
111 int dev_num
= UBI_DEV_NUM_AUTO
;
112 int vol_id
= UBI_VOL_NUM_AUTO
;
113 int vid_hdr_offset
= 0;
115 unsigned long long size_bytes
= size_bytes
; /* for compiler */
116 char *size_bytes_str
;
120 struct ubi_attach_req attach_req
;
121 struct ubi_mkvol_req mkvol_req
;
122 struct ubi_rsvol_req rsvol_req
;
124 #define attach_req req_structs.attach_req
125 #define mkvol_req req_structs.mkvol_req
126 #define rsvol_req req_structs.rsvol_req
127 char path
[sizeof("/sys/class/ubi/ubi%d_%d/usable_eb_size")
128 + 2 * sizeof(int)*3 + /*just in case:*/ 16];
129 #define path_sys_class_ubi_ubi (path + sizeof("/sys/class/ubi/ubi")-1)
131 strcpy(path
, "/sys/class/ubi/ubi");
132 memset(&req_structs
, 0, sizeof(req_structs
));
134 #define OPTION_m (1 << 0)
135 #define OPTION_d (1 << 1)
136 #define OPTION_n (1 << 2)
137 #define OPTION_N (1 << 3)
138 #define OPTION_s (1 << 4)
139 #define OPTION_a (1 << 5)
140 #define OPTION_t (1 << 6)
142 opts
= getopt32(argv
, "^" "md:+n:+N:s:a:+t:O:+" "\0" "-1",
144 &vol_name
, &size_bytes_str
, &alignment
, &type
,
149 opts
= getopt32(argv
, "^" "s:at" "\0" "-1", &size_bytes_str
);
152 opts
= getopt32(argv
, "^" "m:+d:+n:+N:s:a:+t:" "\0" "-1",
153 &mtd_num
, &dev_num
, &vol_id
,
154 &vol_name
, &size_bytes_str
, &alignment
, &type
159 size_bytes
= xatoull_sfx(size_bytes_str
, size_suffixes
);
163 fd
= xopen(ubi_ctrl
, O_RDWR
);
164 //xfstat(fd, &st, ubi_ctrl);
165 //if (!S_ISCHR(st.st_mode))
166 // bb_error_msg_and_die("%s: not a char device", ubi_ctrl);
168 //usage:#define ubiattach_trivial_usage
169 //usage: "-m MTD_NUM [-d UBI_NUM] [-O VID_HDR_OFF] UBI_CTRL_DEV"
170 //usage:#define ubiattach_full_usage "\n\n"
171 //usage: "Attach MTD device to UBI\n"
172 //usage: "\n -m MTD_NUM MTD device number to attach"
173 //usage: "\n -d UBI_NUM UBI device number to assign"
174 //usage: "\n -O VID_HDR_OFF VID header offset"
176 if (!(opts
& OPTION_m
))
177 bb_error_msg_and_die("%s device not specified", "MTD");
179 attach_req
.mtd_num
= mtd_num
;
180 attach_req
.ubi_num
= dev_num
;
181 attach_req
.vid_hdr_offset
= vid_hdr_offset
;
183 xioctl(fd
, UBI_IOCATT
, &attach_req
);
186 //usage:#define ubidetach_trivial_usage
187 //usage: "-d UBI_NUM UBI_CTRL_DEV"
188 //usage:#define ubidetach_full_usage "\n\n"
189 //usage: "Detach MTD device from UBI\n"
190 //usage: "\n -d UBI_NUM UBI device number"
192 if (!(opts
& OPTION_d
))
193 bb_error_msg_and_die("%s device not specified", "UBI");
195 /* FIXME? kernel expects int32_t* here: */
196 xioctl(fd
, UBI_IOCDET
, &dev_num
);
199 //usage:#define ubimkvol_trivial_usage
200 //usage: "-N NAME [-s SIZE | -m] UBI_DEVICE"
201 //usage:#define ubimkvol_full_usage "\n\n"
202 //usage: "Create UBI volume\n"
203 //usage: "\n -a ALIGNMENT Volume alignment (default 1)"
204 //usage: "\n -m Set volume size to maximum available"
205 //usage: "\n -n VOLID Volume ID. If not specified,"
206 //usage: "\n assigned automatically"
207 //usage: "\n -N NAME Volume name"
208 //usage: "\n -s SIZE Size in bytes"
209 //usage: "\n -t TYPE Volume type (static|dynamic)"
211 if (opts
& OPTION_m
) {
217 num
= ubi_devnum_from_devname(ubi_ctrl
);
218 p
= path_sys_class_ubi_ubi
+ sprintf(path_sys_class_ubi_ubi
, "%u/", num
);
220 strcpy(p
, "avail_eraseblocks");
221 leb_avail
= get_num_from_file(path
, UINT_MAX
);
223 strcpy(p
, "eraseblock_size");
224 leb_size
= get_num_from_file(path
, MAX_SANE_ERASEBLOCK
);
226 size_bytes
= leb_avail
* (unsigned long long)leb_size
;
227 //if (size_bytes <= 0)
228 // bb_error_msg_and_die("%s invalid maximum size calculated", "UBI");
230 if (!(opts
& OPTION_s
))
231 bb_simple_error_msg_and_die("size not specified");
233 if (!(opts
& OPTION_N
))
234 bb_simple_error_msg_and_die("name not specified");
236 /* the structure is memset(0) above */
237 mkvol_req
.vol_id
= vol_id
;
238 mkvol_req
.vol_type
= UBI_DYNAMIC_VOLUME
;
239 if ((opts
& OPTION_t
) && type
[0] == 's')
240 mkvol_req
.vol_type
= UBI_STATIC_VOLUME
;
241 mkvol_req
.alignment
= alignment
;
242 mkvol_req
.bytes
= size_bytes
; /* signed int64_t */
243 /* strnlen avoids overflow of 16-bit field (paranoia) */
244 mkvol_req
.name_len
= strnlen(vol_name
, UBI_MAX_VOLUME_NAME
+1);
245 if (mkvol_req
.name_len
> UBI_MAX_VOLUME_NAME
)
246 bb_error_msg_and_die("volume name too long: '%s'", vol_name
);
247 /* this is safe: .name[] is UBI_MAX_VOLUME_NAME+1 bytes */
248 strcpy(mkvol_req
.name
, vol_name
);
250 xioctl(fd
, UBI_IOCMKVOL
, &mkvol_req
);
253 //usage:#define ubirmvol_trivial_usage
254 //usage: "-n VOLID | -N VOLNAME UBI_DEVICE"
255 //usage:#define ubirmvol_full_usage "\n\n"
256 //usage: "Remove UBI volume\n"
257 //usage: "\n -n VOLID Volume ID"
258 //usage: "\n -N VOLNAME Volume name"
260 if (!(opts
& (OPTION_n
|OPTION_N
)))
261 bb_simple_error_msg_and_die("volume id not specified");
263 if (opts
& OPTION_N
) {
264 unsigned num
= ubi_devnum_from_devname(ubi_ctrl
);
265 vol_id
= ubi_get_volid_by_name(num
, vol_name
);
268 if (sizeof(vol_id
) != 4) {
269 /* kernel expects int32_t* in this ioctl */
271 xioctl(fd
, UBI_IOCRMVOL
, &t
);
273 xioctl(fd
, UBI_IOCRMVOL
, &vol_id
);
277 //usage:#define ubirsvol_trivial_usage
278 //usage: "-n VOLID -s SIZE UBI_DEVICE"
279 //usage:#define ubirsvol_full_usage "\n\n"
280 //usage: "Resize UBI volume\n"
281 //usage: "\n -n VOLID Volume ID"
282 //usage: "\n -s SIZE Size in bytes"
284 if (!(opts
& OPTION_s
))
285 bb_simple_error_msg_and_die("size not specified");
286 if (!(opts
& OPTION_n
))
287 bb_simple_error_msg_and_die("volume id not specified");
289 rsvol_req
.bytes
= size_bytes
; /* signed int64_t */
290 rsvol_req
.vol_id
= vol_id
;
292 xioctl(fd
, UBI_IOCRSVOL
, &rsvol_req
);
295 //usage:#define ubiupdatevol_trivial_usage
296 //usage: "-t UBI_DEVICE | [-s SIZE] UBI_DEVICE IMG_FILE"
297 //usage:#define ubiupdatevol_full_usage "\n\n"
298 //usage: "Update UBI volume\n"
299 //usage: "\n -t Truncate to zero size"
300 //usage: "\n -s SIZE Size in bytes to resize to"
304 if (opts
& OPTION_t
) {
305 /* truncate the volume by starting an update for size 0 */
307 /* this ioctl expects int64_t* parameter */
308 xioctl(fd
, UBI_IOCVOLUP
, &bytes64
);
311 unsigned ubinum
, volnum
;
315 /* Assume that device is in normal format. */
316 /* Removes need for scanning sysfs tree as full libubi does. */
317 if (sscanf(ubi_ctrl
, "/dev/ubi%u_%u", &ubinum
, &volnum
) != 2)
318 bb_error_msg_and_die("UBI device name '%s' is not /dev/ubiN_M", ubi_ctrl
);
320 sprintf(path_sys_class_ubi_ubi
, "%u_%u/usable_eb_size", ubinum
, volnum
);
321 leb_size
= get_num_from_file(path
, MAX_SANE_ERASEBLOCK
);
325 if (NOT_LONE_DASH(*argv
)) /* mtd-utils supports "-" as stdin */
326 xmove_fd(xopen(*argv
, O_RDONLY
), STDIN_FILENO
);
328 if (!(opts
& OPTION_s
)) {
330 xfstat(STDIN_FILENO
, &st
, *argv
);
331 size_bytes
= st
.st_size
;
334 bytes64
= size_bytes
;
335 /* this ioctl expects signed int64_t* parameter */
336 xioctl(fd
, UBI_IOCVOLUP
, &bytes64
);
338 /* can't use bb_copyfd_exact_size(): copy in blocks of exactly leb_size */
339 buf
= xmalloc(leb_size
);
340 while (size_bytes
!= 0) {
341 int len
= full_read(STDIN_FILENO
, buf
, leb_size
);
344 bb_perror_msg_and_die("read error from '%s'", *argv
);
347 if ((unsigned)len
> size_bytes
) {
348 /* for this case: "ubiupdatevol -s 1024000 $UBIDEV /dev/urandom" */
351 xwrite(fd
, buf
, len
);
354 if (ENABLE_FEATURE_CLEAN_UP
)
359 if (ENABLE_FEATURE_CLEAN_UP
)