]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/tools/lxc_copy.c
tools: make overlay valid backend
[mirror_lxc.git] / src / lxc / tools / lxc_copy.c
CommitLineData
43cea62d
CB
1/*
2 *
8130ebe8 3 * Copyright © 2015 Christian Brauner <christian.brauner@mailbox.org>.
43cea62d
CB
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2, as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18
19#define _GNU_SOURCE
9dbcd668
SG
20#include "config.h"
21
43cea62d
CB
22#include <unistd.h>
23#include <getopt.h>
24#include <signal.h>
25#include <stdio.h>
26#include <sys/types.h>
27#include <stdint.h>
28#include <sys/wait.h>
29#include <stdlib.h>
30#include <errno.h>
31#include <ctype.h>
32#include <sys/stat.h>
33#include <fcntl.h>
34#include <time.h>
35#include <stdbool.h>
36
37#include <lxc/lxccontainer.h>
38
39#include "attach.h"
d8e48992 40#include "bdev.h"
43cea62d
CB
41#include "log.h"
42#include "confile.h"
43#include "arguments.h"
44#include "lxc.h"
45#include "conf.h"
46#include "state.h"
47#include "utils.h"
43cea62d 48
9dbcd668
SG
49#ifndef HAVE_GETSUBOPT
50#include <../include/getsubopt.h>
51#endif
52
43cea62d
CB
53lxc_log_define(lxc_copy_ui, lxc);
54
55enum mnttype {
56 LXC_MNT_BIND,
57 LXC_MNT_AUFS,
58 LXC_MNT_OVL,
59};
60
61struct mnts {
8130ebe8 62 enum mnttype mnt_type;
43cea62d
CB
63 char *src;
64 char *dest;
65 char *options;
66 char *upper;
67 char *workdir;
68 char *lower;
69};
70
8130ebe8
CB
71static unsigned int mnt_table_size = 0;
72static struct mnts *mnt_table = NULL;
43cea62d
CB
73
74static int my_parser(struct lxc_arguments *args, int c, char *arg);
75
76static const struct option my_longopts[] = {
77 { "newname", required_argument, 0, 'N'},
78 { "newpath", required_argument, 0, 'p'},
79 { "rename", no_argument, 0, 'R'},
80 { "snapshot", no_argument, 0, 's'},
81 { "foreground", no_argument, 0, 'F'},
82 { "daemon", no_argument, 0, 'd'},
83 { "ephemeral", no_argument, 0, 'e'},
84 { "mount", required_argument, 0, 'm'},
85 { "backingstore", required_argument, 0, 'B'},
86 { "fssize", required_argument, 0, 'L'},
87 { "keepdata", no_argument, 0, 'D'},
88 { "keepname", no_argument, 0, 'K'},
89 { "keepmac", no_argument, 0, 'M'},
60a77c18 90 { "tmpfs", no_argument, 0, 't'},
43cea62d
CB
91 LXC_COMMON_OPTIONS
92};
93
94/* mount keys */
95static char *const keys[] = {
96 [LXC_MNT_BIND] = "bind",
97 [LXC_MNT_AUFS] = "aufs",
98 [LXC_MNT_OVL] = "overlay",
99 NULL
100};
101
102static struct lxc_arguments my_args = {
103 .progname = "lxc-copy",
2b47bac3 104 .help = "\n\
a372480c
CB
105--name=NAME [-P lxcpath] -N newname [-p newpath] [-B backingstorage] [-s] [-K] [-M] [-L size [unit]] -- hook options\n\
106--name=NAME [-P lxcpath] [-N newname] [-p newpath] [-B backingstorage] -e [-d] [-D] [-K] [-M] [-m {bind,aufs,overlay}=/src:/dest] -- hook options\n\
43cea62d
CB
107--name=NAME [-P lxcpath] -N newname -R\n\
108\n\
109lxc-copy clone a container\n\
110\n\
111Options :\n\
112 -n, --name=NAME NAME of the container\n\
113 -N, --newname=NEWNAME NEWNAME for the restored container\n\
114 -p, --newpath=NEWPATH NEWPATH for the container to be stored\n\
6f94152d
WB
115 -R, --rename rename container\n\
116 -s, --snapshot create snapshot instead of clone\n\
117 -F, --foreground start with current tty attached to /dev/console\n\
118 -d, --daemon daemonize the container (default)\n\
119 -e, --ephemeral start ephemeral container\n\
120 -m, --mount directory to mount into container, either \n\
121 {bind,aufs,overlay}=/src-path or {bind,aufs,overlay}=/src-path:/dst-path\n\
43cea62d 122 -B, --backingstorage=TYPE backingstorage type for the container\n\
6f94152d
WB
123 -t, --tmpfs place ephemeral container on a tmpfs\n\
124 (WARNING: On reboot all changes made to the container will be lost.)\n\
125 -L, --fssize size of the new block device for block device containers\n\
126 -D, --keedata pass together with -e start a persistent snapshot \n\
127 -K, --keepname keep the hostname of the original container\n\
128 -- hook options arguments passed to the hook program\n\
129 -M, --keepmac keep the MAC address of the original container\n\
130 --rcfile=FILE Load configuration file FILE\n",
43cea62d
CB
131 .options = my_longopts,
132 .parser = my_parser,
133 .task = CLONE,
134 .daemonize = 1,
c89f1f75 135 .quiet = false,
60a77c18 136 .tmpfs = false,
43cea62d
CB
137};
138
139static struct mnts *add_mnt(struct mnts **mnts, unsigned int *num,
140 enum mnttype type);
8130ebe8
CB
141static int mk_rand_ovl_dirs(struct mnts *mnts, unsigned int num,
142 struct lxc_arguments *arg);
43cea62d
CB
143static char *construct_path(char *path, bool as_prefix);
144static char *set_mnt_entry(struct mnts *m);
145static int do_clone(struct lxc_container *c, char *newname, char *newpath,
146 int flags, char *bdevtype, uint64_t fssize, enum task task,
147 char **args);
148static int do_clone_ephemeral(struct lxc_container *c,
8130ebe8 149 struct lxc_arguments *arg, char **args,
43cea62d
CB
150 int flags);
151static int do_clone_rename(struct lxc_container *c, char *newname);
152static int do_clone_task(struct lxc_container *c, enum task task, int flags,
153 char **args);
534dfdeb 154static void free_mnts(void);
43cea62d 155static uint64_t get_fssize(char *s);
60a77c18
CB
156
157/* Place an ephemeral container started with -e flag on a tmpfs. Restrictions
158 * are that you cannot request the data to be kept while placing the container
159 * on a tmpfs and that either overlay or aufs backing storage must be used.
160 */
161static char *mount_tmpfs(const char *oldname, const char *newname,
162 const char *path, struct lxc_arguments *arg);
43cea62d
CB
163static int parse_mntsubopts(char *subopts, char *const *keys,
164 char *mntparameters);
165static int parse_aufs_mnt(char *mntstring, enum mnttype type);
166static int parse_bind_mnt(char *mntstring, enum mnttype type);
167static int parse_ovl_mnt(char *mntstring, enum mnttype type);
168
169int main(int argc, char *argv[])
170{
171 struct lxc_container *c;
172 int flags = 0;
534dfdeb 173 int ret = EXIT_FAILURE;
43cea62d
CB
174
175 if (lxc_arguments_parse(&my_args, argc, argv))
534dfdeb 176 exit(ret);
43cea62d
CB
177
178 if (!my_args.log_file)
179 my_args.log_file = "none";
180
181 if (lxc_log_init(my_args.name, my_args.log_file, my_args.log_priority,
182 my_args.progname, my_args.quiet, my_args.lxcpath[0]))
534dfdeb 183 exit(ret);
43cea62d
CB
184 lxc_log_options_no_override();
185
186 if (geteuid()) {
187 if (access(my_args.lxcpath[0], O_RDWR) < 0) {
c89f1f75
CB
188 if (!my_args.quiet)
189 fprintf(stderr, "You lack access to %s\n", my_args.lxcpath[0]);
534dfdeb 190 exit(ret);
43cea62d
CB
191 }
192 }
193
194 if (!my_args.newname && !(my_args.task == DESTROY)) {
c89f1f75
CB
195 if (!my_args.quiet)
196 printf("Error: You must provide a NEWNAME for the clone.\n");
534dfdeb 197 exit(ret);
43cea62d
CB
198 }
199
200 if (my_args.task == SNAP || my_args.task == DESTROY)
201 flags |= LXC_CLONE_SNAPSHOT;
202 if (my_args.keepname)
203 flags |= LXC_CLONE_KEEPNAME;
204 if (my_args.keepmac)
205 flags |= LXC_CLONE_KEEPMACADDR;
206
207 if (!my_args.newpath)
208 my_args.newpath = (char *)my_args.lxcpath[0];
209
210 c = lxc_container_new(my_args.name, my_args.lxcpath[0]);
211 if (!c)
534dfdeb 212 exit(ret);
43cea62d 213
50b737a3
WB
214 if (my_args.rcfile) {
215 c->clear_config(c);
216 if (!c->load_config(c, my_args.rcfile)) {
217 fprintf(stderr, "Failed to load rcfile\n");
218 goto out;
219 }
6118210e
WB
220 c->configfile = strdup(my_args.rcfile);
221 if (!c->configfile) {
222 fprintf(stderr, "Out of memory setting new config filename\n");
223 goto out;
224 }
50b737a3
WB
225 }
226
43cea62d 227 if (!c->may_control(c)) {
c89f1f75
CB
228 if (!my_args.quiet)
229 fprintf(stderr, "Insufficent privileges to control %s\n", c->name);
534dfdeb 230 goto out;
43cea62d
CB
231 }
232
233 if (!c->is_defined(c)) {
c89f1f75
CB
234 if (!my_args.quiet)
235 fprintf(stderr, "Error: container %s is not defined\n", c->name);
534dfdeb 236 goto out;
43cea62d
CB
237 }
238
239 ret = do_clone_task(c, my_args.task, flags, &argv[optind]);
240
534dfdeb 241out:
43cea62d
CB
242 lxc_container_put(c);
243
244 if (ret == 0)
245 exit(EXIT_SUCCESS);
246 exit(EXIT_FAILURE);
247}
248
249static struct mnts *add_mnt(struct mnts **mnts, unsigned int *num, enum mnttype type)
250{
251 struct mnts *m, *n;
252
253 n = realloc(*mnts, (*num + 1) * sizeof(struct mnts));
254 if (!n)
255 return NULL;
256
257 *mnts = n;
258 m = *mnts + *num;
259 (*num)++;
260
8130ebe8 261 *m = (struct mnts) {.mnt_type = type};
43cea62d
CB
262
263 return m;
264}
265
8130ebe8 266static int mk_rand_ovl_dirs(struct mnts *mnts, unsigned int num, struct lxc_arguments *arg)
43cea62d
CB
267{
268 char upperdir[MAXPATHLEN];
269 char workdir[MAXPATHLEN];
270 unsigned int i;
534dfdeb
CB
271 int ret;
272 struct mnts *m = NULL;
43cea62d 273
534dfdeb 274 for (i = 0, m = mnts; i < num; i++, m++) {
8130ebe8 275 if ((m->mnt_type == LXC_MNT_OVL) || (m->mnt_type == LXC_MNT_AUFS)) {
43cea62d 276 ret = snprintf(upperdir, MAXPATHLEN, "%s/%s/delta#XXXXXX",
8130ebe8 277 arg->newpath, arg->newname);
43cea62d 278 if (ret < 0 || ret >= MAXPATHLEN)
534dfdeb 279 return -1;
43cea62d 280 if (!mkdtemp(upperdir))
534dfdeb 281 return -1;
43cea62d
CB
282 m->upper = strdup(upperdir);
283 if (!m->upper)
534dfdeb 284 return -1;
43cea62d
CB
285 }
286
8130ebe8 287 if (m->mnt_type == LXC_MNT_OVL) {
43cea62d 288 ret = snprintf(workdir, MAXPATHLEN, "%s/%s/work#XXXXXX",
8130ebe8 289 arg->newpath, arg->newname);
43cea62d 290 if (ret < 0 || ret >= MAXPATHLEN)
534dfdeb 291 return -1;
43cea62d 292 if (!mkdtemp(workdir))
534dfdeb 293 return -1;
43cea62d
CB
294 m->workdir = strdup(workdir);
295 if (!m->workdir)
534dfdeb 296 return -1;
43cea62d
CB
297 }
298 }
299
300 return 0;
43cea62d
CB
301}
302
303static char *construct_path(char *path, bool as_prefix)
304{
305 char **components = NULL;
306 char *cleanpath = NULL;
307
308 components = lxc_normalize_path(path);
309 if (!components)
310 return NULL;
311
312 cleanpath = lxc_string_join("/", (const char **)components, as_prefix);
313 lxc_free_array((void **)components, free);
314
315 return cleanpath;
316}
317
318static char *set_mnt_entry(struct mnts *m)
319{
320 char *mntentry = NULL;
321 int ret = 0;
322 size_t len = 0;
323
8130ebe8 324 if (m->mnt_type == LXC_MNT_AUFS) {
43cea62d
CB
325 len = strlen(" aufs br==rw:=ro,xino=,create=dir") +
326 2 * strlen(m->src) + strlen(m->dest) + strlen(m->upper) +
327 strlen(m->workdir) + 1;
328
329 mntentry = malloc(len);
330 if (!mntentry)
331 goto err;
332
333 ret = snprintf(mntentry, len, "%s %s aufs br=%s=rw:%s=ro,xino=%s,create=dir",
334 m->src, m->dest, m->upper, m->src, m->workdir);
335 if (ret < 0 || (size_t)ret >= len)
336 goto err;
8130ebe8 337 } else if (m->mnt_type == LXC_MNT_OVL) {
43cea62d
CB
338 len = strlen(" overlay lowerdir=,upperdir=,workdir=,create=dir") +
339 2 * strlen(m->src) + strlen(m->dest) + strlen(m->upper) +
340 strlen(m->workdir) + 1;
341
342 mntentry = malloc(len);
343 if (!mntentry)
344 goto err;
345
346 ret = snprintf(mntentry, len, "%s %s overlay lowerdir=%s,upperdir=%s,workdir=%s,create=dir",
347 m->src, m->dest, m->src, m->upper, m->workdir);
348 if (ret < 0 || (size_t)ret >= len)
349 goto err;
8130ebe8 350 } else if (m->mnt_type == LXC_MNT_BIND) {
43cea62d
CB
351 len = strlen(" none bind,optional,, 0 0") +
352 strlen(is_dir(m->src) ? "create=dir" : "create=file") +
353 strlen(m->src) + strlen(m->dest) + strlen(m->options) + 1;
354
355 mntentry = malloc(len);
356 if (!mntentry)
357 goto err;
358
359 ret = snprintf(mntentry, len, "%s %s none bind,optional,%s,%s 0 0",
360 m->src, m->dest, m->options,
361 is_dir(m->src) ? "create=dir" : "create=file");
362 if (ret < 0 || (size_t)ret >= len)
363 goto err;
364 }
365
366 return mntentry;
367
368err:
43cea62d
CB
369 free(mntentry);
370 return NULL;
371}
372
373static int do_clone(struct lxc_container *c, char *newname, char *newpath,
374 int flags, char *bdevtype, uint64_t fssize, enum task task,
375 char **args)
376{
377 struct lxc_container *clone;
378
379 clone = c->clone(c, newname, newpath, flags, bdevtype, NULL, fssize,
380 args);
381 if (!clone) {
c89f1f75
CB
382 if (!my_args.quiet)
383 fprintf(stderr, "clone failed\n");
43cea62d
CB
384 return -1;
385 }
386
5a8929b1 387 INFO("Created %s as %s of %s\n", newname, task ? "snapshot" : "copy", c->name);
43cea62d
CB
388
389 lxc_container_put(clone);
390
391 return 0;
392}
393
394static int do_clone_ephemeral(struct lxc_container *c,
534dfdeb 395 struct lxc_arguments *arg, char **args, int flags)
43cea62d 396{
60a77c18
CB
397 char *bdev;
398 char *premount;
43cea62d
CB
399 char randname[MAXPATHLEN];
400 unsigned int i;
401 int ret = 0;
534dfdeb 402 bool bret = true, started = false;
43cea62d 403 struct lxc_container *clone;
43cea62d
CB
404 lxc_attach_options_t attach_options = LXC_ATTACH_OPTIONS_DEFAULT;
405 attach_options.env_policy = LXC_ATTACH_CLEAR_ENV;
406
8130ebe8
CB
407 if (!arg->newname) {
408 ret = snprintf(randname, MAXPATHLEN, "%s/%s_XXXXXX", arg->newpath, arg->name);
43cea62d
CB
409 if (ret < 0 || ret >= MAXPATHLEN)
410 return -1;
411 if (!mkdtemp(randname))
412 return -1;
534dfdeb
CB
413 if (chmod(randname, 0770) < 0) {
414 remove(randname);
b84e8c4b 415 return -1;
534dfdeb 416 }
8130ebe8 417 arg->newname = randname + strlen(arg->newpath) + 1;
43cea62d
CB
418 }
419
8130ebe8
CB
420 clone = c->clone(c, arg->newname, arg->newpath, flags,
421 arg->bdevtype, NULL, arg->fssize, args);
43cea62d 422 if (!clone)
dca0532e 423 return -1;
43cea62d 424
60a77c18
CB
425 if (arg->tmpfs) {
426 bdev = c->lxc_conf->rootfs.bdev_type;
427 if (bdev && strcmp(bdev, "dir")) {
428 fprintf(stderr, "Cannot currently use tmpfs with %s storage backend.\n", bdev);
429 goto destroy_and_put;
430 }
431
432 premount = mount_tmpfs(arg->name, arg->newname, arg->newpath, arg);
433 if (!premount)
434 goto destroy_and_put;
435
436 bret = clone->set_config_item(clone, "lxc.hook.pre-mount", premount);
437 free(premount);
438 if (!bret)
439 goto destroy_and_put;
440 }
441
8130ebe8 442 if (!arg->keepdata)
43cea62d 443 if (!clone->set_config_item(clone, "lxc.ephemeral", "1"))
534dfdeb 444 goto destroy_and_put;
43cea62d
CB
445
446 /* allocate and create random upper- and workdirs for overlay mounts */
8130ebe8 447 if (mk_rand_ovl_dirs(mnt_table, mnt_table_size, arg) < 0)
534dfdeb 448 goto destroy_and_put;
43cea62d
CB
449
450 /* allocate and set mount entries */
534dfdeb
CB
451 struct mnts *n = NULL;
452 for (i = 0, n = mnt_table; i < mnt_table_size; i++, n++) {
43cea62d 453 char *mntentry = NULL;
534dfdeb
CB
454 mntentry = set_mnt_entry(n);
455 if (!mntentry)
456 goto destroy_and_put;
457 bret = clone->set_config_item(clone, "lxc.mount.entry", mntentry);
458 free(mntentry);
459 if (!bret)
460 goto destroy_and_put;
43cea62d
CB
461 }
462
463 if (!clone->save_config(clone, NULL))
534dfdeb 464 goto destroy_and_put;
43cea62d 465
c89f1f75 466 if (!my_args.quiet)
5a8929b1 467 printf("Created %s as clone of %s\n", arg->newname, arg->name);
43cea62d 468
60a77c18
CB
469 if (arg->tmpfs && !my_args.quiet)
470 printf("Container is placed on tmpfs.\nRebooting will cause "
b44c42e8 471 "all changes made to it to be lost!\n");
60a77c18 472
8130ebe8 473 if (!arg->daemonize && arg->argc) {
43cea62d 474 clone->want_daemonize(clone, true);
8130ebe8
CB
475 arg->daemonize = 1;
476 } else if (!arg->daemonize) {
43cea62d
CB
477 clone->want_daemonize(clone, false);
478 }
479
534dfdeb
CB
480 started = clone->start(clone, 0, NULL);
481 if (!started)
482 goto destroy_and_put;
43cea62d 483
8130ebe8
CB
484 if (arg->daemonize && arg->argc) {
485 ret = clone->attach_run_wait(clone, &attach_options, arg->argv[0], (const char *const *)arg->argv);
43cea62d 486 if (ret < 0)
534dfdeb
CB
487 goto destroy_and_put;
488 clone->shutdown(clone, -1);
43cea62d
CB
489 }
490
534dfdeb 491 free_mnts();
43cea62d
CB
492 lxc_container_put(clone);
493 return 0;
494
534dfdeb
CB
495destroy_and_put:
496 if (started)
497 clone->shutdown(clone, -1);
498 if (!started || clone->lxc_conf->ephemeral != 1)
499 clone->destroy(clone);
500 free_mnts();
43cea62d
CB
501 lxc_container_put(clone);
502 return -1;
503}
504
505static int do_clone_rename(struct lxc_container *c, char *newname)
506{
507 if (!c->rename(c, newname)) {
508 ERROR("Error: Renaming container %s to %s failed\n", c->name, newname);
509 return -1;
510 }
511
512 INFO("Renamed container %s to %s\n", c->name, newname);
513
514 return 0;
515}
516
517static int do_clone_task(struct lxc_container *c, enum task task, int flags,
518 char **args)
519{
520 int ret = 0;
521
522 switch (task) {
523 case DESTROY:
524 ret = do_clone_ephemeral(c, &my_args, args, flags);
525 break;
526 case RENAME:
527 ret = do_clone_rename(c, my_args.newname);
528 break;
529 default:
530 ret = do_clone(c, my_args.newname, my_args.newpath, flags,
531 my_args.bdevtype, my_args.fssize, my_args.task,
532 args);
533 break;
534 }
535
536 return ret;
537}
538
534dfdeb 539static void free_mnts()
43cea62d
CB
540{
541 unsigned int i;
534dfdeb 542 struct mnts *n = NULL;
43cea62d 543
534dfdeb 544 for (i = 0, n = mnt_table; i < mnt_table_size; i++, n++) {
43cea62d
CB
545 free(n->src);
546 free(n->dest);
547 free(n->options);
548 free(n->upper);
549 free(n->workdir);
550 }
534dfdeb
CB
551 free(mnt_table);
552 mnt_table = NULL;
553 mnt_table_size = 0;
43cea62d
CB
554}
555
556/* we pass fssize in bytes */
557static uint64_t get_fssize(char *s)
558{
559 uint64_t ret;
560 char *end;
561
562 ret = strtoull(s, &end, 0);
563 if (end == s) {
c89f1f75
CB
564 if (!my_args.quiet)
565 fprintf(stderr, "Invalid blockdev size '%s', using default size\n", s);
43cea62d
CB
566 return 0;
567 }
568 while (isblank(*end))
569 end++;
570 if (*end == '\0') {
571 ret *= 1024ULL * 1024ULL; // MB by default
572 } else if (*end == 'b' || *end == 'B') {
573 ret *= 1ULL;
574 } else if (*end == 'k' || *end == 'K') {
575 ret *= 1024ULL;
576 } else if (*end == 'm' || *end == 'M') {
577 ret *= 1024ULL * 1024ULL;
578 } else if (*end == 'g' || *end == 'G') {
579 ret *= 1024ULL * 1024ULL * 1024ULL;
580 } else if (*end == 't' || *end == 'T') {
581 ret *= 1024ULL * 1024ULL * 1024ULL * 1024ULL;
582 } else {
c89f1f75
CB
583 if (!my_args.quiet)
584 fprintf(stderr, "Invalid blockdev unit size '%c' in '%s', " "using default size\n", *end, s);
43cea62d
CB
585 return 0;
586 }
587
588 return ret;
589}
590
591static int my_parser(struct lxc_arguments *args, int c, char *arg)
592{
593 char *subopts = NULL;
594 char *mntparameters = NULL;
595 switch (c) {
596 case 'N':
597 args->newname = arg;
598 break;
599 case 'p':
600 args->newpath = arg;
601 break;
602 case 'R':
603 args->task = RENAME;
604 break;
605 case 's':
606 args->task = SNAP;
607 break;
608 case 'F':
609 args->daemonize = 0;
610 break;
611 case 'd':
612 args->daemonize = 1;
613 break;
614 case 'e':
615 args->task = DESTROY;
616 break;
617 case 'm':
618 subopts = optarg;
619 if (parse_mntsubopts(subopts, keys, mntparameters) < 0)
620 return -1;
621 break;
622 case 'B':
adc9b249
CB
623 if (strcmp(arg, "overlay") == 0)
624 arg = "overlayfs";
43cea62d
CB
625 args->bdevtype = arg;
626 break;
60a77c18
CB
627 case 't':
628 args->tmpfs = true;
629 break;
43cea62d
CB
630 case 'L':
631 args->fssize = get_fssize(optarg);
632 break;
633 case 'D':
634 args->keepdata = 1;
635 break;
636 case 'K':
637 args->keepname = 1;
638 break;
639 case 'M':
640 args->keepmac = 1;
641 break;
642 }
643
644 return 0;
645}
646
647static int parse_aufs_mnt(char *mntstring, enum mnttype type)
648{
649 int len = 0;
650 const char *xinopath = "/dev/shm/aufs.xino";
651 char **mntarray = NULL;
652 struct mnts *m = NULL;
653
8130ebe8 654 m = add_mnt(&mnt_table, &mnt_table_size, type);
43cea62d
CB
655 if (!m)
656 goto err;
657
658 mntarray = lxc_string_split(mntstring, ':');
659 if (!mntarray)
660 goto err;
661
662 m->src = construct_path(mntarray[0], true);
663 if (!m->src)
664 goto err;
665
666 len = lxc_array_len((void **)mntarray);
667 if (len == 1) /* aufs=src */
668 m->dest = construct_path(mntarray[0], false);
669 else if (len == 2) /* aufs=src:dest */
670 m->dest = construct_path(mntarray[1], false);
671 else
672 INFO("Excess elements in mount specification");
673
674 if (!m->dest)
675 goto err;
676
677 m->workdir = strdup(xinopath);
678 if (!m->workdir)
679 goto err;
680
681 lxc_free_array((void **)mntarray, free);
682 return 0;
683
684err:
534dfdeb 685 free_mnts();
43cea62d
CB
686 lxc_free_array((void **)mntarray, free);
687 return -1;
688}
689
690static int parse_bind_mnt(char *mntstring, enum mnttype type)
691{
692 int len = 0;
693 char **mntarray = NULL;
694 struct mnts *m = NULL;
695
8130ebe8 696 m = add_mnt(&mnt_table, &mnt_table_size, type);
43cea62d
CB
697 if (!m)
698 goto err;
699
700 mntarray = lxc_string_split(mntstring, ':');
701 if (!mntarray)
702 goto err;
703
704 m->src = construct_path(mntarray[0], true);
705 if (!m->src)
706 goto err;
707
708 len = lxc_array_len((void **)mntarray);
709 if (len == 1) { /* bind=src */
710 m->dest = construct_path(mntarray[0], false);
711 } else if (len == 2) { /* bind=src:option or bind=src:dest */
712 if (strncmp(mntarray[1], "rw", strlen(mntarray[1])) == 0)
713 m->options = strdup("rw");
714
715 if (strncmp(mntarray[1], "ro", strlen(mntarray[1])) == 0)
716 m->options = strdup("ro");
717
718 if (m->options)
719 m->dest = construct_path(mntarray[0], false);
720 else
721 m->dest = construct_path(mntarray[1], false);
722 } else if (len == 3) { /* bind=src:dest:option */
723 m->dest = construct_path(mntarray[1], false);
724 m->options = strdup(mntarray[2]);
725 } else {
726 INFO("Excess elements in mount specification");
727 }
728
729 if (!m->dest)
730 goto err;
731
732 if (!m->options)
733 m->options = strdup("rw");
734
735 if (!m->options || (strncmp(m->options, "rw", strlen(m->options)) &&
736 strncmp(m->options, "ro", strlen(m->options))))
737 goto err;
738
739 lxc_free_array((void **)mntarray, free);
740 return 0;
741
742err:
534dfdeb 743 free_mnts();
43cea62d
CB
744 lxc_free_array((void **)mntarray, free);
745 return -1;
746}
747
748static int parse_mntsubopts(char *subopts, char *const *keys, char *mntparameters)
749{
750 while (*subopts != '\0') {
751 switch (getsubopt(&subopts, keys, &mntparameters)) {
752 case LXC_MNT_BIND:
753 if (parse_bind_mnt(mntparameters, LXC_MNT_BIND) < 0)
754 return -1;
755 break;
756 case LXC_MNT_OVL:
757 if (parse_ovl_mnt(mntparameters, LXC_MNT_OVL) < 0)
758 return -1;
759 break;
760 case LXC_MNT_AUFS:
761 if (parse_aufs_mnt(mntparameters, LXC_MNT_AUFS) < 0)
762 return -1;
763 break;
764 default:
765 break;
766 }
767 }
768 return 0;
769}
770
771static int parse_ovl_mnt(char *mntstring, enum mnttype type)
772{
773 int len = 0;
774 char **mntarray = NULL;
775 struct mnts *m;
776
8130ebe8 777 m = add_mnt(&mnt_table, &mnt_table_size, type);
43cea62d
CB
778 if (!m)
779 goto err;
780
781 mntarray = lxc_string_split(mntstring, ':');
782 if (!mntarray)
783 goto err;
784
785 m->src = construct_path(mntarray[0], true);
786 if (!m->src)
787 goto err;
788
789 len = lxc_array_len((void **)mntarray);
790 if (len == 1) /* overlay=src */
791 m->dest = construct_path(mntarray[0], false);
792 else if (len == 2) /* overlay=src:dest */
793 m->dest = construct_path(mntarray[1], false);
794 else
795 INFO("Excess elements in mount specification");
796
797 if (!m->dest)
798 goto err;
799
800 lxc_free_array((void **)mntarray, free);
801 return 0;
802
803err:
534dfdeb 804 free_mnts();
43cea62d
CB
805 lxc_free_array((void **)mntarray, free);
806 return -1;
807}
60a77c18
CB
808
809/* For ephemeral snapshots backed by overlay or aufs filesystems, this function
810 * mounts a fresh tmpfs over the containers directory if the user requests it.
811 * Because we mount a fresh tmpfs over the directory of the container the
812 * updated /etc/hostname file created during the clone residing in the upperdir
813 * (currently named "delta0" by default) will be hidden. Hence, if the user
814 * requests that the old name is not to be kept for the clone, we recreate this
815 * file on the tmpfs. This should be all that is required to restore the exact
816 * behaviour we would get with a normal clone.
817 */
818static char *mount_tmpfs(const char *oldname, const char *newname,
819 const char *path, struct lxc_arguments *arg)
820{
821 int ret, fd;
822 size_t len;
823 char *premount = NULL;
a8e279fd 824 FILE *fp;
60a77c18
CB
825
826 if (arg->tmpfs && arg->keepdata) {
827 fprintf(stderr, "%s\n", "A container can only be placed on a "
828 "tmpfs when storage backend is overlay "
829 "or aufs.");
830 goto err_free;
831 }
832
833 if (arg->tmpfs && !arg->bdevtype) {
834 arg->bdevtype = "overlayfs";
835 } else if (arg->tmpfs && arg->bdevtype && strcmp(arg->bdevtype, "overlayfs") && strcmp(arg->bdevtype, "aufs")) {
836 fprintf(stderr, "%s\n", "A container can only be placed on a "
837 "tmpfs when storage backend is overlay "
838 "or aufs.");
839 goto err_free;
840 }
841
842 len = strlen(path) + strlen(newname) + strlen("pre-start-XXXXXX") + /* //\0 */ 3;
843 premount = malloc(len);
844 if (!premount)
845 goto err_free;
846
847 ret = snprintf(premount, len, "%s/%s/pre-start-XXXXXX", path, newname);
848 if (ret < 0 || (size_t)ret >= len)
849 goto err_free;
850
a8e279fd 851 fd = mkstemp(premount);
60a77c18
CB
852 if (fd < 0)
853 goto err_free;
854
a8e279fd
CB
855 if (fcntl(fd, F_SETFD, FD_CLOEXEC)) {
856 SYSERROR("Failed to set close-on-exec on file descriptor.");
857 goto err_close;
858 }
859
60a77c18
CB
860 if (chmod(premount, 0755) < 0)
861 goto err_close;
862
a8e279fd
CB
863 fp = fdopen(fd, "r+");
864 if (!fp)
865 goto err_close;
866 fd = -1;
867
868 ret = fprintf(fp, "#! /bin/sh\n"
60a77c18
CB
869 "mount -n -t tmpfs -o mode=0755 none %s/%s\n",
870 path, newname);
871 if (ret < 0)
872 goto err_close;
873
874 if (!arg->keepname) {
a8e279fd 875 ret = fprintf(fp, "mkdir -p %s/%s/delta0/etc\n"
60a77c18
CB
876 "echo %s > %s/%s/delta0/etc/hostname\n",
877 path, newname, newname, path, newname);
878 if (ret < 0)
879 goto err_close;
880 }
881
b44c42e8 882 fclose(fp);
60a77c18
CB
883 return premount;
884
885err_close:
a8e279fd
CB
886 if (fd > 0)
887 close(fd);
888 else
889 fclose(fp);
60a77c18
CB
890err_free:
891 free(premount);
892 return NULL;
893}