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 <sys/personality.h>
35 #include <arpa/inet.h>
36 #include <netinet/in.h>
46 lxc_log_define(lxc_confile
, lxc
);
48 static int config_personality(const char *, char *, struct lxc_conf
*);
49 static int config_pts(const char *, char *, struct lxc_conf
*);
50 static int config_tty(const char *, char *, struct lxc_conf
*);
51 static int config_ttydir(const char *, char *, struct lxc_conf
*);
53 static int config_aa_profile(const char *, char *, struct lxc_conf
*);
55 static int config_cgroup(const char *, char *, struct lxc_conf
*);
56 static int config_mount(const char *, char *, struct lxc_conf
*);
57 static int config_rootfs(const char *, char *, struct lxc_conf
*);
58 static int config_rootfs_mount(const char *, char *, struct lxc_conf
*);
59 static int config_pivotdir(const char *, char *, struct lxc_conf
*);
60 static int config_utsname(const char *, char *, struct lxc_conf
*);
61 static int config_network_type(const char *, char *, struct lxc_conf
*);
62 static int config_network_flags(const char *, char *, struct lxc_conf
*);
63 static int config_network_link(const char *, char *, struct lxc_conf
*);
64 static int config_network_name(const char *, char *, struct lxc_conf
*);
65 static int config_network_veth_pair(const char *, char *, struct lxc_conf
*);
66 static int config_network_macvlan_mode(const char *, char *, struct lxc_conf
*);
67 static int config_network_hwaddr(const char *, char *, struct lxc_conf
*);
68 static int config_network_vlan_id(const char *, char *, struct lxc_conf
*);
69 static int config_network_mtu(const char *, char *, struct lxc_conf
*);
70 static int config_network_ipv4(const char *, char *, struct lxc_conf
*);
71 static int config_network_ipv4_gateway(const char *, char *, struct lxc_conf
*);
72 static int config_network_script(const char *, char *, struct lxc_conf
*);
73 static int config_network_ipv6(const char *, char *, struct lxc_conf
*);
74 static int config_network_ipv6_gateway(const char *, char *, struct lxc_conf
*);
75 static int config_cap_drop(const char *, char *, struct lxc_conf
*);
76 static int config_console(const char *, char *, struct lxc_conf
*);
78 typedef int (*config_cb
)(const char *, char *, struct lxc_conf
*);
85 static struct config config
[] = {
87 { "lxc.arch", config_personality
},
88 { "lxc.pts", config_pts
},
89 { "lxc.tty", config_tty
},
90 { "lxc.devttydir", config_ttydir
},
92 { "lxc.aa_profile", config_aa_profile
},
94 { "lxc.cgroup", config_cgroup
},
95 { "lxc.mount", config_mount
},
96 { "lxc.rootfs.mount", config_rootfs_mount
},
97 { "lxc.rootfs", config_rootfs
},
98 { "lxc.pivotdir", config_pivotdir
},
99 { "lxc.utsname", config_utsname
},
100 { "lxc.network.type", config_network_type
},
101 { "lxc.network.flags", config_network_flags
},
102 { "lxc.network.link", config_network_link
},
103 { "lxc.network.name", config_network_name
},
104 { "lxc.network.macvlan.mode", config_network_macvlan_mode
},
105 { "lxc.network.veth.pair", config_network_veth_pair
},
106 { "lxc.network.script.up", config_network_script
},
107 { "lxc.network.hwaddr", config_network_hwaddr
},
108 { "lxc.network.mtu", config_network_mtu
},
109 { "lxc.network.vlan.id", config_network_vlan_id
},
110 { "lxc.network.ipv4.gateway", config_network_ipv4_gateway
},
111 { "lxc.network.ipv4", config_network_ipv4
},
112 { "lxc.network.ipv6.gateway", config_network_ipv6_gateway
},
113 { "lxc.network.ipv6", config_network_ipv6
},
114 { "lxc.cap.drop", config_cap_drop
},
115 { "lxc.console", config_console
},
118 static const size_t config_size
= sizeof(config
)/sizeof(struct config
);
120 static struct config
*getconfig(const char *key
)
124 for (i
= 0; i
< config_size
; i
++)
125 if (!strncmp(config
[i
].name
, key
,
126 strlen(config
[i
].name
)))
131 static int config_network_type(const char *key
, char *value
,
132 struct lxc_conf
*lxc_conf
)
134 struct lxc_list
*network
= &lxc_conf
->network
;
135 struct lxc_netdev
*netdev
;
136 struct lxc_list
*list
;
138 netdev
= malloc(sizeof(*netdev
));
140 SYSERROR("failed to allocate memory");
144 memset(netdev
, 0, sizeof(*netdev
));
145 lxc_list_init(&netdev
->ipv4
);
146 lxc_list_init(&netdev
->ipv6
);
148 list
= malloc(sizeof(*list
));
150 SYSERROR("failed to allocate memory");
157 lxc_list_add_tail(network
, list
);
159 if (!strcmp(value
, "veth"))
160 netdev
->type
= LXC_NET_VETH
;
161 else if (!strcmp(value
, "macvlan"))
162 netdev
->type
= LXC_NET_MACVLAN
;
163 else if (!strcmp(value
, "vlan"))
164 netdev
->type
= LXC_NET_VLAN
;
165 else if (!strcmp(value
, "phys"))
166 netdev
->type
= LXC_NET_PHYS
;
167 else if (!strcmp(value
, "empty"))
168 netdev
->type
= LXC_NET_EMPTY
;
170 ERROR("invalid network type %s", value
);
176 static int config_ip_prefix(struct in_addr
*addr
)
178 if (IN_CLASSA(addr
->s_addr
))
179 return 32 - IN_CLASSA_NSHIFT
;
180 if (IN_CLASSB(addr
->s_addr
))
181 return 32 - IN_CLASSB_NSHIFT
;
182 if (IN_CLASSC(addr
->s_addr
))
183 return 32 - IN_CLASSC_NSHIFT
;
188 static struct lxc_netdev
*network_netdev(const char *key
, const char *value
,
189 struct lxc_list
*network
)
191 struct lxc_netdev
*netdev
;
193 if (lxc_list_empty(network
)) {
194 ERROR("network is not created for '%s' = '%s' option",
199 netdev
= lxc_list_last_elem(network
);
201 ERROR("no network device defined for '%s' = '%s' option",
209 static int network_ifname(char **valuep
, char *value
)
211 if (strlen(value
) >= IFNAMSIZ
) {
212 ERROR("invalid interface name: %s", value
);
216 *valuep
= strdup(value
);
218 ERROR("failed to dup string '%s'", value
);
225 #ifndef MACVLAN_MODE_PRIVATE
226 # define MACVLAN_MODE_PRIVATE 1
229 #ifndef MACVLAN_MODE_VEPA
230 # define MACVLAN_MODE_VEPA 2
233 #ifndef MACVLAN_MODE_BRIDGE
234 # define MACVLAN_MODE_BRIDGE 4
237 static int macvlan_mode(int *valuep
, char *value
)
243 { "private", MACVLAN_MODE_PRIVATE
},
244 { "vepa", MACVLAN_MODE_VEPA
},
245 { "bridge", MACVLAN_MODE_BRIDGE
},
250 for (i
= 0; i
< sizeof(m
)/sizeof(m
[0]); i
++) {
251 if (strcmp(m
[i
].name
, value
))
261 static int config_network_flags(const char *key
, char *value
,
262 struct lxc_conf
*lxc_conf
)
264 struct lxc_netdev
*netdev
;
266 netdev
= network_netdev(key
, value
, &lxc_conf
->network
);
270 netdev
->flags
|= IFF_UP
;
275 static int config_network_link(const char *key
, char *value
,
276 struct lxc_conf
*lxc_conf
)
278 struct lxc_netdev
*netdev
;
280 netdev
= network_netdev(key
, value
, &lxc_conf
->network
);
284 return network_ifname(&netdev
->link
, value
);
287 static int config_network_name(const char *key
, char *value
,
288 struct lxc_conf
*lxc_conf
)
290 struct lxc_netdev
*netdev
;
292 netdev
= network_netdev(key
, value
, &lxc_conf
->network
);
296 return network_ifname(&netdev
->name
, value
);
299 static int config_network_veth_pair(const char *key
, char *value
,
300 struct lxc_conf
*lxc_conf
)
302 struct lxc_netdev
*netdev
;
304 netdev
= network_netdev(key
, value
, &lxc_conf
->network
);
308 return network_ifname(&netdev
->priv
.veth_attr
.pair
, value
);
311 static int config_network_macvlan_mode(const char *key
, char *value
,
312 struct lxc_conf
*lxc_conf
)
314 struct lxc_netdev
*netdev
;
316 netdev
= network_netdev(key
, value
, &lxc_conf
->network
);
320 return macvlan_mode(&netdev
->priv
.macvlan_attr
.mode
, value
);
323 static int config_network_hwaddr(const char *key
, char *value
,
324 struct lxc_conf
*lxc_conf
)
326 struct lxc_netdev
*netdev
;
328 netdev
= network_netdev(key
, value
, &lxc_conf
->network
);
332 netdev
->hwaddr
= strdup(value
);
333 if (!netdev
->hwaddr
) {
334 SYSERROR("failed to dup string '%s'", value
);
341 static int config_network_vlan_id(const char *key
, char *value
,
342 struct lxc_conf
*lxc_conf
)
344 struct lxc_netdev
*netdev
;
346 netdev
= network_netdev(key
, value
, &lxc_conf
->network
);
350 if (get_u16(&netdev
->priv
.vlan_attr
.vid
, value
, 0))
356 static int config_network_mtu(const char *key
, char *value
,
357 struct lxc_conf
*lxc_conf
)
359 struct lxc_netdev
*netdev
;
361 netdev
= network_netdev(key
, value
, &lxc_conf
->network
);
365 netdev
->mtu
= strdup(value
);
367 SYSERROR("failed to dup string '%s'", value
);
374 static int config_network_ipv4(const char *key
, char *value
,
375 struct lxc_conf
*lxc_conf
)
377 struct lxc_netdev
*netdev
;
378 struct lxc_inetdev
*inetdev
;
379 struct lxc_list
*list
;
380 char *cursor
, *slash
, *addr
= NULL
, *bcast
= NULL
, *prefix
= NULL
;
382 netdev
= network_netdev(key
, value
, &lxc_conf
->network
);
386 inetdev
= malloc(sizeof(*inetdev
));
388 SYSERROR("failed to allocate ipv4 address");
391 memset(inetdev
, 0, sizeof(*inetdev
));
393 list
= malloc(sizeof(*list
));
395 SYSERROR("failed to allocate memory");
400 list
->elem
= inetdev
;
404 cursor
= strstr(addr
, " ");
410 slash
= strstr(addr
, "/");
417 ERROR("no address specified");
421 if (!inet_pton(AF_INET
, addr
, &inetdev
->addr
)) {
422 SYSERROR("invalid ipv4 address: %s", value
);
426 if (bcast
&& !inet_pton(AF_INET
, bcast
, &inetdev
->bcast
)) {
427 SYSERROR("invalid ipv4 broadcast address: %s", value
);
431 /* no prefix specified, determine it from the network class */
432 inetdev
->prefix
= prefix
? atoi(prefix
) :
433 config_ip_prefix(&inetdev
->addr
);
435 /* if no broadcast address, let compute one from the
439 inetdev
->bcast
.s_addr
= inetdev
->addr
.s_addr
;
440 inetdev
->bcast
.s_addr
|=
441 htonl(INADDR_BROADCAST
>> inetdev
->prefix
);
444 lxc_list_add(&netdev
->ipv4
, list
);
449 static int config_network_ipv4_gateway(const char *key
, char *value
,
450 struct lxc_conf
*lxc_conf
)
452 struct lxc_netdev
*netdev
;
455 netdev
= network_netdev(key
, value
, &lxc_conf
->network
);
459 gw
= malloc(sizeof(*gw
));
461 SYSERROR("failed to allocate ipv4 gateway address");
466 ERROR("no ipv4 gateway address specified");
470 if (!strcmp(value
, "auto")) {
471 netdev
->ipv4_gateway
= NULL
;
472 netdev
->ipv4_gateway_auto
= true;
474 if (!inet_pton(AF_INET
, value
, gw
)) {
475 SYSERROR("invalid ipv4 gateway address: %s", value
);
479 netdev
->ipv4_gateway
= gw
;
480 netdev
->ipv4_gateway_auto
= false;
486 static int config_network_ipv6(const char *key
, char *value
,
487 struct lxc_conf
*lxc_conf
)
489 struct lxc_netdev
*netdev
;
490 struct lxc_inet6dev
*inet6dev
;
491 struct lxc_list
*list
;
495 netdev
= network_netdev(key
, value
, &lxc_conf
->network
);
499 inet6dev
= malloc(sizeof(*inet6dev
));
501 SYSERROR("failed to allocate ipv6 address");
504 memset(inet6dev
, 0, sizeof(*inet6dev
));
506 list
= malloc(sizeof(*list
));
508 SYSERROR("failed to allocate memory");
513 list
->elem
= inet6dev
;
515 inet6dev
->prefix
= 64;
516 slash
= strstr(value
, "/");
520 inet6dev
->prefix
= atoi(netmask
);
523 if (!inet_pton(AF_INET6
, value
, &inet6dev
->addr
)) {
524 SYSERROR("invalid ipv6 address: %s", value
);
528 lxc_list_add(&netdev
->ipv6
, list
);
533 static int config_network_ipv6_gateway(const char *key
, char *value
,
534 struct lxc_conf
*lxc_conf
)
536 struct lxc_netdev
*netdev
;
539 netdev
= network_netdev(key
, value
, &lxc_conf
->network
);
543 gw
= malloc(sizeof(*gw
));
545 SYSERROR("failed to allocate ipv6 gateway address");
550 ERROR("no ipv6 gateway address specified");
554 if (!strcmp(value
, "auto")) {
555 netdev
->ipv6_gateway
= NULL
;
556 netdev
->ipv6_gateway_auto
= true;
558 if (!inet_pton(AF_INET6
, value
, gw
)) {
559 SYSERROR("invalid ipv6 gateway address: %s", value
);
563 netdev
->ipv6_gateway
= gw
;
564 netdev
->ipv6_gateway_auto
= false;
570 static int config_network_script(const char *key
, char *value
,
571 struct lxc_conf
*lxc_conf
)
573 struct lxc_netdev
*netdev
;
575 netdev
= network_netdev(key
, value
, &lxc_conf
->network
);
579 char *copy
= strdup(value
);
581 SYSERROR("failed to dup string '%s'", value
);
584 if (strcmp(key
, "lxc.network.script.up") == 0) {
585 netdev
->upscript
= copy
;
588 SYSERROR("Unknown key: %s", key
);
593 static int config_personality(const char *key
, char *value
,
594 struct lxc_conf
*lxc_conf
)
596 signed long personality
= lxc_config_parse_arch(value
);
598 if (personality
>= 0)
599 lxc_conf
->personality
= personality
;
601 WARN("unsupported personality '%s'", value
);
606 static int config_pts(const char *key
, char *value
, struct lxc_conf
*lxc_conf
)
608 int maxpts
= atoi(value
);
610 lxc_conf
->pts
= maxpts
;
615 static int config_tty(const char *key
, char *value
, struct lxc_conf
*lxc_conf
)
617 int nbtty
= atoi(value
);
619 lxc_conf
->tty
= nbtty
;
624 static int config_ttydir(const char *key
, char *value
,
625 struct lxc_conf
*lxc_conf
)
629 if (!value
|| strlen(value
) == 0)
631 path
= strdup(value
);
633 SYSERROR("failed to strdup '%s': %m", value
);
637 lxc_conf
->ttydir
= path
;
643 static int config_aa_profile(const char *key
, char *value
, struct lxc_conf
*lxc_conf
)
647 if (!value
|| strlen(value
) == 0)
649 path
= strdup(value
);
651 SYSERROR("failed to strdup '%s': %m", value
);
655 lxc_conf
->aa_profile
= path
;
661 static int config_cgroup(const char *key
, char *value
, struct lxc_conf
*lxc_conf
)
663 char *token
= "lxc.cgroup.";
665 struct lxc_list
*cglist
= NULL
;
666 struct lxc_cgroup
*cgelem
= NULL
;
668 subkey
= strstr(key
, token
);
676 if (strlen(subkey
) == strlen(token
))
679 subkey
+= strlen(token
);
681 cglist
= malloc(sizeof(*cglist
));
685 cgelem
= malloc(sizeof(*cgelem
));
688 memset(cgelem
, 0, sizeof(*cgelem
));
690 cgelem
->subsystem
= strdup(subkey
);
691 cgelem
->value
= strdup(value
);
693 if (!cgelem
->subsystem
|| !cgelem
->value
)
696 cglist
->elem
= cgelem
;
698 lxc_list_add_tail(&lxc_conf
->cgroup
, cglist
);
707 if (cgelem
->subsystem
)
708 free(cgelem
->subsystem
);
719 static int config_fstab(const char *key
, char *value
, struct lxc_conf
*lxc_conf
)
721 if (strlen(value
) >= MAXPATHLEN
) {
722 ERROR("%s path is too long", value
);
726 lxc_conf
->fstab
= strdup(value
);
727 if (!lxc_conf
->fstab
) {
728 SYSERROR("failed to duplicate string %s", value
);
735 static int config_mount(const char *key
, char *value
, struct lxc_conf
*lxc_conf
)
737 char *fstab_token
= "lxc.mount";
738 char *token
= "lxc.mount.entry";
741 struct lxc_list
*mntlist
;
743 subkey
= strstr(key
, token
);
746 subkey
= strstr(key
, fstab_token
);
751 return config_fstab(key
, value
, lxc_conf
);
757 mntlist
= malloc(sizeof(*mntlist
));
761 mntelem
= strdup(value
);
764 mntlist
->elem
= mntelem
;
766 lxc_list_add_tail(&lxc_conf
->mount_list
, mntlist
);
771 static int config_cap_drop(const char *key
, char *value
,
772 struct lxc_conf
*lxc_conf
)
774 char *dropcaps
, *sptr
, *token
;
775 struct lxc_list
*droplist
;
781 dropcaps
= strdup(value
);
783 SYSERROR("failed to dup '%s'", value
);
787 /* in case several capability drop is specified in a single line
788 * split these caps in a single element for the list */
790 token
= strtok_r(dropcaps
, " \t", &sptr
);
797 droplist
= malloc(sizeof(*droplist
));
799 SYSERROR("failed to allocate drop list");
803 droplist
->elem
= strdup(token
);
804 if (!droplist
->elem
) {
805 SYSERROR("failed to dup '%s'", token
);
810 lxc_list_add_tail(&lxc_conf
->caps
, droplist
);
818 static int config_console(const char *key
, char *value
,
819 struct lxc_conf
*lxc_conf
)
823 path
= strdup(value
);
825 SYSERROR("failed to strdup '%s': %m", value
);
829 lxc_conf
->console
.path
= path
;
834 static int config_rootfs(const char *key
, char *value
, struct lxc_conf
*lxc_conf
)
836 if (strlen(value
) >= MAXPATHLEN
) {
837 ERROR("%s path is too long", value
);
841 lxc_conf
->rootfs
.path
= strdup(value
);
842 if (!lxc_conf
->rootfs
.path
) {
843 SYSERROR("failed to duplicate string %s", value
);
850 static int config_rootfs_mount(const char *key
, char *value
, struct lxc_conf
*lxc_conf
)
852 if (strlen(value
) >= MAXPATHLEN
) {
853 ERROR("%s path is too long", value
);
857 lxc_conf
->rootfs
.mount
= strdup(value
);
858 if (!lxc_conf
->rootfs
.mount
) {
859 SYSERROR("failed to duplicate string '%s'", value
);
866 static int config_pivotdir(const char *key
, char *value
, struct lxc_conf
*lxc_conf
)
868 if (strlen(value
) >= MAXPATHLEN
) {
869 ERROR("%s path is too long", value
);
873 lxc_conf
->rootfs
.pivot
= strdup(value
);
874 if (!lxc_conf
->rootfs
.pivot
) {
875 SYSERROR("failed to duplicate string %s", value
);
882 static int config_utsname(const char *key
, char *value
, struct lxc_conf
*lxc_conf
)
884 struct utsname
*utsname
;
886 utsname
= malloc(sizeof(*utsname
));
888 SYSERROR("failed to allocate memory");
892 if (strlen(value
) >= sizeof(utsname
->nodename
)) {
893 ERROR("node name '%s' is too long",
898 strcpy(utsname
->nodename
, value
);
899 lxc_conf
->utsname
= utsname
;
904 static int parse_line(char *buffer
, void *data
)
906 struct config
*config
;
913 if (lxc_is_line_empty(buffer
))
916 /* we have to dup the buffer otherwise, at the re-exec for
917 * reboot we modified the original string on the stack by
918 * replacing '=' by '\0' below
920 linep
= line
= strdup(buffer
);
922 SYSERROR("failed to allocate memory for '%s'", buffer
);
926 line
+= lxc_char_left_gc(line
, strlen(line
));
928 /* martian option - ignoring it, the commented lines beginning by '#'
931 if (strncmp(line
, "lxc.", 4))
936 dot
= strstr(line
, "=");
938 ERROR("invalid configuration line: %s", line
);
946 key
[lxc_char_right_gc(key
, strlen(key
))] = '\0';
948 value
+= lxc_char_left_gc(value
, strlen(value
));
949 value
[lxc_char_right_gc(value
, strlen(value
))] = '\0';
951 config
= getconfig(key
);
953 ERROR("unknow key %s", key
);
957 ret
= config
->cb(key
, value
, data
);
964 int lxc_config_readline(char *buffer
, struct lxc_conf
*conf
)
966 return parse_line(buffer
, conf
);
969 int lxc_config_read(const char *file
, struct lxc_conf
*conf
)
971 return lxc_file_for_each_line(file
, parse_line
, conf
);
974 int lxc_config_define_add(struct lxc_list
*defines
, char* arg
)
976 struct lxc_list
*dent
;
978 dent
= malloc(sizeof(struct lxc_list
));
983 lxc_list_add_tail(defines
, dent
);
987 int lxc_config_define_load(struct lxc_list
*defines
, struct lxc_conf
*conf
)
992 lxc_list_for_each(it
, defines
) {
993 ret
= lxc_config_readline(it
->elem
, conf
);
998 lxc_list_for_each(it
, defines
) {
1006 signed long lxc_config_parse_arch(const char *arch
)
1012 { "x86", PER_LINUX32
},
1013 { "i686", PER_LINUX32
},
1014 { "x86_64", PER_LINUX
},
1015 { "amd64", PER_LINUX
},
1017 size_t len
= sizeof(pername
) / sizeof(pername
[0]);
1021 for (i
= 0; i
< len
; i
++) {
1022 if (!strcmp(pername
[i
].name
, arch
))
1023 return pername
[i
].per
;