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