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