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