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