2 * lxc: linux Container library
4 * (C) Copyright IBM Corp. 2007, 2008
7 * Daniel Lezcano <dlezcano at fr.ibm.com>
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.
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.
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
31 #include <sys/types.h>
32 #include <sys/param.h>
33 #include <sys/utsname.h>
34 #include <arpa/inet.h>
35 #include <netinet/in.h>
47 #if HAVE_SYS_PERSONALITY_H
48 #include <sys/personality.h>
51 lxc_log_define(lxc_confile
, lxc
);
53 static int config_personality(const char *, const char *, struct lxc_conf
*);
54 static int config_pts(const char *, const char *, struct lxc_conf
*);
55 static int config_tty(const char *, const char *, struct lxc_conf
*);
56 static int config_ttydir(const char *, const char *, struct lxc_conf
*);
58 static int config_aa_profile(const char *, const char *, struct lxc_conf
*);
60 static int config_cgroup(const char *, const char *, struct lxc_conf
*);
61 static int config_loglevel(const char *, const char *, struct lxc_conf
*);
62 static int config_logfile(const char *, const char *, struct lxc_conf
*);
63 static int config_mount(const char *, const char *, struct lxc_conf
*);
64 static int config_rootfs(const char *, const char *, struct lxc_conf
*);
65 static int config_rootfs_mount(const char *, const char *, struct lxc_conf
*);
66 static int config_pivotdir(const char *, const char *, struct lxc_conf
*);
67 static int config_utsname(const char *, const char *, struct lxc_conf
*);
68 static int config_hook(const char *, const char *, struct lxc_conf
*lxc_conf
);
69 static int config_network_type(const char *, const char *, struct lxc_conf
*);
70 static int config_network_flags(const char *, const char *, struct lxc_conf
*);
71 static int config_network_link(const char *, const char *, struct lxc_conf
*);
72 static int config_network_name(const char *, const char *, struct lxc_conf
*);
73 static int config_network_veth_pair(const char *, const char *, struct lxc_conf
*);
74 static int config_network_macvlan_mode(const char *, const char *, struct lxc_conf
*);
75 static int config_network_hwaddr(const char *, const char *, struct lxc_conf
*);
76 static int config_network_vlan_id(const char *, const char *, struct lxc_conf
*);
77 static int config_network_mtu(const char *, const char *, struct lxc_conf
*);
78 static int config_network_ipv4(const char *, const char *, struct lxc_conf
*);
79 static int config_network_ipv4_gateway(const char *, const char *, struct lxc_conf
*);
80 static int config_network_script(const char *, const char *, struct lxc_conf
*);
81 static int config_network_ipv6(const char *, const char *, struct lxc_conf
*);
82 static int config_network_ipv6_gateway(const char *, const char *, struct lxc_conf
*);
83 static int config_cap_drop(const char *, const char *, struct lxc_conf
*);
84 static int config_console(const char *, const char *, struct lxc_conf
*);
85 static int config_seccomp(const char *, const char *, struct lxc_conf
*);
86 static int config_includefile(const char *, const char *, struct lxc_conf
*);
87 static int config_network_nic(const char *, const char *, struct lxc_conf
*);
88 static int config_autodev(const char *, const char *, struct lxc_conf
*);
90 static struct lxc_config_t config
[] = {
92 { "lxc.arch", config_personality
},
93 { "lxc.pts", config_pts
},
94 { "lxc.tty", config_tty
},
95 { "lxc.devttydir", config_ttydir
},
97 { "lxc.aa_profile", config_aa_profile
},
99 { "lxc.cgroup", config_cgroup
},
100 { "lxc.loglevel", config_loglevel
},
101 { "lxc.logfile", config_logfile
},
102 { "lxc.mount", config_mount
},
103 { "lxc.rootfs.mount", config_rootfs_mount
},
104 { "lxc.rootfs", config_rootfs
},
105 { "lxc.pivotdir", config_pivotdir
},
106 { "lxc.utsname", config_utsname
},
107 { "lxc.hook.pre-start", config_hook
},
108 { "lxc.hook.pre-mount", config_hook
},
109 { "lxc.hook.mount", config_hook
},
110 { "lxc.hook.start", config_hook
},
111 { "lxc.hook.post-stop", config_hook
},
112 { "lxc.network.type", config_network_type
},
113 { "lxc.network.flags", config_network_flags
},
114 { "lxc.network.link", config_network_link
},
115 { "lxc.network.name", config_network_name
},
116 { "lxc.network.macvlan.mode", config_network_macvlan_mode
},
117 { "lxc.network.veth.pair", config_network_veth_pair
},
118 { "lxc.network.script.up", config_network_script
},
119 { "lxc.network.script.down", config_network_script
},
120 { "lxc.network.hwaddr", config_network_hwaddr
},
121 { "lxc.network.mtu", config_network_mtu
},
122 { "lxc.network.vlan.id", config_network_vlan_id
},
123 { "lxc.network.ipv4.gateway", config_network_ipv4_gateway
},
124 { "lxc.network.ipv4", config_network_ipv4
},
125 { "lxc.network.ipv6.gateway", config_network_ipv6_gateway
},
126 { "lxc.network.ipv6", config_network_ipv6
},
127 /* config_network_nic must come after all other 'lxc.network.*' entries */
128 { "lxc.network.", config_network_nic
},
129 { "lxc.cap.drop", config_cap_drop
},
130 { "lxc.console", config_console
},
131 { "lxc.seccomp", config_seccomp
},
132 { "lxc.include", config_includefile
},
133 { "lxc.autodev", config_autodev
},
136 static const size_t config_size
= sizeof(config
)/sizeof(struct lxc_config_t
);
138 extern struct lxc_config_t
*lxc_getconfig(const char *key
)
142 for (i
= 0; i
< config_size
; i
++)
143 if (!strncmp(config
[i
].name
, key
,
144 strlen(config
[i
].name
)))
149 #define strprint(str, inlen, ...) \
151 len = snprintf(str, inlen, ##__VA_ARGS__); \
152 if (len < 0) { SYSERROR("snprintf"); return -1; }; \
155 if (str) str += len; \
157 if (inlen < 0) inlen = 0; \
161 int lxc_listconfigs(char *retv
, int inlen
)
163 int i
, fulllen
= 0, len
;
168 memset(retv
, 0, inlen
);
169 for (i
= 0; i
< config_size
; i
++) {
170 char *s
= config
[i
].name
;
171 if (s
[strlen(s
)-1] == '.')
173 strprint(retv
, inlen
, "%s\n", s
);
179 * config entry is something like "lxc.network.0.ipv4"
180 * the key 'lxc.network.' was found. So we make sure next
181 * comes an integer, find the right callback (by rewriting
182 * the key), and call it.
184 static int config_network_nic(const char *key
, const char *value
,
185 struct lxc_conf
*lxc_conf
)
187 char *copy
= strdup(key
), *p
;
189 struct lxc_config_t
*config
;
192 SYSERROR("failed to allocate memory");
196 * ok we know that to get here we've got "lxc.network."
197 * and it isn't any of the other network entries. So
198 * after the second . should come an integer (# of defined
199 * nic) followed by a valid entry.
201 if (*(key
+12) < '0' || *(key
+12) > '9')
203 p
= index(key
+12, '.');
206 strcpy(copy
+12, p
+1);
207 config
= lxc_getconfig(copy
);
209 ERROR("unknown key %s", key
);
212 ret
= config
->cb(key
, value
, lxc_conf
);
219 static int config_network_type(const char *key
, const char *value
,
220 struct lxc_conf
*lxc_conf
)
222 struct lxc_list
*network
= &lxc_conf
->network
;
223 struct lxc_netdev
*netdev
;
224 struct lxc_list
*list
;
226 netdev
= malloc(sizeof(*netdev
));
228 SYSERROR("failed to allocate memory");
232 memset(netdev
, 0, sizeof(*netdev
));
233 lxc_list_init(&netdev
->ipv4
);
234 lxc_list_init(&netdev
->ipv6
);
236 list
= malloc(sizeof(*list
));
238 SYSERROR("failed to allocate memory");
245 lxc_list_add_tail(network
, list
);
247 if (!strcmp(value
, "veth"))
248 netdev
->type
= LXC_NET_VETH
;
249 else if (!strcmp(value
, "macvlan"))
250 netdev
->type
= LXC_NET_MACVLAN
;
251 else if (!strcmp(value
, "vlan"))
252 netdev
->type
= LXC_NET_VLAN
;
253 else if (!strcmp(value
, "phys"))
254 netdev
->type
= LXC_NET_PHYS
;
255 else if (!strcmp(value
, "empty"))
256 netdev
->type
= LXC_NET_EMPTY
;
258 ERROR("invalid network type %s", value
);
264 static int config_ip_prefix(struct in_addr
*addr
)
266 if (IN_CLASSA(addr
->s_addr
))
267 return 32 - IN_CLASSA_NSHIFT
;
268 if (IN_CLASSB(addr
->s_addr
))
269 return 32 - IN_CLASSB_NSHIFT
;
270 if (IN_CLASSC(addr
->s_addr
))
271 return 32 - IN_CLASSC_NSHIFT
;
277 * if you have p="lxc.network.0.link", pass it p+12
278 * to get back '0' (the index of the nic)
280 static int get_network_netdev_idx(const char *key
)
284 if (*key
< '0' || *key
> '9')
286 ret
= sscanf(key
, "%d", &idx
);
293 * if you have p="lxc.network.0", pass this p+12 and it will return
294 * the netdev of the first configured nic
296 static struct lxc_netdev
*get_netdev_from_key(const char *key
,
297 struct lxc_list
*network
)
299 int i
= 0, idx
= get_network_netdev_idx(key
);
300 struct lxc_netdev
*netdev
= NULL
;
304 lxc_list_for_each(it
, network
) {
313 extern int lxc_list_nicconfigs(struct lxc_conf
*c
, const char *key
,
314 char *retv
, int inlen
)
316 struct lxc_netdev
*netdev
;
317 int fulllen
= 0, len
;
319 netdev
= get_netdev_from_key(key
+12, &c
->network
);
326 memset(retv
, 0, inlen
);
328 strprint(retv
, inlen
, "script.up\n");
329 if (netdev
->type
!= LXC_NET_EMPTY
) {
330 strprint(retv
, inlen
, "flags\n");
331 strprint(retv
, inlen
, "link\n");
332 strprint(retv
, inlen
, "name\n");
333 strprint(retv
, inlen
, "hwaddr\n");
334 strprint(retv
, inlen
, "mtu\n");
335 strprint(retv
, inlen
, "ipv6\n");
336 strprint(retv
, inlen
, "ipv6_gateway\n");
337 strprint(retv
, inlen
, "ipv4\n");
338 strprint(retv
, inlen
, "ipv4_gateway\n");
340 switch(netdev
->type
) {
342 strprint(retv
, inlen
, "veth.pair\n");
344 case LXC_NET_MACVLAN
:
345 strprint(retv
, inlen
, "macvlan.mode\n");
348 strprint(retv
, inlen
, "vlan.id\n");
356 static struct lxc_netdev
*network_netdev(const char *key
, const char *value
,
357 struct lxc_list
*network
)
359 struct lxc_netdev
*netdev
= NULL
;
361 if (lxc_list_empty(network
)) {
362 ERROR("network is not created for '%s' = '%s' option",
367 if (get_network_netdev_idx(key
+12) == -1)
368 netdev
= lxc_list_last_elem(network
);
370 netdev
= get_netdev_from_key(key
+12, network
);
373 ERROR("no network device defined for '%s' = '%s' option",
381 static int network_ifname(char **valuep
, const char *value
)
383 if (strlen(value
) >= IFNAMSIZ
) {
384 ERROR("interface name '%s' too long (>%d)\n",
385 value
, IFNAMSIZ
- 1);
389 *valuep
= strdup(value
);
391 ERROR("failed to dup string '%s'", value
);
398 #ifndef MACVLAN_MODE_PRIVATE
399 # define MACVLAN_MODE_PRIVATE 1
402 #ifndef MACVLAN_MODE_VEPA
403 # define MACVLAN_MODE_VEPA 2
406 #ifndef MACVLAN_MODE_BRIDGE
407 # define MACVLAN_MODE_BRIDGE 4
410 static int macvlan_mode(int *valuep
, const char *value
)
416 { "private", MACVLAN_MODE_PRIVATE
},
417 { "vepa", MACVLAN_MODE_VEPA
},
418 { "bridge", MACVLAN_MODE_BRIDGE
},
423 for (i
= 0; i
< sizeof(m
)/sizeof(m
[0]); i
++) {
424 if (strcmp(m
[i
].name
, value
))
434 static int config_network_flags(const char *key
, const char *value
,
435 struct lxc_conf
*lxc_conf
)
437 struct lxc_netdev
*netdev
;
439 netdev
= network_netdev(key
, value
, &lxc_conf
->network
);
443 netdev
->flags
|= IFF_UP
;
448 static int config_network_link(const char *key
, const char *value
,
449 struct lxc_conf
*lxc_conf
)
451 struct lxc_netdev
*netdev
;
453 netdev
= network_netdev(key
, value
, &lxc_conf
->network
);
457 return network_ifname(&netdev
->link
, value
);
460 static int config_network_name(const char *key
, const char *value
,
461 struct lxc_conf
*lxc_conf
)
463 struct lxc_netdev
*netdev
;
465 netdev
= network_netdev(key
, value
, &lxc_conf
->network
);
469 return network_ifname(&netdev
->name
, value
);
472 static int config_network_veth_pair(const char *key
, const char *value
,
473 struct lxc_conf
*lxc_conf
)
475 struct lxc_netdev
*netdev
;
477 netdev
= network_netdev(key
, value
, &lxc_conf
->network
);
481 return network_ifname(&netdev
->priv
.veth_attr
.pair
, value
);
484 static int config_network_macvlan_mode(const char *key
, const char *value
,
485 struct lxc_conf
*lxc_conf
)
487 struct lxc_netdev
*netdev
;
489 netdev
= network_netdev(key
, value
, &lxc_conf
->network
);
493 return macvlan_mode(&netdev
->priv
.macvlan_attr
.mode
, value
);
496 static int config_network_hwaddr(const char *key
, const char *value
,
497 struct lxc_conf
*lxc_conf
)
499 struct lxc_netdev
*netdev
;
502 netdev
= network_netdev(key
, value
, &lxc_conf
->network
);
506 hwaddr
= strdup(value
);
508 SYSERROR("failed to dup string '%s'", value
);
513 free(netdev
->hwaddr
);
514 netdev
->hwaddr
= hwaddr
;
518 static int config_network_vlan_id(const char *key
, const char *value
,
519 struct lxc_conf
*lxc_conf
)
521 struct lxc_netdev
*netdev
;
523 netdev
= network_netdev(key
, value
, &lxc_conf
->network
);
527 if (get_u16(&netdev
->priv
.vlan_attr
.vid
, value
, 0))
533 static int config_network_mtu(const char *key
, const char *value
,
534 struct lxc_conf
*lxc_conf
)
536 struct lxc_netdev
*netdev
;
539 netdev
= network_netdev(key
, value
, &lxc_conf
->network
);
545 SYSERROR("failed to dup string '%s'", value
);
555 static int config_network_ipv4(const char *key
, const char *value
,
556 struct lxc_conf
*lxc_conf
)
558 struct lxc_netdev
*netdev
;
559 struct lxc_inetdev
*inetdev
;
560 struct lxc_list
*list
;
561 char *cursor
, *slash
, *addr
= NULL
, *bcast
= NULL
, *prefix
= NULL
;
563 netdev
= network_netdev(key
, value
, &lxc_conf
->network
);
567 inetdev
= malloc(sizeof(*inetdev
));
569 SYSERROR("failed to allocate ipv4 address");
572 memset(inetdev
, 0, sizeof(*inetdev
));
574 list
= malloc(sizeof(*list
));
576 SYSERROR("failed to allocate memory");
581 list
->elem
= inetdev
;
583 addr
= strdup(value
);
585 ERROR("no address specified");
589 cursor
= strstr(addr
, " ");
595 slash
= strstr(addr
, "/");
601 if (!inet_pton(AF_INET
, addr
, &inetdev
->addr
)) {
602 SYSERROR("invalid ipv4 address: %s", value
);
607 if (bcast
&& !inet_pton(AF_INET
, bcast
, &inetdev
->bcast
)) {
608 SYSERROR("invalid ipv4 broadcast address: %s", value
);
613 /* no prefix specified, determine it from the network class */
614 inetdev
->prefix
= prefix
? atoi(prefix
) :
615 config_ip_prefix(&inetdev
->addr
);
617 /* if no broadcast address, let compute one from the
621 inetdev
->bcast
.s_addr
= inetdev
->addr
.s_addr
;
622 inetdev
->bcast
.s_addr
|=
623 htonl(INADDR_BROADCAST
>> inetdev
->prefix
);
626 lxc_list_add(&netdev
->ipv4
, list
);
632 static int config_network_ipv4_gateway(const char *key
, const char *value
,
633 struct lxc_conf
*lxc_conf
)
635 struct lxc_netdev
*netdev
;
638 netdev
= network_netdev(key
, value
, &lxc_conf
->network
);
642 gw
= malloc(sizeof(*gw
));
644 SYSERROR("failed to allocate ipv4 gateway address");
649 ERROR("no ipv4 gateway address specified");
653 if (!strcmp(value
, "auto")) {
654 netdev
->ipv4_gateway
= NULL
;
655 netdev
->ipv4_gateway_auto
= true;
657 if (!inet_pton(AF_INET
, value
, gw
)) {
658 SYSERROR("invalid ipv4 gateway address: %s", value
);
662 netdev
->ipv4_gateway
= gw
;
663 netdev
->ipv4_gateway_auto
= false;
669 static int config_network_ipv6(const char *key
, const char *value
,
670 struct lxc_conf
*lxc_conf
)
672 struct lxc_netdev
*netdev
;
673 struct lxc_inet6dev
*inet6dev
;
674 struct lxc_list
*list
;
678 netdev
= network_netdev(key
, value
, &lxc_conf
->network
);
682 inet6dev
= malloc(sizeof(*inet6dev
));
684 SYSERROR("failed to allocate ipv6 address");
687 memset(inet6dev
, 0, sizeof(*inet6dev
));
689 list
= malloc(sizeof(*list
));
691 SYSERROR("failed to allocate memory");
696 list
->elem
= inet6dev
;
698 valdup
= strdup(value
);
700 ERROR("no address specified");
704 inet6dev
->prefix
= 64;
705 slash
= strstr(valdup
, "/");
709 inet6dev
->prefix
= atoi(netmask
);
712 if (!inet_pton(AF_INET6
, value
, &inet6dev
->addr
)) {
713 SYSERROR("invalid ipv6 address: %s", value
);
718 lxc_list_add(&netdev
->ipv6
, list
);
724 static int config_network_ipv6_gateway(const char *key
, const char *value
,
725 struct lxc_conf
*lxc_conf
)
727 struct lxc_netdev
*netdev
;
730 netdev
= network_netdev(key
, value
, &lxc_conf
->network
);
734 gw
= malloc(sizeof(*gw
));
736 SYSERROR("failed to allocate ipv6 gateway address");
741 ERROR("no ipv6 gateway address specified");
745 if (!strcmp(value
, "auto")) {
746 netdev
->ipv6_gateway
= NULL
;
747 netdev
->ipv6_gateway_auto
= true;
749 if (!inet_pton(AF_INET6
, value
, gw
)) {
750 SYSERROR("invalid ipv6 gateway address: %s", value
);
754 netdev
->ipv6_gateway
= gw
;
755 netdev
->ipv6_gateway_auto
= false;
761 static int config_network_script(const char *key
, const char *value
,
762 struct lxc_conf
*lxc_conf
)
764 struct lxc_netdev
*netdev
;
766 netdev
= network_netdev(key
, value
, &lxc_conf
->network
);
770 char *copy
= strdup(value
);
772 SYSERROR("failed to dup string '%s'", value
);
775 if (strstr(key
, "script.up") != NULL
) {
776 netdev
->upscript
= copy
;
779 if (strcmp(key
, "lxc.network.script.down") == 0) {
780 netdev
->downscript
= copy
;
783 SYSERROR("Unknown key: %s", key
);
788 static int add_hook(struct lxc_conf
*lxc_conf
, int which
, char *hook
)
790 struct lxc_list
*hooklist
;
792 hooklist
= malloc(sizeof(*hooklist
));
797 hooklist
->elem
= hook
;
798 lxc_list_add_tail(&lxc_conf
->hooks
[which
], hooklist
);
802 static int config_seccomp(const char *key
, const char *value
,
803 struct lxc_conf
*lxc_conf
)
807 if (lxc_conf
->seccomp
) {
808 ERROR("seccomp already defined");
811 path
= strdup(value
);
813 SYSERROR("failed to strdup '%s': %m", value
);
817 if (lxc_conf
->seccomp
)
818 free(lxc_conf
->seccomp
);
819 lxc_conf
->seccomp
= path
;
824 static int config_hook(const char *key
, const char *value
,
825 struct lxc_conf
*lxc_conf
)
827 char *copy
= strdup(value
);
829 SYSERROR("failed to dup string '%s'", value
);
832 if (strcmp(key
, "lxc.hook.pre-start") == 0)
833 return add_hook(lxc_conf
, LXCHOOK_PRESTART
, copy
);
834 else if (strcmp(key
, "lxc.hook.pre-mount") == 0)
835 return add_hook(lxc_conf
, LXCHOOK_PREMOUNT
, copy
);
836 else if (strcmp(key
, "lxc.hook.mount") == 0)
837 return add_hook(lxc_conf
, LXCHOOK_MOUNT
, copy
);
838 else if (strcmp(key
, "lxc.hook.start") == 0)
839 return add_hook(lxc_conf
, LXCHOOK_START
, copy
);
840 else if (strcmp(key
, "lxc.hook.post-stop") == 0)
841 return add_hook(lxc_conf
, LXCHOOK_POSTSTOP
, copy
);
842 SYSERROR("Unknown key: %s", key
);
847 static int config_personality(const char *key
, const const char *value
,
848 struct lxc_conf
*lxc_conf
)
850 signed long personality
= lxc_config_parse_arch(value
);
852 if (personality
>= 0)
853 lxc_conf
->personality
= personality
;
855 WARN("unsupported personality '%s'", value
);
860 static int config_pts(const char *key
, const char *value
,
861 struct lxc_conf
*lxc_conf
)
863 int maxpts
= atoi(value
);
865 lxc_conf
->pts
= maxpts
;
870 static int config_tty(const char *key
, const char *value
,
871 struct lxc_conf
*lxc_conf
)
873 int nbtty
= atoi(value
);
875 lxc_conf
->tty
= nbtty
;
880 static int config_ttydir(const char *key
, const char *value
,
881 struct lxc_conf
*lxc_conf
)
885 if (!value
|| strlen(value
) == 0)
887 path
= strdup(value
);
889 SYSERROR("failed to strdup '%s': %m", value
);
893 if (lxc_conf
->ttydir
)
894 free(lxc_conf
->ttydir
);
895 lxc_conf
->ttydir
= path
;
901 static int config_aa_profile(const char *key
, const char *value
,
902 struct lxc_conf
*lxc_conf
)
906 if (!value
|| strlen(value
) == 0)
908 path
= strdup(value
);
910 SYSERROR("failed to strdup '%s': %m", value
);
914 if (lxc_conf
->aa_profile
)
915 free(lxc_conf
->aa_profile
);
916 lxc_conf
->aa_profile
= path
;
922 static int config_logfile(const char *key
, const char *value
,
923 struct lxc_conf
*lxc_conf
)
927 // if given a blank entry, null out any previous entries.
928 if (!value
|| strlen(value
) == 0) {
929 if (lxc_conf
->logfile
) {
930 free(lxc_conf
->logfile
);
931 lxc_conf
->logfile
= NULL
;
936 path
= strdup(value
);
938 SYSERROR("failed to strdup '%s': %m", value
);
942 if (lxc_log_set_file(path
)) {
947 if (lxc_conf
->logfile
)
948 free(lxc_conf
->logfile
);
949 lxc_conf
->logfile
= path
;
954 static int config_loglevel(const char *key
, const char *value
,
955 struct lxc_conf
*lxc_conf
)
957 if (!value
|| strlen(value
) == 0)
960 if (value
[0] >= '0' && value
[0] <= '9')
961 lxc_conf
->loglevel
= atoi(value
);
963 lxc_conf
->loglevel
= lxc_log_priority_to_int(value
);
964 return lxc_log_set_level(lxc_conf
->loglevel
);
967 static int config_autodev(const char *key
, const char *value
,
968 struct lxc_conf
*lxc_conf
)
972 lxc_conf
->autodev
= v
;
977 static int config_cgroup(const char *key
, const char *value
,
978 struct lxc_conf
*lxc_conf
)
980 char *token
= "lxc.cgroup.";
982 struct lxc_list
*cglist
= NULL
;
983 struct lxc_cgroup
*cgelem
= NULL
;
985 subkey
= strstr(key
, token
);
993 if (strlen(subkey
) == strlen(token
))
996 subkey
+= strlen(token
);
998 cglist
= malloc(sizeof(*cglist
));
1002 cgelem
= malloc(sizeof(*cgelem
));
1005 memset(cgelem
, 0, sizeof(*cgelem
));
1007 cgelem
->subsystem
= strdup(subkey
);
1008 cgelem
->value
= strdup(value
);
1010 if (!cgelem
->subsystem
|| !cgelem
->value
)
1013 cglist
->elem
= cgelem
;
1015 lxc_list_add_tail(&lxc_conf
->cgroup
, cglist
);
1024 if (cgelem
->subsystem
)
1025 free(cgelem
->subsystem
);
1028 free(cgelem
->value
);
1036 static int config_path_item(const char *key
, const char *value
,
1037 struct lxc_conf
*lxc_conf
, char **conf_item
)
1040 if (strlen(value
) >= MAXPATHLEN
) {
1041 ERROR("%s path is too long", value
);
1045 valdup
= strdup(value
);
1047 SYSERROR("failed to duplicate string %s", value
);
1052 *conf_item
= valdup
;
1057 static int config_fstab(const char *key
, const char *value
,
1058 struct lxc_conf
*lxc_conf
)
1060 return config_path_item(key
, value
, lxc_conf
, &lxc_conf
->fstab
);
1063 static int config_mount(const char *key
, const char *value
,
1064 struct lxc_conf
*lxc_conf
)
1066 char *fstab_token
= "lxc.mount";
1067 char *token
= "lxc.mount.entry";
1070 struct lxc_list
*mntlist
;
1072 subkey
= strstr(key
, token
);
1075 subkey
= strstr(key
, fstab_token
);
1080 return config_fstab(key
, value
, lxc_conf
);
1083 if (!strlen(subkey
))
1086 mntlist
= malloc(sizeof(*mntlist
));
1090 mntelem
= strdup(value
);
1093 mntlist
->elem
= mntelem
;
1095 lxc_list_add_tail(&lxc_conf
->mount_list
, mntlist
);
1100 static int config_cap_drop(const char *key
, const char *value
,
1101 struct lxc_conf
*lxc_conf
)
1103 char *dropcaps
, *dropptr
, *sptr
, *token
;
1104 struct lxc_list
*droplist
;
1110 dropcaps
= strdup(value
);
1112 SYSERROR("failed to dup '%s'", value
);
1116 /* in case several capability drop is specified in a single line
1117 * split these caps in a single element for the list */
1118 for (dropptr
= dropcaps
;;dropptr
= NULL
) {
1119 token
= strtok_r(dropptr
, " \t", &sptr
);
1125 droplist
= malloc(sizeof(*droplist
));
1127 SYSERROR("failed to allocate drop list");
1131 droplist
->elem
= strdup(token
);
1132 if (!droplist
->elem
) {
1133 SYSERROR("failed to dup '%s'", token
);
1138 lxc_list_add_tail(&lxc_conf
->caps
, droplist
);
1146 static int config_console(const char *key
, const char *value
,
1147 struct lxc_conf
*lxc_conf
)
1151 path
= strdup(value
);
1153 SYSERROR("failed to strdup '%s': %m", value
);
1157 if (lxc_conf
->console
.path
)
1158 free(lxc_conf
->console
.path
);
1159 lxc_conf
->console
.path
= path
;
1164 static int config_includefile(const char *key
, const char *value
,
1165 struct lxc_conf
*lxc_conf
)
1167 return lxc_config_read(value
, lxc_conf
);
1170 static int config_rootfs(const char *key
, const char *value
,
1171 struct lxc_conf
*lxc_conf
)
1173 return config_path_item(key
, value
, lxc_conf
, &lxc_conf
->rootfs
.path
);
1176 static int config_rootfs_mount(const char *key
, const char *value
,
1177 struct lxc_conf
*lxc_conf
)
1179 return config_path_item(key
, value
, lxc_conf
, &lxc_conf
->rootfs
.mount
);
1182 static int config_pivotdir(const char *key
, const char *value
,
1183 struct lxc_conf
*lxc_conf
)
1185 return config_path_item(key
, value
, lxc_conf
, &lxc_conf
->rootfs
.pivot
);
1188 static int config_utsname(const char *key
, const char *value
,
1189 struct lxc_conf
*lxc_conf
)
1191 struct utsname
*utsname
;
1193 utsname
= malloc(sizeof(*utsname
));
1195 SYSERROR("failed to allocate memory");
1199 if (strlen(value
) >= sizeof(utsname
->nodename
)) {
1200 ERROR("node name '%s' is too long",
1205 strcpy(utsname
->nodename
, value
);
1206 if (lxc_conf
->utsname
)
1207 free(lxc_conf
->utsname
);
1208 lxc_conf
->utsname
= utsname
;
1213 static int parse_line(char *buffer
, void *data
)
1215 struct lxc_config_t
*config
;
1222 if (lxc_is_line_empty(buffer
))
1225 /* we have to dup the buffer otherwise, at the re-exec for
1226 * reboot we modified the original string on the stack by
1227 * replacing '=' by '\0' below
1229 linep
= line
= strdup(buffer
);
1231 SYSERROR("failed to allocate memory for '%s'", buffer
);
1235 line
+= lxc_char_left_gc(line
, strlen(line
));
1237 /* martian option - ignoring it, the commented lines beginning by '#'
1240 if (strncmp(line
, "lxc.", 4))
1245 dot
= strstr(line
, "=");
1247 ERROR("invalid configuration line: %s", line
);
1255 key
[lxc_char_right_gc(key
, strlen(key
))] = '\0';
1257 value
+= lxc_char_left_gc(value
, strlen(value
));
1258 value
[lxc_char_right_gc(value
, strlen(value
))] = '\0';
1260 config
= lxc_getconfig(key
);
1262 ERROR("unknown key %s", key
);
1266 ret
= config
->cb(key
, value
, data
);
1273 int lxc_config_readline(char *buffer
, struct lxc_conf
*conf
)
1275 return parse_line(buffer
, conf
);
1278 int lxc_config_read(const char *file
, struct lxc_conf
*conf
)
1280 return lxc_file_for_each_line(file
, parse_line
, conf
);
1283 int lxc_config_define_add(struct lxc_list
*defines
, char* arg
)
1285 struct lxc_list
*dent
;
1287 dent
= malloc(sizeof(struct lxc_list
));
1292 lxc_list_add_tail(defines
, dent
);
1296 int lxc_config_define_load(struct lxc_list
*defines
, struct lxc_conf
*conf
)
1298 struct lxc_list
*it
,*next
;
1301 lxc_list_for_each(it
, defines
) {
1302 ret
= lxc_config_readline(it
->elem
, conf
);
1307 lxc_list_for_each_safe(it
, defines
, next
) {
1315 signed long lxc_config_parse_arch(const char *arch
)
1317 #if HAVE_SYS_PERSONALITY_H
1322 { "x86", PER_LINUX32
},
1323 { "i686", PER_LINUX32
},
1324 { "x86_64", PER_LINUX
},
1325 { "amd64", PER_LINUX
},
1327 size_t len
= sizeof(pername
) / sizeof(pername
[0]);
1331 for (i
= 0; i
< len
; i
++) {
1332 if (!strcmp(pername
[i
].name
, arch
))
1333 return pername
[i
].per
;
1340 static int lxc_get_conf_int(struct lxc_conf
*c
, char *retv
, int inlen
, int v
)
1345 memset(retv
, 0, inlen
);
1346 return snprintf(retv
, inlen
, "%d", v
);
1349 static int lxc_get_arch_entry(struct lxc_conf
*c
, char *retv
, int inlen
)
1356 memset(retv
, 0, inlen
);
1358 #if HAVE_SYS_PERSONALITY_H
1361 switch(c
->personality
) {
1362 case PER_LINUX32
: strprint(retv
, inlen
, "x86"); break;
1363 case PER_LINUX
: strprint(retv
, inlen
, "x86_64"); break;
1372 * If you ask for a specific cgroup value, i.e. lxc.cgroup.devices.list,
1373 * then just the value(s) will be printed. Since there still could be
1374 * more than one, it is newline-separated.
1375 * (Maybe that's ambigous, since some values, i.e. devices.list, will
1376 * already have newlines?)
1377 * If you ask for 'lxc.cgroup", then all cgroup entries will be printed,
1378 * in 'lxc.cgroup.subsystem.key = value' format.
1380 static int lxc_get_cgroup_entry(struct lxc_conf
*c
, char *retv
, int inlen
,
1383 int fulllen
= 0, len
;
1385 struct lxc_list
*it
;
1390 memset(retv
, 0, inlen
);
1392 if (strcmp(key
, "all") == 0)
1395 lxc_list_for_each(it
, &c
->cgroup
) {
1396 struct lxc_cgroup
*cg
= it
->elem
;
1398 strprint(retv
, inlen
, "lxc.cgroup.%s = %s\n", cg
->subsystem
, cg
->value
);
1399 } else if (strcmp(cg
->subsystem
, key
) == 0) {
1400 strprint(retv
, inlen
, "%s\n", cg
->value
);
1406 static int lxc_get_item_hooks(struct lxc_conf
*c
, char *retv
, int inlen
,
1410 int len
, fulllen
= 0, found
= -1;
1411 struct lxc_list
*it
;
1414 /* "lxc.hook.mount" */
1415 subkey
= index(key
, '.');
1416 if (subkey
) subkey
= index(subkey
+1, '.');
1422 for (i
=0; i
<NUM_LXC_HOOKS
; i
++) {
1423 if (strcmp(lxchook_names
[i
], subkey
) == 0) {
1434 memset(retv
, 0, inlen
);
1436 lxc_list_for_each(it
, &c
->hooks
[found
]) {
1437 strprint(retv
, inlen
, "%s\n", (char *)it
->elem
);
1442 static int lxc_get_item_cap_drop(struct lxc_conf
*c
, char *retv
, int inlen
)
1444 int len
, fulllen
= 0;
1445 struct lxc_list
*it
;
1450 memset(retv
, 0, inlen
);
1452 lxc_list_for_each(it
, &c
->caps
) {
1453 strprint(retv
, inlen
, "%s\n", (char *)it
->elem
);
1458 static int lxc_get_mount_entries(struct lxc_conf
*c
, char *retv
, int inlen
)
1460 int len
, fulllen
= 0;
1461 struct lxc_list
*it
;
1466 memset(retv
, 0, inlen
);
1468 lxc_list_for_each(it
, &c
->mount_list
) {
1469 strprint(retv
, inlen
, "%s\n", (char *)it
->elem
);
1475 * lxc.network.0.XXX, where XXX can be: name, type, link, flags, type,
1476 * macvlan.mode, veth.pair, vlan, ipv4, ipv6, upscript, hwaddr, mtu,
1477 * ipv4_gateway, ipv6_gateway. ipvX_gateway can return 'auto' instead
1478 * of an address. ipv4 and ipv6 return lists (newline-separated).
1479 * things like veth.pair return '' if invalid (i.e. if called for vlan
1482 static int lxc_get_item_nic(struct lxc_conf
*c
, char *retv
, int inlen
,
1486 int len
, fulllen
= 0;
1487 struct lxc_netdev
*netdev
;
1492 memset(retv
, 0, inlen
);
1494 p1
= index(key
, '.');
1495 if (!p1
|| *(p1
+1) == '\0') return -1;
1498 netdev
= get_netdev_from_key(key
, &c
->network
);
1501 if (strcmp(p1
, "name") == 0) {
1503 strprint(retv
, inlen
, "%s", netdev
->name
);
1504 } else if (strcmp(p1
, "type") == 0) {
1505 strprint(retv
, inlen
, "%s", lxc_net_type_to_str(netdev
->type
));
1506 } else if (strcmp(p1
, "link") == 0) {
1508 strprint(retv
, inlen
, "%s", netdev
->link
);
1509 } else if (strcmp(p1
, "flags") == 0) {
1510 if (netdev
->flags
& IFF_UP
)
1511 strprint(retv
, inlen
, "up");
1512 } else if (strcmp(p1
, "upscript") == 0) {
1513 if (netdev
->upscript
)
1514 strprint(retv
, inlen
, "%s", netdev
->upscript
);
1515 } else if (strcmp(p1
, "hwaddr") == 0) {
1517 strprint(retv
, inlen
, "%s", netdev
->hwaddr
);
1518 } else if (strcmp(p1
, "mtu") == 0) {
1520 strprint(retv
, inlen
, "%s", netdev
->mtu
);
1521 } else if (strcmp(p1
, "macvlan.mode") == 0) {
1522 if (netdev
->type
== LXC_NET_MACVLAN
) {
1524 switch (netdev
->priv
.macvlan_attr
.mode
) {
1525 case MACVLAN_MODE_PRIVATE
: mode
= "private"; break;
1526 case MACVLAN_MODE_VEPA
: mode
= "vepa"; break;
1527 case MACVLAN_MODE_BRIDGE
: mode
= "bridge"; break;
1528 default: mode
= "(invalid)"; break;
1530 strprint(retv
, inlen
, "%s", mode
);
1532 } else if (strcmp(p1
, "veth.pair") == 0) {
1533 if (netdev
->type
== LXC_NET_VETH
&& netdev
->priv
.veth_attr
.pair
)
1534 strprint(retv
, inlen
, "%s", netdev
->priv
.veth_attr
.pair
);
1535 } else if (strcmp(p1
, "vlan") == 0) {
1536 if (netdev
->type
== LXC_NET_VLAN
) {
1537 strprint(retv
, inlen
, "%d", netdev
->priv
.vlan_attr
.vid
);
1539 } else if (strcmp(p1
, "ipv4_gateway") == 0) {
1540 if (netdev
->ipv4_gateway_auto
) {
1541 strprint(retv
, inlen
, "auto");
1542 } else if (netdev
->ipv4_gateway
) {
1543 char buf
[INET_ADDRSTRLEN
];
1544 inet_ntop(AF_INET
, netdev
->ipv4_gateway
, buf
, sizeof(buf
));
1545 strprint(retv
, inlen
, "%s", buf
);
1547 } else if (strcmp(p1
, "ipv4") == 0) {
1548 struct lxc_list
*it2
;
1549 lxc_list_for_each(it2
, &netdev
->ipv4
) {
1550 struct lxc_inetdev
*i
= it2
->elem
;
1551 char buf
[INET_ADDRSTRLEN
];
1552 inet_ntop(AF_INET
, &i
->addr
, buf
, sizeof(buf
));
1553 strprint(retv
, inlen
, "%s\n", buf
);
1555 } else if (strcmp(p1
, "ipv6_gateway") == 0) {
1556 if (netdev
->ipv6_gateway_auto
) {
1557 strprint(retv
, inlen
, "auto");
1558 } else if (netdev
->ipv6_gateway
) {
1559 char buf
[INET_ADDRSTRLEN
];
1560 inet_ntop(AF_INET
, netdev
->ipv6_gateway
, buf
, sizeof(buf
));
1561 strprint(retv
, inlen
, "%s", buf
);
1563 } else if (strcmp(p1
, "ipv6") == 0) {
1564 struct lxc_list
*it2
;
1565 lxc_list_for_each(it2
, &netdev
->ipv6
) {
1566 struct lxc_inetdev
*i
= it2
->elem
;
1567 char buf
[INET_ADDRSTRLEN
];
1568 inet_ntop(AF_INET6
, &i
->addr
, buf
, sizeof(buf
));
1569 strprint(retv
, inlen
, "%s\n", buf
);
1575 static int lxc_get_item_network(struct lxc_conf
*c
, char *retv
, int inlen
)
1577 int len
, fulllen
= 0;
1578 struct lxc_list
*it
;
1583 memset(retv
, 0, inlen
);
1585 lxc_list_for_each(it
, &c
->network
) {
1586 struct lxc_netdev
*n
= it
->elem
;
1587 const char *t
= lxc_net_type_to_str(n
->type
);
1588 strprint(retv
, inlen
, "%s\n", t
? t
: "(invalid)");
1593 int lxc_get_config_item(struct lxc_conf
*c
, const char *key
, char *retv
,
1596 const char *v
= NULL
;
1598 if (strcmp(key
, "lxc.mount.entry") == 0)
1599 return lxc_get_mount_entries(c
, retv
, inlen
);
1600 else if (strcmp(key
, "lxc.mount") == 0)
1602 else if (strcmp(key
, "lxc.tty") == 0)
1603 return lxc_get_conf_int(c
, retv
, inlen
, c
->tty
);
1604 else if (strcmp(key
, "lxc.pts") == 0)
1605 return lxc_get_conf_int(c
, retv
, inlen
, c
->pts
);
1606 else if (strcmp(key
, "lxc.devttydir") == 0)
1608 else if (strcmp(key
, "lxc.arch") == 0)
1609 return lxc_get_arch_entry(c
, retv
, inlen
);
1611 else if (strcmp(key
, "lxc.aa_profile") == 0)
1614 else if (strcmp(key
, "lxc.logfile") == 0)
1616 else if (strcmp(key
, "lxc.loglevel") == 0)
1617 v
= lxc_log_priority_to_string(c
->loglevel
);
1618 else if (strcmp(key
, "lxc.cgroup") == 0) // all cgroup info
1619 return lxc_get_cgroup_entry(c
, retv
, inlen
, "all");
1620 else if (strncmp(key
, "lxc.cgroup.", 11) == 0) // specific cgroup info
1621 return lxc_get_cgroup_entry(c
, retv
, inlen
, key
+ 11);
1622 else if (strcmp(key
, "lxc.utsname") == 0)
1623 v
= c
->utsname
? c
->utsname
->nodename
: NULL
;
1624 else if (strcmp(key
, "lxc.console") == 0)
1625 v
= c
->console
.path
;
1626 else if (strcmp(key
, "lxc.rootfs.mount") == 0)
1627 v
= c
->rootfs
.mount
;
1628 else if (strcmp(key
, "lxc.rootfs") == 0)
1630 else if (strcmp(key
, "lxc.pivotdir") == 0)
1631 v
= c
->rootfs
.pivot
;
1632 else if (strcmp(key
, "lxc.cap.drop") == 0)
1633 return lxc_get_item_cap_drop(c
, retv
, inlen
);
1634 else if (strncmp(key
, "lxc.hook", 8) == 0)
1635 return lxc_get_item_hooks(c
, retv
, inlen
, key
);
1636 else if (strcmp(key
, "lxc.network") == 0)
1637 return lxc_get_item_network(c
, retv
, inlen
);
1638 else if (strncmp(key
, "lxc.network.", 12) == 0)
1639 return lxc_get_item_nic(c
, retv
, inlen
, key
+ 12);
1644 if (retv
&& inlen
>= strlen(v
) + 1)
1645 strncpy(retv
, v
, strlen(v
)+1);
1649 int lxc_clear_config_item(struct lxc_conf
*c
, const char *key
)
1651 if (strcmp(key
, "lxc.network") == 0)
1652 return lxc_clear_config_network(c
);
1653 else if (strncmp(key
, "lxc.network.", 12) == 0)
1654 return lxc_clear_nic(c
, key
+ 12);
1655 else if (strcmp(key
, "lxc.cap.drop") == 0)
1656 return lxc_clear_config_caps(c
);
1657 else if (strncmp(key
, "lxc.cgroup", 10) == 0)
1658 return lxc_clear_cgroups(c
, key
);
1659 else if (strcmp(key
, "lxc.mount.entries") == 0)
1660 return lxc_clear_mount_entries(c
);
1661 else if (strncmp(key
, "lxc.hook", 8) == 0)
1662 return lxc_clear_hooks(c
, key
);
1668 * writing out a confile.
1670 void write_config(FILE *fout
, struct lxc_conf
*c
)
1672 struct lxc_list
*it
;
1676 fprintf(fout
, "lxc.mount = %s\n", c
->fstab
);
1677 lxc_list_for_each(it
, &c
->mount_list
) {
1678 fprintf(fout
, "lxc.mount.entry = %s\n", (char *)it
->elem
);
1681 fprintf(fout
, "lxc.tty = %d\n", c
->tty
);
1683 fprintf(fout
, "lxc.pts = %d\n", c
->pts
);
1685 fprintf(fout
, "lxc.devttydir = %s\n", c
->ttydir
);
1686 #if HAVE_SYS_PERSONALITY_H
1687 switch(c
->personality
) {
1688 case PER_LINUX32
: fprintf(fout
, "lxc.arch = x86\n"); break;
1689 case PER_LINUX
: fprintf(fout
, "lxc.arch = x86_64\n"); break;
1695 fprintf(fout
, "lxc.aa_profile = %s\n", c
->aa_profile
);
1697 if (c
->loglevel
!= LXC_LOG_PRIORITY_NOTSET
)
1698 fprintf(fout
, "lxc.loglevel = %s\n", lxc_log_priority_to_string(c
->loglevel
));
1700 fprintf(fout
, "lxc.logfile = %s\n", c
->logfile
);
1701 lxc_list_for_each(it
, &c
->cgroup
) {
1702 struct lxc_cgroup
*cg
= it
->elem
;
1703 fprintf(fout
, "lxc.cgroup.%s = %s\n", cg
->subsystem
, cg
->value
);
1706 fprintf(fout
, "lxc.utsname = %s\n", c
->utsname
->nodename
);
1707 lxc_list_for_each(it
, &c
->network
) {
1708 struct lxc_netdev
*n
= it
->elem
;
1709 const char *t
= lxc_net_type_to_str(n
->type
);
1710 struct lxc_list
*it2
;
1711 fprintf(fout
, "lxc.network.type = %s\n", t
? t
: "(invalid)");
1712 if (n
->flags
& IFF_UP
)
1713 fprintf(fout
, "lxc.network.flags = up\n");
1715 fprintf(fout
, "lxc.network.link = %s\n", n
->link
);
1717 fprintf(fout
, "lxc.network.name = %s\n", n
->name
);
1718 if (n
->type
== LXC_NET_MACVLAN
) {
1720 switch (n
->priv
.macvlan_attr
.mode
) {
1721 case MACVLAN_MODE_PRIVATE
: mode
= "private"; break;
1722 case MACVLAN_MODE_VEPA
: mode
= "vepa"; break;
1723 case MACVLAN_MODE_BRIDGE
: mode
= "bridge"; break;
1724 default: mode
= "(invalid)"; break;
1726 fprintf(fout
, "lxc.network.macvlan.mode = %s\n", mode
);
1727 } else if (n
->type
== LXC_NET_VETH
) {
1728 if (n
->priv
.veth_attr
.pair
)
1729 fprintf(fout
, "lxc.network.veth.pair = %s\n",
1730 n
->priv
.veth_attr
.pair
);
1731 } else if (n
->type
== LXC_NET_VLAN
) {
1732 fprintf(fout
, "lxc.network.vlan.id = %d\n", n
->priv
.vlan_attr
.vid
);
1735 fprintf(fout
, "lxc.network.script.up = %s\n", n
->upscript
);
1737 fprintf(fout
, "lxc.network.hwaddr = %s\n", n
->hwaddr
);
1739 fprintf(fout
, "lxc.network.mtu = %s\n", n
->mtu
);
1740 if (n
->ipv4_gateway_auto
)
1741 fprintf(fout
, "lxc.network.ipv4.gateway = auto\n");
1742 else if (n
->ipv4_gateway
) {
1743 char buf
[INET_ADDRSTRLEN
];
1744 inet_ntop(AF_INET
, n
->ipv4_gateway
, buf
, sizeof(buf
));
1745 fprintf(fout
, "lxc.network.ipv4.gateway = %s\n", buf
);
1747 lxc_list_for_each(it2
, &n
->ipv4
) {
1748 struct lxc_inetdev
*i
= it2
->elem
;
1749 char buf
[INET_ADDRSTRLEN
];
1750 inet_ntop(AF_INET
, &i
->addr
, buf
, sizeof(buf
));
1751 fprintf(fout
, "lxc.network.ipv4 = %s\n", buf
);
1753 if (n
->ipv6_gateway_auto
)
1754 fprintf(fout
, "lxc.network.ipv6.gateway = auto\n");
1755 else if (n
->ipv6_gateway
) {
1756 char buf
[INET6_ADDRSTRLEN
];
1757 inet_ntop(AF_INET6
, n
->ipv6_gateway
, buf
, sizeof(buf
));
1758 fprintf(fout
, "lxc.network.ipv6.gateway = %s\n", buf
);
1760 lxc_list_for_each(it2
, &n
->ipv6
) {
1761 struct lxc_inet6dev
*i
= it2
->elem
;
1762 char buf
[INET6_ADDRSTRLEN
];
1763 inet_ntop(AF_INET
, &i
->addr
, buf
, sizeof(buf
));
1764 fprintf(fout
, "lxc.network.ipv6 = %s\n", buf
);
1767 lxc_list_for_each(it
, &c
->caps
)
1768 fprintf(fout
, "lxc.cap.drop = %s\n", (char *)it
->elem
);
1769 for (i
=0; i
<NUM_LXC_HOOKS
; i
++) {
1770 lxc_list_for_each(it
, &c
->hooks
[i
])
1771 fprintf(fout
, "lxc.hook.%s = %s\n",
1772 lxchook_names
[i
], (char *)it
->elem
);
1774 if (c
->console
.path
)
1775 fprintf(fout
, "lxc.console = %s\n", c
->console
.path
);
1777 fprintf(fout
, "lxc.rootfs = %s\n", c
->rootfs
.path
);
1778 if (c
->rootfs
.mount
&& strcmp(c
->rootfs
.mount
, LXCROOTFSMOUNT
) != 0)
1779 fprintf(fout
, "lxc.rootfs.mount = %s\n", c
->rootfs
.mount
);
1780 if (c
->rootfs
.pivot
)
1781 fprintf(fout
, "lxc.pivotdir = %s\n", c
->rootfs
.pivot
);