]>
git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/bdev/storage_utils.c
2 * lxc: linux Container library
4 * Copyright © 2017 Canonical Ltd.
7 * Christian Brauner <christian.brauner@ubuntu.com>
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
36 #include <sys/mount.h>
37 #include <sys/prctl.h>
38 #include <sys/types.h>
46 #include "storage_utils.h"
50 #define BLKGETSIZE64 _IOR(0x12, 114, size_t)
53 lxc_log_define(storage_utils
, lxc
);
55 /* the bulk of this needs to become a common helper */
56 char *dir_new_path(char *src
, const char *oldname
, const char *name
,
57 const char *oldpath
, const char *lxcpath
)
62 nlen
= strlen(src
) + 1;
65 /* if src starts with oldpath, look for oldname only after
67 if (strncmp(src
, oldpath
, l1
) == 0) {
69 nlen
+= (strlen(lxcpath
) - l1
);
72 while ((p
= strstr(p
, oldname
)) != NULL
) {
74 nlen
+= strlen(name
) - l2
;
82 if (strncmp(src
, oldpath
, l1
) == 0) {
83 p
+= sprintf(p
, "%s", lxcpath
);
87 while ((p2
= strstr(src
, oldname
)) != NULL
) {
88 strncpy(p
, src
, p2
- src
); // copy text up to oldname
89 p
+= p2
- src
; // move target pointer (p)
91 name
); // print new name in place of oldname
92 src
= p2
+ l2
; // move src to end of oldname
94 sprintf(p
, "%s", src
); // copy the rest of src
99 * attach_block_device returns true if all went well,
100 * meaning either a block device was attached or was not
101 * needed. It returns false if something went wrong and
102 * container startup should be stopped.
104 bool attach_block_device(struct lxc_conf
*conf
)
108 if (!conf
->rootfs
.path
)
111 path
= conf
->rootfs
.path
;
112 if (!requires_nbd(path
))
115 path
= strchr(path
, ':');
120 if (!attach_nbd(path
, conf
))
127 * return block size of dev->src in units of bytes
129 int blk_getsize(struct bdev
*bdev
, uint64_t *size
)
134 src
= lxc_storage_get_path(bdev
->src
, bdev
->type
);
135 fd
= open(src
, O_RDONLY
);
139 ret
= ioctl(fd
, BLKGETSIZE64
, size
); // size of device in bytes
144 void detach_block_device(struct lxc_conf
*conf
)
146 if (conf
->nbd_idx
!= -1)
147 detach_nbd_idx(conf
->nbd_idx
);
151 * Given a bdev (presumably blockdev-based), detect the fstype
152 * by trying mounting (in a private mntns) it.
153 * @bdev: bdev to investigate
154 * @type: preallocated char* in which to write the fstype
155 * @len: length of passed in char*
156 * Returns length of fstype, of -1 on error
158 int detect_fs(struct bdev
*bdev
, char *type
, int len
)
164 char *sp1
, *sp2
, *sp3
, *srcdev
, *line
= NULL
;
166 if (!bdev
|| !bdev
->src
|| !bdev
->dest
)
169 srcdev
= lxc_storage_get_path(bdev
->src
, bdev
->type
);
175 if ((pid
= fork()) < 0)
181 memset(type
, 0, len
);
182 ret
= read(p
[0], type
, len
- 1);
185 SYSERROR("error reading from pipe");
188 } else if (ret
== 0) {
189 ERROR("child exited early - fstype not found");
194 type
[len
- 1] = '\0';
195 INFO("detected fstype %s for %s", type
, srcdev
);
199 if (unshare(CLONE_NEWNS
) < 0)
202 if (detect_shared_rootfs()) {
203 if (mount(NULL
, "/", NULL
, MS_SLAVE
| MS_REC
, NULL
)) {
204 SYSERROR("Failed to make / rslave");
205 ERROR("Continuing...");
209 ret
= mount_unknown_fs(srcdev
, bdev
->dest
, bdev
->mntopts
);
211 ERROR("failed mounting %s onto %s to detect fstype", srcdev
,
216 // if symlink, get the real dev name
217 char devpath
[MAXPATHLEN
];
218 char *l
= linkderef(srcdev
, devpath
);
221 f
= fopen("/proc/self/mounts", "r");
225 while (getline(&line
, &linelen
, f
) != -1) {
226 sp1
= strchr(line
, ' ');
232 sp2
= strchr(sp1
+ 1, ' ');
236 sp3
= strchr(sp2
+ 1, ' ');
241 if (write(p
[1], sp2
, strlen(sp2
)) != strlen(sp2
))
250 int do_mkfs_exec_wrapper(void *args
)
261 size_t len
= 5 + strlen(data
[0]) + 1;
267 ret
= snprintf(mkfs
, len
, "mkfs.%s", data
[0]);
268 if (ret
< 0 || (size_t)ret
>= len
) {
273 TRACE("executing \"%s %s\"", mkfs
, data
[1]);
274 execlp(mkfs
, mkfs
, data
[1], (char *)NULL
);
275 SYSERROR("failed to run \"%s %s \"", mkfs
, data
[1]);
280 * This will return 1 for physical disks, qemu-nbd, loop, etc right now only lvm
283 int is_blktype(struct bdev
*b
)
285 if (strcmp(b
->type
, "lvm") == 0)
291 int mount_unknown_fs(const char *rootfs
, const char *target
,
307 * find the filesystem type with brute force:
308 * first we check with /etc/filesystems, in case the modules
309 * are auto-loaded and fall back to the supported kernel fs
316 for (i
= 0; i
< sizeof(fsfile
) / sizeof(fsfile
[0]); i
++) {
317 if (access(fsfile
[i
], F_OK
))
320 ret
= lxc_file_for_each_line(fsfile
[i
], find_fstype_cb
, &cbarg
);
322 ERROR("failed to parse '%s'", fsfile
[i
]);
330 ERROR("failed to determine fs type for '%s'", rootfs
);
335 * These are copied from conf.c. However as conf.c will be moved to using
336 * the callback system, they can be pulled from there eventually, so we
337 * don't need to pollute utils.c with these low level functions
339 int find_fstype_cb(char *buffer
, void *data
)
347 unsigned long mntflags
;
351 /* we don't try 'nodev' entries */
352 if (strstr(buffer
, "nodev"))
356 fstype
+= lxc_char_left_gc(fstype
, strlen(fstype
));
357 fstype
[lxc_char_right_gc(fstype
, strlen(fstype
))] = '\0';
359 DEBUG("trying to mount '%s'->'%s' with fstype '%s'", cbarg
->rootfs
,
360 cbarg
->target
, fstype
);
362 if (parse_mntopts(cbarg
->options
, &mntflags
, &mntdata
) < 0) {
367 if (mount(cbarg
->rootfs
, cbarg
->target
, fstype
, mntflags
, mntdata
)) {
368 DEBUG("mount failed with error: %s", strerror(errno
));
375 INFO("mounted '%s' on '%s', with fstype '%s'", cbarg
->rootfs
,
376 cbarg
->target
, fstype
);
381 char *linkderef(char *path
, char *dest
)
386 ret
= stat(path
, &sbuf
);
390 if (!S_ISLNK(sbuf
.st_mode
))
393 ret
= readlink(path
, dest
, MAXPATHLEN
);
395 SYSERROR("error reading link %s", path
);
397 } else if (ret
>= MAXPATHLEN
) {
398 ERROR("link in %s too long", path
);
407 * is an unprivileged user allowed to make this kind of snapshot
409 bool unpriv_snap_allowed(struct bdev
*b
, const char *t
, bool snap
,
413 // new type will be same as original
414 // (unless snap && b->type == dir, in which case it will be
415 // overlayfs -- which is also allowed)
416 if (strcmp(b
->type
, "dir") == 0 ||
417 strcmp(b
->type
, "aufs") == 0 ||
418 strcmp(b
->type
, "overlay") == 0 ||
419 strcmp(b
->type
, "overlayfs") == 0 ||
420 strcmp(b
->type
, "btrfs") == 0 ||
421 strcmp(b
->type
, "loop") == 0)
427 // unprivileged users can copy and snapshot dir, overlayfs,
428 // and loop. In particular, not zfs, btrfs, or lvm.
429 if (strcmp(t
, "dir") == 0 ||
430 strcmp(t
, "aufs") == 0 ||
431 strcmp(t
, "overlay") == 0 ||
432 strcmp(t
, "overlayfs") == 0 ||
433 strcmp(t
, "btrfs") == 0 ||
434 strcmp(t
, "loop") == 0)
440 bool is_valid_bdev_type(const char *type
)
442 if (strcmp(type
, "dir") == 0 ||
443 strcmp(type
, "btrfs") == 0 ||
444 strcmp(type
, "aufs") == 0 ||
445 strcmp(type
, "loop") == 0 ||
446 strcmp(type
, "lvm") == 0 ||
447 strcmp(type
, "nbd") == 0 ||
448 strcmp(type
, "overlayfs") == 0 ||
449 strcmp(type
, "rbd") == 0 ||
450 strcmp(type
, "zfs") == 0)
456 int bdev_destroy_wrapper(void *data
)
458 struct lxc_conf
*conf
= data
;
461 ERROR("Failed to setgid to 0");
465 if (setgroups(0, NULL
) < 0)
466 WARN("Failed to clear groups");
469 ERROR("Failed to setuid to 0");
473 if (!bdev_destroy(conf
))