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