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