]>
git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/storage/storage_utils.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
16 #include <sys/mount.h>
17 #include <sys/prctl.h>
19 #include <sys/types.h>
27 #include "storage_utils.h"
28 #include "syscall_wrappers.h"
36 #define BLKGETSIZE64 _IOR(0x12, 114, size_t)
39 lxc_log_define(storage_utils
, lxc
);
42 * attach_block_device returns true if all went well,
43 * meaning either a block device was attached or was not
44 * needed. It returns false if something went wrong and
45 * container startup should be stopped.
47 bool attach_block_device(struct lxc_conf
*conf
)
51 if (!conf
->rootfs
.path
)
54 path
= conf
->rootfs
.path
;
55 if (!requires_nbd(path
))
58 path
= strchr(path
, ':');
63 if (!attach_nbd(path
, conf
))
70 * return block size of dev->src in units of bytes
72 int blk_getsize(struct lxc_storage
*bdev
, uint64_t *size
)
77 src
= lxc_storage_get_path(bdev
->src
, bdev
->type
);
79 fd
= open(src
, O_RDONLY
| O_CLOEXEC
);
81 SYSERROR("Failed to open \"%s\"", src
);
85 /* size of device in bytes */
86 ret
= ioctl(fd
, BLKGETSIZE64
, size
);
88 SYSERROR("Failed to get block size of dev-src");
94 void detach_block_device(struct lxc_conf
*conf
)
96 if (conf
->nbd_idx
!= -1)
97 detach_nbd_idx(conf
->nbd_idx
);
101 * Given a lxc_storage (presumably blockdev-based), detect the fstype
102 * by trying mounting (in a private mntns) it.
103 * @lxc_storage: bdev to investigate
104 * @type: preallocated char* in which to write the fstype
105 * @len: length of passed in char*
106 * Returns length of fstype, of -1 on error
108 int detect_fs(struct lxc_storage
*bdev
, char *type
, int len
)
115 char *sp1
, *sp2
, *sp3
;
116 const char *l
, *srcdev
;
117 char devpath
[PATH_MAX
];
120 if (!bdev
|| !bdev
->src
|| !bdev
->dest
)
123 srcdev
= lxc_storage_get_path(bdev
->src
, bdev
->type
);
127 SYSERROR("Failed to create pipe");
133 SYSERROR("Failed to fork process");
141 memset(type
, 0, len
);
143 ret
= read(p
[0], type
, len
- 1);
145 SYSERROR("Failed to read FSType from pipe");
146 } else if (ret
== 0) {
147 ERROR("FSType not found - child exited early");
157 type
[len
- 1] = '\0';
158 INFO("Detected FSType \"%s\" for \"%s\"", type
, srcdev
);
163 if (unshare(CLONE_NEWNS
) < 0)
166 if (detect_shared_rootfs() && mount(NULL
, "/", NULL
, MS_SLAVE
| MS_REC
, NULL
))
167 SYSERROR("Failed to recursively turn root mount tree into dependent mount. Continuing...");
169 ret
= mount_unknown_fs(srcdev
, bdev
->dest
, bdev
->mntopts
);
171 ERROR("Failed to mount \"%s\" onto \"%s\" to detect FSType", srcdev
,
176 l
= linkderef(srcdev
, devpath
);
180 f
= fopen("/proc/self/mounts", "r");
184 while (getline(&line
, &linelen
, f
) != -1) {
187 sp1
= strchr(line
, ' ');
195 sp2
= strchr(sp1
+ 1, ' ');
200 sp3
= strchr(sp2
+ 1, ' ');
206 nbytes
= write(p
[1], sp2
, strlen(sp2
));
207 if (nbytes
< 0 || (size_t)nbytes
!= strlen(sp2
))
216 int do_mkfs_exec_wrapper(void *args
)
227 size_t len
= 5 + strlen(data
[0]) + 1;
233 ret
= snprintf(mkfs
, len
, "mkfs.%s", data
[0]);
234 if (ret
< 0 || (size_t)ret
>= len
) {
239 TRACE("Executing \"%s %s\"", mkfs
, data
[1]);
240 execlp(mkfs
, mkfs
, data
[1], (char *)NULL
);
242 SYSERROR("Failed to run \"%s %s\"", mkfs
, data
[1]);
249 * This will return 1 for physical disks, qemu-nbd, loop, etc right now only lvm
252 int is_blktype(struct lxc_storage
*b
)
254 if (strcmp(b
->type
, "lvm") == 0)
260 int mount_unknown_fs(const char *rootfs
, const char *target
,
276 * find the filesystem type with brute force:
277 * first we check with /etc/filesystems, in case the modules
278 * are auto-loaded and fall back to the supported kernel fs
285 for (i
= 0; i
< sizeof(fsfile
) / sizeof(fsfile
[0]); i
++) {
286 if (access(fsfile
[i
], F_OK
))
289 ret
= lxc_file_for_each_line(fsfile
[i
], find_fstype_cb
, &cbarg
);
291 ERROR("Failed to parse \"%s\"", fsfile
[i
]);
299 ERROR("Failed to determine FSType for \"%s\"", rootfs
);
305 * These are copied from conf.c. However as conf.c will be moved to using
306 * the callback system, they can be pulled from there eventually, so we
307 * don't need to pollute utils.c with these low level functions
309 int find_fstype_cb(char *buffer
, void *data
)
316 unsigned long mntflags
= 0;
317 char *mntdata
= NULL
;
320 /* we don't try 'nodev' entries */
321 if (strstr(buffer
, "nodev"))
325 fstype
+= lxc_char_left_gc(fstype
, strlen(fstype
));
326 fstype
[lxc_char_right_gc(fstype
, strlen(fstype
))] = '\0';
328 DEBUG("Trying to mount \"%s\"->\"%s\" with FSType \"%s\"", cbarg
->rootfs
,
329 cbarg
->target
, fstype
);
331 if (parse_mntopts_legacy(cbarg
->options
, &mntflags
, &mntdata
) < 0) {
336 if (mount(cbarg
->rootfs
, cbarg
->target
, fstype
, mntflags
, mntdata
)) {
337 SYSDEBUG("Failed to mount");
344 INFO("Mounted \"%s\" on \"%s\", with FSType \"%s\"", cbarg
->rootfs
,
345 cbarg
->target
, fstype
);
350 const char *linkderef(const char *path
, char *dest
)
355 ret
= stat(path
, &sbuf
);
357 SYSERROR("Failed to get status of file - \"%s\"", path
);
361 if (!S_ISLNK(sbuf
.st_mode
))
364 ret
= readlink(path
, dest
, PATH_MAX
);
366 SYSERROR("Failed to read link of \"%s\"", path
);
368 } else if (ret
>= PATH_MAX
) {
369 ERROR("The name of link of \"%s\" is too long", path
);
378 * is an unprivileged user allowed to make this kind of snapshot
380 bool unpriv_snap_allowed(struct lxc_storage
*b
, const char *t
, bool snap
,
384 /* New type will be same as original (unless snap && b->type ==
385 * dir, in which case it will be overlayfs -- which is also
388 if (strcmp(b
->type
, "dir") == 0 ||
389 strcmp(b
->type
, "overlay") == 0 ||
390 strcmp(b
->type
, "overlayfs") == 0 ||
391 strcmp(b
->type
, "btrfs") == 0 ||
392 strcmp(b
->type
, "loop") == 0)
398 /* Unprivileged users can copy and snapshot dir, overlayfs, and loop.
399 * In particular, not zfs, btrfs, or lvm.
401 if (strcmp(t
, "dir") == 0 ||
402 strcmp(t
, "overlay") == 0 ||
403 strcmp(t
, "overlayfs") == 0 ||
404 strcmp(t
, "btrfs") == 0 ||
405 strcmp(t
, "loop") == 0)
411 uint64_t get_fssize(char *s
)
416 ret
= strtoull(s
, &end
, 0);
418 ERROR("Invalid blockdev size '%s', using default size", s
);
422 while (isblank(*end
))
426 ret
*= 1024ULL * 1024ULL; /* MB by default */
427 } else if (*end
== 'b' || *end
== 'B') {
429 } else if (*end
== 'k' || *end
== 'K') {
431 } else if (*end
== 'm' || *end
== 'M') {
432 ret
*= 1024ULL * 1024ULL;
433 } else if (*end
== 'g' || *end
== 'G') {
434 ret
*= 1024ULL * 1024ULL * 1024ULL;
435 } else if (*end
== 't' || *end
== 'T') {
436 ret
*= 1024ULL * 1024ULL * 1024ULL * 1024ULL;
438 ERROR("Invalid blockdev unit size '%c' in '%s', using default size", *end
, s
);
445 bool is_valid_storage_type(const char *type
)
447 if (strcmp(type
, "dir") == 0 ||
448 strcmp(type
, "btrfs") == 0 ||
449 strcmp(type
, "loop") == 0 ||
450 strcmp(type
, "lvm") == 0 ||
451 strcmp(type
, "nbd") == 0 ||
452 strcmp(type
, "overlay") == 0 ||
453 strcmp(type
, "overlayfs") == 0 ||
454 strcmp(type
, "rbd") == 0 ||
455 strcmp(type
, "zfs") == 0)
461 int storage_destroy_wrapper(void *data
)
463 struct lxc_conf
*conf
= data
;
465 (void)lxc_drop_groups();
468 SYSERROR("Failed to setgid to 0");
473 SYSERROR("Failed to setuid to 0");
477 if (!storage_destroy(conf
)) {
478 ERROR("Failed to destroy storage");