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