]>
Commit | Line | Data |
---|---|---|
c2cc9f0a | 1 | /* |
2 | * lxc: linux Container library | |
3 | * | |
4 | * (C) Copyright IBM Corp. 2007, 2008 | |
5 | * | |
6 | * Authors: | |
7 | * Daniel Lezcano <dlezcano at fr.ibm.com> | |
8 | * | |
9 | * This library is free software; you can redistribute it and/or | |
10 | * modify it under the terms of the GNU Lesser General Public | |
11 | * License as published by the Free Software Foundation; either | |
12 | * version 2.1 of the License, or (at your option) any later version. | |
13 | * | |
14 | * This library is distributed in the hope that it will be useful, | |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
17 | * Lesser General Public License for more details. | |
18 | * | |
19 | * You should have received a copy of the GNU Lesser General Public | |
20 | * License along with this library; if not, write to the Free Software | |
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
22 | */ | |
23 | #include <stdio.h> | |
24 | #include <stdlib.h> | |
25 | #include <string.h> | |
26 | #include <unistd.h> | |
27 | #include <errno.h> | |
63376d7d DL |
28 | #include <fcntl.h> |
29 | #include <pty.h> | |
30 | #include <sys/stat.h> | |
c2cc9f0a | 31 | #include <sys/types.h> |
32 | #include <sys/param.h> | |
33 | #include <sys/utsname.h> | |
34 | #include <arpa/inet.h> | |
35 | #include <netinet/in.h> | |
36 | #include <net/if.h> | |
37 | ||
b2718c72 | 38 | #include "parse.h" |
26c39028 | 39 | #include "utils.h" |
c2cc9f0a | 40 | |
36eb9bde | 41 | #include <lxc/log.h> |
00b3c2e2 | 42 | #include <lxc/conf.h> |
36eb9bde CLG |
43 | |
44 | lxc_log_define(lxc_confile, lxc); | |
576f946d | 45 | |
10db618d | 46 | static int config_pts(const char *, char *, struct lxc_conf *); |
b0a33c1e | 47 | static int config_tty(const char *, char *, struct lxc_conf *); |
576f946d | 48 | static int config_cgroup(const char *, char *, struct lxc_conf *); |
49 | static int config_mount(const char *, char *, struct lxc_conf *); | |
50 | static int config_rootfs(const char *, char *, struct lxc_conf *); | |
23b7ea69 | 51 | static int config_rootfs_mount(const char *, char *, struct lxc_conf *); |
bf601689 | 52 | static int config_pivotdir(const char *, char *, struct lxc_conf *); |
576f946d | 53 | static int config_utsname(const char *, char *, struct lxc_conf *); |
54 | static int config_network_type(const char *, char *, struct lxc_conf *); | |
55 | static int config_network_flags(const char *, char *, struct lxc_conf *); | |
56 | static int config_network_link(const char *, char *, struct lxc_conf *); | |
57 | static int config_network_name(const char *, char *, struct lxc_conf *); | |
e892973e DL |
58 | static int config_network_veth_pair(const char *, char *, struct lxc_conf *); |
59 | static int config_network_macvlan_mode(const char *, char *, struct lxc_conf *); | |
576f946d | 60 | static int config_network_hwaddr(const char *, char *, struct lxc_conf *); |
e892973e | 61 | static int config_network_vlan_id(const char *, char *, struct lxc_conf *); |
442cbbe6 | 62 | static int config_network_mtu(const char *, char *, struct lxc_conf *); |
576f946d | 63 | static int config_network_ipv4(const char *, char *, struct lxc_conf *); |
64 | static int config_network_ipv6(const char *, char *, struct lxc_conf *); | |
81810dd1 | 65 | static int config_cap_drop(const char *, char *, struct lxc_conf *); |
63376d7d | 66 | static int config_console(const char *, char *, struct lxc_conf *); |
c2cc9f0a | 67 | |
b2718c72 | 68 | typedef int (*config_cb)(const char *, char *, struct lxc_conf *); |
69 | ||
c2cc9f0a | 70 | struct config { |
71 | char *name; | |
c2cc9f0a | 72 | config_cb cb; |
73 | }; | |
74 | ||
576f946d | 75 | static struct config config[] = { |
76 | ||
e892973e DL |
77 | { "lxc.pts", config_pts }, |
78 | { "lxc.tty", config_tty }, | |
79 | { "lxc.cgroup", config_cgroup }, | |
80 | { "lxc.mount", config_mount }, | |
23b7ea69 | 81 | { "lxc.rootfs.mount", config_rootfs_mount }, |
e892973e | 82 | { "lxc.rootfs", config_rootfs }, |
bf601689 | 83 | { "lxc.pivotdir", config_pivotdir }, |
e892973e DL |
84 | { "lxc.utsname", config_utsname }, |
85 | { "lxc.network.type", config_network_type }, | |
86 | { "lxc.network.flags", config_network_flags }, | |
87 | { "lxc.network.link", config_network_link }, | |
88 | { "lxc.network.name", config_network_name }, | |
89 | { "lxc.network.macvlan.mode", config_network_macvlan_mode }, | |
90 | { "lxc.network.veth.pair", config_network_veth_pair }, | |
91 | { "lxc.network.hwaddr", config_network_hwaddr }, | |
92 | { "lxc.network.mtu", config_network_mtu }, | |
93 | { "lxc.network.vlan.id", config_network_vlan_id }, | |
94 | { "lxc.network.ipv4", config_network_ipv4 }, | |
95 | { "lxc.network.ipv6", config_network_ipv6 }, | |
81810dd1 | 96 | { "lxc.cap.drop", config_cap_drop }, |
63376d7d | 97 | { "lxc.console", config_console }, |
c2cc9f0a | 98 | }; |
99 | ||
100 | static const size_t config_size = sizeof(config)/sizeof(struct config); | |
101 | ||
102 | static struct config *getconfig(const char *key) | |
103 | { | |
104 | int i; | |
105 | ||
106 | for (i = 0; i < config_size; i++) | |
a871ff6b | 107 | if (!strncmp(config[i].name, key, |
c2cc9f0a | 108 | strlen(config[i].name))) |
109 | return &config[i]; | |
110 | return NULL; | |
111 | } | |
112 | ||
e892973e DL |
113 | static int config_network_type(const char *key, char *value, |
114 | struct lxc_conf *lxc_conf) | |
c2cc9f0a | 115 | { |
5f4535a3 | 116 | struct lxc_list *network = &lxc_conf->network; |
c2cc9f0a | 117 | struct lxc_netdev *netdev; |
118 | struct lxc_list *list; | |
c2cc9f0a | 119 | |
120 | netdev = malloc(sizeof(*netdev)); | |
121 | if (!netdev) { | |
36eb9bde | 122 | SYSERROR("failed to allocate memory"); |
c2cc9f0a | 123 | return -1; |
124 | } | |
125 | ||
82d5ae15 | 126 | memset(netdev, 0, sizeof(*netdev)); |
c2cc9f0a | 127 | lxc_list_init(&netdev->ipv4); |
128 | lxc_list_init(&netdev->ipv6); | |
c2cc9f0a | 129 | |
130 | list = malloc(sizeof(*list)); | |
131 | if (!list) { | |
36eb9bde | 132 | SYSERROR("failed to allocate memory"); |
c2cc9f0a | 133 | return -1; |
134 | } | |
135 | ||
136 | lxc_list_init(list); | |
5f4535a3 | 137 | list->elem = netdev; |
c2cc9f0a | 138 | |
5f4535a3 | 139 | lxc_list_add(network, list); |
a871ff6b | 140 | |
c2cc9f0a | 141 | if (!strcmp(value, "veth")) |
24654103 | 142 | netdev->type = LXC_NET_VETH; |
c2cc9f0a | 143 | else if (!strcmp(value, "macvlan")) |
24654103 | 144 | netdev->type = LXC_NET_MACVLAN; |
26c39028 | 145 | else if (!strcmp(value, "vlan")) |
24654103 | 146 | netdev->type = LXC_NET_VLAN; |
c2cc9f0a | 147 | else if (!strcmp(value, "phys")) |
24654103 | 148 | netdev->type = LXC_NET_PHYS; |
5f58350a | 149 | else if (!strcmp(value, "empty")) |
24654103 | 150 | netdev->type = LXC_NET_EMPTY; |
c2cc9f0a | 151 | else { |
36eb9bde | 152 | ERROR("invalid network type %s", value); |
c2cc9f0a | 153 | return -1; |
154 | } | |
155 | return 0; | |
156 | } | |
157 | ||
a059591e DL |
158 | static int config_ip_prefix(struct in_addr *addr) |
159 | { | |
160 | if (IN_CLASSA(addr->s_addr)) | |
161 | return 32 - IN_CLASSA_NSHIFT; | |
162 | if (IN_CLASSB(addr->s_addr)) | |
163 | return 32 - IN_CLASSB_NSHIFT; | |
164 | if (IN_CLASSC(addr->s_addr)) | |
165 | return 32 - IN_CLASSC_NSHIFT; | |
166 | ||
167 | return 0; | |
168 | } | |
169 | ||
16950ecb DL |
170 | static struct lxc_netdev *network_netdev(const char *key, const char *value, |
171 | struct lxc_list *network) | |
c2cc9f0a | 172 | { |
c2cc9f0a | 173 | struct lxc_netdev *netdev; |
174 | ||
5f4535a3 | 175 | if (lxc_list_empty(network)) { |
16950ecb DL |
176 | ERROR("network is not created for '%s' = '%s' option", |
177 | key, value); | |
33c945e0 | 178 | return NULL; |
c2cc9f0a | 179 | } |
180 | ||
5f4535a3 DL |
181 | netdev = lxc_list_first_elem(network); |
182 | if (!netdev) { | |
16950ecb DL |
183 | ERROR("no network device defined for '%s' = '%s' option", |
184 | key, value); | |
33c945e0 | 185 | return NULL; |
c2cc9f0a | 186 | } |
187 | ||
33c945e0 | 188 | return netdev; |
c2cc9f0a | 189 | } |
190 | ||
33c945e0 | 191 | static int network_ifname(char **valuep, char *value) |
c2cc9f0a | 192 | { |
c2cc9f0a | 193 | if (strlen(value) > IFNAMSIZ) { |
36eb9bde | 194 | ERROR("invalid interface name: %s", value); |
c2cc9f0a | 195 | return -1; |
196 | } | |
197 | ||
33c945e0 | 198 | *valuep = strdup(value); |
16950ecb DL |
199 | if (!*valuep) { |
200 | ERROR("failed to dup string '%s'", value); | |
201 | return -1; | |
202 | } | |
33c945e0 | 203 | |
c2cc9f0a | 204 | return 0; |
205 | } | |
206 | ||
e892973e DL |
207 | #ifndef MACVLAN_MODE_PRIVATE |
208 | # define MACVLAN_MODE_PRIVATE 1 | |
209 | #endif | |
210 | ||
211 | #ifndef MACVLAN_MODE_VEPA | |
212 | # define MACVLAN_MODE_VEPA 2 | |
213 | #endif | |
214 | ||
215 | #ifndef MACVLAN_MODE_BRIDGE | |
216 | # define MACVLAN_MODE_BRIDGE 4 | |
217 | #endif | |
218 | ||
219 | static int macvlan_mode(int *valuep, char *value) | |
220 | { | |
221 | struct mc_mode { | |
222 | char *name; | |
223 | int mode; | |
224 | } m[] = { | |
225 | { "private", MACVLAN_MODE_PRIVATE }, | |
226 | { "vepa", MACVLAN_MODE_VEPA }, | |
227 | { "bridge", MACVLAN_MODE_BRIDGE }, | |
228 | }; | |
229 | ||
230 | int i; | |
231 | ||
232 | for (i = 0; i < sizeof(m)/sizeof(m[0]); i++) { | |
233 | if (strcmp(m[i].name, value)) | |
234 | continue; | |
235 | ||
236 | *valuep = m[i].mode; | |
237 | return 0; | |
238 | } | |
239 | ||
240 | return -1; | |
241 | } | |
242 | ||
33c945e0 MT |
243 | static int config_network_flags(const char *key, char *value, |
244 | struct lxc_conf *lxc_conf) | |
c2cc9f0a | 245 | { |
c2cc9f0a | 246 | struct lxc_netdev *netdev; |
247 | ||
16950ecb | 248 | netdev = network_netdev(key, value, &lxc_conf->network); |
33c945e0 | 249 | if (!netdev) |
c2cc9f0a | 250 | return -1; |
c2cc9f0a | 251 | |
33c945e0 | 252 | netdev->flags |= IFF_UP; |
c2cc9f0a | 253 | |
33c945e0 MT |
254 | return 0; |
255 | } | |
256 | ||
257 | static int config_network_link(const char *key, char *value, | |
258 | struct lxc_conf *lxc_conf) | |
259 | { | |
260 | struct lxc_netdev *netdev; | |
261 | ||
16950ecb | 262 | netdev = network_netdev(key, value, &lxc_conf->network); |
33c945e0 | 263 | if (!netdev) |
c2cc9f0a | 264 | return -1; |
c2cc9f0a | 265 | |
33c945e0 | 266 | return network_ifname(&netdev->link, value); |
c2cc9f0a | 267 | } |
268 | ||
33c945e0 MT |
269 | static int config_network_name(const char *key, char *value, |
270 | struct lxc_conf *lxc_conf) | |
c2cc9f0a | 271 | { |
c2cc9f0a | 272 | struct lxc_netdev *netdev; |
273 | ||
16950ecb | 274 | netdev = network_netdev(key, value, &lxc_conf->network); |
33c945e0 | 275 | if (!netdev) |
c2cc9f0a | 276 | return -1; |
c2cc9f0a | 277 | |
33c945e0 MT |
278 | return network_ifname(&netdev->name, value); |
279 | } | |
280 | ||
e892973e DL |
281 | static int config_network_veth_pair(const char *key, char *value, |
282 | struct lxc_conf *lxc_conf) | |
283 | { | |
284 | struct lxc_netdev *netdev; | |
285 | ||
286 | netdev = network_netdev(key, value, &lxc_conf->network); | |
287 | if (!netdev) | |
288 | return -1; | |
289 | ||
290 | return network_ifname(&netdev->priv.veth_attr.pair, value); | |
291 | } | |
292 | ||
293 | static int config_network_macvlan_mode(const char *key, char *value, | |
294 | struct lxc_conf *lxc_conf) | |
8634bc19 MT |
295 | { |
296 | struct lxc_netdev *netdev; | |
297 | ||
298 | netdev = network_netdev(key, value, &lxc_conf->network); | |
299 | if (!netdev) | |
300 | return -1; | |
301 | ||
e892973e | 302 | return macvlan_mode(&netdev->priv.macvlan_attr.mode, value); |
8634bc19 MT |
303 | } |
304 | ||
33c945e0 MT |
305 | static int config_network_hwaddr(const char *key, char *value, |
306 | struct lxc_conf *lxc_conf) | |
307 | { | |
308 | struct lxc_netdev *netdev; | |
309 | ||
16950ecb | 310 | netdev = network_netdev(key, value, &lxc_conf->network); |
33c945e0 | 311 | if (!netdev) |
c2cc9f0a | 312 | return -1; |
c2cc9f0a | 313 | |
c2cc9f0a | 314 | netdev->hwaddr = strdup(value); |
16950ecb DL |
315 | if (!netdev->hwaddr) { |
316 | SYSERROR("failed to dup string '%s'", value); | |
317 | return -1; | |
318 | } | |
33c945e0 | 319 | |
c2cc9f0a | 320 | return 0; |
321 | } | |
322 | ||
e892973e | 323 | static int config_network_vlan_id(const char *key, char *value, |
26c39028 JHS |
324 | struct lxc_conf *lxc_conf) |
325 | { | |
326 | struct lxc_netdev *netdev; | |
327 | ||
328 | netdev = network_netdev(key, value, &lxc_conf->network); | |
329 | if (!netdev) | |
330 | return -1; | |
331 | ||
f6cc1de1 | 332 | if (get_u16(&netdev->priv.vlan_attr.vid, value, 0)) |
26c39028 JHS |
333 | return -1; |
334 | ||
335 | return 0; | |
336 | } | |
337 | ||
33c945e0 MT |
338 | static int config_network_mtu(const char *key, char *value, |
339 | struct lxc_conf *lxc_conf) | |
442cbbe6 | 340 | { |
442cbbe6 TR |
341 | struct lxc_netdev *netdev; |
342 | ||
16950ecb | 343 | netdev = network_netdev(key, value, &lxc_conf->network); |
33c945e0 | 344 | if (!netdev) |
442cbbe6 | 345 | return -1; |
442cbbe6 | 346 | |
442cbbe6 | 347 | netdev->mtu = strdup(value); |
16950ecb DL |
348 | if (!netdev->mtu) { |
349 | SYSERROR("failed to dup string '%s'", value); | |
350 | return -1; | |
351 | } | |
33c945e0 | 352 | |
442cbbe6 TR |
353 | return 0; |
354 | } | |
355 | ||
33c945e0 MT |
356 | static int config_network_ipv4(const char *key, char *value, |
357 | struct lxc_conf *lxc_conf) | |
c2cc9f0a | 358 | { |
c2cc9f0a | 359 | struct lxc_netdev *netdev; |
33c945e0 | 360 | struct lxc_inetdev *inetdev; |
c2cc9f0a | 361 | struct lxc_list *list; |
362 | char *cursor, *slash, *addr = NULL, *bcast = NULL, *prefix = NULL; | |
363 | ||
16950ecb | 364 | netdev = network_netdev(key, value, &lxc_conf->network); |
33c945e0 | 365 | if (!netdev) |
c2cc9f0a | 366 | return -1; |
c2cc9f0a | 367 | |
368 | inetdev = malloc(sizeof(*inetdev)); | |
369 | if (!inetdev) { | |
36eb9bde | 370 | SYSERROR("failed to allocate ipv4 address"); |
c2cc9f0a | 371 | return -1; |
372 | } | |
373 | memset(inetdev, 0, sizeof(*inetdev)); | |
374 | ||
375 | list = malloc(sizeof(*list)); | |
376 | if (!list) { | |
36eb9bde | 377 | SYSERROR("failed to allocate memory"); |
c2cc9f0a | 378 | return -1; |
379 | } | |
380 | ||
381 | lxc_list_init(list); | |
382 | list->elem = inetdev; | |
383 | ||
384 | addr = value; | |
385 | ||
386 | cursor = strstr(addr, " "); | |
387 | if (cursor) { | |
388 | *cursor = '\0'; | |
389 | bcast = cursor + 1; | |
390 | } | |
391 | ||
392 | slash = strstr(addr, "/"); | |
393 | if (slash) { | |
394 | *slash = '\0'; | |
395 | prefix = slash + 1; | |
396 | } | |
397 | ||
398 | if (!addr) { | |
36eb9bde | 399 | ERROR("no address specified"); |
c2cc9f0a | 400 | return -1; |
401 | } | |
402 | ||
403 | if (!inet_pton(AF_INET, addr, &inetdev->addr)) { | |
36eb9bde | 404 | SYSERROR("invalid ipv4 address: %s", value); |
c2cc9f0a | 405 | return -1; |
406 | } | |
407 | ||
0093bb8c DL |
408 | if (bcast && !inet_pton(AF_INET, bcast, &inetdev->bcast)) { |
409 | SYSERROR("invalid ipv4 broadcast address: %s", value); | |
410 | return -1; | |
411 | } | |
c2cc9f0a | 412 | |
a059591e DL |
413 | /* no prefix specified, determine it from the network class */ |
414 | inetdev->prefix = prefix ? atoi(prefix) : | |
415 | config_ip_prefix(&inetdev->addr); | |
416 | ||
b3df193c | 417 | /* if no broadcast address, let compute one from the |
0093bb8c DL |
418 | * prefix and address |
419 | */ | |
420 | if (!bcast) { | |
b3df193c | 421 | inetdev->bcast.s_addr = |
0093bb8c DL |
422 | htonl(INADDR_BROADCAST << (32 - inetdev->prefix)); |
423 | inetdev->bcast.s_addr &= inetdev->addr.s_addr; | |
424 | } | |
c2cc9f0a | 425 | |
426 | lxc_list_add(&netdev->ipv4, list); | |
427 | ||
428 | return 0; | |
429 | } | |
430 | ||
e892973e DL |
431 | static int config_network_ipv6(const char *key, char *value, |
432 | struct lxc_conf *lxc_conf) | |
c2cc9f0a | 433 | { |
c2cc9f0a | 434 | struct lxc_netdev *netdev; |
435 | struct lxc_inet6dev *inet6dev; | |
436 | struct lxc_list *list; | |
437 | char *slash; | |
438 | char *netmask; | |
439 | ||
16950ecb | 440 | netdev = network_netdev(key, value, &lxc_conf->network); |
33c945e0 | 441 | if (!netdev) |
c2cc9f0a | 442 | return -1; |
c2cc9f0a | 443 | |
444 | inet6dev = malloc(sizeof(*inet6dev)); | |
445 | if (!inet6dev) { | |
36eb9bde | 446 | SYSERROR("failed to allocate ipv6 address"); |
c2cc9f0a | 447 | return -1; |
448 | } | |
449 | memset(inet6dev, 0, sizeof(*inet6dev)); | |
450 | ||
451 | list = malloc(sizeof(*list)); | |
452 | if (!list) { | |
36eb9bde | 453 | SYSERROR("failed to allocate memory"); |
c2cc9f0a | 454 | return -1; |
455 | } | |
456 | ||
457 | lxc_list_init(list); | |
458 | list->elem = inet6dev; | |
459 | ||
a059591e | 460 | inet6dev->prefix = 64; |
c2cc9f0a | 461 | slash = strstr(value, "/"); |
462 | if (slash) { | |
463 | *slash = '\0'; | |
464 | netmask = slash + 1; | |
465 | inet6dev->prefix = atoi(netmask); | |
466 | } | |
467 | ||
468 | if (!inet_pton(AF_INET6, value, &inet6dev->addr)) { | |
36eb9bde | 469 | SYSERROR("invalid ipv6 address: %s", value); |
c2cc9f0a | 470 | return -1; |
471 | } | |
472 | ||
c2cc9f0a | 473 | lxc_list_add(&netdev->ipv6, list); |
474 | ||
475 | return 0; | |
476 | } | |
477 | ||
10db618d | 478 | static int config_pts(const char *key, char *value, struct lxc_conf *lxc_conf) |
479 | { | |
480 | int maxpts = atoi(value); | |
481 | ||
482 | lxc_conf->pts = maxpts; | |
483 | ||
484 | return 0; | |
485 | } | |
486 | ||
b0a33c1e | 487 | static int config_tty(const char *key, char *value, struct lxc_conf *lxc_conf) |
488 | { | |
489 | int nbtty = atoi(value); | |
490 | ||
491 | lxc_conf->tty = nbtty; | |
492 | ||
493 | return 0; | |
494 | } | |
495 | ||
576f946d | 496 | static int config_cgroup(const char *key, char *value, struct lxc_conf *lxc_conf) |
497 | { | |
498 | char *token = "lxc.cgroup."; | |
499 | char *subkey; | |
500 | struct lxc_list *cglist; | |
501 | struct lxc_cgroup *cgelem; | |
502 | ||
503 | subkey = strstr(key, token); | |
504 | ||
505 | if (!subkey) | |
506 | return -1; | |
507 | ||
508 | if (!strlen(subkey)) | |
509 | return -1; | |
510 | ||
511 | if (strlen(subkey) == strlen(token)) | |
512 | return -1; | |
a871ff6b | 513 | |
576f946d | 514 | subkey += strlen(token); |
515 | ||
516 | cglist = malloc(sizeof(*cglist)); | |
517 | if (!cglist) | |
518 | return -1; | |
519 | ||
520 | cgelem = malloc(sizeof(*cgelem)); | |
521 | if (!cgelem) { | |
522 | free(cglist); | |
523 | return -1; | |
524 | } | |
525 | ||
526 | cgelem->subsystem = strdup(subkey); | |
527 | cgelem->value = strdup(value); | |
528 | cglist->elem = cgelem; | |
529 | ||
94d12f0a | 530 | lxc_list_add_tail(&lxc_conf->cgroup, cglist); |
576f946d | 531 | |
532 | return 0; | |
533 | } | |
534 | ||
e7938e9e | 535 | static int config_fstab(const char *key, char *value, struct lxc_conf *lxc_conf) |
c2cc9f0a | 536 | { |
537 | if (strlen(value) >= MAXPATHLEN) { | |
36eb9bde | 538 | ERROR("%s path is too long", value); |
c2cc9f0a | 539 | return -1; |
540 | } | |
541 | ||
542 | lxc_conf->fstab = strdup(value); | |
543 | if (!lxc_conf->fstab) { | |
36eb9bde | 544 | SYSERROR("failed to duplicate string %s", value); |
c2cc9f0a | 545 | return -1; |
546 | } | |
547 | ||
548 | return 0; | |
549 | } | |
550 | ||
e7938e9e MN |
551 | static int config_mount(const char *key, char *value, struct lxc_conf *lxc_conf) |
552 | { | |
553 | char *fstab_token = "lxc.mount"; | |
554 | char *token = "lxc.mount.entry"; | |
555 | char *subkey; | |
556 | char *mntelem; | |
557 | struct lxc_list *mntlist; | |
558 | ||
559 | subkey = strstr(key, token); | |
560 | ||
561 | if (!subkey) { | |
562 | subkey = strstr(key, fstab_token); | |
563 | ||
564 | if (!subkey) | |
565 | return -1; | |
566 | ||
567 | return config_fstab(key, value, lxc_conf); | |
568 | } | |
569 | ||
570 | if (!strlen(subkey)) | |
571 | return -1; | |
572 | ||
573 | mntlist = malloc(sizeof(*mntlist)); | |
574 | if (!mntlist) | |
575 | return -1; | |
576 | ||
577 | mntelem = strdup(value); | |
578 | mntlist->elem = mntelem; | |
579 | ||
580 | lxc_list_add_tail(&lxc_conf->mount_list, mntlist); | |
581 | ||
582 | return 0; | |
583 | } | |
584 | ||
81810dd1 DL |
585 | static int config_cap_drop(const char *key, char *value, |
586 | struct lxc_conf *lxc_conf) | |
587 | { | |
bd288c26 | 588 | char *dropcaps, *sptr, *token; |
81810dd1 DL |
589 | struct lxc_list *droplist; |
590 | int ret = -1; | |
591 | ||
592 | if (!strlen(value)) | |
593 | return -1; | |
594 | ||
595 | dropcaps = strdup(value); | |
596 | if (!dropcaps) { | |
597 | SYSERROR("failed to dup '%s'", value); | |
598 | return -1; | |
599 | } | |
600 | ||
601 | /* in case several capability drop is specified in a single line | |
602 | * split these caps in a single element for the list */ | |
603 | for (;;) { | |
604 | token = strtok_r(dropcaps, " \t", &sptr); | |
605 | if (!token) { | |
606 | ret = 0; | |
607 | break; | |
608 | } | |
609 | dropcaps = NULL; | |
610 | ||
611 | droplist = malloc(sizeof(*droplist)); | |
612 | if (!droplist) { | |
613 | SYSERROR("failed to allocate drop list"); | |
614 | break; | |
615 | } | |
616 | ||
617 | droplist->elem = strdup(token); | |
618 | if (!droplist->elem) { | |
619 | SYSERROR("failed to dup '%s'", token); | |
620 | free(droplist); | |
621 | break; | |
622 | } | |
623 | ||
624 | lxc_list_add_tail(&lxc_conf->caps, droplist); | |
625 | } | |
626 | ||
627 | free(dropcaps); | |
628 | ||
629 | return ret; | |
630 | } | |
631 | ||
28a4b0e5 DL |
632 | static int config_console(const char *key, char *value, |
633 | struct lxc_conf *lxc_conf) | |
634 | { | |
635 | char *path; | |
636 | ||
637 | path = strdup(value); | |
638 | if (!path) { | |
639 | SYSERROR("failed to strdup '%s': %m", value); | |
640 | return -1; | |
641 | } | |
642 | ||
643 | lxc_conf->console.path = path; | |
644 | ||
645 | return 0; | |
646 | } | |
647 | ||
576f946d | 648 | static int config_rootfs(const char *key, char *value, struct lxc_conf *lxc_conf) |
c2cc9f0a | 649 | { |
650 | if (strlen(value) >= MAXPATHLEN) { | |
36eb9bde | 651 | ERROR("%s path is too long", value); |
c2cc9f0a | 652 | return -1; |
653 | } | |
654 | ||
33fcb7a0 DL |
655 | lxc_conf->rootfs.path = strdup(value); |
656 | if (!lxc_conf->rootfs.path) { | |
36eb9bde | 657 | SYSERROR("failed to duplicate string %s", value); |
c2cc9f0a | 658 | return -1; |
659 | } | |
660 | ||
661 | return 0; | |
662 | } | |
663 | ||
23b7ea69 DL |
664 | static int config_rootfs_mount(const char *key, char *value, struct lxc_conf *lxc_conf) |
665 | { | |
666 | if (strlen(value) >= MAXPATHLEN) { | |
667 | ERROR("%s path is too long", value); | |
668 | return -1; | |
669 | } | |
670 | ||
671 | lxc_conf->rootfs.mount = strdup(value); | |
672 | if (!lxc_conf->rootfs.mount) { | |
673 | SYSERROR("failed to duplicate string '%s'", value); | |
674 | return -1; | |
675 | } | |
676 | ||
677 | return 0; | |
678 | } | |
679 | ||
bf601689 MH |
680 | static int config_pivotdir(const char *key, char *value, struct lxc_conf *lxc_conf) |
681 | { | |
682 | if (strlen(value) >= MAXPATHLEN) { | |
683 | ERROR("%s path is too long", value); | |
684 | return -1; | |
685 | } | |
686 | ||
33fcb7a0 DL |
687 | lxc_conf->rootfs.pivot = strdup(value); |
688 | if (!lxc_conf->rootfs.pivot) { | |
bf601689 MH |
689 | SYSERROR("failed to duplicate string %s", value); |
690 | return -1; | |
691 | } | |
692 | ||
693 | return 0; | |
694 | } | |
695 | ||
576f946d | 696 | static int config_utsname(const char *key, char *value, struct lxc_conf *lxc_conf) |
c2cc9f0a | 697 | { |
698 | struct utsname *utsname; | |
699 | ||
700 | utsname = malloc(sizeof(*utsname)); | |
701 | if (!utsname) { | |
36eb9bde | 702 | SYSERROR("failed to allocate memory"); |
c2cc9f0a | 703 | return -1; |
704 | } | |
705 | ||
706 | if (strlen(value) >= sizeof(utsname->nodename)) { | |
36eb9bde | 707 | ERROR("node name '%s' is too long", |
c2cc9f0a | 708 | utsname->nodename); |
709 | return -1; | |
710 | } | |
711 | ||
712 | strcpy(utsname->nodename, value); | |
713 | lxc_conf->utsname = utsname; | |
714 | ||
715 | return 0; | |
716 | } | |
717 | ||
7a7ff0c6 | 718 | static int parse_line(char *buffer, void *data) |
c2cc9f0a | 719 | { |
720 | struct config *config; | |
91480a0f | 721 | char *line; |
c2cc9f0a | 722 | char *dot; |
723 | char *key; | |
724 | char *value; | |
91480a0f | 725 | int ret = -1; |
c2cc9f0a | 726 | |
91480a0f | 727 | if (lxc_is_line_empty(buffer)) |
c2cc9f0a | 728 | return 0; |
729 | ||
91480a0f DL |
730 | /* we have to dup the buffer otherwise, at the re-exec for reboot we modified |
731 | * the original string on the stack by replacing '=' by '\0' below | |
732 | */ | |
733 | line = strdup(buffer); | |
734 | if (!line) { | |
735 | SYSERROR("failed to allocate memory for '%s'", buffer); | |
736 | goto out; | |
737 | } | |
738 | ||
b2718c72 | 739 | line += lxc_char_left_gc(line, strlen(line)); |
91480a0f DL |
740 | if (line[0] == '#') { |
741 | ret = 0; | |
742 | goto out; | |
743 | } | |
c2cc9f0a | 744 | |
b2718c72 | 745 | dot = strstr(line, "="); |
c2cc9f0a | 746 | if (!dot) { |
36eb9bde | 747 | ERROR("invalid configuration line: %s", line); |
91480a0f | 748 | goto out; |
c2cc9f0a | 749 | } |
a871ff6b | 750 | |
c2cc9f0a | 751 | *dot = '\0'; |
752 | value = dot + 1; | |
753 | ||
b2718c72 | 754 | key = line; |
755 | key[lxc_char_right_gc(key, strlen(key))] = '\0'; | |
c2cc9f0a | 756 | |
b2718c72 | 757 | value += lxc_char_left_gc(value, strlen(value)); |
758 | value[lxc_char_right_gc(value, strlen(value))] = '\0'; | |
c2cc9f0a | 759 | |
760 | config = getconfig(key); | |
761 | if (!config) { | |
36eb9bde | 762 | ERROR("unknow key %s", key); |
91480a0f | 763 | goto out; |
c2cc9f0a | 764 | } |
765 | ||
91480a0f DL |
766 | ret = config->cb(key, value, data); |
767 | ||
768 | out: | |
769 | free(line); | |
770 | return ret; | |
c2cc9f0a | 771 | } |
772 | ||
af5b0155 CLG |
773 | int lxc_config_readline(char *buffer, struct lxc_conf *conf) |
774 | { | |
775 | return parse_line(buffer, conf); | |
776 | } | |
777 | ||
b2718c72 | 778 | int lxc_config_read(const char *file, struct lxc_conf *conf) |
c2cc9f0a | 779 | { |
2382ecff | 780 | return lxc_file_for_each_line(file, parse_line, conf); |
c2cc9f0a | 781 | } |
62e46035 CLG |
782 | |
783 | int lxc_config_define_add(struct lxc_list *defines, char* arg) | |
784 | { | |
785 | struct lxc_list *dent; | |
786 | ||
787 | dent = malloc(sizeof(struct lxc_list)); | |
788 | if (!dent) | |
789 | return -1; | |
790 | ||
791 | dent->elem = arg; | |
792 | lxc_list_add_tail(defines, dent); | |
793 | return 0; | |
794 | } | |
795 | ||
226a18d6 | 796 | int lxc_config_define_load(struct lxc_list *defines, struct lxc_conf *conf) |
62e46035 CLG |
797 | { |
798 | struct lxc_list *it; | |
799 | int ret = 0; | |
800 | ||
801 | lxc_list_for_each(it, defines) { | |
802 | ret = lxc_config_readline(it->elem, conf); | |
803 | if (ret) | |
804 | break; | |
805 | } | |
806 | ||
807 | lxc_list_for_each(it, defines) { | |
808 | lxc_list_del(it); | |
809 | free(it); | |
810 | } | |
811 | ||
812 | return ret; | |
813 | } |