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