]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/storage/storage.c
rootfs: remove "options" member
[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 */
59eac805 112static const 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
59eac805 237static struct 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,
facdf925
CB
262 struct bdev_specs *specs,
263 const struct lxc_conf *conf)
f2d5a09d 264{
09f6f8c4 265 int ret;
10bc1861 266 struct lxc_storage *bdev;
f2d5a09d 267
5e78e16a
CB
268 if (!type)
269 type = "dir";
270
10bc1861 271 bdev = storage_get(type);
f2d5a09d
CB
272 if (!bdev)
273 return NULL;
493de765 274
facdf925 275 ret = bdev->ops->create(bdev, dest, cname, specs, conf);
09f6f8c4 276 if (ret < 0) {
10bc1861 277 storage_put(bdev);
f2d5a09d
CB
278 return NULL;
279 }
280
281 return bdev;
cdb4e53a 282}
9be53773 283
10bc1861 284bool storage_can_backup(struct lxc_conf *conf)
cdb4e53a 285{
cdb4e53a 286 bool ret;
8a388ed4 287 struct lxc_storage *bdev;
d659597e 288
8a388ed4 289 bdev = storage_init(conf);
cdb4e53a
CB
290 if (!bdev)
291 return false;
493de765 292
cdb4e53a 293 ret = bdev->ops->can_backup;
10bc1861 294 storage_put(bdev);
9be53773
SH
295 return ret;
296}
297
bf86c00a 298/* If we're not snapshotting, then storage_copy becomes a simple case of mount
cdb4e53a 299 * the original, mount the new, and rsync the contents.
9be53773 300 */
07db51a2 301struct lxc_storage *storage_copy(struct lxc_container *c, const char *cname,
10bc1861
CB
302 const char *lxcpath, const char *bdevtype,
303 int flags, const char *bdevdata,
07db51a2 304 uint64_t newsize, bool *needs_rdep)
9be53773 305{
cdb4e53a 306 int ret;
41dc7155 307 const char *src_no_prefix;
06d0056c
CB
308 struct lxc_storage *new, *orig;
309 bool snap = (flags & LXC_CLONE_SNAPSHOT);
310 bool maybe_snap = (flags & LXC_CLONE_MAYBE_SNAPSHOT);
311 bool keepbdevtype = (flags & LXC_CLONE_KEEPBDEVTYPE);
07db51a2
CB
312 const char *src = c->lxc_conf->rootfs.path;
313 const char *oldname = c->name;
314 const char *oldpath = c->config_path;
339de297 315 char cmd_output[PATH_MAX] = {0};
06d0056c 316 struct rsync_data data = {0};
4e86cad3
CB
317 struct lxc_rootfs new_rootfs = {
318 .managed = true,
319 .dfd_mnt = -EBADF,
320 .dfd_dev = -EBADF,
321 .dfd_host = -EBADF,
322 .fd_path_pin = -EBADF,
323 .dfd_idmapped = -EBADF,
4e86cad3 324 };
9be53773 325
45b4bb96
CB
326 if (!src) {
327 ERROR("No rootfs specified");
328 return NULL;
329 }
330
6f748a97
CB
331 /* If the container name doesn't show up in the rootfs path, then we
332 * don't know how to come up with a new name.
cdb4e53a 333 */
3324c255 334 if (!strstr(src, oldname)) {
6f748a97
CB
335 ERROR("Original rootfs path \"%s\" does not include container "
336 "name \"%s\"", src, oldname);
cdb4e53a
CB
337 return NULL;
338 }
9be53773 339
4e86cad3
CB
340 ret = lxc_storage_prepare(c->lxc_conf);
341 if (ret) {
06d0056c 342 ERROR("Failed to detect storage driver for \"%s\"", oldname);
cdb4e53a
CB
343 return NULL;
344 }
4e86cad3
CB
345 orig = c->lxc_conf->rootfs.storage;
346
347 if (c->lxc_conf->rootfs.dfd_idmapped >= 0) {
2570cdf3 348 new_rootfs.dfd_idmapped = dup_cloexec(c->lxc_conf->rootfs.dfd_idmapped);
4e86cad3
CB
349 if (new_rootfs.dfd_idmapped < 0) {
350 SYSERROR("Failed to duplicate user namespace file descriptor");
351 lxc_storage_put(c->lxc_conf);
352 return NULL;
353 }
354 }
9be53773 355
cdb4e53a 356 if (!orig->dest) {
cdb4e53a
CB
357 size_t len;
358 struct stat sb;
9be53773 359
cdb4e53a
CB
360 len = strlen(oldpath) + strlen(oldname) + strlen("/rootfs") + 2;
361 orig->dest = malloc(len);
362 if (!orig->dest) {
3324c255 363 ERROR("Failed to allocate memory");
07db51a2 364 goto on_error_put_orig;
cdb4e53a 365 }
493de765 366
cdb4e53a
CB
367 ret = snprintf(orig->dest, len, "%s/%s/rootfs", oldpath, oldname);
368 if (ret < 0 || (size_t)ret >= len) {
3324c255 369 ERROR("Failed to create string");
07db51a2 370 goto on_error_put_orig;
cdb4e53a 371 }
493de765 372
6f748a97
CB
373 ret = stat(orig->dest, &sb);
374 if (ret < 0 && errno == ENOENT) {
375 ret = mkdir_p(orig->dest, 0755);
376 if (ret < 0)
eee1a9d7 377 WARN("Failed to create directory \"%s\"", orig->dest);
6f748a97 378 }
cdb4e53a 379 }
9be53773 380
3324c255
CB
381 /* Special case for snapshot. If the caller requested maybe_snapshot and
382 * keepbdevtype and the backing store is directory, then proceed with a
383 * a copy clone rather than returning error.
cdb4e53a
CB
384 */
385 if (maybe_snap && keepbdevtype && !bdevtype && !orig->ops->can_snapshot)
386 snap = false;
387
6f748a97 388 /* If newtype is NULL and snapshot is set, then use overlay. */
70e95c8d 389 if (!bdevtype && !keepbdevtype && snap && !strcmp(orig->type, "dir"))
ba115175 390 bdevtype = "overlay";
cdb4e53a 391
e0010464 392 if (am_guest_unpriv() && !unpriv_snap_allowed(orig, bdevtype, snap, maybe_snap)) {
ba115175
CB
393 ERROR("Unsupported snapshot type \"%s\" for unprivileged users",
394 bdevtype ? bdevtype : "(null)");
07db51a2 395 goto on_error_put_orig;
a17b1e65
SG
396 }
397
07db51a2 398 *needs_rdep = false;
70e95c8d
CB
399 if (bdevtype) {
400 if (snap && !strcmp(orig->type, "lvm") &&
401 !lvm_is_thin_volume(orig->src))
402 *needs_rdep = true;
403 else if (!strcmp(bdevtype, "overlay") ||
404 !strcmp(bdevtype, "overlayfs"))
405 *needs_rdep = true;
406 } else {
407 if (!snap && strcmp(oldpath, lxcpath))
408 bdevtype = "dir";
409 else
410 bdevtype = orig->type;
9be53773 411
70e95c8d
CB
412 if (!strcmp(bdevtype, "overlay") ||
413 !strcmp(bdevtype, "overlayfs"))
414 *needs_rdep = true;
415 }
b196516b
CB
416
417 /* get new bdev type */
10bc1861 418 new = storage_get(bdevtype);
cdb4e53a 419 if (!new) {
06d0056c 420 ERROR("Failed to initialize %s storage driver",
493de765 421 bdevtype ? bdevtype : orig->type);
07db51a2 422 goto on_error_put_orig;
cdb4e53a 423 }
06d0056c 424 TRACE("Initialized %s storage driver", new->type);
4e86cad3 425 new->rootfs = &new_rootfs;
a17b1e65 426
b196516b 427 /* create new paths */
6f748a97 428 ret = new->ops->clone_paths(orig, new, oldname, cname, oldpath, lxcpath,
07db51a2 429 snap, newsize, c->lxc_conf);
6f748a97
CB
430 if (ret < 0) {
431 ERROR("Failed creating new paths for clone of \"%s\"", src);
07db51a2 432 goto on_error_put_new;
cdb4e53a 433 }
9be53773 434
70e95c8d
CB
435 /* When we create an overlay snapshot of an overlay container in the
436 * snapshot directory under "<lxcpath>/<name>/snaps/" we don't need to
437 * record a dependency. If we would restore would also fail.
438 */
06d0056c
CB
439 if ((strcmp(new->type, "overlay") == 0 ||
440 strcmp(new->type, "overlayfs") == 0) &&
70e95c8d
CB
441 ret == LXC_CLONE_SNAPSHOT)
442 *needs_rdep = false;
443
6f748a97 444 /* btrfs */
b196516b 445 if (!strcmp(orig->type, "btrfs") && !strcmp(new->type, "btrfs")) {
06d0056c
CB
446 bool bret;
447
b196516b 448 if (snap || btrfs_same_fs(orig->dest, new->dest) == 0)
07db51a2 449 bret = new->ops->snapshot(c->lxc_conf, orig, new, 0);
b196516b 450 else
07db51a2 451 bret = new->ops->copy(c->lxc_conf, orig, new, 0);
b196516b 452 if (!bret)
07db51a2
CB
453 goto on_error_put_new;
454
455 goto on_success;
b196516b
CB
456 }
457
6f748a97 458 /* lvm */
d91e13d8 459 if (!strcmp(orig->type, "lvm") && !strcmp(new->type, "lvm")) {
06d0056c
CB
460 bool bret;
461
d91e13d8 462 if (snap)
06d0056c 463 bret = new->ops->snapshot(c->lxc_conf, orig, new, newsize);
d91e13d8 464 else
07db51a2 465 bret = new->ops->copy(c->lxc_conf, orig, new, newsize);
3ef1df7c 466 if (!bret)
07db51a2
CB
467 goto on_error_put_new;
468
469 goto on_success;
3ef1df7c
CB
470 }
471
472 /* zfs */
473 if (!strcmp(orig->type, "zfs") && !strcmp(new->type, "zfs")) {
06d0056c 474 bool bret;
3ef1df7c
CB
475
476 if (snap)
06d0056c 477 bret = new->ops->snapshot(c->lxc_conf, orig, new, newsize);
3ef1df7c 478 else
07db51a2 479 bret = new->ops->copy(c->lxc_conf, orig, new, newsize);
d91e13d8 480 if (!bret)
07db51a2
CB
481 goto on_error_put_new;
482
483 goto on_success;
d91e13d8
CB
484 }
485
7a9e0f35 486 if (strcmp(bdevtype, "btrfs")) {
6f748a97 487 if (!strcmp(new->type, "overlay") || !strcmp(new->type, "overlayfs"))
7a9e0f35
CB
488 src_no_prefix = ovl_get_lower(new->src);
489 else
490 src_no_prefix = lxc_storage_get_path(new->src, new->type);
491
e0010464 492 if (am_guest_unpriv()) {
07db51a2 493 ret = chown_mapped_root(src_no_prefix, c->lxc_conf);
6f748a97
CB
494 if (ret < 0)
495 WARN("Failed to chown \"%s\"", new->src);
496 }
7a9e0f35 497 }
9be53773 498
cdb4e53a 499 if (snap)
07db51a2 500 goto on_success;
9be53773 501
6f748a97 502 /* rsync the contents from source to target */
db3ac7ba
CB
503 data.orig = orig;
504 data.new = new;
e0010464 505 if (am_guest_unpriv())
5c05427a
CB
506 ret = userns_exec_full(c->lxc_conf,
507 lxc_storage_rsync_exec_wrapper, &data,
508 "lxc_storage_rsync_exec_wrapper");
07db51a2 509 else
db3ac7ba 510 ret = run_command(cmd_output, sizeof(cmd_output),
17a367d8 511 lxc_storage_rsync_exec_wrapper, (void *)&data);
07db51a2
CB
512 if (ret < 0) {
513 ERROR("Failed to rsync from \"%s\" into \"%s\"%s%s", orig->dest,
514 new->dest,
515 cmd_output[0] != '\0' ? ": " : "",
516 cmd_output[0] != '\0' ? cmd_output : "");
517 goto on_error_put_new;
9be53773
SH
518 }
519
07db51a2 520on_success:
4e86cad3 521 lxc_storage_put(c->lxc_conf);
07db51a2 522
db3ac7ba 523 return new;
cdb4e53a 524
07db51a2 525on_error_put_new:
10bc1861 526 storage_put(new);
07db51a2
CB
527
528on_error_put_orig:
4e86cad3 529 lxc_storage_put(c->lxc_conf);
07db51a2 530
cdb4e53a
CB
531 return NULL;
532}
533
10bc1861 534/* Create a backing store for a container.
cdb4e53a
CB
535 * If successful, return a struct bdev *, with the bdev mounted and ready
536 * for use. Before completing, the caller will need to call the
10bc1861 537 * umount operation and storage_put().
cdb4e53a
CB
538 * @dest: the mountpoint (i.e. /var/lib/lxc/$name/rootfs)
539 * @type: the bdevtype (dir, btrfs, zfs, rbd, etc)
540 * @cname: the container name
541 * @specs: details about the backing store to create, like fstype
542 */
10bc1861 543struct lxc_storage *storage_create(const char *dest, const char *type,
facdf925
CB
544 const char *cname, struct bdev_specs *specs,
545 const struct lxc_conf *conf)
9be53773 546{
e9e29a33 547 int ret;
10bc1861 548 struct lxc_storage *bdev;
cdb4e53a 549 char *best_options[] = {"btrfs", "zfs", "lvm", "dir", "rbd", NULL};
9be53773 550
cdb4e53a 551 if (!type)
facdf925 552 return do_storage_create(dest, "dir", cname, specs, conf);
cdb4e53a 553
e9e29a33
CB
554 ret = strcmp(type, "best");
555 if (ret == 0) {
cdb4e53a 556 int i;
10bc1861
CB
557 /* Try for the best backing store type, according to our
558 * opinionated preferences.
559 */
cdb4e53a 560 for (i = 0; best_options[i]; i++) {
facdf925 561 bdev = do_storage_create(dest, best_options[i], cname, specs, conf);
10bc1861 562 if (bdev)
cdb4e53a
CB
563 return bdev;
564 }
493de765 565
10bc1861 566 return NULL;
9be53773 567 }
9be53773 568
10bc1861 569 /* -B lvm,dir */
e9e29a33 570 if (strchr(type, ',')) {
63fce0c1 571 __do_free char *dup = NULL;
643c9ec9 572 char *token;
43f984ea 573
643c9ec9 574 dup = must_copy_string(type);
eb29852f 575 lxc_iterate_parts(token, dup, ",") {
facdf925 576 bdev = do_storage_create(dest, token, cname, specs, conf);
e9e29a33 577 if (bdev)
cdb4e53a
CB
578 return bdev;
579 }
580 }
581
facdf925 582 return do_storage_create(dest, type, cname, specs, conf);
9be53773
SH
583}
584
10bc1861 585bool storage_destroy(struct lxc_conf *conf)
9be53773 586{
10bc1861 587 struct lxc_storage *r;
cdb4e53a 588 bool ret = false;
ed05aac8 589 int destroy_rv = 0;
9be53773 590
8a388ed4 591 r = storage_init(conf);
cdb4e53a
CB
592 if (!r)
593 return ret;
594
ed05aac8
MM
595 destroy_rv = r->ops->destroy(r);
596 if (destroy_rv == 0)
cdb4e53a 597 ret = true;
cdb4e53a 598
10bc1861 599 storage_put(r);
cdb4e53a
CB
600 return ret;
601}
602
8a388ed4 603struct lxc_storage *storage_init(struct lxc_conf *conf)
cdb4e53a 604{
10bc1861
CB
605 struct lxc_storage *bdev;
606 const struct lxc_storage_type *q;
8a388ed4
CB
607 const char *src = conf->rootfs.path;
608 const char *dst = conf->rootfs.mount;
e73af35b 609 const char *mntopts = conf->rootfs.mnt_opts.raw_options;
cdb4e53a 610
17a367d8
CB
611 BUILD_BUG_ON(LXC_STORAGE_INTERNAL_OVERLAY_RESTORE <= LXC_CLONE_MAXFLAGS);
612
cdb4e53a 613 if (!src)
9be53773 614 return NULL;
cdb4e53a 615
8a388ed4 616 q = storage_query(conf);
cdb4e53a 617 if (!q)
9be53773 618 return NULL;
cdb4e53a 619
79defd88 620 bdev = zalloc(sizeof(struct lxc_storage));
cdb4e53a 621 if (!bdev)
9be53773 622 return NULL;
493de765 623
79defd88
CB
624 bdev->ops = q->ops;
625 bdev->type = q->name;
626 bdev->rootfs = &conf->rootfs;
8a388ed4 627
cdb4e53a
CB
628 if (mntopts)
629 bdev->mntopts = strdup(mntopts);
8a388ed4 630
cdb4e53a
CB
631 if (src)
632 bdev->src = strdup(src);
8a388ed4 633
cdb4e53a
CB
634 if (dst)
635 bdev->dest = strdup(dst);
8a388ed4 636
cdb4e53a
CB
637 if (strcmp(bdev->type, "nbd") == 0)
638 bdev->nbd_idx = conf->nbd_idx;
639
640 return bdev;
641}
642
068aa488 643bool storage_is_dir(struct lxc_conf *conf)
cdb4e53a 644{
10bc1861 645 struct lxc_storage *orig;
068aa488 646 char *type = conf->rootfs.bdev_type;
10bc1861
CB
647 bool bret = false;
648
068aa488
CB
649 if (type)
650 return (strcmp(type, "dir") == 0);
651
8a388ed4 652 orig = storage_init(conf);
cdb4e53a 653 if (!orig)
10bc1861
CB
654 return bret;
655
cdb4e53a 656 if (strcmp(orig->type, "dir") == 0)
10bc1861
CB
657 bret = true;
658
659 storage_put(orig);
660 return bret;
cdb4e53a
CB
661}
662
10bc1861 663void storage_put(struct lxc_storage *bdev)
cdb4e53a 664{
4e86cad3
CB
665 if (bdev) {
666 free_disarm(bdev->mntopts);
667 free_disarm(bdev->src);
668 free_disarm(bdev->dest);
669 free_disarm(bdev);
670 }
cdb4e53a
CB
671}
672
cdb4e53a
CB
673bool rootfs_is_blockdev(struct lxc_conf *conf)
674{
10bc1861 675 const struct lxc_storage_type *q;
cdb4e53a
CB
676 struct stat st;
677 int ret;
678
679 if (!conf->rootfs.path || strcmp(conf->rootfs.path, "/") == 0 ||
493de765 680 strlen(conf->rootfs.path) == 0)
cdb4e53a
CB
681 return false;
682
683 ret = stat(conf->rootfs.path, &st);
684 if (ret == 0 && S_ISBLK(st.st_mode))
685 return true;
493de765 686
8a388ed4 687 q = storage_query(conf);
cdb4e53a
CB
688 if (!q)
689 return false;
493de765 690
cdb4e53a 691 if (strcmp(q->name, "lvm") == 0 ||
493de765 692 strcmp(q->name, "loop") == 0 ||
f83dd99e
CB
693 strcmp(q->name, "nbd") == 0 ||
694 strcmp(q->name, "rbd") == 0 ||
695 strcmp(q->name, "zfs") == 0)
cdb4e53a 696 return true;
493de765 697
cdb4e53a
CB
698 return false;
699}
4f25fd38 700
41dc7155 701const char *lxc_storage_get_path(char *src, const char *prefix)
4f25fd38
CB
702{
703 size_t prefix_len;
704
705 prefix_len = strlen(prefix);
706 if (!strncmp(src, prefix, prefix_len) && (*(src + prefix_len) == ':'))
707 return (src + prefix_len + 1);
708
709 return src;
710}