fix jffs2reset on ubifs overlay
[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 "libubi/libubi-tiny.h"
25
26 static int print_usage(void)
27 {
28 printf("ubi info\n");
29 printf("ubi detach kernel|rootfs\n");
30 printf("ubi kernel <image.kernel.ubi>\n");
31 printf("ubi rootfs <image.rootfs.ubi>\n");
32 printf("ubi overlay <image.rootfs-overlay.ubi>\n");
33
34 return -1;
35 }
36
37 static int mtd_find_index(char *name)
38 {
39 FILE *fp = fopen("/proc/mtd", "r");
40 char line[256];
41 char *index = NULL;
42
43 if (!fp)
44 return -1;
45
46 while (!index && fgets(line, sizeof(line), fp)) {
47 if (strstr(line, name)) {
48 char *eol = strstr(line, ":");
49
50 if (!eol)
51 continue;
52
53 *eol = '\0';
54 index = &line[3];
55 }
56 }
57
58 fclose(fp);
59
60 if (!index)
61 return -1;
62
63 return atoi(index);
64 }
65
66 static int mtd_find(char *name, char *ret)
67 {
68 int index = mtd_find_index(name);
69 if (index < 0)
70 return -1;
71
72 sprintf(ret, "/dev/mtd%d", index);
73
74 return 0;
75 }
76
77 static int ubi_find(libubi_t libubi, char *name, char *ret)
78 {
79 int index = mtd_find_index(name);
80 int ubi = 0;
81
82 while (ubi_dev_present(libubi, ubi))
83 {
84 struct ubi_dev_info info;
85
86 if (ubi_get_dev_info1(libubi, ubi++, &info))
87 continue;
88
89 if (info.mtd_num != index)
90 continue;
91
92 sprintf(ret, "/dev/ubi%d", info.dev_num);
93
94 return 0;
95 }
96
97 return -1;
98 }
99
100 static int volume_find(libubi_t libubi, char *name, char *ret)
101 {
102 int index = mtd_find_index(name);
103 struct ubi_vol_info vol;
104 int ubi = 0;
105
106 if (index < 0)
107 return -1;
108
109 if (mtd_num2ubi_dev(libubi, index, &ubi)) {
110 fprintf(stderr, "failed to get ubi node for %s\n", name);
111 return -1;
112 }
113
114 if (ubi_get_vol_info1_nm(libubi, ubi, name, &vol)) {
115 fprintf(stderr, "failed to get ubi volume info for %s\n", name);
116 return -1;
117 }
118
119 sprintf(ret, "/dev/ubi%d_%d", ubi, vol.vol_id);
120
121 return 0;
122 }
123
124 static int main_detach(char *type)
125 {
126 libubi_t libubi;
127 char mtd[64];
128 int err;
129
130 if (!strcmp(type, "kernel"))
131 err = mtd_find("kernel_ubi", mtd);
132 else if (!strcmp(type, "rootfs"))
133 err = mtd_find("rootfs_ubi", mtd);
134 else
135 return print_usage();
136
137 if (err) {
138 fprintf(stderr, "failed to find mtd partition %s_ubi\n", type);
139 return -1;
140 }
141
142 libubi = libubi_open();
143 if (!libubi) {
144 fprintf(stderr, "cannot open libubi");
145 return -1;
146 }
147
148 err = ubidetach(libubi, mtd);
149 if (err) {
150 fprintf(stderr, "cannot detach \"%s\"", mtd);
151 return -1;
152 }
153
154 return 0;
155 }
156
157 static int main_image(char *partition, char *image, char *overlay)
158 {
159 libubi_t libubi;
160 struct stat s;
161 int err;
162 char mtd[64];
163 char _part[64];
164 char node[64];
165 char volume[64];
166 char _data[64];
167 char *data = NULL;
168
169 if (stat(image, &s)) {
170 fprintf(stderr, "image not found %s\n", image);
171 return -1;
172 }
173
174 if (!strcmp(partition, "kernel"))
175 err = mtd_find("kernel", _part);
176 else
177 err = mtd_find("rootfs", _part);
178
179 if (overlay && !mtd_find(overlay, _data))
180 data = _data;
181
182 libubi = libubi_open();
183 if (!libubi) {
184 fprintf(stderr, "cannot open libubi");
185 return -1;
186 }
187
188 if (!strcmp(partition, "kernel"))
189 err = mtd_find("kernel_ubi", mtd);
190 else
191 err = mtd_find("rootfs_ubi", mtd);
192 if (err) {
193 fprintf(stderr, "failed to find mtd parent %s_ubi\n", partition);
194 return -1;
195 }
196
197 if (!strcmp(partition, "kernel"))
198 err = ubi_find(libubi, "kernel_ubi", node);
199 else
200 err = ubi_find(libubi, "rootfs_ubi", node);
201 if (err) {
202 fprintf(stderr, "failed to find ubi volume %s\n", partition);
203 return -1;
204 }
205
206 err = ubidetach(libubi, mtd);
207 if (err) {
208 fprintf(stderr, "cannot detach \"%s\"", mtd);
209 return -1;
210 }
211
212 err = ubiattach(libubi, mtd);
213 if (err) {
214 fprintf(stderr, "cannot attach \"%s\"", mtd);
215 return -1;
216 }
217
218 if (data) {
219 err = ubirmvol(libubi, node, overlay);
220 if (err) {
221 fprintf(stderr, "cannot remove \"%s\"", node);
222 return -1;
223 }
224 }
225
226 if (volume_find(libubi, partition, volume) < 0) {
227 fprintf(stderr, "failed to find ubi volume %s\n", partition);
228 return -1;
229 }
230
231 err = ubirsvol(libubi, node, partition, s.st_size);
232 if (err) {
233 fprintf(stderr, "cannot resize \"%s\"", partition);
234 return -1;
235 }
236
237 err = ubiupdatevol(libubi, volume, image);
238 if (err) {
239 fprintf(stderr, "cannot update \"%s\"", volume);
240 return -1;
241 }
242
243 if (overlay) {
244 err = ubimkvol(libubi, node, overlay, 1);
245 if (err) {
246 fprintf(stderr, "cannot make \"%s\"", overlay);
247 return -1;
248 }
249 }
250
251 libubi_close(libubi);
252
253 return err;
254 }
255
256 static int main_info(void)
257 {
258 struct ubi_info info;
259 libubi_t libubi;
260 int i;
261
262 libubi = libubi_open();
263 if (!libubi) {
264 fprintf(stderr, "cannot open libubi");
265 return -1;
266 }
267
268 if (ubi_get_info(libubi, &info)) {
269 fprintf(stderr, "failed to get info\n");
270 return -1;
271 }
272
273 for (i = info.lowest_dev_num; i <= info.highest_dev_num; i++) {
274 struct ubi_dev_info dinfo;
275 char ubi[64];
276 int j;
277
278 sprintf(ubi, "/dev/ubi%d", i);
279 if (ubi_get_dev_info(libubi, ubi, &dinfo))
280 continue;
281 printf("device - %s\n size: %lldBytes\n bad blocks: %d\n",
282 &ubi[5], dinfo.total_bytes, dinfo.bad_count);
283 for (j = dinfo.lowest_vol_id; j <= dinfo.highest_vol_id; j++) {
284 struct ubi_vol_info vinfo;
285
286 sprintf(ubi, "/dev/ubi%d_%d", i, j);
287 if (ubi_get_vol_info(libubi, ubi, &vinfo))
288 continue;
289 printf(" volume - %s\n", &ubi[5]);
290 printf("\tname: %s\n", vinfo.name);
291 printf("\tsize: %lld\n", vinfo.data_bytes);
292 }
293 }
294
295 libubi_close(libubi);
296
297 return 0;
298 }
299
300 int main(int argc, char **argv)
301 {
302 if (argc > 1 && !strcmp(argv[1], "info"))
303 return main_info();
304
305 if (argc < 3)
306 return print_usage();
307
308 if (!strcmp(argv[1], "kernel")) {
309 return main_image("kernel", argv[2], NULL);
310
311 } else if (!strcmp(argv[1], "rootfs")) {
312 return main_image("rootfs", argv[2], NULL);
313
314 } else if (!strcmp(argv[1], "overlay")) {
315 return main_image("rootfs", argv[2], "rootfs_data");
316
317 } else if (!strcmp(argv[1], "detach")) {
318 return main_detach(argv[2]);
319 }
320
321 return -1;
322 }
323