]>
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> | |
28 | #include <sys/types.h> | |
29 | #include <sys/param.h> | |
30 | #include <sys/utsname.h> | |
31 | #include <arpa/inet.h> | |
32 | #include <netinet/in.h> | |
33 | #include <net/if.h> | |
34 | ||
b2718c72 | 35 | #include "parse.h" |
26c39028 | 36 | #include "utils.h" |
c2cc9f0a | 37 | |
36eb9bde | 38 | #include <lxc/log.h> |
00b3c2e2 | 39 | #include <lxc/conf.h> |
36eb9bde CLG |
40 | |
41 | lxc_log_define(lxc_confile, lxc); | |
576f946d | 42 | |
10db618d | 43 | static int config_pts(const char *, char *, struct lxc_conf *); |
b0a33c1e | 44 | static int config_tty(const char *, char *, struct lxc_conf *); |
576f946d | 45 | static int config_cgroup(const char *, char *, struct lxc_conf *); |
46 | static int config_mount(const char *, char *, struct lxc_conf *); | |
47 | static int config_rootfs(const char *, char *, struct lxc_conf *); | |
bf601689 | 48 | static int config_pivotdir(const char *, char *, struct lxc_conf *); |
576f946d | 49 | static int config_utsname(const char *, char *, struct lxc_conf *); |
50 | static int config_network_type(const char *, char *, struct lxc_conf *); | |
51 | static int config_network_flags(const char *, char *, struct lxc_conf *); | |
52 | static int config_network_link(const char *, char *, struct lxc_conf *); | |
53 | static int config_network_name(const char *, char *, struct lxc_conf *); | |
e892973e DL |
54 | static int config_network_veth_pair(const char *, char *, struct lxc_conf *); |
55 | static int config_network_macvlan_mode(const char *, char *, struct lxc_conf *); | |
576f946d | 56 | static int config_network_hwaddr(const char *, char *, struct lxc_conf *); |
e892973e | 57 | static int config_network_vlan_id(const char *, char *, struct lxc_conf *); |
442cbbe6 | 58 | static int config_network_mtu(const char *, char *, struct lxc_conf *); |
576f946d | 59 | static int config_network_ipv4(const char *, char *, struct lxc_conf *); |
60 | static int config_network_ipv6(const char *, char *, struct lxc_conf *); | |
c2cc9f0a | 61 | |
b2718c72 | 62 | typedef int (*config_cb)(const char *, char *, struct lxc_conf *); |
63 | ||
c2cc9f0a | 64 | struct config { |
65 | char *name; | |
c2cc9f0a | 66 | config_cb cb; |
67 | }; | |
68 | ||
576f946d | 69 | static struct config config[] = { |
70 | ||
e892973e DL |
71 | { "lxc.pts", config_pts }, |
72 | { "lxc.tty", config_tty }, | |
73 | { "lxc.cgroup", config_cgroup }, | |
74 | { "lxc.mount", config_mount }, | |
75 | { "lxc.rootfs", config_rootfs }, | |
bf601689 | 76 | { "lxc.pivotdir", config_pivotdir }, |
e892973e DL |
77 | { "lxc.utsname", config_utsname }, |
78 | { "lxc.network.type", config_network_type }, | |
79 | { "lxc.network.flags", config_network_flags }, | |
80 | { "lxc.network.link", config_network_link }, | |
81 | { "lxc.network.name", config_network_name }, | |
82 | { "lxc.network.macvlan.mode", config_network_macvlan_mode }, | |
83 | { "lxc.network.veth.pair", config_network_veth_pair }, | |
84 | { "lxc.network.hwaddr", config_network_hwaddr }, | |
85 | { "lxc.network.mtu", config_network_mtu }, | |
86 | { "lxc.network.vlan.id", config_network_vlan_id }, | |
87 | { "lxc.network.ipv4", config_network_ipv4 }, | |
88 | { "lxc.network.ipv6", config_network_ipv6 }, | |
c2cc9f0a | 89 | }; |
90 | ||
91 | static const size_t config_size = sizeof(config)/sizeof(struct config); | |
92 | ||
93 | static struct config *getconfig(const char *key) | |
94 | { | |
95 | int i; | |
96 | ||
97 | for (i = 0; i < config_size; i++) | |
a871ff6b | 98 | if (!strncmp(config[i].name, key, |
c2cc9f0a | 99 | strlen(config[i].name))) |
100 | return &config[i]; | |
101 | return NULL; | |
102 | } | |
103 | ||
e892973e DL |
104 | static int config_network_type(const char *key, char *value, |
105 | struct lxc_conf *lxc_conf) | |
c2cc9f0a | 106 | { |
5f4535a3 | 107 | struct lxc_list *network = &lxc_conf->network; |
c2cc9f0a | 108 | struct lxc_netdev *netdev; |
109 | struct lxc_list *list; | |
c2cc9f0a | 110 | |
111 | netdev = malloc(sizeof(*netdev)); | |
112 | if (!netdev) { | |
36eb9bde | 113 | SYSERROR("failed to allocate memory"); |
c2cc9f0a | 114 | return -1; |
115 | } | |
116 | ||
82d5ae15 | 117 | memset(netdev, 0, sizeof(*netdev)); |
c2cc9f0a | 118 | lxc_list_init(&netdev->ipv4); |
119 | lxc_list_init(&netdev->ipv6); | |
c2cc9f0a | 120 | |
121 | list = malloc(sizeof(*list)); | |
122 | if (!list) { | |
36eb9bde | 123 | SYSERROR("failed to allocate memory"); |
c2cc9f0a | 124 | return -1; |
125 | } | |
126 | ||
127 | lxc_list_init(list); | |
5f4535a3 | 128 | list->elem = netdev; |
c2cc9f0a | 129 | |
5f4535a3 | 130 | lxc_list_add(network, list); |
a871ff6b | 131 | |
c2cc9f0a | 132 | if (!strcmp(value, "veth")) |
5f4535a3 | 133 | netdev->type = VETH; |
c2cc9f0a | 134 | else if (!strcmp(value, "macvlan")) |
5f4535a3 | 135 | netdev->type = MACVLAN; |
26c39028 JHS |
136 | else if (!strcmp(value, "vlan")) |
137 | netdev->type = VLAN; | |
c2cc9f0a | 138 | else if (!strcmp(value, "phys")) |
5f4535a3 | 139 | netdev->type = PHYS; |
5f58350a | 140 | else if (!strcmp(value, "empty")) |
5f4535a3 | 141 | netdev->type = EMPTY; |
c2cc9f0a | 142 | else { |
36eb9bde | 143 | ERROR("invalid network type %s", value); |
c2cc9f0a | 144 | return -1; |
145 | } | |
146 | return 0; | |
147 | } | |
148 | ||
a059591e DL |
149 | static int config_ip_prefix(struct in_addr *addr) |
150 | { | |
151 | if (IN_CLASSA(addr->s_addr)) | |
152 | return 32 - IN_CLASSA_NSHIFT; | |
153 | if (IN_CLASSB(addr->s_addr)) | |
154 | return 32 - IN_CLASSB_NSHIFT; | |
155 | if (IN_CLASSC(addr->s_addr)) | |
156 | return 32 - IN_CLASSC_NSHIFT; | |
157 | ||
158 | return 0; | |
159 | } | |
160 | ||
16950ecb DL |
161 | static struct lxc_netdev *network_netdev(const char *key, const char *value, |
162 | struct lxc_list *network) | |
c2cc9f0a | 163 | { |
c2cc9f0a | 164 | struct lxc_netdev *netdev; |
165 | ||
5f4535a3 | 166 | if (lxc_list_empty(network)) { |
16950ecb DL |
167 | ERROR("network is not created for '%s' = '%s' option", |
168 | key, value); | |
33c945e0 | 169 | return NULL; |
c2cc9f0a | 170 | } |
171 | ||
5f4535a3 DL |
172 | netdev = lxc_list_first_elem(network); |
173 | if (!netdev) { | |
16950ecb DL |
174 | ERROR("no network device defined for '%s' = '%s' option", |
175 | key, value); | |
33c945e0 | 176 | return NULL; |
c2cc9f0a | 177 | } |
178 | ||
33c945e0 | 179 | return netdev; |
c2cc9f0a | 180 | } |
181 | ||
33c945e0 | 182 | static int network_ifname(char **valuep, char *value) |
c2cc9f0a | 183 | { |
c2cc9f0a | 184 | if (strlen(value) > IFNAMSIZ) { |
36eb9bde | 185 | ERROR("invalid interface name: %s", value); |
c2cc9f0a | 186 | return -1; |
187 | } | |
188 | ||
33c945e0 | 189 | *valuep = strdup(value); |
16950ecb DL |
190 | if (!*valuep) { |
191 | ERROR("failed to dup string '%s'", value); | |
192 | return -1; | |
193 | } | |
33c945e0 | 194 | |
c2cc9f0a | 195 | return 0; |
196 | } | |
197 | ||
e892973e DL |
198 | #ifndef MACVLAN_MODE_PRIVATE |
199 | # define MACVLAN_MODE_PRIVATE 1 | |
200 | #endif | |
201 | ||
202 | #ifndef MACVLAN_MODE_VEPA | |
203 | # define MACVLAN_MODE_VEPA 2 | |
204 | #endif | |
205 | ||
206 | #ifndef MACVLAN_MODE_BRIDGE | |
207 | # define MACVLAN_MODE_BRIDGE 4 | |
208 | #endif | |
209 | ||
210 | static int macvlan_mode(int *valuep, char *value) | |
211 | { | |
212 | struct mc_mode { | |
213 | char *name; | |
214 | int mode; | |
215 | } m[] = { | |
216 | { "private", MACVLAN_MODE_PRIVATE }, | |
217 | { "vepa", MACVLAN_MODE_VEPA }, | |
218 | { "bridge", MACVLAN_MODE_BRIDGE }, | |
219 | }; | |
220 | ||
221 | int i; | |
222 | ||
223 | for (i = 0; i < sizeof(m)/sizeof(m[0]); i++) { | |
224 | if (strcmp(m[i].name, value)) | |
225 | continue; | |
226 | ||
227 | *valuep = m[i].mode; | |
228 | return 0; | |
229 | } | |
230 | ||
231 | return -1; | |
232 | } | |
233 | ||
33c945e0 MT |
234 | static int config_network_flags(const char *key, char *value, |
235 | struct lxc_conf *lxc_conf) | |
c2cc9f0a | 236 | { |
c2cc9f0a | 237 | struct lxc_netdev *netdev; |
238 | ||
16950ecb | 239 | netdev = network_netdev(key, value, &lxc_conf->network); |
33c945e0 | 240 | if (!netdev) |
c2cc9f0a | 241 | return -1; |
c2cc9f0a | 242 | |
33c945e0 | 243 | netdev->flags |= IFF_UP; |
c2cc9f0a | 244 | |
33c945e0 MT |
245 | return 0; |
246 | } | |
247 | ||
248 | static int config_network_link(const char *key, char *value, | |
249 | struct lxc_conf *lxc_conf) | |
250 | { | |
251 | struct lxc_netdev *netdev; | |
252 | ||
16950ecb | 253 | netdev = network_netdev(key, value, &lxc_conf->network); |
33c945e0 | 254 | if (!netdev) |
c2cc9f0a | 255 | return -1; |
c2cc9f0a | 256 | |
33c945e0 | 257 | return network_ifname(&netdev->link, value); |
c2cc9f0a | 258 | } |
259 | ||
33c945e0 MT |
260 | static int config_network_name(const char *key, char *value, |
261 | struct lxc_conf *lxc_conf) | |
c2cc9f0a | 262 | { |
c2cc9f0a | 263 | struct lxc_netdev *netdev; |
264 | ||
16950ecb | 265 | netdev = network_netdev(key, value, &lxc_conf->network); |
33c945e0 | 266 | if (!netdev) |
c2cc9f0a | 267 | return -1; |
c2cc9f0a | 268 | |
33c945e0 MT |
269 | return network_ifname(&netdev->name, value); |
270 | } | |
271 | ||
e892973e DL |
272 | static int config_network_veth_pair(const char *key, char *value, |
273 | struct lxc_conf *lxc_conf) | |
274 | { | |
275 | struct lxc_netdev *netdev; | |
276 | ||
277 | netdev = network_netdev(key, value, &lxc_conf->network); | |
278 | if (!netdev) | |
279 | return -1; | |
280 | ||
281 | return network_ifname(&netdev->priv.veth_attr.pair, value); | |
282 | } | |
283 | ||
284 | static int config_network_macvlan_mode(const char *key, char *value, | |
285 | struct lxc_conf *lxc_conf) | |
8634bc19 MT |
286 | { |
287 | struct lxc_netdev *netdev; | |
288 | ||
289 | netdev = network_netdev(key, value, &lxc_conf->network); | |
290 | if (!netdev) | |
291 | return -1; | |
292 | ||
e892973e | 293 | return macvlan_mode(&netdev->priv.macvlan_attr.mode, value); |
8634bc19 MT |
294 | } |
295 | ||
33c945e0 MT |
296 | static int config_network_hwaddr(const char *key, char *value, |
297 | struct lxc_conf *lxc_conf) | |
298 | { | |
299 | struct lxc_netdev *netdev; | |
300 | ||
16950ecb | 301 | netdev = network_netdev(key, value, &lxc_conf->network); |
33c945e0 | 302 | if (!netdev) |
c2cc9f0a | 303 | return -1; |
c2cc9f0a | 304 | |
c2cc9f0a | 305 | netdev->hwaddr = strdup(value); |
16950ecb DL |
306 | if (!netdev->hwaddr) { |
307 | SYSERROR("failed to dup string '%s'", value); | |
308 | return -1; | |
309 | } | |
33c945e0 | 310 | |
c2cc9f0a | 311 | return 0; |
312 | } | |
313 | ||
e892973e | 314 | static int config_network_vlan_id(const char *key, char *value, |
26c39028 JHS |
315 | struct lxc_conf *lxc_conf) |
316 | { | |
317 | struct lxc_netdev *netdev; | |
318 | ||
319 | netdev = network_netdev(key, value, &lxc_conf->network); | |
320 | if (!netdev) | |
321 | return -1; | |
322 | ||
f6cc1de1 | 323 | if (get_u16(&netdev->priv.vlan_attr.vid, value, 0)) |
26c39028 JHS |
324 | return -1; |
325 | ||
326 | return 0; | |
327 | } | |
328 | ||
33c945e0 MT |
329 | static int config_network_mtu(const char *key, char *value, |
330 | struct lxc_conf *lxc_conf) | |
442cbbe6 | 331 | { |
442cbbe6 TR |
332 | struct lxc_netdev *netdev; |
333 | ||
16950ecb | 334 | netdev = network_netdev(key, value, &lxc_conf->network); |
33c945e0 | 335 | if (!netdev) |
442cbbe6 | 336 | return -1; |
442cbbe6 | 337 | |
442cbbe6 | 338 | netdev->mtu = strdup(value); |
16950ecb DL |
339 | if (!netdev->mtu) { |
340 | SYSERROR("failed to dup string '%s'", value); | |
341 | return -1; | |
342 | } | |
33c945e0 | 343 | |
442cbbe6 TR |
344 | return 0; |
345 | } | |
346 | ||
33c945e0 MT |
347 | static int config_network_ipv4(const char *key, char *value, |
348 | struct lxc_conf *lxc_conf) | |
c2cc9f0a | 349 | { |
c2cc9f0a | 350 | struct lxc_netdev *netdev; |
33c945e0 | 351 | struct lxc_inetdev *inetdev; |
c2cc9f0a | 352 | struct lxc_list *list; |
353 | char *cursor, *slash, *addr = NULL, *bcast = NULL, *prefix = NULL; | |
354 | ||
16950ecb | 355 | netdev = network_netdev(key, value, &lxc_conf->network); |
33c945e0 | 356 | if (!netdev) |
c2cc9f0a | 357 | return -1; |
c2cc9f0a | 358 | |
359 | inetdev = malloc(sizeof(*inetdev)); | |
360 | if (!inetdev) { | |
36eb9bde | 361 | SYSERROR("failed to allocate ipv4 address"); |
c2cc9f0a | 362 | return -1; |
363 | } | |
364 | memset(inetdev, 0, sizeof(*inetdev)); | |
365 | ||
366 | list = malloc(sizeof(*list)); | |
367 | if (!list) { | |
36eb9bde | 368 | SYSERROR("failed to allocate memory"); |
c2cc9f0a | 369 | return -1; |
370 | } | |
371 | ||
372 | lxc_list_init(list); | |
373 | list->elem = inetdev; | |
374 | ||
375 | addr = value; | |
376 | ||
377 | cursor = strstr(addr, " "); | |
378 | if (cursor) { | |
379 | *cursor = '\0'; | |
380 | bcast = cursor + 1; | |
381 | } | |
382 | ||
383 | slash = strstr(addr, "/"); | |
384 | if (slash) { | |
385 | *slash = '\0'; | |
386 | prefix = slash + 1; | |
387 | } | |
388 | ||
389 | if (!addr) { | |
36eb9bde | 390 | ERROR("no address specified"); |
c2cc9f0a | 391 | return -1; |
392 | } | |
393 | ||
394 | if (!inet_pton(AF_INET, addr, &inetdev->addr)) { | |
36eb9bde | 395 | SYSERROR("invalid ipv4 address: %s", value); |
c2cc9f0a | 396 | return -1; |
397 | } | |
398 | ||
399 | if (bcast) | |
400 | if (!inet_pton(AF_INET, bcast, &inetdev->bcast)) { | |
36eb9bde | 401 | SYSERROR("invalid ipv4 address: %s", value); |
c2cc9f0a | 402 | return -1; |
403 | } | |
404 | ||
a059591e DL |
405 | /* no prefix specified, determine it from the network class */ |
406 | inetdev->prefix = prefix ? atoi(prefix) : | |
407 | config_ip_prefix(&inetdev->addr); | |
408 | ||
c2cc9f0a | 409 | |
410 | lxc_list_add(&netdev->ipv4, list); | |
411 | ||
412 | return 0; | |
413 | } | |
414 | ||
e892973e DL |
415 | static int config_network_ipv6(const char *key, char *value, |
416 | struct lxc_conf *lxc_conf) | |
c2cc9f0a | 417 | { |
c2cc9f0a | 418 | struct lxc_netdev *netdev; |
419 | struct lxc_inet6dev *inet6dev; | |
420 | struct lxc_list *list; | |
421 | char *slash; | |
422 | char *netmask; | |
423 | ||
16950ecb | 424 | netdev = network_netdev(key, value, &lxc_conf->network); |
33c945e0 | 425 | if (!netdev) |
c2cc9f0a | 426 | return -1; |
c2cc9f0a | 427 | |
428 | inet6dev = malloc(sizeof(*inet6dev)); | |
429 | if (!inet6dev) { | |
36eb9bde | 430 | SYSERROR("failed to allocate ipv6 address"); |
c2cc9f0a | 431 | return -1; |
432 | } | |
433 | memset(inet6dev, 0, sizeof(*inet6dev)); | |
434 | ||
435 | list = malloc(sizeof(*list)); | |
436 | if (!list) { | |
36eb9bde | 437 | SYSERROR("failed to allocate memory"); |
c2cc9f0a | 438 | return -1; |
439 | } | |
440 | ||
441 | lxc_list_init(list); | |
442 | list->elem = inet6dev; | |
443 | ||
a059591e | 444 | inet6dev->prefix = 64; |
c2cc9f0a | 445 | slash = strstr(value, "/"); |
446 | if (slash) { | |
447 | *slash = '\0'; | |
448 | netmask = slash + 1; | |
449 | inet6dev->prefix = atoi(netmask); | |
450 | } | |
451 | ||
452 | if (!inet_pton(AF_INET6, value, &inet6dev->addr)) { | |
36eb9bde | 453 | SYSERROR("invalid ipv6 address: %s", value); |
c2cc9f0a | 454 | return -1; |
455 | } | |
456 | ||
c2cc9f0a | 457 | lxc_list_add(&netdev->ipv6, list); |
458 | ||
459 | return 0; | |
460 | } | |
461 | ||
10db618d | 462 | static int config_pts(const char *key, char *value, struct lxc_conf *lxc_conf) |
463 | { | |
464 | int maxpts = atoi(value); | |
465 | ||
466 | lxc_conf->pts = maxpts; | |
467 | ||
468 | return 0; | |
469 | } | |
470 | ||
b0a33c1e | 471 | static int config_tty(const char *key, char *value, struct lxc_conf *lxc_conf) |
472 | { | |
473 | int nbtty = atoi(value); | |
474 | ||
475 | lxc_conf->tty = nbtty; | |
476 | ||
477 | return 0; | |
478 | } | |
479 | ||
576f946d | 480 | static int config_cgroup(const char *key, char *value, struct lxc_conf *lxc_conf) |
481 | { | |
482 | char *token = "lxc.cgroup."; | |
483 | char *subkey; | |
484 | struct lxc_list *cglist; | |
485 | struct lxc_cgroup *cgelem; | |
486 | ||
487 | subkey = strstr(key, token); | |
488 | ||
489 | if (!subkey) | |
490 | return -1; | |
491 | ||
492 | if (!strlen(subkey)) | |
493 | return -1; | |
494 | ||
495 | if (strlen(subkey) == strlen(token)) | |
496 | return -1; | |
a871ff6b | 497 | |
576f946d | 498 | subkey += strlen(token); |
499 | ||
500 | cglist = malloc(sizeof(*cglist)); | |
501 | if (!cglist) | |
502 | return -1; | |
503 | ||
504 | cgelem = malloc(sizeof(*cgelem)); | |
505 | if (!cgelem) { | |
506 | free(cglist); | |
507 | return -1; | |
508 | } | |
509 | ||
510 | cgelem->subsystem = strdup(subkey); | |
511 | cgelem->value = strdup(value); | |
512 | cglist->elem = cgelem; | |
513 | ||
94d12f0a | 514 | lxc_list_add_tail(&lxc_conf->cgroup, cglist); |
576f946d | 515 | |
516 | return 0; | |
517 | } | |
518 | ||
e7938e9e | 519 | static int config_fstab(const char *key, char *value, struct lxc_conf *lxc_conf) |
c2cc9f0a | 520 | { |
521 | if (strlen(value) >= MAXPATHLEN) { | |
36eb9bde | 522 | ERROR("%s path is too long", value); |
c2cc9f0a | 523 | return -1; |
524 | } | |
525 | ||
526 | lxc_conf->fstab = strdup(value); | |
527 | if (!lxc_conf->fstab) { | |
36eb9bde | 528 | SYSERROR("failed to duplicate string %s", value); |
c2cc9f0a | 529 | return -1; |
530 | } | |
531 | ||
532 | return 0; | |
533 | } | |
534 | ||
e7938e9e MN |
535 | static int config_mount(const char *key, char *value, struct lxc_conf *lxc_conf) |
536 | { | |
537 | char *fstab_token = "lxc.mount"; | |
538 | char *token = "lxc.mount.entry"; | |
539 | char *subkey; | |
540 | char *mntelem; | |
541 | struct lxc_list *mntlist; | |
542 | ||
543 | subkey = strstr(key, token); | |
544 | ||
545 | if (!subkey) { | |
546 | subkey = strstr(key, fstab_token); | |
547 | ||
548 | if (!subkey) | |
549 | return -1; | |
550 | ||
551 | return config_fstab(key, value, lxc_conf); | |
552 | } | |
553 | ||
554 | if (!strlen(subkey)) | |
555 | return -1; | |
556 | ||
557 | mntlist = malloc(sizeof(*mntlist)); | |
558 | if (!mntlist) | |
559 | return -1; | |
560 | ||
561 | mntelem = strdup(value); | |
562 | mntlist->elem = mntelem; | |
563 | ||
564 | lxc_list_add_tail(&lxc_conf->mount_list, mntlist); | |
565 | ||
566 | return 0; | |
567 | } | |
568 | ||
576f946d | 569 | static int config_rootfs(const char *key, char *value, struct lxc_conf *lxc_conf) |
c2cc9f0a | 570 | { |
571 | if (strlen(value) >= MAXPATHLEN) { | |
36eb9bde | 572 | ERROR("%s path is too long", value); |
c2cc9f0a | 573 | return -1; |
574 | } | |
575 | ||
eae6543d | 576 | lxc_conf->rootfs = strdup(value); |
577 | if (!lxc_conf->rootfs) { | |
36eb9bde | 578 | SYSERROR("failed to duplicate string %s", value); |
c2cc9f0a | 579 | return -1; |
580 | } | |
581 | ||
582 | return 0; | |
583 | } | |
584 | ||
bf601689 MH |
585 | static int config_pivotdir(const char *key, char *value, struct lxc_conf *lxc_conf) |
586 | { | |
587 | if (strlen(value) >= MAXPATHLEN) { | |
588 | ERROR("%s path is too long", value); | |
589 | return -1; | |
590 | } | |
591 | ||
592 | lxc_conf->pivotdir = strdup(value); | |
593 | if (!lxc_conf->pivotdir) { | |
594 | SYSERROR("failed to duplicate string %s", value); | |
595 | return -1; | |
596 | } | |
597 | ||
598 | return 0; | |
599 | } | |
600 | ||
576f946d | 601 | static int config_utsname(const char *key, char *value, struct lxc_conf *lxc_conf) |
c2cc9f0a | 602 | { |
603 | struct utsname *utsname; | |
604 | ||
605 | utsname = malloc(sizeof(*utsname)); | |
606 | if (!utsname) { | |
36eb9bde | 607 | SYSERROR("failed to allocate memory"); |
c2cc9f0a | 608 | return -1; |
609 | } | |
610 | ||
611 | if (strlen(value) >= sizeof(utsname->nodename)) { | |
36eb9bde | 612 | ERROR("node name '%s' is too long", |
c2cc9f0a | 613 | utsname->nodename); |
614 | return -1; | |
615 | } | |
616 | ||
617 | strcpy(utsname->nodename, value); | |
618 | lxc_conf->utsname = utsname; | |
619 | ||
620 | return 0; | |
621 | } | |
622 | ||
7a7ff0c6 | 623 | static int parse_line(char *buffer, void *data) |
c2cc9f0a | 624 | { |
625 | struct config *config; | |
b2718c72 | 626 | char *line = buffer; |
c2cc9f0a | 627 | char *dot; |
628 | char *key; | |
629 | char *value; | |
630 | ||
b2718c72 | 631 | if (lxc_is_line_empty(line)) |
c2cc9f0a | 632 | return 0; |
633 | ||
b2718c72 | 634 | line += lxc_char_left_gc(line, strlen(line)); |
635 | if (line[0] == '#') | |
c2cc9f0a | 636 | return 0; |
637 | ||
b2718c72 | 638 | dot = strstr(line, "="); |
c2cc9f0a | 639 | if (!dot) { |
36eb9bde | 640 | ERROR("invalid configuration line: %s", line); |
c2cc9f0a | 641 | return -1; |
642 | } | |
a871ff6b | 643 | |
c2cc9f0a | 644 | *dot = '\0'; |
645 | value = dot + 1; | |
646 | ||
b2718c72 | 647 | key = line; |
648 | key[lxc_char_right_gc(key, strlen(key))] = '\0'; | |
c2cc9f0a | 649 | |
b2718c72 | 650 | value += lxc_char_left_gc(value, strlen(value)); |
651 | value[lxc_char_right_gc(value, strlen(value))] = '\0'; | |
c2cc9f0a | 652 | |
653 | config = getconfig(key); | |
654 | if (!config) { | |
36eb9bde | 655 | ERROR("unknow key %s", key); |
c2cc9f0a | 656 | return -1; |
657 | } | |
658 | ||
576f946d | 659 | return config->cb(key, value, data); |
c2cc9f0a | 660 | } |
661 | ||
af5b0155 CLG |
662 | int lxc_config_readline(char *buffer, struct lxc_conf *conf) |
663 | { | |
664 | return parse_line(buffer, conf); | |
665 | } | |
666 | ||
b2718c72 | 667 | int lxc_config_read(const char *file, struct lxc_conf *conf) |
c2cc9f0a | 668 | { |
2382ecff | 669 | return lxc_file_for_each_line(file, parse_line, conf); |
c2cc9f0a | 670 | } |
62e46035 CLG |
671 | |
672 | int lxc_config_define_add(struct lxc_list *defines, char* arg) | |
673 | { | |
674 | struct lxc_list *dent; | |
675 | ||
676 | dent = malloc(sizeof(struct lxc_list)); | |
677 | if (!dent) | |
678 | return -1; | |
679 | ||
680 | dent->elem = arg; | |
681 | lxc_list_add_tail(defines, dent); | |
682 | return 0; | |
683 | } | |
684 | ||
226a18d6 | 685 | int lxc_config_define_load(struct lxc_list *defines, struct lxc_conf *conf) |
62e46035 CLG |
686 | { |
687 | struct lxc_list *it; | |
688 | int ret = 0; | |
689 | ||
690 | lxc_list_for_each(it, defines) { | |
691 | ret = lxc_config_readline(it->elem, conf); | |
692 | if (ret) | |
693 | break; | |
694 | } | |
695 | ||
696 | lxc_list_for_each(it, defines) { | |
697 | lxc_list_del(it); | |
698 | free(it); | |
699 | } | |
700 | ||
701 | return ret; | |
702 | } |