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