libfstools: properly label ext4 overlay
[project/fstools.git] / libubi / libubi-tiny.c
1 /*
2 * Copyright (C) 2007 Nokia Corporation.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 2 as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License along with
14 * this program; if not, write to the Free Software Foundation, Inc., 51
15 * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
16 */
17
18 /*
19 * An utility to delete UBI devices (detach MTD devices from UBI).
20 *
21 * Author: Artem Bityutskiy
22 */
23
24 #define PROGRAM_NAME "ubidetach"
25 #define VERSION "owrt-fstools"
26
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <fcntl.h>
30 #include <stdio.h>
31 #include <stdint.h>
32 #include <getopt.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <unistd.h>
36
37 #include "libubi-tiny.h"
38
39 #define DEFAULT_CTRL_DEV "/dev/ubi_ctrl"
40
41 static int ubi_write(char *node, int fd, const void *buf, int len)
42 {
43 int ret;
44
45 while (len) {
46 ret = write(fd, buf, len);
47 if (ret < 0) {
48 if (errno == EINTR) {
49 fprintf(stderr, "do not interrupt me!");
50 continue;
51 }
52 fprintf(stderr, "cannot write %d bytes to volume \"%s\"", len, node);
53 return -1;
54 }
55
56 if (ret == 0) {
57 fprintf(stderr, "cannot write %d bytes to volume \"%s\"", len, node);
58 return -1;
59 }
60 len -= ret;
61 buf += ret;
62 }
63
64 return 0;
65 }
66
67 static int update_volume(libubi_t libubi, struct ubi_vol_info *vol_info, char *node, char *img, int skip)
68 {
69 int err, fd, ifd;
70 long long bytes;
71 char *buf;
72 struct stat st;
73
74 buf = malloc(vol_info->leb_size);
75 if (!buf) {
76 fprintf(stderr, "cannot allocate %d bytes of memory", vol_info->leb_size);
77 return -1;
78 }
79 err = stat(img, &st);
80 if (err < 0) {
81 fprintf(stderr, "stat failed on \"%s\"", img);
82 goto out_free;
83 }
84
85 bytes = st.st_size - skip;
86
87 if (bytes > vol_info->rsvd_bytes) {
88 fprintf(stderr, "\"%s\" (size %lld) will not fit volume \"%s\" (size %lld)",
89 img, bytes, node, vol_info->rsvd_bytes);
90 goto out_free;
91 }
92
93 fd = open(node, O_RDWR);
94 if (fd == -1) {
95 fprintf(stderr, "cannot open UBI volume \"%s\"", node);
96 goto out_free;
97 }
98
99 ifd = open(img, O_RDONLY);
100 if (ifd == -1) {
101 fprintf(stderr, "cannot open \"%s\"", img);
102 goto out_close1;
103 }
104
105 if (skip && lseek(ifd, skip, SEEK_CUR) == -1) {
106 fprintf(stderr, "lseek input by %d failed", skip);
107 goto out_close;
108 }
109
110 err = ubi_update_start(libubi, fd, bytes);
111 if (err) {
112 fprintf(stderr, "cannot start volume \"%s\" update", node);
113 goto out_close;
114 }
115
116 while (bytes) {
117 ssize_t ret;
118 int to_copy = vol_info->leb_size;
119 if (to_copy > bytes)
120 to_copy = bytes;
121
122 ret = read(ifd, buf, to_copy);
123 if (ret <= 0) {
124 if (errno == EINTR) {
125 fprintf(stderr, "do not interrupt me!");
126 continue;
127 } else {
128 fprintf(stderr, "cannot read %d bytes from \"%s\"",
129 to_copy, img);
130 goto out_close;
131 }
132 }
133
134 err = ubi_write(node, fd, buf, ret);
135 if (err)
136 goto out_close;
137 bytes -= ret;
138 }
139
140 close(ifd);
141 close(fd);
142 free(buf);
143 return 0;
144
145 out_close:
146 close(ifd);
147 out_close1:
148 close(fd);
149 out_free:
150 free(buf);
151 return -1;
152 }
153
154 int ubiattach(libubi_t libubi, char *mtd)
155 {
156 struct ubi_attach_request req = {
157 .dev_num = UBI_DEV_NUM_AUTO,
158 .mtd_num = -1,
159 .vid_hdr_offset = 0,
160 .max_beb_per1024 = 0,
161 .mtd_dev_node = mtd,
162 };
163 int err = ubi_attach(libubi, DEFAULT_CTRL_DEV, &req);
164
165 if (err) {
166 fprintf(stderr, "cannot attach \"%s\"", mtd);
167 return err;
168 }
169
170 return 0;
171 }
172
173 int ubidetach(libubi_t libubi, char *mtd)
174 {
175 return ubi_detach(libubi, DEFAULT_CTRL_DEV, mtd);
176 }
177
178 int ubirsvol(libubi_t libubi, char *node, char *name, int bytes)
179 {
180 struct ubi_dev_info dev_info;
181 struct ubi_vol_info vol_info;
182 int err = ubi_get_dev_info(libubi, node, &dev_info);
183
184 if (err) {
185 fprintf(stderr, "cannot get information about UBI device \"%s\"",
186 node);
187 return -1;
188 }
189 err = ubi_get_vol_info1_nm(libubi, dev_info.dev_num, name, &vol_info);
190 if (err) {
191 fprintf(stderr, "cannot find UBI volume \"%s\"", name);
192 return -1;
193 }
194
195 err = ubi_rsvol(libubi, node, vol_info.vol_id, bytes);
196 if (err) {
197 fprintf(stderr, "cannot UBI resize volume");
198 return -1;
199 }
200
201 return 0;
202 }
203
204 int ubirmvol(libubi_t libubi, char *node, char *name)
205 {
206 struct ubi_dev_info dev_info;
207 struct ubi_vol_info vol_info;
208 int err = ubi_get_dev_info(libubi, node, &dev_info);
209
210 if (err) {
211 fprintf(stderr, "cannot get information about UBI device \"%s\"",
212 node);
213 return -1;
214 }
215
216 err = ubi_get_vol_info1_nm(libubi, dev_info.dev_num, name, &vol_info);
217 if (err) {
218 fprintf(stderr, "cannot find UBI volume \"%s\"", name);
219 return -1;
220 }
221
222 err = ubi_rmvol(libubi, node, vol_info.vol_id);
223 if (err) {
224 fprintf(stderr, "cannot UBI remove volume");
225 return -1;
226 }
227
228 return 0;
229 }
230
231 int ubimkvol(libubi_t libubi, char *node, char *name, int maxavs)
232 {
233 struct ubi_dev_info dev_info;
234 struct ubi_vol_info vol_info;
235 struct ubi_mkvol_request req;
236 int err = ubi_get_dev_info(libubi, node, &dev_info);
237
238 if (err) {
239 fprintf(stderr, "cannot get information about UBI device \"%s\"",
240 node);
241 return -1;
242 }
243
244 if (dev_info.avail_bytes == 0) {
245 fprintf(stderr, "UBI device does not have free logical eraseblocks");
246 return -1;
247 }
248
249 if (maxavs)
250 printf("Set volume size to %lld\n", dev_info.avail_bytes);
251
252 req.vol_id = UBI_VOL_NUM_AUTO;
253 req.alignment = 1;
254 req.bytes = dev_info.avail_bytes;
255 req.vol_type = UBI_DYNAMIC_VOLUME;
256 req.name = name;
257
258 err = ubi_mkvol(libubi, node, &req);
259 if (err < 0) {
260 fprintf(stderr, "cannot UBI create volume");
261 return -1;
262 }
263
264 /* Print information about the created device */
265 err = ubi_get_vol_info1(libubi, dev_info.dev_num, req.vol_id, &vol_info);
266 if (err) {
267 fprintf(stderr, "cannot get information about newly created UBI volume");
268 return -1;
269 }
270
271 printf("Volume ID %d, size %d LEBs (", vol_info.vol_id, vol_info.rsvd_lebs);
272 ubiutils_print_bytes(vol_info.rsvd_bytes, 0);
273 printf("), LEB size ");
274 ubiutils_print_bytes(vol_info.leb_size, 1);
275 printf(", %s, name \"%s\", alignment %d\n",
276 req.vol_type == UBI_DYNAMIC_VOLUME ? "dynamic" : "static",
277 vol_info.name, vol_info.alignment);
278
279 return 0;
280 }
281
282 int ubiupdatevol(libubi_t libubi, char *node, char *file)
283 {
284 struct ubi_vol_info vol_info;
285 int err = ubi_get_vol_info(libubi, node, &vol_info);
286
287 if (err) {
288 fprintf(stderr, "cannot get information about UBI volume \"%s\"",
289 node);
290 return -1;
291 }
292
293 return update_volume(libubi, &vol_info, node, file, 0);
294 }
295
296 int ubitruncatevol(libubi_t libubi, char *node)
297 {
298 int err, fd;
299
300 fd = open(node, O_RDWR);
301 if (fd == -1) {
302 fprintf(stderr, "cannot open \"%s\"", node);
303 return -1;
304 }
305
306 err = ubi_update_start(libubi, fd, 0);
307 if (err) {
308 fprintf(stderr, "cannot truncate volume \"%s\"", node);
309 close(fd);
310 return -1;
311 }
312
313 close(fd);
314 return 0;
315 }