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