]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/storage/overlay.c
tree-wide: fix lxc header inclusion
[mirror_lxc.git] / src / lxc / storage / overlay.c
CommitLineData
cc73685d 1/* SPDX-License-Identifier: LGPL-2.1+ */
38683db4 2
d38dd64a
CB
3#ifndef _GNU_SOURCE
4#define _GNU_SOURCE 1
5#endif
38683db4
CB
6#include <errno.h>
7#include <stdio.h>
8#include <stdlib.h>
9#include <string.h>
10
12ae2a33
CB
11#include "lxc.h"
12
38683db4 13#include "conf.h"
d38dd64a 14#include "config.h"
38683db4
CB
15#include "confile.h"
16#include "log.h"
6333c915 17#include "macro.h"
e2c6671d 18#include "memory_utils.h"
28d832c4
CB
19#include "overlay.h"
20#include "rsync.h"
21#include "storage.h"
ba115175 22#include "storage_utils.h"
38683db4
CB
23#include "utils.h"
24
10bc1861 25lxc_log_define(overlay, lxc);
38683db4 26
5c484f79 27static char *ovl_name;
88232d3f 28static char *ovl_version[] = {"overlay", "overlayfs"};
5c484f79 29
5c484f79 30static char *ovl_detect_name(void);
17a367d8 31static int ovl_do_rsync(const char *src, const char *dest,
3188197d 32 struct lxc_conf *conf);
88232d3f
CB
33static int ovl_remount_on_enodev(const char *lower, const char *target,
34 const char *name, unsigned long mountflags,
35 const void *options);
38683db4 36
10bc1861 37int ovl_clonepaths(struct lxc_storage *orig, struct lxc_storage *new, const char *oldname,
83e79752
CB
38 const char *cname, const char *oldpath, const char *lxcpath,
39 int snap, uint64_t newsize, struct lxc_conf *conf)
38683db4 40{
241978fa 41 int ret;
41dc7155 42 const char *src;
4d463f62 43
38683db4 44 if (!snap) {
241978fa
CB
45 ERROR("The overlay storage driver can only be used for "
46 "snapshots");
38683db4
CB
47 return -22;
48 }
49
50 if (!orig->src || !orig->dest)
51 return -1;
52
241978fa 53 new->dest = must_make_path(lxcpath, cname, "rootfs", NULL);
ba115175 54
241978fa
CB
55 ret = mkdir_p(new->dest, 0755);
56 if (ret < 0 && errno != EEXIST) {
57 SYSERROR("Failed to create directory \"%s\"", new->dest);
38683db4 58 return -1;
241978fa 59 }
38683db4 60
0589d744 61 if (am_guest_unpriv() || !list_empty(&conf->id_map)) {
241978fa
CB
62 ret = chown_mapped_root(new->dest, conf);
63 if (ret < 0)
64 WARN("Failed to update ownership of %s", new->dest);
65 }
38683db4
CB
66
67 if (strcmp(orig->type, "dir") == 0) {
facdf925
CB
68 __do_free char *delta = NULL, *work = NULL;
69 int len;
38683db4 70
facdf925 71 delta = must_make_path(lxcpath, cname, LXC_OVERLAY_DELTA_PATH, NULL);
38683db4 72
facdf925
CB
73 ret = mkdir_p(delta, 0755);
74 if (ret < 0 && errno != EEXIST)
75 return log_error_errno(-errno, errno, "Failed to create directory \"%s\"", delta);
241978fa 76
facdf925
CB
77 /*
78 * Make workdir for overlayfs.v22 or higher:
5c484f79 79 * The workdir will be
facdf925 80 * /var/lib/lxc/c2/LXC_OVERLAY_WORK_PATH
5c484f79
CB
81 * and is used to prepare files before they are atomically
82 * switched to the overlay destination. Workdirs need to be on
83 * the same filesystem as the upperdir so it's OK for it to be
84 * empty.
85 */
facdf925 86 work = must_make_path(lxcpath, cname, LXC_OVERLAY_WORK_PATH, NULL);
241978fa 87
facdf925
CB
88 ret = mkdir_p(work, 0755);
89 if (ret < 0 && errno != EEXIST)
90 return log_error_errno(-errno, errno, "Failed to create directory \"%s\"", work);
241978fa 91
0589d744 92 if (am_guest_unpriv() || !list_empty(&conf->id_map)) {
facdf925
CB
93 __do_free char *lxc_overlay_delta_dir = NULL,
94 *lxc_overlay_private_dir = NULL;
95
96 lxc_overlay_private_dir = must_make_path(lxcpath, cname, LXC_OVERLAY_PRIVATE_DIR, NULL);
97 ret = chown_mapped_root(lxc_overlay_private_dir, conf);
98 if (ret < 0)
99 WARN("Failed to update ownership of %s", lxc_overlay_private_dir);
100
101 lxc_overlay_delta_dir = must_make_path(lxcpath, cname, LXC_OVERLAY_DELTA_PATH, NULL);
102 ret = chown_mapped_root(lxc_overlay_delta_dir, conf);
103 if (ret < 0)
104 WARN("Failed to update ownership of %s", lxc_overlay_delta_dir);
241978fa 105
241978fa
CB
106 ret = chown_mapped_root(work, conf);
107 if (ret < 0)
108 WARN("Failed to update ownership of %s", work);
109 }
38683db4 110
4d463f62 111 src = lxc_storage_get_path(orig->src, orig->type);
facdf925
CB
112 len = STRLITERALLEN("overlay") + STRLITERALLEN(":") +
113 strlen(src) + STRLITERALLEN(":") + strlen(delta) + 1;
114
38683db4 115 new->src = malloc(len);
facdf925
CB
116 if (!new->src)
117 return log_error_errno(-ENOMEM, ENOMEM, "Failed to allocate memory");
241978fa 118
ba115175 119 ret = snprintf(new->src, len, "overlay:%s:%s", src, delta);
2048ac1a 120 if (ret < 0 || ret >= len)
facdf925 121 return log_error_errno(-EIO, EIO, "Failed to create string");
241978fa
CB
122 } else if (!strcmp(orig->type, "overlayfs") ||
123 !strcmp(orig->type, "overlay")) {
facdf925
CB
124 __do_free char *clean_old_path = NULL, *clean_new_path = NULL,
125 *ndelta = NULL, *osrc = NULL, *work = NULL;
126 char *nsrc, *odelta, *s1, *s2, *s3;
70e95c8d 127 size_t len, name_len;
ba115175
CB
128
129 osrc = strdup(orig->src);
facdf925
CB
130 if (!osrc)
131 return log_error_errno(-22, ENOMEM, "Failed to duplicate string \"%s\"", orig->src);
ba115175 132
09f6f8c4 133 nsrc = osrc;
facdf925
CB
134 if (strncmp(osrc, "overlay:", STRLITERALLEN("overlay:")) == 0)
135 nsrc += STRLITERALLEN("overlay:");
136 else if (strncmp(osrc, "overlayfs:", STRLITERALLEN("overlayfs:")) == 0)
137 nsrc += STRLITERALLEN("overlayfs:");
ba115175
CB
138
139 odelta = strchr(nsrc, ':');
facdf925
CB
140 if (!odelta)
141 return log_error_errno(-22, ENOENT, "Failed to find \":\" in \"%s\"", nsrc);
ba115175 142
38683db4
CB
143 *odelta = '\0';
144 odelta++;
facdf925 145 ndelta = must_make_path(lxcpath, cname, LXC_OVERLAY_DELTA_PATH, NULL);
ba115175 146
facdf925
CB
147 ret = mkdir_p(ndelta, 0755);
148 if (ret < 0 && errno != EEXIST)
149 return log_error_errno(-errno, errno, "Failed to create directory \"%s\"", ndelta);
38683db4 150
241978fa
CB
151 /* Make workdir for overlayfs.v22 or higher (See the comment
152 * further up.).
5c484f79 153 */
facdf925
CB
154 work = must_make_path(lxcpath, cname, LXC_OVERLAY_WORK_PATH, NULL);
155 ret = mkdir_p(work, 0755);
156 if (ret < 0 && errno != EEXIST)
157 return log_error_errno(-errno, errno, "Failed to create directory \"%s\"", ndelta);
241978fa 158
0589d744 159 if (am_guest_unpriv() || !list_empty(&conf->id_map)) {
facdf925
CB
160 __do_free char *lxc_overlay_delta_dir = NULL,
161 *lxc_overlay_private_dir = NULL;
241978fa 162
facdf925
CB
163 lxc_overlay_private_dir = must_make_path(lxcpath, cname, LXC_OVERLAY_PRIVATE_DIR, NULL);
164 ret = chown_mapped_root(lxc_overlay_private_dir, conf);
165 if (ret < 0)
166 WARN("Failed to update ownership of %s", lxc_overlay_private_dir);
167
168 lxc_overlay_delta_dir = must_make_path(lxcpath, cname, LXC_OVERLAY_DELTA_PATH, NULL);
169 ret = chown_mapped_root(lxc_overlay_delta_dir, conf);
170 if (ret < 0)
171 WARN("Failed to update ownership of %s", lxc_overlay_delta_dir);
ba115175 172
241978fa
CB
173 ret = chown_mapped_root(work, conf);
174 if (ret < 0)
175 WARN("Failed to update ownership of %s", work);
176 }
38683db4 177
facdf925 178 len = STRLITERALLEN("overlay") + STRLITERALLEN(":") + strlen(nsrc) + STRLITERALLEN(":") + strlen(ndelta) + 1;
38683db4 179 new->src = malloc(len);
facdf925
CB
180 if (!new->src)
181 return log_error_errno(-ENOMEM, ENOMEM, "Failed to allocate memory");
182
ba115175 183 ret = snprintf(new->src, len, "overlay:%s:%s", nsrc, ndelta);
facdf925
CB
184 if (ret < 0 || (size_t)ret >= len)
185 return log_error_errno(-EIO, EIO, "Failed to create string");
38683db4 186
17a367d8 187 ret = ovl_do_rsync(odelta, ndelta, conf);
70e95c8d
CB
188 if (ret < 0)
189 return -1;
190
191 /* When we create an overlay snapshot of an overlay container in
192 * the snapshot directory under "<lxcpath>/<name>/snaps/" we
193 * don't need to record a dependency. If we would restore would
194 * also fail.
195 */
28e54be1 196 clean_old_path = path_simplify(oldpath);
70e95c8d 197 if (!clean_old_path)
facdf925 198 return log_error_errno(-ENOMEM, ENOMEM, "Failed to create clean path for \"%s\"", oldpath);
70e95c8d 199
28e54be1 200 clean_new_path = path_simplify(lxcpath);
facdf925
CB
201 if (!clean_new_path)
202 return log_error_errno(-ENOMEM, ENOMEM, "Failed to create clean path for \"%s\"", lxcpath);
70e95c8d
CB
203
204 s1 = strrchr(clean_old_path, '/');
facdf925
CB
205 if (!s1)
206 return log_error_errno(-ENOENT, ENOENT, "Failed to detect \"/\" in string \"%s\"", clean_old_path);
70e95c8d
CB
207
208 s2 = strrchr(clean_new_path, '/');
facdf925
CB
209 if (!s2)
210 return log_error_errno(-ENOENT, ENOENT, "Failed to detect \"/\" in string \"%s\"", clean_new_path);
70e95c8d 211
6333c915 212 if (!strncmp(s1, "/snaps", STRLITERALLEN("/snaps"))) {
70e95c8d
CB
213 s1 = clean_new_path;
214 s2 = clean_old_path;
215 s3 = (char *)cname;
6333c915 216 } else if (!strncmp(s2, "/snaps", STRLITERALLEN("/snaps"))) {
70e95c8d
CB
217 s1 = clean_old_path;
218 s2 = clean_new_path;
219 s3 = (char *)oldname;
70e95c8d 220 } else {
70e95c8d
CB
221 return 0;
222 }
223
7f022483 224 len = strlen(s1);
70e95c8d
CB
225 if (!strncmp(s1, s2, len)) {
226 char *tmp;
227
228 tmp = (char *)(s2 + len + 1);
facdf925 229 if (*tmp == '\0')
70e95c8d 230 return 0;
70e95c8d
CB
231
232 name_len = strlen(s3);
facdf925 233 if (strncmp(s3, tmp, name_len))
70e95c8d 234 return 0;
70e95c8d 235
7f022483 236 return LXC_CLONE_SNAPSHOT;
70e95c8d
CB
237 }
238
70e95c8d 239 return 0;
38683db4 240 } else {
facdf925
CB
241 /*
242 * Note, supporting this will require ovl_mount supporting
5c484f79
CB
243 * mounting of the underlay. No big deal, just needs to be done.
244 */
facdf925 245 return log_error_errno(-EINVAL, EINVAL, "overlay clone of %s container is not yet supported", orig->type);
38683db4
CB
246 }
247
248 return 0;
249}
250
241978fa
CB
251/* To say "lxc-create -t ubuntu -n o1 -B overlay" means you want
252 * "<lxcpath>/<lxcname>/rootfs" to have the created container, while all changes
facdf925 253 * after starting the container are written to "<lxcpath>/<lxcname>/LXC_OVERLAY_DELTA_PATH".
38683db4 254 */
10bc1861 255int ovl_create(struct lxc_storage *bdev, const char *dest, const char *n,
facdf925 256 struct bdev_specs *specs, const struct lxc_conf *conf)
38683db4 257{
facdf925 258 __do_free char *delta = NULL, *tmp = NULL;
241978fa 259 int ret;
facdf925 260 size_t len;
38683db4 261
241978fa 262 len = strlen(dest);
facdf925
CB
263 if (len < 8 || strcmp(dest + len - STRLITERALLEN("/rootfs"), "/rootfs"))
264 return log_error_errno(-ENOENT, ENOENT, "Failed to detect \"/rootfs\" in \"%s\"", dest);
38683db4 265
241978fa 266 bdev->dest = strdup(dest);
facdf925
CB
267 if (!bdev->dest)
268 return log_error_errno(-ENOMEM, ENOMEM, "Failed to duplicate string \"%s\"", dest);
38683db4 269
facdf925
CB
270 tmp = strndup(dest, len - STRLITERALLEN("/rootfs"));
271 if (!tmp)
272 return log_error_errno(-ENOMEM, ENOMEM, "Failed to duplicate string \"%s\"", dest);
273
274 delta = must_make_path(tmp, LXC_OVERLAY_DELTA_PATH, NULL);
38683db4 275
241978fa 276 ret = mkdir_p(delta, 0755);
facdf925
CB
277 if (ret < 0 && errno != EEXIST)
278 return log_error_errno(-errno, errno, "Failed to create directory \"%s\"", delta);
279
0589d744 280 if (am_guest_unpriv() || !list_empty(&conf->id_map)) {
facdf925
CB
281 __do_free char *lxc_overlay_private_dir = NULL;
282
283 lxc_overlay_private_dir = must_make_path(tmp, LXC_OVERLAY_PRIVATE_DIR, NULL);
284 ret = chown_mapped_root(lxc_overlay_private_dir, conf);
285 if (ret < 0)
286 WARN("Failed to update ownership of %s", lxc_overlay_private_dir);
287
288 ret = chown_mapped_root(delta, conf);
289 if (ret < 0)
290 WARN("Failed to update ownership of %s", delta);
38683db4
CB
291 }
292
241978fa 293 /* overlay:lower:upper */
facdf925
CB
294 len = STRLITERALLEN("overlay") + STRLITERALLEN(":") + len + STRLITERALLEN(":") + strlen(delta) + 1;
295 bdev->src = malloc(len);
296 if (!bdev->src)
297 return log_error_errno(-ENOMEM, ENOMEM, "Failed to allocate memory");
241978fa 298
facdf925
CB
299 ret = snprintf(bdev->src, len, "overlay:%s:%s", dest, delta);
300 if (ret < 0 || (size_t)ret >= len)
301 return log_error_errno(-EIO, EIO, "Failed to create rootfs path");
38683db4 302
241978fa 303 ret = mkdir_p(bdev->dest, 0755);
facdf925
CB
304 if (ret < 0 && errno != EEXIST)
305 return log_error_errno(-errno, errno, "Failed to create directory \"%s\"", bdev->dest);
38683db4
CB
306
307 return 0;
308}
309
10bc1861 310int ovl_destroy(struct lxc_storage *orig)
5c484f79 311{
ba115175 312 char *upper = orig->src;
5c484f79 313
17a367d8
CB
314 /* For an overlay container the rootfs is considered immutable
315 * and cannot be removed when restoring from a snapshot.
316 */
317 if (orig->flags & LXC_STORAGE_INTERNAL_OVERLAY_RESTORE)
318 return 0;
319
09f6f8c4 320 if (strncmp(upper, "overlay:", 8) == 0)
241978fa 321 upper += 8;
09f6f8c4 322 else if (strncmp(upper, "overlayfs:", 10) == 0)
241978fa 323 upper += 10;
ba115175
CB
324
325 upper = strchr(upper, ':');
5c484f79
CB
326 if (!upper)
327 return -22;
328 upper++;
ba115175 329
5c484f79
CB
330 return lxc_rmdir_onedev(upper, NULL);
331}
332
3d2ae1e2 333bool ovl_detect(const char *path)
5c484f79 334{
09f6f8c4 335 if (!strncmp(path, "overlay:", 8))
3d2ae1e2 336 return true;
f7ac4459 337
09f6f8c4 338 if (!strncmp(path, "overlayfs:", 10))
3d2ae1e2 339 return true;
f7ac4459 340
3d2ae1e2 341 return false;
5c484f79
CB
342}
343
10bc1861 344int ovl_mount(struct lxc_storage *bdev)
5c484f79 345{
a08bfbe3
CB
346 __do_free char *options = NULL, *options_work = NULL;
347 unsigned long mntflags = 0;
348 char *mntdata = NULL;
e2c6671d
CB
349 char *tmp, *dup, *lower, *upper;
350 char *work, *lastslash;
241978fa 351 size_t len, len2;
5c484f79
CB
352 int ret, ret2;
353
ba115175 354 if (strcmp(bdev->type, "overlay") && strcmp(bdev->type, "overlayfs"))
5c484f79 355 return -22;
ba115175 356
5c484f79
CB
357 if (!bdev->src || !bdev->dest)
358 return -22;
359
360 if (!ovl_name)
361 ovl_name = ovl_detect_name();
362
241978fa
CB
363 /* Separately mount it first:
364 * mount -t overlay * -o upperdir=${upper},lowerdir=${lower} lower dest
5c484f79 365 */
241978fa 366 dup = strdup(bdev->src);
facdf925
CB
367 if (!dup)
368 return log_error_errno(-ENOMEM, ENOMEM, "Failed to allocate memory");
09f6f8c4
CB
369 upper = dup;
370 lower = dup;
241978fa 371
facdf925
CB
372 if (strncmp(dup, "overlay:", STRLITERALLEN("overlay:")) == 0)
373 lower += STRLITERALLEN("overlay:");
374 else if (strncmp(dup, "overlayfs:", STRLITERALLEN("overlayfs:")) == 0)
375 lower += STRLITERALLEN("overlayfs:");
09f6f8c4
CB
376 if (upper != lower)
377 upper = lower;
241978fa 378
09f6f8c4
CB
379 /* support multiple lower layers */
380 while ((tmp = strstr(upper, ":/"))) {
381 tmp++;
9208af16
CB
382 upper = tmp;
383 }
241978fa
CB
384
385 upper--;
386 if (upper == lower) {
387 free(dup);
5c484f79 388 return -22;
241978fa 389 }
5c484f79
CB
390 *upper = '\0';
391 upper++;
392
241978fa 393 /* if delta doesn't yet exist, create it */
adcdf4e4 394 ret = mkdir_p(upper, 0755);
241978fa
CB
395 if (ret < 0 && errno != EEXIST) {
396 SYSERROR("Failed to create directory \"%s\"", upper);
397 free(dup);
5c484f79 398 return -22;
241978fa 399 }
5c484f79 400
241978fa 401 /* overlayfs.v22 or higher needs workdir option:
5c484f79 402 * if upper is
facdf925 403 * /var/lib/lxc/c2/LXC_OVERLAY_DELTA_PATH
5c484f79 404 * then workdir is
facdf925 405 * /var/lib/lxc/c2/LXC_OVERLAY_WORK_PATH
5c484f79
CB
406 */
407 lastslash = strrchr(upper, '/');
241978fa
CB
408 if (!lastslash) {
409 ERROR("Failed to detect \"/\" in string \"%s\"", upper);
410 free(dup);
5c484f79 411 return -22;
241978fa
CB
412 }
413
facdf925
CB
414 upper[lastslash - upper] = '\0';
415 work = must_make_path(upper, LXC_OVERLAY_WORK_DIR, NULL);
416 upper[lastslash - upper] = '/';
241978fa 417
d94eb390 418 ret = parse_mntopts_legacy(bdev->mntopts, &mntflags, &mntdata);
241978fa
CB
419 if (ret < 0) {
420 ERROR("Failed to parse mount options");
5c484f79 421 free(mntdata);
241978fa
CB
422 free(dup);
423 free(work);
5c484f79
CB
424 return -22;
425 }
426
241978fa
CB
427 ret = mkdir_p(work, 0755);
428 if (ret < 0 && errno != EEXIST) {
429 SYSERROR("Failed to create directory \"%s\"", work);
5c484f79 430 free(mntdata);
241978fa
CB
431 free(dup);
432 free(work);
5c484f79
CB
433 return -22;
434 }
435
436 /*
437 * TODO:
438 * We should check whether bdev->src is a blockdev but for now only
439 * support overlays of a basic directory
440 */
441
442 if (mntdata) {
241978fa
CB
443 len = strlen(lower) + strlen(upper) +
444 strlen("upperdir=,lowerdir=,") + strlen(mntdata) + 1;
e2c6671d 445 options = must_realloc(NULL, len);
241978fa
CB
446 ret = snprintf(options, len, "upperdir=%s,lowerdir=%s,%s",
447 upper, lower, mntdata);
5c484f79 448
241978fa
CB
449 len2 = strlen(lower) + strlen(upper) + strlen(work) +
450 strlen("upperdir=,lowerdir=,workdir=") +
451 strlen(mntdata) + 1;
e2c6671d 452 options_work = must_realloc(NULL, len2);
241978fa
CB
453 ret2 = snprintf(options, len2,
454 "upperdir=%s,lowerdir=%s,workdir=%s,%s", upper,
455 lower, work, mntdata);
5c484f79 456 } else {
241978fa
CB
457 len = strlen(lower) + strlen(upper) +
458 strlen("upperdir=,lowerdir=") + 1;
e2c6671d 459 options = must_realloc(NULL, len);
241978fa
CB
460 ret = snprintf(options, len, "upperdir=%s,lowerdir=%s", upper,
461 lower);
5c484f79 462
241978fa
CB
463 len2 = strlen(lower) + strlen(upper) + strlen(work) +
464 strlen("upperdir=,lowerdir=,workdir=") + 1;
e2c6671d 465 options_work = must_realloc(NULL, len2);
241978fa
CB
466 ret2 = snprintf(options_work, len2,
467 "upperdir=%s,lowerdir=%s,workdir=%s", upper,
468 lower, work);
5c484f79
CB
469 }
470
2048ac1a 471 if (ret < 0 || (size_t)ret >= len || ret2 < 0 || (size_t)ret2 >= len2) {
241978fa 472 ERROR("Failed to create string");
5c484f79 473 free(mntdata);
241978fa
CB
474 free(dup);
475 free(work);
5c484f79
CB
476 return -1;
477 }
478
241978fa 479 /* Assume we need a workdir as we are on a overlay version >= v22. */
88232d3f
CB
480 ret = ovl_remount_on_enodev(lower, bdev->dest, ovl_name,
481 MS_MGC_VAL | mntflags, options_work);
5c484f79 482 if (ret < 0) {
7874d81a 483 SYSINFO("Failed to mount \"%s\" on \"%s\" with options \"%s\". "
484 "Retrying without workdir",
485 lower, bdev->dest, options_work);
5c484f79 486
241978fa
CB
487 /* Assume we cannot use a workdir as we are on a version <= v21.
488 */
88232d3f 489 ret = ovl_remount_on_enodev(lower, bdev->dest, ovl_name,
241978fa 490 MS_MGC_VAL | mntflags, options);
5c484f79 491 if (ret < 0)
b5be6a7c 492 SYSERROR("Failed to mount \"%s\" on \"%s\" with options \"%s\"",
493 lower, bdev->dest, options);
5c484f79 494 else
241978fa 495 INFO("Mounted \"%s\" on \"%s\" with options \"%s\"",
88232d3f 496 lower, bdev->dest, options);
5c484f79 497 } else {
241978fa 498 INFO("Mounted \"%s\" on \"%s\" with options \"%s\"", lower,
88232d3f 499 bdev->dest, options_work);
5c484f79 500 }
241978fa
CB
501
502 free(dup);
503 free(work);
5c484f79
CB
504 return ret;
505}
506
10bc1861 507int ovl_umount(struct lxc_storage *bdev)
5c484f79 508{
241978fa
CB
509 int ret;
510
ba115175 511 if (strcmp(bdev->type, "overlay") && strcmp(bdev->type, "overlayfs"))
5c484f79 512 return -22;
ba115175 513
5c484f79
CB
514 if (!bdev->src || !bdev->dest)
515 return -22;
ba115175 516
241978fa
CB
517 ret = umount(bdev->dest);
518 if (ret < 0)
519 SYSERROR("Failed to unmount \"%s\"", bdev->dest);
520 else
521 TRACE("Unmounted \"%s\"", bdev->dest);
522
523 return ret;
5c484f79
CB
524}
525
41dc7155 526const char *ovl_get_lower(const char *rootfs_path)
ba115175 527{
41dc7155 528 const char *s1 = rootfs_path;
241978fa 529
41dc7155
CB
530 if (strncmp(rootfs_path, "overlay:", 8) == 0)
531 s1 += 8;
532 else if (strncmp(rootfs_path, "overlayfs:", 10) == 0)
533 s1 += 10;
ba115175
CB
534
535 s1 = strstr(s1, ":/");
536 if (!s1)
537 return NULL;
538 s1++;
539
540 return s1;
541}
542
5c484f79
CB
543char *ovl_get_rootfs(const char *rootfs_path, size_t *rootfslen)
544{
545 char *rootfsdir = NULL;
546 char *s1 = NULL;
547 char *s2 = NULL;
548 char *s3 = NULL;
549
550 if (!rootfs_path || !rootfslen)
551 return NULL;
552
553 s1 = strdup(rootfs_path);
554 if (!s1)
555 return NULL;
556
41dc7155
CB
557 s2 = s1;
558 if (strncmp(rootfs_path, "overlay:", 8) == 0)
559 s2 += 8;
560 else if (strncmp(rootfs_path, "overlayfs:", 10) == 0)
561 s2 += 10;
562
563 s3 = strstr(s2, ":/");
564 if (s3)
565 *s3 = '\0';
566
567 rootfsdir = strdup(s2);
a61b4e85 568 free(s1);
5c484f79 569 if (!rootfsdir)
a61b4e85 570 return NULL;
5c484f79
CB
571
572 *rootfslen = strlen(rootfsdir);
573
574 return rootfsdir;
575}
576
577int ovl_mkdir(const struct mntent *mntent, const struct lxc_rootfs *rootfs,
578 const char *lxc_name, const char *lxc_path)
579{
339de297 580 char lxcpath[PATH_MAX];
241978fa
CB
581 char **opts;
582 int ret;
180c477a 583 size_t arrlen, i, len, rootfslen;
5c484f79 584 int fret = -1;
180c477a 585 size_t dirlen = 0;
241978fa
CB
586 char *rootfs_dir = NULL, *rootfs_path = NULL, *upperdir = NULL,
587 *workdir = NULL;
5c484f79 588
9769034f
CB
589 /* When rootfs == NULL we have a container without a rootfs. */
590 if (rootfs && rootfs->path)
591 rootfs_path = rootfs->path;
5c484f79
CB
592
593 opts = lxc_string_split(mntent->mnt_opts, ',');
594 if (opts)
595 arrlen = lxc_array_len((void **)opts);
596 else
597 goto err;
598
599 for (i = 0; i < arrlen; i++) {
241978fa
CB
600 if (strstr(opts[i], "upperdir=") &&
601 (strlen(opts[i]) > (len = strlen("upperdir="))))
5c484f79 602 upperdir = opts[i] + len;
241978fa
CB
603 else if (strstr(opts[i], "workdir=") &&
604 (strlen(opts[i]) > (len = strlen("workdir="))))
5c484f79
CB
605 workdir = opts[i] + len;
606 }
607
9769034f 608 if (rootfs_path) {
339de297
CB
609 ret = snprintf(lxcpath, PATH_MAX, "%s/%s", lxc_path, lxc_name);
610 if (ret < 0 || ret >= PATH_MAX)
9769034f 611 goto err;
5c484f79 612
241978fa
CB
613 rootfs_dir = ovl_get_rootfs(rootfs_path, &rootfslen);
614 if (!rootfs_dir)
9769034f 615 goto err;
5c484f79 616
9769034f
CB
617 dirlen = strlen(lxcpath);
618 }
5c484f79
CB
619
620 /*
621 * We neither allow users to create upperdirs and workdirs outside the
622 * containerdir nor inside the rootfs. The latter might be debatable.
9769034f 623 * When we have a container without a rootfs we skip the checks.
5c484f79 624 */
9769034f
CB
625 ret = 0;
626 if (upperdir) {
627 if (!rootfs_path)
628 ret = mkdir_p(upperdir, 0755);
241978fa
CB
629 else if (!strncmp(upperdir, lxcpath, dirlen) &&
630 strncmp(upperdir, rootfs_dir, rootfslen))
9769034f 631 ret = mkdir_p(upperdir, 0755);
a24c5678 632
9769034f 633 if (ret < 0)
a24c5678 634 SYSWARN("Failed to create directory \"%s\"", upperdir);
9769034f
CB
635 }
636
637 ret = 0;
638 if (workdir) {
639 if (!rootfs_path)
640 ret = mkdir_p(workdir, 0755);
241978fa
CB
641 else if (!strncmp(workdir, lxcpath, dirlen) &&
642 strncmp(workdir, rootfs_dir, rootfslen))
9769034f 643 ret = mkdir_p(workdir, 0755);
a24c5678 644
9769034f 645 if (ret < 0)
a24c5678 646 SYSWARN("Failed to create directory \"%s\"", workdir);
9769034f 647 }
5c484f79
CB
648
649 fret = 0;
650
651err:
241978fa 652 free(rootfs_dir);
5c484f79
CB
653 lxc_free_array((void **)opts, free);
654 return fret;
655}
656
241978fa 657/* To be called from lxcapi_clone() in lxccontainer.c: When we clone a container
38683db4
CB
658 * with overlay lxc.mount.entry entries we need to update absolute paths for
659 * upper- and workdir. This update is done in two locations:
be0bc4d1 660 * lxc_conf->unexpanded_config and lxc_conf->mount_entries. Both updates are done
241978fa
CB
661 * independent of each other since lxc_conf->mountlist may contain more mount
662 * entries (e.g. from other included files) than lxc_conf->unexpanded_config.
38683db4 663 */
83e79752
CB
664int ovl_update_abs_paths(struct lxc_conf *lxc_conf, const char *lxc_path,
665 const char *lxc_name, const char *newpath,
666 const char *newname)
38683db4 667{
339de297
CB
668 char new_upper[PATH_MAX], new_work[PATH_MAX], old_upper[PATH_MAX],
669 old_work[PATH_MAX];
84760c11 670 size_t i;
be0bc4d1 671 struct string_entry *entry;
241978fa 672 char *cleanpath = NULL;
38683db4
CB
673 int fret = -1;
674 int ret = 0;
38683db4
CB
675 const char *ovl_dirs[] = {"br", "upperdir", "workdir"};
676
677 cleanpath = strdup(newpath);
678 if (!cleanpath)
679 goto err;
680
681 remove_trailing_slashes(cleanpath);
682
5c484f79
CB
683 /*
684 * We have to update lxc_conf->unexpanded_config separately from
be0bc4d1 685 * lxc_conf->mount_entries.
5c484f79 686 */
38683db4
CB
687 for (i = 0; i < sizeof(ovl_dirs) / sizeof(ovl_dirs[0]); i++) {
688 if (!clone_update_unexp_ovl_paths(lxc_conf, lxc_path, newpath,
689 lxc_name, newname,
690 ovl_dirs[i]))
691 goto err;
692 }
693
241978fa 694 ret =
339de297
CB
695 snprintf(old_work, PATH_MAX, "workdir=%s/%s", lxc_path, lxc_name);
696 if (ret < 0 || ret >= PATH_MAX)
38683db4
CB
697 goto err;
698
241978fa 699 ret =
339de297
CB
700 snprintf(new_work, PATH_MAX, "workdir=%s/%s", cleanpath, newname);
701 if (ret < 0 || ret >= PATH_MAX)
38683db4
CB
702 goto err;
703
be0bc4d1 704 list_for_each_entry(entry, &lxc_conf->mount_entries, head) {
241978fa
CB
705 char *mnt_entry = NULL, *new_mnt_entry = NULL, *tmp = NULL,
706 *tmp_mnt_entry = NULL;
707
be0bc4d1 708 mnt_entry = entry->val;
38683db4
CB
709
710 if (strstr(mnt_entry, "overlay"))
711 tmp = "upperdir";
38683db4
CB
712 if (!tmp)
713 continue;
714
339de297 715 ret = snprintf(old_upper, PATH_MAX, "%s=%s/%s", tmp, lxc_path,
241978fa 716 lxc_name);
339de297 717 if (ret < 0 || ret >= PATH_MAX)
38683db4
CB
718 goto err;
719
339de297 720 ret = snprintf(new_upper, PATH_MAX, "%s=%s/%s", tmp,
241978fa 721 cleanpath, newname);
339de297 722 if (ret < 0 || ret >= PATH_MAX)
38683db4
CB
723 goto err;
724
be0bc4d1
CB
725 if (strstr(mnt_entry, old_upper))
726 tmp_mnt_entry = lxc_string_replace(old_upper, new_upper, mnt_entry);
38683db4
CB
727
728 if (strstr(mnt_entry, old_work)) {
729 if (tmp_mnt_entry)
be0bc4d1
CB
730 new_mnt_entry = lxc_string_replace(old_work,
731 new_work,
732 tmp_mnt_entry);
38683db4 733 else
be0bc4d1
CB
734 new_mnt_entry = lxc_string_replace(old_work,
735 new_work,
736 mnt_entry);
38683db4
CB
737 }
738
739 if (new_mnt_entry) {
be0bc4d1
CB
740 free(entry->val);
741 entry->val = strdup(new_mnt_entry);
38683db4 742 } else if (tmp_mnt_entry) {
be0bc4d1
CB
743 free(entry->val);
744 entry->val = strdup(tmp_mnt_entry);
38683db4
CB
745 }
746
747 free(new_mnt_entry);
748 free(tmp_mnt_entry);
749 }
750
751 fret = 0;
752err:
753 free(cleanpath);
754 return fret;
755}
756
88232d3f
CB
757static int ovl_remount_on_enodev(const char *lower, const char *target,
758 const char *name, unsigned long mountflags,
759 const void *options)
760{
241978fa
CB
761 int ret;
762 ret = mount(lower, target, ovl_name, MS_MGC_VAL | mountflags, options);
763 if (ret < 0 && errno == ENODEV) /* Try other module name. */
88232d3f
CB
764 ret = mount(lower, target,
765 ovl_name == ovl_version[0] ? ovl_version[1]
766 : ovl_version[0],
767 MS_MGC_VAL | mountflags, options);
241978fa 768 return ret;
5c484f79
CB
769}
770
771static char *ovl_detect_name(void)
772{
241978fa 773 FILE *f;
88232d3f 774 char *v = ovl_version[0];
5c484f79
CB
775 char *line = NULL;
776 size_t len = 0;
241978fa
CB
777
778 f = fopen("/proc/filesystems", "r");
5c484f79
CB
779 if (!f)
780 return v;
781
782 while (getline(&line, &len, f) != -1) {
88232d3f
CB
783 if (strcmp(line, "nodev\toverlayfs\n") == 0) {
784 v = ovl_version[1];
5c484f79
CB
785 break;
786 }
787 }
788
789 fclose(f);
790 free(line);
791 return v;
792}
793
17a367d8 794static int ovl_do_rsync(const char *src, const char *dest,
241978fa 795 struct lxc_conf *conf)
5c484f79
CB
796{
797 int ret = -1;
17a367d8 798 struct rsync_data_char rdata = {0};
339de297 799 char cmd_output[PATH_MAX] = {0};
5c484f79 800
17a367d8
CB
801 rdata.src = (char *)src;
802 rdata.dest = (char *)dest;
e0010464 803 if (am_guest_unpriv())
5c05427a
CB
804 ret = userns_exec_full(conf, lxc_rsync_exec_wrapper, &rdata,
805 "lxc_rsync_exec_wrapper");
17a367d8 806 else
241978fa
CB
807 ret = run_command(cmd_output, sizeof(cmd_output),
808 lxc_rsync_exec_wrapper, (void *)&rdata);
17a367d8
CB
809 if (ret < 0)
810 ERROR("Failed to rsync from \"%s\" into \"%s\"%s%s", src, dest,
811 cmd_output[0] != '\0' ? ": " : "",
812 cmd_output[0] != '\0' ? cmd_output : "");
5c484f79
CB
813
814 return ret;
815}