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