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