]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/storage/aufs.c
rename am_unpriv to am_host_unpriv
[mirror_lxc.git] / src / lxc / storage / aufs.c
CommitLineData
00f0a1f8
CB
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 <stdint.h>
27#include <string.h>
28#include <sys/stat.h>
29#include <sys/types.h>
30
28d832c4 31#include "aufs.h"
00f0a1f8 32#include "log.h"
28d832c4
CB
33#include "rsync.h"
34#include "storage.h"
00f0a1f8
CB
35#include "utils.h"
36
10bc1861 37lxc_log_define(aufs, lxc);
00f0a1f8
CB
38
39/* the bulk of this needs to become a common helper */
40extern char *dir_new_path(char *src, const char *oldname, const char *name,
41 const char *oldpath, const char *lxcpath);
42
79f4b264
CB
43int lxc_rsync_delta(struct rsync_data_char *data)
44{
45 int ret;
46
47 ret = lxc_switch_uid_gid(0, 0);
48 if (ret < 0)
49 return -1;
50
51 ret = lxc_setgroups(0, NULL);
52 if (ret < 0)
53 return -1;
54
55 ret = lxc_rsync_exec(data->src, data->dest);
56 if (ret < 0) {
57 ERROR("Failed to rsync from \"%s\" into \"%s\"", data->src,
58 data->dest);
59 return -1;
60 }
61
62 return 0;
63}
64
65int lxc_rsync_delta_wrapper(void *data)
66{
67 struct rsync_data_char *arg = data;
68 return lxc_rsync_delta(arg);
69}
70
10bc1861
CB
71int aufs_clonepaths(struct lxc_storage *orig, struct lxc_storage *new,
72 const char *oldname, const char *cname, const char *oldpath,
73 const char *lxcpath, int snap, uint64_t newsize,
74 struct lxc_conf *conf)
00f0a1f8 75{
79f4b264
CB
76 char cmd_output[MAXPATHLEN];
77
00f0a1f8
CB
78 if (!snap) {
79 ERROR("aufs is only for snapshot clones");
80 return -22;
81 }
82
83 if (!orig->src || !orig->dest)
84 return -1;
85
86 new->dest = dir_new_path(orig->dest, oldname, cname, oldpath, lxcpath);
87 if (!new->dest)
88 return -1;
89 if (mkdir_p(new->dest, 0755) < 0)
90 return -1;
91
5384e99d 92 if (am_host_unpriv() && chown_mapped_root(new->dest, conf) < 0)
00f0a1f8
CB
93 WARN("Failed to update ownership of %s", new->dest);
94
95 if (strcmp(orig->type, "dir") == 0) {
96 char *delta, *lastslash;
97 int ret, len, lastslashidx;
98
99 // if we have /var/lib/lxc/c2/rootfs, then delta will be
100 // /var/lib/lxc/c2/delta0
101 lastslash = strrchr(new->dest, '/');
102 if (!lastslash)
103 return -22;
104 if (strlen(lastslash) < 7)
105 return -22;
106 lastslash++;
107 lastslashidx = lastslash - new->dest;
108
109 delta = malloc(lastslashidx + 7);
110 if (!delta)
111 return -1;
112 strncpy(delta, new->dest, lastslashidx+1);
113 strcpy(delta+lastslashidx, "delta0");
114 if ((ret = mkdir(delta, 0755)) < 0) {
115 SYSERROR("error: mkdir %s", delta);
116 free(delta);
117 return -1;
118 }
5384e99d 119 if (am_host_unpriv() && chown_mapped_root(delta, conf) < 0)
00f0a1f8
CB
120 WARN("Failed to update ownership of %s", delta);
121
122 // the src will be 'aufs:lowerdir:upperdir'
123 len = strlen(delta) + strlen(orig->src) + 12;
124 new->src = malloc(len);
125 if (!new->src) {
126 free(delta);
127 return -ENOMEM;
128 }
129 ret = snprintf(new->src, len, "aufs:%s:%s", orig->src, delta);
130 free(delta);
131 if (ret < 0 || ret >= len)
132 return -ENOMEM;
133 } else if (strcmp(orig->type, "aufs") == 0) {
134 // What exactly do we want to do here?
135 // I think we want to use the original lowerdir, with a
136 // private delta which is originally rsynced from the
137 // original delta
138 char *osrc, *odelta, *nsrc, *ndelta;
139 int len, ret;
140 if (!(osrc = strdup(orig->src)))
141 return -22;
142 nsrc = strchr(osrc, ':') + 1;
143 if (nsrc != osrc + 5 || (odelta = strchr(nsrc, ':')) == NULL) {
144 free(osrc);
145 return -22;
146 }
147 *odelta = '\0';
148 odelta++;
149 ndelta = dir_new_path(odelta, oldname, cname, oldpath, lxcpath);
150 if (!ndelta) {
151 free(osrc);
152 return -ENOMEM;
153 }
154 if ((ret = mkdir(ndelta, 0755)) < 0 && errno != EEXIST) {
155 SYSERROR("error: mkdir %s", ndelta);
156 free(osrc);
157 free(ndelta);
158 return -1;
159 }
5384e99d 160 if (am_host_unpriv() && chown_mapped_root(ndelta, conf) < 0)
00f0a1f8
CB
161 WARN("Failed to update ownership of %s", ndelta);
162
163 struct rsync_data_char rdata;
164 rdata.src = odelta;
165 rdata.dest = ndelta;
5384e99d 166 if (am_host_unpriv())
5c05427a
CB
167 ret = userns_exec_full(conf, lxc_rsync_delta_wrapper,
168 &rdata, "lxc_rsync_delta_wrapper");
00f0a1f8 169 else
79f4b264
CB
170 ret = run_command(cmd_output, sizeof(cmd_output),
171 lxc_rsync_delta_wrapper,
172 (void *)&rdata);
00f0a1f8
CB
173 if (ret) {
174 free(osrc);
175 free(ndelta);
176 ERROR("copying aufs delta");
177 return -1;
178 }
179 len = strlen(nsrc) + strlen(ndelta) + 12;
180 new->src = malloc(len);
181 if (!new->src) {
182 free(osrc);
183 free(ndelta);
184 return -ENOMEM;
185 }
186 ret = snprintf(new->src, len, "aufs:%s:%s", nsrc, ndelta);
187 free(osrc);
188 free(ndelta);
189 if (ret < 0 || ret >= len)
190 return -ENOMEM;
191 } else {
192 ERROR("aufs clone of %s container is not yet supported",
193 orig->type);
194 // Note, supporting this will require aufs_mount supporting
195 // mounting of the underlay. No big deal, just needs to be done.
196 return -1;
197 }
198
199 return 0;
200}
201
202/*
203 * to say 'lxc-create -t ubuntu -n o1 -B aufs' means you want
204 * $lxcpath/$lxcname/rootfs to have the created container, while all
205 * changes after starting the container are written to
206 * $lxcpath/$lxcname/delta0
207 */
10bc1861 208int aufs_create(struct lxc_storage *bdev, const char *dest, const char *n,
00f0a1f8
CB
209 struct bdev_specs *specs)
210{
211 char *delta;
212 int ret, len = strlen(dest), newlen;
213
214 if (len < 8 || strcmp(dest+len-7, "/rootfs") != 0)
215 return -1;
216
217 if (!(bdev->dest = strdup(dest))) {
218 ERROR("Out of memory");
219 return -1;
220 }
221
222 delta = alloca(strlen(dest)+1);
223 strcpy(delta, dest);
224 strcpy(delta+len-6, "delta0");
225
226 if (mkdir_p(delta, 0755) < 0) {
227 ERROR("Error creating %s", delta);
228 return -1;
229 }
230
231 /* aufs:lower:upper */
232 newlen = (2 * len) + strlen("aufs:") + 2;
233 bdev->src = malloc(newlen);
234 if (!bdev->src) {
235 ERROR("Out of memory");
236 return -1;
237 }
238 ret = snprintf(bdev->src, newlen, "aufs:%s:%s", dest, delta);
239 if (ret < 0 || ret >= newlen)
240 return -1;
241
242 if (mkdir_p(bdev->dest, 0755) < 0) {
243 ERROR("Error creating %s", bdev->dest);
244 return -1;
245 }
246
247 return 0;
248}
249
10bc1861 250int aufs_destroy(struct lxc_storage *orig)
00f0a1f8
CB
251{
252 char *upper;
253
254 if (strncmp(orig->src, "aufs:", 5) != 0)
255 return -22;
256 upper = strchr(orig->src + 5, ':');
257 if (!upper)
258 return -22;
259 upper++;
260 return lxc_rmdir_onedev(upper, NULL);
261}
262
3d2ae1e2 263bool aufs_detect(const char *path)
00f0a1f8 264{
f7ac4459 265 if (!strncmp(path, "aufs:", 5))
3d2ae1e2 266 return true;
f7ac4459 267
3d2ae1e2 268 return false;
00f0a1f8
CB
269}
270
10bc1861 271int aufs_mount(struct lxc_storage *bdev)
00f0a1f8 272{
410d0f6e 273 char *tmp, *options, *dup, *lower, *upper;
00f0a1f8
CB
274 int len;
275 unsigned long mntflags;
276 char *mntdata;
277 int ret;
278 const char *xinopath = "/dev/shm/aufs.xino";
279
280 if (strcmp(bdev->type, "aufs"))
281 return -22;
282 if (!bdev->src || !bdev->dest)
283 return -22;
284
285 // separately mount it first
286 // mount -t aufs -obr=${upper}=rw:${lower}=ro lower dest
287 dup = alloca(strlen(bdev->src)+1);
288 strcpy(dup, bdev->src);
410d0f6e
CB
289 /* support multiple lower layers */
290 if (!(lower = strstr(dup, ":/")))
291 return -22;
292 lower++;
293 upper = lower;
294 while ((tmp = strstr(++upper, ":/"))) {
295 upper = tmp;
296 }
297 if (--upper == lower)
00f0a1f8
CB
298 return -22;
299 *upper = '\0';
300 upper++;
301
302 if (parse_mntopts(bdev->mntopts, &mntflags, &mntdata) < 0) {
303 free(mntdata);
304 return -22;
305 }
306
307 // TODO We should check whether bdev->src is a blockdev, and if so
308 // but for now, only support aufs of a basic directory
309
310 // AUFS does not work on top of certain filesystems like (XFS or Btrfs)
311 // so add xino=/dev/shm/aufs.xino parameter to mount options.
312 // The same xino option can be specified to multiple aufs mounts, and
313 // a xino file is not shared among multiple aufs mounts.
314 //
315 // see http://www.mail-archive.com/aufs-users@lists.sourceforge.net/msg02587.html
316 // http://www.mail-archive.com/aufs-users@lists.sourceforge.net/msg05126.html
317 if (mntdata) {
318 len = strlen(lower) + strlen(upper) + strlen(xinopath) + strlen("br==rw:=ro,,xino=") + strlen(mntdata) + 1;
319 options = alloca(len);
320 ret = snprintf(options, len, "br=%s=rw:%s=ro,%s,xino=%s", upper, lower, mntdata, xinopath);
321 }
322 else {
323 len = strlen(lower) + strlen(upper) + strlen(xinopath) + strlen("br==rw:=ro,xino=") + 1;
324 options = alloca(len);
325 ret = snprintf(options, len, "br=%s=rw:%s=ro,xino=%s", upper, lower, xinopath);
326 }
327
328 if (ret < 0 || ret >= len) {
329 free(mntdata);
330 return -1;
331 }
332
333 ret = mount(lower, bdev->dest, "aufs", MS_MGC_VAL | mntflags, options);
334 if (ret < 0)
335 SYSERROR("aufs: error mounting %s onto %s options %s",
336 lower, bdev->dest, options);
337 else
338 INFO("aufs: mounted %s onto %s options %s",
339 lower, bdev->dest, options);
340 return ret;
341}
342
10bc1861 343int aufs_umount(struct lxc_storage *bdev)
00f0a1f8
CB
344{
345 if (strcmp(bdev->type, "aufs"))
346 return -22;
347 if (!bdev->src || !bdev->dest)
348 return -22;
349 return umount(bdev->dest);
350}
1d52bdf7
CB
351
352char *aufs_get_rootfs(const char *rootfs_path, size_t *rootfslen)
353{
354 char *rootfsdir = NULL;
355 char *s1 = NULL;
356 char *s2 = NULL;
357 char *s3 = NULL;
358
359 if (!rootfs_path || !rootfslen)
360 return NULL;
361
362 s1 = strdup(rootfs_path);
363 if (!s1)
364 return NULL;
365
366 if ((s2 = strstr(s1, ":/"))) {
367 s2 = s2 + 1;
368 if ((s3 = strstr(s2, ":/")))
369 *s3 = '\0';
370 rootfsdir = strdup(s2);
371 if (!rootfsdir) {
372 free(s1);
373 return NULL;
374 }
375 }
376
377 if (!rootfsdir)
378 rootfsdir = s1;
379 else
380 free(s1);
381
382 *rootfslen = strlen(rootfsdir);
383
384 return rootfsdir;
385}
386
387int aufs_mkdir(const struct mntent *mntent, const struct lxc_rootfs *rootfs,
388 const char *lxc_name, const char *lxc_path)
389{
390 char lxcpath[MAXPATHLEN];
9769034f 391 char *rootfs_path = NULL;
1d52bdf7
CB
392 char *rootfsdir = NULL;
393 char *scratch = NULL;
394 char *tmp = NULL;
395 char *upperdir = NULL;
396 char **opts = NULL;
397 int fret = -1;
398 int ret = 0;
399 size_t arrlen = 0;
400 size_t i;
401 size_t len = 0;
402 size_t rootfslen = 0;
403
9769034f
CB
404 /* When rootfs == NULL we have a container without a rootfs. */
405 if (rootfs && rootfs->path)
406 rootfs_path = rootfs->path;
1d52bdf7
CB
407
408 opts = lxc_string_split(mntent->mnt_opts, ',');
409 if (opts)
410 arrlen = lxc_array_len((void **)opts);
411 else
412 goto err;
413
414 for (i = 0; i < arrlen; i++) {
415 if (strstr(opts[i], "br=") && (strlen(opts[i]) > (len = strlen("br="))))
416 tmp = opts[i] + len;
417 }
418 if (!tmp)
419 goto err;
420
421 upperdir = strtok_r(tmp, ":=", &scratch);
422 if (!upperdir)
423 goto err;
424
9769034f
CB
425 if (rootfs_path) {
426 ret = snprintf(lxcpath, MAXPATHLEN, "%s/%s", lxc_path, lxc_name);
427 if (ret < 0 || ret >= MAXPATHLEN)
428 goto err;
1d52bdf7 429
9769034f
CB
430 rootfsdir = aufs_get_rootfs(rootfs->path, &rootfslen);
431 if (!rootfsdir)
432 goto err;
433 }
1d52bdf7 434
9769034f
CB
435 /*
436 * We neither allow users to create upperdirs and workdirs outside the
437 * containerdir nor inside the rootfs. The latter might be debatable.
438 * When we have a container without a rootfs we skip the checks.
439 */
440 ret = 0;
441 if (!rootfs_path)
442 ret = mkdir_p(upperdir, 0755);
443 else if ((strncmp(upperdir, lxcpath, strlen(lxcpath)) == 0) && (strncmp(upperdir, rootfsdir, rootfslen) != 0))
444 ret = mkdir_p(upperdir, 0755);
445 if (ret < 0)
446 WARN("Failed to create upperdir");
1d52bdf7
CB
447
448 fret = 0;
449
450err:
451 free(rootfsdir);
452 lxc_free_array((void **)opts, free);
453 return fret;
454}
455