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