2 * lxc: linux Container library
4 * (C) Copyright IBM Corp. 2007, 2008
7 * Daniel Lezcano <daniel.lezcano at free.fr>
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
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>
47 #include "lxcseccomp.h"
49 #if HAVE_SYS_PERSONALITY_H
50 #include <sys/personality.h>
53 lxc_log_define(lxc_confile
, lxc
);
55 static int config_personality(const char *, const char *, struct lxc_conf
*);
56 static int config_pts(const char *, const char *, struct lxc_conf
*);
57 static int config_tty(const char *, const char *, struct lxc_conf
*);
58 static int config_ttydir(const char *, const char *, struct lxc_conf
*);
59 static int config_kmsg(const char *, const char *, struct lxc_conf
*);
60 static int config_lsm_aa_profile(const char *, const char *, struct lxc_conf
*);
61 static int config_lsm_se_context(const char *, const char *, struct lxc_conf
*);
62 static int config_cgroup(const char *, const char *, struct lxc_conf
*);
63 static int config_idmap(const char *, const char *, struct lxc_conf
*);
64 static int config_loglevel(const char *, const char *, struct lxc_conf
*);
65 static int config_logfile(const char *, const char *, struct lxc_conf
*);
66 static int config_mount(const char *, const char *, struct lxc_conf
*);
67 static int config_rootfs(const char *, const char *, struct lxc_conf
*);
68 static int config_rootfs_mount(const char *, const char *, struct lxc_conf
*);
69 static int config_rootfs_options(const char *, const char *, struct lxc_conf
*);
70 static int config_pivotdir(const char *, const char *, struct lxc_conf
*);
71 static int config_utsname(const char *, const char *, struct lxc_conf
*);
72 static int config_hook(const char *, const char *, struct lxc_conf
*lxc_conf
);
73 static int config_network_type(const char *, const char *, struct lxc_conf
*);
74 static int config_network_flags(const char *, const char *, struct lxc_conf
*);
75 static int config_network_link(const char *, const char *, struct lxc_conf
*);
76 static int config_network_name(const char *, const char *, struct lxc_conf
*);
77 static int config_network_veth_pair(const char *, const char *, struct lxc_conf
*);
78 static int config_network_macvlan_mode(const char *, const char *, struct lxc_conf
*);
79 static int config_network_hwaddr(const char *, const char *, struct lxc_conf
*);
80 static int config_network_vlan_id(const char *, const char *, struct lxc_conf
*);
81 static int config_network_mtu(const char *, const char *, struct lxc_conf
*);
82 static int config_network_ipv4(const char *, const char *, struct lxc_conf
*);
83 static int config_network_ipv4_gateway(const char *, const char *, struct lxc_conf
*);
84 static int config_network_script_up(const char *, const char *, struct lxc_conf
*);
85 static int config_network_script_down(const char *, const char *, struct lxc_conf
*);
86 static int config_network_ipv6(const char *, const char *, struct lxc_conf
*);
87 static int config_network_ipv6_gateway(const char *, const char *, struct lxc_conf
*);
88 static int config_cap_drop(const char *, const char *, struct lxc_conf
*);
89 static int config_cap_keep(const char *, const char *, struct lxc_conf
*);
90 static int config_console(const char *, const char *, struct lxc_conf
*);
91 static int config_seccomp(const char *, const char *, struct lxc_conf
*);
92 static int config_includefile(const char *, const char *, struct lxc_conf
*);
93 static int config_network_nic(const char *, const char *, struct lxc_conf
*);
94 static int config_autodev(const char *, const char *, struct lxc_conf
*);
95 static int config_haltsignal(const char *, const char *, struct lxc_conf
*);
96 static int config_stopsignal(const char *, const char *, struct lxc_conf
*);
97 static int config_start(const char *, const char *, struct lxc_conf
*);
98 static int config_group(const char *, const char *, struct lxc_conf
*);
100 static struct lxc_config_t config
[] = {
102 { "lxc.arch", config_personality
},
103 { "lxc.pts", config_pts
},
104 { "lxc.tty", config_tty
},
105 { "lxc.devttydir", config_ttydir
},
106 { "lxc.kmsg", config_kmsg
},
107 { "lxc.aa_profile", config_lsm_aa_profile
},
108 { "lxc.se_context", config_lsm_se_context
},
109 { "lxc.cgroup", config_cgroup
},
110 { "lxc.id_map", config_idmap
},
111 { "lxc.loglevel", config_loglevel
},
112 { "lxc.logfile", config_logfile
},
113 { "lxc.mount", config_mount
},
114 { "lxc.rootfs.mount", config_rootfs_mount
},
115 { "lxc.rootfs.options", config_rootfs_options
},
116 { "lxc.rootfs", config_rootfs
},
117 { "lxc.pivotdir", config_pivotdir
},
118 { "lxc.utsname", config_utsname
},
119 { "lxc.hook.pre-start", config_hook
},
120 { "lxc.hook.pre-mount", config_hook
},
121 { "lxc.hook.mount", config_hook
},
122 { "lxc.hook.autodev", config_hook
},
123 { "lxc.hook.start", config_hook
},
124 { "lxc.hook.post-stop", config_hook
},
125 { "lxc.hook.clone", config_hook
},
126 { "lxc.network.type", config_network_type
},
127 { "lxc.network.flags", config_network_flags
},
128 { "lxc.network.link", config_network_link
},
129 { "lxc.network.name", config_network_name
},
130 { "lxc.network.macvlan.mode", config_network_macvlan_mode
},
131 { "lxc.network.veth.pair", config_network_veth_pair
},
132 { "lxc.network.script.up", config_network_script_up
},
133 { "lxc.network.script.down", config_network_script_down
},
134 { "lxc.network.hwaddr", config_network_hwaddr
},
135 { "lxc.network.mtu", config_network_mtu
},
136 { "lxc.network.vlan.id", config_network_vlan_id
},
137 { "lxc.network.ipv4.gateway", config_network_ipv4_gateway
},
138 { "lxc.network.ipv4", config_network_ipv4
},
139 { "lxc.network.ipv6.gateway", config_network_ipv6_gateway
},
140 { "lxc.network.ipv6", config_network_ipv6
},
141 /* config_network_nic must come after all other 'lxc.network.*' entries */
142 { "lxc.network.", config_network_nic
},
143 { "lxc.cap.drop", config_cap_drop
},
144 { "lxc.cap.keep", config_cap_keep
},
145 { "lxc.console", config_console
},
146 { "lxc.seccomp", config_seccomp
},
147 { "lxc.include", config_includefile
},
148 { "lxc.autodev", config_autodev
},
149 { "lxc.haltsignal", config_haltsignal
},
150 { "lxc.stopsignal", config_stopsignal
},
151 { "lxc.start.auto", config_start
},
152 { "lxc.start.delay", config_start
},
153 { "lxc.start.order", config_start
},
154 { "lxc.group", config_group
},
162 static const struct signame signames
[] = {
184 static const size_t config_size
= sizeof(config
)/sizeof(struct lxc_config_t
);
186 extern struct lxc_config_t
*lxc_getconfig(const char *key
)
190 for (i
= 0; i
< config_size
; i
++)
191 if (!strncmp(config
[i
].name
, key
,
192 strlen(config
[i
].name
)))
197 #define strprint(str, inlen, ...) \
199 len = snprintf(str, inlen, ##__VA_ARGS__); \
200 if (len < 0) { SYSERROR("snprintf"); return -1; }; \
203 if (str) str += len; \
205 if (inlen < 0) inlen = 0; \
209 int lxc_listconfigs(char *retv
, int inlen
)
211 int i
, fulllen
= 0, len
;
216 memset(retv
, 0, inlen
);
217 for (i
= 0; i
< config_size
; i
++) {
218 char *s
= config
[i
].name
;
219 if (s
[strlen(s
)-1] == '.')
221 strprint(retv
, inlen
, "%s\n", s
);
226 static int config_string_item(char **conf_item
, const char *value
)
230 if (!value
|| strlen(value
) == 0) {
237 new_value
= strdup(value
);
239 SYSERROR("failed to strdup '%s': %m", value
);
245 *conf_item
= new_value
;
249 static int config_string_item_max(char **conf_item
, const char *value
,
252 if (strlen(value
) >= max
) {
253 ERROR("%s is too long (>= %lu)", value
, (unsigned long)max
);
257 return config_string_item(conf_item
, value
);
260 static int config_path_item(char **conf_item
, const char *value
)
262 return config_string_item_max(conf_item
, value
, PATH_MAX
);
266 * config entry is something like "lxc.network.0.ipv4"
267 * the key 'lxc.network.' was found. So we make sure next
268 * comes an integer, find the right callback (by rewriting
269 * the key), and call it.
271 static int config_network_nic(const char *key
, const char *value
,
272 struct lxc_conf
*lxc_conf
)
274 char *copy
= strdup(key
), *p
;
276 struct lxc_config_t
*config
;
279 SYSERROR("failed to allocate memory");
283 * ok we know that to get here we've got "lxc.network."
284 * and it isn't any of the other network entries. So
285 * after the second . should come an integer (# of defined
286 * nic) followed by a valid entry.
288 if (*(key
+12) < '0' || *(key
+12) > '9')
290 p
= index(key
+12, '.');
293 strcpy(copy
+12, p
+1);
294 config
= lxc_getconfig(copy
);
296 ERROR("unknown key %s", key
);
299 ret
= config
->cb(key
, value
, lxc_conf
);
306 static int macvlan_mode(int *valuep
, const char *value
);
308 static int config_network_type(const char *key
, const char *value
,
309 struct lxc_conf
*lxc_conf
)
311 struct lxc_list
*network
= &lxc_conf
->network
;
312 struct lxc_netdev
*netdev
;
313 struct lxc_list
*list
;
315 if (!value
|| strlen(value
) == 0)
316 return lxc_clear_config_network(lxc_conf
);
318 netdev
= malloc(sizeof(*netdev
));
320 SYSERROR("failed to allocate memory");
324 memset(netdev
, 0, sizeof(*netdev
));
325 lxc_list_init(&netdev
->ipv4
);
326 lxc_list_init(&netdev
->ipv6
);
328 list
= malloc(sizeof(*list
));
330 SYSERROR("failed to allocate memory");
338 lxc_list_add_tail(network
, list
);
340 if (!strcmp(value
, "veth"))
341 netdev
->type
= LXC_NET_VETH
;
342 else if (!strcmp(value
, "macvlan")) {
343 netdev
->type
= LXC_NET_MACVLAN
;
344 macvlan_mode(&netdev
->priv
.macvlan_attr
.mode
, "private");
346 else if (!strcmp(value
, "vlan"))
347 netdev
->type
= LXC_NET_VLAN
;
348 else if (!strcmp(value
, "phys"))
349 netdev
->type
= LXC_NET_PHYS
;
350 else if (!strcmp(value
, "empty"))
351 netdev
->type
= LXC_NET_EMPTY
;
352 else if (!strcmp(value
, "none"))
353 netdev
->type
= LXC_NET_NONE
;
355 ERROR("invalid network type %s", value
);
361 static int config_ip_prefix(struct in_addr
*addr
)
363 if (IN_CLASSA(addr
->s_addr
))
364 return 32 - IN_CLASSA_NSHIFT
;
365 if (IN_CLASSB(addr
->s_addr
))
366 return 32 - IN_CLASSB_NSHIFT
;
367 if (IN_CLASSC(addr
->s_addr
))
368 return 32 - IN_CLASSC_NSHIFT
;
374 * if you have p="lxc.network.0.link", pass it p+12
375 * to get back '0' (the index of the nic)
377 static int get_network_netdev_idx(const char *key
)
381 if (*key
< '0' || *key
> '9')
383 ret
= sscanf(key
, "%d", &idx
);
390 * if you have p="lxc.network.0", pass this p+12 and it will return
391 * the netdev of the first configured nic
393 static struct lxc_netdev
*get_netdev_from_key(const char *key
,
394 struct lxc_list
*network
)
396 int i
= 0, idx
= get_network_netdev_idx(key
);
397 struct lxc_netdev
*netdev
= NULL
;
401 lxc_list_for_each(it
, network
) {
410 extern int lxc_list_nicconfigs(struct lxc_conf
*c
, const char *key
,
411 char *retv
, int inlen
)
413 struct lxc_netdev
*netdev
;
414 int fulllen
= 0, len
;
416 netdev
= get_netdev_from_key(key
+12, &c
->network
);
423 memset(retv
, 0, inlen
);
425 strprint(retv
, inlen
, "script.up\n");
426 strprint(retv
, inlen
, "script.down\n");
427 if (netdev
->type
!= LXC_NET_EMPTY
) {
428 strprint(retv
, inlen
, "flags\n");
429 strprint(retv
, inlen
, "link\n");
430 strprint(retv
, inlen
, "name\n");
431 strprint(retv
, inlen
, "hwaddr\n");
432 strprint(retv
, inlen
, "mtu\n");
433 strprint(retv
, inlen
, "ipv6\n");
434 strprint(retv
, inlen
, "ipv6_gateway\n");
435 strprint(retv
, inlen
, "ipv4\n");
436 strprint(retv
, inlen
, "ipv4_gateway\n");
438 switch(netdev
->type
) {
440 strprint(retv
, inlen
, "veth.pair\n");
442 case LXC_NET_MACVLAN
:
443 strprint(retv
, inlen
, "macvlan.mode\n");
446 strprint(retv
, inlen
, "vlan.id\n");
454 static struct lxc_netdev
*network_netdev(const char *key
, const char *value
,
455 struct lxc_list
*network
)
457 struct lxc_netdev
*netdev
= NULL
;
459 if (lxc_list_empty(network
)) {
460 ERROR("network is not created for '%s' = '%s' option",
465 if (get_network_netdev_idx(key
+12) == -1)
466 netdev
= lxc_list_last_elem(network
);
468 netdev
= get_netdev_from_key(key
+12, network
);
471 ERROR("no network device defined for '%s' = '%s' option",
479 static int network_ifname(char **valuep
, const char *value
)
481 return config_string_item_max(valuep
, value
, IFNAMSIZ
);
484 #ifndef MACVLAN_MODE_PRIVATE
485 # define MACVLAN_MODE_PRIVATE 1
488 #ifndef MACVLAN_MODE_VEPA
489 # define MACVLAN_MODE_VEPA 2
492 #ifndef MACVLAN_MODE_BRIDGE
493 # define MACVLAN_MODE_BRIDGE 4
496 static int macvlan_mode(int *valuep
, const char *value
)
502 { "private", MACVLAN_MODE_PRIVATE
},
503 { "vepa", MACVLAN_MODE_VEPA
},
504 { "bridge", MACVLAN_MODE_BRIDGE
},
509 for (i
= 0; i
< sizeof(m
)/sizeof(m
[0]); i
++) {
510 if (strcmp(m
[i
].name
, value
))
520 static int rand_complete_hwaddr(char *hwaddr
)
522 const char hex
[] = "0123456789abcdef";
528 unsigned int seed
=randseed(false);
530 while (*curs
!= '\0')
532 if ( *curs
== 'x' || *curs
== 'X' ) {
533 if (curs
- hwaddr
== 1) {
534 //ensure address is unicast
536 *curs
= hex
[rand_r(&seed
) & 0x0E];
538 *curs
= hex
[rand_r(&seed
) & 0x0F];
540 *curs
= hex
[rand() & 0x0E];
542 *curs
= hex
[rand() & 0x0F];
551 static int config_network_flags(const char *key
, const char *value
,
552 struct lxc_conf
*lxc_conf
)
554 struct lxc_netdev
*netdev
;
556 netdev
= network_netdev(key
, value
, &lxc_conf
->network
);
560 netdev
->flags
|= IFF_UP
;
565 static int config_network_link(const char *key
, const char *value
,
566 struct lxc_conf
*lxc_conf
)
568 struct lxc_netdev
*netdev
;
570 netdev
= network_netdev(key
, value
, &lxc_conf
->network
);
574 return network_ifname(&netdev
->link
, value
);
577 static int config_network_name(const char *key
, const char *value
,
578 struct lxc_conf
*lxc_conf
)
580 struct lxc_netdev
*netdev
;
582 netdev
= network_netdev(key
, value
, &lxc_conf
->network
);
586 return network_ifname(&netdev
->name
, value
);
589 static int config_network_veth_pair(const char *key
, const char *value
,
590 struct lxc_conf
*lxc_conf
)
592 struct lxc_netdev
*netdev
;
594 netdev
= network_netdev(key
, value
, &lxc_conf
->network
);
598 return network_ifname(&netdev
->priv
.veth_attr
.pair
, value
);
601 static int config_network_macvlan_mode(const char *key
, const char *value
,
602 struct lxc_conf
*lxc_conf
)
604 struct lxc_netdev
*netdev
;
606 netdev
= network_netdev(key
, value
, &lxc_conf
->network
);
610 return macvlan_mode(&netdev
->priv
.macvlan_attr
.mode
, value
);
613 static int config_network_hwaddr(const char *key
, const char *value
,
614 struct lxc_conf
*lxc_conf
)
616 struct lxc_netdev
*netdev
;
618 char *new_value
= strdup(value
);
620 SYSERROR("failed to strdup '%s': %m", value
);
623 rand_complete_hwaddr(new_value
);
625 netdev
= network_netdev(key
, new_value
, &lxc_conf
->network
);
631 if (!new_value
|| strlen(new_value
) == 0) {
633 netdev
->hwaddr
= NULL
;
637 netdev
->hwaddr
= new_value
;
641 static int config_network_vlan_id(const char *key
, const char *value
,
642 struct lxc_conf
*lxc_conf
)
644 struct lxc_netdev
*netdev
;
646 netdev
= network_netdev(key
, value
, &lxc_conf
->network
);
650 if (get_u16(&netdev
->priv
.vlan_attr
.vid
, value
, 0))
656 static int config_network_mtu(const char *key
, const char *value
,
657 struct lxc_conf
*lxc_conf
)
659 struct lxc_netdev
*netdev
;
661 netdev
= network_netdev(key
, value
, &lxc_conf
->network
);
665 return config_string_item(&netdev
->mtu
, value
);
668 static int config_network_ipv4(const char *key
, const char *value
,
669 struct lxc_conf
*lxc_conf
)
671 struct lxc_netdev
*netdev
;
672 struct lxc_inetdev
*inetdev
;
673 struct lxc_list
*list
;
674 char *cursor
, *slash
, *addr
= NULL
, *bcast
= NULL
, *prefix
= NULL
;
676 netdev
= network_netdev(key
, value
, &lxc_conf
->network
);
680 inetdev
= malloc(sizeof(*inetdev
));
682 SYSERROR("failed to allocate ipv4 address");
685 memset(inetdev
, 0, sizeof(*inetdev
));
687 list
= malloc(sizeof(*list
));
689 SYSERROR("failed to allocate memory");
695 list
->elem
= inetdev
;
697 addr
= strdup(value
);
699 ERROR("no address specified");
705 cursor
= strstr(addr
, " ");
711 slash
= strstr(addr
, "/");
717 if (!inet_pton(AF_INET
, addr
, &inetdev
->addr
)) {
718 SYSERROR("invalid ipv4 address: %s", value
);
725 if (bcast
&& !inet_pton(AF_INET
, bcast
, &inetdev
->bcast
)) {
726 SYSERROR("invalid ipv4 broadcast address: %s", value
);
733 /* no prefix specified, determine it from the network class */
734 inetdev
->prefix
= prefix
? atoi(prefix
) :
735 config_ip_prefix(&inetdev
->addr
);
737 /* if no broadcast address, let compute one from the
741 inetdev
->bcast
.s_addr
= inetdev
->addr
.s_addr
;
742 inetdev
->bcast
.s_addr
|=
743 htonl(INADDR_BROADCAST
>> inetdev
->prefix
);
746 lxc_list_add_tail(&netdev
->ipv4
, list
);
752 static int config_network_ipv4_gateway(const char *key
, const char *value
,
753 struct lxc_conf
*lxc_conf
)
755 struct lxc_netdev
*netdev
;
758 netdev
= network_netdev(key
, value
, &lxc_conf
->network
);
762 gw
= malloc(sizeof(*gw
));
764 SYSERROR("failed to allocate ipv4 gateway address");
769 ERROR("no ipv4 gateway address specified");
774 if (!strcmp(value
, "auto")) {
776 netdev
->ipv4_gateway
= NULL
;
777 netdev
->ipv4_gateway_auto
= true;
779 if (!inet_pton(AF_INET
, value
, gw
)) {
780 SYSERROR("invalid ipv4 gateway address: %s", value
);
785 netdev
->ipv4_gateway
= gw
;
786 netdev
->ipv4_gateway_auto
= false;
792 static int config_network_ipv6(const char *key
, const char *value
,
793 struct lxc_conf
*lxc_conf
)
795 struct lxc_netdev
*netdev
;
796 struct lxc_inet6dev
*inet6dev
;
797 struct lxc_list
*list
;
801 netdev
= network_netdev(key
, value
, &lxc_conf
->network
);
805 inet6dev
= malloc(sizeof(*inet6dev
));
807 SYSERROR("failed to allocate ipv6 address");
810 memset(inet6dev
, 0, sizeof(*inet6dev
));
812 list
= malloc(sizeof(*list
));
814 SYSERROR("failed to allocate memory");
820 list
->elem
= inet6dev
;
822 valdup
= strdup(value
);
824 ERROR("no address specified");
830 inet6dev
->prefix
= 64;
831 slash
= strstr(valdup
, "/");
835 inet6dev
->prefix
= atoi(netmask
);
838 if (!inet_pton(AF_INET6
, valdup
, &inet6dev
->addr
)) {
839 SYSERROR("invalid ipv6 address: %s", valdup
);
846 lxc_list_add_tail(&netdev
->ipv6
, list
);
852 static int config_network_ipv6_gateway(const char *key
, const char *value
,
853 struct lxc_conf
*lxc_conf
)
855 struct lxc_netdev
*netdev
;
857 netdev
= network_netdev(key
, value
, &lxc_conf
->network
);
862 ERROR("no ipv6 gateway address specified");
866 if (!strcmp(value
, "auto")) {
867 netdev
->ipv6_gateway
= NULL
;
868 netdev
->ipv6_gateway_auto
= true;
872 gw
= malloc(sizeof(*gw
));
874 SYSERROR("failed to allocate ipv6 gateway address");
878 if (!inet_pton(AF_INET6
, value
, gw
)) {
879 SYSERROR("invalid ipv6 gateway address: %s", value
);
884 netdev
->ipv6_gateway
= gw
;
885 netdev
->ipv6_gateway_auto
= false;
891 static int config_network_script_up(const char *key
, const char *value
,
892 struct lxc_conf
*lxc_conf
)
894 struct lxc_netdev
*netdev
;
896 netdev
= network_netdev(key
, value
, &lxc_conf
->network
);
900 return config_string_item(&netdev
->upscript
, value
);
903 static int config_network_script_down(const char *key
, const char *value
,
904 struct lxc_conf
*lxc_conf
)
906 struct lxc_netdev
*netdev
;
908 netdev
= network_netdev(key
, value
, &lxc_conf
->network
);
912 return config_string_item(&netdev
->downscript
, value
);
915 static int add_hook(struct lxc_conf
*lxc_conf
, int which
, char *hook
)
917 struct lxc_list
*hooklist
;
919 hooklist
= malloc(sizeof(*hooklist
));
924 hooklist
->elem
= hook
;
925 lxc_list_add_tail(&lxc_conf
->hooks
[which
], hooklist
);
929 static int config_seccomp(const char *key
, const char *value
,
930 struct lxc_conf
*lxc_conf
)
932 return config_path_item(&lxc_conf
->seccomp
, value
);
935 static int config_hook(const char *key
, const char *value
,
936 struct lxc_conf
*lxc_conf
)
940 if (!value
|| strlen(value
) == 0)
941 return lxc_clear_hooks(lxc_conf
, key
);
943 copy
= strdup(value
);
945 SYSERROR("failed to dup string '%s'", value
);
948 if (strcmp(key
, "lxc.hook.pre-start") == 0)
949 return add_hook(lxc_conf
, LXCHOOK_PRESTART
, copy
);
950 else if (strcmp(key
, "lxc.hook.pre-mount") == 0)
951 return add_hook(lxc_conf
, LXCHOOK_PREMOUNT
, copy
);
952 else if (strcmp(key
, "lxc.hook.autodev") == 0)
953 return add_hook(lxc_conf
, LXCHOOK_AUTODEV
, copy
);
954 else if (strcmp(key
, "lxc.hook.mount") == 0)
955 return add_hook(lxc_conf
, LXCHOOK_MOUNT
, copy
);
956 else if (strcmp(key
, "lxc.hook.start") == 0)
957 return add_hook(lxc_conf
, LXCHOOK_START
, copy
);
958 else if (strcmp(key
, "lxc.hook.post-stop") == 0)
959 return add_hook(lxc_conf
, LXCHOOK_POSTSTOP
, copy
);
960 else if (strcmp(key
, "lxc.hook.clone") == 0)
961 return add_hook(lxc_conf
, LXCHOOK_CLONE
, copy
);
962 SYSERROR("Unknown key: %s", key
);
967 static int config_personality(const char *key
, const char *value
,
968 struct lxc_conf
*lxc_conf
)
970 signed long personality
= lxc_config_parse_arch(value
);
972 if (personality
>= 0)
973 lxc_conf
->personality
= personality
;
975 WARN("unsupported personality '%s'", value
);
980 static int config_pts(const char *key
, const char *value
,
981 struct lxc_conf
*lxc_conf
)
983 int maxpts
= atoi(value
);
985 lxc_conf
->pts
= maxpts
;
990 static int config_start(const char *key
, const char *value
,
991 struct lxc_conf
*lxc_conf
)
993 if(strcmp(key
, "lxc.start.auto") == 0) {
994 lxc_conf
->start_auto
= atoi(value
);
997 else if (strcmp(key
, "lxc.start.delay") == 0) {
998 lxc_conf
->start_delay
= atoi(value
);
1001 else if (strcmp(key
, "lxc.start.order") == 0) {
1002 lxc_conf
->start_order
= atoi(value
);
1005 SYSERROR("Unknown key: %s", key
);
1009 static int config_group(const char *key
, const char *value
,
1010 struct lxc_conf
*lxc_conf
)
1012 char *groups
, *groupptr
, *sptr
, *token
;
1013 struct lxc_list
*grouplist
;
1017 return lxc_clear_groups(lxc_conf
);
1019 groups
= strdup(value
);
1021 SYSERROR("failed to dup '%s'", value
);
1025 /* in case several groups are specified in a single line
1026 * split these groups in a single element for the list */
1027 for (groupptr
= groups
;;groupptr
= NULL
) {
1028 token
= strtok_r(groupptr
, " \t", &sptr
);
1034 grouplist
= malloc(sizeof(*grouplist
));
1036 SYSERROR("failed to allocate groups list");
1040 grouplist
->elem
= strdup(token
);
1041 if (!grouplist
->elem
) {
1042 SYSERROR("failed to dup '%s'", token
);
1047 lxc_list_add_tail(&lxc_conf
->groups
, grouplist
);
1055 static int config_tty(const char *key
, const char *value
,
1056 struct lxc_conf
*lxc_conf
)
1058 int nbtty
= atoi(value
);
1060 lxc_conf
->tty
= nbtty
;
1065 static int config_ttydir(const char *key
, const char *value
,
1066 struct lxc_conf
*lxc_conf
)
1068 return config_string_item_max(&lxc_conf
->ttydir
, value
, NAME_MAX
+1);
1071 static int config_kmsg(const char *key
, const char *value
,
1072 struct lxc_conf
*lxc_conf
)
1074 int v
= atoi(value
);
1081 static int config_lsm_aa_profile(const char *key
, const char *value
,
1082 struct lxc_conf
*lxc_conf
)
1084 return config_string_item(&lxc_conf
->lsm_aa_profile
, value
);
1087 static int config_lsm_se_context(const char *key
, const char *value
,
1088 struct lxc_conf
*lxc_conf
)
1090 return config_string_item(&lxc_conf
->lsm_se_context
, value
);
1093 static int config_logfile(const char *key
, const char *value
,
1094 struct lxc_conf
*lxc_conf
)
1098 // store these values in the lxc_conf, and then try to set for
1099 // actual current logging.
1100 ret
= config_path_item(&lxc_conf
->logfile
, value
);
1102 ret
= lxc_log_set_file(lxc_conf
->logfile
);
1106 static int config_loglevel(const char *key
, const char *value
,
1107 struct lxc_conf
*lxc_conf
)
1111 if (!value
|| strlen(value
) == 0)
1114 if (value
[0] >= '0' && value
[0] <= '9')
1115 newlevel
= atoi(value
);
1117 newlevel
= lxc_log_priority_to_int(value
);
1118 // store these values in the lxc_conf, and then try to set for
1119 // actual current logging.
1120 lxc_conf
->loglevel
= newlevel
;
1121 return lxc_log_set_level(newlevel
);
1124 static int config_autodev(const char *key
, const char *value
,
1125 struct lxc_conf
*lxc_conf
)
1127 int v
= atoi(value
);
1129 lxc_conf
->autodev
= v
;
1134 static int sig_num(const char *sig
)
1140 n
= strtol(sig
, &endp
, 10);
1141 if (sig
== endp
|| n
< 0 || errno
!= 0)
1146 static int rt_sig_num(const char *signame
)
1151 if (strncasecmp(signame
, "max-", 4) == 0) {
1155 if (!isdigit(*signame
))
1157 sig_n
= sig_num(signame
);
1158 sig_n
= rtmax
? SIGRTMAX
- sig_n
: SIGRTMIN
+ sig_n
;
1159 if (sig_n
> SIGRTMAX
|| sig_n
< SIGRTMIN
)
1164 static const char *sig_name(int signum
) {
1167 for (n
= 0; n
< sizeof(signames
) / sizeof((signames
)[0]); n
++) {
1168 if (signum
== signames
[n
].num
)
1169 return signames
[n
].name
;
1174 static int sig_parse(const char *signame
) {
1177 if (isdigit(*signame
)) {
1178 return sig_num(signame
);
1179 } else if (strncasecmp(signame
, "sig", 3) == 0) {
1181 if (strncasecmp(signame
, "rt", 2) == 0)
1182 return rt_sig_num(signame
+ 2);
1183 for (n
= 0; n
< sizeof(signames
) / sizeof((signames
)[0]); n
++) {
1184 if (strcasecmp (signames
[n
].name
, signame
) == 0)
1185 return signames
[n
].num
;
1191 static int config_haltsignal(const char *key
, const char *value
,
1192 struct lxc_conf
*lxc_conf
)
1194 int sig_n
= sig_parse(value
);
1198 lxc_conf
->haltsignal
= sig_n
;
1203 static int config_stopsignal(const char *key
, const char *value
,
1204 struct lxc_conf
*lxc_conf
)
1206 int sig_n
= sig_parse(value
);
1210 lxc_conf
->stopsignal
= sig_n
;
1215 static int config_cgroup(const char *key
, const char *value
,
1216 struct lxc_conf
*lxc_conf
)
1218 char *token
= "lxc.cgroup.";
1220 struct lxc_list
*cglist
= NULL
;
1221 struct lxc_cgroup
*cgelem
= NULL
;
1223 if (!value
|| strlen(value
) == 0)
1224 return lxc_clear_cgroups(lxc_conf
, key
);
1226 subkey
= strstr(key
, token
);
1231 if (!strlen(subkey
))
1234 if (strlen(subkey
) == strlen(token
))
1237 subkey
+= strlen(token
);
1239 cglist
= malloc(sizeof(*cglist
));
1243 cgelem
= malloc(sizeof(*cgelem
));
1246 memset(cgelem
, 0, sizeof(*cgelem
));
1248 cgelem
->subsystem
= strdup(subkey
);
1249 cgelem
->value
= strdup(value
);
1251 if (!cgelem
->subsystem
|| !cgelem
->value
)
1254 cglist
->elem
= cgelem
;
1256 lxc_list_add_tail(&lxc_conf
->cgroup
, cglist
);
1265 if (cgelem
->subsystem
)
1266 free(cgelem
->subsystem
);
1269 free(cgelem
->value
);
1277 static int config_idmap(const char *key
, const char *value
, struct lxc_conf
*lxc_conf
)
1279 char *token
= "lxc.id_map";
1281 struct lxc_list
*idmaplist
= NULL
;
1282 struct id_map
*idmap
= NULL
;
1283 unsigned long hostid
, nsid
, range
;
1287 if (!value
|| strlen(value
) == 0)
1288 return lxc_clear_idmaps(lxc_conf
);
1290 subkey
= strstr(key
, token
);
1295 if (!strlen(subkey
))
1298 idmaplist
= malloc(sizeof(*idmaplist
));
1302 idmap
= malloc(sizeof(*idmap
));
1305 memset(idmap
, 0, sizeof(*idmap
));
1307 ret
= sscanf(value
, "%c %lu %lu %lu", &type
, &nsid
, &hostid
, &range
);
1311 INFO("read uid map: type %c nsid %lu hostid %lu range %lu", type
, nsid
, hostid
, range
);
1313 idmap
->idtype
= ID_TYPE_UID
;
1314 else if (type
== 'g')
1315 idmap
->idtype
= ID_TYPE_GID
;
1319 idmap
->hostid
= hostid
;
1321 idmap
->range
= range
;
1323 idmaplist
->elem
= idmap
;
1324 lxc_list_add_tail(&lxc_conf
->id_map
, idmaplist
);
1339 static int config_fstab(const char *key
, const char *value
,
1340 struct lxc_conf
*lxc_conf
)
1342 return config_path_item(&lxc_conf
->fstab
, value
);
1345 static int config_mount_auto(const char *key
, const char *value
,
1346 struct lxc_conf
*lxc_conf
)
1348 char *autos
, *autoptr
, *sptr
, *token
;
1349 static struct { const char *token
; int mask
; int flag
; } allowed_auto_mounts
[] = {
1350 { "proc", LXC_AUTO_PROC_MASK
, LXC_AUTO_PROC_MIXED
},
1351 { "proc:mixed", LXC_AUTO_PROC_MASK
, LXC_AUTO_PROC_MIXED
},
1352 { "proc:rw", LXC_AUTO_PROC_MASK
, LXC_AUTO_PROC_RW
},
1353 { "sys", LXC_AUTO_SYS_MASK
, LXC_AUTO_SYS_RO
},
1354 { "sys:ro", LXC_AUTO_SYS_MASK
, LXC_AUTO_SYS_RO
},
1355 { "sys:rw", LXC_AUTO_SYS_MASK
, LXC_AUTO_SYS_RW
},
1356 { "cgroup", LXC_AUTO_CGROUP_MASK
, LXC_AUTO_CGROUP_NOSPEC
},
1357 { "cgroup:mixed", LXC_AUTO_CGROUP_MASK
, LXC_AUTO_CGROUP_MIXED
},
1358 { "cgroup:ro", LXC_AUTO_CGROUP_MASK
, LXC_AUTO_CGROUP_RO
},
1359 { "cgroup:rw", LXC_AUTO_CGROUP_MASK
, LXC_AUTO_CGROUP_RW
},
1360 { "cgroup-full", LXC_AUTO_CGROUP_MASK
, LXC_AUTO_CGROUP_FULL_NOSPEC
},
1361 { "cgroup-full:mixed", LXC_AUTO_CGROUP_MASK
, LXC_AUTO_CGROUP_FULL_MIXED
},
1362 { "cgroup-full:ro", LXC_AUTO_CGROUP_MASK
, LXC_AUTO_CGROUP_FULL_RO
},
1363 { "cgroup-full:rw", LXC_AUTO_CGROUP_MASK
, LXC_AUTO_CGROUP_FULL_RW
},
1364 /* NB: For adding anything that ist just a single on/off, but has
1365 * no options: keep mask and flag identical and just define the
1366 * enum value as an unused bit so far
1376 autos
= strdup(value
);
1378 SYSERROR("failed to dup '%s'", value
);
1382 for (autoptr
= autos
; ; autoptr
= NULL
) {
1383 token
= strtok_r(autoptr
, " \t", &sptr
);
1389 for (i
= 0; allowed_auto_mounts
[i
].token
; i
++) {
1390 if (!strcmp(allowed_auto_mounts
[i
].token
, token
))
1394 if (!allowed_auto_mounts
[i
].token
) {
1395 ERROR("Invalid filesystem to automount: %s", token
);
1399 lxc_conf
->auto_mounts
&= ~allowed_auto_mounts
[i
].mask
;
1400 lxc_conf
->auto_mounts
|= allowed_auto_mounts
[i
].flag
;
1408 static int config_mount(const char *key
, const char *value
,
1409 struct lxc_conf
*lxc_conf
)
1411 char *fstab_token
= "lxc.mount";
1412 char *token
= "lxc.mount.entry";
1413 char *auto_token
= "lxc.mount.auto";
1416 struct lxc_list
*mntlist
;
1418 if (!value
|| strlen(value
) == 0)
1419 return lxc_clear_mount_entries(lxc_conf
);
1421 subkey
= strstr(key
, token
);
1424 subkey
= strstr(key
, auto_token
);
1427 subkey
= strstr(key
, fstab_token
);
1432 return config_fstab(key
, value
, lxc_conf
);
1435 return config_mount_auto(key
, value
, lxc_conf
);
1438 if (!strlen(subkey
))
1441 mntlist
= malloc(sizeof(*mntlist
));
1445 mntelem
= strdup(value
);
1450 mntlist
->elem
= mntelem
;
1452 lxc_list_add_tail(&lxc_conf
->mount_list
, mntlist
);
1457 static int config_cap_keep(const char *key
, const char *value
,
1458 struct lxc_conf
*lxc_conf
)
1460 char *keepcaps
, *keepptr
, *sptr
, *token
;
1461 struct lxc_list
*keeplist
;
1465 return lxc_clear_config_keepcaps(lxc_conf
);
1467 keepcaps
= strdup(value
);
1469 SYSERROR("failed to dup '%s'", value
);
1473 /* in case several capability keep is specified in a single line
1474 * split these caps in a single element for the list */
1475 for (keepptr
= keepcaps
;;keepptr
= NULL
) {
1476 token
= strtok_r(keepptr
, " \t", &sptr
);
1482 if (!strcmp(token
, "none"))
1483 lxc_clear_config_keepcaps(lxc_conf
);
1485 keeplist
= malloc(sizeof(*keeplist
));
1487 SYSERROR("failed to allocate keepcap list");
1491 keeplist
->elem
= strdup(token
);
1492 if (!keeplist
->elem
) {
1493 SYSERROR("failed to dup '%s'", token
);
1498 lxc_list_add_tail(&lxc_conf
->keepcaps
, keeplist
);
1506 static int config_cap_drop(const char *key
, const char *value
,
1507 struct lxc_conf
*lxc_conf
)
1509 char *dropcaps
, *dropptr
, *sptr
, *token
;
1510 struct lxc_list
*droplist
;
1514 return lxc_clear_config_caps(lxc_conf
);
1516 dropcaps
= strdup(value
);
1518 SYSERROR("failed to dup '%s'", value
);
1522 /* in case several capability drop is specified in a single line
1523 * split these caps in a single element for the list */
1524 for (dropptr
= dropcaps
;;dropptr
= NULL
) {
1525 token
= strtok_r(dropptr
, " \t", &sptr
);
1531 droplist
= malloc(sizeof(*droplist
));
1533 SYSERROR("failed to allocate drop list");
1537 droplist
->elem
= strdup(token
);
1538 if (!droplist
->elem
) {
1539 SYSERROR("failed to dup '%s'", token
);
1544 lxc_list_add_tail(&lxc_conf
->caps
, droplist
);
1552 static int config_console(const char *key
, const char *value
,
1553 struct lxc_conf
*lxc_conf
)
1555 return config_path_item(&lxc_conf
->console
.path
, value
);
1558 static int add_include_file(const char *fname
, struct lxc_conf
*lxc_conf
)
1560 struct lxc_list
*list
;
1562 int len
= strlen(fname
);
1564 list
= malloc(sizeof(*list
));
1567 lxc_list_init(list
);
1573 strncpy(v
, fname
, len
);
1576 lxc_list_add_tail(&lxc_conf
->includes
, list
);
1580 static int config_includefile(const char *key
, const char *value
,
1581 struct lxc_conf
*lxc_conf
)
1583 if (lxc_conf
->unexpanded
)
1584 return add_include_file(value
, lxc_conf
);
1585 return lxc_config_read(value
, lxc_conf
, NULL
);
1588 static int config_rootfs(const char *key
, const char *value
,
1589 struct lxc_conf
*lxc_conf
)
1591 return config_path_item(&lxc_conf
->rootfs
.path
, value
);
1594 static int config_rootfs_mount(const char *key
, const char *value
,
1595 struct lxc_conf
*lxc_conf
)
1597 return config_path_item(&lxc_conf
->rootfs
.mount
, value
);
1600 static int config_rootfs_options(const char *key
, const char *value
,
1601 struct lxc_conf
*lxc_conf
)
1603 return config_string_item(&lxc_conf
->rootfs
.options
, value
);
1606 static int config_pivotdir(const char *key
, const char *value
,
1607 struct lxc_conf
*lxc_conf
)
1609 return config_path_item(&lxc_conf
->rootfs
.pivot
, value
);
1612 static int config_utsname(const char *key
, const char *value
,
1613 struct lxc_conf
*lxc_conf
)
1615 struct utsname
*utsname
;
1617 utsname
= malloc(sizeof(*utsname
));
1619 SYSERROR("failed to allocate memory");
1623 if (strlen(value
) >= sizeof(utsname
->nodename
)) {
1624 ERROR("node name '%s' is too long",
1630 strcpy(utsname
->nodename
, value
);
1631 if (lxc_conf
->utsname
)
1632 free(lxc_conf
->utsname
);
1633 lxc_conf
->utsname
= utsname
;
1638 static int store_martian_option(char *line
, void *data
)
1640 struct lxc_conf
*conf
= data
;
1642 struct lxc_list
*list
;
1643 size_t len
= strlen(line
);
1645 if (!conf
->unexpanded
)
1647 list
= malloc(sizeof(*list
));
1650 lxc_list_init(list
);
1651 str
= malloc(len
+1);
1656 strncpy(str
, line
, len
);
1659 lxc_list_add_tail(&conf
->aliens
, list
);
1663 static int parse_line(char *buffer
, void *data
)
1665 struct lxc_config_t
*config
;
1672 if (lxc_is_line_empty(buffer
))
1675 /* we have to dup the buffer otherwise, at the re-exec for
1676 * reboot we modified the original string on the stack by
1677 * replacing '=' by '\0' below
1679 linep
= line
= strdup(buffer
);
1681 SYSERROR("failed to allocate memory for '%s'", buffer
);
1685 line
+= lxc_char_left_gc(line
, strlen(line
));
1687 /* ignore comments */
1691 /* martian option - save it in the unexpanded config only */
1692 if (strncmp(line
, "lxc.", 4)) {
1693 ret
= store_martian_option(line
, data
);
1699 dot
= strstr(line
, "=");
1701 ERROR("invalid configuration line: %s", line
);
1709 key
[lxc_char_right_gc(key
, strlen(key
))] = '\0';
1711 value
+= lxc_char_left_gc(value
, strlen(value
));
1712 value
[lxc_char_right_gc(value
, strlen(value
))] = '\0';
1714 config
= lxc_getconfig(key
);
1716 ERROR("unknown key %s", key
);
1720 ret
= config
->cb(key
, value
, data
);
1727 static int lxc_config_readline(char *buffer
, struct lxc_conf
*conf
)
1729 return parse_line(buffer
, conf
);
1732 int lxc_config_read(const char *file
, struct lxc_conf
*conf
, struct lxc_conf
*unexp_conf
)
1736 if( access(file
, R_OK
) == -1 ) {
1739 /* Catch only the top level config file name in the structure */
1740 if( ! conf
->rcfile
) {
1741 conf
->rcfile
= strdup( file
);
1743 ret
= lxc_file_for_each_line(file
, parse_line
, conf
);
1748 if (!unexp_conf
->rcfile
) {
1749 unexp_conf
->rcfile
= strdup( file
);
1752 return lxc_file_for_each_line(file
, parse_line
, unexp_conf
);
1755 int lxc_config_define_add(struct lxc_list
*defines
, char* arg
)
1757 struct lxc_list
*dent
;
1759 dent
= malloc(sizeof(struct lxc_list
));
1764 lxc_list_add_tail(defines
, dent
);
1768 int lxc_config_define_load(struct lxc_list
*defines
, struct lxc_conf
*conf
)
1770 struct lxc_list
*it
,*next
;
1773 lxc_list_for_each(it
, defines
) {
1774 ret
= lxc_config_readline(it
->elem
, conf
);
1779 lxc_list_for_each_safe(it
, defines
, next
) {
1787 signed long lxc_config_parse_arch(const char *arch
)
1789 #if HAVE_SYS_PERSONALITY_H
1794 { "x86", PER_LINUX32
},
1795 { "linux32", PER_LINUX32
},
1796 { "i386", PER_LINUX32
},
1797 { "i486", PER_LINUX32
},
1798 { "i586", PER_LINUX32
},
1799 { "i686", PER_LINUX32
},
1800 { "athlon", PER_LINUX32
},
1801 { "linux64", PER_LINUX
},
1802 { "x86_64", PER_LINUX
},
1803 { "amd64", PER_LINUX
},
1805 size_t len
= sizeof(pername
) / sizeof(pername
[0]);
1809 for (i
= 0; i
< len
; i
++) {
1810 if (!strcmp(pername
[i
].name
, arch
))
1811 return pername
[i
].per
;
1818 int lxc_fill_elevated_privileges(char *flaglist
, int *flags
)
1820 char *token
, *saveptr
= NULL
;
1822 struct { const char *token
; int flag
; } all_privs
[] = {
1823 { "CGROUP", LXC_ATTACH_MOVE_TO_CGROUP
},
1824 { "CAP", LXC_ATTACH_DROP_CAPABILITIES
},
1825 { "LSM", LXC_ATTACH_LSM_EXEC
},
1830 /* for the sake of backward compatibility, drop all privileges
1831 if none is specified */
1832 for (i
= 0; all_privs
[i
].token
; i
++) {
1833 *flags
|= all_privs
[i
].flag
;
1838 token
= strtok_r(flaglist
, "|", &saveptr
);
1841 for (i
= 0; all_privs
[i
].token
; i
++) {
1842 if (!strcmp(all_privs
[i
].token
, token
))
1843 aflag
= all_privs
[i
].flag
;
1850 token
= strtok_r(NULL
, "|", &saveptr
);
1855 static int lxc_get_conf_int(struct lxc_conf
*c
, char *retv
, int inlen
, int v
)
1860 memset(retv
, 0, inlen
);
1861 return snprintf(retv
, inlen
, "%d", v
);
1864 static int lxc_get_arch_entry(struct lxc_conf
*c
, char *retv
, int inlen
)
1871 memset(retv
, 0, inlen
);
1873 #if HAVE_SYS_PERSONALITY_H
1876 switch(c
->personality
) {
1877 case PER_LINUX32
: strprint(retv
, inlen
, "i686"); break;
1878 case PER_LINUX
: strprint(retv
, inlen
, "x86_64"); break;
1887 * If you ask for a specific cgroup value, i.e. lxc.cgroup.devices.list,
1888 * then just the value(s) will be printed. Since there still could be
1889 * more than one, it is newline-separated.
1890 * (Maybe that's ambigous, since some values, i.e. devices.list, will
1891 * already have newlines?)
1892 * If you ask for 'lxc.cgroup", then all cgroup entries will be printed,
1893 * in 'lxc.cgroup.subsystem.key = value' format.
1895 static int lxc_get_cgroup_entry(struct lxc_conf
*c
, char *retv
, int inlen
,
1898 int fulllen
= 0, len
;
1900 struct lxc_list
*it
;
1905 memset(retv
, 0, inlen
);
1907 if (strcmp(key
, "all") == 0)
1910 lxc_list_for_each(it
, &c
->cgroup
) {
1911 struct lxc_cgroup
*cg
= it
->elem
;
1913 strprint(retv
, inlen
, "lxc.cgroup.%s = %s\n", cg
->subsystem
, cg
->value
);
1914 } else if (strcmp(cg
->subsystem
, key
) == 0) {
1915 strprint(retv
, inlen
, "%s\n", cg
->value
);
1921 static int lxc_get_item_hooks(struct lxc_conf
*c
, char *retv
, int inlen
,
1925 int len
, fulllen
= 0, found
= -1;
1926 struct lxc_list
*it
;
1929 /* "lxc.hook.mount" */
1930 subkey
= index(key
, '.');
1931 if (subkey
) subkey
= index(subkey
+1, '.');
1937 for (i
=0; i
<NUM_LXC_HOOKS
; i
++) {
1938 if (strcmp(lxchook_names
[i
], subkey
) == 0) {
1949 memset(retv
, 0, inlen
);
1951 lxc_list_for_each(it
, &c
->hooks
[found
]) {
1952 strprint(retv
, inlen
, "%s\n", (char *)it
->elem
);
1957 static int lxc_get_item_groups(struct lxc_conf
*c
, char *retv
, int inlen
)
1959 int len
, fulllen
= 0;
1960 struct lxc_list
*it
;
1965 memset(retv
, 0, inlen
);
1967 lxc_list_for_each(it
, &c
->groups
) {
1968 strprint(retv
, inlen
, "%s\n", (char *)it
->elem
);
1973 static int lxc_get_item_cap_drop(struct lxc_conf
*c
, char *retv
, int inlen
)
1975 int len
, fulllen
= 0;
1976 struct lxc_list
*it
;
1981 memset(retv
, 0, inlen
);
1983 lxc_list_for_each(it
, &c
->caps
) {
1984 strprint(retv
, inlen
, "%s\n", (char *)it
->elem
);
1989 static int lxc_get_item_cap_keep(struct lxc_conf
*c
, char *retv
, int inlen
)
1991 int len
, fulllen
= 0;
1992 struct lxc_list
*it
;
1997 memset(retv
, 0, inlen
);
1999 lxc_list_for_each(it
, &c
->keepcaps
) {
2000 strprint(retv
, inlen
, "%s\n", (char *)it
->elem
);
2005 static int lxc_get_mount_entries(struct lxc_conf
*c
, char *retv
, int inlen
)
2007 int len
, fulllen
= 0;
2008 struct lxc_list
*it
;
2013 memset(retv
, 0, inlen
);
2015 lxc_list_for_each(it
, &c
->mount_list
) {
2016 strprint(retv
, inlen
, "%s\n", (char *)it
->elem
);
2021 static int lxc_get_auto_mounts(struct lxc_conf
*c
, char *retv
, int inlen
)
2023 int len
, fulllen
= 0;
2024 const char *sep
= "";
2029 memset(retv
, 0, inlen
);
2031 if (!(c
->auto_mounts
& LXC_AUTO_ALL_MASK
))
2034 switch (c
->auto_mounts
& LXC_AUTO_PROC_MASK
) {
2035 case LXC_AUTO_PROC_MIXED
: strprint(retv
, inlen
, "%sproc:mixed", sep
); sep
= " "; break;
2036 case LXC_AUTO_PROC_RW
: strprint(retv
, inlen
, "%sproc:rw", sep
); sep
= " "; break;
2039 switch (c
->auto_mounts
& LXC_AUTO_SYS_MASK
) {
2040 case LXC_AUTO_SYS_RO
: strprint(retv
, inlen
, "%ssys:ro", sep
); sep
= " "; break;
2041 case LXC_AUTO_SYS_RW
: strprint(retv
, inlen
, "%ssys:rw", sep
); sep
= " "; break;
2044 switch (c
->auto_mounts
& LXC_AUTO_CGROUP_MASK
) {
2045 case LXC_AUTO_CGROUP_NOSPEC
: strprint(retv
, inlen
, "%scgroup", sep
); sep
= " "; break;
2046 case LXC_AUTO_CGROUP_MIXED
: strprint(retv
, inlen
, "%scgroup:mixed", sep
); sep
= " "; break;
2047 case LXC_AUTO_CGROUP_RO
: strprint(retv
, inlen
, "%scgroup:ro", sep
); sep
= " "; break;
2048 case LXC_AUTO_CGROUP_RW
: strprint(retv
, inlen
, "%scgroup:rw", sep
); sep
= " "; break;
2049 case LXC_AUTO_CGROUP_FULL_NOSPEC
: strprint(retv
, inlen
, "%scgroup-full", sep
); sep
= " "; break;
2050 case LXC_AUTO_CGROUP_FULL_MIXED
: strprint(retv
, inlen
, "%scgroup-full:mixed", sep
); sep
= " "; break;
2051 case LXC_AUTO_CGROUP_FULL_RO
: strprint(retv
, inlen
, "%scgroup-full:ro", sep
); sep
= " "; break;
2052 case LXC_AUTO_CGROUP_FULL_RW
: strprint(retv
, inlen
, "%scgroup-full:rw", sep
); sep
= " "; break;
2060 * lxc.network.0.XXX, where XXX can be: name, type, link, flags, type,
2061 * macvlan.mode, veth.pair, vlan, ipv4, ipv6, script.up, hwaddr, mtu,
2062 * ipv4_gateway, ipv6_gateway. ipvX_gateway can return 'auto' instead
2063 * of an address. ipv4 and ipv6 return lists (newline-separated).
2064 * things like veth.pair return '' if invalid (i.e. if called for vlan
2067 static int lxc_get_item_nic(struct lxc_conf
*c
, char *retv
, int inlen
,
2071 int len
, fulllen
= 0;
2072 struct lxc_netdev
*netdev
;
2077 memset(retv
, 0, inlen
);
2079 p1
= index(key
, '.');
2080 if (!p1
|| *(p1
+1) == '\0') return -1;
2083 netdev
= get_netdev_from_key(key
, &c
->network
);
2086 if (strcmp(p1
, "name") == 0) {
2088 strprint(retv
, inlen
, "%s", netdev
->name
);
2089 } else if (strcmp(p1
, "type") == 0) {
2090 strprint(retv
, inlen
, "%s", lxc_net_type_to_str(netdev
->type
));
2091 } else if (strcmp(p1
, "link") == 0) {
2093 strprint(retv
, inlen
, "%s", netdev
->link
);
2094 } else if (strcmp(p1
, "flags") == 0) {
2095 if (netdev
->flags
& IFF_UP
)
2096 strprint(retv
, inlen
, "up");
2097 } else if (strcmp(p1
, "script.up") == 0) {
2098 if (netdev
->upscript
)
2099 strprint(retv
, inlen
, "%s", netdev
->upscript
);
2100 } else if (strcmp(p1
, "script.down") == 0) {
2101 if (netdev
->downscript
)
2102 strprint(retv
, inlen
, "%s", netdev
->downscript
);
2103 } else if (strcmp(p1
, "hwaddr") == 0) {
2105 strprint(retv
, inlen
, "%s", netdev
->hwaddr
);
2106 } else if (strcmp(p1
, "mtu") == 0) {
2108 strprint(retv
, inlen
, "%s", netdev
->mtu
);
2109 } else if (strcmp(p1
, "macvlan.mode") == 0) {
2110 if (netdev
->type
== LXC_NET_MACVLAN
) {
2112 switch (netdev
->priv
.macvlan_attr
.mode
) {
2113 case MACVLAN_MODE_PRIVATE
: mode
= "private"; break;
2114 case MACVLAN_MODE_VEPA
: mode
= "vepa"; break;
2115 case MACVLAN_MODE_BRIDGE
: mode
= "bridge"; break;
2116 default: mode
= "(invalid)"; break;
2118 strprint(retv
, inlen
, "%s", mode
);
2120 } else if (strcmp(p1
, "veth.pair") == 0) {
2121 if (netdev
->type
== LXC_NET_VETH
) {
2122 strprint(retv
, inlen
, "%s",
2123 netdev
->priv
.veth_attr
.pair
?
2124 netdev
->priv
.veth_attr
.pair
:
2125 netdev
->priv
.veth_attr
.veth1
);
2127 } else if (strcmp(p1
, "vlan") == 0) {
2128 if (netdev
->type
== LXC_NET_VLAN
) {
2129 strprint(retv
, inlen
, "%d", netdev
->priv
.vlan_attr
.vid
);
2131 } else if (strcmp(p1
, "ipv4_gateway") == 0) {
2132 if (netdev
->ipv4_gateway_auto
) {
2133 strprint(retv
, inlen
, "auto");
2134 } else if (netdev
->ipv4_gateway
) {
2135 char buf
[INET_ADDRSTRLEN
];
2136 inet_ntop(AF_INET
, netdev
->ipv4_gateway
, buf
, sizeof(buf
));
2137 strprint(retv
, inlen
, "%s", buf
);
2139 } else if (strcmp(p1
, "ipv4") == 0) {
2140 struct lxc_list
*it2
;
2141 lxc_list_for_each(it2
, &netdev
->ipv4
) {
2142 struct lxc_inetdev
*i
= it2
->elem
;
2143 char buf
[INET_ADDRSTRLEN
];
2144 inet_ntop(AF_INET
, &i
->addr
, buf
, sizeof(buf
));
2145 strprint(retv
, inlen
, "%s\n", buf
);
2147 } else if (strcmp(p1
, "ipv6_gateway") == 0) {
2148 if (netdev
->ipv6_gateway_auto
) {
2149 strprint(retv
, inlen
, "auto");
2150 } else if (netdev
->ipv6_gateway
) {
2151 char buf
[INET_ADDRSTRLEN
];
2152 inet_ntop(AF_INET
, netdev
->ipv6_gateway
, buf
, sizeof(buf
));
2153 strprint(retv
, inlen
, "%s", buf
);
2155 } else if (strcmp(p1
, "ipv6") == 0) {
2156 struct lxc_list
*it2
;
2157 lxc_list_for_each(it2
, &netdev
->ipv6
) {
2158 struct lxc_inetdev
*i
= it2
->elem
;
2159 char buf
[INET_ADDRSTRLEN
];
2160 inet_ntop(AF_INET6
, &i
->addr
, buf
, sizeof(buf
));
2161 strprint(retv
, inlen
, "%s\n", buf
);
2167 static int lxc_get_item_network(struct lxc_conf
*c
, char *retv
, int inlen
)
2169 int len
, fulllen
= 0;
2170 struct lxc_list
*it
;
2175 memset(retv
, 0, inlen
);
2177 lxc_list_for_each(it
, &c
->network
) {
2178 struct lxc_netdev
*n
= it
->elem
;
2179 const char *t
= lxc_net_type_to_str(n
->type
);
2180 strprint(retv
, inlen
, "%s\n", t
? t
: "(invalid)");
2185 int lxc_get_config_item(struct lxc_conf
*c
, const char *key
, char *retv
,
2188 const char *v
= NULL
;
2190 if (strcmp(key
, "lxc.mount.entry") == 0)
2191 return lxc_get_mount_entries(c
, retv
, inlen
);
2192 else if (strcmp(key
, "lxc.mount.auto") == 0)
2193 return lxc_get_auto_mounts(c
, retv
, inlen
);
2194 else if (strcmp(key
, "lxc.mount") == 0)
2196 else if (strcmp(key
, "lxc.tty") == 0)
2197 return lxc_get_conf_int(c
, retv
, inlen
, c
->tty
);
2198 else if (strcmp(key
, "lxc.pts") == 0)
2199 return lxc_get_conf_int(c
, retv
, inlen
, c
->pts
);
2200 else if (strcmp(key
, "lxc.devttydir") == 0)
2202 else if (strcmp(key
, "lxc.arch") == 0)
2203 return lxc_get_arch_entry(c
, retv
, inlen
);
2204 else if (strcmp(key
, "lxc.aa_profile") == 0)
2205 v
= c
->lsm_aa_profile
;
2206 else if (strcmp(key
, "lxc.se_context") == 0)
2207 v
= c
->lsm_se_context
;
2208 else if (strcmp(key
, "lxc.logfile") == 0)
2209 v
= lxc_log_get_file();
2210 else if (strcmp(key
, "lxc.loglevel") == 0)
2211 v
= lxc_log_priority_to_string(lxc_log_get_level());
2212 else if (strcmp(key
, "lxc.cgroup") == 0) // all cgroup info
2213 return lxc_get_cgroup_entry(c
, retv
, inlen
, "all");
2214 else if (strncmp(key
, "lxc.cgroup.", 11) == 0) // specific cgroup info
2215 return lxc_get_cgroup_entry(c
, retv
, inlen
, key
+ 11);
2216 else if (strcmp(key
, "lxc.utsname") == 0)
2217 v
= c
->utsname
? c
->utsname
->nodename
: NULL
;
2218 else if (strcmp(key
, "lxc.console") == 0)
2219 v
= c
->console
.path
;
2220 else if (strcmp(key
, "lxc.rootfs.mount") == 0)
2221 v
= c
->rootfs
.mount
;
2222 else if (strcmp(key
, "lxc.rootfs.options") == 0)
2223 v
= c
->rootfs
.options
;
2224 else if (strcmp(key
, "lxc.rootfs") == 0)
2226 else if (strcmp(key
, "lxc.pivotdir") == 0)
2227 v
= c
->rootfs
.pivot
;
2228 else if (strcmp(key
, "lxc.cap.drop") == 0)
2229 return lxc_get_item_cap_drop(c
, retv
, inlen
);
2230 else if (strcmp(key
, "lxc.cap.keep") == 0)
2231 return lxc_get_item_cap_keep(c
, retv
, inlen
);
2232 else if (strncmp(key
, "lxc.hook", 8) == 0)
2233 return lxc_get_item_hooks(c
, retv
, inlen
, key
);
2234 else if (strcmp(key
, "lxc.network") == 0)
2235 return lxc_get_item_network(c
, retv
, inlen
);
2236 else if (strncmp(key
, "lxc.network.", 12) == 0)
2237 return lxc_get_item_nic(c
, retv
, inlen
, key
+ 12);
2238 else if (strcmp(key
, "lxc.start.auto") == 0)
2239 return lxc_get_conf_int(c
, retv
, inlen
, c
->start_auto
);
2240 else if (strcmp(key
, "lxc.start.delay") == 0)
2241 return lxc_get_conf_int(c
, retv
, inlen
, c
->start_delay
);
2242 else if (strcmp(key
, "lxc.start.order") == 0)
2243 return lxc_get_conf_int(c
, retv
, inlen
, c
->start_order
);
2244 else if (strcmp(key
, "lxc.group") == 0)
2245 return lxc_get_item_groups(c
, retv
, inlen
);
2246 else if (strcmp(key
, "lxc.seccomp") == 0)
2252 if (retv
&& inlen
>= strlen(v
) + 1)
2253 strncpy(retv
, v
, strlen(v
)+1);
2257 int lxc_clear_config_item(struct lxc_conf
*c
, const char *key
)
2259 if (strcmp(key
, "lxc.network") == 0)
2260 return lxc_clear_config_network(c
);
2261 else if (strncmp(key
, "lxc.network.", 12) == 0)
2262 return lxc_clear_nic(c
, key
+ 12);
2263 else if (strcmp(key
, "lxc.cap.drop") == 0)
2264 return lxc_clear_config_caps(c
);
2265 else if (strcmp(key
, "lxc.cap.keep") == 0)
2266 return lxc_clear_config_keepcaps(c
);
2267 else if (strncmp(key
, "lxc.cgroup", 10) == 0)
2268 return lxc_clear_cgroups(c
, key
);
2269 else if (strcmp(key
, "lxc.mount.entries") == 0)
2270 return lxc_clear_mount_entries(c
);
2271 else if (strcmp(key
, "lxc.mount.auto") == 0)
2272 return lxc_clear_automounts(c
);
2273 else if (strncmp(key
, "lxc.hook", 8) == 0)
2274 return lxc_clear_hooks(c
, key
);
2275 else if (strncmp(key
, "lxc.group", 9) == 0)
2276 return lxc_clear_groups(c
);
2277 else if (strncmp(key
, "lxc.seccomp", 11) == 0) {
2278 lxc_seccomp_free(c
);
2286 * writing out a confile.
2288 void write_config(FILE *fout
, struct lxc_conf
*c
)
2290 struct lxc_list
*it
;
2292 const char *signame
;
2294 /* first write any includes */
2295 lxc_list_for_each(it
, &c
->includes
) {
2296 fprintf(fout
, "lxc.include = %s\n", (char *)it
->elem
);
2299 /* now write any aliens */
2300 lxc_list_for_each(it
, &c
->aliens
) {
2301 fprintf(fout
, "%s\n", (char *)it
->elem
);
2305 fprintf(fout
, "lxc.mount = %s\n", c
->fstab
);
2306 lxc_list_for_each(it
, &c
->mount_list
) {
2307 fprintf(fout
, "lxc.mount.entry = %s\n", (char *)it
->elem
);
2309 if (c
->auto_mounts
& LXC_AUTO_ALL_MASK
) {
2310 fprintf(fout
, "lxc.mount.auto =");
2311 switch (c
->auto_mounts
& LXC_AUTO_PROC_MASK
) {
2312 case LXC_AUTO_PROC_MIXED
: fprintf(fout
, " proc:mixed"); break;
2313 case LXC_AUTO_PROC_RW
: fprintf(fout
, " proc:rw"); break;
2316 switch (c
->auto_mounts
& LXC_AUTO_SYS_MASK
) {
2317 case LXC_AUTO_SYS_RO
: fprintf(fout
, " sys:ro"); break;
2318 case LXC_AUTO_SYS_RW
: fprintf(fout
, " sys:rw"); break;
2321 switch (c
->auto_mounts
& LXC_AUTO_CGROUP_MASK
) {
2322 case LXC_AUTO_CGROUP_NOSPEC
: fprintf(fout
, " cgroup"); break;
2323 case LXC_AUTO_CGROUP_MIXED
: fprintf(fout
, " cgroup:mixed"); break;
2324 case LXC_AUTO_CGROUP_RO
: fprintf(fout
, " cgroup:ro"); break;
2325 case LXC_AUTO_CGROUP_RW
: fprintf(fout
, " cgroup:rw"); break;
2326 case LXC_AUTO_CGROUP_FULL_NOSPEC
: fprintf(fout
, " cgroup-full"); break;
2327 case LXC_AUTO_CGROUP_FULL_MIXED
: fprintf(fout
, " cgroup-full:mixed"); break;
2328 case LXC_AUTO_CGROUP_FULL_RO
: fprintf(fout
, " cgroup-full:ro"); break;
2329 case LXC_AUTO_CGROUP_FULL_RW
: fprintf(fout
, " cgroup-full:rw"); break;
2332 fprintf(fout
, "\n");
2335 fprintf(fout
, "lxc.tty = %d\n", c
->tty
);
2337 fprintf(fout
, "lxc.pts = %d\n", c
->pts
);
2339 fprintf(fout
, "lxc.devttydir = %s\n", c
->ttydir
);
2340 if (c
->haltsignal
) {
2341 signame
= sig_name(c
->haltsignal
);
2342 if (signame
== NULL
) {
2343 fprintf(fout
, "lxc.haltsignal = %d\n", c
->haltsignal
);
2345 fprintf(fout
, "lxc.haltsignal = SIG%s\n", signame
);
2348 if (c
->stopsignal
) {
2349 signame
= sig_name(c
->stopsignal
);
2350 if (signame
== NULL
) {
2351 fprintf(fout
, "lxc.stopsignal = %d\n", c
->stopsignal
);
2353 fprintf(fout
, "lxc.stopsignal = SIG%s\n", signame
);
2356 #if HAVE_SYS_PERSONALITY_H
2357 switch(c
->personality
) {
2358 case PER_LINUX32
: fprintf(fout
, "lxc.arch = i686\n"); break;
2359 case PER_LINUX
: fprintf(fout
, "lxc.arch = x86_64\n"); break;
2363 if (c
->lsm_aa_profile
)
2364 fprintf(fout
, "lxc.aa_profile = %s\n", c
->lsm_aa_profile
);
2365 if (c
->lsm_se_context
)
2366 fprintf(fout
, "lxc.se_context = %s\n", c
->lsm_se_context
);
2368 fprintf(fout
, "lxc.seccomp = %s\n", c
->seccomp
);
2370 fprintf(fout
, "lxc.kmsg = 0\n");
2372 fprintf(fout
, "lxc.autodev = 1\n");
2373 if (c
->loglevel
!= LXC_LOG_PRIORITY_NOTSET
)
2374 fprintf(fout
, "lxc.loglevel = %s\n", lxc_log_priority_to_string(c
->loglevel
));
2376 fprintf(fout
, "lxc.logfile = %s\n", c
->logfile
);
2377 lxc_list_for_each(it
, &c
->cgroup
) {
2378 struct lxc_cgroup
*cg
= it
->elem
;
2379 fprintf(fout
, "lxc.cgroup.%s = %s\n", cg
->subsystem
, cg
->value
);
2382 fprintf(fout
, "lxc.utsname = %s\n", c
->utsname
->nodename
);
2383 lxc_list_for_each(it
, &c
->network
) {
2384 struct lxc_netdev
*n
= it
->elem
;
2385 const char *t
= lxc_net_type_to_str(n
->type
);
2386 struct lxc_list
*it2
;
2387 fprintf(fout
, "lxc.network.type = %s\n", t
? t
: "(invalid)");
2388 if (n
->flags
& IFF_UP
)
2389 fprintf(fout
, "lxc.network.flags = up\n");
2391 fprintf(fout
, "lxc.network.link = %s\n", n
->link
);
2393 fprintf(fout
, "lxc.network.name = %s\n", n
->name
);
2394 if (n
->type
== LXC_NET_MACVLAN
) {
2396 switch (n
->priv
.macvlan_attr
.mode
) {
2397 case MACVLAN_MODE_PRIVATE
: mode
= "private"; break;
2398 case MACVLAN_MODE_VEPA
: mode
= "vepa"; break;
2399 case MACVLAN_MODE_BRIDGE
: mode
= "bridge"; break;
2400 default: mode
= "(invalid)"; break;
2402 fprintf(fout
, "lxc.network.macvlan.mode = %s\n", mode
);
2403 } else if (n
->type
== LXC_NET_VETH
) {
2404 if (n
->priv
.veth_attr
.pair
)
2405 fprintf(fout
, "lxc.network.veth.pair = %s\n",
2406 n
->priv
.veth_attr
.pair
);
2407 } else if (n
->type
== LXC_NET_VLAN
) {
2408 fprintf(fout
, "lxc.network.vlan.id = %d\n", n
->priv
.vlan_attr
.vid
);
2411 fprintf(fout
, "lxc.network.script.up = %s\n", n
->upscript
);
2413 fprintf(fout
, "lxc.network.script.down = %s\n", n
->downscript
);
2415 fprintf(fout
, "lxc.network.hwaddr = %s\n", n
->hwaddr
);
2417 fprintf(fout
, "lxc.network.mtu = %s\n", n
->mtu
);
2418 if (n
->ipv4_gateway_auto
)
2419 fprintf(fout
, "lxc.network.ipv4.gateway = auto\n");
2420 else if (n
->ipv4_gateway
) {
2421 char buf
[INET_ADDRSTRLEN
];
2422 inet_ntop(AF_INET
, n
->ipv4_gateway
, buf
, sizeof(buf
));
2423 fprintf(fout
, "lxc.network.ipv4.gateway = %s\n", buf
);
2425 lxc_list_for_each(it2
, &n
->ipv4
) {
2426 struct lxc_inetdev
*i
= it2
->elem
;
2427 char buf
[INET_ADDRSTRLEN
];
2428 inet_ntop(AF_INET
, &i
->addr
, buf
, sizeof(buf
));
2429 fprintf(fout
, "lxc.network.ipv4 = %s", buf
);
2432 fprintf(fout
, "/%d", i
->prefix
);
2434 if (i
->bcast
.s_addr
!= (i
->addr
.s_addr
|
2435 htonl(INADDR_BROADCAST
>> i
->prefix
))) {
2437 inet_ntop(AF_INET
, &i
->bcast
, buf
, sizeof(buf
));
2438 fprintf(fout
, " %s\n", buf
);
2441 fprintf(fout
, "\n");
2443 if (n
->ipv6_gateway_auto
)
2444 fprintf(fout
, "lxc.network.ipv6.gateway = auto\n");
2445 else if (n
->ipv6_gateway
) {
2446 char buf
[INET6_ADDRSTRLEN
];
2447 inet_ntop(AF_INET6
, n
->ipv6_gateway
, buf
, sizeof(buf
));
2448 fprintf(fout
, "lxc.network.ipv6.gateway = %s\n", buf
);
2450 lxc_list_for_each(it2
, &n
->ipv6
) {
2451 struct lxc_inet6dev
*i
= it2
->elem
;
2452 char buf
[INET6_ADDRSTRLEN
];
2453 inet_ntop(AF_INET6
, &i
->addr
, buf
, sizeof(buf
));
2455 fprintf(fout
, "lxc.network.ipv6 = %s/%d\n",
2458 fprintf(fout
, "lxc.network.ipv6 = %s\n", buf
);
2461 lxc_list_for_each(it
, &c
->caps
)
2462 fprintf(fout
, "lxc.cap.drop = %s\n", (char *)it
->elem
);
2463 lxc_list_for_each(it
, &c
->keepcaps
)
2464 fprintf(fout
, "lxc.cap.keep = %s\n", (char *)it
->elem
);
2465 lxc_list_for_each(it
, &c
->id_map
) {
2466 struct id_map
*idmap
= it
->elem
;
2467 fprintf(fout
, "lxc.id_map = %c %lu %lu %lu\n",
2468 idmap
->idtype
== ID_TYPE_UID
? 'u' : 'g', idmap
->nsid
,
2469 idmap
->hostid
, idmap
->range
);
2471 for (i
=0; i
<NUM_LXC_HOOKS
; i
++) {
2472 lxc_list_for_each(it
, &c
->hooks
[i
])
2473 fprintf(fout
, "lxc.hook.%s = %s\n",
2474 lxchook_names
[i
], (char *)it
->elem
);
2476 if (c
->console
.path
)
2477 fprintf(fout
, "lxc.console = %s\n", c
->console
.path
);
2479 fprintf(fout
, "lxc.rootfs = %s\n", c
->rootfs
.path
);
2480 if (c
->rootfs
.mount
&& strcmp(c
->rootfs
.mount
, LXCROOTFSMOUNT
) != 0)
2481 fprintf(fout
, "lxc.rootfs.mount = %s\n", c
->rootfs
.mount
);
2482 if (c
->rootfs
.options
)
2483 fprintf(fout
, "lxc.rootfs.options = %s\n", c
->rootfs
.options
);
2484 if (c
->rootfs
.pivot
)
2485 fprintf(fout
, "lxc.pivotdir = %s\n", c
->rootfs
.pivot
);
2487 fprintf(fout
, "lxc.start.auto = %d\n", c
->start_auto
);
2489 fprintf(fout
, "lxc.start.delay = %d\n", c
->start_delay
);
2491 fprintf(fout
, "lxc.start.order = %d\n", c
->start_order
);
2492 lxc_list_for_each(it
, &c
->groups
)
2493 fprintf(fout
, "lxc.group = %s\n", (char *)it
->elem
);