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