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