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