]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/lxc_create.c
Mark functions as static and arguments/arrays as const where possible
[mirror_lxc.git] / src / lxc / 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
948955a2 20#include <lxc/lxccontainer.h>
1897e3bc
SH
21
22#include <stdio.h>
23#include <libgen.h>
24#include <unistd.h>
25#include <ctype.h>
95ee490b 26#include <fcntl.h>
1897e3bc
SH
27#include <sys/types.h>
28
f2363e38
ÇO
29#include "lxc.h"
30#include "log.h"
31#include "bdev.h"
1897e3bc
SH
32#include "arguments.h"
33#include "utils.h"
34
35lxc_log_define(lxc_create, lxc);
36
37/* we pass fssize in bytes */
38static unsigned long get_fssize(char *s)
39{
40 unsigned long ret;
41 char *end;
42
43 ret = strtoul(s, &end, 0);
44 if (end == s)
45 return 0;
46 while (isblank(*end))
47 end++;
48 if (!(*end))
49 return ret;
50 if (*end == 'g' || *end == 'G')
51 ret *= 1000000000;
52 else if (*end == 'm' || *end == 'M')
53 ret *= 1000000;
54 else if (*end == 'k' || *end == 'K')
55 ret *= 1000;
56 return ret;
57}
58
59static int my_parser(struct lxc_arguments* args, int c, char* arg)
60{
61 switch (c) {
62 case 'B': args->bdevtype = arg; break;
63 case 'f': args->configfile = arg; break;
64 case 't': args->template = arg; break;
65 case '0': args->lvname = arg; break;
66 case '1': args->vgname = arg; break;
f99c386b
SS
67 case '2': args->thinpool = arg; break;
68 case '3': args->fstype = arg; break;
69 case '4': args->fssize = get_fssize(arg); break;
70 case '5': args->zfsroot = arg; break;
71 case '6': args->dir = arg; break;
1897e3bc
SH
72 }
73 return 0;
74}
75
76static const struct option my_longopts[] = {
77 {"bdev", required_argument, 0, 'B'},
78 {"config", required_argument, 0, 'f'},
79 {"template", required_argument, 0, 't'},
80 {"lvname", required_argument, 0, '0'},
81 {"vgname", required_argument, 0, '1'},
f99c386b
SS
82 {"thinpool", required_argument, 0, '2'},
83 {"fstype", required_argument, 0, '3'},
84 {"fssize", required_argument, 0, '4'},
85 {"zfsroot", required_argument, 0, '5'},
86 {"dir", required_argument, 0, '6'},
1897e3bc
SH
87 LXC_COMMON_OPTIONS
88};
89
f002c8a7
SH
90static void create_helpfn(const struct lxc_arguments *args) {
91 char *argv[3], *path;
92 size_t len;
93 int ret;
94 pid_t pid;
95
96 if (!args->template)
97 return;
98 if ((pid = fork()) < 0)
99 return;
100 if (pid)
101 wait_for_pid(pid);
102 len = strlen(LXCTEMPLATEDIR) + strlen(args->template) + strlen("/lxc-") + 1;
103 path = alloca(len);
104 ret = snprintf(path, len, "%s/lxc-%s", LXCTEMPLATEDIR, args->template);
105 if (ret < 0 || ret >= len)
106 return;
107
108 argv[0] = path;
109 argv[1] = "-h";
110 argv[2] = NULL;
111 execv(path, argv);
112 ERROR("Error executing %s -h", path);
113 exit(1);
114}
115
1897e3bc
SH
116static struct lxc_arguments my_args = {
117 .progname = "lxc-create",
f002c8a7 118 .helpfn = create_helpfn,
1897e3bc 119 .help = "\
41ace3de 120--name=NAME [-w] [-r] [-t template] [-P lxcpath]\n\
1897e3bc 121\n\
3155e7f9 122lxc-create creates a container\n\
1897e3bc
SH
123\n\
124Options :\n\
e3f46bfb
SH
125 -n, --name=NAME NAME for name of the container\n\
126 -f, --config=file Initial configuration file\n\
127 -t, --template=t Template to use to setup container\n\
128 -B, --bdev=BDEV Backing store type to use\n\
129 -P, --lxcpath=PATH Place container under PATH\n\
130 --lvname=LVNAME Use LVM lv name LVNAME\n\
131 (Default: container name)\n\
132 --vgname=VG Use LVM vg called VG\n\
133 (Default: lxc))\n\
f99c386b 134 --thinpool=TP Use LVM thin pool called TP\n\
055af165 135 (Default: lxc))\n\
e3f46bfb
SH
136 --fstype=TYPE Create fstype TYPE\n\
137 (Default: ext3))\n\
138 --fssize=SIZE Create filesystem of size SIZE\n\
139 (Default: 1G))\n\
140 --dir=DIR Place rootfs directory under DIR\n\
141 --zfsroot=PATH Create zfs under given zfsroot\n\
142 (Default: tank/lxc))\n",
1897e3bc
SH
143 .options = my_longopts,
144 .parser = my_parser,
145 .checker = NULL,
146};
147
74a3920a 148static bool validate_bdev_args(struct lxc_arguments *a)
1897e3bc 149{
72e99249
SS
150 if (strcmp(a->bdevtype, "best") != 0) {
151 if (a->fstype || a->fssize) {
152 if (strcmp(a->bdevtype, "lvm") != 0 &&
153 strcmp(a->bdevtype, "loop") != 0) {
154 fprintf(stderr, "filesystem type and size are only valid with block devices\n");
155 return false;
156 }
1897e3bc 157 }
72e99249
SS
158 if (strcmp(a->bdevtype, "lvm") != 0) {
159 if (a->lvname || a->vgname || a->thinpool) {
160 fprintf(stderr, "--lvname, --vgname and --thinpool are only valid with -B lvm\n");
161 return false;
162 }
1897e3bc 163 }
72e99249
SS
164 if (strcmp(a->bdevtype, "zfs") != 0) {
165 if (a->zfsroot) {
166 fprintf(stderr, "zfsroot is only valid with -B zfs\n");
167 return false;
168 }
1897e3bc
SH
169 }
170 }
171 return true;
172}
173
1897e3bc
SH
174int main(int argc, char *argv[])
175{
176 struct lxc_container *c;
177 struct bdev_specs spec;
dc23c1c8 178 int flags = 0;
1897e3bc 179
1897e3bc
SH
180 if (lxc_arguments_parse(&my_args, argc, argv))
181 exit(1);
182
f5abd74d
SG
183 if (!my_args.log_file)
184 my_args.log_file = "none";
185
1897e3bc
SH
186 if (lxc_log_init(my_args.name, my_args.log_file, my_args.log_priority,
187 my_args.progname, my_args.quiet, my_args.lxcpath[0]))
188 exit(1);
189
190 memset(&spec, 0, sizeof(spec));
191 if (!my_args.bdevtype)
192 my_args.bdevtype = "_unset";
193 if (!validate_bdev_args(&my_args))
194 exit(1);
195
460bcbd8
SH
196 if (geteuid()) {
197 if (access(my_args.lxcpath[0], O_RDWR) < 0) {
198 fprintf(stderr, "You lack access to %s\n", my_args.lxcpath[0]);
199 exit(1);
200 }
201 if (strcmp(my_args.bdevtype, "dir") && strcmp(my_args.bdevtype, "_unset")) {
202 fprintf(stderr, "Unprivileged users can only create directory backed containers\n");
203 exit(1);
204 }
205 }
206
207
1897e3bc
SH
208 c = lxc_container_new(my_args.name, my_args.lxcpath[0]);
209 if (!c) {
210 fprintf(stderr, "System error loading container\n");
211 exit(1);
212 }
213 if (c->is_defined(c)) {
214 fprintf(stderr, "Container already exists\n");
215 exit(1);
216 }
217 if (my_args.configfile)
218 c->load_config(c, my_args.configfile);
219 else
0a18b545 220 c->load_config(c, LXC_DEFAULT_CONFIG);
1897e3bc 221
72e99249
SS
222 if (my_args.fstype)
223 spec.fstype = my_args.fstype;
224 if (my_args.fssize)
225 spec.fssize = my_args.fssize;
226
227 if (strcmp(my_args.bdevtype, "zfs") == 0 || strcmp(my_args.bdevtype, "best") == 0) {
1897e3bc 228 if (my_args.zfsroot)
72e99249
SS
229 spec.zfs.zfsroot = my_args.zfsroot;
230 }
231 if (strcmp(my_args.bdevtype, "lvm") == 0 || strcmp(my_args.bdevtype, "best") == 0) {
1897e3bc 232 if (my_args.lvname)
72e99249 233 spec.lvm.lv = my_args.lvname;
1897e3bc 234 if (my_args.vgname)
72e99249 235 spec.lvm.vg = my_args.vgname;
f99c386b 236 if (my_args.thinpool)
72e99249
SS
237 spec.lvm.thinpool = my_args.thinpool;
238 }
239 if (my_args.dir) {
1897e3bc
SH
240 ERROR("--dir is not yet supported");
241 exit(1);
242 }
243
244 if (strcmp(my_args.bdevtype, "_unset") == 0)
245 my_args.bdevtype = NULL;
dc23c1c8
SH
246 if (my_args.quiet)
247 flags = LXC_CREATE_QUIET;
248 if (!c->create(c, my_args.template, my_args.bdevtype, &spec, flags, &argv[optind])) {
1897e3bc
SH
249 ERROR("Error creating container %s", c->name);
250 lxc_container_put(c);
251 exit(1);
252 }
253 INFO("container %s created", c->name);
254 exit(0);
255}