]>
Commit | Line | Data |
---|---|---|
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 | 53 | lxc_log_define(storage, lxc); |
9be53773 | 54 | |
2b9cbd53 | 55 | /* btrfs */ |
10bc1861 | 56 | static 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 | 70 | static 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 | 84 | static 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 | 98 | static 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 | 112 | 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 | 126 | static 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 | 140 | static 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 | 154 | static 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 | 167 | struct lxc_storage_type { |
cdb4e53a | 168 | const char *name; |
10bc1861 | 169 | const struct lxc_storage_ops *ops; |
cdb4e53a CB |
170 | }; |
171 | ||
10bc1861 | 172 | static 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 | 184 | static const size_t numbdevs = sizeof(bdevs) / sizeof(struct lxc_storage_type); |
cdb4e53a | 185 | |
8a388ed4 | 186 | static 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 | 215 | static 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 | 237 | 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 |
260 | static 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 | 283 | bool 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 | 300 | struct 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 | 500 | on_success: |
10bc1861 | 501 | storage_put(orig); |
07db51a2 | 502 | |
db3ac7ba | 503 | return new; |
cdb4e53a | 504 | |
07db51a2 | 505 | on_error_put_new: |
10bc1861 | 506 | storage_put(new); |
07db51a2 CB |
507 | |
508 | on_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 |
523 | struct 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 | 564 | bool 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 | 582 | struct 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 | 623 | bool 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 | 643 | void 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 |
651 | bool 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 | 679 | const 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 | } |