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