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