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