]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/storage/storage.c
Merge pull request #3235 from xinhua9569/master
[mirror_lxc.git] / src / lxc / storage / storage.c
CommitLineData
cc73685d 1/* SPDX-License-Identifier: LGPL-2.1+ */
9be53773 2
d38dd64a
CB
3#ifndef _GNU_SOURCE
4#define _GNU_SOURCE 1
5#endif
38683db4 6#include <dirent.h>
9be53773 7#include <errno.h>
38683db4
CB
8#include <fcntl.h>
9#include <grp.h>
10#include <inttypes.h>
9be53773 11#include <libgen.h>
38683db4
CB
12#include <sched.h>
13#include <stdint.h>
14#include <stdio.h>
15#include <string.h>
38683db4 16#include <sys/mount.h>
76a26f55 17#include <sys/prctl.h>
38683db4 18#include <sys/stat.h>
d38dd64a 19#include <sys/types.h>
38683db4 20#include <sys/wait.h>
d38dd64a 21#include <unistd.h>
f2363e38 22
28d832c4 23#include "btrfs.h"
9be53773 24#include "conf.h"
3188197d 25#include "config.h"
28d832c4 26#include "dir.h"
9be53773 27#include "error.h"
38683db4 28#include "log.h"
28d832c4
CB
29#include "loop.h"
30#include "lvm.h"
38683db4 31#include "lxc.h"
e9df7e1a 32#include "lxclock.h"
643c9ec9 33#include "memory_utils.h"
38683db4 34#include "namespace.h"
d38dd64a 35#include "nbd.h"
28d832c4 36#include "overlay.h"
38683db4 37#include "parse.h"
28d832c4
CB
38#include "rbd.h"
39#include "rsync.h"
40#include "storage.h"
f2d5a09d 41#include "storage_utils.h"
38683db4 42#include "utils.h"
28d832c4 43#include "zfs.h"
9be53773 44
43f984ea
DJ
45#ifndef HAVE_STRLCPY
46#include "include/strlcpy.h"
47#endif
48
bff13ba2 49#ifndef BLKGETSIZE64
eab15c1e 50#define BLKGETSIZE64 _IOR(0x12, 114, size_t)
bff13ba2
SG
51#endif
52
28d832c4 53lxc_log_define(storage, lxc);
9be53773 54
2b9cbd53 55/* btrfs */
10bc1861 56static const struct lxc_storage_ops btrfs_ops = {
493de765
CB
57 .detect = &btrfs_detect,
58 .mount = &btrfs_mount,
59 .umount = &btrfs_umount,
60 .clone_paths = &btrfs_clonepaths,
61 .destroy = &btrfs_destroy,
62 .create = &btrfs_create,
3ef1df7c
CB
63 .copy = &btrfs_create_clone,
64 .snapshot = &btrfs_create_snapshot,
493de765
CB
65 .can_snapshot = true,
66 .can_backup = true,
2b9cbd53
CB
67};
68
304b4cf3 69/* dir */
10bc1861 70static const struct lxc_storage_ops dir_ops = {
493de765
CB
71 .detect = &dir_detect,
72 .mount = &dir_mount,
73 .umount = &dir_umount,
74 .clone_paths = &dir_clonepaths,
75 .destroy = &dir_destroy,
76 .create = &dir_create,
3ef1df7c
CB
77 .copy = NULL,
78 .snapshot = NULL,
493de765
CB
79 .can_snapshot = false,
80 .can_backup = true,
9d983015
CB
81};
82
304b4cf3 83/* loop */
10bc1861 84static const struct lxc_storage_ops loop_ops = {
493de765
CB
85 .detect = &loop_detect,
86 .mount = &loop_mount,
87 .umount = &loop_umount,
88 .clone_paths = &loop_clonepaths,
89 .destroy = &loop_destroy,
90 .create = &loop_create,
3ef1df7c
CB
91 .copy = NULL,
92 .snapshot = NULL,
493de765
CB
93 .can_snapshot = false,
94 .can_backup = true,
304b4cf3
CB
95};
96
2b9cbd53 97/* lvm */
10bc1861 98static const struct lxc_storage_ops lvm_ops = {
493de765
CB
99 .detect = &lvm_detect,
100 .mount = &lvm_mount,
101 .umount = &lvm_umount,
102 .clone_paths = &lvm_clonepaths,
103 .destroy = &lvm_destroy,
104 .create = &lvm_create,
3ef1df7c
CB
105 .copy = &lvm_create_clone,
106 .snapshot = &lvm_create_snapshot,
493de765
CB
107 .can_snapshot = true,
108 .can_backup = false,
2b9cbd53
CB
109};
110
bf76c012 111/* nbd */
10bc1861 112const struct lxc_storage_ops nbd_ops = {
493de765
CB
113 .detect = &nbd_detect,
114 .mount = &nbd_mount,
115 .umount = &nbd_umount,
116 .clone_paths = &nbd_clonepaths,
117 .destroy = &nbd_destroy,
118 .create = &nbd_create,
3ef1df7c
CB
119 .copy = NULL,
120 .snapshot = NULL,
493de765
CB
121 .can_snapshot = true,
122 .can_backup = false,
bf76c012
CB
123};
124
2b9cbd53 125/* overlay */
10bc1861 126static const struct lxc_storage_ops ovl_ops = {
493de765
CB
127 .detect = &ovl_detect,
128 .mount = &ovl_mount,
129 .umount = &ovl_umount,
130 .clone_paths = &ovl_clonepaths,
131 .destroy = &ovl_destroy,
132 .create = &ovl_create,
3ef1df7c
CB
133 .copy = NULL,
134 .snapshot = NULL,
493de765
CB
135 .can_snapshot = true,
136 .can_backup = true,
2b9cbd53
CB
137};
138
3ceb2820 139/* rbd */
10bc1861 140static const struct lxc_storage_ops rbd_ops = {
493de765
CB
141 .detect = &rbd_detect,
142 .mount = &rbd_mount,
143 .umount = &rbd_umount,
144 .clone_paths = &rbd_clonepaths,
145 .destroy = &rbd_destroy,
146 .create = &rbd_create,
3ef1df7c
CB
147 .copy = NULL,
148 .snapshot = NULL,
493de765
CB
149 .can_snapshot = false,
150 .can_backup = false,
3ceb2820
CB
151};
152
2b9cbd53 153/* zfs */
10bc1861 154static const struct lxc_storage_ops zfs_ops = {
493de765
CB
155 .detect = &zfs_detect,
156 .mount = &zfs_mount,
157 .umount = &zfs_umount,
158 .clone_paths = &zfs_clonepaths,
159 .destroy = &zfs_destroy,
160 .create = &zfs_create,
3ef1df7c
CB
161 .copy = &zfs_copy,
162 .snapshot = &zfs_snapshot,
493de765
CB
163 .can_snapshot = true,
164 .can_backup = true,
2b9cbd53
CB
165};
166
10bc1861 167struct lxc_storage_type {
cdb4e53a 168 const char *name;
10bc1861 169 const struct lxc_storage_ops *ops;
cdb4e53a
CB
170};
171
10bc1861 172static const struct lxc_storage_type bdevs[] = {
f7ac4459 173 { .name = "dir", .ops = &dir_ops, },
493de765
CB
174 { .name = "zfs", .ops = &zfs_ops, },
175 { .name = "lvm", .ops = &lvm_ops, },
176 { .name = "rbd", .ops = &rbd_ops, },
177 { .name = "btrfs", .ops = &btrfs_ops, },
ba115175 178 { .name = "overlay", .ops = &ovl_ops, },
493de765
CB
179 { .name = "overlayfs", .ops = &ovl_ops, },
180 { .name = "loop", .ops = &loop_ops, },
181 { .name = "nbd", .ops = &nbd_ops, },
cdb4e53a
CB
182};
183
10bc1861 184static const size_t numbdevs = sizeof(bdevs) / sizeof(struct lxc_storage_type);
cdb4e53a 185
8a388ed4 186static const struct lxc_storage_type *get_storage_by_name(const char *path,
63c9ffa0 187 const char *type)
38683db4 188{
63c9ffa0 189 int ret;
f2d5a09d 190 size_t i, cmplen;
38683db4 191
63c9ffa0
CB
192 if (type)
193 cmplen = strlen(type);
194 else
8a388ed4 195 cmplen = strcspn(path, ":");
f2d5a09d 196 if (cmplen == 0)
38683db4
CB
197 return NULL;
198
63c9ffa0
CB
199 for (i = 0; i < numbdevs; i++) {
200 if (type)
201 ret = strncmp(bdevs[i].name, type, cmplen);
202 else
8a388ed4 203 ret = strncmp(bdevs[i].name, path, cmplen);
63c9ffa0 204 if (ret == 0)
f2d5a09d 205 break;
63c9ffa0 206 }
38683db4 207
f2d5a09d
CB
208 if (i == numbdevs)
209 return NULL;
210
211 DEBUG("Detected rootfs type \"%s\"", bdevs[i].name);
212 return &bdevs[i];
38683db4
CB
213}
214
8a388ed4 215static const struct lxc_storage_type *storage_query(struct lxc_conf *conf)
9be53773 216{
f2d5a09d 217 size_t i;
10bc1861 218 const struct lxc_storage_type *bdev;
8a388ed4
CB
219 const char *path = conf->rootfs.path;
220 const char *type = conf->rootfs.bdev_type;
eddaaafd 221
8a388ed4 222 bdev = get_storage_by_name(path, type);
f2d5a09d
CB
223 if (bdev)
224 return bdev;
493de765 225
f2d5a09d 226 for (i = 0; i < numbdevs; i++)
8a388ed4 227 if (bdevs[i].ops->detect(path))
f2d5a09d 228 break;
493de765 229
f2d5a09d
CB
230 if (i == numbdevs)
231 return NULL;
493de765 232
f2d5a09d
CB
233 DEBUG("Detected rootfs type \"%s\"", bdevs[i].name);
234 return &bdevs[i];
235}
236
10bc1861 237struct lxc_storage *storage_get(const char *type)
f2d5a09d
CB
238{
239 size_t i;
10bc1861 240 struct lxc_storage *bdev;
f2d5a09d 241
09f6f8c4 242 for (i = 0; i < numbdevs; i++)
f2d5a09d
CB
243 if (strcmp(bdevs[i].name, type) == 0)
244 break;
f2d5a09d
CB
245
246 if (i == numbdevs)
247 return NULL;
248
10bc1861 249 bdev = malloc(sizeof(struct lxc_storage));
f2d5a09d
CB
250 if (!bdev)
251 return NULL;
252
10bc1861 253 memset(bdev, 0, sizeof(struct lxc_storage));
f2d5a09d
CB
254 bdev->ops = bdevs[i].ops;
255 bdev->type = bdevs[i].name;
256
257 return bdev;
258}
259
10bc1861
CB
260static struct lxc_storage *do_storage_create(const char *dest, const char *type,
261 const char *cname,
262 struct bdev_specs *specs)
f2d5a09d 263{
09f6f8c4 264 int ret;
10bc1861 265 struct lxc_storage *bdev;
f2d5a09d 266
5e78e16a
CB
267 if (!type)
268 type = "dir";
269
10bc1861 270 bdev = storage_get(type);
f2d5a09d
CB
271 if (!bdev)
272 return NULL;
493de765 273
09f6f8c4
CB
274 ret = bdev->ops->create(bdev, dest, cname, specs);
275 if (ret < 0) {
10bc1861 276 storage_put(bdev);
f2d5a09d
CB
277 return NULL;
278 }
279
280 return bdev;
cdb4e53a 281}
9be53773 282
10bc1861 283bool storage_can_backup(struct lxc_conf *conf)
cdb4e53a 284{
cdb4e53a 285 bool ret;
8a388ed4 286 struct lxc_storage *bdev;
d659597e 287
8a388ed4 288 bdev = storage_init(conf);
cdb4e53a
CB
289 if (!bdev)
290 return false;
493de765 291
cdb4e53a 292 ret = bdev->ops->can_backup;
10bc1861 293 storage_put(bdev);
9be53773
SH
294 return ret;
295}
296
bf86c00a 297/* If we're not snapshotting, then storage_copy becomes a simple case of mount
cdb4e53a 298 * the original, mount the new, and rsync the contents.
9be53773 299 */
07db51a2 300struct lxc_storage *storage_copy(struct lxc_container *c, const char *cname,
10bc1861
CB
301 const char *lxcpath, const char *bdevtype,
302 int flags, const char *bdevdata,
07db51a2 303 uint64_t newsize, bool *needs_rdep)
9be53773 304{
cdb4e53a 305 int ret;
41dc7155 306 const char *src_no_prefix;
06d0056c
CB
307 struct lxc_storage *new, *orig;
308 bool snap = (flags & LXC_CLONE_SNAPSHOT);
309 bool maybe_snap = (flags & LXC_CLONE_MAYBE_SNAPSHOT);
310 bool keepbdevtype = (flags & LXC_CLONE_KEEPBDEVTYPE);
07db51a2
CB
311 const char *src = c->lxc_conf->rootfs.path;
312 const char *oldname = c->name;
313 const char *oldpath = c->config_path;
339de297 314 char cmd_output[PATH_MAX] = {0};
06d0056c 315 struct rsync_data data = {0};
9be53773 316
45b4bb96
CB
317 if (!src) {
318 ERROR("No rootfs specified");
319 return NULL;
320 }
321
6f748a97
CB
322 /* If the container name doesn't show up in the rootfs path, then we
323 * don't know how to come up with a new name.
cdb4e53a 324 */
3324c255 325 if (!strstr(src, oldname)) {
6f748a97
CB
326 ERROR("Original rootfs path \"%s\" does not include container "
327 "name \"%s\"", src, oldname);
cdb4e53a
CB
328 return NULL;
329 }
9be53773 330
8a388ed4 331 orig = storage_init(c->lxc_conf);
cdb4e53a 332 if (!orig) {
06d0056c 333 ERROR("Failed to detect storage driver for \"%s\"", oldname);
cdb4e53a
CB
334 return NULL;
335 }
9be53773 336
cdb4e53a 337 if (!orig->dest) {
cdb4e53a
CB
338 size_t len;
339 struct stat sb;
9be53773 340
cdb4e53a
CB
341 len = strlen(oldpath) + strlen(oldname) + strlen("/rootfs") + 2;
342 orig->dest = malloc(len);
343 if (!orig->dest) {
3324c255 344 ERROR("Failed to allocate memory");
07db51a2 345 goto on_error_put_orig;
cdb4e53a 346 }
493de765 347
cdb4e53a
CB
348 ret = snprintf(orig->dest, len, "%s/%s/rootfs", oldpath, oldname);
349 if (ret < 0 || (size_t)ret >= len) {
3324c255 350 ERROR("Failed to create string");
07db51a2 351 goto on_error_put_orig;
cdb4e53a 352 }
493de765 353
6f748a97
CB
354 ret = stat(orig->dest, &sb);
355 if (ret < 0 && errno == ENOENT) {
356 ret = mkdir_p(orig->dest, 0755);
357 if (ret < 0)
eee1a9d7 358 WARN("Failed to create directory \"%s\"", orig->dest);
6f748a97 359 }
cdb4e53a 360 }
9be53773 361
3324c255
CB
362 /* Special case for snapshot. If the caller requested maybe_snapshot and
363 * keepbdevtype and the backing store is directory, then proceed with a
364 * a copy clone rather than returning error.
cdb4e53a
CB
365 */
366 if (maybe_snap && keepbdevtype && !bdevtype && !orig->ops->can_snapshot)
367 snap = false;
368
6f748a97 369 /* If newtype is NULL and snapshot is set, then use overlay. */
70e95c8d 370 if (!bdevtype && !keepbdevtype && snap && !strcmp(orig->type, "dir"))
ba115175 371 bdevtype = "overlay";
cdb4e53a 372
e0010464 373 if (am_guest_unpriv() && !unpriv_snap_allowed(orig, bdevtype, snap, maybe_snap)) {
ba115175
CB
374 ERROR("Unsupported snapshot type \"%s\" for unprivileged users",
375 bdevtype ? bdevtype : "(null)");
07db51a2 376 goto on_error_put_orig;
a17b1e65
SG
377 }
378
07db51a2 379 *needs_rdep = false;
70e95c8d
CB
380 if (bdevtype) {
381 if (snap && !strcmp(orig->type, "lvm") &&
382 !lvm_is_thin_volume(orig->src))
383 *needs_rdep = true;
384 else if (!strcmp(bdevtype, "overlay") ||
385 !strcmp(bdevtype, "overlayfs"))
386 *needs_rdep = true;
387 } else {
388 if (!snap && strcmp(oldpath, lxcpath))
389 bdevtype = "dir";
390 else
391 bdevtype = orig->type;
9be53773 392
70e95c8d
CB
393 if (!strcmp(bdevtype, "overlay") ||
394 !strcmp(bdevtype, "overlayfs"))
395 *needs_rdep = true;
396 }
b196516b
CB
397
398 /* get new bdev type */
10bc1861 399 new = storage_get(bdevtype);
cdb4e53a 400 if (!new) {
06d0056c 401 ERROR("Failed to initialize %s storage driver",
493de765 402 bdevtype ? bdevtype : orig->type);
07db51a2 403 goto on_error_put_orig;
cdb4e53a 404 }
06d0056c 405 TRACE("Initialized %s storage driver", new->type);
a17b1e65 406
b196516b 407 /* create new paths */
6f748a97 408 ret = new->ops->clone_paths(orig, new, oldname, cname, oldpath, lxcpath,
07db51a2 409 snap, newsize, c->lxc_conf);
6f748a97
CB
410 if (ret < 0) {
411 ERROR("Failed creating new paths for clone of \"%s\"", src);
07db51a2 412 goto on_error_put_new;
cdb4e53a 413 }
9be53773 414
70e95c8d
CB
415 /* When we create an overlay snapshot of an overlay container in the
416 * snapshot directory under "<lxcpath>/<name>/snaps/" we don't need to
417 * record a dependency. If we would restore would also fail.
418 */
06d0056c
CB
419 if ((strcmp(new->type, "overlay") == 0 ||
420 strcmp(new->type, "overlayfs") == 0) &&
70e95c8d
CB
421 ret == LXC_CLONE_SNAPSHOT)
422 *needs_rdep = false;
423
6f748a97 424 /* btrfs */
b196516b 425 if (!strcmp(orig->type, "btrfs") && !strcmp(new->type, "btrfs")) {
06d0056c
CB
426 bool bret;
427
b196516b 428 if (snap || btrfs_same_fs(orig->dest, new->dest) == 0)
07db51a2 429 bret = new->ops->snapshot(c->lxc_conf, orig, new, 0);
b196516b 430 else
07db51a2 431 bret = new->ops->copy(c->lxc_conf, orig, new, 0);
b196516b 432 if (!bret)
07db51a2
CB
433 goto on_error_put_new;
434
435 goto on_success;
b196516b
CB
436 }
437
6f748a97 438 /* lvm */
d91e13d8 439 if (!strcmp(orig->type, "lvm") && !strcmp(new->type, "lvm")) {
06d0056c
CB
440 bool bret;
441
d91e13d8 442 if (snap)
06d0056c 443 bret = new->ops->snapshot(c->lxc_conf, orig, new, newsize);
d91e13d8 444 else
07db51a2 445 bret = new->ops->copy(c->lxc_conf, orig, new, newsize);
3ef1df7c 446 if (!bret)
07db51a2
CB
447 goto on_error_put_new;
448
449 goto on_success;
3ef1df7c
CB
450 }
451
452 /* zfs */
453 if (!strcmp(orig->type, "zfs") && !strcmp(new->type, "zfs")) {
06d0056c 454 bool bret;
3ef1df7c
CB
455
456 if (snap)
06d0056c 457 bret = new->ops->snapshot(c->lxc_conf, orig, new, newsize);
3ef1df7c 458 else
07db51a2 459 bret = new->ops->copy(c->lxc_conf, orig, new, newsize);
d91e13d8 460 if (!bret)
07db51a2
CB
461 goto on_error_put_new;
462
463 goto on_success;
d91e13d8
CB
464 }
465
7a9e0f35 466 if (strcmp(bdevtype, "btrfs")) {
6f748a97 467 if (!strcmp(new->type, "overlay") || !strcmp(new->type, "overlayfs"))
7a9e0f35
CB
468 src_no_prefix = ovl_get_lower(new->src);
469 else
470 src_no_prefix = lxc_storage_get_path(new->src, new->type);
471
e0010464 472 if (am_guest_unpriv()) {
07db51a2 473 ret = chown_mapped_root(src_no_prefix, c->lxc_conf);
6f748a97
CB
474 if (ret < 0)
475 WARN("Failed to chown \"%s\"", new->src);
476 }
7a9e0f35 477 }
9be53773 478
cdb4e53a 479 if (snap)
07db51a2 480 goto on_success;
9be53773 481
6f748a97 482 /* rsync the contents from source to target */
db3ac7ba
CB
483 data.orig = orig;
484 data.new = new;
e0010464 485 if (am_guest_unpriv())
5c05427a
CB
486 ret = userns_exec_full(c->lxc_conf,
487 lxc_storage_rsync_exec_wrapper, &data,
488 "lxc_storage_rsync_exec_wrapper");
07db51a2 489 else
db3ac7ba 490 ret = run_command(cmd_output, sizeof(cmd_output),
17a367d8 491 lxc_storage_rsync_exec_wrapper, (void *)&data);
07db51a2
CB
492 if (ret < 0) {
493 ERROR("Failed to rsync from \"%s\" into \"%s\"%s%s", orig->dest,
494 new->dest,
495 cmd_output[0] != '\0' ? ": " : "",
496 cmd_output[0] != '\0' ? cmd_output : "");
497 goto on_error_put_new;
9be53773
SH
498 }
499
07db51a2 500on_success:
10bc1861 501 storage_put(orig);
07db51a2 502
db3ac7ba 503 return new;
cdb4e53a 504
07db51a2 505on_error_put_new:
10bc1861 506 storage_put(new);
07db51a2
CB
507
508on_error_put_orig:
509 storage_put(orig);
510
cdb4e53a
CB
511 return NULL;
512}
513
10bc1861 514/* Create a backing store for a container.
cdb4e53a
CB
515 * If successful, return a struct bdev *, with the bdev mounted and ready
516 * for use. Before completing, the caller will need to call the
10bc1861 517 * umount operation and storage_put().
cdb4e53a
CB
518 * @dest: the mountpoint (i.e. /var/lib/lxc/$name/rootfs)
519 * @type: the bdevtype (dir, btrfs, zfs, rbd, etc)
520 * @cname: the container name
521 * @specs: details about the backing store to create, like fstype
522 */
10bc1861
CB
523struct lxc_storage *storage_create(const char *dest, const char *type,
524 const char *cname, struct bdev_specs *specs)
9be53773 525{
e9e29a33 526 int ret;
10bc1861 527 struct lxc_storage *bdev;
cdb4e53a 528 char *best_options[] = {"btrfs", "zfs", "lvm", "dir", "rbd", NULL};
9be53773 529
cdb4e53a 530 if (!type)
10bc1861 531 return do_storage_create(dest, "dir", cname, specs);
cdb4e53a 532
e9e29a33
CB
533 ret = strcmp(type, "best");
534 if (ret == 0) {
cdb4e53a 535 int i;
10bc1861
CB
536 /* Try for the best backing store type, according to our
537 * opinionated preferences.
538 */
cdb4e53a 539 for (i = 0; best_options[i]; i++) {
e9e29a33 540 bdev = do_storage_create(dest, best_options[i], cname, specs);
10bc1861 541 if (bdev)
cdb4e53a
CB
542 return bdev;
543 }
493de765 544
10bc1861 545 return NULL;
9be53773 546 }
9be53773 547
10bc1861 548 /* -B lvm,dir */
e9e29a33 549 if (strchr(type, ',')) {
63fce0c1 550 __do_free char *dup = NULL;
643c9ec9 551 char *token;
43f984ea 552
643c9ec9 553 dup = must_copy_string(type);
eb29852f 554 lxc_iterate_parts(token, dup, ",") {
e9e29a33
CB
555 bdev = do_storage_create(dest, token, cname, specs);
556 if (bdev)
cdb4e53a
CB
557 return bdev;
558 }
559 }
560
10bc1861 561 return do_storage_create(dest, type, cname, specs);
9be53773
SH
562}
563
10bc1861 564bool storage_destroy(struct lxc_conf *conf)
9be53773 565{
10bc1861 566 struct lxc_storage *r;
cdb4e53a 567 bool ret = false;
ed05aac8 568 int destroy_rv = 0;
9be53773 569
8a388ed4 570 r = storage_init(conf);
cdb4e53a
CB
571 if (!r)
572 return ret;
573
ed05aac8
MM
574 destroy_rv = r->ops->destroy(r);
575 if (destroy_rv == 0)
cdb4e53a 576 ret = true;
cdb4e53a 577
10bc1861 578 storage_put(r);
cdb4e53a
CB
579 return ret;
580}
581
8a388ed4 582struct lxc_storage *storage_init(struct lxc_conf *conf)
cdb4e53a 583{
10bc1861
CB
584 struct lxc_storage *bdev;
585 const struct lxc_storage_type *q;
8a388ed4
CB
586 const char *src = conf->rootfs.path;
587 const char *dst = conf->rootfs.mount;
588 const char *mntopts = conf->rootfs.options;
cdb4e53a 589
17a367d8
CB
590 BUILD_BUG_ON(LXC_STORAGE_INTERNAL_OVERLAY_RESTORE <= LXC_CLONE_MAXFLAGS);
591
cdb4e53a 592 if (!src)
9be53773 593 return NULL;
cdb4e53a 594
8a388ed4 595 q = storage_query(conf);
cdb4e53a 596 if (!q)
9be53773 597 return NULL;
cdb4e53a 598
10bc1861 599 bdev = malloc(sizeof(struct lxc_storage));
cdb4e53a 600 if (!bdev)
9be53773 601 return NULL;
493de765 602
10bc1861 603 memset(bdev, 0, sizeof(struct lxc_storage));
8a388ed4 604
cdb4e53a
CB
605 bdev->ops = q->ops;
606 bdev->type = q->name;
8a388ed4 607
cdb4e53a
CB
608 if (mntopts)
609 bdev->mntopts = strdup(mntopts);
8a388ed4 610
cdb4e53a
CB
611 if (src)
612 bdev->src = strdup(src);
8a388ed4 613
cdb4e53a
CB
614 if (dst)
615 bdev->dest = strdup(dst);
8a388ed4 616
cdb4e53a
CB
617 if (strcmp(bdev->type, "nbd") == 0)
618 bdev->nbd_idx = conf->nbd_idx;
619
620 return bdev;
621}
622
068aa488 623bool storage_is_dir(struct lxc_conf *conf)
cdb4e53a 624{
10bc1861 625 struct lxc_storage *orig;
068aa488 626 char *type = conf->rootfs.bdev_type;
10bc1861
CB
627 bool bret = false;
628
068aa488
CB
629 if (type)
630 return (strcmp(type, "dir") == 0);
631
8a388ed4 632 orig = storage_init(conf);
cdb4e53a 633 if (!orig)
10bc1861
CB
634 return bret;
635
cdb4e53a 636 if (strcmp(orig->type, "dir") == 0)
10bc1861
CB
637 bret = true;
638
639 storage_put(orig);
640 return bret;
cdb4e53a
CB
641}
642
10bc1861 643void storage_put(struct lxc_storage *bdev)
cdb4e53a
CB
644{
645 free(bdev->mntopts);
646 free(bdev->src);
647 free(bdev->dest);
648 free(bdev);
649}
650
cdb4e53a
CB
651bool rootfs_is_blockdev(struct lxc_conf *conf)
652{
10bc1861 653 const struct lxc_storage_type *q;
cdb4e53a
CB
654 struct stat st;
655 int ret;
656
657 if (!conf->rootfs.path || strcmp(conf->rootfs.path, "/") == 0 ||
493de765 658 strlen(conf->rootfs.path) == 0)
cdb4e53a
CB
659 return false;
660
661 ret = stat(conf->rootfs.path, &st);
662 if (ret == 0 && S_ISBLK(st.st_mode))
663 return true;
493de765 664
8a388ed4 665 q = storage_query(conf);
cdb4e53a
CB
666 if (!q)
667 return false;
493de765 668
cdb4e53a 669 if (strcmp(q->name, "lvm") == 0 ||
493de765 670 strcmp(q->name, "loop") == 0 ||
f83dd99e
CB
671 strcmp(q->name, "nbd") == 0 ||
672 strcmp(q->name, "rbd") == 0 ||
673 strcmp(q->name, "zfs") == 0)
cdb4e53a 674 return true;
493de765 675
cdb4e53a
CB
676 return false;
677}
4f25fd38 678
41dc7155 679const char *lxc_storage_get_path(char *src, const char *prefix)
4f25fd38
CB
680{
681 size_t prefix_len;
682
683 prefix_len = strlen(prefix);
684 if (!strncmp(src, prefix, prefix_len) && (*(src + prefix_len) == ':'))
685 return (src + prefix_len + 1);
686
687 return src;
688}