]> git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/storage/loop.c
overlay: rewrite and simplify
[mirror_lxc.git] / src / lxc / storage / loop.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2
3 #ifndef _GNU_SOURCE
4 #define _GNU_SOURCE 1
5 #endif
6 #define __STDC_FORMAT_MACROS
7 #include <dirent.h>
8 #include <errno.h>
9 #include <inttypes.h>
10 #include <linux/loop.h>
11 #include <stdint.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <sys/stat.h>
15 #include <sys/types.h>
16 #include <unistd.h>
17
18 #include "config.h"
19 #include "log.h"
20 #include "loop.h"
21 #include "memory_utils.h"
22 #include "storage.h"
23 #include "storage_utils.h"
24 #include "utils.h"
25
26 lxc_log_define(loop, lxc);
27
28 static int do_loop_create(const char *path, uint64_t size, const char *fstype);
29
30 /*
31 * No idea what the original blockdev will be called, but the copy will be
32 * called $lxcpath/$lxcname/rootdev
33 */
34 int loop_clonepaths(struct lxc_storage *orig, struct lxc_storage *new,
35 const char *oldname, const char *cname, const char *oldpath,
36 const char *lxcpath, int snap, uint64_t newsize,
37 struct lxc_conf *conf)
38 {
39 __do_free char *srcdev = NULL;
40 uint64_t size = newsize;
41 int len, ret;
42 char fstype[100] = "ext4";
43
44 if (snap) {
45 ERROR("The loop storage driver does not support snapshots");
46 return -1;
47 }
48
49 if (!orig->dest || !orig->src)
50 return -1;
51
52 len = strlen(lxcpath) + strlen(cname) + strlen("rootdev") + 3;
53 srcdev = must_realloc(NULL, len);
54 ret = snprintf(srcdev, len, "%s/%s/rootdev", lxcpath, cname);
55 if (ret < 0 || ret >= len) {
56 ERROR("Failed to create string");
57 return -1;
58 }
59
60 new->src = malloc(len + 5);
61 if (!new->src) {
62 ERROR("Failed to allocate memory");
63 return -1;
64 }
65
66 ret = snprintf(new->src, (len + 5), "loop:%s", srcdev);
67 if (ret < 0 || ret >= (len + 5)) {
68 ERROR("Failed to create string");
69 return -1;
70 }
71
72 new->dest = malloc(len);
73 if (!new->dest) {
74 ERROR("Failed to allocate memory");
75 return -1;
76 }
77
78 ret = snprintf(new->dest, len, "%s/%s/rootfs", lxcpath, cname);
79 if (ret < 0 || ret >= len) {
80 ERROR("Failed to create string");
81 return -1;
82 }
83
84 /* It's tempting to say: if orig->src == loopback and !newsize, then
85 * copy the loopback file. However, we'd have to make sure to correctly
86 * keep holes! So punt for now.
87 */
88 if (is_blktype(orig)) {
89 /* detect size */
90 if (!newsize && blk_getsize(orig, &size) < 0) {
91 ERROR("Failed to detect size of loop file \"%s\"",
92 orig->src);
93 return -1;
94 }
95
96 /* detect filesystem */
97 if (detect_fs(orig, fstype, 100) < 0) {
98 INFO("Failed to detect filesystem type for \"%s\"", orig->src);
99 return -1;
100 }
101 } else if (!newsize) {
102 size = DEFAULT_FS_SIZE;
103 }
104
105 ret = do_loop_create(srcdev, size, fstype);
106 if (ret < 0) {
107 ERROR("Failed to create loop storage volume \"%s\" with "
108 "filesystem \"%s\" and size \"%" PRIu64 "\"",
109 srcdev, fstype, size);
110 return -1;
111 }
112
113 return 0;
114 }
115
116 int loop_create(struct lxc_storage *bdev, const char *dest, const char *n,
117 struct bdev_specs *specs, const struct lxc_conf *conf)
118 {
119 __do_free char *srcdev = NULL;
120 const char *fstype;
121 uint64_t sz;
122 int ret, len;
123
124 if (!specs)
125 return -1;
126
127 /* <dest> is passed in as <lxcpath>/<lxcname>/rootfs, <srcdev> will
128 * be <lxcpath>/<lxcname>/rootdev, and <src> will be "loop:<srcdev>".
129 */
130 len = strlen(dest) + 2;
131 srcdev = must_realloc(NULL, len);
132
133 ret = snprintf(srcdev, len, "%s", dest);
134 if (ret < 0 || ret >= len) {
135 ERROR("Failed to create string");
136 return -1;
137 }
138
139 ret = sprintf(srcdev + len - 4, "dev");
140 if (ret < 0) {
141 ERROR("Failed to create string");
142 return -1;
143 }
144
145 bdev->src = malloc(len + 5);
146 if (!bdev->src) {
147 ERROR("Failed to allocate memory");
148 return -1;
149 }
150
151 ret = snprintf(bdev->src, len + 5, "loop:%s", srcdev);
152 if (ret < 0 || ret >= len + 5) {
153 ERROR("Failed to create string");
154 return -1;
155 }
156
157 sz = specs->fssize;
158 if (!sz)
159 sz = DEFAULT_FS_SIZE;
160
161 fstype = specs->fstype;
162 if (!fstype)
163 fstype = DEFAULT_FSTYPE;
164
165 bdev->dest = strdup(dest);
166 if (!bdev->dest) {
167 ERROR("Failed to duplicate string \"%s\"", dest);
168 return -1;
169 }
170
171 ret = mkdir_p(bdev->dest, 0755);
172 if (ret < 0) {
173 ERROR("Failed creating directory \"%s\"", bdev->dest);
174 return -1;
175 }
176
177
178 ret = do_loop_create(srcdev, sz, fstype);
179 if (ret < 0) {
180 ERROR("Failed to create loop storage volume \"%s\" with "
181 "filesystem \"%s\" and size \"%" PRIu64 "\"",
182 srcdev, fstype, sz);
183 return -1;
184 }
185
186 return 0;
187 }
188
189 int loop_destroy(struct lxc_storage *orig) {
190 char *dir;
191
192 dir = orig->src;
193 if (strncmp(orig->src, "loop:", 5) == 0)
194 dir += 5;
195
196 return unlink(dir);
197 }
198
199 bool loop_detect(const char *path)
200 {
201 int ret;
202 struct stat s;
203
204 if (!strncmp(path, "loop:", 5))
205 return true;
206
207 ret = stat(path, &s);
208 if (ret < 0)
209 return false;
210
211 if (__S_ISTYPE(s.st_mode, S_IFREG))
212 return true;
213
214 return false;
215 }
216
217 int loop_mount(struct lxc_storage *bdev)
218 {
219 int ret, loopfd;
220 char loname[PATH_MAX];
221 const char *src;
222
223 if (strcmp(bdev->type, "loop"))
224 return -22;
225
226 if (!bdev->src || !bdev->dest)
227 return -22;
228
229 /* skip prefix */
230 src = lxc_storage_get_path(bdev->src, bdev->type);
231
232 loopfd = lxc_prepare_loop_dev(src, loname, LO_FLAGS_AUTOCLEAR);
233 if (loopfd < 0) {
234 ERROR("Failed to prepare loop device for loop file \"%s\"", src);
235 return -1;
236 }
237 DEBUG("Prepared loop device \"%s\"", loname);
238
239 ret = mount_unknown_fs(loname, bdev->dest, bdev->mntopts);
240 if (ret < 0) {
241 ERROR("Failed to mount rootfs \"%s\" on \"%s\" via loop device \"%s\"",
242 bdev->src, bdev->dest, loname);
243 close(loopfd);
244 return -1;
245 }
246
247 bdev->lofd = loopfd;
248 DEBUG("Mounted rootfs \"%s\" on \"%s\" via loop device \"%s\"",
249 bdev->src, bdev->dest, loname);
250
251 return 0;
252 }
253
254 int loop_umount(struct lxc_storage *bdev)
255 {
256 int ret, saved_errno;
257
258 if (strcmp(bdev->type, "loop"))
259 return -22;
260
261 if (!bdev->src || !bdev->dest)
262 return -22;
263
264 ret = umount(bdev->dest);
265 saved_errno = errno;
266 if (bdev->lofd >= 0) {
267 close(bdev->lofd);
268 bdev->lofd = -1;
269 }
270 errno = saved_errno;
271
272 if (ret < 0) {
273 SYSERROR("Failed to umount \"%s\"", bdev->dest);
274 return -1;
275 }
276
277 return 0;
278 }
279
280 static int do_loop_create(const char *path, uint64_t size, const char *fstype)
281 {
282 int fd, ret;
283 off_t ret_size;
284 char cmd_output[PATH_MAX];
285 const char *cmd_args[2] = {fstype, path};
286
287 /* create the new loopback file */
288 fd = creat(path, S_IRUSR | S_IWUSR);
289 if (fd < 0) {
290 SYSERROR("Failed to create new loop file \"%s\"", path);
291 return -1;
292 }
293
294 ret_size = lseek(fd, size, SEEK_SET);
295 if (ret_size < 0) {
296 SYSERROR("Failed to seek to set new loop file size for loop "
297 "file \"%s\"", path);
298 close(fd);
299 return -1;
300 }
301
302 ret = write(fd, "1", 1);
303 if (ret != 1) {
304 SYSERROR("Failed creating new loop file \"%s\"", path);
305 close(fd);
306 return -1;
307 }
308
309 ret = close(fd);
310 if (ret < 0) {
311 SYSERROR("Failed to create new loop file \"%s\"", path);
312 return -1;
313 }
314
315 /* Create an fs in the loopback file. */
316 ret = run_command(cmd_output, sizeof(cmd_output), do_mkfs_exec_wrapper,
317 (void *)cmd_args);
318 if (ret < 0) {
319 ERROR("Failed to create new filesystem \"%s\" for loop file "
320 "\"%s\": %s", fstype, path, cmd_output);
321 return -1;
322 }
323
324 return 0;
325 }