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