source: MondoRescue/branches/3.3/mindi-busybox/miscutils/ubi_tools.c@ 3865

Last change on this file since 3865 was 3621, checked in by Bruno Cornec, 10 years ago

New 3?3 banch for incorporation of latest busybox 1.25. Changing minor version to handle potential incompatibilities.

  • Property svn:eol-style set to native
File size: 10.6 KB
Line 
1/* Ported to busybox from mtd-utils.
2 *
3 * Licensed under GPLv2, see file LICENSE in this source tree.
4 */
5
6//config:config UBIATTACH
7//config: bool "ubiattach"
8//config: default y
9//config: select PLATFORM_LINUX
10//config: help
11//config: Attach MTD device to an UBI device.
12//config:
13//config:config UBIDETACH
14//config: bool "ubidetach"
15//config: default y
16//config: select PLATFORM_LINUX
17//config: help
18//config: Detach MTD device from an UBI device.
19//config:
20//config:config UBIMKVOL
21//config: bool "ubimkvol"
22//config: default y
23//config: select PLATFORM_LINUX
24//config: help
25//config: Create a UBI volume.
26//config:
27//config:config UBIRMVOL
28//config: bool "ubirmvol"
29//config: default y
30//config: select PLATFORM_LINUX
31//config: help
32//config: Delete a UBI volume.
33//config:
34//config:config UBIRSVOL
35//config: bool "ubirsvol"
36//config: default y
37//config: select PLATFORM_LINUX
38//config: help
39//config: Resize a UBI volume.
40//config:
41//config:config UBIUPDATEVOL
42//config: bool "ubiupdatevol"
43//config: default y
44//config: select PLATFORM_LINUX
45//config: help
46//config: Update a UBI volume.
47
48//applet:IF_UBIATTACH(APPLET_ODDNAME(ubiattach, ubi_tools, BB_DIR_USR_SBIN, BB_SUID_DROP, ubiattach))
49//applet:IF_UBIDETACH(APPLET_ODDNAME(ubidetach, ubi_tools, BB_DIR_USR_SBIN, BB_SUID_DROP, ubidetach))
50//applet:IF_UBIMKVOL(APPLET_ODDNAME(ubimkvol, ubi_tools, BB_DIR_USR_SBIN, BB_SUID_DROP, ubimkvol))
51//applet:IF_UBIRMVOL(APPLET_ODDNAME(ubirmvol, ubi_tools, BB_DIR_USR_SBIN, BB_SUID_DROP, ubirmvol))
52//applet:IF_UBIRSVOL(APPLET_ODDNAME(ubirsvol, ubi_tools, BB_DIR_USR_SBIN, BB_SUID_DROP, ubirsvol))
53//applet:IF_UBIUPDATEVOL(APPLET_ODDNAME(ubiupdatevol, ubi_tools, BB_DIR_USR_SBIN, BB_SUID_DROP, ubiupdatevol))
54
55//kbuild:lib-$(CONFIG_UBIATTACH) += ubi_tools.o
56//kbuild:lib-$(CONFIG_UBIDETACH) += ubi_tools.o
57//kbuild:lib-$(CONFIG_UBIMKVOL) += ubi_tools.o
58//kbuild:lib-$(CONFIG_UBIRMVOL) += ubi_tools.o
59//kbuild:lib-$(CONFIG_UBIRSVOL) += ubi_tools.o
60//kbuild:lib-$(CONFIG_UBIUPDATEVOL) += ubi_tools.o
61
62#include "libbb.h"
63/* Some versions of kernel have broken headers, need this hack */
64#ifndef __packed
65# define __packed __attribute__((packed))
66#endif
67#include <mtd/ubi-user.h>
68
69#define do_attach (ENABLE_UBIATTACH && applet_name[3] == 'a')
70#define do_detach (ENABLE_UBIDETACH && applet_name[3] == 'd')
71#define do_mkvol (ENABLE_UBIMKVOL && applet_name[3] == 'm')
72#define do_rmvol (ENABLE_UBIRMVOL && applet_name[4] == 'm')
73#define do_rsvol (ENABLE_UBIRSVOL && applet_name[4] == 's')
74#define do_update (ENABLE_UBIUPDATEVOL && applet_name[3] == 'u')
75
76static unsigned get_num_from_file(const char *path, unsigned max, const char *errmsg)
77{
78 char buf[sizeof(long long)*3];
79 unsigned long long num;
80
81 if (open_read_close(path, buf, sizeof(buf)) < 0)
82 bb_perror_msg_and_die(errmsg, path);
83 /* It can be \n terminated, xatoull won't work well */
84 if (sscanf(buf, "%llu", &num) != 1 || num > max)
85 bb_error_msg_and_die(errmsg, path);
86 return num;
87}
88
89/* To prevent malloc(1G) accidents */
90#define MAX_SANE_ERASEBLOCK (16*1024*1024)
91
92int ubi_tools_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
93int ubi_tools_main(int argc UNUSED_PARAM, char **argv)
94{
95 static const struct suffix_mult size_suffixes[] = {
96 { "KiB", 1024 },
97 { "MiB", 1024*1024 },
98 { "GiB", 1024*1024*1024 },
99 { "", 0 }
100 };
101
102 unsigned opts;
103 char *ubi_ctrl;
104 int fd;
105 int mtd_num;
106 int dev_num = UBI_DEV_NUM_AUTO;
107 int vol_id = UBI_VOL_NUM_AUTO;
108 int vid_hdr_offset = 0;
109 char *vol_name;
110 unsigned long long size_bytes = size_bytes; /* for compiler */
111 char *size_bytes_str;
112 int alignment = 1;
113 char *type;
114 union {
115 struct ubi_attach_req attach_req;
116 struct ubi_mkvol_req mkvol_req;
117 struct ubi_rsvol_req rsvol_req;
118 } req_structs;
119#define attach_req req_structs.attach_req
120#define mkvol_req req_structs.mkvol_req
121#define rsvol_req req_structs.rsvol_req
122 char path[sizeof("/sys/class/ubi/ubi%d_%d/usable_eb_size")
123 + 2 * sizeof(int)*3 + /*just in case:*/ 16];
124#define path_sys_class_ubi_ubi (path + sizeof("/sys/class/ubi/ubi")-1)
125
126 strcpy(path, "/sys/class/ubi/ubi");
127 memset(&req_structs, 0, sizeof(req_structs));
128
129#define OPTION_m (1 << 0)
130#define OPTION_d (1 << 1)
131#define OPTION_n (1 << 2)
132#define OPTION_N (1 << 3)
133#define OPTION_s (1 << 4)
134#define OPTION_a (1 << 5)
135#define OPTION_t (1 << 6)
136 if (do_mkvol) {
137 opt_complementary = "-1:d+:n+:a+:O+";
138 opts = getopt32(argv, "md:n:N:s:a:t:O:",
139 &dev_num, &vol_id,
140 &vol_name, &size_bytes_str, &alignment, &type,
141 &vid_hdr_offset
142 );
143 } else
144 if (do_update) {
145 opt_complementary = "-1";
146 opts = getopt32(argv, "s:at", &size_bytes_str);
147 opts *= OPTION_s;
148 } else {
149 opt_complementary = "-1:m+:d+:n+:a+";
150 opts = getopt32(argv, "m:d:n:N:s:a:t:",
151 &mtd_num, &dev_num, &vol_id,
152 &vol_name, &size_bytes_str, &alignment, &type
153 );
154 }
155
156 if (opts & OPTION_s)
157 size_bytes = xatoull_sfx(size_bytes_str, size_suffixes);
158 argv += optind;
159 ubi_ctrl = *argv++;
160
161 fd = xopen(ubi_ctrl, O_RDWR);
162 //xfstat(fd, &st, ubi_ctrl);
163 //if (!S_ISCHR(st.st_mode))
164 // bb_error_msg_and_die("%s: not a char device", ubi_ctrl);
165
166//usage:#define ubiattach_trivial_usage
167//usage: "-m MTD_NUM [-d UBI_NUM] [-O VID_HDR_OFF] UBI_CTRL_DEV"
168//usage:#define ubiattach_full_usage "\n\n"
169//usage: "Attach MTD device to UBI\n"
170//usage: "\n -m MTD_NUM MTD device number to attach"
171//usage: "\n -d UBI_NUM UBI device number to assign"
172//usage: "\n -O VID_HDR_OFF VID header offset"
173 if (do_attach) {
174 if (!(opts & OPTION_m))
175 bb_error_msg_and_die("%s device not specified", "MTD");
176
177 attach_req.mtd_num = mtd_num;
178 attach_req.ubi_num = dev_num;
179 attach_req.vid_hdr_offset = vid_hdr_offset;
180
181 xioctl(fd, UBI_IOCATT, &attach_req);
182 } else
183
184//usage:#define ubidetach_trivial_usage
185//usage: "-d UBI_NUM UBI_CTRL_DEV"
186//usage:#define ubidetach_full_usage "\n\n"
187//usage: "Detach MTD device from UBI\n"
188//usage: "\n -d UBI_NUM UBI device number"
189 if (do_detach) {
190 if (!(opts & OPTION_d))
191 bb_error_msg_and_die("%s device not specified", "UBI");
192
193 /* FIXME? kernel expects int32_t* here: */
194 xioctl(fd, UBI_IOCDET, &dev_num);
195 } else
196
197//usage:#define ubimkvol_trivial_usage
198//usage: "-N NAME [-s SIZE | -m] UBI_DEVICE"
199//usage:#define ubimkvol_full_usage "\n\n"
200//usage: "Create UBI volume\n"
201//usage: "\n -a ALIGNMENT Volume alignment (default 1)"
202//usage: "\n -m Set volume size to maximum available"
203//usage: "\n -n VOLID Volume ID. If not specified,"
204//usage: "\n assigned automatically"
205//usage: "\n -N NAME Volume name"
206//usage: "\n -s SIZE Size in bytes"
207//usage: "\n -t TYPE Volume type (static|dynamic)"
208 if (do_mkvol) {
209 if (opts & OPTION_m) {
210 unsigned leb_avail;
211 unsigned leb_size;
212 unsigned num;
213 char *p;
214
215 num = ubi_devnum_from_devname(ubi_ctrl);
216 p = path_sys_class_ubi_ubi + sprintf(path_sys_class_ubi_ubi, "%u/", num);
217
218 strcpy(p, "avail_eraseblocks");
219 leb_avail = get_num_from_file(path, UINT_MAX, "Can't get available eraseblocks from '%s'");
220
221 strcpy(p, "eraseblock_size");
222 leb_size = get_num_from_file(path, MAX_SANE_ERASEBLOCK, "Can't get eraseblock size from '%s'");
223
224 size_bytes = leb_avail * (unsigned long long)leb_size;
225 //if (size_bytes <= 0)
226 // bb_error_msg_and_die("%s invalid maximum size calculated", "UBI");
227 } else
228 if (!(opts & OPTION_s))
229 bb_error_msg_and_die("size not specified");
230
231 if (!(opts & OPTION_N))
232 bb_error_msg_and_die("name not specified");
233
234 mkvol_req.vol_id = vol_id;
235 mkvol_req.vol_type = UBI_DYNAMIC_VOLUME;
236 if ((opts & OPTION_t) && type[0] == 's')
237 mkvol_req.vol_type = UBI_STATIC_VOLUME;
238 mkvol_req.alignment = alignment;
239 mkvol_req.bytes = size_bytes; /* signed int64_t */
240 strncpy(mkvol_req.name, vol_name, UBI_MAX_VOLUME_NAME);
241 mkvol_req.name_len = strlen(vol_name);
242 if (mkvol_req.name_len > UBI_MAX_VOLUME_NAME)
243 bb_error_msg_and_die("volume name too long: '%s'", vol_name);
244
245 xioctl(fd, UBI_IOCMKVOL, &mkvol_req);
246 } else
247
248//usage:#define ubirmvol_trivial_usage
249//usage: "-n VOLID / -N VOLNAME UBI_DEVICE"
250//usage:#define ubirmvol_full_usage "\n\n"
251//usage: "Remove UBI volume\n"
252//usage: "\n -n VOLID Volume ID"
253//usage: "\n -N VOLNAME Volume name"
254 if (do_rmvol) {
255 if (!(opts & (OPTION_n|OPTION_N)))
256 bb_error_msg_and_die("volume id not specified");
257
258 if (opts & OPTION_N) {
259 unsigned num = ubi_devnum_from_devname(ubi_ctrl);
260 vol_id = ubi_get_volid_by_name(num, vol_name);
261 }
262
263 if (sizeof(vol_id) != 4) {
264 /* kernel expects int32_t* in this ioctl */
265 int32_t t = vol_id;
266 xioctl(fd, UBI_IOCRMVOL, &t);
267 } else {
268 xioctl(fd, UBI_IOCRMVOL, &vol_id);
269 }
270 } else
271
272//usage:#define ubirsvol_trivial_usage
273//usage: "-n VOLID -s SIZE UBI_DEVICE"
274//usage:#define ubirsvol_full_usage "\n\n"
275//usage: "Resize UBI volume\n"
276//usage: "\n -n VOLID Volume ID"
277//usage: "\n -s SIZE Size in bytes"
278 if (do_rsvol) {
279 if (!(opts & OPTION_s))
280 bb_error_msg_and_die("size not specified");
281 if (!(opts & OPTION_n))
282 bb_error_msg_and_die("volume id not specified");
283
284 rsvol_req.bytes = size_bytes; /* signed int64_t */
285 rsvol_req.vol_id = vol_id;
286
287 xioctl(fd, UBI_IOCRSVOL, &rsvol_req);
288 } else
289
290//usage:#define ubiupdatevol_trivial_usage
291//usage: "[-t | [-s SIZE] IMG_FILE] UBI_DEVICE"
292//usage:#define ubiupdatevol_full_usage "\n\n"
293//usage: "Update UBI volume\n"
294//usage: "\n -t Truncate to zero size"
295//usage: "\n -s SIZE Size in bytes to resize to"
296 if (do_update) {
297 int64_t bytes64;
298
299 if (opts & OPTION_t) {
300 /* truncate the volume by starting an update for size 0 */
301 bytes64 = 0;
302 /* this ioctl expects int64_t* parameter */
303 xioctl(fd, UBI_IOCVOLUP, &bytes64);
304 }
305 else {
306 struct stat st;
307 unsigned ubinum, volnum;
308 unsigned leb_size;
309 ssize_t len;
310 char *input_data;
311
312 /* Assume that device is in normal format. */
313 /* Removes need for scanning sysfs tree as full libubi does. */
314 if (sscanf(ubi_ctrl, "/dev/ubi%u_%u", &ubinum, &volnum) != 2)
315 bb_error_msg_and_die("wrong format of UBI device name");
316
317 sprintf(path_sys_class_ubi_ubi, "%u_%u/usable_eb_size", ubinum, volnum);
318 leb_size = get_num_from_file(path, MAX_SANE_ERASEBLOCK, "Can't get usable eraseblock size from '%s'");
319
320 if (!(opts & OPTION_s)) {
321 if (!*argv)
322 bb_show_usage();
323 xmove_fd(xopen(*argv, O_RDONLY), STDIN_FILENO);
324 xfstat(STDIN_FILENO, &st, *argv);
325 size_bytes = st.st_size;
326 }
327
328 bytes64 = size_bytes;
329 /* this ioctl expects signed int64_t* parameter */
330 xioctl(fd, UBI_IOCVOLUP, &bytes64);
331
332 input_data = xmalloc(leb_size);
333 while ((len = full_read(STDIN_FILENO, input_data, leb_size)) > 0) {
334 xwrite(fd, input_data, len);
335 }
336 if (len < 0)
337 bb_perror_msg_and_die("UBI volume update failed");
338 }
339 }
340
341 if (ENABLE_FEATURE_CLEAN_UP)
342 close(fd);
343
344 return EXIT_SUCCESS;
345}
Note: See TracBrowser for help on using the repository browser.