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