]> git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/tools/lxc_create.c
tree-wide: remove aufs storage driver
[mirror_lxc.git] / src / lxc / tools / lxc_create.c
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
20 #include <ctype.h>
21 #include <fcntl.h>
22 #include <libgen.h>
23 #include <stdint.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <unistd.h>
27 #include <sys/types.h>
28
29 #include <lxc/lxccontainer.h>
30
31 #include "arguments.h"
32 #include "tool_utils.h"
33
34 static uint64_t get_fssize(char *s)
35 {
36 uint64_t ret;
37 char *end;
38
39 ret = strtoull(s, &end, 0);
40 if (end == s)
41 {
42 fprintf(stderr, "Invalid blockdev size '%s', using default size\n", s);
43 return 0;
44 }
45 while (isblank(*end))
46 end++;
47 if (*end == '\0')
48 ret *= 1024ULL * 1024ULL; /* MB by default */
49 else if (*end == 'b' || *end == 'B')
50 ret *= 1ULL;
51 else if (*end == 'k' || *end == 'K')
52 ret *= 1024ULL;
53 else if (*end == 'm' || *end == 'M')
54 ret *= 1024ULL * 1024ULL;
55 else if (*end == 'g' || *end == 'G')
56 ret *= 1024ULL * 1024ULL * 1024ULL;
57 else if (*end == 't' || *end == 'T')
58 ret *= 1024ULL * 1024ULL * 1024ULL * 1024ULL;
59 else
60 {
61 fprintf(stderr, "Invalid blockdev unit size '%c' in '%s', using default size\n", *end, s);
62 return 0;
63 }
64 return ret;
65 }
66
67 static int my_parser(struct lxc_arguments* args, int c, char* arg)
68 {
69 switch (c) {
70 case 'B': args->bdevtype = arg; break;
71 case 'f': args->configfile = arg; break;
72 case 't': args->template = arg; break;
73 case '0': args->lvname = arg; break;
74 case '1': args->vgname = arg; break;
75 case '2': args->thinpool = arg; break;
76 case '3': args->fstype = arg; break;
77 case '4': args->fssize = get_fssize(arg); break;
78 case '5': args->zfsroot = arg; break;
79 case '6': args->dir = arg; break;
80 case '7': args->rbdname = arg; break;
81 case '8': args->rbdpool = arg; break;
82 }
83 return 0;
84 }
85
86 static const struct option my_longopts[] = {
87 {"bdev", required_argument, 0, 'B'},
88 {"config", required_argument, 0, 'f'},
89 {"template", required_argument, 0, 't'},
90 {"lvname", required_argument, 0, '0'},
91 {"vgname", required_argument, 0, '1'},
92 {"thinpool", required_argument, 0, '2'},
93 {"fstype", required_argument, 0, '3'},
94 {"fssize", required_argument, 0, '4'},
95 {"zfsroot", required_argument, 0, '5'},
96 {"dir", required_argument, 0, '6'},
97 {"rbdname", required_argument, 0, '7'},
98 {"rbdpool", required_argument, 0, '8'},
99 LXC_COMMON_OPTIONS
100 };
101
102 static void create_helpfn(const struct lxc_arguments *args)
103 {
104 char *argv[3], *path;
105 pid_t pid;
106
107 if (!args->template)
108 return;
109
110 pid = fork();
111 if (pid) {
112 wait_for_pid(pid);
113 return;
114 }
115
116 path = get_template_path(args->template);
117
118 argv[0] = path;
119 argv[1] = "-h";
120 argv[2] = NULL;
121
122 execv(path, argv);
123 fprintf(stderr, "Error executing %s -h\n", path);
124 exit(EXIT_FAILURE);
125 }
126
127 static struct lxc_arguments my_args = {
128 .progname = "lxc-create",
129 .helpfn = create_helpfn,
130 .help = "\
131 --name=NAME --template=TEMPLATE [OPTION...]\n\
132 \n\
133 lxc-create creates a container\n\
134 \n\
135 Options :\n\
136 -n, --name=NAME NAME of the container\n\
137 -f, --config=CONFIG Initial configuration file\n\
138 -t, --template=TEMPLATE Template to use to setup container\n\
139 -B, --bdev=BDEV Backing store type to use\n\
140 --dir=DIR Place rootfs directory under DIR\n\
141 \n\
142 BDEV options for LVM (with -B/--bdev lvm):\n\
143 --lvname=LVNAME Use LVM lv name LVNAME\n\
144 (Default: container name)\n\
145 --vgname=VG Use LVM vg called VG\n\
146 (Default: lxc)\n\
147 --thinpool=TP Use LVM thin pool called TP\n\
148 (Default: lxc)\n\
149 \n\
150 BDEV options for Ceph RBD (with -B/--bdev rbd) :\n\
151 --rbdname=RBDNAME Use Ceph RBD name RBDNAME\n\
152 (Default: container name)\n\
153 --rbdpool=POOL Use Ceph RBD pool name POOL\n\
154 (Default: lxc)\n\
155 \n\
156 BDEV option for ZFS (with -B/--bdev zfs) :\n\
157 --zfsroot=PATH Create zfs under given zfsroot\n\
158 (Default: tank/lxc)\n\
159 \n\
160 BDEV options for LVM or Loop (with -B/--bdev lvm/loop) :\n\
161 --fstype=TYPE Create fstype TYPE\n\
162 (Default: ext4)\n\
163 --fssize=SIZE[U] Create filesystem of\n\
164 size SIZE * unit U (bBkKmMgGtT)\n\
165 (Default: 1G, default unit: M)\n",
166 .options = my_longopts,
167 .parser = my_parser,
168 .checker = NULL,
169 };
170
171 static bool validate_bdev_args(struct lxc_arguments *a)
172 {
173 if (strcmp(a->bdevtype, "best") != 0) {
174 if (a->fstype || a->fssize) {
175 if (strcmp(a->bdevtype, "lvm") != 0 &&
176 strcmp(a->bdevtype, "loop") != 0 &&
177 strcmp(a->bdevtype, "rbd") != 0) {
178 fprintf(stderr, "filesystem type and size are only valid with block devices\n");
179 return false;
180 }
181 }
182 if (strcmp(a->bdevtype, "lvm") != 0) {
183 if (a->lvname || a->vgname || a->thinpool) {
184 fprintf(stderr, "--lvname, --vgname and --thinpool are only valid with -B lvm\n");
185 return false;
186 }
187 }
188 if (strcmp(a->bdevtype, "rbd") != 0) {
189 if (a->rbdname || a->rbdpool) {
190 fprintf(stderr, "--rbdname and --rbdpool are only valid with -B rbd\n");
191 return false;
192 }
193 }
194 if (strcmp(a->bdevtype, "zfs") != 0) {
195 if (a->zfsroot) {
196 fprintf(stderr, "zfsroot is only valid with -B zfs\n");
197 return false;
198 }
199 }
200 }
201 return true;
202 }
203
204 static bool is_valid_storage_type(const char *type)
205 {
206 if (strcmp(type, "dir") == 0 ||
207 strcmp(type, "btrfs") == 0 ||
208 strcmp(type, "loop") == 0 ||
209 strcmp(type, "lvm") == 0 ||
210 strcmp(type, "nbd") == 0 ||
211 strcmp(type, "overlay") == 0 ||
212 strcmp(type, "overlayfs") == 0 ||
213 strcmp(type, "rbd") == 0 ||
214 strcmp(type, "zfs") == 0)
215 return true;
216
217 return false;
218 }
219
220 int main(int argc, char *argv[])
221 {
222 struct lxc_container *c;
223 struct bdev_specs spec;
224 struct lxc_log log;
225 int flags = 0;
226
227 if (lxc_arguments_parse(&my_args, argc, argv))
228 exit(EXIT_FAILURE);
229
230 if (!my_args.log_file)
231 my_args.log_file = "none";
232
233 log.name = my_args.name;
234 log.file = my_args.log_file;
235 log.level = my_args.log_priority;
236 log.prefix = my_args.progname;
237 log.quiet = my_args.quiet;
238 log.lxcpath = my_args.lxcpath[0];
239
240 if (lxc_log_init(&log))
241 exit(EXIT_FAILURE);
242
243 if (!my_args.template) {
244 fprintf(stderr, "A template must be specified.\n");
245 fprintf(stderr, "Use \"none\" if you really want a container without a rootfs.\n");
246 exit(EXIT_FAILURE);
247 }
248
249 if (strcmp(my_args.template, "none") == 0)
250 my_args.template = NULL;
251
252 memset(&spec, 0, sizeof(spec));
253 if (!my_args.bdevtype)
254 my_args.bdevtype = "_unset";
255
256 if (!validate_bdev_args(&my_args))
257 exit(EXIT_FAILURE);
258
259 if (strcmp(my_args.bdevtype, "none") == 0)
260 my_args.bdevtype = "dir";
261
262 /* Final check whether the user gave use a valid bdev type. */
263 if (strcmp(my_args.bdevtype, "best") &&
264 strcmp(my_args.bdevtype, "_unset") &&
265 !is_valid_storage_type(my_args.bdevtype)) {
266 fprintf(stderr, "%s is not a valid backing storage type.\n", my_args.bdevtype);
267 exit(EXIT_FAILURE);
268 }
269
270 if (geteuid()) {
271 if (mkdir_p(my_args.lxcpath[0], 0755)) {
272 exit(EXIT_FAILURE);
273 }
274 if (access(my_args.lxcpath[0], O_RDONLY) < 0) {
275 fprintf(stderr, "You lack access to %s\n", my_args.lxcpath[0]);
276 exit(EXIT_FAILURE);
277 }
278 if (strcmp(my_args.bdevtype, "dir") && strcmp(my_args.bdevtype, "_unset") &&
279 strcmp(my_args.bdevtype, "btrfs")) {
280 fprintf(stderr, "Unprivileged users cannot create %s containers.\n", my_args.bdevtype);
281 exit(EXIT_FAILURE);
282 }
283 }
284
285
286 c = lxc_container_new(my_args.name, my_args.lxcpath[0]);
287 if (!c) {
288 fprintf(stderr, "Failed to create lxc container.\n");
289 exit(EXIT_FAILURE);
290 }
291 if (c->is_defined(c)) {
292 lxc_container_put(c);
293 fprintf(stderr, "Container already exists\n");
294 exit(EXIT_FAILURE);
295 }
296 if (my_args.configfile)
297 c->load_config(c, my_args.configfile);
298 else
299 c->load_config(c, lxc_get_global_config_item("lxc.default_config"));
300
301 if (my_args.fstype)
302 spec.fstype = my_args.fstype;
303 if (my_args.fssize)
304 spec.fssize = my_args.fssize;
305
306 if ((strcmp(my_args.bdevtype, "zfs") == 0) || (strcmp(my_args.bdevtype, "best") == 0)) {
307 if (my_args.zfsroot)
308 spec.zfs.zfsroot = my_args.zfsroot;
309 }
310
311 if ((strcmp(my_args.bdevtype, "lvm") == 0) || (strcmp(my_args.bdevtype, "best") == 0)) {
312 if (my_args.lvname)
313 spec.lvm.lv = my_args.lvname;
314 if (my_args.vgname)
315 spec.lvm.vg = my_args.vgname;
316 if (my_args.thinpool)
317 spec.lvm.thinpool = my_args.thinpool;
318 }
319
320 if ((strcmp(my_args.bdevtype, "rbd") == 0) || (strcmp(my_args.bdevtype, "best") == 0)) {
321 if (my_args.rbdname)
322 spec.rbd.rbdname = my_args.rbdname;
323 if (my_args.rbdpool)
324 spec.rbd.rbdpool = my_args.rbdpool;
325 }
326
327 if (my_args.dir)
328 spec.dir = my_args.dir;
329
330 if (strcmp(my_args.bdevtype, "_unset") == 0)
331 my_args.bdevtype = NULL;
332
333 if (my_args.quiet)
334 flags = LXC_CREATE_QUIET;
335
336 if (!c->create(c, my_args.template, my_args.bdevtype, &spec, flags, &argv[optind])) {
337 fprintf(stderr, "Error creating container %s\n", c->name);
338 lxc_container_put(c);
339 exit(EXIT_FAILURE);
340 }
341
342 lxc_container_put(c);
343 exit(EXIT_SUCCESS);
344 }