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