]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/confile.c
github: Update for main branch
[mirror_lxc.git] / src / lxc / confile.c
CommitLineData
cc73685d 1/* SPDX-License-Identifier: LGPL-2.1+ */
70c1e708 2
1160ce89
CB
3#include "config.h"
4
d38dd64a 5#include <arpa/inet.h>
70c1e708
CB
6#include <ctype.h>
7#include <dirent.h>
8#include <errno.h>
9#include <fcntl.h>
10#include <inttypes.h>
d38dd64a
CB
11#include <net/if.h>
12#include <netinet/in.h>
70c1e708 13#include <signal.h>
c2cc9f0a 14#include <stdio.h>
15#include <stdlib.h>
16#include <string.h>
70c1e708 17#include <sys/param.h>
63376d7d 18#include <sys/stat.h>
c2cc9f0a 19#include <sys/types.h>
c2cc9f0a 20#include <sys/utsname.h>
d38dd64a 21#include <syslog.h>
15b9e2b0 22#include <sys/time.h>
d38dd64a 23#include <unistd.h>
c2cc9f0a 24
86ce1da1 25#include "af_unix.h"
70c1e708 26#include "conf.h"
525f0002 27#include "confile.h"
0b843d35 28#include "confile_utils.h"
58db1a61 29#include "netns_ifaddrs.h"
f2363e38 30#include "log.h"
58e0f57d 31#include "lxcseccomp.h"
fdf76c6d 32#include "macro.h"
f01d0358 33#include "memory_utils.h"
70c1e708
CB
34#include "network.h"
35#include "parse.h"
70c1e708 36#include "utils.h"
36eb9bde 37
db4af8c5 38#if !HAVE_STRLCPY
58db1a61 39#include "strlcpy.h"
43f984ea
DJ
40#endif
41
db4af8c5 42#if !HAVE_STRLCAT
58db1a61 43#include "strlcat.h"
ebcd5140
DJ
44#endif
45
15b9e2b0
CB
46#if HAVE_SYS_RESOURCE_H
47#include <sys/resource.h>
48#endif
49
ac2cecc4 50lxc_log_define(confile, lxc);
576f946d 51
afeec9b7
CB
52#define lxc_config_define(name) \
53 __hot static int set_config_##name(const char *, const char *, \
54 struct lxc_conf *, void *); \
55 __hot static int get_config_##name(const char *, char *, int, \
56 struct lxc_conf *, void *); \
57 __hot static int clr_config_##name(const char *, struct lxc_conf *, \
58 void *);
71e287ca 59
63bab717 60lxc_config_define(autodev);
63012bdd 61lxc_config_define(autodev_tmpfs_size);
71e287ca 62lxc_config_define(apparmor_allow_incomplete);
1800f924 63lxc_config_define(apparmor_allow_nesting);
63bab717 64lxc_config_define(apparmor_profile);
1800f924 65lxc_config_define(apparmor_raw);
63bab717
CB
66lxc_config_define(cap_drop);
67lxc_config_define(cap_keep);
43654d34 68lxc_config_define(cgroup_controller);
54860ed0 69lxc_config_define(cgroup2_controller);
43654d34 70lxc_config_define(cgroup_dir);
a900cbaf 71lxc_config_define(cgroup_monitor_dir);
7696c1f9 72lxc_config_define(cgroup_monitor_pivot_dir);
a900cbaf
WB
73lxc_config_define(cgroup_container_dir);
74lxc_config_define(cgroup_container_inner_dir);
9caee129 75lxc_config_define(cgroup_relative);
28f3b1cd 76lxc_config_define(console_buffer_size);
861813e5 77lxc_config_define(console_logfile);
63bab717 78lxc_config_define(console_path);
861813e5
CB
79lxc_config_define(console_rotate);
80lxc_config_define(console_size);
6773e108 81lxc_config_define(unsupported_key);
63bab717
CB
82lxc_config_define(environment);
83lxc_config_define(ephemeral);
84lxc_config_define(execute_cmd);
85lxc_config_define(group);
86lxc_config_define(hooks);
44ae0fb6 87lxc_config_define(hooks_version);
71e287ca 88lxc_config_define(idmaps);
63bab717
CB
89lxc_config_define(includefiles);
90lxc_config_define(init_cmd);
3c491553 91lxc_config_define(init_cwd);
63bab717
CB
92lxc_config_define(init_gid);
93lxc_config_define(init_uid);
bf31b337 94lxc_config_define(init_groups);
7707b0e0 95lxc_config_define(jump_table_net);
8f818a84 96lxc_config_define(keyring_session);
46cc906d 97lxc_config_define(log_file);
63bab717
CB
98lxc_config_define(log_level);
99lxc_config_define(log_syslog);
100lxc_config_define(monitor);
258f8051 101lxc_config_define(monitor_signal_pdeath);
71e287ca 102lxc_config_define(mount);
103lxc_config_define(mount_auto);
47148e96 104lxc_config_define(mount_fstab);
1d8d3676 105lxc_config_define(namespace_clone);
abeb5bba 106lxc_config_define(namespace_keep);
70fd7fc9
CB
107lxc_config_define(time_offset_boot);
108lxc_config_define(time_offset_monotonic);
b074bbf1 109lxc_config_define(namespace_share);
63bab717 110lxc_config_define(net);
71e287ca 111lxc_config_define(net_flags);
71e287ca 112lxc_config_define(net_hwaddr);
9ff60df2 113lxc_config_define(net_ipv4_address);
71e287ca 114lxc_config_define(net_ipv4_gateway);
2e44ae28 115lxc_config_define(net_ipv6_address);
71e287ca 116lxc_config_define(net_ipv6_gateway);
63bab717 117lxc_config_define(net_link);
6509154d 118lxc_config_define(net_l2proxy);
63bab717 119lxc_config_define(net_macvlan_mode);
c9f52382 120lxc_config_define(net_ipvlan_mode);
121lxc_config_define(net_ipvlan_isolation);
63bab717
CB
122lxc_config_define(net_mtu);
123lxc_config_define(net_name);
63bab717
CB
124lxc_config_define(net_script_down);
125lxc_config_define(net_script_up);
126lxc_config_define(net_type);
3f0ed090 127lxc_config_define(net_veth_mode);
be538b8b
CD
128lxc_config_define(net_veth_n_rxqueues);
129lxc_config_define(net_veth_n_txqueues);
63bab717 130lxc_config_define(net_veth_pair);
d4a7da46 131lxc_config_define(net_veth_ipv4_route);
132lxc_config_define(net_veth_ipv6_route);
fdf76c6d 133lxc_config_define(net_veth_vlan_id);
b8e06d33 134lxc_config_define(net_veth_vlan_tagged_id);
63bab717
CB
135lxc_config_define(net_vlan_id);
136lxc_config_define(no_new_privs);
63bab717
CB
137lxc_config_define(personality);
138lxc_config_define(prlimit);
139lxc_config_define(pty_max);
6e54330c 140lxc_config_define(rootfs_managed);
63bab717
CB
141lxc_config_define(rootfs_mount);
142lxc_config_define(rootfs_options);
143lxc_config_define(rootfs_path);
0b427da0 144lxc_config_define(seccomp_profile);
50d86993 145lxc_config_define(seccomp_allow_nesting);
84cf6d25 146lxc_config_define(seccomp_notify_cookie);
86ce1da1 147lxc_config_define(seccomp_notify_proxy);
63bab717 148lxc_config_define(selinux_context);
4fef78bc 149lxc_config_define(selinux_context_keyring);
55c84efc 150lxc_config_define(signal_halt);
151lxc_config_define(signal_reboot);
152lxc_config_define(signal_stop);
71e287ca 153lxc_config_define(start);
63bab717
CB
154lxc_config_define(tty_max);
155lxc_config_define(tty_dir);
156lxc_config_define(uts_name);
7edd0540 157lxc_config_define(sysctl);
61d7a733 158lxc_config_define(proc);
09996a48 159lxc_config_define(sched_core);
c2cc9f0a 160
6773e108
CB
161static int set_config_unsupported_key(const char *key, const char *value,
162 struct lxc_conf *lxc_conf, void *data)
163{
164 return syserror_set(-EINVAL, "Unsupported config key \"%s\"", key);
165}
166
167static int get_config_unsupported_key(const char *key, char *retv, int inlen,
168 struct lxc_conf *c, void *data)
169{
170 return syserror_set(-EINVAL, "Unsupported config key \"%s\"", key);
171}
172
173static int clr_config_unsupported_key(const char *key,
174 struct lxc_conf *lxc_conf, void *data)
175{
176 return syserror_set(-EINVAL, "Unsupported config key \"%s\"", key);
177}
178
20c3318a
MB
179/*
180 * Important Note:
4110345b 181 * If a new config option is added to this table, be aware that
20c3318a
MB
182 * the order in which the options are places into the table matters.
183 * That means that more specific options of a namespace have to be
184 * placed above more generic ones.
185 *
186 * For instance: If lxc.ab is placed before lxc.ab.c, the config option
187 * lxc.ab.c will always be matched to lxc.ab. That is, the lxc.ab.c option
188 * has to be placed above lxc.ab.
189 */
33eb2ec1 190static struct lxc_config_t config_jump_table[] = {
12babd78
CB
191 { "lxc.arch", true, set_config_personality, get_config_personality, clr_config_personality, },
192 { "lxc.apparmor.profile", true, set_config_apparmor_profile, get_config_apparmor_profile, clr_config_apparmor_profile, },
193 { "lxc.apparmor.allow_incomplete", true, set_config_apparmor_allow_incomplete, get_config_apparmor_allow_incomplete, clr_config_apparmor_allow_incomplete, },
194 { "lxc.apparmor.allow_nesting", true, set_config_apparmor_allow_nesting, get_config_apparmor_allow_nesting, clr_config_apparmor_allow_nesting, },
195 { "lxc.apparmor.raw", true, set_config_apparmor_raw, get_config_apparmor_raw, clr_config_apparmor_raw, },
196 { "lxc.autodev.tmpfs.size", true, set_config_autodev_tmpfs_size, get_config_autodev_tmpfs_size, clr_config_autodev_tmpfs_size, },
197 { "lxc.autodev", true, set_config_autodev, get_config_autodev, clr_config_autodev, },
198 { "lxc.cap.drop", true, set_config_cap_drop, get_config_cap_drop, clr_config_cap_drop, },
199 { "lxc.cap.keep", true, set_config_cap_keep, get_config_cap_keep, clr_config_cap_keep, },
200 { "lxc.cgroup2", false, set_config_cgroup2_controller, get_config_cgroup2_controller, clr_config_cgroup2_controller, },
201 { "lxc.cgroup.dir.monitor.pivot", true, set_config_cgroup_monitor_pivot_dir, get_config_cgroup_monitor_pivot_dir, clr_config_cgroup_monitor_pivot_dir, },
202 { "lxc.cgroup.dir.monitor", true, set_config_cgroup_monitor_dir, get_config_cgroup_monitor_dir, clr_config_cgroup_monitor_dir, },
203 { "lxc.cgroup.dir.container.inner", true, set_config_cgroup_container_inner_dir, get_config_cgroup_container_inner_dir, clr_config_cgroup_container_inner_dir, },
204 { "lxc.cgroup.dir.container", true, set_config_cgroup_container_dir, get_config_cgroup_container_dir, clr_config_cgroup_container_dir, },
205 { "lxc.cgroup.dir", true, set_config_cgroup_dir, get_config_cgroup_dir, clr_config_cgroup_dir, },
206 { "lxc.cgroup.relative", true, set_config_cgroup_relative, get_config_cgroup_relative, clr_config_cgroup_relative, },
207 { "lxc.cgroup", false, set_config_cgroup_controller, get_config_cgroup_controller, clr_config_cgroup_controller, },
208 { "lxc.console.buffer.size", true, set_config_console_buffer_size, get_config_console_buffer_size, clr_config_console_buffer_size, },
209 { "lxc.console.logfile", true, set_config_console_logfile, get_config_console_logfile, clr_config_console_logfile, },
210 { "lxc.console.path", true, set_config_console_path, get_config_console_path, clr_config_console_path, },
211 { "lxc.console.rotate", true, set_config_console_rotate, get_config_console_rotate, clr_config_console_rotate, },
212 { "lxc.console.size", true, set_config_console_size, get_config_console_size, clr_config_console_size, },
09996a48 213 { "lxc.sched.core", true, set_config_sched_core, get_config_sched_core, clr_config_sched_core, },
12babd78
CB
214 { "lxc.environment", true, set_config_environment, get_config_environment, clr_config_environment, },
215 { "lxc.ephemeral", true, set_config_ephemeral, get_config_ephemeral, clr_config_ephemeral, },
216 { "lxc.execute.cmd", true, set_config_execute_cmd, get_config_execute_cmd, clr_config_execute_cmd, },
217 { "lxc.group", true, set_config_group, get_config_group, clr_config_group, },
218 { "lxc.hook.autodev", true, set_config_hooks, get_config_hooks, clr_config_hooks, },
219 { "lxc.hook.clone", true, set_config_hooks, get_config_hooks, clr_config_hooks, },
220 { "lxc.hook.destroy", true, set_config_hooks, get_config_hooks, clr_config_hooks, },
221 { "lxc.hook.mount", true, set_config_hooks, get_config_hooks, clr_config_hooks, },
222 { "lxc.hook.post-stop", true, set_config_hooks, get_config_hooks, clr_config_hooks, },
223 { "lxc.hook.pre-mount", true, set_config_hooks, get_config_hooks, clr_config_hooks, },
224 { "lxc.hook.pre-start", true, set_config_hooks, get_config_hooks, clr_config_hooks, },
225 { "lxc.hook.start", true, set_config_hooks, get_config_hooks, clr_config_hooks, },
226 { "lxc.hook.start-host", true, set_config_hooks, get_config_hooks, clr_config_hooks, },
227 { "lxc.hook.stop", true, set_config_hooks, get_config_hooks, clr_config_hooks, },
228 { "lxc.hook.version", true, set_config_hooks_version, get_config_hooks_version, clr_config_hooks_version, },
229 { "lxc.hook", true, set_config_hooks, get_config_hooks, clr_config_hooks, },
230 { "lxc.idmap", true, set_config_idmaps, get_config_idmaps, clr_config_idmaps, },
231 { "lxc.include", true, set_config_includefiles, get_config_includefiles, clr_config_includefiles, },
232 { "lxc.init.cmd", true, set_config_init_cmd, get_config_init_cmd, clr_config_init_cmd, },
233 { "lxc.init.gid", true, set_config_init_gid, get_config_init_gid, clr_config_init_gid, },
234 { "lxc.init.groups", true, set_config_init_groups, get_config_init_groups, clr_config_init_groups, },
235 { "lxc.init.uid", true, set_config_init_uid, get_config_init_uid, clr_config_init_uid, },
236 { "lxc.init.cwd", true, set_config_init_cwd, get_config_init_cwd, clr_config_init_cwd, },
237 { "lxc.keyring.session", true, set_config_keyring_session, get_config_keyring_session, clr_config_keyring_session },
238 { "lxc.log.file", true, set_config_log_file, get_config_log_file, clr_config_log_file, },
239 { "lxc.log.level", true, set_config_log_level, get_config_log_level, clr_config_log_level, },
240 { "lxc.log.syslog", true, set_config_log_syslog, get_config_log_syslog, clr_config_log_syslog, },
241 { "lxc.monitor.unshare", true, set_config_monitor, get_config_monitor, clr_config_monitor, },
242 { "lxc.monitor.signal.pdeath", true, set_config_monitor_signal_pdeath, get_config_monitor_signal_pdeath, clr_config_monitor_signal_pdeath, },
243 { "lxc.mount.auto", true, set_config_mount_auto, get_config_mount_auto, clr_config_mount_auto, },
244 { "lxc.mount.entry", true, set_config_mount, get_config_mount, clr_config_mount, },
245 { "lxc.mount.fstab", true, set_config_mount_fstab, get_config_mount_fstab, clr_config_mount_fstab, },
246 { "lxc.namespace.clone", true, set_config_namespace_clone, get_config_namespace_clone, clr_config_namespace_clone, },
247 { "lxc.namespace.keep", true, set_config_namespace_keep, get_config_namespace_keep, clr_config_namespace_keep, },
057d2cae 248 { "lxc.namespace.share.", false, set_config_namespace_share, get_config_namespace_share, clr_config_namespace_share, },
7707b0e0 249 { "lxc.time.offset.boot", true, set_config_time_offset_boot, get_config_time_offset_boot, clr_config_time_offset_boot, },
12babd78 250 { "lxc.time.offset.monotonic", true, set_config_time_offset_monotonic, get_config_time_offset_monotonic, clr_config_time_offset_monotonic, },
7707b0e0 251 { "lxc.net.", false, set_config_jump_table_net, get_config_jump_table_net, clr_config_jump_table_net, },
12babd78
CB
252 { "lxc.net", true, set_config_net, get_config_net, clr_config_net, },
253 { "lxc.no_new_privs", true, set_config_no_new_privs, get_config_no_new_privs, clr_config_no_new_privs, },
254 { "lxc.prlimit", false, set_config_prlimit, get_config_prlimit, clr_config_prlimit, },
255 { "lxc.pty.max", true, set_config_pty_max, get_config_pty_max, clr_config_pty_max, },
256 { "lxc.rootfs.managed", true, set_config_rootfs_managed, get_config_rootfs_managed, clr_config_rootfs_managed, },
257 { "lxc.rootfs.mount", true, set_config_rootfs_mount, get_config_rootfs_mount, clr_config_rootfs_mount, },
258 { "lxc.rootfs.options", true, set_config_rootfs_options, get_config_rootfs_options, clr_config_rootfs_options, },
259 { "lxc.rootfs.path", true, set_config_rootfs_path, get_config_rootfs_path, clr_config_rootfs_path, },
260 { "lxc.seccomp.allow_nesting", true, set_config_seccomp_allow_nesting, get_config_seccomp_allow_nesting, clr_config_seccomp_allow_nesting, },
261 { "lxc.seccomp.notify.cookie", true, set_config_seccomp_notify_cookie, get_config_seccomp_notify_cookie, clr_config_seccomp_notify_cookie, },
262 { "lxc.seccomp.notify.proxy", true, set_config_seccomp_notify_proxy, get_config_seccomp_notify_proxy, clr_config_seccomp_notify_proxy, },
263 { "lxc.seccomp.profile", true, set_config_seccomp_profile, get_config_seccomp_profile, clr_config_seccomp_profile, },
264 { "lxc.selinux.context.keyring", true, set_config_selinux_context_keyring, get_config_selinux_context_keyring, clr_config_selinux_context_keyring },
265 { "lxc.selinux.context", true, set_config_selinux_context, get_config_selinux_context, clr_config_selinux_context, },
266 { "lxc.signal.halt", true, set_config_signal_halt, get_config_signal_halt, clr_config_signal_halt, },
267 { "lxc.signal.reboot", true, set_config_signal_reboot, get_config_signal_reboot, clr_config_signal_reboot, },
268 { "lxc.signal.stop", true, set_config_signal_stop, get_config_signal_stop, clr_config_signal_stop, },
269 { "lxc.start.auto", true, set_config_start, get_config_start, clr_config_start, },
270 { "lxc.start.delay", true, set_config_start, get_config_start, clr_config_start, },
271 { "lxc.start.order", true, set_config_start, get_config_start, clr_config_start, },
272 { "lxc.tty.dir", true, set_config_tty_dir, get_config_tty_dir, clr_config_tty_dir, },
273 { "lxc.tty.max", true, set_config_tty_max, get_config_tty_max, clr_config_tty_max, },
274 { "lxc.uts.name", true, set_config_uts_name, get_config_uts_name, clr_config_uts_name, },
275 { "lxc.sysctl", false, set_config_sysctl, get_config_sysctl, clr_config_sysctl, },
276 { "lxc.proc", false, set_config_proc, get_config_proc, clr_config_proc, },
a84b9932
AV
277};
278
6773e108
CB
279static struct lxc_config_t unsupported_config_key = {
280 NULL,
281 false,
282 set_config_unsupported_key,
283 get_config_unsupported_key,
284 clr_config_unsupported_key,
285};
286
7707b0e0
CB
287struct lxc_config_net_t {
288 LXC_CONFIG_MEMBERS;
289};
290
291static struct lxc_config_net_t config_jump_table_net[] = {
0abcc213
CB
292 /* If a longer key is added please update. */
293 #define NETWORK_SUBKEY_SIZE_MAX (STRLITERALLEN("veth.vlan.tagged.id") * 2)
294 { "flags", true, set_config_net_flags, get_config_net_flags, clr_config_net_flags, },
295 { "hwaddr", true, set_config_net_hwaddr, get_config_net_hwaddr, clr_config_net_hwaddr, },
296 { "ipv4.address", true, set_config_net_ipv4_address, get_config_net_ipv4_address, clr_config_net_ipv4_address, },
297 { "ipv4.gateway", true, set_config_net_ipv4_gateway, get_config_net_ipv4_gateway, clr_config_net_ipv4_gateway, },
298 { "ipv6.address", true, set_config_net_ipv6_address, get_config_net_ipv6_address, clr_config_net_ipv6_address, },
299 { "ipv6.gateway", true, set_config_net_ipv6_gateway, get_config_net_ipv6_gateway, clr_config_net_ipv6_gateway, },
300 { "link", true, set_config_net_link, get_config_net_link, clr_config_net_link, },
301 { "l2proxy", true, set_config_net_l2proxy, get_config_net_l2proxy, clr_config_net_l2proxy, },
302 { "macvlan.mode", true, set_config_net_macvlan_mode, get_config_net_macvlan_mode, clr_config_net_macvlan_mode, },
303 { "ipvlan.mode", true, set_config_net_ipvlan_mode, get_config_net_ipvlan_mode, clr_config_net_ipvlan_mode, },
304 { "ipvlan.isolation", true, set_config_net_ipvlan_isolation, get_config_net_ipvlan_isolation, clr_config_net_ipvlan_isolation, },
305 { "mtu", true, set_config_net_mtu, get_config_net_mtu, clr_config_net_mtu, },
306 { "name", true, set_config_net_name, get_config_net_name, clr_config_net_name, },
307 { "script.down", true, set_config_net_script_down, get_config_net_script_down, clr_config_net_script_down, },
308 { "script.up", true, set_config_net_script_up, get_config_net_script_up, clr_config_net_script_up, },
309 { "type", true, set_config_net_type, get_config_net_type, clr_config_net_type, },
310 { "vlan.id", true, set_config_net_vlan_id, get_config_net_vlan_id, clr_config_net_vlan_id, },
311 { "veth.mode", true, set_config_net_veth_mode, get_config_net_veth_mode, clr_config_net_veth_mode, },
be538b8b
CD
312 { "veth.n_rxqueues", true, set_config_net_veth_n_rxqueues, get_config_net_veth_n_rxqueues, clr_config_net_veth_n_rxqueues, },
313 { "veth.n_txqueues", true, set_config_net_veth_n_txqueues, get_config_net_veth_n_txqueues, clr_config_net_veth_n_txqueues, },
0abcc213
CB
314 { "veth.pair", true, set_config_net_veth_pair, get_config_net_veth_pair, clr_config_net_veth_pair, },
315 { "veth.ipv4.route", true, set_config_net_veth_ipv4_route, get_config_net_veth_ipv4_route, clr_config_net_veth_ipv4_route, },
316 { "veth.ipv6.route", true, set_config_net_veth_ipv6_route, get_config_net_veth_ipv6_route, clr_config_net_veth_ipv6_route, },
317 { "veth.vlan.id", true, set_config_net_veth_vlan_id, get_config_net_veth_vlan_id, clr_config_net_veth_vlan_id, },
318 { "veth.vlan.tagged.id", true, set_config_net_veth_vlan_tagged_id, get_config_net_veth_vlan_tagged_id, clr_config_net_veth_vlan_tagged_id, },
319};
c2cc9f0a 320
6773e108
CB
321static struct lxc_config_net_t unsupported_config_net_key = {
322 NULL,
323 false,
324 set_config_unsupported_key,
325 get_config_unsupported_key,
326 clr_config_unsupported_key,
327};
328
6eb516a7
RJ
329struct lxc_config_t *lxc_get_config_exact(const char *key)
330{
331 size_t i;
332
0abcc213 333 for (i = 0; i < ARRAY_SIZE(config_jump_table); i++)
d62177e9 334 if (strequal(config_jump_table[i].name, key))
6eb516a7
RJ
335 return &config_jump_table[i];
336
337 return NULL;
338}
339
ae393e13
CB
340/* Assume a reasonable subkey size limit. */
341#define LXC_SUBKEY_LEN_MAX 256
342
343static inline int match_config_item(const struct lxc_config_t *entry, const char *key)
0abcc213 344{
ae393e13
CB
345 size_t len;
346
0abcc213
CB
347 if (entry->strict)
348 return strequal(entry->name, key);
ae393e13
CB
349
350 /* There should be no subkey longer than this. */
351 len = strnlen(entry->name, LXC_SUBKEY_LEN_MAX);
352 if (len == LXC_SUBKEY_LEN_MAX)
353 return error_ret(-E2BIG, "Excessive subkey length");
354
355 return strnequal(entry->name, key, len);
0abcc213 356}
6eb516a7 357
300df83e 358struct lxc_config_t *lxc_get_config(const char *key)
c2cc9f0a 359{
0abcc213 360 for (size_t i = 0; i < ARRAY_SIZE(config_jump_table); i++) {
12babd78 361 struct lxc_config_t *cur = &config_jump_table[i];
12babd78 362
ae393e13
CB
363 switch (match_config_item(cur, key)) {
364 case 0:
0abcc213 365 continue;
ae393e13 366 case -E2BIG:
6773e108 367 return &unsupported_config_key;
ae393e13 368 }
0abcc213
CB
369
370 return cur;
371 }
372
6773e108 373 return &unsupported_config_key;
0abcc213
CB
374}
375
7707b0e0
CB
376static inline bool match_config_net_item(const struct lxc_config_net_t *entry,
377 const char *key)
378{
379 if (entry->strict)
380 return strequal(entry->name, key);
381 return strnequal(entry->name, key, strlen(entry->name));
382}
383
384static struct lxc_config_net_t *lxc_get_config_net(const char *key)
0abcc213
CB
385{
386 for (size_t i = 0; i < ARRAY_SIZE(config_jump_table_net); i++) {
7707b0e0 387 struct lxc_config_net_t *cur = &config_jump_table_net[i];
0abcc213 388
7707b0e0 389 if (!match_config_net_item(cur, key))
12babd78
CB
390 continue;
391
392 return cur;
393 }
300df83e 394
6773e108 395 return &unsupported_config_net_key;
c2cc9f0a 396}
397
f9373e40
CB
398static int set_config_net(const char *key, const char *value,
399 struct lxc_conf *lxc_conf, void *data)
6b0d5538 400{
b28be01f
CB
401 if (!lxc_config_value_empty(value))
402 return syserror_set(-EINVAL, "lxc.net must not have a value");
6b0d5538 403
f9373e40 404 return clr_config_net(key, lxc_conf, data);
6b0d5538
SH
405}
406
f9373e40
CB
407static int set_config_net_type(const char *key, const char *value,
408 struct lxc_conf *lxc_conf, void *data)
c2cc9f0a 409{
070a05af 410 struct lxc_netdev *netdev = data;
c2cc9f0a 411
bbc079cf 412 if (!netdev)
059a1ec3 413 return ret_errno(EINVAL);
c2cc9f0a 414
8d508eaa 415 clr_config_net_type(key, lxc_conf, data);
299ddd16 416 if (lxc_config_value_empty(value))
8d508eaa 417 return 0;
299ddd16 418
d62177e9 419 if (strequal(value, "veth")) {
24654103 420 netdev->type = LXC_NET_VETH;
303707f6 421 INIT_LIST_HEAD(&netdev->priv.veth_attr.ipv4_routes);
6bf0c06b 422 INIT_LIST_HEAD(&netdev->priv.veth_attr.ipv6_routes);
b8e06d33 423 lxc_list_init(&netdev->priv.veth_attr.vlan_tagged_ids);
756cadb6
CB
424 if (!lxc_veth_flag_to_mode(netdev->priv.veth_attr.mode))
425 lxc_veth_mode_to_flag(&netdev->priv.veth_attr.mode, "bridge");
d62177e9 426 } else if (strequal(value, "macvlan")) {
24654103 427 netdev->type = LXC_NET_MACVLAN;
756cadb6
CB
428 if (!lxc_macvlan_flag_to_mode(netdev->priv.veth_attr.mode))
429 lxc_macvlan_mode_to_flag(&netdev->priv.macvlan_attr.mode, "private");
d62177e9 430 } else if (strequal(value, "ipvlan")) {
c9f52382 431 netdev->type = LXC_NET_IPVLAN;
756cadb6
CB
432 if (!lxc_ipvlan_flag_to_mode(netdev->priv.ipvlan_attr.mode))
433 lxc_ipvlan_mode_to_flag(&netdev->priv.ipvlan_attr.mode, "l3");
434 if (!lxc_ipvlan_flag_to_isolation(netdev->priv.ipvlan_attr.isolation))
435 lxc_ipvlan_isolation_to_flag(&netdev->priv.ipvlan_attr.isolation, "bridge");
d62177e9 436 } else if (strequal(value, "vlan")) {
24654103 437 netdev->type = LXC_NET_VLAN;
d62177e9 438 } else if (strequal(value, "phys")) {
24654103 439 netdev->type = LXC_NET_PHYS;
d62177e9 440 } else if (strequal(value, "empty")) {
24654103 441 netdev->type = LXC_NET_EMPTY;
43e2a964
CB
442 /* We don't support custom loopback device names. */
443 (void)strlcpy(netdev->name, "lo", IFNAMSIZ);
d62177e9 444 } else if (strequal(value, "none")) {
26b797f3 445 netdev->type = LXC_NET_NONE;
bbc079cf 446 } else {
059a1ec3 447 return log_error(-1, "Invalid network type %s", value);
c2cc9f0a 448 }
bbc079cf 449
c2cc9f0a 450 return 0;
451}
452
f9373e40
CB
453static int set_config_net_flags(const char *key, const char *value,
454 struct lxc_conf *lxc_conf, void *data)
c2cc9f0a 455{
070a05af 456 struct lxc_netdev *netdev = data;
c2cc9f0a 457
33c945e0 458 if (!netdev)
059a1ec3 459 return ret_errno(EINVAL);
c2cc9f0a 460
299ddd16
CB
461 if (lxc_config_value_empty(value))
462 return clr_config_net_flags(key, lxc_conf, data);
463
33c945e0 464 netdev->flags |= IFF_UP;
c2cc9f0a 465
33c945e0
MT
466 return 0;
467}
468
b45e32f9 469static int create_matched_ifnames(const char *value, struct lxc_conf *lxc_conf,
d5aba460 470 struct lxc_netdev *netdev)
576400e5 471{
c4ef8f4c
CB
472 call_cleaner(netns_freeifaddrs) struct netns_ifaddrs *ifaddr = NULL;
473 struct netns_ifaddrs *ifa;
504a2217
CB
474 int n;
475 int ret = 0;
f9373e40
CB
476 const char *type_key = "lxc.net.type";
477 const char *link_key = "lxc.net.link";
576400e5 478 const char *tmpvalue = "phys";
576400e5 479
c4ef8f4c
CB
480 if (netns_getifaddrs(&ifaddr, -1, &(bool){false}) < 0)
481 return log_error_errno(-1, errno, "Failed to get network interfaces");
576400e5 482
483 for (ifa = ifaddr, n = 0; ifa != NULL; ifa = ifa->ifa_next, n++) {
484 if (!ifa->ifa_addr)
485 continue;
47903908 486
576400e5 487 if (ifa->ifa_addr->sa_family != AF_PACKET)
488 continue;
489
1af3044f 490 if (strnequal(value, ifa->ifa_name, strlen(value) - 1)) {
f9373e40
CB
491 ret = set_config_net_type(type_key, tmpvalue, lxc_conf,
492 netdev);
576400e5 493 if (!ret) {
f9373e40 494 ret = set_config_net_link(
c302b476 495 link_key, ifa->ifa_name, lxc_conf, netdev);
576400e5 496 if (ret) {
47903908 497 ERROR("Failed to create matched ifnames");
576400e5 498 break;
499 }
500 } else {
47903908 501 ERROR("Failed to create matched ifnames");
576400e5 502 break;
503 }
504 }
505 }
506
576400e5 507 return ret;
508}
509
f9373e40
CB
510static int set_config_net_link(const char *key, const char *value,
511 struct lxc_conf *lxc_conf, void *data)
33c945e0 512{
070a05af 513 struct lxc_netdev *netdev = data;
576400e5 514 int ret = 0;
33c945e0 515
33c945e0 516 if (!netdev)
059a1ec3 517 return ret_errno(EINVAL);
c2cc9f0a 518
299ddd16
CB
519 if (lxc_config_value_empty(value))
520 return clr_config_net_link(key, lxc_conf, data);
521
b45e32f9
CB
522 if (value[strlen(value) - 1] == '+' && netdev->type == LXC_NET_PHYS)
523 ret = create_matched_ifnames(value, lxc_conf, netdev);
524 else
18cd4b54 525 ret = network_ifname(netdev->link, value, sizeof(netdev->link));
576400e5 526
527 return ret;
c2cc9f0a 528}
529
6509154d 530static int set_config_net_l2proxy(const char *key, const char *value,
531 struct lxc_conf *lxc_conf, void *data)
532{
533 struct lxc_netdev *netdev = data;
534 unsigned int val = 0;
535 int ret;
536
6509154d 537 if (!netdev)
059a1ec3 538 return ret_errno(EINVAL);
6509154d 539
299ddd16
CB
540 if (lxc_config_value_empty(value))
541 return clr_config_net_l2proxy(key, lxc_conf, data);
542
6509154d 543 ret = lxc_safe_uint(value, &val);
544 if (ret < 0)
bcdeed91 545 return ret_errno(ret);
6509154d 546
547 switch (val) {
548 case 0:
549 netdev->l2proxy = false;
550 return 0;
551 case 1:
552 netdev->l2proxy = true;
553 return 0;
554 }
555
bcdeed91 556 return ret_errno(EINVAL);
6509154d 557}
558
f9373e40
CB
559static int set_config_net_name(const char *key, const char *value,
560 struct lxc_conf *lxc_conf, void *data)
c2cc9f0a 561{
070a05af 562 struct lxc_netdev *netdev = data;
c2cc9f0a 563
33c945e0 564 if (!netdev)
059a1ec3 565 return ret_errno(EINVAL);
c2cc9f0a 566
299ddd16
CB
567 if (lxc_config_value_empty(value))
568 return clr_config_net_name(key, lxc_conf, data);
569
18cd4b54 570 return network_ifname(netdev->name, value, sizeof(netdev->name));
33c945e0
MT
571}
572
3f0ed090
TP
573
574static int set_config_net_veth_mode(const char *key, const char *value,
575 struct lxc_conf *lxc_conf, void *data)
576{
577 struct lxc_netdev *netdev = data;
578
299ddd16
CB
579 if (!netdev)
580 return ret_errno(EINVAL);
581
582 if (netdev->type != LXC_NET_VETH)
583 return ret_errno(EINVAL);
584
3f0ed090
TP
585 if (lxc_config_value_empty(value))
586 return clr_config_net_veth_mode(key, lxc_conf, data);
587
588 if (!netdev)
059a1ec3 589 return ret_errno(EINVAL);
3f0ed090
TP
590
591 return lxc_veth_mode_to_flag(&netdev->priv.veth_attr.mode, value);
592}
593
be538b8b
CD
594static int set_config_net_veth_n_rxqueues(const char *key, const char *value,
595 struct lxc_conf *lxc_conf, void *data)
596{
597 int n_rxqueues;
598 struct lxc_netdev *netdev = data;
599
600 if (!netdev)
601 return ret_errno(EINVAL);
602
603 if (netdev->type != LXC_NET_VETH)
604 return ret_errno(EINVAL);
605
606 if (lxc_config_value_empty(value))
607 return clr_config_net_veth_n_rxqueues(key, lxc_conf, data);
608
609 if (lxc_safe_int(value, &n_rxqueues))
610 return ret_errno(EINVAL);
611
612 if (n_rxqueues <= 0)
613 return ret_errno(EINVAL);
614
615 netdev->priv.veth_attr.n_rxqueues = n_rxqueues;
616 return 0;
617}
618
619static int set_config_net_veth_n_txqueues(const char *key, const char *value,
620 struct lxc_conf *lxc_conf, void *data)
621{
622 int n_txqueues;
623 struct lxc_netdev *netdev = data;
624
625 if (!netdev)
626 return ret_errno(EINVAL);
627
628 if (netdev->type != LXC_NET_VETH)
629 return ret_errno(EINVAL);
630
631 if (lxc_config_value_empty(value))
632 return clr_config_net_veth_n_txqueues(key, lxc_conf, data);
633
634 if (lxc_safe_int(value, &n_txqueues))
635 return ret_errno(EINVAL);
636
637 if (n_txqueues <= 0)
638 return ret_errno(EINVAL);
639
640 netdev->priv.veth_attr.n_txqueues = n_txqueues;
641 return 0;
642}
643
f9373e40
CB
644static int set_config_net_veth_pair(const char *key, const char *value,
645 struct lxc_conf *lxc_conf, void *data)
e892973e 646{
070a05af 647 struct lxc_netdev *netdev = data;
e892973e 648
e892973e 649 if (!netdev)
059a1ec3 650 return ret_errno(EINVAL);
e892973e 651
299ddd16
CB
652 if (netdev->type != LXC_NET_VETH)
653 return ret_errno(EINVAL);
654
655 if (lxc_config_value_empty(value))
656 return clr_config_net_veth_pair(key, lxc_conf, data);
657
059a1ec3
CB
658 return network_ifname(netdev->priv.veth_attr.pair, value,
659 sizeof(netdev->priv.veth_attr.pair));
e892973e
DL
660}
661
fdf76c6d 662static int set_config_net_veth_vlan_id(const char *key, const char *value,
299ddd16 663 struct lxc_conf *lxc_conf, void *data)
fdf76c6d
TP
664{
665 int ret;
666 struct lxc_netdev *netdev = data;
667
668 if (!netdev)
669 return ret_errno(EINVAL);
670
299ddd16
CB
671 if (netdev->type != LXC_NET_VETH)
672 return ret_errno(EINVAL);
673
fdf76c6d
TP
674 if (lxc_config_value_empty(value))
675 return clr_config_net_veth_vlan_id(key, lxc_conf, data);
676
d62177e9 677 if (strequal(value, "none")) {
fdf76c6d
TP
678 netdev->priv.veth_attr.vlan_id = BRIDGE_VLAN_NONE;
679 } else {
680 unsigned short vlan_id;
5837aa84 681
fdf76c6d
TP
682 ret = get_u16(&vlan_id, value, 0);
683 if (ret < 0)
684 return ret_errno(EINVAL);
685
686 if (vlan_id > BRIDGE_VLAN_ID_MAX)
687 return ret_errno(EINVAL);
688
689 netdev->priv.veth_attr.vlan_id = vlan_id;
690 }
691
692 netdev->priv.veth_attr.vlan_id_set = true;
693 return 0;
694}
695
b8e06d33 696static int set_config_net_veth_vlan_tagged_id(const char *key, const char *value,
299ddd16
CB
697 struct lxc_conf *lxc_conf,
698 void *data)
b8e06d33
TP
699{
700 __do_free struct lxc_list *list = NULL;
701 int ret;
702 unsigned short vlan_id;
703 struct lxc_netdev *netdev = data;
704
705 if (!netdev)
706 return ret_errno(EINVAL);
707
299ddd16
CB
708 if (netdev->type != LXC_NET_VETH)
709 return ret_errno(EINVAL);
710
b8e06d33
TP
711 if (lxc_config_value_empty(value))
712 return clr_config_net_veth_vlan_tagged_id(key, lxc_conf, data);
713
714 ret = get_u16(&vlan_id, value, 0);
715 if (ret < 0)
5837aa84 716 return ret_errno(EINVAL);
b8e06d33
TP
717
718 if (vlan_id > BRIDGE_VLAN_ID_MAX)
5837aa84 719 return ret_errno(EINVAL);
b8e06d33 720
642751cc 721 list = lxc_list_new();
b8e06d33
TP
722 if (!list)
723 return ret_errno(ENOMEM);
724
b8e06d33
TP
725 list->elem = UINT_TO_PTR(vlan_id);
726
727 lxc_list_add_tail(&netdev->priv.veth_attr.vlan_tagged_ids, move_ptr(list));
728
729 return 0;
730}
731
f9373e40
CB
732static int set_config_net_macvlan_mode(const char *key, const char *value,
733 struct lxc_conf *lxc_conf, void *data)
8634bc19 734{
070a05af 735 struct lxc_netdev *netdev = data;
8634bc19 736
8634bc19 737 if (!netdev)
059a1ec3 738 return ret_errno(EINVAL);
8634bc19 739
299ddd16
CB
740 if (netdev->type != LXC_NET_MACVLAN)
741 return ret_errno(EINVAL);
742
743 if (lxc_config_value_empty(value))
744 return clr_config_net_macvlan_mode(key, lxc_conf, data);
745
9b0df30f 746 return lxc_macvlan_mode_to_flag(&netdev->priv.macvlan_attr.mode, value);
8634bc19
MT
747}
748
c9f52382 749static int set_config_net_ipvlan_mode(const char *key, const char *value,
299ddd16 750 struct lxc_conf *lxc_conf, void *data)
c9f52382 751{
752 struct lxc_netdev *netdev = data;
753
c9f52382 754 if (!netdev)
059a1ec3 755 return ret_errno(EINVAL);
c9f52382 756
059a1ec3 757 if (netdev->type != LXC_NET_IPVLAN)
299ddd16
CB
758 return syserror_set(-EINVAL, "Invalid ipvlan mode \"%s\", can only be used with ipvlan network", value);
759
760 if (lxc_config_value_empty(value))
761 return clr_config_net_ipvlan_mode(key, lxc_conf, data);
c9f52382 762
763 return lxc_ipvlan_mode_to_flag(&netdev->priv.ipvlan_attr.mode, value);
764}
765
766static int set_config_net_ipvlan_isolation(const char *key, const char *value,
299ddd16 767 struct lxc_conf *lxc_conf, void *data)
c9f52382 768{
769 struct lxc_netdev *netdev = data;
770
c9f52382 771 if (!netdev)
059a1ec3 772 return ret_errno(EINVAL);
c9f52382 773
059a1ec3 774 if (netdev->type != LXC_NET_IPVLAN)
299ddd16
CB
775 return syserror_set(-EINVAL, "Invalid ipvlan isolation \"%s\", can only be used with ipvlan network", value);
776
777 if (lxc_config_value_empty(value))
778 return clr_config_net_ipvlan_isolation(key, lxc_conf, data);
c9f52382 779
780 return lxc_ipvlan_isolation_to_flag(&netdev->priv.ipvlan_attr.isolation, value);
781}
782
f9373e40
CB
783static int set_config_net_hwaddr(const char *key, const char *value,
784 struct lxc_conf *lxc_conf, void *data)
33c945e0 785{
0b73eb05 786 __do_free char *new_value = NULL;
070a05af 787 struct lxc_netdev *netdev = data;
33c945e0 788
ecbb3790 789 if (!netdev)
059a1ec3 790 return ret_errno(EINVAL);
ecbb3790 791
a8b7aefc 792 clr_config_net_hwaddr(key, lxc_conf, data);
299ddd16 793 if (lxc_config_value_empty(value))
a8b7aefc 794 return 0;
299ddd16 795
504a2217 796 new_value = strdup(value);
d5aba460 797 if (!new_value)
059a1ec3 798 return ret_errno(ENOMEM);
d5aba460 799
508c263e 800 rand_complete_hwaddr(new_value);
f6848c5f 801 if (!lxc_config_value_empty(new_value))
0b73eb05 802 netdev->hwaddr = move_ptr(new_value);
47903908 803
508c263e 804 return 0;
c2cc9f0a 805}
806
f9373e40
CB
807static int set_config_net_vlan_id(const char *key, const char *value,
808 struct lxc_conf *lxc_conf, void *data)
26c39028 809{
d5aba460 810 int ret;
070a05af 811 struct lxc_netdev *netdev = data;
26c39028 812
26c39028 813 if (!netdev)
059a1ec3 814 return ret_errno(EINVAL);
26c39028 815
299ddd16
CB
816 if (netdev->type != LXC_NET_VLAN)
817 return ret_errno(EINVAL);
818
819 if (lxc_config_value_empty(value))
820 return clr_config_net_vlan_id(key, lxc_conf, data);
821
d5aba460
CB
822 ret = get_u16(&netdev->priv.vlan_attr.vid, value, 0);
823 if (ret < 0)
059a1ec3 824 return ret;
26c39028
JHS
825
826 return 0;
827}
828
f9373e40
CB
829static int set_config_net_mtu(const char *key, const char *value,
830 struct lxc_conf *lxc_conf, void *data)
442cbbe6 831{
070a05af 832 struct lxc_netdev *netdev = data;
442cbbe6 833
33c945e0 834 if (!netdev)
059a1ec3 835 return ret_errno(EINVAL);
442cbbe6 836
6d0297b9 837 clr_config_net_mtu(key, lxc_conf, data);
299ddd16 838 if (lxc_config_value_empty(value))
6d0297b9 839 return 0;
299ddd16 840
713046e3 841 return set_config_string_item(&netdev->mtu, value);
442cbbe6
TR
842}
843
9ff60df2
CB
844static int set_config_net_ipv4_address(const char *key, const char *value,
845 struct lxc_conf *lxc_conf, void *data)
c2cc9f0a 846{
059a1ec3
CB
847 __do_free char *addr = NULL;
848 __do_free struct lxc_inetdev *inetdev = NULL;
d5aba460 849 int ret;
070a05af 850 struct lxc_netdev *netdev = data;
504a2217 851 char *cursor, *slash;
059a1ec3 852 char *bcast = NULL, *prefix = NULL;
c2cc9f0a 853
33c945e0 854 if (!netdev)
059a1ec3 855 return ret_errno(EINVAL);
c2cc9f0a 856
299ddd16
CB
857 if (lxc_config_value_empty(value))
858 return clr_config_net_ipv4_address(key, lxc_conf, data);
859
642751cc 860 inetdev = zalloc(sizeof(*inetdev));
d5aba460 861 if (!inetdev)
059a1ec3 862 return ret_errno(ENOMEM);
c2cc9f0a 863
956edc54 864 addr = strdup(value);
059a1ec3
CB
865 if (!addr)
866 return ret_errno(ENOMEM);
c2cc9f0a 867
868 cursor = strstr(addr, " ");
869 if (cursor) {
870 *cursor = '\0';
871 bcast = cursor + 1;
872 }
873
874 slash = strstr(addr, "/");
875 if (slash) {
876 *slash = '\0';
877 prefix = slash + 1;
878 }
879
d5aba460 880 ret = inet_pton(AF_INET, addr, &inetdev->addr);
059a1ec3
CB
881 if (!ret || ret < 0)
882 return log_error_errno(-1, errno, "Invalid ipv4 address \"%s\"", value);
c2cc9f0a 883
d5aba460
CB
884 if (bcast) {
885 ret = inet_pton(AF_INET, bcast, &inetdev->bcast);
059a1ec3
CB
886 if (!ret || ret < 0)
887 return log_error_errno(-1, errno, "Invalid ipv4 broadcast address \"%s\"", value);
d5aba460 888
0093bb8c 889 }
c2cc9f0a 890
504a2217 891 /* No prefix specified, determine it from the network class. */
36513635
CB
892 ret = 0;
893 if (prefix)
d5aba460 894 ret = lxc_safe_uint(prefix, &inetdev->prefix);
36513635 895 else
1c633398 896 inetdev->prefix = config_ip_prefix(&inetdev->addr);
36513635 897 if (ret || inetdev->prefix > 32)
79d2f54f 898 return ret_errno(EINVAL);
a059591e 899
36513635 900 /* If no broadcast address, compute one from the prefix and address. */
0093bb8c 901 if (!bcast) {
26de6cbc
MF
902 /* 0<=inetdev->prefix<=32 */
903 switch (inetdev->prefix) {
904 case 32: /* single IPv4 network */
905 ; /* fall thru */
906 case 31: /* RFC 3021 point to point network */
907 inetdev->bcast.s_addr = INADDR_ANY;
908 break;
909
910 default:
911 inetdev->bcast.s_addr |= htonl(INADDR_BROADCAST >> inetdev->prefix);
912 break;
913 }
914 }
c2cc9f0a 915
05a54a64 916 list_add_tail(&inetdev->head, &netdev->ipv4_addresses);
059a1ec3 917 move_ptr(inetdev);
47903908 918
c2cc9f0a 919 return 0;
920}
921
f9373e40
CB
922static int set_config_net_ipv4_gateway(const char *key, const char *value,
923 struct lxc_conf *lxc_conf, void *data)
f8fee0e2 924{
070a05af 925 struct lxc_netdev *netdev = data;
f8fee0e2 926
299ddd16
CB
927 if (!netdev)
928 return ret_errno(EINVAL);
929
d21e9500 930 clr_config_net_ipv4_gateway(key, lxc_conf, data);
6bed0fb6 931 if (lxc_config_value_empty(value))
d21e9500 932 return 0;
f8fee0e2 933
d62177e9 934 if (strequal(value, "auto")) {
19a26f82
MK
935 netdev->ipv4_gateway = NULL;
936 netdev->ipv4_gateway_auto = true;
d62177e9 937 } else if (strequal(value, "dev")) {
a2f9a670 938 netdev->ipv4_gateway = NULL;
939 netdev->ipv4_gateway_auto = false;
940 netdev->ipv4_gateway_dev = true;
19a26f82 941 } else {
059a1ec3 942 __do_free struct in_addr *gw = NULL;
25a908b8 943 int ret;
e088e926 944
642751cc 945 gw = zalloc(sizeof(*gw));
25a908b8 946 if (!gw)
059a1ec3 947 return ret_errno(ENOMEM);
e088e926 948
25a908b8 949 ret = inet_pton(AF_INET, value, gw);
059a1ec3
CB
950 if (!ret || ret < 0)
951 return log_error_errno(-1, errno, "Invalid ipv4 gateway address \"%s\"", value);
19a26f82 952
059a1ec3 953 netdev->ipv4_gateway = move_ptr(gw);
19a26f82 954 netdev->ipv4_gateway_auto = false;
f8fee0e2
MK
955 }
956
f8fee0e2
MK
957 return 0;
958}
959
d4a7da46 960static int set_config_net_veth_ipv4_route(const char *key, const char *value,
299ddd16 961 struct lxc_conf *lxc_conf, void *data)
d4a7da46 962{
963 __do_free char *valdup = NULL;
964 __do_free struct lxc_inetdev *inetdev = NULL;
d4a7da46 965 int ret;
966 char *netmask, *slash;
967 struct lxc_netdev *netdev = data;
968
d4a7da46 969 if (!netdev)
059a1ec3 970 return ret_errno(EINVAL);
d4a7da46 971
059a1ec3 972 if (netdev->type != LXC_NET_VETH)
299ddd16
CB
973 return syserror_set(-EINVAL, "Invalid ipv4 route \"%s\", can only be used with veth network", value);
974
975 if (lxc_config_value_empty(value))
976 return clr_config_net_veth_ipv4_route(key, lxc_conf, data);
d4a7da46 977
642751cc 978 inetdev = zalloc(sizeof(*inetdev));
d4a7da46 979 if (!inetdev)
059a1ec3 980 return ret_errno(ENOMEM);
d4a7da46 981
d4a7da46 982 valdup = strdup(value);
983 if (!valdup)
059a1ec3 984 return ret_errno(ENOMEM);
d4a7da46 985
986 slash = strchr(valdup, '/');
987 if (!slash)
059a1ec3 988 return ret_errno(EINVAL);
d4a7da46 989
990 *slash = '\0';
991 slash++;
992 if (*slash == '\0')
059a1ec3 993 return ret_errno(EINVAL);
d4a7da46 994
995 netmask = slash;
996
997 ret = lxc_safe_uint(netmask, &inetdev->prefix);
998 if (ret < 0 || inetdev->prefix > 32)
059a1ec3 999 return ret_errno(EINVAL);
d4a7da46 1000
1001 ret = inet_pton(AF_INET, valdup, &inetdev->addr);
1002 if (!ret || ret < 0)
059a1ec3 1003 return ret_errno(EINVAL);
d4a7da46 1004
303707f6 1005 list_add_tail(&inetdev->head, &netdev->priv.veth_attr.ipv4_routes);
d4a7da46 1006 move_ptr(inetdev);
d4a7da46 1007
1008 return 0;
1009}
1010
2e44ae28
CB
1011static int set_config_net_ipv6_address(const char *key, const char *value,
1012 struct lxc_conf *lxc_conf, void *data)
c2cc9f0a 1013{
059a1ec3
CB
1014 __do_free char *valdup = NULL;
1015 __do_free struct lxc_inet6dev *inet6dev = NULL;
25a908b8 1016 int ret;
070a05af 1017 struct lxc_netdev *netdev = data;
059a1ec3 1018 char *slash, *netmask;
c2cc9f0a 1019
33c945e0 1020 if (!netdev)
059a1ec3 1021 return ret_errno(EINVAL);
c2cc9f0a 1022
299ddd16
CB
1023 if (lxc_config_value_empty(value))
1024 return clr_config_net_ipv6_address(key, lxc_conf, data);
1025
642751cc 1026 inet6dev = zalloc(sizeof(*inet6dev));
25a908b8 1027 if (!inet6dev)
059a1ec3 1028 return ret_errno(ENOMEM);
c2cc9f0a 1029
956edc54 1030 valdup = strdup(value);
059a1ec3
CB
1031 if (!valdup)
1032 return ret_errno(ENOMEM);
956edc54 1033
a059591e 1034 inet6dev->prefix = 64;
12a50cc6 1035 slash = strstr(valdup, "/");
c2cc9f0a 1036 if (slash) {
1037 *slash = '\0';
1038 netmask = slash + 1;
47903908 1039
f54f8d0b 1040 ret = lxc_safe_uint(netmask, &inet6dev->prefix);
059a1ec3
CB
1041 if (ret < 0)
1042 return ret;
c2cc9f0a 1043 }
1044
25a908b8 1045 ret = inet_pton(AF_INET6, valdup, &inet6dev->addr);
059a1ec3
CB
1046 if (!ret || ret < 0)
1047 return log_error_errno(-EINVAL, EINVAL, "Invalid ipv6 address \"%s\"", valdup);
c2cc9f0a 1048
05a54a64 1049 list_add_tail(&inet6dev->head, &netdev->ipv6_addresses);
059a1ec3 1050 move_ptr(inet6dev);
47903908 1051
c2cc9f0a 1052 return 0;
1053}
1054
f9373e40
CB
1055static int set_config_net_ipv6_gateway(const char *key, const char *value,
1056 struct lxc_conf *lxc_conf, void *data)
f8fee0e2 1057{
070a05af 1058 struct lxc_netdev *netdev = data;
f8fee0e2 1059
f8fee0e2 1060 if (!netdev)
059a1ec3 1061 return ret_errno(EINVAL);
f8fee0e2 1062
e0f420d5 1063 clr_config_net_ipv6_gateway(key, lxc_conf, data);
299ddd16 1064 if (lxc_config_value_empty(value))
e0f420d5 1065 return 0;
f8fee0e2 1066
d62177e9 1067 if (strequal(value, "auto")) {
19a26f82
MK
1068 netdev->ipv6_gateway = NULL;
1069 netdev->ipv6_gateway_auto = true;
d62177e9 1070 } else if (strequal(value, "dev")) {
a2f9a670 1071 netdev->ipv6_gateway = NULL;
1072 netdev->ipv6_gateway_auto = false;
1073 netdev->ipv6_gateway_dev = true;
19a26f82 1074 } else {
25a908b8 1075 int ret;
059a1ec3 1076 __do_free struct in6_addr *gw = NULL;
8fb86a37 1077
642751cc 1078 gw = zalloc(sizeof(*gw));
25a908b8 1079 if (!gw)
059a1ec3 1080 return ret_errno(ENOMEM);
bec695f3 1081
25a908b8 1082 ret = inet_pton(AF_INET6, value, gw);
059a1ec3
CB
1083 if (!ret || ret < 0)
1084 return log_error_errno(-EINVAL, EINVAL,
1085 "Invalid ipv6 gateway address \"%s\"", value);
19a26f82 1086
059a1ec3 1087 netdev->ipv6_gateway = move_ptr(gw);
19a26f82 1088 netdev->ipv6_gateway_auto = false;
f8fee0e2
MK
1089 }
1090
f8fee0e2
MK
1091 return 0;
1092}
1093
d4a7da46 1094static int set_config_net_veth_ipv6_route(const char *key, const char *value,
299ddd16 1095 struct lxc_conf *lxc_conf, void *data)
d4a7da46 1096{
6453ba56
CB
1097 __do_free char *valdup = NULL;
1098 __do_free struct lxc_inet6dev *inet6dev = NULL;
d4a7da46 1099 int ret;
1100 char *netmask, *slash;
1101 struct lxc_netdev *netdev = data;
1102
d4a7da46 1103 if (!netdev)
059a1ec3 1104 return ret_errno(EINVAL);
d4a7da46 1105
059a1ec3 1106 if (netdev->type != LXC_NET_VETH)
299ddd16
CB
1107 return syserror_set(-EINVAL, "Invalid ipv6 route \"%s\", can only be used with veth network", value);
1108
1109 if (lxc_config_value_empty(value))
1110 return clr_config_net_veth_ipv6_route(key, lxc_conf, data);
d4a7da46 1111
642751cc 1112 inet6dev = zalloc(sizeof(*inet6dev));
d4a7da46 1113 if (!inet6dev)
059a1ec3 1114 return ret_errno(ENOMEM);
d4a7da46 1115
d4a7da46 1116 valdup = strdup(value);
1117 if (!valdup)
b28be01f 1118 return ret_errno(ENOMEM);
d4a7da46 1119
1120 slash = strchr(valdup, '/');
1121 if (!slash)
059a1ec3 1122 return ret_errno(EINVAL);
d4a7da46 1123
1124 *slash = '\0';
1125 slash++;
1126 if (*slash == '\0')
059a1ec3 1127 return ret_errno(EINVAL);
d4a7da46 1128
1129 netmask = slash;
1130
1131 ret = lxc_safe_uint(netmask, &inet6dev->prefix);
1132 if (ret < 0 || inet6dev->prefix > 128)
059a1ec3 1133 return ret_errno(EINVAL);
d4a7da46 1134
1135 ret = inet_pton(AF_INET6, valdup, &inet6dev->addr);
1136 if (!ret || ret < 0)
059a1ec3 1137 return ret_errno(EINVAL);
d4a7da46 1138
6bf0c06b 1139 list_add_tail(&inet6dev->head, &netdev->priv.veth_attr.ipv6_routes);
d4a7da46 1140 move_ptr(inet6dev);
d4a7da46 1141
1142 return 0;
1143}
1144
f9373e40
CB
1145static int set_config_net_script_up(const char *key, const char *value,
1146 struct lxc_conf *lxc_conf, void *data)
e3b4c4c4 1147{
070a05af 1148 struct lxc_netdev *netdev = data;
e3b4c4c4 1149
e3b4c4c4 1150 if (!netdev)
059a1ec3 1151 return ret_errno(EINVAL);
e3b4c4c4 1152
040b3e1d 1153 clr_config_net_script_up(key, lxc_conf, data);
299ddd16 1154 if (lxc_config_value_empty(value))
040b3e1d 1155 return 0;
299ddd16 1156
713046e3 1157 return set_config_string_item(&netdev->upscript, value);
8fc8295a
DE
1158}
1159
f9373e40
CB
1160static int set_config_net_script_down(const char *key, const char *value,
1161 struct lxc_conf *lxc_conf, void *data)
8fc8295a 1162{
070a05af 1163 struct lxc_netdev *netdev = data;
8fc8295a 1164
8fc8295a 1165 if (!netdev)
059a1ec3 1166 return ret_errno(EINVAL);
8fc8295a 1167
f0383b96 1168 clr_config_net_script_down(key, lxc_conf, data);
299ddd16 1169 if (lxc_config_value_empty(value))
f0383b96 1170 return 0;
299ddd16 1171
713046e3 1172 return set_config_string_item(&netdev->downscript, value);
e3b4c4c4
ST
1173}
1174
059a1ec3 1175static int add_hook(struct lxc_conf *lxc_conf, int which, __owns char *hook)
26ddeedd 1176{
059a1ec3 1177 __do_free char *val = hook;
5090de3e 1178 __do_free struct string_entry *entry;
26ddeedd 1179
5090de3e
CB
1180 entry = zalloc(sizeof(struct string_entry));
1181 if (!entry)
059a1ec3 1182 return ret_errno(ENOMEM);
504a2217 1183
5090de3e
CB
1184 entry->val = move_ptr(val);
1185 list_add_tail(&entry->head, &lxc_conf->hooks[which]);
1186 move_ptr(entry);
47903908 1187
26ddeedd
SH
1188 return 0;
1189}
1190
50d86993
CB
1191static int set_config_seccomp_allow_nesting(const char *key, const char *value,
1192 struct lxc_conf *lxc_conf, void *data)
1193{
6ae86a9c 1194#if HAVE_SECCOMP
50d86993
CB
1195 if (lxc_config_value_empty(value))
1196 return clr_config_seccomp_allow_nesting(key, lxc_conf, NULL);
1197
c3e3c21a 1198 if (lxc_safe_uint(value, &lxc_conf->seccomp.allow_nesting) < 0)
b28be01f 1199 return -errno;
50d86993 1200
c3e3c21a 1201 if (lxc_conf->seccomp.allow_nesting > 1)
b28be01f 1202 return ret_errno(EINVAL);
86ce1da1
CB
1203
1204 return 0;
c3e3c21a 1205#else
b28be01f 1206 return ret_errno(ENOSYS);
c3e3c21a 1207#endif
86ce1da1
CB
1208}
1209
84cf6d25
WB
1210static int set_config_seccomp_notify_cookie(const char *key, const char *value,
1211 struct lxc_conf *lxc_conf, void *data)
1212{
331ef062 1213#if HAVE_DECL_SECCOMP_NOTIFY_FD
84cf6d25
WB
1214 return set_config_string_item(&lxc_conf->seccomp.notifier.cookie, value);
1215#else
b28be01f 1216 return ret_errno(ENOSYS);
84cf6d25
WB
1217#endif
1218}
1219
86ce1da1
CB
1220static int set_config_seccomp_notify_proxy(const char *key, const char *value,
1221 struct lxc_conf *lxc_conf, void *data)
1222{
331ef062 1223#if HAVE_DECL_SECCOMP_NOTIFY_FD
86ce1da1
CB
1224 const char *offset;
1225
1226 if (lxc_config_value_empty(value))
1227 return clr_config_seccomp_notify_proxy(key, lxc_conf, NULL);
1228
1af3044f 1229 if (!strnequal(value, "unix:", 5))
b28be01f 1230 return ret_errno(EINVAL);
86ce1da1
CB
1231
1232 offset = value + 5;
c3e3c21a 1233 if (lxc_unix_sockaddr(&lxc_conf->seccomp.notifier.proxy_addr, offset) < 0)
b28be01f 1234 return -errno;
50d86993
CB
1235
1236 return 0;
86ce1da1 1237#else
b28be01f 1238 return ret_errno(ENOSYS);
86ce1da1 1239#endif
50d86993
CB
1240}
1241
0b427da0
CB
1242static int set_config_seccomp_profile(const char *key, const char *value,
1243 struct lxc_conf *lxc_conf, void *data)
8f2c3a70 1244{
6ae86a9c 1245#if HAVE_SECCOMP
c3e3c21a 1246 return set_config_path_item(&lxc_conf->seccomp.seccomp, value);
3d46e1d1 1247#else
b28be01f 1248 return ret_errno(ENOSYS);
3d46e1d1 1249#endif
8f2c3a70
SH
1250}
1251
5cda27c1
SH
1252static int set_config_execute_cmd(const char *key, const char *value,
1253 struct lxc_conf *lxc_conf, void *data)
1254{
51d40b68 1255 return set_config_string_item(&lxc_conf->execute_cmd, value);
5cda27c1
SH
1256}
1257
713046e3 1258static int set_config_init_cmd(const char *key, const char *value,
c7e27aaf 1259 struct lxc_conf *lxc_conf, void *data)
67c660d0 1260{
51d40b68 1261 return set_config_string_item(&lxc_conf->init_cmd, value);
67c660d0
SG
1262}
1263
3c491553
L
1264static int set_config_init_cwd(const char *key, const char *value,
1265 struct lxc_conf *lxc_conf, void *data)
1266{
1267 return set_config_path_item(&lxc_conf->init_cwd, value);
1268}
1269
713046e3 1270static int set_config_init_uid(const char *key, const char *value,
c7e27aaf 1271 struct lxc_conf *lxc_conf, void *data)
72bb04e4 1272{
d1e5d636
CB
1273 unsigned int init_uid;
1274
663e9916 1275 if (lxc_config_value_empty(value)) {
2e7cde40 1276 lxc_conf->init_uid = 0;
fee80911 1277 return 0;
2e7cde40 1278 }
fee80911 1279
d1e5d636 1280 if (lxc_safe_uint(value, &init_uid) < 0)
b28be01f 1281 return -errno;
25a908b8 1282
d1e5d636
CB
1283 lxc_conf->init_uid = init_uid;
1284
72bb04e4
PT
1285 return 0;
1286}
1287
713046e3 1288static int set_config_init_gid(const char *key, const char *value,
c7e27aaf 1289 struct lxc_conf *lxc_conf, void *data)
72bb04e4 1290{
d1e5d636
CB
1291 unsigned int init_gid;
1292
663e9916 1293 if (lxc_config_value_empty(value)) {
2debb6e6 1294 lxc_conf->init_gid = 0;
a757cc7d 1295 return 0;
2debb6e6 1296 }
a757cc7d 1297
d1e5d636 1298 if (lxc_safe_uint(value, &init_gid) < 0)
b28be01f 1299 return -errno;
25a908b8 1300
d1e5d636
CB
1301 lxc_conf->init_gid = init_gid;
1302
72bb04e4
PT
1303 return 0;
1304}
1305
bf31b337
RJ
1306static int set_config_init_groups(const char *key, const char *value,
1307 struct lxc_conf *lxc_conf, void *data)
1308{
1309 __do_free char *value_dup = NULL;
c71f64cb
CB
1310 gid_t *init_groups = NULL;
1311 size_t num_groups = 0;
1312 size_t idx;
bf31b337
RJ
1313 char *token;
1314
1315 if (lxc_config_value_empty(value))
1316 return clr_config_init_groups(key, lxc_conf, NULL);
1317
1318 value_dup = strdup(value);
1319 if (!value_dup)
1320 return -ENOMEM;
1321
1322 lxc_iterate_parts(token, value_dup, ",")
1323 num_groups++;
1324
c71f64cb
CB
1325 if (num_groups == INT_MAX)
1326 return log_error_errno(-ERANGE, ERANGE, "Excessive number of supplementary groups specified");
1327
7fe8120e 1328 /* This means the string wasn't empty and all we found was garbage. */
bf31b337 1329 if (num_groups == 0)
7fe8120e 1330 return log_error_errno(-EINVAL, EINVAL, "No valid groups specified %s", value);
bf31b337 1331
c71f64cb
CB
1332 idx = lxc_conf->init_groups.size;
1333 init_groups = realloc(lxc_conf->init_groups.list, sizeof(gid_t) * (idx + num_groups));
bf31b337
RJ
1334 if (!init_groups)
1335 return ret_errno(ENOMEM);
1336
c71f64cb
CB
1337 /*
1338 * Once the realloc() succeeded we need to hand control of the memory
1339 * back to the config otherwise we risk a double-free when
1340 * lxc_conf_free() is called.
1341 */
1342 lxc_conf->init_groups.list = init_groups;
1343
bf31b337
RJ
1344 /* Restore duplicated value so we can call lxc_iterate_parts() again. */
1345 strcpy(value_dup, value);
1346
1347 lxc_iterate_parts(token, value_dup, ",") {
1348 int ret;
1349
1350 gid_t group;
1351
1352 ret = lxc_safe_uint(token, &group);
1353 if (ret)
7fe8120e 1354 return log_error_errno(ret, -ret, "Failed to parse group %s", token);
bf31b337 1355
c71f64cb 1356 init_groups[idx++] = group;
bf31b337
RJ
1357 }
1358
c71f64cb 1359 lxc_conf->init_groups.size += num_groups;
bf31b337
RJ
1360
1361 return 0;
1362}
1363
466c2e93 1364static int set_config_hooks(const char *key, const char *value,
c7e27aaf 1365 struct lxc_conf *lxc_conf, void *data)
26ddeedd 1366{
059a1ec3 1367 __do_free char *copy = NULL;
72bb04e4 1368
663e9916 1369 if (lxc_config_value_empty(value))
7d0eb87e
SH
1370 return lxc_clear_hooks(lxc_conf, key);
1371
d62177e9 1372 if (strequal(key + 4, "hook"))
ed1454e8 1373 return log_error_errno(-EINVAL, EINVAL, "lxc.hook must not have a value");
25a908b8 1374
7d0eb87e 1375 copy = strdup(value);
25a908b8 1376 if (!copy)
059a1ec3 1377 return ret_errno(ENOMEM);
504a2217 1378
d62177e9 1379 if (strequal(key + 9, "pre-start"))
059a1ec3 1380 return add_hook(lxc_conf, LXCHOOK_PRESTART, move_ptr(copy));
d62177e9 1381 else if (strequal(key + 9, "start-host"))
059a1ec3 1382 return add_hook(lxc_conf, LXCHOOK_START_HOST, move_ptr(copy));
d62177e9 1383 else if (strequal(key + 9, "pre-mount"))
059a1ec3 1384 return add_hook(lxc_conf, LXCHOOK_PREMOUNT, move_ptr(copy));
d62177e9 1385 else if (strequal(key + 9, "autodev"))
059a1ec3 1386 return add_hook(lxc_conf, LXCHOOK_AUTODEV, move_ptr(copy));
d62177e9 1387 else if (strequal(key + 9, "mount"))
059a1ec3 1388 return add_hook(lxc_conf, LXCHOOK_MOUNT, move_ptr(copy));
d62177e9 1389 else if (strequal(key + 9, "start"))
059a1ec3 1390 return add_hook(lxc_conf, LXCHOOK_START, move_ptr(copy));
d62177e9 1391 else if (strequal(key + 9, "stop"))
059a1ec3 1392 return add_hook(lxc_conf, LXCHOOK_STOP, move_ptr(copy));
d62177e9 1393 else if (strequal(key + 9, "post-stop"))
059a1ec3 1394 return add_hook(lxc_conf, LXCHOOK_POSTSTOP, move_ptr(copy));
d62177e9 1395 else if (strequal(key + 9, "clone"))
059a1ec3 1396 return add_hook(lxc_conf, LXCHOOK_CLONE, move_ptr(copy));
d62177e9 1397 else if (strequal(key + 9, "destroy"))
059a1ec3 1398 return add_hook(lxc_conf, LXCHOOK_DESTROY, move_ptr(copy));
47903908 1399
667fcc0e 1400 return ret_errno(EINVAL);
26ddeedd
SH
1401}
1402
44ae0fb6
CB
1403static int set_config_hooks_version(const char *key, const char *value,
1404 struct lxc_conf *lxc_conf, void *data)
1405{
1406 int ret;
1407 unsigned int tmp;
1408
1409 if (lxc_config_value_empty(value))
1410 return clr_config_hooks_version(key, lxc_conf, NULL);
1411
1412 ret = lxc_safe_uint(value, &tmp);
1413 if (ret < 0)
b28be01f 1414 return -errno;
44ae0fb6 1415
ed1454e8 1416 if (tmp > 1)
b28be01f 1417 return syserror_set(-EINVAL, "Invalid hook version specified. Currently only 0 (legacy) and 1 are supported");
44ae0fb6
CB
1418
1419 lxc_conf->hooks_version = tmp;
47903908 1420
44ae0fb6
CB
1421 return 0;
1422}
1423
713046e3 1424static int set_config_personality(const char *key, const char *value,
c7e27aaf 1425 struct lxc_conf *lxc_conf, void *data)
cccc74b5 1426{
7c43fa56 1427 int ret;
64a04c84 1428 personality_t personality;
cccc74b5 1429
7c43fa56
CB
1430 ret = lxc_config_parse_arch(value, &personality);
1431 if (ret < 0)
1432 return syserror("Unsupported personality \"%s\"", value);
970ab589 1433
7c43fa56 1434 lxc_conf->personality = personality;
970ab589 1435 return 0;
cccc74b5
DL
1436}
1437
232763d6
CB
1438static int set_config_pty_max(const char *key, const char *value,
1439 struct lxc_conf *lxc_conf, void *data)
10db618d 1440{
e528c735
CB
1441 int ret;
1442 unsigned int max = 0;
1443
663e9916 1444 if (lxc_config_value_empty(value)) {
e528c735 1445 lxc_conf->pty_max = 0;
884a4580 1446 return 0;
ec200ce9 1447 }
884a4580 1448
e528c735
CB
1449 ret = lxc_safe_uint(value, &max);
1450 if (ret < 0)
49aabd9d 1451 return ret_errno(EINVAL);
10db618d 1452
e528c735 1453 lxc_conf->pty_max = max;
47903908 1454
10db618d 1455 return 0;
1456}
1457
a182feae
CB
1458/* We only need to check whether the first byte of the key after the lxc.start.
1459 * prefix matches our expectations since they fortunately all start with a
1460 * different letter. If anything was wrong with the key we would have already
1461 * noticed when the callback was called.
1462 */
713046e3 1463static int set_config_start(const char *key, const char *value,
c7e27aaf 1464 struct lxc_conf *lxc_conf, void *data)
ee1e7aa0 1465{
572f6a14 1466 int ret;
ebb80f95
CB
1467 bool is_empty;
1468
663e9916 1469 is_empty = lxc_config_value_empty(value);
ebb80f95 1470
a182feae 1471 if (*(key + 10) == 'a') { /* lxc.start.auto */
ebb80f95
CB
1472 if (is_empty) {
1473 lxc_conf->start_auto = 0;
1474 return 0;
1475 }
61ff8fc8 1476
572f6a14
CB
1477 ret = lxc_safe_uint(value, &lxc_conf->start_auto);
1478 if (ret)
1479 return ret;
ebb80f95 1480
3590152f 1481 if (lxc_conf->start_auto > 1)
572f6a14 1482 return ret_errno(EINVAL);
ebb80f95 1483
ee1e7aa0 1484 return 0;
a182feae 1485 } else if (*(key + 10) == 'd') { /* lxc.start.delay */
ebb80f95
CB
1486 if (is_empty) {
1487 lxc_conf->start_delay = 0;
1488 return 0;
1489 }
1490
ebb80f95 1491 return lxc_safe_uint(value, &lxc_conf->start_delay);
a182feae 1492 } else if (*(key + 10) == 'o') { /* lxc.start.order */
ebb80f95
CB
1493 if (is_empty) {
1494 lxc_conf->start_order = 0;
1495 return 0;
1496 }
1497
ebb80f95 1498 return lxc_safe_int(value, &lxc_conf->start_order);
ee1e7aa0 1499 }
ebb80f95 1500
572f6a14 1501 return ret_errno(EINVAL);
ee1e7aa0
SG
1502}
1503
713046e3 1504static int set_config_monitor(const char *key, const char *value,
c7e27aaf 1505 struct lxc_conf *lxc_conf, void *data)
a8dfe4e0 1506{
663e9916 1507 if (lxc_config_value_empty(value)) {
4ad9cd26 1508 lxc_conf->monitor_unshare = 0;
a8dfe4e0
WB
1509 return 0;
1510 }
4ad9cd26 1511
d62177e9 1512 if (strequal(key + 12, "unshare"))
4ad9cd26
CB
1513 return lxc_safe_uint(value, &lxc_conf->monitor_unshare);
1514
e1665973 1515 return ret_errno(EINVAL);
a8dfe4e0
WB
1516}
1517
258f8051
CB
1518static int set_config_monitor_signal_pdeath(const char *key, const char *value,
1519 struct lxc_conf *lxc_conf, void *data)
1520{
1521 if (lxc_config_value_empty(value)) {
1522 lxc_conf->monitor_signal_pdeath = 0;
1523 return 0;
1524 }
1525
d62177e9 1526 if (strequal(key + 12, "signal.pdeath")) {
258f8051
CB
1527 int sig_n;
1528
1529 sig_n = sig_parse(value);
1530 if (sig_n < 0)
cb5f3df2 1531 return ret_errno(EINVAL);
258f8051
CB
1532
1533 lxc_conf->monitor_signal_pdeath = sig_n;
1534 return 0;
1535 }
1536
cb5f3df2 1537 return ret_errno(EINVAL);
258f8051
CB
1538}
1539
713046e3 1540static int set_config_group(const char *key, const char *value,
c7e27aaf 1541 struct lxc_conf *lxc_conf, void *data)
ee1e7aa0 1542{
15436995
CB
1543 __do_free char *groups = NULL;
1544 char *token;
ee1e7aa0 1545
663e9916 1546 if (lxc_config_value_empty(value))
ee1e7aa0
SG
1547 return lxc_clear_groups(lxc_conf);
1548
1549 groups = strdup(value);
25a908b8 1550 if (!groups)
15436995 1551 return ret_errno(ENOMEM);
ee1e7aa0 1552
ffb2a35f
CB
1553 /*
1554 * In case several groups are specified in a single line split these
25a908b8 1555 * groups in a single element for the list.
504a2217 1556 */
62dd965e 1557 lxc_iterate_parts(token, groups, " \t") {
ffb2a35f
CB
1558 __do_free char *val = NULL;
1559 __do_free struct string_entry *entry = NULL;
15436995 1560
ffb2a35f
CB
1561 entry = zalloc(sizeof(struct string_entry));
1562 if (!entry)
15436995 1563 return ret_errno(ENOMEM);
ee1e7aa0 1564
ffb2a35f
CB
1565 val = strdup(token);
1566 if (!val)
15436995 1567 return ret_errno(ENOMEM);
ee1e7aa0 1568
ffb2a35f
CB
1569 entry->val = move_ptr(val);
1570 list_add_tail(&entry->head, &lxc_conf->groups);
1571 move_ptr(entry);
d028235d 1572 }
ee1e7aa0 1573
15436995 1574 return 0;
ee1e7aa0
SG
1575}
1576
713046e3 1577static int set_config_environment(const char *key, const char *value,
c7e27aaf 1578 struct lxc_conf *lxc_conf, void *data)
7c661726 1579{
c294a68d
CB
1580 __do_free char *dup = NULL, *val = NULL;
1581 __do_free struct environment_entry *new_env = NULL;
1582 char *env_val;
7c661726 1583
663e9916 1584 if (lxc_config_value_empty(value))
ab799c0b
SG
1585 return lxc_clear_environment(lxc_conf);
1586
c294a68d
CB
1587 new_env = zalloc(sizeof(struct environment_entry));
1588 if (!new_env)
a6bf1128 1589 return ret_errno(ENOMEM);
7c661726 1590
c294a68d
CB
1591 dup = strdup(value);
1592 if (!dup)
1593 return ret_errno(ENOMEM);
5eab47bc 1594
c294a68d
CB
1595 env_val = strchr(dup, '=');
1596 if (!env_val) {
1597 env_val = getenv(dup);
5eab47bc 1598 } else {
c294a68d
CB
1599 *env_val = '\0';
1600 env_val++;
5eab47bc 1601 }
c294a68d
CB
1602 if (!env_val)
1603 return ret_errno(ENOENT);
7c661726 1604
c294a68d
CB
1605 val = strdup(env_val);
1606 if (!val)
a6bf1128 1607 return ret_errno(ENOMEM);
7c661726 1608
c294a68d
CB
1609 new_env->key = move_ptr(dup);
1610 new_env->val = move_ptr(val);
1611
1612 list_add_tail(&new_env->head, &lxc_conf->environment);
1613 move_ptr(new_env);
7c661726
MP
1614
1615 return 0;
7c661726
MP
1616}
1617
fe1c5887
CB
1618static int set_config_tty_max(const char *key, const char *value,
1619 struct lxc_conf *lxc_conf, void *data)
b0a33c1e 1620{
885766f5
CB
1621 int ret;
1622 unsigned int nbtty = 0;
1623
663e9916 1624 if (lxc_config_value_empty(value)) {
885766f5 1625 lxc_conf->ttys.max = 0;
fb12b12a 1626 return 0;
cb508ee8 1627 }
fb12b12a 1628
885766f5
CB
1629 ret = lxc_safe_uint(value, &nbtty);
1630 if (ret < 0)
755d6532 1631 return ret;
885766f5
CB
1632
1633 lxc_conf->ttys.max = nbtty;
47903908 1634
885766f5 1635 return 0;
b0a33c1e 1636}
1637
42e53c29 1638static int set_config_tty_dir(const char *key, const char *value,
c7e27aaf 1639 struct lxc_conf *lxc_conf, void *data)
7c6ef2a2 1640{
885766f5 1641 return set_config_string_item_max(&lxc_conf->ttys.dir, value,
504a2217 1642 NAME_MAX + 1);
7c6ef2a2
SH
1643}
1644
953fe44f
CB
1645static int set_config_apparmor_profile(const char *key, const char *value,
1646 struct lxc_conf *lxc_conf, void *data)
e075f5d9 1647{
8f899a4a 1648#if HAVE_APPARMOR
713046e3 1649 return set_config_string_item(&lxc_conf->lsm_aa_profile, value);
8f899a4a
CB
1650#else
1651 return syserror_set(-EINVAL, "Built without AppArmor support");
1652#endif
fe4de9a6
DE
1653}
1654
953fe44f
CB
1655static int set_config_apparmor_allow_incomplete(const char *key,
1656 const char *value,
1657 struct lxc_conf *lxc_conf,
1658 void *data)
7aff4f43 1659{
8f899a4a 1660#if HAVE_APPARMOR
042f8711
CB
1661 int ret;
1662
663e9916 1663 if (lxc_config_value_empty(value)) {
cccfa758 1664 lxc_conf->lsm_aa_allow_incomplete = 0;
a678e9fa 1665 return 0;
cccfa758 1666 }
a678e9fa 1667
042f8711
CB
1668 ret = lxc_safe_uint(value, &lxc_conf->lsm_aa_allow_incomplete);
1669 if (ret)
1670 return ret;
7aff4f43 1671
25a908b8 1672 if (lxc_conf->lsm_aa_allow_incomplete > 1)
042f8711 1673 return ret_errno(EINVAL);
7aff4f43
SH
1674
1675 return 0;
8f899a4a
CB
1676#else
1677 return syserror_set(-EINVAL, "Built without AppArmor support");
1678#endif
7aff4f43
SH
1679}
1680
1800f924
WB
1681static int set_config_apparmor_allow_nesting(const char *key,
1682 const char *value,
1683 struct lxc_conf *lxc_conf,
1684 void *data)
1685{
8f899a4a 1686#if HAVE_APPARMOR
55a76891
CB
1687 int ret;
1688
1800f924
WB
1689 if (lxc_config_value_empty(value))
1690 return clr_config_apparmor_allow_nesting(key, lxc_conf, NULL);
1691
55a76891
CB
1692 ret = lxc_safe_uint(value, &lxc_conf->lsm_aa_allow_nesting);
1693 if (ret)
1694 return ret;
1800f924
WB
1695
1696 if (lxc_conf->lsm_aa_allow_nesting > 1)
55a76891 1697 return ret_errno(EINVAL);
1800f924
WB
1698
1699 return 0;
8f899a4a
CB
1700#else
1701 return syserror_set(-EINVAL, "Built without AppArmor support");
1702#endif
1800f924
WB
1703}
1704
1705static int set_config_apparmor_raw(const char *key,
1706 const char *value,
1707 struct lxc_conf *lxc_conf,
1708 void *data)
1709{
8f899a4a 1710#if HAVE_APPARMOR
7f44fda1 1711 __do_free char *elem = NULL;
1fb1e667 1712 __do_free struct string_entry *entry = NULL;
1800f924
WB
1713
1714 if (lxc_config_value_empty(value))
1715 return lxc_clear_apparmor_raw(lxc_conf);
1716
1fb1e667
CB
1717 entry = zalloc(sizeof(struct string_entry));
1718 if (!entry)
7f44fda1 1719 return ret_errno(ENOMEM);
1800f924
WB
1720
1721 elem = strdup(value);
7f44fda1
CB
1722 if (!elem)
1723 return ret_errno(ENOMEM);
1800f924 1724
1fb1e667
CB
1725 entry->val = move_ptr(elem);
1726 list_add_tail(&entry->head, &lxc_conf->lsm_aa_raw);
1727 move_ptr(entry);
1800f924
WB
1728
1729 return 0;
8f899a4a
CB
1730#else
1731 return syserror_set(-EINVAL, "Built without AppArmor support");
1732#endif
1800f924
WB
1733}
1734
953fe44f
CB
1735static int set_config_selinux_context(const char *key, const char *value,
1736 struct lxc_conf *lxc_conf, void *data)
fe4de9a6 1737{
d6df2b8f 1738#if HAVE_SELINUX
713046e3 1739 return set_config_string_item(&lxc_conf->lsm_se_context, value);
d6df2b8f
CB
1740#else
1741 return syserror_set(-EINVAL, "Built without SELinux support");
1742#endif
e075f5d9 1743}
e075f5d9 1744
4fef78bc
MB
1745static int set_config_selinux_context_keyring(const char *key, const char *value,
1746 struct lxc_conf *lxc_conf, void *data)
1747{
d6df2b8f 1748#if HAVE_SELINUX
4fef78bc 1749 return set_config_string_item(&lxc_conf->lsm_se_keyring_context, value);
d6df2b8f
CB
1750#else
1751 return syserror_set(-EINVAL, "Built without SELinux support");
1752#endif
4fef78bc
MB
1753}
1754
8f818a84
MB
1755static int set_config_keyring_session(const char *key, const char *value,
1756 struct lxc_conf *lxc_conf, void *data)
1757{
1758 return set_config_bool_item(&lxc_conf->keyring_disable_session, value, false);
1759}
1760
46cc906d 1761static int set_config_log_file(const char *key, const char *value,
c7e27aaf 1762 struct lxc_conf *c, void *data)
4a85ce2a 1763{
6d03d92a
DE
1764 int ret;
1765
663e9916 1766 if (lxc_config_value_empty(value)) {
34f3b30a 1767 free_disarm(c->logfile);
0d601acb
CB
1768 return 0;
1769 }
1770
34f3b30a
CB
1771 /*
1772 * Store these values in the lxc_conf, and then try to set for actual
504a2217
CB
1773 * current logging.
1774 */
713046e3 1775 ret = set_config_path_item(&c->logfile, value);
6d03d92a 1776 if (ret == 0)
858377e4 1777 ret = lxc_log_set_file(&c->logfd, c->logfile);
25a908b8 1778
6d03d92a 1779 return ret;
4a85ce2a
SH
1780}
1781
46cc906d 1782static int set_config_log_level(const char *key, const char *value,
c7e27aaf 1783 struct lxc_conf *lxc_conf, void *data)
4a85ce2a 1784{
9ea87d5d
SH
1785 int newlevel;
1786
663e9916 1787 if (lxc_config_value_empty(value)) {
4b73005c 1788 lxc_conf->loglevel = LXC_LOG_LEVEL_NOTSET;
4a85ce2a 1789 return 0;
575b9745 1790 }
4a85ce2a 1791
a56e2df9 1792 if (value[0] >= '0' && value[0] <= '9') {
806244c6
CB
1793 int ret;
1794
1795 ret = lxc_safe_int(value, &newlevel);
1796 if (ret)
1797 return ret_errno(EINVAL);
a56e2df9 1798 } else {
9ea87d5d 1799 newlevel = lxc_log_priority_to_int(value);
a56e2df9 1800 }
575b9745 1801
806244c6
CB
1802 /*
1803 * Store these values in the lxc_conf, and then try to set for actual
575b9745
CB
1804 * current logging.
1805 */
b40a606e 1806 lxc_conf->loglevel = newlevel;
47903908 1807
858377e4 1808 return lxc_log_set_level(&lxc_conf->loglevel, newlevel);
4a85ce2a
SH
1809}
1810
713046e3 1811static int set_config_autodev(const char *key, const char *value,
c7e27aaf 1812 struct lxc_conf *lxc_conf, void *data)
c6883f38 1813{
0c48b874
CB
1814 int ret;
1815
663e9916 1816 if (lxc_config_value_empty(value)) {
1045031e 1817 lxc_conf->autodev = 0;
180abbc0 1818 return 0;
1045031e 1819 }
180abbc0 1820
0c48b874
CB
1821 ret = lxc_safe_uint(value, &lxc_conf->autodev);
1822 if (ret)
1823 return ret_errno(EINVAL);
c6883f38 1824
25a908b8 1825 if (lxc_conf->autodev > 1)
0c48b874 1826 return ret_errno(EINVAL);
c6883f38
SH
1827
1828 return 0;
1829}
1830
63012bdd
CK
1831static int set_config_autodev_tmpfs_size(const char *key, const char *value,
1832 struct lxc_conf *lxc_conf, void *data)
1833{
1834 if (lxc_config_value_empty(value)) {
1835 lxc_conf->autodevtmpfssize = 500000;
1836 return 0;
1837 }
1838
1839 if (lxc_safe_int(value, &lxc_conf->autodevtmpfssize) < 0)
1840 lxc_conf->autodevtmpfssize = 500000;
1841
1842 return 0;
1843}
1844
55c84efc 1845static int set_config_signal_halt(const char *key, const char *value,
c7e27aaf 1846 struct lxc_conf *lxc_conf, void *data)
f0f1d8c0 1847{
62a085fb 1848 int sig_n;
f0f1d8c0 1849
663e9916 1850 if (lxc_config_value_empty(value)) {
c1a64603 1851 lxc_conf->haltsignal = 0;
955912f0 1852 return 0;
c1a64603 1853 }
955912f0 1854
62a085fb 1855 sig_n = sig_parse(value);
f0f1d8c0 1856 if (sig_n < 0)
d12fabf8 1857 return ret_errno(EINVAL);
25a908b8 1858
f0f1d8c0
DE
1859 lxc_conf->haltsignal = sig_n;
1860
1861 return 0;
1862}
1863
55c84efc 1864static int set_config_signal_reboot(const char *key, const char *value,
c7e27aaf 1865 struct lxc_conf *lxc_conf, void *data)
dd267776 1866{
9d7e7587 1867 int sig_n;
dd267776 1868
663e9916 1869 if (lxc_config_value_empty(value)) {
18fcee44 1870 lxc_conf->rebootsignal = 0;
9d7e7587 1871 return 0;
18fcee44 1872 }
9d7e7587
CB
1873
1874 sig_n = sig_parse(value);
dd267776 1875 if (sig_n < 0)
7d6b1a20 1876 return ret_errno(EINVAL);
25a908b8 1877
dd267776
BP
1878 lxc_conf->rebootsignal = sig_n;
1879
1880 return 0;
1881}
1882
55c84efc 1883static int set_config_signal_stop(const char *key, const char *value,
c7e27aaf 1884 struct lxc_conf *lxc_conf, void *data)
a84b9932 1885{
6ca6aedd 1886 int sig_n;
a84b9932 1887
663e9916 1888 if (lxc_config_value_empty(value)) {
4100d1a7 1889 lxc_conf->stopsignal = 0;
6ca6aedd 1890 return 0;
4100d1a7 1891 }
6ca6aedd
CB
1892
1893 sig_n = sig_parse(value);
a84b9932 1894 if (sig_n < 0)
c4d9b159 1895 return ret_errno(EINVAL);
25a908b8 1896
a84b9932
AV
1897 lxc_conf->stopsignal = sig_n;
1898
1899 return 0;
1900}
1901
54860ed0
CB
1902static int __set_config_cgroup_controller(const char *key, const char *value,
1903 struct lxc_conf *lxc_conf, int version)
576f946d 1904{
c9dbb8ed 1905 call_cleaner(free_lxc_cgroup) struct lxc_cgroup *new_cgroup = NULL;
54860ed0
CB
1906 const char *subkey, *token;
1907 size_t token_len;
576f946d 1908
663e9916 1909 if (lxc_config_value_empty(value))
54860ed0
CB
1910 return lxc_clear_cgroups(lxc_conf, key, version);
1911
1912 if (version == CGROUP2_SUPER_MAGIC) {
1913 token = "lxc.cgroup2.";
1914 token_len = 12;
1915 } else if (version == CGROUP_SUPER_MAGIC) {
1916 token = "lxc.cgroup.";
1917 token_len = 11;
1918 } else {
ee91fa06 1919 return ret_errno(EINVAL);
54860ed0 1920 }
576f946d 1921
1af3044f 1922 if (!strnequal(key, token, token_len))
ee91fa06 1923 return ret_errno(EINVAL);
a871ff6b 1924
54860ed0
CB
1925 subkey = key + token_len;
1926 if (*subkey == '\0')
ee91fa06 1927 return ret_errno(EINVAL);
576f946d 1928
c9dbb8ed
CB
1929 new_cgroup = zalloc(sizeof(*new_cgroup));
1930 if (!new_cgroup)
ee91fa06 1931 return ret_errno(ENOMEM);
576f946d 1932
c9dbb8ed
CB
1933 new_cgroup->subsystem = strdup(subkey);
1934 if (!new_cgroup->subsystem)
ee91fa06 1935 return ret_errno(ENOMEM);
576f946d 1936
c9dbb8ed
CB
1937 new_cgroup->value = strdup(value);
1938 if (!new_cgroup->value)
ee91fa06 1939 return ret_errno(ENOMEM);
bf83c5b9 1940
c9dbb8ed 1941 new_cgroup->version = version;
576f946d 1942
54860ed0 1943 if (version == CGROUP2_SUPER_MAGIC)
c9dbb8ed 1944 list_add_tail(&new_cgroup->head, &lxc_conf->cgroup2);
54860ed0 1945 else
c9dbb8ed
CB
1946 list_add_tail(&new_cgroup->head, &lxc_conf->cgroup);
1947 move_ptr(new_cgroup);
576f946d 1948
1949 return 0;
1950}
1951
54860ed0
CB
1952static int set_config_cgroup_controller(const char *key, const char *value,
1953 struct lxc_conf *lxc_conf, void *data)
1954{
1955 return __set_config_cgroup_controller(key, value, lxc_conf,
1956 CGROUP_SUPER_MAGIC);
1957}
1958
1959static int set_config_cgroup2_controller(const char *key, const char *value,
1960 struct lxc_conf *lxc_conf, void *data)
1961{
1962 return __set_config_cgroup_controller(key, value, lxc_conf,
1963 CGROUP2_SUPER_MAGIC);
1964}
1965
43654d34
CB
1966static int set_config_cgroup_dir(const char *key, const char *value,
1967 struct lxc_conf *lxc_conf, void *data)
1968{
d62177e9 1969 if (!strequal(key, "lxc.cgroup.dir"))
c583072d
CB
1970 return ret_errno(EINVAL);
1971
43654d34
CB
1972 if (lxc_config_value_empty(value))
1973 return clr_config_cgroup_dir(key, lxc_conf, NULL);
1974
f63ef155 1975 if (abspath(value))
060aaa39 1976 return syserror_set(-EINVAL, "%s paths may not be absolute", key);
f63ef155 1977
0a48ee66 1978 if (dotdot(value))
060aaa39 1979 return syserror_set(-EINVAL, "%s paths may not walk upwards via \"../\"", key);
0a48ee66 1980
ee94a8b5 1981 return set_config_path_item(&lxc_conf->cgroup_meta.dir, value);
43654d34
CB
1982}
1983
a900cbaf
WB
1984static int set_config_cgroup_monitor_dir(const char *key, const char *value,
1985 struct lxc_conf *lxc_conf, void *data)
1986{
1987 if (lxc_config_value_empty(value))
1988 return clr_config_cgroup_monitor_dir(key, lxc_conf, NULL);
1989
f63ef155 1990 if (abspath(value))
060aaa39 1991 return syserror_set(-EINVAL, "%s paths may not be absolute", key);
f63ef155 1992
0a48ee66 1993 if (dotdot(value))
060aaa39 1994 return syserror_set(-EINVAL, "%s paths may not walk upwards via \"../\"", key);
0a48ee66 1995
ee94a8b5 1996 return set_config_path_item(&lxc_conf->cgroup_meta.monitor_dir, value);
a900cbaf
WB
1997}
1998
7696c1f9
RJ
1999static int set_config_cgroup_monitor_pivot_dir(const char *key, const char *value,
2000 struct lxc_conf *lxc_conf, void *data)
2001{
2002 if (lxc_config_value_empty(value))
2003 return clr_config_cgroup_monitor_pivot_dir(key, lxc_conf, NULL);
2004
f63ef155 2005 if (abspath(value))
060aaa39 2006 return syserror_set(-EINVAL, "%s paths may not be absolute", key);
f63ef155 2007
0a48ee66 2008 if (dotdot(value))
060aaa39 2009 return syserror_set(-EINVAL, "%s paths may not walk upwards via \"../\"", key);
0a48ee66 2010
ee94a8b5 2011 return set_config_path_item(&lxc_conf->cgroup_meta.monitor_pivot_dir, value);
7696c1f9
RJ
2012}
2013
a900cbaf
WB
2014static int set_config_cgroup_container_dir(const char *key, const char *value,
2015 struct lxc_conf *lxc_conf,
2016 void *data)
2017{
2018 if (lxc_config_value_empty(value))
2019 return clr_config_cgroup_container_dir(key, lxc_conf, NULL);
2020
f63ef155 2021 if (abspath(value))
060aaa39 2022 return syserror_set(-EINVAL, "%s paths may not be absolute", key);
f63ef155 2023
0a48ee66 2024 if (dotdot(value))
060aaa39 2025 return syserror_set(-EINVAL, "%s paths may not walk upwards via \"../\"", key);
0a48ee66 2026
ee94a8b5 2027 return set_config_path_item(&lxc_conf->cgroup_meta.container_dir, value);
a900cbaf
WB
2028}
2029
2030static int set_config_cgroup_container_inner_dir(const char *key,
2031 const char *value,
2032 struct lxc_conf *lxc_conf,
2033 void *data)
2034{
2035 if (lxc_config_value_empty(value))
e93197e7 2036 return clr_config_cgroup_container_inner_dir(key, lxc_conf, NULL);
a900cbaf 2037
f63ef155 2038 if (abspath(value))
060aaa39 2039 return syserror_set(-EINVAL, "%s paths may not be absolute", key);
f63ef155 2040
d62177e9 2041 if (strchr(value, '/') || strequal(value, ".") || strequal(value, ".."))
e93197e7 2042 return log_error_errno(-EINVAL, EINVAL, "lxc.cgroup.dir.container.inner must be a single directory name");
a900cbaf 2043
e93197e7 2044 return set_config_string_item(&lxc_conf->cgroup_meta.namespace_dir, value);
a900cbaf
WB
2045}
2046
9caee129
CB
2047static int set_config_cgroup_relative(const char *key, const char *value,
2048 struct lxc_conf *lxc_conf, void *data)
76f0e2e7
CB
2049{
2050 unsigned int converted;
2051 int ret;
2052
2053 if (lxc_config_value_empty(value))
9caee129 2054 return clr_config_cgroup_relative(key, lxc_conf, NULL);
76f0e2e7
CB
2055
2056 ret = lxc_safe_uint(value, &converted);
c521771a
CB
2057 if (ret)
2058 return ret;
76f0e2e7
CB
2059
2060 if (converted == 1) {
9caee129 2061 lxc_conf->cgroup_meta.relative = true;
76f0e2e7
CB
2062 return 0;
2063 }
2064
2065 if (converted == 0) {
9caee129 2066 lxc_conf->cgroup_meta.relative = false;
76f0e2e7
CB
2067 return 0;
2068 }
2069
c521771a 2070 return ret_errno(EINVAL);
76f0e2e7
CB
2071}
2072
f7662514
CB
2073static bool parse_limit_value(const char **value, rlim_t *res)
2074{
2075 char *endptr = NULL;
2076
1af3044f 2077 if (strnequal(*value, "unlimited", STRLITERALLEN("unlimited"))) {
f7662514
CB
2078 *res = RLIM_INFINITY;
2079 *value += STRLITERALLEN("unlimited");
2080 return true;
2081 }
2082
2083 errno = 0;
2084 *res = strtoull(*value, &endptr, 10);
2085 if (errno || !endptr)
2086 return false;
2087
2088 *value = endptr;
2089
2090 return true;
2091}
2092
240d4b74 2093static int set_config_prlimit(const char *key, const char *value,
c7e27aaf 2094 struct lxc_conf *lxc_conf, void *data)
c6d09e15 2095{
223797c3 2096 call_cleaner(free_lxc_limit) struct lxc_limit *new_lim = NULL;
c6d09e15 2097 struct rlimit limit;
71460831 2098 rlim_t limit_value;
223797c3 2099 struct lxc_limit *lim;
c6d09e15 2100
663e9916 2101 if (lxc_config_value_empty(value))
c6d09e15
WB
2102 return lxc_clear_limits(lxc_conf, key);
2103
1af3044f 2104 if (!strnequal(key, "lxc.prlimit.", STRLITERALLEN("lxc.prlimit.")))
8fa831e0 2105 return ret_errno(EINVAL);
c6d09e15 2106
6333c915 2107 key += STRLITERALLEN("lxc.prlimit.");
c6d09e15
WB
2108
2109 /* soft limit comes first in the value */
2110 if (!parse_limit_value(&value, &limit_value))
8fa831e0 2111 return ret_errno(EINVAL);
47903908 2112
c6d09e15
WB
2113 limit.rlim_cur = limit_value;
2114
2115 /* skip spaces and a colon */
2116 while (isspace(*value))
2117 ++value;
504a2217 2118
c6d09e15
WB
2119 if (*value == ':')
2120 ++value;
2121 else if (*value) /* any other character is an error here */
8fa831e0 2122 return ret_errno(EINVAL);
504a2217 2123
c6d09e15
WB
2124 while (isspace(*value))
2125 ++value;
2126
2127 /* optional hard limit */
2128 if (*value) {
2129 if (!parse_limit_value(&value, &limit_value))
8fa831e0 2130 return ret_errno(EINVAL);
47903908 2131
c6d09e15 2132 limit.rlim_max = limit_value;
504a2217 2133
c6d09e15
WB
2134 /* check for trailing garbage */
2135 while (isspace(*value))
2136 ++value;
504a2217 2137
c6d09e15 2138 if (*value)
8fa831e0 2139 return ret_errno(EINVAL);
c6d09e15
WB
2140 } else {
2141 /* a single value sets both hard and soft limit */
2142 limit.rlim_max = limit.rlim_cur;
2143 }
2144
2145 /* find existing list element */
223797c3
CB
2146 list_for_each_entry(lim, &lxc_conf->limits, head) {
2147 if (!strequal(key, lim->resource))
631d2715
CB
2148 continue;
2149
223797c3 2150 lim->limit = limit;
631d2715 2151 return 0;
c6d09e15
WB
2152 }
2153
223797c3
CB
2154 new_lim = zalloc(sizeof(*new_lim));
2155 if (!new_lim)
8fa831e0 2156 return ret_errno(ENOMEM);
c6d09e15 2157
223797c3
CB
2158 new_lim->resource = strdup(key);
2159 if (!new_lim->resource)
8fa831e0 2160 return ret_errno(ENOMEM);
c6d09e15 2161
223797c3
CB
2162 new_lim->limit = limit;
2163 list_add_tail(&new_lim->head, &lxc_conf->limits);
2164 move_ptr(new_lim);
c6d09e15
WB
2165
2166 return 0;
c6d09e15
WB
2167}
2168
7edd0540
L
2169static int set_config_sysctl(const char *key, const char *value,
2170 struct lxc_conf *lxc_conf, void *data)
2171{
f10c80d2 2172 call_cleaner(free_lxc_sysctl) struct lxc_sysctl *sysctl_elem = NULL;
ba9f9347 2173 struct lxc_sysctl *sysctl, *nsysctl;
7edd0540
L
2174
2175 if (lxc_config_value_empty(value))
e409b214 2176 return clr_config_sysctl(key, lxc_conf, NULL);
7edd0540 2177
1af3044f 2178 if (!strnequal(key, "lxc.sysctl.", STRLITERALLEN("lxc.sysctl.")))
b28be01f 2179 return ret_errno(EINVAL);
7edd0540 2180
6333c915 2181 key += STRLITERALLEN("lxc.sysctl.");
b5fdc164 2182 if (is_empty_string(key))
b28be01f 2183 return ret_errno(EINVAL);
7edd0540
L
2184
2185 /* find existing list element */
ba9f9347 2186 list_for_each_entry_safe(sysctl, nsysctl, &lxc_conf->sysctls, head) {
f10c80d2
CB
2187 __do_free char *replace_value = NULL;
2188
ba9f9347 2189 if (!strequal(key, sysctl->key))
e409b214
CB
2190 continue;
2191
2192 replace_value = strdup(value);
2193 if (!replace_value)
f10c80d2 2194 return ret_errno(EINVAL);
e409b214 2195
ba9f9347
CB
2196 free(sysctl->value);
2197 sysctl->value = move_ptr(replace_value);
47903908 2198
e409b214 2199 return 0;
7edd0540
L
2200 }
2201
b5fdc164 2202 sysctl_elem = zalloc(sizeof(*sysctl_elem));
7edd0540 2203 if (!sysctl_elem)
f10c80d2 2204 return ret_errno(ENOMEM);
7edd0540
L
2205
2206 sysctl_elem->key = strdup(key);
2207 if (!sysctl_elem->key)
f10c80d2 2208 return ret_errno(ENOMEM);
7edd0540
L
2209
2210 sysctl_elem->value = strdup(value);
2211 if (!sysctl_elem->value)
f10c80d2 2212 return ret_errno(ENOMEM);
7edd0540 2213
ba9f9347
CB
2214 list_add_tail(&sysctl_elem->head, &lxc_conf->sysctls);
2215 move_ptr(sysctl_elem);
7edd0540
L
2216
2217 return 0;
7edd0540
L
2218}
2219
61d7a733
YT
2220static int set_config_proc(const char *key, const char *value,
2221 struct lxc_conf *lxc_conf, void *data)
2222{
91d04bf9 2223 call_cleaner(free_lxc_proc) struct lxc_proc *new_proc = NULL;
61d7a733 2224 const char *subkey;
61d7a733
YT
2225
2226 if (lxc_config_value_empty(value))
2227 return clr_config_proc(key, lxc_conf, NULL);
2228
1af3044f 2229 if (!strnequal(key, "lxc.proc.", STRLITERALLEN("lxc.proc.")))
b28be01f 2230 return ret_errno(EINVAL);
61d7a733 2231
6333c915 2232 subkey = key + STRLITERALLEN("lxc.proc.");
61d7a733 2233 if (*subkey == '\0')
83332c24 2234 return ret_errno(EINVAL);
61d7a733 2235
91d04bf9
CB
2236 new_proc = zalloc(sizeof(*new_proc));
2237 if (!new_proc)
83332c24 2238 return ret_errno(ENOMEM);
61d7a733 2239
91d04bf9
CB
2240 new_proc->filename = strdup(subkey);
2241 if (!new_proc->filename)
83332c24 2242 return ret_errno(ENOMEM);
61d7a733 2243
91d04bf9
CB
2244 new_proc->value = strdup(value);
2245 if (!new_proc->value)
83332c24 2246 return ret_errno(ENOMEM);
61d7a733 2247
91d04bf9
CB
2248 list_add_tail(&new_proc->head, &lxc_conf->procs);
2249 move_ptr(new_proc);
61d7a733
YT
2250
2251 return 0;
61d7a733
YT
2252}
2253
5014ff2e 2254static int set_config_idmaps(const char *key, const char *value,
c7e27aaf 2255 struct lxc_conf *lxc_conf, void *data)
f6d3e3e4 2256{
5c856bcb 2257 __do_free struct id_map *idmap = NULL;
251d0d2a 2258 unsigned long hostid, nsid, range;
f6d3e3e4 2259 char type;
0b843d35 2260 int ret;
f6d3e3e4 2261
663e9916 2262 if (lxc_config_value_empty(value))
7d0eb87e
SH
2263 return lxc_clear_idmaps(lxc_conf);
2264
642751cc 2265 idmap = zalloc(sizeof(*idmap));
f6d3e3e4 2266 if (!idmap)
5c856bcb 2267 return ret_errno(ENOMEM);
f6d3e3e4 2268
0b843d35 2269 ret = parse_idmaps(value, &type, &nsid, &hostid, &range);
5c856bcb
CB
2270 if (ret < 0)
2271 return log_error_errno(-EINVAL, EINVAL, "Failed to parse id mappings");
34a7a4c6 2272
25a908b8 2273 INFO("Read uid map: type %c nsid %lu hostid %lu range %lu", type, nsid, hostid, range);
ac7725e7 2274 if (type == 'u')
f6d3e3e4 2275 idmap->idtype = ID_TYPE_UID;
ac7725e7 2276 else if (type == 'g')
f6d3e3e4
SH
2277 idmap->idtype = ID_TYPE_GID;
2278 else
5c856bcb 2279 return ret_errno(EINVAL);
7e60c3f0 2280
f6d3e3e4
SH
2281 idmap->hostid = hostid;
2282 idmap->nsid = nsid;
2283 idmap->range = range;
0589d744 2284 list_add_tail(&idmap->head, &lxc_conf->id_map);
46ad64ab
CB
2285
2286 if (!lxc_conf->root_nsuid_map && idmap->idtype == ID_TYPE_UID)
2287 if (idmap->nsid == 0)
2288 lxc_conf->root_nsuid_map = idmap;
2289
4160c3a0 2290 if (!lxc_conf->root_nsgid_map && idmap->idtype == ID_TYPE_GID)
46ad64ab
CB
2291 if (idmap->nsid == 0)
2292 lxc_conf->root_nsgid_map = idmap;
2293
5c856bcb 2294 move_ptr(idmap);
7e60c3f0 2295
f6d3e3e4 2296 return 0;
f6d3e3e4
SH
2297}
2298
47148e96
CB
2299static int set_config_mount_fstab(const char *key, const char *value,
2300 struct lxc_conf *lxc_conf, void *data)
d95db067 2301{
663e9916 2302 if (lxc_config_value_empty(value)) {
47148e96 2303 clr_config_mount_fstab(key, lxc_conf, NULL);
e9cda8ec 2304 return ret_errno(EINVAL);
46f3de30 2305 }
6f5685f0 2306
713046e3 2307 return set_config_path_item(&lxc_conf->fstab, value);
d95db067
DE
2308}
2309
713046e3 2310static int set_config_mount_auto(const char *key, const char *value,
c7e27aaf 2311 struct lxc_conf *lxc_conf, void *data)
368bbc02 2312{
138079ee
CB
2313 __do_free char *autos = NULL;
2314 char *token;
368bbc02 2315 int i;
504a2217
CB
2316 static struct {
2317 const char *token;
2318 int mask;
2319 int flag;
2320 } allowed_auto_mounts[] = {
138079ee
CB
2321 { "proc", LXC_AUTO_PROC_MASK, LXC_AUTO_PROC_MIXED },
2322 { "proc:mixed", LXC_AUTO_PROC_MASK, LXC_AUTO_PROC_MIXED },
2323 { "proc:rw", LXC_AUTO_PROC_MASK, LXC_AUTO_PROC_RW },
2324 { "sys", LXC_AUTO_SYS_MASK, LXC_AUTO_SYS_MIXED },
2325 { "sys:ro", LXC_AUTO_SYS_MASK, LXC_AUTO_SYS_RO },
2326 { "sys:mixed", LXC_AUTO_SYS_MASK, LXC_AUTO_SYS_MIXED },
2327 { "sys:rw", LXC_AUTO_SYS_MASK, LXC_AUTO_SYS_RW },
d90d3007
CB
2328 { "cgroup2", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP2_RW | LXC_AUTO_CGROUP_FORCE },
2329 { "cgroup2:ro", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP2_RO | LXC_AUTO_CGROUP_FORCE },
2330 { "cgroup2:force", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP2_RW | LXC_AUTO_CGROUP_FORCE },
2331 { "cgroup2:ro:force", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP2_RO | LXC_AUTO_CGROUP_FORCE },
138079ee
CB
2332 { "cgroup", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_NOSPEC },
2333 { "cgroup:mixed", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_MIXED },
2334 { "cgroup:ro", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_RO },
2335 { "cgroup:rw", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_RW },
2336 { "cgroup:force", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_NOSPEC | LXC_AUTO_CGROUP_FORCE },
2337 { "cgroup:mixed:force", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_MIXED | LXC_AUTO_CGROUP_FORCE },
2338 { "cgroup:ro:force", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_RO | LXC_AUTO_CGROUP_FORCE },
2339 { "cgroup:rw:force", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_RW | LXC_AUTO_CGROUP_FORCE },
2340 { "cgroup-full", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_FULL_NOSPEC },
2341 { "cgroup-full:mixed", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_FULL_MIXED },
2342 { "cgroup-full:ro", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_FULL_RO },
2343 { "cgroup-full:rw", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_FULL_RW },
2344 { "cgroup-full:force", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_FULL_NOSPEC | LXC_AUTO_CGROUP_FORCE },
2345 { "cgroup-full:mixed:force", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_FULL_MIXED | LXC_AUTO_CGROUP_FORCE },
2346 { "cgroup-full:ro:force", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_FULL_RO | LXC_AUTO_CGROUP_FORCE },
2347 { "cgroup-full:rw:force", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_FULL_RW | LXC_AUTO_CGROUP_FORCE },
2348 { "shmounts:", LXC_AUTO_SHMOUNTS_MASK, LXC_AUTO_SHMOUNTS },
2349 /*
2350 * For adding anything that is just a single on/off, but has no
2351 * options: keep mask and flag identical and just define the
2352 * enum value as an unused bit so far
2353 */
2354 { NULL, 0, 0 }
504a2217 2355 };
368bbc02 2356
663e9916 2357 if (lxc_config_value_empty(value)) {
d9192f5d
SH
2358 lxc_conf->auto_mounts = 0;
2359 return 0;
2360 }
368bbc02
CS
2361
2362 autos = strdup(value);
25a908b8 2363 if (!autos)
138079ee 2364 return ret_errno(ENOMEM);
368bbc02 2365
62dd965e 2366 lxc_iterate_parts(token, autos, " \t") {
0d190408
LT
2367 bool is_shmounts = false;
2368
368bbc02 2369 for (i = 0; allowed_auto_mounts[i].token; i++) {
d62177e9 2370 if (strequal(allowed_auto_mounts[i].token, token))
368bbc02 2371 break;
0d190408 2372
d62177e9 2373 if (strequal("shmounts:", allowed_auto_mounts[i].token) &&
1af3044f 2374 strnequal("shmounts:", token, STRLITERALLEN("shmounts:"))) {
0d190408
LT
2375 is_shmounts = true;
2376 break;
2377 }
368bbc02
CS
2378 }
2379
138079ee
CB
2380 if (!allowed_auto_mounts[i].token)
2381 return log_error_errno(-EINVAL, EINVAL, "Invalid filesystem to automount \"%s\"", token);
368bbc02 2382
b06b8511 2383 lxc_conf->auto_mounts &= ~allowed_auto_mounts[i].mask;
368bbc02 2384 lxc_conf->auto_mounts |= allowed_auto_mounts[i].flag;
47903908 2385
0d190408 2386 if (is_shmounts) {
138079ee
CB
2387 __do_free char *container_path = NULL, *host_path = NULL;
2388 char *val;
594426ca 2389
138079ee
CB
2390 val = token + STRLITERALLEN("shmounts:");
2391 if (*val == '\0')
2392 return log_error_errno(-EINVAL, EINVAL, "Failed to copy shmounts host path");
2393
2394 host_path = strdup(val);
2395 if (!host_path)
2396 return log_error_errno(-EINVAL, EINVAL, "Failed to copy shmounts host path");
fd14fdb8 2397
138079ee
CB
2398 val = strchr(host_path, ':');
2399 if (!val || *(val + 1) == '\0')
2400 val = "/dev/.lxc-mounts";
6437f1c1 2401 else
138079ee 2402 *val++ = '\0';
6437f1c1 2403
138079ee
CB
2404 container_path = strdup(val);
2405 if(!container_path)
2406 return log_error_errno(-EINVAL, EINVAL, "Failed to copy shmounts container path");
fd14fdb8 2407
405b28a4 2408 free_disarm(lxc_conf->shmount.path_host);
138079ee 2409 lxc_conf->shmount.path_host = move_ptr(host_path);
405b28a4
CB
2410
2411 free_disarm(lxc_conf->shmount.path_cont);
138079ee 2412 lxc_conf->shmount.path_cont = move_ptr(container_path);
0d190408 2413 }
d028235d 2414 }
368bbc02 2415
138079ee 2416 return 0;
368bbc02
CS
2417}
2418
713046e3 2419static int set_config_mount(const char *key, const char *value,
c7e27aaf 2420 struct lxc_conf *lxc_conf, void *data)
e7938e9e 2421{
48c367c0 2422 __do_free char *mntelem = NULL;
be0bc4d1 2423 __do_free struct string_entry *entry = NULL;
e7938e9e 2424
663e9916 2425 if (lxc_config_value_empty(value))
d9192f5d 2426 return lxc_clear_mount_entries(lxc_conf);
e7938e9e 2427
be0bc4d1
CB
2428 entry = zalloc(sizeof(struct string_entry));
2429 if (!entry)
48c367c0 2430 return ret_errno(ENOMEM);
e7938e9e
MN
2431
2432 mntelem = strdup(value);
48c367c0
CB
2433 if (!mntelem)
2434 return ret_errno(ENOMEM);
e7938e9e 2435
be0bc4d1
CB
2436 entry->val = move_ptr(mntelem);
2437 list_add_tail(&entry->head, &lxc_conf->mount_entries);
2438 move_ptr(entry);
e7938e9e
MN
2439
2440 return 0;
2441}
2442
0d190408
LT
2443int add_elem_to_mount_list(const char *value, struct lxc_conf *lxc_conf) {
2444 return set_config_mount(NULL, value, lxc_conf, NULL);
2445}
2446
20ab7578 2447static int add_cap_entry(struct lxc_conf *conf, char *caps, bool keep)
1fb86a7c 2448{
bd7c5371 2449 char *token;
1fb86a7c 2450
20ab7578
CB
2451 /*
2452 * In case several capability keep is specified in a single line split
2453 * these caps in a single element for the list.
2454 */
2455 lxc_iterate_parts(token, caps, " \t") {
2456 __do_free struct cap_entry *new_cap = NULL;
7418b27f
CB
2457 int ret;
2458 __u32 cap;
1fb86a7c 2459
20ab7578
CB
2460 if (strequal(token, "none")) {
2461 if (!keep)
2462 return syserror_set(-EINVAL, "The \"none\" keyword is only valid when keeping caps");
1fb86a7c 2463
20ab7578
CB
2464 lxc_clear_config_caps(conf);
2465 continue;
2466 }
2467
7418b27f
CB
2468 ret = parse_cap(token, &cap);
2469 if (ret < 0) {
2470 if (ret != -2)
20ab7578
CB
2471 return syserror_set(-EINVAL, "Invalid capability specified");
2472
2473 INFO("Ignoring unknown capability \"%s\"", token);
2474 continue;
2475 }
7035407c 2476
20ab7578
CB
2477 new_cap = zalloc(sizeof(struct cap_entry));
2478 if (!new_cap)
bd7c5371 2479 return ret_errno(ENOMEM);
1fb86a7c 2480
20ab7578
CB
2481 new_cap->cap_name = strdup(token);
2482 if (!new_cap->cap_name)
bd7c5371 2483 return ret_errno(ENOMEM);
20ab7578 2484 new_cap->cap = cap;
1fb86a7c 2485
20ab7578
CB
2486 list_add_tail(&new_cap->head, &conf->caps.list);
2487 move_ptr(new_cap);
d028235d 2488 }
1fb86a7c 2489
bd7c5371 2490 return 0;
1fb86a7c
SH
2491}
2492
20ab7578 2493static int set_config_cap_keep(const char *key, const char *value,
c7e27aaf 2494 struct lxc_conf *lxc_conf, void *data)
81810dd1 2495{
20ab7578
CB
2496 __do_free char *caps = NULL;
2497 int ret;
81810dd1 2498
663e9916 2499 if (lxc_config_value_empty(value))
7d0eb87e 2500 return lxc_clear_config_caps(lxc_conf);
81810dd1 2501
20ab7578
CB
2502 caps = strdup(value);
2503 if (!caps)
c5c4831c 2504 return ret_errno(ENOMEM);
81810dd1 2505
20ab7578
CB
2506 if (!lxc_conf->caps.keep && !list_empty(&lxc_conf->caps.list))
2507 return syserror_set(-EINVAL, "Keeping and dropping capabilities are mutually exclusive");
81810dd1 2508
20ab7578
CB
2509 ret = add_cap_entry(lxc_conf, caps, true);
2510 if (ret < 0)
2511 return ret;
81810dd1 2512
20ab7578
CB
2513 lxc_conf->caps.keep = true;
2514 return 0;
2515}
2516
2517static int set_config_cap_drop(const char *key, const char *value,
2518 struct lxc_conf *lxc_conf, void *data)
2519{
2520 __do_free char *caps = NULL;
2521 int ret;
2522
2523 if (lxc_config_value_empty(value))
2524 return lxc_clear_config_caps(lxc_conf);
81810dd1 2525
20ab7578
CB
2526 if (lxc_conf->caps.keep)
2527 return syserror_set(-EINVAL, "Keeping and dropping capabilities are mutually exclusive");
2528
2529 caps = strdup(value);
2530 if (!caps)
2531 return ret_errno(ENOMEM);
2532
2533 ret = add_cap_entry(lxc_conf, caps, false);
2534 if (ret < 0)
2535 return ret;
2536
2537 lxc_conf->caps.keep = false;
c5c4831c 2538 return 0;
81810dd1
DL
2539}
2540
3aed4934
CB
2541static int set_config_console_path(const char *key, const char *value,
2542 struct lxc_conf *lxc_conf, void *data)
28a4b0e5 2543{
713046e3 2544 return set_config_path_item(&lxc_conf->console.path, value);
28a4b0e5
DL
2545}
2546
d91adfa6
CB
2547static int set_config_console_rotate(const char *key, const char *value,
2548 struct lxc_conf *lxc_conf, void *data)
2549{
9a26e4af
CB
2550 int ret;
2551
d91adfa6
CB
2552 if (lxc_config_value_empty(value)) {
2553 lxc_conf->console.log_rotate = 0;
2554 return 0;
2555 }
2556
9a26e4af
CB
2557 ret = lxc_safe_uint(value, &lxc_conf->console.log_rotate);
2558 if (ret)
2559 return ret_errno(EINVAL);
d91adfa6 2560
9a26e4af
CB
2561 if (lxc_conf->console.log_rotate > 1)
2562 return log_error_errno(-EINVAL, EINVAL, "The \"lxc.console.rotate\" config key can only be set to 0 or 1");
d91adfa6
CB
2563
2564 return 0;
2565}
2566
713046e3 2567static int set_config_console_logfile(const char *key, const char *value,
c7e27aaf 2568 struct lxc_conf *lxc_conf, void *data)
96f15ca1 2569{
713046e3 2570 return set_config_path_item(&lxc_conf->console.log_path, value);
96f15ca1
SH
2571}
2572
28f3b1cd
CB
2573static int set_config_console_buffer_size(const char *key, const char *value,
2574 struct lxc_conf *lxc_conf, void *data)
a04220de
CB
2575{
2576 int ret;
4c5479d2 2577 long long int size;
28f3b1cd 2578 uint64_t buffer_size, pgsz;
a04220de
CB
2579
2580 if (lxc_config_value_empty(value)) {
28f3b1cd 2581 lxc_conf->console.buffer_size = 0;
a04220de
CB
2582 return 0;
2583 }
2584
2585 /* If the user specified "auto" the default log size is 2^17 = 128 Kib */
d62177e9 2586 if (strequal(value, "auto")) {
28f3b1cd 2587 lxc_conf->console.buffer_size = 1 << 17;
a04220de
CB
2588 return 0;
2589 }
2590
2591 ret = parse_byte_size_string(value, &size);
3f5c01db
CB
2592 if (ret)
2593 return ret;
a04220de
CB
2594
2595 if (size < 0)
3f5c01db 2596 return ret_errno(EINVAL);
a04220de
CB
2597
2598 /* must be at least a page size */
2599 pgsz = lxc_getpagesize();
2600 if ((uint64_t)size < pgsz) {
4c5479d2 2601 NOTICE("Requested ringbuffer size for the console is %lld but must be at least %" PRId64 " bytes. Setting ringbuffer size to %" PRId64 " bytes",
a04220de
CB
2602 size, pgsz, pgsz);
2603 size = pgsz;
2604 }
2605
28f3b1cd
CB
2606 buffer_size = lxc_find_next_power2((uint64_t)size);
2607 if (buffer_size == 0)
3f5c01db 2608 return ret_errno(EINVAL);
a04220de 2609
15b9e2b0 2610 if (buffer_size != (uint64_t)size)
3f5c01db 2611 NOTICE("Passed size was not a power of 2. Rounding log size to next power of two: %" PRIu64 " bytes", buffer_size);
a04220de 2612
28f3b1cd 2613 lxc_conf->console.buffer_size = buffer_size;
47903908 2614
a04220de
CB
2615 return 0;
2616}
2617
861813e5
CB
2618static int set_config_console_size(const char *key, const char *value,
2619 struct lxc_conf *lxc_conf, void *data)
2620{
2621 int ret;
4c5479d2 2622 long long int size;
861813e5
CB
2623 uint64_t log_size, pgsz;
2624
2625 if (lxc_config_value_empty(value)) {
2626 lxc_conf->console.log_size = 0;
2627 return 0;
2628 }
2629
2630 /* If the user specified "auto" the default log size is 2^17 = 128 Kib */
d62177e9 2631 if (strequal(value, "auto")) {
861813e5
CB
2632 lxc_conf->console.log_size = 1 << 17;
2633 return 0;
2634 }
2635
2636 ret = parse_byte_size_string(value, &size);
a7ac0d1e
CB
2637 if (ret)
2638 return ret_errno(EINVAL);
861813e5
CB
2639
2640 if (size < 0)
a7ac0d1e 2641 return ret_errno(EINVAL);
861813e5
CB
2642
2643 /* must be at least a page size */
2644 pgsz = lxc_getpagesize();
2645 if ((uint64_t)size < pgsz) {
4c5479d2 2646 NOTICE("Requested ringbuffer size for the console is %lld but must be at least %" PRId64 " bytes. Setting ringbuffer size to %" PRId64 " bytes",
861813e5
CB
2647 size, pgsz, pgsz);
2648 size = pgsz;
2649 }
2650
2651 log_size = lxc_find_next_power2((uint64_t)size);
2652 if (log_size == 0)
a7ac0d1e 2653 return ret_errno(EINVAL);
861813e5 2654
15b9e2b0 2655 if (log_size != (uint64_t)size)
a7ac0d1e 2656 NOTICE("Passed size was not a power of 2. Rounding log size to next power of two: %" PRIu64 " bytes", log_size);
861813e5
CB
2657
2658 lxc_conf->console.log_size = log_size;
47903908 2659
861813e5
CB
2660 return 0;
2661}
2662
5648fc19
CB
2663/*
2664 * If we find a lxc.net.[i].hwaddr or lxc.network.hwaddr in the original config
2665 * file, we expand it in the unexpanded_config, so that after a save_config we
2666 * store the hwaddr for re-use.
2667 * This is only called when reading the config file, not when executing a
2668 * lxc.include.
2669 * 'x' and 'X' are substituted in-place.
2670 */
2671static void update_hwaddr(const char *line)
2672{
2673 char *p;
2674
2675 line += lxc_char_left_gc(line, strlen(line));
2676 if (line[0] == '#')
2677 return;
2678
2679 if (!lxc_config_net_is_hwaddr(line))
2680 return;
2681
2682 /* Let config_net_hwaddr raise the error. */
2683 p = strchr(line, '=');
2684 if (!p)
2685 return;
2686 p++;
2687
2688 while (isblank(*p))
2689 p++;
2690
2691 if (!*p)
2692 return;
2693
2694 rand_complete_hwaddr(p);
2695}
2696
6b0d5538 2697int append_unexp_config_line(const char *line, struct lxc_conf *conf)
f979ac15 2698{
62a821f1
CB
2699 size_t linelen;
2700 size_t len = conf->unexpanded_len;
f979ac15 2701
e6744e9b
SH
2702 update_hwaddr(line);
2703
62a821f1 2704 linelen = strlen(line);
6b0d5538 2705 while (conf->unexpanded_alloced <= len + linelen + 2) {
1161f50d
CB
2706 char *tmp;
2707
2708 tmp = realloc(conf->unexpanded_config, conf->unexpanded_alloced + 1024);
6b0d5538 2709 if (!tmp)
1161f50d 2710 return ret_errno(EINVAL);
504a2217 2711
6b0d5538
SH
2712 if (!conf->unexpanded_config)
2713 *tmp = '\0';
62a821f1 2714
6b0d5538
SH
2715 conf->unexpanded_config = tmp;
2716 conf->unexpanded_alloced += 1024;
2717 }
efed99a4 2718
62a821f1 2719 memcpy(conf->unexpanded_config + conf->unexpanded_len, line, linelen);
6b0d5538 2720 conf->unexpanded_len += linelen;
62a821f1
CB
2721 if (line[linelen - 1] != '\n')
2722 conf->unexpanded_config[conf->unexpanded_len++] = '\n';
2723 conf->unexpanded_config[conf->unexpanded_len] = '\0';
25a908b8 2724
f979ac15
SH
2725 return 0;
2726}
2727
e1daebd9
SH
2728static int do_includedir(const char *dirp, struct lxc_conf *lxc_conf)
2729{
4110345b 2730 __do_closedir DIR *dir = NULL;
74f96976 2731 struct dirent *direntp;
c1b2319b 2732 int len, ret;
e1daebd9
SH
2733
2734 dir = opendir(dirp);
25a908b8 2735 if (!dir)
dc73e0f0 2736 return errno == ENOENT ? 0 : -errno;
e1daebd9 2737
74f96976 2738 while ((direntp = readdir(dir))) {
e1daebd9 2739 const char *fnam;
c1b2319b 2740 char path[PATH_MAX];
e1daebd9
SH
2741
2742 fnam = direntp->d_name;
d62177e9 2743 if (strequal(fnam, "."))
e1daebd9
SH
2744 continue;
2745
d62177e9 2746 if (strequal(fnam, ".."))
e1daebd9
SH
2747 continue;
2748
2749 len = strlen(fnam);
1af3044f 2750 if (len < 6 || !strnequal(fnam + len - 5, ".conf", 5))
e1daebd9 2751 continue;
25a908b8 2752
3948c252
CB
2753 len = strnprintf(path, sizeof(path), "%s/%s", dirp, fnam);
2754 if (len < 0)
c1b2319b 2755 return ret_errno(EIO);
e1daebd9
SH
2756
2757 ret = lxc_config_read(path, lxc_conf, true);
2758 if (ret < 0)
c1b2319b 2759 return ret;
e1daebd9 2760 }
e1daebd9 2761
4110345b 2762 return 0;
e1daebd9
SH
2763}
2764
973082f5 2765static int set_config_includefiles(const char *key, const char *value,
c7e27aaf 2766 struct lxc_conf *lxc_conf, void *data)
09ad6246 2767{
663e9916 2768 if (lxc_config_value_empty(value)) {
26471403 2769 clr_config_includefiles(key, lxc_conf, NULL);
616422f1 2770 return 0;
355c5701 2771 }
616422f1 2772
539c3977 2773 if (value[strlen(value)-1] == '/' || lxc_is_dir(value))
e1daebd9
SH
2774 return do_includedir(value, lxc_conf);
2775
6b0d5538 2776 return lxc_config_read(value, lxc_conf, true);
09ad6246
SH
2777}
2778
7a96a068
CB
2779static int set_config_rootfs_path(const char *key, const char *value,
2780 struct lxc_conf *lxc_conf, void *data)
c2cc9f0a 2781{
d8cf0289 2782 __do_free char *dup = NULL;
693dbdb9 2783 int ret;
d8cf0289 2784 char *tmp;
693dbdb9
CB
2785 const char *container_path;
2786
2787 if (lxc_config_value_empty(value)) {
2788 free(lxc_conf->rootfs.path);
2789 lxc_conf->rootfs.path = NULL;
2790 return 0;
2791 }
2792
2793 dup = strdup(value);
2794 if (!dup)
d8cf0289 2795 return ret_errno(ENOMEM);
693dbdb9
CB
2796
2797 /* Split <storage type>:<container path> into <storage type> and
2798 * <container path>. Set "rootfs.bdev_type" to <storage type> and
2799 * "rootfs.path" to <container path>.
2800 */
2801 tmp = strchr(dup, ':');
2802 if (tmp) {
2803 *tmp = '\0';
47903908 2804
693dbdb9 2805 ret = set_config_path_item(&lxc_conf->rootfs.bdev_type, dup);
d8cf0289
CB
2806 if (ret < 0)
2807 return ret_errno(ENOMEM);
47903908 2808
693dbdb9
CB
2809 tmp++;
2810 container_path = tmp;
2811 } else {
2812 container_path = value;
2813 }
2814
d8cf0289 2815 return set_config_path_item(&lxc_conf->rootfs.path, container_path);
c2cc9f0a 2816}
2817
6e54330c
CB
2818static int set_config_rootfs_managed(const char *key, const char *value,
2819 struct lxc_conf *lxc_conf, void *data)
2820{
8f818a84 2821 return set_config_bool_item(&lxc_conf->rootfs.managed, value, true);
6e54330c
CB
2822}
2823
713046e3 2824static int set_config_rootfs_mount(const char *key, const char *value,
c7e27aaf 2825 struct lxc_conf *lxc_conf, void *data)
23b7ea69 2826{
713046e3 2827 return set_config_path_item(&lxc_conf->rootfs.mount, value);
23b7ea69
DL
2828}
2829
713046e3 2830static int set_config_rootfs_options(const char *key, const char *value,
c7e27aaf 2831 struct lxc_conf *lxc_conf, void *data)
a17b1e65 2832{
704cadd5 2833 __do_free char *dup = NULL, *raw_options = NULL;
3437f95c 2834 struct lxc_rootfs *rootfs = &lxc_conf->rootfs;
423374e9 2835 struct lxc_mount_options *mnt_opts = &rootfs->mnt_opts;
f9d29e1f 2836 int ret;
3437f95c 2837
c04f4221
CB
2838 clr_config_rootfs_options(key, lxc_conf, data);
2839 if (lxc_config_value_empty(value))
2840 return 0;
2841
704cadd5
CB
2842 ret = set_config_string_item(&raw_options, value);
2843 if (ret < 0)
2844 return ret_errno(ENOMEM);
2845
16fcdacc
CB
2846 dup = strdup(value);
2847 if (!dup)
2848 return -ENOMEM;
2849
1b82d721 2850 ret = parse_lxc_mount_attrs(mnt_opts, dup);
16fcdacc
CB
2851 if (ret < 0)
2852 return ret;
3437f95c 2853
704cadd5 2854 /* Make sure we're only valid LXC specific mount options. */
423374e9
CB
2855 if (mnt_opts->create_dir || mnt_opts->create_file ||
2856 mnt_opts->optional || mnt_opts->relative)
10fe481d 2857 return syserror_set(-EINVAL, "Invalid LXC specific mount option for rootfs mount");
16fcdacc 2858
704cadd5
CB
2859 ret = parse_mount_attrs(mnt_opts, dup);
2860 if (ret < 0)
2861 return ret_errno(EINVAL);
3437f95c 2862
e73af35b 2863 rootfs->mnt_opts.raw_options = move_ptr(raw_options);
3437f95c 2864 return 0;
a17b1e65
SG
2865}
2866
b67771bc 2867static int set_config_uts_name(const char *key, const char *value,
c7e27aaf 2868 struct lxc_conf *lxc_conf, void *data)
c2cc9f0a 2869{
cde6d8b4 2870 __do_free struct utsname *utsname = NULL;
c2cc9f0a 2871
663e9916 2872 if (lxc_config_value_empty(value)) {
b67771bc 2873 clr_config_uts_name(key, lxc_conf, NULL);
1939e73d 2874 return 0;
00cd8039 2875 }
1939e73d 2876
642751cc 2877 utsname = zalloc(sizeof(*utsname));
25a908b8 2878 if (!utsname)
cde6d8b4 2879 return ret_errno(ENOMEM);
c2cc9f0a 2880
cde6d8b4
CB
2881 if (strlen(value) >= sizeof(utsname->nodename))
2882 return ret_errno(EINVAL);
c2cc9f0a 2883
43f984ea 2884 (void)strlcpy(utsname->nodename, value, sizeof(utsname->nodename));
f10fad2f 2885 free(lxc_conf->utsname);
cde6d8b4 2886 lxc_conf->utsname = move_ptr(utsname);
c2cc9f0a 2887
2888 return 0;
2889}
2890
1d8d3676
CB
2891static int set_config_namespace_clone(const char *key, const char *value,
2892 struct lxc_conf *lxc_conf, void *data)
2893{
7454047d
CB
2894 __do_free char *ns = NULL;
2895 char *token;
1d8d3676 2896 int cloneflag = 0;
1d8d3676
CB
2897
2898 if (lxc_config_value_empty(value))
2899 return clr_config_namespace_clone(key, lxc_conf, data);
2900
7454047d
CB
2901 if (lxc_conf->ns_keep != 0)
2902 return log_error_errno(-EINVAL, EINVAL, "Cannot set both \"lxc.namespace.clone\" and \"lxc.namespace.keep\"");
8bc8c715 2903
1d8d3676
CB
2904 ns = strdup(value);
2905 if (!ns)
7454047d 2906 return ret_errno(ENOMEM);
1d8d3676 2907
62dd965e 2908 lxc_iterate_parts(token, ns, " \t") {
1d8d3676
CB
2909 token += lxc_char_left_gc(token, strlen(token));
2910 token[lxc_char_right_gc(token, strlen(token))] = '\0';
2911 cloneflag = lxc_namespace_2_cloneflag(token);
7454047d
CB
2912 if (cloneflag < 0)
2913 return ret_errno(EINVAL);
1d8d3676
CB
2914 lxc_conf->ns_clone |= cloneflag;
2915 }
1d8d3676
CB
2916
2917 return 0;
2918}
2919
abeb5bba
CB
2920static int set_config_namespace_keep(const char *key, const char *value,
2921 struct lxc_conf *lxc_conf, void *data)
2922{
6c90df0e
CB
2923 __do_free char *ns = NULL;
2924 char *token;
abeb5bba 2925 int cloneflag = 0;
abeb5bba
CB
2926
2927 if (lxc_config_value_empty(value))
2928 return clr_config_namespace_keep(key, lxc_conf, data);
2929
6c90df0e
CB
2930 if (lxc_conf->ns_clone != 0)
2931 return log_error_errno(-EINVAL, EINVAL, "Cannot set both \"lxc.namespace.clone\" and \"lxc.namespace.keep\"");
8bc8c715 2932
abeb5bba
CB
2933 ns = strdup(value);
2934 if (!ns)
6c90df0e 2935 return ret_errno(ENOMEM);
abeb5bba 2936
62dd965e 2937 lxc_iterate_parts(token, ns, " \t") {
abeb5bba
CB
2938 token += lxc_char_left_gc(token, strlen(token));
2939 token[lxc_char_right_gc(token, strlen(token))] = '\0';
2940 cloneflag = lxc_namespace_2_cloneflag(token);
6c90df0e
CB
2941 if (cloneflag < 0)
2942 return ret_errno(EINVAL);
abeb5bba
CB
2943 lxc_conf->ns_keep |= cloneflag;
2944 }
abeb5bba
CB
2945
2946 return 0;
2947}
2948
70fd7fc9
CB
2949static int set_config_time_offset_boot(const char *key, const char *value,
2950 struct lxc_conf *lxc_conf, void *data)
2951{
2952 int ret;
2953 char *unit;
2954 int64_t offset = 0;
2955 char buf[STRLITERALLEN("ms") + 1];
2956
2957 if (lxc_config_value_empty(value))
2958 return clr_config_time_offset_boot(key, lxc_conf, data);
2959
2960 ret = lxc_safe_int64_residual(value, &offset, 10, buf, sizeof(buf));
2961 if (ret)
2962 return ret;
2963
70fd7fc9 2964 unit = lxc_trim_whitespace_in_place(buf);
d62177e9 2965 if (strequal(unit, "h")) {
07f89c1e 2966 if (!multiply_overflow(offset, 3600, &lxc_conf->timens.s_boot))
b9965fd7 2967 return ret_errno(EOVERFLOW);
d62177e9 2968 } else if (strequal(unit, "m")) {
07f89c1e 2969 if (!multiply_overflow(offset, 60, &lxc_conf->timens.s_boot))
b9965fd7 2970 return ret_errno(EOVERFLOW);
d62177e9 2971 } else if (strequal(unit, "s")) {
70fd7fc9 2972 lxc_conf->timens.s_boot = offset;
d62177e9 2973 } else if (strequal(unit, "ms")) {
07f89c1e 2974 if (!multiply_overflow(offset, 1000000, &lxc_conf->timens.ns_boot))
b9965fd7 2975 return ret_errno(EOVERFLOW);
d62177e9 2976 } else if (strequal(unit, "us")) {
07f89c1e 2977 if (!multiply_overflow(offset, 1000, &lxc_conf->timens.ns_boot))
b9965fd7 2978 return ret_errno(EOVERFLOW);
d62177e9 2979 } else if (strequal(unit, "ns")) {
70fd7fc9 2980 lxc_conf->timens.ns_boot = offset;
07f89c1e 2981 } else {
70fd7fc9 2982 return ret_errno(EINVAL);
07f89c1e 2983 }
70fd7fc9
CB
2984
2985 return 0;
2986}
2987
2988static int set_config_time_offset_monotonic(const char *key, const char *value,
2989 struct lxc_conf *lxc_conf, void *data)
2990{
2991 int ret;
2992 char *unit;
2993 int64_t offset = 0;
2994 char buf[STRLITERALLEN("ms") + 1];
2995
2996 if (lxc_config_value_empty(value))
2997 return clr_config_time_offset_monotonic(key, lxc_conf, data);
2998
2999 ret = lxc_safe_int64_residual(value, &offset, 10, buf, sizeof(buf));
3000 if (ret)
3001 return ret;
3002
70fd7fc9 3003 unit = lxc_trim_whitespace_in_place(buf);
d62177e9 3004 if (strequal(unit, "h")) {
07f89c1e 3005 if (!multiply_overflow(offset, 3600, &lxc_conf->timens.s_monotonic))
8f204445 3006 return ret_errno(EOVERFLOW);
d62177e9 3007 } else if (strequal(unit, "m")) {
07f89c1e 3008 if (!multiply_overflow(offset, 60, &lxc_conf->timens.s_monotonic))
8f204445 3009 return ret_errno(EOVERFLOW);
d62177e9 3010 } else if (strequal(unit, "s")) {
70fd7fc9 3011 lxc_conf->timens.s_monotonic = offset;
d62177e9 3012 } else if (strequal(unit, "ms")) {
07f89c1e 3013 if (!multiply_overflow(offset, 1000000, &lxc_conf->timens.ns_monotonic))
8f204445 3014 return ret_errno(EOVERFLOW);
d62177e9 3015 } else if (strequal(unit, "us")) {
07f89c1e 3016 if (!multiply_overflow(offset, 1000, &lxc_conf->timens.ns_monotonic))
8f204445 3017 return ret_errno(EOVERFLOW);
d62177e9 3018 } else if (strequal(unit, "ns")) {
70fd7fc9 3019 lxc_conf->timens.ns_monotonic = offset;
07f89c1e 3020 } else {
70fd7fc9 3021 return ret_errno(EINVAL);
07f89c1e 3022 }
70fd7fc9
CB
3023
3024 return 0;
3025}
3026
b074bbf1
CB
3027static int set_config_namespace_share(const char *key, const char *value,
3028 struct lxc_conf *lxc_conf, void *data)
28d9e29e
CB
3029{
3030 int ns_idx;
3031 const char *namespace;
3032
3033 if (lxc_config_value_empty(value))
b074bbf1 3034 return clr_config_namespace_share(key, lxc_conf, data);
28d9e29e 3035
6333c915 3036 namespace = key + STRLITERALLEN("lxc.namespace.share.");
057d2cae
CB
3037 if (is_empty_string(namespace))
3038 return ret_errno(EINVAL);
3039
28d9e29e
CB
3040 ns_idx = lxc_namespace_2_ns_idx(namespace);
3041 if (ns_idx < 0)
3042 return ns_idx;
3043
b074bbf1 3044 return set_config_string_item(&lxc_conf->ns_share[ns_idx], value);
28d9e29e
CB
3045}
3046
6b0d5538
SH
3047struct parse_line_conf {
3048 struct lxc_conf *conf;
3049 bool from_include;
3050};
4184c3e1 3051
7a7ff0c6 3052static int parse_line(char *buffer, void *data)
c2cc9f0a 3053{
2e373df3
CB
3054 __do_free char *linep = NULL;
3055 char *dot, *key, *line, *value;
3b13691d
CB
3056 bool empty_line;
3057 struct lxc_config_t *config;
2e373df3 3058 int ret;
3b13691d
CB
3059 char *dup = buffer;
3060 struct parse_line_conf *plc = data;
c2cc9f0a 3061
d60ba568
CB
3062 if (!plc->conf)
3063 return syserror_set(-EINVAL, "Missing config");
3064
3b13691d
CB
3065 /* If there are newlines in the config file we should keep them. */
3066 empty_line = lxc_is_line_empty(dup);
3067 if (empty_line)
3068 dup = "\n";
c2cc9f0a 3069
25a908b8
CB
3070 /* We have to dup the buffer otherwise, at the re-exec for reboot we
3071 * modified the original string on the stack by replacing '=' by '\0'
3072 * below.
91480a0f 3073 */
3b13691d 3074 linep = line = strdup(dup);
25a908b8 3075 if (!line)
2e373df3 3076 return ret_errno(ENOMEM);
91480a0f 3077
3b13691d
CB
3078 if (!plc->from_include) {
3079 ret = append_unexp_config_line(line, plc->conf);
3080 if (ret < 0)
2e373df3 3081 return ret;
3b13691d
CB
3082 }
3083
3084 if (empty_line)
2e373df3 3085 return 0;
6b0d5538 3086
b2718c72 3087 line += lxc_char_left_gc(line, strlen(line));
476d4cf1 3088
4184c3e1
SH
3089 /* ignore comments */
3090 if (line[0] == '#')
2e373df3 3091 return 0;
476d4cf1 3092
6b0d5538 3093 /* martian option - don't add it to the config itself */
1af3044f 3094 if (!strnequal(line, "lxc.", 4))
2e373df3 3095 return 0;
c2cc9f0a 3096
3b13691d 3097 dot = strchr(line, '=');
2e373df3
CB
3098 if (!dot)
3099 return log_error_errno(-EINVAL, EINVAL, "Invalid configuration line: %s", line);
a871ff6b 3100
c2cc9f0a 3101 *dot = '\0';
3102 value = dot + 1;
3103
b2718c72 3104 key = line;
3105 key[lxc_char_right_gc(key, strlen(key))] = '\0';
c2cc9f0a 3106
b2718c72 3107 value += lxc_char_left_gc(value, strlen(value));
3108 value[lxc_char_right_gc(value, strlen(value))] = '\0';
c2cc9f0a 3109
bd878dee 3110 if (*value == '\'' || *value == '\"') {
25a908b8
CB
3111 size_t len;
3112
3113 len = strlen(value);
504a2217
CB
3114 if (len > 1 && value[len - 1] == *value) {
3115 value[len - 1] = '\0';
bd878dee
SB
3116 value++;
3117 }
3118 }
3119
300df83e 3120 config = lxc_get_config(key);
2e373df3 3121 return config->set(key, value, plc->conf, NULL);
c2cc9f0a 3122}
3123
d899f11b 3124static struct new_config_item *parse_new_conf_line(char *buffer)
3125{
2b4cdcdb
CB
3126 __do_free char *k = NULL, *linep = NULL, *v = NULL;
3127 __do_free struct new_config_item *new = NULL;
d899f11b 3128 char *dup = buffer;
2b4cdcdb 3129 char *dot, *key, *line, *value;
d899f11b 3130
d60ba568
CB
3131 if (is_empty_string(buffer))
3132 return log_error_errno(NULL, EINVAL, "Empty configuration line");
3133
d899f11b 3134 linep = line = strdup(dup);
3135 if (!line)
3136 return NULL;
3137
3138 line += lxc_char_left_gc(line, strlen(line));
3139
3140 /* martian option - don't add it to the config itself */
1af3044f 3141 if (!strnequal(line, "lxc.", 4))
2b4cdcdb 3142 return 0;
d899f11b 3143
d899f11b 3144 dot = strchr(line, '=');
2b4cdcdb
CB
3145 if (!dot)
3146 return log_error_errno(NULL, EINVAL, "Invalid configuration line: %s", line);
d899f11b 3147
3148 *dot = '\0';
3149 value = dot + 1;
3150
3151 key = line;
3152 key[lxc_char_right_gc(key, strlen(key))] = '\0';
3153
3154 value += lxc_char_left_gc(value, strlen(value));
3155 value[lxc_char_right_gc(value, strlen(value))] = '\0';
3156
3157 if (*value == '\'' || *value == '\"') {
3158 size_t len;
3159
3160 len = strlen(value);
3161 if (len > 1 && value[len - 1] == *value) {
3162 value[len - 1] = '\0';
3163 value++;
3164 }
3165 }
3166
642751cc 3167 new = zalloc(sizeof(struct new_config_item));
d899f11b 3168 if (!new)
2b4cdcdb 3169 return NULL;
d899f11b 3170
2b4cdcdb
CB
3171 k = strdup(key);
3172 if (!k)
3173 return NULL;
d899f11b 3174
2b4cdcdb
CB
3175 v = strdup(value);
3176 if (!v)
3177 return NULL;
d899f11b 3178
2b4cdcdb
CB
3179 new->key = move_ptr(k);
3180 new->val = move_ptr(v);
3181 return move_ptr(new);
d899f11b 3182}
3183
6b0d5538 3184int lxc_config_read(const char *file, struct lxc_conf *conf, bool from_include)
c2cc9f0a 3185{
d60ba568
CB
3186 struct parse_line_conf plc;
3187
3188 if (!conf)
3189 return syserror_set(-EINVAL, "Missing config");
6b0d5538 3190
d60ba568
CB
3191 plc.conf = conf;
3192 plc.from_include = from_include;
f979ac15 3193
25a908b8 3194 /* Catch only the top level config file name in the structure. */
504a2217 3195 if (!conf->rcfile)
76d0127f 3196 conf->rcfile = strdup(file);
f979ac15 3197
d60ba568 3198 return lxc_file_for_each_line_mmap(file, parse_line, &plc);
c2cc9f0a 3199}
62e46035 3200
504a2217 3201int lxc_config_define_add(struct lxc_list *defines, char *arg)
62e46035 3202{
bce0472a 3203 __do_free struct lxc_list *dent = NULL;
62e46035 3204
642751cc 3205 dent = lxc_list_new();
62e46035 3206 if (!dent)
bce0472a 3207 return ret_errno(ENOMEM);
62e46035 3208
d899f11b 3209 dent->elem = parse_new_conf_line(arg);
bce0472a
CB
3210 if (!dent->elem)
3211 return ret_errno(ENOMEM);
d899f11b 3212
bce0472a 3213 lxc_list_add_tail(defines, move_ptr(dent));
47903908 3214
62e46035
CLG
3215 return 0;
3216}
3217
eb0c9382 3218bool lxc_config_define_load(struct lxc_list *defines, struct lxc_container *c)
62e46035 3219{
eb0c9382 3220 struct lxc_list *it;
3221 bool bret = true;
62e46035
CLG
3222
3223 lxc_list_for_each(it, defines) {
eb0c9382 3224 struct new_config_item *new_item = it->elem;
3225 bret = c->set_config_item(c, new_item->key, new_item->val);
3226 if (!bret)
62e46035
CLG
3227 break;
3228 }
3229
e8694d9a 3230#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
eb0c9382 3231 lxc_config_define_free(defines);
e8694d9a 3232#endif /* !FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION */
47903908 3233
eb0c9382 3234 return bret;
3235}
3236
3237void lxc_config_define_free(struct lxc_list *defines)
3238{
3239 struct lxc_list *it, *next;
3240
9ebb03ad 3241 lxc_list_for_each_safe(it, defines, next) {
eb0c9382 3242 struct new_config_item *new_item = it->elem;
3243 free(new_item->key);
3244 free(new_item->val);
62e46035 3245 lxc_list_del(it);
1a46f853 3246 free(it->elem);
62e46035
CLG
3247 free(it);
3248 }
62e46035 3249}
525f0002 3250
7c43fa56 3251int lxc_config_parse_arch(const char *arch, signed long *persona)
525f0002 3252{
5f2a6ec4 3253 static struct per_name {
525f0002
CS
3254 char *name;
3255 unsigned long per;
bb8d8207 3256 } pername[] = {
c852678b
CB
3257 { "arm", PER_LINUX32 },
3258 { "armel", PER_LINUX32 },
3259 { "armhf", PER_LINUX32 },
3260 { "armv7l", PER_LINUX32 },
3261 { "athlon", PER_LINUX32 },
3262 { "i386", PER_LINUX32 },
3263 { "i486", PER_LINUX32 },
3264 { "i586", PER_LINUX32 },
3265 { "i686", PER_LINUX32 },
3266 { "linux32", PER_LINUX32 },
3267 { "mips", PER_LINUX32 },
3268 { "mipsel", PER_LINUX32 },
3269 { "ppc", PER_LINUX32 },
3270 { "powerpc", PER_LINUX32 },
3271 { "x86", PER_LINUX32 },
cae2b16f 3272 { "aarch64", PER_LINUX },
c852678b
CB
3273 { "amd64", PER_LINUX },
3274 { "arm64", PER_LINUX },
3275 { "linux64", PER_LINUX },
3276 { "mips64", PER_LINUX },
3277 { "mips64el", PER_LINUX },
3278 { "ppc64", PER_LINUX },
3279 { "ppc64el", PER_LINUX },
3280 { "ppc64le", PER_LINUX },
3281 { "powerpc64", PER_LINUX },
07459c88 3282 { "riscv64", PER_LINUX },
c852678b
CB
3283 { "s390x", PER_LINUX },
3284 { "x86_64", PER_LINUX },
525f0002 3285 };
525f0002 3286
15b9e2b0 3287 for (size_t i = 0; i < ARRAY_SIZE(pername); i++) {
7c43fa56
CB
3288 if (!strequal(pername[i].name, arch))
3289 continue;
3290
3291 *persona = pername[i].per;
3292 return 0;
3293 }
525f0002 3294
7c43fa56 3295 return ret_errno(EINVAL);
525f0002 3296}
72d0e1cb 3297
d253a09f 3298int lxc_fill_elevated_privileges(char *flaglist, unsigned int *flags)
eb0c9382 3299{
d253a09f 3300 unsigned int flags_tmp = 0;
62dd965e 3301 char *token;
eb0c9382 3302 struct {
3303 const char *token;
3304 int flag;
3305 } all_privs[] = {
3306 { "CGROUP", LXC_ATTACH_MOVE_TO_CGROUP },
3307 { "CAP", LXC_ATTACH_DROP_CAPABILITIES },
3308 { "LSM", LXC_ATTACH_LSM_EXEC },
3309 { NULL, 0 }
3310 };
3311
3312 if (!flaglist) {
d253a09f
CB
3313 /*
3314 * For the sake of backward compatibility, keep all privileges
3315 * if no specific privileges are specified.
eb0c9382 3316 */
d253a09f
CB
3317 for (unsigned int i = 0; all_privs[i].token; i++)
3318 flags_tmp |= all_privs[i].flag;
eb0c9382 3319
d253a09f 3320 *flags = flags_tmp;
eb0c9382 3321 return 0;
3322 }
3323
62dd965e 3324 lxc_iterate_parts(token, flaglist, "|") {
d253a09f 3325 bool valid_token = false;
eb0c9382 3326
d253a09f
CB
3327 for (unsigned int i = 0; all_privs[i].token; i++) {
3328 if (!strequal(all_privs[i].token, token))
3329 continue;
eb0c9382 3330
d253a09f
CB
3331 valid_token = true;
3332 flags_tmp |= all_privs[i].flag;
3333 }
eb0c9382 3334
d253a09f
CB
3335 if (!valid_token)
3336 return syserror_set(-EINVAL, "Invalid elevated privilege \"%s\" requested", token);
eb0c9382 3337 }
3338
d253a09f 3339 *flags = flags_tmp;
eb0c9382 3340 return 0;
3341}
3342
504a2217 3343/* Write out a configuration file. */
0e1a60b0 3344int write_config(int fd, const struct lxc_conf *conf)
72d0e1cb 3345{
6b0d5538 3346 int ret;
0e1a60b0 3347 size_t len = conf->unexpanded_len;
72d0e1cb 3348
0e1a60b0
CB
3349 if (len == 0)
3350 return 0;
504a2217 3351
0e1a60b0 3352 ret = lxc_write_nointr(fd, conf->unexpanded_config, len);
f2c64408
CB
3353 if (ret < 0)
3354 return log_error_errno(-errno, errno, "Failed to write configuration file");
0e1a60b0
CB
3355
3356 return 0;
6b0d5538 3357}
f979ac15 3358
504a2217
CB
3359bool do_append_unexp_config_line(struct lxc_conf *conf, const char *key,
3360 const char *v)
6b0d5538 3361{
0cacddda 3362 __do_free char *tmp = NULL;
6b0d5538 3363 int ret;
151d2da2 3364 size_t len;
4184c3e1 3365
151d2da2 3366 len = strlen(key) + strlen(v) + 4;
f01d0358 3367 tmp = must_realloc(NULL, len);
151d2da2 3368
663e9916 3369 if (lxc_config_value_empty(v))
3948c252 3370 ret = strnprintf(tmp, len, "%s =", key);
151d2da2 3371 else
3948c252
CB
3372 ret = strnprintf(tmp, len, "%s = %s", key, v);
3373 if (ret < 0)
6b0d5538
SH
3374 return false;
3375
3376 /* Save the line verbatim into unexpanded_conf */
3377 if (append_unexp_config_line(tmp, conf))
3378 return false;
3379
3380 return true;
3381}
3382
504a2217
CB
3383void clear_unexp_config_line(struct lxc_conf *conf, const char *key,
3384 bool rm_subkeys)
6b0d5538 3385{
504a2217
CB
3386 char *lend;
3387 char *lstart = conf->unexpanded_config;
6b0d5538
SH
3388
3389 if (!conf->unexpanded_config)
3390 return;
504a2217 3391
6b0d5538
SH
3392 while (*lstart) {
3393 lend = strchr(lstart, '\n');
3394 char v;
47903908 3395
6b0d5538
SH
3396 if (!lend)
3397 lend = lstart + strlen(lstart);
3398 else
3399 lend++;
47903908 3400
1af3044f 3401 if (!strnequal(lstart, key, strlen(key))) {
6b0d5538
SH
3402 lstart = lend;
3403 continue;
5f62730e 3404 }
47903908 3405
6b0d5538
SH
3406 if (!rm_subkeys) {
3407 v = lstart[strlen(key)];
3408 if (!isspace(v) && v != '=') {
3409 lstart = lend;
3410 continue;
3411 }
5f62730e 3412 }
47903908 3413
6b0d5538 3414 conf->unexpanded_len -= (lend - lstart);
47903908 3415
6b0d5538
SH
3416 if (*lend == '\0') {
3417 *lstart = '\0';
3418 return;
fd986e08 3419 }
47903908 3420
504a2217 3421 memmove(lstart, lend, strlen(lend) + 1);
fd986e08 3422 }
6b0d5538
SH
3423}
3424
329b3625
CB
3425bool clone_update_unexp_ovl_paths(struct lxc_conf *conf, const char *oldpath,
3426 const char *newpath, const char *oldname,
3427 const char *newname, const char *ovldir)
3428{
b063ba29
CB
3429 __do_free char *newdir = NULL, *olddir = NULL;
3430 char *lstart = conf->unexpanded_config;
3431 const char *key = "lxc.mount.entry";
329b3625 3432 int ret;
f01d0358 3433 char *lend, *p, *q;
504a2217 3434 size_t newdirlen, olddirlen;
329b3625 3435
504a2217 3436 olddirlen = strlen(ovldir) + strlen(oldpath) + strlen(oldname) + 2;
f01d0358 3437 olddir = must_realloc(NULL, olddirlen + 1);
3948c252
CB
3438 ret = strnprintf(olddir, olddirlen + 1, "%s=%s/%s", ovldir, oldpath, oldname);
3439 if (ret < 0)
329b3625 3440 return false;
504a2217
CB
3441
3442 newdirlen = strlen(ovldir) + strlen(newpath) + strlen(newname) + 2;
f01d0358 3443 newdir = must_realloc(NULL, newdirlen + 1);
3948c252
CB
3444 ret = strnprintf(newdir, newdirlen + 1, "%s=%s/%s", ovldir, newpath, newname);
3445 if (ret < 0)
329b3625 3446 return false;
504a2217 3447
329b3625
CB
3448 if (!conf->unexpanded_config)
3449 return true;
504a2217 3450
329b3625
CB
3451 while (*lstart) {
3452 lend = strchr(lstart, '\n');
3453 if (!lend)
3454 lend = lstart + strlen(lstart);
3455 else
3456 lend++;
504a2217 3457
1af3044f 3458 if (!strnequal(lstart, key, strlen(key)))
504a2217
CB
3459 goto next;
3460
329b3625
CB
3461 p = strchr(lstart + strlen(key), '=');
3462 if (!p)
504a2217 3463 goto next;
329b3625 3464 p++;
504a2217 3465
329b3625
CB
3466 while (isblank(*p))
3467 p++;
504a2217 3468
329b3625 3469 if (p >= lend)
504a2217
CB
3470 goto next;
3471
12e6ab5d
CB
3472 /* Whenever a lxc.mount.entry entry is found in a line we check
3473 * if the substring "overlay" is present before doing any
3474 * further work. We check for "overlay" because substrings need
3475 * to have at least one space before them in a valid overlay
504a2217
CB
3476 * lxc.mount.entry (/A B overlay). When the space before is
3477 * missing it is very likely that these substrings are part of a
3478 * path or something else. (Checking q >= lend ensures that we
3479 * only count matches in the current line.) */
12e6ab5d
CB
3480 q = strstr(p, " overlay");
3481 if (!q || q >= lend)
504a2217
CB
3482 goto next;
3483
329b3625 3484 if (!(q = strstr(p, olddir)) || (q >= lend))
504a2217 3485 goto next;
329b3625
CB
3486
3487 /* replace the olddir with newdir */
3488 if (olddirlen >= newdirlen) {
3489 size_t diff = olddirlen - newdirlen;
3490 memcpy(q, newdir, newdirlen);
47903908 3491
329b3625
CB
3492 if (olddirlen != newdirlen) {
3493 memmove(q + newdirlen, q + newdirlen + diff,
47903908 3494 strlen(q) - newdirlen - diff + 1);
329b3625
CB
3495 lend -= diff;
3496 conf->unexpanded_len -= diff;
3497 }
3498 } else {
3499 char *new;
3500 size_t diff = newdirlen - olddirlen;
3501 size_t oldlen = conf->unexpanded_len;
3502 size_t newlen = oldlen + diff;
3503 size_t poffset = q - conf->unexpanded_config;
504a2217 3504
329b3625 3505 new = realloc(conf->unexpanded_config, newlen + 1);
25a908b8 3506 if (!new)
329b3625 3507 return false;
25a908b8 3508
329b3625
CB
3509 conf->unexpanded_len = newlen;
3510 conf->unexpanded_alloced = newlen + 1;
3511 new[newlen - 1] = '\0';
3512 lend = new + (lend - conf->unexpanded_config);
47903908 3513
25a908b8 3514 /* Move over the remainder to make room for the newdir.
504a2217 3515 */
329b3625 3516 memmove(new + poffset + newdirlen,
47903908 3517 new + poffset + olddirlen,
3518 oldlen - poffset - olddirlen + 1);
329b3625 3519 conf->unexpanded_config = new;
47903908 3520
329b3625
CB
3521 memcpy(new + poffset, newdir, newdirlen);
3522 lend += diff;
3523 }
47903908 3524
504a2217
CB
3525 next:
3526 lstart = lend;
329b3625 3527 }
504a2217 3528
329b3625
CB
3529 return true;
3530}
3531
67702c21 3532bool clone_update_unexp_hooks(struct lxc_conf *conf, const char *oldpath,
d546aa0e
CB
3533 const char *newpath, const char *oldname,
3534 const char *newname)
6b0d5538 3535{
29e78cb9
CB
3536 __do_free char *newdir = NULL, *olddir = NULL;
3537 char *lstart = conf->unexpanded_config;
3538 const char *key = "lxc.hook";
67702c21 3539 int ret;
f01d0358 3540 char *lend, *p;
504a2217 3541 size_t newdirlen, olddirlen;
67702c21 3542
504a2217 3543 olddirlen = strlen(oldpath) + strlen(oldname) + 1;
f01d0358 3544 olddir = must_realloc(NULL, olddirlen + 1);
3948c252
CB
3545 ret = strnprintf(olddir, olddirlen + 1, "%s/%s", oldpath, oldname);
3546 if (ret < 0)
67702c21 3547 return false;
504a2217
CB
3548
3549 newdirlen = strlen(newpath) + strlen(newname) + 1;
f01d0358 3550 newdir = must_realloc(NULL, newdirlen + 1);
3948c252
CB
3551 ret = strnprintf(newdir, newdirlen + 1, "%s/%s", newpath, newname);
3552 if (ret < 0)
67702c21 3553 return false;
25a908b8 3554
67702c21
SH
3555 if (!conf->unexpanded_config)
3556 return true;
25a908b8 3557
67702c21
SH
3558 while (*lstart) {
3559 lend = strchr(lstart, '\n');
3560 if (!lend)
3561 lend = lstart + strlen(lstart);
3562 else
3563 lend++;
504a2217 3564
1af3044f 3565 if (!strnequal(lstart, key, strlen(key)))
504a2217
CB
3566 goto next;
3567
d546aa0e
CB
3568 p = strchr(lstart + strlen(key), '=');
3569 if (!p)
504a2217 3570 goto next;
67702c21 3571 p++;
504a2217 3572
67702c21
SH
3573 while (isblank(*p))
3574 p++;
504a2217
CB
3575
3576 if (p >= lend)
3577 goto next;
3578
1af3044f 3579 if (!strnequal(p, olddir, strlen(olddir)))
504a2217
CB
3580 goto next;
3581
67702c21
SH
3582 /* replace the olddir with newdir */
3583 if (olddirlen >= newdirlen) {
3584 size_t diff = olddirlen - newdirlen;
3585 memcpy(p, newdir, newdirlen);
47903908 3586
67702c21 3587 if (olddirlen != newdirlen) {
d546aa0e 3588 memmove(p + newdirlen, p + newdirlen + diff,
47903908 3589 strlen(p) - newdirlen - diff + 1);
67702c21
SH
3590 lend -= diff;
3591 conf->unexpanded_len -= diff;
3592 }
67702c21
SH
3593 } else {
3594 char *new;
3595 size_t diff = newdirlen - olddirlen;
3596 size_t oldlen = conf->unexpanded_len;
3597 size_t newlen = oldlen + diff;
3598 size_t poffset = p - conf->unexpanded_config;
504a2217 3599
d546aa0e 3600 new = realloc(conf->unexpanded_config, newlen + 1);
25a908b8 3601 if (!new)
6b0d5538 3602 return false;
25a908b8 3603
67702c21 3604 conf->unexpanded_len = newlen;
d546aa0e
CB
3605 conf->unexpanded_alloced = newlen + 1;
3606 new[newlen - 1] = '\0';
67702c21 3607 lend = new + (lend - conf->unexpanded_config);
47903908 3608
25a908b8 3609 /* Move over the remainder to make room for the newdir.
504a2217 3610 */
d546aa0e 3611 memmove(new + poffset + newdirlen,
47903908 3612 new + poffset + olddirlen,
3613 oldlen - poffset - olddirlen + 1);
67702c21 3614 conf->unexpanded_config = new;
47903908 3615
d546aa0e
CB
3616 memcpy(new + poffset, newdir, newdirlen);
3617 lend += diff;
fd986e08 3618 }
47903908 3619
504a2217
CB
3620 next:
3621 lstart = lend;
fd986e08 3622 }
504a2217 3623
6b0d5538
SH
3624 return true;
3625}
3626
504a2217
CB
3627#define DO(cmd) \
3628 { \
3629 if (!(cmd)) { \
3630 ERROR("Error writing to new config"); \
3631 return false; \
3632 } \
3633 }
6b0d5538 3634
25a908b8
CB
3635/* This is called only from clone. We wish to update all hwaddrs in the
3636 * unexpanded config file. We can't/don't want to update any which come from
504a2217
CB
3637 * lxc.includes (there shouldn't be any).
3638 * We can't just walk the c->lxc-conf->network list because that includes netifs
3639 * from the include files. So we update the ones which we find in the unexp
3640 * config file, then find the original macaddr in the conf->network, and update
3641 * that to the same value.
67702c21
SH
3642 */
3643bool network_new_hwaddrs(struct lxc_conf *conf)
6b0d5538 3644{
504a2217 3645 char *lend, *p, *p2;
504a2217 3646 char *lstart = conf->unexpanded_config;
6b0d5538 3647
67702c21
SH
3648 if (!conf->unexpanded_config)
3649 return true;
091045f8 3650
67702c21
SH
3651 while (*lstart) {
3652 char newhwaddr[18], oldhwaddr[17];
87d0990c 3653 struct lxc_netdev *netdev;
091045f8 3654
67702c21
SH
3655 lend = strchr(lstart, '\n');
3656 if (!lend)
3657 lend = lstart + strlen(lstart);
3658 else
3659 lend++;
091045f8 3660
3db41a6c 3661 if (!lxc_config_net_is_hwaddr(lstart)) {
67702c21
SH
3662 lstart = lend;
3663 continue;
72d0e1cb 3664 }
091045f8 3665
4a787c27 3666 p = strchr(lstart, '=');
67702c21
SH
3667 if (!p) {
3668 lstart = lend;
3669 continue;
72d0e1cb 3670 }
091045f8 3671
67702c21
SH
3672 p++;
3673 while (isblank(*p))
3674 p++;
3675 if (!*p)
3676 return true;
091045f8 3677
67702c21
SH
3678 p2 = p;
3679 while (*p2 && !isblank(*p2) && *p2 != '\n')
3680 p2++;
504a2217
CB
3681
3682 if ((p2 - p) != 17) {
67702c21
SH
3683 WARN("Bad hwaddr entry");
3684 lstart = lend;
3685 continue;
72d0e1cb 3686 }
091045f8 3687
67702c21 3688 memcpy(oldhwaddr, p, 17);
091045f8
CB
3689
3690 if (!new_hwaddr(newhwaddr))
3691 return false;
3692
67702c21 3693 memcpy(p, newhwaddr, 17);
87d0990c
CB
3694 list_for_each_entry(netdev, &conf->netdevs, head) {
3695 if (netdev->hwaddr && memcmp(oldhwaddr, netdev->hwaddr, 17) == 0)
3696 memcpy(netdev->hwaddr, newhwaddr, 17);
72d0e1cb 3697 }
67702c21
SH
3698
3699 lstart = lend;
72d0e1cb 3700 }
091045f8 3701
6b0d5538 3702 return true;
72d0e1cb 3703}
8796becf 3704
713046e3 3705static int set_config_ephemeral(const char *key, const char *value,
c7e27aaf 3706 struct lxc_conf *lxc_conf, void *data)
8796becf 3707{
4486ea13
CB
3708 int ret;
3709
663e9916 3710 if (lxc_config_value_empty(value)) {
3c6cf53a 3711 lxc_conf->ephemeral = 0;
78304622 3712 return 0;
3c6cf53a 3713 }
78304622 3714
4486ea13
CB
3715 ret = lxc_safe_uint(value, &lxc_conf->ephemeral);
3716 if (ret < 0)
3717 return ret;
8796becf 3718
25a908b8 3719 if (lxc_conf->ephemeral > 1)
4486ea13 3720 return ret_errno(EINVAL);
8796becf
CB
3721
3722 return 0;
3723}
3724
46cc906d 3725static int set_config_log_syslog(const char *key, const char *value,
c7e27aaf 3726 struct lxc_conf *lxc_conf, void *data)
64c57ea1 3727{
76d0127f 3728 int facility;
7ca56b84 3729
b8a0e944
CB
3730 if (lxc_conf->syslog)
3731 free_disarm(lxc_conf->syslog);
ee10a69c 3732
663e9916 3733 if (lxc_config_value_empty(value))
7ca56b84
CB
3734 return 0;
3735
76d0127f 3736 facility = lxc_syslog_priority_to_int(value);
25a908b8 3737 if (facility == -EINVAL)
b8a0e944 3738 return ret_errno(EINVAL);
64c57ea1 3739
76d0127f 3740 lxc_log_syslog(facility);
47903908 3741
713046e3 3742 return set_config_string_item(&lxc_conf->syslog, value);
64c57ea1 3743}
5a46f283 3744
713046e3 3745static int set_config_no_new_privs(const char *key, const char *value,
c7e27aaf 3746 struct lxc_conf *lxc_conf, void *data)
5a46f283 3747{
ad9a0d33 3748 int ret;
e8ec7c9e 3749 unsigned int v;
5a46f283 3750
663e9916 3751 if (lxc_config_value_empty(value)) {
cf3f8bf6 3752 lxc_conf->no_new_privs = false;
80926845 3753 return 0;
cf3f8bf6 3754 }
80926845 3755
ad9a0d33
CB
3756 ret = lxc_safe_uint(value, &v);
3757 if (ret < 0)
3758 return ret;
e8ec7c9e 3759
25a908b8 3760 if (v > 1)
ad9a0d33 3761 return ret_errno(EINVAL);
e8ec7c9e 3762
5a46f283
CB
3763 lxc_conf->no_new_privs = v ? true : false;
3764
3765 return 0;
3766}
7b992a3e
CB
3767
3768/* Callbacks to get configuration items. */
6bede808 3769static int get_config_personality(const char *key, char *retv, int inlen,
cccd2219 3770 struct lxc_conf *c, void *data)
7b992a3e
CB
3771{
3772 int fulllen = 0;
3773
3774 if (!retv)
3775 inlen = 0;
3776 else
3777 memset(retv, 0, inlen);
3778
7b992a3e
CB
3779 int len = 0;
3780
6bede808 3781 switch (c->personality) {
7b992a3e
CB
3782 case PER_LINUX32:
3783 strprint(retv, inlen, "i686");
3784 break;
3785 case PER_LINUX:
3786 strprint(retv, inlen, "x86_64");
3787 break;
3788 default:
3789 break;
3790 }
7b992a3e
CB
3791
3792 return fulllen;
3793}
bdf91ab4 3794
232763d6
CB
3795static int get_config_pty_max(const char *key, char *retv, int inlen,
3796 struct lxc_conf *c, void *data)
bdf91ab4 3797{
e528c735 3798 return lxc_get_conf_size_t(c, retv, inlen, c->pty_max);
bdf91ab4 3799}
5485782f 3800
fe1c5887
CB
3801static int get_config_tty_max(const char *key, char *retv, int inlen,
3802 struct lxc_conf *c, void *data)
5485782f 3803{
885766f5 3804 return lxc_get_conf_size_t(c, retv, inlen, c->ttys.max);
5485782f 3805}
8015e018 3806
42e53c29 3807static int get_config_tty_dir(const char *key, char *retv, int inlen,
cccd2219 3808 struct lxc_conf *c, void *data)
8015e018 3809{
885766f5 3810 return lxc_get_conf_str(retv, inlen, c->ttys.dir);
8015e018 3811}
de1ede69 3812
953fe44f
CB
3813static int get_config_apparmor_profile(const char *key, char *retv, int inlen,
3814 struct lxc_conf *c, void *data)
104c8e6c 3815{
8f899a4a 3816#if HAVE_APPARMOR
6bede808 3817 return lxc_get_conf_str(retv, inlen, c->lsm_aa_profile);
8f899a4a
CB
3818#else
3819 return syserror_set(-EINVAL, "Built without AppArmor support");
3820#endif
104c8e6c 3821}
d60d18c6 3822
953fe44f
CB
3823static int get_config_apparmor_allow_incomplete(const char *key, char *retv,
3824 int inlen, struct lxc_conf *c,
3825 void *data)
d60d18c6 3826{
8f899a4a
CB
3827#if HAVE_APPARMOR
3828 return lxc_get_conf_int(c, retv, inlen, c->lsm_aa_allow_incomplete);
3829#else
3830 return syserror_set(-EINVAL, "Built without AppArmor support");
3831#endif
d60d18c6 3832}
4203a0b5 3833
1800f924
WB
3834static int get_config_apparmor_allow_nesting(const char *key, char *retv,
3835 int inlen, struct lxc_conf *c,
3836 void *data)
3837{
8f899a4a
CB
3838#if HAVE_APPARMOR
3839 return lxc_get_conf_int(c, retv, inlen, c->lsm_aa_allow_nesting);
3840#else
3841 return syserror_set(-EINVAL, "Built without AppArmor support");
3842#endif
1800f924
WB
3843}
3844
3845static int get_config_apparmor_raw(const char *key, char *retv,
3846 int inlen, struct lxc_conf *c,
3847 void *data)
3848{
8f899a4a 3849#if HAVE_APPARMOR
1800f924 3850 int len;
1fb1e667 3851 struct string_entry *entry;
1800f924
WB
3852 int fulllen = 0;
3853
3854 if (!retv)
3855 inlen = 0;
3856 else
3857 memset(retv, 0, inlen);
3858
1fb1e667
CB
3859 list_for_each_entry(entry, &c->lsm_aa_raw, head) {
3860 strprint(retv, inlen, "%s\n", entry->val);
1800f924
WB
3861 }
3862
3863 return fulllen;
8f899a4a
CB
3864#else
3865 return syserror_set(-EINVAL, "Built without AppArmor support");
3866#endif
1800f924
WB
3867}
3868
953fe44f
CB
3869static int get_config_selinux_context(const char *key, char *retv, int inlen,
3870 struct lxc_conf *c, void *data)
4203a0b5 3871{
d6df2b8f 3872#if HAVE_SELINUX
6bede808 3873 return lxc_get_conf_str(retv, inlen, c->lsm_se_context);
d6df2b8f
CB
3874#else
3875 return syserror_set(-EINVAL, "Built without SELinux support");
3876#endif
4203a0b5 3877}
b863bf92 3878
4fef78bc
MB
3879static int get_config_selinux_context_keyring(const char *key, char *retv, int inlen,
3880 struct lxc_conf *c, void *data)
3881{
d6df2b8f 3882#if HAVE_SELINUX
4fef78bc 3883 return lxc_get_conf_str(retv, inlen, c->lsm_se_keyring_context);
d6df2b8f
CB
3884#else
3885 return syserror_set(-EINVAL, "Built without SELinux support");
3886#endif
4fef78bc
MB
3887}
3888
8f818a84
MB
3889static int get_config_keyring_session(const char *key, char *retv, int inlen,
3890 struct lxc_conf *c, void *data)
3891{
3892 return lxc_get_conf_bool(c, retv, inlen, c->keyring_disable_session);
3893}
3894
4fef78bc 3895
25a908b8
CB
3896/* If you ask for a specific cgroup value, i.e. lxc.cgroup.devices.list, then
3897 * just the value(s) will be printed. Since there still could be more than one,
3898 * it is newline-separated.
8d47350b 3899 * (Maybe that's ambiguous, since some values, i.e. devices.list, will already
25a908b8
CB
3900 * have newlines?)
3901 * If you ask for 'lxc.cgroup", then all cgroup entries will be printed, in
3902 * 'lxc.cgroup.subsystem.key = value' format.
b863bf92 3903 */
54860ed0
CB
3904static int __get_config_cgroup_controller(const char *key, char *retv,
3905 int inlen, struct lxc_conf *c,
3906 int version)
b863bf92 3907{
c9dbb8ed
CB
3908 int fulllen = 0;
3909 bool get_all = false;
b863bf92 3910 int len;
54860ed0
CB
3911 size_t namespaced_token_len;
3912 char *global_token, *namespaced_token;
c9dbb8ed
CB
3913 struct list_head *list;
3914 struct lxc_cgroup *cgroup;
b863bf92
CB
3915
3916 if (!retv)
3917 inlen = 0;
3918 else
3919 memset(retv, 0, inlen);
3920
54860ed0
CB
3921 if (version == CGROUP2_SUPER_MAGIC) {
3922 global_token = "lxc.cgroup2";
3923 namespaced_token = "lxc.cgroup2.";
6333c915 3924 namespaced_token_len = STRLITERALLEN("lxc.cgroup2.");
c9dbb8ed 3925 list = &c->cgroup2;
54860ed0
CB
3926 } else if (version == CGROUP_SUPER_MAGIC) {
3927 global_token = "lxc.cgroup";
3928 namespaced_token = "lxc.cgroup.";
6333c915 3929 namespaced_token_len = STRLITERALLEN("lxc.cgroup.");
c9dbb8ed 3930 list = &c->cgroup;
54860ed0 3931 } else {
78205814 3932 return ret_errno(EINVAL);
54860ed0
CB
3933 }
3934
d62177e9 3935 if (strequal(key, global_token))
b863bf92 3936 get_all = true;
1af3044f 3937 else if (strnequal(key, namespaced_token, namespaced_token_len))
54860ed0 3938 key += namespaced_token_len;
b863bf92 3939 else
78205814 3940 return ret_errno(EINVAL);
b863bf92 3941
c9dbb8ed 3942 list_for_each_entry(cgroup, list, head) {
b863bf92 3943 if (get_all) {
c9dbb8ed 3944 if (version != cgroup->version)
54860ed0
CB
3945 continue;
3946
47903908 3947 strprint(retv, inlen, "%s.%s = %s\n", global_token,
c9dbb8ed
CB
3948 cgroup->subsystem, cgroup->value);
3949 } else if (strequal(cgroup->subsystem, key)) {
3950 strprint(retv, inlen, "%s\n", cgroup->value);
b863bf92
CB
3951 }
3952 }
3953
3954 return fulllen;
3955}
5014ff2e 3956
54860ed0
CB
3957static int get_config_cgroup_controller(const char *key, char *retv, int inlen,
3958 struct lxc_conf *c, void *data)
3959{
3960 return __get_config_cgroup_controller(key, retv, inlen, c,
3961 CGROUP_SUPER_MAGIC);
3962}
3963
3964static int get_config_cgroup2_controller(const char *key, char *retv, int inlen,
3965 struct lxc_conf *c, void *data)
3966{
3967 return __get_config_cgroup_controller(key, retv, inlen, c,
3968 CGROUP2_SUPER_MAGIC);
3969}
3970
43654d34
CB
3971static int get_config_cgroup_dir(const char *key, char *retv, int inlen,
3972 struct lxc_conf *lxc_conf, void *data)
3973{
3974 int len;
3975 int fulllen = 0;
3976
d62177e9 3977 if (!strequal(key, "lxc.cgroup.dir"))
c583072d
CB
3978 return ret_errno(EINVAL);
3979
43654d34
CB
3980 if (!retv)
3981 inlen = 0;
3982 else
3983 memset(retv, 0, inlen);
3984
3985 strprint(retv, inlen, "%s", lxc_conf->cgroup_meta.dir);
3986
3987 return fulllen;
3988}
3989
a900cbaf
WB
3990static int get_config_cgroup_monitor_dir(const char *key, char *retv, int inlen,
3991 struct lxc_conf *lxc_conf, void *data)
3992{
3993 int len;
3994 int fulllen = 0;
3995
3996 if (!retv)
3997 inlen = 0;
3998 else
3999 memset(retv, 0, inlen);
4000
4001 strprint(retv, inlen, "%s", lxc_conf->cgroup_meta.monitor_dir);
4002
4003 return fulllen;
4004}
4005
7696c1f9
RJ
4006static int get_config_cgroup_monitor_pivot_dir(const char *key, char *retv, int inlen,
4007 struct lxc_conf *lxc_conf, void *data)
4008{
4009 int len;
4010 int fulllen = 0;
4011
4012 if (!retv)
4013 inlen = 0;
4014 else
4015 memset(retv, 0, inlen);
4016
4017 strprint(retv, inlen, "%s", lxc_conf->cgroup_meta.monitor_pivot_dir);
4018
4019 return fulllen;
4020}
4021
a900cbaf
WB
4022static int get_config_cgroup_container_dir(const char *key, char *retv,
4023 int inlen,
4024 struct lxc_conf *lxc_conf,
4025 void *data)
4026{
4027 int len;
4028 int fulllen = 0;
4029
4030 if (!retv)
4031 inlen = 0;
4032 else
4033 memset(retv, 0, inlen);
4034
4035 strprint(retv, inlen, "%s", lxc_conf->cgroup_meta.container_dir);
4036
4037 return fulllen;
4038}
4039
4040static int get_config_cgroup_container_inner_dir(const char *key, char *retv,
4041 int inlen,
4042 struct lxc_conf *lxc_conf,
4043 void *data)
4044{
4045 int len;
4046 int fulllen = 0;
4047
4048 if (!retv)
4049 inlen = 0;
4050 else
4051 memset(retv, 0, inlen);
4052
4053 strprint(retv, inlen, "%s", lxc_conf->cgroup_meta.namespace_dir);
4054
4055 return fulllen;
4056}
4057
9caee129
CB
4058static inline int get_config_cgroup_relative(const char *key, char *retv,
4059 int inlen, struct lxc_conf *lxc_conf,
4060 void *data)
76f0e2e7
CB
4061{
4062 return lxc_get_conf_int(lxc_conf, retv, inlen,
9caee129 4063 lxc_conf->cgroup_meta.relative);
76f0e2e7
CB
4064}
4065
6bede808 4066static int get_config_idmaps(const char *key, char *retv, int inlen,
cccd2219 4067 struct lxc_conf *c, void *data)
5014ff2e 4068{
0589d744 4069 struct id_map *map;
5014ff2e
CB
4070 int len, listlen, ret;
4071 int fulllen = 0;
4072/* "u 1000 1000000 65536"
4073 *
4074 * let's render this as
4075 *
4076 * sizeof(char)
4077 * +
4078 * sizeof(" ")
4079 * +
c77aee64 4080 * sizeof(uint32_t)
5014ff2e
CB
4081 * +
4082 * sizeof(" ")
4083 * +
c77aee64 4084 * sizeof(uint32_t)
5014ff2e
CB
4085 * +
4086 * sizeof(" ")
4087 * +
c77aee64 4088 * sizeof(uint32_t)
5014ff2e
CB
4089 * +
4090 * \0
4091 */
c77aee64 4092#define __LXC_IDMAP_STR_BUF (3 * INTTYPE_TO_STRLEN(uint32_t) + 3 + 1 + 1)
5014ff2e
CB
4093 char buf[__LXC_IDMAP_STR_BUF];
4094
4095 if (!retv)
4096 inlen = 0;
4097 else
4098 memset(retv, 0, inlen);
4099
d696c45e 4100 listlen = list_len(map, &c->id_map, head);
0589d744 4101 list_for_each_entry(map, &c->id_map, head) {
3948c252
CB
4102 ret = strnprintf(buf, sizeof(buf), "%c %lu %lu %lu",
4103 (map->idtype == ID_TYPE_UID) ? 'u' : 'g',
4104 map->nsid, map->hostid, map->range);
4105 if (ret < 0)
2e5db3a2 4106 return ret_errno(EIO);
5014ff2e
CB
4107
4108 strprint(retv, inlen, "%s%s", buf, (listlen-- > 1) ? "\n" : "");
4109 }
47903908 4110
5014ff2e
CB
4111 return fulllen;
4112}
b29b29be 4113
46cc906d 4114static int get_config_log_level(const char *key, char *retv, int inlen,
cccd2219 4115 struct lxc_conf *c, void *data)
b29b29be
CB
4116{
4117 const char *v;
6bede808 4118 v = lxc_log_priority_to_string(c->loglevel);
b29b29be
CB
4119 return lxc_get_conf_str(retv, inlen, v);
4120}
3d4630ab 4121
46cc906d 4122static int get_config_log_file(const char *key, char *retv, int inlen,
cccd2219 4123 struct lxc_conf *c, void *data)
3d4630ab 4124{
6bede808 4125 return lxc_get_conf_str(retv, inlen, c->logfile);
3d4630ab 4126}
0d601acb 4127
47148e96
CB
4128static int get_config_mount_fstab(const char *key, char *retv, int inlen,
4129 struct lxc_conf *c, void *data)
0d601acb 4130{
6bede808 4131 return lxc_get_conf_str(retv, inlen, c->fstab);
0d601acb 4132}
43fbf8d9 4133
6bede808 4134static int get_config_mount_auto(const char *key, char *retv, int inlen,
cccd2219 4135 struct lxc_conf *c, void *data)
43fbf8d9
CB
4136{
4137 int len, fulllen = 0;
4138 const char *sep = "";
4139
4140 if (!retv)
4141 inlen = 0;
4142 else
4143 memset(retv, 0, inlen);
4144
6bede808 4145 if (!(c->auto_mounts & LXC_AUTO_ALL_MASK))
43fbf8d9
CB
4146 return 0;
4147
6bede808 4148 switch (c->auto_mounts & LXC_AUTO_PROC_MASK) {
43fbf8d9
CB
4149 case LXC_AUTO_PROC_MIXED:
4150 strprint(retv, inlen, "%sproc:mixed", sep);
4151 sep = " ";
4152 break;
4153 case LXC_AUTO_PROC_RW:
4154 strprint(retv, inlen, "%sproc:rw", sep);
4155 sep = " ";
4156 break;
4157 default:
4158 break;
4159 }
4160
6bede808 4161 switch (c->auto_mounts & LXC_AUTO_SYS_MASK) {
43fbf8d9
CB
4162 case LXC_AUTO_SYS_RO:
4163 strprint(retv, inlen, "%ssys:ro", sep);
4164 sep = " ";
4165 break;
4166 case LXC_AUTO_SYS_RW:
4167 strprint(retv, inlen, "%ssys:rw", sep);
4168 sep = " ";
4169 break;
4170 case LXC_AUTO_SYS_MIXED:
4171 strprint(retv, inlen, "%ssys:mixed", sep);
4172 sep = " ";
4173 break;
4174 default:
4175 break;
4176 }
4177
6bede808 4178 switch (c->auto_mounts & LXC_AUTO_CGROUP_MASK) {
43fbf8d9
CB
4179 case LXC_AUTO_CGROUP_NOSPEC:
4180 strprint(retv, inlen, "%scgroup", sep);
43fbf8d9
CB
4181 break;
4182 case LXC_AUTO_CGROUP_MIXED:
4183 strprint(retv, inlen, "%scgroup:mixed", sep);
43fbf8d9
CB
4184 break;
4185 case LXC_AUTO_CGROUP_RO:
4186 strprint(retv, inlen, "%scgroup:ro", sep);
43fbf8d9
CB
4187 break;
4188 case LXC_AUTO_CGROUP_RW:
4189 strprint(retv, inlen, "%scgroup:rw", sep);
43fbf8d9
CB
4190 break;
4191 case LXC_AUTO_CGROUP_FULL_NOSPEC:
4192 strprint(retv, inlen, "%scgroup-full", sep);
43fbf8d9
CB
4193 break;
4194 case LXC_AUTO_CGROUP_FULL_MIXED:
4195 strprint(retv, inlen, "%scgroup-full:mixed", sep);
43fbf8d9
CB
4196 break;
4197 case LXC_AUTO_CGROUP_FULL_RO:
4198 strprint(retv, inlen, "%scgroup-full:ro", sep);
43fbf8d9
CB
4199 break;
4200 case LXC_AUTO_CGROUP_FULL_RW:
4201 strprint(retv, inlen, "%scgroup-full:rw", sep);
43fbf8d9
CB
4202 break;
4203 default:
4204 break;
4205 }
4206
4207 return fulllen;
4208}
cc921848 4209
6bede808 4210static int get_config_mount(const char *key, char *retv, int inlen,
cccd2219 4211 struct lxc_conf *c, void *data)
cc921848
CB
4212{
4213 int len, fulllen = 0;
be0bc4d1 4214 struct string_entry *entry;
cc921848
CB
4215
4216 if (!retv)
4217 inlen = 0;
4218 else
4219 memset(retv, 0, inlen);
4220
be0bc4d1
CB
4221 list_for_each_entry(entry, &c->mount_entries, head) {
4222 strprint(retv, inlen, "%s\n", entry->val);
cc921848
CB
4223 }
4224
4225 return fulllen;
4226}
819114b6 4227
7a96a068
CB
4228static int get_config_rootfs_path(const char *key, char *retv, int inlen,
4229 struct lxc_conf *c, void *data)
819114b6 4230{
6bede808 4231 return lxc_get_conf_str(retv, inlen, c->rootfs.path);
819114b6 4232}
3af60359 4233
6e54330c
CB
4234static int get_config_rootfs_managed(const char *key, char *retv, int inlen,
4235 struct lxc_conf *c, void *data)
4236{
4237 return lxc_get_conf_bool(c, retv, inlen, c->rootfs.managed);
4238}
4239
6bede808 4240static int get_config_rootfs_mount(const char *key, char *retv, int inlen,
cccd2219 4241 struct lxc_conf *c, void *data)
3af60359 4242{
6bede808 4243 return lxc_get_conf_str(retv, inlen, c->rootfs.mount);
3af60359 4244}
0e9db631 4245
6bede808 4246static int get_config_rootfs_options(const char *key, char *retv, int inlen,
cccd2219 4247 struct lxc_conf *c, void *data)
0e9db631 4248{
e73af35b 4249 return lxc_get_conf_str(retv, inlen, c->rootfs.mnt_opts.raw_options);
0e9db631 4250}
8f183f38 4251
b67771bc 4252static int get_config_uts_name(const char *key, char *retv, int inlen,
cccd2219 4253 struct lxc_conf *c, void *data)
e274f8b0
CB
4254{
4255 return lxc_get_conf_str(
4256 retv, inlen,
6bede808 4257 c->utsname ? c->utsname->nodename : NULL);
e274f8b0 4258}
466c2e93 4259
6bede808 4260static int get_config_hooks(const char *key, char *retv, int inlen,
cccd2219 4261 struct lxc_conf *c, void *data)
466c2e93
CB
4262{
4263 char *subkey;
4264 int len, fulllen = 0, found = -1;
5090de3e 4265 struct string_entry *entry;
466c2e93
CB
4266 int i;
4267
466c2e93 4268 subkey = strchr(key, '.');
466c2e93 4269 if (!subkey)
5a848c4b 4270 return ret_errno(EINVAL);
47903908 4271
4272 subkey = strchr(subkey + 1, '.');
637d38f2 4273 if (!subkey)
5a848c4b 4274 return ret_errno(EINVAL);
466c2e93 4275 subkey++;
637d38f2 4276 if (*subkey == '\0')
5a848c4b 4277 return ret_errno(EINVAL);
47903908 4278
466c2e93 4279 for (i = 0; i < NUM_LXC_HOOKS; i++) {
d62177e9 4280 if (strequal(lxchook_names[i], subkey)) {
466c2e93
CB
4281 found = i;
4282 break;
4283 }
4284 }
47903908 4285
466c2e93 4286 if (found == -1)
5a848c4b 4287 return ret_errno(EINVAL);
466c2e93
CB
4288
4289 if (!retv)
4290 inlen = 0;
4291 else
4292 memset(retv, 0, inlen);
4293
5090de3e
CB
4294 list_for_each_entry(entry, &c->hooks[found], head) {
4295 strprint(retv, inlen, "%s\n", entry->val);
466c2e93 4296 }
47903908 4297
466c2e93
CB
4298 return fulllen;
4299}
d2ceff53 4300
44ae0fb6
CB
4301static int get_config_hooks_version(const char *key, char *retv, int inlen,
4302 struct lxc_conf *c, void *data)
4303{
4304 return lxc_get_conf_int(c, retv, inlen, c->hooks_version);
4305}
4306
f9373e40
CB
4307static int get_config_net(const char *key, char *retv, int inlen,
4308 struct lxc_conf *c, void *data)
d2ceff53
CB
4309{
4310 int len, fulllen = 0;
87d0990c 4311 struct lxc_netdev *netdev;
d2ceff53
CB
4312
4313 if (!retv)
4314 inlen = 0;
4315 else
4316 memset(retv, 0, inlen);
4317
87d0990c
CB
4318 list_for_each_entry(netdev, &c->netdevs, head) {
4319 const char *t = lxc_net_type_to_str(netdev->type);
d2ceff53
CB
4320 strprint(retv, inlen, "%s\n", t ? t : "(invalid)");
4321 }
4322
4323 return fulllen;
4324}
bdccff60 4325
6bede808 4326static int get_config_cap_drop(const char *key, char *retv, int inlen,
cccd2219 4327 struct lxc_conf *c, void *data)
1c96d6d8
CB
4328{
4329 int len, fulllen = 0;
20ab7578 4330 struct cap_entry *cap;
1c96d6d8
CB
4331
4332 if (!retv)
4333 inlen = 0;
4334 else
4335 memset(retv, 0, inlen);
4336
20ab7578
CB
4337 list_for_each_entry(cap, &c->caps.list, head) {
4338 strprint(retv, inlen, "%s\n", cap->cap_name);
b80927f2 4339 }
25a908b8 4340
b80927f2
CB
4341 return fulllen;
4342}
4343
6bede808 4344static int get_config_cap_keep(const char *key, char *retv, int inlen,
cccd2219 4345 struct lxc_conf *c, void *data)
b80927f2
CB
4346{
4347 int len, fulllen = 0;
20ab7578 4348 struct cap_entry *cap;
b80927f2
CB
4349
4350 if (!retv)
4351 inlen = 0;
4352 else
4353 memset(retv, 0, inlen);
4354
20ab7578
CB
4355 list_for_each_entry(cap, &c->caps.list, head) {
4356 strprint(retv, inlen, "%s\n", cap->cap_name);
1c96d6d8 4357 }
25a908b8 4358
1c96d6d8
CB
4359 return fulllen;
4360}
0692663a 4361
3aed4934
CB
4362static int get_config_console_path(const char *key, char *retv, int inlen,
4363 struct lxc_conf *c, void *data)
0692663a 4364{
6bede808 4365 return lxc_get_conf_str(retv, inlen, c->console.path);
0692663a 4366}
794d1c06 4367
6bede808 4368static int get_config_console_logfile(const char *key, char *retv, int inlen,
cccd2219 4369 struct lxc_conf *c, void *data)
794d1c06 4370{
6bede808 4371 return lxc_get_conf_str(retv, inlen, c->console.log_path);
794d1c06 4372}
75f55b1f 4373
d91adfa6
CB
4374static int get_config_console_rotate(const char *key, char *retv, int inlen,
4375 struct lxc_conf *c, void *data)
4376{
4377 return lxc_get_conf_int(c, retv, inlen, c->console.log_rotate);
4378}
4379
4380
28f3b1cd
CB
4381static int get_config_console_buffer_size(const char *key, char *retv,
4382 int inlen, struct lxc_conf *c,
4383 void *data)
a04220de 4384{
dcea90a0 4385 return lxc_get_conf_uint64(c, retv, inlen, c->console.buffer_size);
a04220de
CB
4386}
4387
861813e5
CB
4388static int get_config_console_size(const char *key, char *retv, int inlen,
4389 struct lxc_conf *c, void *data)
4390{
4391 return lxc_get_conf_uint64(c, retv, inlen, c->console.log_size);
4392}
4393
50d86993
CB
4394static int get_config_seccomp_allow_nesting(const char *key, char *retv,
4395 int inlen, struct lxc_conf *c,
4396 void *data)
4397{
6ae86a9c 4398#if HAVE_SECCOMP
c3e3c21a
CB
4399 return lxc_get_conf_int(c, retv, inlen, c->seccomp.allow_nesting);
4400#else
254b5bdd 4401 return ret_errno(ENOSYS);
c3e3c21a 4402#endif
50d86993 4403}
861813e5 4404
84cf6d25
WB
4405static int get_config_seccomp_notify_cookie(const char *key, char *retv, int inlen,
4406 struct lxc_conf *c, void *data)
4407{
331ef062 4408#if HAVE_DECL_SECCOMP_NOTIFY_FD
84cf6d25
WB
4409 return lxc_get_conf_str(retv, inlen, c->seccomp.notifier.cookie);
4410#else
6d38035e 4411 return ret_errno(ENOSYS);
84cf6d25
WB
4412#endif
4413}
4414
86ce1da1
CB
4415static int get_config_seccomp_notify_proxy(const char *key, char *retv, int inlen,
4416 struct lxc_conf *c, void *data)
4417{
331ef062 4418#if HAVE_DECL_SECCOMP_NOTIFY_FD
86ce1da1 4419 return lxc_get_conf_str(retv, inlen,
c3e3c21a
CB
4420 (c->seccomp.notifier.proxy_addr.sun_path[0]) == '/'
4421 ? &c->seccomp.notifier.proxy_addr.sun_path[0]
4422 : &c->seccomp.notifier.proxy_addr.sun_path[1]);
86ce1da1 4423#else
010d7deb 4424 return ret_errno(ENOSYS);
86ce1da1
CB
4425#endif
4426}
4427
0b427da0
CB
4428static int get_config_seccomp_profile(const char *key, char *retv, int inlen,
4429 struct lxc_conf *c, void *data)
75f55b1f 4430{
6ae86a9c 4431#if HAVE_SECCOMP
c3e3c21a 4432 return lxc_get_conf_str(retv, inlen, c->seccomp.seccomp);
3d46e1d1
MB
4433#else
4434 return ret_errno(ENOSYS);
4435#endif
75f55b1f 4436}
97f6dad0 4437
6bede808 4438static int get_config_autodev(const char *key, char *retv, int inlen,
cccd2219 4439 struct lxc_conf *c, void *data)
97f6dad0 4440{
6bede808 4441 return lxc_get_conf_int(c, retv, inlen, c->autodev);
97f6dad0 4442}
afee4324 4443
63012bdd
CK
4444static int get_config_autodev_tmpfs_size(const char *key, char *retv, int inlen,
4445 struct lxc_conf *c, void *data)
4446{
4447 return lxc_get_conf_int(c, retv, inlen, c->autodevtmpfssize);
4448}
4449
55c84efc 4450static int get_config_signal_halt(const char *key, char *retv, int inlen,
25a908b8 4451 struct lxc_conf *c, void *data)
afee4324 4452{
6bede808 4453 return lxc_get_conf_int(c, retv, inlen, c->haltsignal);
afee4324 4454}
3aa8f359 4455
55c84efc 4456static int get_config_signal_reboot(const char *key, char *retv, int inlen,
25a908b8 4457 struct lxc_conf *c, void *data)
3aa8f359 4458{
6bede808 4459 return lxc_get_conf_int(c, retv, inlen, c->rebootsignal);
3aa8f359 4460}
2e16269f 4461
55c84efc 4462static int get_config_signal_stop(const char *key, char *retv, int inlen,
25a908b8 4463 struct lxc_conf *c, void *data)
2e16269f 4464{
6bede808 4465 return lxc_get_conf_int(c, retv, inlen, c->stopsignal);
2e16269f 4466}
54345299 4467
6bede808 4468static int get_config_start(const char *key, char *retv, int inlen,
cccd2219 4469 struct lxc_conf *c, void *data)
54345299 4470{
d62177e9 4471 if (strequal(key + 10, "auto"))
6bede808 4472 return lxc_get_conf_int(c, retv, inlen, c->start_auto);
d62177e9 4473 else if (strequal(key + 10, "delay"))
6bede808 4474 return lxc_get_conf_int(c, retv, inlen, c->start_delay);
d62177e9 4475 else if (strequal(key + 10, "order"))
6bede808 4476 return lxc_get_conf_int(c, retv, inlen, c->start_order);
54345299 4477
b28be01f 4478 return ret_errno(EINVAL);
54345299 4479}
de9df15e 4480
46cc906d 4481static int get_config_log_syslog(const char *key, char *retv, int inlen,
25a908b8 4482 struct lxc_conf *c, void *data)
de9df15e 4483{
6bede808 4484 return lxc_get_conf_str(retv, inlen, c->syslog);
de9df15e 4485}
ac0f949c 4486
6bede808 4487static int get_config_monitor(const char *key, char *retv, int inlen,
cccd2219 4488 struct lxc_conf *c, void *data)
ac0f949c 4489{
6bede808 4490 return lxc_get_conf_int(c, retv, inlen, c->monitor_unshare);
ac0f949c 4491}
90ec7b6e 4492
258f8051
CB
4493static int get_config_monitor_signal_pdeath(const char *key, char *retv,
4494 int inlen, struct lxc_conf *c,
4495 void *data)
4496{
4497 return lxc_get_conf_int(c, retv, inlen, c->monitor_signal_pdeath);
4498}
4499
6bede808 4500static int get_config_group(const char *key, char *retv, int inlen,
cccd2219 4501 struct lxc_conf *c, void *data)
90ec7b6e
CB
4502{
4503 int len, fulllen = 0;
ffb2a35f 4504 struct string_entry *entry;
90ec7b6e
CB
4505
4506 if (!retv)
4507 inlen = 0;
4508 else
4509 memset(retv, 0, inlen);
4510
ffb2a35f
CB
4511 list_for_each_entry(entry, &c->groups, head) {
4512 strprint(retv, inlen, "%s\n", entry->val);
90ec7b6e 4513 }
25a908b8 4514
90ec7b6e
CB
4515 return fulllen;
4516}
aa0db7d3 4517
6bede808 4518static int get_config_environment(const char *key, char *retv, int inlen,
cccd2219 4519 struct lxc_conf *c, void *data)
aa0db7d3
CB
4520{
4521 int len, fulllen = 0;
c294a68d 4522 struct environment_entry *env;
aa0db7d3
CB
4523
4524 if (!retv)
4525 inlen = 0;
4526 else
4527 memset(retv, 0, inlen);
4528
c294a68d
CB
4529 list_for_each_entry(env, &c->environment, head) {
4530 strprint(retv, inlen, "%s=%s\n", env->key, env->val);
aa0db7d3 4531 }
25a908b8 4532
aa0db7d3
CB
4533 return fulllen;
4534}
96dfcb7d 4535
5cda27c1
SH
4536static int get_config_execute_cmd(const char *key, char *retv, int inlen,
4537 struct lxc_conf *c, void *data)
4538{
4539 return lxc_get_conf_str(retv, inlen, c->execute_cmd);
4540}
4541
6bede808 4542static int get_config_init_cmd(const char *key, char *retv, int inlen,
cccd2219 4543 struct lxc_conf *c, void *data)
96dfcb7d 4544{
6bede808 4545 return lxc_get_conf_str(retv, inlen, c->init_cmd);
96dfcb7d 4546}
1398e9b1 4547
3c491553
L
4548static int get_config_init_cwd(const char *key, char *retv, int inlen,
4549 struct lxc_conf *c, void *data)
4550{
4551 return lxc_get_conf_str(retv, inlen, c->init_cwd);
4552}
4553
6bede808 4554static int get_config_init_uid(const char *key, char *retv, int inlen,
cccd2219 4555 struct lxc_conf *c, void *data)
1398e9b1 4556{
6bede808 4557 return lxc_get_conf_int(c, retv, inlen, c->init_uid);
1398e9b1 4558}
dfeb7e42 4559
6bede808 4560static int get_config_init_gid(const char *key, char *retv, int inlen,
cccd2219 4561 struct lxc_conf *c, void *data)
dfeb7e42 4562{
6bede808 4563 return lxc_get_conf_int(c, retv, inlen, c->init_gid);
dfeb7e42 4564}
62048afe 4565
bf31b337
RJ
4566static int get_config_init_groups(const char *key, char *retv, int inlen,
4567 struct lxc_conf *c, void *data)
4568{
4569 int fulllen = 0, len;
4570
4571 if (!retv)
4572 inlen = 0;
4573 else
4574 memset(retv, 0, inlen);
4575
4576 if (c->init_groups.size == 0)
4577 return 0;
4578
15b9e2b0 4579 for (size_t i = 0; i < c->init_groups.size; i++)
bf31b337
RJ
4580 strprint(retv, inlen, "%s%d", (i > 0) ? "," : "",
4581 c->init_groups.list[i]);
4582
4583 return fulllen;
4584}
4585
6bede808 4586static int get_config_ephemeral(const char *key, char *retv, int inlen,
cccd2219 4587 struct lxc_conf *c, void *data)
62048afe 4588{
6bede808 4589 return lxc_get_conf_int(c, retv, inlen, c->ephemeral);
62048afe 4590}
b09521ac 4591
6bede808 4592static int get_config_no_new_privs(const char *key, char *retv, int inlen,
cccd2219 4593 struct lxc_conf *c, void *data)
b09521ac 4594{
6bede808 4595 return lxc_get_conf_int(c, retv, inlen, c->no_new_privs);
b09521ac 4596}
389f6466 4597
25a908b8 4598/* If you ask for a specific value, i.e. lxc.prlimit.nofile, then just the value
240d4b74 4599 * will be printed. If you ask for 'lxc.prlimit', then all limit entries will be
4600 * printed, in 'lxc.prlimit.resource = value' format.
389f6466 4601 */
240d4b74 4602static int get_config_prlimit(const char *key, char *retv, int inlen,
47903908 4603 struct lxc_conf *c, void *data)
389f6466
CB
4604{
4605 int fulllen = 0, len;
4606 bool get_all = false;
223797c3 4607 struct lxc_limit *lim;
389f6466
CB
4608
4609 if (!retv)
4610 inlen = 0;
4611 else
4612 memset(retv, 0, inlen);
4613
d62177e9 4614 if (strequal(key, "lxc.prlimit"))
389f6466 4615 get_all = true;
1af3044f 4616 else if (strnequal(key, "lxc.prlimit.", 12))
240d4b74 4617 key += 12;
389f6466 4618 else
4c12267e 4619 return ret_errno(EINVAL);
389f6466 4620
223797c3 4621 list_for_each_entry(lim, &c->limits, head) {
c77aee64
CB
4622 /* 2 colon separated 64 bit integers or the word 'unlimited' */
4623 char buf[INTTYPE_TO_STRLEN(uint64_t) * 2 + 2];
389f6466 4624 int partlen;
389f6466
CB
4625
4626 if (lim->limit.rlim_cur == RLIM_INFINITY) {
6333c915
CB
4627 memcpy(buf, "unlimited", STRLITERALLEN("unlimited") + 1);
4628 partlen = STRLITERALLEN("unlimited");
389f6466
CB
4629 } else {
4630 partlen = sprintf(buf, "%" PRIu64,
4631 (uint64_t)lim->limit.rlim_cur);
4632 }
47903908 4633
389f6466 4634 if (lim->limit.rlim_cur != lim->limit.rlim_max) {
25a908b8 4635 if (lim->limit.rlim_max == RLIM_INFINITY)
389f6466 4636 memcpy(buf + partlen, ":unlimited",
6333c915 4637 STRLITERALLEN(":unlimited") + 1);
25a908b8 4638 else
389f6466
CB
4639 sprintf(buf + partlen, ":%" PRIu64,
4640 (uint64_t)lim->limit.rlim_max);
389f6466
CB
4641 }
4642
4643 if (get_all) {
240d4b74 4644 strprint(retv, inlen, "lxc.prlimit.%s = %s\n",
389f6466 4645 lim->resource, buf);
d62177e9 4646 } else if (strequal(lim->resource, key)) {
389f6466
CB
4647 strprint(retv, inlen, "%s", buf);
4648 }
4649 }
4650
4651 return fulllen;
4652}
e08cb901 4653
e409b214
CB
4654/* If you ask for a specific value, i.e. lxc.sysctl.net.ipv4.ip_forward, then
4655 * just the value will be printed. If you ask for 'lxc.sysctl', then all sysctl
4656 * entries will be printed, in 'lxc.sysctl.key = value' format.
7edd0540
L
4657 */
4658static int get_config_sysctl(const char *key, char *retv, int inlen,
47903908 4659 struct lxc_conf *c, void *data)
7edd0540 4660{
7edd0540
L
4661 int fulllen = 0;
4662 bool get_all = false;
ba9f9347
CB
4663 int len;
4664 struct lxc_sysctl *sysctl;
7edd0540
L
4665
4666 if (!retv)
4667 inlen = 0;
4668 else
4669 memset(retv, 0, inlen);
4670
d62177e9 4671 if (strequal(key, "lxc.sysctl"))
7edd0540 4672 get_all = true;
1af3044f 4673 else if (strnequal(key, "lxc.sysctl.", STRLITERALLEN("lxc.sysctl.")))
6333c915 4674 key += STRLITERALLEN("lxc.sysctl.");
7edd0540 4675 else
4b1ef6aa 4676 return ret_errno(EINVAL);
7edd0540 4677
ba9f9347 4678 list_for_each_entry(sysctl, &c->sysctls, head) {
7edd0540 4679 if (get_all) {
ba9f9347
CB
4680 strprint(retv, inlen, "lxc.sysctl.%s = %s\n", sysctl->key,
4681 sysctl->value);
4682 } else if (strequal(sysctl->key, key)) {
4683 strprint(retv, inlen, "%s", sysctl->value);
7edd0540
L
4684 }
4685 }
4686
4687 return fulllen;
4688}
4689
61d7a733 4690static int get_config_proc(const char *key, char *retv, int inlen,
47903908 4691 struct lxc_conf *c, void *data)
61d7a733 4692{
61d7a733
YT
4693 int fulllen = 0;
4694 bool get_all = false;
91d04bf9
CB
4695 int len;
4696 struct lxc_proc *proc;
61d7a733
YT
4697
4698 if (!retv)
4699 inlen = 0;
4700 else
4701 memset(retv, 0, inlen);
4702
d62177e9 4703 if (strequal(key, "lxc.proc"))
61d7a733 4704 get_all = true;
1af3044f 4705 else if (strnequal(key, "lxc.proc.", STRLITERALLEN("lxc.proc.")))
6333c915 4706 key += STRLITERALLEN("lxc.proc.");
61d7a733 4707 else
5ab1dbcf 4708 return ret_errno(EINVAL);
61d7a733 4709
91d04bf9 4710 list_for_each_entry(proc, &c->procs, head) {
61d7a733
YT
4711 if (get_all) {
4712 strprint(retv, inlen, "lxc.proc.%s = %s\n",
47903908 4713 proc->filename, proc->value);
d62177e9 4714 } else if (strequal(proc->filename, key)) {
61d7a733
YT
4715 strprint(retv, inlen, "%s", proc->value);
4716 }
4717 }
4718
4719 return fulllen;
4720}
4721
1d8d3676
CB
4722static int get_config_namespace_clone(const char *key, char *retv, int inlen,
4723 struct lxc_conf *c, void *data)
4724{
4725 int i, len;
4726 int fulllen = 0;
4727
4728 if (!retv)
4729 inlen = 0;
4730 else
4731 memset(retv, 0, inlen);
4732
4733 for (i = 0; i < LXC_NS_MAX; i++) {
4734 if (c->ns_clone & ns_info[i].clone_flag)
4735 strprint(retv, inlen, "%s\n", ns_info[i].proc_name);
4736 }
4737
4738 return fulllen;
4739}
4740
abeb5bba
CB
4741static int get_config_namespace_keep(const char *key, char *retv, int inlen,
4742 struct lxc_conf *c, void *data)
4743{
4744 int i, len;
4745 int fulllen = 0;
4746
4747 if (!retv)
4748 inlen = 0;
4749 else
4750 memset(retv, 0, inlen);
4751
4752 for (i = 0; i < LXC_NS_MAX; i++) {
4753 if (c->ns_keep & ns_info[i].clone_flag)
4754 strprint(retv, inlen, "%s\n", ns_info[i].proc_name);
4755 }
4756
4757 return fulllen;
4758}
4759
70fd7fc9
CB
4760static int get_config_time_offset_boot(const char *key, char *retv, int inlen, struct lxc_conf *c,
4761 void *data)
4762{
4763 int len;
4764 int fulllen = 0;
4765
4766 if (!retv)
4767 inlen = 0;
4768 else
4769 memset(retv, 0, inlen);
4770
4771 if (c->timens.s_boot) {
4772 strprint(retv, inlen, "%" PRId64 " s\n", c->timens.s_boot);
4773 } else {
4774 strprint(retv, inlen, "%" PRId64 " ns\n", c->timens.ns_boot);
4775 }
4776
4777 return fulllen;
4778}
4779
4780static int get_config_time_offset_monotonic(const char *key, char *retv, int inlen,
4781 struct lxc_conf *c, void *data)
4782{
4783 int len;
4784 int fulllen = 0;
4785
4786 if (!retv)
4787 inlen = 0;
4788 else
4789 memset(retv, 0, inlen);
4790
4791 if (c->timens.s_monotonic) {
4792 strprint(retv, inlen, "%" PRId64 "s\n", c->timens.s_monotonic);
4793 } else {
4794 strprint(retv, inlen, "%" PRId64 "ns\n", c->timens.ns_monotonic);
4795 }
4796
4797 return fulllen;
4798}
4799
b074bbf1
CB
4800static int get_config_namespace_share(const char *key, char *retv, int inlen,
4801 struct lxc_conf *c, void *data)
28d9e29e
CB
4802{
4803 int len, ns_idx;
4804 const char *namespace;
4805 int fulllen = 0;
4806
4807 if (!retv)
4808 inlen = 0;
4809 else
4810 memset(retv, 0, inlen);
4811
6333c915 4812 namespace = key + STRLITERALLEN("lxc.namespace.share.");
057d2cae
CB
4813 if (is_empty_string(namespace))
4814 return ret_errno(EINVAL);
4815
28d9e29e
CB
4816 ns_idx = lxc_namespace_2_ns_idx(namespace);
4817 if (ns_idx < 0)
4818 return ns_idx;
4819
b074bbf1 4820 strprint(retv, inlen, "%s", c->ns_share[ns_idx]);
28d9e29e
CB
4821
4822 return fulllen;
4823}
4824
e08cb901 4825/* Callbacks to clear config items. */
26471403
CB
4826static inline int clr_config_personality(const char *key, struct lxc_conf *c,
4827 void *data)
e08cb901
CB
4828{
4829 c->personality = -1;
4830 return 0;
4831}
03818ae3 4832
232763d6
CB
4833static inline int clr_config_pty_max(const char *key, struct lxc_conf *c,
4834 void *data)
03818ae3 4835{
e528c735 4836 c->pty_max = 0;
03818ae3
CB
4837 return 0;
4838}
e7a4b096 4839
fe1c5887
CB
4840static inline int clr_config_tty_max(const char *key, struct lxc_conf *c,
4841 void *data)
e7a4b096 4842{
885766f5 4843 c->ttys.tty = 0;
e7a4b096
CB
4844 return 0;
4845}
eaf8c0c7 4846
42e53c29 4847static inline int clr_config_tty_dir(const char *key, struct lxc_conf *c,
26471403 4848 void *data)
eaf8c0c7 4849{
faf3d0ae 4850 free_disarm(c->ttys.dir);
eaf8c0c7
CB
4851 return 0;
4852}
6bd86308 4853
953fe44f
CB
4854static inline int clr_config_apparmor_profile(const char *key,
4855 struct lxc_conf *c, void *data)
025718fb 4856{
8f899a4a 4857#if HAVE_APPARMOR
1c64e3ed 4858 free_disarm(c->lsm_aa_profile);
025718fb 4859 return 0;
8f899a4a
CB
4860#else
4861 return syserror_set(-EINVAL, "Built without AppArmor support");
4862#endif
025718fb 4863}
3061e04e 4864
953fe44f
CB
4865static inline int clr_config_apparmor_allow_incomplete(const char *key,
4866 struct lxc_conf *c,
4867 void *data)
3061e04e 4868{
8f899a4a 4869#if HAVE_APPARMOR
3061e04e
CB
4870 c->lsm_aa_allow_incomplete = 0;
4871 return 0;
8f899a4a
CB
4872#else
4873 return syserror_set(-EINVAL, "Built without AppArmor support");
4874#endif
3061e04e 4875}
31fc3494 4876
1800f924
WB
4877static inline int clr_config_apparmor_allow_nesting(const char *key,
4878 struct lxc_conf *c,
4879 void *data)
4880{
8f899a4a 4881#if HAVE_APPARMOR
1800f924
WB
4882 c->lsm_aa_allow_nesting = 0;
4883 return 0;
8f899a4a
CB
4884#else
4885 return syserror_set(-EINVAL, "Built without AppArmor support");
4886#endif
1800f924
WB
4887}
4888
4889static inline int clr_config_apparmor_raw(const char *key,
4890 struct lxc_conf *c,
4891 void *data)
4892{
8f899a4a 4893#if HAVE_APPARMOR
1800f924 4894 return lxc_clear_apparmor_raw(c);
8f899a4a
CB
4895#else
4896 return syserror_set(-EINVAL, "Built without AppArmor support");
4897#endif
1800f924
WB
4898}
4899
953fe44f
CB
4900static inline int clr_config_selinux_context(const char *key,
4901 struct lxc_conf *c, void *data)
31fc3494 4902{
d6df2b8f 4903#if HAVE_SELINUX
6afcf6dd 4904 free_disarm(c->lsm_se_context);
31fc3494 4905 return 0;
d6df2b8f
CB
4906#else
4907 return syserror_set(-EINVAL, "Built without SELinux support");
4908#endif
31fc3494 4909}
754d01ce 4910
4fef78bc
MB
4911static inline int clr_config_selinux_context_keyring(const char *key,
4912 struct lxc_conf *c, void *data)
4913{
d6df2b8f 4914#if HAVE_SELINUX
b60c8dd9 4915 free_disarm(c->lsm_se_keyring_context);
4fef78bc 4916 return 0;
d6df2b8f
CB
4917#else
4918 return syserror_set(-EINVAL, "Built without SELinux support");
4919#endif
4fef78bc
MB
4920}
4921
8f818a84
MB
4922static inline int clr_config_keyring_session(const char *key,
4923 struct lxc_conf *c, void *data)
4924{
4925 c->keyring_disable_session = false;
4926 return 0;
4927}
4928
43654d34
CB
4929static inline int clr_config_cgroup_controller(const char *key,
4930 struct lxc_conf *c, void *data)
754d01ce 4931{
54860ed0
CB
4932 return lxc_clear_cgroups(c, key, CGROUP_SUPER_MAGIC);
4933}
4934
4935static inline int clr_config_cgroup2_controller(const char *key,
4936 struct lxc_conf *c, void *data)
4937{
4938 return lxc_clear_cgroups(c, key, CGROUP2_SUPER_MAGIC);
754d01ce 4939}
d3a178de 4940
43654d34
CB
4941static int clr_config_cgroup_dir(const char *key, struct lxc_conf *lxc_conf,
4942 void *data)
4943{
d62177e9 4944 if (!strequal(key, "lxc.cgroup.dir"))
c583072d
CB
4945 return ret_errno(EINVAL);
4946
bd5501d2
CB
4947 if (lxc_conf->cgroup_meta.dir)
4948 free_disarm(lxc_conf->cgroup_meta.dir);
43654d34
CB
4949
4950 return 0;
4951}
4952
a900cbaf
WB
4953static int clr_config_cgroup_monitor_dir(const char *key,
4954 struct lxc_conf *lxc_conf,
4955 void *data)
4956{
4957 free_disarm(lxc_conf->cgroup_meta.monitor_dir);
4958 return 0;
4959}
4960
7696c1f9
RJ
4961static int clr_config_cgroup_monitor_pivot_dir(const char *key,
4962 struct lxc_conf *lxc_conf,
4963 void *data)
4964{
4965 free_disarm(lxc_conf->cgroup_meta.monitor_pivot_dir);
4966 return 0;
4967}
4968
a900cbaf
WB
4969static int clr_config_cgroup_container_dir(const char *key,
4970 struct lxc_conf *lxc_conf,
4971 void *data)
4972{
4973 free_disarm(lxc_conf->cgroup_meta.container_dir);
4974 return 0;
4975}
4976
4977static int clr_config_cgroup_container_inner_dir(const char *key,
4978 struct lxc_conf *lxc_conf,
4979 void *data)
4980{
4981 free_disarm(lxc_conf->cgroup_meta.namespace_dir);
4982 return 0;
4983}
4984
9caee129
CB
4985static inline int clr_config_cgroup_relative(const char *key,
4986 struct lxc_conf *lxc_conf,
4987 void *data)
76f0e2e7 4988{
9caee129 4989 lxc_conf->cgroup_meta.relative = false;
76f0e2e7
CB
4990 return 0;
4991}
4992
26471403
CB
4993static inline int clr_config_idmaps(const char *key, struct lxc_conf *c,
4994 void *data)
d3a178de
CB
4995{
4996 return lxc_clear_idmaps(c);
4997}
97d3338d 4998
46cc906d 4999static inline int clr_config_log_level(const char *key, struct lxc_conf *c,
26471403 5000 void *data)
97d3338d 5001{
4b73005c 5002 c->loglevel = LXC_LOG_LEVEL_NOTSET;
97d3338d
CB
5003 return 0;
5004}
de46099c 5005
46cc906d 5006static inline int clr_config_log_file(const char *key, struct lxc_conf *c,
26471403 5007 void *data)
de46099c 5008{
150c191e 5009 free_disarm(c->logfile);
de46099c
CB
5010 return 0;
5011}
b4fa13cd 5012
26471403
CB
5013static inline int clr_config_mount(const char *key, struct lxc_conf *c,
5014 void *data)
b4fa13cd
CB
5015{
5016 return lxc_clear_mount_entries(c);
5017}
4be81021 5018
26471403
CB
5019static inline int clr_config_mount_auto(const char *key, struct lxc_conf *c,
5020 void *data)
4be81021
CB
5021{
5022 return lxc_clear_automounts(c);
5023}
350d4b15 5024
47148e96
CB
5025static inline int clr_config_mount_fstab(const char *key, struct lxc_conf *c,
5026 void *data)
350d4b15 5027{
6620228b 5028 free_disarm(c->fstab);
350d4b15
CB
5029 return 0;
5030}
faca124d 5031
7a96a068
CB
5032static inline int clr_config_rootfs_path(const char *key, struct lxc_conf *c,
5033 void *data)
faca124d 5034{
ad16f12d 5035 free_disarm(c->rootfs.path);
faca124d
CB
5036 return 0;
5037}
5038
6e54330c
CB
5039static inline int clr_config_rootfs_managed(const char *key, struct lxc_conf *c,
5040 void *data)
5041{
5042 c->rootfs.managed = true;
5043 return 0;
5044}
5045
26471403
CB
5046static inline int clr_config_rootfs_mount(const char *key, struct lxc_conf *c,
5047 void *data)
fddefc2d 5048{
7decd496 5049 free_disarm(c->rootfs.mount);
fddefc2d
CB
5050 return 0;
5051}
7b1eb67d 5052
26471403
CB
5053static inline int clr_config_rootfs_options(const char *key, struct lxc_conf *c,
5054 void *data)
7b1eb67d 5055{
423374e9 5056 put_lxc_mount_options(&c->rootfs.mnt_opts);
3437f95c 5057
7b1eb67d
CB
5058 return 0;
5059}
02becb8d 5060
b67771bc 5061static inline int clr_config_uts_name(const char *key, struct lxc_conf *c,
26471403 5062 void *data)
d31d0103 5063{
137ee4b6 5064 free_disarm(c->utsname);
d31d0103
CB
5065 return 0;
5066}
c9eeb90c 5067
26471403
CB
5068static inline int clr_config_hooks(const char *key, struct lxc_conf *c,
5069 void *data)
c9eeb90c
CB
5070{
5071 return lxc_clear_hooks(c, key);
5072}
5073
44ae0fb6
CB
5074static inline int clr_config_hooks_version(const char *key, struct lxc_conf *c,
5075 void *data)
5076{
5077 /* default to legacy hooks version */
5078 c->hooks_version = 0;
5079 return 0;
5080}
5081
f9373e40
CB
5082static inline int clr_config_net(const char *key, struct lxc_conf *c,
5083 void *data)
f4488271 5084{
87d0990c 5085 lxc_free_networks(c);
c302b476 5086
e5d2fd7c 5087 return 0;
f4488271
CB
5088}
5089
26471403
CB
5090static inline int clr_config_cap_drop(const char *key, struct lxc_conf *c,
5091 void *data)
244cb55b
CB
5092{
5093 return lxc_clear_config_caps(c);
5094}
c74cc490 5095
26471403
CB
5096static inline int clr_config_cap_keep(const char *key, struct lxc_conf *c,
5097 void *data)
c74cc490 5098{
20ab7578 5099 return lxc_clear_config_caps(c);
c74cc490 5100}
4e5b633f 5101
3aed4934
CB
5102static inline int clr_config_console_path(const char *key, struct lxc_conf *c,
5103 void *data)
4e5b633f 5104{
2ed97e6f 5105 free_disarm(c->console.path);
4e5b633f
CB
5106 return 0;
5107}
5108
7c2ec23a 5109static inline int clr_config_console_logfile(const char *key,
26471403 5110 struct lxc_conf *c, void *data)
7c2ec23a 5111{
e68dfc25 5112 free_disarm(c->console.log_path);
7c2ec23a
CB
5113 return 0;
5114}
bbca37d8 5115
d91adfa6
CB
5116static inline int clr_config_console_rotate(const char *key, struct lxc_conf *c,
5117 void *data)
5118{
5119 c->console.log_rotate = 0;
5120 return 0;
5121}
5122
28f3b1cd
CB
5123static inline int clr_config_console_buffer_size(const char *key,
5124 struct lxc_conf *c, void *data)
a04220de 5125{
28f3b1cd 5126 c->console.buffer_size = 0;
a04220de
CB
5127 return 0;
5128}
5129
861813e5
CB
5130static inline int clr_config_console_size(const char *key, struct lxc_conf *c,
5131 void *data)
5132{
5133 c->console.log_size = 0;
5134 return 0;
5135}
5136
50d86993
CB
5137static inline int clr_config_seccomp_allow_nesting(const char *key,
5138 struct lxc_conf *c, void *data)
5139{
6ae86a9c 5140#if HAVE_SECCOMP
c3e3c21a 5141 c->seccomp.allow_nesting = 0;
50d86993 5142 return 0;
c3e3c21a 5143#else
0a6980fe 5144 return ret_errno(ENOSYS);
c3e3c21a 5145#endif
50d86993
CB
5146}
5147
84cf6d25
WB
5148static inline int clr_config_seccomp_notify_cookie(const char *key,
5149 struct lxc_conf *c, void *data)
5150{
331ef062 5151#if HAVE_DECL_SECCOMP_NOTIFY_FD
46bc1573 5152 free_disarm(c->seccomp.notifier.cookie);
84cf6d25
WB
5153 return 0;
5154#else
46bc1573 5155 return ret_errno(ENOSYS);
84cf6d25
WB
5156#endif
5157}
5158
86ce1da1
CB
5159static inline int clr_config_seccomp_notify_proxy(const char *key,
5160 struct lxc_conf *c, void *data)
5161{
331ef062 5162#if HAVE_DECL_SECCOMP_NOTIFY_FD
c3e3c21a
CB
5163 memset(&c->seccomp.notifier.proxy_addr, 0,
5164 sizeof(c->seccomp.notifier.proxy_addr));
86ce1da1
CB
5165 return 0;
5166#else
eaade76d 5167 return ret_errno(ENOSYS);
86ce1da1
CB
5168#endif
5169}
5170
0b427da0
CB
5171static inline int clr_config_seccomp_profile(const char *key,
5172 struct lxc_conf *c, void *data)
bbca37d8 5173{
9902a5d0 5174 free_disarm(c->seccomp.seccomp);
bbca37d8
CB
5175 return 0;
5176}
c721e86c 5177
26471403
CB
5178static inline int clr_config_autodev(const char *key, struct lxc_conf *c,
5179 void *data)
c721e86c
CB
5180{
5181 c->autodev = 1;
5182 return 0;
5183}
87b288d1 5184
63012bdd
CK
5185static inline int clr_config_autodev_tmpfs_size(const char *key, struct lxc_conf *c,
5186 void *data)
5187{
5188 c->autodevtmpfssize = 500000;
5189 return 0;
5190}
5191
55c84efc 5192static inline int clr_config_signal_halt(const char *key, struct lxc_conf *c,
26471403 5193 void *data)
87b288d1
CB
5194{
5195 c->haltsignal = 0;
5196 return 0;
5197}
cae63cfa 5198
55c84efc 5199static inline int clr_config_signal_reboot(const char *key, struct lxc_conf *c,
26471403 5200 void *data)
cae63cfa
CB
5201{
5202 c->rebootsignal = 0;
5203 return 0;
5204}
de45f3a8 5205
55c84efc 5206static inline int clr_config_signal_stop(const char *key, struct lxc_conf *c,
26471403 5207 void *data)
de45f3a8
CB
5208{
5209 c->stopsignal = 0;
5210 return 0;
5211}
c6182222 5212
26471403
CB
5213static inline int clr_config_start(const char *key, struct lxc_conf *c,
5214 void *data)
c6182222 5215{
d62177e9 5216 if (strequal(key + 10, "auto"))
c6182222 5217 c->start_auto = 0;
d62177e9 5218 else if (strequal(key + 10, "delay"))
c6182222 5219 c->start_delay = 0;
d62177e9 5220 else if (strequal(key + 10, "order"))
c6182222
CB
5221 c->start_order = 0;
5222
5223 return 0;
5224}
998ca94f 5225
46cc906d 5226static inline int clr_config_log_syslog(const char *key, struct lxc_conf *c,
26471403 5227 void *data)
998ca94f 5228{
f9f6f28f 5229 free_disarm(c->syslog);
998ca94f
CB
5230 return 0;
5231}
adad12ca 5232
26471403
CB
5233static inline int clr_config_monitor(const char *key, struct lxc_conf *c,
5234 void *data)
adad12ca
CB
5235{
5236 c->monitor_unshare = 0;
5237 return 0;
5238}
4850d223 5239
258f8051
CB
5240static inline int clr_config_monitor_signal_pdeath(const char *key,
5241 struct lxc_conf *c, void *data)
5242{
5243 c->monitor_signal_pdeath = 0;
5244 return 0;
5245}
5246
26471403
CB
5247static inline int clr_config_group(const char *key, struct lxc_conf *c,
5248 void *data)
4850d223
CB
5249{
5250 return lxc_clear_groups(c);
5251}
832fb63a 5252
26471403
CB
5253static inline int clr_config_environment(const char *key, struct lxc_conf *c,
5254 void *data)
832fb63a
CB
5255{
5256 return lxc_clear_environment(c);
4850d223 5257}
8e90af3e 5258
5cda27c1
SH
5259static inline int clr_config_execute_cmd(const char *key, struct lxc_conf *c,
5260 void *data)
5261{
e8f6cdb3 5262 free_disarm(c->execute_cmd);
5cda27c1
SH
5263 return 0;
5264}
5265
26471403
CB
5266static inline int clr_config_init_cmd(const char *key, struct lxc_conf *c,
5267 void *data)
8e90af3e 5268{
df45b761 5269 free_disarm(c->init_cmd);
8e90af3e
CB
5270 return 0;
5271}
ec76dcfb 5272
3c491553
L
5273static inline int clr_config_init_cwd(const char *key, struct lxc_conf *c,
5274 void *data)
5275{
5fab421a 5276 free_disarm(c->init_cwd);
3c491553
L
5277 return 0;
5278}
5279
26471403
CB
5280static inline int clr_config_init_uid(const char *key, struct lxc_conf *c,
5281 void *data)
ec76dcfb
CB
5282{
5283 c->init_uid = 0;
5284 return 0;
5285}
1044b247 5286
26471403
CB
5287static inline int clr_config_init_gid(const char *key, struct lxc_conf *c,
5288 void *data)
1044b247
CB
5289{
5290 c->init_gid = 0;
5291 return 0;
5292}
59e370db 5293
bf31b337
RJ
5294static inline int clr_config_init_groups(const char *key, struct lxc_conf *c,
5295 void *data)
5296{
bf31b337 5297 c->init_groups.size = 0;
c71f64cb 5298 free_disarm(c->init_groups.list);
bf31b337
RJ
5299 return 0;
5300}
5301
26471403
CB
5302static inline int clr_config_ephemeral(const char *key, struct lxc_conf *c,
5303 void *data)
59e370db
CB
5304{
5305 c->ephemeral = 0;
5306 return 0;
5307}
b98c5ab0 5308
26471403
CB
5309static inline int clr_config_no_new_privs(const char *key, struct lxc_conf *c,
5310 void *data)
b98c5ab0
CB
5311{
5312 c->no_new_privs = false;
5313 return 0;
5314}
715ccc96 5315
240d4b74 5316static inline int clr_config_prlimit(const char *key, struct lxc_conf *c,
26471403 5317 void *data)
715ccc96
CB
5318{
5319 return lxc_clear_limits(c, key);
5320}
fdf3c589 5321
7edd0540
L
5322static inline int clr_config_sysctl(const char *key, struct lxc_conf *c,
5323 void *data)
5324{
5325 return lxc_clear_sysctls(c, key);
5326}
5327
61d7a733
YT
5328static inline int clr_config_proc(const char *key, struct lxc_conf *c,
5329 void *data)
5330{
5331 return lxc_clear_procs(c, key);
5332}
5333
26471403
CB
5334static inline int clr_config_includefiles(const char *key, struct lxc_conf *c,
5335 void *data)
fdf3c589 5336{
fdf3c589
CB
5337 return 0;
5338}
a3c8e600 5339
1d8d3676
CB
5340static int clr_config_namespace_clone(const char *key,
5341 struct lxc_conf *lxc_conf, void *data)
5342{
5343 lxc_conf->ns_clone = 0;
5344 return 0;
5345}
5346
abeb5bba
CB
5347static int clr_config_namespace_keep(const char *key, struct lxc_conf *lxc_conf,
5348 void *data)
5349{
5350 lxc_conf->ns_keep = 0;
5351 return 0;
5352}
5353
70fd7fc9
CB
5354static int clr_config_time_offset_boot(const char *key, struct lxc_conf *lxc_conf, void *data)
5355{
5356 lxc_conf->timens.s_boot = 0;
5357 lxc_conf->timens.ns_boot = 0;
5358 return 0;
5359}
5360
5361static int clr_config_time_offset_monotonic(const char *key, struct lxc_conf *lxc_conf, void *data)
5362{
5363 lxc_conf->timens.s_monotonic = 0;
5364 lxc_conf->timens.ns_monotonic = 0;
5365 return 0;
5366}
5367
b074bbf1
CB
5368static int clr_config_namespace_share(const char *key,
5369 struct lxc_conf *lxc_conf, void *data)
28d9e29e
CB
5370{
5371 int ns_idx;
5372 const char *namespace;
5373
6333c915 5374 namespace = key + STRLITERALLEN("lxc.namespace.share.");
057d2cae
CB
5375 if (is_empty_string(namespace))
5376 return ret_errno(EINVAL);
5377
28d9e29e
CB
5378 ns_idx = lxc_namespace_2_ns_idx(namespace);
5379 if (ns_idx < 0)
5380 return ns_idx;
5381
b074bbf1
CB
5382 free(lxc_conf->ns_share[ns_idx]);
5383 lxc_conf->ns_share[ns_idx] = NULL;
28d9e29e
CB
5384
5385 return 0;
5386}
5387
a3c8e600 5388static int get_config_includefiles(const char *key, char *retv, int inlen,
cccd2219 5389 struct lxc_conf *c, void *data)
a3c8e600 5390{
218c46ec 5391 return ret_errno(ENOSYS);
a3c8e600 5392}
40db5d2f 5393
7707b0e0
CB
5394struct config_net_info {
5395 char buf[NETWORK_SUBKEY_SIZE_MAX];
5396 const char *subkey;
5397 const struct lxc_config_net_t *ops;
5398 struct lxc_netdev *netdev;
5399};
5400
5401static int get_network_config_ops(const char *key, struct lxc_conf *lxc_conf,
5402 struct config_net_info *info, bool allocate)
40db5d2f 5403{
31ee747b 5404 int ret;
0abcc213 5405 int64_t tmpidx;
7707b0e0
CB
5406 unsigned int idx;
5407 const char *idx_start;
0abcc213
CB
5408
5409 if (is_empty_string(key))
7707b0e0 5410 return ret_errno(EINVAL);
40db5d2f
CB
5411
5412 /* check that this is a sensible network key */
6a52a513 5413 if (!strnequal("lxc.net.", key, STRLITERALLEN("lxc.net.")))
7707b0e0 5414 return syserror_set(-EINVAL, "Invalid network configuration key \"%s\"", key);
40db5d2f 5415
f9373e40 5416 /* lxc.net.<n> */
0abcc213
CB
5417 /* beginning of index string */
5418 idx_start = key + STRLITERALLEN("lxc.net.");
5419 if (!isdigit(*idx_start))
7707b0e0 5420 return syserror_set(-EINVAL, "Failed to detect digit in string \"%s\"", key + 8);
40db5d2f 5421
7707b0e0 5422 ret = lxc_safe_int64_residual(idx_start, &tmpidx, 10, info->buf, sizeof(info->buf));
0abcc213 5423 if (ret)
7707b0e0 5424 return syserror("Failed to parse network index");
40db5d2f 5425
0abcc213 5426 if (tmpidx < 0 || tmpidx >= INT_MAX)
7707b0e0
CB
5427 return syserror_set(-ERANGE, "Number of configured networks would overflow the counter");
5428 idx = (unsigned int)tmpidx;
31ee747b 5429
7707b0e0
CB
5430 info->netdev = lxc_get_netdev_by_idx(lxc_conf, idx, allocate);
5431 if (!info->netdev)
5432 return ret_errno(EINVAL);
5433
5434 /* Make sure subkey points to the empty string. */
5435 info->subkey = info->buf;
5436 if (is_empty_string(info->subkey))
5437 return ret_errno(ENOENT);
31ee747b 5438
7707b0e0
CB
5439 if (info->subkey[0] != '.')
5440 return syserror_set(-EINVAL, "Invalid subkey");
5441 info->subkey++;
31ee747b 5442
7451daf8 5443 /* lxc.net.<idx>.<subkey> */
7707b0e0 5444 info->ops = lxc_get_config_net(info->subkey);
6773e108 5445 if (info->ops == &unsupported_config_net_key)
7707b0e0 5446 return syserror_set(-ENOENT, "Unknown network configuration key \"%s\"", key);
7451daf8 5447
7707b0e0 5448 return 0;
40db5d2f
CB
5449}
5450
25a908b8
CB
5451/* Config entry is something like "lxc.net.0.ipv4" the key 'lxc.net.' was
5452 * found. So we make sure next comes an integer, find the right callback (by
5453 * rewriting the key), and call it.
40db5d2f 5454 */
7707b0e0
CB
5455static int set_config_jump_table_net(const char *key, const char *value,
5456 struct lxc_conf *lxc_conf, void *data)
40db5d2f 5457{
7707b0e0
CB
5458 struct config_net_info info = {};
5459 int ret;
31ee747b 5460 const char *idxstring;
31ee747b 5461
0abcc213 5462 idxstring = key + STRLITERALLEN("lxc.net.");
31ee747b 5463 if (!isdigit(*idxstring))
d5c2cd94 5464 return ret_errno(EINVAL);
40db5d2f 5465
6bed0fb6 5466 if (lxc_config_value_empty(value))
7707b0e0 5467 return clr_config_jump_table_net(key, lxc_conf, data);
40db5d2f 5468
7707b0e0
CB
5469 ret = get_network_config_ops(key, lxc_conf, &info, true);
5470 if (ret)
5471 return ret;
47903908 5472
7707b0e0 5473 return info.ops->set(info.subkey, value, lxc_conf, info.netdev);
40db5d2f 5474}
ff6da295 5475
7707b0e0
CB
5476static int clr_config_jump_table_net(const char *key, struct lxc_conf *lxc_conf,
5477 void *data)
ff6da295 5478{
7707b0e0 5479 struct config_net_info info = {};
31ee747b 5480 int ret;
519df1c1 5481 const char *idxstring;
519df1c1 5482
31ee747b
CB
5483 idxstring = key + 8;
5484 if (!isdigit(*idxstring))
ec35c656 5485 return ret_errno(EINVAL);
519df1c1 5486
519df1c1 5487 /* The left conjunct is pretty self-explanatory. The right conjunct
31ee747b 5488 * checks whether the two pointers are equal. If they are we know that
519df1c1
CB
5489 * this is not a key that is namespaced any further and so we are
5490 * supposed to clear the whole network.
5491 */
5492 if (isdigit(*idxstring) && (strrchr(key, '.') == (idxstring - 1))) {
5493 unsigned int rmnetdevidx;
5494
ec35c656
CB
5495 ret = lxc_safe_uint(idxstring, &rmnetdevidx);
5496 if (ret < 0)
5497 return ret;
519df1c1
CB
5498
5499 /* Remove network from network list. */
5500 lxc_remove_nic_by_idx(lxc_conf, rmnetdevidx);
5501 return 0;
5502 }
ff6da295 5503
7707b0e0
CB
5504 ret = get_network_config_ops(key, lxc_conf, &info, false);
5505 if (ret)
5506 return ret;
47903908 5507
7707b0e0 5508 return info.ops->clr(info.subkey, lxc_conf, info.netdev);
ff6da295
CB
5509}
5510
f9373e40
CB
5511static int clr_config_net_type(const char *key, struct lxc_conf *lxc_conf,
5512 void *data)
ff6da295 5513{
070a05af 5514 struct lxc_netdev *netdev = data;
ff6da295 5515
ff6da295 5516 if (!netdev)
ee52bb2f 5517 return ret_errno(EINVAL);
ff6da295 5518
8d508eaa 5519 lxc_clear_netdev(netdev);
ff6da295
CB
5520
5521 return 0;
5522}
5523
f9373e40
CB
5524static int clr_config_net_name(const char *key, struct lxc_conf *lxc_conf,
5525 void *data)
ff6da295 5526{
070a05af 5527 struct lxc_netdev *netdev = data;
ff6da295 5528
ff6da295 5529 if (!netdev)
24a28704 5530 return ret_errno(EINVAL);
ff6da295 5531
de4855a8 5532 netdev->name[0] = '\0';
ff6da295
CB
5533
5534 return 0;
5535}
5536
f9373e40
CB
5537static int clr_config_net_flags(const char *key, struct lxc_conf *lxc_conf,
5538 void *data)
ff6da295 5539{
070a05af 5540 struct lxc_netdev *netdev = data;
ff6da295 5541
ff6da295 5542 if (!netdev)
a1ff93c9 5543 return ret_errno(EINVAL);
ff6da295
CB
5544
5545 netdev->flags = 0;
5546
5547 return 0;
5548}
5549
f9373e40
CB
5550static int clr_config_net_link(const char *key, struct lxc_conf *lxc_conf,
5551 void *data)
ff6da295 5552{
070a05af 5553 struct lxc_netdev *netdev = data;
ff6da295 5554
ff6da295 5555 if (!netdev)
08146143 5556 return ret_errno(EINVAL);
ff6da295 5557
de4855a8 5558 netdev->link[0] = '\0';
ff6da295
CB
5559
5560 return 0;
5561}
5562
6509154d 5563static int clr_config_net_l2proxy(const char *key, struct lxc_conf *lxc_conf,
5564 void *data)
5565{
5566 struct lxc_netdev *netdev = data;
5567
5568 if (!netdev)
0171e2a9 5569 return ret_errno(EINVAL);
6509154d 5570
5571 netdev->l2proxy = false;
5572
5573 return 0;
5574}
5575
f9373e40
CB
5576static int clr_config_net_macvlan_mode(const char *key,
5577 struct lxc_conf *lxc_conf, void *data)
ff6da295 5578{
070a05af 5579 struct lxc_netdev *netdev = data;
ff6da295 5580
ff6da295 5581 if (!netdev)
a0ea16c5 5582 return ret_errno(EINVAL);
ff6da295 5583
6bed0fb6
CB
5584 if (netdev->type != LXC_NET_MACVLAN)
5585 return 0;
5586
ff6da295
CB
5587 netdev->priv.macvlan_attr.mode = -1;
5588
5589 return 0;
5590}
5591
c9f52382 5592static int clr_config_net_ipvlan_mode(const char *key,
5593 struct lxc_conf *lxc_conf, void *data)
5594{
5595 struct lxc_netdev *netdev = data;
5596
5597 if (!netdev)
6288bd57 5598 return ret_errno(EINVAL);
c9f52382 5599
5600 if (netdev->type != LXC_NET_IPVLAN)
5601 return 0;
5602
5603 netdev->priv.ipvlan_attr.mode = -1;
5604
5605 return 0;
5606}
5607
5608static int clr_config_net_ipvlan_isolation(const char *key,
299ddd16 5609 struct lxc_conf *lxc_conf, void *data)
c9f52382 5610{
5611 struct lxc_netdev *netdev = data;
5612
5613 if (!netdev)
ce79ece8 5614 return ret_errno(EINVAL);
c9f52382 5615
5616 if (netdev->type != LXC_NET_IPVLAN)
5617 return 0;
5618
5619 netdev->priv.ipvlan_attr.isolation = -1;
5620
5621 return 0;
5622}
5623
3f0ed090
TP
5624static int clr_config_net_veth_mode(const char *key,
5625 struct lxc_conf *lxc_conf, void *data)
5626{
5627 struct lxc_netdev *netdev = data;
5628
5629 if (!netdev)
7b39759d 5630 return ret_errno(EINVAL);
3f0ed090
TP
5631
5632 if (netdev->type != LXC_NET_VETH)
5633 return 0;
5634
5635 netdev->priv.veth_attr.mode = -1;
5636
5637 return 0;
5638}
5639
be538b8b
CD
5640static int clr_config_net_veth_n_rxqueues(const char *key, struct lxc_conf *lxc_conf,
5641 void *data)
5642{
5643 struct lxc_netdev *netdev = data;
5644
5645 if (!netdev)
5646 return ret_errno(EINVAL);
5647
5648 if (netdev->type != LXC_NET_VETH)
5649 return 0;
5650
5651 netdev->priv.veth_attr.n_rxqueues = -1;
5652
5653 return 0;
5654}
5655
5656static int clr_config_net_veth_n_txqueues(const char *key, struct lxc_conf *lxc_conf,
5657 void *data)
5658{
5659 struct lxc_netdev *netdev = data;
5660
5661 if (!netdev)
5662 return ret_errno(EINVAL);
5663
5664 if (netdev->type != LXC_NET_VETH)
5665 return 0;
5666
5667 netdev->priv.veth_attr.n_txqueues = -1;
5668
5669 return 0;
5670}
5671
5672
f9373e40
CB
5673static int clr_config_net_veth_pair(const char *key, struct lxc_conf *lxc_conf,
5674 void *data)
ff6da295 5675{
070a05af 5676 struct lxc_netdev *netdev = data;
ff6da295 5677
ff6da295 5678 if (!netdev)
a69a835e 5679 return ret_errno(EINVAL);
ff6da295 5680
299ddd16
CB
5681 if (netdev->type != LXC_NET_VETH)
5682 return 0;
5683
de4855a8 5684 netdev->priv.veth_attr.pair[0] = '\0';
ff6da295
CB
5685
5686 return 0;
5687}
5688
fdf76c6d
TP
5689static int clr_config_net_veth_vlan_id(const char *key, struct lxc_conf *lxc_conf,
5690 void *data)
5691{
5692 struct lxc_netdev *netdev = data;
5693
5694 if (!netdev)
5695 return ret_errno(EINVAL);
5696
299ddd16
CB
5697 if (netdev->type != LXC_NET_VETH)
5698 return 0;
5699
fdf76c6d
TP
5700 netdev->priv.veth_attr.vlan_id = 0;
5701 netdev->priv.veth_attr.vlan_id_set = false;
5702
5703 return 0;
5704}
5705
b8e06d33
TP
5706static int clr_config_net_veth_vlan_tagged_id(const char *key,
5707 struct lxc_conf *lxc_conf, void *data)
5708{
5709 struct lxc_netdev *netdev = data;
5710 struct lxc_list *cur, *next;
5711
5712 if (!netdev)
5713 return ret_errno(EINVAL);
5714
299ddd16
CB
5715 if (netdev->type != LXC_NET_VETH)
5716 return 0;
5717
b8e06d33
TP
5718 lxc_list_for_each_safe(cur, &netdev->priv.veth_attr.vlan_tagged_ids, next) {
5719 lxc_list_del(cur);
5720 free(cur);
5721 }
5722
5723 return 0;
5724}
5725
5726
f9373e40
CB
5727static int clr_config_net_script_up(const char *key, struct lxc_conf *lxc_conf,
5728 void *data)
ff6da295 5729{
070a05af 5730 struct lxc_netdev *netdev = data;
ff6da295 5731
ff6da295 5732 if (!netdev)
9e1608ec 5733 return ret_errno(EINVAL);
ff6da295 5734
9e1608ec 5735 free_disarm(netdev->upscript);
ff6da295
CB
5736
5737 return 0;
5738}
5739
f9373e40
CB
5740static int clr_config_net_script_down(const char *key,
5741 struct lxc_conf *lxc_conf, void *data)
ff6da295 5742{
070a05af 5743 struct lxc_netdev *netdev = data;
ff6da295 5744
ff6da295 5745 if (!netdev)
25dea1a3 5746 return ret_errno(EINVAL);
ff6da295 5747
25dea1a3 5748 free_disarm(netdev->downscript);
ff6da295
CB
5749
5750 return 0;
5751}
5752
f9373e40
CB
5753static int clr_config_net_hwaddr(const char *key, struct lxc_conf *lxc_conf,
5754 void *data)
ff6da295 5755{
070a05af 5756 struct lxc_netdev *netdev = data;
ff6da295 5757
ff6da295 5758 if (!netdev)
afa97df5 5759 return ret_errno(EINVAL);
ff6da295 5760
afa97df5 5761 free_disarm(netdev->hwaddr);
ff6da295
CB
5762
5763 return 0;
5764}
5765
f9373e40
CB
5766static int clr_config_net_mtu(const char *key, struct lxc_conf *lxc_conf,
5767 void *data)
ff6da295 5768{
070a05af 5769 struct lxc_netdev *netdev = data;
ff6da295 5770
ff6da295 5771 if (!netdev)
18bab943 5772 return ret_errno(EINVAL);
ff6da295 5773
18bab943 5774 free_disarm(netdev->mtu);
ff6da295
CB
5775
5776 return 0;
5777}
5778
f9373e40
CB
5779static int clr_config_net_vlan_id(const char *key, struct lxc_conf *lxc_conf,
5780 void *data)
ff6da295 5781{
070a05af 5782 struct lxc_netdev *netdev = data;
ff6da295 5783
ff6da295 5784 if (!netdev)
2c76b1ba 5785 return ret_errno(EINVAL);
ff6da295 5786
299ddd16
CB
5787 if (netdev->type != LXC_NET_VLAN)
5788 return 0;
5789
ff6da295
CB
5790 netdev->priv.vlan_attr.vid = 0;
5791
5792 return 0;
5793}
5794
f9373e40
CB
5795static int clr_config_net_ipv4_gateway(const char *key,
5796 struct lxc_conf *lxc_conf, void *data)
ff6da295 5797{
070a05af 5798 struct lxc_netdev *netdev = data;
ff6da295 5799
ff6da295 5800 if (!netdev)
69a91fd3 5801 return ret_errno(EINVAL);
ff6da295 5802
69a91fd3 5803 free_disarm(netdev->ipv4_gateway);
ff6da295
CB
5804
5805 return 0;
5806}
5807
9ff60df2
CB
5808static int clr_config_net_ipv4_address(const char *key,
5809 struct lxc_conf *lxc_conf, void *data)
ff6da295 5810{
070a05af 5811 struct lxc_netdev *netdev = data;
2ec31bbd 5812 struct lxc_inetdev *inetdev, *ninetdev;
ff6da295 5813
ecbb3790 5814 if (!netdev)
54148d69 5815 return ret_errno(EINVAL);
ff6da295 5816
05a54a64 5817 list_for_each_entry_safe(inetdev, ninetdev, &netdev->ipv4_addresses, head) {
2ec31bbd
CB
5818 list_del(&inetdev->head);
5819 free(inetdev);
ff6da295
CB
5820 }
5821
5822 return 0;
5823}
5824
d4a7da46 5825static int clr_config_net_veth_ipv4_route(const char *key,
6340f28f 5826 struct lxc_conf *lxc_conf, void *data)
d4a7da46 5827{
5828 struct lxc_netdev *netdev = data;
303707f6 5829 struct lxc_inetdev *inetdev, *ninetdev;
d4a7da46 5830
5831 if (!netdev)
6340f28f 5832 return ret_errno(EINVAL);
d4a7da46 5833
299ddd16
CB
5834 if (netdev->type != LXC_NET_VETH)
5835 return 0;
5836
303707f6
CB
5837 list_for_each_entry_safe(inetdev, ninetdev, &netdev->priv.veth_attr.ipv4_routes, head) {
5838 list_del(&inetdev->head);
5839 free(inetdev);
d4a7da46 5840 }
5841
5842 return 0;
5843}
5844
f9373e40
CB
5845static int clr_config_net_ipv6_gateway(const char *key,
5846 struct lxc_conf *lxc_conf, void *data)
ff6da295 5847{
070a05af 5848 struct lxc_netdev *netdev = data;
ff6da295 5849
ff6da295 5850 if (!netdev)
20959044 5851 return ret_errno(EINVAL);
ff6da295 5852
20959044 5853 free_disarm(netdev->ipv6_gateway);
ff6da295
CB
5854
5855 return 0;
5856}
5857
2e44ae28
CB
5858static int clr_config_net_ipv6_address(const char *key,
5859 struct lxc_conf *lxc_conf, void *data)
ff6da295 5860{
070a05af 5861 struct lxc_netdev *netdev = data;
cd32fc73 5862 struct lxc_inet6dev *inet6dev, *ninet6dev;
ff6da295 5863
ecbb3790 5864 if (!netdev)
2b592308 5865 return ret_errno(EINVAL);
ff6da295 5866
05a54a64 5867 list_for_each_entry_safe(inet6dev, ninet6dev, &netdev->ipv6_addresses, head) {
cd32fc73
CB
5868 list_del(&inet6dev->head);
5869 free(inet6dev);
ff6da295
CB
5870 }
5871
5872 return 0;
5873}
9d4bf22d 5874
d4a7da46 5875static int clr_config_net_veth_ipv6_route(const char *key,
b67488ec 5876 struct lxc_conf *lxc_conf, void *data)
d4a7da46 5877{
5878 struct lxc_netdev *netdev = data;
6bf0c06b 5879 struct lxc_inet6dev *inet6dev, *ninet6dev;
d4a7da46 5880
5881 if (!netdev)
b67488ec 5882 return ret_errno(EINVAL);
d4a7da46 5883
299ddd16
CB
5884 if (netdev->type != LXC_NET_VETH)
5885 return 0;
5886
6bf0c06b
CB
5887 list_for_each_entry_safe(inet6dev, ninet6dev, &netdev->priv.veth_attr.ipv6_routes, head) {
5888 list_del(&inet6dev->head);
5889 free(inet6dev);
d4a7da46 5890 }
5891
5892 return 0;
5893}
5894
7707b0e0
CB
5895static int get_config_jump_table_net(const char *key, char *retv, int inlen,
5896 struct lxc_conf *c, void *data)
9d4bf22d 5897{
7707b0e0
CB
5898 struct config_net_info info = {};
5899 int ret;
31ee747b 5900 const char *idxstring;
9d4bf22d 5901
0abcc213 5902 idxstring = key + STRLITERALLEN("lxc.net.");
31ee747b 5903 if (!isdigit(*idxstring))
05a9b967 5904 return ret_errno(EINVAL);
31ee747b 5905
7707b0e0
CB
5906 ret = get_network_config_ops(key, c, &info, false);
5907 if (ret)
5908 return ret;
47903908 5909
7707b0e0 5910 return info.ops->get(info.subkey, retv, inlen, c, info.netdev);
9d4bf22d
CB
5911}
5912
f9373e40
CB
5913static int get_config_net_type(const char *key, char *retv, int inlen,
5914 struct lxc_conf *c, void *data)
9d4bf22d 5915{
070a05af
CB
5916 int len;
5917 int fulllen = 0;
5918 struct lxc_netdev *netdev = data;
9d4bf22d 5919
299ddd16
CB
5920 if (!netdev)
5921 return ret_errno(EINVAL);
5922
9d4bf22d
CB
5923 if (!retv)
5924 inlen = 0;
5925 else
5926 memset(retv, 0, inlen);
5927
9d4bf22d
CB
5928 strprint(retv, inlen, "%s", lxc_net_type_to_str(netdev->type));
5929
5930 return fulllen;
5931}
5932
f9373e40
CB
5933static int get_config_net_flags(const char *key, char *retv, int inlen,
5934 struct lxc_conf *c, void *data)
9d4bf22d 5935{
070a05af
CB
5936 int len;
5937 int fulllen = 0;
5938 struct lxc_netdev *netdev = data;
9d4bf22d 5939
299ddd16
CB
5940 if (!netdev)
5941 return ret_errno(EINVAL);
5942
9d4bf22d
CB
5943 if (!retv)
5944 inlen = 0;
5945 else
5946 memset(retv, 0, inlen);
5947
9d4bf22d
CB
5948 if (netdev->flags & IFF_UP)
5949 strprint(retv, inlen, "up");
5950
5951 return fulllen;
5952}
5953
f9373e40
CB
5954static int get_config_net_link(const char *key, char *retv, int inlen,
5955 struct lxc_conf *c, void *data)
9d4bf22d 5956{
070a05af
CB
5957 int len;
5958 int fulllen = 0;
5959 struct lxc_netdev *netdev = data;
9d4bf22d 5960
299ddd16
CB
5961 if (!netdev)
5962 return ret_errno(EINVAL);
5963
9d4bf22d
CB
5964 if (!retv)
5965 inlen = 0;
5966 else
5967 memset(retv, 0, inlen);
5968
de4855a8 5969 if (netdev->link[0] != '\0')
9d4bf22d
CB
5970 strprint(retv, inlen, "%s", netdev->link);
5971
5972 return fulllen;
5973}
5974
6509154d 5975static int get_config_net_l2proxy(const char *key, char *retv, int inlen,
5cd78f55 5976 struct lxc_conf *c, void *data)
6509154d 5977{
5978 struct lxc_netdev *netdev = data;
299ddd16
CB
5979
5980 if (!netdev)
5981 return ret_errno(EINVAL);
5982
6509154d 5983 return lxc_get_conf_bool(c, retv, inlen, netdev->l2proxy);
5984}
5985
f9373e40
CB
5986static int get_config_net_name(const char *key, char *retv, int inlen,
5987 struct lxc_conf *c, void *data)
9d4bf22d 5988{
070a05af
CB
5989 int len;
5990 int fulllen = 0;
5991 struct lxc_netdev *netdev = data;
9d4bf22d 5992
299ddd16
CB
5993 if (!netdev)
5994 return ret_errno(EINVAL);
5995
9d4bf22d
CB
5996 if (!retv)
5997 inlen = 0;
5998 else
5999 memset(retv, 0, inlen);
6000
de4855a8 6001 if (netdev->name[0] != '\0')
9d4bf22d
CB
6002 strprint(retv, inlen, "%s", netdev->name);
6003
6004 return fulllen;
6005}
6006
f9373e40
CB
6007static int get_config_net_macvlan_mode(const char *key, char *retv, int inlen,
6008 struct lxc_conf *c, void *data)
9d4bf22d 6009{
070a05af
CB
6010 int len;
6011 int fulllen = 0;
9d4bf22d 6012 const char *mode;
070a05af 6013 struct lxc_netdev *netdev = data;
9d4bf22d 6014
9d4bf22d 6015 if (!netdev)
3d72edbe 6016 return ret_errno(EINVAL);
9d4bf22d
CB
6017
6018 if (netdev->type != LXC_NET_MACVLAN)
299ddd16
CB
6019 return ret_errno(EINVAL);
6020
6021 if (!retv)
6022 inlen = 0;
6023 else
6024 memset(retv, 0, inlen);
9d4bf22d
CB
6025
6026 switch (netdev->priv.macvlan_attr.mode) {
6027 case MACVLAN_MODE_PRIVATE:
6028 mode = "private";
6029 break;
6030 case MACVLAN_MODE_VEPA:
6031 mode = "vepa";
6032 break;
6033 case MACVLAN_MODE_BRIDGE:
6034 mode = "bridge";
6035 break;
6036 case MACVLAN_MODE_PASSTHRU:
6037 mode = "passthru";
6038 break;
6039 default:
6040 mode = "(invalid)";
6041 break;
6042 }
6043
6044 strprint(retv, inlen, "%s", mode);
6045
6046 return fulllen;
6047}
6048
c9f52382 6049static int get_config_net_ipvlan_mode(const char *key, char *retv, int inlen,
6050 struct lxc_conf *c, void *data)
6051{
c9f52382 6052 int fulllen = 0;
c9f52382 6053 struct lxc_netdev *netdev = data;
dff2db42
CB
6054 int len;
6055 const char *mode;
c9f52382 6056
c9f52382 6057 if (!netdev)
dff2db42 6058 return ret_errno(EINVAL);
c9f52382 6059
6060 if (netdev->type != LXC_NET_IPVLAN)
299ddd16
CB
6061 return ret_errno(EINVAL);
6062
6063 if (!retv)
6064 inlen = 0;
6065 else
6066 memset(retv, 0, inlen);
c9f52382 6067
6068 switch (netdev->priv.ipvlan_attr.mode) {
6069 case IPVLAN_MODE_L3:
6070 mode = "l3";
6071 break;
6072 case IPVLAN_MODE_L3S:
6073 mode = "l3s";
6074 break;
6075 case IPVLAN_MODE_L2:
6076 mode = "l2";
6077 break;
6078 default:
6079 mode = "(invalid)";
6080 break;
6081 }
6082
6083 strprint(retv, inlen, "%s", mode);
6084
6085 return fulllen;
6086}
6087
6088static int get_config_net_ipvlan_isolation(const char *key, char *retv, int inlen,
6089 struct lxc_conf *c, void *data)
6090{
c9f52382 6091 int fulllen = 0;
c9f52382 6092 struct lxc_netdev *netdev = data;
56ce6747
CB
6093 int len;
6094 const char *mode;
c9f52382 6095
c9f52382 6096 if (!netdev)
56ce6747 6097 return ret_errno(EINVAL);
c9f52382 6098
6099 if (netdev->type != LXC_NET_IPVLAN)
299ddd16
CB
6100 return ret_errno(EINVAL);
6101
6102 if (!retv)
6103 inlen = 0;
6104 else
6105 memset(retv, 0, inlen);
c9f52382 6106
6107 switch (netdev->priv.ipvlan_attr.isolation) {
6108 case IPVLAN_ISOLATION_BRIDGE:
6109 mode = "bridge";
6110 break;
6111 case IPVLAN_ISOLATION_PRIVATE:
6112 mode = "private";
6113 break;
6114 case IPVLAN_ISOLATION_VEPA:
6115 mode = "vepa";
6116 break;
6117 default:
6118 mode = "(invalid)";
6119 break;
6120 }
6121
6122 strprint(retv, inlen, "%s", mode);
6123
6124 return fulllen;
6125}
6126
3f0ed090 6127static int get_config_net_veth_mode(const char *key, char *retv, int inlen,
299ddd16 6128 struct lxc_conf *c, void *data)
3f0ed090 6129{
3f0ed090 6130 int fulllen = 0;
3f0ed090 6131 struct lxc_netdev *netdev = data;
7d6ccf8c
CB
6132 int len;
6133 const char *mode;
3f0ed090 6134
3f0ed090 6135 if (!netdev)
7d6ccf8c 6136 return ret_errno(EINVAL);
3f0ed090
TP
6137
6138 if (netdev->type != LXC_NET_VETH)
299ddd16
CB
6139 return ret_errno(EINVAL);
6140
6141 if (!retv)
6142 inlen = 0;
6143 else
6144 memset(retv, 0, inlen);
3f0ed090
TP
6145
6146 switch (netdev->priv.veth_attr.mode) {
6147 case VETH_MODE_BRIDGE:
6148 mode = "bridge";
6149 break;
6150 case VETH_MODE_ROUTER:
6151 mode = "router";
6152 break;
6153 default:
6154 mode = "(invalid)";
6155 break;
6156 }
6157
6158 strprint(retv, inlen, "%s", mode);
6159
6160 return fulllen;
6161}
6162
be538b8b
CD
6163static int get_config_net_veth_n_rxqueues(const char *key, char *retv, int inlen,
6164 struct lxc_conf *c, void *data)
6165{
6166 int len;
6167 int fulllen = 0;
6168 struct lxc_netdev *netdev = data;
6169
6170 if (!netdev)
6171 return ret_errno(EINVAL);
6172
6173 if (netdev->type != LXC_NET_VETH)
6174 return ret_errno(EINVAL);
6175
6176 if (!retv)
6177 inlen = 0;
6178 else
6179 memset(retv, 0, inlen);
6180
6181 if (netdev->priv.veth_attr.n_rxqueues > 0)
6182 strprint(retv, inlen, "%d", netdev->priv.veth_attr.n_rxqueues);
6183
6184 return fulllen;
6185}
6186
6187static int get_config_net_veth_n_txqueues(const char *key, char *retv, int inlen,
6188 struct lxc_conf *c, void *data)
6189{
6190 int len;
6191 int fulllen = 0;
6192 struct lxc_netdev *netdev = data;
6193
6194 if (!netdev)
6195 return ret_errno(EINVAL);
6196
6197 if (netdev->type != LXC_NET_VETH)
6198 return ret_errno(EINVAL);
6199
6200 if (!retv)
6201 inlen = 0;
6202 else
6203 memset(retv, 0, inlen);
6204
6205 if (netdev->priv.veth_attr.n_txqueues > 0)
6206 strprint(retv, inlen, "%d", netdev->priv.veth_attr.n_txqueues);
6207
6208 return fulllen;
6209}
6210
f9373e40
CB
6211static int get_config_net_veth_pair(const char *key, char *retv, int inlen,
6212 struct lxc_conf *c, void *data)
9d4bf22d 6213{
070a05af
CB
6214 int len;
6215 int fulllen = 0;
6216 struct lxc_netdev *netdev = data;
9d4bf22d 6217
9d4bf22d 6218 if (!netdev)
9e86b442 6219 return ret_errno(EINVAL);
9d4bf22d
CB
6220
6221 if (netdev->type != LXC_NET_VETH)
299ddd16
CB
6222 return ret_errno(EINVAL);
6223
6224 if (!retv)
6225 inlen = 0;
6226 else
6227 memset(retv, 0, inlen);
9d4bf22d
CB
6228
6229 strprint(retv, inlen, "%s",
de4855a8
CB
6230 netdev->priv.veth_attr.pair[0] != '\0'
6231 ? netdev->priv.veth_attr.pair
6232 : netdev->priv.veth_attr.veth1);
9d4bf22d
CB
6233
6234 return fulllen;
6235}
6236
fdf76c6d 6237static int get_config_net_veth_vlan_id(const char *key, char *retv, int inlen,
a90dc552 6238 struct lxc_conf *c, void *data)
fdf76c6d
TP
6239{
6240 int len;
6241 int fulllen = 0;
6242 struct lxc_netdev *netdev = data;
6243
6244 if (!netdev)
6245 return ret_errno(EINVAL);
6246
6247 if (netdev->type != LXC_NET_VETH)
299ddd16 6248 return ret_errno(EINVAL);
fdf76c6d
TP
6249
6250 if (!retv)
6251 inlen = 0;
6252 else
6253 memset(retv, 0, inlen);
6254
6255 strprint(retv, inlen, "%d", netdev->priv.veth_attr.vlan_id);
6256
6257 return fulllen;
6258}
6259
299ddd16
CB
6260static int get_config_net_veth_vlan_tagged_id(const char *key, char *retv,
6261 int inlen, struct lxc_conf *c,
6262 void *data)
b8e06d33
TP
6263{
6264 int len;
6265 size_t listlen;
6266 struct lxc_list *it;
6267 int fulllen = 0;
6268 struct lxc_netdev *netdev = data;
6269
6270 if (!netdev)
4e61b19d 6271 return ret_errno(EINVAL);
b8e06d33
TP
6272
6273 if (netdev->type != LXC_NET_VETH)
299ddd16 6274 return ret_errno(EINVAL);
b8e06d33
TP
6275
6276 if (!retv)
6277 inlen = 0;
6278 else
6279 memset(retv, 0, inlen);
6280
6281 listlen = lxc_list_len(&netdev->priv.veth_attr.vlan_tagged_ids);
6282
6283 lxc_list_for_each(it, &netdev->priv.veth_attr.vlan_tagged_ids) {
6284 unsigned short i = PTR_TO_USHORT(it->elem);
299ddd16 6285 strprint(retv, inlen, "%u%s", i, (listlen-- > 1) ? "\n" : "");
b8e06d33
TP
6286 }
6287
6288 return fulllen;
6289}
6290
f9373e40
CB
6291static int get_config_net_script_up(const char *key, char *retv, int inlen,
6292 struct lxc_conf *c, void *data)
9d4bf22d 6293{
070a05af
CB
6294 int len;
6295 int fulllen = 0;
6296 struct lxc_netdev *netdev = data;
9d4bf22d 6297
299ddd16
CB
6298 if (!netdev)
6299 return ret_errno(EINVAL);
6300
9d4bf22d
CB
6301 if (!retv)
6302 inlen = 0;
6303 else
6304 memset(retv, 0, inlen);
6305
9d4bf22d
CB
6306 if (netdev->upscript)
6307 strprint(retv, inlen, "%s", netdev->upscript);
6308
6309 return fulllen;
6310}
6311
f9373e40
CB
6312static int get_config_net_script_down(const char *key, char *retv, int inlen,
6313 struct lxc_conf *c, void *data)
9d4bf22d 6314{
070a05af
CB
6315 int len;
6316 int fulllen = 0;
6317 struct lxc_netdev *netdev = data;
9d4bf22d 6318
299ddd16
CB
6319 if (!netdev)
6320 return ret_errno(EINVAL);
6321
9d4bf22d
CB
6322 if (!retv)
6323 inlen = 0;
6324 else
6325 memset(retv, 0, inlen);
6326
9d4bf22d
CB
6327 if (netdev->downscript)
6328 strprint(retv, inlen, "%s", netdev->downscript);
6329
6330 return fulllen;
6331}
6332
f9373e40
CB
6333static int get_config_net_hwaddr(const char *key, char *retv, int inlen,
6334 struct lxc_conf *c, void *data)
9d4bf22d 6335{
070a05af
CB
6336 int len;
6337 int fulllen = 0;
6338 struct lxc_netdev *netdev = data;
9d4bf22d 6339
299ddd16
CB
6340 if (!netdev)
6341 return ret_errno(EINVAL);
6342
9d4bf22d
CB
6343 if (!retv)
6344 inlen = 0;
6345 else
6346 memset(retv, 0, inlen);
6347
9d4bf22d
CB
6348 if (netdev->hwaddr)
6349 strprint(retv, inlen, "%s", netdev->hwaddr);
6350
6351 return fulllen;
6352}
6353
f9373e40
CB
6354static int get_config_net_mtu(const char *key, char *retv, int inlen,
6355 struct lxc_conf *c, void *data)
9d4bf22d 6356{
070a05af
CB
6357 int len;
6358 int fulllen = 0;
6359 struct lxc_netdev *netdev = data;
9d4bf22d 6360
299ddd16
CB
6361 if (!netdev)
6362 return ret_errno(EINVAL);
6363
9d4bf22d
CB
6364 if (!retv)
6365 inlen = 0;
6366 else
6367 memset(retv, 0, inlen);
6368
9d4bf22d
CB
6369 if (netdev->mtu)
6370 strprint(retv, inlen, "%s", netdev->mtu);
6371
6372 return fulllen;
6373}
6374
f9373e40
CB
6375static int get_config_net_vlan_id(const char *key, char *retv, int inlen,
6376 struct lxc_conf *c, void *data)
9d4bf22d 6377{
070a05af
CB
6378 int len;
6379 int fulllen = 0;
6380 struct lxc_netdev *netdev = data;
9d4bf22d 6381
9d4bf22d 6382 if (!netdev)
5b2a5509 6383 return ret_errno(EINVAL);
9d4bf22d
CB
6384
6385 if (netdev->type != LXC_NET_VLAN)
299ddd16
CB
6386 return ret_errno(EINVAL);
6387
6388 if (!retv)
6389 inlen = 0;
6390 else
6391 memset(retv, 0, inlen);
9d4bf22d
CB
6392
6393 strprint(retv, inlen, "%d", netdev->priv.vlan_attr.vid);
6394
6395 return fulllen;
6396}
6397
f9373e40
CB
6398static int get_config_net_ipv4_gateway(const char *key, char *retv, int inlen,
6399 struct lxc_conf *c, void *data)
9d4bf22d 6400{
070a05af 6401 int len;
9d4bf22d 6402 char buf[INET_ADDRSTRLEN];
070a05af
CB
6403 int fulllen = 0;
6404 struct lxc_netdev *netdev = data;
9d4bf22d 6405
299ddd16
CB
6406 if (!netdev)
6407 return ret_errno(EINVAL);
6408
9d4bf22d
CB
6409 if (!retv)
6410 inlen = 0;
6411 else
6412 memset(retv, 0, inlen);
6413
9d4bf22d
CB
6414 if (netdev->ipv4_gateway_auto) {
6415 strprint(retv, inlen, "auto");
a2f9a670 6416 } else if (netdev->ipv4_gateway_dev) {
6417 strprint(retv, inlen, "dev");
9d4bf22d 6418 } else if (netdev->ipv4_gateway) {
f203e57c
CB
6419 if (!inet_ntop(AF_INET, netdev->ipv4_gateway, buf, sizeof(buf)))
6420 return -errno;
9d4bf22d
CB
6421 strprint(retv, inlen, "%s", buf);
6422 }
6423
6424 return fulllen;
6425}
6426
9ff60df2
CB
6427static int get_config_net_ipv4_address(const char *key, char *retv, int inlen,
6428 struct lxc_conf *c, void *data)
9d4bf22d 6429{
2ec31bbd
CB
6430 int fulllen = 0;
6431 struct lxc_netdev *netdev = data;
070a05af 6432 int len;
9d4bf22d
CB
6433 size_t listlen;
6434 char buf[INET_ADDRSTRLEN];
2ec31bbd 6435 struct lxc_inetdev *inetdev;
9d4bf22d 6436
299ddd16
CB
6437 if (!netdev)
6438 return ret_errno(EINVAL);
6439
9d4bf22d
CB
6440 if (!retv)
6441 inlen = 0;
6442 else
6443 memset(retv, 0, inlen);
6444
d696c45e 6445 listlen = list_len(inetdev, &netdev->ipv4_addresses, head);
47903908 6446
05a54a64 6447 list_for_each_entry(inetdev, &netdev->ipv4_addresses, head) {
2ec31bbd 6448 if (!inet_ntop(AF_INET, &inetdev->addr, buf, sizeof(buf)))
c3410544 6449 return -errno;
2ec31bbd 6450 strprint(retv, inlen, "%s/%u%s", buf, inetdev->prefix,
9d4bf22d
CB
6451 (listlen-- > 1) ? "\n" : "");
6452 }
6453
6454 return fulllen;
6455}
6456
d4a7da46 6457static int get_config_net_veth_ipv4_route(const char *key, char *retv, int inlen,
299ddd16 6458 struct lxc_conf *c, void *data)
d4a7da46 6459{
6460 int len;
6461 size_t listlen;
6462 char buf[INET_ADDRSTRLEN];
303707f6 6463 struct lxc_inetdev *inetdev;
d4a7da46 6464 int fulllen = 0;
6465 struct lxc_netdev *netdev = data;
6466
d4a7da46 6467 if (!netdev)
5d4611dc 6468 return ret_errno(EINVAL);
d4a7da46 6469
6470 if (netdev->type != LXC_NET_VETH)
299ddd16
CB
6471 return ret_errno(EINVAL);
6472
6473 if (!retv)
6474 inlen = 0;
6475 else
6476 memset(retv, 0, inlen);
d4a7da46 6477
d696c45e 6478 listlen = list_len(inetdev, &netdev->priv.veth_attr.ipv4_routes, head);
303707f6
CB
6479 list_for_each_entry(inetdev, &netdev->priv.veth_attr.ipv4_routes, head) {
6480 if (!inet_ntop(AF_INET, &inetdev->addr, buf, sizeof(buf)))
5d4611dc 6481 return -errno;
303707f6 6482 strprint(retv, inlen, "%s/%u%s", buf, inetdev->prefix,
d4a7da46 6483 (listlen-- > 1) ? "\n" : "");
6484 }
6485
6486 return fulllen;
6487}
6488
f9373e40
CB
6489static int get_config_net_ipv6_gateway(const char *key, char *retv, int inlen,
6490 struct lxc_conf *c, void *data)
9d4bf22d 6491{
070a05af 6492 int len;
9d4bf22d 6493 char buf[INET6_ADDRSTRLEN];
070a05af
CB
6494 int fulllen = 0;
6495 struct lxc_netdev *netdev = data;
9d4bf22d 6496
299ddd16
CB
6497 if (!netdev)
6498 return ret_errno(EINVAL);
6499
9d4bf22d
CB
6500 if (!retv)
6501 inlen = 0;
6502 else
6503 memset(retv, 0, inlen);
6504
9d4bf22d
CB
6505 if (netdev->ipv6_gateway_auto) {
6506 strprint(retv, inlen, "auto");
a2f9a670 6507 } else if (netdev->ipv6_gateway_dev) {
6508 strprint(retv, inlen, "dev");
9d4bf22d 6509 } else if (netdev->ipv6_gateway) {
d8009ed2
CB
6510 if (!inet_ntop(AF_INET6, netdev->ipv6_gateway, buf, sizeof(buf)))
6511 return -errno;
9d4bf22d
CB
6512 strprint(retv, inlen, "%s", buf);
6513 }
6514
6515 return fulllen;
6516}
6517
2e44ae28
CB
6518static int get_config_net_ipv6_address(const char *key, char *retv, int inlen,
6519 struct lxc_conf *c, void *data)
9d4bf22d 6520{
070a05af 6521 int len;
9d4bf22d
CB
6522 size_t listlen;
6523 char buf[INET6_ADDRSTRLEN];
070a05af
CB
6524 int fulllen = 0;
6525 struct lxc_netdev *netdev = data;
cd32fc73 6526 struct lxc_inet6dev *inet6dev;
9d4bf22d 6527
299ddd16
CB
6528 if (!netdev)
6529 return ret_errno(EINVAL);
6530
9d4bf22d
CB
6531 if (!retv)
6532 inlen = 0;
6533 else
6534 memset(retv, 0, inlen);
6535
d696c45e 6536 listlen = list_len(inet6dev, &netdev->ipv6_addresses, head);
05a54a64 6537 list_for_each_entry(inet6dev, &netdev->ipv6_addresses, head) {
cd32fc73 6538 if (!inet_ntop(AF_INET6, &inet6dev->addr, buf, sizeof(buf)))
396acb62 6539 return -errno;
cd32fc73 6540 strprint(retv, inlen, "%s/%u%s", buf, inet6dev->prefix,
9d4bf22d
CB
6541 (listlen-- > 1) ? "\n" : "");
6542 }
6543
6544 return fulllen;
6545}
cfc67626 6546
d4a7da46 6547static int get_config_net_veth_ipv6_route(const char *key, char *retv, int inlen,
98485389 6548 struct lxc_conf *c, void *data)
d4a7da46 6549{
6550 int len;
6551 size_t listlen;
6552 char buf[INET6_ADDRSTRLEN];
6bf0c06b 6553 struct lxc_inet6dev *inet6dev;
d4a7da46 6554 int fulllen = 0;
6555 struct lxc_netdev *netdev = data;
6556
d4a7da46 6557 if (!netdev)
98485389 6558 return ret_errno(EINVAL);
d4a7da46 6559
6560 if (netdev->type != LXC_NET_VETH)
299ddd16
CB
6561 return ret_errno(EINVAL);
6562
6563 if (!retv)
6564 inlen = 0;
6565 else
6566 memset(retv, 0, inlen);
d4a7da46 6567
d696c45e 6568 listlen = list_len(inet6dev, &netdev->priv.veth_attr.ipv6_routes, head);
6bf0c06b
CB
6569 list_for_each_entry(inet6dev, &netdev->priv.veth_attr.ipv6_routes, head) {
6570 if (!inet_ntop(AF_INET6, &inet6dev->addr, buf, sizeof(buf)))
98485389 6571 return -errno;
6bf0c06b 6572 strprint(retv, inlen, "%s/%u%s", buf, inet6dev->prefix,
d4a7da46 6573 (listlen-- > 1) ? "\n" : "");
6574 }
6575
6576 return fulllen;
6577}
6578
cfc67626
CB
6579int lxc_list_config_items(char *retv, int inlen)
6580{
6581 size_t i;
6582 int len;
6583 int fulllen = 0;
6584
6585 if (!retv)
6586 inlen = 0;
6587 else
6588 memset(retv, 0, inlen);
6589
0abcc213 6590 for (i = 0; i < ARRAY_SIZE(config_jump_table); i++) {
33eb2ec1 6591 char *s = config_jump_table[i].name;
300df83e 6592
cfc67626
CB
6593 if (s[strlen(s) - 1] == '.')
6594 continue;
300df83e 6595
cfc67626
CB
6596 strprint(retv, inlen, "%s\n", s);
6597 }
6598
6599 return fulllen;
6600}
a5448c15 6601
fe9b7349
CB
6602int lxc_list_subkeys(struct lxc_conf *conf, const char *key, char *retv,
6603 int inlen)
6604{
6605 int len;
6606 int fulllen = 0;
6607
6608 if (!retv)
6609 inlen = 0;
6610 else
6611 memset(retv, 0, inlen);
6612
d62177e9 6613 if (strequal(key, "lxc.apparmor")) {
fe9b7349 6614 strprint(retv, inlen, "allow_incomplete\n");
1800f924 6615 strprint(retv, inlen, "allow_nesting\n");
fe9b7349 6616 strprint(retv, inlen, "profile\n");
1800f924 6617 strprint(retv, inlen, "raw\n");
d62177e9 6618 } else if (strequal(key, "lxc.cgroup")) {
dae8c253 6619 strprint(retv, inlen, "dir\n");
d62177e9 6620 } else if (strequal(key, "lxc.selinux")) {
fe9b7349 6621 strprint(retv, inlen, "context\n");
4fef78bc 6622 strprint(retv, inlen, "context.keyring\n");
d62177e9 6623 } else if (strequal(key, "lxc.mount")) {
fe9b7349
CB
6624 strprint(retv, inlen, "auto\n");
6625 strprint(retv, inlen, "entry\n");
6626 strprint(retv, inlen, "fstab\n");
d62177e9 6627 } else if (strequal(key, "lxc.rootfs")) {
fe9b7349
CB
6628 strprint(retv, inlen, "mount\n");
6629 strprint(retv, inlen, "options\n");
6630 strprint(retv, inlen, "path\n");
d62177e9 6631 } else if (strequal(key, "lxc.uts")) {
fe9b7349 6632 strprint(retv, inlen, "name\n");
d62177e9 6633 } else if (strequal(key, "lxc.hook")) {
fe9b7349 6634 strprint(retv, inlen, "autodev\n");
63012bdd 6635 strprint(retv, inlen, "autodevtmpfssize\n");
fe9b7349
CB
6636 strprint(retv, inlen, "clone\n");
6637 strprint(retv, inlen, "destroy\n");
6638 strprint(retv, inlen, "mount\n");
6639 strprint(retv, inlen, "post-stop\n");
6640 strprint(retv, inlen, "pre-mount\n");
6641 strprint(retv, inlen, "pre-start\n");
08dd2805 6642 strprint(retv, inlen, "start-host\n");
fe9b7349
CB
6643 strprint(retv, inlen, "start\n");
6644 strprint(retv, inlen, "stop\n");
d62177e9 6645 } else if (strequal(key, "lxc.cap")) {
fe9b7349
CB
6646 strprint(retv, inlen, "drop\n");
6647 strprint(retv, inlen, "keep\n");
d62177e9 6648 } else if (strequal(key, "lxc.console")) {
fe9b7349
CB
6649 strprint(retv, inlen, "logfile\n");
6650 strprint(retv, inlen, "path\n");
d62177e9 6651 } else if (strequal(key, "lxc.seccomp")) {
fe9b7349 6652 strprint(retv, inlen, "profile\n");
d62177e9 6653 } else if (strequal(key, "lxc.signal")) {
fe9b7349
CB
6654 strprint(retv, inlen, "halt\n");
6655 strprint(retv, inlen, "reboot\n");
6656 strprint(retv, inlen, "stop\n");
d62177e9 6657 } else if (strequal(key, "lxc.start")) {
fe9b7349
CB
6658 strprint(retv, inlen, "auto\n");
6659 strprint(retv, inlen, "delay\n");
6660 strprint(retv, inlen, "order\n");
d62177e9 6661 } else if (strequal(key, "lxc.monitor")) {
fe9b7349 6662 strprint(retv, inlen, "unshare\n");
d62177e9 6663 } else if (strequal(key, "lxc.keyring")) {
8f818a84 6664 strprint(retv, inlen, "session\n");
fe9b7349 6665 } else {
efcba3c3 6666 fulllen = ret_errno(EINVAL);
fe9b7349
CB
6667 }
6668
6669 return fulllen;
6670}
6671
a5448c15
CB
6672int lxc_list_net(struct lxc_conf *c, const char *key, char *retv, int inlen)
6673{
7707b0e0 6674 struct config_net_info info = {};
a5448c15 6675 struct lxc_netdev *netdev;
7707b0e0
CB
6676 int len, ret;
6677 const char *idxstring;
a5448c15 6678 int fulllen = 0;
a5448c15 6679
0abcc213 6680 idxstring = key + STRLITERALLEN("lxc.net.");
a5448c15 6681 if (!isdigit(*idxstring))
0abcc213 6682 return ret_errno(EINVAL);
a5448c15 6683
7707b0e0
CB
6684 ret = get_network_config_ops(key, c, &info, false);
6685 if (ret) {
6686 if (ret != -ENOENT)
6687 return ret_errno(EINVAL);
6688 }
6689 netdev = info.netdev;
a5448c15
CB
6690
6691 if (!retv)
6692 inlen = 0;
6693 else
6694 memset(retv, 0, inlen);
6695
6696 strprint(retv, inlen, "type\n");
6697 strprint(retv, inlen, "script.up\n");
6698 strprint(retv, inlen, "script.down\n");
47903908 6699
a5448c15
CB
6700 if (netdev->type != LXC_NET_EMPTY) {
6701 strprint(retv, inlen, "flags\n");
6702 strprint(retv, inlen, "link\n");
6703 strprint(retv, inlen, "name\n");
6704 strprint(retv, inlen, "hwaddr\n");
6705 strprint(retv, inlen, "mtu\n");
6706 strprint(retv, inlen, "ipv6.address\n");
6707 strprint(retv, inlen, "ipv6.gateway\n");
6708 strprint(retv, inlen, "ipv4.address\n");
6709 strprint(retv, inlen, "ipv4.gateway\n");
6710 }
6711
6712 switch (netdev->type) {
6713 case LXC_NET_VETH:
6714 strprint(retv, inlen, "veth.pair\n");
d4a7da46 6715 strprint(retv, inlen, "veth.ipv4.route\n");
6716 strprint(retv, inlen, "veth.ipv6.route\n");
fdf76c6d 6717 strprint(retv, inlen, "veth.vlan.id\n");
a5448c15
CB
6718 break;
6719 case LXC_NET_MACVLAN:
6720 strprint(retv, inlen, "macvlan.mode\n");
6721 break;
c9f52382 6722 case LXC_NET_IPVLAN:
6723 strprint(retv, inlen, "ipvlan.mode\n");
6724 strprint(retv, inlen, "ipvlan.isolation\n");
6725 break;
a5448c15
CB
6726 case LXC_NET_VLAN:
6727 strprint(retv, inlen, "vlan.id\n");
6728 break;
6729 case LXC_NET_PHYS:
6730 break;
6731 }
6732
6733 return fulllen;
6734}
09996a48
CB
6735
6736static int set_config_sched_core(const char *key, const char *value,
6737 struct lxc_conf *lxc_conf, void *data)
6738{
6739 int ret;
6740 unsigned int nr;
6741
6742 if (lxc_config_value_empty(value))
6743 return clr_config_sched_core(key, lxc_conf, data);
6744
6745 ret = lxc_safe_uint(value, &nr);
6746 if (ret)
6747 return ret_errno(EINVAL);
6748
6749 if (nr != 0 && nr != 1)
6750 return ret_errno(EINVAL);
6751
6752 lxc_conf->sched_core = (nr == 1);
6753 return 0;
6754}
6755
6756static int get_config_sched_core(const char *key, char *retv, int inlen,
6757 struct lxc_conf *c, void *data)
6758{
6759 return lxc_get_conf_bool(c, retv, inlen, c->sched_core);
6760}
6761
6762static int clr_config_sched_core(const char *key, struct lxc_conf *c, void *data)
6763{
6764 c->sched_core = false;
6765 return 0;
6766}