]> git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/storage/overlay.c
Merge pull request #3235 from xinhua9569/master
[mirror_lxc.git] / src / lxc / storage / overlay.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2
3 #ifndef _GNU_SOURCE
4 #define _GNU_SOURCE 1
5 #endif
6 #include <errno.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10
11 #include "conf.h"
12 #include "config.h"
13 #include "confile.h"
14 #include "log.h"
15 #include "lxccontainer.h"
16 #include "macro.h"
17 #include "memory_utils.h"
18 #include "overlay.h"
19 #include "rsync.h"
20 #include "storage.h"
21 #include "storage_utils.h"
22 #include "utils.h"
23
24 lxc_log_define(overlay, lxc);
25
26 static char *ovl_name;
27 static char *ovl_version[] = {"overlay", "overlayfs"};
28
29 static char *ovl_detect_name(void);
30 static int ovl_do_rsync(const char *src, const char *dest,
31 struct lxc_conf *conf);
32 static int ovl_remount_on_enodev(const char *lower, const char *target,
33 const char *name, unsigned long mountflags,
34 const void *options);
35
36 int ovl_clonepaths(struct lxc_storage *orig, struct lxc_storage *new, const char *oldname,
37 const char *cname, const char *oldpath, const char *lxcpath,
38 int snap, uint64_t newsize, struct lxc_conf *conf)
39 {
40 int ret;
41 const char *src;
42
43 if (!snap) {
44 ERROR("The overlay storage driver can only be used for "
45 "snapshots");
46 return -22;
47 }
48
49 if (!orig->src || !orig->dest)
50 return -1;
51
52 new->dest = must_make_path(lxcpath, cname, "rootfs", NULL);
53
54 ret = mkdir_p(new->dest, 0755);
55 if (ret < 0 && errno != EEXIST) {
56 SYSERROR("Failed to create directory \"%s\"", new->dest);
57 return -1;
58 }
59
60 if (am_guest_unpriv()) {
61 ret = chown_mapped_root(new->dest, conf);
62 if (ret < 0)
63 WARN("Failed to update ownership of %s", new->dest);
64 }
65
66 if (strcmp(orig->type, "dir") == 0) {
67 char *delta, *lastslash;
68 char *work;
69 int len, lastslashidx;
70
71 /* If we have "/var/lib/lxc/c2/rootfs" then delta will be
72 * "/var/lib/lxc/c2/delta0".
73 */
74 lastslash = strrchr(new->dest, '/');
75 if (!lastslash) {
76 ERROR("Failed to detect \"/\" in string \"%s\"",
77 new->dest);
78 return -22;
79 }
80
81 if (strlen(lastslash) < STRLITERALLEN("/rootfs")) {
82 ERROR("Failed to detect \"/rootfs\" in string \"%s\"",
83 new->dest);
84 return -22;
85 }
86
87 lastslash++;
88 lastslashidx = lastslash - new->dest;
89
90 delta = malloc(lastslashidx + 7);
91 if (!delta) {
92 ERROR("Failed to allocate memory");
93 return -1;
94 }
95
96 memcpy(delta, new->dest, lastslashidx + 1);
97 memcpy(delta + lastslashidx, "delta0", STRLITERALLEN("delta0"));
98 delta[lastslashidx + STRLITERALLEN("delta0")] = '\0';
99
100 ret = mkdir(delta, 0755);
101 if (ret < 0 && errno != EEXIST) {
102 SYSERROR("Failed to create directory \"%s\"", delta);
103 free(delta);
104 return -1;
105 }
106
107 if (am_guest_unpriv()) {
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:
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 */
121 work = malloc(lastslashidx + 7);
122 if (!work) {
123 ERROR("Failed to allocate memory");
124 free(delta);
125 return -1;
126 }
127
128 memcpy(work, new->dest, lastslashidx + 1);
129 memcpy(work + lastslashidx, "olwork", STRLITERALLEN("olwork"));
130 work[lastslashidx + STRLITERALLEN("olwork")] = '\0';
131
132 ret = mkdir(work, 0755);
133 if (ret < 0) {
134 SYSERROR("Failed to create directory \"%s\"", work);
135 free(delta);
136 free(work);
137 return -1;
138 }
139
140 if (am_guest_unpriv()) {
141 ret = chown_mapped_root(work, conf);
142 if (ret < 0)
143 WARN("Failed to update ownership of %s", work);
144 }
145 free(work);
146
147 /* strlen("overlay:") = 8
148 * +
149 * strlen(delta)
150 * +
151 * :
152 * +
153 * strlen(src)
154 * +
155 * \0
156 */
157 src = lxc_storage_get_path(orig->src, orig->type);
158 len = 8 + strlen(delta) + 1 + strlen(src) + 1;
159 new->src = malloc(len);
160 if (!new->src) {
161 ERROR("Failed to allocate memory");
162 free(delta);
163 return -ENOMEM;
164 }
165
166 ret = snprintf(new->src, len, "overlay:%s:%s", src, delta);
167 free(delta);
168 if (ret < 0 || (size_t)ret >= len) {
169 ERROR("Failed to create string");
170 return -1;
171 }
172 } else if (!strcmp(orig->type, "overlayfs") ||
173 !strcmp(orig->type, "overlay")) {
174 char *clean_old_path, *clean_new_path;
175 char *lastslash, *ndelta, *nsrc, *odelta, *osrc, *s1, *s2, *s3,
176 *work;
177 int lastslashidx;
178 size_t len, name_len;
179
180 osrc = strdup(orig->src);
181 if (!osrc) {
182 ERROR("Failed to duplicate string \"%s\"", orig->src);
183 return -22;
184 }
185
186 nsrc = osrc;
187 if (strncmp(osrc, "overlay:", 8) == 0)
188 nsrc += 8;
189 else if (strncmp(osrc, "overlayfs:", 10) == 0)
190 nsrc += 10;
191
192 odelta = strchr(nsrc, ':');
193 if (!odelta) {
194 ERROR("Failed to find \":\" in \"%s\"", nsrc);
195 free(osrc);
196 return -22;
197 }
198
199 *odelta = '\0';
200 odelta++;
201 ndelta = must_make_path(lxcpath, cname, "delta0", NULL);
202
203 ret = mkdir(ndelta, 0755);
204 if (ret < 0 && errno != EEXIST) {
205 SYSERROR("Failed to create directory \"%s\"", ndelta);
206 free(osrc);
207 free(ndelta);
208 return -1;
209 }
210
211 if (am_guest_unpriv()) {
212 ret = chown_mapped_root(ndelta, conf);
213 if (ret < 0)
214 WARN("Failed to update ownership of %s",
215 ndelta);
216 }
217
218 /* Make workdir for overlayfs.v22 or higher (See the comment
219 * further up.).
220 */
221 lastslash = strrchr(ndelta, '/');
222 if (!lastslash) {
223 ERROR("Failed to detect \"/\" in \"%s\"", ndelta);
224 free(osrc);
225 free(ndelta);
226 return -1;
227 }
228 lastslash++;
229 lastslashidx = lastslash - ndelta;
230
231 work = malloc(lastslashidx + 7);
232 if (!work) {
233 free(osrc);
234 free(ndelta);
235 ERROR("Failed to allocate memory");
236 return -1;
237 }
238
239 memcpy(work, ndelta, lastslashidx + 1);
240 memcpy(work + lastslashidx, "olwork", STRLITERALLEN("olwork"));
241 work[lastslashidx + STRLITERALLEN("olwork")] = '\0';
242
243 ret = mkdir(work, 0755);
244 if (ret < 0 && errno != EEXIST) {
245 SYSERROR("Failed to create directory \"%s\"", ndelta);
246 free(osrc);
247 free(ndelta);
248 free(work);
249 return -1;
250 }
251
252 if (am_guest_unpriv()) {
253 ret = chown_mapped_root(work, conf);
254 if (ret < 0)
255 WARN("Failed to update ownership of %s", work);
256 }
257 free(work);
258
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;
270 new->src = malloc(len);
271 if (!new->src) {
272 free(osrc);
273 free(ndelta);
274 ERROR("Failed to allocate memory");
275 return -ENOMEM;
276 }
277 ret = snprintf(new->src, len, "overlay:%s:%s", nsrc, ndelta);
278 if (ret < 0 || (size_t)ret >= len) {
279 ERROR("Failed to create string");
280 free(osrc);
281 free(ndelta);
282 return -1;
283 }
284
285 ret = ovl_do_rsync(odelta, ndelta, conf);
286 free(osrc);
287 free(ndelta);
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) {
308 ERROR("Failed to detect \"/\" in string \"%s\"", clean_old_path);
309 free(clean_old_path);
310 free(clean_new_path);
311 return -1;
312 }
313
314 s2 = strrchr(clean_new_path, '/');
315 if (!s2) {
316 ERROR("Failed to detect \"/\" in string \"%s\"", clean_new_path);
317 free(clean_old_path);
318 free(clean_new_path);
319 return -1;
320 }
321
322 if (!strncmp(s1, "/snaps", STRLITERALLEN("/snaps"))) {
323 s1 = clean_new_path;
324 s2 = clean_old_path;
325 s3 = (char *)cname;
326 } else if (!strncmp(s2, "/snaps", STRLITERALLEN("/snaps"))) {
327 s1 = clean_old_path;
328 s2 = clean_new_path;
329 s3 = (char *)oldname;
330 } else {
331 free(clean_old_path);
332 free(clean_new_path);
333 return 0;
334 }
335
336 len = strlen(s1);
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
354 free(clean_old_path);
355 free(clean_new_path);
356 return LXC_CLONE_SNAPSHOT;
357 }
358
359 free(clean_old_path);
360 free(clean_new_path);
361 return 0;
362 } else {
363 ERROR("overlay clone of %s container is not yet supported",
364 orig->type);
365 /* Note, supporting this will require ovl_mount supporting
366 * mounting of the underlay. No big deal, just needs to be done.
367 */
368 return -1;
369 }
370
371 return 0;
372 }
373
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".
377 */
378 int ovl_create(struct lxc_storage *bdev, const char *dest, const char *n,
379 struct bdev_specs *specs)
380 {
381 char *delta;
382 int ret;
383 size_t len, newlen;
384
385 len = strlen(dest);
386 if (len < 8 || strcmp(dest + len - 7, "/rootfs")) {
387 ERROR("Failed to detect \"/rootfs\" in \"%s\"", dest);
388 return -1;
389 }
390
391 bdev->dest = strdup(dest);
392 if (!bdev->dest) {
393 ERROR("Failed to duplicate string \"%s\"", dest);
394 return -1;
395 }
396
397 delta = strdup(dest);
398 if (!delta) {
399 ERROR("Failed to allocate memory");
400 return -1;
401 }
402 memcpy(delta + len - 6, "delta0", STRLITERALLEN("delta0"));
403
404 ret = mkdir_p(delta, 0755);
405 if (ret < 0) {
406 SYSERROR("Failed to create directory \"%s\"", delta);
407 free(delta);
408 return -1;
409 }
410
411 /* overlay:lower:upper */
412 newlen = (2 * len) + strlen("overlay:") + 2;
413 bdev->src = malloc(newlen);
414 if (!bdev->src) {
415 ERROR("Failed to allocate memory");
416 free(delta);
417 return -1;
418 }
419
420 ret = snprintf(bdev->src, newlen, "overlay:%s:%s", dest, delta);
421 if (ret < 0 || (size_t)ret >= newlen) {
422 ERROR("Failed to create string");
423 free(delta);
424 return -1;
425 }
426
427 ret = mkdir_p(bdev->dest, 0755);
428 if (ret < 0) {
429 SYSERROR("Failed to create directory \"%s\"", bdev->dest);
430 free(delta);
431 return -1;
432 }
433
434 free(delta);
435 return 0;
436 }
437
438 int ovl_destroy(struct lxc_storage *orig)
439 {
440 char *upper = orig->src;
441
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
448 if (strncmp(upper, "overlay:", 8) == 0)
449 upper += 8;
450 else if (strncmp(upper, "overlayfs:", 10) == 0)
451 upper += 10;
452
453 upper = strchr(upper, ':');
454 if (!upper)
455 return -22;
456 upper++;
457
458 return lxc_rmdir_onedev(upper, NULL);
459 }
460
461 bool ovl_detect(const char *path)
462 {
463 if (!strncmp(path, "overlay:", 8))
464 return true;
465
466 if (!strncmp(path, "overlayfs:", 10))
467 return true;
468
469 return false;
470 }
471
472 int ovl_mount(struct lxc_storage *bdev)
473 {
474 __do_free char *options = NULL,
475 *options_work = NULL;
476 char *tmp, *dup, *lower, *upper;
477 char *work, *lastslash;
478 int lastslashidx;
479 size_t len, len2;
480 unsigned long mntflags;
481 char *mntdata;
482 int ret, ret2;
483
484 if (strcmp(bdev->type, "overlay") && strcmp(bdev->type, "overlayfs"))
485 return -22;
486
487 if (!bdev->src || !bdev->dest)
488 return -22;
489
490 if (!ovl_name)
491 ovl_name = ovl_detect_name();
492
493 /* Separately mount it first:
494 * mount -t overlay * -o upperdir=${upper},lowerdir=${lower} lower dest
495 */
496 dup = strdup(bdev->src);
497 if (!dup) {
498 ERROR("Failed to allocate memory");
499 return -1;
500 }
501 upper = dup;
502 lower = dup;
503
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;
510
511 /* support multiple lower layers */
512 while ((tmp = strstr(upper, ":/"))) {
513 tmp++;
514 upper = tmp;
515 }
516
517 upper--;
518 if (upper == lower) {
519 free(dup);
520 return -22;
521 }
522 *upper = '\0';
523 upper++;
524
525 /* if delta doesn't yet exist, create it */
526 ret = mkdir_p(upper, 0755);
527 if (ret < 0 && errno != EEXIST) {
528 SYSERROR("Failed to create directory \"%s\"", upper);
529 free(dup);
530 return -22;
531 }
532
533 /* overlayfs.v22 or higher needs workdir option:
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, '/');
540 if (!lastslash) {
541 ERROR("Failed to detect \"/\" in string \"%s\"", upper);
542 free(dup);
543 return -22;
544 }
545
546 lastslash++;
547 lastslashidx = lastslash - upper;
548
549 work = malloc(lastslashidx + 7);
550 if (!work) {
551 ERROR("Failed to allocate memory");
552 free(dup);
553 return -22;
554 }
555
556 memcpy(work, upper, lastslashidx + 1);
557 memcpy(work + lastslashidx, "olwork", STRLITERALLEN("olwork"));
558 work[lastslashidx + STRLITERALLEN("olwork")] = '\0';
559
560 ret = parse_mntopts(bdev->mntopts, &mntflags, &mntdata);
561 if (ret < 0) {
562 ERROR("Failed to parse mount options");
563 free(mntdata);
564 free(dup);
565 free(work);
566 return -22;
567 }
568
569 ret = mkdir_p(work, 0755);
570 if (ret < 0 && errno != EEXIST) {
571 SYSERROR("Failed to create directory \"%s\"", work);
572 free(mntdata);
573 free(dup);
574 free(work);
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) {
585 len = strlen(lower) + strlen(upper) +
586 strlen("upperdir=,lowerdir=,") + strlen(mntdata) + 1;
587 options = must_realloc(NULL, len);
588 ret = snprintf(options, len, "upperdir=%s,lowerdir=%s,%s",
589 upper, lower, mntdata);
590
591 len2 = strlen(lower) + strlen(upper) + strlen(work) +
592 strlen("upperdir=,lowerdir=,workdir=") +
593 strlen(mntdata) + 1;
594 options_work = must_realloc(NULL, len2);
595 ret2 = snprintf(options, len2,
596 "upperdir=%s,lowerdir=%s,workdir=%s,%s", upper,
597 lower, work, mntdata);
598 } else {
599 len = strlen(lower) + strlen(upper) +
600 strlen("upperdir=,lowerdir=") + 1;
601 options = must_realloc(NULL, len);
602 ret = snprintf(options, len, "upperdir=%s,lowerdir=%s", upper,
603 lower);
604
605 len2 = strlen(lower) + strlen(upper) + strlen(work) +
606 strlen("upperdir=,lowerdir=,workdir=") + 1;
607 options_work = must_realloc(NULL, len2);
608 ret2 = snprintf(options_work, len2,
609 "upperdir=%s,lowerdir=%s,workdir=%s", upper,
610 lower, work);
611 }
612
613 if (ret < 0 || ret >= len || ret2 < 0 || ret2 >= len2) {
614 ERROR("Failed to create string");
615 free(mntdata);
616 free(dup);
617 free(work);
618 return -1;
619 }
620
621 /* Assume we need a workdir as we are on a overlay version >= v22. */
622 ret = ovl_remount_on_enodev(lower, bdev->dest, ovl_name,
623 MS_MGC_VAL | mntflags, options_work);
624 if (ret < 0) {
625 SYSINFO("Failed to mount \"%s\" on \"%s\" with options \"%s\". "
626 "Retrying without workdir",
627 lower, bdev->dest, options_work);
628
629 /* Assume we cannot use a workdir as we are on a version <= v21.
630 */
631 ret = ovl_remount_on_enodev(lower, bdev->dest, ovl_name,
632 MS_MGC_VAL | mntflags, options);
633 if (ret < 0)
634 SYSERROR("Failed to mount \"%s\" on \"%s\" with options \"%s\"",
635 lower, bdev->dest, options);
636 else
637 INFO("Mounted \"%s\" on \"%s\" with options \"%s\"",
638 lower, bdev->dest, options);
639 } else {
640 INFO("Mounted \"%s\" on \"%s\" with options \"%s\"", lower,
641 bdev->dest, options_work);
642 }
643
644 free(dup);
645 free(work);
646 return ret;
647 }
648
649 int ovl_umount(struct lxc_storage *bdev)
650 {
651 int ret;
652
653 if (strcmp(bdev->type, "overlay") && strcmp(bdev->type, "overlayfs"))
654 return -22;
655
656 if (!bdev->src || !bdev->dest)
657 return -22;
658
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;
666 }
667
668 const char *ovl_get_lower(const char *rootfs_path)
669 {
670 const char *s1 = rootfs_path;
671
672 if (strncmp(rootfs_path, "overlay:", 8) == 0)
673 s1 += 8;
674 else if (strncmp(rootfs_path, "overlayfs:", 10) == 0)
675 s1 += 10;
676
677 s1 = strstr(s1, ":/");
678 if (!s1)
679 return NULL;
680 s1++;
681
682 return s1;
683 }
684
685 char *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
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);
710 free(s1);
711 if (!rootfsdir)
712 return NULL;
713
714 *rootfslen = strlen(rootfsdir);
715
716 return rootfsdir;
717 }
718
719 int ovl_mkdir(const struct mntent *mntent, const struct lxc_rootfs *rootfs,
720 const char *lxc_name, const char *lxc_path)
721 {
722 char lxcpath[PATH_MAX];
723 char **opts;
724 int ret;
725 size_t arrlen, i, len, rootfslen;
726 int fret = -1;
727 size_t dirlen = 0;
728 char *rootfs_dir = NULL, *rootfs_path = NULL, *upperdir = NULL,
729 *workdir = NULL;
730
731 /* When rootfs == NULL we have a container without a rootfs. */
732 if (rootfs && rootfs->path)
733 rootfs_path = rootfs->path;
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++) {
742 if (strstr(opts[i], "upperdir=") &&
743 (strlen(opts[i]) > (len = strlen("upperdir="))))
744 upperdir = opts[i] + len;
745 else if (strstr(opts[i], "workdir=") &&
746 (strlen(opts[i]) > (len = strlen("workdir="))))
747 workdir = opts[i] + len;
748 }
749
750 if (rootfs_path) {
751 ret = snprintf(lxcpath, PATH_MAX, "%s/%s", lxc_path, lxc_name);
752 if (ret < 0 || ret >= PATH_MAX)
753 goto err;
754
755 rootfs_dir = ovl_get_rootfs(rootfs_path, &rootfslen);
756 if (!rootfs_dir)
757 goto err;
758
759 dirlen = strlen(lxcpath);
760 }
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.
765 * When we have a container without a rootfs we skip the checks.
766 */
767 ret = 0;
768 if (upperdir) {
769 if (!rootfs_path)
770 ret = mkdir_p(upperdir, 0755);
771 else if (!strncmp(upperdir, lxcpath, dirlen) &&
772 strncmp(upperdir, rootfs_dir, rootfslen))
773 ret = mkdir_p(upperdir, 0755);
774
775 if (ret < 0)
776 SYSWARN("Failed to create directory \"%s\"", upperdir);
777 }
778
779 ret = 0;
780 if (workdir) {
781 if (!rootfs_path)
782 ret = mkdir_p(workdir, 0755);
783 else if (!strncmp(workdir, lxcpath, dirlen) &&
784 strncmp(workdir, rootfs_dir, rootfslen))
785 ret = mkdir_p(workdir, 0755);
786
787 if (ret < 0)
788 SYSWARN("Failed to create directory \"%s\"", workdir);
789 }
790
791 fret = 0;
792
793 err:
794 free(rootfs_dir);
795 lxc_free_array((void **)opts, free);
796 return fret;
797 }
798
799 /* To be called from lxcapi_clone() in lxccontainer.c: When we clone a container
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
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.
805 */
806 int 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)
809 {
810 char new_upper[PATH_MAX], new_work[PATH_MAX], old_upper[PATH_MAX],
811 old_work[PATH_MAX];
812 size_t i;
813 struct lxc_list *iterator;
814 char *cleanpath = NULL;
815 int fret = -1;
816 int ret = 0;
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
825 /*
826 * We have to update lxc_conf->unexpanded_config separately from
827 * lxc_conf->mount_list.
828 */
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
836 ret =
837 snprintf(old_work, PATH_MAX, "workdir=%s/%s", lxc_path, lxc_name);
838 if (ret < 0 || ret >= PATH_MAX)
839 goto err;
840
841 ret =
842 snprintf(new_work, PATH_MAX, "workdir=%s/%s", cleanpath, newname);
843 if (ret < 0 || ret >= PATH_MAX)
844 goto err;
845
846 lxc_list_for_each(iterator, &lxc_conf->mount_list) {
847 char *mnt_entry = NULL, *new_mnt_entry = NULL, *tmp = NULL,
848 *tmp_mnt_entry = NULL;
849
850 mnt_entry = iterator->elem;
851
852 if (strstr(mnt_entry, "overlay"))
853 tmp = "upperdir";
854 if (!tmp)
855 continue;
856
857 ret = snprintf(old_upper, PATH_MAX, "%s=%s/%s", tmp, lxc_path,
858 lxc_name);
859 if (ret < 0 || ret >= PATH_MAX)
860 goto err;
861
862 ret = snprintf(new_upper, PATH_MAX, "%s=%s/%s", tmp,
863 cleanpath, newname);
864 if (ret < 0 || ret >= PATH_MAX)
865 goto err;
866
867 if (strstr(mnt_entry, old_upper)) {
868 tmp_mnt_entry =
869 lxc_string_replace(old_upper, new_upper, mnt_entry);
870 }
871
872 if (strstr(mnt_entry, old_work)) {
873 if (tmp_mnt_entry)
874 new_mnt_entry = lxc_string_replace(
875 old_work, new_work, tmp_mnt_entry);
876 else
877 new_mnt_entry = lxc_string_replace(
878 old_work, new_work, mnt_entry);
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;
894 err:
895 free(cleanpath);
896 return fret;
897 }
898
899 static int ovl_remount_on_enodev(const char *lower, const char *target,
900 const char *name, unsigned long mountflags,
901 const void *options)
902 {
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. */
906 ret = mount(lower, target,
907 ovl_name == ovl_version[0] ? ovl_version[1]
908 : ovl_version[0],
909 MS_MGC_VAL | mountflags, options);
910 return ret;
911 }
912
913 static char *ovl_detect_name(void)
914 {
915 FILE *f;
916 char *v = ovl_version[0];
917 char *line = NULL;
918 size_t len = 0;
919
920 f = fopen("/proc/filesystems", "r");
921 if (!f)
922 return v;
923
924 while (getline(&line, &len, f) != -1) {
925 if (strcmp(line, "nodev\toverlayfs\n") == 0) {
926 v = ovl_version[1];
927 break;
928 }
929 }
930
931 fclose(f);
932 free(line);
933 return v;
934 }
935
936 static int ovl_do_rsync(const char *src, const char *dest,
937 struct lxc_conf *conf)
938 {
939 int ret = -1;
940 struct rsync_data_char rdata = {0};
941 char cmd_output[PATH_MAX] = {0};
942
943 rdata.src = (char *)src;
944 rdata.dest = (char *)dest;
945 if (am_guest_unpriv())
946 ret = userns_exec_full(conf, lxc_rsync_exec_wrapper, &rdata,
947 "lxc_rsync_exec_wrapper");
948 else
949 ret = run_command(cmd_output, sizeof(cmd_output),
950 lxc_rsync_exec_wrapper, (void *)&rdata);
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 : "");
955
956 return ret;
957 }