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