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