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