block: also probe loop devices
[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 }