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