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