libfstools: fit: improve fit_volume_find string handling
[project/fstools.git] / ubi.c
1 /*
2 * Copyright (C) 2014 John Crispin <blogic@openwrt.org>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License version 2.1
6 * as published by the Free Software Foundation
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14 #include <sys/types.h>
15 #include <sys/stat.h>
16 #include <fcntl.h>
17 #include <stdio.h>
18 #include <stdint.h>
19 #include <getopt.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <unistd.h>
23
24 #include <libubox/ulog.h>
25
26 #include "libubi/libubi-tiny.h"
27
28 static int print_usage(void)
29 {
30 printf("ubi info\n");
31 printf("ubi detach kernel|rootfs\n");
32 printf("ubi kernel <image.kernel.ubi>\n");
33 printf("ubi rootfs <image.rootfs.ubi>\n");
34 printf("ubi overlay <image.rootfs-overlay.ubi>\n");
35
36 return -1;
37 }
38
39 static int mtd_find_index(char *name)
40 {
41 FILE *fp = fopen("/proc/mtd", "r");
42 char line[256];
43 char *index = NULL;
44
45 if (!fp)
46 return -1;
47
48 while (!index && fgets(line, sizeof(line), fp)) {
49 if (strstr(line, name)) {
50 char *eol = strstr(line, ":");
51
52 if (!eol)
53 continue;
54
55 *eol = '\0';
56 index = &line[3];
57 }
58 }
59
60 fclose(fp);
61
62 if (!index)
63 return -1;
64
65 return atoi(index);
66 }
67
68 static int mtd_find(char *name, char *ret)
69 {
70 int index = mtd_find_index(name);
71 if (index < 0)
72 return -1;
73
74 sprintf(ret, "/dev/mtd%d", index);
75
76 return 0;
77 }
78
79 static int ubi_find(libubi_t libubi, char *name, char *ret)
80 {
81 int index = mtd_find_index(name);
82 int ubi = 0;
83
84 while (ubi_dev_present(libubi, ubi))
85 {
86 struct ubi_dev_info info;
87
88 if (ubi_get_dev_info1(libubi, ubi++, &info))
89 continue;
90
91 if (info.mtd_num != index)
92 continue;
93
94 sprintf(ret, "/dev/ubi%d", info.dev_num);
95
96 return 0;
97 }
98
99 return -1;
100 }
101
102 static int volume_find(libubi_t libubi, char *name, char *ret)
103 {
104 int index = mtd_find_index(name);
105 struct ubi_vol_info vol;
106 int ubi = 0;
107
108 if (index < 0)
109 return -1;
110
111 if (mtd_num2ubi_dev(libubi, index, &ubi)) {
112 ULOG_ERR("failed to get ubi node for %s\n", name);
113 return -1;
114 }
115
116 if (ubi_get_vol_info1_nm(libubi, ubi, name, &vol)) {
117 ULOG_ERR("failed to get ubi volume info for %s\n", name);
118 return -1;
119 }
120
121 sprintf(ret, "/dev/ubi%d_%d", ubi, vol.vol_id);
122
123 return 0;
124 }
125
126 static int main_detach(char *type)
127 {
128 libubi_t libubi;
129 char mtd[64];
130 int err;
131
132 if (!strcmp(type, "kernel"))
133 err = mtd_find("kernel_ubi", mtd);
134 else if (!strcmp(type, "rootfs"))
135 err = mtd_find("rootfs_ubi", mtd);
136 else
137 return print_usage();
138
139 if (err) {
140 ULOG_ERR("MTD partition '%s_ubi' not found\n", type);
141 return -1;
142 }
143
144 libubi = libubi_open();
145 if (!libubi) {
146 ULOG_ERR("cannot open libubi");
147 return -1;
148 }
149
150 err = ubidetach(libubi, mtd);
151 if (err) {
152 ULOG_ERR("cannot detach \"%s\"", mtd);
153 libubi_close(libubi);
154 return -1;
155 }
156
157 libubi_close(libubi);
158 return 0;
159 }
160
161 static int main_image(char *partition, char *image, char *overlay)
162 {
163 libubi_t libubi;
164 struct stat s;
165 int err;
166 char mtd[64];
167 char _part[64];
168 char node[64];
169 char volume[64];
170 char _data[64];
171 char *data = NULL;
172
173 if (stat(image, &s)) {
174 ULOG_ERR("image not found %s\n", image);
175 return -1;
176 }
177
178 if (!strcmp(partition, "kernel"))
179 err = mtd_find("kernel", _part);
180 else
181 err = mtd_find("rootfs", _part);
182
183 if (overlay && !mtd_find(overlay, _data))
184 data = _data;
185
186 libubi = libubi_open();
187 if (!libubi) {
188 ULOG_ERR("cannot open libubi");
189 return -1;
190 }
191
192 if (!strcmp(partition, "kernel"))
193 err = mtd_find("kernel_ubi", mtd);
194 else
195 err = mtd_find("rootfs_ubi", mtd);
196 if (err) {
197 ULOG_ERR("MTD partition '%s_ubi' not found\n", partition);
198 libubi_close(libubi);
199 return -1;
200 }
201
202 if (!strcmp(partition, "kernel"))
203 err = ubi_find(libubi, "kernel_ubi", node);
204 else
205 err = ubi_find(libubi, "rootfs_ubi", node);
206 if (err) {
207 ULOG_ERR("UBI volume '%s' not found\n", partition);
208 libubi_close(libubi);
209 return -1;
210 }
211
212 err = ubidetach(libubi, mtd);
213 if (err) {
214 ULOG_ERR("cannot detach \"%s\"", mtd);
215 libubi_close(libubi);
216 return -1;
217 }
218
219 err = ubiattach(libubi, mtd);
220 if (err) {
221 ULOG_ERR("cannot attach \"%s\"", mtd);
222 libubi_close(libubi);
223 return -1;
224 }
225
226 if (data) {
227 err = ubirmvol(libubi, node, overlay);
228 if (err) {
229 ULOG_ERR("cannot remove \"%s\"", node);
230 libubi_close(libubi);
231 return -1;
232 }
233 }
234
235 if (volume_find(libubi, partition, volume) < 0) {
236 ULOG_ERR("UBI volume '%s' not found\n", partition);
237 libubi_close(libubi);
238 return -1;
239 }
240
241 err = ubirsvol(libubi, node, partition, s.st_size);
242 if (err) {
243 ULOG_ERR("cannot resize \"%s\"", partition);
244 libubi_close(libubi);
245 return -1;
246 }
247
248 err = ubiupdatevol(libubi, volume, image);
249 if (err) {
250 ULOG_ERR("cannot update \"%s\"", volume);
251 libubi_close(libubi);
252 return -1;
253 }
254
255 if (overlay) {
256 err = ubimkvol(libubi, node, overlay, 1);
257 if (err) {
258 ULOG_ERR("cannot make \"%s\"", overlay);
259 libubi_close(libubi);
260 return -1;
261 }
262 }
263
264 libubi_close(libubi);
265
266 return err;
267 }
268
269 static int main_info(void)
270 {
271 struct ubi_info info;
272 libubi_t libubi;
273 int i;
274
275 libubi = libubi_open();
276 if (!libubi) {
277 ULOG_ERR("cannot open libubi");
278 return -1;
279 }
280
281 if (ubi_get_info(libubi, &info)) {
282 ULOG_ERR("failed to get info\n");
283 libubi_close(libubi);
284 return -1;
285 }
286
287 for (i = info.lowest_dev_num; i <= info.highest_dev_num; i++) {
288 struct ubi_dev_info dinfo;
289 char ubi[64];
290 int j;
291
292 sprintf(ubi, "/dev/ubi%d", i);
293 if (ubi_get_dev_info(libubi, ubi, &dinfo))
294 continue;
295 printf("device - %s\n size: %lldBytes\n bad blocks: %d\n",
296 &ubi[5], dinfo.total_bytes, dinfo.bad_count);
297 for (j = dinfo.lowest_vol_id; j <= dinfo.highest_vol_id; j++) {
298 struct ubi_vol_info vinfo;
299
300 sprintf(ubi, "/dev/ubi%d_%d", i, j);
301 if (ubi_get_vol_info(libubi, ubi, &vinfo))
302 continue;
303 printf(" volume - %s\n", &ubi[5]);
304 printf("\tname: %s\n", vinfo.name);
305 printf("\tsize: %lld\n", vinfo.data_bytes);
306 }
307 }
308
309 libubi_close(libubi);
310
311 return 0;
312 }
313
314 int main(int argc, char **argv)
315 {
316 if (argc > 1 && !strcmp(argv[1], "info"))
317 return main_info();
318
319 if (argc < 3)
320 return print_usage();
321
322 if (!strcmp(argv[1], "kernel")) {
323 return main_image("kernel", argv[2], NULL);
324
325 } else if (!strcmp(argv[1], "rootfs")) {
326 return main_image("rootfs", argv[2], NULL);
327
328 } else if (!strcmp(argv[1], "overlay")) {
329 return main_image("rootfs", argv[2], "rootfs_data");
330
331 } else if (!strcmp(argv[1], "detach")) {
332 return main_detach(argv[2]);
333 }
334
335 return -1;
336 }
337