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