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