]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/confile.c
conf{ile}: detect ns{g,u}id mapping for root
[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>
70c1e708
CB
7 * Serge Hallyn <serge@hallyn.com>
8 * Christian Brauner <christian.brauner@ubuntu.com>
c2cc9f0a 9 *
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
14 *
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
19 *
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
250b1eec 22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
c2cc9f0a 23 */
70c1e708 24
12a50cc6 25#define _GNU_SOURCE
70c1e708
CB
26#define __STDC_FORMAT_MACROS
27#include <ctype.h>
28#include <dirent.h>
29#include <errno.h>
30#include <fcntl.h>
31#include <inttypes.h>
32#include <signal.h>
c2cc9f0a 33#include <stdio.h>
34#include <stdlib.h>
35#include <string.h>
70c1e708
CB
36#include <syslog.h>
37#include <time.h>
c2cc9f0a 38#include <unistd.h>
70c1e708
CB
39#include <arpa/inet.h>
40#include <net/if.h>
41#include <netinet/in.h>
42#include <sys/param.h>
63376d7d 43#include <sys/stat.h>
c2cc9f0a 44#include <sys/types.h>
c2cc9f0a 45#include <sys/utsname.h>
c2cc9f0a 46
70c1e708 47#include "conf.h"
6ff05e18 48#include "config.h"
525f0002 49#include "confile.h"
953fe44f 50#include "confile_legacy.h"
0b843d35 51#include "confile_utils.h"
f2363e38 52#include "log.h"
58e0f57d 53#include "lxcseccomp.h"
70c1e708
CB
54#include "network.h"
55#include "parse.h"
28d832c4 56#include "storage.h"
70c1e708 57#include "utils.h"
36eb9bde 58
576400e5 59#if HAVE_IFADDRS_H
60#include <ifaddrs.h>
61#else
62#include <../include/ifaddrs.h>
63#endif
64
6ff05e18
SG
65#if HAVE_SYS_PERSONALITY_H
66#include <sys/personality.h>
67#endif
68
36eb9bde 69lxc_log_define(lxc_confile, lxc);
576f946d 70
861d1ada
CB
71#define lxc_config_define(name) \
72 static int set_config_##name(const char *, const char *, \
73 struct lxc_conf *, void *); \
74 static int get_config_##name(const char *, char *, int, \
75 struct lxc_conf *, void *); \
76 static int clr_config_##name(const char *, struct lxc_conf *, void *);
71e287ca 77
63bab717 78lxc_config_define(autodev);
71e287ca 79lxc_config_define(apparmor_allow_incomplete);
63bab717
CB
80lxc_config_define(apparmor_profile);
81lxc_config_define(cap_drop);
82lxc_config_define(cap_keep);
43654d34
CB
83lxc_config_define(cgroup_controller);
84lxc_config_define(cgroup_dir);
63bab717 85lxc_config_define(console_logfile);
d91adfa6 86lxc_config_define(console_rotate);
3a784510 87lxc_config_define(console_buffer_logfile);
28f3b1cd 88lxc_config_define(console_buffer_size);
63bab717
CB
89lxc_config_define(console_path);
90lxc_config_define(environment);
91lxc_config_define(ephemeral);
92lxc_config_define(execute_cmd);
93lxc_config_define(group);
94lxc_config_define(hooks);
44ae0fb6 95lxc_config_define(hooks_version);
71e287ca 96lxc_config_define(idmaps);
63bab717
CB
97lxc_config_define(includefiles);
98lxc_config_define(init_cmd);
3c491553 99lxc_config_define(init_cwd);
63bab717
CB
100lxc_config_define(init_gid);
101lxc_config_define(init_uid);
46cc906d 102lxc_config_define(log_file);
63bab717
CB
103lxc_config_define(log_level);
104lxc_config_define(log_syslog);
105lxc_config_define(monitor);
71e287ca 106lxc_config_define(mount);
107lxc_config_define(mount_auto);
47148e96 108lxc_config_define(mount_fstab);
28d9e29e 109lxc_config_define(namespace);
63bab717 110lxc_config_define(net);
71e287ca 111lxc_config_define(net_flags);
71e287ca 112lxc_config_define(net_hwaddr);
9ff60df2 113lxc_config_define(net_ipv4_address);
71e287ca 114lxc_config_define(net_ipv4_gateway);
2e44ae28 115lxc_config_define(net_ipv6_address);
71e287ca 116lxc_config_define(net_ipv6_gateway);
63bab717
CB
117lxc_config_define(net_link);
118lxc_config_define(net_macvlan_mode);
119lxc_config_define(net_mtu);
120lxc_config_define(net_name);
71e287ca 121lxc_config_define(net_nic);
63bab717
CB
122lxc_config_define(net_script_down);
123lxc_config_define(net_script_up);
124lxc_config_define(net_type);
125lxc_config_define(net_veth_pair);
126lxc_config_define(net_vlan_id);
127lxc_config_define(no_new_privs);
128lxc_config_define(noop);
129lxc_config_define(personality);
130lxc_config_define(prlimit);
131lxc_config_define(pty_max);
132lxc_config_define(rootfs_backend);
133lxc_config_define(rootfs_mount);
134lxc_config_define(rootfs_options);
135lxc_config_define(rootfs_path);
0b427da0 136lxc_config_define(seccomp_profile);
63bab717 137lxc_config_define(selinux_context);
55c84efc 138lxc_config_define(signal_halt);
139lxc_config_define(signal_reboot);
140lxc_config_define(signal_stop);
71e287ca 141lxc_config_define(start);
63bab717
CB
142lxc_config_define(tty_max);
143lxc_config_define(tty_dir);
144lxc_config_define(uts_name);
7edd0540 145lxc_config_define(sysctl);
61d7a733 146lxc_config_define(proc);
c2cc9f0a 147
72d0e1cb 148static struct lxc_config_t config[] = {
7ec2e32a
CB
149 /* REMOVE in LXC 3.0 */
150 { "lxc.arch", false, set_config_personality, get_config_personality, clr_config_personality, },
7ec2e32a
CB
151 { "lxc.apparmor.profile", false, set_config_apparmor_profile, get_config_apparmor_profile, clr_config_apparmor_profile, },
152 { "lxc.apparmor.allow_incomplete", false, set_config_apparmor_allow_incomplete, get_config_apparmor_allow_incomplete, clr_config_apparmor_allow_incomplete, },
71acf5d0
CB
153 { "lxc.autodev", false, set_config_autodev, get_config_autodev, clr_config_autodev, },
154 { "lxc.cap.drop", false, set_config_cap_drop, get_config_cap_drop, clr_config_cap_drop, },
155 { "lxc.cap.keep", false, set_config_cap_keep, get_config_cap_keep, clr_config_cap_keep, },
43654d34
CB
156 { "lxc.cgroup.dir", false, set_config_cgroup_dir, get_config_cgroup_dir, clr_config_cgroup_dir, },
157 { "lxc.cgroup", false, set_config_cgroup_controller, get_config_cgroup_controller, clr_config_cgroup_controller, },
3a784510 158 { "lxc.console.buffer.logfile", false, set_config_console_buffer_logfile, get_config_console_buffer_logfile, clr_config_console_buffer_logfile, },
28f3b1cd 159 { "lxc.console.buffer.size", false, set_config_console_buffer_size, get_config_console_buffer_size, clr_config_console_buffer_size, },
71acf5d0
CB
160 { "lxc.console.logfile", false, set_config_console_logfile, get_config_console_logfile, clr_config_console_logfile, },
161 { "lxc.console.path", false, set_config_console_path, get_config_console_path, clr_config_console_path, },
d91adfa6 162 { "lxc.console.rotate", false, set_config_console_rotate, get_config_console_rotate, clr_config_console_rotate, },
71acf5d0
CB
163 { "lxc.environment", false, set_config_environment, get_config_environment, clr_config_environment, },
164 { "lxc.ephemeral", false, set_config_ephemeral, get_config_ephemeral, clr_config_ephemeral, },
3a784510 165 { "lxc.execute.cmd", false, set_config_execute_cmd, get_config_execute_cmd, clr_config_execute_cmd, },
71acf5d0
CB
166 { "lxc.group", false, set_config_group, get_config_group, clr_config_group, },
167 { "lxc.hook.autodev", false, set_config_hooks, get_config_hooks, clr_config_hooks, },
168 { "lxc.hook.clone", false, set_config_hooks, get_config_hooks, clr_config_hooks, },
169 { "lxc.hook.destroy", false, set_config_hooks, get_config_hooks, clr_config_hooks, },
170 { "lxc.hook.mount", false, set_config_hooks, get_config_hooks, clr_config_hooks, },
171 { "lxc.hook.post-stop", false, set_config_hooks, get_config_hooks, clr_config_hooks, },
7ec2e32a 172 { "lxc.hook.pre-mount", false, set_config_hooks, get_config_hooks, clr_config_hooks, },
44ae0fb6 173 { "lxc.hook.pre-start", false, set_config_hooks, get_config_hooks, clr_config_hooks, },
7ec2e32a 174 { "lxc.hook.start", false, set_config_hooks, get_config_hooks, clr_config_hooks, },
44ae0fb6 175 { "lxc.hook.start-host", false, set_config_hooks, get_config_hooks, clr_config_hooks, },
7ec2e32a 176 { "lxc.hook.stop", false, set_config_hooks, get_config_hooks, clr_config_hooks, },
44ae0fb6 177 { "lxc.hook.version", false, set_config_hooks_version, get_config_hooks_version, clr_config_hooks_version, },
7ec2e32a 178 { "lxc.hook", false, set_config_hooks, get_config_hooks, clr_config_hooks, },
71acf5d0
CB
179 { "lxc.idmap", false, set_config_idmaps, get_config_idmaps, clr_config_idmaps, },
180 { "lxc.include", false, set_config_includefiles, get_config_includefiles, clr_config_includefiles, },
181 { "lxc.init.cmd", false, set_config_init_cmd, get_config_init_cmd, clr_config_init_cmd, },
182 { "lxc.init.gid", false, set_config_init_gid, get_config_init_gid, clr_config_init_gid, },
183 { "lxc.init.uid", false, set_config_init_uid, get_config_init_uid, clr_config_init_uid, },
3c491553 184 { "lxc.init.cwd", false, set_config_init_cwd, get_config_init_cwd, clr_config_init_cwd, },
71acf5d0
CB
185 { "lxc.log.file", false, set_config_log_file, get_config_log_file, clr_config_log_file, },
186 { "lxc.log.level", false, set_config_log_level, get_config_log_level, clr_config_log_level, },
187 { "lxc.log.syslog", false, set_config_log_syslog, get_config_log_syslog, clr_config_log_syslog, },
188 { "lxc.monitor.unshare", false, set_config_monitor, get_config_monitor, clr_config_monitor, },
189 { "lxc.mount.auto", false, set_config_mount_auto, get_config_mount_auto, clr_config_mount_auto, },
190 { "lxc.mount.entry", false, set_config_mount, get_config_mount, clr_config_mount, },
191 { "lxc.mount.fstab", false, set_config_mount_fstab, get_config_mount_fstab, clr_config_mount_fstab, },
28d9e29e 192 { "lxc.namespace", false, set_config_namespace, get_config_namespace, clr_config_namespace, },
953fe44f 193
49072f06 194 /* [START]: REMOVE IN LXC 3.0 */
7ec2e32a
CB
195 { "lxc.network.type", true, set_config_network_legacy_type, get_config_network_legacy_item, clr_config_network_legacy_item, },
196 { "lxc.network.flags", true, set_config_network_legacy_flags, get_config_network_legacy_item, clr_config_network_legacy_item, },
197 { "lxc.network.link", true, set_config_network_legacy_link, get_config_network_legacy_item, clr_config_network_legacy_item, },
198 { "lxc.network.name", true, set_config_network_legacy_name, get_config_network_legacy_item, clr_config_network_legacy_item, },
199 { "lxc.network.macvlan.mode", true, set_config_network_legacy_macvlan_mode, get_config_network_legacy_item, clr_config_network_legacy_item, },
200 { "lxc.network.veth.pair", true, set_config_network_legacy_veth_pair, get_config_network_legacy_item, clr_config_network_legacy_item, },
201 { "lxc.network.script.up", true, set_config_network_legacy_script_up, get_config_network_legacy_item, clr_config_network_legacy_item, },
202 { "lxc.network.script.down", true, set_config_network_legacy_script_down, get_config_network_legacy_item, clr_config_network_legacy_item, },
203 { "lxc.network.hwaddr", true, set_config_network_legacy_hwaddr, get_config_network_legacy_item, clr_config_network_legacy_item, },
204 { "lxc.network.mtu", true, set_config_network_legacy_mtu, get_config_network_legacy_item, clr_config_network_legacy_item, },
205 { "lxc.network.vlan.id", true, set_config_network_legacy_vlan_id, get_config_network_legacy_item, clr_config_network_legacy_item, },
206 { "lxc.network.ipv4.gateway", true, set_config_network_legacy_ipv4_gateway, get_config_network_legacy_item, clr_config_network_legacy_item, },
207 { "lxc.network.ipv4", true, set_config_network_legacy_ipv4, get_config_network_legacy_item, clr_config_network_legacy_item, },
208 { "lxc.network.ipv6.gateway", true, set_config_network_legacy_ipv6_gateway, get_config_network_legacy_item, clr_config_network_legacy_item, },
209 { "lxc.network.ipv6", true, set_config_network_legacy_ipv6, get_config_network_legacy_item, clr_config_network_legacy_item, },
210 { "lxc.network.", true, set_config_network_legacy_nic, get_config_network_legacy_item, clr_config_network_legacy_item, },
211 { "lxc.network", true, set_config_network_legacy, get_config_network_legacy, clr_config_network_legacy, },
49072f06 212 /* [END]: REMOVE IN LXC 3.0 */
953fe44f 213
7ec2e32a 214 { "lxc.net.flags", false, set_config_net_flags, get_config_net_flags, clr_config_net_flags, },
71acf5d0
CB
215 { "lxc.net.hwaddr", false, set_config_net_hwaddr, get_config_net_hwaddr, clr_config_net_hwaddr, },
216 { "lxc.net.ipv4.address", false, set_config_net_ipv4_address, get_config_net_ipv4_address, clr_config_net_ipv4_address, },
217 { "lxc.net.ipv4.gateway", false, set_config_net_ipv4_gateway, get_config_net_ipv4_gateway, clr_config_net_ipv4_gateway, },
218 { "lxc.net.ipv6.address", false, set_config_net_ipv6_address, get_config_net_ipv6_address, clr_config_net_ipv6_address, },
219 { "lxc.net.ipv6.gateway", false, set_config_net_ipv6_gateway, get_config_net_ipv6_gateway, clr_config_net_ipv6_gateway, },
7ec2e32a 220 { "lxc.net.link", false, set_config_net_link, get_config_net_link, clr_config_net_link, },
7ec2e32a 221 { "lxc.net.macvlan.mode", false, set_config_net_macvlan_mode, get_config_net_macvlan_mode, clr_config_net_macvlan_mode, },
7ec2e32a 222 { "lxc.net.mtu", false, set_config_net_mtu, get_config_net_mtu, clr_config_net_mtu, },
71acf5d0
CB
223 { "lxc.net.name", false, set_config_net_name, get_config_net_name, clr_config_net_name, },
224 { "lxc.net.script.down", false, set_config_net_script_down, get_config_net_script_down, clr_config_net_script_down, },
225 { "lxc.net.script.up", false, set_config_net_script_up, get_config_net_script_up, clr_config_net_script_up, },
226 { "lxc.net.type", false, set_config_net_type, get_config_net_type, clr_config_net_type, },
7ec2e32a 227 { "lxc.net.vlan.id", false, set_config_net_vlan_id, get_config_net_vlan_id, clr_config_net_vlan_id, },
71acf5d0 228 { "lxc.net.veth.pair", false, set_config_net_veth_pair, get_config_net_veth_pair, clr_config_net_veth_pair, },
7ec2e32a
CB
229 { "lxc.net.", false, set_config_net_nic, get_config_net_nic, clr_config_net_nic, },
230 { "lxc.net", false, set_config_net, get_config_net, clr_config_net, },
71acf5d0
CB
231 { "lxc.no_new_privs", false, set_config_no_new_privs, get_config_no_new_privs, clr_config_no_new_privs, },
232 { "lxc.prlimit", false, set_config_prlimit, get_config_prlimit, clr_config_prlimit, },
233 { "lxc.pty.max", false, set_config_pty_max, get_config_pty_max, clr_config_pty_max, },
234 { "lxc.rootfs.mount", false, set_config_rootfs_mount, get_config_rootfs_mount, clr_config_rootfs_mount, },
235 { "lxc.rootfs.options", false, set_config_rootfs_options, get_config_rootfs_options, clr_config_rootfs_options, },
236 { "lxc.rootfs.path", false, set_config_rootfs_path, get_config_rootfs_path, clr_config_rootfs_path, },
7ec2e32a 237 { "lxc.seccomp.profile", false, set_config_seccomp_profile, get_config_seccomp_profile, clr_config_seccomp_profile, },
71acf5d0 238 { "lxc.selinux.context", false, set_config_selinux_context, get_config_selinux_context, clr_config_selinux_context, },
7ec2e32a
CB
239 { "lxc.signal.halt", false, set_config_signal_halt, get_config_signal_halt, clr_config_signal_halt, },
240 { "lxc.signal.reboot", false, set_config_signal_reboot, get_config_signal_reboot, clr_config_signal_reboot, },
241 { "lxc.signal.stop", false, set_config_signal_stop, get_config_signal_stop, clr_config_signal_stop, },
242 { "lxc.start.auto", false, set_config_start, get_config_start, clr_config_start, },
243 { "lxc.start.delay", false, set_config_start, get_config_start, clr_config_start, },
244 { "lxc.start.order", false, set_config_start, get_config_start, clr_config_start, },
71acf5d0
CB
245 { "lxc.tty.dir", false, set_config_tty_dir, get_config_tty_dir, clr_config_tty_dir, },
246 { "lxc.tty.max", false, set_config_tty_max, get_config_tty_max, clr_config_tty_max, },
247 { "lxc.uts.name", false, set_config_uts_name, get_config_uts_name, clr_config_uts_name, },
7edd0540 248 { "lxc.sysctl", false, set_config_sysctl, get_config_sysctl, clr_config_sysctl, },
61d7a733 249 { "lxc.proc", false, set_config_proc, get_config_proc, clr_config_proc, },
240d4b74 250
49072f06 251 /* [START]: REMOVE IN LXC 3.0 */
71acf5d0
CB
252 { "lxc.pts", true, set_config_pty_max, get_config_pty_max, clr_config_pty_max, },
253 { "lxc.devttydir", true, set_config_tty_dir, get_config_tty_dir, clr_config_tty_dir, },
254 { "lxc.tty", true, set_config_tty_max, get_config_tty_max, clr_config_tty_max, },
255 { "lxc.aa_profile", true, set_config_lsm_aa_profile, get_config_lsm_aa_profile, clr_config_lsm_aa_profile, },
256 { "lxc.aa_allow_incomplete", true, set_config_lsm_aa_incomplete, get_config_lsm_aa_incomplete, clr_config_lsm_aa_incomplete, },
257 { "lxc.se_context", true, set_config_lsm_se_context, get_config_lsm_se_context, clr_config_lsm_se_context, },
258 { "lxc.id_map", true, set_config_idmaps, get_config_idmaps, clr_config_idmaps, },
259 { "lxc.mount", true, set_config_mount_fstab, get_config_mount_fstab, clr_config_mount_fstab, },
260 { "lxc.rootfs.backend", true, set_config_rootfs_backend, get_config_rootfs_backend, clr_config_rootfs_backend, },
261 { "lxc.rootfs", true, set_config_rootfs_path, get_config_rootfs_path, clr_config_rootfs_path, },
262 { "lxc.utsname", true, set_config_uts_name, get_config_uts_name, clr_config_uts_name, },
263 { "lxc.seccomp", true, set_config_seccomp_profile, get_config_seccomp_profile, clr_config_seccomp_profile, },
264 { "lxc.console", true, set_config_console_path, get_config_console_path, clr_config_console_path, },
265 { "lxc.haltsignal", true, set_config_signal_halt, get_config_signal_halt, clr_config_signal_halt, },
266 { "lxc.rebootsignal", true, set_config_signal_reboot, get_config_signal_reboot, clr_config_signal_reboot, },
267 { "lxc.stopsignal", true, set_config_signal_stop, get_config_signal_stop, clr_config_signal_stop, },
7ec2e32a 268 { "lxc.syslog", true, set_config_log_syslog, get_config_log_syslog, clr_config_log_syslog, },
63bab717 269 { "lxc.kmsg", true, set_config_noop, get_config_noop, clr_config_noop, },
7ec2e32a
CB
270 { "lxc.loglevel", true, set_config_log_level, get_config_log_level, clr_config_log_level, },
271 { "lxc.logfile", true, set_config_log_file, get_config_log_file, clr_config_log_file, },
272 { "lxc.init_cmd", true, set_config_init_cmd, get_config_init_cmd, clr_config_init_cmd, },
273 { "lxc.init_uid", true, set_config_init_uid, get_config_init_uid, clr_config_init_uid, },
274 { "lxc.init_gid", true, set_config_init_gid, get_config_init_gid, clr_config_init_gid, },
275 { "lxc.limit", true, set_config_limit, get_config_limit, clr_config_limit, },
63bab717 276 { "lxc.pivotdir", true, set_config_noop, get_config_noop, clr_config_noop, },
49072f06 277 /* [END]: REMOVE IN LXC 3.0 */
a84b9932
AV
278};
279
280struct signame {
281 int num;
74a3920a 282 const char *name;
a84b9932
AV
283};
284
74a3920a 285static const struct signame signames[] = {
504a2217
CB
286 { SIGHUP, "HUP" },
287 { SIGINT, "INT" },
288 { SIGQUIT, "QUIT" },
289 { SIGILL, "ILL" },
290 { SIGABRT, "ABRT" },
291 { SIGFPE, "FPE" },
292 { SIGKILL, "KILL" },
293 { SIGSEGV, "SEGV" },
294 { SIGPIPE, "PIPE" },
295 { SIGALRM, "ALRM" },
296 { SIGTERM, "TERM" },
297 { SIGUSR1, "USR1" },
298 { SIGUSR2, "USR2" },
299 { SIGCHLD, "CHLD" },
300 { SIGCONT, "CONT" },
301 { SIGSTOP, "STOP" },
302 { SIGTSTP, "TSTP" },
303 { SIGTTIN, "TTIN" },
304 { SIGTTOU, "TTOU" },
89dfc302 305#ifdef SIGTRAP
504a2217 306 { SIGTRAP, "TRAP" },
89dfc302
SY
307#endif
308#ifdef SIGIOT
504a2217 309 { SIGIOT, "IOT" },
89dfc302
SY
310#endif
311#ifdef SIGEMT
504a2217 312 { SIGEMT, "EMT" },
89dfc302
SY
313#endif
314#ifdef SIGBUS
504a2217 315 { SIGBUS, "BUS" },
89dfc302
SY
316#endif
317#ifdef SIGSTKFLT
318 { SIGSTKFLT, "STKFLT" },
319#endif
320#ifdef SIGCLD
504a2217 321 { SIGCLD, "CLD" },
89dfc302
SY
322#endif
323#ifdef SIGURG
504a2217 324 { SIGURG, "URG" },
89dfc302
SY
325#endif
326#ifdef SIGXCPU
504a2217 327 { SIGXCPU, "XCPU" },
89dfc302
SY
328#endif
329#ifdef SIGXFSZ
504a2217 330 { SIGXFSZ, "XFSZ" },
89dfc302
SY
331#endif
332#ifdef SIGVTALRM
333 { SIGVTALRM, "VTALRM" },
334#endif
335#ifdef SIGPROF
504a2217 336 { SIGPROF, "PROF" },
89dfc302
SY
337#endif
338#ifdef SIGWINCH
504a2217 339 { SIGWINCH, "WINCH" },
89dfc302
SY
340#endif
341#ifdef SIGIO
504a2217 342 { SIGIO, "IO" },
89dfc302
SY
343#endif
344#ifdef SIGPOLL
504a2217 345 { SIGPOLL, "POLL" },
89dfc302
SY
346#endif
347#ifdef SIGINFO
504a2217 348 { SIGINFO, "INFO" },
89dfc302
SY
349#endif
350#ifdef SIGLOST
504a2217 351 { SIGLOST, "LOST" },
89dfc302
SY
352#endif
353#ifdef SIGPWR
504a2217 354 { SIGPWR, "PWR" },
89dfc302
SY
355#endif
356#ifdef SIGUNUSED
357 { SIGUNUSED, "UNUSED" },
358#endif
359#ifdef SIGSYS
504a2217 360 { SIGSYS, "SYS" },
89dfc302 361#endif
c2cc9f0a 362};
363
504a2217 364static const size_t config_size = sizeof(config) / sizeof(struct lxc_config_t);
c2cc9f0a 365
300df83e 366struct lxc_config_t *lxc_get_config(const char *key)
c2cc9f0a 367{
84760c11 368 size_t i;
c2cc9f0a 369
370 for (i = 0; i < config_size; i++)
504a2217 371 if (!strncmp(config[i].name, key, strlen(config[i].name)))
c2cc9f0a 372 return &config[i];
300df83e 373
c2cc9f0a 374 return NULL;
375}
376
f9373e40
CB
377static int set_config_net(const char *key, const char *value,
378 struct lxc_conf *lxc_conf, void *data)
6b0d5538 379{
663e9916 380 if (!lxc_config_value_empty(value)) {
f9373e40 381 ERROR("lxc.net must not have a value");
6b0d5538
SH
382 return -1;
383 }
384
f9373e40 385 return clr_config_net(key, lxc_conf, data);
6b0d5538
SH
386}
387
f9373e40
CB
388static int set_config_net_type(const char *key, const char *value,
389 struct lxc_conf *lxc_conf, void *data)
c2cc9f0a 390{
070a05af 391 struct lxc_netdev *netdev = data;
c2cc9f0a 392
663e9916 393 if (lxc_config_value_empty(value))
f9373e40 394 return clr_config_net_type(key, lxc_conf, data);
c302b476 395
bbc079cf 396 if (!netdev)
c2cc9f0a 397 return -1;
c2cc9f0a 398
bbc079cf 399 if (!strcmp(value, "veth")) {
24654103 400 netdev->type = LXC_NET_VETH;
bbc079cf 401 } else if (!strcmp(value, "macvlan")) {
24654103 402 netdev->type = LXC_NET_MACVLAN;
9b0df30f
CB
403 lxc_macvlan_mode_to_flag(&netdev->priv.macvlan_attr.mode,
404 "private");
bbc079cf 405 } else if (!strcmp(value, "vlan")) {
24654103 406 netdev->type = LXC_NET_VLAN;
bbc079cf 407 } else if (!strcmp(value, "phys")) {
24654103 408 netdev->type = LXC_NET_PHYS;
bbc079cf 409 } else if (!strcmp(value, "empty")) {
24654103 410 netdev->type = LXC_NET_EMPTY;
bbc079cf 411 } else if (!strcmp(value, "none")) {
26b797f3 412 netdev->type = LXC_NET_NONE;
bbc079cf 413 } else {
36eb9bde 414 ERROR("invalid network type %s", value);
c2cc9f0a 415 return -1;
416 }
bbc079cf 417
c2cc9f0a 418 return 0;
419}
420
f9373e40
CB
421static int set_config_net_flags(const char *key, const char *value,
422 struct lxc_conf *lxc_conf, void *data)
c2cc9f0a 423{
070a05af 424 struct lxc_netdev *netdev = data;
c2cc9f0a 425
9d4bf22d 426 if (lxc_config_value_empty(value))
f9373e40 427 return clr_config_net_flags(key, lxc_conf, data);
9d4bf22d 428
33c945e0 429 if (!netdev)
c2cc9f0a 430 return -1;
c2cc9f0a 431
33c945e0 432 netdev->flags |= IFF_UP;
c2cc9f0a 433
33c945e0
MT
434 return 0;
435}
436
b45e32f9 437static int create_matched_ifnames(const char *value, struct lxc_conf *lxc_conf,
d5aba460 438 struct lxc_netdev *netdev)
576400e5 439{
440 struct ifaddrs *ifaddr, *ifa;
504a2217
CB
441 int n;
442 int ret = 0;
f9373e40
CB
443 const char *type_key = "lxc.net.type";
444 const char *link_key = "lxc.net.link";
576400e5 445 const char *tmpvalue = "phys";
576400e5 446
447 if (getifaddrs(&ifaddr) == -1) {
448 SYSERROR("Get network interfaces failed");
449 return -1;
450 }
451
452 for (ifa = ifaddr, n = 0; ifa != NULL; ifa = ifa->ifa_next, n++) {
453 if (!ifa->ifa_addr)
454 continue;
455 if (ifa->ifa_addr->sa_family != AF_PACKET)
456 continue;
457
504a2217 458 if (!strncmp(value, ifa->ifa_name, strlen(value) - 1)) {
f9373e40
CB
459 ret = set_config_net_type(type_key, tmpvalue, lxc_conf,
460 netdev);
576400e5 461 if (!ret) {
f9373e40 462 ret = set_config_net_link(
c302b476 463 link_key, ifa->ifa_name, lxc_conf, netdev);
576400e5 464 if (ret) {
465 ERROR("failed to create matched ifnames");
466 break;
467 }
468 } else {
469 ERROR("failed to create matched ifnames");
470 break;
471 }
472 }
473 }
474
504a2217
CB
475 freeifaddrs(ifaddr);
476 ifaddr = NULL;
091045f8 477
576400e5 478 return ret;
479}
480
f9373e40
CB
481static int set_config_net_link(const char *key, const char *value,
482 struct lxc_conf *lxc_conf, void *data)
33c945e0 483{
070a05af 484 struct lxc_netdev *netdev = data;
576400e5 485 int ret = 0;
33c945e0 486
6bed0fb6 487 if (lxc_config_value_empty(value))
f9373e40 488 return clr_config_net_link(key, lxc_conf, data);
6bed0fb6 489
33c945e0 490 if (!netdev)
c2cc9f0a 491 return -1;
c2cc9f0a 492
b45e32f9
CB
493 if (value[strlen(value) - 1] == '+' && netdev->type == LXC_NET_PHYS)
494 ret = create_matched_ifnames(value, lxc_conf, netdev);
495 else
de4855a8 496 ret = network_ifname(netdev->link, value);
576400e5 497
498 return ret;
c2cc9f0a 499}
500
f9373e40
CB
501static int set_config_net_name(const char *key, const char *value,
502 struct lxc_conf *lxc_conf, void *data)
c2cc9f0a 503{
070a05af 504 struct lxc_netdev *netdev = data;
c2cc9f0a 505
6bed0fb6 506 if (lxc_config_value_empty(value))
f9373e40 507 return clr_config_net_name(key, lxc_conf, data);
6bed0fb6 508
33c945e0 509 if (!netdev)
c2cc9f0a 510 return -1;
c2cc9f0a 511
de4855a8 512 return network_ifname(netdev->name, value);
33c945e0
MT
513}
514
f9373e40
CB
515static int set_config_net_veth_pair(const char *key, const char *value,
516 struct lxc_conf *lxc_conf, void *data)
e892973e 517{
070a05af 518 struct lxc_netdev *netdev = data;
e892973e 519
6bed0fb6 520 if (lxc_config_value_empty(value))
f9373e40 521 return clr_config_net_veth_pair(key, lxc_conf, data);
6bed0fb6 522
e892973e
DL
523 if (!netdev)
524 return -1;
525
de4855a8 526 return network_ifname(netdev->priv.veth_attr.pair, value);
e892973e
DL
527}
528
f9373e40
CB
529static int set_config_net_macvlan_mode(const char *key, const char *value,
530 struct lxc_conf *lxc_conf, void *data)
8634bc19 531{
070a05af 532 struct lxc_netdev *netdev = data;
8634bc19 533
6bed0fb6 534 if (lxc_config_value_empty(value))
f9373e40 535 return clr_config_net_macvlan_mode(key, lxc_conf, data);
6bed0fb6 536
8634bc19
MT
537 if (!netdev)
538 return -1;
539
9b0df30f 540 return lxc_macvlan_mode_to_flag(&netdev->priv.macvlan_attr.mode, value);
8634bc19
MT
541}
542
f9373e40
CB
543static int set_config_net_hwaddr(const char *key, const char *value,
544 struct lxc_conf *lxc_conf, void *data)
33c945e0 545{
070a05af 546 struct lxc_netdev *netdev = data;
504a2217 547 char *new_value;
33c945e0 548
6bed0fb6 549 if (lxc_config_value_empty(value))
f9373e40 550 return clr_config_net_hwaddr(key, lxc_conf, data);
6bed0fb6 551
ecbb3790
CB
552 if (!netdev)
553 return -1;
554
504a2217 555 new_value = strdup(value);
d5aba460 556 if (!new_value)
c2cc9f0a 557 return -1;
d5aba460 558
508c263e 559 rand_complete_hwaddr(new_value);
c2cc9f0a 560
663e9916 561 if (lxc_config_value_empty(new_value)) {
508c263e
SH
562 free(new_value);
563 netdev->hwaddr = NULL;
564 return 0;
565 }
566
567 netdev->hwaddr = new_value;
568 return 0;
c2cc9f0a 569}
570
f9373e40
CB
571static int set_config_net_vlan_id(const char *key, const char *value,
572 struct lxc_conf *lxc_conf, void *data)
26c39028 573{
d5aba460 574 int ret;
070a05af 575 struct lxc_netdev *netdev = data;
26c39028 576
6bed0fb6 577 if (lxc_config_value_empty(value))
f9373e40 578 return clr_config_net_vlan_id(key, lxc_conf, data);
6bed0fb6 579
26c39028
JHS
580 if (!netdev)
581 return -1;
582
d5aba460
CB
583 ret = get_u16(&netdev->priv.vlan_attr.vid, value, 0);
584 if (ret < 0)
26c39028
JHS
585 return -1;
586
587 return 0;
588}
589
f9373e40
CB
590static int set_config_net_mtu(const char *key, const char *value,
591 struct lxc_conf *lxc_conf, void *data)
442cbbe6 592{
070a05af 593 struct lxc_netdev *netdev = data;
442cbbe6 594
6bed0fb6 595 if (lxc_config_value_empty(value))
f9373e40 596 return clr_config_net_mtu(key, lxc_conf, data);
6bed0fb6 597
33c945e0 598 if (!netdev)
442cbbe6 599 return -1;
442cbbe6 600
713046e3 601 return set_config_string_item(&netdev->mtu, value);
442cbbe6
TR
602}
603
9ff60df2
CB
604static int set_config_net_ipv4_address(const char *key, const char *value,
605 struct lxc_conf *lxc_conf, void *data)
c2cc9f0a 606{
d5aba460 607 int ret;
070a05af 608 struct lxc_netdev *netdev = data;
33c945e0 609 struct lxc_inetdev *inetdev;
c2cc9f0a 610 struct lxc_list *list;
504a2217
CB
611 char *cursor, *slash;
612 char *addr = NULL, *bcast = NULL, *prefix = NULL;
c2cc9f0a 613
663e9916 614 if (lxc_config_value_empty(value))
9ff60df2 615 return clr_config_net_ipv4_address(key, lxc_conf, data);
0797e123 616
33c945e0 617 if (!netdev)
c2cc9f0a 618 return -1;
c2cc9f0a 619
620 inetdev = malloc(sizeof(*inetdev));
d5aba460 621 if (!inetdev)
c2cc9f0a 622 return -1;
d5aba460 623
c2cc9f0a 624 memset(inetdev, 0, sizeof(*inetdev));
625
626 list = malloc(sizeof(*list));
627 if (!list) {
53719062 628 free(inetdev);
c2cc9f0a 629 return -1;
630 }
631
632 lxc_list_init(list);
633 list->elem = inetdev;
634
956edc54
SG
635 addr = strdup(value);
636 if (!addr) {
53719062
SH
637 free(inetdev);
638 free(list);
956edc54
SG
639 return -1;
640 }
c2cc9f0a 641
642 cursor = strstr(addr, " ");
643 if (cursor) {
644 *cursor = '\0';
645 bcast = cursor + 1;
646 }
647
648 slash = strstr(addr, "/");
649 if (slash) {
650 *slash = '\0';
651 prefix = slash + 1;
652 }
653
d5aba460
CB
654 ret = inet_pton(AF_INET, addr, &inetdev->addr);
655 if (!ret || ret < 0) {
656 SYSERROR("Invalid ipv4 address \"%s\"", value);
53719062 657 free(inetdev);
956edc54 658 free(addr);
53719062 659 free(list);
c2cc9f0a 660 return -1;
661 }
662
d5aba460
CB
663 if (bcast) {
664 ret = inet_pton(AF_INET, bcast, &inetdev->bcast);
665 if (!ret || ret < 0) {
666 SYSERROR("Invalid ipv4 broadcast address \"%s\"", value);
667 free(inetdev);
668 free(list);
669 free(addr);
670 return -1;
671 }
672
0093bb8c 673 }
c2cc9f0a 674
504a2217 675 /* No prefix specified, determine it from the network class. */
1c633398 676 if (prefix) {
d5aba460
CB
677 ret = lxc_safe_uint(prefix, &inetdev->prefix);
678 if (ret < 0)
1c633398
CB
679 return -1;
680 } else {
681 inetdev->prefix = config_ip_prefix(&inetdev->addr);
682 }
a059591e 683
504a2217
CB
684 /* If no broadcast address, let compute one from the
685 * prefix and address.
0093bb8c
DL
686 */
687 if (!bcast) {
1b7d4743 688 inetdev->bcast.s_addr = inetdev->addr.s_addr;
d5aba460 689 inetdev->bcast.s_addr |= htonl(INADDR_BROADCAST >> inetdev->prefix);
0093bb8c 690 }
c2cc9f0a 691
8538f388 692 lxc_list_add_tail(&netdev->ipv4, list);
c2cc9f0a 693
956edc54 694 free(addr);
c2cc9f0a 695 return 0;
696}
697
f9373e40
CB
698static int set_config_net_ipv4_gateway(const char *key, const char *value,
699 struct lxc_conf *lxc_conf, void *data)
f8fee0e2 700{
070a05af 701 struct lxc_netdev *netdev = data;
f8fee0e2 702
6bed0fb6 703 if (lxc_config_value_empty(value))
f9373e40 704 return clr_config_net_ipv4_gateway(key, lxc_conf, data);
6bed0fb6 705
f8fee0e2
MK
706 if (!netdev)
707 return -1;
708
e088e926 709 free(netdev->ipv4_gateway);
f8fee0e2 710
ab6faf2e 711 if (!strcmp(value, "auto")) {
19a26f82
MK
712 netdev->ipv4_gateway = NULL;
713 netdev->ipv4_gateway_auto = true;
714 } else {
25a908b8 715 int ret;
e088e926
SG
716 struct in_addr *gw;
717
718 gw = malloc(sizeof(*gw));
25a908b8 719 if (!gw)
e088e926 720 return -1;
e088e926 721
25a908b8
CB
722 ret = inet_pton(AF_INET, value, gw);
723 if (!ret || ret < 0) {
724 SYSERROR("Invalid ipv4 gateway address \"%s\"", value);
53719062 725 free(gw);
19a26f82
MK
726 return -1;
727 }
728
729 netdev->ipv4_gateway = gw;
730 netdev->ipv4_gateway_auto = false;
f8fee0e2
MK
731 }
732
f8fee0e2
MK
733 return 0;
734}
735
2e44ae28
CB
736static int set_config_net_ipv6_address(const char *key, const char *value,
737 struct lxc_conf *lxc_conf, void *data)
c2cc9f0a 738{
25a908b8 739 int ret;
070a05af 740 struct lxc_netdev *netdev = data;
c2cc9f0a 741 struct lxc_inet6dev *inet6dev;
742 struct lxc_list *list;
504a2217 743 char *slash, *valdup, *netmask;
c2cc9f0a 744
6bed0fb6 745 if (lxc_config_value_empty(value))
2e44ae28 746 return clr_config_net_ipv6_address(key, lxc_conf, data);
6bed0fb6 747
33c945e0 748 if (!netdev)
c2cc9f0a 749 return -1;
c2cc9f0a 750
751 inet6dev = malloc(sizeof(*inet6dev));
25a908b8 752 if (!inet6dev)
c2cc9f0a 753 return -1;
25a908b8 754
c2cc9f0a 755 memset(inet6dev, 0, sizeof(*inet6dev));
756
757 list = malloc(sizeof(*list));
758 if (!list) {
28027320 759 free(inet6dev);
c2cc9f0a 760 return -1;
761 }
762
763 lxc_list_init(list);
764 list->elem = inet6dev;
765
956edc54
SG
766 valdup = strdup(value);
767 if (!valdup) {
28027320
SH
768 free(list);
769 free(inet6dev);
956edc54
SG
770 return -1;
771 }
772
a059591e 773 inet6dev->prefix = 64;
12a50cc6 774 slash = strstr(valdup, "/");
c2cc9f0a 775 if (slash) {
776 *slash = '\0';
777 netmask = slash + 1;
f54f8d0b
CB
778 ret = lxc_safe_uint(netmask, &inet6dev->prefix);
779 if (ret < 0) {
780 free(list);
781 free(inet6dev);
782 free(valdup);
1c633398 783 return -1;
f54f8d0b 784 }
c2cc9f0a 785 }
786
25a908b8
CB
787 ret = inet_pton(AF_INET6, valdup, &inet6dev->addr);
788 if (!ret || ret < 0) {
789 SYSERROR("Invalid ipv6 address \"%s\"", valdup);
28027320
SH
790 free(list);
791 free(inet6dev);
956edc54 792 free(valdup);
c2cc9f0a 793 return -1;
794 }
795
8538f388 796 lxc_list_add_tail(&netdev->ipv6, list);
c2cc9f0a 797
956edc54 798 free(valdup);
c2cc9f0a 799 return 0;
800}
801
f9373e40
CB
802static int set_config_net_ipv6_gateway(const char *key, const char *value,
803 struct lxc_conf *lxc_conf, void *data)
f8fee0e2 804{
070a05af 805 struct lxc_netdev *netdev = data;
f8fee0e2 806
6bed0fb6 807 if (lxc_config_value_empty(value))
f9373e40 808 return clr_config_net_ipv6_gateway(key, lxc_conf, data);
6bed0fb6 809
f8fee0e2
MK
810 if (!netdev)
811 return -1;
812
e088e926 813 free(netdev->ipv6_gateway);
f8fee0e2 814
ab6faf2e 815 if (!strcmp(value, "auto")) {
19a26f82
MK
816 netdev->ipv6_gateway = NULL;
817 netdev->ipv6_gateway_auto = true;
818 } else {
25a908b8 819 int ret;
8fb86a37
SH
820 struct in6_addr *gw;
821
bec695f3 822 gw = malloc(sizeof(*gw));
25a908b8 823 if (!gw)
bec695f3 824 return -1;
bec695f3 825
25a908b8
CB
826 ret = inet_pton(AF_INET6, value, gw);
827 if (!ret || ret < 0) {
828 SYSERROR("Invalid ipv6 gateway address \"%s\"", value);
28027320 829 free(gw);
19a26f82
MK
830 return -1;
831 }
832
833 netdev->ipv6_gateway = gw;
834 netdev->ipv6_gateway_auto = false;
f8fee0e2
MK
835 }
836
f8fee0e2
MK
837 return 0;
838}
839
f9373e40
CB
840static int set_config_net_script_up(const char *key, const char *value,
841 struct lxc_conf *lxc_conf, void *data)
e3b4c4c4 842{
070a05af 843 struct lxc_netdev *netdev = data;
e3b4c4c4 844
6bed0fb6 845 if (lxc_config_value_empty(value))
f9373e40 846 return clr_config_net_script_up(key, lxc_conf, data);
6bed0fb6 847
e3b4c4c4 848 if (!netdev)
504a2217 849 return -1;
e3b4c4c4 850
713046e3 851 return set_config_string_item(&netdev->upscript, value);
8fc8295a
DE
852}
853
f9373e40
CB
854static int set_config_net_script_down(const char *key, const char *value,
855 struct lxc_conf *lxc_conf, void *data)
8fc8295a 856{
070a05af 857 struct lxc_netdev *netdev = data;
8fc8295a 858
6bed0fb6 859 if (lxc_config_value_empty(value))
f9373e40 860 return clr_config_net_script_down(key, lxc_conf, data);
6bed0fb6 861
8fc8295a 862 if (!netdev)
504a2217 863 return -1;
8fc8295a 864
713046e3 865 return set_config_string_item(&netdev->downscript, value);
e3b4c4c4
ST
866}
867
26ddeedd
SH
868static int add_hook(struct lxc_conf *lxc_conf, int which, char *hook)
869{
870 struct lxc_list *hooklist;
871
872 hooklist = malloc(sizeof(*hooklist));
873 if (!hooklist) {
874 free(hook);
875 return -1;
876 }
504a2217 877
26ddeedd
SH
878 hooklist->elem = hook;
879 lxc_list_add_tail(&lxc_conf->hooks[which], hooklist);
880 return 0;
881}
882
0b427da0
CB
883static int set_config_seccomp_profile(const char *key, const char *value,
884 struct lxc_conf *lxc_conf, void *data)
8f2c3a70 885{
713046e3 886 return set_config_path_item(&lxc_conf->seccomp, value);
8f2c3a70
SH
887}
888
5cda27c1
SH
889static int set_config_execute_cmd(const char *key, const char *value,
890 struct lxc_conf *lxc_conf, void *data)
891{
892 return set_config_path_item(&lxc_conf->execute_cmd, value);
893}
894
713046e3 895static int set_config_init_cmd(const char *key, const char *value,
c7e27aaf 896 struct lxc_conf *lxc_conf, void *data)
67c660d0 897{
713046e3 898 return set_config_path_item(&lxc_conf->init_cmd, value);
67c660d0
SG
899}
900
3c491553
L
901static int set_config_init_cwd(const char *key, const char *value,
902 struct lxc_conf *lxc_conf, void *data)
903{
904 return set_config_path_item(&lxc_conf->init_cwd, value);
905}
906
713046e3 907static int set_config_init_uid(const char *key, const char *value,
c7e27aaf 908 struct lxc_conf *lxc_conf, void *data)
72bb04e4 909{
d1e5d636
CB
910 unsigned int init_uid;
911
663e9916 912 if (lxc_config_value_empty(value)) {
2e7cde40 913 lxc_conf->init_uid = 0;
fee80911 914 return 0;
2e7cde40 915 }
fee80911 916
d1e5d636
CB
917 if (lxc_safe_uint(value, &init_uid) < 0)
918 return -1;
25a908b8 919
d1e5d636
CB
920 lxc_conf->init_uid = init_uid;
921
72bb04e4
PT
922 return 0;
923}
924
713046e3 925static int set_config_init_gid(const char *key, const char *value,
c7e27aaf 926 struct lxc_conf *lxc_conf, void *data)
72bb04e4 927{
d1e5d636
CB
928 unsigned int init_gid;
929
663e9916 930 if (lxc_config_value_empty(value)) {
2debb6e6 931 lxc_conf->init_gid = 0;
a757cc7d 932 return 0;
2debb6e6 933 }
a757cc7d 934
d1e5d636
CB
935 if (lxc_safe_uint(value, &init_gid) < 0)
936 return -1;
25a908b8 937
d1e5d636
CB
938 lxc_conf->init_gid = init_gid;
939
72bb04e4
PT
940 return 0;
941}
942
466c2e93 943static int set_config_hooks(const char *key, const char *value,
c7e27aaf 944 struct lxc_conf *lxc_conf, void *data)
26ddeedd 945{
7d0eb87e 946 char *copy;
72bb04e4 947
663e9916 948 if (lxc_config_value_empty(value))
7d0eb87e
SH
949 return lxc_clear_hooks(lxc_conf, key);
950
a182feae 951 if (strcmp(key + 4, "hook") == 0) {
25a908b8 952 ERROR("lxc.hook must not have a value");
6b0d5538
SH
953 return -1;
954 }
25a908b8 955
7d0eb87e 956 copy = strdup(value);
25a908b8 957 if (!copy)
26ddeedd 958 return -1;
504a2217 959
a182feae 960 if (strcmp(key + 9, "pre-start") == 0)
26ddeedd 961 return add_hook(lxc_conf, LXCHOOK_PRESTART, copy);
08dd2805
SH
962 else if (strcmp(key + 9, "start-host") == 0)
963 return add_hook(lxc_conf, LXCHOOK_START_HOST, copy);
a182feae 964 else if (strcmp(key + 9, "pre-mount") == 0)
5ea6163a 965 return add_hook(lxc_conf, LXCHOOK_PREMOUNT, copy);
a182feae 966 else if (strcmp(key + 9, "autodev") == 0)
f7bee6c6 967 return add_hook(lxc_conf, LXCHOOK_AUTODEV, copy);
a182feae 968 else if (strcmp(key + 9, "mount") == 0)
26ddeedd 969 return add_hook(lxc_conf, LXCHOOK_MOUNT, copy);
a182feae 970 else if (strcmp(key + 9, "start") == 0)
26ddeedd 971 return add_hook(lxc_conf, LXCHOOK_START, copy);
a182feae 972 else if (strcmp(key + 9, "stop") == 0)
52492063 973 return add_hook(lxc_conf, LXCHOOK_STOP, copy);
a182feae 974 else if (strcmp(key + 9, "post-stop") == 0)
26ddeedd 975 return add_hook(lxc_conf, LXCHOOK_POSTSTOP, copy);
a182feae 976 else if (strcmp(key + 9, "clone") == 0)
148e91f5 977 return add_hook(lxc_conf, LXCHOOK_CLONE, copy);
a182feae 978 else if (strcmp(key + 9, "destroy") == 0)
37cf711b 979 return add_hook(lxc_conf, LXCHOOK_DESTROY, copy);
504a2217 980
26ddeedd
SH
981 free(copy);
982 return -1;
983}
984
44ae0fb6
CB
985static int set_config_hooks_version(const char *key, const char *value,
986 struct lxc_conf *lxc_conf, void *data)
987{
988 int ret;
989 unsigned int tmp;
990
991 if (lxc_config_value_empty(value))
992 return clr_config_hooks_version(key, lxc_conf, NULL);
993
994 ret = lxc_safe_uint(value, &tmp);
995 if (ret < 0)
996 return -1;
997
998 if (tmp > 1) {
999 ERROR("Invalid hook version specified. Currently only 0 "
1000 "(legacy) and 1 are supported");
1001 return -1;
1002 }
1003
1004 lxc_conf->hooks_version = tmp;
1005 return 0;
1006}
1007
713046e3 1008static int set_config_personality(const char *key, const char *value,
c7e27aaf 1009 struct lxc_conf *lxc_conf, void *data)
cccc74b5 1010{
525f0002 1011 signed long personality = lxc_config_parse_arch(value);
cccc74b5 1012
525f0002
CS
1013 if (personality >= 0)
1014 lxc_conf->personality = personality;
1015 else
25a908b8 1016 WARN("Unsupported personality \"%s\"", value);
970ab589
DL
1017
1018 return 0;
cccc74b5
DL
1019}
1020
232763d6
CB
1021static int set_config_pty_max(const char *key, const char *value,
1022 struct lxc_conf *lxc_conf, void *data)
10db618d 1023{
663e9916 1024 if (lxc_config_value_empty(value)) {
ec200ce9 1025 lxc_conf->pts = 0;
884a4580 1026 return 0;
ec200ce9 1027 }
884a4580 1028
17919969
CB
1029 if (lxc_safe_uint(value, &lxc_conf->pts) < 0)
1030 return -1;
10db618d 1031
1032 return 0;
1033}
1034
a182feae
CB
1035/* We only need to check whether the first byte of the key after the lxc.start.
1036 * prefix matches our expectations since they fortunately all start with a
1037 * different letter. If anything was wrong with the key we would have already
1038 * noticed when the callback was called.
1039 */
713046e3 1040static int set_config_start(const char *key, const char *value,
c7e27aaf 1041 struct lxc_conf *lxc_conf, void *data)
ee1e7aa0 1042{
ebb80f95
CB
1043 bool is_empty;
1044
663e9916 1045 is_empty = lxc_config_value_empty(value);
ebb80f95 1046
a182feae 1047 if (*(key + 10) == 'a') { /* lxc.start.auto */
ebb80f95
CB
1048 if (is_empty) {
1049 lxc_conf->start_auto = 0;
1050 return 0;
1051 }
61ff8fc8 1052
3590152f
CB
1053 if (lxc_safe_uint(value, &lxc_conf->start_auto) < 0)
1054 return -1;
ebb80f95 1055
3590152f
CB
1056 if (lxc_conf->start_auto > 1)
1057 return -1;
ebb80f95 1058
ee1e7aa0 1059 return 0;
a182feae 1060 } else if (*(key + 10) == 'd') { /* lxc.start.delay */
ebb80f95
CB
1061 if (is_empty) {
1062 lxc_conf->start_delay = 0;
1063 return 0;
1064 }
1065
ebb80f95 1066 return lxc_safe_uint(value, &lxc_conf->start_delay);
a182feae 1067 } else if (*(key + 10) == 'o') { /* lxc.start.order */
ebb80f95
CB
1068 if (is_empty) {
1069 lxc_conf->start_order = 0;
1070 return 0;
1071 }
1072
ebb80f95 1073 return lxc_safe_int(value, &lxc_conf->start_order);
ee1e7aa0 1074 }
ebb80f95 1075
ee1e7aa0
SG
1076 return -1;
1077}
1078
713046e3 1079static int set_config_monitor(const char *key, const char *value,
c7e27aaf 1080 struct lxc_conf *lxc_conf, void *data)
a8dfe4e0 1081{
663e9916 1082 if (lxc_config_value_empty(value)) {
4ad9cd26 1083 lxc_conf->monitor_unshare = 0;
a8dfe4e0
WB
1084 return 0;
1085 }
4ad9cd26 1086
a182feae 1087 if (strcmp(key + 12, "unshare") == 0)
4ad9cd26
CB
1088 return lxc_safe_uint(value, &lxc_conf->monitor_unshare);
1089
a8dfe4e0
WB
1090 return -1;
1091}
1092
713046e3 1093static int set_config_group(const char *key, const char *value,
c7e27aaf 1094 struct lxc_conf *lxc_conf, void *data)
ee1e7aa0
SG
1095{
1096 char *groups, *groupptr, *sptr, *token;
1097 struct lxc_list *grouplist;
1098 int ret = -1;
1099
663e9916 1100 if (lxc_config_value_empty(value))
ee1e7aa0
SG
1101 return lxc_clear_groups(lxc_conf);
1102
1103 groups = strdup(value);
25a908b8 1104 if (!groups)
ee1e7aa0 1105 return -1;
ee1e7aa0 1106
25a908b8
CB
1107 /* In case several groups are specified in a single line split these
1108 * groups in a single element for the list.
504a2217
CB
1109 */
1110 for (groupptr = groups;; groupptr = NULL) {
d028235d
SG
1111 token = strtok_r(groupptr, " \t", &sptr);
1112 if (!token) {
ee1e7aa0 1113 ret = 0;
d028235d 1114 break;
ee1e7aa0
SG
1115 }
1116
1117 grouplist = malloc(sizeof(*grouplist));
25a908b8 1118 if (!grouplist)
ee1e7aa0 1119 break;
ee1e7aa0
SG
1120
1121 grouplist->elem = strdup(token);
1122 if (!grouplist->elem) {
ee1e7aa0
SG
1123 free(grouplist);
1124 break;
1125 }
1126
1127 lxc_list_add_tail(&lxc_conf->groups, grouplist);
d028235d 1128 }
ee1e7aa0
SG
1129
1130 free(groups);
ee1e7aa0
SG
1131 return ret;
1132}
1133
713046e3 1134static int set_config_environment(const char *key, const char *value,
c7e27aaf 1135 struct lxc_conf *lxc_conf, void *data)
7c661726
MP
1136{
1137 struct lxc_list *list_item = NULL;
1138
663e9916 1139 if (lxc_config_value_empty(value))
ab799c0b
SG
1140 return lxc_clear_environment(lxc_conf);
1141
7c661726
MP
1142 list_item = malloc(sizeof(*list_item));
1143 if (!list_item)
504a2217 1144 goto on_error;
7c661726
MP
1145
1146 list_item->elem = strdup(value);
1147
1148 if (!list_item->elem)
504a2217 1149 goto on_error;
7c661726
MP
1150
1151 lxc_list_add_tail(&lxc_conf->environment, list_item);
1152
1153 return 0;
1154
504a2217 1155on_error:
f10fad2f 1156 free(list_item);
7c661726
MP
1157 return -1;
1158}
1159
fe1c5887
CB
1160static int set_config_tty_max(const char *key, const char *value,
1161 struct lxc_conf *lxc_conf, void *data)
b0a33c1e 1162{
663e9916 1163 if (lxc_config_value_empty(value)) {
cb508ee8 1164 lxc_conf->tty = 0;
fb12b12a 1165 return 0;
cb508ee8 1166 }
fb12b12a 1167
cb508ee8 1168 return lxc_safe_uint(value, &lxc_conf->tty);
b0a33c1e 1169}
1170
42e53c29 1171static int set_config_tty_dir(const char *key, const char *value,
c7e27aaf 1172 struct lxc_conf *lxc_conf, void *data)
7c6ef2a2 1173{
504a2217
CB
1174 return set_config_string_item_max(&lxc_conf->ttydir, value,
1175 NAME_MAX + 1);
7c6ef2a2
SH
1176}
1177
953fe44f
CB
1178static int set_config_apparmor_profile(const char *key, const char *value,
1179 struct lxc_conf *lxc_conf, void *data)
e075f5d9 1180{
713046e3 1181 return set_config_string_item(&lxc_conf->lsm_aa_profile, value);
fe4de9a6
DE
1182}
1183
953fe44f
CB
1184static int set_config_apparmor_allow_incomplete(const char *key,
1185 const char *value,
1186 struct lxc_conf *lxc_conf,
1187 void *data)
7aff4f43 1188{
663e9916 1189 if (lxc_config_value_empty(value)) {
cccfa758 1190 lxc_conf->lsm_aa_allow_incomplete = 0;
a678e9fa 1191 return 0;
cccfa758 1192 }
a678e9fa 1193
a56e2df9
CB
1194 if (lxc_safe_uint(value, &lxc_conf->lsm_aa_allow_incomplete) < 0)
1195 return -1;
7aff4f43 1196
25a908b8 1197 if (lxc_conf->lsm_aa_allow_incomplete > 1)
a56e2df9 1198 return -1;
7aff4f43
SH
1199
1200 return 0;
1201}
1202
953fe44f
CB
1203static int set_config_selinux_context(const char *key, const char *value,
1204 struct lxc_conf *lxc_conf, void *data)
fe4de9a6 1205{
713046e3 1206 return set_config_string_item(&lxc_conf->lsm_se_context, value);
e075f5d9 1207}
e075f5d9 1208
46cc906d 1209static int set_config_log_file(const char *key, const char *value,
c7e27aaf 1210 struct lxc_conf *c, void *data)
4a85ce2a 1211{
6d03d92a
DE
1212 int ret;
1213
663e9916 1214 if (lxc_config_value_empty(value)) {
0d601acb
CB
1215 free(c->logfile);
1216 c->logfile = NULL;
1217 return 0;
1218 }
1219
1220 /* Store these values in the lxc_conf, and then try to set for actual
504a2217
CB
1221 * current logging.
1222 */
713046e3 1223 ret = set_config_path_item(&c->logfile, value);
6d03d92a 1224 if (ret == 0)
858377e4 1225 ret = lxc_log_set_file(&c->logfd, c->logfile);
25a908b8 1226
6d03d92a 1227 return ret;
4a85ce2a
SH
1228}
1229
46cc906d 1230static int set_config_log_level(const char *key, const char *value,
c7e27aaf 1231 struct lxc_conf *lxc_conf, void *data)
4a85ce2a 1232{
9ea87d5d
SH
1233 int newlevel;
1234
663e9916 1235 if (lxc_config_value_empty(value)) {
4b73005c 1236 lxc_conf->loglevel = LXC_LOG_LEVEL_NOTSET;
4a85ce2a 1237 return 0;
575b9745 1238 }
4a85ce2a 1239
a56e2df9
CB
1240 if (value[0] >= '0' && value[0] <= '9') {
1241 if (lxc_safe_int(value, &newlevel) < 0)
1242 return -1;
1243 } else {
9ea87d5d 1244 newlevel = lxc_log_priority_to_int(value);
a56e2df9 1245 }
575b9745 1246
504a2217 1247 /* Store these values in the lxc_conf, and then try to set for actual
575b9745
CB
1248 * current logging.
1249 */
b40a606e 1250 lxc_conf->loglevel = newlevel;
858377e4 1251 return lxc_log_set_level(&lxc_conf->loglevel, newlevel);
4a85ce2a
SH
1252}
1253
713046e3 1254static int set_config_autodev(const char *key, const char *value,
c7e27aaf 1255 struct lxc_conf *lxc_conf, void *data)
c6883f38 1256{
663e9916 1257 if (lxc_config_value_empty(value)) {
1045031e 1258 lxc_conf->autodev = 0;
180abbc0 1259 return 0;
1045031e 1260 }
180abbc0 1261
ff6cb4ed
CB
1262 if (lxc_safe_uint(value, &lxc_conf->autodev) < 0)
1263 return -1;
c6883f38 1264
25a908b8 1265 if (lxc_conf->autodev > 1)
ff6cb4ed 1266 return -1;
c6883f38
SH
1267
1268 return 0;
1269}
1270
a84b9932
AV
1271static int sig_num(const char *sig)
1272{
f2e539b3 1273 unsigned int signum;
a84b9932 1274
f2e539b3 1275 if (lxc_safe_uint(sig, &signum) < 0)
a84b9932 1276 return -1;
f2e539b3
CB
1277
1278 return signum;
a84b9932
AV
1279}
1280
1281static int rt_sig_num(const char *signame)
1282{
504a2217 1283 int rtmax = 0, sig_n = 0;
a84b9932
AV
1284
1285 if (strncasecmp(signame, "max-", 4) == 0) {
1286 rtmax = 1;
1287 }
504a2217 1288
a84b9932
AV
1289 signame += 4;
1290 if (!isdigit(*signame))
1291 return -1;
504a2217 1292
a84b9932
AV
1293 sig_n = sig_num(signame);
1294 sig_n = rtmax ? SIGRTMAX - sig_n : SIGRTMIN + sig_n;
1295 if (sig_n > SIGRTMAX || sig_n < SIGRTMIN)
1296 return -1;
504a2217 1297
a84b9932
AV
1298 return sig_n;
1299}
1300
504a2217
CB
1301static int sig_parse(const char *signame)
1302{
84760c11 1303 size_t n;
a84b9932
AV
1304
1305 if (isdigit(*signame)) {
1306 return sig_num(signame);
1307 } else if (strncasecmp(signame, "sig", 3) == 0) {
1308 signame += 3;
1309 if (strncasecmp(signame, "rt", 2) == 0)
1310 return rt_sig_num(signame + 2);
1311 for (n = 0; n < sizeof(signames) / sizeof((signames)[0]); n++) {
504a2217 1312 if (strcasecmp(signames[n].name, signame) == 0)
a84b9932
AV
1313 return signames[n].num;
1314 }
1315 }
504a2217 1316
a84b9932
AV
1317 return -1;
1318}
1319
55c84efc 1320static int set_config_signal_halt(const char *key, const char *value,
c7e27aaf 1321 struct lxc_conf *lxc_conf, void *data)
f0f1d8c0 1322{
62a085fb 1323 int sig_n;
f0f1d8c0 1324
663e9916 1325 if (lxc_config_value_empty(value)) {
c1a64603 1326 lxc_conf->haltsignal = 0;
955912f0 1327 return 0;
c1a64603 1328 }
955912f0 1329
62a085fb 1330 sig_n = sig_parse(value);
f0f1d8c0
DE
1331 if (sig_n < 0)
1332 return -1;
25a908b8 1333
f0f1d8c0
DE
1334 lxc_conf->haltsignal = sig_n;
1335
1336 return 0;
1337}
1338
55c84efc 1339static int set_config_signal_reboot(const char *key, const char *value,
c7e27aaf 1340 struct lxc_conf *lxc_conf, void *data)
dd267776 1341{
9d7e7587 1342 int sig_n;
dd267776 1343
663e9916 1344 if (lxc_config_value_empty(value)) {
18fcee44 1345 lxc_conf->rebootsignal = 0;
9d7e7587 1346 return 0;
18fcee44 1347 }
9d7e7587
CB
1348
1349 sig_n = sig_parse(value);
dd267776
BP
1350 if (sig_n < 0)
1351 return -1;
25a908b8 1352
dd267776
BP
1353 lxc_conf->rebootsignal = sig_n;
1354
1355 return 0;
1356}
1357
55c84efc 1358static int set_config_signal_stop(const char *key, const char *value,
c7e27aaf 1359 struct lxc_conf *lxc_conf, void *data)
a84b9932 1360{
6ca6aedd 1361 int sig_n;
a84b9932 1362
663e9916 1363 if (lxc_config_value_empty(value)) {
4100d1a7 1364 lxc_conf->stopsignal = 0;
6ca6aedd 1365 return 0;
4100d1a7 1366 }
6ca6aedd
CB
1367
1368 sig_n = sig_parse(value);
a84b9932
AV
1369 if (sig_n < 0)
1370 return -1;
25a908b8 1371
a84b9932
AV
1372 lxc_conf->stopsignal = sig_n;
1373
1374 return 0;
1375}
1376
43654d34
CB
1377static int set_config_cgroup_controller(const char *key, const char *value,
1378 struct lxc_conf *lxc_conf, void *data)
576f946d 1379{
576f946d 1380 char *subkey;
504a2217 1381 char *token = "lxc.cgroup.";
bf83c5b9
MS
1382 struct lxc_list *cglist = NULL;
1383 struct lxc_cgroup *cgelem = NULL;
576f946d 1384
663e9916 1385 if (lxc_config_value_empty(value))
7d0eb87e
SH
1386 return lxc_clear_cgroups(lxc_conf, key);
1387
576f946d 1388 subkey = strstr(key, token);
576f946d 1389 if (!subkey)
1390 return -1;
1391
1392 if (!strlen(subkey))
1393 return -1;
1394
1395 if (strlen(subkey) == strlen(token))
1396 return -1;
a871ff6b 1397
576f946d 1398 subkey += strlen(token);
1399
1400 cglist = malloc(sizeof(*cglist));
1401 if (!cglist)
bf83c5b9 1402 goto out;
576f946d 1403
1404 cgelem = malloc(sizeof(*cgelem));
bf83c5b9
MS
1405 if (!cgelem)
1406 goto out;
1407 memset(cgelem, 0, sizeof(*cgelem));
576f946d 1408
1409 cgelem->subsystem = strdup(subkey);
1410 cgelem->value = strdup(value);
bf83c5b9
MS
1411
1412 if (!cgelem->subsystem || !cgelem->value)
1413 goto out;
1414
576f946d 1415 cglist->elem = cgelem;
1416
94d12f0a 1417 lxc_list_add_tail(&lxc_conf->cgroup, cglist);
576f946d 1418
1419 return 0;
bf83c5b9
MS
1420
1421out:
f10fad2f 1422 free(cglist);
bf83c5b9 1423 if (cgelem) {
f10fad2f 1424 free(cgelem->subsystem);
f10fad2f 1425 free(cgelem->value);
bf83c5b9
MS
1426 free(cgelem);
1427 }
1428
1429 return -1;
576f946d 1430}
1431
43654d34
CB
1432static int set_config_cgroup_dir(const char *key, const char *value,
1433 struct lxc_conf *lxc_conf, void *data)
1434{
1435 if (lxc_config_value_empty(value))
1436 return clr_config_cgroup_dir(key, lxc_conf, NULL);
1437
43654d34
CB
1438 return set_config_string_item(&lxc_conf->cgroup_meta.dir, value);
1439}
1440
240d4b74 1441static int set_config_prlimit(const char *key, const char *value,
c7e27aaf 1442 struct lxc_conf *lxc_conf, void *data)
c6d09e15 1443{
c6d09e15
WB
1444 struct lxc_list *iter;
1445 struct rlimit limit;
71460831 1446 rlim_t limit_value;
504a2217
CB
1447 struct lxc_list *limlist = NULL;
1448 struct lxc_limit *limelem = NULL;
c6d09e15 1449
663e9916 1450 if (lxc_config_value_empty(value))
c6d09e15
WB
1451 return lxc_clear_limits(lxc_conf, key);
1452
240d4b74 1453 if (strncmp(key, "lxc.prlimit.", sizeof("lxc.prlimit.") - 1) != 0)
c6d09e15
WB
1454 return -1;
1455
240d4b74 1456 key += sizeof("lxc.prlimit.") - 1;
c6d09e15
WB
1457
1458 /* soft limit comes first in the value */
1459 if (!parse_limit_value(&value, &limit_value))
1460 return -1;
1461 limit.rlim_cur = limit_value;
1462
1463 /* skip spaces and a colon */
1464 while (isspace(*value))
1465 ++value;
504a2217 1466
c6d09e15
WB
1467 if (*value == ':')
1468 ++value;
1469 else if (*value) /* any other character is an error here */
1470 return -1;
504a2217 1471
c6d09e15
WB
1472 while (isspace(*value))
1473 ++value;
1474
1475 /* optional hard limit */
1476 if (*value) {
1477 if (!parse_limit_value(&value, &limit_value))
1478 return -1;
1479 limit.rlim_max = limit_value;
504a2217 1480
c6d09e15
WB
1481 /* check for trailing garbage */
1482 while (isspace(*value))
1483 ++value;
504a2217 1484
c6d09e15
WB
1485 if (*value)
1486 return -1;
1487 } else {
1488 /* a single value sets both hard and soft limit */
1489 limit.rlim_max = limit.rlim_cur;
1490 }
1491
1492 /* find existing list element */
7edd0540 1493 lxc_list_for_each(iter, &lxc_conf->limits) {
c6d09e15
WB
1494 limelem = iter->elem;
1495 if (!strcmp(key, limelem->resource)) {
1496 limelem->limit = limit;
1497 return 0;
1498 }
1499 }
1500
1501 /* allocate list element */
1502 limlist = malloc(sizeof(*limlist));
1503 if (!limlist)
7edd0540 1504 goto on_error;
2e6e3feb 1505
c6d09e15
WB
1506 limelem = malloc(sizeof(*limelem));
1507 if (!limelem)
7edd0540 1508 goto on_error;
c6d09e15
WB
1509 memset(limelem, 0, sizeof(*limelem));
1510
1511 limelem->resource = strdup(key);
1512 if (!limelem->resource)
7edd0540 1513 goto on_error;
c6d09e15
WB
1514 limelem->limit = limit;
1515
7edd0540 1516 lxc_list_add_elem(limlist, limelem);;
c6d09e15
WB
1517
1518 lxc_list_add_tail(&lxc_conf->limits, limlist);
1519
1520 return 0;
1521
7edd0540 1522on_error:
c6d09e15
WB
1523 free(limlist);
1524 if (limelem) {
1525 free(limelem->resource);
1526 free(limelem);
1527 }
1528 return -1;
1529}
1530
7edd0540
L
1531static int set_config_sysctl(const char *key, const char *value,
1532 struct lxc_conf *lxc_conf, void *data)
1533{
1534 struct lxc_list *iter;
e409b214 1535 char *replace_value = NULL;
7edd0540
L
1536 struct lxc_list *sysctl_list = NULL;
1537 struct lxc_sysctl *sysctl_elem = NULL;
7edd0540
L
1538
1539 if (lxc_config_value_empty(value))
e409b214 1540 return clr_config_sysctl(key, lxc_conf, NULL);
7edd0540
L
1541
1542 if (strncmp(key, "lxc.sysctl.", sizeof("lxc.sysctl.") - 1) != 0)
1543 return -1;
1544
1545 key += sizeof("lxc.sysctl.") - 1;
1546
1547 /* find existing list element */
1548 lxc_list_for_each(iter, &lxc_conf->sysctls) {
1549 sysctl_elem = iter->elem;
e409b214
CB
1550
1551 if (strcmp(key, sysctl_elem->key) != 0)
1552 continue;
1553
1554 replace_value = strdup(value);
1555 if (!replace_value)
1556 return -1;
1557
1558 free(sysctl_elem->value);
1559 sysctl_elem->value = replace_value;
1560 return 0;
7edd0540
L
1561 }
1562
1563 /* allocate list element */
1564 sysctl_list = malloc(sizeof(*sysctl_list));
1565 if (!sysctl_list)
1566 goto on_error;
1567
1568 sysctl_elem = malloc(sizeof(*sysctl_elem));
1569 if (!sysctl_elem)
1570 goto on_error;
1571 memset(sysctl_elem, 0, sizeof(*sysctl_elem));
1572
1573 sysctl_elem->key = strdup(key);
1574 if (!sysctl_elem->key)
1575 goto on_error;
1576
1577 sysctl_elem->value = strdup(value);
1578 if (!sysctl_elem->value)
1579 goto on_error;
1580
1581 lxc_list_add_elem(sysctl_list, sysctl_elem);
1582
1583 lxc_list_add_tail(&lxc_conf->sysctls, sysctl_list);
1584
1585 return 0;
1586
1587on_error:
1588 free(sysctl_list);
1589 if (sysctl_elem) {
1590 free(sysctl_elem->key);
1591 free(sysctl_elem->value);
1592 free(sysctl_elem);
1593 }
1594 return -1;
7edd0540
L
1595}
1596
61d7a733
YT
1597static int set_config_proc(const char *key, const char *value,
1598 struct lxc_conf *lxc_conf, void *data)
1599{
1600 const char *subkey;
1601 struct lxc_list *proclist = NULL;
1602 struct lxc_proc *procelem = NULL;
1603
1604 if (lxc_config_value_empty(value))
1605 return clr_config_proc(key, lxc_conf, NULL);
1606
1607 if (strncmp(key, "lxc.proc.", sizeof("lxc.proc.") -1) != 0)
1608 return -1;
1609
1610 subkey = key + sizeof("lxc.proc.") - 1;
1611 if (*subkey == '\0')
1612 return -EINVAL;
1613
1614 proclist = malloc(sizeof(*proclist));
1615 if (!proclist)
1616 goto on_error;
1617
1618 procelem = malloc(sizeof(*procelem));
1619 if (!procelem)
1620 goto on_error;
1621 memset(procelem, 0, sizeof(*procelem));
1622
1623 procelem->filename = strdup(subkey);
1624 procelem->value = strdup(value);
1625
1626 if (!procelem->filename || !procelem->value)
1627 goto on_error;
1628
1629 proclist->elem = procelem;
1630
1631 lxc_list_add_tail(&lxc_conf->procs, proclist);
1632
1633 return 0;
1634
1635on_error:
1636 free(proclist);
1637 if (procelem) {
1638 free(procelem->filename);
1639 free(procelem->value);
1640 free(procelem);
1641 }
1642
1643 return -1;
1644}
1645
5014ff2e 1646static int set_config_idmaps(const char *key, const char *value,
c7e27aaf 1647 struct lxc_conf *lxc_conf, void *data)
f6d3e3e4 1648{
251d0d2a 1649 unsigned long hostid, nsid, range;
f6d3e3e4 1650 char type;
0b843d35 1651 int ret;
34a7a4c6
CB
1652 struct lxc_list *idmaplist = NULL;
1653 struct id_map *idmap = NULL;
f6d3e3e4 1654
663e9916 1655 if (lxc_config_value_empty(value))
7d0eb87e
SH
1656 return lxc_clear_idmaps(lxc_conf);
1657
f6d3e3e4
SH
1658 idmaplist = malloc(sizeof(*idmaplist));
1659 if (!idmaplist)
34a7a4c6 1660 goto on_error;
f6d3e3e4
SH
1661
1662 idmap = malloc(sizeof(*idmap));
1663 if (!idmap)
34a7a4c6 1664 goto on_error;
f6d3e3e4
SH
1665 memset(idmap, 0, sizeof(*idmap));
1666
0b843d35
CB
1667 ret = parse_idmaps(value, &type, &nsid, &hostid, &range);
1668 if (ret < 0)
34a7a4c6
CB
1669 goto on_error;
1670
25a908b8 1671 INFO("Read uid map: type %c nsid %lu hostid %lu range %lu", type, nsid, hostid, range);
ac7725e7 1672 if (type == 'u')
f6d3e3e4 1673 idmap->idtype = ID_TYPE_UID;
ac7725e7 1674 else if (type == 'g')
f6d3e3e4
SH
1675 idmap->idtype = ID_TYPE_GID;
1676 else
34a7a4c6 1677 goto on_error;
7e60c3f0 1678
f6d3e3e4
SH
1679 idmap->hostid = hostid;
1680 idmap->nsid = nsid;
1681 idmap->range = range;
7e60c3f0
SG
1682 idmaplist->elem = idmap;
1683 lxc_list_add_tail(&lxc_conf->id_map, idmaplist);
46ad64ab
CB
1684
1685 if (!lxc_conf->root_nsuid_map && idmap->idtype == ID_TYPE_UID)
1686 if (idmap->nsid == 0)
1687 lxc_conf->root_nsuid_map = idmap;
1688
1689
1690 if (!lxc_conf->root_nsuid_map && idmap->idtype == ID_TYPE_GID)
1691 if (idmap->nsid == 0)
1692 lxc_conf->root_nsgid_map = idmap;
1693
34a7a4c6 1694 idmap = NULL;
7e60c3f0 1695
f6d3e3e4
SH
1696 return 0;
1697
34a7a4c6 1698on_error:
f10fad2f 1699 free(idmaplist);
34a7a4c6 1700 free(idmap);
f6d3e3e4
SH
1701
1702 return -1;
1703}
1704
47148e96
CB
1705static int set_config_mount_fstab(const char *key, const char *value,
1706 struct lxc_conf *lxc_conf, void *data)
d95db067 1707{
663e9916 1708 if (lxc_config_value_empty(value)) {
47148e96 1709 clr_config_mount_fstab(key, lxc_conf, NULL);
d9192f5d 1710 return -1;
46f3de30 1711 }
6f5685f0 1712
713046e3 1713 return set_config_path_item(&lxc_conf->fstab, value);
d95db067
DE
1714}
1715
713046e3 1716static int set_config_mount_auto(const char *key, const char *value,
c7e27aaf 1717 struct lxc_conf *lxc_conf, void *data)
368bbc02
CS
1718{
1719 char *autos, *autoptr, *sptr, *token;
368bbc02
CS
1720 int i;
1721 int ret = -1;
504a2217
CB
1722 static struct {
1723 const char *token;
1724 int mask;
1725 int flag;
1726 } allowed_auto_mounts[] = {
1727 { "proc", LXC_AUTO_PROC_MASK, LXC_AUTO_PROC_MIXED },
1728 { "proc:mixed", LXC_AUTO_PROC_MASK, LXC_AUTO_PROC_MIXED },
1729 { "proc:rw", LXC_AUTO_PROC_MASK, LXC_AUTO_PROC_RW },
1730 { "sys", LXC_AUTO_SYS_MASK, LXC_AUTO_SYS_MIXED },
1731 { "sys:ro", LXC_AUTO_SYS_MASK, LXC_AUTO_SYS_RO },
1732 { "sys:mixed", LXC_AUTO_SYS_MASK, LXC_AUTO_SYS_MIXED },
1733 { "sys:rw", LXC_AUTO_SYS_MASK, LXC_AUTO_SYS_RW },
1734 { "cgroup", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_NOSPEC },
1735 { "cgroup:mixed", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_MIXED },
1736 { "cgroup:ro", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_RO },
1737 { "cgroup:rw", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_RW },
1738 { "cgroup-full", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_FULL_NOSPEC },
1739 { "cgroup-full:mixed", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_FULL_MIXED },
1740 { "cgroup-full:ro", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_FULL_RO },
1741 { "cgroup-full:rw", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_FULL_RW },
25a908b8
CB
1742 /* For adding anything that is just a single on/off, but has no
1743 * options: keep mask and flag identical and just define the enum
1744 * value as an unused bit so far
504a2217
CB
1745 */
1746 { NULL, 0, 0 }
1747 };
368bbc02 1748
663e9916 1749 if (lxc_config_value_empty(value)) {
d9192f5d
SH
1750 lxc_conf->auto_mounts = 0;
1751 return 0;
1752 }
368bbc02
CS
1753
1754 autos = strdup(value);
25a908b8 1755 if (!autos)
368bbc02 1756 return -1;
368bbc02 1757
504a2217 1758 for (autoptr = autos;; autoptr = NULL) {
d028235d
SG
1759 token = strtok_r(autoptr, " \t", &sptr);
1760 if (!token) {
368bbc02 1761 ret = 0;
d028235d 1762 break;
368bbc02
CS
1763 }
1764
1765 for (i = 0; allowed_auto_mounts[i].token; i++) {
1766 if (!strcmp(allowed_auto_mounts[i].token, token))
1767 break;
1768 }
1769
1770 if (!allowed_auto_mounts[i].token) {
25a908b8 1771 ERROR("Invalid filesystem to automount \"%s\"", token);
368bbc02
CS
1772 break;
1773 }
1774
b06b8511 1775 lxc_conf->auto_mounts &= ~allowed_auto_mounts[i].mask;
368bbc02 1776 lxc_conf->auto_mounts |= allowed_auto_mounts[i].flag;
d028235d 1777 }
368bbc02
CS
1778
1779 free(autos);
368bbc02
CS
1780 return ret;
1781}
1782
713046e3 1783static int set_config_mount(const char *key, const char *value,
c7e27aaf 1784 struct lxc_conf *lxc_conf, void *data)
e7938e9e 1785{
e7938e9e
MN
1786 char *mntelem;
1787 struct lxc_list *mntlist;
1788
663e9916 1789 if (lxc_config_value_empty(value))
d9192f5d 1790 return lxc_clear_mount_entries(lxc_conf);
e7938e9e
MN
1791
1792 mntlist = malloc(sizeof(*mntlist));
1793 if (!mntlist)
1794 return -1;
1795
1796 mntelem = strdup(value);
00b6be44
SH
1797 if (!mntelem) {
1798 free(mntlist);
bf83c5b9 1799 return -1;
00b6be44 1800 }
e7938e9e
MN
1801 mntlist->elem = mntelem;
1802
1803 lxc_list_add_tail(&lxc_conf->mount_list, mntlist);
1804
1805 return 0;
1806}
1807
713046e3 1808static int set_config_cap_keep(const char *key, const char *value,
c7e27aaf 1809 struct lxc_conf *lxc_conf, void *data)
1fb86a7c
SH
1810{
1811 char *keepcaps, *keepptr, *sptr, *token;
1812 struct lxc_list *keeplist;
1813 int ret = -1;
1814
663e9916 1815 if (lxc_config_value_empty(value))
7d0eb87e 1816 return lxc_clear_config_keepcaps(lxc_conf);
1fb86a7c
SH
1817
1818 keepcaps = strdup(value);
25a908b8 1819 if (!keepcaps)
1fb86a7c 1820 return -1;
1fb86a7c 1821
504a2217
CB
1822 /* In case several capability keep is specified in a single line
1823 * split these caps in a single element for the list.
1824 */
1825 for (keepptr = keepcaps;; keepptr = NULL) {
d028235d
SG
1826 token = strtok_r(keepptr, " \t", &sptr);
1827 if (!token) {
1fb86a7c 1828 ret = 0;
d028235d 1829 break;
1fb86a7c
SH
1830 }
1831
7035407c
DE
1832 if (!strcmp(token, "none"))
1833 lxc_clear_config_keepcaps(lxc_conf);
1834
1fb86a7c 1835 keeplist = malloc(sizeof(*keeplist));
25a908b8 1836 if (!keeplist)
1fb86a7c 1837 break;
1fb86a7c
SH
1838
1839 keeplist->elem = strdup(token);
1840 if (!keeplist->elem) {
1fb86a7c
SH
1841 free(keeplist);
1842 break;
1843 }
1844
1845 lxc_list_add_tail(&lxc_conf->keepcaps, keeplist);
d028235d 1846 }
1fb86a7c
SH
1847
1848 free(keepcaps);
1849
1850 return ret;
1851}
1852
713046e3 1853static int set_config_cap_drop(const char *key, const char *value,
c7e27aaf 1854 struct lxc_conf *lxc_conf, void *data)
81810dd1 1855{
d95db067 1856 char *dropcaps, *dropptr, *sptr, *token;
81810dd1
DL
1857 struct lxc_list *droplist;
1858 int ret = -1;
1859
663e9916 1860 if (lxc_config_value_empty(value))
7d0eb87e 1861 return lxc_clear_config_caps(lxc_conf);
81810dd1
DL
1862
1863 dropcaps = strdup(value);
25a908b8 1864 if (!dropcaps)
81810dd1 1865 return -1;
81810dd1 1866
504a2217
CB
1867 /* In case several capability drop is specified in a single line
1868 * split these caps in a single element for the list.
1869 */
1870 for (dropptr = dropcaps;; dropptr = NULL) {
d028235d
SG
1871 token = strtok_r(dropptr, " \t", &sptr);
1872 if (!token) {
81810dd1 1873 ret = 0;
d028235d 1874 break;
81810dd1 1875 }
81810dd1
DL
1876
1877 droplist = malloc(sizeof(*droplist));
25a908b8 1878 if (!droplist)
81810dd1 1879 break;
81810dd1
DL
1880
1881 droplist->elem = strdup(token);
1882 if (!droplist->elem) {
81810dd1
DL
1883 free(droplist);
1884 break;
1885 }
1886
1887 lxc_list_add_tail(&lxc_conf->caps, droplist);
d028235d 1888 }
81810dd1
DL
1889
1890 free(dropcaps);
1891
1892 return ret;
1893}
1894
3aed4934
CB
1895static int set_config_console_path(const char *key, const char *value,
1896 struct lxc_conf *lxc_conf, void *data)
28a4b0e5 1897{
713046e3 1898 return set_config_path_item(&lxc_conf->console.path, value);
28a4b0e5
DL
1899}
1900
d91adfa6
CB
1901static int set_config_console_rotate(const char *key, const char *value,
1902 struct lxc_conf *lxc_conf, void *data)
1903{
1904 if (lxc_config_value_empty(value)) {
1905 lxc_conf->console.log_rotate = 0;
1906 return 0;
1907 }
1908
1909 if (lxc_safe_uint(value, &lxc_conf->console.log_rotate) < 0)
1910 return -1;
1911
966b9ecd
CB
1912 if (lxc_conf->console.log_rotate > 1) {
1913 ERROR("The \"lxc.console.rotate\" config key can only be set "
1914 "to 0 or 1");
d91adfa6 1915 return -1;
966b9ecd 1916 }
d91adfa6
CB
1917
1918 return 0;
1919}
1920
713046e3 1921static int set_config_console_logfile(const char *key, const char *value,
c7e27aaf 1922 struct lxc_conf *lxc_conf, void *data)
96f15ca1 1923{
713046e3 1924 return set_config_path_item(&lxc_conf->console.log_path, value);
96f15ca1
SH
1925}
1926
28f3b1cd
CB
1927static int set_config_console_buffer_size(const char *key, const char *value,
1928 struct lxc_conf *lxc_conf, void *data)
a04220de
CB
1929{
1930 int ret;
1931 int64_t size;
28f3b1cd 1932 uint64_t buffer_size, pgsz;
a04220de
CB
1933
1934 if (lxc_config_value_empty(value)) {
28f3b1cd 1935 lxc_conf->console.buffer_size = 0;
a04220de
CB
1936 return 0;
1937 }
1938
1939 /* If the user specified "auto" the default log size is 2^17 = 128 Kib */
1940 if (!strcmp(value, "auto")) {
28f3b1cd 1941 lxc_conf->console.buffer_size = 1 << 17;
a04220de
CB
1942 return 0;
1943 }
1944
1945 ret = parse_byte_size_string(value, &size);
1946 if (ret < 0)
1947 return -1;
1948
1949 if (size < 0)
1950 return -EINVAL;
1951
1952 /* must be at least a page size */
1953 pgsz = lxc_getpagesize();
1954 if ((uint64_t)size < pgsz) {
1955 NOTICE("Requested ringbuffer size for the console is %" PRId64
1956 " but must be at least %" PRId64
1957 " bytes. Setting ringbuffer size to %" PRId64 " bytes",
1958 size, pgsz, pgsz);
1959 size = pgsz;
1960 }
1961
28f3b1cd
CB
1962 buffer_size = lxc_find_next_power2((uint64_t)size);
1963 if (buffer_size == 0)
a04220de
CB
1964 return -EINVAL;
1965
28f3b1cd 1966 if (buffer_size != size)
a04220de 1967 NOTICE("Passed size was not a power of 2. Rounding log size to "
28f3b1cd 1968 "next power of two: %" PRIu64 " bytes", buffer_size);
a04220de 1969
28f3b1cd 1970 lxc_conf->console.buffer_size = buffer_size;
a04220de
CB
1971 return 0;
1972}
1973
3a784510
CB
1974static int set_config_console_buffer_logfile(const char *key, const char *value,
1975 struct lxc_conf *lxc_conf,
1976 void *data)
1977{
1978 return set_config_path_item(&lxc_conf->console.buffer_log_file, value);
1979}
1980
6b0d5538 1981int append_unexp_config_line(const char *line, struct lxc_conf *conf)
f979ac15 1982{
6b0d5538 1983 size_t len = conf->unexpanded_len, linelen = strlen(line);
f979ac15 1984
e6744e9b
SH
1985 update_hwaddr(line);
1986
6b0d5538 1987 while (conf->unexpanded_alloced <= len + linelen + 2) {
504a2217
CB
1988 char *tmp = realloc(conf->unexpanded_config,
1989 conf->unexpanded_alloced + 1024);
6b0d5538
SH
1990 if (!tmp)
1991 return -1;
504a2217 1992
6b0d5538
SH
1993 if (!conf->unexpanded_config)
1994 *tmp = '\0';
1995 conf->unexpanded_config = tmp;
1996 conf->unexpanded_alloced += 1024;
1997 }
1998 strcat(conf->unexpanded_config, line);
1999 conf->unexpanded_len += linelen;
504a2217 2000 if (line[linelen - 1] != '\n') {
6b0d5538
SH
2001 strcat(conf->unexpanded_config, "\n");
2002 conf->unexpanded_len++;
f979ac15 2003 }
25a908b8 2004
f979ac15
SH
2005 return 0;
2006}
2007
e1daebd9
SH
2008static int do_includedir(const char *dirp, struct lxc_conf *lxc_conf)
2009{
74f96976 2010 struct dirent *direntp;
e1daebd9
SH
2011 DIR *dir;
2012 char path[MAXPATHLEN];
504a2217
CB
2013 int len;
2014 int ret = -1;
e1daebd9
SH
2015
2016 dir = opendir(dirp);
25a908b8 2017 if (!dir)
e1daebd9 2018 return -1;
e1daebd9 2019
74f96976 2020 while ((direntp = readdir(dir))) {
e1daebd9
SH
2021 const char *fnam;
2022 if (!direntp)
2023 break;
2024
2025 fnam = direntp->d_name;
2026 if (!strcmp(fnam, "."))
2027 continue;
2028
2029 if (!strcmp(fnam, ".."))
2030 continue;
2031
2032 len = strlen(fnam);
504a2217 2033 if (len < 6 || strncmp(fnam + len - 5, ".conf", 5) != 0)
e1daebd9 2034 continue;
25a908b8 2035
e1daebd9
SH
2036 len = snprintf(path, MAXPATHLEN, "%s/%s", dirp, fnam);
2037 if (len < 0 || len >= MAXPATHLEN) {
e1daebd9
SH
2038 ret = -1;
2039 goto out;
2040 }
2041
2042 ret = lxc_config_read(path, lxc_conf, true);
2043 if (ret < 0)
2044 goto out;
2045 }
2046 ret = 0;
2047
2048out:
25a908b8 2049 closedir(dir);
e1daebd9
SH
2050
2051 return ret;
2052}
2053
973082f5 2054static int set_config_includefiles(const char *key, const char *value,
c7e27aaf 2055 struct lxc_conf *lxc_conf, void *data)
09ad6246 2056{
663e9916 2057 if (lxc_config_value_empty(value)) {
26471403 2058 clr_config_includefiles(key, lxc_conf, NULL);
616422f1 2059 return 0;
355c5701 2060 }
616422f1 2061
e1daebd9
SH
2062 if (is_dir(value))
2063 return do_includedir(value, lxc_conf);
2064
6b0d5538 2065 return lxc_config_read(value, lxc_conf, true);
09ad6246
SH
2066}
2067
7a96a068
CB
2068static int set_config_rootfs_path(const char *key, const char *value,
2069 struct lxc_conf *lxc_conf, void *data)
c2cc9f0a 2070{
693dbdb9
CB
2071 int ret;
2072 char *dup, *tmp;
2073 const char *container_path;
2074
2075 if (lxc_config_value_empty(value)) {
2076 free(lxc_conf->rootfs.path);
2077 lxc_conf->rootfs.path = NULL;
2078 return 0;
2079 }
2080
2081 dup = strdup(value);
2082 if (!dup)
2083 return -1;
2084
2085 /* Split <storage type>:<container path> into <storage type> and
2086 * <container path>. Set "rootfs.bdev_type" to <storage type> and
2087 * "rootfs.path" to <container path>.
2088 */
2089 tmp = strchr(dup, ':');
2090 if (tmp) {
2091 *tmp = '\0';
2092 ret = set_config_path_item(&lxc_conf->rootfs.bdev_type, dup);
2093 if (ret < 0) {
2094 free(dup);
2095 return -1;
2096 }
2097 tmp++;
2098 container_path = tmp;
2099 } else {
2100 container_path = value;
2101 }
2102
2103 ret = set_config_path_item(&lxc_conf->rootfs.path, container_path);
2104 free(dup);
2105 return ret;
c2cc9f0a 2106}
2107
713046e3 2108static int set_config_rootfs_mount(const char *key, const char *value,
c7e27aaf 2109 struct lxc_conf *lxc_conf, void *data)
23b7ea69 2110{
713046e3 2111 return set_config_path_item(&lxc_conf->rootfs.mount, value);
23b7ea69
DL
2112}
2113
713046e3 2114static int set_config_rootfs_options(const char *key, const char *value,
c7e27aaf 2115 struct lxc_conf *lxc_conf, void *data)
a17b1e65 2116{
713046e3 2117 return set_config_string_item(&lxc_conf->rootfs.options, value);
a17b1e65
SG
2118}
2119
713046e3 2120static int set_config_rootfs_backend(const char *key, const char *value,
c7e27aaf 2121 struct lxc_conf *lxc_conf, void *data)
bfd77214 2122{
f7ac4459 2123 return 0;
bfd77214
SH
2124}
2125
b67771bc 2126static int set_config_uts_name(const char *key, const char *value,
c7e27aaf 2127 struct lxc_conf *lxc_conf, void *data)
c2cc9f0a 2128{
2129 struct utsname *utsname;
2130
663e9916 2131 if (lxc_config_value_empty(value)) {
b67771bc 2132 clr_config_uts_name(key, lxc_conf, NULL);
1939e73d 2133 return 0;
00cd8039 2134 }
1939e73d 2135
c2cc9f0a 2136 utsname = malloc(sizeof(*utsname));
25a908b8 2137 if (!utsname)
c2cc9f0a 2138 return -1;
c2cc9f0a 2139
2140 if (strlen(value) >= sizeof(utsname->nodename)) {
b6f24d54 2141 free(utsname);
c2cc9f0a 2142 return -1;
2143 }
2144
2145 strcpy(utsname->nodename, value);
f10fad2f 2146 free(lxc_conf->utsname);
c2cc9f0a 2147 lxc_conf->utsname = utsname;
2148
2149 return 0;
2150}
2151
28d9e29e
CB
2152static int set_config_namespace(const char *key, const char *value,
2153 struct lxc_conf *lxc_conf, void *data)
2154{
2155 int ns_idx;
2156 const char *namespace;
2157
2158 if (lxc_config_value_empty(value))
2159 return clr_config_namespace(key, lxc_conf, data);
2160
2161 namespace = key + sizeof("lxc.namespace.") - 1;
2162 ns_idx = lxc_namespace_2_ns_idx(namespace);
2163 if (ns_idx < 0)
2164 return ns_idx;
2165
2166 return set_config_string_item(&lxc_conf->inherit_ns[ns_idx], value);
2167}
2168
6b0d5538
SH
2169struct parse_line_conf {
2170 struct lxc_conf *conf;
2171 bool from_include;
2172};
4184c3e1 2173
7a7ff0c6 2174static int parse_line(char *buffer, void *data)
c2cc9f0a 2175{
504a2217 2176 char *dot, *key, *line, *linep, *value;
3b13691d
CB
2177 bool empty_line;
2178 struct lxc_config_t *config;
504a2217 2179 int ret = 0;
3b13691d
CB
2180 char *dup = buffer;
2181 struct parse_line_conf *plc = data;
c2cc9f0a 2182
3b13691d
CB
2183 /* If there are newlines in the config file we should keep them. */
2184 empty_line = lxc_is_line_empty(dup);
2185 if (empty_line)
2186 dup = "\n";
c2cc9f0a 2187
25a908b8
CB
2188 /* We have to dup the buffer otherwise, at the re-exec for reboot we
2189 * modified the original string on the stack by replacing '=' by '\0'
2190 * below.
91480a0f 2191 */
3b13691d 2192 linep = line = strdup(dup);
25a908b8 2193 if (!line)
81192358 2194 return -1;
91480a0f 2195
3b13691d
CB
2196 if (!plc->from_include) {
2197 ret = append_unexp_config_line(line, plc->conf);
2198 if (ret < 0)
2199 goto on_error;
2200 }
2201
2202 if (empty_line)
327500d4 2203 goto on_error;
6b0d5538 2204
b2718c72 2205 line += lxc_char_left_gc(line, strlen(line));
476d4cf1 2206
4184c3e1
SH
2207 /* ignore comments */
2208 if (line[0] == '#')
3b13691d 2209 goto on_error;
476d4cf1 2210
6b0d5538
SH
2211 /* martian option - don't add it to the config itself */
2212 if (strncmp(line, "lxc.", 4))
3b13691d 2213 goto on_error;
4184c3e1 2214
476d4cf1 2215 ret = -1;
c2cc9f0a 2216
3b13691d 2217 dot = strchr(line, '=');
c2cc9f0a 2218 if (!dot) {
3b13691d
CB
2219 ERROR("Invalid configuration line: %s", line);
2220 goto on_error;
c2cc9f0a 2221 }
a871ff6b 2222
c2cc9f0a 2223 *dot = '\0';
2224 value = dot + 1;
2225
b2718c72 2226 key = line;
2227 key[lxc_char_right_gc(key, strlen(key))] = '\0';
c2cc9f0a 2228
b2718c72 2229 value += lxc_char_left_gc(value, strlen(value));
2230 value[lxc_char_right_gc(value, strlen(value))] = '\0';
c2cc9f0a 2231
bd878dee 2232 if (*value == '\'' || *value == '\"') {
25a908b8
CB
2233 size_t len;
2234
2235 len = strlen(value);
504a2217
CB
2236 if (len > 1 && value[len - 1] == *value) {
2237 value[len - 1] = '\0';
bd878dee
SB
2238 value++;
2239 }
2240 }
2241
300df83e 2242 config = lxc_get_config(key);
c2cc9f0a 2243 if (!config) {
25a908b8 2244 ERROR("Unknown configuration key \"%s\"", key);
3b13691d 2245 goto on_error;
c2cc9f0a 2246 }
2247
7ec2e32a
CB
2248 /* [START]: REMOVE IN LXC 3.0 */
2249 if (config->is_legacy_key && !plc->conf->contains_legacy_key) {
2250 plc->conf->contains_legacy_key = true;
70952c01
CB
2251 if (getenv("LXC_UPDATE_CONFIG_FORMAT")) {
2252 /* Warn the user once loud and clear that there is at
2253 * least one legacy configuration item in the
2254 * configuration file and then an update is required.
2255 */
2256 fprintf(stderr, "The configuration file contains "
2257 "legacy configuration keys.\nPlease "
ece913fe
CB
2258 "update your configuration file!\nThe "
2259 "update script lxc-update-config -c "
2260 "<path-to-config> can be used for "
2261 "this.\n");
70952c01 2262 }
7ec2e32a
CB
2263 }
2264 /* [END]: REMOVE IN LXC 3.0 */
2265
bbc079cf 2266 ret = config->set(key, value, plc->conf, NULL);
91480a0f 2267
3b13691d 2268on_error:
81192358 2269 free(linep);
91480a0f 2270 return ret;
c2cc9f0a 2271}
2272
74a3920a 2273static int lxc_config_readline(char *buffer, struct lxc_conf *conf)
af5b0155 2274{
6b0d5538
SH
2275 struct parse_line_conf c;
2276
2277 c.conf = conf;
2278 c.from_include = false;
2279
2280 return parse_line(buffer, &c);
af5b0155
CLG
2281}
2282
6b0d5538 2283int lxc_config_read(const char *file, struct lxc_conf *conf, bool from_include)
c2cc9f0a 2284{
25a908b8 2285 int ret;
6b0d5538
SH
2286 struct parse_line_conf c;
2287
2288 c.conf = conf;
2289 c.from_include = from_include;
f979ac15 2290
25a908b8
CB
2291 ret = access(file, R_OK);
2292 if (ret < 0)
f3ca99fd 2293 return -1;
6b0d5538 2294
25a908b8 2295 /* Catch only the top level config file name in the structure. */
504a2217 2296 if (!conf->rcfile)
76d0127f 2297 conf->rcfile = strdup(file);
f979ac15 2298
6b0d5538 2299 return lxc_file_for_each_line(file, parse_line, &c);
c2cc9f0a 2300}
62e46035 2301
504a2217 2302int lxc_config_define_add(struct lxc_list *defines, char *arg)
62e46035
CLG
2303{
2304 struct lxc_list *dent;
2305
2306 dent = malloc(sizeof(struct lxc_list));
2307 if (!dent)
2308 return -1;
2309
2310 dent->elem = arg;
2311 lxc_list_add_tail(defines, dent);
2312 return 0;
2313}
2314
226a18d6 2315int lxc_config_define_load(struct lxc_list *defines, struct lxc_conf *conf)
62e46035 2316{
504a2217 2317 struct lxc_list *it, *next;
62e46035
CLG
2318 int ret = 0;
2319
2320 lxc_list_for_each(it, defines) {
2321 ret = lxc_config_readline(it->elem, conf);
2322 if (ret)
2323 break;
2324 }
2325
9ebb03ad 2326 lxc_list_for_each_safe(it, defines, next) {
62e46035
CLG
2327 lxc_list_del(it);
2328 free(it);
2329 }
2330
2331 return ret;
2332}
525f0002
CS
2333
2334signed long lxc_config_parse_arch(const char *arch)
2335{
504a2217
CB
2336#if HAVE_SYS_PERSONALITY_H
2337 size_t i;
525f0002
CS
2338 struct per_name {
2339 char *name;
2340 unsigned long per;
bb8d8207 2341 } pername[] = {
504a2217
CB
2342 { "x86", PER_LINUX32 },
2343 { "linux32", PER_LINUX32 },
2344 { "i386", PER_LINUX32 },
2345 { "i486", PER_LINUX32 },
2346 { "i586", PER_LINUX32 },
2347 { "i686", PER_LINUX32 },
2348 { "athlon", PER_LINUX32 },
2349 { "mips", PER_LINUX32 },
2350 { "mipsel", PER_LINUX32 },
2351 { "ppc", PER_LINUX32 },
2352 { "arm", PER_LINUX32 },
2353 { "armv7l", PER_LINUX32 },
2354 { "armhf", PER_LINUX32 },
2355 { "armel", PER_LINUX32 },
2356 { "powerpc", PER_LINUX32 },
2357 { "linux64", PER_LINUX },
2358 { "x86_64", PER_LINUX },
2359 { "amd64", PER_LINUX },
2360 { "mips64", PER_LINUX },
2361 { "mips64el", PER_LINUX },
2362 { "ppc64", PER_LINUX },
2363 { "ppc64le", PER_LINUX },
2364 { "ppc64el", PER_LINUX },
2365 { "powerpc64", PER_LINUX },
2366 { "s390x", PER_LINUX },
2367 { "aarch64", PER_LINUX },
2368 { "arm64", PER_LINUX },
525f0002
CS
2369 };
2370 size_t len = sizeof(pername) / sizeof(pername[0]);
2371
525f0002
CS
2372 for (i = 0; i < len; i++) {
2373 if (!strcmp(pername[i].name, arch))
504a2217 2374 return pername[i].per;
525f0002 2375 }
504a2217 2376#endif
525f0002
CS
2377
2378 return -1;
2379}
72d0e1cb 2380
4d69b293
NK
2381int lxc_fill_elevated_privileges(char *flaglist, int *flags)
2382{
2383 char *token, *saveptr = NULL;
2384 int i, aflag;
504a2217
CB
2385 struct {
2386 const char *token;
2387 int flag;
2388 } all_privs[] = {
2389 { "CGROUP", LXC_ATTACH_MOVE_TO_CGROUP },
2390 { "CAP", LXC_ATTACH_DROP_CAPABILITIES },
2391 { "LSM", LXC_ATTACH_LSM_EXEC },
2392 { NULL, 0 }
4d69b293
NK
2393 };
2394
2395 if (!flaglist) {
504a2217 2396 /* For the sake of backward compatibility, drop all privileges
25a908b8 2397 * if none is specified.
504a2217 2398 */
25a908b8 2399 for (i = 0; all_privs[i].token; i++)
d028235d 2400 *flags |= all_privs[i].flag;
25a908b8 2401
4d69b293
NK
2402 return 0;
2403 }
2404
2405 token = strtok_r(flaglist, "|", &saveptr);
2406 while (token) {
2407 aflag = -1;
25a908b8 2408 for (i = 0; all_privs[i].token; i++)
4d69b293
NK
2409 if (!strcmp(all_privs[i].token, token))
2410 aflag = all_privs[i].flag;
4d69b293
NK
2411 if (aflag < 0)
2412 return -1;
2413
2414 *flags |= aflag;
2415
2416 token = strtok_r(NULL, "|", &saveptr);
2417 }
504a2217 2418
4d69b293
NK
2419 return 0;
2420}
2421
504a2217 2422/* Write out a configuration file. */
72d0e1cb
SG
2423void write_config(FILE *fout, struct lxc_conf *c)
2424{
6b0d5538 2425 int ret;
504a2217 2426 size_t len = c->unexpanded_len;
72d0e1cb 2427
6b0d5538
SH
2428 if (!len)
2429 return;
504a2217 2430
6b0d5538
SH
2431 ret = fwrite(c->unexpanded_config, 1, len, fout);
2432 if (ret != len)
25a908b8 2433 SYSERROR("Failed to write configuration file");
6b0d5538 2434}
f979ac15 2435
504a2217
CB
2436bool do_append_unexp_config_line(struct lxc_conf *conf, const char *key,
2437 const char *v)
6b0d5538
SH
2438{
2439 int ret;
151d2da2
CB
2440 size_t len;
2441 char *tmp;
4184c3e1 2442
151d2da2
CB
2443 len = strlen(key) + strlen(v) + 4;
2444 tmp = alloca(len);
2445
663e9916 2446 if (lxc_config_value_empty(v))
151d2da2
CB
2447 ret = snprintf(tmp, len, "%s =", key);
2448 else
2449 ret = snprintf(tmp, len, "%s = %s", key, v);
6b0d5538
SH
2450 if (ret < 0 || ret >= len)
2451 return false;
2452
2453 /* Save the line verbatim into unexpanded_conf */
2454 if (append_unexp_config_line(tmp, conf))
2455 return false;
2456
2457 return true;
2458}
2459
504a2217
CB
2460void clear_unexp_config_line(struct lxc_conf *conf, const char *key,
2461 bool rm_subkeys)
6b0d5538 2462{
504a2217
CB
2463 char *lend;
2464 char *lstart = conf->unexpanded_config;
6b0d5538
SH
2465
2466 if (!conf->unexpanded_config)
2467 return;
504a2217 2468
6b0d5538
SH
2469 while (*lstart) {
2470 lend = strchr(lstart, '\n');
2471 char v;
2472 if (!lend)
2473 lend = lstart + strlen(lstart);
2474 else
2475 lend++;
2476 if (strncmp(lstart, key, strlen(key)) != 0) {
2477 lstart = lend;
2478 continue;
5f62730e 2479 }
6b0d5538
SH
2480 if (!rm_subkeys) {
2481 v = lstart[strlen(key)];
2482 if (!isspace(v) && v != '=') {
2483 lstart = lend;
2484 continue;
2485 }
5f62730e 2486 }
6b0d5538
SH
2487 conf->unexpanded_len -= (lend - lstart);
2488 if (*lend == '\0') {
2489 *lstart = '\0';
2490 return;
fd986e08 2491 }
504a2217 2492 memmove(lstart, lend, strlen(lend) + 1);
fd986e08 2493 }
6b0d5538
SH
2494}
2495
329b3625
CB
2496bool clone_update_unexp_ovl_paths(struct lxc_conf *conf, const char *oldpath,
2497 const char *newpath, const char *oldname,
2498 const char *newname, const char *ovldir)
2499{
329b3625 2500 int ret;
504a2217
CB
2501 char *lend, *newdir, *olddir, *p, *q;
2502 size_t newdirlen, olddirlen;
329b3625 2503 char *lstart = conf->unexpanded_config;
504a2217 2504 const char *key = "lxc.mount.entry";
329b3625 2505
504a2217
CB
2506 olddirlen = strlen(ovldir) + strlen(oldpath) + strlen(oldname) + 2;
2507 olddir = alloca(olddirlen + 1);
2508 ret = snprintf(olddir, olddirlen + 1, "%s=%s/%s", ovldir, oldpath,
2509 oldname);
25a908b8 2510 if (ret < 0 || ret >= olddirlen + 1)
329b3625 2511 return false;
504a2217
CB
2512
2513 newdirlen = strlen(ovldir) + strlen(newpath) + strlen(newname) + 2;
2514 newdir = alloca(newdirlen + 1);
2515 ret = snprintf(newdir, newdirlen + 1, "%s=%s/%s", ovldir, newpath,
2516 newname);
25a908b8 2517 if (ret < 0 || ret >= newdirlen + 1)
329b3625 2518 return false;
504a2217 2519
329b3625
CB
2520 if (!conf->unexpanded_config)
2521 return true;
504a2217 2522
329b3625
CB
2523 while (*lstart) {
2524 lend = strchr(lstart, '\n');
2525 if (!lend)
2526 lend = lstart + strlen(lstart);
2527 else
2528 lend++;
504a2217 2529
329b3625 2530 if (strncmp(lstart, key, strlen(key)) != 0)
504a2217
CB
2531 goto next;
2532
329b3625
CB
2533 p = strchr(lstart + strlen(key), '=');
2534 if (!p)
504a2217 2535 goto next;
329b3625 2536 p++;
504a2217 2537
329b3625
CB
2538 while (isblank(*p))
2539 p++;
504a2217 2540
329b3625 2541 if (p >= lend)
504a2217
CB
2542 goto next;
2543
2544 /* Whenever an lxc.mount.entry entry is found in a line we check
2545 * if the substring " overlay" or the substring " aufs" is
2546 * present before doing any further work. We check for "
2547 * overlay" and " aufs" since both substrings need to have at
2548 * least one space before them in a valid overlay
2549 * lxc.mount.entry (/A B overlay). When the space before is
2550 * missing it is very likely that these substrings are part of a
2551 * path or something else. (Checking q >= lend ensures that we
2552 * only count matches in the current line.) */
2553 if ((!(q = strstr(p, " overlay")) || q >= lend) &&
2554 (!(q = strstr(p, " aufs")) || q >= lend))
2555 goto next;
2556
329b3625 2557 if (!(q = strstr(p, olddir)) || (q >= lend))
504a2217 2558 goto next;
329b3625
CB
2559
2560 /* replace the olddir with newdir */
2561 if (olddirlen >= newdirlen) {
2562 size_t diff = olddirlen - newdirlen;
2563 memcpy(q, newdir, newdirlen);
2564 if (olddirlen != newdirlen) {
2565 memmove(q + newdirlen, q + newdirlen + diff,
2566 strlen(q) - newdirlen - diff + 1);
2567 lend -= diff;
2568 conf->unexpanded_len -= diff;
2569 }
2570 } else {
2571 char *new;
2572 size_t diff = newdirlen - olddirlen;
2573 size_t oldlen = conf->unexpanded_len;
2574 size_t newlen = oldlen + diff;
2575 size_t poffset = q - conf->unexpanded_config;
504a2217 2576
329b3625 2577 new = realloc(conf->unexpanded_config, newlen + 1);
25a908b8 2578 if (!new)
329b3625 2579 return false;
25a908b8 2580
329b3625
CB
2581 conf->unexpanded_len = newlen;
2582 conf->unexpanded_alloced = newlen + 1;
2583 new[newlen - 1] = '\0';
2584 lend = new + (lend - conf->unexpanded_config);
25a908b8 2585 /* Move over the remainder to make room for the newdir.
504a2217 2586 */
329b3625
CB
2587 memmove(new + poffset + newdirlen,
2588 new + poffset + olddirlen,
2589 oldlen - poffset - olddirlen + 1);
2590 conf->unexpanded_config = new;
2591 memcpy(new + poffset, newdir, newdirlen);
2592 lend += diff;
2593 }
504a2217
CB
2594 next:
2595 lstart = lend;
329b3625 2596 }
504a2217 2597
329b3625
CB
2598 return true;
2599}
2600
67702c21 2601bool clone_update_unexp_hooks(struct lxc_conf *conf, const char *oldpath,
d546aa0e
CB
2602 const char *newpath, const char *oldname,
2603 const char *newname)
6b0d5538 2604{
67702c21 2605 int ret;
504a2217
CB
2606 char *lend, *newdir, *olddir, *p;
2607 char *lstart = conf->unexpanded_config;
2608 size_t newdirlen, olddirlen;
2609 const char *key = "lxc.hook";
67702c21 2610
504a2217
CB
2611 olddirlen = strlen(oldpath) + strlen(oldname) + 1;
2612 olddir = alloca(olddirlen + 1);
d546aa0e 2613 ret = snprintf(olddir, olddirlen + 1, "%s/%s", oldpath, oldname);
25a908b8 2614 if (ret < 0 || ret >= olddirlen + 1)
67702c21 2615 return false;
504a2217
CB
2616
2617 newdirlen = strlen(newpath) + strlen(newname) + 1;
2618 newdir = alloca(newdirlen + 1);
d546aa0e 2619 ret = snprintf(newdir, newdirlen + 1, "%s/%s", newpath, newname);
25a908b8 2620 if (ret < 0 || ret >= newdirlen + 1)
67702c21 2621 return false;
25a908b8 2622
67702c21
SH
2623 if (!conf->unexpanded_config)
2624 return true;
25a908b8 2625
67702c21
SH
2626 while (*lstart) {
2627 lend = strchr(lstart, '\n');
2628 if (!lend)
2629 lend = lstart + strlen(lstart);
2630 else
2631 lend++;
504a2217 2632
d546aa0e 2633 if (strncmp(lstart, key, strlen(key)) != 0)
504a2217
CB
2634 goto next;
2635
d546aa0e
CB
2636 p = strchr(lstart + strlen(key), '=');
2637 if (!p)
504a2217 2638 goto next;
67702c21 2639 p++;
504a2217 2640
67702c21
SH
2641 while (isblank(*p))
2642 p++;
504a2217
CB
2643
2644 if (p >= lend)
2645 goto next;
2646
d546aa0e 2647 if (strncmp(p, olddir, strlen(olddir)) != 0)
504a2217
CB
2648 goto next;
2649
67702c21
SH
2650 /* replace the olddir with newdir */
2651 if (olddirlen >= newdirlen) {
2652 size_t diff = olddirlen - newdirlen;
2653 memcpy(p, newdir, newdirlen);
2654 if (olddirlen != newdirlen) {
d546aa0e
CB
2655 memmove(p + newdirlen, p + newdirlen + diff,
2656 strlen(p) - newdirlen - diff + 1);
67702c21
SH
2657 lend -= diff;
2658 conf->unexpanded_len -= diff;
2659 }
67702c21
SH
2660 } else {
2661 char *new;
2662 size_t diff = newdirlen - olddirlen;
2663 size_t oldlen = conf->unexpanded_len;
2664 size_t newlen = oldlen + diff;
2665 size_t poffset = p - conf->unexpanded_config;
504a2217 2666
d546aa0e 2667 new = realloc(conf->unexpanded_config, newlen + 1);
25a908b8 2668 if (!new)
6b0d5538 2669 return false;
25a908b8 2670
67702c21 2671 conf->unexpanded_len = newlen;
d546aa0e
CB
2672 conf->unexpanded_alloced = newlen + 1;
2673 new[newlen - 1] = '\0';
67702c21 2674 lend = new + (lend - conf->unexpanded_config);
25a908b8 2675 /* Move over the remainder to make room for the newdir.
504a2217 2676 */
d546aa0e
CB
2677 memmove(new + poffset + newdirlen,
2678 new + poffset + olddirlen,
2679 oldlen - poffset - olddirlen + 1);
67702c21 2680 conf->unexpanded_config = new;
d546aa0e
CB
2681 memcpy(new + poffset, newdir, newdirlen);
2682 lend += diff;
fd986e08 2683 }
504a2217
CB
2684 next:
2685 lstart = lend;
fd986e08 2686 }
504a2217 2687
6b0d5538
SH
2688 return true;
2689}
2690
504a2217
CB
2691#define DO(cmd) \
2692 { \
2693 if (!(cmd)) { \
2694 ERROR("Error writing to new config"); \
2695 return false; \
2696 } \
2697 }
6b0d5538 2698
25a908b8
CB
2699/* This is called only from clone. We wish to update all hwaddrs in the
2700 * unexpanded config file. We can't/don't want to update any which come from
504a2217
CB
2701 * lxc.includes (there shouldn't be any).
2702 * We can't just walk the c->lxc-conf->network list because that includes netifs
2703 * from the include files. So we update the ones which we find in the unexp
2704 * config file, then find the original macaddr in the conf->network, and update
2705 * that to the same value.
67702c21
SH
2706 */
2707bool network_new_hwaddrs(struct lxc_conf *conf)
6b0d5538 2708{
504a2217 2709 char *lend, *p, *p2;
6b0d5538 2710 struct lxc_list *it;
504a2217 2711 char *lstart = conf->unexpanded_config;
6b0d5538 2712
67702c21
SH
2713 if (!conf->unexpanded_config)
2714 return true;
091045f8 2715
67702c21
SH
2716 while (*lstart) {
2717 char newhwaddr[18], oldhwaddr[17];
091045f8 2718
67702c21
SH
2719 lend = strchr(lstart, '\n');
2720 if (!lend)
2721 lend = lstart + strlen(lstart);
2722 else
2723 lend++;
091045f8 2724
4a787c27 2725 if (!lxc_config_net_hwaddr(lstart)) {
67702c21
SH
2726 lstart = lend;
2727 continue;
72d0e1cb 2728 }
091045f8 2729
4a787c27 2730 p = strchr(lstart, '=');
67702c21
SH
2731 if (!p) {
2732 lstart = lend;
2733 continue;
72d0e1cb 2734 }
091045f8 2735
67702c21
SH
2736 p++;
2737 while (isblank(*p))
2738 p++;
2739 if (!*p)
2740 return true;
091045f8 2741
67702c21
SH
2742 p2 = p;
2743 while (*p2 && !isblank(*p2) && *p2 != '\n')
2744 p2++;
504a2217
CB
2745
2746 if ((p2 - p) != 17) {
67702c21
SH
2747 WARN("Bad hwaddr entry");
2748 lstart = lend;
2749 continue;
72d0e1cb 2750 }
091045f8 2751
67702c21 2752 memcpy(oldhwaddr, p, 17);
091045f8
CB
2753
2754 if (!new_hwaddr(newhwaddr))
2755 return false;
2756
67702c21 2757 memcpy(p, newhwaddr, 17);
25a908b8 2758 lxc_list_for_each(it, &conf->network) {
67702c21 2759 struct lxc_netdev *n = it->elem;
25a908b8 2760
67702c21
SH
2761 if (n->hwaddr && memcmp(oldhwaddr, n->hwaddr, 17) == 0)
2762 memcpy(n->hwaddr, newhwaddr, 17);
72d0e1cb 2763 }
67702c21
SH
2764
2765 lstart = lend;
72d0e1cb 2766 }
091045f8 2767
6b0d5538 2768 return true;
72d0e1cb 2769}
8796becf 2770
713046e3 2771static int set_config_ephemeral(const char *key, const char *value,
c7e27aaf 2772 struct lxc_conf *lxc_conf, void *data)
8796becf 2773{
663e9916 2774 if (lxc_config_value_empty(value)) {
3c6cf53a 2775 lxc_conf->ephemeral = 0;
78304622 2776 return 0;
3c6cf53a 2777 }
78304622 2778
66ffdb1a
CB
2779 if (lxc_safe_uint(value, &lxc_conf->ephemeral) < 0)
2780 return -1;
8796becf 2781
25a908b8 2782 if (lxc_conf->ephemeral > 1)
8796becf 2783 return -1;
8796becf
CB
2784
2785 return 0;
2786}
2787
46cc906d 2788static int set_config_log_syslog(const char *key, const char *value,
c7e27aaf 2789 struct lxc_conf *lxc_conf, void *data)
64c57ea1 2790{
76d0127f 2791 int facility;
7ca56b84 2792
ee10a69c
CB
2793 if (lxc_conf->syslog) {
2794 free(lxc_conf->syslog);
2795 lxc_conf->syslog = NULL;
2796 }
2797
663e9916 2798 if (lxc_config_value_empty(value))
7ca56b84
CB
2799 return 0;
2800
76d0127f 2801 facility = lxc_syslog_priority_to_int(value);
25a908b8 2802 if (facility == -EINVAL)
76d0127f 2803 return -1;
64c57ea1 2804
76d0127f 2805 lxc_log_syslog(facility);
713046e3 2806 return set_config_string_item(&lxc_conf->syslog, value);
64c57ea1 2807}
5a46f283 2808
713046e3 2809static int set_config_no_new_privs(const char *key, const char *value,
c7e27aaf 2810 struct lxc_conf *lxc_conf, void *data)
5a46f283 2811{
e8ec7c9e 2812 unsigned int v;
5a46f283 2813
663e9916 2814 if (lxc_config_value_empty(value)) {
cf3f8bf6 2815 lxc_conf->no_new_privs = false;
80926845 2816 return 0;
cf3f8bf6 2817 }
80926845 2818
e8ec7c9e
CB
2819 if (lxc_safe_uint(value, &v) < 0)
2820 return -1;
2821
25a908b8 2822 if (v > 1)
5a46f283 2823 return -1;
e8ec7c9e 2824
5a46f283
CB
2825 lxc_conf->no_new_privs = v ? true : false;
2826
2827 return 0;
2828}
7b992a3e 2829
63bab717
CB
2830static int set_config_noop(const char *key, const char *value,
2831 struct lxc_conf *lxc_conf, void *data)
2832{
2833 return 0;
2834}
2835
7b992a3e 2836/* Callbacks to get configuration items. */
6bede808 2837static int get_config_personality(const char *key, char *retv, int inlen,
cccd2219 2838 struct lxc_conf *c, void *data)
7b992a3e
CB
2839{
2840 int fulllen = 0;
2841
2842 if (!retv)
2843 inlen = 0;
2844 else
2845 memset(retv, 0, inlen);
2846
2847#if HAVE_SYS_PERSONALITY_H
2848 int len = 0;
2849
6bede808 2850 switch (c->personality) {
7b992a3e
CB
2851 case PER_LINUX32:
2852 strprint(retv, inlen, "i686");
2853 break;
2854 case PER_LINUX:
2855 strprint(retv, inlen, "x86_64");
2856 break;
2857 default:
2858 break;
2859 }
2860#endif
2861
2862 return fulllen;
2863}
bdf91ab4 2864
232763d6
CB
2865static int get_config_pty_max(const char *key, char *retv, int inlen,
2866 struct lxc_conf *c, void *data)
bdf91ab4 2867{
6bede808 2868 return lxc_get_conf_int(c, retv, inlen, c->pts);
bdf91ab4 2869}
5485782f 2870
fe1c5887
CB
2871static int get_config_tty_max(const char *key, char *retv, int inlen,
2872 struct lxc_conf *c, void *data)
5485782f 2873{
6bede808 2874 return lxc_get_conf_int(c, retv, inlen, c->tty);
5485782f 2875}
8015e018 2876
42e53c29 2877static int get_config_tty_dir(const char *key, char *retv, int inlen,
cccd2219 2878 struct lxc_conf *c, void *data)
8015e018 2879{
6bede808 2880 return lxc_get_conf_str(retv, inlen, c->ttydir);
8015e018 2881}
de1ede69 2882
953fe44f
CB
2883static int get_config_apparmor_profile(const char *key, char *retv, int inlen,
2884 struct lxc_conf *c, void *data)
104c8e6c 2885{
6bede808 2886 return lxc_get_conf_str(retv, inlen, c->lsm_aa_profile);
104c8e6c 2887}
d60d18c6 2888
953fe44f
CB
2889static int get_config_apparmor_allow_incomplete(const char *key, char *retv,
2890 int inlen, struct lxc_conf *c,
2891 void *data)
d60d18c6 2892{
6bede808
CB
2893 return lxc_get_conf_int(c, retv, inlen,
2894 c->lsm_aa_allow_incomplete);
d60d18c6 2895}
4203a0b5 2896
953fe44f
CB
2897static int get_config_selinux_context(const char *key, char *retv, int inlen,
2898 struct lxc_conf *c, void *data)
4203a0b5 2899{
6bede808 2900 return lxc_get_conf_str(retv, inlen, c->lsm_se_context);
4203a0b5 2901}
b863bf92 2902
25a908b8
CB
2903/* If you ask for a specific cgroup value, i.e. lxc.cgroup.devices.list, then
2904 * just the value(s) will be printed. Since there still could be more than one,
2905 * it is newline-separated.
2906 * (Maybe that's ambigous, since some values, i.e. devices.list, will already
2907 * have newlines?)
2908 * If you ask for 'lxc.cgroup", then all cgroup entries will be printed, in
2909 * 'lxc.cgroup.subsystem.key = value' format.
b863bf92 2910 */
43654d34
CB
2911static int get_config_cgroup_controller(const char *key, char *retv, int inlen,
2912 struct lxc_conf *c, void *data)
b863bf92
CB
2913{
2914 struct lxc_list *it;
2915 int len;
2916 int fulllen = 0;
2917 bool get_all = false;
2918
2919 if (!retv)
2920 inlen = 0;
2921 else
2922 memset(retv, 0, inlen);
2923
2924 if (!strcmp(key, "lxc.cgroup"))
2925 get_all = true;
2926 else if (!strncmp(key, "lxc.cgroup.", 11))
2927 key += 11;
2928 else
2929 return -1;
2930
6bede808 2931 lxc_list_for_each(it, &c->cgroup) {
b863bf92 2932 struct lxc_cgroup *cg = it->elem;
25a908b8 2933
b863bf92 2934 if (get_all) {
25a908b8
CB
2935 strprint(retv, inlen, "lxc.cgroup.%s = %s\n",
2936 cg->subsystem, cg->value);
b863bf92
CB
2937 } else if (!strcmp(cg->subsystem, key)) {
2938 strprint(retv, inlen, "%s\n", cg->value);
2939 }
2940 }
2941
2942 return fulllen;
2943}
5014ff2e 2944
43654d34
CB
2945static int get_config_cgroup_dir(const char *key, char *retv, int inlen,
2946 struct lxc_conf *lxc_conf, void *data)
2947{
2948 int len;
2949 int fulllen = 0;
2950
2951 if (!retv)
2952 inlen = 0;
2953 else
2954 memset(retv, 0, inlen);
2955
2956 strprint(retv, inlen, "%s", lxc_conf->cgroup_meta.dir);
2957
2958 return fulllen;
2959}
2960
6bede808 2961static int get_config_idmaps(const char *key, char *retv, int inlen,
cccd2219 2962 struct lxc_conf *c, void *data)
5014ff2e
CB
2963{
2964 struct lxc_list *it;
2965 int len, listlen, ret;
2966 int fulllen = 0;
2967/* "u 1000 1000000 65536"
2968 *
2969 * let's render this as
2970 *
2971 * sizeof(char)
2972 * +
2973 * sizeof(" ")
2974 * +
2975 * sizeof(uint64_t)
2976 * +
2977 * sizeof(" ")
2978 * +
2979 * sizeof(uint64_t)
2980 * +
2981 * sizeof(" ")
2982 * +
2983 * sizeof(uint64_t)
2984 * +
2985 * \0
2986 */
2987#define __LXC_IDMAP_STR_BUF (3 * LXC_NUMSTRLEN64 + 3 + 1 + 1)
2988 char buf[__LXC_IDMAP_STR_BUF];
2989
2990 if (!retv)
2991 inlen = 0;
2992 else
2993 memset(retv, 0, inlen);
2994
6bede808
CB
2995 listlen = lxc_list_len(&c->id_map);
2996 lxc_list_for_each(it, &c->id_map)
5014ff2e
CB
2997 {
2998 struct id_map *map = it->elem;
2999 ret = snprintf(buf, __LXC_IDMAP_STR_BUF, "%c %lu %lu %lu",
3000 (map->idtype == ID_TYPE_UID) ? 'u' : 'g',
3001 map->nsid, map->hostid, map->range);
3002 if (ret < 0 || ret >= __LXC_IDMAP_STR_BUF)
3003 return -1;
3004
3005 strprint(retv, inlen, "%s%s", buf, (listlen-- > 1) ? "\n" : "");
3006 }
3007 return fulllen;
3008}
b29b29be 3009
46cc906d 3010static int get_config_log_level(const char *key, char *retv, int inlen,
cccd2219 3011 struct lxc_conf *c, void *data)
b29b29be
CB
3012{
3013 const char *v;
6bede808 3014 v = lxc_log_priority_to_string(c->loglevel);
b29b29be
CB
3015 return lxc_get_conf_str(retv, inlen, v);
3016}
3d4630ab 3017
46cc906d 3018static int get_config_log_file(const char *key, char *retv, int inlen,
cccd2219 3019 struct lxc_conf *c, void *data)
3d4630ab 3020{
6bede808 3021 return lxc_get_conf_str(retv, inlen, c->logfile);
3d4630ab 3022}
0d601acb 3023
47148e96
CB
3024static int get_config_mount_fstab(const char *key, char *retv, int inlen,
3025 struct lxc_conf *c, void *data)
0d601acb 3026{
6bede808 3027 return lxc_get_conf_str(retv, inlen, c->fstab);
0d601acb 3028}
43fbf8d9 3029
6bede808 3030static int get_config_mount_auto(const char *key, char *retv, int inlen,
cccd2219 3031 struct lxc_conf *c, void *data)
43fbf8d9
CB
3032{
3033 int len, fulllen = 0;
3034 const char *sep = "";
3035
3036 if (!retv)
3037 inlen = 0;
3038 else
3039 memset(retv, 0, inlen);
3040
6bede808 3041 if (!(c->auto_mounts & LXC_AUTO_ALL_MASK))
43fbf8d9
CB
3042 return 0;
3043
6bede808 3044 switch (c->auto_mounts & LXC_AUTO_PROC_MASK) {
43fbf8d9
CB
3045 case LXC_AUTO_PROC_MIXED:
3046 strprint(retv, inlen, "%sproc:mixed", sep);
3047 sep = " ";
3048 break;
3049 case LXC_AUTO_PROC_RW:
3050 strprint(retv, inlen, "%sproc:rw", sep);
3051 sep = " ";
3052 break;
3053 default:
3054 break;
3055 }
3056
6bede808 3057 switch (c->auto_mounts & LXC_AUTO_SYS_MASK) {
43fbf8d9
CB
3058 case LXC_AUTO_SYS_RO:
3059 strprint(retv, inlen, "%ssys:ro", sep);
3060 sep = " ";
3061 break;
3062 case LXC_AUTO_SYS_RW:
3063 strprint(retv, inlen, "%ssys:rw", sep);
3064 sep = " ";
3065 break;
3066 case LXC_AUTO_SYS_MIXED:
3067 strprint(retv, inlen, "%ssys:mixed", sep);
3068 sep = " ";
3069 break;
3070 default:
3071 break;
3072 }
3073
6bede808 3074 switch (c->auto_mounts & LXC_AUTO_CGROUP_MASK) {
43fbf8d9
CB
3075 case LXC_AUTO_CGROUP_NOSPEC:
3076 strprint(retv, inlen, "%scgroup", sep);
43fbf8d9
CB
3077 break;
3078 case LXC_AUTO_CGROUP_MIXED:
3079 strprint(retv, inlen, "%scgroup:mixed", sep);
43fbf8d9
CB
3080 break;
3081 case LXC_AUTO_CGROUP_RO:
3082 strprint(retv, inlen, "%scgroup:ro", sep);
43fbf8d9
CB
3083 break;
3084 case LXC_AUTO_CGROUP_RW:
3085 strprint(retv, inlen, "%scgroup:rw", sep);
43fbf8d9
CB
3086 break;
3087 case LXC_AUTO_CGROUP_FULL_NOSPEC:
3088 strprint(retv, inlen, "%scgroup-full", sep);
43fbf8d9
CB
3089 break;
3090 case LXC_AUTO_CGROUP_FULL_MIXED:
3091 strprint(retv, inlen, "%scgroup-full:mixed", sep);
43fbf8d9
CB
3092 break;
3093 case LXC_AUTO_CGROUP_FULL_RO:
3094 strprint(retv, inlen, "%scgroup-full:ro", sep);
43fbf8d9
CB
3095 break;
3096 case LXC_AUTO_CGROUP_FULL_RW:
3097 strprint(retv, inlen, "%scgroup-full:rw", sep);
43fbf8d9
CB
3098 break;
3099 default:
3100 break;
3101 }
3102
3103 return fulllen;
3104}
cc921848 3105
6bede808 3106static int get_config_mount(const char *key, char *retv, int inlen,
cccd2219 3107 struct lxc_conf *c, void *data)
cc921848
CB
3108{
3109 int len, fulllen = 0;
3110 struct lxc_list *it;
3111
3112 if (!retv)
3113 inlen = 0;
3114 else
3115 memset(retv, 0, inlen);
3116
25a908b8 3117 lxc_list_for_each(it, &c->mount_list) {
cc921848
CB
3118 strprint(retv, inlen, "%s\n", (char *)it->elem);
3119 }
3120
3121 return fulllen;
3122}
819114b6 3123
7a96a068
CB
3124static int get_config_rootfs_path(const char *key, char *retv, int inlen,
3125 struct lxc_conf *c, void *data)
819114b6 3126{
6bede808 3127 return lxc_get_conf_str(retv, inlen, c->rootfs.path);
819114b6 3128}
3af60359 3129
6bede808 3130static int get_config_rootfs_mount(const char *key, char *retv, int inlen,
cccd2219 3131 struct lxc_conf *c, void *data)
3af60359 3132{
6bede808 3133 return lxc_get_conf_str(retv, inlen, c->rootfs.mount);
3af60359 3134}
0e9db631 3135
6bede808 3136static int get_config_rootfs_options(const char *key, char *retv, int inlen,
cccd2219 3137 struct lxc_conf *c, void *data)
0e9db631 3138{
6bede808 3139 return lxc_get_conf_str(retv, inlen, c->rootfs.options);
0e9db631 3140}
8f183f38 3141
6bede808 3142static int get_config_rootfs_backend(const char *key, char *retv, int inlen,
cccd2219 3143 struct lxc_conf *c, void *data)
8f183f38 3144{
f7ac4459 3145 return 0;
8f183f38 3146}
b87574e7 3147
b67771bc 3148static int get_config_uts_name(const char *key, char *retv, int inlen,
cccd2219 3149 struct lxc_conf *c, void *data)
e274f8b0
CB
3150{
3151 return lxc_get_conf_str(
3152 retv, inlen,
6bede808 3153 c->utsname ? c->utsname->nodename : NULL);
e274f8b0 3154}
466c2e93 3155
6bede808 3156static int get_config_hooks(const char *key, char *retv, int inlen,
cccd2219 3157 struct lxc_conf *c, void *data)
466c2e93
CB
3158{
3159 char *subkey;
3160 int len, fulllen = 0, found = -1;
3161 struct lxc_list *it;
3162 int i;
3163
466c2e93
CB
3164 subkey = strchr(key, '.');
3165 if (subkey)
3166 subkey = strchr(subkey + 1, '.');
3167 if (!subkey)
3168 return -1;
3169 subkey++;
3170 if (!*subkey)
3171 return -1;
3172 for (i = 0; i < NUM_LXC_HOOKS; i++) {
3173 if (strcmp(lxchook_names[i], subkey) == 0) {
3174 found = i;
3175 break;
3176 }
3177 }
3178 if (found == -1)
3179 return -1;
3180
3181 if (!retv)
3182 inlen = 0;
3183 else
3184 memset(retv, 0, inlen);
3185
6bede808 3186 lxc_list_for_each(it, &c->hooks[found]) {
466c2e93
CB
3187 strprint(retv, inlen, "%s\n", (char *)it->elem);
3188 }
3189 return fulllen;
3190}
d2ceff53 3191
44ae0fb6
CB
3192static int get_config_hooks_version(const char *key, char *retv, int inlen,
3193 struct lxc_conf *c, void *data)
3194{
3195 return lxc_get_conf_int(c, retv, inlen, c->hooks_version);
3196}
3197
f9373e40
CB
3198static int get_config_net(const char *key, char *retv, int inlen,
3199 struct lxc_conf *c, void *data)
d2ceff53
CB
3200{
3201 int len, fulllen = 0;
3202 struct lxc_list *it;
3203
3204 if (!retv)
3205 inlen = 0;
3206 else
3207 memset(retv, 0, inlen);
3208
6bede808 3209 lxc_list_for_each(it, &c->network) {
d2ceff53
CB
3210 struct lxc_netdev *n = it->elem;
3211 const char *t = lxc_net_type_to_str(n->type);
3212 strprint(retv, inlen, "%s\n", t ? t : "(invalid)");
3213 }
3214
3215 return fulllen;
3216}
bdccff60 3217
6bede808 3218static int get_config_cap_drop(const char *key, char *retv, int inlen,
cccd2219 3219 struct lxc_conf *c, void *data)
1c96d6d8
CB
3220{
3221 int len, fulllen = 0;
3222 struct lxc_list *it;
3223
3224 if (!retv)
3225 inlen = 0;
3226 else
3227 memset(retv, 0, inlen);
3228
6bede808 3229 lxc_list_for_each(it, &c->caps) {
b80927f2
CB
3230 strprint(retv, inlen, "%s\n", (char *)it->elem);
3231 }
25a908b8 3232
b80927f2
CB
3233 return fulllen;
3234}
3235
6bede808 3236static int get_config_cap_keep(const char *key, char *retv, int inlen,
cccd2219 3237 struct lxc_conf *c, void *data)
b80927f2
CB
3238{
3239 int len, fulllen = 0;
3240 struct lxc_list *it;
3241
3242 if (!retv)
3243 inlen = 0;
3244 else
3245 memset(retv, 0, inlen);
3246
6bede808 3247 lxc_list_for_each(it, &c->keepcaps) {
1c96d6d8
CB
3248 strprint(retv, inlen, "%s\n", (char *)it->elem);
3249 }
25a908b8 3250
1c96d6d8
CB
3251 return fulllen;
3252}
0692663a 3253
3aed4934
CB
3254static int get_config_console_path(const char *key, char *retv, int inlen,
3255 struct lxc_conf *c, void *data)
0692663a 3256{
6bede808 3257 return lxc_get_conf_str(retv, inlen, c->console.path);
0692663a 3258}
794d1c06 3259
6bede808 3260static int get_config_console_logfile(const char *key, char *retv, int inlen,
cccd2219 3261 struct lxc_conf *c, void *data)
794d1c06 3262{
6bede808 3263 return lxc_get_conf_str(retv, inlen, c->console.log_path);
794d1c06 3264}
75f55b1f 3265
d91adfa6
CB
3266static int get_config_console_rotate(const char *key, char *retv, int inlen,
3267 struct lxc_conf *c, void *data)
3268{
3269 return lxc_get_conf_int(c, retv, inlen, c->console.log_rotate);
3270}
3271
3272
28f3b1cd
CB
3273static int get_config_console_buffer_size(const char *key, char *retv,
3274 int inlen, struct lxc_conf *c,
3275 void *data)
a04220de
CB
3276{
3277 return lxc_get_conf_uint64(c, retv, inlen, c->autodev);
3278}
3279
3a784510
CB
3280static int get_config_console_buffer_logfile(const char *key, char *retv,
3281 int inlen, struct lxc_conf *c,
3282 void *data)
3283{
3284 return lxc_get_conf_str(retv, inlen, c->console.buffer_log_file);
3285}
3286
0b427da0
CB
3287static int get_config_seccomp_profile(const char *key, char *retv, int inlen,
3288 struct lxc_conf *c, void *data)
75f55b1f 3289{
6bede808 3290 return lxc_get_conf_str(retv, inlen, c->seccomp);
75f55b1f 3291}
97f6dad0 3292
6bede808 3293static int get_config_autodev(const char *key, char *retv, int inlen,
cccd2219 3294 struct lxc_conf *c, void *data)
97f6dad0 3295{
6bede808 3296 return lxc_get_conf_int(c, retv, inlen, c->autodev);
97f6dad0 3297}
afee4324 3298
55c84efc 3299static int get_config_signal_halt(const char *key, char *retv, int inlen,
25a908b8 3300 struct lxc_conf *c, void *data)
afee4324 3301{
6bede808 3302 return lxc_get_conf_int(c, retv, inlen, c->haltsignal);
afee4324 3303}
3aa8f359 3304
55c84efc 3305static int get_config_signal_reboot(const char *key, char *retv, int inlen,
25a908b8 3306 struct lxc_conf *c, void *data)
3aa8f359 3307{
6bede808 3308 return lxc_get_conf_int(c, retv, inlen, c->rebootsignal);
3aa8f359 3309}
2e16269f 3310
55c84efc 3311static int get_config_signal_stop(const char *key, char *retv, int inlen,
25a908b8 3312 struct lxc_conf *c, void *data)
2e16269f 3313{
6bede808 3314 return lxc_get_conf_int(c, retv, inlen, c->stopsignal);
2e16269f 3315}
54345299 3316
6bede808 3317static int get_config_start(const char *key, char *retv, int inlen,
cccd2219 3318 struct lxc_conf *c, void *data)
54345299 3319{
c6182222 3320 if (strcmp(key + 10, "auto") == 0)
6bede808 3321 return lxc_get_conf_int(c, retv, inlen, c->start_auto);
c6182222 3322 else if (strcmp(key + 10, "delay") == 0)
6bede808 3323 return lxc_get_conf_int(c, retv, inlen, c->start_delay);
c6182222 3324 else if (strcmp(key + 10, "order") == 0)
6bede808 3325 return lxc_get_conf_int(c, retv, inlen, c->start_order);
54345299
CB
3326
3327 return -1;
3328}
de9df15e 3329
46cc906d 3330static int get_config_log_syslog(const char *key, char *retv, int inlen,
25a908b8 3331 struct lxc_conf *c, void *data)
de9df15e 3332{
6bede808 3333 return lxc_get_conf_str(retv, inlen, c->syslog);
de9df15e 3334}
ac0f949c 3335
6bede808 3336static int get_config_monitor(const char *key, char *retv, int inlen,
cccd2219 3337 struct lxc_conf *c, void *data)
ac0f949c 3338{
6bede808 3339 return lxc_get_conf_int(c, retv, inlen, c->monitor_unshare);
ac0f949c 3340}
90ec7b6e 3341
6bede808 3342static int get_config_group(const char *key, char *retv, int inlen,
cccd2219 3343 struct lxc_conf *c, void *data)
90ec7b6e
CB
3344{
3345 int len, fulllen = 0;
3346 struct lxc_list *it;
3347
3348 if (!retv)
3349 inlen = 0;
3350 else
3351 memset(retv, 0, inlen);
3352
6bede808 3353 lxc_list_for_each(it, &c->groups) {
90ec7b6e
CB
3354 strprint(retv, inlen, "%s\n", (char *)it->elem);
3355 }
25a908b8 3356
90ec7b6e
CB
3357 return fulllen;
3358}
aa0db7d3 3359
6bede808 3360static int get_config_environment(const char *key, char *retv, int inlen,
cccd2219 3361 struct lxc_conf *c, void *data)
aa0db7d3
CB
3362{
3363 int len, fulllen = 0;
3364 struct lxc_list *it;
3365
3366 if (!retv)
3367 inlen = 0;
3368 else
3369 memset(retv, 0, inlen);
3370
6bede808 3371 lxc_list_for_each(it, &c->environment) {
aa0db7d3
CB
3372 strprint(retv, inlen, "%s\n", (char *)it->elem);
3373 }
25a908b8 3374
aa0db7d3
CB
3375 return fulllen;
3376}
96dfcb7d 3377
5cda27c1
SH
3378static int get_config_execute_cmd(const char *key, char *retv, int inlen,
3379 struct lxc_conf *c, void *data)
3380{
3381 return lxc_get_conf_str(retv, inlen, c->execute_cmd);
3382}
3383
6bede808 3384static int get_config_init_cmd(const char *key, char *retv, int inlen,
cccd2219 3385 struct lxc_conf *c, void *data)
96dfcb7d 3386{
6bede808 3387 return lxc_get_conf_str(retv, inlen, c->init_cmd);
96dfcb7d 3388}
1398e9b1 3389
3c491553
L
3390static int get_config_init_cwd(const char *key, char *retv, int inlen,
3391 struct lxc_conf *c, void *data)
3392{
3393 return lxc_get_conf_str(retv, inlen, c->init_cwd);
3394}
3395
6bede808 3396static int get_config_init_uid(const char *key, char *retv, int inlen,
cccd2219 3397 struct lxc_conf *c, void *data)
1398e9b1 3398{
6bede808 3399 return lxc_get_conf_int(c, retv, inlen, c->init_uid);
1398e9b1 3400}
dfeb7e42 3401
6bede808 3402static int get_config_init_gid(const char *key, char *retv, int inlen,
cccd2219 3403 struct lxc_conf *c, void *data)
dfeb7e42 3404{
6bede808 3405 return lxc_get_conf_int(c, retv, inlen, c->init_gid);
dfeb7e42 3406}
62048afe 3407
6bede808 3408static int get_config_ephemeral(const char *key, char *retv, int inlen,
cccd2219 3409 struct lxc_conf *c, void *data)
62048afe 3410{
6bede808 3411 return lxc_get_conf_int(c, retv, inlen, c->ephemeral);
62048afe 3412}
b09521ac 3413
6bede808 3414static int get_config_no_new_privs(const char *key, char *retv, int inlen,
cccd2219 3415 struct lxc_conf *c, void *data)
b09521ac 3416{
6bede808 3417 return lxc_get_conf_int(c, retv, inlen, c->no_new_privs);
b09521ac 3418}
389f6466 3419
25a908b8 3420/* If you ask for a specific value, i.e. lxc.prlimit.nofile, then just the value
240d4b74 3421 * will be printed. If you ask for 'lxc.prlimit', then all limit entries will be
3422 * printed, in 'lxc.prlimit.resource = value' format.
389f6466 3423 */
240d4b74 3424static int get_config_prlimit(const char *key, char *retv, int inlen,
cccd2219 3425 struct lxc_conf *c, void *data)
389f6466
CB
3426{
3427 int fulllen = 0, len;
3428 bool get_all = false;
3429 struct lxc_list *it;
3430
3431 if (!retv)
3432 inlen = 0;
3433 else
3434 memset(retv, 0, inlen);
3435
240d4b74 3436 if (!strcmp(key, "lxc.prlimit"))
389f6466 3437 get_all = true;
240d4b74 3438 else if (strncmp(key, "lxc.prlimit.", 12) == 0)
3439 key += 12;
389f6466
CB
3440 else
3441 return -1;
3442
6bede808 3443 lxc_list_for_each(it, &c->limits) {
389f6466
CB
3444 char buf[LXC_NUMSTRLEN64 * 2 + 2]; /* 2 colon separated 64 bit
3445 integers or the word
3446 'unlimited' */
3447 int partlen;
3448 struct lxc_limit *lim = it->elem;
3449
3450 if (lim->limit.rlim_cur == RLIM_INFINITY) {
3451 memcpy(buf, "unlimited", sizeof("unlimited"));
3452 partlen = sizeof("unlimited") - 1;
3453 } else {
3454 partlen = sprintf(buf, "%" PRIu64,
3455 (uint64_t)lim->limit.rlim_cur);
3456 }
3457 if (lim->limit.rlim_cur != lim->limit.rlim_max) {
25a908b8 3458 if (lim->limit.rlim_max == RLIM_INFINITY)
389f6466
CB
3459 memcpy(buf + partlen, ":unlimited",
3460 sizeof(":unlimited"));
25a908b8 3461 else
389f6466
CB
3462 sprintf(buf + partlen, ":%" PRIu64,
3463 (uint64_t)lim->limit.rlim_max);
389f6466
CB
3464 }
3465
3466 if (get_all) {
240d4b74 3467 strprint(retv, inlen, "lxc.prlimit.%s = %s\n",
389f6466 3468 lim->resource, buf);
25a908b8 3469 } else if (!strcmp(lim->resource, key)) {
389f6466
CB
3470 strprint(retv, inlen, "%s", buf);
3471 }
3472 }
3473
3474 return fulllen;
3475}
e08cb901 3476
e409b214
CB
3477/* If you ask for a specific value, i.e. lxc.sysctl.net.ipv4.ip_forward, then
3478 * just the value will be printed. If you ask for 'lxc.sysctl', then all sysctl
3479 * entries will be printed, in 'lxc.sysctl.key = value' format.
7edd0540
L
3480 */
3481static int get_config_sysctl(const char *key, char *retv, int inlen,
3482 struct lxc_conf *c, void *data)
3483{
3484 int len;
3485 struct lxc_list *it;
3486 int fulllen = 0;
3487 bool get_all = false;
3488
3489 if (!retv)
3490 inlen = 0;
3491 else
3492 memset(retv, 0, inlen);
3493
3494 if (strcmp(key, "lxc.sysctl") == 0)
3495 get_all = true;
3496 else if (strncmp(key, "lxc.sysctl.", sizeof("lxc.sysctl.") - 1) == 0)
3497 key += sizeof("lxc.sysctl.") - 1;
3498 else
3499 return -1;
3500
3501 lxc_list_for_each(it, &c->sysctls) {
3502 struct lxc_sysctl *elem = it->elem;
3503 if (get_all) {
3504 strprint(retv, inlen, "lxc.sysctl.%s = %s\n",
3505 elem->key, elem->value);
3506 } else if (strcmp(elem->key, key) == 0) {
3507 strprint(retv, inlen, "%s", elem->value);
3508 }
3509 }
3510
3511 return fulllen;
3512}
3513
61d7a733
YT
3514static int get_config_proc(const char *key, char *retv, int inlen,
3515 struct lxc_conf *c, void *data)
3516{
3517 struct lxc_list *it;
3518 int len;
3519 int fulllen = 0;
3520 bool get_all = false;
3521
3522 if (!retv)
3523 inlen = 0;
3524 else
3525 memset(retv, 0, inlen);
3526
3527 if (strcmp(key, "lxc.proc") == 0)
3528 get_all = true;
3529 else if (strncmp(key, "lxc.proc.", sizeof("lxc.proc.") - 1) == 0)
3530 key += sizeof("lxc.proc.") - 1;
3531 else
3532 return -1;
3533
3534 lxc_list_for_each(it, &c->procs) {
3535 struct lxc_proc *proc = it->elem;
3536
3537 if (get_all) {
3538 strprint(retv, inlen, "lxc.proc.%s = %s\n",
3539 proc->filename, proc->value);
3540 } else if (strcmp(proc->filename, key) == 0) {
3541 strprint(retv, inlen, "%s", proc->value);
3542 }
3543 }
3544
3545 return fulllen;
3546}
3547
63bab717
CB
3548static int get_config_noop(const char *key, char *retv, int inlen,
3549 struct lxc_conf *c, void *data)
3550{
3551 return 0;
3552}
3553
28d9e29e
CB
3554static int get_config_namespace(const char *key, char *retv, int inlen,
3555 struct lxc_conf *c, void *data)
3556{
3557 int len, ns_idx;
3558 const char *namespace;
3559 int fulllen = 0;
3560
3561 if (!retv)
3562 inlen = 0;
3563 else
3564 memset(retv, 0, inlen);
3565
3566 namespace = key + sizeof("lxc.namespace.") - 1;
3567 ns_idx = lxc_namespace_2_ns_idx(namespace);
3568 if (ns_idx < 0)
3569 return ns_idx;
3570
3571 strprint(retv, inlen, "%s", c->inherit_ns[ns_idx]);
3572
3573 return fulllen;
3574}
3575
e08cb901 3576/* Callbacks to clear config items. */
26471403
CB
3577static inline int clr_config_personality(const char *key, struct lxc_conf *c,
3578 void *data)
e08cb901
CB
3579{
3580 c->personality = -1;
3581 return 0;
3582}
03818ae3 3583
232763d6
CB
3584static inline int clr_config_pty_max(const char *key, struct lxc_conf *c,
3585 void *data)
03818ae3
CB
3586{
3587 c->pts = 0;
3588 return 0;
3589}
e7a4b096 3590
fe1c5887
CB
3591static inline int clr_config_tty_max(const char *key, struct lxc_conf *c,
3592 void *data)
e7a4b096
CB
3593{
3594 c->tty = 0;
3595 return 0;
3596}
eaf8c0c7 3597
42e53c29 3598static inline int clr_config_tty_dir(const char *key, struct lxc_conf *c,
26471403 3599 void *data)
eaf8c0c7
CB
3600{
3601 free(c->ttydir);
3602 c->ttydir = NULL;
3603 return 0;
3604}
6bd86308 3605
953fe44f
CB
3606static inline int clr_config_apparmor_profile(const char *key,
3607 struct lxc_conf *c, void *data)
025718fb
CB
3608{
3609 free(c->lsm_aa_profile);
3610 c->lsm_aa_profile = NULL;
3611 return 0;
3612}
3061e04e 3613
953fe44f
CB
3614static inline int clr_config_apparmor_allow_incomplete(const char *key,
3615 struct lxc_conf *c,
3616 void *data)
3061e04e
CB
3617{
3618 c->lsm_aa_allow_incomplete = 0;
3619 return 0;
3620}
31fc3494 3621
953fe44f
CB
3622static inline int clr_config_selinux_context(const char *key,
3623 struct lxc_conf *c, void *data)
31fc3494
CB
3624{
3625 free(c->lsm_se_context);
3626 c->lsm_se_context = NULL;
3627 return 0;
3628}
754d01ce 3629
43654d34
CB
3630static inline int clr_config_cgroup_controller(const char *key,
3631 struct lxc_conf *c, void *data)
754d01ce
CB
3632{
3633 return lxc_clear_cgroups(c, key);
3634}
d3a178de 3635
43654d34
CB
3636static int clr_config_cgroup_dir(const char *key, struct lxc_conf *lxc_conf,
3637 void *data)
3638{
3639 if (lxc_conf->cgroup_meta.dir) {
3640 free(lxc_conf->cgroup_meta.dir);
3641 lxc_conf->cgroup_meta.dir = NULL;
3642 }
3643
3644 return 0;
3645}
3646
26471403
CB
3647static inline int clr_config_idmaps(const char *key, struct lxc_conf *c,
3648 void *data)
d3a178de
CB
3649{
3650 return lxc_clear_idmaps(c);
3651}
97d3338d 3652
46cc906d 3653static inline int clr_config_log_level(const char *key, struct lxc_conf *c,
26471403 3654 void *data)
97d3338d 3655{
4b73005c 3656 c->loglevel = LXC_LOG_LEVEL_NOTSET;
97d3338d
CB
3657 return 0;
3658}
de46099c 3659
46cc906d 3660static inline int clr_config_log_file(const char *key, struct lxc_conf *c,
26471403 3661 void *data)
de46099c
CB
3662{
3663 free(c->logfile);
3664 c->logfile = NULL;
3665 return 0;
3666}
b4fa13cd 3667
26471403
CB
3668static inline int clr_config_mount(const char *key, struct lxc_conf *c,
3669 void *data)
b4fa13cd
CB
3670{
3671 return lxc_clear_mount_entries(c);
3672}
4be81021 3673
26471403
CB
3674static inline int clr_config_mount_auto(const char *key, struct lxc_conf *c,
3675 void *data)
4be81021
CB
3676{
3677 return lxc_clear_automounts(c);
3678}
350d4b15 3679
47148e96
CB
3680static inline int clr_config_mount_fstab(const char *key, struct lxc_conf *c,
3681 void *data)
350d4b15
CB
3682{
3683 free(c->fstab);
3684 c->fstab = NULL;
3685 return 0;
3686}
faca124d 3687
7a96a068
CB
3688static inline int clr_config_rootfs_path(const char *key, struct lxc_conf *c,
3689 void *data)
faca124d
CB
3690{
3691 free(c->rootfs.path);
3692 c->rootfs.path = NULL;
3693 return 0;
3694}
3695
26471403
CB
3696static inline int clr_config_rootfs_mount(const char *key, struct lxc_conf *c,
3697 void *data)
fddefc2d
CB
3698{
3699 free(c->rootfs.mount);
3700 c->rootfs.mount = NULL;
3701 return 0;
3702}
7b1eb67d 3703
26471403
CB
3704static inline int clr_config_rootfs_options(const char *key, struct lxc_conf *c,
3705 void *data)
7b1eb67d
CB
3706{
3707 free(c->rootfs.options);
3708 c->rootfs.options = NULL;
3709 return 0;
3710}
02becb8d 3711
26471403
CB
3712static inline int clr_config_rootfs_backend(const char *key, struct lxc_conf *c,
3713 void *data)
02becb8d 3714{
02becb8d
CB
3715 return 0;
3716}
3717
b67771bc 3718static inline int clr_config_uts_name(const char *key, struct lxc_conf *c,
26471403 3719 void *data)
d31d0103
CB
3720{
3721 free(c->utsname);
3722 c->utsname = NULL;
3723 return 0;
3724}
c9eeb90c 3725
26471403
CB
3726static inline int clr_config_hooks(const char *key, struct lxc_conf *c,
3727 void *data)
c9eeb90c
CB
3728{
3729 return lxc_clear_hooks(c, key);
3730}
3731
44ae0fb6
CB
3732static inline int clr_config_hooks_version(const char *key, struct lxc_conf *c,
3733 void *data)
3734{
3735 /* default to legacy hooks version */
3736 c->hooks_version = 0;
3737 return 0;
3738}
3739
f9373e40
CB
3740static inline int clr_config_net(const char *key, struct lxc_conf *c,
3741 void *data)
f4488271 3742{
c302b476
CB
3743 lxc_free_networks(&c->network);
3744
e5d2fd7c 3745 return 0;
f4488271
CB
3746}
3747
26471403
CB
3748static inline int clr_config_cap_drop(const char *key, struct lxc_conf *c,
3749 void *data)
244cb55b
CB
3750{
3751 return lxc_clear_config_caps(c);
3752}
c74cc490 3753
26471403
CB
3754static inline int clr_config_cap_keep(const char *key, struct lxc_conf *c,
3755 void *data)
c74cc490
CB
3756{
3757 return lxc_clear_config_keepcaps(c);
3758}
4e5b633f 3759
3aed4934
CB
3760static inline int clr_config_console_path(const char *key, struct lxc_conf *c,
3761 void *data)
4e5b633f
CB
3762{
3763 free(c->console.path);
3764 c->console.path = NULL;
3765 return 0;
3766}
3767
7c2ec23a 3768static inline int clr_config_console_logfile(const char *key,
26471403 3769 struct lxc_conf *c, void *data)
7c2ec23a
CB
3770{
3771 free(c->console.log_path);
3772 c->console.log_path = NULL;
3773 return 0;
3774}
bbca37d8 3775
d91adfa6
CB
3776static inline int clr_config_console_rotate(const char *key, struct lxc_conf *c,
3777 void *data)
3778{
3779 c->console.log_rotate = 0;
3780 return 0;
3781}
3782
28f3b1cd
CB
3783static inline int clr_config_console_buffer_size(const char *key,
3784 struct lxc_conf *c, void *data)
a04220de 3785{
28f3b1cd 3786 c->console.buffer_size = 0;
a04220de
CB
3787 return 0;
3788}
3789
3a784510
CB
3790static inline int clr_config_console_buffer_logfile(const char *key,
3791 struct lxc_conf *c,
3792 void *data)
3793{
3794 free(c->console.buffer_log_file);
3795 c->console.buffer_log_file = NULL;
3796 return 0;
3797}
3798
0b427da0
CB
3799static inline int clr_config_seccomp_profile(const char *key,
3800 struct lxc_conf *c, void *data)
bbca37d8
CB
3801{
3802 free(c->seccomp);
3803 c->seccomp = NULL;
3804 return 0;
3805}
c721e86c 3806
26471403
CB
3807static inline int clr_config_autodev(const char *key, struct lxc_conf *c,
3808 void *data)
c721e86c
CB
3809{
3810 c->autodev = 1;
3811 return 0;
3812}
87b288d1 3813
55c84efc 3814static inline int clr_config_signal_halt(const char *key, struct lxc_conf *c,
26471403 3815 void *data)
87b288d1
CB
3816{
3817 c->haltsignal = 0;
3818 return 0;
3819}
cae63cfa 3820
55c84efc 3821static inline int clr_config_signal_reboot(const char *key, struct lxc_conf *c,
26471403 3822 void *data)
cae63cfa
CB
3823{
3824 c->rebootsignal = 0;
3825 return 0;
3826}
de45f3a8 3827
55c84efc 3828static inline int clr_config_signal_stop(const char *key, struct lxc_conf *c,
26471403 3829 void *data)
de45f3a8
CB
3830{
3831 c->stopsignal = 0;
3832 return 0;
3833}
c6182222 3834
26471403
CB
3835static inline int clr_config_start(const char *key, struct lxc_conf *c,
3836 void *data)
c6182222
CB
3837{
3838 if (strcmp(key + 10, "auto") == 0)
3839 c->start_auto = 0;
3840 else if (strcmp(key + 10, "delay") == 0)
3841 c->start_delay = 0;
3842 else if (strcmp(key + 10, "order") == 0)
3843 c->start_order = 0;
3844
3845 return 0;
3846}
998ca94f 3847
46cc906d 3848static inline int clr_config_log_syslog(const char *key, struct lxc_conf *c,
26471403 3849 void *data)
998ca94f
CB
3850{
3851 free(c->syslog);
3852 c->syslog = NULL;
3853 return 0;
3854}
adad12ca 3855
26471403
CB
3856static inline int clr_config_monitor(const char *key, struct lxc_conf *c,
3857 void *data)
adad12ca
CB
3858{
3859 c->monitor_unshare = 0;
3860 return 0;
3861}
4850d223 3862
26471403
CB
3863static inline int clr_config_group(const char *key, struct lxc_conf *c,
3864 void *data)
4850d223
CB
3865{
3866 return lxc_clear_groups(c);
3867}
832fb63a 3868
26471403
CB
3869static inline int clr_config_environment(const char *key, struct lxc_conf *c,
3870 void *data)
832fb63a
CB
3871{
3872 return lxc_clear_environment(c);
4850d223 3873}
8e90af3e 3874
5cda27c1
SH
3875static inline int clr_config_execute_cmd(const char *key, struct lxc_conf *c,
3876 void *data)
3877{
3878 free(c->execute_cmd);
3879 c->execute_cmd = NULL;
3880 return 0;
3881}
3882
26471403
CB
3883static inline int clr_config_init_cmd(const char *key, struct lxc_conf *c,
3884 void *data)
8e90af3e
CB
3885{
3886 free(c->init_cmd);
3887 c->init_cmd = NULL;
3888 return 0;
3889}
ec76dcfb 3890
3c491553
L
3891static inline int clr_config_init_cwd(const char *key, struct lxc_conf *c,
3892 void *data)
3893{
3894 free(c->init_cwd);
3895 c->init_cwd = NULL;
3896 return 0;
3897}
3898
26471403
CB
3899static inline int clr_config_init_uid(const char *key, struct lxc_conf *c,
3900 void *data)
ec76dcfb
CB
3901{
3902 c->init_uid = 0;
3903 return 0;
3904}
1044b247 3905
26471403
CB
3906static inline int clr_config_init_gid(const char *key, struct lxc_conf *c,
3907 void *data)
1044b247
CB
3908{
3909 c->init_gid = 0;
3910 return 0;
3911}
59e370db 3912
26471403
CB
3913static inline int clr_config_ephemeral(const char *key, struct lxc_conf *c,
3914 void *data)
59e370db
CB
3915{
3916 c->ephemeral = 0;
3917 return 0;
3918}
b98c5ab0 3919
26471403
CB
3920static inline int clr_config_no_new_privs(const char *key, struct lxc_conf *c,
3921 void *data)
b98c5ab0
CB
3922{
3923 c->no_new_privs = false;
3924 return 0;
3925}
715ccc96 3926
240d4b74 3927static inline int clr_config_prlimit(const char *key, struct lxc_conf *c,
26471403 3928 void *data)
715ccc96
CB
3929{
3930 return lxc_clear_limits(c, key);
3931}
fdf3c589 3932
7edd0540
L
3933static inline int clr_config_sysctl(const char *key, struct lxc_conf *c,
3934 void *data)
3935{
3936 return lxc_clear_sysctls(c, key);
3937}
3938
61d7a733
YT
3939static inline int clr_config_proc(const char *key, struct lxc_conf *c,
3940 void *data)
3941{
3942 return lxc_clear_procs(c, key);
3943}
3944
26471403
CB
3945static inline int clr_config_includefiles(const char *key, struct lxc_conf *c,
3946 void *data)
fdf3c589
CB
3947{
3948 lxc_clear_includes(c);
3949 return 0;
3950}
a3c8e600 3951
63bab717
CB
3952static inline int clr_config_noop(const char *key, struct lxc_conf *c,
3953 void *data)
3954{
3955 return 0;
3956}
3957
28d9e29e
CB
3958static int clr_config_namespace(const char *key, struct lxc_conf *lxc_conf,
3959 void *data)
3960{
3961 int ns_idx;
3962 const char *namespace;
3963
3964 namespace = key + sizeof("lxc.namespace.") - 1;
3965 ns_idx = lxc_namespace_2_ns_idx(namespace);
3966 if (ns_idx < 0)
3967 return ns_idx;
3968
3969 free(lxc_conf->inherit_ns[ns_idx]);
3970 lxc_conf->inherit_ns[ns_idx] = NULL;
3971
3972 return 0;
3973}
3974
a3c8e600 3975static int get_config_includefiles(const char *key, char *retv, int inlen,
cccd2219 3976 struct lxc_conf *c, void *data)
a3c8e600
CB
3977{
3978 return -ENOSYS;
3979}
40db5d2f 3980
31ee747b
CB
3981static struct lxc_config_t *get_network_config_ops(const char *key,
3982 struct lxc_conf *lxc_conf,
3983 ssize_t *idx,
3984 char **deindexed_key)
40db5d2f 3985{
31ee747b
CB
3986 int ret;
3987 unsigned int tmpidx;
3988 size_t numstrlen;
40db5d2f
CB
3989 char *copy, *idx_start, *idx_end;
3990 struct lxc_config_t *config = NULL;
3991
3992 /* check that this is a sensible network key */
31ee747b
CB
3993 if (strncmp("lxc.net.", key, 8)) {
3994 ERROR("Invalid network configuration key \"%s\"", key);
40db5d2f 3995 return NULL;
31ee747b 3996 }
40db5d2f
CB
3997
3998 copy = strdup(key);
31ee747b
CB
3999 if (!copy) {
4000 ERROR("Failed to duplicate string \"%s\"", key);
40db5d2f 4001 return NULL;
31ee747b 4002 }
40db5d2f 4003
f9373e40 4004 /* lxc.net.<n> */
31ee747b
CB
4005 if (!isdigit(*(key + 8))) {
4006 ERROR("Failed to detect digit in string \"%s\"", key + 8);
4007 goto on_error;
4008 }
40db5d2f 4009
31ee747b
CB
4010 /* beginning of index string */
4011 idx_start = (copy + 7);
4012 *idx_start = '\0';
40db5d2f 4013
31ee747b
CB
4014 /* end of index string */
4015 idx_end = strchr((copy + 8), '.');
7451daf8
CB
4016 if (idx_end)
4017 *idx_end = '\0';
31ee747b
CB
4018
4019 /* parse current index */
4020 ret = lxc_safe_uint((idx_start + 1), &tmpidx);
4021 if (ret < 0) {
4022 ERROR("Failed to parse usigned integer from string \"%s\": %s",
4023 idx_start + 1, strerror(-ret));
4024 *idx = ret;
4025 goto on_error;
4026 }
40db5d2f 4027
31ee747b
CB
4028 /* This, of course is utterly nonsensical on so many levels, but
4029 * better safe than sorry.
4030 * (Checking for INT_MAX here is intentional.)
4031 */
4032 if (tmpidx == INT_MAX) {
25a908b8
CB
4033 SYSERROR("Number of configured networks would overflow the "
4034 "counter");
31ee747b 4035 goto on_error;
40db5d2f 4036 }
31ee747b
CB
4037 *idx = tmpidx;
4038
4039 numstrlen = strlen((idx_start + 1));
4040
4041 /* repair configuration key */
4042 *idx_start = '.';
31ee747b 4043
7451daf8
CB
4044 /* lxc.net.<idx>.<subkey> */
4045 if (idx_end) {
4046 *idx_end = '.';
24fa7df6
FA
4047 if (strlen(idx_end + 1) == 0) {
4048 ERROR("No subkey in network configuration key \"%s\"", key);
4049 goto on_error;
4050 }
40db5d2f 4051
7451daf8
CB
4052 memmove(copy + 8, idx_end + 1, strlen(idx_end + 1));
4053 copy[strlen(key) - numstrlen + 1] = '\0';
4054
300df83e 4055 config = lxc_get_config(copy);
7451daf8 4056 if (!config) {
25a908b8 4057 ERROR("Unknown network configuration key \"%s\"", key);
7451daf8
CB
4058 goto on_error;
4059 }
31ee747b
CB
4060 }
4061
7451daf8
CB
4062 if (deindexed_key)
4063 *deindexed_key = copy;
4064
31ee747b 4065 return config;
40db5d2f
CB
4066
4067on_error:
4068 free(copy);
31ee747b 4069 return NULL;
40db5d2f
CB
4070}
4071
25a908b8
CB
4072/* Config entry is something like "lxc.net.0.ipv4" the key 'lxc.net.' was
4073 * found. So we make sure next comes an integer, find the right callback (by
4074 * rewriting the key), and call it.
40db5d2f 4075 */
f9373e40
CB
4076static int set_config_net_nic(const char *key, const char *value,
4077 struct lxc_conf *lxc_conf, void *data)
40db5d2f 4078{
31ee747b
CB
4079 int ret;
4080 const char *idxstring;
40db5d2f
CB
4081 struct lxc_config_t *config;
4082 struct lxc_netdev *netdev;
4083 ssize_t idx = -1;
31ee747b
CB
4084 char *deindexed_key = NULL;
4085
4086 idxstring = key + 8;
4087 if (!isdigit(*idxstring))
4088 return -1;
40db5d2f 4089
6bed0fb6 4090 if (lxc_config_value_empty(value))
f9373e40 4091 return clr_config_net_nic(key, lxc_conf, data);
6bed0fb6 4092
31ee747b 4093 config = get_network_config_ops(key, lxc_conf, &idx, &deindexed_key);
40db5d2f
CB
4094 if (!config || idx < 0)
4095 return -1;
4096
0070b1c4 4097 netdev = lxc_get_netdev_by_idx(lxc_conf, (unsigned int)idx, true);
31ee747b
CB
4098 if (!netdev) {
4099 free(deindexed_key);
40db5d2f 4100 return -1;
31ee747b 4101 }
40db5d2f 4102
31ee747b
CB
4103 ret = config->set(deindexed_key, value, lxc_conf, netdev);
4104 free(deindexed_key);
4105 return ret;
40db5d2f 4106}
ff6da295 4107
f9373e40
CB
4108static int clr_config_net_nic(const char *key, struct lxc_conf *lxc_conf,
4109 void *data)
ff6da295 4110{
31ee747b 4111 int ret;
519df1c1 4112 const char *idxstring;
ff6da295
CB
4113 struct lxc_config_t *config;
4114 struct lxc_netdev *netdev;
31ee747b
CB
4115 ssize_t idx = -1;
4116 char *deindexed_key = NULL;
519df1c1 4117
31ee747b
CB
4118 idxstring = key + 8;
4119 if (!isdigit(*idxstring))
519df1c1
CB
4120 return -1;
4121
519df1c1 4122 /* The left conjunct is pretty self-explanatory. The right conjunct
31ee747b 4123 * checks whether the two pointers are equal. If they are we know that
519df1c1
CB
4124 * this is not a key that is namespaced any further and so we are
4125 * supposed to clear the whole network.
4126 */
4127 if (isdigit(*idxstring) && (strrchr(key, '.') == (idxstring - 1))) {
4128 unsigned int rmnetdevidx;
4129
4130 if (lxc_safe_uint(idxstring, &rmnetdevidx) < 0)
4131 return -1;
4132
4133 /* Remove network from network list. */
4134 lxc_remove_nic_by_idx(lxc_conf, rmnetdevidx);
4135 return 0;
4136 }
ff6da295 4137
31ee747b 4138 config = get_network_config_ops(key, lxc_conf, &idx, &deindexed_key);
ff6da295
CB
4139 if (!config || idx < 0)
4140 return -1;
4141
0070b1c4 4142 netdev = lxc_get_netdev_by_idx(lxc_conf, (unsigned int)idx, false);
31ee747b
CB
4143 if (!netdev) {
4144 free(deindexed_key);
ff6da295 4145 return -1;
31ee747b 4146 }
ff6da295 4147
31ee747b
CB
4148 ret = config->clr(deindexed_key, lxc_conf, netdev);
4149 free(deindexed_key);
4150 return ret;
ff6da295
CB
4151}
4152
f9373e40
CB
4153static int clr_config_net_type(const char *key, struct lxc_conf *lxc_conf,
4154 void *data)
ff6da295 4155{
070a05af 4156 struct lxc_netdev *netdev = data;
ff6da295 4157
ff6da295
CB
4158 if (!netdev)
4159 return -1;
4160
4161 netdev->type = -1;
4162
4163 return 0;
4164}
4165
f9373e40
CB
4166static int clr_config_net_name(const char *key, struct lxc_conf *lxc_conf,
4167 void *data)
ff6da295 4168{
070a05af 4169 struct lxc_netdev *netdev = data;
ff6da295 4170
ff6da295
CB
4171 if (!netdev)
4172 return -1;
4173
de4855a8 4174 netdev->name[0] = '\0';
ff6da295
CB
4175
4176 return 0;
4177}
4178
f9373e40
CB
4179static int clr_config_net_flags(const char *key, struct lxc_conf *lxc_conf,
4180 void *data)
ff6da295 4181{
070a05af 4182 struct lxc_netdev *netdev = data;
ff6da295 4183
ff6da295
CB
4184 if (!netdev)
4185 return -1;
4186
4187 netdev->flags = 0;
4188
4189 return 0;
4190}
4191
f9373e40
CB
4192static int clr_config_net_link(const char *key, struct lxc_conf *lxc_conf,
4193 void *data)
ff6da295 4194{
070a05af 4195 struct lxc_netdev *netdev = data;
ff6da295 4196
ff6da295
CB
4197 if (!netdev)
4198 return -1;
4199
de4855a8 4200 netdev->link[0] = '\0';
ff6da295
CB
4201
4202 return 0;
4203}
4204
f9373e40
CB
4205static int clr_config_net_macvlan_mode(const char *key,
4206 struct lxc_conf *lxc_conf, void *data)
ff6da295 4207{
070a05af 4208 struct lxc_netdev *netdev = data;
ff6da295 4209
ff6da295
CB
4210 if (!netdev)
4211 return -1;
4212
6bed0fb6
CB
4213 if (netdev->type != LXC_NET_MACVLAN)
4214 return 0;
4215
ff6da295
CB
4216 netdev->priv.macvlan_attr.mode = -1;
4217
4218 return 0;
4219}
4220
f9373e40
CB
4221static int clr_config_net_veth_pair(const char *key, struct lxc_conf *lxc_conf,
4222 void *data)
ff6da295 4223{
070a05af 4224 struct lxc_netdev *netdev = data;
ff6da295 4225
ff6da295
CB
4226 if (!netdev)
4227 return -1;
4228
de4855a8 4229 netdev->priv.veth_attr.pair[0] = '\0';
ff6da295
CB
4230
4231 return 0;
4232}
4233
f9373e40
CB
4234static int clr_config_net_script_up(const char *key, struct lxc_conf *lxc_conf,
4235 void *data)
ff6da295 4236{
070a05af 4237 struct lxc_netdev *netdev = data;
ff6da295 4238
ff6da295
CB
4239 if (!netdev)
4240 return -1;
4241
4242 free(netdev->upscript);
4243 netdev->upscript = NULL;
4244
4245 return 0;
4246}
4247
f9373e40
CB
4248static int clr_config_net_script_down(const char *key,
4249 struct lxc_conf *lxc_conf, void *data)
ff6da295 4250{
070a05af 4251 struct lxc_netdev *netdev = data;
ff6da295 4252
ff6da295
CB
4253 if (!netdev)
4254 return -1;
4255
4256 free(netdev->downscript);
4257 netdev->downscript = NULL;
4258
4259 return 0;
4260}
4261
f9373e40
CB
4262static int clr_config_net_hwaddr(const char *key, struct lxc_conf *lxc_conf,
4263 void *data)
ff6da295 4264{
070a05af 4265 struct lxc_netdev *netdev = data;
ff6da295 4266
ff6da295
CB
4267 if (!netdev)
4268 return -1;
4269
4270 free(netdev->hwaddr);
4271 netdev->hwaddr = NULL;
4272
4273 return 0;
4274}
4275
f9373e40
CB
4276static int clr_config_net_mtu(const char *key, struct lxc_conf *lxc_conf,
4277 void *data)
ff6da295 4278{
070a05af 4279 struct lxc_netdev *netdev = data;
ff6da295 4280
ff6da295
CB
4281 if (!netdev)
4282 return -1;
4283
4284 free(netdev->mtu);
4285 netdev->mtu = NULL;
4286
4287 return 0;
4288}
4289
f9373e40
CB
4290static int clr_config_net_vlan_id(const char *key, struct lxc_conf *lxc_conf,
4291 void *data)
ff6da295 4292{
070a05af 4293 struct lxc_netdev *netdev = data;
ff6da295 4294
ff6da295
CB
4295 if (!netdev)
4296 return -1;
4297
4298 netdev->priv.vlan_attr.vid = 0;
4299
4300 return 0;
4301}
4302
f9373e40
CB
4303static int clr_config_net_ipv4_gateway(const char *key,
4304 struct lxc_conf *lxc_conf, void *data)
ff6da295 4305{
070a05af 4306 struct lxc_netdev *netdev = data;
ff6da295 4307
ff6da295
CB
4308 if (!netdev)
4309 return -1;
4310
4311 free(netdev->ipv4_gateway);
4312 netdev->ipv4_gateway = NULL;
4313
4314 return 0;
4315}
4316
9ff60df2
CB
4317static int clr_config_net_ipv4_address(const char *key,
4318 struct lxc_conf *lxc_conf, void *data)
ff6da295 4319{
070a05af 4320 struct lxc_netdev *netdev = data;
ff6da295
CB
4321 struct lxc_list *cur, *next;
4322
ecbb3790
CB
4323 if (!netdev)
4324 return -1;
ff6da295
CB
4325
4326 lxc_list_for_each_safe(cur, &netdev->ipv4, next) {
4327 lxc_list_del(cur);
4328 free(cur->elem);
4329 free(cur);
4330 }
4331
4332 return 0;
4333}
4334
f9373e40
CB
4335static int clr_config_net_ipv6_gateway(const char *key,
4336 struct lxc_conf *lxc_conf, void *data)
ff6da295 4337{
070a05af 4338 struct lxc_netdev *netdev = data;
ff6da295 4339
ff6da295
CB
4340 if (!netdev)
4341 return -1;
4342
4343 free(netdev->ipv6_gateway);
4344 netdev->ipv6_gateway = NULL;
4345
4346 return 0;
4347}
4348
2e44ae28
CB
4349static int clr_config_net_ipv6_address(const char *key,
4350 struct lxc_conf *lxc_conf, void *data)
ff6da295 4351{
070a05af 4352 struct lxc_netdev *netdev = data;
ff6da295
CB
4353 struct lxc_list *cur, *next;
4354
ecbb3790
CB
4355 if (!netdev)
4356 return -1;
ff6da295
CB
4357
4358 lxc_list_for_each_safe(cur, &netdev->ipv6, next) {
4359 lxc_list_del(cur);
4360 free(cur->elem);
4361 free(cur);
4362 }
4363
4364 return 0;
4365}
9d4bf22d 4366
f9373e40
CB
4367static int get_config_net_nic(const char *key, char *retv, int inlen,
4368 struct lxc_conf *c, void *data)
9d4bf22d 4369{
31ee747b
CB
4370 int ret;
4371 const char *idxstring;
9d4bf22d
CB
4372 struct lxc_config_t *config;
4373 struct lxc_netdev *netdev;
4374 ssize_t idx = -1;
31ee747b 4375 char *deindexed_key = NULL;
9d4bf22d 4376
31ee747b
CB
4377 idxstring = key + 8;
4378 if (!isdigit(*idxstring))
4379 return -1;
4380
4381 config = get_network_config_ops(key, c, &idx, &deindexed_key);
9d4bf22d
CB
4382 if (!config || idx < 0)
4383 return -1;
4384
0070b1c4 4385 netdev = lxc_get_netdev_by_idx(c, (unsigned int)idx, false);
31ee747b
CB
4386 if (!netdev) {
4387 free(deindexed_key);
9d4bf22d 4388 return -1;
31ee747b 4389 }
9d4bf22d 4390
31ee747b
CB
4391 ret = config->get(deindexed_key, retv, inlen, c, netdev);
4392 free(deindexed_key);
4393 return ret;
9d4bf22d
CB
4394}
4395
f9373e40
CB
4396static int get_config_net_type(const char *key, char *retv, int inlen,
4397 struct lxc_conf *c, void *data)
9d4bf22d 4398{
070a05af
CB
4399 int len;
4400 int fulllen = 0;
4401 struct lxc_netdev *netdev = data;
9d4bf22d
CB
4402
4403 if (!retv)
4404 inlen = 0;
4405 else
4406 memset(retv, 0, inlen);
4407
9d4bf22d
CB
4408 if (!netdev)
4409 return -1;
4410
4411 strprint(retv, inlen, "%s", lxc_net_type_to_str(netdev->type));
4412
4413 return fulllen;
4414}
4415
f9373e40
CB
4416static int get_config_net_flags(const char *key, char *retv, int inlen,
4417 struct lxc_conf *c, void *data)
9d4bf22d 4418{
070a05af
CB
4419 int len;
4420 int fulllen = 0;
4421 struct lxc_netdev *netdev = data;
9d4bf22d
CB
4422
4423 if (!retv)
4424 inlen = 0;
4425 else
4426 memset(retv, 0, inlen);
4427
9d4bf22d
CB
4428 if (!netdev)
4429 return -1;
4430
4431 if (netdev->flags & IFF_UP)
4432 strprint(retv, inlen, "up");
4433
4434 return fulllen;
4435}
4436
f9373e40
CB
4437static int get_config_net_link(const char *key, char *retv, int inlen,
4438 struct lxc_conf *c, void *data)
9d4bf22d 4439{
070a05af
CB
4440 int len;
4441 int fulllen = 0;
4442 struct lxc_netdev *netdev = data;
9d4bf22d
CB
4443
4444 if (!retv)
4445 inlen = 0;
4446 else
4447 memset(retv, 0, inlen);
4448
9d4bf22d
CB
4449 if (!netdev)
4450 return -1;
4451
de4855a8 4452 if (netdev->link[0] != '\0')
9d4bf22d
CB
4453 strprint(retv, inlen, "%s", netdev->link);
4454
4455 return fulllen;
4456}
4457
f9373e40
CB
4458static int get_config_net_name(const char *key, char *retv, int inlen,
4459 struct lxc_conf *c, void *data)
9d4bf22d 4460{
070a05af
CB
4461 int len;
4462 int fulllen = 0;
4463 struct lxc_netdev *netdev = data;
9d4bf22d
CB
4464
4465 if (!retv)
4466 inlen = 0;
4467 else
4468 memset(retv, 0, inlen);
4469
9d4bf22d
CB
4470 if (!netdev)
4471 return -1;
4472
de4855a8 4473 if (netdev->name[0] != '\0')
9d4bf22d
CB
4474 strprint(retv, inlen, "%s", netdev->name);
4475
4476 return fulllen;
4477}
4478
f9373e40
CB
4479static int get_config_net_macvlan_mode(const char *key, char *retv, int inlen,
4480 struct lxc_conf *c, void *data)
9d4bf22d 4481{
070a05af
CB
4482 int len;
4483 int fulllen = 0;
9d4bf22d 4484 const char *mode;
070a05af 4485 struct lxc_netdev *netdev = data;
9d4bf22d
CB
4486
4487 if (!retv)
4488 inlen = 0;
4489 else
4490 memset(retv, 0, inlen);
4491
9d4bf22d
CB
4492 if (!netdev)
4493 return -1;
4494
4495 if (netdev->type != LXC_NET_MACVLAN)
4496 return 0;
4497
4498 switch (netdev->priv.macvlan_attr.mode) {
4499 case MACVLAN_MODE_PRIVATE:
4500 mode = "private";
4501 break;
4502 case MACVLAN_MODE_VEPA:
4503 mode = "vepa";
4504 break;
4505 case MACVLAN_MODE_BRIDGE:
4506 mode = "bridge";
4507 break;
4508 case MACVLAN_MODE_PASSTHRU:
4509 mode = "passthru";
4510 break;
4511 default:
4512 mode = "(invalid)";
4513 break;
4514 }
4515
4516 strprint(retv, inlen, "%s", mode);
4517
4518 return fulllen;
4519}
4520
f9373e40
CB
4521static int get_config_net_veth_pair(const char *key, char *retv, int inlen,
4522 struct lxc_conf *c, void *data)
9d4bf22d 4523{
070a05af
CB
4524 int len;
4525 int fulllen = 0;
4526 struct lxc_netdev *netdev = data;
9d4bf22d
CB
4527
4528 if (!retv)
4529 inlen = 0;
4530 else
4531 memset(retv, 0, inlen);
4532
9d4bf22d
CB
4533 if (!netdev)
4534 return -1;
4535
4536 if (netdev->type != LXC_NET_VETH)
4537 return 0;
4538
4539 strprint(retv, inlen, "%s",
de4855a8
CB
4540 netdev->priv.veth_attr.pair[0] != '\0'
4541 ? netdev->priv.veth_attr.pair
4542 : netdev->priv.veth_attr.veth1);
9d4bf22d
CB
4543
4544 return fulllen;
4545}
4546
f9373e40
CB
4547static int get_config_net_script_up(const char *key, char *retv, int inlen,
4548 struct lxc_conf *c, void *data)
9d4bf22d 4549{
070a05af
CB
4550 int len;
4551 int fulllen = 0;
4552 struct lxc_netdev *netdev = data;
9d4bf22d
CB
4553
4554 if (!retv)
4555 inlen = 0;
4556 else
4557 memset(retv, 0, inlen);
4558
9d4bf22d
CB
4559 if (!netdev)
4560 return -1;
4561
4562 if (netdev->upscript)
4563 strprint(retv, inlen, "%s", netdev->upscript);
4564
4565 return fulllen;
4566}
4567
f9373e40
CB
4568static int get_config_net_script_down(const char *key, char *retv, int inlen,
4569 struct lxc_conf *c, void *data)
9d4bf22d 4570{
070a05af
CB
4571 int len;
4572 int fulllen = 0;
4573 struct lxc_netdev *netdev = data;
9d4bf22d
CB
4574
4575 if (!retv)
4576 inlen = 0;
4577 else
4578 memset(retv, 0, inlen);
4579
9d4bf22d
CB
4580 if (!netdev)
4581 return -1;
4582
4583 if (netdev->downscript)
4584 strprint(retv, inlen, "%s", netdev->downscript);
4585
4586 return fulllen;
4587}
4588
f9373e40
CB
4589static int get_config_net_hwaddr(const char *key, char *retv, int inlen,
4590 struct lxc_conf *c, void *data)
9d4bf22d 4591{
070a05af
CB
4592 int len;
4593 int fulllen = 0;
4594 struct lxc_netdev *netdev = data;
9d4bf22d
CB
4595
4596 if (!retv)
4597 inlen = 0;
4598 else
4599 memset(retv, 0, inlen);
4600
9d4bf22d
CB
4601 if (!netdev)
4602 return -1;
4603
4604 if (netdev->hwaddr)
4605 strprint(retv, inlen, "%s", netdev->hwaddr);
4606
4607 return fulllen;
4608}
4609
f9373e40
CB
4610static int get_config_net_mtu(const char *key, char *retv, int inlen,
4611 struct lxc_conf *c, void *data)
9d4bf22d 4612{
070a05af
CB
4613 int len;
4614 int fulllen = 0;
4615 struct lxc_netdev *netdev = data;
9d4bf22d
CB
4616
4617 if (!retv)
4618 inlen = 0;
4619 else
4620 memset(retv, 0, inlen);
4621
9d4bf22d
CB
4622 if (!netdev)
4623 return -1;
4624
4625 if (netdev->mtu)
4626 strprint(retv, inlen, "%s", netdev->mtu);
4627
4628 return fulllen;
4629}
4630
f9373e40
CB
4631static int get_config_net_vlan_id(const char *key, char *retv, int inlen,
4632 struct lxc_conf *c, void *data)
9d4bf22d 4633{
070a05af
CB
4634 int len;
4635 int fulllen = 0;
4636 struct lxc_netdev *netdev = data;
9d4bf22d
CB
4637
4638 if (!retv)
4639 inlen = 0;
4640 else
4641 memset(retv, 0, inlen);
4642
9d4bf22d
CB
4643 if (!netdev)
4644 return -1;
4645
4646 if (netdev->type != LXC_NET_VLAN)
4647 return 0;
4648
4649 strprint(retv, inlen, "%d", netdev->priv.vlan_attr.vid);
4650
4651 return fulllen;
4652}
4653
f9373e40
CB
4654static int get_config_net_ipv4_gateway(const char *key, char *retv, int inlen,
4655 struct lxc_conf *c, void *data)
9d4bf22d 4656{
070a05af 4657 int len;
9d4bf22d 4658 char buf[INET_ADDRSTRLEN];
070a05af
CB
4659 int fulllen = 0;
4660 struct lxc_netdev *netdev = data;
9d4bf22d
CB
4661
4662 if (!retv)
4663 inlen = 0;
4664 else
4665 memset(retv, 0, inlen);
4666
9d4bf22d
CB
4667 if (!netdev)
4668 return -1;
4669
4670 if (netdev->ipv4_gateway_auto) {
4671 strprint(retv, inlen, "auto");
4672 } else if (netdev->ipv4_gateway) {
4673 inet_ntop(AF_INET, netdev->ipv4_gateway, buf, sizeof(buf));
4674 strprint(retv, inlen, "%s", buf);
4675 }
4676
4677 return fulllen;
4678}
4679
9ff60df2
CB
4680static int get_config_net_ipv4_address(const char *key, char *retv, int inlen,
4681 struct lxc_conf *c, void *data)
9d4bf22d 4682{
070a05af 4683 int len;
9d4bf22d
CB
4684 size_t listlen;
4685 char buf[INET_ADDRSTRLEN];
9d4bf22d 4686 struct lxc_list *it;
070a05af
CB
4687 int fulllen = 0;
4688 struct lxc_netdev *netdev = data;
9d4bf22d
CB
4689
4690 if (!retv)
4691 inlen = 0;
4692 else
4693 memset(retv, 0, inlen);
4694
9d4bf22d
CB
4695 if (!netdev)
4696 return -1;
4697
4698 listlen = lxc_list_len(&netdev->ipv4);
4699 lxc_list_for_each(it, &netdev->ipv4) {
4700 struct lxc_inetdev *i = it->elem;
4701 inet_ntop(AF_INET, &i->addr, buf, sizeof(buf));
6fc7d8b6 4702 strprint(retv, inlen, "%s/%u%s", buf, i->prefix,
9d4bf22d
CB
4703 (listlen-- > 1) ? "\n" : "");
4704 }
4705
4706 return fulllen;
4707}
4708
f9373e40
CB
4709static int get_config_net_ipv6_gateway(const char *key, char *retv, int inlen,
4710 struct lxc_conf *c, void *data)
9d4bf22d 4711{
070a05af 4712 int len;
9d4bf22d 4713 char buf[INET6_ADDRSTRLEN];
070a05af
CB
4714 int fulllen = 0;
4715 struct lxc_netdev *netdev = data;
9d4bf22d
CB
4716
4717 if (!retv)
4718 inlen = 0;
4719 else
4720 memset(retv, 0, inlen);
4721
9d4bf22d
CB
4722 if (!netdev)
4723 return -1;
4724
4725 if (netdev->ipv6_gateway_auto) {
4726 strprint(retv, inlen, "auto");
4727 } else if (netdev->ipv6_gateway) {
4728 inet_ntop(AF_INET6, netdev->ipv6_gateway, buf, sizeof(buf));
4729 strprint(retv, inlen, "%s", buf);
4730 }
4731
4732 return fulllen;
4733}
4734
2e44ae28
CB
4735static int get_config_net_ipv6_address(const char *key, char *retv, int inlen,
4736 struct lxc_conf *c, void *data)
9d4bf22d 4737{
070a05af 4738 int len;
9d4bf22d
CB
4739 size_t listlen;
4740 char buf[INET6_ADDRSTRLEN];
9d4bf22d 4741 struct lxc_list *it;
070a05af
CB
4742 int fulllen = 0;
4743 struct lxc_netdev *netdev = data;
9d4bf22d
CB
4744
4745 if (!retv)
4746 inlen = 0;
4747 else
4748 memset(retv, 0, inlen);
4749
9d4bf22d
CB
4750 if (!netdev)
4751 return -1;
4752
4753 listlen = lxc_list_len(&netdev->ipv6);
4754 lxc_list_for_each(it, &netdev->ipv6) {
4755 struct lxc_inet6dev *i = it->elem;
4756 inet_ntop(AF_INET6, &i->addr, buf, sizeof(buf));
6fc7d8b6 4757 strprint(retv, inlen, "%s/%u%s", buf, i->prefix,
9d4bf22d
CB
4758 (listlen-- > 1) ? "\n" : "");
4759 }
4760
4761 return fulllen;
4762}
cfc67626
CB
4763
4764int lxc_list_config_items(char *retv, int inlen)
4765{
4766 size_t i;
4767 int len;
4768 int fulllen = 0;
4769
4770 if (!retv)
4771 inlen = 0;
4772 else
4773 memset(retv, 0, inlen);
4774
4775 for (i = 0; i < config_size; i++) {
4776 char *s = config[i].name;
300df83e 4777
cfc67626
CB
4778 if (s[strlen(s) - 1] == '.')
4779 continue;
300df83e 4780
cfc67626
CB
4781 strprint(retv, inlen, "%s\n", s);
4782 }
4783
4784 return fulllen;
4785}
a5448c15 4786
fe9b7349
CB
4787int lxc_list_subkeys(struct lxc_conf *conf, const char *key, char *retv,
4788 int inlen)
4789{
4790 int len;
4791 int fulllen = 0;
4792
4793 if (!retv)
4794 inlen = 0;
4795 else
4796 memset(retv, 0, inlen);
4797
4798 if (!strcmp(key, "lxc.apparmor")) {
4799 strprint(retv, inlen, "allow_incomplete\n");
4800 strprint(retv, inlen, "profile\n");
dae8c253
CB
4801 } else if (!strcmp(key, "lxc.cgroup")) {
4802 strprint(retv, inlen, "dir\n");
fe9b7349
CB
4803 } else if (!strcmp(key, "lxc.selinux")) {
4804 strprint(retv, inlen, "context\n");
4805 } else if (!strcmp(key, "lxc.mount")) {
4806 strprint(retv, inlen, "auto\n");
4807 strprint(retv, inlen, "entry\n");
4808 strprint(retv, inlen, "fstab\n");
4809 } else if (!strcmp(key, "lxc.rootfs")) {
4810 strprint(retv, inlen, "mount\n");
4811 strprint(retv, inlen, "options\n");
4812 strprint(retv, inlen, "path\n");
4813 } else if (!strcmp(key, "lxc.uts")) {
4814 strprint(retv, inlen, "name\n");
4815 } else if (!strcmp(key, "lxc.hook")) {
4816 strprint(retv, inlen, "autodev\n");
4817 strprint(retv, inlen, "clone\n");
4818 strprint(retv, inlen, "destroy\n");
4819 strprint(retv, inlen, "mount\n");
4820 strprint(retv, inlen, "post-stop\n");
4821 strprint(retv, inlen, "pre-mount\n");
4822 strprint(retv, inlen, "pre-start\n");
08dd2805 4823 strprint(retv, inlen, "start-host\n");
fe9b7349
CB
4824 strprint(retv, inlen, "start\n");
4825 strprint(retv, inlen, "stop\n");
4826 } else if (!strcmp(key, "lxc.cap")) {
4827 strprint(retv, inlen, "drop\n");
4828 strprint(retv, inlen, "keep\n");
4829 } else if (!strcmp(key, "lxc.console")) {
4830 strprint(retv, inlen, "logfile\n");
4831 strprint(retv, inlen, "path\n");
4832 } else if (!strcmp(key, "lxc.seccomp")) {
4833 strprint(retv, inlen, "profile\n");
4834 } else if (!strcmp(key, "lxc.signal")) {
4835 strprint(retv, inlen, "halt\n");
4836 strprint(retv, inlen, "reboot\n");
4837 strprint(retv, inlen, "stop\n");
4838 } else if (!strcmp(key, "lxc.start")) {
4839 strprint(retv, inlen, "auto\n");
4840 strprint(retv, inlen, "delay\n");
4841 strprint(retv, inlen, "order\n");
4842 } else if (!strcmp(key, "lxc.monitor")) {
4843 strprint(retv, inlen, "unshare\n");
4844 } else {
4845 fulllen = -1;
4846 }
4847
4848 return fulllen;
4849}
4850
a5448c15
CB
4851int lxc_list_net(struct lxc_conf *c, const char *key, char *retv, int inlen)
4852{
4853 int len;
4854 const char *idxstring;
a5448c15
CB
4855 struct lxc_netdev *netdev;
4856 int fulllen = 0;
4857 ssize_t idx = -1;
a5448c15
CB
4858
4859 idxstring = key + 8;
4860 if (!isdigit(*idxstring))
4861 return -1;
4862
7451daf8
CB
4863 (void)get_network_config_ops(key, c, &idx, NULL);
4864 if (idx < 0)
a5448c15
CB
4865 return -1;
4866
4867 netdev = lxc_get_netdev_by_idx(c, (unsigned int)idx, false);
a5448c15
CB
4868 if (!netdev)
4869 return -1;
4870
4871 if (!retv)
4872 inlen = 0;
4873 else
4874 memset(retv, 0, inlen);
4875
4876 strprint(retv, inlen, "type\n");
4877 strprint(retv, inlen, "script.up\n");
4878 strprint(retv, inlen, "script.down\n");
4879 if (netdev->type != LXC_NET_EMPTY) {
4880 strprint(retv, inlen, "flags\n");
4881 strprint(retv, inlen, "link\n");
4882 strprint(retv, inlen, "name\n");
4883 strprint(retv, inlen, "hwaddr\n");
4884 strprint(retv, inlen, "mtu\n");
4885 strprint(retv, inlen, "ipv6.address\n");
4886 strprint(retv, inlen, "ipv6.gateway\n");
4887 strprint(retv, inlen, "ipv4.address\n");
4888 strprint(retv, inlen, "ipv4.gateway\n");
4889 }
4890
4891 switch (netdev->type) {
4892 case LXC_NET_VETH:
4893 strprint(retv, inlen, "veth.pair\n");
4894 break;
4895 case LXC_NET_MACVLAN:
4896 strprint(retv, inlen, "macvlan.mode\n");
4897 break;
4898 case LXC_NET_VLAN:
4899 strprint(retv, inlen, "vlan.id\n");
4900 break;
4901 case LXC_NET_PHYS:
4902 break;
4903 }
4904
4905 return fulllen;
4906}