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