]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/tools/lxc_copy.c
Merge pull request #1756 from brauner/2017-08-10/further_lxc_2.1_preparations
[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"
40#include "log.h"
41#include "confile.h"
42#include "arguments.h"
43#include "lxc.h"
44#include "conf.h"
45#include "state.h"
28d832c4 46#include "storage.h"
43cea62d 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'},
3b0dcf2c 85 { "backingstorage", required_argument, 0, 'B'},
43cea62d
CB
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;
73b910a3 172 struct lxc_log log;
43cea62d 173 int flags = 0;
534dfdeb 174 int ret = EXIT_FAILURE;
43cea62d
CB
175
176 if (lxc_arguments_parse(&my_args, argc, argv))
534dfdeb 177 exit(ret);
43cea62d
CB
178
179 if (!my_args.log_file)
180 my_args.log_file = "none";
181
73b910a3 182 log.name = my_args.name;
183 log.file = my_args.log_file;
4b73005c 184 log.level = my_args.log_priority;
73b910a3 185 log.prefix = my_args.progname;
186 log.quiet = my_args.quiet;
187 log.lxcpath = my_args.lxcpath[0];
188
189 if (lxc_log_init(&log))
534dfdeb 190 exit(ret);
43cea62d
CB
191 lxc_log_options_no_override();
192
193 if (geteuid()) {
37180208 194 if (access(my_args.lxcpath[0], O_RDONLY) < 0) {
c89f1f75
CB
195 if (!my_args.quiet)
196 fprintf(stderr, "You lack access to %s\n", my_args.lxcpath[0]);
534dfdeb 197 exit(ret);
43cea62d
CB
198 }
199 }
200
201 if (!my_args.newname && !(my_args.task == DESTROY)) {
c89f1f75
CB
202 if (!my_args.quiet)
203 printf("Error: You must provide a NEWNAME for the clone.\n");
534dfdeb 204 exit(ret);
43cea62d
CB
205 }
206
207 if (my_args.task == SNAP || my_args.task == DESTROY)
208 flags |= LXC_CLONE_SNAPSHOT;
209 if (my_args.keepname)
210 flags |= LXC_CLONE_KEEPNAME;
211 if (my_args.keepmac)
212 flags |= LXC_CLONE_KEEPMACADDR;
213
214 if (!my_args.newpath)
215 my_args.newpath = (char *)my_args.lxcpath[0];
216
217 c = lxc_container_new(my_args.name, my_args.lxcpath[0]);
218 if (!c)
534dfdeb 219 exit(ret);
43cea62d 220
50b737a3
WB
221 if (my_args.rcfile) {
222 c->clear_config(c);
223 if (!c->load_config(c, my_args.rcfile)) {
224 fprintf(stderr, "Failed to load rcfile\n");
225 goto out;
226 }
6118210e
WB
227 c->configfile = strdup(my_args.rcfile);
228 if (!c->configfile) {
229 fprintf(stderr, "Out of memory setting new config filename\n");
230 goto out;
231 }
50b737a3
WB
232 }
233
43cea62d 234 if (!c->may_control(c)) {
c89f1f75
CB
235 if (!my_args.quiet)
236 fprintf(stderr, "Insufficent privileges to control %s\n", c->name);
534dfdeb 237 goto out;
43cea62d
CB
238 }
239
240 if (!c->is_defined(c)) {
c89f1f75
CB
241 if (!my_args.quiet)
242 fprintf(stderr, "Error: container %s is not defined\n", c->name);
534dfdeb 243 goto out;
43cea62d
CB
244 }
245
246 ret = do_clone_task(c, my_args.task, flags, &argv[optind]);
247
534dfdeb 248out:
43cea62d
CB
249 lxc_container_put(c);
250
251 if (ret == 0)
252 exit(EXIT_SUCCESS);
253 exit(EXIT_FAILURE);
254}
255
256static struct mnts *add_mnt(struct mnts **mnts, unsigned int *num, enum mnttype type)
257{
258 struct mnts *m, *n;
259
260 n = realloc(*mnts, (*num + 1) * sizeof(struct mnts));
261 if (!n)
262 return NULL;
263
264 *mnts = n;
265 m = *mnts + *num;
266 (*num)++;
267
8130ebe8 268 *m = (struct mnts) {.mnt_type = type};
43cea62d
CB
269
270 return m;
271}
272
8130ebe8 273static int mk_rand_ovl_dirs(struct mnts *mnts, unsigned int num, struct lxc_arguments *arg)
43cea62d
CB
274{
275 char upperdir[MAXPATHLEN];
276 char workdir[MAXPATHLEN];
277 unsigned int i;
534dfdeb
CB
278 int ret;
279 struct mnts *m = NULL;
43cea62d 280
534dfdeb 281 for (i = 0, m = mnts; i < num; i++, m++) {
8130ebe8 282 if ((m->mnt_type == LXC_MNT_OVL) || (m->mnt_type == LXC_MNT_AUFS)) {
43cea62d 283 ret = snprintf(upperdir, MAXPATHLEN, "%s/%s/delta#XXXXXX",
8130ebe8 284 arg->newpath, arg->newname);
43cea62d 285 if (ret < 0 || ret >= MAXPATHLEN)
534dfdeb 286 return -1;
43cea62d 287 if (!mkdtemp(upperdir))
534dfdeb 288 return -1;
43cea62d
CB
289 m->upper = strdup(upperdir);
290 if (!m->upper)
534dfdeb 291 return -1;
43cea62d
CB
292 }
293
8130ebe8 294 if (m->mnt_type == LXC_MNT_OVL) {
43cea62d 295 ret = snprintf(workdir, MAXPATHLEN, "%s/%s/work#XXXXXX",
8130ebe8 296 arg->newpath, arg->newname);
43cea62d 297 if (ret < 0 || ret >= MAXPATHLEN)
534dfdeb 298 return -1;
43cea62d 299 if (!mkdtemp(workdir))
534dfdeb 300 return -1;
43cea62d
CB
301 m->workdir = strdup(workdir);
302 if (!m->workdir)
534dfdeb 303 return -1;
43cea62d
CB
304 }
305 }
306
307 return 0;
43cea62d
CB
308}
309
310static char *construct_path(char *path, bool as_prefix)
311{
312 char **components = NULL;
313 char *cleanpath = NULL;
314
315 components = lxc_normalize_path(path);
316 if (!components)
317 return NULL;
318
319 cleanpath = lxc_string_join("/", (const char **)components, as_prefix);
320 lxc_free_array((void **)components, free);
321
322 return cleanpath;
323}
324
325static char *set_mnt_entry(struct mnts *m)
326{
327 char *mntentry = NULL;
328 int ret = 0;
329 size_t len = 0;
330
8130ebe8 331 if (m->mnt_type == LXC_MNT_AUFS) {
43cea62d
CB
332 len = strlen(" aufs br==rw:=ro,xino=,create=dir") +
333 2 * strlen(m->src) + strlen(m->dest) + strlen(m->upper) +
334 strlen(m->workdir) + 1;
335
336 mntentry = malloc(len);
337 if (!mntentry)
338 goto err;
339
340 ret = snprintf(mntentry, len, "%s %s aufs br=%s=rw:%s=ro,xino=%s,create=dir",
341 m->src, m->dest, m->upper, m->src, m->workdir);
342 if (ret < 0 || (size_t)ret >= len)
343 goto err;
8130ebe8 344 } else if (m->mnt_type == LXC_MNT_OVL) {
43cea62d
CB
345 len = strlen(" overlay lowerdir=,upperdir=,workdir=,create=dir") +
346 2 * strlen(m->src) + strlen(m->dest) + strlen(m->upper) +
347 strlen(m->workdir) + 1;
348
349 mntentry = malloc(len);
350 if (!mntentry)
351 goto err;
352
353 ret = snprintf(mntentry, len, "%s %s overlay lowerdir=%s,upperdir=%s,workdir=%s,create=dir",
354 m->src, m->dest, m->src, m->upper, m->workdir);
355 if (ret < 0 || (size_t)ret >= len)
356 goto err;
8130ebe8 357 } else if (m->mnt_type == LXC_MNT_BIND) {
43cea62d
CB
358 len = strlen(" none bind,optional,, 0 0") +
359 strlen(is_dir(m->src) ? "create=dir" : "create=file") +
360 strlen(m->src) + strlen(m->dest) + strlen(m->options) + 1;
361
362 mntentry = malloc(len);
363 if (!mntentry)
364 goto err;
365
366 ret = snprintf(mntentry, len, "%s %s none bind,optional,%s,%s 0 0",
367 m->src, m->dest, m->options,
368 is_dir(m->src) ? "create=dir" : "create=file");
369 if (ret < 0 || (size_t)ret >= len)
370 goto err;
371 }
372
373 return mntentry;
374
375err:
43cea62d
CB
376 free(mntentry);
377 return NULL;
378}
379
380static int do_clone(struct lxc_container *c, char *newname, char *newpath,
381 int flags, char *bdevtype, uint64_t fssize, enum task task,
382 char **args)
383{
384 struct lxc_container *clone;
385
386 clone = c->clone(c, newname, newpath, flags, bdevtype, NULL, fssize,
387 args);
388 if (!clone) {
c89f1f75
CB
389 if (!my_args.quiet)
390 fprintf(stderr, "clone failed\n");
43cea62d
CB
391 return -1;
392 }
393
5a8929b1 394 INFO("Created %s as %s of %s\n", newname, task ? "snapshot" : "copy", c->name);
43cea62d
CB
395
396 lxc_container_put(clone);
397
398 return 0;
399}
400
401static int do_clone_ephemeral(struct lxc_container *c,
534dfdeb 402 struct lxc_arguments *arg, char **args, int flags)
43cea62d 403{
60a77c18
CB
404 char *bdev;
405 char *premount;
43cea62d
CB
406 char randname[MAXPATHLEN];
407 unsigned int i;
408 int ret = 0;
534dfdeb 409 bool bret = true, started = false;
43cea62d 410 struct lxc_container *clone;
43cea62d
CB
411 lxc_attach_options_t attach_options = LXC_ATTACH_OPTIONS_DEFAULT;
412 attach_options.env_policy = LXC_ATTACH_CLEAR_ENV;
413
8130ebe8
CB
414 if (!arg->newname) {
415 ret = snprintf(randname, MAXPATHLEN, "%s/%s_XXXXXX", arg->newpath, arg->name);
43cea62d
CB
416 if (ret < 0 || ret >= MAXPATHLEN)
417 return -1;
418 if (!mkdtemp(randname))
419 return -1;
534dfdeb
CB
420 if (chmod(randname, 0770) < 0) {
421 remove(randname);
b84e8c4b 422 return -1;
534dfdeb 423 }
8130ebe8 424 arg->newname = randname + strlen(arg->newpath) + 1;
43cea62d
CB
425 }
426
8130ebe8
CB
427 clone = c->clone(c, arg->newname, arg->newpath, flags,
428 arg->bdevtype, NULL, arg->fssize, args);
43cea62d 429 if (!clone)
dca0532e 430 return -1;
43cea62d 431
60a77c18
CB
432 if (arg->tmpfs) {
433 bdev = c->lxc_conf->rootfs.bdev_type;
434 if (bdev && strcmp(bdev, "dir")) {
435 fprintf(stderr, "Cannot currently use tmpfs with %s storage backend.\n", bdev);
436 goto destroy_and_put;
437 }
438
439 premount = mount_tmpfs(arg->name, arg->newname, arg->newpath, arg);
440 if (!premount)
441 goto destroy_and_put;
442
443 bret = clone->set_config_item(clone, "lxc.hook.pre-mount", premount);
444 free(premount);
445 if (!bret)
446 goto destroy_and_put;
447 }
448
8130ebe8 449 if (!arg->keepdata)
43cea62d 450 if (!clone->set_config_item(clone, "lxc.ephemeral", "1"))
534dfdeb 451 goto destroy_and_put;
43cea62d
CB
452
453 /* allocate and create random upper- and workdirs for overlay mounts */
8130ebe8 454 if (mk_rand_ovl_dirs(mnt_table, mnt_table_size, arg) < 0)
534dfdeb 455 goto destroy_and_put;
43cea62d
CB
456
457 /* allocate and set mount entries */
534dfdeb
CB
458 struct mnts *n = NULL;
459 for (i = 0, n = mnt_table; i < mnt_table_size; i++, n++) {
43cea62d 460 char *mntentry = NULL;
534dfdeb
CB
461 mntentry = set_mnt_entry(n);
462 if (!mntentry)
463 goto destroy_and_put;
464 bret = clone->set_config_item(clone, "lxc.mount.entry", mntentry);
465 free(mntentry);
466 if (!bret)
467 goto destroy_and_put;
43cea62d
CB
468 }
469
470 if (!clone->save_config(clone, NULL))
534dfdeb 471 goto destroy_and_put;
43cea62d 472
c89f1f75 473 if (!my_args.quiet)
5a8929b1 474 printf("Created %s as clone of %s\n", arg->newname, arg->name);
43cea62d 475
60a77c18
CB
476 if (arg->tmpfs && !my_args.quiet)
477 printf("Container is placed on tmpfs.\nRebooting will cause "
b44c42e8 478 "all changes made to it to be lost!\n");
60a77c18 479
8130ebe8 480 if (!arg->daemonize && arg->argc) {
43cea62d 481 clone->want_daemonize(clone, true);
8130ebe8
CB
482 arg->daemonize = 1;
483 } else if (!arg->daemonize) {
43cea62d
CB
484 clone->want_daemonize(clone, false);
485 }
486
534dfdeb
CB
487 started = clone->start(clone, 0, NULL);
488 if (!started)
489 goto destroy_and_put;
43cea62d 490
8130ebe8
CB
491 if (arg->daemonize && arg->argc) {
492 ret = clone->attach_run_wait(clone, &attach_options, arg->argv[0], (const char *const *)arg->argv);
43cea62d 493 if (ret < 0)
534dfdeb
CB
494 goto destroy_and_put;
495 clone->shutdown(clone, -1);
43cea62d
CB
496 }
497
534dfdeb 498 free_mnts();
43cea62d
CB
499 lxc_container_put(clone);
500 return 0;
501
534dfdeb
CB
502destroy_and_put:
503 if (started)
504 clone->shutdown(clone, -1);
505 if (!started || clone->lxc_conf->ephemeral != 1)
506 clone->destroy(clone);
507 free_mnts();
43cea62d
CB
508 lxc_container_put(clone);
509 return -1;
510}
511
512static int do_clone_rename(struct lxc_container *c, char *newname)
513{
514 if (!c->rename(c, newname)) {
515 ERROR("Error: Renaming container %s to %s failed\n", c->name, newname);
516 return -1;
517 }
518
519 INFO("Renamed container %s to %s\n", c->name, newname);
520
521 return 0;
522}
523
524static int do_clone_task(struct lxc_container *c, enum task task, int flags,
525 char **args)
526{
527 int ret = 0;
528
529 switch (task) {
530 case DESTROY:
531 ret = do_clone_ephemeral(c, &my_args, args, flags);
532 break;
533 case RENAME:
534 ret = do_clone_rename(c, my_args.newname);
535 break;
536 default:
537 ret = do_clone(c, my_args.newname, my_args.newpath, flags,
538 my_args.bdevtype, my_args.fssize, my_args.task,
539 args);
540 break;
541 }
542
543 return ret;
544}
545
534dfdeb 546static void free_mnts()
43cea62d
CB
547{
548 unsigned int i;
534dfdeb 549 struct mnts *n = NULL;
43cea62d 550
534dfdeb 551 for (i = 0, n = mnt_table; i < mnt_table_size; i++, n++) {
43cea62d
CB
552 free(n->src);
553 free(n->dest);
554 free(n->options);
555 free(n->upper);
556 free(n->workdir);
557 }
534dfdeb
CB
558 free(mnt_table);
559 mnt_table = NULL;
560 mnt_table_size = 0;
43cea62d
CB
561}
562
563/* we pass fssize in bytes */
564static uint64_t get_fssize(char *s)
565{
566 uint64_t ret;
567 char *end;
568
569 ret = strtoull(s, &end, 0);
570 if (end == s) {
c89f1f75
CB
571 if (!my_args.quiet)
572 fprintf(stderr, "Invalid blockdev size '%s', using default size\n", s);
43cea62d
CB
573 return 0;
574 }
575 while (isblank(*end))
576 end++;
577 if (*end == '\0') {
578 ret *= 1024ULL * 1024ULL; // MB by default
579 } else if (*end == 'b' || *end == 'B') {
580 ret *= 1ULL;
581 } else if (*end == 'k' || *end == 'K') {
582 ret *= 1024ULL;
583 } else if (*end == 'm' || *end == 'M') {
584 ret *= 1024ULL * 1024ULL;
585 } else if (*end == 'g' || *end == 'G') {
586 ret *= 1024ULL * 1024ULL * 1024ULL;
587 } else if (*end == 't' || *end == 'T') {
588 ret *= 1024ULL * 1024ULL * 1024ULL * 1024ULL;
589 } else {
c89f1f75
CB
590 if (!my_args.quiet)
591 fprintf(stderr, "Invalid blockdev unit size '%c' in '%s', " "using default size\n", *end, s);
43cea62d
CB
592 return 0;
593 }
594
595 return ret;
596}
597
598static int my_parser(struct lxc_arguments *args, int c, char *arg)
599{
600 char *subopts = NULL;
601 char *mntparameters = NULL;
602 switch (c) {
603 case 'N':
604 args->newname = arg;
605 break;
606 case 'p':
607 args->newpath = arg;
608 break;
609 case 'R':
610 args->task = RENAME;
611 break;
612 case 's':
613 args->task = SNAP;
614 break;
615 case 'F':
616 args->daemonize = 0;
617 break;
618 case 'd':
619 args->daemonize = 1;
620 break;
621 case 'e':
622 args->task = DESTROY;
623 break;
624 case 'm':
625 subopts = optarg;
626 if (parse_mntsubopts(subopts, keys, mntparameters) < 0)
627 return -1;
628 break;
629 case 'B':
adc9b249
CB
630 if (strcmp(arg, "overlay") == 0)
631 arg = "overlayfs";
43cea62d
CB
632 args->bdevtype = arg;
633 break;
60a77c18
CB
634 case 't':
635 args->tmpfs = true;
636 break;
43cea62d
CB
637 case 'L':
638 args->fssize = get_fssize(optarg);
639 break;
640 case 'D':
641 args->keepdata = 1;
642 break;
643 case 'K':
644 args->keepname = 1;
645 break;
646 case 'M':
647 args->keepmac = 1;
648 break;
649 }
650
651 return 0;
652}
653
654static int parse_aufs_mnt(char *mntstring, enum mnttype type)
655{
656 int len = 0;
657 const char *xinopath = "/dev/shm/aufs.xino";
658 char **mntarray = NULL;
659 struct mnts *m = NULL;
660
8130ebe8 661 m = add_mnt(&mnt_table, &mnt_table_size, type);
43cea62d
CB
662 if (!m)
663 goto err;
664
665 mntarray = lxc_string_split(mntstring, ':');
666 if (!mntarray)
667 goto err;
668
669 m->src = construct_path(mntarray[0], true);
670 if (!m->src)
671 goto err;
672
673 len = lxc_array_len((void **)mntarray);
674 if (len == 1) /* aufs=src */
675 m->dest = construct_path(mntarray[0], false);
676 else if (len == 2) /* aufs=src:dest */
677 m->dest = construct_path(mntarray[1], false);
678 else
679 INFO("Excess elements in mount specification");
680
681 if (!m->dest)
682 goto err;
683
684 m->workdir = strdup(xinopath);
685 if (!m->workdir)
686 goto err;
687
688 lxc_free_array((void **)mntarray, free);
689 return 0;
690
691err:
534dfdeb 692 free_mnts();
43cea62d
CB
693 lxc_free_array((void **)mntarray, free);
694 return -1;
695}
696
697static int parse_bind_mnt(char *mntstring, enum mnttype type)
698{
699 int len = 0;
700 char **mntarray = NULL;
701 struct mnts *m = NULL;
702
8130ebe8 703 m = add_mnt(&mnt_table, &mnt_table_size, type);
43cea62d
CB
704 if (!m)
705 goto err;
706
707 mntarray = lxc_string_split(mntstring, ':');
708 if (!mntarray)
709 goto err;
710
711 m->src = construct_path(mntarray[0], true);
712 if (!m->src)
713 goto err;
714
715 len = lxc_array_len((void **)mntarray);
716 if (len == 1) { /* bind=src */
717 m->dest = construct_path(mntarray[0], false);
718 } else if (len == 2) { /* bind=src:option or bind=src:dest */
719 if (strncmp(mntarray[1], "rw", strlen(mntarray[1])) == 0)
720 m->options = strdup("rw");
721
722 if (strncmp(mntarray[1], "ro", strlen(mntarray[1])) == 0)
723 m->options = strdup("ro");
724
725 if (m->options)
726 m->dest = construct_path(mntarray[0], false);
727 else
728 m->dest = construct_path(mntarray[1], false);
729 } else if (len == 3) { /* bind=src:dest:option */
730 m->dest = construct_path(mntarray[1], false);
731 m->options = strdup(mntarray[2]);
732 } else {
733 INFO("Excess elements in mount specification");
734 }
735
736 if (!m->dest)
737 goto err;
738
739 if (!m->options)
740 m->options = strdup("rw");
741
742 if (!m->options || (strncmp(m->options, "rw", strlen(m->options)) &&
743 strncmp(m->options, "ro", strlen(m->options))))
744 goto err;
745
746 lxc_free_array((void **)mntarray, free);
747 return 0;
748
749err:
534dfdeb 750 free_mnts();
43cea62d
CB
751 lxc_free_array((void **)mntarray, free);
752 return -1;
753}
754
755static int parse_mntsubopts(char *subopts, char *const *keys, char *mntparameters)
756{
757 while (*subopts != '\0') {
758 switch (getsubopt(&subopts, keys, &mntparameters)) {
759 case LXC_MNT_BIND:
760 if (parse_bind_mnt(mntparameters, LXC_MNT_BIND) < 0)
761 return -1;
762 break;
763 case LXC_MNT_OVL:
764 if (parse_ovl_mnt(mntparameters, LXC_MNT_OVL) < 0)
765 return -1;
766 break;
767 case LXC_MNT_AUFS:
768 if (parse_aufs_mnt(mntparameters, LXC_MNT_AUFS) < 0)
769 return -1;
770 break;
771 default:
772 break;
773 }
774 }
775 return 0;
776}
777
778static int parse_ovl_mnt(char *mntstring, enum mnttype type)
779{
780 int len = 0;
781 char **mntarray = NULL;
782 struct mnts *m;
783
8130ebe8 784 m = add_mnt(&mnt_table, &mnt_table_size, type);
43cea62d
CB
785 if (!m)
786 goto err;
787
788 mntarray = lxc_string_split(mntstring, ':');
789 if (!mntarray)
790 goto err;
791
792 m->src = construct_path(mntarray[0], true);
793 if (!m->src)
794 goto err;
795
796 len = lxc_array_len((void **)mntarray);
797 if (len == 1) /* overlay=src */
798 m->dest = construct_path(mntarray[0], false);
799 else if (len == 2) /* overlay=src:dest */
800 m->dest = construct_path(mntarray[1], false);
801 else
802 INFO("Excess elements in mount specification");
803
804 if (!m->dest)
805 goto err;
806
807 lxc_free_array((void **)mntarray, free);
808 return 0;
809
810err:
534dfdeb 811 free_mnts();
43cea62d
CB
812 lxc_free_array((void **)mntarray, free);
813 return -1;
814}
60a77c18
CB
815
816/* For ephemeral snapshots backed by overlay or aufs filesystems, this function
817 * mounts a fresh tmpfs over the containers directory if the user requests it.
818 * Because we mount a fresh tmpfs over the directory of the container the
819 * updated /etc/hostname file created during the clone residing in the upperdir
820 * (currently named "delta0" by default) will be hidden. Hence, if the user
821 * requests that the old name is not to be kept for the clone, we recreate this
822 * file on the tmpfs. This should be all that is required to restore the exact
823 * behaviour we would get with a normal clone.
824 */
825static char *mount_tmpfs(const char *oldname, const char *newname,
826 const char *path, struct lxc_arguments *arg)
827{
828 int ret, fd;
829 size_t len;
830 char *premount = NULL;
a8e279fd 831 FILE *fp;
60a77c18
CB
832
833 if (arg->tmpfs && arg->keepdata) {
834 fprintf(stderr, "%s\n", "A container can only be placed on a "
835 "tmpfs when storage backend is overlay "
836 "or aufs.");
837 goto err_free;
838 }
839
840 if (arg->tmpfs && !arg->bdevtype) {
841 arg->bdevtype = "overlayfs";
842 } else if (arg->tmpfs && arg->bdevtype && strcmp(arg->bdevtype, "overlayfs") && strcmp(arg->bdevtype, "aufs")) {
843 fprintf(stderr, "%s\n", "A container can only be placed on a "
844 "tmpfs when storage backend is overlay "
845 "or aufs.");
846 goto err_free;
847 }
848
849 len = strlen(path) + strlen(newname) + strlen("pre-start-XXXXXX") + /* //\0 */ 3;
850 premount = malloc(len);
851 if (!premount)
852 goto err_free;
853
854 ret = snprintf(premount, len, "%s/%s/pre-start-XXXXXX", path, newname);
855 if (ret < 0 || (size_t)ret >= len)
856 goto err_free;
857
a8e279fd 858 fd = mkstemp(premount);
60a77c18
CB
859 if (fd < 0)
860 goto err_free;
861
a8e279fd
CB
862 if (fcntl(fd, F_SETFD, FD_CLOEXEC)) {
863 SYSERROR("Failed to set close-on-exec on file descriptor.");
864 goto err_close;
865 }
866
60a77c18
CB
867 if (chmod(premount, 0755) < 0)
868 goto err_close;
869
a8e279fd
CB
870 fp = fdopen(fd, "r+");
871 if (!fp)
872 goto err_close;
873 fd = -1;
874
875 ret = fprintf(fp, "#! /bin/sh\n"
60a77c18
CB
876 "mount -n -t tmpfs -o mode=0755 none %s/%s\n",
877 path, newname);
878 if (ret < 0)
879 goto err_close;
880
881 if (!arg->keepname) {
a8e279fd 882 ret = fprintf(fp, "mkdir -p %s/%s/delta0/etc\n"
60a77c18
CB
883 "echo %s > %s/%s/delta0/etc/hostname\n",
884 path, newname, newname, path, newname);
885 if (ret < 0)
886 goto err_close;
887 }
888
b44c42e8 889 fclose(fp);
60a77c18
CB
890 return premount;
891
892err_close:
a8e279fd
CB
893 if (fd > 0)
894 close(fd);
895 else
896 fclose(fp);
60a77c18
CB
897err_free:
898 free(premount);
899 return NULL;
900}