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