block: print mountpoint if already mounted
[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                 return -1;
154         }
155
156         return 0;
157 }
158
159 static int main_image(char *partition, char *image, char *overlay)
160 {
161         libubi_t libubi;
162         struct stat s;
163         int err;
164         char mtd[64];
165         char _part[64];
166         char node[64];
167         char volume[64];
168         char _data[64];
169         char *data = NULL;
170
171         if (stat(image, &s)) {
172                 ULOG_ERR("image not found %s\n", image);
173                 return -1;
174         }
175
176         if (!strcmp(partition, "kernel"))
177                 err = mtd_find("kernel", _part);
178         else
179                 err = mtd_find("rootfs", _part);
180
181         if (overlay && !mtd_find(overlay, _data))
182                 data = _data;
183
184         libubi = libubi_open();
185         if (!libubi) {
186                 ULOG_ERR("cannot open libubi");
187                 return -1;
188         }
189
190         if (!strcmp(partition, "kernel"))
191                 err = mtd_find("kernel_ubi", mtd);
192         else
193                 err = mtd_find("rootfs_ubi", mtd);
194         if (err) {
195                 ULOG_ERR("MTD partition '%s_ubi' not found\n", partition);
196                 return -1;
197         }
198
199         if (!strcmp(partition, "kernel"))
200                 err = ubi_find(libubi, "kernel_ubi", node);
201         else
202                 err = ubi_find(libubi, "rootfs_ubi", node);
203         if (err) {
204                 ULOG_ERR("UBI volume '%s' not found\n", partition);
205                 return -1;
206         }
207
208         err = ubidetach(libubi, mtd);
209         if (err) {
210                 ULOG_ERR("cannot detach \"%s\"", mtd);
211                 return -1;
212         }
213
214         err = ubiattach(libubi, mtd);
215         if (err) {
216                 ULOG_ERR("cannot attach \"%s\"", mtd);
217                 return -1;
218         }
219
220         if (data) {
221                 err = ubirmvol(libubi, node, overlay);
222                 if (err) {
223                         ULOG_ERR("cannot remove \"%s\"", node);
224                         return -1;
225                 }
226         }
227
228         if (volume_find(libubi, partition, volume) < 0) {
229                 ULOG_ERR("UBI volume '%s' not found\n", partition);
230                 return -1;
231         }
232
233         err = ubirsvol(libubi, node, partition, s.st_size);
234         if (err) {
235                 ULOG_ERR("cannot resize \"%s\"", partition);
236                 return -1;
237         }
238
239         err = ubiupdatevol(libubi, volume, image);
240         if (err) {
241                 ULOG_ERR("cannot update \"%s\"", volume);
242                 return -1;
243         }
244
245         if (overlay) {
246                 err = ubimkvol(libubi, node, overlay, 1);
247                 if (err) {
248                         ULOG_ERR("cannot make \"%s\"", overlay);
249                         return -1;
250                 }
251         }
252
253         libubi_close(libubi);
254
255         return err;
256 }
257
258 static int main_info(void)
259 {
260         struct ubi_info info;
261         libubi_t libubi;
262         int i;
263
264         libubi = libubi_open();
265         if (!libubi) {
266                 ULOG_ERR("cannot open libubi");
267                 return -1;
268         }
269
270         if (ubi_get_info(libubi, &info)) {
271                 ULOG_ERR("failed to get info\n");
272                 return -1;
273         }
274
275         for (i = info.lowest_dev_num; i <= info.highest_dev_num; i++) {
276                 struct ubi_dev_info dinfo;
277                 char ubi[64];
278                 int j;
279
280                 sprintf(ubi, "/dev/ubi%d", i);
281                 if (ubi_get_dev_info(libubi, ubi, &dinfo))
282                         continue;
283                 printf("device - %s\n  size: %lldBytes\n  bad blocks: %d\n",
284                        &ubi[5], dinfo.total_bytes, dinfo.bad_count);
285                 for (j = dinfo.lowest_vol_id; j <= dinfo.highest_vol_id; j++) {
286                         struct ubi_vol_info vinfo;
287
288                         sprintf(ubi, "/dev/ubi%d_%d", i, j);
289                         if (ubi_get_vol_info(libubi, ubi, &vinfo))
290                                 continue;
291                         printf("  volume - %s\n", &ubi[5]);
292                         printf("\tname: %s\n", vinfo.name);
293                         printf("\tsize: %lld\n", vinfo.data_bytes);
294                 }
295         }
296
297         libubi_close(libubi);
298
299         return 0;
300 }
301
302 int main(int argc, char **argv)
303 {
304         if (argc > 1 && !strcmp(argv[1], "info"))
305                 return main_info();
306
307         if (argc < 3)
308                 return print_usage();
309
310         if (!strcmp(argv[1], "kernel")) {
311                 return main_image("kernel", argv[2], NULL);
312
313         } else if (!strcmp(argv[1], "rootfs")) {
314                 return main_image("rootfs", argv[2], NULL);
315
316         } else if (!strcmp(argv[1], "overlay")) {
317                 return main_image("rootfs", argv[2], "rootfs_data");
318
319         } else if (!strcmp(argv[1], "detach")) {
320                 return main_detach(argv[2]);
321         }
322
323         return -1;
324 }
325