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