]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/lxc_clone.c
ovl_rsync: make sure to umount
[mirror_lxc.git] / src / lxc / lxc_clone.c
CommitLineData
20ab58c7
SH
1/*
2 *
3 * Copyright © 2013 Serge Hallyn <serge.hallyn@ubuntu.com>.
4 * Copyright © 2013 Canonical Ltd.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2, as
8 * published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
9be53773
SH
20#include <unistd.h>
21#include <getopt.h>
22#include <signal.h>
23#include <stdio.h>
24#include <sys/types.h>
d659597e 25#include <stdint.h>
9be53773
SH
26#include <sys/wait.h>
27#include <stdlib.h>
28#include <errno.h>
ae13ae08 29#include <ctype.h>
9be53773 30
f2363e38
ÇO
31#include <lxc/lxccontainer.h>
32
9be53773 33#include "log.h"
965ef7f4 34#include "config.h"
9be53773
SH
35#include "lxc.h"
36#include "conf.h"
37#include "state.h"
9be53773 38
6ea518f6 39lxc_log_define(lxc_clone_ui, lxc);
9be53773 40
965ef7f4
SH
41/* we pass fssize in bytes */
42static uint64_t get_fssize(char *s)
43{
44 uint64_t ret;
45 char *end;
9be53773 46
965ef7f4
SH
47 ret = strtoull(s, &end, 0);
48 if (end == s)
49 {
50 fprintf(stderr, "Invalid blockdev size '%s', using default size\n", s);
51 return 0;
52 }
53 while (isblank(*end))
54 end++;
55 if (*end == '\0')
56 ret *= 1024ULL * 1024ULL; // MB by default
57 else if (*end == 'b' || *end == 'B')
58 ret *= 1ULL;
59 else if (*end == 'k' || *end == 'K')
60 ret *= 1024ULL;
61 else if (*end == 'm' || *end == 'M')
62 ret *= 1024ULL * 1024ULL;
63 else if (*end == 'g' || *end == 'G')
64 ret *= 1024ULL * 1024ULL * 1024ULL;
65 else if (*end == 't' || *end == 'T')
66 ret *= 1024ULL * 1024ULL * 1024ULL * 1024ULL;
67 else
68 {
69 fprintf(stderr, "Invalid blockdev unit size '%c' in '%s', using default size\n", *end, s);
70 return 0;
71 }
72 return ret;
73}
74
75static void usage(const char *me)
76{
77 printf("Usage: %s [-s] [-B backingstore] [-L size[unit]] [-K] [-M] [-H]\n", me);
78 printf(" [-p lxcpath] [-P newlxcpath] orig new\n");
79 printf("\n");
80 printf(" -s: snapshot rather than copy\n");
81 printf(" -B: use specified new backingstore. Default is the same as\n");
82 printf(" the original. Options include aufs, btrfs, lvm, overlayfs, \n");
83 printf(" dir and loop\n");
84 printf(" -L: for blockdev-backed backingstore, use specified size * specified\n");
85 printf(" unit. Default size is the size of the source blockdev, default\n");
86 printf(" unit is MB\n");
87 printf(" -K: Keep name - do not change the container name\n");
88 printf(" -M: Keep macaddr - do not choose a random new mac address\n");
89 printf(" -p: use container orig from custom lxcpath\n");
90 printf(" -P: create container new in custom lxcpath\n");
91 printf(" -R: rename existing container\n");
92 exit(1);
93}
94
95static struct option options[] = {
9be53773
SH
96 { "snapshot", no_argument, 0, 's'},
97 { "backingstore", required_argument, 0, 'B'},
965ef7f4
SH
98 { "size", required_argument, 0, 'L'},
99 { "orig", required_argument, 0, 'o'},
100 { "new", required_argument, 0, 'n'},
101 { "vgname", required_argument, 0, 'v'},
102 { "rename", no_argument, 0, 'R'},
9be53773
SH
103 { "keepname", no_argument, 0, 'K'},
104 { "keepmac", no_argument, 0, 'M'},
965ef7f4
SH
105 { "lxcpath", required_argument, 0, 'p'},
106 { "newpath", required_argument, 0, 'P'},
107 { "fstype", required_argument, 0, 't'},
108 { "help", no_argument, 0, 'h'},
109 { 0, 0, 0, 0 },
9be53773
SH
110};
111
112int main(int argc, char *argv[])
113{
965ef7f4
SH
114 struct lxc_container *c1 = NULL, *c2 = NULL;
115 int snapshot = 0, keepname = 0, keepmac = 0, rename = 0;
116 int flags = 0, option_index;
117 uint64_t newsize = 0;
118 char *bdevtype = NULL, *lxcpath = NULL, *newpath = NULL, *fstype = NULL;
119 char *orig = NULL, *new = NULL, *vgname = NULL;
120 char **args = NULL;
121 int c;
122 bool ret;
9be53773 123
965ef7f4
SH
124 if (argc < 3)
125 usage(argv[0]);
126
127 while (1) {
128 c = getopt_long(argc, argv, "sB:L:o:n:v:KMHp:P:Rt:h", options, &option_index);
129 if (c == -1)
130 break;
131 switch (c) {
132 case 's': snapshot = 1; break;
133 case 'B': bdevtype = optarg; break;
134 case 'L': newsize = get_fssize(optarg); break;
135 case 'o': orig = optarg; break;
136 case 'n': new = optarg; break;
137 case 'v': vgname = optarg; break;
138 case 'K': keepname = 1; break;
139 case 'M': keepmac = 1; break;
140 case 'p': lxcpath = optarg; break;
141 case 'P': newpath = optarg; break;
142 case 'R': rename = 1; break;
143 case 't': fstype = optarg; break;
144 case 'h': usage(argv[0]);
145 default: break;
840d2afe 146 }
9be53773 147 }
965ef7f4
SH
148 if (optind < argc && !orig)
149 orig = argv[optind++];
150 if (optind < argc && !new)
151 new = argv[optind++];
152 if (optind < argc)
153 /* arguments for the clone hook */
154 args = &argv[optind];
155 if (!new || !orig) {
156 printf("Error: you must provide orig and new names\n");
157 usage(argv[0]);
9be53773
SH
158 }
159
965ef7f4
SH
160 if (snapshot) flags |= LXC_CLONE_SNAPSHOT;
161 if (keepname) flags |= LXC_CLONE_KEEPNAME;
162 if (keepmac) flags |= LXC_CLONE_KEEPMACADDR;
f5abd74d 163
965ef7f4
SH
164 // vgname and fstype could be supported by sending them through the
165 // bdevdata. However, they currently are not yet. I'm not convinced
166 // they are worthwhile.
167 if (vgname) {
168 printf("Error: vgname not supported\n");
169 usage(argv[0]);
9be53773 170 }
965ef7f4
SH
171 if (fstype) {
172 printf("Error: fstype not supported\n");
173 usage(argv[0]);
9be53773 174 }
ef44c2f6 175
965ef7f4
SH
176 c1 = lxc_container_new(orig, lxcpath);
177 if (!c1)
178 exit(EXIT_FAILURE);
840d2afe 179
965ef7f4
SH
180 if (!c1->may_control(c1)) {
181 fprintf(stderr, "Insufficent privileges to control %s\n", orig);
182 lxc_container_put(c1);
183 exit(EXIT_FAILURE);
840d2afe
CB
184 }
185
965ef7f4
SH
186 if (!c1->is_defined(c1)) {
187 fprintf(stderr, "Error: container %s is not defined\n", orig);
188 lxc_container_put(c1);
189 exit(EXIT_FAILURE);
840d2afe 190 }
965ef7f4
SH
191 if (rename) {
192 ret = c1->rename(c1, new);
193 if (!ret) {
194 fprintf(stderr,
195 "Error: Renaming container %s to %s failed\n",
196 c1->name, new);
197 lxc_container_put(c1);
198 exit(EXIT_FAILURE);
199 }
840d2afe 200 } else {
965ef7f4
SH
201 c2 = c1->clone(c1, new, newpath, flags, bdevtype, NULL, newsize,
202 args);
203 if (c2 == NULL) {
204 lxc_container_put(c1);
205 fprintf(stderr, "clone failed\n");
206 exit(EXIT_FAILURE);
207 }
208 printf("Created container %s as %s of %s\n", new,
209 snapshot ? "snapshot" : "copy", orig);
210 lxc_container_put(c2);
840d2afe 211 }
965ef7f4 212 lxc_container_put(c1);
840d2afe 213
965ef7f4 214 exit(EXIT_SUCCESS);
840d2afe 215}