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