]> git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/lxc_create.c
ovl_rsync: make sure to umount
[mirror_lxc.git] / src / lxc / 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 <lxc/lxccontainer.h>
21
22 #include <stdio.h>
23 #include <libgen.h>
24 #include <unistd.h>
25 #include <ctype.h>
26 #include <fcntl.h>
27 #include <sys/types.h>
28 #include <stdint.h>
29
30 #include "lxc.h"
31 #include "log.h"
32 #include "bdev.h"
33 #include "arguments.h"
34 #include "utils.h"
35
36 lxc_log_define(lxc_create_ui, lxc);
37
38 static uint64_t get_fssize(char *s)
39 {
40 uint64_t ret;
41 char *end;
42
43 ret = strtoull(s, &end, 0);
44 if (end == s)
45 {
46 fprintf(stderr, "Invalid blockdev size '%s', using default size\n", s);
47 return 0;
48 }
49 while (isblank(*end))
50 end++;
51 if (*end == '\0')
52 ret *= 1024ULL * 1024ULL; // MB by default
53 else if (*end == 'b' || *end == 'B')
54 ret *= 1ULL;
55 else if (*end == 'k' || *end == 'K')
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
64 {
65 fprintf(stderr, "Invalid blockdev unit size '%c' in '%s', using default size\n", *end, s);
66 return 0;
67 }
68 return ret;
69 }
70
71 static 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;
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;
84 }
85 return 0;
86 }
87
88 static const struct option my_longopts[] = {
89 {"bdev", required_argument, 0, 'B'},
90 {"config", required_argument, 0, 'f'},
91 {"template", required_argument, 0, 't'},
92 {"lvname", required_argument, 0, '0'},
93 {"vgname", required_argument, 0, '1'},
94 {"thinpool", required_argument, 0, '2'},
95 {"fstype", required_argument, 0, '3'},
96 {"fssize", required_argument, 0, '4'},
97 {"zfsroot", required_argument, 0, '5'},
98 {"dir", required_argument, 0, '6'},
99 LXC_COMMON_OPTIONS
100 };
101
102 static void create_helpfn(const struct lxc_arguments *args) {
103 char *argv[3], *path;
104 pid_t pid;
105
106 if (!args->template)
107 return;
108
109 pid = fork();
110 if (pid) {
111 wait_for_pid(pid);
112 return;
113 }
114
115 path = get_template_path(args->template);
116
117 argv[0] = path;
118 argv[1] = "-h";
119 argv[2] = NULL;
120 execv(path, argv);
121 ERROR("Error executing %s -h", path);
122 exit(1);
123 }
124
125 static struct lxc_arguments my_args = {
126 .progname = "lxc-create",
127 .helpfn = create_helpfn,
128 .help = "\
129 --name=NAME -t template [-w] [-r] [-P lxcpath]\n\
130 \n\
131 lxc-create creates a container\n\
132 \n\
133 Options :\n\
134 -n, --name=NAME NAME of the container\n\
135 -f, --config=file Initial configuration file\n\
136 -t, --template=t Template to use to setup container\n\
137 -B, --bdev=BDEV Backing store type to use\n\
138 -P, --lxcpath=PATH Place container under PATH\n\
139 --lvname=LVNAME Use LVM lv name LVNAME\n\
140 (Default: container name)\n\
141 --vgname=VG Use LVM vg called VG\n\
142 (Default: lxc)\n\
143 --thinpool=TP Use LVM thin pool called TP\n\
144 (Default: lxc)\n\
145 --fstype=TYPE Create fstype TYPE\n\
146 (Default: ext3)\n\
147 --fssize=SIZE[U] Create filesystem of size SIZE * unit U (bBkKmMgGtT)\n\
148 (Default: 1G, default unit: M)\n\
149 --dir=DIR Place rootfs directory under DIR\n\
150 --zfsroot=PATH Create zfs under given zfsroot\n\
151 (Default: tank/lxc)\n",
152 .options = my_longopts,
153 .parser = my_parser,
154 .checker = NULL,
155 };
156
157 static bool validate_bdev_args(struct lxc_arguments *a)
158 {
159 if (strcmp(a->bdevtype, "best") != 0) {
160 if (a->fstype || a->fssize) {
161 if (strcmp(a->bdevtype, "lvm") != 0 &&
162 strcmp(a->bdevtype, "loop") != 0) {
163 fprintf(stderr, "filesystem type and size are only valid with block devices\n");
164 return false;
165 }
166 }
167 if (strcmp(a->bdevtype, "lvm") != 0) {
168 if (a->lvname || a->vgname || a->thinpool) {
169 fprintf(stderr, "--lvname, --vgname and --thinpool are only valid with -B lvm\n");
170 return false;
171 }
172 }
173 if (strcmp(a->bdevtype, "zfs") != 0) {
174 if (a->zfsroot) {
175 fprintf(stderr, "zfsroot is only valid with -B zfs\n");
176 return false;
177 }
178 }
179 }
180 return true;
181 }
182
183 int main(int argc, char *argv[])
184 {
185 struct lxc_container *c;
186 struct bdev_specs spec;
187 int flags = 0;
188
189 if (lxc_arguments_parse(&my_args, argc, argv))
190 exit(1);
191
192 if (!my_args.log_file)
193 my_args.log_file = "none";
194
195 if (lxc_log_init(my_args.name, my_args.log_file, my_args.log_priority,
196 my_args.progname, my_args.quiet, my_args.lxcpath[0]))
197 exit(1);
198 lxc_log_options_no_override();
199
200 if (!my_args.template) {
201 fprintf(stderr, "A template must be specified.\n");
202 fprintf(stderr, "Use \"none\" if you really want a container without a rootfs.\n");
203 exit(1);
204 }
205
206 if (strcmp(my_args.template, "none") == 0)
207 my_args.template = NULL;
208
209 memset(&spec, 0, sizeof(spec));
210 if (!my_args.bdevtype)
211 my_args.bdevtype = "_unset";
212 if (!validate_bdev_args(&my_args))
213 exit(1);
214
215 if (strcmp(my_args.bdevtype, "none") == 0)
216 my_args.bdevtype = "dir";
217
218 if (geteuid()) {
219 if (mkdir_p(my_args.lxcpath[0], 0755)) {
220 exit(1);
221 }
222 if (access(my_args.lxcpath[0], O_RDWR) < 0) {
223 fprintf(stderr, "You lack access to %s\n", my_args.lxcpath[0]);
224 exit(1);
225 }
226 if (strcmp(my_args.bdevtype, "dir") && strcmp(my_args.bdevtype, "_unset") &&
227 strcmp(my_args.bdevtype, "btrfs")) {
228 fprintf(stderr, "Unprivileged users cannot create %s containers", my_args.bdevtype);
229 exit(1);
230 }
231 }
232
233
234 c = lxc_container_new(my_args.name, my_args.lxcpath[0]);
235 if (!c) {
236 fprintf(stderr, "System error loading container\n");
237 exit(1);
238 }
239 if (c->is_defined(c)) {
240 fprintf(stderr, "Container already exists\n");
241 exit(1);
242 }
243 if (my_args.configfile)
244 c->load_config(c, my_args.configfile);
245 else
246 c->load_config(c, lxc_global_config_value("lxc.default_config"));
247
248 if (my_args.fstype)
249 spec.fstype = my_args.fstype;
250 if (my_args.fssize)
251 spec.fssize = my_args.fssize;
252
253 if (strcmp(my_args.bdevtype, "zfs") == 0 || strcmp(my_args.bdevtype, "best") == 0) {
254 if (my_args.zfsroot)
255 spec.zfs.zfsroot = my_args.zfsroot;
256 }
257 if (strcmp(my_args.bdevtype, "lvm") == 0 || strcmp(my_args.bdevtype, "best") == 0) {
258 if (my_args.lvname)
259 spec.lvm.lv = my_args.lvname;
260 if (my_args.vgname)
261 spec.lvm.vg = my_args.vgname;
262 if (my_args.thinpool)
263 spec.lvm.thinpool = my_args.thinpool;
264 }
265 if (my_args.dir) {
266 spec.dir = my_args.dir;
267 }
268
269 if (strcmp(my_args.bdevtype, "_unset") == 0)
270 my_args.bdevtype = NULL;
271 if (my_args.quiet)
272 flags = LXC_CREATE_QUIET;
273 if (!c->create(c, my_args.template, my_args.bdevtype, &spec, flags, &argv[optind])) {
274 ERROR("Error creating container %s", c->name);
275 lxc_container_put(c);
276 exit(1);
277 }
278 INFO("container %s created", c->name);
279 exit(0);
280 }