1 /* SPDX-License-Identifier: LGPL-2.1+ */
6 #define __STDC_FORMAT_MACROS
14 #include <netinet/in.h>
19 #include <sys/param.h>
21 #include <sys/types.h>
22 #include <sys/utsname.h>
31 #include "confile_utils.h"
32 #include "../include/netns_ifaddrs.h"
34 #include "lxcseccomp.h"
36 #include "memory_utils.h"
39 #include "storage/storage.h"
43 #include "include/strlcpy.h"
47 #include "include/strlcat.h"
50 lxc_log_define(confile
, lxc
);
52 #define lxc_config_define(name) \
53 __hot static int set_config_##name(const char *, const char *, \
54 struct lxc_conf *, void *); \
55 __hot static int get_config_##name(const char *, char *, int, \
56 struct lxc_conf *, void *); \
57 __hot static int clr_config_##name(const char *, struct lxc_conf *, \
60 lxc_config_define(autodev
);
61 lxc_config_define(autodev_tmpfs_size
);
62 lxc_config_define(apparmor_allow_incomplete
);
63 lxc_config_define(apparmor_allow_nesting
);
64 lxc_config_define(apparmor_profile
);
65 lxc_config_define(apparmor_raw
);
66 lxc_config_define(cap_drop
);
67 lxc_config_define(cap_keep
);
68 lxc_config_define(cgroup_controller
);
69 lxc_config_define(cgroup2_controller
);
70 lxc_config_define(cgroup_dir
);
71 lxc_config_define(cgroup_monitor_dir
);
72 lxc_config_define(cgroup_monitor_pivot_dir
);
73 lxc_config_define(cgroup_container_dir
);
74 lxc_config_define(cgroup_container_inner_dir
);
75 lxc_config_define(cgroup_relative
);
76 lxc_config_define(console_buffer_size
);
77 lxc_config_define(console_logfile
);
78 lxc_config_define(console_path
);
79 lxc_config_define(console_rotate
);
80 lxc_config_define(console_size
);
81 lxc_config_define(unsupported_key
);
82 lxc_config_define(environment
);
83 lxc_config_define(ephemeral
);
84 lxc_config_define(execute_cmd
);
85 lxc_config_define(group
);
86 lxc_config_define(hooks
);
87 lxc_config_define(hooks_version
);
88 lxc_config_define(idmaps
);
89 lxc_config_define(includefiles
);
90 lxc_config_define(init_cmd
);
91 lxc_config_define(init_cwd
);
92 lxc_config_define(init_gid
);
93 lxc_config_define(init_uid
);
94 lxc_config_define(init_groups
);
95 lxc_config_define(jump_table_net
);
96 lxc_config_define(keyring_session
);
97 lxc_config_define(log_file
);
98 lxc_config_define(log_level
);
99 lxc_config_define(log_syslog
);
100 lxc_config_define(monitor
);
101 lxc_config_define(monitor_signal_pdeath
);
102 lxc_config_define(mount
);
103 lxc_config_define(mount_auto
);
104 lxc_config_define(mount_fstab
);
105 lxc_config_define(namespace_clone
);
106 lxc_config_define(namespace_keep
);
107 lxc_config_define(time_offset_boot
);
108 lxc_config_define(time_offset_monotonic
);
109 lxc_config_define(namespace_share
);
110 lxc_config_define(net
);
111 lxc_config_define(net_flags
);
112 lxc_config_define(net_hwaddr
);
113 lxc_config_define(net_ipv4_address
);
114 lxc_config_define(net_ipv4_gateway
);
115 lxc_config_define(net_ipv6_address
);
116 lxc_config_define(net_ipv6_gateway
);
117 lxc_config_define(net_link
);
118 lxc_config_define(net_l2proxy
);
119 lxc_config_define(net_macvlan_mode
);
120 lxc_config_define(net_ipvlan_mode
);
121 lxc_config_define(net_ipvlan_isolation
);
122 lxc_config_define(net_mtu
);
123 lxc_config_define(net_name
);
124 lxc_config_define(net_script_down
);
125 lxc_config_define(net_script_up
);
126 lxc_config_define(net_type
);
127 lxc_config_define(net_veth_mode
);
128 lxc_config_define(net_veth_pair
);
129 lxc_config_define(net_veth_ipv4_route
);
130 lxc_config_define(net_veth_ipv6_route
);
131 lxc_config_define(net_veth_vlan_id
);
132 lxc_config_define(net_veth_vlan_tagged_id
);
133 lxc_config_define(net_vlan_id
);
134 lxc_config_define(no_new_privs
);
135 lxc_config_define(personality
);
136 lxc_config_define(prlimit
);
137 lxc_config_define(pty_max
);
138 lxc_config_define(rootfs_managed
);
139 lxc_config_define(rootfs_mount
);
140 lxc_config_define(rootfs_options
);
141 lxc_config_define(rootfs_path
);
142 lxc_config_define(seccomp_profile
);
143 lxc_config_define(seccomp_allow_nesting
);
144 lxc_config_define(seccomp_notify_cookie
);
145 lxc_config_define(seccomp_notify_proxy
);
146 lxc_config_define(selinux_context
);
147 lxc_config_define(selinux_context_keyring
);
148 lxc_config_define(signal_halt
);
149 lxc_config_define(signal_reboot
);
150 lxc_config_define(signal_stop
);
151 lxc_config_define(start
);
152 lxc_config_define(tty_max
);
153 lxc_config_define(tty_dir
);
154 lxc_config_define(uts_name
);
155 lxc_config_define(sysctl
);
156 lxc_config_define(proc
);
158 static int set_config_unsupported_key(const char *key
, const char *value
,
159 struct lxc_conf
*lxc_conf
, void *data
)
161 return syserror_set(-EINVAL
, "Unsupported config key \"%s\"", key
);
164 static int get_config_unsupported_key(const char *key
, char *retv
, int inlen
,
165 struct lxc_conf
*c
, void *data
)
167 return syserror_set(-EINVAL
, "Unsupported config key \"%s\"", key
);
170 static int clr_config_unsupported_key(const char *key
,
171 struct lxc_conf
*lxc_conf
, void *data
)
173 return syserror_set(-EINVAL
, "Unsupported config key \"%s\"", key
);
178 * If a new config option is added to this table, be aware that
179 * the order in which the options are places into the table matters.
180 * That means that more specific options of a namespace have to be
181 * placed above more generic ones.
183 * For instance: If lxc.ab is placed before lxc.ab.c, the config option
184 * lxc.ab.c will always be matched to lxc.ab. That is, the lxc.ab.c option
185 * has to be placed above lxc.ab.
187 static struct lxc_config_t config_jump_table
[] = {
188 { "lxc.arch", true, set_config_personality
, get_config_personality
, clr_config_personality
, },
189 { "lxc.apparmor.profile", true, set_config_apparmor_profile
, get_config_apparmor_profile
, clr_config_apparmor_profile
, },
190 { "lxc.apparmor.allow_incomplete", true, set_config_apparmor_allow_incomplete
, get_config_apparmor_allow_incomplete
, clr_config_apparmor_allow_incomplete
, },
191 { "lxc.apparmor.allow_nesting", true, set_config_apparmor_allow_nesting
, get_config_apparmor_allow_nesting
, clr_config_apparmor_allow_nesting
, },
192 { "lxc.apparmor.raw", true, set_config_apparmor_raw
, get_config_apparmor_raw
, clr_config_apparmor_raw
, },
193 { "lxc.autodev.tmpfs.size", true, set_config_autodev_tmpfs_size
, get_config_autodev_tmpfs_size
, clr_config_autodev_tmpfs_size
, },
194 { "lxc.autodev", true, set_config_autodev
, get_config_autodev
, clr_config_autodev
, },
195 { "lxc.cap.drop", true, set_config_cap_drop
, get_config_cap_drop
, clr_config_cap_drop
, },
196 { "lxc.cap.keep", true, set_config_cap_keep
, get_config_cap_keep
, clr_config_cap_keep
, },
197 { "lxc.cgroup2", false, set_config_cgroup2_controller
, get_config_cgroup2_controller
, clr_config_cgroup2_controller
, },
198 { "lxc.cgroup.dir.monitor.pivot", true, set_config_cgroup_monitor_pivot_dir
, get_config_cgroup_monitor_pivot_dir
, clr_config_cgroup_monitor_pivot_dir
, },
199 { "lxc.cgroup.dir.monitor", true, set_config_cgroup_monitor_dir
, get_config_cgroup_monitor_dir
, clr_config_cgroup_monitor_dir
, },
200 { "lxc.cgroup.dir.container.inner", true, set_config_cgroup_container_inner_dir
, get_config_cgroup_container_inner_dir
, clr_config_cgroup_container_inner_dir
, },
201 { "lxc.cgroup.dir.container", true, set_config_cgroup_container_dir
, get_config_cgroup_container_dir
, clr_config_cgroup_container_dir
, },
202 { "lxc.cgroup.dir", true, set_config_cgroup_dir
, get_config_cgroup_dir
, clr_config_cgroup_dir
, },
203 { "lxc.cgroup.relative", true, set_config_cgroup_relative
, get_config_cgroup_relative
, clr_config_cgroup_relative
, },
204 { "lxc.cgroup", false, set_config_cgroup_controller
, get_config_cgroup_controller
, clr_config_cgroup_controller
, },
205 { "lxc.console.buffer.size", true, set_config_console_buffer_size
, get_config_console_buffer_size
, clr_config_console_buffer_size
, },
206 { "lxc.console.logfile", true, set_config_console_logfile
, get_config_console_logfile
, clr_config_console_logfile
, },
207 { "lxc.console.path", true, set_config_console_path
, get_config_console_path
, clr_config_console_path
, },
208 { "lxc.console.rotate", true, set_config_console_rotate
, get_config_console_rotate
, clr_config_console_rotate
, },
209 { "lxc.console.size", true, set_config_console_size
, get_config_console_size
, clr_config_console_size
, },
210 { "lxc.environment", true, set_config_environment
, get_config_environment
, clr_config_environment
, },
211 { "lxc.ephemeral", true, set_config_ephemeral
, get_config_ephemeral
, clr_config_ephemeral
, },
212 { "lxc.execute.cmd", true, set_config_execute_cmd
, get_config_execute_cmd
, clr_config_execute_cmd
, },
213 { "lxc.group", true, set_config_group
, get_config_group
, clr_config_group
, },
214 { "lxc.hook.autodev", true, set_config_hooks
, get_config_hooks
, clr_config_hooks
, },
215 { "lxc.hook.clone", true, set_config_hooks
, get_config_hooks
, clr_config_hooks
, },
216 { "lxc.hook.destroy", true, set_config_hooks
, get_config_hooks
, clr_config_hooks
, },
217 { "lxc.hook.mount", true, set_config_hooks
, get_config_hooks
, clr_config_hooks
, },
218 { "lxc.hook.post-stop", true, set_config_hooks
, get_config_hooks
, clr_config_hooks
, },
219 { "lxc.hook.pre-mount", true, set_config_hooks
, get_config_hooks
, clr_config_hooks
, },
220 { "lxc.hook.pre-start", true, set_config_hooks
, get_config_hooks
, clr_config_hooks
, },
221 { "lxc.hook.start", true, set_config_hooks
, get_config_hooks
, clr_config_hooks
, },
222 { "lxc.hook.start-host", true, set_config_hooks
, get_config_hooks
, clr_config_hooks
, },
223 { "lxc.hook.stop", true, set_config_hooks
, get_config_hooks
, clr_config_hooks
, },
224 { "lxc.hook.version", true, set_config_hooks_version
, get_config_hooks_version
, clr_config_hooks_version
, },
225 { "lxc.hook", true, set_config_hooks
, get_config_hooks
, clr_config_hooks
, },
226 { "lxc.idmap", true, set_config_idmaps
, get_config_idmaps
, clr_config_idmaps
, },
227 { "lxc.include", true, set_config_includefiles
, get_config_includefiles
, clr_config_includefiles
, },
228 { "lxc.init.cmd", true, set_config_init_cmd
, get_config_init_cmd
, clr_config_init_cmd
, },
229 { "lxc.init.gid", true, set_config_init_gid
, get_config_init_gid
, clr_config_init_gid
, },
230 { "lxc.init.groups", true, set_config_init_groups
, get_config_init_groups
, clr_config_init_groups
, },
231 { "lxc.init.uid", true, set_config_init_uid
, get_config_init_uid
, clr_config_init_uid
, },
232 { "lxc.init.cwd", true, set_config_init_cwd
, get_config_init_cwd
, clr_config_init_cwd
, },
233 { "lxc.keyring.session", true, set_config_keyring_session
, get_config_keyring_session
, clr_config_keyring_session
},
234 { "lxc.log.file", true, set_config_log_file
, get_config_log_file
, clr_config_log_file
, },
235 { "lxc.log.level", true, set_config_log_level
, get_config_log_level
, clr_config_log_level
, },
236 { "lxc.log.syslog", true, set_config_log_syslog
, get_config_log_syslog
, clr_config_log_syslog
, },
237 { "lxc.monitor.unshare", true, set_config_monitor
, get_config_monitor
, clr_config_monitor
, },
238 { "lxc.monitor.signal.pdeath", true, set_config_monitor_signal_pdeath
, get_config_monitor_signal_pdeath
, clr_config_monitor_signal_pdeath
, },
239 { "lxc.mount.auto", true, set_config_mount_auto
, get_config_mount_auto
, clr_config_mount_auto
, },
240 { "lxc.mount.entry", true, set_config_mount
, get_config_mount
, clr_config_mount
, },
241 { "lxc.mount.fstab", true, set_config_mount_fstab
, get_config_mount_fstab
, clr_config_mount_fstab
, },
242 { "lxc.namespace.clone", true, set_config_namespace_clone
, get_config_namespace_clone
, clr_config_namespace_clone
, },
243 { "lxc.namespace.keep", true, set_config_namespace_keep
, get_config_namespace_keep
, clr_config_namespace_keep
, },
244 { "lxc.namespace.share.", false, set_config_namespace_share
, get_config_namespace_share
, clr_config_namespace_share
, },
245 { "lxc.time.offset.boot", true, set_config_time_offset_boot
, get_config_time_offset_boot
, clr_config_time_offset_boot
, },
246 { "lxc.time.offset.monotonic", true, set_config_time_offset_monotonic
, get_config_time_offset_monotonic
, clr_config_time_offset_monotonic
, },
247 { "lxc.net.", false, set_config_jump_table_net
, get_config_jump_table_net
, clr_config_jump_table_net
, },
248 { "lxc.net", true, set_config_net
, get_config_net
, clr_config_net
, },
249 { "lxc.no_new_privs", true, set_config_no_new_privs
, get_config_no_new_privs
, clr_config_no_new_privs
, },
250 { "lxc.prlimit", false, set_config_prlimit
, get_config_prlimit
, clr_config_prlimit
, },
251 { "lxc.pty.max", true, set_config_pty_max
, get_config_pty_max
, clr_config_pty_max
, },
252 { "lxc.rootfs.managed", true, set_config_rootfs_managed
, get_config_rootfs_managed
, clr_config_rootfs_managed
, },
253 { "lxc.rootfs.mount", true, set_config_rootfs_mount
, get_config_rootfs_mount
, clr_config_rootfs_mount
, },
254 { "lxc.rootfs.options", true, set_config_rootfs_options
, get_config_rootfs_options
, clr_config_rootfs_options
, },
255 { "lxc.rootfs.path", true, set_config_rootfs_path
, get_config_rootfs_path
, clr_config_rootfs_path
, },
256 { "lxc.seccomp.allow_nesting", true, set_config_seccomp_allow_nesting
, get_config_seccomp_allow_nesting
, clr_config_seccomp_allow_nesting
, },
257 { "lxc.seccomp.notify.cookie", true, set_config_seccomp_notify_cookie
, get_config_seccomp_notify_cookie
, clr_config_seccomp_notify_cookie
, },
258 { "lxc.seccomp.notify.proxy", true, set_config_seccomp_notify_proxy
, get_config_seccomp_notify_proxy
, clr_config_seccomp_notify_proxy
, },
259 { "lxc.seccomp.profile", true, set_config_seccomp_profile
, get_config_seccomp_profile
, clr_config_seccomp_profile
, },
260 { "lxc.selinux.context.keyring", true, set_config_selinux_context_keyring
, get_config_selinux_context_keyring
, clr_config_selinux_context_keyring
},
261 { "lxc.selinux.context", true, set_config_selinux_context
, get_config_selinux_context
, clr_config_selinux_context
, },
262 { "lxc.signal.halt", true, set_config_signal_halt
, get_config_signal_halt
, clr_config_signal_halt
, },
263 { "lxc.signal.reboot", true, set_config_signal_reboot
, get_config_signal_reboot
, clr_config_signal_reboot
, },
264 { "lxc.signal.stop", true, set_config_signal_stop
, get_config_signal_stop
, clr_config_signal_stop
, },
265 { "lxc.start.auto", true, set_config_start
, get_config_start
, clr_config_start
, },
266 { "lxc.start.delay", true, set_config_start
, get_config_start
, clr_config_start
, },
267 { "lxc.start.order", true, set_config_start
, get_config_start
, clr_config_start
, },
268 { "lxc.tty.dir", true, set_config_tty_dir
, get_config_tty_dir
, clr_config_tty_dir
, },
269 { "lxc.tty.max", true, set_config_tty_max
, get_config_tty_max
, clr_config_tty_max
, },
270 { "lxc.uts.name", true, set_config_uts_name
, get_config_uts_name
, clr_config_uts_name
, },
271 { "lxc.sysctl", false, set_config_sysctl
, get_config_sysctl
, clr_config_sysctl
, },
272 { "lxc.proc", false, set_config_proc
, get_config_proc
, clr_config_proc
, },
275 static struct lxc_config_t unsupported_config_key
= {
278 set_config_unsupported_key
,
279 get_config_unsupported_key
,
280 clr_config_unsupported_key
,
283 struct lxc_config_net_t
{
287 static struct lxc_config_net_t config_jump_table_net
[] = {
288 /* If a longer key is added please update. */
289 #define NETWORK_SUBKEY_SIZE_MAX (STRLITERALLEN("veth.vlan.tagged.id") * 2)
290 { "flags", true, set_config_net_flags
, get_config_net_flags
, clr_config_net_flags
, },
291 { "hwaddr", true, set_config_net_hwaddr
, get_config_net_hwaddr
, clr_config_net_hwaddr
, },
292 { "ipv4.address", true, set_config_net_ipv4_address
, get_config_net_ipv4_address
, clr_config_net_ipv4_address
, },
293 { "ipv4.gateway", true, set_config_net_ipv4_gateway
, get_config_net_ipv4_gateway
, clr_config_net_ipv4_gateway
, },
294 { "ipv6.address", true, set_config_net_ipv6_address
, get_config_net_ipv6_address
, clr_config_net_ipv6_address
, },
295 { "ipv6.gateway", true, set_config_net_ipv6_gateway
, get_config_net_ipv6_gateway
, clr_config_net_ipv6_gateway
, },
296 { "link", true, set_config_net_link
, get_config_net_link
, clr_config_net_link
, },
297 { "l2proxy", true, set_config_net_l2proxy
, get_config_net_l2proxy
, clr_config_net_l2proxy
, },
298 { "macvlan.mode", true, set_config_net_macvlan_mode
, get_config_net_macvlan_mode
, clr_config_net_macvlan_mode
, },
299 { "ipvlan.mode", true, set_config_net_ipvlan_mode
, get_config_net_ipvlan_mode
, clr_config_net_ipvlan_mode
, },
300 { "ipvlan.isolation", true, set_config_net_ipvlan_isolation
, get_config_net_ipvlan_isolation
, clr_config_net_ipvlan_isolation
, },
301 { "mtu", true, set_config_net_mtu
, get_config_net_mtu
, clr_config_net_mtu
, },
302 { "name", true, set_config_net_name
, get_config_net_name
, clr_config_net_name
, },
303 { "script.down", true, set_config_net_script_down
, get_config_net_script_down
, clr_config_net_script_down
, },
304 { "script.up", true, set_config_net_script_up
, get_config_net_script_up
, clr_config_net_script_up
, },
305 { "type", true, set_config_net_type
, get_config_net_type
, clr_config_net_type
, },
306 { "vlan.id", true, set_config_net_vlan_id
, get_config_net_vlan_id
, clr_config_net_vlan_id
, },
307 { "veth.mode", true, set_config_net_veth_mode
, get_config_net_veth_mode
, clr_config_net_veth_mode
, },
308 { "veth.pair", true, set_config_net_veth_pair
, get_config_net_veth_pair
, clr_config_net_veth_pair
, },
309 { "veth.ipv4.route", true, set_config_net_veth_ipv4_route
, get_config_net_veth_ipv4_route
, clr_config_net_veth_ipv4_route
, },
310 { "veth.ipv6.route", true, set_config_net_veth_ipv6_route
, get_config_net_veth_ipv6_route
, clr_config_net_veth_ipv6_route
, },
311 { "veth.vlan.id", true, set_config_net_veth_vlan_id
, get_config_net_veth_vlan_id
, clr_config_net_veth_vlan_id
, },
312 { "veth.vlan.tagged.id", true, set_config_net_veth_vlan_tagged_id
, get_config_net_veth_vlan_tagged_id
, clr_config_net_veth_vlan_tagged_id
, },
315 static struct lxc_config_net_t unsupported_config_net_key
= {
318 set_config_unsupported_key
,
319 get_config_unsupported_key
,
320 clr_config_unsupported_key
,
323 struct lxc_config_t
*lxc_get_config_exact(const char *key
)
327 for (i
= 0; i
< ARRAY_SIZE(config_jump_table
); i
++)
328 if (strequal(config_jump_table
[i
].name
, key
))
329 return &config_jump_table
[i
];
334 /* Assume a reasonable subkey size limit. */
335 #define LXC_SUBKEY_LEN_MAX 256
337 static inline int match_config_item(const struct lxc_config_t
*entry
, const char *key
)
342 return strequal(entry
->name
, key
);
344 /* There should be no subkey longer than this. */
345 len
= strnlen(entry
->name
, LXC_SUBKEY_LEN_MAX
);
346 if (len
== LXC_SUBKEY_LEN_MAX
)
347 return error_ret(-E2BIG
, "Excessive subkey length");
349 return strnequal(entry
->name
, key
, len
);
352 struct lxc_config_t
*lxc_get_config(const char *key
)
354 for (size_t i
= 0; i
< ARRAY_SIZE(config_jump_table
); i
++) {
355 struct lxc_config_t
*cur
= &config_jump_table
[i
];
357 switch (match_config_item(cur
, key
)) {
361 return &unsupported_config_key
;
367 return &unsupported_config_key
;
370 static inline bool match_config_net_item(const struct lxc_config_net_t
*entry
,
374 return strequal(entry
->name
, key
);
375 return strnequal(entry
->name
, key
, strlen(entry
->name
));
378 static struct lxc_config_net_t
*lxc_get_config_net(const char *key
)
380 for (size_t i
= 0; i
< ARRAY_SIZE(config_jump_table_net
); i
++) {
381 struct lxc_config_net_t
*cur
= &config_jump_table_net
[i
];
383 if (!match_config_net_item(cur
, key
))
389 return &unsupported_config_net_key
;
392 static int set_config_net(const char *key
, const char *value
,
393 struct lxc_conf
*lxc_conf
, void *data
)
395 if (!lxc_config_value_empty(value
))
396 return syserror_set(-EINVAL
, "lxc.net must not have a value");
398 return clr_config_net(key
, lxc_conf
, data
);
401 static int set_config_net_type(const char *key
, const char *value
,
402 struct lxc_conf
*lxc_conf
, void *data
)
404 struct lxc_netdev
*netdev
= data
;
407 return ret_errno(EINVAL
);
409 clr_config_net_type(key
, lxc_conf
, data
);
410 if (lxc_config_value_empty(value
))
413 if (strequal(value
, "veth")) {
414 netdev
->type
= LXC_NET_VETH
;
415 lxc_list_init(&netdev
->priv
.veth_attr
.ipv4_routes
);
416 lxc_list_init(&netdev
->priv
.veth_attr
.ipv6_routes
);
417 lxc_list_init(&netdev
->priv
.veth_attr
.vlan_tagged_ids
);
418 if (!lxc_veth_flag_to_mode(netdev
->priv
.veth_attr
.mode
))
419 lxc_veth_mode_to_flag(&netdev
->priv
.veth_attr
.mode
, "bridge");
420 } else if (strequal(value
, "macvlan")) {
421 netdev
->type
= LXC_NET_MACVLAN
;
422 if (!lxc_macvlan_flag_to_mode(netdev
->priv
.veth_attr
.mode
))
423 lxc_macvlan_mode_to_flag(&netdev
->priv
.macvlan_attr
.mode
, "private");
424 } else if (strequal(value
, "ipvlan")) {
425 netdev
->type
= LXC_NET_IPVLAN
;
426 if (!lxc_ipvlan_flag_to_mode(netdev
->priv
.ipvlan_attr
.mode
))
427 lxc_ipvlan_mode_to_flag(&netdev
->priv
.ipvlan_attr
.mode
, "l3");
428 if (!lxc_ipvlan_flag_to_isolation(netdev
->priv
.ipvlan_attr
.isolation
))
429 lxc_ipvlan_isolation_to_flag(&netdev
->priv
.ipvlan_attr
.isolation
, "bridge");
430 } else if (strequal(value
, "vlan")) {
431 netdev
->type
= LXC_NET_VLAN
;
432 } else if (strequal(value
, "phys")) {
433 netdev
->type
= LXC_NET_PHYS
;
434 } else if (strequal(value
, "empty")) {
435 netdev
->type
= LXC_NET_EMPTY
;
436 /* We don't support custom loopback device names. */
437 (void)strlcpy(netdev
->name
, "lo", IFNAMSIZ
);
438 } else if (strequal(value
, "none")) {
439 netdev
->type
= LXC_NET_NONE
;
441 return log_error(-1, "Invalid network type %s", value
);
447 static int set_config_net_flags(const char *key
, const char *value
,
448 struct lxc_conf
*lxc_conf
, void *data
)
450 struct lxc_netdev
*netdev
= data
;
453 return ret_errno(EINVAL
);
455 if (lxc_config_value_empty(value
))
456 return clr_config_net_flags(key
, lxc_conf
, data
);
458 netdev
->flags
|= IFF_UP
;
463 static int create_matched_ifnames(const char *value
, struct lxc_conf
*lxc_conf
,
464 struct lxc_netdev
*netdev
)
466 call_cleaner(netns_freeifaddrs
) struct netns_ifaddrs
*ifaddr
= NULL
;
467 struct netns_ifaddrs
*ifa
;
470 const char *type_key
= "lxc.net.type";
471 const char *link_key
= "lxc.net.link";
472 const char *tmpvalue
= "phys";
474 if (netns_getifaddrs(&ifaddr
, -1, &(bool){false}) < 0)
475 return log_error_errno(-1, errno
, "Failed to get network interfaces");
477 for (ifa
= ifaddr
, n
= 0; ifa
!= NULL
; ifa
= ifa
->ifa_next
, n
++) {
481 if (ifa
->ifa_addr
->sa_family
!= AF_PACKET
)
484 if (strnequal(value
, ifa
->ifa_name
, strlen(value
) - 1)) {
485 ret
= set_config_net_type(type_key
, tmpvalue
, lxc_conf
,
488 ret
= set_config_net_link(
489 link_key
, ifa
->ifa_name
, lxc_conf
, netdev
);
491 ERROR("Failed to create matched ifnames");
495 ERROR("Failed to create matched ifnames");
504 static int set_config_net_link(const char *key
, const char *value
,
505 struct lxc_conf
*lxc_conf
, void *data
)
507 struct lxc_netdev
*netdev
= data
;
511 return ret_errno(EINVAL
);
513 if (lxc_config_value_empty(value
))
514 return clr_config_net_link(key
, lxc_conf
, data
);
516 if (value
[strlen(value
) - 1] == '+' && netdev
->type
== LXC_NET_PHYS
)
517 ret
= create_matched_ifnames(value
, lxc_conf
, netdev
);
519 ret
= network_ifname(netdev
->link
, value
, sizeof(netdev
->link
));
524 static int set_config_net_l2proxy(const char *key
, const char *value
,
525 struct lxc_conf
*lxc_conf
, void *data
)
527 struct lxc_netdev
*netdev
= data
;
528 unsigned int val
= 0;
532 return ret_errno(EINVAL
);
534 if (lxc_config_value_empty(value
))
535 return clr_config_net_l2proxy(key
, lxc_conf
, data
);
537 ret
= lxc_safe_uint(value
, &val
);
539 return ret_errno(ret
);
543 netdev
->l2proxy
= false;
546 netdev
->l2proxy
= true;
550 return ret_errno(EINVAL
);
553 static int set_config_net_name(const char *key
, const char *value
,
554 struct lxc_conf
*lxc_conf
, void *data
)
556 struct lxc_netdev
*netdev
= data
;
559 return ret_errno(EINVAL
);
561 if (lxc_config_value_empty(value
))
562 return clr_config_net_name(key
, lxc_conf
, data
);
564 return network_ifname(netdev
->name
, value
, sizeof(netdev
->name
));
568 static int set_config_net_veth_mode(const char *key
, const char *value
,
569 struct lxc_conf
*lxc_conf
, void *data
)
571 struct lxc_netdev
*netdev
= data
;
574 return ret_errno(EINVAL
);
576 if (netdev
->type
!= LXC_NET_VETH
)
577 return ret_errno(EINVAL
);
579 if (lxc_config_value_empty(value
))
580 return clr_config_net_veth_mode(key
, lxc_conf
, data
);
583 return ret_errno(EINVAL
);
585 return lxc_veth_mode_to_flag(&netdev
->priv
.veth_attr
.mode
, value
);
588 static int set_config_net_veth_pair(const char *key
, const char *value
,
589 struct lxc_conf
*lxc_conf
, void *data
)
591 struct lxc_netdev
*netdev
= data
;
594 return ret_errno(EINVAL
);
596 if (netdev
->type
!= LXC_NET_VETH
)
597 return ret_errno(EINVAL
);
599 if (lxc_config_value_empty(value
))
600 return clr_config_net_veth_pair(key
, lxc_conf
, data
);
602 return network_ifname(netdev
->priv
.veth_attr
.pair
, value
,
603 sizeof(netdev
->priv
.veth_attr
.pair
));
606 static int set_config_net_veth_vlan_id(const char *key
, const char *value
,
607 struct lxc_conf
*lxc_conf
, void *data
)
610 struct lxc_netdev
*netdev
= data
;
613 return ret_errno(EINVAL
);
615 if (netdev
->type
!= LXC_NET_VETH
)
616 return ret_errno(EINVAL
);
618 if (lxc_config_value_empty(value
))
619 return clr_config_net_veth_vlan_id(key
, lxc_conf
, data
);
621 if (strequal(value
, "none")) {
622 netdev
->priv
.veth_attr
.vlan_id
= BRIDGE_VLAN_NONE
;
624 unsigned short vlan_id
;
626 ret
= get_u16(&vlan_id
, value
, 0);
628 return ret_errno(EINVAL
);
630 if (vlan_id
> BRIDGE_VLAN_ID_MAX
)
631 return ret_errno(EINVAL
);
633 netdev
->priv
.veth_attr
.vlan_id
= vlan_id
;
636 netdev
->priv
.veth_attr
.vlan_id_set
= true;
640 static int set_config_net_veth_vlan_tagged_id(const char *key
, const char *value
,
641 struct lxc_conf
*lxc_conf
,
644 __do_free
struct lxc_list
*list
= NULL
;
646 unsigned short vlan_id
;
647 struct lxc_netdev
*netdev
= data
;
650 return ret_errno(EINVAL
);
652 if (netdev
->type
!= LXC_NET_VETH
)
653 return ret_errno(EINVAL
);
655 if (lxc_config_value_empty(value
))
656 return clr_config_net_veth_vlan_tagged_id(key
, lxc_conf
, data
);
658 ret
= get_u16(&vlan_id
, value
, 0);
660 return ret_errno(EINVAL
);
662 if (vlan_id
> BRIDGE_VLAN_ID_MAX
)
663 return ret_errno(EINVAL
);
665 list
= lxc_list_new();
667 return ret_errno(ENOMEM
);
669 list
->elem
= UINT_TO_PTR(vlan_id
);
671 lxc_list_add_tail(&netdev
->priv
.veth_attr
.vlan_tagged_ids
, move_ptr(list
));
676 static int set_config_net_macvlan_mode(const char *key
, const char *value
,
677 struct lxc_conf
*lxc_conf
, void *data
)
679 struct lxc_netdev
*netdev
= data
;
682 return ret_errno(EINVAL
);
684 if (netdev
->type
!= LXC_NET_MACVLAN
)
685 return ret_errno(EINVAL
);
687 if (lxc_config_value_empty(value
))
688 return clr_config_net_macvlan_mode(key
, lxc_conf
, data
);
690 return lxc_macvlan_mode_to_flag(&netdev
->priv
.macvlan_attr
.mode
, value
);
693 static int set_config_net_ipvlan_mode(const char *key
, const char *value
,
694 struct lxc_conf
*lxc_conf
, void *data
)
696 struct lxc_netdev
*netdev
= data
;
699 return ret_errno(EINVAL
);
701 if (netdev
->type
!= LXC_NET_IPVLAN
)
702 return syserror_set(-EINVAL
, "Invalid ipvlan mode \"%s\", can only be used with ipvlan network", value
);
704 if (lxc_config_value_empty(value
))
705 return clr_config_net_ipvlan_mode(key
, lxc_conf
, data
);
707 return lxc_ipvlan_mode_to_flag(&netdev
->priv
.ipvlan_attr
.mode
, value
);
710 static int set_config_net_ipvlan_isolation(const char *key
, const char *value
,
711 struct lxc_conf
*lxc_conf
, void *data
)
713 struct lxc_netdev
*netdev
= data
;
716 return ret_errno(EINVAL
);
718 if (netdev
->type
!= LXC_NET_IPVLAN
)
719 return syserror_set(-EINVAL
, "Invalid ipvlan isolation \"%s\", can only be used with ipvlan network", value
);
721 if (lxc_config_value_empty(value
))
722 return clr_config_net_ipvlan_isolation(key
, lxc_conf
, data
);
724 return lxc_ipvlan_isolation_to_flag(&netdev
->priv
.ipvlan_attr
.isolation
, value
);
727 static int set_config_net_hwaddr(const char *key
, const char *value
,
728 struct lxc_conf
*lxc_conf
, void *data
)
730 __do_free
char *new_value
= NULL
;
731 struct lxc_netdev
*netdev
= data
;
734 return ret_errno(EINVAL
);
736 clr_config_net_hwaddr(key
, lxc_conf
, data
);
737 if (lxc_config_value_empty(value
))
740 new_value
= strdup(value
);
742 return ret_errno(ENOMEM
);
744 rand_complete_hwaddr(new_value
);
745 if (!lxc_config_value_empty(new_value
))
746 netdev
->hwaddr
= move_ptr(new_value
);
751 static int set_config_net_vlan_id(const char *key
, const char *value
,
752 struct lxc_conf
*lxc_conf
, void *data
)
755 struct lxc_netdev
*netdev
= data
;
758 return ret_errno(EINVAL
);
760 if (netdev
->type
!= LXC_NET_VLAN
)
761 return ret_errno(EINVAL
);
763 if (lxc_config_value_empty(value
))
764 return clr_config_net_vlan_id(key
, lxc_conf
, data
);
766 ret
= get_u16(&netdev
->priv
.vlan_attr
.vid
, value
, 0);
773 static int set_config_net_mtu(const char *key
, const char *value
,
774 struct lxc_conf
*lxc_conf
, void *data
)
776 struct lxc_netdev
*netdev
= data
;
779 return ret_errno(EINVAL
);
781 clr_config_net_mtu(key
, lxc_conf
, data
);
782 if (lxc_config_value_empty(value
))
785 return set_config_string_item(&netdev
->mtu
, value
);
788 static int set_config_net_ipv4_address(const char *key
, const char *value
,
789 struct lxc_conf
*lxc_conf
, void *data
)
791 __do_free
char *addr
= NULL
;
792 __do_free
struct lxc_inetdev
*inetdev
= NULL
;
793 __do_free
struct lxc_list
*list
= NULL
;
795 struct lxc_netdev
*netdev
= data
;
796 char *cursor
, *slash
;
797 char *bcast
= NULL
, *prefix
= NULL
;
800 return ret_errno(EINVAL
);
802 if (lxc_config_value_empty(value
))
803 return clr_config_net_ipv4_address(key
, lxc_conf
, data
);
805 inetdev
= zalloc(sizeof(*inetdev
));
807 return ret_errno(ENOMEM
);
809 list
= lxc_list_new();
811 return ret_errno(ENOMEM
);
813 addr
= strdup(value
);
815 return ret_errno(ENOMEM
);
817 cursor
= strstr(addr
, " ");
823 slash
= strstr(addr
, "/");
829 ret
= inet_pton(AF_INET
, addr
, &inetdev
->addr
);
831 return log_error_errno(-1, errno
, "Invalid ipv4 address \"%s\"", value
);
834 ret
= inet_pton(AF_INET
, bcast
, &inetdev
->bcast
);
836 return log_error_errno(-1, errno
, "Invalid ipv4 broadcast address \"%s\"", value
);
840 /* No prefix specified, determine it from the network class. */
843 ret
= lxc_safe_uint(prefix
, &inetdev
->prefix
);
845 inetdev
->prefix
= config_ip_prefix(&inetdev
->addr
);
846 if (ret
|| inetdev
->prefix
> 32)
847 return ret_errno(EINVAL
);
849 /* If no broadcast address, compute one from the prefix and address. */
851 unsigned int shift
= LAST_BIT_PER_TYPE(inetdev
->prefix
);
853 inetdev
->bcast
.s_addr
= inetdev
->addr
.s_addr
;
854 if (inetdev
->prefix
< shift
)
855 shift
= inetdev
->prefix
;
856 inetdev
->bcast
.s_addr
|= htonl(INADDR_BROADCAST
>> shift
);
859 list
->elem
= inetdev
;
860 lxc_list_add_tail(&netdev
->ipv4
, list
);
867 static int set_config_net_ipv4_gateway(const char *key
, const char *value
,
868 struct lxc_conf
*lxc_conf
, void *data
)
870 struct lxc_netdev
*netdev
= data
;
873 return ret_errno(EINVAL
);
875 clr_config_net_ipv4_gateway(key
, lxc_conf
, data
);
876 if (lxc_config_value_empty(value
))
879 if (strequal(value
, "auto")) {
880 netdev
->ipv4_gateway
= NULL
;
881 netdev
->ipv4_gateway_auto
= true;
882 } else if (strequal(value
, "dev")) {
883 netdev
->ipv4_gateway
= NULL
;
884 netdev
->ipv4_gateway_auto
= false;
885 netdev
->ipv4_gateway_dev
= true;
887 __do_free
struct in_addr
*gw
= NULL
;
890 gw
= zalloc(sizeof(*gw
));
892 return ret_errno(ENOMEM
);
894 ret
= inet_pton(AF_INET
, value
, gw
);
896 return log_error_errno(-1, errno
, "Invalid ipv4 gateway address \"%s\"", value
);
898 netdev
->ipv4_gateway
= move_ptr(gw
);
899 netdev
->ipv4_gateway_auto
= false;
905 static int set_config_net_veth_ipv4_route(const char *key
, const char *value
,
906 struct lxc_conf
*lxc_conf
, void *data
)
908 __do_free
char *valdup
= NULL
;
909 __do_free
struct lxc_inetdev
*inetdev
= NULL
;
910 __do_free
struct lxc_list
*list
= NULL
;
912 char *netmask
, *slash
;
913 struct lxc_netdev
*netdev
= data
;
916 return ret_errno(EINVAL
);
918 if (netdev
->type
!= LXC_NET_VETH
)
919 return syserror_set(-EINVAL
, "Invalid ipv4 route \"%s\", can only be used with veth network", value
);
921 if (lxc_config_value_empty(value
))
922 return clr_config_net_veth_ipv4_route(key
, lxc_conf
, data
);
924 inetdev
= zalloc(sizeof(*inetdev
));
926 return ret_errno(ENOMEM
);
928 list
= lxc_list_new();
930 return ret_errno(ENOMEM
);
932 list
->elem
= inetdev
;
934 valdup
= strdup(value
);
936 return ret_errno(ENOMEM
);
938 slash
= strchr(valdup
, '/');
940 return ret_errno(EINVAL
);
945 return ret_errno(EINVAL
);
949 ret
= lxc_safe_uint(netmask
, &inetdev
->prefix
);
950 if (ret
< 0 || inetdev
->prefix
> 32)
951 return ret_errno(EINVAL
);
953 ret
= inet_pton(AF_INET
, valdup
, &inetdev
->addr
);
955 return ret_errno(EINVAL
);
957 lxc_list_add_tail(&netdev
->priv
.veth_attr
.ipv4_routes
, list
);
964 static int set_config_net_ipv6_address(const char *key
, const char *value
,
965 struct lxc_conf
*lxc_conf
, void *data
)
967 __do_free
char *valdup
= NULL
;
968 __do_free
struct lxc_inet6dev
*inet6dev
= NULL
;
969 __do_free
struct lxc_list
*list
= NULL
;
971 struct lxc_netdev
*netdev
= data
;
972 char *slash
, *netmask
;
975 return ret_errno(EINVAL
);
977 if (lxc_config_value_empty(value
))
978 return clr_config_net_ipv6_address(key
, lxc_conf
, data
);
980 inet6dev
= zalloc(sizeof(*inet6dev
));
982 return ret_errno(ENOMEM
);
984 list
= lxc_list_new();
986 return ret_errno(ENOMEM
);
988 valdup
= strdup(value
);
990 return ret_errno(ENOMEM
);
992 inet6dev
->prefix
= 64;
993 slash
= strstr(valdup
, "/");
998 ret
= lxc_safe_uint(netmask
, &inet6dev
->prefix
);
1003 ret
= inet_pton(AF_INET6
, valdup
, &inet6dev
->addr
);
1004 if (!ret
|| ret
< 0)
1005 return log_error_errno(-EINVAL
, EINVAL
, "Invalid ipv6 address \"%s\"", valdup
);
1007 list
->elem
= inet6dev
;
1008 lxc_list_add_tail(&netdev
->ipv6
, list
);
1015 static int set_config_net_ipv6_gateway(const char *key
, const char *value
,
1016 struct lxc_conf
*lxc_conf
, void *data
)
1018 struct lxc_netdev
*netdev
= data
;
1021 return ret_errno(EINVAL
);
1023 clr_config_net_ipv6_gateway(key
, lxc_conf
, data
);
1024 if (lxc_config_value_empty(value
))
1027 if (strequal(value
, "auto")) {
1028 netdev
->ipv6_gateway
= NULL
;
1029 netdev
->ipv6_gateway_auto
= true;
1030 } else if (strequal(value
, "dev")) {
1031 netdev
->ipv6_gateway
= NULL
;
1032 netdev
->ipv6_gateway_auto
= false;
1033 netdev
->ipv6_gateway_dev
= true;
1036 __do_free
struct in6_addr
*gw
= NULL
;
1038 gw
= zalloc(sizeof(*gw
));
1040 return ret_errno(ENOMEM
);
1042 ret
= inet_pton(AF_INET6
, value
, gw
);
1043 if (!ret
|| ret
< 0)
1044 return log_error_errno(-EINVAL
, EINVAL
,
1045 "Invalid ipv6 gateway address \"%s\"", value
);
1047 netdev
->ipv6_gateway
= move_ptr(gw
);
1048 netdev
->ipv6_gateway_auto
= false;
1054 static int set_config_net_veth_ipv6_route(const char *key
, const char *value
,
1055 struct lxc_conf
*lxc_conf
, void *data
)
1057 __do_free
char *valdup
= NULL
;
1058 __do_free
struct lxc_inet6dev
*inet6dev
= NULL
;
1059 __do_free
struct lxc_list
*list
= NULL
;
1061 char *netmask
, *slash
;
1062 struct lxc_netdev
*netdev
= data
;
1065 return ret_errno(EINVAL
);
1067 if (netdev
->type
!= LXC_NET_VETH
)
1068 return syserror_set(-EINVAL
, "Invalid ipv6 route \"%s\", can only be used with veth network", value
);
1070 if (lxc_config_value_empty(value
))
1071 return clr_config_net_veth_ipv6_route(key
, lxc_conf
, data
);
1073 inet6dev
= zalloc(sizeof(*inet6dev
));
1075 return ret_errno(ENOMEM
);
1077 list
= lxc_list_new();
1079 return ret_errno(ENOMEM
);
1081 valdup
= strdup(value
);
1083 return ret_errno(ENOMEM
);
1085 slash
= strchr(valdup
, '/');
1087 return ret_errno(EINVAL
);
1092 return ret_errno(EINVAL
);
1096 ret
= lxc_safe_uint(netmask
, &inet6dev
->prefix
);
1097 if (ret
< 0 || inet6dev
->prefix
> 128)
1098 return ret_errno(EINVAL
);
1100 ret
= inet_pton(AF_INET6
, valdup
, &inet6dev
->addr
);
1101 if (!ret
|| ret
< 0)
1102 return ret_errno(EINVAL
);
1104 list
->elem
= inet6dev
;
1105 lxc_list_add_tail(&netdev
->priv
.veth_attr
.ipv6_routes
, list
);
1112 static int set_config_net_script_up(const char *key
, const char *value
,
1113 struct lxc_conf
*lxc_conf
, void *data
)
1115 struct lxc_netdev
*netdev
= data
;
1118 return ret_errno(EINVAL
);
1120 clr_config_net_script_up(key
, lxc_conf
, data
);
1121 if (lxc_config_value_empty(value
))
1124 return set_config_string_item(&netdev
->upscript
, value
);
1127 static int set_config_net_script_down(const char *key
, const char *value
,
1128 struct lxc_conf
*lxc_conf
, void *data
)
1130 struct lxc_netdev
*netdev
= data
;
1133 return ret_errno(EINVAL
);
1135 clr_config_net_script_down(key
, lxc_conf
, data
);
1136 if (lxc_config_value_empty(value
))
1139 return set_config_string_item(&netdev
->downscript
, value
);
1142 static int add_hook(struct lxc_conf
*lxc_conf
, int which
, __owns
char *hook
)
1144 __do_free
char *val
= hook
;
1145 struct lxc_list
*hooklist
;
1147 hooklist
= lxc_list_new();
1149 return ret_errno(ENOMEM
);
1151 hooklist
->elem
= move_ptr(val
);
1152 lxc_list_add_tail(&lxc_conf
->hooks
[which
], hooklist
);
1157 static int set_config_seccomp_allow_nesting(const char *key
, const char *value
,
1158 struct lxc_conf
*lxc_conf
, void *data
)
1161 if (lxc_config_value_empty(value
))
1162 return clr_config_seccomp_allow_nesting(key
, lxc_conf
, NULL
);
1164 if (lxc_safe_uint(value
, &lxc_conf
->seccomp
.allow_nesting
) < 0)
1167 if (lxc_conf
->seccomp
.allow_nesting
> 1)
1168 return ret_errno(EINVAL
);
1172 return ret_errno(ENOSYS
);
1176 static int set_config_seccomp_notify_cookie(const char *key
, const char *value
,
1177 struct lxc_conf
*lxc_conf
, void *data
)
1179 #ifdef HAVE_SECCOMP_NOTIFY
1180 return set_config_string_item(&lxc_conf
->seccomp
.notifier
.cookie
, value
);
1182 return ret_errno(ENOSYS
);
1186 static int set_config_seccomp_notify_proxy(const char *key
, const char *value
,
1187 struct lxc_conf
*lxc_conf
, void *data
)
1189 #ifdef HAVE_SECCOMP_NOTIFY
1192 if (lxc_config_value_empty(value
))
1193 return clr_config_seccomp_notify_proxy(key
, lxc_conf
, NULL
);
1195 if (!strnequal(value
, "unix:", 5))
1196 return ret_errno(EINVAL
);
1199 if (lxc_unix_sockaddr(&lxc_conf
->seccomp
.notifier
.proxy_addr
, offset
) < 0)
1204 return ret_errno(ENOSYS
);
1208 static int set_config_seccomp_profile(const char *key
, const char *value
,
1209 struct lxc_conf
*lxc_conf
, void *data
)
1212 return set_config_path_item(&lxc_conf
->seccomp
.seccomp
, value
);
1214 return ret_errno(ENOSYS
);
1218 static int set_config_execute_cmd(const char *key
, const char *value
,
1219 struct lxc_conf
*lxc_conf
, void *data
)
1221 return set_config_path_item(&lxc_conf
->execute_cmd
, value
);
1224 static int set_config_init_cmd(const char *key
, const char *value
,
1225 struct lxc_conf
*lxc_conf
, void *data
)
1227 return set_config_path_item(&lxc_conf
->init_cmd
, value
);
1230 static int set_config_init_cwd(const char *key
, const char *value
,
1231 struct lxc_conf
*lxc_conf
, void *data
)
1233 return set_config_path_item(&lxc_conf
->init_cwd
, value
);
1236 static int set_config_init_uid(const char *key
, const char *value
,
1237 struct lxc_conf
*lxc_conf
, void *data
)
1239 unsigned int init_uid
;
1241 if (lxc_config_value_empty(value
)) {
1242 lxc_conf
->init_uid
= 0;
1246 if (lxc_safe_uint(value
, &init_uid
) < 0)
1249 lxc_conf
->init_uid
= init_uid
;
1254 static int set_config_init_gid(const char *key
, const char *value
,
1255 struct lxc_conf
*lxc_conf
, void *data
)
1257 unsigned int init_gid
;
1259 if (lxc_config_value_empty(value
)) {
1260 lxc_conf
->init_gid
= 0;
1264 if (lxc_safe_uint(value
, &init_gid
) < 0)
1267 lxc_conf
->init_gid
= init_gid
;
1272 static int set_config_init_groups(const char *key
, const char *value
,
1273 struct lxc_conf
*lxc_conf
, void *data
)
1275 __do_free
char *value_dup
= NULL
;
1276 gid_t
*init_groups
= NULL
;
1277 size_t num_groups
= 0;
1281 if (lxc_config_value_empty(value
))
1282 return clr_config_init_groups(key
, lxc_conf
, NULL
);
1284 value_dup
= strdup(value
);
1288 lxc_iterate_parts(token
, value_dup
, ",")
1291 if (num_groups
== INT_MAX
)
1292 return log_error_errno(-ERANGE
, ERANGE
, "Excessive number of supplementary groups specified");
1294 /* This means the string wasn't empty and all we found was garbage. */
1295 if (num_groups
== 0)
1296 return log_error_errno(-EINVAL
, EINVAL
, "No valid groups specified %s", value
);
1298 idx
= lxc_conf
->init_groups
.size
;
1299 init_groups
= realloc(lxc_conf
->init_groups
.list
, sizeof(gid_t
) * (idx
+ num_groups
));
1301 return ret_errno(ENOMEM
);
1304 * Once the realloc() succeeded we need to hand control of the memory
1305 * back to the config otherwise we risk a double-free when
1306 * lxc_conf_free() is called.
1308 lxc_conf
->init_groups
.list
= init_groups
;
1310 /* Restore duplicated value so we can call lxc_iterate_parts() again. */
1311 strcpy(value_dup
, value
);
1313 lxc_iterate_parts(token
, value_dup
, ",") {
1318 ret
= lxc_safe_uint(token
, &group
);
1320 return log_error_errno(ret
, -ret
, "Failed to parse group %s", token
);
1322 init_groups
[idx
++] = group
;
1325 lxc_conf
->init_groups
.size
+= num_groups
;
1330 static int set_config_hooks(const char *key
, const char *value
,
1331 struct lxc_conf
*lxc_conf
, void *data
)
1333 __do_free
char *copy
= NULL
;
1335 if (lxc_config_value_empty(value
))
1336 return lxc_clear_hooks(lxc_conf
, key
);
1338 if (strequal(key
+ 4, "hook"))
1339 return log_error_errno(-EINVAL
, EINVAL
, "lxc.hook must not have a value");
1341 copy
= strdup(value
);
1343 return ret_errno(ENOMEM
);
1345 if (strequal(key
+ 9, "pre-start"))
1346 return add_hook(lxc_conf
, LXCHOOK_PRESTART
, move_ptr(copy
));
1347 else if (strequal(key
+ 9, "start-host"))
1348 return add_hook(lxc_conf
, LXCHOOK_START_HOST
, move_ptr(copy
));
1349 else if (strequal(key
+ 9, "pre-mount"))
1350 return add_hook(lxc_conf
, LXCHOOK_PREMOUNT
, move_ptr(copy
));
1351 else if (strequal(key
+ 9, "autodev"))
1352 return add_hook(lxc_conf
, LXCHOOK_AUTODEV
, move_ptr(copy
));
1353 else if (strequal(key
+ 9, "mount"))
1354 return add_hook(lxc_conf
, LXCHOOK_MOUNT
, move_ptr(copy
));
1355 else if (strequal(key
+ 9, "start"))
1356 return add_hook(lxc_conf
, LXCHOOK_START
, move_ptr(copy
));
1357 else if (strequal(key
+ 9, "stop"))
1358 return add_hook(lxc_conf
, LXCHOOK_STOP
, move_ptr(copy
));
1359 else if (strequal(key
+ 9, "post-stop"))
1360 return add_hook(lxc_conf
, LXCHOOK_POSTSTOP
, move_ptr(copy
));
1361 else if (strequal(key
+ 9, "clone"))
1362 return add_hook(lxc_conf
, LXCHOOK_CLONE
, move_ptr(copy
));
1363 else if (strequal(key
+ 9, "destroy"))
1364 return add_hook(lxc_conf
, LXCHOOK_DESTROY
, move_ptr(copy
));
1366 return ret_errno(EINVAL
);
1369 static int set_config_hooks_version(const char *key
, const char *value
,
1370 struct lxc_conf
*lxc_conf
, void *data
)
1375 if (lxc_config_value_empty(value
))
1376 return clr_config_hooks_version(key
, lxc_conf
, NULL
);
1378 ret
= lxc_safe_uint(value
, &tmp
);
1383 return syserror_set(-EINVAL
, "Invalid hook version specified. Currently only 0 (legacy) and 1 are supported");
1385 lxc_conf
->hooks_version
= tmp
;
1390 static int set_config_personality(const char *key
, const char *value
,
1391 struct lxc_conf
*lxc_conf
, void *data
)
1394 personality_t personality
;
1396 ret
= lxc_config_parse_arch(value
, &personality
);
1398 return syserror("Unsupported personality \"%s\"", value
);
1400 lxc_conf
->personality
= personality
;
1404 static int set_config_pty_max(const char *key
, const char *value
,
1405 struct lxc_conf
*lxc_conf
, void *data
)
1408 unsigned int max
= 0;
1410 if (lxc_config_value_empty(value
)) {
1411 lxc_conf
->pty_max
= 0;
1415 ret
= lxc_safe_uint(value
, &max
);
1417 return ret_errno(EINVAL
);
1419 lxc_conf
->pty_max
= max
;
1424 /* We only need to check whether the first byte of the key after the lxc.start.
1425 * prefix matches our expectations since they fortunately all start with a
1426 * different letter. If anything was wrong with the key we would have already
1427 * noticed when the callback was called.
1429 static int set_config_start(const char *key
, const char *value
,
1430 struct lxc_conf
*lxc_conf
, void *data
)
1435 is_empty
= lxc_config_value_empty(value
);
1437 if (*(key
+ 10) == 'a') { /* lxc.start.auto */
1439 lxc_conf
->start_auto
= 0;
1443 ret
= lxc_safe_uint(value
, &lxc_conf
->start_auto
);
1447 if (lxc_conf
->start_auto
> 1)
1448 return ret_errno(EINVAL
);
1451 } else if (*(key
+ 10) == 'd') { /* lxc.start.delay */
1453 lxc_conf
->start_delay
= 0;
1457 return lxc_safe_uint(value
, &lxc_conf
->start_delay
);
1458 } else if (*(key
+ 10) == 'o') { /* lxc.start.order */
1460 lxc_conf
->start_order
= 0;
1464 return lxc_safe_int(value
, &lxc_conf
->start_order
);
1467 return ret_errno(EINVAL
);
1470 static int set_config_monitor(const char *key
, const char *value
,
1471 struct lxc_conf
*lxc_conf
, void *data
)
1473 if (lxc_config_value_empty(value
)) {
1474 lxc_conf
->monitor_unshare
= 0;
1478 if (strequal(key
+ 12, "unshare"))
1479 return lxc_safe_uint(value
, &lxc_conf
->monitor_unshare
);
1481 return ret_errno(EINVAL
);
1484 static int set_config_monitor_signal_pdeath(const char *key
, const char *value
,
1485 struct lxc_conf
*lxc_conf
, void *data
)
1487 if (lxc_config_value_empty(value
)) {
1488 lxc_conf
->monitor_signal_pdeath
= 0;
1492 if (strequal(key
+ 12, "signal.pdeath")) {
1495 sig_n
= sig_parse(value
);
1497 return ret_errno(EINVAL
);
1499 lxc_conf
->monitor_signal_pdeath
= sig_n
;
1503 return ret_errno(EINVAL
);
1506 static int set_config_group(const char *key
, const char *value
,
1507 struct lxc_conf
*lxc_conf
, void *data
)
1509 __do_free
char *groups
= NULL
;
1512 if (lxc_config_value_empty(value
))
1513 return lxc_clear_groups(lxc_conf
);
1515 groups
= strdup(value
);
1517 return ret_errno(ENOMEM
);
1519 /* In case several groups are specified in a single line split these
1520 * groups in a single element for the list.
1522 lxc_iterate_parts(token
, groups
, " \t") {
1523 __do_free
struct lxc_list
*grouplist
= NULL
;
1525 grouplist
= lxc_list_new();
1527 return ret_errno(ENOMEM
);
1529 grouplist
->elem
= strdup(token
);
1530 if (!grouplist
->elem
)
1531 return ret_errno(ENOMEM
);
1533 lxc_list_add_tail(&lxc_conf
->groups
, move_ptr(grouplist
));
1539 static int set_config_environment(const char *key
, const char *value
,
1540 struct lxc_conf
*lxc_conf
, void *data
)
1542 __do_free
char *dup
= NULL
, *val
= NULL
;
1543 __do_free
struct environment_entry
*new_env
= NULL
;
1546 if (lxc_config_value_empty(value
))
1547 return lxc_clear_environment(lxc_conf
);
1549 new_env
= zalloc(sizeof(struct environment_entry
));
1551 return ret_errno(ENOMEM
);
1553 dup
= strdup(value
);
1555 return ret_errno(ENOMEM
);
1557 env_val
= strchr(dup
, '=');
1559 env_val
= getenv(dup
);
1565 return ret_errno(ENOENT
);
1567 val
= strdup(env_val
);
1569 return ret_errno(ENOMEM
);
1571 new_env
->key
= move_ptr(dup
);
1572 new_env
->val
= move_ptr(val
);
1574 list_add_tail(&new_env
->head
, &lxc_conf
->environment
);
1580 static int set_config_tty_max(const char *key
, const char *value
,
1581 struct lxc_conf
*lxc_conf
, void *data
)
1584 unsigned int nbtty
= 0;
1586 if (lxc_config_value_empty(value
)) {
1587 lxc_conf
->ttys
.max
= 0;
1591 ret
= lxc_safe_uint(value
, &nbtty
);
1595 lxc_conf
->ttys
.max
= nbtty
;
1600 static int set_config_tty_dir(const char *key
, const char *value
,
1601 struct lxc_conf
*lxc_conf
, void *data
)
1603 return set_config_string_item_max(&lxc_conf
->ttys
.dir
, value
,
1607 static int set_config_apparmor_profile(const char *key
, const char *value
,
1608 struct lxc_conf
*lxc_conf
, void *data
)
1611 return set_config_string_item(&lxc_conf
->lsm_aa_profile
, value
);
1613 return syserror_set(-EINVAL
, "Built without AppArmor support");
1617 static int set_config_apparmor_allow_incomplete(const char *key
,
1619 struct lxc_conf
*lxc_conf
,
1625 if (lxc_config_value_empty(value
)) {
1626 lxc_conf
->lsm_aa_allow_incomplete
= 0;
1630 ret
= lxc_safe_uint(value
, &lxc_conf
->lsm_aa_allow_incomplete
);
1634 if (lxc_conf
->lsm_aa_allow_incomplete
> 1)
1635 return ret_errno(EINVAL
);
1639 return syserror_set(-EINVAL
, "Built without AppArmor support");
1643 static int set_config_apparmor_allow_nesting(const char *key
,
1645 struct lxc_conf
*lxc_conf
,
1651 if (lxc_config_value_empty(value
))
1652 return clr_config_apparmor_allow_nesting(key
, lxc_conf
, NULL
);
1654 ret
= lxc_safe_uint(value
, &lxc_conf
->lsm_aa_allow_nesting
);
1658 if (lxc_conf
->lsm_aa_allow_nesting
> 1)
1659 return ret_errno(EINVAL
);
1663 return syserror_set(-EINVAL
, "Built without AppArmor support");
1667 static int set_config_apparmor_raw(const char *key
,
1669 struct lxc_conf
*lxc_conf
,
1673 __do_free
char *elem
= NULL
;
1674 __do_free
struct lxc_list
*list
= NULL
;
1676 if (lxc_config_value_empty(value
))
1677 return lxc_clear_apparmor_raw(lxc_conf
);
1679 list
= lxc_list_new();
1681 return ret_errno(ENOMEM
);
1683 elem
= strdup(value
);
1685 return ret_errno(ENOMEM
);
1687 list
->elem
= move_ptr(elem
);
1688 lxc_list_add_tail(&lxc_conf
->lsm_aa_raw
, move_ptr(list
));
1692 return syserror_set(-EINVAL
, "Built without AppArmor support");
1696 static int set_config_selinux_context(const char *key
, const char *value
,
1697 struct lxc_conf
*lxc_conf
, void *data
)
1700 return set_config_string_item(&lxc_conf
->lsm_se_context
, value
);
1702 return syserror_set(-EINVAL
, "Built without SELinux support");
1706 static int set_config_selinux_context_keyring(const char *key
, const char *value
,
1707 struct lxc_conf
*lxc_conf
, void *data
)
1710 return set_config_string_item(&lxc_conf
->lsm_se_keyring_context
, value
);
1712 return syserror_set(-EINVAL
, "Built without SELinux support");
1716 static int set_config_keyring_session(const char *key
, const char *value
,
1717 struct lxc_conf
*lxc_conf
, void *data
)
1719 return set_config_bool_item(&lxc_conf
->keyring_disable_session
, value
, false);
1722 static int set_config_log_file(const char *key
, const char *value
,
1723 struct lxc_conf
*c
, void *data
)
1727 if (lxc_config_value_empty(value
)) {
1728 free_disarm(c
->logfile
);
1733 * Store these values in the lxc_conf, and then try to set for actual
1736 ret
= set_config_path_item(&c
->logfile
, value
);
1738 ret
= lxc_log_set_file(&c
->logfd
, c
->logfile
);
1743 static int set_config_log_level(const char *key
, const char *value
,
1744 struct lxc_conf
*lxc_conf
, void *data
)
1748 if (lxc_config_value_empty(value
)) {
1749 lxc_conf
->loglevel
= LXC_LOG_LEVEL_NOTSET
;
1753 if (value
[0] >= '0' && value
[0] <= '9') {
1756 ret
= lxc_safe_int(value
, &newlevel
);
1758 return ret_errno(EINVAL
);
1760 newlevel
= lxc_log_priority_to_int(value
);
1764 * Store these values in the lxc_conf, and then try to set for actual
1767 lxc_conf
->loglevel
= newlevel
;
1769 return lxc_log_set_level(&lxc_conf
->loglevel
, newlevel
);
1772 static int set_config_autodev(const char *key
, const char *value
,
1773 struct lxc_conf
*lxc_conf
, void *data
)
1777 if (lxc_config_value_empty(value
)) {
1778 lxc_conf
->autodev
= 0;
1782 ret
= lxc_safe_uint(value
, &lxc_conf
->autodev
);
1784 return ret_errno(EINVAL
);
1786 if (lxc_conf
->autodev
> 1)
1787 return ret_errno(EINVAL
);
1792 static int set_config_autodev_tmpfs_size(const char *key
, const char *value
,
1793 struct lxc_conf
*lxc_conf
, void *data
)
1795 if (lxc_config_value_empty(value
)) {
1796 lxc_conf
->autodevtmpfssize
= 500000;
1800 if (lxc_safe_int(value
, &lxc_conf
->autodevtmpfssize
) < 0)
1801 lxc_conf
->autodevtmpfssize
= 500000;
1806 static int set_config_signal_halt(const char *key
, const char *value
,
1807 struct lxc_conf
*lxc_conf
, void *data
)
1811 if (lxc_config_value_empty(value
)) {
1812 lxc_conf
->haltsignal
= 0;
1816 sig_n
= sig_parse(value
);
1818 return ret_errno(EINVAL
);
1820 lxc_conf
->haltsignal
= sig_n
;
1825 static int set_config_signal_reboot(const char *key
, const char *value
,
1826 struct lxc_conf
*lxc_conf
, void *data
)
1830 if (lxc_config_value_empty(value
)) {
1831 lxc_conf
->rebootsignal
= 0;
1835 sig_n
= sig_parse(value
);
1837 return ret_errno(EINVAL
);
1839 lxc_conf
->rebootsignal
= sig_n
;
1844 static int set_config_signal_stop(const char *key
, const char *value
,
1845 struct lxc_conf
*lxc_conf
, void *data
)
1849 if (lxc_config_value_empty(value
)) {
1850 lxc_conf
->stopsignal
= 0;
1854 sig_n
= sig_parse(value
);
1856 return ret_errno(EINVAL
);
1858 lxc_conf
->stopsignal
= sig_n
;
1863 static int __set_config_cgroup_controller(const char *key
, const char *value
,
1864 struct lxc_conf
*lxc_conf
, int version
)
1866 call_cleaner(free_lxc_cgroup
) struct lxc_cgroup
*new_cgroup
= NULL
;
1867 const char *subkey
, *token
;
1870 if (lxc_config_value_empty(value
))
1871 return lxc_clear_cgroups(lxc_conf
, key
, version
);
1873 if (version
== CGROUP2_SUPER_MAGIC
) {
1874 token
= "lxc.cgroup2.";
1876 } else if (version
== CGROUP_SUPER_MAGIC
) {
1877 token
= "lxc.cgroup.";
1880 return ret_errno(EINVAL
);
1883 if (!strnequal(key
, token
, token_len
))
1884 return ret_errno(EINVAL
);
1886 subkey
= key
+ token_len
;
1887 if (*subkey
== '\0')
1888 return ret_errno(EINVAL
);
1890 new_cgroup
= zalloc(sizeof(*new_cgroup
));
1892 return ret_errno(ENOMEM
);
1894 new_cgroup
->subsystem
= strdup(subkey
);
1895 if (!new_cgroup
->subsystem
)
1896 return ret_errno(ENOMEM
);
1898 new_cgroup
->value
= strdup(value
);
1899 if (!new_cgroup
->value
)
1900 return ret_errno(ENOMEM
);
1902 new_cgroup
->version
= version
;
1904 if (version
== CGROUP2_SUPER_MAGIC
)
1905 list_add_tail(&new_cgroup
->head
, &lxc_conf
->cgroup2
);
1907 list_add_tail(&new_cgroup
->head
, &lxc_conf
->cgroup
);
1908 move_ptr(new_cgroup
);
1913 static int set_config_cgroup_controller(const char *key
, const char *value
,
1914 struct lxc_conf
*lxc_conf
, void *data
)
1916 return __set_config_cgroup_controller(key
, value
, lxc_conf
,
1917 CGROUP_SUPER_MAGIC
);
1920 static int set_config_cgroup2_controller(const char *key
, const char *value
,
1921 struct lxc_conf
*lxc_conf
, void *data
)
1923 return __set_config_cgroup_controller(key
, value
, lxc_conf
,
1924 CGROUP2_SUPER_MAGIC
);
1927 static int set_config_cgroup_dir(const char *key
, const char *value
,
1928 struct lxc_conf
*lxc_conf
, void *data
)
1930 if (!strequal(key
, "lxc.cgroup.dir"))
1931 return ret_errno(EINVAL
);
1933 if (lxc_config_value_empty(value
))
1934 return clr_config_cgroup_dir(key
, lxc_conf
, NULL
);
1937 return syserror_set(-EINVAL
, "%s paths may not be absolute", key
);
1940 return syserror_set(-EINVAL
, "%s paths may not walk upwards via \"../\"", key
);
1942 return set_config_path_item(&lxc_conf
->cgroup_meta
.dir
, value
);
1945 static int set_config_cgroup_monitor_dir(const char *key
, const char *value
,
1946 struct lxc_conf
*lxc_conf
, void *data
)
1948 if (lxc_config_value_empty(value
))
1949 return clr_config_cgroup_monitor_dir(key
, lxc_conf
, NULL
);
1952 return syserror_set(-EINVAL
, "%s paths may not be absolute", key
);
1955 return syserror_set(-EINVAL
, "%s paths may not walk upwards via \"../\"", key
);
1957 return set_config_path_item(&lxc_conf
->cgroup_meta
.monitor_dir
, value
);
1960 static int set_config_cgroup_monitor_pivot_dir(const char *key
, const char *value
,
1961 struct lxc_conf
*lxc_conf
, void *data
)
1963 if (lxc_config_value_empty(value
))
1964 return clr_config_cgroup_monitor_pivot_dir(key
, lxc_conf
, NULL
);
1967 return syserror_set(-EINVAL
, "%s paths may not be absolute", key
);
1970 return syserror_set(-EINVAL
, "%s paths may not walk upwards via \"../\"", key
);
1972 return set_config_path_item(&lxc_conf
->cgroup_meta
.monitor_pivot_dir
, value
);
1975 static int set_config_cgroup_container_dir(const char *key
, const char *value
,
1976 struct lxc_conf
*lxc_conf
,
1979 if (lxc_config_value_empty(value
))
1980 return clr_config_cgroup_container_dir(key
, lxc_conf
, NULL
);
1983 return syserror_set(-EINVAL
, "%s paths may not be absolute", key
);
1986 return syserror_set(-EINVAL
, "%s paths may not walk upwards via \"../\"", key
);
1988 return set_config_path_item(&lxc_conf
->cgroup_meta
.container_dir
, value
);
1991 static int set_config_cgroup_container_inner_dir(const char *key
,
1993 struct lxc_conf
*lxc_conf
,
1996 if (lxc_config_value_empty(value
))
1997 return clr_config_cgroup_container_inner_dir(key
, lxc_conf
, NULL
);
2000 return syserror_set(-EINVAL
, "%s paths may not be absolute", key
);
2002 if (strchr(value
, '/') || strequal(value
, ".") || strequal(value
, ".."))
2003 return log_error_errno(-EINVAL
, EINVAL
, "lxc.cgroup.dir.container.inner must be a single directory name");
2005 return set_config_string_item(&lxc_conf
->cgroup_meta
.namespace_dir
, value
);
2008 static int set_config_cgroup_relative(const char *key
, const char *value
,
2009 struct lxc_conf
*lxc_conf
, void *data
)
2011 unsigned int converted
;
2014 if (lxc_config_value_empty(value
))
2015 return clr_config_cgroup_relative(key
, lxc_conf
, NULL
);
2017 ret
= lxc_safe_uint(value
, &converted
);
2021 if (converted
== 1) {
2022 lxc_conf
->cgroup_meta
.relative
= true;
2026 if (converted
== 0) {
2027 lxc_conf
->cgroup_meta
.relative
= false;
2031 return ret_errno(EINVAL
);
2034 static bool parse_limit_value(const char **value
, rlim_t
*res
)
2036 char *endptr
= NULL
;
2038 if (strnequal(*value
, "unlimited", STRLITERALLEN("unlimited"))) {
2039 *res
= RLIM_INFINITY
;
2040 *value
+= STRLITERALLEN("unlimited");
2045 *res
= strtoull(*value
, &endptr
, 10);
2046 if (errno
|| !endptr
)
2054 static int set_config_prlimit(const char *key
, const char *value
,
2055 struct lxc_conf
*lxc_conf
, void *data
)
2057 call_cleaner(free_lxc_limit
) struct lxc_limit
*new_lim
= NULL
;
2058 struct rlimit limit
;
2060 struct lxc_limit
*lim
;
2062 if (lxc_config_value_empty(value
))
2063 return lxc_clear_limits(lxc_conf
, key
);
2065 if (!strnequal(key
, "lxc.prlimit.", STRLITERALLEN("lxc.prlimit.")))
2066 return ret_errno(EINVAL
);
2068 key
+= STRLITERALLEN("lxc.prlimit.");
2070 /* soft limit comes first in the value */
2071 if (!parse_limit_value(&value
, &limit_value
))
2072 return ret_errno(EINVAL
);
2074 limit
.rlim_cur
= limit_value
;
2076 /* skip spaces and a colon */
2077 while (isspace(*value
))
2082 else if (*value
) /* any other character is an error here */
2083 return ret_errno(EINVAL
);
2085 while (isspace(*value
))
2088 /* optional hard limit */
2090 if (!parse_limit_value(&value
, &limit_value
))
2091 return ret_errno(EINVAL
);
2093 limit
.rlim_max
= limit_value
;
2095 /* check for trailing garbage */
2096 while (isspace(*value
))
2100 return ret_errno(EINVAL
);
2102 /* a single value sets both hard and soft limit */
2103 limit
.rlim_max
= limit
.rlim_cur
;
2106 /* find existing list element */
2107 list_for_each_entry(lim
, &lxc_conf
->limits
, head
) {
2108 if (!strequal(key
, lim
->resource
))
2115 new_lim
= zalloc(sizeof(*new_lim
));
2117 return ret_errno(ENOMEM
);
2119 new_lim
->resource
= strdup(key
);
2120 if (!new_lim
->resource
)
2121 return ret_errno(ENOMEM
);
2123 new_lim
->limit
= limit
;
2124 list_add_tail(&new_lim
->head
, &lxc_conf
->limits
);
2130 static int set_config_sysctl(const char *key
, const char *value
,
2131 struct lxc_conf
*lxc_conf
, void *data
)
2133 call_cleaner(free_lxc_sysctl
) struct lxc_sysctl
*sysctl_elem
= NULL
;
2134 struct lxc_sysctl
*sysctl
, *nsysctl
;
2136 if (lxc_config_value_empty(value
))
2137 return clr_config_sysctl(key
, lxc_conf
, NULL
);
2139 if (!strnequal(key
, "lxc.sysctl.", STRLITERALLEN("lxc.sysctl.")))
2140 return ret_errno(EINVAL
);
2142 key
+= STRLITERALLEN("lxc.sysctl.");
2143 if (is_empty_string(key
))
2144 return ret_errno(EINVAL
);
2146 /* find existing list element */
2147 list_for_each_entry_safe(sysctl
, nsysctl
, &lxc_conf
->sysctls
, head
) {
2148 __do_free
char *replace_value
= NULL
;
2150 if (!strequal(key
, sysctl
->key
))
2153 replace_value
= strdup(value
);
2155 return ret_errno(EINVAL
);
2157 free(sysctl
->value
);
2158 sysctl
->value
= move_ptr(replace_value
);
2163 sysctl_elem
= zalloc(sizeof(*sysctl_elem
));
2165 return ret_errno(ENOMEM
);
2167 sysctl_elem
->key
= strdup(key
);
2168 if (!sysctl_elem
->key
)
2169 return ret_errno(ENOMEM
);
2171 sysctl_elem
->value
= strdup(value
);
2172 if (!sysctl_elem
->value
)
2173 return ret_errno(ENOMEM
);
2175 list_add_tail(&sysctl_elem
->head
, &lxc_conf
->sysctls
);
2176 move_ptr(sysctl_elem
);
2181 static int set_config_proc(const char *key
, const char *value
,
2182 struct lxc_conf
*lxc_conf
, void *data
)
2184 call_cleaner(free_lxc_proc
) struct lxc_proc
*new_proc
= NULL
;
2187 if (lxc_config_value_empty(value
))
2188 return clr_config_proc(key
, lxc_conf
, NULL
);
2190 if (!strnequal(key
, "lxc.proc.", STRLITERALLEN("lxc.proc.")))
2191 return ret_errno(EINVAL
);
2193 subkey
= key
+ STRLITERALLEN("lxc.proc.");
2194 if (*subkey
== '\0')
2195 return ret_errno(EINVAL
);
2197 new_proc
= zalloc(sizeof(*new_proc
));
2199 return ret_errno(ENOMEM
);
2201 new_proc
->filename
= strdup(subkey
);
2202 if (!new_proc
->filename
)
2203 return ret_errno(ENOMEM
);
2205 new_proc
->value
= strdup(value
);
2206 if (!new_proc
->value
)
2207 return ret_errno(ENOMEM
);
2209 list_add_tail(&new_proc
->head
, &lxc_conf
->procs
);
2215 static int set_config_idmaps(const char *key
, const char *value
,
2216 struct lxc_conf
*lxc_conf
, void *data
)
2218 __do_free
struct id_map
*idmap
= NULL
;
2219 unsigned long hostid
, nsid
, range
;
2223 if (lxc_config_value_empty(value
))
2224 return lxc_clear_idmaps(lxc_conf
);
2226 idmap
= zalloc(sizeof(*idmap
));
2228 return ret_errno(ENOMEM
);
2230 ret
= parse_idmaps(value
, &type
, &nsid
, &hostid
, &range
);
2232 return log_error_errno(-EINVAL
, EINVAL
, "Failed to parse id mappings");
2234 INFO("Read uid map: type %c nsid %lu hostid %lu range %lu", type
, nsid
, hostid
, range
);
2236 idmap
->idtype
= ID_TYPE_UID
;
2237 else if (type
== 'g')
2238 idmap
->idtype
= ID_TYPE_GID
;
2240 return ret_errno(EINVAL
);
2242 idmap
->hostid
= hostid
;
2244 idmap
->range
= range
;
2245 list_add_tail(&idmap
->head
, &lxc_conf
->id_map
);
2247 if (!lxc_conf
->root_nsuid_map
&& idmap
->idtype
== ID_TYPE_UID
)
2248 if (idmap
->nsid
== 0)
2249 lxc_conf
->root_nsuid_map
= idmap
;
2251 if (!lxc_conf
->root_nsgid_map
&& idmap
->idtype
== ID_TYPE_GID
)
2252 if (idmap
->nsid
== 0)
2253 lxc_conf
->root_nsgid_map
= idmap
;
2260 static int set_config_mount_fstab(const char *key
, const char *value
,
2261 struct lxc_conf
*lxc_conf
, void *data
)
2263 if (lxc_config_value_empty(value
)) {
2264 clr_config_mount_fstab(key
, lxc_conf
, NULL
);
2265 return ret_errno(EINVAL
);
2268 return set_config_path_item(&lxc_conf
->fstab
, value
);
2271 static int set_config_mount_auto(const char *key
, const char *value
,
2272 struct lxc_conf
*lxc_conf
, void *data
)
2274 __do_free
char *autos
= NULL
;
2281 } allowed_auto_mounts
[] = {
2282 { "proc", LXC_AUTO_PROC_MASK
, LXC_AUTO_PROC_MIXED
},
2283 { "proc:mixed", LXC_AUTO_PROC_MASK
, LXC_AUTO_PROC_MIXED
},
2284 { "proc:rw", LXC_AUTO_PROC_MASK
, LXC_AUTO_PROC_RW
},
2285 { "sys", LXC_AUTO_SYS_MASK
, LXC_AUTO_SYS_MIXED
},
2286 { "sys:ro", LXC_AUTO_SYS_MASK
, LXC_AUTO_SYS_RO
},
2287 { "sys:mixed", LXC_AUTO_SYS_MASK
, LXC_AUTO_SYS_MIXED
},
2288 { "sys:rw", LXC_AUTO_SYS_MASK
, LXC_AUTO_SYS_RW
},
2289 { "cgroup", LXC_AUTO_CGROUP_MASK
, LXC_AUTO_CGROUP_NOSPEC
},
2290 { "cgroup:mixed", LXC_AUTO_CGROUP_MASK
, LXC_AUTO_CGROUP_MIXED
},
2291 { "cgroup:ro", LXC_AUTO_CGROUP_MASK
, LXC_AUTO_CGROUP_RO
},
2292 { "cgroup:rw", LXC_AUTO_CGROUP_MASK
, LXC_AUTO_CGROUP_RW
},
2293 { "cgroup:force", LXC_AUTO_CGROUP_MASK
, LXC_AUTO_CGROUP_NOSPEC
| LXC_AUTO_CGROUP_FORCE
},
2294 { "cgroup:mixed:force", LXC_AUTO_CGROUP_MASK
, LXC_AUTO_CGROUP_MIXED
| LXC_AUTO_CGROUP_FORCE
},
2295 { "cgroup:ro:force", LXC_AUTO_CGROUP_MASK
, LXC_AUTO_CGROUP_RO
| LXC_AUTO_CGROUP_FORCE
},
2296 { "cgroup:rw:force", LXC_AUTO_CGROUP_MASK
, LXC_AUTO_CGROUP_RW
| LXC_AUTO_CGROUP_FORCE
},
2297 { "cgroup-full", LXC_AUTO_CGROUP_MASK
, LXC_AUTO_CGROUP_FULL_NOSPEC
},
2298 { "cgroup-full:mixed", LXC_AUTO_CGROUP_MASK
, LXC_AUTO_CGROUP_FULL_MIXED
},
2299 { "cgroup-full:ro", LXC_AUTO_CGROUP_MASK
, LXC_AUTO_CGROUP_FULL_RO
},
2300 { "cgroup-full:rw", LXC_AUTO_CGROUP_MASK
, LXC_AUTO_CGROUP_FULL_RW
},
2301 { "cgroup-full:force", LXC_AUTO_CGROUP_MASK
, LXC_AUTO_CGROUP_FULL_NOSPEC
| LXC_AUTO_CGROUP_FORCE
},
2302 { "cgroup-full:mixed:force", LXC_AUTO_CGROUP_MASK
, LXC_AUTO_CGROUP_FULL_MIXED
| LXC_AUTO_CGROUP_FORCE
},
2303 { "cgroup-full:ro:force", LXC_AUTO_CGROUP_MASK
, LXC_AUTO_CGROUP_FULL_RO
| LXC_AUTO_CGROUP_FORCE
},
2304 { "cgroup-full:rw:force", LXC_AUTO_CGROUP_MASK
, LXC_AUTO_CGROUP_FULL_RW
| LXC_AUTO_CGROUP_FORCE
},
2305 { "shmounts:", LXC_AUTO_SHMOUNTS_MASK
, LXC_AUTO_SHMOUNTS
},
2307 * For adding anything that is just a single on/off, but has no
2308 * options: keep mask and flag identical and just define the
2309 * enum value as an unused bit so far
2314 if (lxc_config_value_empty(value
)) {
2315 lxc_conf
->auto_mounts
= 0;
2319 autos
= strdup(value
);
2321 return ret_errno(ENOMEM
);
2323 lxc_iterate_parts(token
, autos
, " \t") {
2324 bool is_shmounts
= false;
2326 for (i
= 0; allowed_auto_mounts
[i
].token
; i
++) {
2327 if (strequal(allowed_auto_mounts
[i
].token
, token
))
2330 if (strequal("shmounts:", allowed_auto_mounts
[i
].token
) &&
2331 strnequal("shmounts:", token
, STRLITERALLEN("shmounts:"))) {
2337 if (!allowed_auto_mounts
[i
].token
)
2338 return log_error_errno(-EINVAL
, EINVAL
, "Invalid filesystem to automount \"%s\"", token
);
2340 lxc_conf
->auto_mounts
&= ~allowed_auto_mounts
[i
].mask
;
2341 lxc_conf
->auto_mounts
|= allowed_auto_mounts
[i
].flag
;
2344 __do_free
char *container_path
= NULL
, *host_path
= NULL
;
2347 val
= token
+ STRLITERALLEN("shmounts:");
2349 return log_error_errno(-EINVAL
, EINVAL
, "Failed to copy shmounts host path");
2351 host_path
= strdup(val
);
2353 return log_error_errno(-EINVAL
, EINVAL
, "Failed to copy shmounts host path");
2355 val
= strchr(host_path
, ':');
2356 if (!val
|| *(val
+ 1) == '\0')
2357 val
= "/dev/.lxc-mounts";
2361 container_path
= strdup(val
);
2363 return log_error_errno(-EINVAL
, EINVAL
, "Failed to copy shmounts container path");
2365 free_disarm(lxc_conf
->shmount
.path_host
);
2366 lxc_conf
->shmount
.path_host
= move_ptr(host_path
);
2368 free_disarm(lxc_conf
->shmount
.path_cont
);
2369 lxc_conf
->shmount
.path_cont
= move_ptr(container_path
);
2376 static int set_config_mount(const char *key
, const char *value
,
2377 struct lxc_conf
*lxc_conf
, void *data
)
2379 __do_free
char *mntelem
= NULL
;
2380 __do_free
struct lxc_list
*mntlist
= NULL
;
2382 if (lxc_config_value_empty(value
))
2383 return lxc_clear_mount_entries(lxc_conf
);
2385 mntlist
= lxc_list_new();
2387 return ret_errno(ENOMEM
);
2389 mntelem
= strdup(value
);
2391 return ret_errno(ENOMEM
);
2393 mntlist
->elem
= move_ptr(mntelem
);
2394 lxc_list_add_tail(&lxc_conf
->mount_list
, move_ptr(mntlist
));
2399 int add_elem_to_mount_list(const char *value
, struct lxc_conf
*lxc_conf
) {
2400 return set_config_mount(NULL
, value
, lxc_conf
, NULL
);
2403 static int set_config_cap_keep(const char *key
, const char *value
,
2404 struct lxc_conf
*lxc_conf
, void *data
)
2406 __do_free
char *keepcaps
= NULL
;
2407 __do_free
struct lxc_list
*keeplist
= NULL
;
2410 if (lxc_config_value_empty(value
))
2411 return lxc_clear_config_keepcaps(lxc_conf
);
2413 keepcaps
= strdup(value
);
2415 return ret_errno(ENOMEM
);
2417 /* In case several capability keep is specified in a single line
2418 * split these caps in a single element for the list.
2420 lxc_iterate_parts(token
, keepcaps
, " \t") {
2421 if (strequal(token
, "none"))
2422 lxc_clear_config_keepcaps(lxc_conf
);
2424 keeplist
= lxc_list_new();
2426 return ret_errno(ENOMEM
);
2428 keeplist
->elem
= strdup(token
);
2429 if (!keeplist
->elem
)
2430 return ret_errno(ENOMEM
);
2432 lxc_list_add_tail(&lxc_conf
->keepcaps
, move_ptr(keeplist
));
2438 static int set_config_cap_drop(const char *key
, const char *value
,
2439 struct lxc_conf
*lxc_conf
, void *data
)
2441 __do_free
char *dropcaps
= NULL
;
2442 __do_free
struct lxc_list
*droplist
= NULL
;
2445 if (lxc_config_value_empty(value
))
2446 return lxc_clear_config_caps(lxc_conf
);
2448 dropcaps
= strdup(value
);
2450 return ret_errno(ENOMEM
);
2452 /* In case several capability drop is specified in a single line
2453 * split these caps in a single element for the list.
2455 lxc_iterate_parts(token
, dropcaps
, " \t") {
2456 droplist
= lxc_list_new();
2458 return ret_errno(ENOMEM
);
2460 droplist
->elem
= strdup(token
);
2461 if (!droplist
->elem
)
2462 return ret_errno(ENOMEM
);
2464 lxc_list_add_tail(&lxc_conf
->caps
, move_ptr(droplist
));
2470 static int set_config_console_path(const char *key
, const char *value
,
2471 struct lxc_conf
*lxc_conf
, void *data
)
2473 return set_config_path_item(&lxc_conf
->console
.path
, value
);
2476 static int set_config_console_rotate(const char *key
, const char *value
,
2477 struct lxc_conf
*lxc_conf
, void *data
)
2481 if (lxc_config_value_empty(value
)) {
2482 lxc_conf
->console
.log_rotate
= 0;
2486 ret
= lxc_safe_uint(value
, &lxc_conf
->console
.log_rotate
);
2488 return ret_errno(EINVAL
);
2490 if (lxc_conf
->console
.log_rotate
> 1)
2491 return log_error_errno(-EINVAL
, EINVAL
, "The \"lxc.console.rotate\" config key can only be set to 0 or 1");
2496 static int set_config_console_logfile(const char *key
, const char *value
,
2497 struct lxc_conf
*lxc_conf
, void *data
)
2499 return set_config_path_item(&lxc_conf
->console
.log_path
, value
);
2502 static int set_config_console_buffer_size(const char *key
, const char *value
,
2503 struct lxc_conf
*lxc_conf
, void *data
)
2507 uint64_t buffer_size
, pgsz
;
2509 if (lxc_config_value_empty(value
)) {
2510 lxc_conf
->console
.buffer_size
= 0;
2514 /* If the user specified "auto" the default log size is 2^17 = 128 Kib */
2515 if (strequal(value
, "auto")) {
2516 lxc_conf
->console
.buffer_size
= 1 << 17;
2520 ret
= parse_byte_size_string(value
, &size
);
2525 return ret_errno(EINVAL
);
2527 /* must be at least a page size */
2528 pgsz
= lxc_getpagesize();
2529 if ((uint64_t)size
< pgsz
) {
2530 NOTICE("Requested ringbuffer size for the console is %lld but must be at least %" PRId64
" bytes. Setting ringbuffer size to %" PRId64
" bytes",
2535 buffer_size
= lxc_find_next_power2((uint64_t)size
);
2536 if (buffer_size
== 0)
2537 return ret_errno(EINVAL
);
2539 if (buffer_size
!= size
)
2540 NOTICE("Passed size was not a power of 2. Rounding log size to next power of two: %" PRIu64
" bytes", buffer_size
);
2542 lxc_conf
->console
.buffer_size
= buffer_size
;
2547 static int set_config_console_size(const char *key
, const char *value
,
2548 struct lxc_conf
*lxc_conf
, void *data
)
2552 uint64_t log_size
, pgsz
;
2554 if (lxc_config_value_empty(value
)) {
2555 lxc_conf
->console
.log_size
= 0;
2559 /* If the user specified "auto" the default log size is 2^17 = 128 Kib */
2560 if (strequal(value
, "auto")) {
2561 lxc_conf
->console
.log_size
= 1 << 17;
2565 ret
= parse_byte_size_string(value
, &size
);
2567 return ret_errno(EINVAL
);
2570 return ret_errno(EINVAL
);
2572 /* must be at least a page size */
2573 pgsz
= lxc_getpagesize();
2574 if ((uint64_t)size
< pgsz
) {
2575 NOTICE("Requested ringbuffer size for the console is %lld but must be at least %" PRId64
" bytes. Setting ringbuffer size to %" PRId64
" bytes",
2580 log_size
= lxc_find_next_power2((uint64_t)size
);
2582 return ret_errno(EINVAL
);
2584 if (log_size
!= size
)
2585 NOTICE("Passed size was not a power of 2. Rounding log size to next power of two: %" PRIu64
" bytes", log_size
);
2587 lxc_conf
->console
.log_size
= log_size
;
2593 * If we find a lxc.net.[i].hwaddr or lxc.network.hwaddr in the original config
2594 * file, we expand it in the unexpanded_config, so that after a save_config we
2595 * store the hwaddr for re-use.
2596 * This is only called when reading the config file, not when executing a
2598 * 'x' and 'X' are substituted in-place.
2600 static void update_hwaddr(const char *line
)
2604 line
+= lxc_char_left_gc(line
, strlen(line
));
2608 if (!lxc_config_net_is_hwaddr(line
))
2611 /* Let config_net_hwaddr raise the error. */
2612 p
= strchr(line
, '=');
2623 rand_complete_hwaddr(p
);
2626 int append_unexp_config_line(const char *line
, struct lxc_conf
*conf
)
2629 size_t len
= conf
->unexpanded_len
;
2631 update_hwaddr(line
);
2633 linelen
= strlen(line
);
2634 while (conf
->unexpanded_alloced
<= len
+ linelen
+ 2) {
2637 tmp
= realloc(conf
->unexpanded_config
, conf
->unexpanded_alloced
+ 1024);
2639 return ret_errno(EINVAL
);
2641 if (!conf
->unexpanded_config
)
2644 conf
->unexpanded_config
= tmp
;
2645 conf
->unexpanded_alloced
+= 1024;
2648 memcpy(conf
->unexpanded_config
+ conf
->unexpanded_len
, line
, linelen
);
2649 conf
->unexpanded_len
+= linelen
;
2650 if (line
[linelen
- 1] != '\n')
2651 conf
->unexpanded_config
[conf
->unexpanded_len
++] = '\n';
2652 conf
->unexpanded_config
[conf
->unexpanded_len
] = '\0';
2657 static int do_includedir(const char *dirp
, struct lxc_conf
*lxc_conf
)
2659 __do_closedir
DIR *dir
= NULL
;
2660 struct dirent
*direntp
;
2663 dir
= opendir(dirp
);
2665 return errno
== ENOENT
? 0 : -errno
;
2667 while ((direntp
= readdir(dir
))) {
2669 char path
[PATH_MAX
];
2671 fnam
= direntp
->d_name
;
2672 if (strequal(fnam
, "."))
2675 if (strequal(fnam
, ".."))
2679 if (len
< 6 || !strnequal(fnam
+ len
- 5, ".conf", 5))
2682 len
= strnprintf(path
, sizeof(path
), "%s/%s", dirp
, fnam
);
2684 return ret_errno(EIO
);
2686 ret
= lxc_config_read(path
, lxc_conf
, true);
2694 static int set_config_includefiles(const char *key
, const char *value
,
2695 struct lxc_conf
*lxc_conf
, void *data
)
2697 if (lxc_config_value_empty(value
)) {
2698 clr_config_includefiles(key
, lxc_conf
, NULL
);
2702 if (value
[strlen(value
)-1] == '/' || is_dir(value
))
2703 return do_includedir(value
, lxc_conf
);
2705 return lxc_config_read(value
, lxc_conf
, true);
2708 static int set_config_rootfs_path(const char *key
, const char *value
,
2709 struct lxc_conf
*lxc_conf
, void *data
)
2711 __do_free
char *dup
= NULL
;
2714 const char *container_path
;
2716 if (lxc_config_value_empty(value
)) {
2717 free(lxc_conf
->rootfs
.path
);
2718 lxc_conf
->rootfs
.path
= NULL
;
2722 dup
= strdup(value
);
2724 return ret_errno(ENOMEM
);
2726 /* Split <storage type>:<container path> into <storage type> and
2727 * <container path>. Set "rootfs.bdev_type" to <storage type> and
2728 * "rootfs.path" to <container path>.
2730 tmp
= strchr(dup
, ':');
2734 ret
= set_config_path_item(&lxc_conf
->rootfs
.bdev_type
, dup
);
2736 return ret_errno(ENOMEM
);
2739 container_path
= tmp
;
2741 container_path
= value
;
2744 return set_config_path_item(&lxc_conf
->rootfs
.path
, container_path
);
2747 static int set_config_rootfs_managed(const char *key
, const char *value
,
2748 struct lxc_conf
*lxc_conf
, void *data
)
2750 return set_config_bool_item(&lxc_conf
->rootfs
.managed
, value
, true);
2753 static int set_config_rootfs_mount(const char *key
, const char *value
,
2754 struct lxc_conf
*lxc_conf
, void *data
)
2756 return set_config_path_item(&lxc_conf
->rootfs
.mount
, value
);
2759 static int set_config_rootfs_options(const char *key
, const char *value
,
2760 struct lxc_conf
*lxc_conf
, void *data
)
2762 __do_free
char *dup
= NULL
, *raw_options
= NULL
;
2763 struct lxc_rootfs
*rootfs
= &lxc_conf
->rootfs
;
2764 struct lxc_mount_options
*mnt_opts
= &rootfs
->mnt_opts
;
2767 clr_config_rootfs_options(key
, lxc_conf
, data
);
2768 if (lxc_config_value_empty(value
))
2771 ret
= set_config_string_item(&raw_options
, value
);
2773 return ret_errno(ENOMEM
);
2775 dup
= strdup(value
);
2779 ret
= parse_lxc_mount_attrs(mnt_opts
, dup
);
2783 /* Make sure we're only valid LXC specific mount options. */
2784 if (mnt_opts
->create_dir
|| mnt_opts
->create_file
||
2785 mnt_opts
->optional
|| mnt_opts
->relative
)
2786 return syserror_set(-EINVAL
, "Invalid LXC specific mount option for rootfs mount");
2788 ret
= parse_mount_attrs(mnt_opts
, dup
);
2790 return ret_errno(EINVAL
);
2792 rootfs
->mnt_opts
.raw_options
= move_ptr(raw_options
);
2796 static int set_config_uts_name(const char *key
, const char *value
,
2797 struct lxc_conf
*lxc_conf
, void *data
)
2799 __do_free
struct utsname
*utsname
= NULL
;
2801 if (lxc_config_value_empty(value
)) {
2802 clr_config_uts_name(key
, lxc_conf
, NULL
);
2806 utsname
= zalloc(sizeof(*utsname
));
2808 return ret_errno(ENOMEM
);
2810 if (strlen(value
) >= sizeof(utsname
->nodename
))
2811 return ret_errno(EINVAL
);
2813 (void)strlcpy(utsname
->nodename
, value
, sizeof(utsname
->nodename
));
2814 free(lxc_conf
->utsname
);
2815 lxc_conf
->utsname
= move_ptr(utsname
);
2820 static int set_config_namespace_clone(const char *key
, const char *value
,
2821 struct lxc_conf
*lxc_conf
, void *data
)
2823 __do_free
char *ns
= NULL
;
2827 if (lxc_config_value_empty(value
))
2828 return clr_config_namespace_clone(key
, lxc_conf
, data
);
2830 if (lxc_conf
->ns_keep
!= 0)
2831 return log_error_errno(-EINVAL
, EINVAL
, "Cannot set both \"lxc.namespace.clone\" and \"lxc.namespace.keep\"");
2835 return ret_errno(ENOMEM
);
2837 lxc_iterate_parts(token
, ns
, " \t") {
2838 token
+= lxc_char_left_gc(token
, strlen(token
));
2839 token
[lxc_char_right_gc(token
, strlen(token
))] = '\0';
2840 cloneflag
= lxc_namespace_2_cloneflag(token
);
2842 return ret_errno(EINVAL
);
2843 lxc_conf
->ns_clone
|= cloneflag
;
2849 static int set_config_namespace_keep(const char *key
, const char *value
,
2850 struct lxc_conf
*lxc_conf
, void *data
)
2852 __do_free
char *ns
= NULL
;
2856 if (lxc_config_value_empty(value
))
2857 return clr_config_namespace_keep(key
, lxc_conf
, data
);
2859 if (lxc_conf
->ns_clone
!= 0)
2860 return log_error_errno(-EINVAL
, EINVAL
, "Cannot set both \"lxc.namespace.clone\" and \"lxc.namespace.keep\"");
2864 return ret_errno(ENOMEM
);
2866 lxc_iterate_parts(token
, ns
, " \t") {
2867 token
+= lxc_char_left_gc(token
, strlen(token
));
2868 token
[lxc_char_right_gc(token
, strlen(token
))] = '\0';
2869 cloneflag
= lxc_namespace_2_cloneflag(token
);
2871 return ret_errno(EINVAL
);
2872 lxc_conf
->ns_keep
|= cloneflag
;
2878 static int set_config_time_offset_boot(const char *key
, const char *value
,
2879 struct lxc_conf
*lxc_conf
, void *data
)
2884 char buf
[STRLITERALLEN("ms") + 1];
2886 if (lxc_config_value_empty(value
))
2887 return clr_config_time_offset_boot(key
, lxc_conf
, data
);
2889 ret
= lxc_safe_int64_residual(value
, &offset
, 10, buf
, sizeof(buf
));
2893 unit
= lxc_trim_whitespace_in_place(buf
);
2894 if (strequal(unit
, "h")) {
2895 if (!multiply_overflow(offset
, 3600, &lxc_conf
->timens
.s_boot
))
2896 return ret_errno(EOVERFLOW
);
2897 } else if (strequal(unit
, "m")) {
2898 if (!multiply_overflow(offset
, 60, &lxc_conf
->timens
.s_boot
))
2899 return ret_errno(EOVERFLOW
);
2900 } else if (strequal(unit
, "s")) {
2901 lxc_conf
->timens
.s_boot
= offset
;
2902 } else if (strequal(unit
, "ms")) {
2903 if (!multiply_overflow(offset
, 1000000, &lxc_conf
->timens
.ns_boot
))
2904 return ret_errno(EOVERFLOW
);
2905 } else if (strequal(unit
, "us")) {
2906 if (!multiply_overflow(offset
, 1000, &lxc_conf
->timens
.ns_boot
))
2907 return ret_errno(EOVERFLOW
);
2908 } else if (strequal(unit
, "ns")) {
2909 lxc_conf
->timens
.ns_boot
= offset
;
2911 return ret_errno(EINVAL
);
2917 static int set_config_time_offset_monotonic(const char *key
, const char *value
,
2918 struct lxc_conf
*lxc_conf
, void *data
)
2923 char buf
[STRLITERALLEN("ms") + 1];
2925 if (lxc_config_value_empty(value
))
2926 return clr_config_time_offset_monotonic(key
, lxc_conf
, data
);
2928 ret
= lxc_safe_int64_residual(value
, &offset
, 10, buf
, sizeof(buf
));
2932 unit
= lxc_trim_whitespace_in_place(buf
);
2933 if (strequal(unit
, "h")) {
2934 if (!multiply_overflow(offset
, 3600, &lxc_conf
->timens
.s_monotonic
))
2935 return ret_errno(EOVERFLOW
);
2936 } else if (strequal(unit
, "m")) {
2937 if (!multiply_overflow(offset
, 60, &lxc_conf
->timens
.s_monotonic
))
2938 return ret_errno(EOVERFLOW
);
2939 } else if (strequal(unit
, "s")) {
2940 lxc_conf
->timens
.s_monotonic
= offset
;
2941 } else if (strequal(unit
, "ms")) {
2942 if (!multiply_overflow(offset
, 1000000, &lxc_conf
->timens
.ns_monotonic
))
2943 return ret_errno(EOVERFLOW
);
2944 } else if (strequal(unit
, "us")) {
2945 if (!multiply_overflow(offset
, 1000, &lxc_conf
->timens
.ns_monotonic
))
2946 return ret_errno(EOVERFLOW
);
2947 } else if (strequal(unit
, "ns")) {
2948 lxc_conf
->timens
.ns_monotonic
= offset
;
2950 return ret_errno(EINVAL
);
2956 static int set_config_namespace_share(const char *key
, const char *value
,
2957 struct lxc_conf
*lxc_conf
, void *data
)
2960 const char *namespace;
2962 if (lxc_config_value_empty(value
))
2963 return clr_config_namespace_share(key
, lxc_conf
, data
);
2965 namespace = key
+ STRLITERALLEN("lxc.namespace.share.");
2966 if (is_empty_string(namespace))
2967 return ret_errno(EINVAL
);
2969 ns_idx
= lxc_namespace_2_ns_idx(namespace);
2973 return set_config_string_item(&lxc_conf
->ns_share
[ns_idx
], value
);
2976 struct parse_line_conf
{
2977 struct lxc_conf
*conf
;
2981 static int parse_line(char *buffer
, void *data
)
2983 __do_free
char *linep
= NULL
;
2984 char *dot
, *key
, *line
, *value
;
2986 struct lxc_config_t
*config
;
2989 struct parse_line_conf
*plc
= data
;
2992 return syserror_set(-EINVAL
, "Missing config");
2994 /* If there are newlines in the config file we should keep them. */
2995 empty_line
= lxc_is_line_empty(dup
);
2999 /* We have to dup the buffer otherwise, at the re-exec for reboot we
3000 * modified the original string on the stack by replacing '=' by '\0'
3003 linep
= line
= strdup(dup
);
3005 return ret_errno(ENOMEM
);
3007 if (!plc
->from_include
) {
3008 ret
= append_unexp_config_line(line
, plc
->conf
);
3016 line
+= lxc_char_left_gc(line
, strlen(line
));
3018 /* ignore comments */
3022 /* martian option - don't add it to the config itself */
3023 if (!strnequal(line
, "lxc.", 4))
3026 dot
= strchr(line
, '=');
3028 return log_error_errno(-EINVAL
, EINVAL
, "Invalid configuration line: %s", line
);
3034 key
[lxc_char_right_gc(key
, strlen(key
))] = '\0';
3036 value
+= lxc_char_left_gc(value
, strlen(value
));
3037 value
[lxc_char_right_gc(value
, strlen(value
))] = '\0';
3039 if (*value
== '\'' || *value
== '\"') {
3042 len
= strlen(value
);
3043 if (len
> 1 && value
[len
- 1] == *value
) {
3044 value
[len
- 1] = '\0';
3049 config
= lxc_get_config(key
);
3050 return config
->set(key
, value
, plc
->conf
, NULL
);
3053 static struct new_config_item
*parse_new_conf_line(char *buffer
)
3055 __do_free
char *k
= NULL
, *linep
= NULL
, *v
= NULL
;
3056 __do_free
struct new_config_item
*new = NULL
;
3058 char *dot
, *key
, *line
, *value
;
3060 if (is_empty_string(buffer
))
3061 return log_error_errno(NULL
, EINVAL
, "Empty configuration line");
3063 linep
= line
= strdup(dup
);
3067 line
+= lxc_char_left_gc(line
, strlen(line
));
3069 /* martian option - don't add it to the config itself */
3070 if (!strnequal(line
, "lxc.", 4))
3073 dot
= strchr(line
, '=');
3075 return log_error_errno(NULL
, EINVAL
, "Invalid configuration line: %s", line
);
3081 key
[lxc_char_right_gc(key
, strlen(key
))] = '\0';
3083 value
+= lxc_char_left_gc(value
, strlen(value
));
3084 value
[lxc_char_right_gc(value
, strlen(value
))] = '\0';
3086 if (*value
== '\'' || *value
== '\"') {
3089 len
= strlen(value
);
3090 if (len
> 1 && value
[len
- 1] == *value
) {
3091 value
[len
- 1] = '\0';
3096 new = zalloc(sizeof(struct new_config_item
));
3108 new->key
= move_ptr(k
);
3109 new->val
= move_ptr(v
);
3110 return move_ptr(new);
3113 int lxc_config_read(const char *file
, struct lxc_conf
*conf
, bool from_include
)
3115 struct parse_line_conf plc
;
3118 return syserror_set(-EINVAL
, "Missing config");
3121 plc
.from_include
= from_include
;
3123 /* Catch only the top level config file name in the structure. */
3125 conf
->rcfile
= strdup(file
);
3127 return lxc_file_for_each_line_mmap(file
, parse_line
, &plc
);
3130 int lxc_config_define_add(struct lxc_list
*defines
, char *arg
)
3132 __do_free
struct lxc_list
*dent
= NULL
;
3134 dent
= lxc_list_new();
3136 return ret_errno(ENOMEM
);
3138 dent
->elem
= parse_new_conf_line(arg
);
3140 return ret_errno(ENOMEM
);
3142 lxc_list_add_tail(defines
, move_ptr(dent
));
3147 bool lxc_config_define_load(struct lxc_list
*defines
, struct lxc_container
*c
)
3149 struct lxc_list
*it
;
3152 lxc_list_for_each(it
, defines
) {
3153 struct new_config_item
*new_item
= it
->elem
;
3154 bret
= c
->set_config_item(c
, new_item
->key
, new_item
->val
);
3159 #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
3160 lxc_config_define_free(defines
);
3161 #endif /* !FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION */
3166 void lxc_config_define_free(struct lxc_list
*defines
)
3168 struct lxc_list
*it
, *next
;
3170 lxc_list_for_each_safe(it
, defines
, next
) {
3171 struct new_config_item
*new_item
= it
->elem
;
3172 free(new_item
->key
);
3173 free(new_item
->val
);
3180 int lxc_config_parse_arch(const char *arch
, signed long *persona
)
3182 static struct per_name
{
3186 { "arm", PER_LINUX32
},
3187 { "armel", PER_LINUX32
},
3188 { "armhf", PER_LINUX32
},
3189 { "armv7l", PER_LINUX32
},
3190 { "athlon", PER_LINUX32
},
3191 { "i386", PER_LINUX32
},
3192 { "i486", PER_LINUX32
},
3193 { "i586", PER_LINUX32
},
3194 { "i686", PER_LINUX32
},
3195 { "linux32", PER_LINUX32
},
3196 { "mips", PER_LINUX32
},
3197 { "mipsel", PER_LINUX32
},
3198 { "ppc", PER_LINUX32
},
3199 { "powerpc", PER_LINUX32
},
3200 { "x86", PER_LINUX32
},
3201 { "aarch64", PER_LINUX
},
3202 { "amd64", PER_LINUX
},
3203 { "arm64", PER_LINUX
},
3204 { "linux64", PER_LINUX
},
3205 { "mips64", PER_LINUX
},
3206 { "mips64el", PER_LINUX
},
3207 { "ppc64", PER_LINUX
},
3208 { "ppc64el", PER_LINUX
},
3209 { "ppc64le", PER_LINUX
},
3210 { "powerpc64", PER_LINUX
},
3211 { "s390x", PER_LINUX
},
3212 { "x86_64", PER_LINUX
},
3215 for (int i
= 0; i
< ARRAY_SIZE(pername
); i
++) {
3216 if (!strequal(pername
[i
].name
, arch
))
3219 *persona
= pername
[i
].per
;
3223 return ret_errno(EINVAL
);
3226 int lxc_fill_elevated_privileges(char *flaglist
, unsigned int *flags
)
3228 unsigned int flags_tmp
= 0;
3234 { "CGROUP", LXC_ATTACH_MOVE_TO_CGROUP
},
3235 { "CAP", LXC_ATTACH_DROP_CAPABILITIES
},
3236 { "LSM", LXC_ATTACH_LSM_EXEC
},
3242 * For the sake of backward compatibility, keep all privileges
3243 * if no specific privileges are specified.
3245 for (unsigned int i
= 0; all_privs
[i
].token
; i
++)
3246 flags_tmp
|= all_privs
[i
].flag
;
3252 lxc_iterate_parts(token
, flaglist
, "|") {
3253 bool valid_token
= false;
3255 for (unsigned int i
= 0; all_privs
[i
].token
; i
++) {
3256 if (!strequal(all_privs
[i
].token
, token
))
3260 flags_tmp
|= all_privs
[i
].flag
;
3264 return syserror_set(-EINVAL
, "Invalid elevated privilege \"%s\" requested", token
);
3271 /* Write out a configuration file. */
3272 int write_config(int fd
, const struct lxc_conf
*conf
)
3275 size_t len
= conf
->unexpanded_len
;
3280 ret
= lxc_write_nointr(fd
, conf
->unexpanded_config
, len
);
3282 return log_error_errno(-errno
, errno
, "Failed to write configuration file");
3287 bool do_append_unexp_config_line(struct lxc_conf
*conf
, const char *key
,
3290 __do_free
char *tmp
= NULL
;
3294 len
= strlen(key
) + strlen(v
) + 4;
3295 tmp
= must_realloc(NULL
, len
);
3297 if (lxc_config_value_empty(v
))
3298 ret
= strnprintf(tmp
, len
, "%s =", key
);
3300 ret
= strnprintf(tmp
, len
, "%s = %s", key
, v
);
3304 /* Save the line verbatim into unexpanded_conf */
3305 if (append_unexp_config_line(tmp
, conf
))
3311 void clear_unexp_config_line(struct lxc_conf
*conf
, const char *key
,
3315 char *lstart
= conf
->unexpanded_config
;
3317 if (!conf
->unexpanded_config
)
3321 lend
= strchr(lstart
, '\n');
3325 lend
= lstart
+ strlen(lstart
);
3329 if (!strnequal(lstart
, key
, strlen(key
))) {
3335 v
= lstart
[strlen(key
)];
3336 if (!isspace(v
) && v
!= '=') {
3342 conf
->unexpanded_len
-= (lend
- lstart
);
3344 if (*lend
== '\0') {
3349 memmove(lstart
, lend
, strlen(lend
) + 1);
3353 bool clone_update_unexp_ovl_paths(struct lxc_conf
*conf
, const char *oldpath
,
3354 const char *newpath
, const char *oldname
,
3355 const char *newname
, const char *ovldir
)
3357 __do_free
char *newdir
= NULL
, *olddir
= NULL
;
3358 char *lstart
= conf
->unexpanded_config
;
3359 const char *key
= "lxc.mount.entry";
3362 size_t newdirlen
, olddirlen
;
3364 olddirlen
= strlen(ovldir
) + strlen(oldpath
) + strlen(oldname
) + 2;
3365 olddir
= must_realloc(NULL
, olddirlen
+ 1);
3366 ret
= strnprintf(olddir
, olddirlen
+ 1, "%s=%s/%s", ovldir
, oldpath
, oldname
);
3370 newdirlen
= strlen(ovldir
) + strlen(newpath
) + strlen(newname
) + 2;
3371 newdir
= must_realloc(NULL
, newdirlen
+ 1);
3372 ret
= strnprintf(newdir
, newdirlen
+ 1, "%s=%s/%s", ovldir
, newpath
, newname
);
3376 if (!conf
->unexpanded_config
)
3380 lend
= strchr(lstart
, '\n');
3382 lend
= lstart
+ strlen(lstart
);
3386 if (!strnequal(lstart
, key
, strlen(key
)))
3389 p
= strchr(lstart
+ strlen(key
), '=');
3400 /* Whenever a lxc.mount.entry entry is found in a line we check
3401 * if the substring "overlay" is present before doing any
3402 * further work. We check for "overlay" because substrings need
3403 * to have at least one space before them in a valid overlay
3404 * lxc.mount.entry (/A B overlay). When the space before is
3405 * missing it is very likely that these substrings are part of a
3406 * path or something else. (Checking q >= lend ensures that we
3407 * only count matches in the current line.) */
3408 q
= strstr(p
, " overlay");
3409 if (!q
|| q
>= lend
)
3412 if (!(q
= strstr(p
, olddir
)) || (q
>= lend
))
3415 /* replace the olddir with newdir */
3416 if (olddirlen
>= newdirlen
) {
3417 size_t diff
= olddirlen
- newdirlen
;
3418 memcpy(q
, newdir
, newdirlen
);
3420 if (olddirlen
!= newdirlen
) {
3421 memmove(q
+ newdirlen
, q
+ newdirlen
+ diff
,
3422 strlen(q
) - newdirlen
- diff
+ 1);
3424 conf
->unexpanded_len
-= diff
;
3428 size_t diff
= newdirlen
- olddirlen
;
3429 size_t oldlen
= conf
->unexpanded_len
;
3430 size_t newlen
= oldlen
+ diff
;
3431 size_t poffset
= q
- conf
->unexpanded_config
;
3433 new = realloc(conf
->unexpanded_config
, newlen
+ 1);
3437 conf
->unexpanded_len
= newlen
;
3438 conf
->unexpanded_alloced
= newlen
+ 1;
3439 new[newlen
- 1] = '\0';
3440 lend
= new + (lend
- conf
->unexpanded_config
);
3442 /* Move over the remainder to make room for the newdir.
3444 memmove(new + poffset
+ newdirlen
,
3445 new + poffset
+ olddirlen
,
3446 oldlen
- poffset
- olddirlen
+ 1);
3447 conf
->unexpanded_config
= new;
3449 memcpy(new + poffset
, newdir
, newdirlen
);
3460 bool clone_update_unexp_hooks(struct lxc_conf
*conf
, const char *oldpath
,
3461 const char *newpath
, const char *oldname
,
3462 const char *newname
)
3464 __do_free
char *newdir
= NULL
, *olddir
= NULL
;
3465 char *lstart
= conf
->unexpanded_config
;
3466 const char *key
= "lxc.hook";
3469 size_t newdirlen
, olddirlen
;
3471 olddirlen
= strlen(oldpath
) + strlen(oldname
) + 1;
3472 olddir
= must_realloc(NULL
, olddirlen
+ 1);
3473 ret
= strnprintf(olddir
, olddirlen
+ 1, "%s/%s", oldpath
, oldname
);
3477 newdirlen
= strlen(newpath
) + strlen(newname
) + 1;
3478 newdir
= must_realloc(NULL
, newdirlen
+ 1);
3479 ret
= strnprintf(newdir
, newdirlen
+ 1, "%s/%s", newpath
, newname
);
3483 if (!conf
->unexpanded_config
)
3487 lend
= strchr(lstart
, '\n');
3489 lend
= lstart
+ strlen(lstart
);
3493 if (!strnequal(lstart
, key
, strlen(key
)))
3496 p
= strchr(lstart
+ strlen(key
), '=');
3507 if (!strnequal(p
, olddir
, strlen(olddir
)))
3510 /* replace the olddir with newdir */
3511 if (olddirlen
>= newdirlen
) {
3512 size_t diff
= olddirlen
- newdirlen
;
3513 memcpy(p
, newdir
, newdirlen
);
3515 if (olddirlen
!= newdirlen
) {
3516 memmove(p
+ newdirlen
, p
+ newdirlen
+ diff
,
3517 strlen(p
) - newdirlen
- diff
+ 1);
3519 conf
->unexpanded_len
-= diff
;
3523 size_t diff
= newdirlen
- olddirlen
;
3524 size_t oldlen
= conf
->unexpanded_len
;
3525 size_t newlen
= oldlen
+ diff
;
3526 size_t poffset
= p
- conf
->unexpanded_config
;
3528 new = realloc(conf
->unexpanded_config
, newlen
+ 1);
3532 conf
->unexpanded_len
= newlen
;
3533 conf
->unexpanded_alloced
= newlen
+ 1;
3534 new[newlen
- 1] = '\0';
3535 lend
= new + (lend
- conf
->unexpanded_config
);
3537 /* Move over the remainder to make room for the newdir.
3539 memmove(new + poffset
+ newdirlen
,
3540 new + poffset
+ olddirlen
,
3541 oldlen
- poffset
- olddirlen
+ 1);
3542 conf
->unexpanded_config
= new;
3544 memcpy(new + poffset
, newdir
, newdirlen
);
3558 ERROR("Error writing to new config"); \
3563 /* This is called only from clone. We wish to update all hwaddrs in the
3564 * unexpanded config file. We can't/don't want to update any which come from
3565 * lxc.includes (there shouldn't be any).
3566 * We can't just walk the c->lxc-conf->network list because that includes netifs
3567 * from the include files. So we update the ones which we find in the unexp
3568 * config file, then find the original macaddr in the conf->network, and update
3569 * that to the same value.
3571 bool network_new_hwaddrs(struct lxc_conf
*conf
)
3573 char *lend
, *p
, *p2
;
3574 char *lstart
= conf
->unexpanded_config
;
3576 if (!conf
->unexpanded_config
)
3580 char newhwaddr
[18], oldhwaddr
[17];
3581 struct lxc_netdev
*netdev
;
3583 lend
= strchr(lstart
, '\n');
3585 lend
= lstart
+ strlen(lstart
);
3589 if (!lxc_config_net_is_hwaddr(lstart
)) {
3594 p
= strchr(lstart
, '=');
3607 while (*p2
&& !isblank(*p2
) && *p2
!= '\n')
3610 if ((p2
- p
) != 17) {
3611 WARN("Bad hwaddr entry");
3616 memcpy(oldhwaddr
, p
, 17);
3618 if (!new_hwaddr(newhwaddr
))
3621 memcpy(p
, newhwaddr
, 17);
3622 list_for_each_entry(netdev
, &conf
->netdevs
, head
) {
3623 if (netdev
->hwaddr
&& memcmp(oldhwaddr
, netdev
->hwaddr
, 17) == 0)
3624 memcpy(netdev
->hwaddr
, newhwaddr
, 17);
3633 static int set_config_ephemeral(const char *key
, const char *value
,
3634 struct lxc_conf
*lxc_conf
, void *data
)
3638 if (lxc_config_value_empty(value
)) {
3639 lxc_conf
->ephemeral
= 0;
3643 ret
= lxc_safe_uint(value
, &lxc_conf
->ephemeral
);
3647 if (lxc_conf
->ephemeral
> 1)
3648 return ret_errno(EINVAL
);
3653 static int set_config_log_syslog(const char *key
, const char *value
,
3654 struct lxc_conf
*lxc_conf
, void *data
)
3658 if (lxc_conf
->syslog
)
3659 free_disarm(lxc_conf
->syslog
);
3661 if (lxc_config_value_empty(value
))
3664 facility
= lxc_syslog_priority_to_int(value
);
3665 if (facility
== -EINVAL
)
3666 return ret_errno(EINVAL
);
3668 lxc_log_syslog(facility
);
3670 return set_config_string_item(&lxc_conf
->syslog
, value
);
3673 static int set_config_no_new_privs(const char *key
, const char *value
,
3674 struct lxc_conf
*lxc_conf
, void *data
)
3679 if (lxc_config_value_empty(value
)) {
3680 lxc_conf
->no_new_privs
= false;
3684 ret
= lxc_safe_uint(value
, &v
);
3689 return ret_errno(EINVAL
);
3691 lxc_conf
->no_new_privs
= v
? true : false;
3696 /* Callbacks to get configuration items. */
3697 static int get_config_personality(const char *key
, char *retv
, int inlen
,
3698 struct lxc_conf
*c
, void *data
)
3705 memset(retv
, 0, inlen
);
3709 switch (c
->personality
) {
3711 strprint(retv
, inlen
, "i686");
3714 strprint(retv
, inlen
, "x86_64");
3723 static int get_config_pty_max(const char *key
, char *retv
, int inlen
,
3724 struct lxc_conf
*c
, void *data
)
3726 return lxc_get_conf_size_t(c
, retv
, inlen
, c
->pty_max
);
3729 static int get_config_tty_max(const char *key
, char *retv
, int inlen
,
3730 struct lxc_conf
*c
, void *data
)
3732 return lxc_get_conf_size_t(c
, retv
, inlen
, c
->ttys
.max
);
3735 static int get_config_tty_dir(const char *key
, char *retv
, int inlen
,
3736 struct lxc_conf
*c
, void *data
)
3738 return lxc_get_conf_str(retv
, inlen
, c
->ttys
.dir
);
3741 static int get_config_apparmor_profile(const char *key
, char *retv
, int inlen
,
3742 struct lxc_conf
*c
, void *data
)
3745 return lxc_get_conf_str(retv
, inlen
, c
->lsm_aa_profile
);
3747 return syserror_set(-EINVAL
, "Built without AppArmor support");
3751 static int get_config_apparmor_allow_incomplete(const char *key
, char *retv
,
3752 int inlen
, struct lxc_conf
*c
,
3756 return lxc_get_conf_int(c
, retv
, inlen
, c
->lsm_aa_allow_incomplete
);
3758 return syserror_set(-EINVAL
, "Built without AppArmor support");
3762 static int get_config_apparmor_allow_nesting(const char *key
, char *retv
,
3763 int inlen
, struct lxc_conf
*c
,
3767 return lxc_get_conf_int(c
, retv
, inlen
, c
->lsm_aa_allow_nesting
);
3769 return syserror_set(-EINVAL
, "Built without AppArmor support");
3773 static int get_config_apparmor_raw(const char *key
, char *retv
,
3774 int inlen
, struct lxc_conf
*c
,
3779 struct lxc_list
*it
;
3785 memset(retv
, 0, inlen
);
3787 lxc_list_for_each(it
, &c
->lsm_aa_raw
) {
3788 strprint(retv
, inlen
, "%s\n", (char *)it
->elem
);
3793 return syserror_set(-EINVAL
, "Built without AppArmor support");
3797 static int get_config_selinux_context(const char *key
, char *retv
, int inlen
,
3798 struct lxc_conf
*c
, void *data
)
3801 return lxc_get_conf_str(retv
, inlen
, c
->lsm_se_context
);
3803 return syserror_set(-EINVAL
, "Built without SELinux support");
3807 static int get_config_selinux_context_keyring(const char *key
, char *retv
, int inlen
,
3808 struct lxc_conf
*c
, void *data
)
3811 return lxc_get_conf_str(retv
, inlen
, c
->lsm_se_keyring_context
);
3813 return syserror_set(-EINVAL
, "Built without SELinux support");
3817 static int get_config_keyring_session(const char *key
, char *retv
, int inlen
,
3818 struct lxc_conf
*c
, void *data
)
3820 return lxc_get_conf_bool(c
, retv
, inlen
, c
->keyring_disable_session
);
3824 /* If you ask for a specific cgroup value, i.e. lxc.cgroup.devices.list, then
3825 * just the value(s) will be printed. Since there still could be more than one,
3826 * it is newline-separated.
3827 * (Maybe that's ambiguous, since some values, i.e. devices.list, will already
3829 * If you ask for 'lxc.cgroup", then all cgroup entries will be printed, in
3830 * 'lxc.cgroup.subsystem.key = value' format.
3832 static int __get_config_cgroup_controller(const char *key
, char *retv
,
3833 int inlen
, struct lxc_conf
*c
,
3837 bool get_all
= false;
3839 size_t namespaced_token_len
;
3840 char *global_token
, *namespaced_token
;
3841 struct list_head
*list
;
3842 struct lxc_cgroup
*cgroup
;
3847 memset(retv
, 0, inlen
);
3849 if (version
== CGROUP2_SUPER_MAGIC
) {
3850 global_token
= "lxc.cgroup2";
3851 namespaced_token
= "lxc.cgroup2.";
3852 namespaced_token_len
= STRLITERALLEN("lxc.cgroup2.");
3854 } else if (version
== CGROUP_SUPER_MAGIC
) {
3855 global_token
= "lxc.cgroup";
3856 namespaced_token
= "lxc.cgroup.";
3857 namespaced_token_len
= STRLITERALLEN("lxc.cgroup.");
3860 return ret_errno(EINVAL
);
3863 if (strequal(key
, global_token
))
3865 else if (strnequal(key
, namespaced_token
, namespaced_token_len
))
3866 key
+= namespaced_token_len
;
3868 return ret_errno(EINVAL
);
3870 list_for_each_entry(cgroup
, list
, head
) {
3872 if (version
!= cgroup
->version
)
3875 strprint(retv
, inlen
, "%s.%s = %s\n", global_token
,
3876 cgroup
->subsystem
, cgroup
->value
);
3877 } else if (strequal(cgroup
->subsystem
, key
)) {
3878 strprint(retv
, inlen
, "%s\n", cgroup
->value
);
3885 static int get_config_cgroup_controller(const char *key
, char *retv
, int inlen
,
3886 struct lxc_conf
*c
, void *data
)
3888 return __get_config_cgroup_controller(key
, retv
, inlen
, c
,
3889 CGROUP_SUPER_MAGIC
);
3892 static int get_config_cgroup2_controller(const char *key
, char *retv
, int inlen
,
3893 struct lxc_conf
*c
, void *data
)
3895 return __get_config_cgroup_controller(key
, retv
, inlen
, c
,
3896 CGROUP2_SUPER_MAGIC
);
3899 static int get_config_cgroup_dir(const char *key
, char *retv
, int inlen
,
3900 struct lxc_conf
*lxc_conf
, void *data
)
3905 if (!strequal(key
, "lxc.cgroup.dir"))
3906 return ret_errno(EINVAL
);
3911 memset(retv
, 0, inlen
);
3913 strprint(retv
, inlen
, "%s", lxc_conf
->cgroup_meta
.dir
);
3918 static int get_config_cgroup_monitor_dir(const char *key
, char *retv
, int inlen
,
3919 struct lxc_conf
*lxc_conf
, void *data
)
3927 memset(retv
, 0, inlen
);
3929 strprint(retv
, inlen
, "%s", lxc_conf
->cgroup_meta
.monitor_dir
);
3934 static int get_config_cgroup_monitor_pivot_dir(const char *key
, char *retv
, int inlen
,
3935 struct lxc_conf
*lxc_conf
, void *data
)
3943 memset(retv
, 0, inlen
);
3945 strprint(retv
, inlen
, "%s", lxc_conf
->cgroup_meta
.monitor_pivot_dir
);
3950 static int get_config_cgroup_container_dir(const char *key
, char *retv
,
3952 struct lxc_conf
*lxc_conf
,
3961 memset(retv
, 0, inlen
);
3963 strprint(retv
, inlen
, "%s", lxc_conf
->cgroup_meta
.container_dir
);
3968 static int get_config_cgroup_container_inner_dir(const char *key
, char *retv
,
3970 struct lxc_conf
*lxc_conf
,
3979 memset(retv
, 0, inlen
);
3981 strprint(retv
, inlen
, "%s", lxc_conf
->cgroup_meta
.namespace_dir
);
3986 static inline int get_config_cgroup_relative(const char *key
, char *retv
,
3987 int inlen
, struct lxc_conf
*lxc_conf
,
3990 return lxc_get_conf_int(lxc_conf
, retv
, inlen
,
3991 lxc_conf
->cgroup_meta
.relative
);
3994 static int get_config_idmaps(const char *key
, char *retv
, int inlen
,
3995 struct lxc_conf
*c
, void *data
)
3998 int len
, listlen
, ret
;
4000 /* "u 1000 1000000 65536"
4002 * let's render this as
4020 #define __LXC_IDMAP_STR_BUF (3 * INTTYPE_TO_STRLEN(uint32_t) + 3 + 1 + 1)
4021 char buf
[__LXC_IDMAP_STR_BUF
];
4026 memset(retv
, 0, inlen
);
4028 listlen
= list_len(&c
->id_map
);
4029 list_for_each_entry(map
, &c
->id_map
, head
) {
4030 ret
= strnprintf(buf
, sizeof(buf
), "%c %lu %lu %lu",
4031 (map
->idtype
== ID_TYPE_UID
) ? 'u' : 'g',
4032 map
->nsid
, map
->hostid
, map
->range
);
4034 return ret_errno(EIO
);
4036 strprint(retv
, inlen
, "%s%s", buf
, (listlen
-- > 1) ? "\n" : "");
4042 static int get_config_log_level(const char *key
, char *retv
, int inlen
,
4043 struct lxc_conf
*c
, void *data
)
4046 v
= lxc_log_priority_to_string(c
->loglevel
);
4047 return lxc_get_conf_str(retv
, inlen
, v
);
4050 static int get_config_log_file(const char *key
, char *retv
, int inlen
,
4051 struct lxc_conf
*c
, void *data
)
4053 return lxc_get_conf_str(retv
, inlen
, c
->logfile
);
4056 static int get_config_mount_fstab(const char *key
, char *retv
, int inlen
,
4057 struct lxc_conf
*c
, void *data
)
4059 return lxc_get_conf_str(retv
, inlen
, c
->fstab
);
4062 static int get_config_mount_auto(const char *key
, char *retv
, int inlen
,
4063 struct lxc_conf
*c
, void *data
)
4065 int len
, fulllen
= 0;
4066 const char *sep
= "";
4071 memset(retv
, 0, inlen
);
4073 if (!(c
->auto_mounts
& LXC_AUTO_ALL_MASK
))
4076 switch (c
->auto_mounts
& LXC_AUTO_PROC_MASK
) {
4077 case LXC_AUTO_PROC_MIXED
:
4078 strprint(retv
, inlen
, "%sproc:mixed", sep
);
4081 case LXC_AUTO_PROC_RW
:
4082 strprint(retv
, inlen
, "%sproc:rw", sep
);
4089 switch (c
->auto_mounts
& LXC_AUTO_SYS_MASK
) {
4090 case LXC_AUTO_SYS_RO
:
4091 strprint(retv
, inlen
, "%ssys:ro", sep
);
4094 case LXC_AUTO_SYS_RW
:
4095 strprint(retv
, inlen
, "%ssys:rw", sep
);
4098 case LXC_AUTO_SYS_MIXED
:
4099 strprint(retv
, inlen
, "%ssys:mixed", sep
);
4106 switch (c
->auto_mounts
& LXC_AUTO_CGROUP_MASK
) {
4107 case LXC_AUTO_CGROUP_NOSPEC
:
4108 strprint(retv
, inlen
, "%scgroup", sep
);
4110 case LXC_AUTO_CGROUP_MIXED
:
4111 strprint(retv
, inlen
, "%scgroup:mixed", sep
);
4113 case LXC_AUTO_CGROUP_RO
:
4114 strprint(retv
, inlen
, "%scgroup:ro", sep
);
4116 case LXC_AUTO_CGROUP_RW
:
4117 strprint(retv
, inlen
, "%scgroup:rw", sep
);
4119 case LXC_AUTO_CGROUP_FULL_NOSPEC
:
4120 strprint(retv
, inlen
, "%scgroup-full", sep
);
4122 case LXC_AUTO_CGROUP_FULL_MIXED
:
4123 strprint(retv
, inlen
, "%scgroup-full:mixed", sep
);
4125 case LXC_AUTO_CGROUP_FULL_RO
:
4126 strprint(retv
, inlen
, "%scgroup-full:ro", sep
);
4128 case LXC_AUTO_CGROUP_FULL_RW
:
4129 strprint(retv
, inlen
, "%scgroup-full:rw", sep
);
4138 static int get_config_mount(const char *key
, char *retv
, int inlen
,
4139 struct lxc_conf
*c
, void *data
)
4141 int len
, fulllen
= 0;
4142 struct lxc_list
*it
;
4147 memset(retv
, 0, inlen
);
4149 lxc_list_for_each(it
, &c
->mount_list
) {
4150 strprint(retv
, inlen
, "%s\n", (char *)it
->elem
);
4156 static int get_config_rootfs_path(const char *key
, char *retv
, int inlen
,
4157 struct lxc_conf
*c
, void *data
)
4159 return lxc_get_conf_str(retv
, inlen
, c
->rootfs
.path
);
4162 static int get_config_rootfs_managed(const char *key
, char *retv
, int inlen
,
4163 struct lxc_conf
*c
, void *data
)
4165 return lxc_get_conf_bool(c
, retv
, inlen
, c
->rootfs
.managed
);
4168 static int get_config_rootfs_mount(const char *key
, char *retv
, int inlen
,
4169 struct lxc_conf
*c
, void *data
)
4171 return lxc_get_conf_str(retv
, inlen
, c
->rootfs
.mount
);
4174 static int get_config_rootfs_options(const char *key
, char *retv
, int inlen
,
4175 struct lxc_conf
*c
, void *data
)
4177 return lxc_get_conf_str(retv
, inlen
, c
->rootfs
.mnt_opts
.raw_options
);
4180 static int get_config_uts_name(const char *key
, char *retv
, int inlen
,
4181 struct lxc_conf
*c
, void *data
)
4183 return lxc_get_conf_str(
4185 c
->utsname
? c
->utsname
->nodename
: NULL
);
4188 static int get_config_hooks(const char *key
, char *retv
, int inlen
,
4189 struct lxc_conf
*c
, void *data
)
4192 int len
, fulllen
= 0, found
= -1;
4193 struct lxc_list
*it
;
4196 subkey
= strchr(key
, '.');
4198 return ret_errno(EINVAL
);
4200 subkey
= strchr(subkey
+ 1, '.');
4202 return ret_errno(EINVAL
);
4204 if (*subkey
== '\0')
4205 return ret_errno(EINVAL
);
4207 for (i
= 0; i
< NUM_LXC_HOOKS
; i
++) {
4208 if (strequal(lxchook_names
[i
], subkey
)) {
4215 return ret_errno(EINVAL
);
4220 memset(retv
, 0, inlen
);
4222 lxc_list_for_each(it
, &c
->hooks
[found
]) {
4223 strprint(retv
, inlen
, "%s\n", (char *)it
->elem
);
4229 static int get_config_hooks_version(const char *key
, char *retv
, int inlen
,
4230 struct lxc_conf
*c
, void *data
)
4232 return lxc_get_conf_int(c
, retv
, inlen
, c
->hooks_version
);
4235 static int get_config_net(const char *key
, char *retv
, int inlen
,
4236 struct lxc_conf
*c
, void *data
)
4238 int len
, fulllen
= 0;
4239 struct lxc_netdev
*netdev
;
4244 memset(retv
, 0, inlen
);
4246 list_for_each_entry(netdev
, &c
->netdevs
, head
) {
4247 const char *t
= lxc_net_type_to_str(netdev
->type
);
4248 strprint(retv
, inlen
, "%s\n", t
? t
: "(invalid)");
4254 static int get_config_cap_drop(const char *key
, char *retv
, int inlen
,
4255 struct lxc_conf
*c
, void *data
)
4257 int len
, fulllen
= 0;
4258 struct lxc_list
*it
;
4263 memset(retv
, 0, inlen
);
4265 lxc_list_for_each(it
, &c
->caps
) {
4266 strprint(retv
, inlen
, "%s\n", (char *)it
->elem
);
4272 static int get_config_cap_keep(const char *key
, char *retv
, int inlen
,
4273 struct lxc_conf
*c
, void *data
)
4275 int len
, fulllen
= 0;
4276 struct lxc_list
*it
;
4281 memset(retv
, 0, inlen
);
4283 lxc_list_for_each(it
, &c
->keepcaps
) {
4284 strprint(retv
, inlen
, "%s\n", (char *)it
->elem
);
4290 static int get_config_console_path(const char *key
, char *retv
, int inlen
,
4291 struct lxc_conf
*c
, void *data
)
4293 return lxc_get_conf_str(retv
, inlen
, c
->console
.path
);
4296 static int get_config_console_logfile(const char *key
, char *retv
, int inlen
,
4297 struct lxc_conf
*c
, void *data
)
4299 return lxc_get_conf_str(retv
, inlen
, c
->console
.log_path
);
4302 static int get_config_console_rotate(const char *key
, char *retv
, int inlen
,
4303 struct lxc_conf
*c
, void *data
)
4305 return lxc_get_conf_int(c
, retv
, inlen
, c
->console
.log_rotate
);
4309 static int get_config_console_buffer_size(const char *key
, char *retv
,
4310 int inlen
, struct lxc_conf
*c
,
4313 return lxc_get_conf_uint64(c
, retv
, inlen
, c
->console
.buffer_size
);
4316 static int get_config_console_size(const char *key
, char *retv
, int inlen
,
4317 struct lxc_conf
*c
, void *data
)
4319 return lxc_get_conf_uint64(c
, retv
, inlen
, c
->console
.log_size
);
4322 static int get_config_seccomp_allow_nesting(const char *key
, char *retv
,
4323 int inlen
, struct lxc_conf
*c
,
4327 return lxc_get_conf_int(c
, retv
, inlen
, c
->seccomp
.allow_nesting
);
4329 return ret_errno(ENOSYS
);
4333 static int get_config_seccomp_notify_cookie(const char *key
, char *retv
, int inlen
,
4334 struct lxc_conf
*c
, void *data
)
4336 #ifdef HAVE_SECCOMP_NOTIFY
4337 return lxc_get_conf_str(retv
, inlen
, c
->seccomp
.notifier
.cookie
);
4339 return ret_errno(ENOSYS
);
4343 static int get_config_seccomp_notify_proxy(const char *key
, char *retv
, int inlen
,
4344 struct lxc_conf
*c
, void *data
)
4346 #ifdef HAVE_SECCOMP_NOTIFY
4347 return lxc_get_conf_str(retv
, inlen
,
4348 (c
->seccomp
.notifier
.proxy_addr
.sun_path
[0]) == '/'
4349 ? &c
->seccomp
.notifier
.proxy_addr
.sun_path
[0]
4350 : &c
->seccomp
.notifier
.proxy_addr
.sun_path
[1]);
4352 return ret_errno(ENOSYS
);
4356 static int get_config_seccomp_profile(const char *key
, char *retv
, int inlen
,
4357 struct lxc_conf
*c
, void *data
)
4360 return lxc_get_conf_str(retv
, inlen
, c
->seccomp
.seccomp
);
4362 return ret_errno(ENOSYS
);
4366 static int get_config_autodev(const char *key
, char *retv
, int inlen
,
4367 struct lxc_conf
*c
, void *data
)
4369 return lxc_get_conf_int(c
, retv
, inlen
, c
->autodev
);
4372 static int get_config_autodev_tmpfs_size(const char *key
, char *retv
, int inlen
,
4373 struct lxc_conf
*c
, void *data
)
4375 return lxc_get_conf_int(c
, retv
, inlen
, c
->autodevtmpfssize
);
4378 static int get_config_signal_halt(const char *key
, char *retv
, int inlen
,
4379 struct lxc_conf
*c
, void *data
)
4381 return lxc_get_conf_int(c
, retv
, inlen
, c
->haltsignal
);
4384 static int get_config_signal_reboot(const char *key
, char *retv
, int inlen
,
4385 struct lxc_conf
*c
, void *data
)
4387 return lxc_get_conf_int(c
, retv
, inlen
, c
->rebootsignal
);
4390 static int get_config_signal_stop(const char *key
, char *retv
, int inlen
,
4391 struct lxc_conf
*c
, void *data
)
4393 return lxc_get_conf_int(c
, retv
, inlen
, c
->stopsignal
);
4396 static int get_config_start(const char *key
, char *retv
, int inlen
,
4397 struct lxc_conf
*c
, void *data
)
4399 if (strequal(key
+ 10, "auto"))
4400 return lxc_get_conf_int(c
, retv
, inlen
, c
->start_auto
);
4401 else if (strequal(key
+ 10, "delay"))
4402 return lxc_get_conf_int(c
, retv
, inlen
, c
->start_delay
);
4403 else if (strequal(key
+ 10, "order"))
4404 return lxc_get_conf_int(c
, retv
, inlen
, c
->start_order
);
4406 return ret_errno(EINVAL
);
4409 static int get_config_log_syslog(const char *key
, char *retv
, int inlen
,
4410 struct lxc_conf
*c
, void *data
)
4412 return lxc_get_conf_str(retv
, inlen
, c
->syslog
);
4415 static int get_config_monitor(const char *key
, char *retv
, int inlen
,
4416 struct lxc_conf
*c
, void *data
)
4418 return lxc_get_conf_int(c
, retv
, inlen
, c
->monitor_unshare
);
4421 static int get_config_monitor_signal_pdeath(const char *key
, char *retv
,
4422 int inlen
, struct lxc_conf
*c
,
4425 return lxc_get_conf_int(c
, retv
, inlen
, c
->monitor_signal_pdeath
);
4428 static int get_config_group(const char *key
, char *retv
, int inlen
,
4429 struct lxc_conf
*c
, void *data
)
4431 int len
, fulllen
= 0;
4432 struct lxc_list
*it
;
4437 memset(retv
, 0, inlen
);
4439 lxc_list_for_each(it
, &c
->groups
) {
4440 strprint(retv
, inlen
, "%s\n", (char *)it
->elem
);
4446 static int get_config_environment(const char *key
, char *retv
, int inlen
,
4447 struct lxc_conf
*c
, void *data
)
4449 int len
, fulllen
= 0;
4450 struct environment_entry
*env
;
4455 memset(retv
, 0, inlen
);
4457 list_for_each_entry(env
, &c
->environment
, head
) {
4458 strprint(retv
, inlen
, "%s=%s\n", env
->key
, env
->val
);
4464 static int get_config_execute_cmd(const char *key
, char *retv
, int inlen
,
4465 struct lxc_conf
*c
, void *data
)
4467 return lxc_get_conf_str(retv
, inlen
, c
->execute_cmd
);
4470 static int get_config_init_cmd(const char *key
, char *retv
, int inlen
,
4471 struct lxc_conf
*c
, void *data
)
4473 return lxc_get_conf_str(retv
, inlen
, c
->init_cmd
);
4476 static int get_config_init_cwd(const char *key
, char *retv
, int inlen
,
4477 struct lxc_conf
*c
, void *data
)
4479 return lxc_get_conf_str(retv
, inlen
, c
->init_cwd
);
4482 static int get_config_init_uid(const char *key
, char *retv
, int inlen
,
4483 struct lxc_conf
*c
, void *data
)
4485 return lxc_get_conf_int(c
, retv
, inlen
, c
->init_uid
);
4488 static int get_config_init_gid(const char *key
, char *retv
, int inlen
,
4489 struct lxc_conf
*c
, void *data
)
4491 return lxc_get_conf_int(c
, retv
, inlen
, c
->init_gid
);
4494 static int get_config_init_groups(const char *key
, char *retv
, int inlen
,
4495 struct lxc_conf
*c
, void *data
)
4497 int fulllen
= 0, len
;
4502 memset(retv
, 0, inlen
);
4504 if (c
->init_groups
.size
== 0)
4507 for (int i
= 0; i
< c
->init_groups
.size
; i
++)
4508 strprint(retv
, inlen
, "%s%d", (i
> 0) ? "," : "",
4509 c
->init_groups
.list
[i
]);
4514 static int get_config_ephemeral(const char *key
, char *retv
, int inlen
,
4515 struct lxc_conf
*c
, void *data
)
4517 return lxc_get_conf_int(c
, retv
, inlen
, c
->ephemeral
);
4520 static int get_config_no_new_privs(const char *key
, char *retv
, int inlen
,
4521 struct lxc_conf
*c
, void *data
)
4523 return lxc_get_conf_int(c
, retv
, inlen
, c
->no_new_privs
);
4526 /* If you ask for a specific value, i.e. lxc.prlimit.nofile, then just the value
4527 * will be printed. If you ask for 'lxc.prlimit', then all limit entries will be
4528 * printed, in 'lxc.prlimit.resource = value' format.
4530 static int get_config_prlimit(const char *key
, char *retv
, int inlen
,
4531 struct lxc_conf
*c
, void *data
)
4533 int fulllen
= 0, len
;
4534 bool get_all
= false;
4535 struct lxc_limit
*lim
;
4540 memset(retv
, 0, inlen
);
4542 if (strequal(key
, "lxc.prlimit"))
4544 else if (strnequal(key
, "lxc.prlimit.", 12))
4547 return ret_errno(EINVAL
);
4549 list_for_each_entry(lim
, &c
->limits
, head
) {
4550 /* 2 colon separated 64 bit integers or the word 'unlimited' */
4551 char buf
[INTTYPE_TO_STRLEN(uint64_t) * 2 + 2];
4554 if (lim
->limit
.rlim_cur
== RLIM_INFINITY
) {
4555 memcpy(buf
, "unlimited", STRLITERALLEN("unlimited") + 1);
4556 partlen
= STRLITERALLEN("unlimited");
4558 partlen
= sprintf(buf
, "%" PRIu64
,
4559 (uint64_t)lim
->limit
.rlim_cur
);
4562 if (lim
->limit
.rlim_cur
!= lim
->limit
.rlim_max
) {
4563 if (lim
->limit
.rlim_max
== RLIM_INFINITY
)
4564 memcpy(buf
+ partlen
, ":unlimited",
4565 STRLITERALLEN(":unlimited") + 1);
4567 sprintf(buf
+ partlen
, ":%" PRIu64
,
4568 (uint64_t)lim
->limit
.rlim_max
);
4572 strprint(retv
, inlen
, "lxc.prlimit.%s = %s\n",
4573 lim
->resource
, buf
);
4574 } else if (strequal(lim
->resource
, key
)) {
4575 strprint(retv
, inlen
, "%s", buf
);
4582 /* If you ask for a specific value, i.e. lxc.sysctl.net.ipv4.ip_forward, then
4583 * just the value will be printed. If you ask for 'lxc.sysctl', then all sysctl
4584 * entries will be printed, in 'lxc.sysctl.key = value' format.
4586 static int get_config_sysctl(const char *key
, char *retv
, int inlen
,
4587 struct lxc_conf
*c
, void *data
)
4590 bool get_all
= false;
4592 struct lxc_sysctl
*sysctl
;
4597 memset(retv
, 0, inlen
);
4599 if (strequal(key
, "lxc.sysctl"))
4601 else if (strnequal(key
, "lxc.sysctl.", STRLITERALLEN("lxc.sysctl.")))
4602 key
+= STRLITERALLEN("lxc.sysctl.");
4604 return ret_errno(EINVAL
);
4606 list_for_each_entry(sysctl
, &c
->sysctls
, head
) {
4608 strprint(retv
, inlen
, "lxc.sysctl.%s = %s\n", sysctl
->key
,
4610 } else if (strequal(sysctl
->key
, key
)) {
4611 strprint(retv
, inlen
, "%s", sysctl
->value
);
4618 static int get_config_proc(const char *key
, char *retv
, int inlen
,
4619 struct lxc_conf
*c
, void *data
)
4622 bool get_all
= false;
4624 struct lxc_proc
*proc
;
4629 memset(retv
, 0, inlen
);
4631 if (strequal(key
, "lxc.proc"))
4633 else if (strnequal(key
, "lxc.proc.", STRLITERALLEN("lxc.proc.")))
4634 key
+= STRLITERALLEN("lxc.proc.");
4636 return ret_errno(EINVAL
);
4638 list_for_each_entry(proc
, &c
->procs
, head
) {
4640 strprint(retv
, inlen
, "lxc.proc.%s = %s\n",
4641 proc
->filename
, proc
->value
);
4642 } else if (strequal(proc
->filename
, key
)) {
4643 strprint(retv
, inlen
, "%s", proc
->value
);
4650 static int get_config_namespace_clone(const char *key
, char *retv
, int inlen
,
4651 struct lxc_conf
*c
, void *data
)
4659 memset(retv
, 0, inlen
);
4661 for (i
= 0; i
< LXC_NS_MAX
; i
++) {
4662 if (c
->ns_clone
& ns_info
[i
].clone_flag
)
4663 strprint(retv
, inlen
, "%s\n", ns_info
[i
].proc_name
);
4669 static int get_config_namespace_keep(const char *key
, char *retv
, int inlen
,
4670 struct lxc_conf
*c
, void *data
)
4678 memset(retv
, 0, inlen
);
4680 for (i
= 0; i
< LXC_NS_MAX
; i
++) {
4681 if (c
->ns_keep
& ns_info
[i
].clone_flag
)
4682 strprint(retv
, inlen
, "%s\n", ns_info
[i
].proc_name
);
4688 static int get_config_time_offset_boot(const char *key
, char *retv
, int inlen
, struct lxc_conf
*c
,
4697 memset(retv
, 0, inlen
);
4699 if (c
->timens
.s_boot
) {
4700 strprint(retv
, inlen
, "%" PRId64
" s\n", c
->timens
.s_boot
);
4702 strprint(retv
, inlen
, "%" PRId64
" ns\n", c
->timens
.ns_boot
);
4708 static int get_config_time_offset_monotonic(const char *key
, char *retv
, int inlen
,
4709 struct lxc_conf
*c
, void *data
)
4717 memset(retv
, 0, inlen
);
4719 if (c
->timens
.s_monotonic
) {
4720 strprint(retv
, inlen
, "%" PRId64
"s\n", c
->timens
.s_monotonic
);
4722 strprint(retv
, inlen
, "%" PRId64
"ns\n", c
->timens
.ns_monotonic
);
4728 static int get_config_namespace_share(const char *key
, char *retv
, int inlen
,
4729 struct lxc_conf
*c
, void *data
)
4732 const char *namespace;
4738 memset(retv
, 0, inlen
);
4740 namespace = key
+ STRLITERALLEN("lxc.namespace.share.");
4741 if (is_empty_string(namespace))
4742 return ret_errno(EINVAL
);
4744 ns_idx
= lxc_namespace_2_ns_idx(namespace);
4748 strprint(retv
, inlen
, "%s", c
->ns_share
[ns_idx
]);
4753 /* Callbacks to clear config items. */
4754 static inline int clr_config_personality(const char *key
, struct lxc_conf
*c
,
4757 c
->personality
= -1;
4761 static inline int clr_config_pty_max(const char *key
, struct lxc_conf
*c
,
4768 static inline int clr_config_tty_max(const char *key
, struct lxc_conf
*c
,
4775 static inline int clr_config_tty_dir(const char *key
, struct lxc_conf
*c
,
4778 free_disarm(c
->ttys
.dir
);
4782 static inline int clr_config_apparmor_profile(const char *key
,
4783 struct lxc_conf
*c
, void *data
)
4786 free_disarm(c
->lsm_aa_profile
);
4789 return syserror_set(-EINVAL
, "Built without AppArmor support");
4793 static inline int clr_config_apparmor_allow_incomplete(const char *key
,
4798 c
->lsm_aa_allow_incomplete
= 0;
4801 return syserror_set(-EINVAL
, "Built without AppArmor support");
4805 static inline int clr_config_apparmor_allow_nesting(const char *key
,
4810 c
->lsm_aa_allow_nesting
= 0;
4813 return syserror_set(-EINVAL
, "Built without AppArmor support");
4817 static inline int clr_config_apparmor_raw(const char *key
,
4822 return lxc_clear_apparmor_raw(c
);
4824 return syserror_set(-EINVAL
, "Built without AppArmor support");
4828 static inline int clr_config_selinux_context(const char *key
,
4829 struct lxc_conf
*c
, void *data
)
4832 free_disarm(c
->lsm_se_context
);
4835 return syserror_set(-EINVAL
, "Built without SELinux support");
4839 static inline int clr_config_selinux_context_keyring(const char *key
,
4840 struct lxc_conf
*c
, void *data
)
4843 free_disarm(c
->lsm_se_keyring_context
);
4846 return syserror_set(-EINVAL
, "Built without SELinux support");
4850 static inline int clr_config_keyring_session(const char *key
,
4851 struct lxc_conf
*c
, void *data
)
4853 c
->keyring_disable_session
= false;
4857 static inline int clr_config_cgroup_controller(const char *key
,
4858 struct lxc_conf
*c
, void *data
)
4860 return lxc_clear_cgroups(c
, key
, CGROUP_SUPER_MAGIC
);
4863 static inline int clr_config_cgroup2_controller(const char *key
,
4864 struct lxc_conf
*c
, void *data
)
4866 return lxc_clear_cgroups(c
, key
, CGROUP2_SUPER_MAGIC
);
4869 static int clr_config_cgroup_dir(const char *key
, struct lxc_conf
*lxc_conf
,
4872 if (!strequal(key
, "lxc.cgroup.dir"))
4873 return ret_errno(EINVAL
);
4875 if (lxc_conf
->cgroup_meta
.dir
)
4876 free_disarm(lxc_conf
->cgroup_meta
.dir
);
4881 static int clr_config_cgroup_monitor_dir(const char *key
,
4882 struct lxc_conf
*lxc_conf
,
4885 free_disarm(lxc_conf
->cgroup_meta
.monitor_dir
);
4889 static int clr_config_cgroup_monitor_pivot_dir(const char *key
,
4890 struct lxc_conf
*lxc_conf
,
4893 free_disarm(lxc_conf
->cgroup_meta
.monitor_pivot_dir
);
4897 static int clr_config_cgroup_container_dir(const char *key
,
4898 struct lxc_conf
*lxc_conf
,
4901 free_disarm(lxc_conf
->cgroup_meta
.container_dir
);
4905 static int clr_config_cgroup_container_inner_dir(const char *key
,
4906 struct lxc_conf
*lxc_conf
,
4909 free_disarm(lxc_conf
->cgroup_meta
.namespace_dir
);
4913 static inline int clr_config_cgroup_relative(const char *key
,
4914 struct lxc_conf
*lxc_conf
,
4917 lxc_conf
->cgroup_meta
.relative
= false;
4921 static inline int clr_config_idmaps(const char *key
, struct lxc_conf
*c
,
4924 return lxc_clear_idmaps(c
);
4927 static inline int clr_config_log_level(const char *key
, struct lxc_conf
*c
,
4930 c
->loglevel
= LXC_LOG_LEVEL_NOTSET
;
4934 static inline int clr_config_log_file(const char *key
, struct lxc_conf
*c
,
4937 free_disarm(c
->logfile
);
4941 static inline int clr_config_mount(const char *key
, struct lxc_conf
*c
,
4944 return lxc_clear_mount_entries(c
);
4947 static inline int clr_config_mount_auto(const char *key
, struct lxc_conf
*c
,
4950 return lxc_clear_automounts(c
);
4953 static inline int clr_config_mount_fstab(const char *key
, struct lxc_conf
*c
,
4956 free_disarm(c
->fstab
);
4960 static inline int clr_config_rootfs_path(const char *key
, struct lxc_conf
*c
,
4963 free_disarm(c
->rootfs
.path
);
4967 static inline int clr_config_rootfs_managed(const char *key
, struct lxc_conf
*c
,
4970 c
->rootfs
.managed
= true;
4974 static inline int clr_config_rootfs_mount(const char *key
, struct lxc_conf
*c
,
4977 free_disarm(c
->rootfs
.mount
);
4981 static inline int clr_config_rootfs_options(const char *key
, struct lxc_conf
*c
,
4984 put_lxc_mount_options(&c
->rootfs
.mnt_opts
);
4989 static inline int clr_config_uts_name(const char *key
, struct lxc_conf
*c
,
4992 free_disarm(c
->utsname
);
4996 static inline int clr_config_hooks(const char *key
, struct lxc_conf
*c
,
4999 return lxc_clear_hooks(c
, key
);
5002 static inline int clr_config_hooks_version(const char *key
, struct lxc_conf
*c
,
5005 /* default to legacy hooks version */
5006 c
->hooks_version
= 0;
5010 static inline int clr_config_net(const char *key
, struct lxc_conf
*c
,
5013 lxc_free_networks(c
);
5018 static inline int clr_config_cap_drop(const char *key
, struct lxc_conf
*c
,
5021 return lxc_clear_config_caps(c
);
5024 static inline int clr_config_cap_keep(const char *key
, struct lxc_conf
*c
,
5027 return lxc_clear_config_keepcaps(c
);
5030 static inline int clr_config_console_path(const char *key
, struct lxc_conf
*c
,
5033 free_disarm(c
->console
.path
);
5037 static inline int clr_config_console_logfile(const char *key
,
5038 struct lxc_conf
*c
, void *data
)
5040 free_disarm(c
->console
.log_path
);
5044 static inline int clr_config_console_rotate(const char *key
, struct lxc_conf
*c
,
5047 c
->console
.log_rotate
= 0;
5051 static inline int clr_config_console_buffer_size(const char *key
,
5052 struct lxc_conf
*c
, void *data
)
5054 c
->console
.buffer_size
= 0;
5058 static inline int clr_config_console_size(const char *key
, struct lxc_conf
*c
,
5061 c
->console
.log_size
= 0;
5065 static inline int clr_config_seccomp_allow_nesting(const char *key
,
5066 struct lxc_conf
*c
, void *data
)
5069 c
->seccomp
.allow_nesting
= 0;
5072 return ret_errno(ENOSYS
);
5076 static inline int clr_config_seccomp_notify_cookie(const char *key
,
5077 struct lxc_conf
*c
, void *data
)
5079 #ifdef HAVE_SECCOMP_NOTIFY
5080 free_disarm(c
->seccomp
.notifier
.cookie
);
5083 return ret_errno(ENOSYS
);
5087 static inline int clr_config_seccomp_notify_proxy(const char *key
,
5088 struct lxc_conf
*c
, void *data
)
5090 #ifdef HAVE_SECCOMP_NOTIFY
5091 memset(&c
->seccomp
.notifier
.proxy_addr
, 0,
5092 sizeof(c
->seccomp
.notifier
.proxy_addr
));
5095 return ret_errno(ENOSYS
);
5099 static inline int clr_config_seccomp_profile(const char *key
,
5100 struct lxc_conf
*c
, void *data
)
5102 free_disarm(c
->seccomp
.seccomp
);
5106 static inline int clr_config_autodev(const char *key
, struct lxc_conf
*c
,
5113 static inline int clr_config_autodev_tmpfs_size(const char *key
, struct lxc_conf
*c
,
5116 c
->autodevtmpfssize
= 500000;
5120 static inline int clr_config_signal_halt(const char *key
, struct lxc_conf
*c
,
5127 static inline int clr_config_signal_reboot(const char *key
, struct lxc_conf
*c
,
5130 c
->rebootsignal
= 0;
5134 static inline int clr_config_signal_stop(const char *key
, struct lxc_conf
*c
,
5141 static inline int clr_config_start(const char *key
, struct lxc_conf
*c
,
5144 if (strequal(key
+ 10, "auto"))
5146 else if (strequal(key
+ 10, "delay"))
5148 else if (strequal(key
+ 10, "order"))
5154 static inline int clr_config_log_syslog(const char *key
, struct lxc_conf
*c
,
5157 free_disarm(c
->syslog
);
5161 static inline int clr_config_monitor(const char *key
, struct lxc_conf
*c
,
5164 c
->monitor_unshare
= 0;
5168 static inline int clr_config_monitor_signal_pdeath(const char *key
,
5169 struct lxc_conf
*c
, void *data
)
5171 c
->monitor_signal_pdeath
= 0;
5175 static inline int clr_config_group(const char *key
, struct lxc_conf
*c
,
5178 return lxc_clear_groups(c
);
5181 static inline int clr_config_environment(const char *key
, struct lxc_conf
*c
,
5184 return lxc_clear_environment(c
);
5187 static inline int clr_config_execute_cmd(const char *key
, struct lxc_conf
*c
,
5190 free_disarm(c
->execute_cmd
);
5194 static inline int clr_config_init_cmd(const char *key
, struct lxc_conf
*c
,
5197 free_disarm(c
->init_cmd
);
5201 static inline int clr_config_init_cwd(const char *key
, struct lxc_conf
*c
,
5204 free_disarm(c
->init_cwd
);
5208 static inline int clr_config_init_uid(const char *key
, struct lxc_conf
*c
,
5215 static inline int clr_config_init_gid(const char *key
, struct lxc_conf
*c
,
5222 static inline int clr_config_init_groups(const char *key
, struct lxc_conf
*c
,
5225 c
->init_groups
.size
= 0;
5226 free_disarm(c
->init_groups
.list
);
5230 static inline int clr_config_ephemeral(const char *key
, struct lxc_conf
*c
,
5237 static inline int clr_config_no_new_privs(const char *key
, struct lxc_conf
*c
,
5240 c
->no_new_privs
= false;
5244 static inline int clr_config_prlimit(const char *key
, struct lxc_conf
*c
,
5247 return lxc_clear_limits(c
, key
);
5250 static inline int clr_config_sysctl(const char *key
, struct lxc_conf
*c
,
5253 return lxc_clear_sysctls(c
, key
);
5256 static inline int clr_config_proc(const char *key
, struct lxc_conf
*c
,
5259 return lxc_clear_procs(c
, key
);
5262 static inline int clr_config_includefiles(const char *key
, struct lxc_conf
*c
,
5268 static int clr_config_namespace_clone(const char *key
,
5269 struct lxc_conf
*lxc_conf
, void *data
)
5271 lxc_conf
->ns_clone
= 0;
5275 static int clr_config_namespace_keep(const char *key
, struct lxc_conf
*lxc_conf
,
5278 lxc_conf
->ns_keep
= 0;
5282 static int clr_config_time_offset_boot(const char *key
, struct lxc_conf
*lxc_conf
, void *data
)
5284 lxc_conf
->timens
.s_boot
= 0;
5285 lxc_conf
->timens
.ns_boot
= 0;
5289 static int clr_config_time_offset_monotonic(const char *key
, struct lxc_conf
*lxc_conf
, void *data
)
5291 lxc_conf
->timens
.s_monotonic
= 0;
5292 lxc_conf
->timens
.ns_monotonic
= 0;
5296 static int clr_config_namespace_share(const char *key
,
5297 struct lxc_conf
*lxc_conf
, void *data
)
5300 const char *namespace;
5302 namespace = key
+ STRLITERALLEN("lxc.namespace.share.");
5303 if (is_empty_string(namespace))
5304 return ret_errno(EINVAL
);
5306 ns_idx
= lxc_namespace_2_ns_idx(namespace);
5310 free(lxc_conf
->ns_share
[ns_idx
]);
5311 lxc_conf
->ns_share
[ns_idx
] = NULL
;
5316 static int get_config_includefiles(const char *key
, char *retv
, int inlen
,
5317 struct lxc_conf
*c
, void *data
)
5319 return ret_errno(ENOSYS
);
5322 struct config_net_info
{
5323 char buf
[NETWORK_SUBKEY_SIZE_MAX
];
5325 const struct lxc_config_net_t
*ops
;
5326 struct lxc_netdev
*netdev
;
5329 static int get_network_config_ops(const char *key
, struct lxc_conf
*lxc_conf
,
5330 struct config_net_info
*info
, bool allocate
)
5335 const char *idx_start
;
5337 if (is_empty_string(key
))
5338 return ret_errno(EINVAL
);
5340 /* check that this is a sensible network key */
5341 if (!strnequal("lxc.net.", key
, STRLITERALLEN("lxc.net.")))
5342 return syserror_set(-EINVAL
, "Invalid network configuration key \"%s\"", key
);
5345 /* beginning of index string */
5346 idx_start
= key
+ STRLITERALLEN("lxc.net.");
5347 if (!isdigit(*idx_start
))
5348 return syserror_set(-EINVAL
, "Failed to detect digit in string \"%s\"", key
+ 8);
5350 ret
= lxc_safe_int64_residual(idx_start
, &tmpidx
, 10, info
->buf
, sizeof(info
->buf
));
5352 return syserror("Failed to parse network index");
5354 if (tmpidx
< 0 || tmpidx
>= INT_MAX
)
5355 return syserror_set(-ERANGE
, "Number of configured networks would overflow the counter");
5356 idx
= (unsigned int)tmpidx
;
5358 info
->netdev
= lxc_get_netdev_by_idx(lxc_conf
, idx
, allocate
);
5360 return ret_errno(EINVAL
);
5362 /* Make sure subkey points to the empty string. */
5363 info
->subkey
= info
->buf
;
5364 if (is_empty_string(info
->subkey
))
5365 return ret_errno(ENOENT
);
5367 if (info
->subkey
[0] != '.')
5368 return syserror_set(-EINVAL
, "Invalid subkey");
5371 /* lxc.net.<idx>.<subkey> */
5372 info
->ops
= lxc_get_config_net(info
->subkey
);
5373 if (info
->ops
== &unsupported_config_net_key
)
5374 return syserror_set(-ENOENT
, "Unknown network configuration key \"%s\"", key
);
5379 /* Config entry is something like "lxc.net.0.ipv4" the key 'lxc.net.' was
5380 * found. So we make sure next comes an integer, find the right callback (by
5381 * rewriting the key), and call it.
5383 static int set_config_jump_table_net(const char *key
, const char *value
,
5384 struct lxc_conf
*lxc_conf
, void *data
)
5386 struct config_net_info info
= {};
5388 const char *idxstring
;
5390 idxstring
= key
+ STRLITERALLEN("lxc.net.");
5391 if (!isdigit(*idxstring
))
5392 return ret_errno(EINVAL
);
5394 if (lxc_config_value_empty(value
))
5395 return clr_config_jump_table_net(key
, lxc_conf
, data
);
5397 ret
= get_network_config_ops(key
, lxc_conf
, &info
, true);
5401 return info
.ops
->set(info
.subkey
, value
, lxc_conf
, info
.netdev
);
5404 static int clr_config_jump_table_net(const char *key
, struct lxc_conf
*lxc_conf
,
5407 struct config_net_info info
= {};
5409 const char *idxstring
;
5411 idxstring
= key
+ 8;
5412 if (!isdigit(*idxstring
))
5413 return ret_errno(EINVAL
);
5415 /* The left conjunct is pretty self-explanatory. The right conjunct
5416 * checks whether the two pointers are equal. If they are we know that
5417 * this is not a key that is namespaced any further and so we are
5418 * supposed to clear the whole network.
5420 if (isdigit(*idxstring
) && (strrchr(key
, '.') == (idxstring
- 1))) {
5421 unsigned int rmnetdevidx
;
5423 ret
= lxc_safe_uint(idxstring
, &rmnetdevidx
);
5427 /* Remove network from network list. */
5428 lxc_remove_nic_by_idx(lxc_conf
, rmnetdevidx
);
5432 ret
= get_network_config_ops(key
, lxc_conf
, &info
, false);
5436 return info
.ops
->clr(info
.subkey
, lxc_conf
, info
.netdev
);
5439 static int clr_config_net_type(const char *key
, struct lxc_conf
*lxc_conf
,
5442 struct lxc_netdev
*netdev
= data
;
5445 return ret_errno(EINVAL
);
5447 lxc_clear_netdev(netdev
);
5452 static int clr_config_net_name(const char *key
, struct lxc_conf
*lxc_conf
,
5455 struct lxc_netdev
*netdev
= data
;
5458 return ret_errno(EINVAL
);
5460 netdev
->name
[0] = '\0';
5465 static int clr_config_net_flags(const char *key
, struct lxc_conf
*lxc_conf
,
5468 struct lxc_netdev
*netdev
= data
;
5471 return ret_errno(EINVAL
);
5478 static int clr_config_net_link(const char *key
, struct lxc_conf
*lxc_conf
,
5481 struct lxc_netdev
*netdev
= data
;
5484 return ret_errno(EINVAL
);
5486 netdev
->link
[0] = '\0';
5491 static int clr_config_net_l2proxy(const char *key
, struct lxc_conf
*lxc_conf
,
5494 struct lxc_netdev
*netdev
= data
;
5497 return ret_errno(EINVAL
);
5499 netdev
->l2proxy
= false;
5504 static int clr_config_net_macvlan_mode(const char *key
,
5505 struct lxc_conf
*lxc_conf
, void *data
)
5507 struct lxc_netdev
*netdev
= data
;
5510 return ret_errno(EINVAL
);
5512 if (netdev
->type
!= LXC_NET_MACVLAN
)
5515 netdev
->priv
.macvlan_attr
.mode
= -1;
5520 static int clr_config_net_ipvlan_mode(const char *key
,
5521 struct lxc_conf
*lxc_conf
, void *data
)
5523 struct lxc_netdev
*netdev
= data
;
5526 return ret_errno(EINVAL
);
5528 if (netdev
->type
!= LXC_NET_IPVLAN
)
5531 netdev
->priv
.ipvlan_attr
.mode
= -1;
5536 static int clr_config_net_ipvlan_isolation(const char *key
,
5537 struct lxc_conf
*lxc_conf
, void *data
)
5539 struct lxc_netdev
*netdev
= data
;
5542 return ret_errno(EINVAL
);
5544 if (netdev
->type
!= LXC_NET_IPVLAN
)
5547 netdev
->priv
.ipvlan_attr
.isolation
= -1;
5552 static int clr_config_net_veth_mode(const char *key
,
5553 struct lxc_conf
*lxc_conf
, void *data
)
5555 struct lxc_netdev
*netdev
= data
;
5558 return ret_errno(EINVAL
);
5560 if (netdev
->type
!= LXC_NET_VETH
)
5563 netdev
->priv
.veth_attr
.mode
= -1;
5568 static int clr_config_net_veth_pair(const char *key
, struct lxc_conf
*lxc_conf
,
5571 struct lxc_netdev
*netdev
= data
;
5574 return ret_errno(EINVAL
);
5576 if (netdev
->type
!= LXC_NET_VETH
)
5579 netdev
->priv
.veth_attr
.pair
[0] = '\0';
5584 static int clr_config_net_veth_vlan_id(const char *key
, struct lxc_conf
*lxc_conf
,
5587 struct lxc_netdev
*netdev
= data
;
5590 return ret_errno(EINVAL
);
5592 if (netdev
->type
!= LXC_NET_VETH
)
5595 netdev
->priv
.veth_attr
.vlan_id
= 0;
5596 netdev
->priv
.veth_attr
.vlan_id_set
= false;
5601 static int clr_config_net_veth_vlan_tagged_id(const char *key
,
5602 struct lxc_conf
*lxc_conf
, void *data
)
5604 struct lxc_netdev
*netdev
= data
;
5605 struct lxc_list
*cur
, *next
;
5608 return ret_errno(EINVAL
);
5610 if (netdev
->type
!= LXC_NET_VETH
)
5613 lxc_list_for_each_safe(cur
, &netdev
->priv
.veth_attr
.vlan_tagged_ids
, next
) {
5622 static int clr_config_net_script_up(const char *key
, struct lxc_conf
*lxc_conf
,
5625 struct lxc_netdev
*netdev
= data
;
5628 return ret_errno(EINVAL
);
5630 free_disarm(netdev
->upscript
);
5635 static int clr_config_net_script_down(const char *key
,
5636 struct lxc_conf
*lxc_conf
, void *data
)
5638 struct lxc_netdev
*netdev
= data
;
5641 return ret_errno(EINVAL
);
5643 free_disarm(netdev
->downscript
);
5648 static int clr_config_net_hwaddr(const char *key
, struct lxc_conf
*lxc_conf
,
5651 struct lxc_netdev
*netdev
= data
;
5654 return ret_errno(EINVAL
);
5656 free_disarm(netdev
->hwaddr
);
5661 static int clr_config_net_mtu(const char *key
, struct lxc_conf
*lxc_conf
,
5664 struct lxc_netdev
*netdev
= data
;
5667 return ret_errno(EINVAL
);
5669 free_disarm(netdev
->mtu
);
5674 static int clr_config_net_vlan_id(const char *key
, struct lxc_conf
*lxc_conf
,
5677 struct lxc_netdev
*netdev
= data
;
5680 return ret_errno(EINVAL
);
5682 if (netdev
->type
!= LXC_NET_VLAN
)
5685 netdev
->priv
.vlan_attr
.vid
= 0;
5690 static int clr_config_net_ipv4_gateway(const char *key
,
5691 struct lxc_conf
*lxc_conf
, void *data
)
5693 struct lxc_netdev
*netdev
= data
;
5696 return ret_errno(EINVAL
);
5698 free_disarm(netdev
->ipv4_gateway
);
5703 static int clr_config_net_ipv4_address(const char *key
,
5704 struct lxc_conf
*lxc_conf
, void *data
)
5706 struct lxc_netdev
*netdev
= data
;
5707 struct lxc_list
*cur
, *next
;
5710 return ret_errno(EINVAL
);
5712 lxc_list_for_each_safe(cur
, &netdev
->ipv4
, next
) {
5721 static int clr_config_net_veth_ipv4_route(const char *key
,
5722 struct lxc_conf
*lxc_conf
, void *data
)
5724 struct lxc_netdev
*netdev
= data
;
5725 struct lxc_list
*cur
, *next
;
5728 return ret_errno(EINVAL
);
5730 if (netdev
->type
!= LXC_NET_VETH
)
5733 lxc_list_for_each_safe(cur
, &netdev
->priv
.veth_attr
.ipv4_routes
, next
) {
5742 static int clr_config_net_ipv6_gateway(const char *key
,
5743 struct lxc_conf
*lxc_conf
, void *data
)
5745 struct lxc_netdev
*netdev
= data
;
5748 return ret_errno(EINVAL
);
5750 free_disarm(netdev
->ipv6_gateway
);
5755 static int clr_config_net_ipv6_address(const char *key
,
5756 struct lxc_conf
*lxc_conf
, void *data
)
5758 struct lxc_netdev
*netdev
= data
;
5759 struct lxc_list
*cur
, *next
;
5762 return ret_errno(EINVAL
);
5764 lxc_list_for_each_safe(cur
, &netdev
->ipv6
, next
) {
5773 static int clr_config_net_veth_ipv6_route(const char *key
,
5774 struct lxc_conf
*lxc_conf
, void *data
)
5776 struct lxc_netdev
*netdev
= data
;
5777 struct lxc_list
*cur
, *next
;
5780 return ret_errno(EINVAL
);
5782 if (netdev
->type
!= LXC_NET_VETH
)
5785 lxc_list_for_each_safe(cur
, &netdev
->priv
.veth_attr
.ipv6_routes
, next
) {
5794 static int get_config_jump_table_net(const char *key
, char *retv
, int inlen
,
5795 struct lxc_conf
*c
, void *data
)
5797 struct config_net_info info
= {};
5799 const char *idxstring
;
5801 idxstring
= key
+ STRLITERALLEN("lxc.net.");
5802 if (!isdigit(*idxstring
))
5803 return ret_errno(EINVAL
);
5805 ret
= get_network_config_ops(key
, c
, &info
, false);
5809 return info
.ops
->get(info
.subkey
, retv
, inlen
, c
, info
.netdev
);
5812 static int get_config_net_type(const char *key
, char *retv
, int inlen
,
5813 struct lxc_conf
*c
, void *data
)
5817 struct lxc_netdev
*netdev
= data
;
5820 return ret_errno(EINVAL
);
5825 memset(retv
, 0, inlen
);
5827 strprint(retv
, inlen
, "%s", lxc_net_type_to_str(netdev
->type
));
5832 static int get_config_net_flags(const char *key
, char *retv
, int inlen
,
5833 struct lxc_conf
*c
, void *data
)
5837 struct lxc_netdev
*netdev
= data
;
5840 return ret_errno(EINVAL
);
5845 memset(retv
, 0, inlen
);
5847 if (netdev
->flags
& IFF_UP
)
5848 strprint(retv
, inlen
, "up");
5853 static int get_config_net_link(const char *key
, char *retv
, int inlen
,
5854 struct lxc_conf
*c
, void *data
)
5858 struct lxc_netdev
*netdev
= data
;
5861 return ret_errno(EINVAL
);
5866 memset(retv
, 0, inlen
);
5868 if (netdev
->link
[0] != '\0')
5869 strprint(retv
, inlen
, "%s", netdev
->link
);
5874 static int get_config_net_l2proxy(const char *key
, char *retv
, int inlen
,
5875 struct lxc_conf
*c
, void *data
)
5877 struct lxc_netdev
*netdev
= data
;
5880 return ret_errno(EINVAL
);
5882 return lxc_get_conf_bool(c
, retv
, inlen
, netdev
->l2proxy
);
5885 static int get_config_net_name(const char *key
, char *retv
, int inlen
,
5886 struct lxc_conf
*c
, void *data
)
5890 struct lxc_netdev
*netdev
= data
;
5893 return ret_errno(EINVAL
);
5898 memset(retv
, 0, inlen
);
5900 if (netdev
->name
[0] != '\0')
5901 strprint(retv
, inlen
, "%s", netdev
->name
);
5906 static int get_config_net_macvlan_mode(const char *key
, char *retv
, int inlen
,
5907 struct lxc_conf
*c
, void *data
)
5912 struct lxc_netdev
*netdev
= data
;
5915 return ret_errno(EINVAL
);
5917 if (netdev
->type
!= LXC_NET_MACVLAN
)
5918 return ret_errno(EINVAL
);
5923 memset(retv
, 0, inlen
);
5925 switch (netdev
->priv
.macvlan_attr
.mode
) {
5926 case MACVLAN_MODE_PRIVATE
:
5929 case MACVLAN_MODE_VEPA
:
5932 case MACVLAN_MODE_BRIDGE
:
5935 case MACVLAN_MODE_PASSTHRU
:
5943 strprint(retv
, inlen
, "%s", mode
);
5948 static int get_config_net_ipvlan_mode(const char *key
, char *retv
, int inlen
,
5949 struct lxc_conf
*c
, void *data
)
5952 struct lxc_netdev
*netdev
= data
;
5957 return ret_errno(EINVAL
);
5959 if (netdev
->type
!= LXC_NET_IPVLAN
)
5960 return ret_errno(EINVAL
);
5965 memset(retv
, 0, inlen
);
5967 switch (netdev
->priv
.ipvlan_attr
.mode
) {
5968 case IPVLAN_MODE_L3
:
5971 case IPVLAN_MODE_L3S
:
5974 case IPVLAN_MODE_L2
:
5982 strprint(retv
, inlen
, "%s", mode
);
5987 static int get_config_net_ipvlan_isolation(const char *key
, char *retv
, int inlen
,
5988 struct lxc_conf
*c
, void *data
)
5991 struct lxc_netdev
*netdev
= data
;
5996 return ret_errno(EINVAL
);
5998 if (netdev
->type
!= LXC_NET_IPVLAN
)
5999 return ret_errno(EINVAL
);
6004 memset(retv
, 0, inlen
);
6006 switch (netdev
->priv
.ipvlan_attr
.isolation
) {
6007 case IPVLAN_ISOLATION_BRIDGE
:
6010 case IPVLAN_ISOLATION_PRIVATE
:
6013 case IPVLAN_ISOLATION_VEPA
:
6021 strprint(retv
, inlen
, "%s", mode
);
6026 static int get_config_net_veth_mode(const char *key
, char *retv
, int inlen
,
6027 struct lxc_conf
*c
, void *data
)
6030 struct lxc_netdev
*netdev
= data
;
6035 return ret_errno(EINVAL
);
6037 if (netdev
->type
!= LXC_NET_VETH
)
6038 return ret_errno(EINVAL
);
6043 memset(retv
, 0, inlen
);
6045 switch (netdev
->priv
.veth_attr
.mode
) {
6046 case VETH_MODE_BRIDGE
:
6049 case VETH_MODE_ROUTER
:
6057 strprint(retv
, inlen
, "%s", mode
);
6062 static int get_config_net_veth_pair(const char *key
, char *retv
, int inlen
,
6063 struct lxc_conf
*c
, void *data
)
6067 struct lxc_netdev
*netdev
= data
;
6070 return ret_errno(EINVAL
);
6072 if (netdev
->type
!= LXC_NET_VETH
)
6073 return ret_errno(EINVAL
);
6078 memset(retv
, 0, inlen
);
6080 strprint(retv
, inlen
, "%s",
6081 netdev
->priv
.veth_attr
.pair
[0] != '\0'
6082 ? netdev
->priv
.veth_attr
.pair
6083 : netdev
->priv
.veth_attr
.veth1
);
6088 static int get_config_net_veth_vlan_id(const char *key
, char *retv
, int inlen
,
6089 struct lxc_conf
*c
, void *data
)
6093 struct lxc_netdev
*netdev
= data
;
6096 return ret_errno(EINVAL
);
6098 if (netdev
->type
!= LXC_NET_VETH
)
6099 return ret_errno(EINVAL
);
6104 memset(retv
, 0, inlen
);
6106 strprint(retv
, inlen
, "%d", netdev
->priv
.veth_attr
.vlan_id
);
6111 static int get_config_net_veth_vlan_tagged_id(const char *key
, char *retv
,
6112 int inlen
, struct lxc_conf
*c
,
6117 struct lxc_list
*it
;
6119 struct lxc_netdev
*netdev
= data
;
6122 return ret_errno(EINVAL
);
6124 if (netdev
->type
!= LXC_NET_VETH
)
6125 return ret_errno(EINVAL
);
6130 memset(retv
, 0, inlen
);
6132 listlen
= lxc_list_len(&netdev
->priv
.veth_attr
.vlan_tagged_ids
);
6134 lxc_list_for_each(it
, &netdev
->priv
.veth_attr
.vlan_tagged_ids
) {
6135 unsigned short i
= PTR_TO_USHORT(it
->elem
);
6136 strprint(retv
, inlen
, "%u%s", i
, (listlen
-- > 1) ? "\n" : "");
6142 static int get_config_net_script_up(const char *key
, char *retv
, int inlen
,
6143 struct lxc_conf
*c
, void *data
)
6147 struct lxc_netdev
*netdev
= data
;
6150 return ret_errno(EINVAL
);
6155 memset(retv
, 0, inlen
);
6157 if (netdev
->upscript
)
6158 strprint(retv
, inlen
, "%s", netdev
->upscript
);
6163 static int get_config_net_script_down(const char *key
, char *retv
, int inlen
,
6164 struct lxc_conf
*c
, void *data
)
6168 struct lxc_netdev
*netdev
= data
;
6171 return ret_errno(EINVAL
);
6176 memset(retv
, 0, inlen
);
6178 if (netdev
->downscript
)
6179 strprint(retv
, inlen
, "%s", netdev
->downscript
);
6184 static int get_config_net_hwaddr(const char *key
, char *retv
, int inlen
,
6185 struct lxc_conf
*c
, void *data
)
6189 struct lxc_netdev
*netdev
= data
;
6192 return ret_errno(EINVAL
);
6197 memset(retv
, 0, inlen
);
6200 strprint(retv
, inlen
, "%s", netdev
->hwaddr
);
6205 static int get_config_net_mtu(const char *key
, char *retv
, int inlen
,
6206 struct lxc_conf
*c
, void *data
)
6210 struct lxc_netdev
*netdev
= data
;
6213 return ret_errno(EINVAL
);
6218 memset(retv
, 0, inlen
);
6221 strprint(retv
, inlen
, "%s", netdev
->mtu
);
6226 static int get_config_net_vlan_id(const char *key
, char *retv
, int inlen
,
6227 struct lxc_conf
*c
, void *data
)
6231 struct lxc_netdev
*netdev
= data
;
6234 return ret_errno(EINVAL
);
6236 if (netdev
->type
!= LXC_NET_VLAN
)
6237 return ret_errno(EINVAL
);
6242 memset(retv
, 0, inlen
);
6244 strprint(retv
, inlen
, "%d", netdev
->priv
.vlan_attr
.vid
);
6249 static int get_config_net_ipv4_gateway(const char *key
, char *retv
, int inlen
,
6250 struct lxc_conf
*c
, void *data
)
6253 char buf
[INET_ADDRSTRLEN
];
6255 struct lxc_netdev
*netdev
= data
;
6258 return ret_errno(EINVAL
);
6263 memset(retv
, 0, inlen
);
6265 if (netdev
->ipv4_gateway_auto
) {
6266 strprint(retv
, inlen
, "auto");
6267 } else if (netdev
->ipv4_gateway_dev
) {
6268 strprint(retv
, inlen
, "dev");
6269 } else if (netdev
->ipv4_gateway
) {
6270 if (!inet_ntop(AF_INET
, netdev
->ipv4_gateway
, buf
, sizeof(buf
)))
6272 strprint(retv
, inlen
, "%s", buf
);
6278 static int get_config_net_ipv4_address(const char *key
, char *retv
, int inlen
,
6279 struct lxc_conf
*c
, void *data
)
6283 char buf
[INET_ADDRSTRLEN
];
6284 struct lxc_list
*it
;
6286 struct lxc_netdev
*netdev
= data
;
6289 return ret_errno(EINVAL
);
6294 memset(retv
, 0, inlen
);
6296 listlen
= lxc_list_len(&netdev
->ipv4
);
6298 lxc_list_for_each(it
, &netdev
->ipv4
) {
6299 struct lxc_inetdev
*i
= it
->elem
;
6300 if (!inet_ntop(AF_INET
, &i
->addr
, buf
, sizeof(buf
)))
6302 strprint(retv
, inlen
, "%s/%u%s", buf
, i
->prefix
,
6303 (listlen
-- > 1) ? "\n" : "");
6309 static int get_config_net_veth_ipv4_route(const char *key
, char *retv
, int inlen
,
6310 struct lxc_conf
*c
, void *data
)
6314 char buf
[INET_ADDRSTRLEN
];
6315 struct lxc_list
*it
;
6317 struct lxc_netdev
*netdev
= data
;
6320 return ret_errno(EINVAL
);
6322 if (netdev
->type
!= LXC_NET_VETH
)
6323 return ret_errno(EINVAL
);
6328 memset(retv
, 0, inlen
);
6330 listlen
= lxc_list_len(&netdev
->priv
.veth_attr
.ipv4_routes
);
6332 lxc_list_for_each(it
, &netdev
->priv
.veth_attr
.ipv4_routes
) {
6333 struct lxc_inetdev
*i
= it
->elem
;
6334 if (!inet_ntop(AF_INET
, &i
->addr
, buf
, sizeof(buf
)))
6336 strprint(retv
, inlen
, "%s/%u%s", buf
, i
->prefix
,
6337 (listlen
-- > 1) ? "\n" : "");
6343 static int get_config_net_ipv6_gateway(const char *key
, char *retv
, int inlen
,
6344 struct lxc_conf
*c
, void *data
)
6347 char buf
[INET6_ADDRSTRLEN
];
6349 struct lxc_netdev
*netdev
= data
;
6352 return ret_errno(EINVAL
);
6357 memset(retv
, 0, inlen
);
6359 if (netdev
->ipv6_gateway_auto
) {
6360 strprint(retv
, inlen
, "auto");
6361 } else if (netdev
->ipv6_gateway_dev
) {
6362 strprint(retv
, inlen
, "dev");
6363 } else if (netdev
->ipv6_gateway
) {
6364 if (!inet_ntop(AF_INET6
, netdev
->ipv6_gateway
, buf
, sizeof(buf
)))
6366 strprint(retv
, inlen
, "%s", buf
);
6372 static int get_config_net_ipv6_address(const char *key
, char *retv
, int inlen
,
6373 struct lxc_conf
*c
, void *data
)
6377 char buf
[INET6_ADDRSTRLEN
];
6378 struct lxc_list
*it
;
6380 struct lxc_netdev
*netdev
= data
;
6383 return ret_errno(EINVAL
);
6388 memset(retv
, 0, inlen
);
6390 listlen
= lxc_list_len(&netdev
->ipv6
);
6392 lxc_list_for_each(it
, &netdev
->ipv6
) {
6393 struct lxc_inet6dev
*i
= it
->elem
;
6394 if (!inet_ntop(AF_INET6
, &i
->addr
, buf
, sizeof(buf
)))
6396 strprint(retv
, inlen
, "%s/%u%s", buf
, i
->prefix
,
6397 (listlen
-- > 1) ? "\n" : "");
6403 static int get_config_net_veth_ipv6_route(const char *key
, char *retv
, int inlen
,
6404 struct lxc_conf
*c
, void *data
)
6408 char buf
[INET6_ADDRSTRLEN
];
6409 struct lxc_list
*it
;
6411 struct lxc_netdev
*netdev
= data
;
6414 return ret_errno(EINVAL
);
6416 if (netdev
->type
!= LXC_NET_VETH
)
6417 return ret_errno(EINVAL
);
6422 memset(retv
, 0, inlen
);
6424 listlen
= lxc_list_len(&netdev
->priv
.veth_attr
.ipv6_routes
);
6426 lxc_list_for_each(it
, &netdev
->priv
.veth_attr
.ipv6_routes
) {
6427 struct lxc_inet6dev
*i
= it
->elem
;
6428 if (!inet_ntop(AF_INET6
, &i
->addr
, buf
, sizeof(buf
)))
6430 strprint(retv
, inlen
, "%s/%u%s", buf
, i
->prefix
,
6431 (listlen
-- > 1) ? "\n" : "");
6437 int lxc_list_config_items(char *retv
, int inlen
)
6446 memset(retv
, 0, inlen
);
6448 for (i
= 0; i
< ARRAY_SIZE(config_jump_table
); i
++) {
6449 char *s
= config_jump_table
[i
].name
;
6451 if (s
[strlen(s
) - 1] == '.')
6454 strprint(retv
, inlen
, "%s\n", s
);
6460 int lxc_list_subkeys(struct lxc_conf
*conf
, const char *key
, char *retv
,
6469 memset(retv
, 0, inlen
);
6471 if (strequal(key
, "lxc.apparmor")) {
6472 strprint(retv
, inlen
, "allow_incomplete\n");
6473 strprint(retv
, inlen
, "allow_nesting\n");
6474 strprint(retv
, inlen
, "profile\n");
6475 strprint(retv
, inlen
, "raw\n");
6476 } else if (strequal(key
, "lxc.cgroup")) {
6477 strprint(retv
, inlen
, "dir\n");
6478 } else if (strequal(key
, "lxc.selinux")) {
6479 strprint(retv
, inlen
, "context\n");
6480 strprint(retv
, inlen
, "context.keyring\n");
6481 } else if (strequal(key
, "lxc.mount")) {
6482 strprint(retv
, inlen
, "auto\n");
6483 strprint(retv
, inlen
, "entry\n");
6484 strprint(retv
, inlen
, "fstab\n");
6485 } else if (strequal(key
, "lxc.rootfs")) {
6486 strprint(retv
, inlen
, "mount\n");
6487 strprint(retv
, inlen
, "options\n");
6488 strprint(retv
, inlen
, "path\n");
6489 } else if (strequal(key
, "lxc.uts")) {
6490 strprint(retv
, inlen
, "name\n");
6491 } else if (strequal(key
, "lxc.hook")) {
6492 strprint(retv
, inlen
, "autodev\n");
6493 strprint(retv
, inlen
, "autodevtmpfssize\n");
6494 strprint(retv
, inlen
, "clone\n");
6495 strprint(retv
, inlen
, "destroy\n");
6496 strprint(retv
, inlen
, "mount\n");
6497 strprint(retv
, inlen
, "post-stop\n");
6498 strprint(retv
, inlen
, "pre-mount\n");
6499 strprint(retv
, inlen
, "pre-start\n");
6500 strprint(retv
, inlen
, "start-host\n");
6501 strprint(retv
, inlen
, "start\n");
6502 strprint(retv
, inlen
, "stop\n");
6503 } else if (strequal(key
, "lxc.cap")) {
6504 strprint(retv
, inlen
, "drop\n");
6505 strprint(retv
, inlen
, "keep\n");
6506 } else if (strequal(key
, "lxc.console")) {
6507 strprint(retv
, inlen
, "logfile\n");
6508 strprint(retv
, inlen
, "path\n");
6509 } else if (strequal(key
, "lxc.seccomp")) {
6510 strprint(retv
, inlen
, "profile\n");
6511 } else if (strequal(key
, "lxc.signal")) {
6512 strprint(retv
, inlen
, "halt\n");
6513 strprint(retv
, inlen
, "reboot\n");
6514 strprint(retv
, inlen
, "stop\n");
6515 } else if (strequal(key
, "lxc.start")) {
6516 strprint(retv
, inlen
, "auto\n");
6517 strprint(retv
, inlen
, "delay\n");
6518 strprint(retv
, inlen
, "order\n");
6519 } else if (strequal(key
, "lxc.monitor")) {
6520 strprint(retv
, inlen
, "unshare\n");
6521 } else if (strequal(key
, "lxc.keyring")) {
6522 strprint(retv
, inlen
, "session\n");
6524 fulllen
= ret_errno(EINVAL
);
6530 int lxc_list_net(struct lxc_conf
*c
, const char *key
, char *retv
, int inlen
)
6532 struct config_net_info info
= {};
6533 struct lxc_netdev
*netdev
;
6535 const char *idxstring
;
6538 idxstring
= key
+ STRLITERALLEN("lxc.net.");
6539 if (!isdigit(*idxstring
))
6540 return ret_errno(EINVAL
);
6542 ret
= get_network_config_ops(key
, c
, &info
, false);
6545 return ret_errno(EINVAL
);
6547 netdev
= info
.netdev
;
6552 memset(retv
, 0, inlen
);
6554 strprint(retv
, inlen
, "type\n");
6555 strprint(retv
, inlen
, "script.up\n");
6556 strprint(retv
, inlen
, "script.down\n");
6558 if (netdev
->type
!= LXC_NET_EMPTY
) {
6559 strprint(retv
, inlen
, "flags\n");
6560 strprint(retv
, inlen
, "link\n");
6561 strprint(retv
, inlen
, "name\n");
6562 strprint(retv
, inlen
, "hwaddr\n");
6563 strprint(retv
, inlen
, "mtu\n");
6564 strprint(retv
, inlen
, "ipv6.address\n");
6565 strprint(retv
, inlen
, "ipv6.gateway\n");
6566 strprint(retv
, inlen
, "ipv4.address\n");
6567 strprint(retv
, inlen
, "ipv4.gateway\n");
6570 switch (netdev
->type
) {
6572 strprint(retv
, inlen
, "veth.pair\n");
6573 strprint(retv
, inlen
, "veth.ipv4.route\n");
6574 strprint(retv
, inlen
, "veth.ipv6.route\n");
6575 strprint(retv
, inlen
, "veth.vlan.id\n");
6577 case LXC_NET_MACVLAN
:
6578 strprint(retv
, inlen
, "macvlan.mode\n");
6580 case LXC_NET_IPVLAN
:
6581 strprint(retv
, inlen
, "ipvlan.mode\n");
6582 strprint(retv
, inlen
, "ipvlan.isolation\n");
6585 strprint(retv
, inlen
, "vlan.id\n");