]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/confile.c
network: mv config_value_empty() to confile_utils
[mirror_lxc.git] / src / lxc / confile.c
CommitLineData
c2cc9f0a 1/*
2 * lxc: linux Container library
c2cc9f0a 3 * (C) Copyright IBM Corp. 2007, 2008
4 *
5 * Authors:
9afe19d6 6 * Daniel Lezcano <daniel.lezcano at free.fr>
c2cc9f0a 7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
250b1eec 20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
c2cc9f0a 21 */
12a50cc6 22#define _GNU_SOURCE
2e6e3feb 23#define __STDC_FORMAT_MACROS /* Required for PRIu64 to work. */
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 30#include <ctype.h>
2e6e3feb 31#include <inttypes.h> /* Required for PRIu64 to work. */
a84b9932 32#include <signal.h>
63376d7d 33#include <sys/stat.h>
c2cc9f0a 34#include <sys/types.h>
35#include <sys/param.h>
36#include <sys/utsname.h>
37#include <arpa/inet.h>
38#include <netinet/in.h>
39#include <net/if.h>
67702c21 40#include <time.h>
e1daebd9 41#include <dirent.h>
64c57ea1 42#include <syslog.h>
c2cc9f0a 43
d8e48992 44#include "bdev.h"
b2718c72 45#include "parse.h"
6ff05e18 46#include "config.h"
525f0002 47#include "confile.h"
0b843d35 48#include "confile_utils.h"
26c39028 49#include "utils.h"
f2363e38
ÇO
50#include "log.h"
51#include "conf.h"
72d0e1cb 52#include "network.h"
58e0f57d 53#include "lxcseccomp.h"
36eb9bde 54
576400e5 55#if HAVE_IFADDRS_H
56#include <ifaddrs.h>
57#else
58#include <../include/ifaddrs.h>
59#endif
60
6ff05e18
SG
61#if HAVE_SYS_PERSONALITY_H
62#include <sys/personality.h>
63#endif
64
36eb9bde 65lxc_log_define(lxc_confile, lxc);
576f946d 66
713046e3 67static int set_config_personality(const char *, const char *, struct lxc_conf *);
6bede808 68static int get_config_personality(const char *, char *, int, struct lxc_conf *);
e08cb901 69static int clr_config_personality(const char *, struct lxc_conf *);
bdf91ab4 70
713046e3 71static int set_config_pts(const char *, const char *, struct lxc_conf *);
6bede808 72static int get_config_pts(const char *, char *, int, struct lxc_conf *);
03818ae3 73static int clr_config_pts(const char *, struct lxc_conf *);
bdf91ab4 74
713046e3 75static int set_config_tty(const char *, const char *, struct lxc_conf *);
6bede808 76static int get_config_tty(const char *, char *, int, struct lxc_conf *);
e7a4b096 77static int clr_config_tty(const char *, struct lxc_conf *);
5485782f 78
713046e3 79static int set_config_ttydir(const char *, const char *, struct lxc_conf *);
6bede808 80static int get_config_ttydir(const char *, char *, int, struct lxc_conf *);
eaf8c0c7 81static int clr_config_ttydir(const char *, struct lxc_conf *);
8015e018 82
713046e3 83static int set_config_kmsg(const char *, const char *, struct lxc_conf *);
6bede808 84static int get_config_kmsg(const char *, char *, int, struct lxc_conf *);
6bd86308 85static int clr_config_kmsg(const char *, struct lxc_conf *);
de1ede69 86
713046e3 87static int set_config_lsm_aa_profile(const char *, const char *, struct lxc_conf *);
6bede808 88static int get_config_lsm_aa_profile(const char *, char *, int, struct lxc_conf *);
025718fb 89static int clr_config_lsm_aa_profile(const char *, struct lxc_conf *);
104c8e6c 90
713046e3 91static int set_config_lsm_aa_incomplete(const char *, const char *, struct lxc_conf *);
6bede808 92static int get_config_lsm_aa_incomplete(const char *, char *, int, struct lxc_conf *);
3061e04e 93static int clr_config_lsm_aa_incomplete(const char *, struct lxc_conf *);
d60d18c6 94
713046e3 95static int set_config_lsm_se_context(const char *, const char *, struct lxc_conf *);
6bede808 96static int get_config_lsm_se_context(const char *, char *, int, struct lxc_conf *);
31fc3494 97static int clr_config_lsm_se_context(const char *, struct lxc_conf *);
4203a0b5 98
713046e3 99static int set_config_cgroup(const char *, const char *, struct lxc_conf *);
6bede808 100static int get_config_cgroup(const char *, char *, int, struct lxc_conf *);
754d01ce 101static int clr_config_cgroup(const char *, struct lxc_conf *);
b863bf92 102
5014ff2e 103static int set_config_idmaps(const char *, const char *, struct lxc_conf *);
6bede808 104static int get_config_idmaps(const char *, char *, int, struct lxc_conf *);
d3a178de 105static int clr_config_idmaps(const char *, struct lxc_conf *);
5014ff2e 106
713046e3 107static int set_config_loglevel(const char *, const char *, struct lxc_conf *);
6bede808 108static int get_config_loglevel(const char *, char *, int, struct lxc_conf *);
97d3338d 109static int clr_config_loglevel(const char *, struct lxc_conf *);
b29b29be 110
713046e3 111static int set_config_logfile(const char *, const char *, struct lxc_conf *);
6bede808 112static int get_config_logfile(const char *, char *, int, struct lxc_conf *);
de46099c 113static int clr_config_logfile(const char *, struct lxc_conf *);
3d4630ab 114
713046e3 115static int set_config_mount(const char *, const char *, struct lxc_conf *);
6bede808 116static int get_config_mount(const char *, char *, int, struct lxc_conf *);
b4fa13cd 117static int clr_config_mount(const char *, struct lxc_conf *);
0d601acb 118
713046e3 119static int set_config_mount_auto(const char *, const char *, struct lxc_conf *);
6bede808 120static int get_config_mount_auto(const char *, char *, int, struct lxc_conf *);
4be81021 121static int clr_config_mount_auto(const char *, struct lxc_conf *);
0d601acb 122
713046e3 123static int set_config_fstab(const char *, const char *, struct lxc_conf *);
6bede808 124static int get_config_fstab(const char *, char *, int, struct lxc_conf *);
350d4b15 125static int clr_config_fstab(const char *, struct lxc_conf *);
0d601acb 126
713046e3 127static int set_config_rootfs_mount(const char *, const char *, struct lxc_conf *);
6bede808 128static int get_config_rootfs_mount(const char *, char *, int, struct lxc_conf *);
fddefc2d 129static int clr_config_rootfs_mount(const char *, struct lxc_conf *);
3af60359 130
713046e3 131static int set_config_rootfs_options(const char *, const char *, struct lxc_conf *);
6bede808 132static int get_config_rootfs_options(const char *, char *, int, struct lxc_conf *);
7b1eb67d 133static int clr_config_rootfs_options(const char *, struct lxc_conf *);
0e9db631 134
713046e3 135static int set_config_rootfs_backend(const char *, const char *, struct lxc_conf *);
6bede808 136static int get_config_rootfs_backend(const char *, char *, int, struct lxc_conf *);
02becb8d 137static int clr_config_rootfs_backend(const char *, struct lxc_conf *);
8f183f38 138
faca124d
CB
139static int set_config_rootfs(const char *, const char *, struct lxc_conf *);
140static int get_config_rootfs(const char *, char *, int, struct lxc_conf *);
141static int clr_config_rootfs(const char *, struct lxc_conf *);
142
713046e3 143static int set_config_pivotdir(const char *, const char *, struct lxc_conf *);
6bede808 144static int get_config_pivotdir(const char *, char *, int, struct lxc_conf *);
57928a51 145static int clr_config_pivotdir(const char *, struct lxc_conf *);
b87574e7 146
713046e3 147static int set_config_utsname(const char *, const char *, struct lxc_conf *);
6bede808 148static int get_config_utsname(const char *, char *, int, struct lxc_conf *);
d31d0103 149static int clr_config_utsname(const char *, struct lxc_conf *);
e274f8b0 150
466c2e93 151static int set_config_hooks(const char *, const char *, struct lxc_conf *lxc_conf);
6bede808 152static int get_config_hooks(const char *, char *, int, struct lxc_conf *);
c9eeb90c 153static int clr_config_hooks(const char *, struct lxc_conf *);
466c2e93 154
713046e3
CB
155static int set_config_network_type(const char *, const char *, struct lxc_conf *);
156static int set_config_network_flags(const char *, const char *, struct lxc_conf *);
157static int set_config_network_link(const char *, const char *, struct lxc_conf *);
158static int set_config_network_name(const char *, const char *, struct lxc_conf *);
159static int set_config_network_veth_pair(const char *, const char *, struct lxc_conf *);
160static int set_config_network_macvlan_mode(const char *, const char *, struct lxc_conf *);
161static int set_config_network_hwaddr(const char *, const char *, struct lxc_conf *);
162static int set_config_network_vlan_id(const char *, const char *, struct lxc_conf *);
163static int set_config_network_mtu(const char *, const char *, struct lxc_conf *);
164static int set_config_network_ipv4(const char *, const char *, struct lxc_conf *);
165static int set_config_network_ipv4_gateway(const char *, const char *, struct lxc_conf *);
166static int set_config_network_script_up(const char *, const char *, struct lxc_conf *);
167static int set_config_network_script_down(const char *, const char *, struct lxc_conf *);
168static int set_config_network_ipv6(const char *, const char *, struct lxc_conf *);
169static int set_config_network_ipv6_gateway(const char *, const char *, struct lxc_conf *);
c721e86c 170static int set_config_network_nic(const char *, const char *, struct lxc_conf *);
6bede808 171static int get_config_network_item(const char *, char *, int, struct lxc_conf *);
e2410c4e
CB
172static int clr_config_network_item(const char *, struct lxc_conf *);
173
174static int set_config_network(const char *, const char *, struct lxc_conf *);
175static int get_config_network(const char *, char *, int, struct lxc_conf *);
f4488271 176static int clr_config_network(const char *, struct lxc_conf *);
bdccff60 177
713046e3 178static int set_config_cap_drop(const char *, const char *, struct lxc_conf *);
6bede808 179static int get_config_cap_drop(const char *, char *, int, struct lxc_conf *);
244cb55b 180static int clr_config_cap_drop(const char *, struct lxc_conf *);
1c96d6d8 181
713046e3 182static int set_config_cap_keep(const char *, const char *, struct lxc_conf *);
6bede808 183static int get_config_cap_keep(const char *, char *, int, struct lxc_conf *);
c74cc490 184static int clr_config_cap_keep(const char *, struct lxc_conf *);
b80927f2 185
713046e3 186static int set_config_console_logfile(const char *, const char *, struct lxc_conf *);
6bede808 187static int get_config_console_logfile(const char *, char *, int, struct lxc_conf *);
7c2ec23a 188static int clr_config_console_logfile(const char *, struct lxc_conf *);
794d1c06 189
4e5b633f
CB
190static int set_config_console(const char *, const char *, struct lxc_conf *);
191static int get_config_console(const char *, char *, int, struct lxc_conf *);
192static int clr_config_console(const char *, struct lxc_conf *);
193
713046e3 194static int set_config_seccomp(const char *, const char *, struct lxc_conf *);
6bede808 195static int get_config_seccomp(const char *, char *, int, struct lxc_conf *);
bbca37d8 196static int clr_config_seccomp(const char *, struct lxc_conf *);
75f55b1f 197
973082f5 198static int set_config_includefiles(const char *, const char *, struct lxc_conf *);
a3c8e600 199static int get_config_includefiles(const char *, char *, int, struct lxc_conf *);
973082f5 200static int clr_config_includefiles(const char *, struct lxc_conf *);
97f6dad0 201
713046e3 202static int set_config_autodev(const char *, const char *, struct lxc_conf *);
6bede808 203static int get_config_autodev(const char *, char *, int, struct lxc_conf *);
c721e86c 204static int clr_config_autodev(const char *, struct lxc_conf *);
97f6dad0 205
713046e3 206static int set_config_haltsignal(const char *, const char *, struct lxc_conf *);
6bede808 207static int get_config_haltsignal(const char *, char *, int, struct lxc_conf *);
87b288d1 208static int clr_config_haltsignal(const char *, struct lxc_conf *);
afee4324 209
713046e3 210static int set_config_rebootsignal(const char *, const char *, struct lxc_conf *);
6bede808 211static int get_config_rebootsignal(const char *, char *, int, struct lxc_conf *);
cae63cfa 212static int clr_config_rebootsignal(const char *, struct lxc_conf *);
3aa8f359 213
713046e3 214static int set_config_stopsignal(const char *, const char *, struct lxc_conf *);
6bede808 215static int get_config_stopsignal(const char *, char *, int, struct lxc_conf *);
de45f3a8 216static int clr_config_stopsignal(const char *, struct lxc_conf *);
2e16269f 217
713046e3 218static int set_config_start(const char *, const char *, struct lxc_conf *);
6bede808 219static int get_config_start(const char *, char *, int, struct lxc_conf *);
c6182222 220static int clr_config_start(const char *, struct lxc_conf *);
54345299 221
713046e3 222static int set_config_monitor(const char *, const char *, struct lxc_conf *);
6bede808 223static int get_config_monitor(const char *, char *, int, struct lxc_conf *);
adad12ca 224static int clr_config_monitor(const char *, struct lxc_conf *);
ac0f949c 225
713046e3 226static int set_config_group(const char *, const char *, struct lxc_conf *);
6bede808 227static int get_config_group(const char *, char *, int, struct lxc_conf *);
4850d223 228static int clr_config_group(const char *, struct lxc_conf *);
90ec7b6e 229
713046e3 230static int set_config_environment(const char *, const char *, struct lxc_conf *);
6bede808 231static int get_config_environment(const char *, char *, int, struct lxc_conf *);
832fb63a 232static int clr_config_environment(const char *, struct lxc_conf *);
aa0db7d3 233
713046e3 234static int set_config_init_cmd(const char *, const char *, struct lxc_conf *);
6bede808 235static int get_config_init_cmd(const char *, char *, int, struct lxc_conf *);
8e90af3e 236static int clr_config_init_cmd(const char *, struct lxc_conf *);
96dfcb7d 237
713046e3 238static int set_config_init_uid(const char *, const char *, struct lxc_conf *);
6bede808 239static int get_config_init_uid(const char *, char *, int, struct lxc_conf *);
ec76dcfb 240static int clr_config_init_uid(const char *, struct lxc_conf *);
1398e9b1 241
713046e3 242static int set_config_init_gid(const char *, const char *, struct lxc_conf *);
6bede808 243static int get_config_init_gid(const char *, char *, int, struct lxc_conf *);
1044b247 244static int clr_config_init_gid(const char *, struct lxc_conf *);
dfeb7e42 245
713046e3 246static int set_config_ephemeral(const char *, const char *, struct lxc_conf *);
6bede808 247static int get_config_ephemeral(const char *, char *, int, struct lxc_conf *);
59e370db 248static int clr_config_ephemeral(const char *, struct lxc_conf *);
62048afe 249
998ca94f
CB
250static int set_config_syslog(const char *, const char *, struct lxc_conf *);
251static int get_config_syslog(const char *, char *, int, struct lxc_conf *);
252static int clr_config_syslog(const char *, struct lxc_conf *);
253
713046e3 254static int set_config_no_new_privs(const char *, const char *, struct lxc_conf *);
6bede808 255static int get_config_no_new_privs(const char *, char *, int, struct lxc_conf *);
b98c5ab0 256static int clr_config_no_new_privs(const char *, struct lxc_conf *);
b09521ac 257
713046e3 258static int set_config_limit(const char *, const char *, struct lxc_conf *);
6bede808 259static int get_config_limit(const char *, char *, int, struct lxc_conf *);
715ccc96 260static int clr_config_limit(const char *, struct lxc_conf *);
c2cc9f0a 261
72d0e1cb 262static struct lxc_config_t config[] = {
3061e04e
CB
263 { "lxc.arch", set_config_personality, get_config_personality, clr_config_personality, },
264 { "lxc.pts", set_config_pts, get_config_pts, clr_config_pts, },
265 { "lxc.tty", set_config_tty, get_config_tty, clr_config_tty, },
266 { "lxc.devttydir", set_config_ttydir, get_config_ttydir, clr_config_ttydir, },
267 { "lxc.kmsg", set_config_kmsg, get_config_kmsg, clr_config_kmsg, },
268 { "lxc.aa_profile", set_config_lsm_aa_profile, get_config_lsm_aa_profile, clr_config_lsm_aa_profile, },
269 { "lxc.aa_allow_incomplete", set_config_lsm_aa_incomplete, get_config_lsm_aa_incomplete, clr_config_lsm_aa_incomplete, },
31fc3494 270 { "lxc.se_context", set_config_lsm_se_context, get_config_lsm_se_context, clr_config_lsm_se_context, },
754d01ce 271 { "lxc.cgroup", set_config_cgroup, get_config_cgroup, clr_config_cgroup, },
d3a178de 272 { "lxc.id_map", set_config_idmaps, get_config_idmaps, clr_config_idmaps, },
97d3338d 273 { "lxc.loglevel", set_config_loglevel, get_config_loglevel, clr_config_loglevel, },
de46099c 274 { "lxc.logfile", set_config_logfile, get_config_logfile, clr_config_logfile, },
b4fa13cd 275 { "lxc.mount.entry", set_config_mount, get_config_mount, clr_config_mount, },
350d4b15
CB
276 { "lxc.mount.auto", set_config_mount_auto, get_config_mount_auto, clr_config_mount_auto, },
277 { "lxc.mount", set_config_fstab, get_config_fstab, clr_config_fstab, },
fddefc2d 278 { "lxc.rootfs.mount", set_config_rootfs_mount, get_config_rootfs_mount, clr_config_rootfs_mount, },
7b1eb67d 279 { "lxc.rootfs.options", set_config_rootfs_options, get_config_rootfs_options, clr_config_rootfs_options, },
02becb8d 280 { "lxc.rootfs.backend", set_config_rootfs_backend, get_config_rootfs_backend, clr_config_rootfs_backend, },
fddefc2d 281 { "lxc.rootfs", set_config_rootfs, get_config_rootfs, clr_config_rootfs, },
57928a51 282 { "lxc.pivotdir", set_config_pivotdir, get_config_pivotdir, clr_config_pivotdir, },
d31d0103 283 { "lxc.utsname", set_config_utsname, get_config_utsname, clr_config_utsname, },
c9eeb90c
CB
284 { "lxc.hook.pre-start", set_config_hooks, get_config_hooks, clr_config_hooks, },
285 { "lxc.hook.pre-mount", set_config_hooks, get_config_hooks, clr_config_hooks, },
286 { "lxc.hook.mount", set_config_hooks, get_config_hooks, clr_config_hooks, },
287 { "lxc.hook.autodev", set_config_hooks, get_config_hooks, clr_config_hooks, },
288 { "lxc.hook.start", set_config_hooks, get_config_hooks, clr_config_hooks, },
289 { "lxc.hook.stop", set_config_hooks, get_config_hooks, clr_config_hooks, },
290 { "lxc.hook.post-stop", set_config_hooks, get_config_hooks, clr_config_hooks, },
291 { "lxc.hook.clone", set_config_hooks, get_config_hooks, clr_config_hooks, },
292 { "lxc.hook.destroy", set_config_hooks, get_config_hooks, clr_config_hooks, },
293 { "lxc.hook", set_config_hooks, get_config_hooks, clr_config_hooks, },
e2410c4e
CB
294 { "lxc.network.type", set_config_network_type, get_config_network_item, clr_config_network_item, },
295 { "lxc.network.flags", set_config_network_flags, get_config_network_item, clr_config_network_item, },
296 { "lxc.network.link", set_config_network_link, get_config_network_item, clr_config_network_item, },
297 { "lxc.network.name", set_config_network_name, get_config_network_item, clr_config_network_item, },
298 { "lxc.network.macvlan.mode", set_config_network_macvlan_mode, get_config_network_item, clr_config_network_item, },
299 { "lxc.network.veth.pair", set_config_network_veth_pair, get_config_network_item, clr_config_network_item, },
300 { "lxc.network.script.up", set_config_network_script_up, get_config_network_item, clr_config_network_item, },
301 { "lxc.network.script.down", set_config_network_script_down, get_config_network_item, clr_config_network_item, },
302 { "lxc.network.hwaddr", set_config_network_hwaddr, get_config_network_item, clr_config_network_item, },
303 { "lxc.network.mtu", set_config_network_mtu, get_config_network_item, clr_config_network_item, },
304 { "lxc.network.vlan.id", set_config_network_vlan_id, get_config_network_item, clr_config_network_item, },
305 { "lxc.network.ipv4.gateway", set_config_network_ipv4_gateway, get_config_network_item, clr_config_network_item, },
306 { "lxc.network.ipv4", set_config_network_ipv4, get_config_network_item, clr_config_network_item, },
307 { "lxc.network.ipv6.gateway", set_config_network_ipv6_gateway, get_config_network_item, clr_config_network_item, },
308 { "lxc.network.ipv6", set_config_network_ipv6, get_config_network_item, clr_config_network_item, },
309 { "lxc.network.", set_config_network_nic, get_config_network_item, clr_config_network_item, },
f4488271 310 { "lxc.network", set_config_network, get_config_network, clr_config_network, },
244cb55b 311 { "lxc.cap.drop", set_config_cap_drop, get_config_cap_drop, clr_config_cap_drop, },
c74cc490 312 { "lxc.cap.keep", set_config_cap_keep, get_config_cap_keep, clr_config_cap_keep, },
7c2ec23a 313 { "lxc.console.logfile", set_config_console_logfile, get_config_console_logfile, clr_config_console_logfile, },
4e5b633f 314 { "lxc.console", set_config_console, get_config_console, clr_config_console, },
bbca37d8 315 { "lxc.seccomp", set_config_seccomp, get_config_seccomp, clr_config_seccomp, },
a3c8e600 316 { "lxc.include", set_config_includefiles, get_config_includefiles, clr_config_includefiles, },
c721e86c 317 { "lxc.autodev", set_config_autodev, get_config_autodev, clr_config_autodev, },
87b288d1 318 { "lxc.haltsignal", set_config_haltsignal, get_config_haltsignal, clr_config_haltsignal, },
cae63cfa 319 { "lxc.rebootsignal", set_config_rebootsignal, get_config_rebootsignal, clr_config_rebootsignal, },
de45f3a8 320 { "lxc.stopsignal", set_config_stopsignal, get_config_stopsignal, clr_config_stopsignal, },
c6182222
CB
321 { "lxc.start.auto", set_config_start, get_config_start, clr_config_start, },
322 { "lxc.start.delay", set_config_start, get_config_start, clr_config_start, },
323 { "lxc.start.order", set_config_start, get_config_start, clr_config_start, },
adad12ca 324 { "lxc.monitor.unshare", set_config_monitor, get_config_monitor, clr_config_monitor, },
4850d223 325 { "lxc.group", set_config_group, get_config_group, clr_config_group, },
832fb63a 326 { "lxc.environment", set_config_environment, get_config_environment, clr_config_environment, },
8e90af3e 327 { "lxc.init_cmd", set_config_init_cmd, get_config_init_cmd, clr_config_init_cmd, },
ec76dcfb 328 { "lxc.init_uid", set_config_init_uid, get_config_init_uid, clr_config_init_uid, },
1044b247 329 { "lxc.init_gid", set_config_init_gid, get_config_init_gid, clr_config_init_gid, },
59e370db 330 { "lxc.ephemeral", set_config_ephemeral, get_config_ephemeral, clr_config_ephemeral, },
998ca94f 331 { "lxc.syslog", set_config_syslog, get_config_syslog, clr_config_syslog, },
b98c5ab0 332 { "lxc.no_new_privs", set_config_no_new_privs, get_config_no_new_privs, clr_config_no_new_privs, },
715ccc96 333 { "lxc.limit", set_config_limit, get_config_limit, clr_config_limit, },
a84b9932
AV
334};
335
336struct signame {
337 int num;
74a3920a 338 const char *name;
a84b9932
AV
339};
340
74a3920a 341static const struct signame signames[] = {
504a2217
CB
342 { SIGHUP, "HUP" },
343 { SIGINT, "INT" },
344 { SIGQUIT, "QUIT" },
345 { SIGILL, "ILL" },
346 { SIGABRT, "ABRT" },
347 { SIGFPE, "FPE" },
348 { SIGKILL, "KILL" },
349 { SIGSEGV, "SEGV" },
350 { SIGPIPE, "PIPE" },
351 { SIGALRM, "ALRM" },
352 { SIGTERM, "TERM" },
353 { SIGUSR1, "USR1" },
354 { SIGUSR2, "USR2" },
355 { SIGCHLD, "CHLD" },
356 { SIGCONT, "CONT" },
357 { SIGSTOP, "STOP" },
358 { SIGTSTP, "TSTP" },
359 { SIGTTIN, "TTIN" },
360 { SIGTTOU, "TTOU" },
89dfc302 361#ifdef SIGTRAP
504a2217 362 { SIGTRAP, "TRAP" },
89dfc302
SY
363#endif
364#ifdef SIGIOT
504a2217 365 { SIGIOT, "IOT" },
89dfc302
SY
366#endif
367#ifdef SIGEMT
504a2217 368 { SIGEMT, "EMT" },
89dfc302
SY
369#endif
370#ifdef SIGBUS
504a2217 371 { SIGBUS, "BUS" },
89dfc302
SY
372#endif
373#ifdef SIGSTKFLT
374 { SIGSTKFLT, "STKFLT" },
375#endif
376#ifdef SIGCLD
504a2217 377 { SIGCLD, "CLD" },
89dfc302
SY
378#endif
379#ifdef SIGURG
504a2217 380 { SIGURG, "URG" },
89dfc302
SY
381#endif
382#ifdef SIGXCPU
504a2217 383 { SIGXCPU, "XCPU" },
89dfc302
SY
384#endif
385#ifdef SIGXFSZ
504a2217 386 { SIGXFSZ, "XFSZ" },
89dfc302
SY
387#endif
388#ifdef SIGVTALRM
389 { SIGVTALRM, "VTALRM" },
390#endif
391#ifdef SIGPROF
504a2217 392 { SIGPROF, "PROF" },
89dfc302
SY
393#endif
394#ifdef SIGWINCH
504a2217 395 { SIGWINCH, "WINCH" },
89dfc302
SY
396#endif
397#ifdef SIGIO
504a2217 398 { SIGIO, "IO" },
89dfc302
SY
399#endif
400#ifdef SIGPOLL
504a2217 401 { SIGPOLL, "POLL" },
89dfc302
SY
402#endif
403#ifdef SIGINFO
504a2217 404 { SIGINFO, "INFO" },
89dfc302
SY
405#endif
406#ifdef SIGLOST
504a2217 407 { SIGLOST, "LOST" },
89dfc302
SY
408#endif
409#ifdef SIGPWR
504a2217 410 { SIGPWR, "PWR" },
89dfc302
SY
411#endif
412#ifdef SIGUNUSED
413 { SIGUNUSED, "UNUSED" },
414#endif
415#ifdef SIGSYS
504a2217 416 { SIGSYS, "SYS" },
89dfc302 417#endif
c2cc9f0a 418};
419
504a2217 420static const size_t config_size = sizeof(config) / sizeof(struct lxc_config_t);
c2cc9f0a 421
72d0e1cb 422extern struct lxc_config_t *lxc_getconfig(const char *key)
c2cc9f0a 423{
84760c11 424 size_t i;
c2cc9f0a 425
426 for (i = 0; i < config_size; i++)
504a2217 427 if (!strncmp(config[i].name, key, strlen(config[i].name)))
c2cc9f0a 428 return &config[i];
429 return NULL;
430}
431
504a2217
CB
432#define strprint(str, inlen, ...) \
433 do { \
434 len = snprintf(str, inlen, ##__VA_ARGS__); \
435 if (len < 0) { \
436 SYSERROR("failed to create string"); \
437 return -1; \
438 }; \
439 fulllen += len; \
440 if (inlen > 0) { \
441 if (str) \
442 str += len; \
443 inlen -= len; \
444 if (inlen < 0) \
445 inlen = 0; \
446 } \
72d0e1cb
SG
447 } while (0);
448
449int lxc_listconfigs(char *retv, int inlen)
450{
84760c11 451 size_t i;
504a2217
CB
452 int len;
453 int fulllen = 0;
72d0e1cb
SG
454
455 if (!retv)
456 inlen = 0;
457 else
458 memset(retv, 0, inlen);
504a2217 459
72d0e1cb
SG
460 for (i = 0; i < config_size; i++) {
461 char *s = config[i].name;
504a2217 462 if (s[strlen(s) - 1] == '.')
72d0e1cb
SG
463 continue;
464 strprint(retv, inlen, "%s\n", s);
465 }
504a2217 466
72d0e1cb
SG
467 return fulllen;
468}
469
713046e3 470static int set_config_string_item(char **conf_item, const char *value)
6d03d92a
DE
471{
472 char *new_value;
473
663e9916 474 if (lxc_config_value_empty(value)) {
f10fad2f 475 free(*conf_item);
d6eca240 476 *conf_item = NULL;
6d03d92a 477 return 0;
d6eca240 478 }
6d03d92a
DE
479
480 new_value = strdup(value);
481 if (!new_value) {
e70b9db5 482 SYSERROR("failed to duplicate string \"%s\"", value);
6d03d92a
DE
483 return -1;
484 }
485
f10fad2f 486 free(*conf_item);
6d03d92a
DE
487 *conf_item = new_value;
488 return 0;
489}
490
713046e3 491static int set_config_string_item_max(char **conf_item, const char *value,
504a2217 492 size_t max)
6d03d92a
DE
493{
494 if (strlen(value) >= max) {
a5a82508 495 ERROR("%s is too long (>= %lu)", value, (unsigned long)max);
6d03d92a
DE
496 return -1;
497 }
498
713046e3 499 return set_config_string_item(conf_item, value);
6d03d92a
DE
500}
501
713046e3 502static int set_config_path_item(char **conf_item, const char *value)
6d03d92a 503{
713046e3 504 return set_config_string_item_max(conf_item, value, PATH_MAX);
6d03d92a
DE
505}
506
72d0e1cb 507/*
504a2217
CB
508 * Config entry is something like "lxc.network.0.ipv4" the key 'lxc.network.'
509 * was found. So we make sure next comes an integer, find the right callback
510 * (by rewriting the key), and call it.
72d0e1cb 511 */
713046e3 512static int set_config_network_nic(const char *key, const char *value,
504a2217 513 struct lxc_conf *lxc_conf)
72d0e1cb
SG
514{
515 char *copy = strdup(key), *p;
516 int ret = -1;
517 struct lxc_config_t *config;
518
519 if (!copy) {
520 SYSERROR("failed to allocate memory");
521 return -1;
522 }
523 /*
504a2217 524 * Ok we know that to get here we've got "lxc.network."
72d0e1cb 525 * and it isn't any of the other network entries. So
504a2217 526 * after the second . Should come an integer (# of defined
72d0e1cb
SG
527 * nic) followed by a valid entry.
528 */
504a2217 529 if (*(key + 12) < '0' || *(key + 12) > '9')
72d0e1cb 530 goto out;
504a2217
CB
531
532 p = strchr(key + 12, '.');
72d0e1cb
SG
533 if (!p)
534 goto out;
504a2217
CB
535
536 strcpy(copy + 12, p + 1);
72d0e1cb
SG
537 config = lxc_getconfig(copy);
538 if (!config) {
539 ERROR("unknown key %s", key);
540 goto out;
541 }
d37f7cd7 542 ret = config->set(key, value, lxc_conf);
72d0e1cb
SG
543
544out:
545 free(copy);
546 return ret;
547}
548
713046e3 549static int set_config_network(const char *key, const char *value,
504a2217 550 struct lxc_conf *lxc_conf)
6b0d5538 551{
663e9916 552 if (!lxc_config_value_empty(value)) {
6b0d5538
SH
553 ERROR("lxc.network must not have a value");
554 return -1;
555 }
556
557 return lxc_clear_config_network(lxc_conf);
558}
559
261658e8
BP
560static int macvlan_mode(int *valuep, const char *value);
561
713046e3 562static int set_config_network_type(const char *key, const char *value,
504a2217 563 struct lxc_conf *lxc_conf)
c2cc9f0a 564{
5f4535a3 565 struct lxc_list *network = &lxc_conf->network;
c2cc9f0a 566 struct lxc_netdev *netdev;
567 struct lxc_list *list;
c2cc9f0a 568
663e9916 569 if (lxc_config_value_empty(value))
7d0eb87e
SH
570 return lxc_clear_config_network(lxc_conf);
571
c2cc9f0a 572 netdev = malloc(sizeof(*netdev));
573 if (!netdev) {
36eb9bde 574 SYSERROR("failed to allocate memory");
c2cc9f0a 575 return -1;
576 }
577
82d5ae15 578 memset(netdev, 0, sizeof(*netdev));
c2cc9f0a 579 lxc_list_init(&netdev->ipv4);
580 lxc_list_init(&netdev->ipv6);
c2cc9f0a 581
582 list = malloc(sizeof(*list));
583 if (!list) {
36eb9bde 584 SYSERROR("failed to allocate memory");
022de5f3 585 free(netdev);
c2cc9f0a 586 return -1;
587 }
588
589 lxc_list_init(list);
5f4535a3 590 list->elem = netdev;
c2cc9f0a 591
bac89583 592 lxc_list_add_tail(network, list);
a871ff6b 593
c2cc9f0a 594 if (!strcmp(value, "veth"))
24654103 595 netdev->type = LXC_NET_VETH;
261658e8 596 else if (!strcmp(value, "macvlan")) {
24654103 597 netdev->type = LXC_NET_MACVLAN;
261658e8 598 macvlan_mode(&netdev->priv.macvlan_attr.mode, "private");
504a2217 599 } else if (!strcmp(value, "vlan"))
24654103 600 netdev->type = LXC_NET_VLAN;
c2cc9f0a 601 else if (!strcmp(value, "phys"))
24654103 602 netdev->type = LXC_NET_PHYS;
5f58350a 603 else if (!strcmp(value, "empty"))
24654103 604 netdev->type = LXC_NET_EMPTY;
26b797f3
SH
605 else if (!strcmp(value, "none"))
606 netdev->type = LXC_NET_NONE;
c2cc9f0a 607 else {
36eb9bde 608 ERROR("invalid network type %s", value);
c2cc9f0a 609 return -1;
610 }
611 return 0;
612}
613
a059591e
DL
614static int config_ip_prefix(struct in_addr *addr)
615{
616 if (IN_CLASSA(addr->s_addr))
617 return 32 - IN_CLASSA_NSHIFT;
618 if (IN_CLASSB(addr->s_addr))
619 return 32 - IN_CLASSB_NSHIFT;
620 if (IN_CLASSC(addr->s_addr))
621 return 32 - IN_CLASSC_NSHIFT;
622
623 return 0;
624}
625
72d0e1cb 626/*
504a2217
CB
627 * If you have p="lxc.network.0.link", pass it p+12
628 * to get back '0' (the index of the nic).
72d0e1cb
SG
629 */
630static int get_network_netdev_idx(const char *key)
631{
632 int ret, idx;
633
634 if (*key < '0' || *key > '9')
635 return -1;
504a2217 636
72d0e1cb
SG
637 ret = sscanf(key, "%d", &idx);
638 if (ret != 1)
639 return -1;
504a2217 640
72d0e1cb
SG
641 return idx;
642}
643
644/*
504a2217
CB
645 * If you have p="lxc.network.0", pass this p+12 and it will return
646 * the netdev of the first configured nic.
72d0e1cb
SG
647 */
648static struct lxc_netdev *get_netdev_from_key(const char *key,
649 struct lxc_list *network)
650{
504a2217 651 int idx;
72d0e1cb 652 struct lxc_list *it;
504a2217
CB
653 int i = 0;
654 struct lxc_netdev *netdev = NULL;
655
656 idx = get_network_netdev_idx(key);
72d0e1cb
SG
657 if (idx == -1)
658 return NULL;
504a2217 659
72d0e1cb
SG
660 lxc_list_for_each(it, network) {
661 if (idx == i++) {
662 netdev = it->elem;
663 break;
664 }
665 }
504a2217 666
72d0e1cb
SG
667 return netdev;
668}
669
504a2217
CB
670extern int lxc_list_nicconfigs(struct lxc_conf *c, const char *key, char *retv,
671 int inlen)
72d0e1cb
SG
672{
673 struct lxc_netdev *netdev;
504a2217
CB
674 int len;
675 int fulllen = 0;
72d0e1cb 676
504a2217 677 netdev = get_netdev_from_key(key + 12, &c->network);
72d0e1cb
SG
678 if (!netdev)
679 return -1;
680
681 if (!retv)
682 inlen = 0;
683 else
684 memset(retv, 0, inlen);
685
74836992 686 strprint(retv, inlen, "type\n");
72d0e1cb 687 strprint(retv, inlen, "script.up\n");
8fc8295a 688 strprint(retv, inlen, "script.down\n");
72d0e1cb
SG
689 if (netdev->type != LXC_NET_EMPTY) {
690 strprint(retv, inlen, "flags\n");
691 strprint(retv, inlen, "link\n");
692 strprint(retv, inlen, "name\n");
693 strprint(retv, inlen, "hwaddr\n");
694 strprint(retv, inlen, "mtu\n");
695 strprint(retv, inlen, "ipv6\n");
9eaf8a59 696 strprint(retv, inlen, "ipv6.gateway\n");
72d0e1cb 697 strprint(retv, inlen, "ipv4\n");
9eaf8a59 698 strprint(retv, inlen, "ipv4.gateway\n");
72d0e1cb 699 }
504a2217
CB
700
701 switch (netdev->type) {
72d0e1cb
SG
702 case LXC_NET_VETH:
703 strprint(retv, inlen, "veth.pair\n");
704 break;
705 case LXC_NET_MACVLAN:
706 strprint(retv, inlen, "macvlan.mode\n");
707 break;
708 case LXC_NET_VLAN:
709 strprint(retv, inlen, "vlan.id\n");
710 break;
711 case LXC_NET_PHYS:
712 break;
713 }
504a2217 714
72d0e1cb
SG
715 return fulllen;
716}
717
16950ecb
DL
718static struct lxc_netdev *network_netdev(const char *key, const char *value,
719 struct lxc_list *network)
c2cc9f0a 720{
72d0e1cb 721 struct lxc_netdev *netdev = NULL;
c2cc9f0a 722
5f4535a3 723 if (lxc_list_empty(network)) {
504a2217
CB
724 ERROR("network is not created for '%s' = '%s' option", key,
725 value);
33c945e0 726 return NULL;
c2cc9f0a 727 }
728
504a2217 729 if (get_network_netdev_idx(key + 12) == -1)
72d0e1cb
SG
730 netdev = lxc_list_last_elem(network);
731 else
504a2217 732 netdev = get_netdev_from_key(key + 12, network);
72d0e1cb 733
5f4535a3 734 if (!netdev) {
504a2217
CB
735 ERROR("no network device defined for '%s' = '%s' option", key,
736 value);
33c945e0 737 return NULL;
c2cc9f0a 738 }
739
33c945e0 740 return netdev;
c2cc9f0a 741}
742
12a50cc6 743static int network_ifname(char **valuep, const char *value)
c2cc9f0a 744{
713046e3 745 return set_config_string_item_max(valuep, value, IFNAMSIZ);
c2cc9f0a 746}
747
e892973e 748#ifndef MACVLAN_MODE_PRIVATE
504a2217 749#define MACVLAN_MODE_PRIVATE 1
e892973e
DL
750#endif
751
752#ifndef MACVLAN_MODE_VEPA
504a2217 753#define MACVLAN_MODE_VEPA 2
e892973e
DL
754#endif
755
756#ifndef MACVLAN_MODE_BRIDGE
504a2217 757#define MACVLAN_MODE_BRIDGE 4
e892973e
DL
758#endif
759
99854161 760#ifndef MACVLAN_MODE_PASSTHRU
504a2217 761#define MACVLAN_MODE_PASSTHRU 8
99854161
EL
762#endif
763
12a50cc6 764static int macvlan_mode(int *valuep, const char *value)
e892973e
DL
765{
766 struct mc_mode {
767 char *name;
768 int mode;
769 } m[] = {
504a2217
CB
770 { "private", MACVLAN_MODE_PRIVATE },
771 { "vepa", MACVLAN_MODE_VEPA },
772 { "bridge", MACVLAN_MODE_BRIDGE },
773 { "passthru", MACVLAN_MODE_PASSTHRU },
e892973e
DL
774 };
775
84760c11 776 size_t i;
e892973e 777
504a2217 778 for (i = 0; i < sizeof(m) / sizeof(m[0]); i++) {
e892973e
DL
779 if (strcmp(m[i].name, value))
780 continue;
781
782 *valuep = m[i].mode;
783 return 0;
784 }
785
786 return -1;
787}
788
508c263e
SH
789static int rand_complete_hwaddr(char *hwaddr)
790{
791 const char hex[] = "0123456789abcdef";
792 char *curs = hwaddr;
793
794#ifndef HAVE_RAND_R
795 randseed(true);
796#else
504a2217
CB
797 unsigned int seed;
798
799 seed = randseed(false);
508c263e 800#endif
504a2217
CB
801 while (*curs != '\0' && *curs != '\n') {
802 if (*curs == 'x' || *curs == 'X') {
508c263e 803 if (curs - hwaddr == 1) {
504a2217 804 /* ensure address is unicast */
508c263e
SH
805#ifdef HAVE_RAND_R
806 *curs = hex[rand_r(&seed) & 0x0E];
807 } else {
808 *curs = hex[rand_r(&seed) & 0x0F];
809#else
810 *curs = hex[rand() & 0x0E];
811 } else {
812 *curs = hex[rand() & 0x0F];
813#endif
814 }
815 }
816 curs++;
817 }
818 return 0;
819}
820
713046e3 821static int set_config_network_flags(const char *key, const char *value,
504a2217 822 struct lxc_conf *lxc_conf)
c2cc9f0a 823{
c2cc9f0a 824 struct lxc_netdev *netdev;
825
16950ecb 826 netdev = network_netdev(key, value, &lxc_conf->network);
33c945e0 827 if (!netdev)
c2cc9f0a 828 return -1;
c2cc9f0a 829
33c945e0 830 netdev->flags |= IFF_UP;
c2cc9f0a 831
33c945e0
MT
832 return 0;
833}
834
504a2217
CB
835static int set_network_link(const char *key, const char *value,
836 struct lxc_conf *lxc_conf)
576400e5 837{
504a2217 838 struct lxc_netdev *netdev;
576400e5 839
504a2217
CB
840 netdev = network_netdev(key, value, &lxc_conf->network);
841 if (!netdev)
842 return -1;
576400e5 843
504a2217 844 return network_ifname(&netdev->link, value);
576400e5 845}
846
847static int create_matched_ifnames(const char *value, struct lxc_conf *lxc_conf)
848{
849 struct ifaddrs *ifaddr, *ifa;
504a2217
CB
850 int n;
851 int ret = 0;
576400e5 852 const char *type_key = "lxc.network.type";
853 const char *link_key = "lxc.network.link";
854 const char *tmpvalue = "phys";
576400e5 855
856 if (getifaddrs(&ifaddr) == -1) {
857 SYSERROR("Get network interfaces failed");
858 return -1;
859 }
860
861 for (ifa = ifaddr, n = 0; ifa != NULL; ifa = ifa->ifa_next, n++) {
862 if (!ifa->ifa_addr)
863 continue;
864 if (ifa->ifa_addr->sa_family != AF_PACKET)
865 continue;
866
504a2217
CB
867 if (!strncmp(value, ifa->ifa_name, strlen(value) - 1)) {
868 ret = set_config_network_type(type_key, tmpvalue,
869 lxc_conf);
576400e5 870 if (!ret) {
504a2217
CB
871 ret = set_network_link(link_key, ifa->ifa_name,
872 lxc_conf);
576400e5 873 if (ret) {
874 ERROR("failed to create matched ifnames");
875 break;
876 }
877 } else {
878 ERROR("failed to create matched ifnames");
879 break;
880 }
881 }
882 }
883
504a2217
CB
884 freeifaddrs(ifaddr);
885 ifaddr = NULL;
091045f8 886
576400e5 887 return ret;
888}
889
713046e3 890static int set_config_network_link(const char *key, const char *value,
504a2217 891 struct lxc_conf *lxc_conf)
33c945e0
MT
892{
893 struct lxc_netdev *netdev;
504a2217 894 struct lxc_list *it;
576400e5 895 int ret = 0;
33c945e0 896
16950ecb 897 netdev = network_netdev(key, value, &lxc_conf->network);
33c945e0 898 if (!netdev)
c2cc9f0a 899 return -1;
c2cc9f0a 900
576400e5 901 if (value[strlen(value) - 1] == '+' && netdev->type == LXC_NET_PHYS) {
504a2217 902 /* Get the last network list and remove it. */
576400e5 903 it = lxc_conf->network.prev;
904 if (((struct lxc_netdev *)(it->elem))->type != LXC_NET_PHYS) {
504a2217
CB
905 ERROR("lxc config cannot support string pattern "
906 "matching for this link type");
576400e5 907 return -1;
908 }
909
910 lxc_list_del(it);
911 free(it);
912 ret = create_matched_ifnames(value, lxc_conf);
576400e5 913 } else {
914 ret = network_ifname(&netdev->link, value);
915 }
916
917 return ret;
c2cc9f0a 918}
919
713046e3 920static int set_config_network_name(const char *key, const char *value,
504a2217 921 struct lxc_conf *lxc_conf)
c2cc9f0a 922{
c2cc9f0a 923 struct lxc_netdev *netdev;
924
16950ecb 925 netdev = network_netdev(key, value, &lxc_conf->network);
33c945e0 926 if (!netdev)
c2cc9f0a 927 return -1;
c2cc9f0a 928
33c945e0
MT
929 return network_ifname(&netdev->name, value);
930}
931
713046e3 932static int set_config_network_veth_pair(const char *key, const char *value,
504a2217 933 struct lxc_conf *lxc_conf)
e892973e
DL
934{
935 struct lxc_netdev *netdev;
936
937 netdev = network_netdev(key, value, &lxc_conf->network);
938 if (!netdev)
939 return -1;
940
c5316d60 941 if (netdev->type != LXC_NET_VETH) {
128d327a 942 ERROR("Invalid veth pair for a non-veth netdev");
c5316d60
SH
943 return -1;
944 }
504a2217 945
e892973e
DL
946 return network_ifname(&netdev->priv.veth_attr.pair, value);
947}
948
713046e3 949static int set_config_network_macvlan_mode(const char *key, const char *value,
504a2217 950 struct lxc_conf *lxc_conf)
8634bc19
MT
951{
952 struct lxc_netdev *netdev;
953
954 netdev = network_netdev(key, value, &lxc_conf->network);
955 if (!netdev)
956 return -1;
957
c5316d60 958 if (netdev->type != LXC_NET_MACVLAN) {
128d327a 959 ERROR("Invalid macvlan.mode for a non-macvlan netdev");
c5316d60
SH
960 return -1;
961 }
504a2217 962
e892973e 963 return macvlan_mode(&netdev->priv.macvlan_attr.mode, value);
8634bc19
MT
964}
965
713046e3 966static int set_config_network_hwaddr(const char *key, const char *value,
504a2217 967 struct lxc_conf *lxc_conf)
33c945e0
MT
968{
969 struct lxc_netdev *netdev;
504a2217 970 char *new_value;
33c945e0 971
504a2217 972 new_value = strdup(value);
508c263e 973 if (!new_value) {
504a2217 974 SYSERROR("failed to strdup \"%s\"", value);
c2cc9f0a 975 return -1;
508c263e
SH
976 }
977 rand_complete_hwaddr(new_value);
c2cc9f0a 978
508c263e
SH
979 netdev = network_netdev(key, new_value, &lxc_conf->network);
980 if (!netdev) {
981 free(new_value);
982 return -1;
983 };
984
663e9916 985 if (lxc_config_value_empty(new_value)) {
508c263e
SH
986 free(new_value);
987 netdev->hwaddr = NULL;
988 return 0;
989 }
990
991 netdev->hwaddr = new_value;
992 return 0;
c2cc9f0a 993}
994
713046e3 995static int set_config_network_vlan_id(const char *key, const char *value,
504a2217 996 struct lxc_conf *lxc_conf)
26c39028
JHS
997{
998 struct lxc_netdev *netdev;
999
1000 netdev = network_netdev(key, value, &lxc_conf->network);
1001 if (!netdev)
1002 return -1;
1003
c5316d60 1004 if (netdev->type != LXC_NET_VLAN) {
128d327a 1005 ERROR("Invalid vlan.id for a non-macvlan netdev");
c5316d60
SH
1006 return -1;
1007 }
504a2217 1008
f6cc1de1 1009 if (get_u16(&netdev->priv.vlan_attr.vid, value, 0))
26c39028
JHS
1010 return -1;
1011
1012 return 0;
1013}
1014
713046e3 1015static int set_config_network_mtu(const char *key, const char *value,
504a2217 1016 struct lxc_conf *lxc_conf)
442cbbe6 1017{
442cbbe6
TR
1018 struct lxc_netdev *netdev;
1019
16950ecb 1020 netdev = network_netdev(key, value, &lxc_conf->network);
33c945e0 1021 if (!netdev)
442cbbe6 1022 return -1;
442cbbe6 1023
713046e3 1024 return set_config_string_item(&netdev->mtu, value);
442cbbe6
TR
1025}
1026
713046e3 1027static int set_config_network_ipv4(const char *key, const char *value,
504a2217 1028 struct lxc_conf *lxc_conf)
c2cc9f0a 1029{
c2cc9f0a 1030 struct lxc_netdev *netdev;
33c945e0 1031 struct lxc_inetdev *inetdev;
c2cc9f0a 1032 struct lxc_list *list;
504a2217
CB
1033 char *cursor, *slash;
1034 char *addr = NULL, *bcast = NULL, *prefix = NULL;
c2cc9f0a 1035
663e9916 1036 if (lxc_config_value_empty(value))
6afd673f 1037 return clr_config_network_item(key, lxc_conf);
0797e123 1038
16950ecb 1039 netdev = network_netdev(key, value, &lxc_conf->network);
33c945e0 1040 if (!netdev)
c2cc9f0a 1041 return -1;
c2cc9f0a 1042
1043 inetdev = malloc(sizeof(*inetdev));
1044 if (!inetdev) {
36eb9bde 1045 SYSERROR("failed to allocate ipv4 address");
c2cc9f0a 1046 return -1;
1047 }
1048 memset(inetdev, 0, sizeof(*inetdev));
1049
1050 list = malloc(sizeof(*list));
1051 if (!list) {
36eb9bde 1052 SYSERROR("failed to allocate memory");
53719062 1053 free(inetdev);
c2cc9f0a 1054 return -1;
1055 }
1056
1057 lxc_list_init(list);
1058 list->elem = inetdev;
1059
956edc54
SG
1060 addr = strdup(value);
1061 if (!addr) {
1062 ERROR("no address specified");
53719062
SH
1063 free(inetdev);
1064 free(list);
956edc54
SG
1065 return -1;
1066 }
c2cc9f0a 1067
1068 cursor = strstr(addr, " ");
1069 if (cursor) {
1070 *cursor = '\0';
1071 bcast = cursor + 1;
1072 }
1073
1074 slash = strstr(addr, "/");
1075 if (slash) {
1076 *slash = '\0';
1077 prefix = slash + 1;
1078 }
1079
c2cc9f0a 1080 if (!inet_pton(AF_INET, addr, &inetdev->addr)) {
36eb9bde 1081 SYSERROR("invalid ipv4 address: %s", value);
53719062 1082 free(inetdev);
956edc54 1083 free(addr);
53719062 1084 free(list);
c2cc9f0a 1085 return -1;
1086 }
1087
0093bb8c
DL
1088 if (bcast && !inet_pton(AF_INET, bcast, &inetdev->bcast)) {
1089 SYSERROR("invalid ipv4 broadcast address: %s", value);
53719062
SH
1090 free(inetdev);
1091 free(list);
956edc54 1092 free(addr);
0093bb8c
DL
1093 return -1;
1094 }
c2cc9f0a 1095
504a2217 1096 /* No prefix specified, determine it from the network class. */
1c633398
CB
1097 if (prefix) {
1098 if (lxc_safe_uint(prefix, &inetdev->prefix) < 0)
1099 return -1;
1100 } else {
1101 inetdev->prefix = config_ip_prefix(&inetdev->addr);
1102 }
a059591e 1103
504a2217
CB
1104 /* If no broadcast address, let compute one from the
1105 * prefix and address.
0093bb8c
DL
1106 */
1107 if (!bcast) {
1b7d4743
DL
1108 inetdev->bcast.s_addr = inetdev->addr.s_addr;
1109 inetdev->bcast.s_addr |=
504a2217 1110 htonl(INADDR_BROADCAST >> inetdev->prefix);
0093bb8c 1111 }
c2cc9f0a 1112
8538f388 1113 lxc_list_add_tail(&netdev->ipv4, list);
c2cc9f0a 1114
956edc54 1115 free(addr);
c2cc9f0a 1116 return 0;
1117}
1118
713046e3 1119static int set_config_network_ipv4_gateway(const char *key, const char *value,
504a2217 1120 struct lxc_conf *lxc_conf)
f8fee0e2
MK
1121{
1122 struct lxc_netdev *netdev;
f8fee0e2
MK
1123
1124 netdev = network_netdev(key, value, &lxc_conf->network);
1125 if (!netdev)
1126 return -1;
1127
e088e926 1128 free(netdev->ipv4_gateway);
f8fee0e2 1129
663e9916 1130 if (lxc_config_value_empty(value)) {
e088e926
SG
1131 netdev->ipv4_gateway = NULL;
1132 } else if (!strcmp(value, "auto")) {
19a26f82
MK
1133 netdev->ipv4_gateway = NULL;
1134 netdev->ipv4_gateway_auto = true;
1135 } else {
e088e926
SG
1136 struct in_addr *gw;
1137
1138 gw = malloc(sizeof(*gw));
1139 if (!gw) {
1140 SYSERROR("failed to allocate ipv4 gateway address");
1141 return -1;
1142 }
1143
19a26f82
MK
1144 if (!inet_pton(AF_INET, value, gw)) {
1145 SYSERROR("invalid ipv4 gateway address: %s", value);
53719062 1146 free(gw);
19a26f82
MK
1147 return -1;
1148 }
1149
1150 netdev->ipv4_gateway = gw;
1151 netdev->ipv4_gateway_auto = false;
f8fee0e2
MK
1152 }
1153
f8fee0e2
MK
1154 return 0;
1155}
1156
713046e3 1157static int set_config_network_ipv6(const char *key, const char *value,
504a2217 1158 struct lxc_conf *lxc_conf)
c2cc9f0a 1159{
c2cc9f0a 1160 struct lxc_netdev *netdev;
1161 struct lxc_inet6dev *inet6dev;
1162 struct lxc_list *list;
504a2217 1163 char *slash, *valdup, *netmask;
c2cc9f0a 1164
663e9916 1165 if (lxc_config_value_empty(value))
6afd673f 1166 return clr_config_network_item(key, lxc_conf);
0797e123 1167
16950ecb 1168 netdev = network_netdev(key, value, &lxc_conf->network);
33c945e0 1169 if (!netdev)
c2cc9f0a 1170 return -1;
c2cc9f0a 1171
1172 inet6dev = malloc(sizeof(*inet6dev));
1173 if (!inet6dev) {
36eb9bde 1174 SYSERROR("failed to allocate ipv6 address");
c2cc9f0a 1175 return -1;
1176 }
1177 memset(inet6dev, 0, sizeof(*inet6dev));
1178
1179 list = malloc(sizeof(*list));
1180 if (!list) {
36eb9bde 1181 SYSERROR("failed to allocate memory");
28027320 1182 free(inet6dev);
c2cc9f0a 1183 return -1;
1184 }
1185
1186 lxc_list_init(list);
1187 list->elem = inet6dev;
1188
956edc54
SG
1189 valdup = strdup(value);
1190 if (!valdup) {
1191 ERROR("no address specified");
28027320
SH
1192 free(list);
1193 free(inet6dev);
956edc54
SG
1194 return -1;
1195 }
1196
a059591e 1197 inet6dev->prefix = 64;
12a50cc6 1198 slash = strstr(valdup, "/");
c2cc9f0a 1199 if (slash) {
1200 *slash = '\0';
1201 netmask = slash + 1;
1c633398
CB
1202 if (lxc_safe_uint(netmask, &inet6dev->prefix) < 0)
1203 return -1;
c2cc9f0a 1204 }
1205
5acccf95
SH
1206 if (!inet_pton(AF_INET6, valdup, &inet6dev->addr)) {
1207 SYSERROR("invalid ipv6 address: %s", valdup);
28027320
SH
1208 free(list);
1209 free(inet6dev);
956edc54 1210 free(valdup);
c2cc9f0a 1211 return -1;
1212 }
1213
8538f388 1214 lxc_list_add_tail(&netdev->ipv6, list);
c2cc9f0a 1215
956edc54 1216 free(valdup);
c2cc9f0a 1217 return 0;
1218}
1219
713046e3 1220static int set_config_network_ipv6_gateway(const char *key, const char *value,
504a2217 1221 struct lxc_conf *lxc_conf)
f8fee0e2
MK
1222{
1223 struct lxc_netdev *netdev;
f8fee0e2
MK
1224
1225 netdev = network_netdev(key, value, &lxc_conf->network);
1226 if (!netdev)
1227 return -1;
1228
e088e926 1229 free(netdev->ipv6_gateway);
f8fee0e2 1230
663e9916 1231 if (lxc_config_value_empty(value)) {
ffe34437 1232 netdev->ipv6_gateway = NULL;
e088e926 1233 } else if (!strcmp(value, "auto")) {
19a26f82
MK
1234 netdev->ipv6_gateway = NULL;
1235 netdev->ipv6_gateway_auto = true;
1236 } else {
8fb86a37
SH
1237 struct in6_addr *gw;
1238
bec695f3
DE
1239 gw = malloc(sizeof(*gw));
1240 if (!gw) {
1241 SYSERROR("failed to allocate ipv6 gateway address");
1242 return -1;
1243 }
1244
19a26f82
MK
1245 if (!inet_pton(AF_INET6, value, gw)) {
1246 SYSERROR("invalid ipv6 gateway address: %s", value);
28027320 1247 free(gw);
19a26f82
MK
1248 return -1;
1249 }
1250
1251 netdev->ipv6_gateway = gw;
1252 netdev->ipv6_gateway_auto = false;
f8fee0e2
MK
1253 }
1254
f8fee0e2
MK
1255 return 0;
1256}
1257
713046e3 1258static int set_config_network_script_up(const char *key, const char *value,
504a2217 1259 struct lxc_conf *lxc_conf)
e3b4c4c4
ST
1260{
1261 struct lxc_netdev *netdev;
1262
1263 netdev = network_netdev(key, value, &lxc_conf->network);
1264 if (!netdev)
504a2217 1265 return -1;
e3b4c4c4 1266
713046e3 1267 return set_config_string_item(&netdev->upscript, value);
8fc8295a
DE
1268}
1269
713046e3 1270static int set_config_network_script_down(const char *key, const char *value,
504a2217 1271 struct lxc_conf *lxc_conf)
8fc8295a
DE
1272{
1273 struct lxc_netdev *netdev;
1274
1275 netdev = network_netdev(key, value, &lxc_conf->network);
1276 if (!netdev)
504a2217 1277 return -1;
8fc8295a 1278
713046e3 1279 return set_config_string_item(&netdev->downscript, value);
e3b4c4c4
ST
1280}
1281
26ddeedd
SH
1282static int add_hook(struct lxc_conf *lxc_conf, int which, char *hook)
1283{
1284 struct lxc_list *hooklist;
1285
1286 hooklist = malloc(sizeof(*hooklist));
1287 if (!hooklist) {
1288 free(hook);
1289 return -1;
1290 }
504a2217 1291
26ddeedd
SH
1292 hooklist->elem = hook;
1293 lxc_list_add_tail(&lxc_conf->hooks[which], hooklist);
1294 return 0;
1295}
1296
713046e3 1297static int set_config_seccomp(const char *key, const char *value,
504a2217 1298 struct lxc_conf *lxc_conf)
8f2c3a70 1299{
713046e3 1300 return set_config_path_item(&lxc_conf->seccomp, value);
8f2c3a70
SH
1301}
1302
713046e3 1303static int set_config_init_cmd(const char *key, const char *value,
504a2217 1304 struct lxc_conf *lxc_conf)
67c660d0 1305{
713046e3 1306 return set_config_path_item(&lxc_conf->init_cmd, value);
67c660d0
SG
1307}
1308
713046e3 1309static int set_config_init_uid(const char *key, const char *value,
504a2217 1310 struct lxc_conf *lxc_conf)
72bb04e4 1311{
d1e5d636
CB
1312 unsigned int init_uid;
1313
2e7cde40 1314 /* Set config value to default. */
663e9916 1315 if (lxc_config_value_empty(value)) {
2e7cde40 1316 lxc_conf->init_uid = 0;
fee80911 1317 return 0;
2e7cde40 1318 }
fee80911 1319
2e7cde40 1320 /* Parse new config value. */
d1e5d636
CB
1321 if (lxc_safe_uint(value, &init_uid) < 0)
1322 return -1;
1323 lxc_conf->init_uid = init_uid;
1324
72bb04e4
PT
1325 return 0;
1326}
1327
713046e3 1328static int set_config_init_gid(const char *key, const char *value,
504a2217 1329 struct lxc_conf *lxc_conf)
72bb04e4 1330{
d1e5d636
CB
1331 unsigned int init_gid;
1332
2debb6e6 1333 /* Set config value to default. */
663e9916 1334 if (lxc_config_value_empty(value)) {
2debb6e6 1335 lxc_conf->init_gid = 0;
a757cc7d 1336 return 0;
2debb6e6 1337 }
a757cc7d 1338
2debb6e6 1339 /* Parse new config value. */
d1e5d636
CB
1340 if (lxc_safe_uint(value, &init_gid) < 0)
1341 return -1;
1342 lxc_conf->init_gid = init_gid;
1343
72bb04e4
PT
1344 return 0;
1345}
1346
466c2e93
CB
1347static int set_config_hooks(const char *key, const char *value,
1348 struct lxc_conf *lxc_conf)
26ddeedd 1349{
7d0eb87e 1350 char *copy;
72bb04e4 1351
663e9916 1352 if (lxc_config_value_empty(value))
7d0eb87e
SH
1353 return lxc_clear_hooks(lxc_conf, key);
1354
a182feae 1355 if (strcmp(key + 4, "hook") == 0) {
6b0d5538
SH
1356 ERROR("lxc.hook cannot take a value");
1357 return -1;
1358 }
7d0eb87e 1359 copy = strdup(value);
26ddeedd
SH
1360 if (!copy) {
1361 SYSERROR("failed to dup string '%s'", value);
1362 return -1;
1363 }
504a2217 1364
a182feae 1365 if (strcmp(key + 9, "pre-start") == 0)
26ddeedd 1366 return add_hook(lxc_conf, LXCHOOK_PRESTART, copy);
a182feae 1367 else if (strcmp(key + 9, "pre-mount") == 0)
5ea6163a 1368 return add_hook(lxc_conf, LXCHOOK_PREMOUNT, copy);
a182feae 1369 else if (strcmp(key + 9, "autodev") == 0)
f7bee6c6 1370 return add_hook(lxc_conf, LXCHOOK_AUTODEV, copy);
a182feae 1371 else if (strcmp(key + 9, "mount") == 0)
26ddeedd 1372 return add_hook(lxc_conf, LXCHOOK_MOUNT, copy);
a182feae 1373 else if (strcmp(key + 9, "start") == 0)
26ddeedd 1374 return add_hook(lxc_conf, LXCHOOK_START, copy);
a182feae 1375 else if (strcmp(key + 9, "stop") == 0)
52492063 1376 return add_hook(lxc_conf, LXCHOOK_STOP, copy);
a182feae 1377 else if (strcmp(key + 9, "post-stop") == 0)
26ddeedd 1378 return add_hook(lxc_conf, LXCHOOK_POSTSTOP, copy);
a182feae 1379 else if (strcmp(key + 9, "clone") == 0)
148e91f5 1380 return add_hook(lxc_conf, LXCHOOK_CLONE, copy);
a182feae 1381 else if (strcmp(key + 9, "destroy") == 0)
37cf711b 1382 return add_hook(lxc_conf, LXCHOOK_DESTROY, copy);
504a2217 1383
26ddeedd
SH
1384 SYSERROR("Unknown key: %s", key);
1385 free(copy);
1386 return -1;
1387}
1388
713046e3 1389static int set_config_personality(const char *key, const char *value,
504a2217 1390 struct lxc_conf *lxc_conf)
cccc74b5 1391{
525f0002 1392 signed long personality = lxc_config_parse_arch(value);
cccc74b5 1393
525f0002
CS
1394 if (personality >= 0)
1395 lxc_conf->personality = personality;
1396 else
1397 WARN("unsupported personality '%s'", value);
970ab589
DL
1398
1399 return 0;
cccc74b5
DL
1400}
1401
713046e3 1402static int set_config_pts(const char *key, const char *value,
504a2217 1403 struct lxc_conf *lxc_conf)
10db618d 1404{
ec200ce9 1405 /* Set config value to default. */
663e9916 1406 if (lxc_config_value_empty(value)) {
ec200ce9 1407 lxc_conf->pts = 0;
884a4580 1408 return 0;
ec200ce9 1409 }
884a4580 1410
ec200ce9 1411 /* Parse new config value. */
17919969
CB
1412 if (lxc_safe_uint(value, &lxc_conf->pts) < 0)
1413 return -1;
10db618d 1414
1415 return 0;
1416}
1417
a182feae
CB
1418/* We only need to check whether the first byte of the key after the lxc.start.
1419 * prefix matches our expectations since they fortunately all start with a
1420 * different letter. If anything was wrong with the key we would have already
1421 * noticed when the callback was called.
1422 */
713046e3 1423static int set_config_start(const char *key, const char *value,
504a2217 1424 struct lxc_conf *lxc_conf)
ee1e7aa0 1425{
ebb80f95
CB
1426 bool is_empty;
1427
663e9916 1428 is_empty = lxc_config_value_empty(value);
ebb80f95 1429
a182feae 1430 if (*(key + 10) == 'a') { /* lxc.start.auto */
ebb80f95
CB
1431 /* Set config value to default. */
1432 if (is_empty) {
1433 lxc_conf->start_auto = 0;
1434 return 0;
1435 }
61ff8fc8 1436
ebb80f95 1437 /* Parse new config value. */
3590152f
CB
1438 if (lxc_safe_uint(value, &lxc_conf->start_auto) < 0)
1439 return -1;
ebb80f95 1440
3590152f
CB
1441 if (lxc_conf->start_auto > 1)
1442 return -1;
ebb80f95 1443
ee1e7aa0 1444 return 0;
a182feae 1445 } else if (*(key + 10) == 'd') { /* lxc.start.delay */
ebb80f95
CB
1446 /* Set config value to default. */
1447 if (is_empty) {
1448 lxc_conf->start_delay = 0;
1449 return 0;
1450 }
1451
1452 /* Parse new config value. */
1453 return lxc_safe_uint(value, &lxc_conf->start_delay);
a182feae 1454 } else if (*(key + 10) == 'o') { /* lxc.start.order */
ebb80f95
CB
1455 /* Set config value to default. */
1456 if (is_empty) {
1457 lxc_conf->start_order = 0;
1458 return 0;
1459 }
1460
1461 /* Parse new config value. */
1462 return lxc_safe_int(value, &lxc_conf->start_order);
ee1e7aa0 1463 }
ebb80f95 1464
ee1e7aa0
SG
1465 SYSERROR("Unknown key: %s", key);
1466 return -1;
1467}
1468
713046e3 1469static int set_config_monitor(const char *key, const char *value,
504a2217 1470 struct lxc_conf *lxc_conf)
a8dfe4e0 1471{
4ad9cd26 1472 /* Set config value to default. */
663e9916 1473 if (lxc_config_value_empty(value)) {
4ad9cd26 1474 lxc_conf->monitor_unshare = 0;
a8dfe4e0
WB
1475 return 0;
1476 }
4ad9cd26
CB
1477
1478 /* Parse new config value. */
a182feae 1479 if (strcmp(key + 12, "unshare") == 0)
4ad9cd26
CB
1480 return lxc_safe_uint(value, &lxc_conf->monitor_unshare);
1481
a8dfe4e0
WB
1482 SYSERROR("Unknown key: %s", key);
1483 return -1;
1484}
1485
713046e3 1486static int set_config_group(const char *key, const char *value,
504a2217 1487 struct lxc_conf *lxc_conf)
ee1e7aa0
SG
1488{
1489 char *groups, *groupptr, *sptr, *token;
1490 struct lxc_list *grouplist;
1491 int ret = -1;
1492
663e9916 1493 if (lxc_config_value_empty(value))
ee1e7aa0
SG
1494 return lxc_clear_groups(lxc_conf);
1495
1496 groups = strdup(value);
1497 if (!groups) {
1498 SYSERROR("failed to dup '%s'", value);
1499 return -1;
1500 }
1501
504a2217
CB
1502 /* In case several groups are specified in a single line
1503 * split these groups in a single element for the list.
1504 */
1505 for (groupptr = groups;; groupptr = NULL) {
d028235d
SG
1506 token = strtok_r(groupptr, " \t", &sptr);
1507 if (!token) {
ee1e7aa0 1508 ret = 0;
d028235d 1509 break;
ee1e7aa0
SG
1510 }
1511
1512 grouplist = malloc(sizeof(*grouplist));
1513 if (!grouplist) {
1514 SYSERROR("failed to allocate groups list");
1515 break;
1516 }
1517
1518 grouplist->elem = strdup(token);
1519 if (!grouplist->elem) {
1520 SYSERROR("failed to dup '%s'", token);
1521 free(grouplist);
1522 break;
1523 }
1524
1525 lxc_list_add_tail(&lxc_conf->groups, grouplist);
d028235d 1526 }
ee1e7aa0
SG
1527
1528 free(groups);
ee1e7aa0
SG
1529 return ret;
1530}
1531
713046e3 1532static int set_config_environment(const char *key, const char *value,
504a2217 1533 struct lxc_conf *lxc_conf)
7c661726
MP
1534{
1535 struct lxc_list *list_item = NULL;
1536
663e9916 1537 if (lxc_config_value_empty(value))
ab799c0b
SG
1538 return lxc_clear_environment(lxc_conf);
1539
7c661726
MP
1540 list_item = malloc(sizeof(*list_item));
1541 if (!list_item)
504a2217 1542 goto on_error;
7c661726
MP
1543
1544 list_item->elem = strdup(value);
1545
1546 if (!list_item->elem)
504a2217 1547 goto on_error;
7c661726
MP
1548
1549 lxc_list_add_tail(&lxc_conf->environment, list_item);
1550
1551 return 0;
1552
504a2217 1553on_error:
f10fad2f 1554 free(list_item);
7c661726
MP
1555 return -1;
1556}
1557
713046e3 1558static int set_config_tty(const char *key, const char *value,
504a2217 1559 struct lxc_conf *lxc_conf)
b0a33c1e 1560{
cb508ee8 1561 /* Set config value to default. */
663e9916 1562 if (lxc_config_value_empty(value)) {
cb508ee8 1563 lxc_conf->tty = 0;
fb12b12a 1564 return 0;
cb508ee8 1565 }
fb12b12a 1566
cb508ee8
CB
1567 /* Parse new config value. */
1568 return lxc_safe_uint(value, &lxc_conf->tty);
b0a33c1e 1569}
1570
713046e3 1571static int set_config_ttydir(const char *key, const char *value,
504a2217 1572 struct lxc_conf *lxc_conf)
7c6ef2a2 1573{
504a2217
CB
1574 return set_config_string_item_max(&lxc_conf->ttydir, value,
1575 NAME_MAX + 1);
7c6ef2a2
SH
1576}
1577
713046e3 1578static int set_config_kmsg(const char *key, const char *value,
504a2217 1579 struct lxc_conf *lxc_conf)
7e0e1d94 1580{
3d6b7fdc 1581 /* Set config value to default. */
663e9916 1582 if (lxc_config_value_empty(value)) {
3d6b7fdc 1583 lxc_conf->kmsg = 0;
5767e9ba 1584 return 0;
3d6b7fdc 1585 }
5767e9ba 1586
3d6b7fdc 1587 /* Parse new config value. */
91863d36
CB
1588 if (lxc_safe_uint(value, &lxc_conf->kmsg) < 0)
1589 return -1;
7e0e1d94 1590
91863d36
CB
1591 if (lxc_conf->kmsg > 1)
1592 return -1;
7e0e1d94
AV
1593
1594 return 0;
1595}
1596
713046e3 1597static int set_config_lsm_aa_profile(const char *key, const char *value,
504a2217 1598 struct lxc_conf *lxc_conf)
e075f5d9 1599{
713046e3 1600 return set_config_string_item(&lxc_conf->lsm_aa_profile, value);
fe4de9a6
DE
1601}
1602
713046e3 1603static int set_config_lsm_aa_incomplete(const char *key, const char *value,
504a2217 1604 struct lxc_conf *lxc_conf)
7aff4f43 1605{
cccfa758 1606 /* Set config value to default. */
663e9916 1607 if (lxc_config_value_empty(value)) {
cccfa758 1608 lxc_conf->lsm_aa_allow_incomplete = 0;
a678e9fa 1609 return 0;
cccfa758 1610 }
a678e9fa 1611
cccfa758 1612 /* Parse new config value. */
a56e2df9
CB
1613 if (lxc_safe_uint(value, &lxc_conf->lsm_aa_allow_incomplete) < 0)
1614 return -1;
7aff4f43 1615
a56e2df9 1616 if (lxc_conf->lsm_aa_allow_incomplete > 1) {
cccfa758
CB
1617 ERROR("Wrong value for lxc.lsm_aa_allow_incomplete. Can only "
1618 "be set to 0 or 1");
a56e2df9
CB
1619 return -1;
1620 }
7aff4f43
SH
1621
1622 return 0;
1623}
1624
713046e3 1625static int set_config_lsm_se_context(const char *key, const char *value,
504a2217 1626 struct lxc_conf *lxc_conf)
fe4de9a6 1627{
713046e3 1628 return set_config_string_item(&lxc_conf->lsm_se_context, value);
e075f5d9 1629}
e075f5d9 1630
713046e3 1631static int set_config_logfile(const char *key, const char *value,
0d601acb 1632 struct lxc_conf *c)
4a85ce2a 1633{
6d03d92a
DE
1634 int ret;
1635
663e9916 1636 if (lxc_config_value_empty(value)) {
0d601acb
CB
1637 free(c->logfile);
1638 c->logfile = NULL;
1639 return 0;
1640 }
1641
1642 /* Store these values in the lxc_conf, and then try to set for actual
504a2217
CB
1643 * current logging.
1644 */
713046e3 1645 ret = set_config_path_item(&c->logfile, value);
6d03d92a 1646 if (ret == 0)
858377e4 1647 ret = lxc_log_set_file(&c->logfd, c->logfile);
6d03d92a 1648 return ret;
4a85ce2a
SH
1649}
1650
713046e3 1651static int set_config_loglevel(const char *key, const char *value,
504a2217 1652 struct lxc_conf *lxc_conf)
4a85ce2a 1653{
9ea87d5d
SH
1654 int newlevel;
1655
575b9745 1656 /* Set config value to default. */
663e9916 1657 if (lxc_config_value_empty(value)) {
4b73005c 1658 lxc_conf->loglevel = LXC_LOG_LEVEL_NOTSET;
4a85ce2a 1659 return 0;
575b9745 1660 }
4a85ce2a 1661
575b9745 1662 /* Parse new config value. */
a56e2df9
CB
1663 if (value[0] >= '0' && value[0] <= '9') {
1664 if (lxc_safe_int(value, &newlevel) < 0)
1665 return -1;
1666 } else {
9ea87d5d 1667 newlevel = lxc_log_priority_to_int(value);
a56e2df9 1668 }
575b9745 1669
504a2217 1670 /* Store these values in the lxc_conf, and then try to set for actual
575b9745
CB
1671 * current logging.
1672 */
b40a606e 1673 lxc_conf->loglevel = newlevel;
858377e4 1674 return lxc_log_set_level(&lxc_conf->loglevel, newlevel);
4a85ce2a
SH
1675}
1676
713046e3 1677static int set_config_autodev(const char *key, const char *value,
504a2217 1678 struct lxc_conf *lxc_conf)
c6883f38 1679{
1045031e 1680 /* Set config value to default. */
663e9916 1681 if (lxc_config_value_empty(value)) {
1045031e 1682 lxc_conf->autodev = 0;
180abbc0 1683 return 0;
1045031e 1684 }
180abbc0 1685
1045031e 1686 /* Parse new config value. */
ff6cb4ed
CB
1687 if (lxc_safe_uint(value, &lxc_conf->autodev) < 0)
1688 return -1;
c6883f38 1689
ff6cb4ed
CB
1690 if (lxc_conf->autodev > 1) {
1691 ERROR("Wrong value for lxc.autodev. Can only be set to 0 or 1");
1692 return -1;
1693 }
c6883f38
SH
1694
1695 return 0;
1696}
1697
a84b9932
AV
1698static int sig_num(const char *sig)
1699{
f2e539b3 1700 unsigned int signum;
a84b9932 1701
f2e539b3 1702 if (lxc_safe_uint(sig, &signum) < 0)
a84b9932 1703 return -1;
f2e539b3
CB
1704
1705 return signum;
a84b9932
AV
1706}
1707
1708static int rt_sig_num(const char *signame)
1709{
504a2217 1710 int rtmax = 0, sig_n = 0;
a84b9932
AV
1711
1712 if (strncasecmp(signame, "max-", 4) == 0) {
1713 rtmax = 1;
1714 }
504a2217 1715
a84b9932
AV
1716 signame += 4;
1717 if (!isdigit(*signame))
1718 return -1;
504a2217 1719
a84b9932
AV
1720 sig_n = sig_num(signame);
1721 sig_n = rtmax ? SIGRTMAX - sig_n : SIGRTMIN + sig_n;
1722 if (sig_n > SIGRTMAX || sig_n < SIGRTMIN)
1723 return -1;
504a2217 1724
a84b9932
AV
1725 return sig_n;
1726}
1727
504a2217
CB
1728static int sig_parse(const char *signame)
1729{
84760c11 1730 size_t n;
a84b9932
AV
1731
1732 if (isdigit(*signame)) {
1733 return sig_num(signame);
1734 } else if (strncasecmp(signame, "sig", 3) == 0) {
1735 signame += 3;
1736 if (strncasecmp(signame, "rt", 2) == 0)
1737 return rt_sig_num(signame + 2);
1738 for (n = 0; n < sizeof(signames) / sizeof((signames)[0]); n++) {
504a2217 1739 if (strcasecmp(signames[n].name, signame) == 0)
a84b9932
AV
1740 return signames[n].num;
1741 }
1742 }
504a2217 1743
a84b9932
AV
1744 return -1;
1745}
1746
713046e3 1747static int set_config_haltsignal(const char *key, const char *value,
504a2217 1748 struct lxc_conf *lxc_conf)
f0f1d8c0 1749{
62a085fb 1750 int sig_n;
f0f1d8c0 1751
c1a64603 1752 /* Set config value to default. */
663e9916 1753 if (lxc_config_value_empty(value)) {
c1a64603 1754 lxc_conf->haltsignal = 0;
955912f0 1755 return 0;
c1a64603 1756 }
955912f0 1757
c1a64603 1758 /* Parse new config value. */
62a085fb
CB
1759 sig_n = sig_parse(value);
1760
f0f1d8c0
DE
1761 if (sig_n < 0)
1762 return -1;
1763 lxc_conf->haltsignal = sig_n;
1764
1765 return 0;
1766}
1767
713046e3 1768static int set_config_rebootsignal(const char *key, const char *value,
504a2217 1769 struct lxc_conf *lxc_conf)
dd267776 1770{
9d7e7587 1771 int sig_n;
dd267776 1772
18fcee44 1773 /* Set config value to default. */
663e9916 1774 if (lxc_config_value_empty(value)) {
18fcee44 1775 lxc_conf->rebootsignal = 0;
9d7e7587 1776 return 0;
18fcee44 1777 }
9d7e7587 1778
18fcee44 1779 /* Parse new config value. */
9d7e7587 1780 sig_n = sig_parse(value);
dd267776
BP
1781 if (sig_n < 0)
1782 return -1;
1783 lxc_conf->rebootsignal = sig_n;
1784
1785 return 0;
1786}
1787
713046e3 1788static int set_config_stopsignal(const char *key, const char *value,
504a2217 1789 struct lxc_conf *lxc_conf)
a84b9932 1790{
6ca6aedd 1791 int sig_n;
a84b9932 1792
4100d1a7 1793 /* Set config value to default. */
663e9916 1794 if (lxc_config_value_empty(value)) {
4100d1a7 1795 lxc_conf->stopsignal = 0;
6ca6aedd 1796 return 0;
4100d1a7 1797 }
6ca6aedd 1798
4100d1a7 1799 /* Parse new config value. */
6ca6aedd 1800 sig_n = sig_parse(value);
a84b9932
AV
1801 if (sig_n < 0)
1802 return -1;
1803 lxc_conf->stopsignal = sig_n;
1804
1805 return 0;
1806}
1807
713046e3 1808static int set_config_cgroup(const char *key, const char *value,
504a2217 1809 struct lxc_conf *lxc_conf)
576f946d 1810{
576f946d 1811 char *subkey;
504a2217 1812 char *token = "lxc.cgroup.";
bf83c5b9
MS
1813 struct lxc_list *cglist = NULL;
1814 struct lxc_cgroup *cgelem = NULL;
576f946d 1815
663e9916 1816 if (lxc_config_value_empty(value))
7d0eb87e
SH
1817 return lxc_clear_cgroups(lxc_conf, key);
1818
576f946d 1819 subkey = strstr(key, token);
576f946d 1820 if (!subkey)
1821 return -1;
1822
1823 if (!strlen(subkey))
1824 return -1;
1825
1826 if (strlen(subkey) == strlen(token))
1827 return -1;
a871ff6b 1828
576f946d 1829 subkey += strlen(token);
1830
1831 cglist = malloc(sizeof(*cglist));
1832 if (!cglist)
bf83c5b9 1833 goto out;
576f946d 1834
1835 cgelem = malloc(sizeof(*cgelem));
bf83c5b9
MS
1836 if (!cgelem)
1837 goto out;
1838 memset(cgelem, 0, sizeof(*cgelem));
576f946d 1839
1840 cgelem->subsystem = strdup(subkey);
1841 cgelem->value = strdup(value);
bf83c5b9
MS
1842
1843 if (!cgelem->subsystem || !cgelem->value)
1844 goto out;
1845
576f946d 1846 cglist->elem = cgelem;
1847
94d12f0a 1848 lxc_list_add_tail(&lxc_conf->cgroup, cglist);
576f946d 1849
1850 return 0;
bf83c5b9
MS
1851
1852out:
f10fad2f 1853 free(cglist);
bf83c5b9
MS
1854
1855 if (cgelem) {
f10fad2f 1856 free(cgelem->subsystem);
bf83c5b9 1857
f10fad2f 1858 free(cgelem->value);
bf83c5b9
MS
1859
1860 free(cgelem);
1861 }
1862
1863 return -1;
576f946d 1864}
1865
504a2217
CB
1866static bool parse_limit_value(const char **value, unsigned long *res)
1867{
c6d09e15
WB
1868 char *endptr = NULL;
1869
504a2217 1870 if (strncmp(*value, "unlimited", sizeof("unlimited") - 1) == 0) {
c6d09e15 1871 *res = RLIM_INFINITY;
504a2217 1872 *value += sizeof("unlimited") - 1;
c6d09e15
WB
1873 return true;
1874 }
1875
1876 errno = 0;
1877 *res = strtoul(*value, &endptr, 10);
1878 if (errno || !endptr)
1879 return false;
1880 *value = endptr;
1881
1882 return true;
1883}
1884
713046e3 1885static int set_config_limit(const char *key, const char *value,
504a2217 1886 struct lxc_conf *lxc_conf)
c6d09e15 1887{
c6d09e15
WB
1888 struct lxc_list *iter;
1889 struct rlimit limit;
1890 unsigned long limit_value;
504a2217
CB
1891 struct lxc_list *limlist = NULL;
1892 struct lxc_limit *limelem = NULL;
c6d09e15 1893
663e9916 1894 if (lxc_config_value_empty(value))
c6d09e15
WB
1895 return lxc_clear_limits(lxc_conf, key);
1896
504a2217 1897 if (strncmp(key, "lxc.limit.", sizeof("lxc.limit.") - 1) != 0)
c6d09e15
WB
1898 return -1;
1899
504a2217 1900 key += sizeof("lxc.limit.") - 1;
c6d09e15
WB
1901
1902 /* soft limit comes first in the value */
1903 if (!parse_limit_value(&value, &limit_value))
1904 return -1;
1905 limit.rlim_cur = limit_value;
1906
1907 /* skip spaces and a colon */
1908 while (isspace(*value))
1909 ++value;
504a2217 1910
c6d09e15
WB
1911 if (*value == ':')
1912 ++value;
1913 else if (*value) /* any other character is an error here */
1914 return -1;
504a2217 1915
c6d09e15
WB
1916 while (isspace(*value))
1917 ++value;
1918
1919 /* optional hard limit */
1920 if (*value) {
1921 if (!parse_limit_value(&value, &limit_value))
1922 return -1;
1923 limit.rlim_max = limit_value;
504a2217 1924
c6d09e15
WB
1925 /* check for trailing garbage */
1926 while (isspace(*value))
1927 ++value;
504a2217 1928
c6d09e15
WB
1929 if (*value)
1930 return -1;
1931 } else {
1932 /* a single value sets both hard and soft limit */
1933 limit.rlim_max = limit.rlim_cur;
1934 }
1935
1936 /* find existing list element */
504a2217
CB
1937 lxc_list_for_each(iter, &lxc_conf->limits)
1938 {
c6d09e15
WB
1939 limelem = iter->elem;
1940 if (!strcmp(key, limelem->resource)) {
1941 limelem->limit = limit;
1942 return 0;
1943 }
1944 }
1945
1946 /* allocate list element */
1947 limlist = malloc(sizeof(*limlist));
1948 if (!limlist)
1949 goto out;
2e6e3feb 1950
c6d09e15
WB
1951 limelem = malloc(sizeof(*limelem));
1952 if (!limelem)
1953 goto out;
1954 memset(limelem, 0, sizeof(*limelem));
1955
1956 limelem->resource = strdup(key);
1957 if (!limelem->resource)
1958 goto out;
1959 limelem->limit = limit;
1960
1961 limlist->elem = limelem;
1962
1963 lxc_list_add_tail(&lxc_conf->limits, limlist);
1964
1965 return 0;
1966
1967out:
1968 free(limlist);
1969 if (limelem) {
1970 free(limelem->resource);
1971 free(limelem);
1972 }
1973 return -1;
1974}
1975
5014ff2e
CB
1976static int set_config_idmaps(const char *key, const char *value,
1977 struct lxc_conf *lxc_conf)
f6d3e3e4 1978{
251d0d2a 1979 unsigned long hostid, nsid, range;
f6d3e3e4 1980 char type;
0b843d35 1981 int ret;
34a7a4c6
CB
1982 struct lxc_list *idmaplist = NULL;
1983 struct id_map *idmap = NULL;
f6d3e3e4 1984
663e9916 1985 if (lxc_config_value_empty(value))
7d0eb87e
SH
1986 return lxc_clear_idmaps(lxc_conf);
1987
f6d3e3e4
SH
1988 idmaplist = malloc(sizeof(*idmaplist));
1989 if (!idmaplist)
34a7a4c6 1990 goto on_error;
f6d3e3e4
SH
1991
1992 idmap = malloc(sizeof(*idmap));
1993 if (!idmap)
34a7a4c6 1994 goto on_error;
f6d3e3e4
SH
1995 memset(idmap, 0, sizeof(*idmap));
1996
0b843d35
CB
1997 ret = parse_idmaps(value, &type, &nsid, &hostid, &range);
1998 if (ret < 0)
34a7a4c6
CB
1999 goto on_error;
2000
251d0d2a 2001 INFO("read uid map: type %c nsid %lu hostid %lu range %lu", type, nsid, hostid, range);
ac7725e7 2002 if (type == 'u')
f6d3e3e4 2003 idmap->idtype = ID_TYPE_UID;
ac7725e7 2004 else if (type == 'g')
f6d3e3e4
SH
2005 idmap->idtype = ID_TYPE_GID;
2006 else
34a7a4c6 2007 goto on_error;
7e60c3f0 2008
f6d3e3e4
SH
2009 idmap->hostid = hostid;
2010 idmap->nsid = nsid;
2011 idmap->range = range;
7e60c3f0
SG
2012 idmaplist->elem = idmap;
2013 lxc_list_add_tail(&lxc_conf->id_map, idmaplist);
34a7a4c6 2014 idmap = NULL;
7e60c3f0 2015
f6d3e3e4
SH
2016 return 0;
2017
34a7a4c6 2018on_error:
f10fad2f 2019 free(idmaplist);
34a7a4c6 2020 free(idmap);
f6d3e3e4
SH
2021
2022 return -1;
2023}
2024
713046e3 2025static int set_config_fstab(const char *key, const char *value,
504a2217 2026 struct lxc_conf *lxc_conf)
d95db067 2027{
663e9916 2028 if (lxc_config_value_empty(value)) {
6afd673f 2029 clr_config_fstab(key, lxc_conf);
d9192f5d 2030 return -1;
46f3de30 2031 }
6f5685f0 2032
713046e3 2033 return set_config_path_item(&lxc_conf->fstab, value);
d95db067
DE
2034}
2035
713046e3 2036static int set_config_mount_auto(const char *key, const char *value,
504a2217 2037 struct lxc_conf *lxc_conf)
368bbc02
CS
2038{
2039 char *autos, *autoptr, *sptr, *token;
368bbc02
CS
2040 int i;
2041 int ret = -1;
504a2217
CB
2042 static struct {
2043 const char *token;
2044 int mask;
2045 int flag;
2046 } allowed_auto_mounts[] = {
2047 { "proc", LXC_AUTO_PROC_MASK, LXC_AUTO_PROC_MIXED },
2048 { "proc:mixed", LXC_AUTO_PROC_MASK, LXC_AUTO_PROC_MIXED },
2049 { "proc:rw", LXC_AUTO_PROC_MASK, LXC_AUTO_PROC_RW },
2050 { "sys", LXC_AUTO_SYS_MASK, LXC_AUTO_SYS_MIXED },
2051 { "sys:ro", LXC_AUTO_SYS_MASK, LXC_AUTO_SYS_RO },
2052 { "sys:mixed", LXC_AUTO_SYS_MASK, LXC_AUTO_SYS_MIXED },
2053 { "sys:rw", LXC_AUTO_SYS_MASK, LXC_AUTO_SYS_RW },
2054 { "cgroup", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_NOSPEC },
2055 { "cgroup:mixed", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_MIXED },
2056 { "cgroup:ro", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_RO },
2057 { "cgroup:rw", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_RW },
2058 { "cgroup-full", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_FULL_NOSPEC },
2059 { "cgroup-full:mixed", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_FULL_MIXED },
2060 { "cgroup-full:ro", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_FULL_RO },
2061 { "cgroup-full:rw", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_FULL_RW },
2062 /* NB: For adding anything that is just a single on/off, but has
2063 * no options: keep mask and flag identical and just define the
2064 * enum value as an unused bit so far
2065 */
2066 { NULL, 0, 0 }
2067 };
368bbc02 2068
663e9916 2069 if (lxc_config_value_empty(value)) {
d9192f5d
SH
2070 lxc_conf->auto_mounts = 0;
2071 return 0;
2072 }
368bbc02
CS
2073
2074 autos = strdup(value);
2075 if (!autos) {
2076 SYSERROR("failed to dup '%s'", value);
2077 return -1;
2078 }
2079
504a2217 2080 for (autoptr = autos;; autoptr = NULL) {
d028235d
SG
2081 token = strtok_r(autoptr, " \t", &sptr);
2082 if (!token) {
368bbc02 2083 ret = 0;
d028235d 2084 break;
368bbc02
CS
2085 }
2086
2087 for (i = 0; allowed_auto_mounts[i].token; i++) {
2088 if (!strcmp(allowed_auto_mounts[i].token, token))
2089 break;
2090 }
2091
2092 if (!allowed_auto_mounts[i].token) {
2093 ERROR("Invalid filesystem to automount: %s", token);
2094 break;
2095 }
2096
b06b8511 2097 lxc_conf->auto_mounts &= ~allowed_auto_mounts[i].mask;
368bbc02 2098 lxc_conf->auto_mounts |= allowed_auto_mounts[i].flag;
d028235d 2099 }
368bbc02
CS
2100
2101 free(autos);
368bbc02
CS
2102 return ret;
2103}
2104
713046e3 2105static int set_config_mount(const char *key, const char *value,
504a2217 2106 struct lxc_conf *lxc_conf)
e7938e9e 2107{
e7938e9e
MN
2108 char *mntelem;
2109 struct lxc_list *mntlist;
2110
663e9916 2111 if (lxc_config_value_empty(value))
d9192f5d 2112 return lxc_clear_mount_entries(lxc_conf);
e7938e9e
MN
2113
2114 mntlist = malloc(sizeof(*mntlist));
2115 if (!mntlist)
2116 return -1;
2117
2118 mntelem = strdup(value);
00b6be44
SH
2119 if (!mntelem) {
2120 free(mntlist);
bf83c5b9 2121 return -1;
00b6be44 2122 }
e7938e9e
MN
2123 mntlist->elem = mntelem;
2124
2125 lxc_list_add_tail(&lxc_conf->mount_list, mntlist);
2126
2127 return 0;
2128}
2129
713046e3 2130static int set_config_cap_keep(const char *key, const char *value,
504a2217 2131 struct lxc_conf *lxc_conf)
1fb86a7c
SH
2132{
2133 char *keepcaps, *keepptr, *sptr, *token;
2134 struct lxc_list *keeplist;
2135 int ret = -1;
2136
663e9916 2137 if (lxc_config_value_empty(value))
7d0eb87e 2138 return lxc_clear_config_keepcaps(lxc_conf);
1fb86a7c
SH
2139
2140 keepcaps = strdup(value);
2141 if (!keepcaps) {
2142 SYSERROR("failed to dup '%s'", value);
2143 return -1;
2144 }
2145
504a2217
CB
2146 /* In case several capability keep is specified in a single line
2147 * split these caps in a single element for the list.
2148 */
2149 for (keepptr = keepcaps;; keepptr = NULL) {
d028235d
SG
2150 token = strtok_r(keepptr, " \t", &sptr);
2151 if (!token) {
1fb86a7c 2152 ret = 0;
d028235d 2153 break;
1fb86a7c
SH
2154 }
2155
7035407c
DE
2156 if (!strcmp(token, "none"))
2157 lxc_clear_config_keepcaps(lxc_conf);
2158
1fb86a7c
SH
2159 keeplist = malloc(sizeof(*keeplist));
2160 if (!keeplist) {
2161 SYSERROR("failed to allocate keepcap list");
2162 break;
2163 }
2164
2165 keeplist->elem = strdup(token);
2166 if (!keeplist->elem) {
2167 SYSERROR("failed to dup '%s'", token);
2168 free(keeplist);
2169 break;
2170 }
2171
2172 lxc_list_add_tail(&lxc_conf->keepcaps, keeplist);
d028235d 2173 }
1fb86a7c
SH
2174
2175 free(keepcaps);
2176
2177 return ret;
2178}
2179
713046e3 2180static int set_config_cap_drop(const char *key, const char *value,
504a2217 2181 struct lxc_conf *lxc_conf)
81810dd1 2182{
d95db067 2183 char *dropcaps, *dropptr, *sptr, *token;
81810dd1
DL
2184 struct lxc_list *droplist;
2185 int ret = -1;
2186
663e9916 2187 if (lxc_config_value_empty(value))
7d0eb87e 2188 return lxc_clear_config_caps(lxc_conf);
81810dd1
DL
2189
2190 dropcaps = strdup(value);
2191 if (!dropcaps) {
2192 SYSERROR("failed to dup '%s'", value);
2193 return -1;
2194 }
2195
504a2217
CB
2196 /* In case several capability drop is specified in a single line
2197 * split these caps in a single element for the list.
2198 */
2199 for (dropptr = dropcaps;; dropptr = NULL) {
d028235d
SG
2200 token = strtok_r(dropptr, " \t", &sptr);
2201 if (!token) {
81810dd1 2202 ret = 0;
d028235d 2203 break;
81810dd1 2204 }
81810dd1
DL
2205
2206 droplist = malloc(sizeof(*droplist));
2207 if (!droplist) {
2208 SYSERROR("failed to allocate drop list");
2209 break;
2210 }
2211
2212 droplist->elem = strdup(token);
2213 if (!droplist->elem) {
2214 SYSERROR("failed to dup '%s'", token);
2215 free(droplist);
2216 break;
2217 }
2218
2219 lxc_list_add_tail(&lxc_conf->caps, droplist);
d028235d 2220 }
81810dd1
DL
2221
2222 free(dropcaps);
2223
2224 return ret;
2225}
2226
713046e3 2227static int set_config_console(const char *key, const char *value,
504a2217 2228 struct lxc_conf *lxc_conf)
28a4b0e5 2229{
713046e3 2230 return set_config_path_item(&lxc_conf->console.path, value);
28a4b0e5
DL
2231}
2232
713046e3 2233static int set_config_console_logfile(const char *key, const char *value,
504a2217 2234 struct lxc_conf *lxc_conf)
96f15ca1 2235{
713046e3 2236 return set_config_path_item(&lxc_conf->console.log_path, value);
96f15ca1
SH
2237}
2238
e6744e9b 2239/*
504a2217
CB
2240 * If we find a lxc.network.hwaddr in the original config file, we expand it in
2241 * the unexpanded_config, so that after a save_config we store the hwaddr for
2242 * re-use.
2243 * This is only called when reading the config file, not when executing a
2244 * lxc.include.
e6744e9b
SH
2245 * 'x' and 'X' are substituted in-place.
2246 */
2247static void update_hwaddr(const char *line)
2248{
2249 char *p;
2250
2251 line += lxc_char_left_gc(line, strlen(line));
2252 if (line[0] == '#')
2253 return;
504a2217 2254
e6744e9b
SH
2255 if (strncmp(line, "lxc.network.hwaddr", 18) != 0)
2256 return;
504a2217
CB
2257
2258 /* Let config_network_hwaddr raise the error. */
e6744e9b
SH
2259 p = strchr(line, '=');
2260 if (!p)
504a2217 2261 return;
e6744e9b 2262 p++;
504a2217 2263
e6744e9b
SH
2264 while (isblank(*p))
2265 p++;
504a2217 2266
e6744e9b
SH
2267 if (!*p)
2268 return;
2269
2270 rand_complete_hwaddr(p);
2271}
2272
6b0d5538 2273int append_unexp_config_line(const char *line, struct lxc_conf *conf)
f979ac15 2274{
6b0d5538 2275 size_t len = conf->unexpanded_len, linelen = strlen(line);
f979ac15 2276
e6744e9b
SH
2277 update_hwaddr(line);
2278
6b0d5538 2279 while (conf->unexpanded_alloced <= len + linelen + 2) {
504a2217
CB
2280 char *tmp = realloc(conf->unexpanded_config,
2281 conf->unexpanded_alloced + 1024);
6b0d5538
SH
2282 if (!tmp)
2283 return -1;
504a2217 2284
6b0d5538
SH
2285 if (!conf->unexpanded_config)
2286 *tmp = '\0';
2287 conf->unexpanded_config = tmp;
2288 conf->unexpanded_alloced += 1024;
2289 }
2290 strcat(conf->unexpanded_config, line);
2291 conf->unexpanded_len += linelen;
504a2217 2292 if (line[linelen - 1] != '\n') {
6b0d5538
SH
2293 strcat(conf->unexpanded_config, "\n");
2294 conf->unexpanded_len++;
f979ac15 2295 }
f979ac15
SH
2296 return 0;
2297}
2298
e1daebd9
SH
2299static int do_includedir(const char *dirp, struct lxc_conf *lxc_conf)
2300{
74f96976 2301 struct dirent *direntp;
e1daebd9
SH
2302 DIR *dir;
2303 char path[MAXPATHLEN];
504a2217
CB
2304 int len;
2305 int ret = -1;
e1daebd9
SH
2306
2307 dir = opendir(dirp);
2308 if (!dir) {
2309 SYSERROR("failed to open '%s'", dirp);
2310 return -1;
2311 }
2312
74f96976 2313 while ((direntp = readdir(dir))) {
e1daebd9
SH
2314 const char *fnam;
2315 if (!direntp)
2316 break;
2317
2318 fnam = direntp->d_name;
2319 if (!strcmp(fnam, "."))
2320 continue;
2321
2322 if (!strcmp(fnam, ".."))
2323 continue;
2324
2325 len = strlen(fnam);
504a2217 2326 if (len < 6 || strncmp(fnam + len - 5, ".conf", 5) != 0)
e1daebd9
SH
2327 continue;
2328 len = snprintf(path, MAXPATHLEN, "%s/%s", dirp, fnam);
2329 if (len < 0 || len >= MAXPATHLEN) {
2330 ERROR("lxc.include filename too long under '%s'", dirp);
2331 ret = -1;
2332 goto out;
2333 }
2334
2335 ret = lxc_config_read(path, lxc_conf, true);
2336 if (ret < 0)
2337 goto out;
2338 }
2339 ret = 0;
2340
2341out:
2342 if (closedir(dir))
2343 WARN("lxc.include dir: failed to close directory");
2344
2345 return ret;
2346}
2347
973082f5
CB
2348static int set_config_includefiles(const char *key, const char *value,
2349 struct lxc_conf *lxc_conf)
09ad6246 2350{
355c5701 2351 /* Set config value to default. */
663e9916 2352 if (lxc_config_value_empty(value)) {
6afd673f 2353 clr_config_includefiles(key, lxc_conf);
616422f1 2354 return 0;
355c5701 2355 }
616422f1 2356
355c5701 2357 /* Parse new config value. */
e1daebd9
SH
2358 if (is_dir(value))
2359 return do_includedir(value, lxc_conf);
2360
6b0d5538 2361 return lxc_config_read(value, lxc_conf, true);
09ad6246
SH
2362}
2363
713046e3 2364static int set_config_rootfs(const char *key, const char *value,
504a2217 2365 struct lxc_conf *lxc_conf)
c2cc9f0a 2366{
713046e3 2367 return set_config_path_item(&lxc_conf->rootfs.path, value);
c2cc9f0a 2368}
2369
713046e3 2370static int set_config_rootfs_mount(const char *key, const char *value,
504a2217 2371 struct lxc_conf *lxc_conf)
23b7ea69 2372{
713046e3 2373 return set_config_path_item(&lxc_conf->rootfs.mount, value);
23b7ea69
DL
2374}
2375
713046e3 2376static int set_config_rootfs_options(const char *key, const char *value,
504a2217 2377 struct lxc_conf *lxc_conf)
a17b1e65 2378{
713046e3 2379 return set_config_string_item(&lxc_conf->rootfs.options, value);
a17b1e65
SG
2380}
2381
713046e3 2382static int set_config_rootfs_backend(const char *key, const char *value,
504a2217 2383 struct lxc_conf *lxc_conf)
bfd77214 2384{
663e9916 2385 if (lxc_config_value_empty(value)) {
6a21d4ae
SH
2386 free(lxc_conf->rootfs.bdev_type);
2387 lxc_conf->rootfs.bdev_type = NULL;
b8223439 2388 return 0;
6a21d4ae 2389 }
b8223439 2390
bfd77214 2391 if (!is_valid_bdev_type(value)) {
327a1e78 2392 ERROR("Bad rootfs.backend: '%s'", value);
bfd77214
SH
2393 return -1;
2394 }
2395
713046e3 2396 return set_config_string_item(&lxc_conf->rootfs.bdev_type, value);
bfd77214
SH
2397}
2398
713046e3 2399static int set_config_pivotdir(const char *key, const char *value,
504a2217 2400 struct lxc_conf *lxc_conf)
bf601689 2401{
2d489f9e 2402 WARN("lxc.pivotdir is ignored. It will soon become an error.");
59bb8698 2403 return 0;
bf601689
MH
2404}
2405
713046e3 2406static int set_config_utsname(const char *key, const char *value,
504a2217 2407 struct lxc_conf *lxc_conf)
c2cc9f0a 2408{
2409 struct utsname *utsname;
2410
663e9916 2411 if (lxc_config_value_empty(value)) {
6afd673f 2412 clr_config_utsname(key, lxc_conf);
1939e73d 2413 return 0;
00cd8039 2414 }
1939e73d 2415
c2cc9f0a 2416 utsname = malloc(sizeof(*utsname));
2417 if (!utsname) {
36eb9bde 2418 SYSERROR("failed to allocate memory");
c2cc9f0a 2419 return -1;
2420 }
2421
2422 if (strlen(value) >= sizeof(utsname->nodename)) {
00cd8039 2423 ERROR("node name '%s' is too long", value);
b6f24d54 2424 free(utsname);
c2cc9f0a 2425 return -1;
2426 }
2427
2428 strcpy(utsname->nodename, value);
f10fad2f 2429 free(lxc_conf->utsname);
c2cc9f0a 2430 lxc_conf->utsname = utsname;
2431
2432 return 0;
2433}
2434
6b0d5538
SH
2435struct parse_line_conf {
2436 struct lxc_conf *conf;
2437 bool from_include;
2438};
4184c3e1 2439
7a7ff0c6 2440static int parse_line(char *buffer, void *data)
c2cc9f0a 2441{
72d0e1cb 2442 struct lxc_config_t *config;
504a2217 2443 char *dot, *key, *line, *linep, *value;
6b0d5538 2444 struct parse_line_conf *plc = data;
504a2217 2445 int ret = 0;
c2cc9f0a 2446
91480a0f 2447 if (lxc_is_line_empty(buffer))
c2cc9f0a 2448 return 0;
2449
81192358
DL
2450 /* we have to dup the buffer otherwise, at the re-exec for
2451 * reboot we modified the original string on the stack by
2452 * replacing '=' by '\0' below
91480a0f 2453 */
81192358 2454 linep = line = strdup(buffer);
91480a0f
DL
2455 if (!line) {
2456 SYSERROR("failed to allocate memory for '%s'", buffer);
81192358 2457 return -1;
91480a0f
DL
2458 }
2459
6b0d5538
SH
2460 if (!plc->from_include)
2461 if ((ret = append_unexp_config_line(line, plc->conf)))
2462 goto out;
2463
b2718c72 2464 line += lxc_char_left_gc(line, strlen(line));
476d4cf1 2465
4184c3e1
SH
2466 /* ignore comments */
2467 if (line[0] == '#')
91480a0f 2468 goto out;
476d4cf1 2469
6b0d5538
SH
2470 /* martian option - don't add it to the config itself */
2471 if (strncmp(line, "lxc.", 4))
4184c3e1 2472 goto out;
4184c3e1 2473
476d4cf1 2474 ret = -1;
c2cc9f0a 2475
b2718c72 2476 dot = strstr(line, "=");
c2cc9f0a 2477 if (!dot) {
36eb9bde 2478 ERROR("invalid configuration line: %s", line);
91480a0f 2479 goto out;
c2cc9f0a 2480 }
a871ff6b 2481
c2cc9f0a 2482 *dot = '\0';
2483 value = dot + 1;
2484
b2718c72 2485 key = line;
2486 key[lxc_char_right_gc(key, strlen(key))] = '\0';
c2cc9f0a 2487
b2718c72 2488 value += lxc_char_left_gc(value, strlen(value));
2489 value[lxc_char_right_gc(value, strlen(value))] = '\0';
c2cc9f0a 2490
bd878dee
SB
2491 if (*value == '\'' || *value == '\"') {
2492 size_t len = strlen(value);
504a2217
CB
2493 if (len > 1 && value[len - 1] == *value) {
2494 value[len - 1] = '\0';
bd878dee
SB
2495 value++;
2496 }
2497 }
2498
72d0e1cb 2499 config = lxc_getconfig(key);
c2cc9f0a 2500 if (!config) {
6e1d9b94 2501 ERROR("unknown key %s", key);
91480a0f 2502 goto out;
c2cc9f0a 2503 }
2504
d37f7cd7 2505 ret = config->set(key, value, plc->conf);
91480a0f
DL
2506
2507out:
81192358 2508 free(linep);
91480a0f 2509 return ret;
c2cc9f0a 2510}
2511
74a3920a 2512static int lxc_config_readline(char *buffer, struct lxc_conf *conf)
af5b0155 2513{
6b0d5538
SH
2514 struct parse_line_conf c;
2515
2516 c.conf = conf;
2517 c.from_include = false;
2518
2519 return parse_line(buffer, &c);
af5b0155
CLG
2520}
2521
6b0d5538 2522int lxc_config_read(const char *file, struct lxc_conf *conf, bool from_include)
c2cc9f0a 2523{
6b0d5538
SH
2524 struct parse_line_conf c;
2525
2526 c.conf = conf;
2527 c.from_include = from_include;
f979ac15 2528
504a2217 2529 if (access(file, R_OK) == -1) {
f3ca99fd
SH
2530 return -1;
2531 }
6b0d5538 2532
f7bee6c6 2533 /* Catch only the top level config file name in the structure */
504a2217 2534 if (!conf->rcfile)
76d0127f 2535 conf->rcfile = strdup(file);
f979ac15 2536
6b0d5538 2537 return lxc_file_for_each_line(file, parse_line, &c);
c2cc9f0a 2538}
62e46035 2539
504a2217 2540int lxc_config_define_add(struct lxc_list *defines, char *arg)
62e46035
CLG
2541{
2542 struct lxc_list *dent;
2543
2544 dent = malloc(sizeof(struct lxc_list));
2545 if (!dent)
2546 return -1;
2547
2548 dent->elem = arg;
2549 lxc_list_add_tail(defines, dent);
2550 return 0;
2551}
2552
226a18d6 2553int lxc_config_define_load(struct lxc_list *defines, struct lxc_conf *conf)
62e46035 2554{
504a2217 2555 struct lxc_list *it, *next;
62e46035
CLG
2556 int ret = 0;
2557
2558 lxc_list_for_each(it, defines) {
2559 ret = lxc_config_readline(it->elem, conf);
2560 if (ret)
2561 break;
2562 }
2563
9ebb03ad 2564 lxc_list_for_each_safe(it, defines, next) {
62e46035
CLG
2565 lxc_list_del(it);
2566 free(it);
2567 }
2568
2569 return ret;
2570}
525f0002
CS
2571
2572signed long lxc_config_parse_arch(const char *arch)
2573{
504a2217
CB
2574#if HAVE_SYS_PERSONALITY_H
2575 size_t i;
525f0002
CS
2576 struct per_name {
2577 char *name;
2578 unsigned long per;
bb8d8207 2579 } pername[] = {
504a2217
CB
2580 { "x86", PER_LINUX32 },
2581 { "linux32", PER_LINUX32 },
2582 { "i386", PER_LINUX32 },
2583 { "i486", PER_LINUX32 },
2584 { "i586", PER_LINUX32 },
2585 { "i686", PER_LINUX32 },
2586 { "athlon", PER_LINUX32 },
2587 { "mips", PER_LINUX32 },
2588 { "mipsel", PER_LINUX32 },
2589 { "ppc", PER_LINUX32 },
2590 { "arm", PER_LINUX32 },
2591 { "armv7l", PER_LINUX32 },
2592 { "armhf", PER_LINUX32 },
2593 { "armel", PER_LINUX32 },
2594 { "powerpc", PER_LINUX32 },
2595 { "linux64", PER_LINUX },
2596 { "x86_64", PER_LINUX },
2597 { "amd64", PER_LINUX },
2598 { "mips64", PER_LINUX },
2599 { "mips64el", PER_LINUX },
2600 { "ppc64", PER_LINUX },
2601 { "ppc64le", PER_LINUX },
2602 { "ppc64el", PER_LINUX },
2603 { "powerpc64", PER_LINUX },
2604 { "s390x", PER_LINUX },
2605 { "aarch64", PER_LINUX },
2606 { "arm64", PER_LINUX },
525f0002
CS
2607 };
2608 size_t len = sizeof(pername) / sizeof(pername[0]);
2609
525f0002
CS
2610 for (i = 0; i < len; i++) {
2611 if (!strcmp(pername[i].name, arch))
504a2217 2612 return pername[i].per;
525f0002 2613 }
504a2217 2614#endif
525f0002
CS
2615
2616 return -1;
2617}
72d0e1cb 2618
4d69b293
NK
2619int lxc_fill_elevated_privileges(char *flaglist, int *flags)
2620{
2621 char *token, *saveptr = NULL;
2622 int i, aflag;
504a2217
CB
2623 struct {
2624 const char *token;
2625 int flag;
2626 } all_privs[] = {
2627 { "CGROUP", LXC_ATTACH_MOVE_TO_CGROUP },
2628 { "CAP", LXC_ATTACH_DROP_CAPABILITIES },
2629 { "LSM", LXC_ATTACH_LSM_EXEC },
2630 { NULL, 0 }
4d69b293
NK
2631 };
2632
2633 if (!flaglist) {
504a2217
CB
2634 /* For the sake of backward compatibility, drop all privileges
2635 * if none is specified.
2636 */
4d69b293 2637 for (i = 0; all_privs[i].token; i++) {
d028235d 2638 *flags |= all_privs[i].flag;
4d69b293
NK
2639 }
2640 return 0;
2641 }
2642
2643 token = strtok_r(flaglist, "|", &saveptr);
2644 while (token) {
2645 aflag = -1;
2646 for (i = 0; all_privs[i].token; i++) {
2647 if (!strcmp(all_privs[i].token, token))
2648 aflag = all_privs[i].flag;
2649 }
2650 if (aflag < 0)
2651 return -1;
2652
2653 *flags |= aflag;
2654
2655 token = strtok_r(NULL, "|", &saveptr);
2656 }
504a2217 2657
4d69b293
NK
2658 return 0;
2659}
2660
bdf91ab4
CB
2661static inline int lxc_get_conf_int(struct lxc_conf *c, char *retv, int inlen,
2662 int v)
72d0e1cb
SG
2663{
2664 if (!retv)
2665 inlen = 0;
2666 else
2667 memset(retv, 0, inlen);
bdf91ab4 2668
72d0e1cb
SG
2669 return snprintf(retv, inlen, "%d", v);
2670}
2671
504a2217 2672/* Write out a configuration file. */
72d0e1cb
SG
2673void write_config(FILE *fout, struct lxc_conf *c)
2674{
6b0d5538 2675 int ret;
504a2217 2676 size_t len = c->unexpanded_len;
72d0e1cb 2677
6b0d5538
SH
2678 if (!len)
2679 return;
504a2217 2680
6b0d5538
SH
2681 ret = fwrite(c->unexpanded_config, 1, len, fout);
2682 if (ret != len)
2683 SYSERROR("Error writing configuration file");
2684}
f979ac15 2685
504a2217
CB
2686bool do_append_unexp_config_line(struct lxc_conf *conf, const char *key,
2687 const char *v)
6b0d5538
SH
2688{
2689 int ret;
151d2da2
CB
2690 size_t len;
2691 char *tmp;
4184c3e1 2692
151d2da2
CB
2693 len = strlen(key) + strlen(v) + 4;
2694 tmp = alloca(len);
2695
663e9916 2696 if (lxc_config_value_empty(v))
151d2da2
CB
2697 ret = snprintf(tmp, len, "%s =", key);
2698 else
2699 ret = snprintf(tmp, len, "%s = %s", key, v);
6b0d5538
SH
2700 if (ret < 0 || ret >= len)
2701 return false;
2702
2703 /* Save the line verbatim into unexpanded_conf */
2704 if (append_unexp_config_line(tmp, conf))
2705 return false;
2706
2707 return true;
2708}
2709
504a2217
CB
2710void clear_unexp_config_line(struct lxc_conf *conf, const char *key,
2711 bool rm_subkeys)
6b0d5538 2712{
504a2217
CB
2713 char *lend;
2714 char *lstart = conf->unexpanded_config;
6b0d5538
SH
2715
2716 if (!conf->unexpanded_config)
2717 return;
504a2217 2718
6b0d5538
SH
2719 while (*lstart) {
2720 lend = strchr(lstart, '\n');
2721 char v;
2722 if (!lend)
2723 lend = lstart + strlen(lstart);
2724 else
2725 lend++;
2726 if (strncmp(lstart, key, strlen(key)) != 0) {
2727 lstart = lend;
2728 continue;
5f62730e 2729 }
6b0d5538
SH
2730 if (!rm_subkeys) {
2731 v = lstart[strlen(key)];
2732 if (!isspace(v) && v != '=') {
2733 lstart = lend;
2734 continue;
2735 }
5f62730e 2736 }
6b0d5538
SH
2737 conf->unexpanded_len -= (lend - lstart);
2738 if (*lend == '\0') {
2739 *lstart = '\0';
2740 return;
fd986e08 2741 }
504a2217 2742 memmove(lstart, lend, strlen(lend) + 1);
fd986e08 2743 }
6b0d5538
SH
2744}
2745
329b3625
CB
2746bool clone_update_unexp_ovl_paths(struct lxc_conf *conf, const char *oldpath,
2747 const char *newpath, const char *oldname,
2748 const char *newname, const char *ovldir)
2749{
329b3625 2750 int ret;
504a2217
CB
2751 char *lend, *newdir, *olddir, *p, *q;
2752 size_t newdirlen, olddirlen;
329b3625 2753 char *lstart = conf->unexpanded_config;
504a2217 2754 const char *key = "lxc.mount.entry";
329b3625 2755
504a2217
CB
2756 olddirlen = strlen(ovldir) + strlen(oldpath) + strlen(oldname) + 2;
2757 olddir = alloca(olddirlen + 1);
2758 ret = snprintf(olddir, olddirlen + 1, "%s=%s/%s", ovldir, oldpath,
2759 oldname);
329b3625 2760 if (ret < 0 || ret >= olddirlen + 1) {
504a2217 2761 ERROR("failed to create string");
329b3625
CB
2762 return false;
2763 }
504a2217
CB
2764
2765 newdirlen = strlen(ovldir) + strlen(newpath) + strlen(newname) + 2;
2766 newdir = alloca(newdirlen + 1);
2767 ret = snprintf(newdir, newdirlen + 1, "%s=%s/%s", ovldir, newpath,
2768 newname);
329b3625 2769 if (ret < 0 || ret >= newdirlen + 1) {
504a2217 2770 ERROR("failed to create string");
329b3625
CB
2771 return false;
2772 }
504a2217 2773
329b3625
CB
2774 if (!conf->unexpanded_config)
2775 return true;
504a2217 2776
329b3625
CB
2777 while (*lstart) {
2778 lend = strchr(lstart, '\n');
2779 if (!lend)
2780 lend = lstart + strlen(lstart);
2781 else
2782 lend++;
504a2217 2783
329b3625 2784 if (strncmp(lstart, key, strlen(key)) != 0)
504a2217
CB
2785 goto next;
2786
329b3625
CB
2787 p = strchr(lstart + strlen(key), '=');
2788 if (!p)
504a2217 2789 goto next;
329b3625 2790 p++;
504a2217 2791
329b3625
CB
2792 while (isblank(*p))
2793 p++;
504a2217 2794
329b3625 2795 if (p >= lend)
504a2217
CB
2796 goto next;
2797
2798 /* Whenever an lxc.mount.entry entry is found in a line we check
2799 * if the substring " overlay" or the substring " aufs" is
2800 * present before doing any further work. We check for "
2801 * overlay" and " aufs" since both substrings need to have at
2802 * least one space before them in a valid overlay
2803 * lxc.mount.entry (/A B overlay). When the space before is
2804 * missing it is very likely that these substrings are part of a
2805 * path or something else. (Checking q >= lend ensures that we
2806 * only count matches in the current line.) */
2807 if ((!(q = strstr(p, " overlay")) || q >= lend) &&
2808 (!(q = strstr(p, " aufs")) || q >= lend))
2809 goto next;
2810
329b3625 2811 if (!(q = strstr(p, olddir)) || (q >= lend))
504a2217 2812 goto next;
329b3625
CB
2813
2814 /* replace the olddir with newdir */
2815 if (olddirlen >= newdirlen) {
2816 size_t diff = olddirlen - newdirlen;
2817 memcpy(q, newdir, newdirlen);
2818 if (olddirlen != newdirlen) {
2819 memmove(q + newdirlen, q + newdirlen + diff,
2820 strlen(q) - newdirlen - diff + 1);
2821 lend -= diff;
2822 conf->unexpanded_len -= diff;
2823 }
2824 } else {
2825 char *new;
2826 size_t diff = newdirlen - olddirlen;
2827 size_t oldlen = conf->unexpanded_len;
2828 size_t newlen = oldlen + diff;
2829 size_t poffset = q - conf->unexpanded_config;
504a2217 2830
329b3625
CB
2831 new = realloc(conf->unexpanded_config, newlen + 1);
2832 if (!new) {
2833 ERROR("Out of memory");
2834 return false;
2835 }
2836 conf->unexpanded_len = newlen;
2837 conf->unexpanded_alloced = newlen + 1;
2838 new[newlen - 1] = '\0';
2839 lend = new + (lend - conf->unexpanded_config);
504a2217
CB
2840 /* move over the remainder to make room for the newdir
2841 */
329b3625
CB
2842 memmove(new + poffset + newdirlen,
2843 new + poffset + olddirlen,
2844 oldlen - poffset - olddirlen + 1);
2845 conf->unexpanded_config = new;
2846 memcpy(new + poffset, newdir, newdirlen);
2847 lend += diff;
2848 }
504a2217
CB
2849 next:
2850 lstart = lend;
329b3625 2851 }
504a2217 2852
329b3625
CB
2853 return true;
2854}
2855
67702c21 2856bool clone_update_unexp_hooks(struct lxc_conf *conf, const char *oldpath,
d546aa0e
CB
2857 const char *newpath, const char *oldname,
2858 const char *newname)
6b0d5538 2859{
67702c21 2860 int ret;
504a2217
CB
2861 char *lend, *newdir, *olddir, *p;
2862 char *lstart = conf->unexpanded_config;
2863 size_t newdirlen, olddirlen;
2864 const char *key = "lxc.hook";
67702c21 2865
504a2217
CB
2866 olddirlen = strlen(oldpath) + strlen(oldname) + 1;
2867 olddir = alloca(olddirlen + 1);
d546aa0e
CB
2868 ret = snprintf(olddir, olddirlen + 1, "%s/%s", oldpath, oldname);
2869 if (ret < 0 || ret >= olddirlen + 1) {
504a2217 2870 ERROR("failed to create string");
67702c21
SH
2871 return false;
2872 }
504a2217
CB
2873
2874 newdirlen = strlen(newpath) + strlen(newname) + 1;
2875 newdir = alloca(newdirlen + 1);
d546aa0e
CB
2876 ret = snprintf(newdir, newdirlen + 1, "%s/%s", newpath, newname);
2877 if (ret < 0 || ret >= newdirlen + 1) {
504a2217 2878 ERROR("failed to create string");
67702c21
SH
2879 return false;
2880 }
2881 if (!conf->unexpanded_config)
2882 return true;
2883 while (*lstart) {
2884 lend = strchr(lstart, '\n');
2885 if (!lend)
2886 lend = lstart + strlen(lstart);
2887 else
2888 lend++;
504a2217 2889
d546aa0e 2890 if (strncmp(lstart, key, strlen(key)) != 0)
504a2217
CB
2891 goto next;
2892
d546aa0e
CB
2893 p = strchr(lstart + strlen(key), '=');
2894 if (!p)
504a2217 2895 goto next;
67702c21 2896 p++;
504a2217 2897
67702c21
SH
2898 while (isblank(*p))
2899 p++;
504a2217
CB
2900
2901 if (p >= lend)
2902 goto next;
2903
d546aa0e 2904 if (strncmp(p, olddir, strlen(olddir)) != 0)
504a2217
CB
2905 goto next;
2906
67702c21
SH
2907 /* replace the olddir with newdir */
2908 if (olddirlen >= newdirlen) {
2909 size_t diff = olddirlen - newdirlen;
2910 memcpy(p, newdir, newdirlen);
2911 if (olddirlen != newdirlen) {
d546aa0e
CB
2912 memmove(p + newdirlen, p + newdirlen + diff,
2913 strlen(p) - newdirlen - diff + 1);
67702c21
SH
2914 lend -= diff;
2915 conf->unexpanded_len -= diff;
2916 }
67702c21
SH
2917 } else {
2918 char *new;
2919 size_t diff = newdirlen - olddirlen;
2920 size_t oldlen = conf->unexpanded_len;
2921 size_t newlen = oldlen + diff;
2922 size_t poffset = p - conf->unexpanded_config;
504a2217 2923
d546aa0e 2924 new = realloc(conf->unexpanded_config, newlen + 1);
67702c21 2925 if (!new) {
504a2217 2926 ERROR("failed to allocate memory");
6b0d5538 2927 return false;
67702c21
SH
2928 }
2929 conf->unexpanded_len = newlen;
d546aa0e
CB
2930 conf->unexpanded_alloced = newlen + 1;
2931 new[newlen - 1] = '\0';
67702c21 2932 lend = new + (lend - conf->unexpanded_config);
504a2217
CB
2933 /* move over the remainder to make room for the newdir
2934 */
d546aa0e
CB
2935 memmove(new + poffset + newdirlen,
2936 new + poffset + olddirlen,
2937 oldlen - poffset - olddirlen + 1);
67702c21 2938 conf->unexpanded_config = new;
d546aa0e
CB
2939 memcpy(new + poffset, newdir, newdirlen);
2940 lend += diff;
fd986e08 2941 }
504a2217
CB
2942 next:
2943 lstart = lend;
fd986e08 2944 }
504a2217 2945
6b0d5538
SH
2946 return true;
2947}
2948
504a2217
CB
2949#define DO(cmd) \
2950 { \
2951 if (!(cmd)) { \
2952 ERROR("Error writing to new config"); \
2953 return false; \
2954 } \
2955 }
6b0d5538 2956
091045f8 2957static bool new_hwaddr(char *hwaddr)
67702c21 2958{
091045f8
CB
2959 int ret;
2960
091045f8
CB
2961 (void)randseed(true);
2962
2963 ret = snprintf(hwaddr, 18, "00:16:3e:%02x:%02x:%02x", rand() % 255,
2964 rand() % 255, rand() % 255);
2965 if (ret < 0 || ret >= 18) {
2966 SYSERROR("Failed to call snprintf().");
2967 return false;
2968 }
2969
2970 return true;
67702c21
SH
2971}
2972
2973/*
504a2217
CB
2974 * This is called only from clone. We wish to update all hwaddrs in the
2975 * unexpanded config file. We can't/don't want to update any which come from
2976 * lxc.includes (there shouldn't be any).
2977 * We can't just walk the c->lxc-conf->network list because that includes netifs
2978 * from the include files. So we update the ones which we find in the unexp
2979 * config file, then find the original macaddr in the conf->network, and update
2980 * that to the same value.
67702c21
SH
2981 */
2982bool network_new_hwaddrs(struct lxc_conf *conf)
6b0d5538 2983{
504a2217 2984 char *lend, *p, *p2;
6b0d5538 2985 struct lxc_list *it;
67702c21 2986 const char *key = "lxc.network.hwaddr";
504a2217 2987 char *lstart = conf->unexpanded_config;
6b0d5538 2988
67702c21
SH
2989 if (!conf->unexpanded_config)
2990 return true;
091045f8 2991
67702c21
SH
2992 while (*lstart) {
2993 char newhwaddr[18], oldhwaddr[17];
091045f8 2994
67702c21
SH
2995 lend = strchr(lstart, '\n');
2996 if (!lend)
2997 lend = lstart + strlen(lstart);
2998 else
2999 lend++;
091045f8 3000
67702c21
SH
3001 if (strncmp(lstart, key, strlen(key)) != 0) {
3002 lstart = lend;
3003 continue;
72d0e1cb 3004 }
091045f8 3005
504a2217 3006 p = strchr(lstart + strlen(key), '=');
67702c21
SH
3007 if (!p) {
3008 lstart = lend;
3009 continue;
72d0e1cb 3010 }
091045f8 3011
67702c21
SH
3012 p++;
3013 while (isblank(*p))
3014 p++;
3015 if (!*p)
3016 return true;
091045f8 3017
67702c21
SH
3018 p2 = p;
3019 while (*p2 && !isblank(*p2) && *p2 != '\n')
3020 p2++;
504a2217
CB
3021
3022 if ((p2 - p) != 17) {
67702c21
SH
3023 WARN("Bad hwaddr entry");
3024 lstart = lend;
3025 continue;
72d0e1cb 3026 }
091045f8 3027
67702c21 3028 memcpy(oldhwaddr, p, 17);
091045f8
CB
3029
3030 if (!new_hwaddr(newhwaddr))
3031 return false;
3032
67702c21 3033 memcpy(p, newhwaddr, 17);
504a2217
CB
3034 lxc_list_for_each(it, &conf->network)
3035 {
67702c21
SH
3036 struct lxc_netdev *n = it->elem;
3037 if (n->hwaddr && memcmp(oldhwaddr, n->hwaddr, 17) == 0)
3038 memcpy(n->hwaddr, newhwaddr, 17);
72d0e1cb 3039 }
67702c21
SH
3040
3041 lstart = lend;
72d0e1cb 3042 }
091045f8 3043
6b0d5538 3044 return true;
72d0e1cb 3045}
8796becf 3046
713046e3 3047static int set_config_ephemeral(const char *key, const char *value,
504a2217 3048 struct lxc_conf *lxc_conf)
8796becf 3049{
3c6cf53a 3050 /* Set config value to default. */
663e9916 3051 if (lxc_config_value_empty(value)) {
3c6cf53a 3052 lxc_conf->ephemeral = 0;
78304622 3053 return 0;
3c6cf53a 3054 }
78304622 3055
3c6cf53a 3056 /* Parse new config value. */
66ffdb1a
CB
3057 if (lxc_safe_uint(value, &lxc_conf->ephemeral) < 0)
3058 return -1;
8796becf 3059
66ffdb1a 3060 if (lxc_conf->ephemeral > 1) {
504a2217
CB
3061 ERROR(
3062 "Wrong value for lxc.ephemeral. Can only be set to 0 or 1");
8796becf 3063 return -1;
8796becf
CB
3064 }
3065
3066 return 0;
3067}
3068
713046e3 3069static int set_config_syslog(const char *key, const char *value,
504a2217 3070 struct lxc_conf *lxc_conf)
64c57ea1 3071{
76d0127f 3072 int facility;
7ca56b84 3073
ee10a69c
CB
3074 /* Clear any previously set value. */
3075 if (lxc_conf->syslog) {
3076 free(lxc_conf->syslog);
3077 lxc_conf->syslog = NULL;
3078 }
3079
3080 /* Check if value is empty. */
663e9916 3081 if (lxc_config_value_empty(value))
7ca56b84
CB
3082 return 0;
3083
ee10a69c 3084 /* Parse value. */
76d0127f
CB
3085 facility = lxc_syslog_priority_to_int(value);
3086 if (facility == -EINVAL) {
d47f1b43 3087 ERROR("Wrong value for lxc.syslog.");
76d0127f 3088 return -1;
64c57ea1
BD
3089 }
3090
76d0127f 3091 lxc_log_syslog(facility);
713046e3 3092 return set_config_string_item(&lxc_conf->syslog, value);
64c57ea1 3093}
5a46f283 3094
713046e3 3095static int set_config_no_new_privs(const char *key, const char *value,
504a2217 3096 struct lxc_conf *lxc_conf)
5a46f283 3097{
e8ec7c9e 3098 unsigned int v;
5a46f283 3099
cf3f8bf6 3100 /* Set config value to default. */
663e9916 3101 if (lxc_config_value_empty(value)) {
cf3f8bf6 3102 lxc_conf->no_new_privs = false;
80926845 3103 return 0;
cf3f8bf6 3104 }
80926845 3105
cf3f8bf6 3106 /* Parse new config value. */
e8ec7c9e
CB
3107 if (lxc_safe_uint(value, &v) < 0)
3108 return -1;
3109
3110 if (v > 1) {
504a2217
CB
3111 ERROR("Wrong value for lxc.no_new_privs. Can only be set to 0 "
3112 "or 1");
5a46f283
CB
3113 return -1;
3114 }
e8ec7c9e 3115
5a46f283
CB
3116 lxc_conf->no_new_privs = v ? true : false;
3117
3118 return 0;
3119}
7b992a3e
CB
3120
3121/* Callbacks to get configuration items. */
6bede808
CB
3122static int get_config_personality(const char *key, char *retv, int inlen,
3123 struct lxc_conf *c)
7b992a3e
CB
3124{
3125 int fulllen = 0;
3126
3127 if (!retv)
3128 inlen = 0;
3129 else
3130 memset(retv, 0, inlen);
3131
3132#if HAVE_SYS_PERSONALITY_H
3133 int len = 0;
3134
6bede808 3135 switch (c->personality) {
7b992a3e
CB
3136 case PER_LINUX32:
3137 strprint(retv, inlen, "i686");
3138 break;
3139 case PER_LINUX:
3140 strprint(retv, inlen, "x86_64");
3141 break;
3142 default:
3143 break;
3144 }
3145#endif
3146
3147 return fulllen;
3148}
bdf91ab4 3149
6bede808
CB
3150static int get_config_pts(const char *key, char *retv, int inlen,
3151 struct lxc_conf *c)
bdf91ab4 3152{
6bede808 3153 return lxc_get_conf_int(c, retv, inlen, c->pts);
bdf91ab4 3154}
5485782f 3155
6bede808
CB
3156static int get_config_tty(const char *key, char *retv, int inlen,
3157 struct lxc_conf *c)
5485782f 3158{
6bede808 3159 return lxc_get_conf_int(c, retv, inlen, c->tty);
5485782f 3160}
8015e018 3161
b29b29be 3162static inline int lxc_get_conf_str(char *retv, int inlen, const char *value)
8015e018
CB
3163{
3164 if (!value)
3165 return 0;
3166 if (retv && inlen >= strlen(value) + 1)
3167 strncpy(retv, value, strlen(value) + 1);
3168
3169 return strlen(value);
3170}
3171
6bede808
CB
3172static int get_config_ttydir(const char *key, char *retv, int inlen,
3173 struct lxc_conf *c)
8015e018 3174{
6bede808 3175 return lxc_get_conf_str(retv, inlen, c->ttydir);
8015e018 3176}
de1ede69 3177
6bede808
CB
3178static int get_config_kmsg(const char *key, char *retv, int inlen,
3179 struct lxc_conf *c)
de1ede69 3180{
6bede808 3181 return lxc_get_conf_int(c, retv, inlen, c->kmsg);
de1ede69 3182}
104c8e6c 3183
6bede808
CB
3184static int get_config_lsm_aa_profile(const char *key, char *retv, int inlen,
3185 struct lxc_conf *c)
104c8e6c 3186{
6bede808 3187 return lxc_get_conf_str(retv, inlen, c->lsm_aa_profile);
104c8e6c 3188}
d60d18c6 3189
6bede808
CB
3190static int get_config_lsm_aa_incomplete(const char *key, char *retv, int inlen,
3191 struct lxc_conf *c)
d60d18c6 3192{
6bede808
CB
3193 return lxc_get_conf_int(c, retv, inlen,
3194 c->lsm_aa_allow_incomplete);
d60d18c6 3195}
4203a0b5 3196
6bede808
CB
3197static int get_config_lsm_se_context(const char *key, char *retv, int inlen,
3198 struct lxc_conf *c)
4203a0b5 3199{
6bede808 3200 return lxc_get_conf_str(retv, inlen, c->lsm_se_context);
4203a0b5 3201}
b863bf92
CB
3202
3203/*
3204 * If you ask for a specific cgroup value, i.e. lxc.cgroup.devices.list,
3205 * then just the value(s) will be printed. Since there still could be
3206 * more than one, it is newline-separated.
3207 * (Maybe that's ambigous, since some values, i.e. devices.list, will
3208 * already have newlines?)
3209 * If you ask for 'lxc.cgroup", then all cgroup entries will be printed,
3210 * in 'lxc.cgroup.subsystem.key = value' format.
3211 */
6bede808
CB
3212static int get_config_cgroup(const char *key, char *retv, int inlen,
3213 struct lxc_conf *c)
b863bf92
CB
3214{
3215 struct lxc_list *it;
3216 int len;
3217 int fulllen = 0;
3218 bool get_all = false;
3219
3220 if (!retv)
3221 inlen = 0;
3222 else
3223 memset(retv, 0, inlen);
3224
3225 if (!strcmp(key, "lxc.cgroup"))
3226 get_all = true;
3227 else if (!strncmp(key, "lxc.cgroup.", 11))
3228 key += 11;
3229 else
3230 return -1;
3231
6bede808 3232 lxc_list_for_each(it, &c->cgroup) {
b863bf92
CB
3233 struct lxc_cgroup *cg = it->elem;
3234 if (get_all) {
3235 strprint(retv, inlen, "lxc.cgroup.%s = %s\n", cg->subsystem, cg->value);
3236 } else if (!strcmp(cg->subsystem, key)) {
3237 strprint(retv, inlen, "%s\n", cg->value);
3238 }
3239 }
3240
3241 return fulllen;
3242}
5014ff2e 3243
6bede808
CB
3244static int get_config_idmaps(const char *key, char *retv, int inlen,
3245 struct lxc_conf *c)
5014ff2e
CB
3246{
3247 struct lxc_list *it;
3248 int len, listlen, ret;
3249 int fulllen = 0;
3250/* "u 1000 1000000 65536"
3251 *
3252 * let's render this as
3253 *
3254 * sizeof(char)
3255 * +
3256 * sizeof(" ")
3257 * +
3258 * sizeof(uint64_t)
3259 * +
3260 * sizeof(" ")
3261 * +
3262 * sizeof(uint64_t)
3263 * +
3264 * sizeof(" ")
3265 * +
3266 * sizeof(uint64_t)
3267 * +
3268 * \0
3269 */
3270#define __LXC_IDMAP_STR_BUF (3 * LXC_NUMSTRLEN64 + 3 + 1 + 1)
3271 char buf[__LXC_IDMAP_STR_BUF];
3272
3273 if (!retv)
3274 inlen = 0;
3275 else
3276 memset(retv, 0, inlen);
3277
6bede808
CB
3278 listlen = lxc_list_len(&c->id_map);
3279 lxc_list_for_each(it, &c->id_map)
5014ff2e
CB
3280 {
3281 struct id_map *map = it->elem;
3282 ret = snprintf(buf, __LXC_IDMAP_STR_BUF, "%c %lu %lu %lu",
3283 (map->idtype == ID_TYPE_UID) ? 'u' : 'g',
3284 map->nsid, map->hostid, map->range);
3285 if (ret < 0 || ret >= __LXC_IDMAP_STR_BUF)
3286 return -1;
3287
3288 strprint(retv, inlen, "%s%s", buf, (listlen-- > 1) ? "\n" : "");
3289 }
3290 return fulllen;
3291}
b29b29be 3292
6bede808
CB
3293static int get_config_loglevel(const char *key, char *retv, int inlen,
3294 struct lxc_conf *c)
b29b29be
CB
3295{
3296 const char *v;
6bede808 3297 v = lxc_log_priority_to_string(c->loglevel);
b29b29be
CB
3298 return lxc_get_conf_str(retv, inlen, v);
3299}
3d4630ab 3300
6bede808
CB
3301static int get_config_logfile(const char *key, char *retv, int inlen,
3302 struct lxc_conf *c)
3d4630ab 3303{
6bede808 3304 return lxc_get_conf_str(retv, inlen, c->logfile);
3d4630ab 3305}
0d601acb 3306
6bede808
CB
3307static int get_config_fstab(const char *key, char *retv, int inlen,
3308 struct lxc_conf *c)
0d601acb 3309{
6bede808 3310 return lxc_get_conf_str(retv, inlen, c->fstab);
0d601acb 3311}
43fbf8d9 3312
6bede808
CB
3313static int get_config_mount_auto(const char *key, char *retv, int inlen,
3314 struct lxc_conf *c)
43fbf8d9
CB
3315{
3316 int len, fulllen = 0;
3317 const char *sep = "";
3318
3319 if (!retv)
3320 inlen = 0;
3321 else
3322 memset(retv, 0, inlen);
3323
6bede808 3324 if (!(c->auto_mounts & LXC_AUTO_ALL_MASK))
43fbf8d9
CB
3325 return 0;
3326
6bede808 3327 switch (c->auto_mounts & LXC_AUTO_PROC_MASK) {
43fbf8d9
CB
3328 case LXC_AUTO_PROC_MIXED:
3329 strprint(retv, inlen, "%sproc:mixed", sep);
3330 sep = " ";
3331 break;
3332 case LXC_AUTO_PROC_RW:
3333 strprint(retv, inlen, "%sproc:rw", sep);
3334 sep = " ";
3335 break;
3336 default:
3337 break;
3338 }
3339
6bede808 3340 switch (c->auto_mounts & LXC_AUTO_SYS_MASK) {
43fbf8d9
CB
3341 case LXC_AUTO_SYS_RO:
3342 strprint(retv, inlen, "%ssys:ro", sep);
3343 sep = " ";
3344 break;
3345 case LXC_AUTO_SYS_RW:
3346 strprint(retv, inlen, "%ssys:rw", sep);
3347 sep = " ";
3348 break;
3349 case LXC_AUTO_SYS_MIXED:
3350 strprint(retv, inlen, "%ssys:mixed", sep);
3351 sep = " ";
3352 break;
3353 default:
3354 break;
3355 }
3356
6bede808 3357 switch (c->auto_mounts & LXC_AUTO_CGROUP_MASK) {
43fbf8d9
CB
3358 case LXC_AUTO_CGROUP_NOSPEC:
3359 strprint(retv, inlen, "%scgroup", sep);
3360 sep = " ";
3361 break;
3362 case LXC_AUTO_CGROUP_MIXED:
3363 strprint(retv, inlen, "%scgroup:mixed", sep);
3364 sep = " ";
3365 break;
3366 case LXC_AUTO_CGROUP_RO:
3367 strprint(retv, inlen, "%scgroup:ro", sep);
3368 sep = " ";
3369 break;
3370 case LXC_AUTO_CGROUP_RW:
3371 strprint(retv, inlen, "%scgroup:rw", sep);
3372 sep = " ";
3373 break;
3374 case LXC_AUTO_CGROUP_FULL_NOSPEC:
3375 strprint(retv, inlen, "%scgroup-full", sep);
3376 sep = " ";
3377 break;
3378 case LXC_AUTO_CGROUP_FULL_MIXED:
3379 strprint(retv, inlen, "%scgroup-full:mixed", sep);
3380 sep = " ";
3381 break;
3382 case LXC_AUTO_CGROUP_FULL_RO:
3383 strprint(retv, inlen, "%scgroup-full:ro", sep);
3384 sep = " ";
3385 break;
3386 case LXC_AUTO_CGROUP_FULL_RW:
3387 strprint(retv, inlen, "%scgroup-full:rw", sep);
3388 sep = " ";
3389 break;
3390 default:
3391 break;
3392 }
3393
3394 return fulllen;
3395}
cc921848 3396
6bede808
CB
3397static int get_config_mount(const char *key, char *retv, int inlen,
3398 struct lxc_conf *c)
cc921848
CB
3399{
3400 int len, fulllen = 0;
3401 struct lxc_list *it;
3402
3403 if (!retv)
3404 inlen = 0;
3405 else
3406 memset(retv, 0, inlen);
3407
6bede808 3408 lxc_list_for_each(it, &c->mount_list)
cc921848
CB
3409 {
3410 strprint(retv, inlen, "%s\n", (char *)it->elem);
3411 }
3412
3413 return fulllen;
3414}
819114b6 3415
6bede808
CB
3416static int get_config_rootfs(const char *key, char *retv, int inlen,
3417 struct lxc_conf *c)
819114b6 3418{
6bede808 3419 return lxc_get_conf_str(retv, inlen, c->rootfs.path);
819114b6 3420}
3af60359 3421
6bede808
CB
3422static int get_config_rootfs_mount(const char *key, char *retv, int inlen,
3423 struct lxc_conf *c)
3af60359 3424{
6bede808 3425 return lxc_get_conf_str(retv, inlen, c->rootfs.mount);
3af60359 3426}
0e9db631 3427
6bede808
CB
3428static int get_config_rootfs_options(const char *key, char *retv, int inlen,
3429 struct lxc_conf *c)
0e9db631 3430{
6bede808 3431 return lxc_get_conf_str(retv, inlen, c->rootfs.options);
0e9db631 3432}
8f183f38 3433
6bede808
CB
3434static int get_config_rootfs_backend(const char *key, char *retv, int inlen,
3435 struct lxc_conf *c)
8f183f38 3436{
6bede808 3437 return lxc_get_conf_str(retv, inlen, c->rootfs.bdev_type);
8f183f38 3438}
b87574e7 3439
6bede808
CB
3440static int get_config_pivotdir(const char *key, char *retv, int inlen,
3441 struct lxc_conf *c)
b87574e7
CB
3442{
3443 return 0;
3444}
e274f8b0 3445
6bede808
CB
3446static int get_config_utsname(const char *key, char *retv, int inlen,
3447 struct lxc_conf *c)
e274f8b0
CB
3448{
3449 return lxc_get_conf_str(
3450 retv, inlen,
6bede808 3451 c->utsname ? c->utsname->nodename : NULL);
e274f8b0 3452}
466c2e93 3453
6bede808
CB
3454static int get_config_hooks(const char *key, char *retv, int inlen,
3455 struct lxc_conf *c)
466c2e93
CB
3456{
3457 char *subkey;
3458 int len, fulllen = 0, found = -1;
3459 struct lxc_list *it;
3460 int i;
3461
3462 /* "lxc.hook.mount" */
3463 subkey = strchr(key, '.');
3464 if (subkey)
3465 subkey = strchr(subkey + 1, '.');
3466 if (!subkey)
3467 return -1;
3468 subkey++;
3469 if (!*subkey)
3470 return -1;
3471 for (i = 0; i < NUM_LXC_HOOKS; i++) {
3472 if (strcmp(lxchook_names[i], subkey) == 0) {
3473 found = i;
3474 break;
3475 }
3476 }
3477 if (found == -1)
3478 return -1;
3479
3480 if (!retv)
3481 inlen = 0;
3482 else
3483 memset(retv, 0, inlen);
3484
6bede808 3485 lxc_list_for_each(it, &c->hooks[found]) {
466c2e93
CB
3486 strprint(retv, inlen, "%s\n", (char *)it->elem);
3487 }
3488 return fulllen;
3489}
d2ceff53 3490
6bede808
CB
3491static int get_config_network(const char *key, char *retv, int inlen,
3492 struct lxc_conf *c)
d2ceff53
CB
3493{
3494 int len, fulllen = 0;
3495 struct lxc_list *it;
3496
3497 if (!retv)
3498 inlen = 0;
3499 else
3500 memset(retv, 0, inlen);
3501
6bede808 3502 lxc_list_for_each(it, &c->network) {
d2ceff53
CB
3503 struct lxc_netdev *n = it->elem;
3504 const char *t = lxc_net_type_to_str(n->type);
3505 strprint(retv, inlen, "%s\n", t ? t : "(invalid)");
3506 }
3507
3508 return fulllen;
3509}
bdccff60
CB
3510
3511/*
3512 * lxc.network.0.XXX, where XXX can be: name, type, link, flags, type,
3513 * macvlan.mode, veth.pair, vlan, ipv4, ipv6, script.up, hwaddr, mtu,
3514 * ipv4.gateway, ipv6.gateway. ipvX.gateway can return 'auto' instead
3515 * of an address. ipv4 and ipv6 return lists (newline-separated).
3516 * things like veth.pair return '' if invalid (i.e. if called for vlan
3517 * type).
3518 */
6bede808
CB
3519static int get_config_network_item(const char *key, char *retv, int inlen,
3520 struct lxc_conf *c)
bdccff60
CB
3521{
3522 char *p1;
3523 int len, fulllen = 0;
3524 struct lxc_netdev *netdev;
3525
3526 if (!retv)
3527 inlen = 0;
3528 else
3529 memset(retv, 0, inlen);
3530
3531 if (!strncmp(key, "lxc.network.", 12))
3532 key += 12;
3533 else
3534 return -1;
3535
3536 p1 = strchr(key, '.');
3537 if (!p1 || *(p1 + 1) == '\0')
3538 return -1;
3539 p1++;
3540
6bede808 3541 netdev = get_netdev_from_key(key, &c->network);
bdccff60
CB
3542 if (!netdev)
3543 return -1;
3544 if (strcmp(p1, "name") == 0) {
3545 if (netdev->name)
3546 strprint(retv, inlen, "%s", netdev->name);
3547 } else if (strcmp(p1, "type") == 0) {
3548 strprint(retv, inlen, "%s", lxc_net_type_to_str(netdev->type));
3549 } else if (strcmp(p1, "link") == 0) {
3550 if (netdev->link)
3551 strprint(retv, inlen, "%s", netdev->link);
3552 } else if (strcmp(p1, "flags") == 0) {
3553 if (netdev->flags & IFF_UP)
3554 strprint(retv, inlen, "up");
3555 } else if (strcmp(p1, "script.up") == 0) {
3556 if (netdev->upscript)
3557 strprint(retv, inlen, "%s", netdev->upscript);
3558 } else if (strcmp(p1, "script.down") == 0) {
3559 if (netdev->downscript)
3560 strprint(retv, inlen, "%s", netdev->downscript);
3561 } else if (strcmp(p1, "hwaddr") == 0) {
3562 if (netdev->hwaddr)
3563 strprint(retv, inlen, "%s", netdev->hwaddr);
3564 } else if (strcmp(p1, "mtu") == 0) {
3565 if (netdev->mtu)
3566 strprint(retv, inlen, "%s", netdev->mtu);
3567 } else if (strcmp(p1, "macvlan.mode") == 0) {
3568 if (netdev->type == LXC_NET_MACVLAN) {
3569 const char *mode;
3570 switch (netdev->priv.macvlan_attr.mode) {
3571 case MACVLAN_MODE_PRIVATE:
3572 mode = "private";
3573 break;
3574 case MACVLAN_MODE_VEPA:
3575 mode = "vepa";
3576 break;
3577 case MACVLAN_MODE_BRIDGE:
3578 mode = "bridge";
3579 break;
3580 case MACVLAN_MODE_PASSTHRU:
3581 mode = "passthru";
3582 break;
3583 default:
3584 mode = "(invalid)";
3585 break;
3586 }
3587 strprint(retv, inlen, "%s", mode);
3588 }
3589 } else if (strcmp(p1, "veth.pair") == 0) {
3590 if (netdev->type == LXC_NET_VETH) {
3591 strprint(retv, inlen, "%s",
3592 netdev->priv.veth_attr.pair
3593 ? netdev->priv.veth_attr.pair
3594 : netdev->priv.veth_attr.veth1);
3595 }
3596 } else if (strcmp(p1, "vlan") == 0) {
3597 if (netdev->type == LXC_NET_VLAN) {
3598 strprint(retv, inlen, "%d", netdev->priv.vlan_attr.vid);
3599 }
3600 } else if (strcmp(p1, "ipv4.gateway") == 0) {
3601 if (netdev->ipv4_gateway_auto) {
3602 strprint(retv, inlen, "auto");
3603 } else if (netdev->ipv4_gateway) {
3604 char buf[INET_ADDRSTRLEN];
3605 inet_ntop(AF_INET, netdev->ipv4_gateway, buf,
3606 sizeof(buf));
3607 strprint(retv, inlen, "%s", buf);
3608 }
3609 } else if (strcmp(p1, "ipv4") == 0) {
3610 struct lxc_list *it2;
3611 lxc_list_for_each(it2, &netdev->ipv4) {
3612 struct lxc_inetdev *i = it2->elem;
3613 char buf[INET_ADDRSTRLEN];
3614 inet_ntop(AF_INET, &i->addr, buf, sizeof(buf));
3615 strprint(retv, inlen, "%s/%d\n", buf, i->prefix);
3616 }
3617 } else if (strcmp(p1, "ipv6.gateway") == 0) {
3618 if (netdev->ipv6_gateway_auto) {
3619 strprint(retv, inlen, "auto");
3620 } else if (netdev->ipv6_gateway) {
3621 char buf[INET6_ADDRSTRLEN];
3622 inet_ntop(AF_INET6, netdev->ipv6_gateway, buf,
3623 sizeof(buf));
3624 strprint(retv, inlen, "%s", buf);
3625 }
3626 } else if (strcmp(p1, "ipv6") == 0) {
3627 struct lxc_list *it2;
3628 lxc_list_for_each(it2, &netdev->ipv6) {
3629 struct lxc_inet6dev *i = it2->elem;
3630 char buf[INET6_ADDRSTRLEN];
3631 inet_ntop(AF_INET6, &i->addr, buf, sizeof(buf));
3632 strprint(retv, inlen, "%s/%d\n", buf, i->prefix);
3633 }
3634 }
3635 return fulllen;
3636}
1c96d6d8 3637
6bede808
CB
3638static int get_config_cap_drop(const char *key, char *retv, int inlen,
3639 struct lxc_conf *c)
1c96d6d8
CB
3640{
3641 int len, fulllen = 0;
3642 struct lxc_list *it;
3643
3644 if (!retv)
3645 inlen = 0;
3646 else
3647 memset(retv, 0, inlen);
3648
6bede808 3649 lxc_list_for_each(it, &c->caps) {
b80927f2
CB
3650 strprint(retv, inlen, "%s\n", (char *)it->elem);
3651 }
3652 return fulllen;
3653}
3654
6bede808
CB
3655static int get_config_cap_keep(const char *key, char *retv, int inlen,
3656 struct lxc_conf *c)
b80927f2
CB
3657{
3658 int len, fulllen = 0;
3659 struct lxc_list *it;
3660
3661 if (!retv)
3662 inlen = 0;
3663 else
3664 memset(retv, 0, inlen);
3665
6bede808 3666 lxc_list_for_each(it, &c->keepcaps) {
1c96d6d8
CB
3667 strprint(retv, inlen, "%s\n", (char *)it->elem);
3668 }
3669 return fulllen;
3670}
0692663a 3671
6bede808
CB
3672static int get_config_console(const char *key, char *retv, int inlen,
3673 struct lxc_conf *c)
0692663a 3674{
6bede808 3675 return lxc_get_conf_str(retv, inlen, c->console.path);
0692663a 3676}
794d1c06 3677
6bede808
CB
3678static int get_config_console_logfile(const char *key, char *retv, int inlen,
3679 struct lxc_conf *c)
794d1c06 3680{
6bede808 3681 return lxc_get_conf_str(retv, inlen, c->console.log_path);
794d1c06 3682}
75f55b1f 3683
6bede808
CB
3684static int get_config_seccomp(const char *key, char *retv, int inlen,
3685 struct lxc_conf *c)
75f55b1f 3686{
6bede808 3687 return lxc_get_conf_str(retv, inlen, c->seccomp);
75f55b1f 3688}
97f6dad0 3689
6bede808
CB
3690static int get_config_autodev(const char *key, char *retv, int inlen,
3691 struct lxc_conf *c)
97f6dad0 3692{
6bede808 3693 return lxc_get_conf_int(c, retv, inlen, c->autodev);
97f6dad0 3694}
afee4324 3695
6bede808
CB
3696static int get_config_haltsignal(const char *key, char *retv, int inlen,
3697 struct lxc_conf *c)
afee4324 3698{
6bede808 3699 return lxc_get_conf_int(c, retv, inlen, c->haltsignal);
afee4324 3700}
3aa8f359 3701
6bede808
CB
3702static int get_config_rebootsignal(const char *key, char *retv, int inlen,
3703 struct lxc_conf *c)
3aa8f359 3704{
6bede808 3705 return lxc_get_conf_int(c, retv, inlen, c->rebootsignal);
3aa8f359 3706}
2e16269f 3707
6bede808
CB
3708static int get_config_stopsignal(const char *key, char *retv, int inlen,
3709 struct lxc_conf *c)
2e16269f 3710{
6bede808 3711 return lxc_get_conf_int(c, retv, inlen, c->stopsignal);
2e16269f 3712}
54345299 3713
6bede808
CB
3714static int get_config_start(const char *key, char *retv, int inlen,
3715 struct lxc_conf *c)
54345299 3716{
c6182222 3717 if (strcmp(key + 10, "auto") == 0)
6bede808 3718 return lxc_get_conf_int(c, retv, inlen, c->start_auto);
c6182222 3719 else if (strcmp(key + 10, "delay") == 0)
6bede808 3720 return lxc_get_conf_int(c, retv, inlen, c->start_delay);
c6182222 3721 else if (strcmp(key + 10, "order") == 0)
6bede808 3722 return lxc_get_conf_int(c, retv, inlen, c->start_order);
54345299
CB
3723
3724 return -1;
3725}
de9df15e 3726
6bede808
CB
3727static int get_config_syslog(const char *key, char *retv, int inlen,
3728 struct lxc_conf *c)
de9df15e 3729{
6bede808 3730 return lxc_get_conf_str(retv, inlen, c->syslog);
de9df15e 3731}
ac0f949c 3732
6bede808
CB
3733static int get_config_monitor(const char *key, char *retv, int inlen,
3734 struct lxc_conf *c)
ac0f949c 3735{
6bede808 3736 return lxc_get_conf_int(c, retv, inlen, c->monitor_unshare);
ac0f949c 3737}
90ec7b6e 3738
6bede808
CB
3739static int get_config_group(const char *key, char *retv, int inlen,
3740 struct lxc_conf *c)
90ec7b6e
CB
3741{
3742 int len, fulllen = 0;
3743 struct lxc_list *it;
3744
3745 if (!retv)
3746 inlen = 0;
3747 else
3748 memset(retv, 0, inlen);
3749
6bede808 3750 lxc_list_for_each(it, &c->groups) {
90ec7b6e
CB
3751 strprint(retv, inlen, "%s\n", (char *)it->elem);
3752 }
3753 return fulllen;
3754}
aa0db7d3 3755
6bede808
CB
3756static int get_config_environment(const char *key, char *retv, int inlen,
3757 struct lxc_conf *c)
aa0db7d3
CB
3758{
3759 int len, fulllen = 0;
3760 struct lxc_list *it;
3761
3762 if (!retv)
3763 inlen = 0;
3764 else
3765 memset(retv, 0, inlen);
3766
6bede808 3767 lxc_list_for_each(it, &c->environment) {
aa0db7d3
CB
3768 strprint(retv, inlen, "%s\n", (char *)it->elem);
3769 }
3770 return fulllen;
3771}
96dfcb7d 3772
6bede808
CB
3773static int get_config_init_cmd(const char *key, char *retv, int inlen,
3774 struct lxc_conf *c)
96dfcb7d 3775{
6bede808 3776 return lxc_get_conf_str(retv, inlen, c->init_cmd);
96dfcb7d 3777}
1398e9b1 3778
6bede808
CB
3779static int get_config_init_uid(const char *key, char *retv, int inlen,
3780 struct lxc_conf *c)
1398e9b1 3781{
6bede808 3782 return lxc_get_conf_int(c, retv, inlen, c->init_uid);
1398e9b1 3783}
dfeb7e42 3784
6bede808
CB
3785static int get_config_init_gid(const char *key, char *retv, int inlen,
3786 struct lxc_conf *c)
dfeb7e42 3787{
6bede808 3788 return lxc_get_conf_int(c, retv, inlen, c->init_gid);
dfeb7e42 3789}
62048afe 3790
6bede808
CB
3791static int get_config_ephemeral(const char *key, char *retv, int inlen,
3792 struct lxc_conf *c)
62048afe 3793{
6bede808 3794 return lxc_get_conf_int(c, retv, inlen, c->ephemeral);
62048afe 3795}
b09521ac 3796
6bede808
CB
3797static int get_config_no_new_privs(const char *key, char *retv, int inlen,
3798 struct lxc_conf *c)
b09521ac 3799{
6bede808 3800 return lxc_get_conf_int(c, retv, inlen, c->no_new_privs);
b09521ac 3801}
389f6466
CB
3802
3803/*
3804 * If you ask for a specific value, i.e. lxc.limit.nofile, then just the value
3805 * will be printed. If you ask for 'lxc.limit', then all limit entries will be
3806 * printed, in 'lxc.limit.resource = value' format.
3807 */
6bede808
CB
3808static int get_config_limit(const char *key, char *retv, int inlen,
3809 struct lxc_conf *c)
389f6466
CB
3810{
3811 int fulllen = 0, len;
3812 bool get_all = false;
3813 struct lxc_list *it;
3814
3815 if (!retv)
3816 inlen = 0;
3817 else
3818 memset(retv, 0, inlen);
3819
3820 if (!strcmp(key, "lxc.limit"))
3821 get_all = true;
3822 else if (strncmp(key, "lxc.limit.", 10) == 0)
3823 key += 10;
3824 else
3825 return -1;
3826
6bede808 3827 lxc_list_for_each(it, &c->limits) {
389f6466
CB
3828 char buf[LXC_NUMSTRLEN64 * 2 + 2]; /* 2 colon separated 64 bit
3829 integers or the word
3830 'unlimited' */
3831 int partlen;
3832 struct lxc_limit *lim = it->elem;
3833
3834 if (lim->limit.rlim_cur == RLIM_INFINITY) {
3835 memcpy(buf, "unlimited", sizeof("unlimited"));
3836 partlen = sizeof("unlimited") - 1;
3837 } else {
3838 partlen = sprintf(buf, "%" PRIu64,
3839 (uint64_t)lim->limit.rlim_cur);
3840 }
3841 if (lim->limit.rlim_cur != lim->limit.rlim_max) {
3842 if (lim->limit.rlim_max == RLIM_INFINITY) {
3843 memcpy(buf + partlen, ":unlimited",
3844 sizeof(":unlimited"));
3845 } else {
3846 sprintf(buf + partlen, ":%" PRIu64,
3847 (uint64_t)lim->limit.rlim_max);
3848 }
3849 }
3850
3851 if (get_all) {
3852 strprint(retv, inlen, "lxc.limit.%s = %s\n",
3853 lim->resource, buf);
3854 } else if (strcmp(lim->resource, key) == 0) {
3855 strprint(retv, inlen, "%s", buf);
3856 }
3857 }
3858
3859 return fulllen;
3860}
e08cb901
CB
3861
3862/* Callbacks to clear config items. */
3863static inline int clr_config_personality(const char *key, struct lxc_conf *c)
3864{
3865 c->personality = -1;
3866 return 0;
3867}
03818ae3
CB
3868
3869static inline int clr_config_pts(const char *key, struct lxc_conf *c)
3870{
3871 c->pts = 0;
3872 return 0;
3873}
e7a4b096
CB
3874
3875static inline int clr_config_tty(const char *key, struct lxc_conf *c)
3876{
3877 c->tty = 0;
3878 return 0;
3879}
eaf8c0c7
CB
3880
3881static inline int clr_config_ttydir(const char *key, struct lxc_conf *c)
3882{
3883 free(c->ttydir);
3884 c->ttydir = NULL;
3885 return 0;
3886}
6bd86308
CB
3887
3888static inline int clr_config_kmsg(const char *key, struct lxc_conf *c)
3889{
3890 c->kmsg = 0;
3891 return 0;
3892}
025718fb
CB
3893
3894static inline int clr_config_lsm_aa_profile(const char *key, struct lxc_conf *c)
3895{
3896 free(c->lsm_aa_profile);
3897 c->lsm_aa_profile = NULL;
3898 return 0;
3899}
3061e04e
CB
3900
3901static inline int clr_config_lsm_aa_incomplete(const char *key,
3902 struct lxc_conf *c)
3903{
3904 c->lsm_aa_allow_incomplete = 0;
3905 return 0;
3906}
31fc3494
CB
3907
3908static inline int clr_config_lsm_se_context(const char *key, struct lxc_conf *c)
3909{
3910 free(c->lsm_se_context);
3911 c->lsm_se_context = NULL;
3912 return 0;
3913}
754d01ce
CB
3914
3915static inline int clr_config_cgroup(const char *key, struct lxc_conf *c)
3916{
3917 return lxc_clear_cgroups(c, key);
3918}
d3a178de
CB
3919
3920static inline int clr_config_idmaps(const char *key, struct lxc_conf *c)
3921{
3922 return lxc_clear_idmaps(c);
3923}
97d3338d
CB
3924
3925static inline int clr_config_loglevel(const char *key, struct lxc_conf *c)
3926{
4b73005c 3927 c->loglevel = LXC_LOG_LEVEL_NOTSET;
97d3338d
CB
3928 return 0;
3929}
de46099c
CB
3930
3931static inline int clr_config_logfile(const char *key, struct lxc_conf *c)
3932{
3933 free(c->logfile);
3934 c->logfile = NULL;
3935 return 0;
3936}
b4fa13cd
CB
3937
3938static inline int clr_config_mount(const char *key, struct lxc_conf *c)
3939{
3940 return lxc_clear_mount_entries(c);
3941}
4be81021
CB
3942
3943static inline int clr_config_mount_auto(const char *key, struct lxc_conf *c)
3944{
3945 return lxc_clear_automounts(c);
3946}
350d4b15
CB
3947
3948static inline int clr_config_fstab(const char *key, struct lxc_conf *c)
3949{
3950 free(c->fstab);
3951 c->fstab = NULL;
3952 return 0;
3953}
faca124d
CB
3954
3955static inline int clr_config_rootfs(const char *key, struct lxc_conf *c)
3956{
3957 free(c->rootfs.path);
3958 c->rootfs.path = NULL;
3959 return 0;
3960}
3961
fddefc2d
CB
3962static inline int clr_config_rootfs_mount(const char *key, struct lxc_conf *c)
3963{
3964 free(c->rootfs.mount);
3965 c->rootfs.mount = NULL;
3966 return 0;
3967}
7b1eb67d
CB
3968
3969static inline int clr_config_rootfs_options(const char *key, struct lxc_conf *c)
3970{
3971 free(c->rootfs.options);
3972 c->rootfs.options = NULL;
3973 return 0;
3974}
02becb8d
CB
3975
3976static inline int clr_config_rootfs_backend(const char *key, struct lxc_conf *c)
3977{
3978 free(c->rootfs.bdev_type);
3979 c->rootfs.bdev_type = NULL;
3980 return 0;
3981}
3982
57928a51
CB
3983static inline int clr_config_pivotdir(const char *key, struct lxc_conf *c)
3984{
3985 return 0;
3986}
d31d0103
CB
3987
3988static inline int clr_config_utsname(const char *key, struct lxc_conf *c)
3989{
3990 free(c->utsname);
3991 c->utsname = NULL;
3992 return 0;
3993}
c9eeb90c
CB
3994
3995static inline int clr_config_hooks(const char *key, struct lxc_conf *c)
3996{
3997 return lxc_clear_hooks(c, key);
3998}
3999
e2410c4e
CB
4000static inline int clr_config_network_item(const char *key, struct lxc_conf *c)
4001{
4002 return lxc_clear_nic(c, key + 12);
4003}
f4488271
CB
4004
4005static inline int clr_config_network(const char *key, struct lxc_conf *c)
4006{
4007 return lxc_clear_config_network(c);
4008}
4009
244cb55b
CB
4010static inline int clr_config_cap_drop(const char *key, struct lxc_conf *c)
4011{
4012 return lxc_clear_config_caps(c);
4013}
c74cc490
CB
4014
4015static inline int clr_config_cap_keep(const char *key, struct lxc_conf *c)
4016{
4017 return lxc_clear_config_keepcaps(c);
4018}
4e5b633f
CB
4019
4020static inline int clr_config_console(const char *key, struct lxc_conf *c)
4021{
4022 free(c->console.path);
4023 c->console.path = NULL;
4024 return 0;
4025}
4026
7c2ec23a
CB
4027static inline int clr_config_console_logfile(const char *key,
4028 struct lxc_conf *c)
4029{
4030 free(c->console.log_path);
4031 c->console.log_path = NULL;
4032 return 0;
4033}
bbca37d8
CB
4034
4035static inline int clr_config_seccomp(const char *key, struct lxc_conf *c)
4036{
4037 free(c->seccomp);
4038 c->seccomp = NULL;
4039 return 0;
4040}
c721e86c
CB
4041
4042static inline int clr_config_autodev(const char *key, struct lxc_conf *c)
4043{
4044 c->autodev = 1;
4045 return 0;
4046}
87b288d1
CB
4047
4048static inline int clr_config_haltsignal(const char *key, struct lxc_conf *c)
4049{
4050 c->haltsignal = 0;
4051 return 0;
4052}
cae63cfa
CB
4053
4054static inline int clr_config_rebootsignal(const char *key, struct lxc_conf *c)
4055{
4056 c->rebootsignal = 0;
4057 return 0;
4058}
de45f3a8
CB
4059
4060static inline int clr_config_stopsignal(const char *key, struct lxc_conf *c)
4061{
4062 c->stopsignal = 0;
4063 return 0;
4064}
c6182222
CB
4065
4066static inline int clr_config_start(const char *key, struct lxc_conf *c)
4067{
4068 if (strcmp(key + 10, "auto") == 0)
4069 c->start_auto = 0;
4070 else if (strcmp(key + 10, "delay") == 0)
4071 c->start_delay = 0;
4072 else if (strcmp(key + 10, "order") == 0)
4073 c->start_order = 0;
4074
4075 return 0;
4076}
998ca94f
CB
4077
4078static inline int clr_config_syslog(const char *key, struct lxc_conf *c)
4079{
4080 free(c->syslog);
4081 c->syslog = NULL;
4082 return 0;
4083}
adad12ca
CB
4084
4085static inline int clr_config_monitor(const char *key, struct lxc_conf *c)
4086{
4087 c->monitor_unshare = 0;
4088 return 0;
4089}
4850d223
CB
4090
4091static inline int clr_config_group(const char *key, struct lxc_conf *c)
4092{
4093 return lxc_clear_groups(c);
4094}
832fb63a
CB
4095
4096static inline int clr_config_environment(const char *key, struct lxc_conf *c)
4097{
4098 return lxc_clear_environment(c);
4850d223 4099}
8e90af3e
CB
4100
4101static inline int clr_config_init_cmd(const char *key, struct lxc_conf *c)
4102{
4103 free(c->init_cmd);
4104 c->init_cmd = NULL;
4105 return 0;
4106}
ec76dcfb
CB
4107
4108static inline int clr_config_init_uid(const char *key, struct lxc_conf *c)
4109{
4110 c->init_uid = 0;
4111 return 0;
4112}
1044b247
CB
4113
4114static inline int clr_config_init_gid(const char *key, struct lxc_conf *c)
4115{
4116 c->init_gid = 0;
4117 return 0;
4118}
59e370db
CB
4119
4120static inline int clr_config_ephemeral(const char *key, struct lxc_conf *c)
4121{
4122 c->ephemeral = 0;
4123 return 0;
4124}
b98c5ab0
CB
4125
4126static inline int clr_config_no_new_privs(const char *key, struct lxc_conf *c)
4127{
4128 c->no_new_privs = false;
4129 return 0;
4130}
715ccc96
CB
4131
4132static inline int clr_config_limit(const char *key, struct lxc_conf *c)
4133{
4134 return lxc_clear_limits(c, key);
4135}
fdf3c589 4136
973082f5 4137static inline int clr_config_includefiles(const char *key, struct lxc_conf *c)
fdf3c589
CB
4138{
4139 lxc_clear_includes(c);
4140 return 0;
4141}
a3c8e600
CB
4142
4143static int get_config_includefiles(const char *key, char *retv, int inlen,
4144 struct lxc_conf *c)
4145{
4146 return -ENOSYS;
4147}