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