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