]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/confile.c
lxc.sgml.in: Fix typo in man page.
[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:
9afe19d6 7 * Daniel Lezcano <daniel.lezcano at free.fr>
c2cc9f0a 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 */
12a50cc6 23#define _GNU_SOURCE
c2cc9f0a 24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27#include <unistd.h>
28#include <errno.h>
63376d7d 29#include <fcntl.h>
a84b9932
AV
30#include <ctype.h>
31#include <signal.h>
63376d7d 32#include <sys/stat.h>
c2cc9f0a 33#include <sys/types.h>
34#include <sys/param.h>
35#include <sys/utsname.h>
36#include <arpa/inet.h>
37#include <netinet/in.h>
38#include <net/if.h>
39
b2718c72 40#include "parse.h"
6ff05e18 41#include "config.h"
525f0002 42#include "confile.h"
26c39028 43#include "utils.h"
c2cc9f0a 44
36eb9bde 45#include <lxc/log.h>
00b3c2e2 46#include <lxc/conf.h>
72d0e1cb 47#include "network.h"
36eb9bde 48
6ff05e18
SG
49#if HAVE_SYS_PERSONALITY_H
50#include <sys/personality.h>
51#endif
52
36eb9bde 53lxc_log_define(lxc_confile, lxc);
576f946d 54
12a50cc6
DE
55static int config_personality(const char *, const char *, struct lxc_conf *);
56static int config_pts(const char *, const char *, struct lxc_conf *);
57static int config_tty(const char *, const char *, struct lxc_conf *);
58static int config_ttydir(const char *, const char *, struct lxc_conf *);
7e0e1d94 59static int config_kmsg(const char *, const char *, struct lxc_conf *);
e075f5d9 60#if HAVE_APPARMOR
12a50cc6 61static int config_aa_profile(const char *, const char *, struct lxc_conf *);
e075f5d9 62#endif
12a50cc6 63static int config_cgroup(const char *, const char *, struct lxc_conf *);
f6d3e3e4 64static int config_idmap(const char *, const char *, struct lxc_conf *);
4a85ce2a
SH
65static int config_loglevel(const char *, const char *, struct lxc_conf *);
66static int config_logfile(const char *, const char *, struct lxc_conf *);
12a50cc6
DE
67static int config_mount(const char *, const char *, struct lxc_conf *);
68static int config_rootfs(const char *, const char *, struct lxc_conf *);
69static int config_rootfs_mount(const char *, const char *, struct lxc_conf *);
70static int config_pivotdir(const char *, const char *, struct lxc_conf *);
71static int config_utsname(const char *, const char *, struct lxc_conf *);
72static int config_hook(const char *, const char *, struct lxc_conf *lxc_conf);
73static int config_network_type(const char *, const char *, struct lxc_conf *);
74static int config_network_flags(const char *, const char *, struct lxc_conf *);
75static int config_network_link(const char *, const char *, struct lxc_conf *);
76static int config_network_name(const char *, const char *, struct lxc_conf *);
77static int config_network_veth_pair(const char *, const char *, struct lxc_conf *);
78static int config_network_macvlan_mode(const char *, const char *, struct lxc_conf *);
79static int config_network_hwaddr(const char *, const char *, struct lxc_conf *);
80static int config_network_vlan_id(const char *, const char *, struct lxc_conf *);
81static int config_network_mtu(const char *, const char *, struct lxc_conf *);
82static int config_network_ipv4(const char *, const char *, struct lxc_conf *);
83static int config_network_ipv4_gateway(const char *, const char *, struct lxc_conf *);
84static int config_network_script(const char *, const char *, struct lxc_conf *);
85static int config_network_ipv6(const char *, const char *, struct lxc_conf *);
86static int config_network_ipv6_gateway(const char *, const char *, struct lxc_conf *);
87static int config_cap_drop(const char *, const char *, struct lxc_conf *);
88static int config_console(const char *, const char *, struct lxc_conf *);
89static int config_seccomp(const char *, const char *, struct lxc_conf *);
90static int config_includefile(const char *, const char *, struct lxc_conf *);
91static int config_network_nic(const char *, const char *, struct lxc_conf *);
92static int config_autodev(const char *, const char *, struct lxc_conf *);
a84b9932 93static int config_stopsignal(const char *, const char *, struct lxc_conf *);
c2cc9f0a 94
72d0e1cb 95static struct lxc_config_t config[] = {
576f946d 96
cccc74b5 97 { "lxc.arch", config_personality },
e892973e
DL
98 { "lxc.pts", config_pts },
99 { "lxc.tty", config_tty },
7c6ef2a2 100 { "lxc.devttydir", config_ttydir },
7e0e1d94 101 { "lxc.kmsg", config_kmsg },
e075f5d9
SH
102#if HAVE_APPARMOR
103 { "lxc.aa_profile", config_aa_profile },
104#endif
e892973e 105 { "lxc.cgroup", config_cgroup },
f6d3e3e4 106 { "lxc.id_map", config_idmap },
4a85ce2a
SH
107 { "lxc.loglevel", config_loglevel },
108 { "lxc.logfile", config_logfile },
e892973e 109 { "lxc.mount", config_mount },
23b7ea69 110 { "lxc.rootfs.mount", config_rootfs_mount },
e892973e 111 { "lxc.rootfs", config_rootfs },
bf601689 112 { "lxc.pivotdir", config_pivotdir },
e892973e 113 { "lxc.utsname", config_utsname },
26ddeedd 114 { "lxc.hook.pre-start", config_hook },
12a50cc6 115 { "lxc.hook.pre-mount", config_hook },
26ddeedd 116 { "lxc.hook.mount", config_hook },
f7bee6c6 117 { "lxc.hook.autodev", config_hook },
26ddeedd
SH
118 { "lxc.hook.start", config_hook },
119 { "lxc.hook.post-stop", config_hook },
e892973e
DL
120 { "lxc.network.type", config_network_type },
121 { "lxc.network.flags", config_network_flags },
122 { "lxc.network.link", config_network_link },
123 { "lxc.network.name", config_network_name },
124 { "lxc.network.macvlan.mode", config_network_macvlan_mode },
125 { "lxc.network.veth.pair", config_network_veth_pair },
e3b4c4c4 126 { "lxc.network.script.up", config_network_script },
74a2b586 127 { "lxc.network.script.down", config_network_script },
e892973e
DL
128 { "lxc.network.hwaddr", config_network_hwaddr },
129 { "lxc.network.mtu", config_network_mtu },
130 { "lxc.network.vlan.id", config_network_vlan_id },
f8fee0e2 131 { "lxc.network.ipv4.gateway", config_network_ipv4_gateway },
e892973e 132 { "lxc.network.ipv4", config_network_ipv4 },
f8fee0e2 133 { "lxc.network.ipv6.gateway", config_network_ipv6_gateway },
e892973e 134 { "lxc.network.ipv6", config_network_ipv6 },
72d0e1cb
SG
135 /* config_network_nic must come after all other 'lxc.network.*' entries */
136 { "lxc.network.", config_network_nic },
81810dd1 137 { "lxc.cap.drop", config_cap_drop },
63376d7d 138 { "lxc.console", config_console },
8f2c3a70 139 { "lxc.seccomp", config_seccomp },
09ad6246 140 { "lxc.include", config_includefile },
c6883f38 141 { "lxc.autodev", config_autodev },
a84b9932
AV
142 { "lxc.stopsignal", config_stopsignal },
143};
144
145struct signame {
146 int num;
147 char *name;
148};
149
150struct signame signames[] = {
151 { SIGHUP, "HUP" },
152 { SIGINT, "INT" },
153 { SIGQUIT, "QUIT" },
154 { SIGILL, "ILL" },
155 { SIGABRT, "ABRT" },
156 { SIGFPE, "FPE" },
157 { SIGKILL, "KILL" },
158 { SIGSEGV, "SEGV" },
159 { SIGPIPE, "PIPE" },
160 { SIGALRM, "ALRM" },
161 { SIGTERM, "TERM" },
162 { SIGUSR1, "USR1" },
163 { SIGUSR2, "USR2" },
164 { SIGCHLD, "CHLD" },
165 { SIGCONT, "CONT" },
166 { SIGSTOP, "STOP" },
167 { SIGTSTP, "TSTP" },
168 { SIGTTIN, "TTIN" },
169 { SIGTTOU, "TTOU" },
c2cc9f0a 170};
171
72d0e1cb 172static const size_t config_size = sizeof(config)/sizeof(struct lxc_config_t);
c2cc9f0a 173
72d0e1cb 174extern struct lxc_config_t *lxc_getconfig(const char *key)
c2cc9f0a 175{
176 int i;
177
178 for (i = 0; i < config_size; i++)
a871ff6b 179 if (!strncmp(config[i].name, key,
c2cc9f0a 180 strlen(config[i].name)))
181 return &config[i];
182 return NULL;
183}
184
72d0e1cb
SG
185#define strprint(str, inlen, ...) \
186 do { \
187 len = snprintf(str, inlen, ##__VA_ARGS__); \
188 if (len < 0) { SYSERROR("snprintf"); return -1; }; \
189 fulllen += len; \
190 if (inlen > 0) { \
191 if (str) str += len; \
192 inlen -= len; \
193 if (inlen < 0) inlen = 0; \
194 } \
195 } while (0);
196
197int lxc_listconfigs(char *retv, int inlen)
198{
199 int i, fulllen = 0, len;
200
201 if (!retv)
202 inlen = 0;
203 else
204 memset(retv, 0, inlen);
205 for (i = 0; i < config_size; i++) {
206 char *s = config[i].name;
207 if (s[strlen(s)-1] == '.')
208 continue;
209 strprint(retv, inlen, "%s\n", s);
210 }
211 return fulllen;
212}
213
214/*
215 * config entry is something like "lxc.network.0.ipv4"
216 * the key 'lxc.network.' was found. So we make sure next
217 * comes an integer, find the right callback (by rewriting
218 * the key), and call it.
219 */
12a50cc6 220static int config_network_nic(const char *key, const char *value,
72d0e1cb
SG
221 struct lxc_conf *lxc_conf)
222{
223 char *copy = strdup(key), *p;
224 int ret = -1;
225 struct lxc_config_t *config;
226
227 if (!copy) {
228 SYSERROR("failed to allocate memory");
229 return -1;
230 }
231 /*
232 * ok we know that to get here we've got "lxc.network."
233 * and it isn't any of the other network entries. So
234 * after the second . should come an integer (# of defined
235 * nic) followed by a valid entry.
236 */
237 if (*(key+12) < '0' || *(key+12) > '9')
238 goto out;
239 p = index(key+12, '.');
240 if (!p)
241 goto out;
242 strcpy(copy+12, p+1);
243 config = lxc_getconfig(copy);
244 if (!config) {
245 ERROR("unknown key %s", key);
246 goto out;
247 }
248 ret = config->cb(key, value, lxc_conf);
249
250out:
251 free(copy);
252 return ret;
253}
254
12a50cc6 255static int config_network_type(const char *key, const char *value,
e892973e 256 struct lxc_conf *lxc_conf)
c2cc9f0a 257{
5f4535a3 258 struct lxc_list *network = &lxc_conf->network;
c2cc9f0a 259 struct lxc_netdev *netdev;
260 struct lxc_list *list;
c2cc9f0a 261
262 netdev = malloc(sizeof(*netdev));
263 if (!netdev) {
36eb9bde 264 SYSERROR("failed to allocate memory");
c2cc9f0a 265 return -1;
266 }
267
82d5ae15 268 memset(netdev, 0, sizeof(*netdev));
c2cc9f0a 269 lxc_list_init(&netdev->ipv4);
270 lxc_list_init(&netdev->ipv6);
c2cc9f0a 271
272 list = malloc(sizeof(*list));
273 if (!list) {
36eb9bde 274 SYSERROR("failed to allocate memory");
c2cc9f0a 275 return -1;
276 }
277
278 lxc_list_init(list);
5f4535a3 279 list->elem = netdev;
c2cc9f0a 280
bac89583 281 lxc_list_add_tail(network, list);
a871ff6b 282
c2cc9f0a 283 if (!strcmp(value, "veth"))
24654103 284 netdev->type = LXC_NET_VETH;
c2cc9f0a 285 else if (!strcmp(value, "macvlan"))
24654103 286 netdev->type = LXC_NET_MACVLAN;
26c39028 287 else if (!strcmp(value, "vlan"))
24654103 288 netdev->type = LXC_NET_VLAN;
c2cc9f0a 289 else if (!strcmp(value, "phys"))
24654103 290 netdev->type = LXC_NET_PHYS;
5f58350a 291 else if (!strcmp(value, "empty"))
24654103 292 netdev->type = LXC_NET_EMPTY;
c2cc9f0a 293 else {
36eb9bde 294 ERROR("invalid network type %s", value);
c2cc9f0a 295 return -1;
296 }
297 return 0;
298}
299
a059591e
DL
300static int config_ip_prefix(struct in_addr *addr)
301{
302 if (IN_CLASSA(addr->s_addr))
303 return 32 - IN_CLASSA_NSHIFT;
304 if (IN_CLASSB(addr->s_addr))
305 return 32 - IN_CLASSB_NSHIFT;
306 if (IN_CLASSC(addr->s_addr))
307 return 32 - IN_CLASSC_NSHIFT;
308
309 return 0;
310}
311
72d0e1cb
SG
312/*
313 * if you have p="lxc.network.0.link", pass it p+12
314 * to get back '0' (the index of the nic)
315 */
316static int get_network_netdev_idx(const char *key)
317{
318 int ret, idx;
319
320 if (*key < '0' || *key > '9')
321 return -1;
322 ret = sscanf(key, "%d", &idx);
323 if (ret != 1)
324 return -1;
325 return idx;
326}
327
328/*
329 * if you have p="lxc.network.0", pass this p+12 and it will return
330 * the netdev of the first configured nic
331 */
332static struct lxc_netdev *get_netdev_from_key(const char *key,
333 struct lxc_list *network)
334{
335 int i = 0, idx = get_network_netdev_idx(key);
336 struct lxc_netdev *netdev = NULL;
337 struct lxc_list *it;
338 if (idx == -1)
339 return NULL;
340 lxc_list_for_each(it, network) {
341 if (idx == i++) {
342 netdev = it->elem;
343 break;
344 }
345 }
346 return netdev;
347}
348
12a50cc6
DE
349extern int lxc_list_nicconfigs(struct lxc_conf *c, const char *key,
350 char *retv, int inlen)
72d0e1cb
SG
351{
352 struct lxc_netdev *netdev;
353 int fulllen = 0, len;
354
355 netdev = get_netdev_from_key(key+12, &c->network);
356 if (!netdev)
357 return -1;
358
359 if (!retv)
360 inlen = 0;
361 else
362 memset(retv, 0, inlen);
363
364 strprint(retv, inlen, "script.up\n");
365 if (netdev->type != LXC_NET_EMPTY) {
366 strprint(retv, inlen, "flags\n");
367 strprint(retv, inlen, "link\n");
368 strprint(retv, inlen, "name\n");
369 strprint(retv, inlen, "hwaddr\n");
370 strprint(retv, inlen, "mtu\n");
371 strprint(retv, inlen, "ipv6\n");
372 strprint(retv, inlen, "ipv6_gateway\n");
373 strprint(retv, inlen, "ipv4\n");
374 strprint(retv, inlen, "ipv4_gateway\n");
375 }
376 switch(netdev->type) {
377 case LXC_NET_VETH:
378 strprint(retv, inlen, "veth.pair\n");
379 break;
380 case LXC_NET_MACVLAN:
381 strprint(retv, inlen, "macvlan.mode\n");
382 break;
383 case LXC_NET_VLAN:
384 strprint(retv, inlen, "vlan.id\n");
385 break;
386 case LXC_NET_PHYS:
387 break;
388 }
389 return fulllen;
390}
391
16950ecb
DL
392static struct lxc_netdev *network_netdev(const char *key, const char *value,
393 struct lxc_list *network)
c2cc9f0a 394{
72d0e1cb 395 struct lxc_netdev *netdev = NULL;
c2cc9f0a 396
5f4535a3 397 if (lxc_list_empty(network)) {
16950ecb
DL
398 ERROR("network is not created for '%s' = '%s' option",
399 key, value);
33c945e0 400 return NULL;
c2cc9f0a 401 }
402
72d0e1cb
SG
403 if (get_network_netdev_idx(key+12) == -1)
404 netdev = lxc_list_last_elem(network);
405 else
406 netdev = get_netdev_from_key(key+12, network);
407
5f4535a3 408 if (!netdev) {
16950ecb
DL
409 ERROR("no network device defined for '%s' = '%s' option",
410 key, value);
33c945e0 411 return NULL;
c2cc9f0a 412 }
413
33c945e0 414 return netdev;
c2cc9f0a 415}
416
12a50cc6 417static int network_ifname(char **valuep, const char *value)
c2cc9f0a 418{
bf83c5b9 419 if (strlen(value) >= IFNAMSIZ) {
5480b13b
DL
420 ERROR("interface name '%s' too long (>%d)\n",
421 value, IFNAMSIZ - 1);
c2cc9f0a 422 return -1;
423 }
424
33c945e0 425 *valuep = strdup(value);
16950ecb
DL
426 if (!*valuep) {
427 ERROR("failed to dup string '%s'", value);
428 return -1;
429 }
33c945e0 430
c2cc9f0a 431 return 0;
432}
433
e892973e
DL
434#ifndef MACVLAN_MODE_PRIVATE
435# define MACVLAN_MODE_PRIVATE 1
436#endif
437
438#ifndef MACVLAN_MODE_VEPA
439# define MACVLAN_MODE_VEPA 2
440#endif
441
442#ifndef MACVLAN_MODE_BRIDGE
443# define MACVLAN_MODE_BRIDGE 4
444#endif
445
12a50cc6 446static int macvlan_mode(int *valuep, const char *value)
e892973e
DL
447{
448 struct mc_mode {
449 char *name;
450 int mode;
451 } m[] = {
452 { "private", MACVLAN_MODE_PRIVATE },
453 { "vepa", MACVLAN_MODE_VEPA },
454 { "bridge", MACVLAN_MODE_BRIDGE },
455 };
456
457 int i;
458
459 for (i = 0; i < sizeof(m)/sizeof(m[0]); i++) {
460 if (strcmp(m[i].name, value))
461 continue;
462
463 *valuep = m[i].mode;
464 return 0;
465 }
466
467 return -1;
468}
469
12a50cc6 470static int config_network_flags(const char *key, const char *value,
33c945e0 471 struct lxc_conf *lxc_conf)
c2cc9f0a 472{
c2cc9f0a 473 struct lxc_netdev *netdev;
474
16950ecb 475 netdev = network_netdev(key, value, &lxc_conf->network);
33c945e0 476 if (!netdev)
c2cc9f0a 477 return -1;
c2cc9f0a 478
33c945e0 479 netdev->flags |= IFF_UP;
c2cc9f0a 480
33c945e0
MT
481 return 0;
482}
483
12a50cc6 484static int config_network_link(const char *key, const char *value,
33c945e0
MT
485 struct lxc_conf *lxc_conf)
486{
487 struct lxc_netdev *netdev;
488
16950ecb 489 netdev = network_netdev(key, value, &lxc_conf->network);
33c945e0 490 if (!netdev)
c2cc9f0a 491 return -1;
c2cc9f0a 492
33c945e0 493 return network_ifname(&netdev->link, value);
c2cc9f0a 494}
495
12a50cc6 496static int config_network_name(const char *key, const char *value,
33c945e0 497 struct lxc_conf *lxc_conf)
c2cc9f0a 498{
c2cc9f0a 499 struct lxc_netdev *netdev;
500
16950ecb 501 netdev = network_netdev(key, value, &lxc_conf->network);
33c945e0 502 if (!netdev)
c2cc9f0a 503 return -1;
c2cc9f0a 504
33c945e0
MT
505 return network_ifname(&netdev->name, value);
506}
507
12a50cc6 508static int config_network_veth_pair(const char *key, const char *value,
e892973e
DL
509 struct lxc_conf *lxc_conf)
510{
511 struct lxc_netdev *netdev;
512
513 netdev = network_netdev(key, value, &lxc_conf->network);
514 if (!netdev)
515 return -1;
516
517 return network_ifname(&netdev->priv.veth_attr.pair, value);
518}
519
12a50cc6 520static int config_network_macvlan_mode(const char *key, const char *value,
e892973e 521 struct lxc_conf *lxc_conf)
8634bc19
MT
522{
523 struct lxc_netdev *netdev;
524
525 netdev = network_netdev(key, value, &lxc_conf->network);
526 if (!netdev)
527 return -1;
528
e892973e 529 return macvlan_mode(&netdev->priv.macvlan_attr.mode, value);
8634bc19
MT
530}
531
12a50cc6 532static int config_network_hwaddr(const char *key, const char *value,
33c945e0
MT
533 struct lxc_conf *lxc_conf)
534{
535 struct lxc_netdev *netdev;
d95db067 536 char *hwaddr;
33c945e0 537
16950ecb 538 netdev = network_netdev(key, value, &lxc_conf->network);
33c945e0 539 if (!netdev)
c2cc9f0a 540 return -1;
c2cc9f0a 541
d95db067
DE
542 hwaddr = strdup(value);
543 if (!hwaddr) {
16950ecb
DL
544 SYSERROR("failed to dup string '%s'", value);
545 return -1;
546 }
33c945e0 547
d95db067
DE
548 if (netdev->hwaddr)
549 free(netdev->hwaddr);
550 netdev->hwaddr = hwaddr;
c2cc9f0a 551 return 0;
552}
553
12a50cc6 554static int config_network_vlan_id(const char *key, const char *value,
26c39028
JHS
555 struct lxc_conf *lxc_conf)
556{
557 struct lxc_netdev *netdev;
558
559 netdev = network_netdev(key, value, &lxc_conf->network);
560 if (!netdev)
561 return -1;
562
f6cc1de1 563 if (get_u16(&netdev->priv.vlan_attr.vid, value, 0))
26c39028
JHS
564 return -1;
565
566 return 0;
567}
568
12a50cc6 569static int config_network_mtu(const char *key, const char *value,
33c945e0 570 struct lxc_conf *lxc_conf)
442cbbe6 571{
442cbbe6 572 struct lxc_netdev *netdev;
d95db067 573 char *mtu;
442cbbe6 574
16950ecb 575 netdev = network_netdev(key, value, &lxc_conf->network);
33c945e0 576 if (!netdev)
442cbbe6 577 return -1;
442cbbe6 578
d95db067
DE
579 mtu = strdup(value);
580 if (!mtu) {
16950ecb
DL
581 SYSERROR("failed to dup string '%s'", value);
582 return -1;
583 }
33c945e0 584
d95db067
DE
585 if (netdev->mtu)
586 free(netdev->mtu);
587 netdev->mtu = mtu;
442cbbe6
TR
588 return 0;
589}
590
12a50cc6 591static int config_network_ipv4(const char *key, const char *value,
33c945e0 592 struct lxc_conf *lxc_conf)
c2cc9f0a 593{
c2cc9f0a 594 struct lxc_netdev *netdev;
33c945e0 595 struct lxc_inetdev *inetdev;
c2cc9f0a 596 struct lxc_list *list;
597 char *cursor, *slash, *addr = NULL, *bcast = NULL, *prefix = NULL;
598
16950ecb 599 netdev = network_netdev(key, value, &lxc_conf->network);
33c945e0 600 if (!netdev)
c2cc9f0a 601 return -1;
c2cc9f0a 602
603 inetdev = malloc(sizeof(*inetdev));
604 if (!inetdev) {
36eb9bde 605 SYSERROR("failed to allocate ipv4 address");
c2cc9f0a 606 return -1;
607 }
608 memset(inetdev, 0, sizeof(*inetdev));
609
610 list = malloc(sizeof(*list));
611 if (!list) {
36eb9bde 612 SYSERROR("failed to allocate memory");
c2cc9f0a 613 return -1;
614 }
615
616 lxc_list_init(list);
617 list->elem = inetdev;
618
956edc54
SG
619 addr = strdup(value);
620 if (!addr) {
621 ERROR("no address specified");
622 return -1;
623 }
c2cc9f0a 624
625 cursor = strstr(addr, " ");
626 if (cursor) {
627 *cursor = '\0';
628 bcast = cursor + 1;
629 }
630
631 slash = strstr(addr, "/");
632 if (slash) {
633 *slash = '\0';
634 prefix = slash + 1;
635 }
636
c2cc9f0a 637 if (!inet_pton(AF_INET, addr, &inetdev->addr)) {
36eb9bde 638 SYSERROR("invalid ipv4 address: %s", value);
956edc54 639 free(addr);
c2cc9f0a 640 return -1;
641 }
642
0093bb8c
DL
643 if (bcast && !inet_pton(AF_INET, bcast, &inetdev->bcast)) {
644 SYSERROR("invalid ipv4 broadcast address: %s", value);
956edc54 645 free(addr);
0093bb8c
DL
646 return -1;
647 }
c2cc9f0a 648
a059591e
DL
649 /* no prefix specified, determine it from the network class */
650 inetdev->prefix = prefix ? atoi(prefix) :
651 config_ip_prefix(&inetdev->addr);
652
b3df193c 653 /* if no broadcast address, let compute one from the
0093bb8c
DL
654 * prefix and address
655 */
656 if (!bcast) {
1b7d4743
DL
657 inetdev->bcast.s_addr = inetdev->addr.s_addr;
658 inetdev->bcast.s_addr |=
659 htonl(INADDR_BROADCAST >> inetdev->prefix);
0093bb8c 660 }
c2cc9f0a 661
8538f388 662 lxc_list_add_tail(&netdev->ipv4, list);
c2cc9f0a 663
956edc54 664 free(addr);
c2cc9f0a 665 return 0;
666}
667
12a50cc6 668static int config_network_ipv4_gateway(const char *key, const char *value,
f8fee0e2
MK
669 struct lxc_conf *lxc_conf)
670{
671 struct lxc_netdev *netdev;
672 struct in_addr *gw;
673
674 netdev = network_netdev(key, value, &lxc_conf->network);
675 if (!netdev)
676 return -1;
677
678 gw = malloc(sizeof(*gw));
679 if (!gw) {
680 SYSERROR("failed to allocate ipv4 gateway address");
681 return -1;
682 }
683
684 if (!value) {
685 ERROR("no ipv4 gateway address specified");
686 return -1;
687 }
688
19a26f82
MK
689 if (!strcmp(value, "auto")) {
690 netdev->ipv4_gateway = NULL;
691 netdev->ipv4_gateway_auto = true;
692 } else {
693 if (!inet_pton(AF_INET, value, gw)) {
694 SYSERROR("invalid ipv4 gateway address: %s", value);
695 return -1;
696 }
697
698 netdev->ipv4_gateway = gw;
699 netdev->ipv4_gateway_auto = false;
f8fee0e2
MK
700 }
701
f8fee0e2
MK
702 return 0;
703}
704
12a50cc6 705static int config_network_ipv6(const char *key, const char *value,
e892973e 706 struct lxc_conf *lxc_conf)
c2cc9f0a 707{
c2cc9f0a 708 struct lxc_netdev *netdev;
709 struct lxc_inet6dev *inet6dev;
710 struct lxc_list *list;
12a50cc6 711 char *slash,*valdup;
c2cc9f0a 712 char *netmask;
713
16950ecb 714 netdev = network_netdev(key, value, &lxc_conf->network);
33c945e0 715 if (!netdev)
c2cc9f0a 716 return -1;
c2cc9f0a 717
718 inet6dev = malloc(sizeof(*inet6dev));
719 if (!inet6dev) {
36eb9bde 720 SYSERROR("failed to allocate ipv6 address");
c2cc9f0a 721 return -1;
722 }
723 memset(inet6dev, 0, sizeof(*inet6dev));
724
725 list = malloc(sizeof(*list));
726 if (!list) {
36eb9bde 727 SYSERROR("failed to allocate memory");
c2cc9f0a 728 return -1;
729 }
730
731 lxc_list_init(list);
732 list->elem = inet6dev;
733
956edc54
SG
734 valdup = strdup(value);
735 if (!valdup) {
736 ERROR("no address specified");
737 return -1;
738 }
739
a059591e 740 inet6dev->prefix = 64;
12a50cc6 741 slash = strstr(valdup, "/");
c2cc9f0a 742 if (slash) {
743 *slash = '\0';
744 netmask = slash + 1;
745 inet6dev->prefix = atoi(netmask);
746 }
747
748 if (!inet_pton(AF_INET6, value, &inet6dev->addr)) {
36eb9bde 749 SYSERROR("invalid ipv6 address: %s", value);
956edc54 750 free(valdup);
c2cc9f0a 751 return -1;
752 }
753
8538f388 754 lxc_list_add_tail(&netdev->ipv6, list);
c2cc9f0a 755
956edc54 756 free(valdup);
c2cc9f0a 757 return 0;
758}
759
12a50cc6 760static int config_network_ipv6_gateway(const char *key, const char *value,
f8fee0e2
MK
761 struct lxc_conf *lxc_conf)
762{
763 struct lxc_netdev *netdev;
764 struct in6_addr *gw;
765
766 netdev = network_netdev(key, value, &lxc_conf->network);
767 if (!netdev)
768 return -1;
769
770 gw = malloc(sizeof(*gw));
771 if (!gw) {
772 SYSERROR("failed to allocate ipv6 gateway address");
773 return -1;
774 }
775
776 if (!value) {
777 ERROR("no ipv6 gateway address specified");
778 return -1;
779 }
780
19a26f82
MK
781 if (!strcmp(value, "auto")) {
782 netdev->ipv6_gateway = NULL;
783 netdev->ipv6_gateway_auto = true;
784 } else {
785 if (!inet_pton(AF_INET6, value, gw)) {
786 SYSERROR("invalid ipv6 gateway address: %s", value);
787 return -1;
788 }
789
790 netdev->ipv6_gateway = gw;
791 netdev->ipv6_gateway_auto = false;
f8fee0e2
MK
792 }
793
f8fee0e2
MK
794 return 0;
795}
796
12a50cc6 797static int config_network_script(const char *key, const char *value,
e3b4c4c4
ST
798 struct lxc_conf *lxc_conf)
799{
800 struct lxc_netdev *netdev;
801
802 netdev = network_netdev(key, value, &lxc_conf->network);
803 if (!netdev)
804 return -1;
805
806 char *copy = strdup(value);
807 if (!copy) {
808 SYSERROR("failed to dup string '%s'", value);
809 return -1;
810 }
72d0e1cb 811 if (strstr(key, "script.up") != NULL) {
e3b4c4c4
ST
812 netdev->upscript = copy;
813 return 0;
814 }
74a2b586
JK
815 if (strcmp(key, "lxc.network.script.down") == 0) {
816 netdev->downscript = copy;
817 return 0;
818 }
e3b4c4c4
ST
819 SYSERROR("Unknown key: %s", key);
820 free(copy);
821 return -1;
822}
823
26ddeedd
SH
824static int add_hook(struct lxc_conf *lxc_conf, int which, char *hook)
825{
826 struct lxc_list *hooklist;
827
828 hooklist = malloc(sizeof(*hooklist));
829 if (!hooklist) {
830 free(hook);
831 return -1;
832 }
833 hooklist->elem = hook;
834 lxc_list_add_tail(&lxc_conf->hooks[which], hooklist);
835 return 0;
836}
837
12a50cc6 838static int config_seccomp(const char *key, const char *value,
8f2c3a70
SH
839 struct lxc_conf *lxc_conf)
840{
841 char *path;
842
843 if (lxc_conf->seccomp) {
844 ERROR("seccomp already defined");
845 return -1;
846 }
847 path = strdup(value);
848 if (!path) {
849 SYSERROR("failed to strdup '%s': %m", value);
850 return -1;
851 }
852
d95db067
DE
853 if (lxc_conf->seccomp)
854 free(lxc_conf->seccomp);
8f2c3a70
SH
855 lxc_conf->seccomp = path;
856
857 return 0;
858}
859
12a50cc6 860static int config_hook(const char *key, const char *value,
26ddeedd
SH
861 struct lxc_conf *lxc_conf)
862{
863 char *copy = strdup(value);
864 if (!copy) {
865 SYSERROR("failed to dup string '%s'", value);
866 return -1;
867 }
868 if (strcmp(key, "lxc.hook.pre-start") == 0)
869 return add_hook(lxc_conf, LXCHOOK_PRESTART, copy);
5ea6163a
SH
870 else if (strcmp(key, "lxc.hook.pre-mount") == 0)
871 return add_hook(lxc_conf, LXCHOOK_PREMOUNT, copy);
f7bee6c6
MW
872 else if (strcmp(key, "lxc.hook.autodev") == 0)
873 return add_hook(lxc_conf, LXCHOOK_AUTODEV, copy);
26ddeedd
SH
874 else if (strcmp(key, "lxc.hook.mount") == 0)
875 return add_hook(lxc_conf, LXCHOOK_MOUNT, copy);
876 else if (strcmp(key, "lxc.hook.start") == 0)
877 return add_hook(lxc_conf, LXCHOOK_START, copy);
878 else if (strcmp(key, "lxc.hook.post-stop") == 0)
879 return add_hook(lxc_conf, LXCHOOK_POSTSTOP, copy);
880 SYSERROR("Unknown key: %s", key);
881 free(copy);
882 return -1;
883}
884
12a50cc6 885static int config_personality(const char *key, const const char *value,
cccc74b5
DL
886 struct lxc_conf *lxc_conf)
887{
525f0002 888 signed long personality = lxc_config_parse_arch(value);
cccc74b5 889
525f0002
CS
890 if (personality >= 0)
891 lxc_conf->personality = personality;
892 else
893 WARN("unsupported personality '%s'", value);
970ab589
DL
894
895 return 0;
cccc74b5
DL
896}
897
12a50cc6
DE
898static int config_pts(const char *key, const char *value,
899 struct lxc_conf *lxc_conf)
10db618d 900{
901 int maxpts = atoi(value);
902
903 lxc_conf->pts = maxpts;
904
905 return 0;
906}
907
12a50cc6
DE
908static int config_tty(const char *key, const char *value,
909 struct lxc_conf *lxc_conf)
b0a33c1e 910{
911 int nbtty = atoi(value);
912
913 lxc_conf->tty = nbtty;
914
915 return 0;
916}
917
12a50cc6 918static int config_ttydir(const char *key, const char *value,
7c6ef2a2
SH
919 struct lxc_conf *lxc_conf)
920{
921 char *path;
922
923 if (!value || strlen(value) == 0)
924 return 0;
925 path = strdup(value);
926 if (!path) {
927 SYSERROR("failed to strdup '%s': %m", value);
928 return -1;
929 }
930
d95db067
DE
931 if (lxc_conf->ttydir)
932 free(lxc_conf->ttydir);
7c6ef2a2
SH
933 lxc_conf->ttydir = path;
934
935 return 0;
936}
937
7e0e1d94
AV
938static int config_kmsg(const char *key, const char *value,
939 struct lxc_conf *lxc_conf)
940{
941 int v = atoi(value);
942
943 lxc_conf->kmsg = v;
944
945 return 0;
946}
947
e075f5d9 948#if HAVE_APPARMOR
12a50cc6
DE
949static int config_aa_profile(const char *key, const char *value,
950 struct lxc_conf *lxc_conf)
e075f5d9
SH
951{
952 char *path;
953
954 if (!value || strlen(value) == 0)
955 return 0;
956 path = strdup(value);
957 if (!path) {
958 SYSERROR("failed to strdup '%s': %m", value);
959 return -1;
960 }
961
d95db067
DE
962 if (lxc_conf->aa_profile)
963 free(lxc_conf->aa_profile);
e075f5d9
SH
964 lxc_conf->aa_profile = path;
965
966 return 0;
967}
968#endif
969
4a85ce2a
SH
970static int config_logfile(const char *key, const char *value,
971 struct lxc_conf *lxc_conf)
972{
9ea87d5d 973 return lxc_log_set_file(value);
4a85ce2a
SH
974}
975
976static int config_loglevel(const char *key, const char *value,
977 struct lxc_conf *lxc_conf)
978{
9ea87d5d
SH
979 int newlevel;
980
4a85ce2a
SH
981 if (!value || strlen(value) == 0)
982 return 0;
983
9ea87d5d
SH
984 if (lxc_log_get_level() != LXC_LOG_PRIORITY_NOTSET) {
985 DEBUG("Log level already set - ignoring new value");
986 return 0;
987 }
4a85ce2a 988 if (value[0] >= '0' && value[0] <= '9')
9ea87d5d 989 newlevel = atoi(value);
4a85ce2a 990 else
9ea87d5d
SH
991 newlevel = lxc_log_priority_to_int(value);
992 return lxc_log_set_level(newlevel);
4a85ce2a
SH
993}
994
12a50cc6 995static int config_autodev(const char *key, const char *value,
c6883f38
SH
996 struct lxc_conf *lxc_conf)
997{
998 int v = atoi(value);
999
1000 lxc_conf->autodev = v;
1001
1002 return 0;
1003}
1004
a84b9932
AV
1005static int sig_num(const char *sig)
1006{
1007 int n;
1008 char *endp = NULL;
1009
1010 errno = 0;
1011 n = strtol(sig, &endp, 10);
1012 if (sig == endp || n < 0 || errno != 0)
1013 return -1;
1014 return n;
1015}
1016
1017static int rt_sig_num(const char *signame)
1018{
1019 int sig_n = 0;
1020 int rtmax = 0;
1021
1022 if (strncasecmp(signame, "max-", 4) == 0) {
1023 rtmax = 1;
1024 }
1025 signame += 4;
1026 if (!isdigit(*signame))
1027 return -1;
1028 sig_n = sig_num(signame);
1029 sig_n = rtmax ? SIGRTMAX - sig_n : SIGRTMIN + sig_n;
1030 if (sig_n > SIGRTMAX || sig_n < SIGRTMIN)
1031 return -1;
1032 return sig_n;
1033}
1034
1035static int sig_parse(const char *signame) {
1036 int n;
1037
1038 if (isdigit(*signame)) {
1039 return sig_num(signame);
1040 } else if (strncasecmp(signame, "sig", 3) == 0) {
1041 signame += 3;
1042 if (strncasecmp(signame, "rt", 2) == 0)
1043 return rt_sig_num(signame + 2);
1044 for (n = 0; n < sizeof(signames) / sizeof((signames)[0]); n++) {
1045 if (strcasecmp (signames[n].name, signame) == 0)
1046 return signames[n].num;
1047 }
1048 }
1049 return -1;
1050}
1051
1052static int config_stopsignal(const char *key, const char *value,
1053 struct lxc_conf *lxc_conf)
1054{
1055 int sig_n = sig_parse(value);
1056
1057 if (sig_n < 0)
1058 return -1;
1059 lxc_conf->stopsignal = sig_n;
1060
1061 return 0;
1062}
1063
12a50cc6
DE
1064static int config_cgroup(const char *key, const char *value,
1065 struct lxc_conf *lxc_conf)
576f946d 1066{
1067 char *token = "lxc.cgroup.";
1068 char *subkey;
bf83c5b9
MS
1069 struct lxc_list *cglist = NULL;
1070 struct lxc_cgroup *cgelem = NULL;
576f946d 1071
1072 subkey = strstr(key, token);
1073
1074 if (!subkey)
1075 return -1;
1076
1077 if (!strlen(subkey))
1078 return -1;
1079
1080 if (strlen(subkey) == strlen(token))
1081 return -1;
a871ff6b 1082
576f946d 1083 subkey += strlen(token);
1084
1085 cglist = malloc(sizeof(*cglist));
1086 if (!cglist)
bf83c5b9 1087 goto out;
576f946d 1088
1089 cgelem = malloc(sizeof(*cgelem));
bf83c5b9
MS
1090 if (!cgelem)
1091 goto out;
1092 memset(cgelem, 0, sizeof(*cgelem));
576f946d 1093
1094 cgelem->subsystem = strdup(subkey);
1095 cgelem->value = strdup(value);
bf83c5b9
MS
1096
1097 if (!cgelem->subsystem || !cgelem->value)
1098 goto out;
1099
576f946d 1100 cglist->elem = cgelem;
1101
94d12f0a 1102 lxc_list_add_tail(&lxc_conf->cgroup, cglist);
576f946d 1103
1104 return 0;
bf83c5b9
MS
1105
1106out:
1107 if (cglist)
1108 free(cglist);
1109
1110 if (cgelem) {
1111 if (cgelem->subsystem)
1112 free(cgelem->subsystem);
1113
1114 if (cgelem->value)
1115 free(cgelem->value);
1116
1117 free(cgelem);
1118 }
1119
1120 return -1;
576f946d 1121}
1122
f6d3e3e4
SH
1123static int config_idmap(const char *key, const char *value, struct lxc_conf *lxc_conf)
1124{
1125 char *token = "lxc.id_map";
1126 char *subkey;
1127 struct lxc_list *idmaplist = NULL;
1128 struct id_map *idmap = NULL;
251d0d2a 1129 unsigned long hostid, nsid, range;
f6d3e3e4
SH
1130 char type;
1131 int ret;
1132
1133 subkey = strstr(key, token);
1134
1135 if (!subkey)
1136 return -1;
1137
1138 if (!strlen(subkey))
1139 return -1;
1140
1141 idmaplist = malloc(sizeof(*idmaplist));
1142 if (!idmaplist)
1143 goto out;
1144
1145 idmap = malloc(sizeof(*idmap));
1146 if (!idmap)
1147 goto out;
1148 memset(idmap, 0, sizeof(*idmap));
1149
1150 idmaplist->elem = idmap;
1151
1152 lxc_list_add_tail(&lxc_conf->id_map, idmaplist);
1153
251d0d2a 1154 ret = sscanf(value, "%c %lu %lu %lu", &type, &nsid, &hostid, &range);
f6d3e3e4
SH
1155 if (ret != 4)
1156 goto out;
251d0d2a 1157 INFO("read uid map: type %c nsid %lu hostid %lu range %lu", type, nsid, hostid, range);
ac7725e7 1158 if (type == 'u')
f6d3e3e4 1159 idmap->idtype = ID_TYPE_UID;
ac7725e7 1160 else if (type == 'g')
f6d3e3e4
SH
1161 idmap->idtype = ID_TYPE_GID;
1162 else
1163 goto out;
1164 idmap->hostid = hostid;
1165 idmap->nsid = nsid;
1166 idmap->range = range;
1167
1168 return 0;
1169
1170out:
1171 if (idmaplist)
1172 free(idmaplist);
1173
1174 if (idmap) {
1175 free(idmap);
1176 }
1177
1178 return -1;
1179}
1180
d95db067
DE
1181static int config_path_item(const char *key, const char *value,
1182 struct lxc_conf *lxc_conf, char **conf_item)
c2cc9f0a 1183{
d95db067 1184 char *valdup;
c2cc9f0a 1185 if (strlen(value) >= MAXPATHLEN) {
36eb9bde 1186 ERROR("%s path is too long", value);
c2cc9f0a 1187 return -1;
1188 }
1189
d95db067
DE
1190 valdup = strdup(value);
1191 if (!valdup) {
36eb9bde 1192 SYSERROR("failed to duplicate string %s", value);
c2cc9f0a 1193 return -1;
1194 }
d95db067
DE
1195 if (*conf_item)
1196 free(*conf_item);
1197 *conf_item = valdup;
c2cc9f0a 1198
1199 return 0;
1200}
1201
d95db067
DE
1202static int config_fstab(const char *key, const char *value,
1203 struct lxc_conf *lxc_conf)
1204{
1205 return config_path_item(key, value, lxc_conf, &lxc_conf->fstab);
1206}
1207
12a50cc6
DE
1208static int config_mount(const char *key, const char *value,
1209 struct lxc_conf *lxc_conf)
e7938e9e
MN
1210{
1211 char *fstab_token = "lxc.mount";
1212 char *token = "lxc.mount.entry";
1213 char *subkey;
1214 char *mntelem;
1215 struct lxc_list *mntlist;
1216
1217 subkey = strstr(key, token);
1218
1219 if (!subkey) {
1220 subkey = strstr(key, fstab_token);
1221
1222 if (!subkey)
1223 return -1;
1224
1225 return config_fstab(key, value, lxc_conf);
1226 }
1227
1228 if (!strlen(subkey))
1229 return -1;
1230
1231 mntlist = malloc(sizeof(*mntlist));
1232 if (!mntlist)
1233 return -1;
1234
1235 mntelem = strdup(value);
bf83c5b9
MS
1236 if (!mntelem)
1237 return -1;
e7938e9e
MN
1238 mntlist->elem = mntelem;
1239
1240 lxc_list_add_tail(&lxc_conf->mount_list, mntlist);
1241
1242 return 0;
1243}
1244
12a50cc6 1245static int config_cap_drop(const char *key, const char *value,
81810dd1
DL
1246 struct lxc_conf *lxc_conf)
1247{
d95db067 1248 char *dropcaps, *dropptr, *sptr, *token;
81810dd1
DL
1249 struct lxc_list *droplist;
1250 int ret = -1;
1251
1252 if (!strlen(value))
1253 return -1;
1254
1255 dropcaps = strdup(value);
1256 if (!dropcaps) {
1257 SYSERROR("failed to dup '%s'", value);
1258 return -1;
1259 }
1260
1261 /* in case several capability drop is specified in a single line
1262 * split these caps in a single element for the list */
d95db067
DE
1263 for (dropptr = dropcaps;;dropptr = NULL) {
1264 token = strtok_r(dropptr, " \t", &sptr);
81810dd1
DL
1265 if (!token) {
1266 ret = 0;
1267 break;
1268 }
81810dd1
DL
1269
1270 droplist = malloc(sizeof(*droplist));
1271 if (!droplist) {
1272 SYSERROR("failed to allocate drop list");
1273 break;
1274 }
1275
1276 droplist->elem = strdup(token);
1277 if (!droplist->elem) {
1278 SYSERROR("failed to dup '%s'", token);
1279 free(droplist);
1280 break;
1281 }
1282
1283 lxc_list_add_tail(&lxc_conf->caps, droplist);
1284 }
1285
1286 free(dropcaps);
1287
1288 return ret;
1289}
1290
12a50cc6 1291static int config_console(const char *key, const char *value,
28a4b0e5
DL
1292 struct lxc_conf *lxc_conf)
1293{
1294 char *path;
1295
1296 path = strdup(value);
1297 if (!path) {
1298 SYSERROR("failed to strdup '%s': %m", value);
1299 return -1;
1300 }
1301
d95db067
DE
1302 if (lxc_conf->console.path)
1303 free(lxc_conf->console.path);
28a4b0e5
DL
1304 lxc_conf->console.path = path;
1305
1306 return 0;
1307}
1308
12a50cc6 1309static int config_includefile(const char *key, const char *value,
09ad6246
SH
1310 struct lxc_conf *lxc_conf)
1311{
1312 return lxc_config_read(value, lxc_conf);
1313}
1314
12a50cc6
DE
1315static int config_rootfs(const char *key, const char *value,
1316 struct lxc_conf *lxc_conf)
c2cc9f0a 1317{
d95db067 1318 return config_path_item(key, value, lxc_conf, &lxc_conf->rootfs.path);
c2cc9f0a 1319}
1320
12a50cc6
DE
1321static int config_rootfs_mount(const char *key, const char *value,
1322 struct lxc_conf *lxc_conf)
23b7ea69 1323{
d95db067 1324 return config_path_item(key, value, lxc_conf, &lxc_conf->rootfs.mount);
23b7ea69
DL
1325}
1326
12a50cc6
DE
1327static int config_pivotdir(const char *key, const char *value,
1328 struct lxc_conf *lxc_conf)
bf601689 1329{
d95db067 1330 return config_path_item(key, value, lxc_conf, &lxc_conf->rootfs.pivot);
bf601689
MH
1331}
1332
12a50cc6
DE
1333static int config_utsname(const char *key, const char *value,
1334 struct lxc_conf *lxc_conf)
c2cc9f0a 1335{
1336 struct utsname *utsname;
1337
1338 utsname = malloc(sizeof(*utsname));
1339 if (!utsname) {
36eb9bde 1340 SYSERROR("failed to allocate memory");
c2cc9f0a 1341 return -1;
1342 }
1343
1344 if (strlen(value) >= sizeof(utsname->nodename)) {
36eb9bde 1345 ERROR("node name '%s' is too long",
c2cc9f0a 1346 utsname->nodename);
1347 return -1;
1348 }
1349
1350 strcpy(utsname->nodename, value);
d95db067
DE
1351 if (lxc_conf->utsname)
1352 free(lxc_conf->utsname);
c2cc9f0a 1353 lxc_conf->utsname = utsname;
1354
1355 return 0;
1356}
1357
7a7ff0c6 1358static int parse_line(char *buffer, void *data)
c2cc9f0a 1359{
72d0e1cb 1360 struct lxc_config_t *config;
81192358 1361 char *line, *linep;
c2cc9f0a 1362 char *dot;
1363 char *key;
1364 char *value;
476d4cf1 1365 int ret = 0;
c2cc9f0a 1366
91480a0f 1367 if (lxc_is_line_empty(buffer))
c2cc9f0a 1368 return 0;
1369
81192358
DL
1370 /* we have to dup the buffer otherwise, at the re-exec for
1371 * reboot we modified the original string on the stack by
1372 * replacing '=' by '\0' below
91480a0f 1373 */
81192358 1374 linep = line = strdup(buffer);
91480a0f
DL
1375 if (!line) {
1376 SYSERROR("failed to allocate memory for '%s'", buffer);
81192358 1377 return -1;
91480a0f
DL
1378 }
1379
b2718c72 1380 line += lxc_char_left_gc(line, strlen(line));
476d4cf1
DL
1381
1382 /* martian option - ignoring it, the commented lines beginning by '#'
1383 * fall in this case
1384 */
1385 if (strncmp(line, "lxc.", 4))
91480a0f 1386 goto out;
476d4cf1
DL
1387
1388 ret = -1;
c2cc9f0a 1389
b2718c72 1390 dot = strstr(line, "=");
c2cc9f0a 1391 if (!dot) {
36eb9bde 1392 ERROR("invalid configuration line: %s", line);
91480a0f 1393 goto out;
c2cc9f0a 1394 }
a871ff6b 1395
c2cc9f0a 1396 *dot = '\0';
1397 value = dot + 1;
1398
b2718c72 1399 key = line;
1400 key[lxc_char_right_gc(key, strlen(key))] = '\0';
c2cc9f0a 1401
b2718c72 1402 value += lxc_char_left_gc(value, strlen(value));
1403 value[lxc_char_right_gc(value, strlen(value))] = '\0';
c2cc9f0a 1404
72d0e1cb 1405 config = lxc_getconfig(key);
c2cc9f0a 1406 if (!config) {
6e1d9b94 1407 ERROR("unknown key %s", key);
91480a0f 1408 goto out;
c2cc9f0a 1409 }
1410
91480a0f
DL
1411 ret = config->cb(key, value, data);
1412
1413out:
81192358 1414 free(linep);
91480a0f 1415 return ret;
c2cc9f0a 1416}
1417
af5b0155
CLG
1418int lxc_config_readline(char *buffer, struct lxc_conf *conf)
1419{
1420 return parse_line(buffer, conf);
1421}
1422
b2718c72 1423int lxc_config_read(const char *file, struct lxc_conf *conf)
c2cc9f0a 1424{
f7bee6c6
MW
1425 /* Catch only the top level config file name in the structure */
1426 if( ! conf->rcfile ) {
1427 conf->rcfile = strdup( file );
1428 }
2382ecff 1429 return lxc_file_for_each_line(file, parse_line, conf);
c2cc9f0a 1430}
62e46035
CLG
1431
1432int lxc_config_define_add(struct lxc_list *defines, char* arg)
1433{
1434 struct lxc_list *dent;
1435
1436 dent = malloc(sizeof(struct lxc_list));
1437 if (!dent)
1438 return -1;
1439
1440 dent->elem = arg;
1441 lxc_list_add_tail(defines, dent);
1442 return 0;
1443}
1444
226a18d6 1445int lxc_config_define_load(struct lxc_list *defines, struct lxc_conf *conf)
62e46035 1446{
9ebb03ad 1447 struct lxc_list *it,*next;
62e46035
CLG
1448 int ret = 0;
1449
1450 lxc_list_for_each(it, defines) {
1451 ret = lxc_config_readline(it->elem, conf);
1452 if (ret)
1453 break;
1454 }
1455
9ebb03ad 1456 lxc_list_for_each_safe(it, defines, next) {
62e46035
CLG
1457 lxc_list_del(it);
1458 free(it);
1459 }
1460
1461 return ret;
1462}
525f0002
CS
1463
1464signed long lxc_config_parse_arch(const char *arch)
1465{
6ff05e18 1466 #if HAVE_SYS_PERSONALITY_H
525f0002
CS
1467 struct per_name {
1468 char *name;
1469 unsigned long per;
1470 } pername[4] = {
1471 { "x86", PER_LINUX32 },
1472 { "i686", PER_LINUX32 },
1473 { "x86_64", PER_LINUX },
1474 { "amd64", PER_LINUX },
1475 };
1476 size_t len = sizeof(pername) / sizeof(pername[0]);
1477
1478 int i;
1479
1480 for (i = 0; i < len; i++) {
1481 if (!strcmp(pername[i].name, arch))
1482 return pername[i].per;
1483 }
6ff05e18 1484 #endif
525f0002
CS
1485
1486 return -1;
1487}
72d0e1cb
SG
1488
1489static int lxc_get_conf_int(struct lxc_conf *c, char *retv, int inlen, int v)
1490{
1491 if (!retv)
1492 inlen = 0;
1493 else
1494 memset(retv, 0, inlen);
1495 return snprintf(retv, inlen, "%d", v);
1496}
1497
1498static int lxc_get_arch_entry(struct lxc_conf *c, char *retv, int inlen)
1499{
6ff05e18 1500 int fulllen = 0;
72d0e1cb
SG
1501
1502 if (!retv)
1503 inlen = 0;
1504 else
1505 memset(retv, 0, inlen);
1506
6ff05e18
SG
1507 #if HAVE_SYS_PERSONALITY_H
1508 int len = 0;
1509
72d0e1cb
SG
1510 switch(c->personality) {
1511 case PER_LINUX32: strprint(retv, inlen, "x86"); break;
1512 case PER_LINUX: strprint(retv, inlen, "x86_64"); break;
1513 default: break;
1514 }
6ff05e18 1515 #endif
72d0e1cb
SG
1516
1517 return fulllen;
1518}
1519
1520/*
1521 * If you ask for a specific cgroup value, i.e. lxc.cgroup.devices.list,
1522 * then just the value(s) will be printed. Since there still could be
1523 * more than one, it is newline-separated.
1524 * (Maybe that's ambigous, since some values, i.e. devices.list, will
1525 * already have newlines?)
1526 * If you ask for 'lxc.cgroup", then all cgroup entries will be printed,
1527 * in 'lxc.cgroup.subsystem.key = value' format.
1528 */
12a50cc6
DE
1529static int lxc_get_cgroup_entry(struct lxc_conf *c, char *retv, int inlen,
1530 const char *key)
72d0e1cb
SG
1531{
1532 int fulllen = 0, len;
1533 int all = 0;
1534 struct lxc_list *it;
1535
1536 if (!retv)
1537 inlen = 0;
1538 else
1539 memset(retv, 0, inlen);
1540
1541 if (strcmp(key, "all") == 0)
1542 all = 1;
1543
1544 lxc_list_for_each(it, &c->cgroup) {
1545 struct lxc_cgroup *cg = it->elem;
1546 if (all) {
1547 strprint(retv, inlen, "lxc.cgroup.%s = %s\n", cg->subsystem, cg->value);
1548 } else if (strcmp(cg->subsystem, key) == 0) {
1549 strprint(retv, inlen, "%s\n", cg->value);
1550 }
1551 }
1552 return fulllen;
1553}
1554
12a50cc6
DE
1555static int lxc_get_item_hooks(struct lxc_conf *c, char *retv, int inlen,
1556 const char *key)
72d0e1cb
SG
1557{
1558 char *subkey;
1559 int len, fulllen = 0, found = -1;
1560 struct lxc_list *it;
1561 int i;
1562
1563 /* "lxc.hook.mount" */
1564 subkey = index(key, '.');
1565 if (subkey) subkey = index(subkey+1, '.');
1566 if (!subkey)
1567 return -1;
1568 subkey++;
1569 if (!*subkey)
1570 return -1;
1571 for (i=0; i<NUM_LXC_HOOKS; i++) {
1572 if (strcmp(lxchook_names[i], subkey) == 0) {
1573 found=i;
1574 break;
1575 }
1576 }
1577 if (found == -1)
1578 return -1;
1579
1580 if (!retv)
1581 inlen = 0;
1582 else
1583 memset(retv, 0, inlen);
1584
1585 lxc_list_for_each(it, &c->hooks[found]) {
1586 strprint(retv, inlen, "%s\n", (char *)it->elem);
1587 }
1588 return fulllen;
1589}
1590
1591static int lxc_get_item_cap_drop(struct lxc_conf *c, char *retv, int inlen)
1592{
1593 int len, fulllen = 0;
1594 struct lxc_list *it;
1595
1596 if (!retv)
1597 inlen = 0;
1598 else
1599 memset(retv, 0, inlen);
1600
1601 lxc_list_for_each(it, &c->caps) {
1602 strprint(retv, inlen, "%s\n", (char *)it->elem);
1603 }
1604 return fulllen;
1605}
1606
1607static int lxc_get_mount_entries(struct lxc_conf *c, char *retv, int inlen)
1608{
1609 int len, fulllen = 0;
1610 struct lxc_list *it;
1611
1612 if (!retv)
1613 inlen = 0;
1614 else
1615 memset(retv, 0, inlen);
1616
1617 lxc_list_for_each(it, &c->mount_list) {
1618 strprint(retv, inlen, "%s\n", (char *)it->elem);
1619 }
1620 return fulllen;
1621}
1622
1623/*
1624 * lxc.network.0.XXX, where XXX can be: name, type, link, flags, type,
1625 * macvlan.mode, veth.pair, vlan, ipv4, ipv6, upscript, hwaddr, mtu,
1626 * ipv4_gateway, ipv6_gateway. ipvX_gateway can return 'auto' instead
1627 * of an address. ipv4 and ipv6 return lists (newline-separated).
1628 * things like veth.pair return '' if invalid (i.e. if called for vlan
1629 * type).
1630 */
12a50cc6
DE
1631static int lxc_get_item_nic(struct lxc_conf *c, char *retv, int inlen,
1632 const char *key)
72d0e1cb
SG
1633{
1634 char *p1;
fe88b9d2 1635 int len, fulllen = 0;
72d0e1cb
SG
1636 struct lxc_netdev *netdev;
1637
1638 if (!retv)
1639 inlen = 0;
1640 else
1641 memset(retv, 0, inlen);
1642
1643 p1 = index(key, '.');
1644 if (!p1 || *(p1+1) == '\0') return -1;
1645 p1++;
1646
1647 netdev = get_netdev_from_key(key, &c->network);
1648 if (!netdev)
1649 return -1;
1650 if (strcmp(p1, "name") == 0) {
1651 if (netdev->name)
1652 strprint(retv, inlen, "%s", netdev->name);
1653 } else if (strcmp(p1, "type") == 0) {
1654 strprint(retv, inlen, "%s", lxc_net_type_to_str(netdev->type));
1655 } else if (strcmp(p1, "link") == 0) {
1656 if (netdev->link)
1657 strprint(retv, inlen, "%s", netdev->link);
1658 } else if (strcmp(p1, "flags") == 0) {
1659 if (netdev->flags & IFF_UP)
1660 strprint(retv, inlen, "up");
1661 } else if (strcmp(p1, "upscript") == 0) {
1662 if (netdev->upscript)
1663 strprint(retv, inlen, "%s", netdev->upscript);
1664 } else if (strcmp(p1, "hwaddr") == 0) {
1665 if (netdev->hwaddr)
1666 strprint(retv, inlen, "%s", netdev->hwaddr);
1667 } else if (strcmp(p1, "mtu") == 0) {
1668 if (netdev->mtu)
1669 strprint(retv, inlen, "%s", netdev->mtu);
1670 } else if (strcmp(p1, "macvlan.mode") == 0) {
1671 if (netdev->type == LXC_NET_MACVLAN) {
1672 const char *mode;
1673 switch (netdev->priv.macvlan_attr.mode) {
1674 case MACVLAN_MODE_PRIVATE: mode = "private"; break;
1675 case MACVLAN_MODE_VEPA: mode = "vepa"; break;
1676 case MACVLAN_MODE_BRIDGE: mode = "bridge"; break;
1677 default: mode = "(invalid)"; break;
1678 }
1679 strprint(retv, inlen, "%s", mode);
1680 }
1681 } else if (strcmp(p1, "veth.pair") == 0) {
1682 if (netdev->type == LXC_NET_VETH && netdev->priv.veth_attr.pair)
1683 strprint(retv, inlen, "%s", netdev->priv.veth_attr.pair);
1684 } else if (strcmp(p1, "vlan") == 0) {
1685 if (netdev->type == LXC_NET_VLAN) {
1686 strprint(retv, inlen, "%d", netdev->priv.vlan_attr.vid);
1687 }
1688 } else if (strcmp(p1, "ipv4_gateway") == 0) {
1689 if (netdev->ipv4_gateway_auto) {
1690 strprint(retv, inlen, "auto");
1691 } else if (netdev->ipv4_gateway) {
1692 char buf[INET_ADDRSTRLEN];
1693 inet_ntop(AF_INET, netdev->ipv4_gateway, buf, sizeof(buf));
1694 strprint(retv, inlen, "%s", buf);
1695 }
1696 } else if (strcmp(p1, "ipv4") == 0) {
1697 struct lxc_list *it2;
1698 lxc_list_for_each(it2, &netdev->ipv4) {
1699 struct lxc_inetdev *i = it2->elem;
1700 char buf[INET_ADDRSTRLEN];
1701 inet_ntop(AF_INET, &i->addr, buf, sizeof(buf));
1702 strprint(retv, inlen, "%s\n", buf);
1703 }
1704 } else if (strcmp(p1, "ipv6_gateway") == 0) {
1705 if (netdev->ipv6_gateway_auto) {
1706 strprint(retv, inlen, "auto");
1707 } else if (netdev->ipv6_gateway) {
1708 char buf[INET_ADDRSTRLEN];
1709 inet_ntop(AF_INET, netdev->ipv6_gateway, buf, sizeof(buf));
1710 strprint(retv, inlen, "%s", buf);
1711 }
1712 } else if (strcmp(p1, "ipv6") == 0) {
1713 struct lxc_list *it2;
1714 lxc_list_for_each(it2, &netdev->ipv6) {
1715 struct lxc_inetdev *i = it2->elem;
1716 char buf[INET_ADDRSTRLEN];
1717 inet_ntop(AF_INET6, &i->addr, buf, sizeof(buf));
1718 strprint(retv, inlen, "%s\n", buf);
1719 }
1720 }
1721 return fulllen;
1722}
1723
1724static int lxc_get_item_network(struct lxc_conf *c, char *retv, int inlen)
1725{
1726 int len, fulllen = 0;
1727 struct lxc_list *it;
1728
1729 if (!retv)
1730 inlen = 0;
1731 else
1732 memset(retv, 0, inlen);
1733
1734 lxc_list_for_each(it, &c->network) {
1735 struct lxc_netdev *n = it->elem;
1736 const char *t = lxc_net_type_to_str(n->type);
1737 strprint(retv, inlen, "%s\n", t ? t : "(invalid)");
1738 }
1739 return fulllen;
1740}
1741
12a50cc6
DE
1742int lxc_get_config_item(struct lxc_conf *c, const char *key, char *retv,
1743 int inlen)
72d0e1cb 1744{
4a85ce2a 1745 const char *v = NULL;
72d0e1cb
SG
1746
1747 if (strcmp(key, "lxc.mount.entry") == 0)
1748 return lxc_get_mount_entries(c, retv, inlen);
1749 else if (strcmp(key, "lxc.mount") == 0)
1750 v = c->fstab;
1751 else if (strcmp(key, "lxc.tty") == 0)
1752 return lxc_get_conf_int(c, retv, inlen, c->tty);
1753 else if (strcmp(key, "lxc.pts") == 0)
1754 return lxc_get_conf_int(c, retv, inlen, c->pts);
1755 else if (strcmp(key, "lxc.devttydir") == 0)
1756 v = c->ttydir;
1757 else if (strcmp(key, "lxc.arch") == 0)
1758 return lxc_get_arch_entry(c, retv, inlen);
1f530df6 1759#if HAVE_APPARMOR
72d0e1cb
SG
1760 else if (strcmp(key, "lxc.aa_profile") == 0)
1761 v = c->aa_profile;
1f530df6 1762#endif
4a85ce2a 1763 else if (strcmp(key, "lxc.logfile") == 0)
9ea87d5d 1764 v = lxc_log_get_file();
4a85ce2a 1765 else if (strcmp(key, "lxc.loglevel") == 0)
9ea87d5d 1766 v = lxc_log_priority_to_string(lxc_log_get_level());
72d0e1cb
SG
1767 else if (strcmp(key, "lxc.cgroup") == 0) // all cgroup info
1768 return lxc_get_cgroup_entry(c, retv, inlen, "all");
1769 else if (strncmp(key, "lxc.cgroup.", 11) == 0) // specific cgroup info
1770 return lxc_get_cgroup_entry(c, retv, inlen, key + 11);
1771 else if (strcmp(key, "lxc.utsname") == 0)
64fca455 1772 v = c->utsname ? c->utsname->nodename : NULL;
72d0e1cb
SG
1773 else if (strcmp(key, "lxc.console") == 0)
1774 v = c->console.path;
1775 else if (strcmp(key, "lxc.rootfs.mount") == 0)
1776 v = c->rootfs.mount;
1777 else if (strcmp(key, "lxc.rootfs") == 0)
1778 v = c->rootfs.path;
1779 else if (strcmp(key, "lxc.pivotdir") == 0)
1780 v = c->rootfs.pivot;
1781 else if (strcmp(key, "lxc.cap.drop") == 0)
1782 return lxc_get_item_cap_drop(c, retv, inlen);
1783 else if (strncmp(key, "lxc.hook", 8) == 0)
1784 return lxc_get_item_hooks(c, retv, inlen, key);
1785 else if (strcmp(key, "lxc.network") == 0)
1786 return lxc_get_item_network(c, retv, inlen);
1787 else if (strncmp(key, "lxc.network.", 12) == 0)
1788 return lxc_get_item_nic(c, retv, inlen, key + 12);
1789 else return -1;
1790
1791 if (!v)
1792 return 0;
1793 if (retv && inlen >= strlen(v) + 1)
1794 strncpy(retv, v, strlen(v)+1);
1795 return strlen(v);
1796}
1797
12a50cc6 1798int lxc_clear_config_item(struct lxc_conf *c, const char *key)
72d0e1cb
SG
1799{
1800 if (strcmp(key, "lxc.network") == 0)
1801 return lxc_clear_config_network(c);
1802 else if (strncmp(key, "lxc.network.", 12) == 0)
1803 return lxc_clear_nic(c, key + 12);
1804 else if (strcmp(key, "lxc.cap.drop") == 0)
1805 return lxc_clear_config_caps(c);
1806 else if (strncmp(key, "lxc.cgroup", 10) == 0)
1807 return lxc_clear_cgroups(c, key);
1808 else if (strcmp(key, "lxc.mount.entries") == 0)
1809 return lxc_clear_mount_entries(c);
17ed13a3
SH
1810 else if (strncmp(key, "lxc.hook", 8) == 0)
1811 return lxc_clear_hooks(c, key);
72d0e1cb
SG
1812
1813 return -1;
1814}
1815
1816/*
1817 * writing out a confile.
1818 */
1819void write_config(FILE *fout, struct lxc_conf *c)
1820{
1821 struct lxc_list *it;
1822 int i;
1823
1824 if (c->fstab)
1825 fprintf(fout, "lxc.mount = %s\n", c->fstab);
1826 lxc_list_for_each(it, &c->mount_list) {
1827 fprintf(fout, "lxc.mount.entry = %s\n", (char *)it->elem);
1828 }
1829 if (c->tty)
1830 fprintf(fout, "lxc.tty = %d\n", c->tty);
1831 if (c->pts)
1832 fprintf(fout, "lxc.pts = %d\n", c->pts);
1833 if (c->ttydir)
1834 fprintf(fout, "lxc.devttydir = %s\n", c->ttydir);
6ff05e18 1835 #if HAVE_SYS_PERSONALITY_H
72d0e1cb
SG
1836 switch(c->personality) {
1837 case PER_LINUX32: fprintf(fout, "lxc.arch = x86\n"); break;
1838 case PER_LINUX: fprintf(fout, "lxc.arch = x86_64\n"); break;
1839 default: break;
1840 }
6ff05e18 1841 #endif
1f530df6 1842#if HAVE_APPARMOR
72d0e1cb
SG
1843 if (c->aa_profile)
1844 fprintf(fout, "lxc.aa_profile = %s\n", c->aa_profile);
1f530df6 1845#endif
9ea87d5d
SH
1846 if (lxc_log_get_level() != LXC_LOG_PRIORITY_NOTSET)
1847 fprintf(fout, "lxc.loglevel = %s\n", lxc_log_priority_to_string(lxc_log_get_level()));
1848 if (lxc_log_get_file())
1849 fprintf(fout, "lxc.logfile = %s\n", lxc_log_get_file());
72d0e1cb
SG
1850 lxc_list_for_each(it, &c->cgroup) {
1851 struct lxc_cgroup *cg = it->elem;
1852 fprintf(fout, "lxc.cgroup.%s = %s\n", cg->subsystem, cg->value);
1853 }
1854 if (c->utsname)
1855 fprintf(fout, "lxc.utsname = %s\n", c->utsname->nodename);
1856 lxc_list_for_each(it, &c->network) {
1857 struct lxc_netdev *n = it->elem;
1858 const char *t = lxc_net_type_to_str(n->type);
1859 struct lxc_list *it2;
1860 fprintf(fout, "lxc.network.type = %s\n", t ? t : "(invalid)");
1861 if (n->flags & IFF_UP)
1862 fprintf(fout, "lxc.network.flags = up\n");
1863 if (n->link)
1864 fprintf(fout, "lxc.network.link = %s\n", n->link);
1865 if (n->name)
1866 fprintf(fout, "lxc.network.name = %s\n", n->name);
1867 if (n->type == LXC_NET_MACVLAN) {
1868 const char *mode;
1869 switch (n->priv.macvlan_attr.mode) {
1870 case MACVLAN_MODE_PRIVATE: mode = "private"; break;
1871 case MACVLAN_MODE_VEPA: mode = "vepa"; break;
1872 case MACVLAN_MODE_BRIDGE: mode = "bridge"; break;
1873 default: mode = "(invalid)"; break;
1874 }
1875 fprintf(fout, "lxc.network.macvlan.mode = %s\n", mode);
1876 } else if (n->type == LXC_NET_VETH) {
1877 if (n->priv.veth_attr.pair)
1878 fprintf(fout, "lxc.network.veth.pair = %s\n",
1879 n->priv.veth_attr.pair);
1880 } else if (n->type == LXC_NET_VLAN) {
1881 fprintf(fout, "lxc.network.vlan.id = %d\n", n->priv.vlan_attr.vid);
1882 }
1883 if (n->upscript)
1884 fprintf(fout, "lxc.network.script.up = %s\n", n->upscript);
1885 if (n->hwaddr)
1886 fprintf(fout, "lxc.network.hwaddr = %s\n", n->hwaddr);
1887 if (n->mtu)
1888 fprintf(fout, "lxc.network.mtu = %s\n", n->mtu);
1889 if (n->ipv4_gateway_auto)
1890 fprintf(fout, "lxc.network.ipv4.gateway = auto\n");
1891 else if (n->ipv4_gateway) {
1892 char buf[INET_ADDRSTRLEN];
1893 inet_ntop(AF_INET, n->ipv4_gateway, buf, sizeof(buf));
1894 fprintf(fout, "lxc.network.ipv4.gateway = %s\n", buf);
1895 }
1896 lxc_list_for_each(it2, &n->ipv4) {
1897 struct lxc_inetdev *i = it2->elem;
1898 char buf[INET_ADDRSTRLEN];
1899 inet_ntop(AF_INET, &i->addr, buf, sizeof(buf));
1900 fprintf(fout, "lxc.network.ipv4 = %s\n", buf);
1901 }
1902 if (n->ipv6_gateway_auto)
1903 fprintf(fout, "lxc.network.ipv6.gateway = auto\n");
1904 else if (n->ipv6_gateway) {
1905 char buf[INET6_ADDRSTRLEN];
1906 inet_ntop(AF_INET6, n->ipv6_gateway, buf, sizeof(buf));
1907 fprintf(fout, "lxc.network.ipv6.gateway = %s\n", buf);
1908 }
1909 lxc_list_for_each(it2, &n->ipv6) {
1910 struct lxc_inet6dev *i = it2->elem;
1911 char buf[INET6_ADDRSTRLEN];
1912 inet_ntop(AF_INET, &i->addr, buf, sizeof(buf));
1913 fprintf(fout, "lxc.network.ipv6 = %s\n", buf);
1914 }
1915 }
1916 lxc_list_for_each(it, &c->caps)
1917 fprintf(fout, "lxc.cap.drop = %s\n", (char *)it->elem);
1918 for (i=0; i<NUM_LXC_HOOKS; i++) {
1919 lxc_list_for_each(it, &c->hooks[i])
1920 fprintf(fout, "lxc.hook.%s = %s\n",
1921 lxchook_names[i], (char *)it->elem);
1922 }
1923 if (c->console.path)
1924 fprintf(fout, "lxc.console = %s\n", c->console.path);
1925 if (c->rootfs.path)
1926 fprintf(fout, "lxc.rootfs = %s\n", c->rootfs.path);
1927 if (c->rootfs.mount && strcmp(c->rootfs.mount, LXCROOTFSMOUNT) != 0)
1928 fprintf(fout, "lxc.rootfs.mount = %s\n", c->rootfs.mount);
1929 if (c->rootfs.pivot)
1930 fprintf(fout, "lxc.pivotdir = %s\n", c->rootfs.pivot);
1931}