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