aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--miscutils/ubi_tools.c303
1 files changed, 154 insertions, 149 deletions
diff --git a/miscutils/ubi_tools.c b/miscutils/ubi_tools.c
index 6f20f300c..79fb2044d 100644
--- a/miscutils/ubi_tools.c
+++ b/miscutils/ubi_tools.c
@@ -66,14 +66,6 @@
66#endif 66#endif
67#include <mtd/ubi-user.h> 67#include <mtd/ubi-user.h>
68 68
69#define OPTION_M (1 << 0)
70#define OPTION_D (1 << 1)
71#define OPTION_n (1 << 2)
72#define OPTION_N (1 << 3)
73#define OPTION_s (1 << 4)
74#define OPTION_a (1 << 5)
75#define OPTION_t (1 << 6)
76
77#define do_attach (ENABLE_UBIATTACH && applet_name[3] == 'a') 69#define do_attach (ENABLE_UBIATTACH && applet_name[3] == 'a')
78#define do_detach (ENABLE_UBIDETACH && applet_name[3] == 'd') 70#define do_detach (ENABLE_UBIDETACH && applet_name[3] == 'd')
79#define do_mkvol (ENABLE_UBIMKVOL && applet_name[3] == 'm') 71#define do_mkvol (ENABLE_UBIMKVOL && applet_name[3] == 'm')
@@ -81,230 +73,243 @@
81#define do_rsvol (ENABLE_UBIRSVOL && applet_name[4] == 's') 73#define do_rsvol (ENABLE_UBIRSVOL && applet_name[4] == 's')
82#define do_update (ENABLE_UBIUPDATEVOL && applet_name[3] == 'u') 74#define do_update (ENABLE_UBIUPDATEVOL && applet_name[3] == 'u')
83 75
84//usage:#define ubiattach_trivial_usage 76static unsigned get_num_from_file(const char *path, unsigned max, const char *errmsg)
85//usage: "-m MTD_NUM [-d UBI_NUM] UBI_CTRL_DEV" 77{
86//usage:#define ubiattach_full_usage "\n\n" 78 char buf[sizeof(long long)*3];
87//usage: "Attach MTD device to UBI\n" 79 unsigned long long num;
88//usage: "\n -m MTD_NUM MTD device number to attach" 80
89//usage: "\n -d UBI_NUM UBI device number to assign" 81 if (open_read_close(path, buf, sizeof(buf)) < 0)
90//usage: 82 bb_perror_msg_and_die(errmsg, path);
91//usage:#define ubidetach_trivial_usage 83 /* It can be \n terminated, xatoull won't work well */
92//usage: "-d UBI_NUM UBI_CTRL_DEV" 84 if (sscanf(buf, "%llu", &num) != 1 || num > max)
93//usage:#define ubidetach_full_usage "\n\n" 85 bb_error_msg_and_die(errmsg, path);
94//usage: "Detach MTD device from UBI\n" 86 return num;
95//usage: "\n -d UBI_NUM UBI device number" 87}
96//usage:
97//usage:#define ubimkvol_trivial_usage
98//usage: "UBI_DEVICE -N NAME [-s SIZE | -m]"
99//usage:#define ubimkvol_full_usage "\n\n"
100//usage: "Create UBI volume\n"
101//usage: "\n -a ALIGNMENT Volume alignment (default 1)"
102//usage: "\n -m Set volume size to maximum available"
103//usage: "\n -n VOLID Volume ID, if not specified, it"
104//usage: "\n will be assigned automatically"
105//usage: "\n -N NAME Volume name"
106//usage: "\n -s SIZE Size in bytes"
107//usage: "\n -t TYPE Volume type (static|dynamic)"
108//usage:
109//usage:#define ubirmvol_trivial_usage
110//usage: "UBI_DEVICE -n VOLID"
111//usage:#define ubirmvol_full_usage "\n\n"
112//usage: "Remove UBI volume\n"
113//usage: "\n -n VOLID Volume ID"
114//usage:
115//usage:#define ubirsvol_trivial_usage
116//usage: "UBI_DEVICE -n VOLID -s SIZE"
117//usage:#define ubirsvol_full_usage "\n\n"
118//usage: "Resize UBI volume\n"
119//usage: "\n -n VOLID Volume ID to resize"
120//usage: "\n -s SIZE Size in bytes"
121//usage:
122//usage:#define ubiupdatevol_trivial_usage
123//usage: "UBI_DEVICE [IMG_FILE]"
124//usage:#define ubiupdatevol_full_usage "\n\n"
125//usage: "Update UBI volume\n"
126//usage: "\n -t Truncate UBI volume"
127//usage: "\n -s SIZE Bytes in input (if reading stdin)"
128 88
89/* To prevent malloc(1G) accidents */
90#define MAX_SANE_ERASEBLOCK (16*1024*1024)
129 91
130int ubi_tools_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 92int ubi_tools_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
131int ubi_tools_main(int argc UNUSED_PARAM, char **argv) 93int ubi_tools_main(int argc UNUSED_PARAM, char **argv)
132{ 94{
133 unsigned opts; 95 unsigned opts;
134 char *ubi_ctrl; 96 char *ubi_ctrl;
135 //struct stat st;
136 int fd; 97 int fd;
137 int mtd_num; 98 int mtd_num;
138 int dev_num = UBI_DEV_NUM_AUTO; 99 int dev_num = UBI_DEV_NUM_AUTO;
139 int vol_id = UBI_VOL_NUM_AUTO; 100 int vol_id = UBI_VOL_NUM_AUTO;
140 char *vol_name = NULL; 101 char *vol_name;
141 int size_bytes; 102 unsigned long long size_bytes = size_bytes; /* for compiler */
103 char *size_bytes_str;
142 int alignment = 1; 104 int alignment = 1;
143 char *type = NULL; 105 char *type;
106 union {
107 struct ubi_attach_req attach_req;
108 struct ubi_mkvol_req mkvol_req;
109 struct ubi_rsvol_req rsvol_req;
110 } req_structs;
111#define attach_req req_structs.attach_req
112#define mkvol_req req_structs.mkvol_req
113#define rsvol_req req_structs.rsvol_req
114 char path[sizeof("/sys/class/ubi/ubi%d_%d/usable_eb_size")
115 + 2 * sizeof(int)*3 + /*just in case:*/ 16];
116#define path_sys_class_ubi_ubi (path + sizeof("/sys/class/ubi/ubi")-1)
117
118 strcpy(path_sys_class_ubi_ubi, "/sys/class/ubi/ubi");
119 memset(&req_structs, 0, sizeof(req_structs));
144 120
145 if (do_mkvol) { 121 if (do_mkvol) {
146 opt_complementary = "-1:d+:n+:s+:a+"; 122 opt_complementary = "-1:d+:n+:a+";
147 opts = getopt32(argv, "md:n:N:s:a:t::", 123 opts = getopt32(argv, "md:n:N:s:a:t:",
148 &dev_num, &vol_id, 124 &dev_num, &vol_id,
149 &vol_name, &size_bytes, &alignment, &type 125 &vol_name, &size_bytes_str, &alignment, &type
150 ); 126 );
151 } else { 127 } else {
152 opt_complementary = "-1:m+:d+:n+:s+:a+"; 128 opt_complementary = "-1:m+:d+:n+:a+";
153 opts = getopt32(argv, "m:d:n:N:s:a:t::", 129 opts = getopt32(argv, "m:d:n:N:s:a:t:",
154 &mtd_num, &dev_num, &vol_id, 130 &mtd_num, &dev_num, &vol_id,
155 &vol_name, &size_bytes, &alignment, &type 131 &vol_name, &size_bytes_str, &alignment, &type
156 ); 132 );
157 } 133 }
158 ubi_ctrl = argv[optind]; 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)
141
142 if (opts & OPTION_s)
143 size_bytes = xatoull(size_bytes_str);
144 argv += optind;
145 ubi_ctrl = *argv;
159 146
160 fd = xopen(ubi_ctrl, O_RDWR); 147 fd = xopen(ubi_ctrl, O_RDWR);
161 //xfstat(fd, &st, ubi_ctrl); 148 //xfstat(fd, &st, ubi_ctrl);
162 //if (!S_ISCHR(st.st_mode)) 149 //if (!S_ISCHR(st.st_mode))
163 // bb_error_msg_and_die("%s: not a char device", ubi_ctrl); 150 // bb_error_msg_and_die("%s: not a char device", ubi_ctrl);
164 151
152//usage:#define ubiattach_trivial_usage
153//usage: "-m MTD_NUM [-d UBI_NUM] UBI_CTRL_DEV"
154//usage:#define ubiattach_full_usage "\n\n"
155//usage: "Attach MTD device to UBI\n"
156//usage: "\n -m MTD_NUM MTD device number to attach"
157//usage: "\n -d UBI_NUM UBI device number to assign"
165 if (do_attach) { 158 if (do_attach) {
166 struct ubi_attach_req req; 159 if (!(opts & OPTION_m))
167 if (!(opts & OPTION_M))
168 bb_error_msg_and_die("%s device not specified", "MTD"); 160 bb_error_msg_and_die("%s device not specified", "MTD");
169 161
170 memset(&req, 0, sizeof(req)); 162 attach_req.mtd_num = mtd_num;
171 req.mtd_num = mtd_num; 163 attach_req.ubi_num = dev_num;
172 req.ubi_num = dev_num;
173 164
174 xioctl(fd, UBI_IOCATT, &req); 165 xioctl(fd, UBI_IOCATT, &attach_req);
175 } else 166 } else
167
168//usage:#define ubidetach_trivial_usage
169//usage: "-d UBI_NUM UBI_CTRL_DEV"
170//usage:#define ubidetach_full_usage "\n\n"
171//usage: "Detach MTD device from UBI\n"
172//usage: "\n -d UBI_NUM UBI device number"
176 if (do_detach) { 173 if (do_detach) {
177 if (!(opts & OPTION_D)) 174 if (!(opts & OPTION_d))
178 bb_error_msg_and_die("%s device not specified", "UBI"); 175 bb_error_msg_and_die("%s device not specified", "UBI");
179 176
177 /* FIXME? kernel expects int32_t* here: */
180 xioctl(fd, UBI_IOCDET, &dev_num); 178 xioctl(fd, UBI_IOCDET, &dev_num);
181 } else 179 } else
180
181//usage:#define ubimkvol_trivial_usage
182//usage: "UBI_DEVICE -N NAME [-s SIZE | -m]"
183//usage:#define ubimkvol_full_usage "\n\n"
184//usage: "Create UBI volume\n"
185//usage: "\n -a ALIGNMENT Volume alignment (default 1)"
186//usage: "\n -m Set volume size to maximum available"
187//usage: "\n -n VOLID Volume ID. If not specified,"
188//usage: "\n assigned automatically"
189//usage: "\n -N NAME Volume name"
190//usage: "\n -s SIZE Size in bytes"
191//usage: "\n -t TYPE Volume type (static|dynamic)"
182 if (do_mkvol) { 192 if (do_mkvol) {
183 struct ubi_mkvol_req req; 193 if (opts & OPTION_m) {
184 int vol_name_len;
185 if (opts & OPTION_M) {
186 unsigned leb_avail; 194 unsigned leb_avail;
187 unsigned leb_size; 195 unsigned leb_size;
188 unsigned num; 196 unsigned num;
189 char path[sizeof("/sys/class/ubi/ubi%d/avail_eraseblocks") + sizeof(int)*3];
190 char *p; 197 char *p;
191 char buf[20];
192 198
193 if (strncmp(ubi_ctrl, "/dev/ubi", 8) != 0) 199 if (sscanf(ubi_ctrl, "/dev/ubi%u", &num) != 1)
194 bb_error_msg_and_die("%s device node not in correct format", "UBI"); 200 bb_error_msg_and_die("wrong format of UBI device name");
195 num = xstrtou(ubi_ctrl+8, 10); 201
196 p = path + sprintf(path, "/sys/class/ubi/ubi%d/", num); 202 p = path_sys_class_ubi_ubi + sprintf(path_sys_class_ubi_ubi, "%u/", num);
197 203
198 strcpy(p, "avail_eraseblocks"); 204 strcpy(p, "avail_eraseblocks");
199 if ((num = open_read_close(path, buf, sizeof(buf))) <= 1) 205 leb_avail = get_num_from_file(path, UINT_MAX, "Can't get available eraseblocks from '%s'");
200 bb_error_msg_and_die("%s could not get LEB available", "UBI");
201 buf[num-1] = '\0'; // trim trailing newline
202 leb_avail = xstrtou(buf, 10);
203 206
204 strcpy(p, "eraseblock_size"); 207 strcpy(p, "eraseblock_size");
205 if ((num = open_read_close(path, buf, sizeof(buf))) <= 0) 208 leb_size = get_num_from_file(path, MAX_SANE_ERASEBLOCK, "Can't get eraseblock size from '%s'");
206 bb_error_msg_and_die("%s could not get LEB size", "UBI");
207 buf[num-1] = '\0'; // trim trailing newline
208 leb_size = xstrtou(buf, 10);
209 209
210 size_bytes = leb_avail * leb_size; 210 size_bytes = leb_avail * (unsigned long long)leb_size;
211 211 //if (size_bytes <= 0)
212 if (size_bytes <= 0) 212 // bb_error_msg_and_die("%s invalid maximum size calculated", "UBI");
213 bb_error_msg_and_die("%s invalid maximum size calculated", "UBI");
214 } else 213 } else
215 if (!(opts & OPTION_s)) 214 if (!(opts & OPTION_s))
216 bb_error_msg_and_die("%s size not specified", "UBI"); 215 bb_error_msg_and_die("size not specified");
217 if (!(opts & OPTION_N))
218 bb_error_msg_and_die("%s name not specified", "UBI");
219 vol_name_len = strlen(vol_name);
220 if (vol_name_len > UBI_MAX_VOLUME_NAME)
221 bb_error_msg_and_die("%s volume name too long", "UBI");
222
223 memset(&req, 0, sizeof(req));
224 req.vol_id = vol_id;
225 if ((opts & OPTION_t) && type) {
226 if (type[0] == 's')
227 req.vol_type = UBI_STATIC_VOLUME;
228 else
229 req.vol_type = UBI_DYNAMIC_VOLUME;
230 } else {
231 req.vol_type = UBI_DYNAMIC_VOLUME;
232 }
233 req.alignment = alignment;
234 req.bytes = size_bytes;
235 strncpy(req.name, vol_name, UBI_MAX_VOLUME_NAME);
236 req.name_len = vol_name_len;
237 216
238 xioctl(fd, UBI_IOCMKVOL, &req); 217 if (!(opts & OPTION_N))
218 bb_error_msg_and_die("name not specified");
219
220 mkvol_req.vol_id = vol_id;
221 mkvol_req.vol_type = UBI_DYNAMIC_VOLUME;
222 if ((opts & OPTION_t) && type[0] == 's')
223 mkvol_req.vol_type = UBI_STATIC_VOLUME;
224 mkvol_req.alignment = alignment;
225 mkvol_req.bytes = size_bytes; /* signed int64_t */
226 strncpy(mkvol_req.name, vol_name, UBI_MAX_VOLUME_NAME);
227 mkvol_req.name_len = strlen(vol_name);
228 if (mkvol_req.name_len > UBI_MAX_VOLUME_NAME)
229 bb_error_msg_and_die("volume name too long: '%s'", vol_name);
230
231 xioctl(fd, UBI_IOCMKVOL, &mkvol_req);
239 } else 232 } else
233
234//usage:#define ubirmvol_trivial_usage
235//usage: "UBI_DEVICE -n VOLID"
236//usage:#define ubirmvol_full_usage "\n\n"
237//usage: "Remove UBI volume\n"
238//usage: "\n -n VOLID Volume ID"
240 if (do_rmvol) { 239 if (do_rmvol) {
241 if (!(opts & OPTION_n)) 240 if (!(opts & OPTION_n))
242 bb_error_msg_and_die("%s volume id not specified", "UBI"); 241 bb_error_msg_and_die("volume id not specified");
243 242
243 /* FIXME? kernel expects int32_t* here: */
244 xioctl(fd, UBI_IOCRMVOL, &vol_id); 244 xioctl(fd, UBI_IOCRMVOL, &vol_id);
245 } else 245 } else
246
247//usage:#define ubirsvol_trivial_usage
248//usage: "UBI_DEVICE -n VOLID -s SIZE"
249//usage:#define ubirsvol_full_usage "\n\n"
250//usage: "Resize UBI volume\n"
251//usage: "\n -n VOLID Volume ID"
252//usage: "\n -s SIZE Size in bytes"
246 if (do_rsvol) { 253 if (do_rsvol) {
247 struct ubi_rsvol_req req;
248 if (!(opts & OPTION_s)) 254 if (!(opts & OPTION_s))
249 bb_error_msg_and_die("%s size not specified", "UBI"); 255 bb_error_msg_and_die("size not specified");
250 if (!(opts & OPTION_n)) 256 if (!(opts & OPTION_n))
251 bb_error_msg_and_die("%s volume id not specified", "UBI"); 257 bb_error_msg_and_die("volume id not specified");
252 258
253 memset(&req, 0, sizeof(req)); 259 rsvol_req.bytes = size_bytes; /* signed int64_t */
254 req.bytes = size_bytes; 260 rsvol_req.vol_id = vol_id;
255 req.vol_id = vol_id;
256 261
257 xioctl(fd, UBI_IOCRSVOL, &req); 262 xioctl(fd, UBI_IOCRSVOL, &rsvol_req);
258 } else 263 } else
264
265//usage:#define ubiupdatevol_trivial_usage
266//usage: "UBI_DEVICE [-t | [-s SIZE] IMG_FILE]"
267//usage:#define ubiupdatevol_full_usage "\n\n"
268//usage: "Update UBI volume\n"
269//usage: "\n -t Truncate to zero size"
270//usage: "\n -s SIZE Size in bytes to resize to"
259 if (do_update) { 271 if (do_update) {
260 long long bytes; 272 int64_t bytes64;
261 273
262 if (opts & OPTION_t) { 274 if (opts & OPTION_t) {
263 // truncate the volume by starting an update for size 0 275 /* truncate the volume by starting an update for size 0 */
264 bytes = 0; 276 bytes64 = 0;
265 xioctl(fd, UBI_IOCVOLUP, &bytes); 277 /* this ioctl expects int64_t* parameter */
278 xioctl(fd, UBI_IOCVOLUP, &bytes64);
266 } 279 }
267 else { 280 else {
268 struct stat st; 281 struct stat st;
269 char buf[sizeof("/sys/class/ubi/ubi%d_%d/usable_eb_size") + 2 * sizeof(int)*3];
270 int input_fd;
271 unsigned ubinum, volnum; 282 unsigned ubinum, volnum;
272 unsigned leb_size; 283 unsigned leb_size;
273 ssize_t len; 284 ssize_t len;
274 char *input_data; 285 char *input_data;
275 286
276 // Make assumption that device not is in normal format. 287 /* Assume that device is in normal format. */
277 // Removes need for scanning sysfs tree as full libubi does 288 /* Removes need for scanning sysfs tree as full libubi does. */
278 if (sscanf(ubi_ctrl, "/dev/ubi%u_%u", &ubinum, &volnum) != 2) 289 if (sscanf(ubi_ctrl, "/dev/ubi%u_%u", &ubinum, &volnum) != 2)
279 bb_error_msg_and_die("%s volume node not in correct format", "UBI"); 290 bb_error_msg_and_die("wrong format of UBI device name");
280 291
281 sprintf(buf, "/sys/class/ubi/ubi%u_%u/usable_eb_size", ubinum, volnum); 292 sprintf(path_sys_class_ubi_ubi, "%u_%u/usable_eb_size", ubinum, volnum);
282 if (open_read_close(buf, buf, sizeof(buf)) <= 0) 293 leb_size = get_num_from_file(path, MAX_SANE_ERASEBLOCK, "Can't get usable eraseblock size from '%s'");
283 bb_error_msg_and_die("%s could not get LEB size", "UBI"); 294
284 if (sscanf(buf, "%u", &leb_size) != 1) 295 if (!(opts & OPTION_s)) {
285 bb_error_msg_and_die("%s could not get LEB size", "UBI"); 296 if (!*argv)
286
287 if (opts & OPTION_s) {
288 input_fd = 0;
289 } else {
290 if (!argv[optind+1])
291 bb_show_usage(); 297 bb_show_usage();
292 xstat(argv[optind+1], &st); 298 xstat(*argv, &st);
293 size_bytes = st.st_size; 299 size_bytes = st.st_size;
294 input_fd = xopen(argv[optind+1], O_RDONLY); 300 xmove_fd(xopen(*argv, O_RDONLY), STDIN_FILENO);
295 } 301 }
296 302
297 bytes = size_bytes; 303 bytes64 = size_bytes;
298 xioctl(fd, UBI_IOCVOLUP, &bytes); 304 /* this ioctl expects signed int64_t* parameter */
305 xioctl(fd, UBI_IOCVOLUP, &bytes64);
299 306
300 input_data = xmalloc(leb_size); 307 input_data = xmalloc(leb_size);
301 while ((len = full_read(input_fd, input_data, leb_size)) > 0) { 308 while ((len = full_read(STDIN_FILENO, input_data, leb_size)) > 0) {
302 xwrite(fd, input_data, len); 309 xwrite(fd, input_data, len);
303 } 310 }
304 if (len < 0) 311 if (len < 0)
305 bb_error_msg_and_die("%s volume update failed", "UBI"); 312 bb_perror_msg_and_die("UBI volume update failed");
306 if (ENABLE_FEATURE_CLEAN_UP)
307 close(input_fd);
308 } 313 }
309 } 314 }
310 315