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 ERROR("lxc.net must not have a value");
400 return clr_config_net(key
, lxc_conf
, data
);
403 static int set_config_net_type(const char *key
, const char *value
,
404 struct lxc_conf
*lxc_conf
, void *data
)
406 struct lxc_netdev
*netdev
= data
;
409 return ret_errno(EINVAL
);
411 clr_config_net_type(key
, lxc_conf
, data
);
412 if (lxc_config_value_empty(value
))
415 if (strequal(value
, "veth")) {
416 netdev
->type
= LXC_NET_VETH
;
417 lxc_list_init(&netdev
->priv
.veth_attr
.ipv4_routes
);
418 lxc_list_init(&netdev
->priv
.veth_attr
.ipv6_routes
);
419 lxc_list_init(&netdev
->priv
.veth_attr
.vlan_tagged_ids
);
420 if (!lxc_veth_flag_to_mode(netdev
->priv
.veth_attr
.mode
))
421 lxc_veth_mode_to_flag(&netdev
->priv
.veth_attr
.mode
, "bridge");
422 } else if (strequal(value
, "macvlan")) {
423 netdev
->type
= LXC_NET_MACVLAN
;
424 if (!lxc_macvlan_flag_to_mode(netdev
->priv
.veth_attr
.mode
))
425 lxc_macvlan_mode_to_flag(&netdev
->priv
.macvlan_attr
.mode
, "private");
426 } else if (strequal(value
, "ipvlan")) {
427 netdev
->type
= LXC_NET_IPVLAN
;
428 if (!lxc_ipvlan_flag_to_mode(netdev
->priv
.ipvlan_attr
.mode
))
429 lxc_ipvlan_mode_to_flag(&netdev
->priv
.ipvlan_attr
.mode
, "l3");
430 if (!lxc_ipvlan_flag_to_isolation(netdev
->priv
.ipvlan_attr
.isolation
))
431 lxc_ipvlan_isolation_to_flag(&netdev
->priv
.ipvlan_attr
.isolation
, "bridge");
432 } else if (strequal(value
, "vlan")) {
433 netdev
->type
= LXC_NET_VLAN
;
434 } else if (strequal(value
, "phys")) {
435 netdev
->type
= LXC_NET_PHYS
;
436 } else if (strequal(value
, "empty")) {
437 netdev
->type
= LXC_NET_EMPTY
;
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
);
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_set_errno(-1, EINVAL
);
1177 static int set_config_seccomp_notify_cookie(const char *key
, const char *value
,
1178 struct lxc_conf
*lxc_conf
, void *data
)
1180 #ifdef HAVE_SECCOMP_NOTIFY
1181 return set_config_string_item(&lxc_conf
->seccomp
.notifier
.cookie
, value
);
1183 return ret_set_errno(-1, ENOSYS
);
1187 static int set_config_seccomp_notify_proxy(const char *key
, const char *value
,
1188 struct lxc_conf
*lxc_conf
, void *data
)
1190 #ifdef HAVE_SECCOMP_NOTIFY
1193 if (lxc_config_value_empty(value
))
1194 return clr_config_seccomp_notify_proxy(key
, lxc_conf
, NULL
);
1196 if (!strnequal(value
, "unix:", 5))
1197 return ret_set_errno(-1, EINVAL
);
1200 if (lxc_unix_sockaddr(&lxc_conf
->seccomp
.notifier
.proxy_addr
, offset
) < 0)
1205 return ret_set_errno(-1, ENOSYS
);
1209 static int set_config_seccomp_profile(const char *key
, const char *value
,
1210 struct lxc_conf
*lxc_conf
, void *data
)
1212 return set_config_path_item(&lxc_conf
->seccomp
.seccomp
, value
);
1215 static int set_config_execute_cmd(const char *key
, const char *value
,
1216 struct lxc_conf
*lxc_conf
, void *data
)
1218 return set_config_path_item(&lxc_conf
->execute_cmd
, value
);
1221 static int set_config_init_cmd(const char *key
, const char *value
,
1222 struct lxc_conf
*lxc_conf
, void *data
)
1224 return set_config_path_item(&lxc_conf
->init_cmd
, value
);
1227 static int set_config_init_cwd(const char *key
, const char *value
,
1228 struct lxc_conf
*lxc_conf
, void *data
)
1230 return set_config_path_item(&lxc_conf
->init_cwd
, value
);
1233 static int set_config_init_uid(const char *key
, const char *value
,
1234 struct lxc_conf
*lxc_conf
, void *data
)
1236 unsigned int init_uid
;
1238 if (lxc_config_value_empty(value
)) {
1239 lxc_conf
->init_uid
= 0;
1243 if (lxc_safe_uint(value
, &init_uid
) < 0)
1246 lxc_conf
->init_uid
= init_uid
;
1251 static int set_config_init_gid(const char *key
, const char *value
,
1252 struct lxc_conf
*lxc_conf
, void *data
)
1254 unsigned int init_gid
;
1256 if (lxc_config_value_empty(value
)) {
1257 lxc_conf
->init_gid
= 0;
1261 if (lxc_safe_uint(value
, &init_gid
) < 0)
1264 lxc_conf
->init_gid
= init_gid
;
1269 static int set_config_init_groups(const char *key
, const char *value
,
1270 struct lxc_conf
*lxc_conf
, void *data
)
1272 __do_free
char *value_dup
= NULL
;
1273 gid_t
*init_groups
= NULL
;
1274 size_t num_groups
= 0;
1278 if (lxc_config_value_empty(value
))
1279 return clr_config_init_groups(key
, lxc_conf
, NULL
);
1281 value_dup
= strdup(value
);
1285 lxc_iterate_parts(token
, value_dup
, ",")
1288 if (num_groups
== INT_MAX
)
1289 return log_error_errno(-ERANGE
, ERANGE
, "Excessive number of supplementary groups specified");
1291 /* This means the string wasn't empty and all we found was garbage. */
1292 if (num_groups
== 0)
1293 return log_error_errno(-EINVAL
, EINVAL
, "No valid groups specified %s", value
);
1295 idx
= lxc_conf
->init_groups
.size
;
1296 init_groups
= realloc(lxc_conf
->init_groups
.list
, sizeof(gid_t
) * (idx
+ num_groups
));
1298 return ret_errno(ENOMEM
);
1301 * Once the realloc() succeeded we need to hand control of the memory
1302 * back to the config otherwise we risk a double-free when
1303 * lxc_conf_free() is called.
1305 lxc_conf
->init_groups
.list
= init_groups
;
1307 /* Restore duplicated value so we can call lxc_iterate_parts() again. */
1308 strcpy(value_dup
, value
);
1310 lxc_iterate_parts(token
, value_dup
, ",") {
1315 ret
= lxc_safe_uint(token
, &group
);
1317 return log_error_errno(ret
, -ret
, "Failed to parse group %s", token
);
1319 init_groups
[idx
++] = group
;
1322 lxc_conf
->init_groups
.size
+= num_groups
;
1327 static int set_config_hooks(const char *key
, const char *value
,
1328 struct lxc_conf
*lxc_conf
, void *data
)
1330 __do_free
char *copy
= NULL
;
1332 if (lxc_config_value_empty(value
))
1333 return lxc_clear_hooks(lxc_conf
, key
);
1335 if (strequal(key
+ 4, "hook"))
1336 return log_error_errno(-EINVAL
, EINVAL
, "lxc.hook must not have a value");
1338 copy
= strdup(value
);
1340 return ret_errno(ENOMEM
);
1342 if (strequal(key
+ 9, "pre-start"))
1343 return add_hook(lxc_conf
, LXCHOOK_PRESTART
, move_ptr(copy
));
1344 else if (strequal(key
+ 9, "start-host"))
1345 return add_hook(lxc_conf
, LXCHOOK_START_HOST
, move_ptr(copy
));
1346 else if (strequal(key
+ 9, "pre-mount"))
1347 return add_hook(lxc_conf
, LXCHOOK_PREMOUNT
, move_ptr(copy
));
1348 else if (strequal(key
+ 9, "autodev"))
1349 return add_hook(lxc_conf
, LXCHOOK_AUTODEV
, move_ptr(copy
));
1350 else if (strequal(key
+ 9, "mount"))
1351 return add_hook(lxc_conf
, LXCHOOK_MOUNT
, move_ptr(copy
));
1352 else if (strequal(key
+ 9, "start"))
1353 return add_hook(lxc_conf
, LXCHOOK_START
, move_ptr(copy
));
1354 else if (strequal(key
+ 9, "stop"))
1355 return add_hook(lxc_conf
, LXCHOOK_STOP
, move_ptr(copy
));
1356 else if (strequal(key
+ 9, "post-stop"))
1357 return add_hook(lxc_conf
, LXCHOOK_POSTSTOP
, move_ptr(copy
));
1358 else if (strequal(key
+ 9, "clone"))
1359 return add_hook(lxc_conf
, LXCHOOK_CLONE
, move_ptr(copy
));
1360 else if (strequal(key
+ 9, "destroy"))
1361 return add_hook(lxc_conf
, LXCHOOK_DESTROY
, move_ptr(copy
));
1363 return ret_errno(EINVAL
);
1366 static int set_config_hooks_version(const char *key
, const char *value
,
1367 struct lxc_conf
*lxc_conf
, void *data
)
1372 if (lxc_config_value_empty(value
))
1373 return clr_config_hooks_version(key
, lxc_conf
, NULL
);
1375 ret
= lxc_safe_uint(value
, &tmp
);
1380 return log_error_errno(-EINVAL
,
1381 EINVAL
, "Invalid hook version specified. Currently only 0 (legacy) and 1 are supported");
1383 lxc_conf
->hooks_version
= tmp
;
1388 static int set_config_personality(const char *key
, const char *value
,
1389 struct lxc_conf
*lxc_conf
, void *data
)
1392 personality_t personality
;
1394 ret
= lxc_config_parse_arch(value
, &personality
);
1396 return syserror("Unsupported personality \"%s\"", value
);
1398 lxc_conf
->personality
= personality
;
1402 static int set_config_pty_max(const char *key
, const char *value
,
1403 struct lxc_conf
*lxc_conf
, void *data
)
1406 unsigned int max
= 0;
1408 if (lxc_config_value_empty(value
)) {
1409 lxc_conf
->pty_max
= 0;
1413 ret
= lxc_safe_uint(value
, &max
);
1415 return ret_errno(EINVAL
);
1417 lxc_conf
->pty_max
= max
;
1422 /* We only need to check whether the first byte of the key after the lxc.start.
1423 * prefix matches our expectations since they fortunately all start with a
1424 * different letter. If anything was wrong with the key we would have already
1425 * noticed when the callback was called.
1427 static int set_config_start(const char *key
, const char *value
,
1428 struct lxc_conf
*lxc_conf
, void *data
)
1433 is_empty
= lxc_config_value_empty(value
);
1435 if (*(key
+ 10) == 'a') { /* lxc.start.auto */
1437 lxc_conf
->start_auto
= 0;
1441 ret
= lxc_safe_uint(value
, &lxc_conf
->start_auto
);
1445 if (lxc_conf
->start_auto
> 1)
1446 return ret_errno(EINVAL
);
1449 } else if (*(key
+ 10) == 'd') { /* lxc.start.delay */
1451 lxc_conf
->start_delay
= 0;
1455 return lxc_safe_uint(value
, &lxc_conf
->start_delay
);
1456 } else if (*(key
+ 10) == 'o') { /* lxc.start.order */
1458 lxc_conf
->start_order
= 0;
1462 return lxc_safe_int(value
, &lxc_conf
->start_order
);
1465 return ret_errno(EINVAL
);
1468 static int set_config_monitor(const char *key
, const char *value
,
1469 struct lxc_conf
*lxc_conf
, void *data
)
1471 if (lxc_config_value_empty(value
)) {
1472 lxc_conf
->monitor_unshare
= 0;
1476 if (strequal(key
+ 12, "unshare"))
1477 return lxc_safe_uint(value
, &lxc_conf
->monitor_unshare
);
1479 return ret_errno(EINVAL
);
1482 static int set_config_monitor_signal_pdeath(const char *key
, const char *value
,
1483 struct lxc_conf
*lxc_conf
, void *data
)
1485 if (lxc_config_value_empty(value
)) {
1486 lxc_conf
->monitor_signal_pdeath
= 0;
1490 if (strequal(key
+ 12, "signal.pdeath")) {
1493 sig_n
= sig_parse(value
);
1495 return ret_errno(EINVAL
);
1497 lxc_conf
->monitor_signal_pdeath
= sig_n
;
1501 return ret_errno(EINVAL
);
1504 static int set_config_group(const char *key
, const char *value
,
1505 struct lxc_conf
*lxc_conf
, void *data
)
1507 __do_free
char *groups
= NULL
;
1510 if (lxc_config_value_empty(value
))
1511 return lxc_clear_groups(lxc_conf
);
1513 groups
= strdup(value
);
1515 return ret_errno(ENOMEM
);
1517 /* In case several groups are specified in a single line split these
1518 * groups in a single element for the list.
1520 lxc_iterate_parts(token
, groups
, " \t") {
1521 __do_free
struct lxc_list
*grouplist
= NULL
;
1523 grouplist
= lxc_list_new();
1525 return ret_errno(ENOMEM
);
1527 grouplist
->elem
= strdup(token
);
1528 if (!grouplist
->elem
)
1529 return ret_errno(ENOMEM
);
1531 lxc_list_add_tail(&lxc_conf
->groups
, move_ptr(grouplist
));
1537 static int set_config_environment(const char *key
, const char *value
,
1538 struct lxc_conf
*lxc_conf
, void *data
)
1540 __do_free
struct lxc_list
*list_item
= NULL
;
1542 if (lxc_config_value_empty(value
))
1543 return lxc_clear_environment(lxc_conf
);
1545 list_item
= lxc_list_new();
1547 return ret_errno(ENOMEM
);
1549 if (!strchr(value
, '=')) {
1550 const char *env_val
;
1551 const char *env_key
= value
;
1552 const char *env_var
[3] = {0};
1554 env_val
= getenv(env_key
);
1556 return ret_errno(ENOENT
);
1558 env_var
[0] = env_key
;
1559 env_var
[1] = env_val
;
1560 list_item
->elem
= lxc_string_join("=", env_var
, false);
1562 list_item
->elem
= strdup(value
);
1565 if (!list_item
->elem
)
1566 return ret_errno(ENOMEM
);
1568 lxc_list_add_tail(&lxc_conf
->environment
, move_ptr(list_item
));
1573 static int set_config_tty_max(const char *key
, const char *value
,
1574 struct lxc_conf
*lxc_conf
, void *data
)
1577 unsigned int nbtty
= 0;
1579 if (lxc_config_value_empty(value
)) {
1580 lxc_conf
->ttys
.max
= 0;
1584 ret
= lxc_safe_uint(value
, &nbtty
);
1588 lxc_conf
->ttys
.max
= nbtty
;
1593 static int set_config_tty_dir(const char *key
, const char *value
,
1594 struct lxc_conf
*lxc_conf
, void *data
)
1596 return set_config_string_item_max(&lxc_conf
->ttys
.dir
, value
,
1600 static int set_config_apparmor_profile(const char *key
, const char *value
,
1601 struct lxc_conf
*lxc_conf
, void *data
)
1604 return set_config_string_item(&lxc_conf
->lsm_aa_profile
, value
);
1606 return syserror_set(-EINVAL
, "Built without AppArmor support");
1610 static int set_config_apparmor_allow_incomplete(const char *key
,
1612 struct lxc_conf
*lxc_conf
,
1618 if (lxc_config_value_empty(value
)) {
1619 lxc_conf
->lsm_aa_allow_incomplete
= 0;
1623 ret
= lxc_safe_uint(value
, &lxc_conf
->lsm_aa_allow_incomplete
);
1627 if (lxc_conf
->lsm_aa_allow_incomplete
> 1)
1628 return ret_errno(EINVAL
);
1632 return syserror_set(-EINVAL
, "Built without AppArmor support");
1636 static int set_config_apparmor_allow_nesting(const char *key
,
1638 struct lxc_conf
*lxc_conf
,
1644 if (lxc_config_value_empty(value
))
1645 return clr_config_apparmor_allow_nesting(key
, lxc_conf
, NULL
);
1647 ret
= lxc_safe_uint(value
, &lxc_conf
->lsm_aa_allow_nesting
);
1651 if (lxc_conf
->lsm_aa_allow_nesting
> 1)
1652 return ret_errno(EINVAL
);
1656 return syserror_set(-EINVAL
, "Built without AppArmor support");
1660 static int set_config_apparmor_raw(const char *key
,
1662 struct lxc_conf
*lxc_conf
,
1666 __do_free
char *elem
= NULL
;
1667 __do_free
struct lxc_list
*list
= NULL
;
1669 if (lxc_config_value_empty(value
))
1670 return lxc_clear_apparmor_raw(lxc_conf
);
1672 list
= lxc_list_new();
1674 return ret_errno(ENOMEM
);
1676 elem
= strdup(value
);
1678 return ret_errno(ENOMEM
);
1680 list
->elem
= move_ptr(elem
);
1681 lxc_list_add_tail(&lxc_conf
->lsm_aa_raw
, move_ptr(list
));
1685 return syserror_set(-EINVAL
, "Built without AppArmor support");
1689 static int set_config_selinux_context(const char *key
, const char *value
,
1690 struct lxc_conf
*lxc_conf
, void *data
)
1693 return set_config_string_item(&lxc_conf
->lsm_se_context
, value
);
1695 return syserror_set(-EINVAL
, "Built without SELinux support");
1699 static int set_config_selinux_context_keyring(const char *key
, const char *value
,
1700 struct lxc_conf
*lxc_conf
, void *data
)
1703 return set_config_string_item(&lxc_conf
->lsm_se_keyring_context
, value
);
1705 return syserror_set(-EINVAL
, "Built without SELinux support");
1709 static int set_config_keyring_session(const char *key
, const char *value
,
1710 struct lxc_conf
*lxc_conf
, void *data
)
1712 return set_config_bool_item(&lxc_conf
->keyring_disable_session
, value
, false);
1715 static int set_config_log_file(const char *key
, const char *value
,
1716 struct lxc_conf
*c
, void *data
)
1720 if (lxc_config_value_empty(value
)) {
1721 free_disarm(c
->logfile
);
1726 * Store these values in the lxc_conf, and then try to set for actual
1729 ret
= set_config_path_item(&c
->logfile
, value
);
1731 ret
= lxc_log_set_file(&c
->logfd
, c
->logfile
);
1736 static int set_config_log_level(const char *key
, const char *value
,
1737 struct lxc_conf
*lxc_conf
, void *data
)
1741 if (lxc_config_value_empty(value
)) {
1742 lxc_conf
->loglevel
= LXC_LOG_LEVEL_NOTSET
;
1746 if (value
[0] >= '0' && value
[0] <= '9') {
1749 ret
= lxc_safe_int(value
, &newlevel
);
1751 return ret_errno(EINVAL
);
1753 newlevel
= lxc_log_priority_to_int(value
);
1757 * Store these values in the lxc_conf, and then try to set for actual
1760 lxc_conf
->loglevel
= newlevel
;
1762 return lxc_log_set_level(&lxc_conf
->loglevel
, newlevel
);
1765 static int set_config_autodev(const char *key
, const char *value
,
1766 struct lxc_conf
*lxc_conf
, void *data
)
1770 if (lxc_config_value_empty(value
)) {
1771 lxc_conf
->autodev
= 0;
1775 ret
= lxc_safe_uint(value
, &lxc_conf
->autodev
);
1777 return ret_errno(EINVAL
);
1779 if (lxc_conf
->autodev
> 1)
1780 return ret_errno(EINVAL
);
1785 static int set_config_autodev_tmpfs_size(const char *key
, const char *value
,
1786 struct lxc_conf
*lxc_conf
, void *data
)
1788 if (lxc_config_value_empty(value
)) {
1789 lxc_conf
->autodevtmpfssize
= 500000;
1793 if (lxc_safe_int(value
, &lxc_conf
->autodevtmpfssize
) < 0)
1794 lxc_conf
->autodevtmpfssize
= 500000;
1799 static int set_config_signal_halt(const char *key
, const char *value
,
1800 struct lxc_conf
*lxc_conf
, void *data
)
1804 if (lxc_config_value_empty(value
)) {
1805 lxc_conf
->haltsignal
= 0;
1809 sig_n
= sig_parse(value
);
1811 return ret_errno(EINVAL
);
1813 lxc_conf
->haltsignal
= sig_n
;
1818 static int set_config_signal_reboot(const char *key
, const char *value
,
1819 struct lxc_conf
*lxc_conf
, void *data
)
1823 if (lxc_config_value_empty(value
)) {
1824 lxc_conf
->rebootsignal
= 0;
1828 sig_n
= sig_parse(value
);
1830 return ret_errno(EINVAL
);
1832 lxc_conf
->rebootsignal
= sig_n
;
1837 static int set_config_signal_stop(const char *key
, const char *value
,
1838 struct lxc_conf
*lxc_conf
, void *data
)
1842 if (lxc_config_value_empty(value
)) {
1843 lxc_conf
->stopsignal
= 0;
1847 sig_n
= sig_parse(value
);
1849 return ret_errno(EINVAL
);
1851 lxc_conf
->stopsignal
= sig_n
;
1856 static int __set_config_cgroup_controller(const char *key
, const char *value
,
1857 struct lxc_conf
*lxc_conf
, int version
)
1859 __do_free
struct lxc_list
*cglist
= NULL
;
1860 call_cleaner(free_lxc_cgroup
) struct lxc_cgroup
*cgelem
= NULL
;
1861 const char *subkey
, *token
;
1864 if (lxc_config_value_empty(value
))
1865 return lxc_clear_cgroups(lxc_conf
, key
, version
);
1867 if (version
== CGROUP2_SUPER_MAGIC
) {
1868 token
= "lxc.cgroup2.";
1870 } else if (version
== CGROUP_SUPER_MAGIC
) {
1871 token
= "lxc.cgroup.";
1874 return ret_errno(EINVAL
);
1877 if (!strnequal(key
, token
, token_len
))
1878 return ret_errno(EINVAL
);
1880 subkey
= key
+ token_len
;
1881 if (*subkey
== '\0')
1882 return ret_errno(EINVAL
);
1884 cglist
= lxc_list_new();
1886 return ret_errno(ENOMEM
);
1888 cgelem
= zalloc(sizeof(*cgelem
));
1890 return ret_errno(ENOMEM
);
1892 cgelem
->subsystem
= strdup(subkey
);
1893 if (!cgelem
->subsystem
)
1894 return ret_errno(ENOMEM
);
1896 cgelem
->value
= strdup(value
);
1898 return ret_errno(ENOMEM
);
1900 cgelem
->version
= version
;
1902 lxc_list_add_elem(cglist
, move_ptr(cgelem
));
1904 if (version
== CGROUP2_SUPER_MAGIC
)
1905 lxc_list_add_tail(&lxc_conf
->cgroup2
, cglist
);
1907 lxc_list_add_tail(&lxc_conf
->cgroup
, cglist
);
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 __do_free
struct lxc_list
*list
= NULL
;
2058 call_cleaner(free_lxc_limit
) struct lxc_limit
*elem
= NULL
;
2059 struct lxc_list
*iter
;
2060 struct rlimit limit
;
2063 if (lxc_config_value_empty(value
))
2064 return lxc_clear_limits(lxc_conf
, key
);
2066 if (!strnequal(key
, "lxc.prlimit.", STRLITERALLEN("lxc.prlimit.")))
2067 return ret_errno(EINVAL
);
2069 key
+= STRLITERALLEN("lxc.prlimit.");
2071 /* soft limit comes first in the value */
2072 if (!parse_limit_value(&value
, &limit_value
))
2073 return ret_errno(EINVAL
);
2075 limit
.rlim_cur
= limit_value
;
2077 /* skip spaces and a colon */
2078 while (isspace(*value
))
2083 else if (*value
) /* any other character is an error here */
2084 return ret_errno(EINVAL
);
2086 while (isspace(*value
))
2089 /* optional hard limit */
2091 if (!parse_limit_value(&value
, &limit_value
))
2092 return ret_errno(EINVAL
);
2094 limit
.rlim_max
= limit_value
;
2096 /* check for trailing garbage */
2097 while (isspace(*value
))
2101 return ret_errno(EINVAL
);
2103 /* a single value sets both hard and soft limit */
2104 limit
.rlim_max
= limit
.rlim_cur
;
2107 /* find existing list element */
2108 lxc_list_for_each(iter
, &lxc_conf
->limits
) {
2109 struct lxc_limit
*cur
= iter
->elem
;
2111 if (!strequal(key
, cur
->resource
))
2118 /* allocate list element */
2119 list
= lxc_list_new();
2121 return ret_errno(ENOMEM
);
2123 elem
= zalloc(sizeof(*elem
));
2125 return ret_errno(ENOMEM
);
2127 elem
->resource
= strdup(key
);
2128 if (!elem
->resource
)
2129 return ret_errno(ENOMEM
);
2131 elem
->limit
= limit
;
2132 lxc_list_add_elem(list
, move_ptr(elem
));;
2133 lxc_list_add_tail(&lxc_conf
->limits
, move_ptr(list
));
2138 static int set_config_sysctl(const char *key
, const char *value
,
2139 struct lxc_conf
*lxc_conf
, void *data
)
2141 __do_free
struct lxc_list
*sysctl_list
= NULL
;
2142 call_cleaner(free_lxc_sysctl
) struct lxc_sysctl
*sysctl_elem
= NULL
;
2143 struct lxc_list
*iter
;
2145 if (lxc_config_value_empty(value
))
2146 return clr_config_sysctl(key
, lxc_conf
, NULL
);
2148 if (!strnequal(key
, "lxc.sysctl.", STRLITERALLEN("lxc.sysctl.")))
2151 key
+= STRLITERALLEN("lxc.sysctl.");
2152 if (is_empty_string(key
))
2153 return ret_errno(-EINVAL
);
2155 /* find existing list element */
2156 lxc_list_for_each(iter
, &lxc_conf
->sysctls
) {
2157 __do_free
char *replace_value
= NULL
;
2158 struct lxc_sysctl
*cur
= iter
->elem
;
2160 if (!strequal(key
, cur
->key
))
2163 replace_value
= strdup(value
);
2165 return ret_errno(EINVAL
);
2168 cur
->value
= move_ptr(replace_value
);
2173 /* allocate list element */
2174 sysctl_list
= lxc_list_new();
2176 return ret_errno(ENOMEM
);
2178 sysctl_elem
= zalloc(sizeof(*sysctl_elem
));
2180 return ret_errno(ENOMEM
);
2182 sysctl_elem
->key
= strdup(key
);
2183 if (!sysctl_elem
->key
)
2184 return ret_errno(ENOMEM
);
2186 sysctl_elem
->value
= strdup(value
);
2187 if (!sysctl_elem
->value
)
2188 return ret_errno(ENOMEM
);
2190 lxc_list_add_elem(sysctl_list
, move_ptr(sysctl_elem
));
2191 lxc_list_add_tail(&lxc_conf
->sysctls
, move_ptr(sysctl_list
));
2196 static int set_config_proc(const char *key
, const char *value
,
2197 struct lxc_conf
*lxc_conf
, void *data
)
2199 __do_free
struct lxc_list
*proclist
= NULL
;
2200 call_cleaner(free_lxc_proc
) struct lxc_proc
*procelem
= NULL
;
2203 if (lxc_config_value_empty(value
))
2204 return clr_config_proc(key
, lxc_conf
, NULL
);
2206 if (!strnequal(key
, "lxc.proc.", STRLITERALLEN("lxc.proc.")))
2209 subkey
= key
+ STRLITERALLEN("lxc.proc.");
2210 if (*subkey
== '\0')
2211 return ret_errno(EINVAL
);
2213 proclist
= lxc_list_new();
2215 return ret_errno(ENOMEM
);
2217 procelem
= zalloc(sizeof(*procelem
));
2219 return ret_errno(ENOMEM
);
2221 procelem
->filename
= strdup(subkey
);
2222 if (!procelem
->filename
)
2223 return ret_errno(ENOMEM
);
2225 procelem
->value
= strdup(value
);
2226 if (!procelem
->value
)
2227 return ret_errno(ENOMEM
);
2229 proclist
->elem
= move_ptr(procelem
);
2230 lxc_list_add_tail(&lxc_conf
->procs
, move_ptr(proclist
));
2235 static int set_config_idmaps(const char *key
, const char *value
,
2236 struct lxc_conf
*lxc_conf
, void *data
)
2238 __do_free
struct lxc_list
*idmaplist
= NULL
;
2239 __do_free
struct id_map
*idmap
= NULL
;
2240 unsigned long hostid
, nsid
, range
;
2244 if (lxc_config_value_empty(value
))
2245 return lxc_clear_idmaps(lxc_conf
);
2247 idmaplist
= lxc_list_new();
2249 return ret_errno(ENOMEM
);
2251 idmap
= zalloc(sizeof(*idmap
));
2253 return ret_errno(ENOMEM
);
2255 ret
= parse_idmaps(value
, &type
, &nsid
, &hostid
, &range
);
2257 return log_error_errno(-EINVAL
, EINVAL
, "Failed to parse id mappings");
2259 INFO("Read uid map: type %c nsid %lu hostid %lu range %lu", type
, nsid
, hostid
, range
);
2261 idmap
->idtype
= ID_TYPE_UID
;
2262 else if (type
== 'g')
2263 idmap
->idtype
= ID_TYPE_GID
;
2265 return ret_errno(EINVAL
);
2267 idmap
->hostid
= hostid
;
2269 idmap
->range
= range
;
2270 idmaplist
->elem
= idmap
;
2271 lxc_list_add_tail(&lxc_conf
->id_map
, idmaplist
);
2273 if (!lxc_conf
->root_nsuid_map
&& idmap
->idtype
== ID_TYPE_UID
)
2274 if (idmap
->nsid
== 0)
2275 lxc_conf
->root_nsuid_map
= idmap
;
2277 if (!lxc_conf
->root_nsgid_map
&& idmap
->idtype
== ID_TYPE_GID
)
2278 if (idmap
->nsid
== 0)
2279 lxc_conf
->root_nsgid_map
= idmap
;
2282 move_ptr(idmaplist
);
2287 static int set_config_mount_fstab(const char *key
, const char *value
,
2288 struct lxc_conf
*lxc_conf
, void *data
)
2290 if (lxc_config_value_empty(value
)) {
2291 clr_config_mount_fstab(key
, lxc_conf
, NULL
);
2292 return ret_errno(EINVAL
);
2295 return set_config_path_item(&lxc_conf
->fstab
, value
);
2298 static int set_config_mount_auto(const char *key
, const char *value
,
2299 struct lxc_conf
*lxc_conf
, void *data
)
2301 __do_free
char *autos
= NULL
;
2308 } allowed_auto_mounts
[] = {
2309 { "proc", LXC_AUTO_PROC_MASK
, LXC_AUTO_PROC_MIXED
},
2310 { "proc:mixed", LXC_AUTO_PROC_MASK
, LXC_AUTO_PROC_MIXED
},
2311 { "proc:rw", LXC_AUTO_PROC_MASK
, LXC_AUTO_PROC_RW
},
2312 { "sys", LXC_AUTO_SYS_MASK
, LXC_AUTO_SYS_MIXED
},
2313 { "sys:ro", LXC_AUTO_SYS_MASK
, LXC_AUTO_SYS_RO
},
2314 { "sys:mixed", LXC_AUTO_SYS_MASK
, LXC_AUTO_SYS_MIXED
},
2315 { "sys:rw", LXC_AUTO_SYS_MASK
, LXC_AUTO_SYS_RW
},
2316 { "cgroup", LXC_AUTO_CGROUP_MASK
, LXC_AUTO_CGROUP_NOSPEC
},
2317 { "cgroup:mixed", LXC_AUTO_CGROUP_MASK
, LXC_AUTO_CGROUP_MIXED
},
2318 { "cgroup:ro", LXC_AUTO_CGROUP_MASK
, LXC_AUTO_CGROUP_RO
},
2319 { "cgroup:rw", LXC_AUTO_CGROUP_MASK
, LXC_AUTO_CGROUP_RW
},
2320 { "cgroup:force", LXC_AUTO_CGROUP_MASK
, LXC_AUTO_CGROUP_NOSPEC
| LXC_AUTO_CGROUP_FORCE
},
2321 { "cgroup:mixed:force", LXC_AUTO_CGROUP_MASK
, LXC_AUTO_CGROUP_MIXED
| LXC_AUTO_CGROUP_FORCE
},
2322 { "cgroup:ro:force", LXC_AUTO_CGROUP_MASK
, LXC_AUTO_CGROUP_RO
| LXC_AUTO_CGROUP_FORCE
},
2323 { "cgroup:rw:force", LXC_AUTO_CGROUP_MASK
, LXC_AUTO_CGROUP_RW
| LXC_AUTO_CGROUP_FORCE
},
2324 { "cgroup-full", LXC_AUTO_CGROUP_MASK
, LXC_AUTO_CGROUP_FULL_NOSPEC
},
2325 { "cgroup-full:mixed", LXC_AUTO_CGROUP_MASK
, LXC_AUTO_CGROUP_FULL_MIXED
},
2326 { "cgroup-full:ro", LXC_AUTO_CGROUP_MASK
, LXC_AUTO_CGROUP_FULL_RO
},
2327 { "cgroup-full:rw", LXC_AUTO_CGROUP_MASK
, LXC_AUTO_CGROUP_FULL_RW
},
2328 { "cgroup-full:force", LXC_AUTO_CGROUP_MASK
, LXC_AUTO_CGROUP_FULL_NOSPEC
| LXC_AUTO_CGROUP_FORCE
},
2329 { "cgroup-full:mixed:force", LXC_AUTO_CGROUP_MASK
, LXC_AUTO_CGROUP_FULL_MIXED
| LXC_AUTO_CGROUP_FORCE
},
2330 { "cgroup-full:ro:force", LXC_AUTO_CGROUP_MASK
, LXC_AUTO_CGROUP_FULL_RO
| LXC_AUTO_CGROUP_FORCE
},
2331 { "cgroup-full:rw:force", LXC_AUTO_CGROUP_MASK
, LXC_AUTO_CGROUP_FULL_RW
| LXC_AUTO_CGROUP_FORCE
},
2332 { "shmounts:", LXC_AUTO_SHMOUNTS_MASK
, LXC_AUTO_SHMOUNTS
},
2334 * For adding anything that is just a single on/off, but has no
2335 * options: keep mask and flag identical and just define the
2336 * enum value as an unused bit so far
2341 if (lxc_config_value_empty(value
)) {
2342 lxc_conf
->auto_mounts
= 0;
2346 autos
= strdup(value
);
2348 return ret_errno(ENOMEM
);
2350 lxc_iterate_parts(token
, autos
, " \t") {
2351 bool is_shmounts
= false;
2353 for (i
= 0; allowed_auto_mounts
[i
].token
; i
++) {
2354 if (strequal(allowed_auto_mounts
[i
].token
, token
))
2357 if (strequal("shmounts:", allowed_auto_mounts
[i
].token
) &&
2358 strnequal("shmounts:", token
, STRLITERALLEN("shmounts:"))) {
2364 if (!allowed_auto_mounts
[i
].token
)
2365 return log_error_errno(-EINVAL
, EINVAL
, "Invalid filesystem to automount \"%s\"", token
);
2367 lxc_conf
->auto_mounts
&= ~allowed_auto_mounts
[i
].mask
;
2368 lxc_conf
->auto_mounts
|= allowed_auto_mounts
[i
].flag
;
2371 __do_free
char *container_path
= NULL
, *host_path
= NULL
;
2374 val
= token
+ STRLITERALLEN("shmounts:");
2376 return log_error_errno(-EINVAL
, EINVAL
, "Failed to copy shmounts host path");
2378 host_path
= strdup(val
);
2380 return log_error_errno(-EINVAL
, EINVAL
, "Failed to copy shmounts host path");
2382 val
= strchr(host_path
, ':');
2383 if (!val
|| *(val
+ 1) == '\0')
2384 val
= "/dev/.lxc-mounts";
2388 container_path
= strdup(val
);
2390 return log_error_errno(-EINVAL
, EINVAL
, "Failed to copy shmounts container path");
2392 free_disarm(lxc_conf
->shmount
.path_host
);
2393 lxc_conf
->shmount
.path_host
= move_ptr(host_path
);
2395 free_disarm(lxc_conf
->shmount
.path_cont
);
2396 lxc_conf
->shmount
.path_cont
= move_ptr(container_path
);
2403 static int set_config_mount(const char *key
, const char *value
,
2404 struct lxc_conf
*lxc_conf
, void *data
)
2406 __do_free
char *mntelem
= NULL
;
2407 __do_free
struct lxc_list
*mntlist
= NULL
;
2409 if (lxc_config_value_empty(value
))
2410 return lxc_clear_mount_entries(lxc_conf
);
2412 mntlist
= lxc_list_new();
2414 return ret_errno(ENOMEM
);
2416 mntelem
= strdup(value
);
2418 return ret_errno(ENOMEM
);
2420 mntlist
->elem
= move_ptr(mntelem
);
2421 lxc_list_add_tail(&lxc_conf
->mount_list
, move_ptr(mntlist
));
2426 int add_elem_to_mount_list(const char *value
, struct lxc_conf
*lxc_conf
) {
2427 return set_config_mount(NULL
, value
, lxc_conf
, NULL
);
2430 static int set_config_cap_keep(const char *key
, const char *value
,
2431 struct lxc_conf
*lxc_conf
, void *data
)
2433 __do_free
char *keepcaps
= NULL
;
2434 __do_free
struct lxc_list
*keeplist
= NULL
;
2437 if (lxc_config_value_empty(value
))
2438 return lxc_clear_config_keepcaps(lxc_conf
);
2440 keepcaps
= strdup(value
);
2442 return ret_errno(ENOMEM
);
2444 /* In case several capability keep is specified in a single line
2445 * split these caps in a single element for the list.
2447 lxc_iterate_parts(token
, keepcaps
, " \t") {
2448 if (strequal(token
, "none"))
2449 lxc_clear_config_keepcaps(lxc_conf
);
2451 keeplist
= lxc_list_new();
2453 return ret_errno(ENOMEM
);
2455 keeplist
->elem
= strdup(token
);
2456 if (!keeplist
->elem
)
2457 return ret_errno(ENOMEM
);
2459 lxc_list_add_tail(&lxc_conf
->keepcaps
, move_ptr(keeplist
));
2465 static int set_config_cap_drop(const char *key
, const char *value
,
2466 struct lxc_conf
*lxc_conf
, void *data
)
2468 __do_free
char *dropcaps
= NULL
;
2469 __do_free
struct lxc_list
*droplist
= NULL
;
2472 if (lxc_config_value_empty(value
))
2473 return lxc_clear_config_caps(lxc_conf
);
2475 dropcaps
= strdup(value
);
2477 return ret_errno(ENOMEM
);
2479 /* In case several capability drop is specified in a single line
2480 * split these caps in a single element for the list.
2482 lxc_iterate_parts(token
, dropcaps
, " \t") {
2483 droplist
= lxc_list_new();
2485 return ret_errno(ENOMEM
);
2487 droplist
->elem
= strdup(token
);
2488 if (!droplist
->elem
)
2489 return ret_errno(ENOMEM
);
2491 lxc_list_add_tail(&lxc_conf
->caps
, move_ptr(droplist
));
2497 static int set_config_console_path(const char *key
, const char *value
,
2498 struct lxc_conf
*lxc_conf
, void *data
)
2500 return set_config_path_item(&lxc_conf
->console
.path
, value
);
2503 static int set_config_console_rotate(const char *key
, const char *value
,
2504 struct lxc_conf
*lxc_conf
, void *data
)
2508 if (lxc_config_value_empty(value
)) {
2509 lxc_conf
->console
.log_rotate
= 0;
2513 ret
= lxc_safe_uint(value
, &lxc_conf
->console
.log_rotate
);
2515 return ret_errno(EINVAL
);
2517 if (lxc_conf
->console
.log_rotate
> 1)
2518 return log_error_errno(-EINVAL
, EINVAL
, "The \"lxc.console.rotate\" config key can only be set to 0 or 1");
2523 static int set_config_console_logfile(const char *key
, const char *value
,
2524 struct lxc_conf
*lxc_conf
, void *data
)
2526 return set_config_path_item(&lxc_conf
->console
.log_path
, value
);
2529 static int set_config_console_buffer_size(const char *key
, const char *value
,
2530 struct lxc_conf
*lxc_conf
, void *data
)
2534 uint64_t buffer_size
, pgsz
;
2536 if (lxc_config_value_empty(value
)) {
2537 lxc_conf
->console
.buffer_size
= 0;
2541 /* If the user specified "auto" the default log size is 2^17 = 128 Kib */
2542 if (strequal(value
, "auto")) {
2543 lxc_conf
->console
.buffer_size
= 1 << 17;
2547 ret
= parse_byte_size_string(value
, &size
);
2552 return ret_errno(EINVAL
);
2554 /* must be at least a page size */
2555 pgsz
= lxc_getpagesize();
2556 if ((uint64_t)size
< pgsz
) {
2557 NOTICE("Requested ringbuffer size for the console is %lld but must be at least %" PRId64
" bytes. Setting ringbuffer size to %" PRId64
" bytes",
2562 buffer_size
= lxc_find_next_power2((uint64_t)size
);
2563 if (buffer_size
== 0)
2564 return ret_errno(EINVAL
);
2566 if (buffer_size
!= size
)
2567 NOTICE("Passed size was not a power of 2. Rounding log size to next power of two: %" PRIu64
" bytes", buffer_size
);
2569 lxc_conf
->console
.buffer_size
= buffer_size
;
2574 static int set_config_console_size(const char *key
, const char *value
,
2575 struct lxc_conf
*lxc_conf
, void *data
)
2579 uint64_t log_size
, pgsz
;
2581 if (lxc_config_value_empty(value
)) {
2582 lxc_conf
->console
.log_size
= 0;
2586 /* If the user specified "auto" the default log size is 2^17 = 128 Kib */
2587 if (strequal(value
, "auto")) {
2588 lxc_conf
->console
.log_size
= 1 << 17;
2592 ret
= parse_byte_size_string(value
, &size
);
2594 return ret_errno(EINVAL
);
2597 return ret_errno(EINVAL
);
2599 /* must be at least a page size */
2600 pgsz
= lxc_getpagesize();
2601 if ((uint64_t)size
< pgsz
) {
2602 NOTICE("Requested ringbuffer size for the console is %lld but must be at least %" PRId64
" bytes. Setting ringbuffer size to %" PRId64
" bytes",
2607 log_size
= lxc_find_next_power2((uint64_t)size
);
2609 return ret_errno(EINVAL
);
2611 if (log_size
!= size
)
2612 NOTICE("Passed size was not a power of 2. Rounding log size to next power of two: %" PRIu64
" bytes", log_size
);
2614 lxc_conf
->console
.log_size
= log_size
;
2620 * If we find a lxc.net.[i].hwaddr or lxc.network.hwaddr in the original config
2621 * file, we expand it in the unexpanded_config, so that after a save_config we
2622 * store the hwaddr for re-use.
2623 * This is only called when reading the config file, not when executing a
2625 * 'x' and 'X' are substituted in-place.
2627 static void update_hwaddr(const char *line
)
2631 line
+= lxc_char_left_gc(line
, strlen(line
));
2635 if (!lxc_config_net_is_hwaddr(line
))
2638 /* Let config_net_hwaddr raise the error. */
2639 p
= strchr(line
, '=');
2650 rand_complete_hwaddr(p
);
2653 int append_unexp_config_line(const char *line
, struct lxc_conf
*conf
)
2656 size_t len
= conf
->unexpanded_len
;
2658 update_hwaddr(line
);
2660 linelen
= strlen(line
);
2661 while (conf
->unexpanded_alloced
<= len
+ linelen
+ 2) {
2664 tmp
= realloc(conf
->unexpanded_config
, conf
->unexpanded_alloced
+ 1024);
2666 return ret_errno(EINVAL
);
2668 if (!conf
->unexpanded_config
)
2671 conf
->unexpanded_config
= tmp
;
2672 conf
->unexpanded_alloced
+= 1024;
2675 memcpy(conf
->unexpanded_config
+ conf
->unexpanded_len
, line
, linelen
);
2676 conf
->unexpanded_len
+= linelen
;
2677 if (line
[linelen
- 1] != '\n')
2678 conf
->unexpanded_config
[conf
->unexpanded_len
++] = '\n';
2679 conf
->unexpanded_config
[conf
->unexpanded_len
] = '\0';
2684 static int do_includedir(const char *dirp
, struct lxc_conf
*lxc_conf
)
2686 __do_closedir
DIR *dir
= NULL
;
2687 struct dirent
*direntp
;
2690 dir
= opendir(dirp
);
2694 while ((direntp
= readdir(dir
))) {
2696 char path
[PATH_MAX
];
2698 fnam
= direntp
->d_name
;
2699 if (strequal(fnam
, "."))
2702 if (strequal(fnam
, ".."))
2706 if (len
< 6 || !strnequal(fnam
+ len
- 5, ".conf", 5))
2709 len
= strnprintf(path
, sizeof(path
), "%s/%s", dirp
, fnam
);
2711 return ret_errno(EIO
);
2713 ret
= lxc_config_read(path
, lxc_conf
, true);
2721 static int set_config_includefiles(const char *key
, const char *value
,
2722 struct lxc_conf
*lxc_conf
, void *data
)
2724 if (lxc_config_value_empty(value
)) {
2725 clr_config_includefiles(key
, lxc_conf
, NULL
);
2730 return do_includedir(value
, lxc_conf
);
2732 return lxc_config_read(value
, lxc_conf
, true);
2735 static int set_config_rootfs_path(const char *key
, const char *value
,
2736 struct lxc_conf
*lxc_conf
, void *data
)
2738 __do_free
char *dup
= NULL
;
2741 const char *container_path
;
2743 if (lxc_config_value_empty(value
)) {
2744 free(lxc_conf
->rootfs
.path
);
2745 lxc_conf
->rootfs
.path
= NULL
;
2749 dup
= strdup(value
);
2751 return ret_errno(ENOMEM
);
2753 /* Split <storage type>:<container path> into <storage type> and
2754 * <container path>. Set "rootfs.bdev_type" to <storage type> and
2755 * "rootfs.path" to <container path>.
2757 tmp
= strchr(dup
, ':');
2761 ret
= set_config_path_item(&lxc_conf
->rootfs
.bdev_type
, dup
);
2763 return ret_errno(ENOMEM
);
2766 container_path
= tmp
;
2768 container_path
= value
;
2771 return set_config_path_item(&lxc_conf
->rootfs
.path
, container_path
);
2774 static int set_config_rootfs_managed(const char *key
, const char *value
,
2775 struct lxc_conf
*lxc_conf
, void *data
)
2777 return set_config_bool_item(&lxc_conf
->rootfs
.managed
, value
, true);
2780 static int set_config_rootfs_mount(const char *key
, const char *value
,
2781 struct lxc_conf
*lxc_conf
, void *data
)
2783 return set_config_path_item(&lxc_conf
->rootfs
.mount
, value
);
2786 static int set_config_rootfs_options(const char *key
, const char *value
,
2787 struct lxc_conf
*lxc_conf
, void *data
)
2789 __do_free
char *dup
= NULL
, *mdata
= NULL
, *opts
= NULL
;
2790 struct lxc_rootfs
*rootfs
= &lxc_conf
->rootfs
;
2791 struct lxc_mount_options
*mnt_opts
= &rootfs
->mnt_opts
;
2794 clr_config_rootfs_options(key
, lxc_conf
, data
);
2795 if (lxc_config_value_empty(value
))
2798 dup
= strdup(value
);
2802 ret
= parse_lxc_mntopts(mnt_opts
, dup
);
2806 ret
= parse_mntopts(dup
, &mnt_opts
->mnt_flags
, &mdata
);
2808 return ret_errno(EINVAL
);
2810 ret
= parse_propagationopts(dup
, &mnt_opts
->prop_flags
);
2812 return ret_errno(EINVAL
);
2814 ret
= set_config_string_item(&opts
, dup
);
2816 return ret_errno(ENOMEM
);
2818 if (mnt_opts
->create_dir
|| mnt_opts
->create_file
||
2819 mnt_opts
->optional
|| mnt_opts
->relative
)
2820 return syserror_set(-EINVAL
, "Invalid LXC specifc mount option for rootfs mount");
2822 mnt_opts
->data
= move_ptr(mdata
);
2823 rootfs
->options
= move_ptr(opts
);
2828 static int set_config_uts_name(const char *key
, const char *value
,
2829 struct lxc_conf
*lxc_conf
, void *data
)
2831 __do_free
struct utsname
*utsname
= NULL
;
2833 if (lxc_config_value_empty(value
)) {
2834 clr_config_uts_name(key
, lxc_conf
, NULL
);
2838 utsname
= zalloc(sizeof(*utsname
));
2840 return ret_errno(ENOMEM
);
2842 if (strlen(value
) >= sizeof(utsname
->nodename
))
2843 return ret_errno(EINVAL
);
2845 (void)strlcpy(utsname
->nodename
, value
, sizeof(utsname
->nodename
));
2846 free(lxc_conf
->utsname
);
2847 lxc_conf
->utsname
= move_ptr(utsname
);
2852 static int set_config_namespace_clone(const char *key
, const char *value
,
2853 struct lxc_conf
*lxc_conf
, void *data
)
2855 __do_free
char *ns
= NULL
;
2859 if (lxc_config_value_empty(value
))
2860 return clr_config_namespace_clone(key
, lxc_conf
, data
);
2862 if (lxc_conf
->ns_keep
!= 0)
2863 return log_error_errno(-EINVAL
, EINVAL
, "Cannot set both \"lxc.namespace.clone\" and \"lxc.namespace.keep\"");
2867 return ret_errno(ENOMEM
);
2869 lxc_iterate_parts(token
, ns
, " \t") {
2870 token
+= lxc_char_left_gc(token
, strlen(token
));
2871 token
[lxc_char_right_gc(token
, strlen(token
))] = '\0';
2872 cloneflag
= lxc_namespace_2_cloneflag(token
);
2874 return ret_errno(EINVAL
);
2875 lxc_conf
->ns_clone
|= cloneflag
;
2881 static int set_config_namespace_keep(const char *key
, const char *value
,
2882 struct lxc_conf
*lxc_conf
, void *data
)
2884 __do_free
char *ns
= NULL
;
2888 if (lxc_config_value_empty(value
))
2889 return clr_config_namespace_keep(key
, lxc_conf
, data
);
2891 if (lxc_conf
->ns_clone
!= 0)
2892 return log_error_errno(-EINVAL
, EINVAL
, "Cannot set both \"lxc.namespace.clone\" and \"lxc.namespace.keep\"");
2896 return ret_errno(ENOMEM
);
2898 lxc_iterate_parts(token
, ns
, " \t") {
2899 token
+= lxc_char_left_gc(token
, strlen(token
));
2900 token
[lxc_char_right_gc(token
, strlen(token
))] = '\0';
2901 cloneflag
= lxc_namespace_2_cloneflag(token
);
2903 return ret_errno(EINVAL
);
2904 lxc_conf
->ns_keep
|= cloneflag
;
2910 static int set_config_time_offset_boot(const char *key
, const char *value
,
2911 struct lxc_conf
*lxc_conf
, void *data
)
2916 char buf
[STRLITERALLEN("ms") + 1];
2918 if (lxc_config_value_empty(value
))
2919 return clr_config_time_offset_boot(key
, lxc_conf
, data
);
2921 ret
= lxc_safe_int64_residual(value
, &offset
, 10, buf
, sizeof(buf
));
2925 unit
= lxc_trim_whitespace_in_place(buf
);
2926 if (strequal(unit
, "h")) {
2927 if (!multiply_overflow(offset
, 3600, &lxc_conf
->timens
.s_boot
))
2928 return ret_errno(EOVERFLOW
);
2929 } else if (strequal(unit
, "m")) {
2930 if (!multiply_overflow(offset
, 60, &lxc_conf
->timens
.s_boot
))
2931 return ret_errno(EOVERFLOW
);
2932 } else if (strequal(unit
, "s")) {
2933 lxc_conf
->timens
.s_boot
= offset
;
2934 } else if (strequal(unit
, "ms")) {
2935 if (!multiply_overflow(offset
, 1000000, &lxc_conf
->timens
.ns_boot
))
2936 return ret_errno(EOVERFLOW
);
2937 } else if (strequal(unit
, "us")) {
2938 if (!multiply_overflow(offset
, 1000, &lxc_conf
->timens
.ns_boot
))
2939 return ret_errno(EOVERFLOW
);
2940 } else if (strequal(unit
, "ns")) {
2941 lxc_conf
->timens
.ns_boot
= offset
;
2943 return ret_errno(EINVAL
);
2949 static int set_config_time_offset_monotonic(const char *key
, const char *value
,
2950 struct lxc_conf
*lxc_conf
, void *data
)
2955 char buf
[STRLITERALLEN("ms") + 1];
2957 if (lxc_config_value_empty(value
))
2958 return clr_config_time_offset_monotonic(key
, lxc_conf
, data
);
2960 ret
= lxc_safe_int64_residual(value
, &offset
, 10, buf
, sizeof(buf
));
2964 unit
= lxc_trim_whitespace_in_place(buf
);
2965 if (strequal(unit
, "h")) {
2966 if (!multiply_overflow(offset
, 3600, &lxc_conf
->timens
.s_monotonic
))
2967 return ret_errno(EOVERFLOW
);
2968 } else if (strequal(unit
, "m")) {
2969 if (!multiply_overflow(offset
, 60, &lxc_conf
->timens
.s_monotonic
))
2970 return ret_errno(EOVERFLOW
);
2971 } else if (strequal(unit
, "s")) {
2972 lxc_conf
->timens
.s_monotonic
= offset
;
2973 } else if (strequal(unit
, "ms")) {
2974 if (!multiply_overflow(offset
, 1000000, &lxc_conf
->timens
.ns_monotonic
))
2975 return ret_errno(EOVERFLOW
);
2976 } else if (strequal(unit
, "us")) {
2977 if (!multiply_overflow(offset
, 1000, &lxc_conf
->timens
.ns_monotonic
))
2978 return ret_errno(EOVERFLOW
);
2979 } else if (strequal(unit
, "ns")) {
2980 lxc_conf
->timens
.ns_monotonic
= offset
;
2982 return ret_errno(EINVAL
);
2988 static int set_config_namespace_share(const char *key
, const char *value
,
2989 struct lxc_conf
*lxc_conf
, void *data
)
2992 const char *namespace;
2994 if (lxc_config_value_empty(value
))
2995 return clr_config_namespace_share(key
, lxc_conf
, data
);
2997 namespace = key
+ STRLITERALLEN("lxc.namespace.share.");
2998 if (is_empty_string(namespace))
2999 return ret_errno(EINVAL
);
3001 ns_idx
= lxc_namespace_2_ns_idx(namespace);
3005 return set_config_string_item(&lxc_conf
->ns_share
[ns_idx
], value
);
3008 struct parse_line_conf
{
3009 struct lxc_conf
*conf
;
3013 static int parse_line(char *buffer
, void *data
)
3015 __do_free
char *linep
= NULL
;
3016 char *dot
, *key
, *line
, *value
;
3018 struct lxc_config_t
*config
;
3021 struct parse_line_conf
*plc
= data
;
3024 return syserror_set(-EINVAL
, "Missing config");
3026 /* If there are newlines in the config file we should keep them. */
3027 empty_line
= lxc_is_line_empty(dup
);
3031 /* We have to dup the buffer otherwise, at the re-exec for reboot we
3032 * modified the original string on the stack by replacing '=' by '\0'
3035 linep
= line
= strdup(dup
);
3037 return ret_errno(ENOMEM
);
3039 if (!plc
->from_include
) {
3040 ret
= append_unexp_config_line(line
, plc
->conf
);
3048 line
+= lxc_char_left_gc(line
, strlen(line
));
3050 /* ignore comments */
3054 /* martian option - don't add it to the config itself */
3055 if (!strnequal(line
, "lxc.", 4))
3058 dot
= strchr(line
, '=');
3060 return log_error_errno(-EINVAL
, EINVAL
, "Invalid configuration line: %s", line
);
3066 key
[lxc_char_right_gc(key
, strlen(key
))] = '\0';
3068 value
+= lxc_char_left_gc(value
, strlen(value
));
3069 value
[lxc_char_right_gc(value
, strlen(value
))] = '\0';
3071 if (*value
== '\'' || *value
== '\"') {
3074 len
= strlen(value
);
3075 if (len
> 1 && value
[len
- 1] == *value
) {
3076 value
[len
- 1] = '\0';
3081 config
= lxc_get_config(key
);
3082 return config
->set(key
, value
, plc
->conf
, NULL
);
3085 static struct new_config_item
*parse_new_conf_line(char *buffer
)
3087 __do_free
char *k
= NULL
, *linep
= NULL
, *v
= NULL
;
3088 __do_free
struct new_config_item
*new = NULL
;
3090 char *dot
, *key
, *line
, *value
;
3092 if (is_empty_string(buffer
))
3093 return log_error_errno(NULL
, EINVAL
, "Empty configuration line");
3095 linep
= line
= strdup(dup
);
3099 line
+= lxc_char_left_gc(line
, strlen(line
));
3101 /* martian option - don't add it to the config itself */
3102 if (!strnequal(line
, "lxc.", 4))
3105 dot
= strchr(line
, '=');
3107 return log_error_errno(NULL
, EINVAL
, "Invalid configuration line: %s", line
);
3113 key
[lxc_char_right_gc(key
, strlen(key
))] = '\0';
3115 value
+= lxc_char_left_gc(value
, strlen(value
));
3116 value
[lxc_char_right_gc(value
, strlen(value
))] = '\0';
3118 if (*value
== '\'' || *value
== '\"') {
3121 len
= strlen(value
);
3122 if (len
> 1 && value
[len
- 1] == *value
) {
3123 value
[len
- 1] = '\0';
3128 new = zalloc(sizeof(struct new_config_item
));
3140 new->key
= move_ptr(k
);
3141 new->val
= move_ptr(v
);
3142 return move_ptr(new);
3145 int lxc_config_read(const char *file
, struct lxc_conf
*conf
, bool from_include
)
3147 struct parse_line_conf plc
;
3150 return syserror_set(-EINVAL
, "Missing config");
3153 plc
.from_include
= from_include
;
3155 /* Catch only the top level config file name in the structure. */
3157 conf
->rcfile
= strdup(file
);
3159 return lxc_file_for_each_line_mmap(file
, parse_line
, &plc
);
3162 int lxc_config_define_add(struct lxc_list
*defines
, char *arg
)
3164 __do_free
struct lxc_list
*dent
= NULL
;
3166 dent
= lxc_list_new();
3168 return ret_errno(ENOMEM
);
3170 dent
->elem
= parse_new_conf_line(arg
);
3172 return ret_errno(ENOMEM
);
3174 lxc_list_add_tail(defines
, move_ptr(dent
));
3179 bool lxc_config_define_load(struct lxc_list
*defines
, struct lxc_container
*c
)
3181 struct lxc_list
*it
;
3184 lxc_list_for_each(it
, defines
) {
3185 struct new_config_item
*new_item
= it
->elem
;
3186 bret
= c
->set_config_item(c
, new_item
->key
, new_item
->val
);
3191 #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
3192 lxc_config_define_free(defines
);
3193 #endif /* !FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION */
3198 void lxc_config_define_free(struct lxc_list
*defines
)
3200 struct lxc_list
*it
, *next
;
3202 lxc_list_for_each_safe(it
, defines
, next
) {
3203 struct new_config_item
*new_item
= it
->elem
;
3204 free(new_item
->key
);
3205 free(new_item
->val
);
3212 int lxc_config_parse_arch(const char *arch
, signed long *persona
)
3214 static struct per_name
{
3218 { "arm", PER_LINUX32
},
3219 { "armel", PER_LINUX32
},
3220 { "armhf", PER_LINUX32
},
3221 { "armv7l", PER_LINUX32
},
3222 { "athlon", PER_LINUX32
},
3223 { "i386", PER_LINUX32
},
3224 { "i486", PER_LINUX32
},
3225 { "i586", PER_LINUX32
},
3226 { "i686", PER_LINUX32
},
3227 { "linux32", PER_LINUX32
},
3228 { "mips", PER_LINUX32
},
3229 { "mipsel", PER_LINUX32
},
3230 { "ppc", PER_LINUX32
},
3231 { "powerpc", PER_LINUX32
},
3232 { "x86", PER_LINUX32
},
3233 { "aarch64", PER_LINUX
},
3234 { "amd64", PER_LINUX
},
3235 { "arm64", PER_LINUX
},
3236 { "linux64", PER_LINUX
},
3237 { "mips64", PER_LINUX
},
3238 { "mips64el", PER_LINUX
},
3239 { "ppc64", PER_LINUX
},
3240 { "ppc64el", PER_LINUX
},
3241 { "ppc64le", PER_LINUX
},
3242 { "powerpc64", PER_LINUX
},
3243 { "s390x", PER_LINUX
},
3244 { "x86_64", PER_LINUX
},
3247 for (int i
= 0; i
< ARRAY_SIZE(pername
); i
++) {
3248 if (!strequal(pername
[i
].name
, arch
))
3251 *persona
= pername
[i
].per
;
3255 return ret_errno(EINVAL
);
3258 int lxc_fill_elevated_privileges(char *flaglist
, int *flags
)
3266 { "CGROUP", LXC_ATTACH_MOVE_TO_CGROUP
},
3267 { "CAP", LXC_ATTACH_DROP_CAPABILITIES
},
3268 { "LSM", LXC_ATTACH_LSM_EXEC
},
3273 /* For the sake of backward compatibility, drop all privileges
3274 * if none is specified.
3276 for (i
= 0; all_privs
[i
].token
; i
++)
3277 *flags
|= all_privs
[i
].flag
;
3282 lxc_iterate_parts(token
, flaglist
, "|") {
3285 for (i
= 0; all_privs
[i
].token
; i
++)
3286 if (strequal(all_privs
[i
].token
, token
))
3287 aflag
= all_privs
[i
].flag
;
3290 return ret_errno(EINVAL
);
3298 /* Write out a configuration file. */
3299 int write_config(int fd
, const struct lxc_conf
*conf
)
3302 size_t len
= conf
->unexpanded_len
;
3307 ret
= lxc_write_nointr(fd
, conf
->unexpanded_config
, len
);
3309 return log_error_errno(-errno
, errno
, "Failed to write configuration file");
3314 bool do_append_unexp_config_line(struct lxc_conf
*conf
, const char *key
,
3317 __do_free
char *tmp
= NULL
;
3321 len
= strlen(key
) + strlen(v
) + 4;
3322 tmp
= must_realloc(NULL
, len
);
3324 if (lxc_config_value_empty(v
))
3325 ret
= strnprintf(tmp
, len
, "%s =", key
);
3327 ret
= strnprintf(tmp
, len
, "%s = %s", key
, v
);
3331 /* Save the line verbatim into unexpanded_conf */
3332 if (append_unexp_config_line(tmp
, conf
))
3338 void clear_unexp_config_line(struct lxc_conf
*conf
, const char *key
,
3342 char *lstart
= conf
->unexpanded_config
;
3344 if (!conf
->unexpanded_config
)
3348 lend
= strchr(lstart
, '\n');
3352 lend
= lstart
+ strlen(lstart
);
3356 if (!strnequal(lstart
, key
, strlen(key
))) {
3362 v
= lstart
[strlen(key
)];
3363 if (!isspace(v
) && v
!= '=') {
3369 conf
->unexpanded_len
-= (lend
- lstart
);
3371 if (*lend
== '\0') {
3376 memmove(lstart
, lend
, strlen(lend
) + 1);
3380 bool clone_update_unexp_ovl_paths(struct lxc_conf
*conf
, const char *oldpath
,
3381 const char *newpath
, const char *oldname
,
3382 const char *newname
, const char *ovldir
)
3384 __do_free
char *newdir
= NULL
, *olddir
= NULL
;
3385 char *lstart
= conf
->unexpanded_config
;
3386 const char *key
= "lxc.mount.entry";
3389 size_t newdirlen
, olddirlen
;
3391 olddirlen
= strlen(ovldir
) + strlen(oldpath
) + strlen(oldname
) + 2;
3392 olddir
= must_realloc(NULL
, olddirlen
+ 1);
3393 ret
= strnprintf(olddir
, olddirlen
+ 1, "%s=%s/%s", ovldir
, oldpath
, oldname
);
3397 newdirlen
= strlen(ovldir
) + strlen(newpath
) + strlen(newname
) + 2;
3398 newdir
= must_realloc(NULL
, newdirlen
+ 1);
3399 ret
= strnprintf(newdir
, newdirlen
+ 1, "%s=%s/%s", ovldir
, newpath
, newname
);
3403 if (!conf
->unexpanded_config
)
3407 lend
= strchr(lstart
, '\n');
3409 lend
= lstart
+ strlen(lstart
);
3413 if (!strnequal(lstart
, key
, strlen(key
)))
3416 p
= strchr(lstart
+ strlen(key
), '=');
3427 /* Whenever a lxc.mount.entry entry is found in a line we check
3428 * if the substring "overlay" is present before doing any
3429 * further work. We check for "overlay" because substrings need
3430 * to have at least one space before them in a valid overlay
3431 * lxc.mount.entry (/A B overlay). When the space before is
3432 * missing it is very likely that these substrings are part of a
3433 * path or something else. (Checking q >= lend ensures that we
3434 * only count matches in the current line.) */
3435 q
= strstr(p
, " overlay");
3436 if (!q
|| q
>= lend
)
3439 if (!(q
= strstr(p
, olddir
)) || (q
>= lend
))
3442 /* replace the olddir with newdir */
3443 if (olddirlen
>= newdirlen
) {
3444 size_t diff
= olddirlen
- newdirlen
;
3445 memcpy(q
, newdir
, newdirlen
);
3447 if (olddirlen
!= newdirlen
) {
3448 memmove(q
+ newdirlen
, q
+ newdirlen
+ diff
,
3449 strlen(q
) - newdirlen
- diff
+ 1);
3451 conf
->unexpanded_len
-= diff
;
3455 size_t diff
= newdirlen
- olddirlen
;
3456 size_t oldlen
= conf
->unexpanded_len
;
3457 size_t newlen
= oldlen
+ diff
;
3458 size_t poffset
= q
- conf
->unexpanded_config
;
3460 new = realloc(conf
->unexpanded_config
, newlen
+ 1);
3464 conf
->unexpanded_len
= newlen
;
3465 conf
->unexpanded_alloced
= newlen
+ 1;
3466 new[newlen
- 1] = '\0';
3467 lend
= new + (lend
- conf
->unexpanded_config
);
3469 /* Move over the remainder to make room for the newdir.
3471 memmove(new + poffset
+ newdirlen
,
3472 new + poffset
+ olddirlen
,
3473 oldlen
- poffset
- olddirlen
+ 1);
3474 conf
->unexpanded_config
= new;
3476 memcpy(new + poffset
, newdir
, newdirlen
);
3487 bool clone_update_unexp_hooks(struct lxc_conf
*conf
, const char *oldpath
,
3488 const char *newpath
, const char *oldname
,
3489 const char *newname
)
3491 __do_free
char *newdir
= NULL
, *olddir
= NULL
;
3492 char *lstart
= conf
->unexpanded_config
;
3493 const char *key
= "lxc.hook";
3496 size_t newdirlen
, olddirlen
;
3498 olddirlen
= strlen(oldpath
) + strlen(oldname
) + 1;
3499 olddir
= must_realloc(NULL
, olddirlen
+ 1);
3500 ret
= strnprintf(olddir
, olddirlen
+ 1, "%s/%s", oldpath
, oldname
);
3504 newdirlen
= strlen(newpath
) + strlen(newname
) + 1;
3505 newdir
= must_realloc(NULL
, newdirlen
+ 1);
3506 ret
= strnprintf(newdir
, newdirlen
+ 1, "%s/%s", newpath
, newname
);
3510 if (!conf
->unexpanded_config
)
3514 lend
= strchr(lstart
, '\n');
3516 lend
= lstart
+ strlen(lstart
);
3520 if (!strnequal(lstart
, key
, strlen(key
)))
3523 p
= strchr(lstart
+ strlen(key
), '=');
3534 if (!strnequal(p
, olddir
, strlen(olddir
)))
3537 /* replace the olddir with newdir */
3538 if (olddirlen
>= newdirlen
) {
3539 size_t diff
= olddirlen
- newdirlen
;
3540 memcpy(p
, newdir
, newdirlen
);
3542 if (olddirlen
!= newdirlen
) {
3543 memmove(p
+ newdirlen
, p
+ newdirlen
+ diff
,
3544 strlen(p
) - newdirlen
- diff
+ 1);
3546 conf
->unexpanded_len
-= diff
;
3550 size_t diff
= newdirlen
- olddirlen
;
3551 size_t oldlen
= conf
->unexpanded_len
;
3552 size_t newlen
= oldlen
+ diff
;
3553 size_t poffset
= p
- conf
->unexpanded_config
;
3555 new = realloc(conf
->unexpanded_config
, newlen
+ 1);
3559 conf
->unexpanded_len
= newlen
;
3560 conf
->unexpanded_alloced
= newlen
+ 1;
3561 new[newlen
- 1] = '\0';
3562 lend
= new + (lend
- conf
->unexpanded_config
);
3564 /* Move over the remainder to make room for the newdir.
3566 memmove(new + poffset
+ newdirlen
,
3567 new + poffset
+ olddirlen
,
3568 oldlen
- poffset
- olddirlen
+ 1);
3569 conf
->unexpanded_config
= new;
3571 memcpy(new + poffset
, newdir
, newdirlen
);
3585 ERROR("Error writing to new config"); \
3590 /* This is called only from clone. We wish to update all hwaddrs in the
3591 * unexpanded config file. We can't/don't want to update any which come from
3592 * lxc.includes (there shouldn't be any).
3593 * We can't just walk the c->lxc-conf->network list because that includes netifs
3594 * from the include files. So we update the ones which we find in the unexp
3595 * config file, then find the original macaddr in the conf->network, and update
3596 * that to the same value.
3598 bool network_new_hwaddrs(struct lxc_conf
*conf
)
3600 char *lend
, *p
, *p2
;
3601 struct lxc_list
*it
;
3602 char *lstart
= conf
->unexpanded_config
;
3604 if (!conf
->unexpanded_config
)
3608 char newhwaddr
[18], oldhwaddr
[17];
3610 lend
= strchr(lstart
, '\n');
3612 lend
= lstart
+ strlen(lstart
);
3616 if (!lxc_config_net_is_hwaddr(lstart
)) {
3621 p
= strchr(lstart
, '=');
3634 while (*p2
&& !isblank(*p2
) && *p2
!= '\n')
3637 if ((p2
- p
) != 17) {
3638 WARN("Bad hwaddr entry");
3643 memcpy(oldhwaddr
, p
, 17);
3645 if (!new_hwaddr(newhwaddr
))
3648 memcpy(p
, newhwaddr
, 17);
3649 lxc_list_for_each(it
, &conf
->network
) {
3650 struct lxc_netdev
*n
= it
->elem
;
3652 if (n
->hwaddr
&& memcmp(oldhwaddr
, n
->hwaddr
, 17) == 0)
3653 memcpy(n
->hwaddr
, newhwaddr
, 17);
3662 static int set_config_ephemeral(const char *key
, const char *value
,
3663 struct lxc_conf
*lxc_conf
, void *data
)
3667 if (lxc_config_value_empty(value
)) {
3668 lxc_conf
->ephemeral
= 0;
3672 ret
= lxc_safe_uint(value
, &lxc_conf
->ephemeral
);
3676 if (lxc_conf
->ephemeral
> 1)
3677 return ret_errno(EINVAL
);
3682 static int set_config_log_syslog(const char *key
, const char *value
,
3683 struct lxc_conf
*lxc_conf
, void *data
)
3687 if (lxc_conf
->syslog
)
3688 free_disarm(lxc_conf
->syslog
);
3690 if (lxc_config_value_empty(value
))
3693 facility
= lxc_syslog_priority_to_int(value
);
3694 if (facility
== -EINVAL
)
3695 return ret_errno(EINVAL
);
3697 lxc_log_syslog(facility
);
3699 return set_config_string_item(&lxc_conf
->syslog
, value
);
3702 static int set_config_no_new_privs(const char *key
, const char *value
,
3703 struct lxc_conf
*lxc_conf
, void *data
)
3708 if (lxc_config_value_empty(value
)) {
3709 lxc_conf
->no_new_privs
= false;
3713 ret
= lxc_safe_uint(value
, &v
);
3718 return ret_errno(EINVAL
);
3720 lxc_conf
->no_new_privs
= v
? true : false;
3725 /* Callbacks to get configuration items. */
3726 static int get_config_personality(const char *key
, char *retv
, int inlen
,
3727 struct lxc_conf
*c
, void *data
)
3734 memset(retv
, 0, inlen
);
3738 switch (c
->personality
) {
3740 strprint(retv
, inlen
, "i686");
3743 strprint(retv
, inlen
, "x86_64");
3752 static int get_config_pty_max(const char *key
, char *retv
, int inlen
,
3753 struct lxc_conf
*c
, void *data
)
3755 return lxc_get_conf_size_t(c
, retv
, inlen
, c
->pty_max
);
3758 static int get_config_tty_max(const char *key
, char *retv
, int inlen
,
3759 struct lxc_conf
*c
, void *data
)
3761 return lxc_get_conf_size_t(c
, retv
, inlen
, c
->ttys
.max
);
3764 static int get_config_tty_dir(const char *key
, char *retv
, int inlen
,
3765 struct lxc_conf
*c
, void *data
)
3767 return lxc_get_conf_str(retv
, inlen
, c
->ttys
.dir
);
3770 static int get_config_apparmor_profile(const char *key
, char *retv
, int inlen
,
3771 struct lxc_conf
*c
, void *data
)
3774 return lxc_get_conf_str(retv
, inlen
, c
->lsm_aa_profile
);
3776 return syserror_set(-EINVAL
, "Built without AppArmor support");
3780 static int get_config_apparmor_allow_incomplete(const char *key
, char *retv
,
3781 int inlen
, struct lxc_conf
*c
,
3785 return lxc_get_conf_int(c
, retv
, inlen
, c
->lsm_aa_allow_incomplete
);
3787 return syserror_set(-EINVAL
, "Built without AppArmor support");
3791 static int get_config_apparmor_allow_nesting(const char *key
, char *retv
,
3792 int inlen
, struct lxc_conf
*c
,
3796 return lxc_get_conf_int(c
, retv
, inlen
, c
->lsm_aa_allow_nesting
);
3798 return syserror_set(-EINVAL
, "Built without AppArmor support");
3802 static int get_config_apparmor_raw(const char *key
, char *retv
,
3803 int inlen
, struct lxc_conf
*c
,
3808 struct lxc_list
*it
;
3814 memset(retv
, 0, inlen
);
3816 lxc_list_for_each(it
, &c
->lsm_aa_raw
) {
3817 strprint(retv
, inlen
, "%s\n", (char *)it
->elem
);
3822 return syserror_set(-EINVAL
, "Built without AppArmor support");
3826 static int get_config_selinux_context(const char *key
, char *retv
, int inlen
,
3827 struct lxc_conf
*c
, void *data
)
3830 return lxc_get_conf_str(retv
, inlen
, c
->lsm_se_context
);
3832 return syserror_set(-EINVAL
, "Built without SELinux support");
3836 static int get_config_selinux_context_keyring(const char *key
, char *retv
, int inlen
,
3837 struct lxc_conf
*c
, void *data
)
3840 return lxc_get_conf_str(retv
, inlen
, c
->lsm_se_keyring_context
);
3842 return syserror_set(-EINVAL
, "Built without SELinux support");
3846 static int get_config_keyring_session(const char *key
, char *retv
, int inlen
,
3847 struct lxc_conf
*c
, void *data
)
3849 return lxc_get_conf_bool(c
, retv
, inlen
, c
->keyring_disable_session
);
3853 /* If you ask for a specific cgroup value, i.e. lxc.cgroup.devices.list, then
3854 * just the value(s) will be printed. Since there still could be more than one,
3855 * it is newline-separated.
3856 * (Maybe that's ambiguous, since some values, i.e. devices.list, will already
3858 * If you ask for 'lxc.cgroup", then all cgroup entries will be printed, in
3859 * 'lxc.cgroup.subsystem.key = value' format.
3861 static int __get_config_cgroup_controller(const char *key
, char *retv
,
3862 int inlen
, struct lxc_conf
*c
,
3866 size_t namespaced_token_len
;
3867 char *global_token
, *namespaced_token
;
3868 struct lxc_list
*it
;
3870 bool get_all
= false;
3875 memset(retv
, 0, inlen
);
3877 if (version
== CGROUP2_SUPER_MAGIC
) {
3878 global_token
= "lxc.cgroup2";
3879 namespaced_token
= "lxc.cgroup2.";
3880 namespaced_token_len
= STRLITERALLEN("lxc.cgroup2.");
3881 } else if (version
== CGROUP_SUPER_MAGIC
) {
3882 global_token
= "lxc.cgroup";
3883 namespaced_token
= "lxc.cgroup.";
3884 namespaced_token_len
= STRLITERALLEN("lxc.cgroup.");
3886 return ret_errno(EINVAL
);
3889 if (strequal(key
, global_token
))
3891 else if (strnequal(key
, namespaced_token
, namespaced_token_len
))
3892 key
+= namespaced_token_len
;
3894 return ret_errno(EINVAL
);
3896 lxc_list_for_each(it
, &c
->cgroup
) {
3897 struct lxc_cgroup
*cg
= it
->elem
;
3900 if (version
!= cg
->version
)
3903 strprint(retv
, inlen
, "%s.%s = %s\n", global_token
,
3904 cg
->subsystem
, cg
->value
);
3905 } else if (strequal(cg
->subsystem
, key
)) {
3906 strprint(retv
, inlen
, "%s\n", cg
->value
);
3913 static int get_config_cgroup_controller(const char *key
, char *retv
, int inlen
,
3914 struct lxc_conf
*c
, void *data
)
3916 return __get_config_cgroup_controller(key
, retv
, inlen
, c
,
3917 CGROUP_SUPER_MAGIC
);
3920 static int get_config_cgroup2_controller(const char *key
, char *retv
, int inlen
,
3921 struct lxc_conf
*c
, void *data
)
3923 return __get_config_cgroup_controller(key
, retv
, inlen
, c
,
3924 CGROUP2_SUPER_MAGIC
);
3927 static int get_config_cgroup_dir(const char *key
, char *retv
, int inlen
,
3928 struct lxc_conf
*lxc_conf
, void *data
)
3933 if (!strequal(key
, "lxc.cgroup.dir"))
3934 return ret_errno(EINVAL
);
3939 memset(retv
, 0, inlen
);
3941 strprint(retv
, inlen
, "%s", lxc_conf
->cgroup_meta
.dir
);
3946 static int get_config_cgroup_monitor_dir(const char *key
, char *retv
, int inlen
,
3947 struct lxc_conf
*lxc_conf
, void *data
)
3955 memset(retv
, 0, inlen
);
3957 strprint(retv
, inlen
, "%s", lxc_conf
->cgroup_meta
.monitor_dir
);
3962 static int get_config_cgroup_monitor_pivot_dir(const char *key
, char *retv
, int inlen
,
3963 struct lxc_conf
*lxc_conf
, void *data
)
3971 memset(retv
, 0, inlen
);
3973 strprint(retv
, inlen
, "%s", lxc_conf
->cgroup_meta
.monitor_pivot_dir
);
3978 static int get_config_cgroup_container_dir(const char *key
, char *retv
,
3980 struct lxc_conf
*lxc_conf
,
3989 memset(retv
, 0, inlen
);
3991 strprint(retv
, inlen
, "%s", lxc_conf
->cgroup_meta
.container_dir
);
3996 static int get_config_cgroup_container_inner_dir(const char *key
, char *retv
,
3998 struct lxc_conf
*lxc_conf
,
4007 memset(retv
, 0, inlen
);
4009 strprint(retv
, inlen
, "%s", lxc_conf
->cgroup_meta
.namespace_dir
);
4014 static inline int get_config_cgroup_relative(const char *key
, char *retv
,
4015 int inlen
, struct lxc_conf
*lxc_conf
,
4018 return lxc_get_conf_int(lxc_conf
, retv
, inlen
,
4019 lxc_conf
->cgroup_meta
.relative
);
4022 static int get_config_idmaps(const char *key
, char *retv
, int inlen
,
4023 struct lxc_conf
*c
, void *data
)
4025 struct lxc_list
*it
;
4026 int len
, listlen
, ret
;
4028 /* "u 1000 1000000 65536"
4030 * let's render this as
4048 #define __LXC_IDMAP_STR_BUF (3 * INTTYPE_TO_STRLEN(uint32_t) + 3 + 1 + 1)
4049 char buf
[__LXC_IDMAP_STR_BUF
];
4054 memset(retv
, 0, inlen
);
4056 listlen
= lxc_list_len(&c
->id_map
);
4057 lxc_list_for_each(it
, &c
->id_map
) {
4058 struct id_map
*map
= it
->elem
;
4059 ret
= strnprintf(buf
, sizeof(buf
), "%c %lu %lu %lu",
4060 (map
->idtype
== ID_TYPE_UID
) ? 'u' : 'g',
4061 map
->nsid
, map
->hostid
, map
->range
);
4063 return ret_errno(EIO
);
4065 strprint(retv
, inlen
, "%s%s", buf
, (listlen
-- > 1) ? "\n" : "");
4071 static int get_config_log_level(const char *key
, char *retv
, int inlen
,
4072 struct lxc_conf
*c
, void *data
)
4075 v
= lxc_log_priority_to_string(c
->loglevel
);
4076 return lxc_get_conf_str(retv
, inlen
, v
);
4079 static int get_config_log_file(const char *key
, char *retv
, int inlen
,
4080 struct lxc_conf
*c
, void *data
)
4082 return lxc_get_conf_str(retv
, inlen
, c
->logfile
);
4085 static int get_config_mount_fstab(const char *key
, char *retv
, int inlen
,
4086 struct lxc_conf
*c
, void *data
)
4088 return lxc_get_conf_str(retv
, inlen
, c
->fstab
);
4091 static int get_config_mount_auto(const char *key
, char *retv
, int inlen
,
4092 struct lxc_conf
*c
, void *data
)
4094 int len
, fulllen
= 0;
4095 const char *sep
= "";
4100 memset(retv
, 0, inlen
);
4102 if (!(c
->auto_mounts
& LXC_AUTO_ALL_MASK
))
4105 switch (c
->auto_mounts
& LXC_AUTO_PROC_MASK
) {
4106 case LXC_AUTO_PROC_MIXED
:
4107 strprint(retv
, inlen
, "%sproc:mixed", sep
);
4110 case LXC_AUTO_PROC_RW
:
4111 strprint(retv
, inlen
, "%sproc:rw", sep
);
4118 switch (c
->auto_mounts
& LXC_AUTO_SYS_MASK
) {
4119 case LXC_AUTO_SYS_RO
:
4120 strprint(retv
, inlen
, "%ssys:ro", sep
);
4123 case LXC_AUTO_SYS_RW
:
4124 strprint(retv
, inlen
, "%ssys:rw", sep
);
4127 case LXC_AUTO_SYS_MIXED
:
4128 strprint(retv
, inlen
, "%ssys:mixed", sep
);
4135 switch (c
->auto_mounts
& LXC_AUTO_CGROUP_MASK
) {
4136 case LXC_AUTO_CGROUP_NOSPEC
:
4137 strprint(retv
, inlen
, "%scgroup", sep
);
4139 case LXC_AUTO_CGROUP_MIXED
:
4140 strprint(retv
, inlen
, "%scgroup:mixed", sep
);
4142 case LXC_AUTO_CGROUP_RO
:
4143 strprint(retv
, inlen
, "%scgroup:ro", sep
);
4145 case LXC_AUTO_CGROUP_RW
:
4146 strprint(retv
, inlen
, "%scgroup:rw", sep
);
4148 case LXC_AUTO_CGROUP_FULL_NOSPEC
:
4149 strprint(retv
, inlen
, "%scgroup-full", sep
);
4151 case LXC_AUTO_CGROUP_FULL_MIXED
:
4152 strprint(retv
, inlen
, "%scgroup-full:mixed", sep
);
4154 case LXC_AUTO_CGROUP_FULL_RO
:
4155 strprint(retv
, inlen
, "%scgroup-full:ro", sep
);
4157 case LXC_AUTO_CGROUP_FULL_RW
:
4158 strprint(retv
, inlen
, "%scgroup-full:rw", sep
);
4167 static int get_config_mount(const char *key
, char *retv
, int inlen
,
4168 struct lxc_conf
*c
, void *data
)
4170 int len
, fulllen
= 0;
4171 struct lxc_list
*it
;
4176 memset(retv
, 0, inlen
);
4178 lxc_list_for_each(it
, &c
->mount_list
) {
4179 strprint(retv
, inlen
, "%s\n", (char *)it
->elem
);
4185 static int get_config_rootfs_path(const char *key
, char *retv
, int inlen
,
4186 struct lxc_conf
*c
, void *data
)
4188 return lxc_get_conf_str(retv
, inlen
, c
->rootfs
.path
);
4191 static int get_config_rootfs_managed(const char *key
, char *retv
, int inlen
,
4192 struct lxc_conf
*c
, void *data
)
4194 return lxc_get_conf_bool(c
, retv
, inlen
, c
->rootfs
.managed
);
4197 static int get_config_rootfs_mount(const char *key
, char *retv
, int inlen
,
4198 struct lxc_conf
*c
, void *data
)
4200 return lxc_get_conf_str(retv
, inlen
, c
->rootfs
.mount
);
4203 static int get_config_rootfs_options(const char *key
, char *retv
, int inlen
,
4204 struct lxc_conf
*c
, void *data
)
4206 return lxc_get_conf_str(retv
, inlen
, c
->rootfs
.options
);
4209 static int get_config_uts_name(const char *key
, char *retv
, int inlen
,
4210 struct lxc_conf
*c
, void *data
)
4212 return lxc_get_conf_str(
4214 c
->utsname
? c
->utsname
->nodename
: NULL
);
4217 static int get_config_hooks(const char *key
, char *retv
, int inlen
,
4218 struct lxc_conf
*c
, void *data
)
4221 int len
, fulllen
= 0, found
= -1;
4222 struct lxc_list
*it
;
4225 subkey
= strchr(key
, '.');
4227 return ret_errno(EINVAL
);
4229 subkey
= strchr(subkey
+ 1, '.');
4231 return ret_errno(EINVAL
);
4233 if (*subkey
== '\0')
4234 return ret_errno(EINVAL
);
4236 for (i
= 0; i
< NUM_LXC_HOOKS
; i
++) {
4237 if (strequal(lxchook_names
[i
], subkey
)) {
4244 return ret_errno(EINVAL
);
4249 memset(retv
, 0, inlen
);
4251 lxc_list_for_each(it
, &c
->hooks
[found
]) {
4252 strprint(retv
, inlen
, "%s\n", (char *)it
->elem
);
4258 static int get_config_hooks_version(const char *key
, char *retv
, int inlen
,
4259 struct lxc_conf
*c
, void *data
)
4261 return lxc_get_conf_int(c
, retv
, inlen
, c
->hooks_version
);
4264 static int get_config_net(const char *key
, char *retv
, int inlen
,
4265 struct lxc_conf
*c
, void *data
)
4267 int len
, fulllen
= 0;
4268 struct lxc_list
*it
;
4273 memset(retv
, 0, inlen
);
4275 lxc_list_for_each(it
, &c
->network
) {
4276 struct lxc_netdev
*n
= it
->elem
;
4277 const char *t
= lxc_net_type_to_str(n
->type
);
4278 strprint(retv
, inlen
, "%s\n", t
? t
: "(invalid)");
4284 static int get_config_cap_drop(const char *key
, char *retv
, int inlen
,
4285 struct lxc_conf
*c
, void *data
)
4287 int len
, fulllen
= 0;
4288 struct lxc_list
*it
;
4293 memset(retv
, 0, inlen
);
4295 lxc_list_for_each(it
, &c
->caps
) {
4296 strprint(retv
, inlen
, "%s\n", (char *)it
->elem
);
4302 static int get_config_cap_keep(const char *key
, char *retv
, int inlen
,
4303 struct lxc_conf
*c
, void *data
)
4305 int len
, fulllen
= 0;
4306 struct lxc_list
*it
;
4311 memset(retv
, 0, inlen
);
4313 lxc_list_for_each(it
, &c
->keepcaps
) {
4314 strprint(retv
, inlen
, "%s\n", (char *)it
->elem
);
4320 static int get_config_console_path(const char *key
, char *retv
, int inlen
,
4321 struct lxc_conf
*c
, void *data
)
4323 return lxc_get_conf_str(retv
, inlen
, c
->console
.path
);
4326 static int get_config_console_logfile(const char *key
, char *retv
, int inlen
,
4327 struct lxc_conf
*c
, void *data
)
4329 return lxc_get_conf_str(retv
, inlen
, c
->console
.log_path
);
4332 static int get_config_console_rotate(const char *key
, char *retv
, int inlen
,
4333 struct lxc_conf
*c
, void *data
)
4335 return lxc_get_conf_int(c
, retv
, inlen
, c
->console
.log_rotate
);
4339 static int get_config_console_buffer_size(const char *key
, char *retv
,
4340 int inlen
, struct lxc_conf
*c
,
4343 return lxc_get_conf_uint64(c
, retv
, inlen
, c
->console
.buffer_size
);
4346 static int get_config_console_size(const char *key
, char *retv
, int inlen
,
4347 struct lxc_conf
*c
, void *data
)
4349 return lxc_get_conf_uint64(c
, retv
, inlen
, c
->console
.log_size
);
4352 static int get_config_seccomp_allow_nesting(const char *key
, char *retv
,
4353 int inlen
, struct lxc_conf
*c
,
4357 return lxc_get_conf_int(c
, retv
, inlen
, c
->seccomp
.allow_nesting
);
4359 return ret_errno(ENOSYS
);
4363 static int get_config_seccomp_notify_cookie(const char *key
, char *retv
, int inlen
,
4364 struct lxc_conf
*c
, void *data
)
4366 #ifdef HAVE_SECCOMP_NOTIFY
4367 return lxc_get_conf_str(retv
, inlen
, c
->seccomp
.notifier
.cookie
);
4369 return ret_errno(ENOSYS
);
4373 static int get_config_seccomp_notify_proxy(const char *key
, char *retv
, int inlen
,
4374 struct lxc_conf
*c
, void *data
)
4376 #ifdef HAVE_SECCOMP_NOTIFY
4377 return lxc_get_conf_str(retv
, inlen
,
4378 (c
->seccomp
.notifier
.proxy_addr
.sun_path
[0]) == '/'
4379 ? &c
->seccomp
.notifier
.proxy_addr
.sun_path
[0]
4380 : &c
->seccomp
.notifier
.proxy_addr
.sun_path
[1]);
4382 return ret_errno(ENOSYS
);
4386 static int get_config_seccomp_profile(const char *key
, char *retv
, int inlen
,
4387 struct lxc_conf
*c
, void *data
)
4389 return lxc_get_conf_str(retv
, inlen
, c
->seccomp
.seccomp
);
4392 static int get_config_autodev(const char *key
, char *retv
, int inlen
,
4393 struct lxc_conf
*c
, void *data
)
4395 return lxc_get_conf_int(c
, retv
, inlen
, c
->autodev
);
4398 static int get_config_autodev_tmpfs_size(const char *key
, char *retv
, int inlen
,
4399 struct lxc_conf
*c
, void *data
)
4401 return lxc_get_conf_int(c
, retv
, inlen
, c
->autodevtmpfssize
);
4404 static int get_config_signal_halt(const char *key
, char *retv
, int inlen
,
4405 struct lxc_conf
*c
, void *data
)
4407 return lxc_get_conf_int(c
, retv
, inlen
, c
->haltsignal
);
4410 static int get_config_signal_reboot(const char *key
, char *retv
, int inlen
,
4411 struct lxc_conf
*c
, void *data
)
4413 return lxc_get_conf_int(c
, retv
, inlen
, c
->rebootsignal
);
4416 static int get_config_signal_stop(const char *key
, char *retv
, int inlen
,
4417 struct lxc_conf
*c
, void *data
)
4419 return lxc_get_conf_int(c
, retv
, inlen
, c
->stopsignal
);
4422 static int get_config_start(const char *key
, char *retv
, int inlen
,
4423 struct lxc_conf
*c
, void *data
)
4425 if (strequal(key
+ 10, "auto"))
4426 return lxc_get_conf_int(c
, retv
, inlen
, c
->start_auto
);
4427 else if (strequal(key
+ 10, "delay"))
4428 return lxc_get_conf_int(c
, retv
, inlen
, c
->start_delay
);
4429 else if (strequal(key
+ 10, "order"))
4430 return lxc_get_conf_int(c
, retv
, inlen
, c
->start_order
);
4435 static int get_config_log_syslog(const char *key
, char *retv
, int inlen
,
4436 struct lxc_conf
*c
, void *data
)
4438 return lxc_get_conf_str(retv
, inlen
, c
->syslog
);
4441 static int get_config_monitor(const char *key
, char *retv
, int inlen
,
4442 struct lxc_conf
*c
, void *data
)
4444 return lxc_get_conf_int(c
, retv
, inlen
, c
->monitor_unshare
);
4447 static int get_config_monitor_signal_pdeath(const char *key
, char *retv
,
4448 int inlen
, struct lxc_conf
*c
,
4451 return lxc_get_conf_int(c
, retv
, inlen
, c
->monitor_signal_pdeath
);
4454 static int get_config_group(const char *key
, char *retv
, int inlen
,
4455 struct lxc_conf
*c
, void *data
)
4457 int len
, fulllen
= 0;
4458 struct lxc_list
*it
;
4463 memset(retv
, 0, inlen
);
4465 lxc_list_for_each(it
, &c
->groups
) {
4466 strprint(retv
, inlen
, "%s\n", (char *)it
->elem
);
4472 static int get_config_environment(const char *key
, char *retv
, int inlen
,
4473 struct lxc_conf
*c
, void *data
)
4475 int len
, fulllen
= 0;
4476 struct lxc_list
*it
;
4481 memset(retv
, 0, inlen
);
4483 lxc_list_for_each(it
, &c
->environment
) {
4484 strprint(retv
, inlen
, "%s\n", (char *)it
->elem
);
4490 static int get_config_execute_cmd(const char *key
, char *retv
, int inlen
,
4491 struct lxc_conf
*c
, void *data
)
4493 return lxc_get_conf_str(retv
, inlen
, c
->execute_cmd
);
4496 static int get_config_init_cmd(const char *key
, char *retv
, int inlen
,
4497 struct lxc_conf
*c
, void *data
)
4499 return lxc_get_conf_str(retv
, inlen
, c
->init_cmd
);
4502 static int get_config_init_cwd(const char *key
, char *retv
, int inlen
,
4503 struct lxc_conf
*c
, void *data
)
4505 return lxc_get_conf_str(retv
, inlen
, c
->init_cwd
);
4508 static int get_config_init_uid(const char *key
, char *retv
, int inlen
,
4509 struct lxc_conf
*c
, void *data
)
4511 return lxc_get_conf_int(c
, retv
, inlen
, c
->init_uid
);
4514 static int get_config_init_gid(const char *key
, char *retv
, int inlen
,
4515 struct lxc_conf
*c
, void *data
)
4517 return lxc_get_conf_int(c
, retv
, inlen
, c
->init_gid
);
4520 static int get_config_init_groups(const char *key
, char *retv
, int inlen
,
4521 struct lxc_conf
*c
, void *data
)
4523 int fulllen
= 0, len
;
4528 memset(retv
, 0, inlen
);
4530 if (c
->init_groups
.size
== 0)
4533 for (int i
= 0; i
< c
->init_groups
.size
; i
++)
4534 strprint(retv
, inlen
, "%s%d", (i
> 0) ? "," : "",
4535 c
->init_groups
.list
[i
]);
4540 static int get_config_ephemeral(const char *key
, char *retv
, int inlen
,
4541 struct lxc_conf
*c
, void *data
)
4543 return lxc_get_conf_int(c
, retv
, inlen
, c
->ephemeral
);
4546 static int get_config_no_new_privs(const char *key
, char *retv
, int inlen
,
4547 struct lxc_conf
*c
, void *data
)
4549 return lxc_get_conf_int(c
, retv
, inlen
, c
->no_new_privs
);
4552 /* If you ask for a specific value, i.e. lxc.prlimit.nofile, then just the value
4553 * will be printed. If you ask for 'lxc.prlimit', then all limit entries will be
4554 * printed, in 'lxc.prlimit.resource = value' format.
4556 static int get_config_prlimit(const char *key
, char *retv
, int inlen
,
4557 struct lxc_conf
*c
, void *data
)
4559 int fulllen
= 0, len
;
4560 bool get_all
= false;
4561 struct lxc_list
*it
;
4566 memset(retv
, 0, inlen
);
4568 if (strequal(key
, "lxc.prlimit"))
4570 else if (strnequal(key
, "lxc.prlimit.", 12))
4573 return ret_errno(EINVAL
);
4575 lxc_list_for_each(it
, &c
->limits
) {
4576 /* 2 colon separated 64 bit integers or the word 'unlimited' */
4577 char buf
[INTTYPE_TO_STRLEN(uint64_t) * 2 + 2];
4579 struct lxc_limit
*lim
= it
->elem
;
4581 if (lim
->limit
.rlim_cur
== RLIM_INFINITY
) {
4582 memcpy(buf
, "unlimited", STRLITERALLEN("unlimited") + 1);
4583 partlen
= STRLITERALLEN("unlimited");
4585 partlen
= sprintf(buf
, "%" PRIu64
,
4586 (uint64_t)lim
->limit
.rlim_cur
);
4589 if (lim
->limit
.rlim_cur
!= lim
->limit
.rlim_max
) {
4590 if (lim
->limit
.rlim_max
== RLIM_INFINITY
)
4591 memcpy(buf
+ partlen
, ":unlimited",
4592 STRLITERALLEN(":unlimited") + 1);
4594 sprintf(buf
+ partlen
, ":%" PRIu64
,
4595 (uint64_t)lim
->limit
.rlim_max
);
4599 strprint(retv
, inlen
, "lxc.prlimit.%s = %s\n",
4600 lim
->resource
, buf
);
4601 } else if (strequal(lim
->resource
, key
)) {
4602 strprint(retv
, inlen
, "%s", buf
);
4609 /* If you ask for a specific value, i.e. lxc.sysctl.net.ipv4.ip_forward, then
4610 * just the value will be printed. If you ask for 'lxc.sysctl', then all sysctl
4611 * entries will be printed, in 'lxc.sysctl.key = value' format.
4613 static int get_config_sysctl(const char *key
, char *retv
, int inlen
,
4614 struct lxc_conf
*c
, void *data
)
4617 struct lxc_list
*it
;
4619 bool get_all
= false;
4624 memset(retv
, 0, inlen
);
4626 if (strequal(key
, "lxc.sysctl"))
4628 else if (strnequal(key
, "lxc.sysctl.", STRLITERALLEN("lxc.sysctl.")))
4629 key
+= STRLITERALLEN("lxc.sysctl.");
4631 return ret_errno(EINVAL
);
4633 lxc_list_for_each(it
, &c
->sysctls
) {
4634 struct lxc_sysctl
*elem
= it
->elem
;
4636 strprint(retv
, inlen
, "lxc.sysctl.%s = %s\n", elem
->key
,
4638 } else if (strequal(elem
->key
, key
)) {
4639 strprint(retv
, inlen
, "%s", elem
->value
);
4646 static int get_config_proc(const char *key
, char *retv
, int inlen
,
4647 struct lxc_conf
*c
, void *data
)
4649 struct lxc_list
*it
;
4652 bool get_all
= false;
4657 memset(retv
, 0, inlen
);
4659 if (strequal(key
, "lxc.proc"))
4661 else if (strnequal(key
, "lxc.proc.", STRLITERALLEN("lxc.proc.")))
4662 key
+= STRLITERALLEN("lxc.proc.");
4664 return ret_errno(EINVAL
);
4666 lxc_list_for_each(it
, &c
->procs
) {
4667 struct lxc_proc
*proc
= it
->elem
;
4670 strprint(retv
, inlen
, "lxc.proc.%s = %s\n",
4671 proc
->filename
, proc
->value
);
4672 } else if (strequal(proc
->filename
, key
)) {
4673 strprint(retv
, inlen
, "%s", proc
->value
);
4680 static int get_config_namespace_clone(const char *key
, char *retv
, int inlen
,
4681 struct lxc_conf
*c
, void *data
)
4689 memset(retv
, 0, inlen
);
4691 for (i
= 0; i
< LXC_NS_MAX
; i
++) {
4692 if (c
->ns_clone
& ns_info
[i
].clone_flag
)
4693 strprint(retv
, inlen
, "%s\n", ns_info
[i
].proc_name
);
4699 static int get_config_namespace_keep(const char *key
, char *retv
, int inlen
,
4700 struct lxc_conf
*c
, void *data
)
4708 memset(retv
, 0, inlen
);
4710 for (i
= 0; i
< LXC_NS_MAX
; i
++) {
4711 if (c
->ns_keep
& ns_info
[i
].clone_flag
)
4712 strprint(retv
, inlen
, "%s\n", ns_info
[i
].proc_name
);
4718 static int get_config_time_offset_boot(const char *key
, char *retv
, int inlen
, struct lxc_conf
*c
,
4727 memset(retv
, 0, inlen
);
4729 if (c
->timens
.s_boot
) {
4730 strprint(retv
, inlen
, "%" PRId64
" s\n", c
->timens
.s_boot
);
4732 strprint(retv
, inlen
, "%" PRId64
" ns\n", c
->timens
.ns_boot
);
4738 static int get_config_time_offset_monotonic(const char *key
, char *retv
, int inlen
,
4739 struct lxc_conf
*c
, void *data
)
4747 memset(retv
, 0, inlen
);
4749 if (c
->timens
.s_monotonic
) {
4750 strprint(retv
, inlen
, "%" PRId64
"s\n", c
->timens
.s_monotonic
);
4752 strprint(retv
, inlen
, "%" PRId64
"ns\n", c
->timens
.ns_monotonic
);
4758 static int get_config_namespace_share(const char *key
, char *retv
, int inlen
,
4759 struct lxc_conf
*c
, void *data
)
4762 const char *namespace;
4768 memset(retv
, 0, inlen
);
4770 namespace = key
+ STRLITERALLEN("lxc.namespace.share.");
4771 if (is_empty_string(namespace))
4772 return ret_errno(EINVAL
);
4774 ns_idx
= lxc_namespace_2_ns_idx(namespace);
4778 strprint(retv
, inlen
, "%s", c
->ns_share
[ns_idx
]);
4783 /* Callbacks to clear config items. */
4784 static inline int clr_config_personality(const char *key
, struct lxc_conf
*c
,
4787 c
->personality
= -1;
4791 static inline int clr_config_pty_max(const char *key
, struct lxc_conf
*c
,
4798 static inline int clr_config_tty_max(const char *key
, struct lxc_conf
*c
,
4805 static inline int clr_config_tty_dir(const char *key
, struct lxc_conf
*c
,
4808 free_disarm(c
->ttys
.dir
);
4812 static inline int clr_config_apparmor_profile(const char *key
,
4813 struct lxc_conf
*c
, void *data
)
4816 free_disarm(c
->lsm_aa_profile
);
4819 return syserror_set(-EINVAL
, "Built without AppArmor support");
4823 static inline int clr_config_apparmor_allow_incomplete(const char *key
,
4828 c
->lsm_aa_allow_incomplete
= 0;
4831 return syserror_set(-EINVAL
, "Built without AppArmor support");
4835 static inline int clr_config_apparmor_allow_nesting(const char *key
,
4840 c
->lsm_aa_allow_nesting
= 0;
4843 return syserror_set(-EINVAL
, "Built without AppArmor support");
4847 static inline int clr_config_apparmor_raw(const char *key
,
4852 return lxc_clear_apparmor_raw(c
);
4854 return syserror_set(-EINVAL
, "Built without AppArmor support");
4858 static inline int clr_config_selinux_context(const char *key
,
4859 struct lxc_conf
*c
, void *data
)
4862 free_disarm(c
->lsm_se_context
);
4865 return syserror_set(-EINVAL
, "Built without SELinux support");
4869 static inline int clr_config_selinux_context_keyring(const char *key
,
4870 struct lxc_conf
*c
, void *data
)
4873 free_disarm(c
->lsm_se_keyring_context
);
4876 return syserror_set(-EINVAL
, "Built without SELinux support");
4880 static inline int clr_config_keyring_session(const char *key
,
4881 struct lxc_conf
*c
, void *data
)
4883 c
->keyring_disable_session
= false;
4887 static inline int clr_config_cgroup_controller(const char *key
,
4888 struct lxc_conf
*c
, void *data
)
4890 return lxc_clear_cgroups(c
, key
, CGROUP_SUPER_MAGIC
);
4893 static inline int clr_config_cgroup2_controller(const char *key
,
4894 struct lxc_conf
*c
, void *data
)
4896 return lxc_clear_cgroups(c
, key
, CGROUP2_SUPER_MAGIC
);
4899 static int clr_config_cgroup_dir(const char *key
, struct lxc_conf
*lxc_conf
,
4902 if (!strequal(key
, "lxc.cgroup.dir"))
4903 return ret_errno(EINVAL
);
4905 if (lxc_conf
->cgroup_meta
.dir
)
4906 free_disarm(lxc_conf
->cgroup_meta
.dir
);
4911 static int clr_config_cgroup_monitor_dir(const char *key
,
4912 struct lxc_conf
*lxc_conf
,
4915 free_disarm(lxc_conf
->cgroup_meta
.monitor_dir
);
4919 static int clr_config_cgroup_monitor_pivot_dir(const char *key
,
4920 struct lxc_conf
*lxc_conf
,
4923 free_disarm(lxc_conf
->cgroup_meta
.monitor_pivot_dir
);
4927 static int clr_config_cgroup_container_dir(const char *key
,
4928 struct lxc_conf
*lxc_conf
,
4931 free_disarm(lxc_conf
->cgroup_meta
.container_dir
);
4935 static int clr_config_cgroup_container_inner_dir(const char *key
,
4936 struct lxc_conf
*lxc_conf
,
4939 free_disarm(lxc_conf
->cgroup_meta
.namespace_dir
);
4943 static inline int clr_config_cgroup_relative(const char *key
,
4944 struct lxc_conf
*lxc_conf
,
4947 lxc_conf
->cgroup_meta
.relative
= false;
4951 static inline int clr_config_idmaps(const char *key
, struct lxc_conf
*c
,
4954 return lxc_clear_idmaps(c
);
4957 static inline int clr_config_log_level(const char *key
, struct lxc_conf
*c
,
4960 c
->loglevel
= LXC_LOG_LEVEL_NOTSET
;
4964 static inline int clr_config_log_file(const char *key
, struct lxc_conf
*c
,
4967 free_disarm(c
->logfile
);
4971 static inline int clr_config_mount(const char *key
, struct lxc_conf
*c
,
4974 return lxc_clear_mount_entries(c
);
4977 static inline int clr_config_mount_auto(const char *key
, struct lxc_conf
*c
,
4980 return lxc_clear_automounts(c
);
4983 static inline int clr_config_mount_fstab(const char *key
, struct lxc_conf
*c
,
4986 free_disarm(c
->fstab
);
4990 static inline int clr_config_rootfs_path(const char *key
, struct lxc_conf
*c
,
4993 free_disarm(c
->rootfs
.path
);
4997 static inline int clr_config_rootfs_managed(const char *key
, struct lxc_conf
*c
,
5000 c
->rootfs
.managed
= true;
5004 static inline int clr_config_rootfs_mount(const char *key
, struct lxc_conf
*c
,
5007 free_disarm(c
->rootfs
.mount
);
5011 static inline int clr_config_rootfs_options(const char *key
, struct lxc_conf
*c
,
5014 free_disarm(c
->rootfs
.options
);
5015 put_lxc_mount_options(&c
->rootfs
.mnt_opts
);
5020 static inline int clr_config_uts_name(const char *key
, struct lxc_conf
*c
,
5023 free_disarm(c
->utsname
);
5027 static inline int clr_config_hooks(const char *key
, struct lxc_conf
*c
,
5030 return lxc_clear_hooks(c
, key
);
5033 static inline int clr_config_hooks_version(const char *key
, struct lxc_conf
*c
,
5036 /* default to legacy hooks version */
5037 c
->hooks_version
= 0;
5041 static inline int clr_config_net(const char *key
, struct lxc_conf
*c
,
5044 lxc_free_networks(&c
->network
);
5049 static inline int clr_config_cap_drop(const char *key
, struct lxc_conf
*c
,
5052 return lxc_clear_config_caps(c
);
5055 static inline int clr_config_cap_keep(const char *key
, struct lxc_conf
*c
,
5058 return lxc_clear_config_keepcaps(c
);
5061 static inline int clr_config_console_path(const char *key
, struct lxc_conf
*c
,
5064 free_disarm(c
->console
.path
);
5068 static inline int clr_config_console_logfile(const char *key
,
5069 struct lxc_conf
*c
, void *data
)
5071 free_disarm(c
->console
.log_path
);
5075 static inline int clr_config_console_rotate(const char *key
, struct lxc_conf
*c
,
5078 c
->console
.log_rotate
= 0;
5082 static inline int clr_config_console_buffer_size(const char *key
,
5083 struct lxc_conf
*c
, void *data
)
5085 c
->console
.buffer_size
= 0;
5089 static inline int clr_config_console_size(const char *key
, struct lxc_conf
*c
,
5092 c
->console
.log_size
= 0;
5096 static inline int clr_config_seccomp_allow_nesting(const char *key
,
5097 struct lxc_conf
*c
, void *data
)
5100 c
->seccomp
.allow_nesting
= 0;
5103 return ret_errno(ENOSYS
);
5107 static inline int clr_config_seccomp_notify_cookie(const char *key
,
5108 struct lxc_conf
*c
, void *data
)
5110 #ifdef HAVE_SECCOMP_NOTIFY
5111 free_disarm(c
->seccomp
.notifier
.cookie
);
5114 return ret_errno(ENOSYS
);
5118 static inline int clr_config_seccomp_notify_proxy(const char *key
,
5119 struct lxc_conf
*c
, void *data
)
5121 #ifdef HAVE_SECCOMP_NOTIFY
5122 memset(&c
->seccomp
.notifier
.proxy_addr
, 0,
5123 sizeof(c
->seccomp
.notifier
.proxy_addr
));
5126 return ret_errno(ENOSYS
);
5130 static inline int clr_config_seccomp_profile(const char *key
,
5131 struct lxc_conf
*c
, void *data
)
5133 free_disarm(c
->seccomp
.seccomp
);
5137 static inline int clr_config_autodev(const char *key
, struct lxc_conf
*c
,
5144 static inline int clr_config_autodev_tmpfs_size(const char *key
, struct lxc_conf
*c
,
5147 c
->autodevtmpfssize
= 500000;
5151 static inline int clr_config_signal_halt(const char *key
, struct lxc_conf
*c
,
5158 static inline int clr_config_signal_reboot(const char *key
, struct lxc_conf
*c
,
5161 c
->rebootsignal
= 0;
5165 static inline int clr_config_signal_stop(const char *key
, struct lxc_conf
*c
,
5172 static inline int clr_config_start(const char *key
, struct lxc_conf
*c
,
5175 if (strequal(key
+ 10, "auto"))
5177 else if (strequal(key
+ 10, "delay"))
5179 else if (strequal(key
+ 10, "order"))
5185 static inline int clr_config_log_syslog(const char *key
, struct lxc_conf
*c
,
5188 free_disarm(c
->syslog
);
5192 static inline int clr_config_monitor(const char *key
, struct lxc_conf
*c
,
5195 c
->monitor_unshare
= 0;
5199 static inline int clr_config_monitor_signal_pdeath(const char *key
,
5200 struct lxc_conf
*c
, void *data
)
5202 c
->monitor_signal_pdeath
= 0;
5206 static inline int clr_config_group(const char *key
, struct lxc_conf
*c
,
5209 return lxc_clear_groups(c
);
5212 static inline int clr_config_environment(const char *key
, struct lxc_conf
*c
,
5215 return lxc_clear_environment(c
);
5218 static inline int clr_config_execute_cmd(const char *key
, struct lxc_conf
*c
,
5221 free_disarm(c
->execute_cmd
);
5225 static inline int clr_config_init_cmd(const char *key
, struct lxc_conf
*c
,
5228 free_disarm(c
->init_cmd
);
5232 static inline int clr_config_init_cwd(const char *key
, struct lxc_conf
*c
,
5235 free_disarm(c
->init_cwd
);
5239 static inline int clr_config_init_uid(const char *key
, struct lxc_conf
*c
,
5246 static inline int clr_config_init_gid(const char *key
, struct lxc_conf
*c
,
5253 static inline int clr_config_init_groups(const char *key
, struct lxc_conf
*c
,
5256 c
->init_groups
.size
= 0;
5257 free_disarm(c
->init_groups
.list
);
5261 static inline int clr_config_ephemeral(const char *key
, struct lxc_conf
*c
,
5268 static inline int clr_config_no_new_privs(const char *key
, struct lxc_conf
*c
,
5271 c
->no_new_privs
= false;
5275 static inline int clr_config_prlimit(const char *key
, struct lxc_conf
*c
,
5278 return lxc_clear_limits(c
, key
);
5281 static inline int clr_config_sysctl(const char *key
, struct lxc_conf
*c
,
5284 return lxc_clear_sysctls(c
, key
);
5287 static inline int clr_config_proc(const char *key
, struct lxc_conf
*c
,
5290 return lxc_clear_procs(c
, key
);
5293 static inline int clr_config_includefiles(const char *key
, struct lxc_conf
*c
,
5296 lxc_clear_includes(c
);
5300 static int clr_config_namespace_clone(const char *key
,
5301 struct lxc_conf
*lxc_conf
, void *data
)
5303 lxc_conf
->ns_clone
= 0;
5307 static int clr_config_namespace_keep(const char *key
, struct lxc_conf
*lxc_conf
,
5310 lxc_conf
->ns_keep
= 0;
5314 static int clr_config_time_offset_boot(const char *key
, struct lxc_conf
*lxc_conf
, void *data
)
5316 lxc_conf
->timens
.s_boot
= 0;
5317 lxc_conf
->timens
.ns_boot
= 0;
5321 static int clr_config_time_offset_monotonic(const char *key
, struct lxc_conf
*lxc_conf
, void *data
)
5323 lxc_conf
->timens
.s_monotonic
= 0;
5324 lxc_conf
->timens
.ns_monotonic
= 0;
5328 static int clr_config_namespace_share(const char *key
,
5329 struct lxc_conf
*lxc_conf
, void *data
)
5332 const char *namespace;
5334 namespace = key
+ STRLITERALLEN("lxc.namespace.share.");
5335 if (is_empty_string(namespace))
5336 return ret_errno(EINVAL
);
5338 ns_idx
= lxc_namespace_2_ns_idx(namespace);
5342 free(lxc_conf
->ns_share
[ns_idx
]);
5343 lxc_conf
->ns_share
[ns_idx
] = NULL
;
5348 static int get_config_includefiles(const char *key
, char *retv
, int inlen
,
5349 struct lxc_conf
*c
, void *data
)
5351 return ret_errno(ENOSYS
);
5354 struct config_net_info
{
5355 char buf
[NETWORK_SUBKEY_SIZE_MAX
];
5357 const struct lxc_config_net_t
*ops
;
5358 struct lxc_netdev
*netdev
;
5361 static int get_network_config_ops(const char *key
, struct lxc_conf
*lxc_conf
,
5362 struct config_net_info
*info
, bool allocate
)
5367 const char *idx_start
;
5369 if (is_empty_string(key
))
5370 return ret_errno(EINVAL
);
5372 /* check that this is a sensible network key */
5373 if (!strnequal("lxc.net.", key
, STRLITERALLEN("lxc.net.")))
5374 return syserror_set(-EINVAL
, "Invalid network configuration key \"%s\"", key
);
5377 /* beginning of index string */
5378 idx_start
= key
+ STRLITERALLEN("lxc.net.");
5379 if (!isdigit(*idx_start
))
5380 return syserror_set(-EINVAL
, "Failed to detect digit in string \"%s\"", key
+ 8);
5382 ret
= lxc_safe_int64_residual(idx_start
, &tmpidx
, 10, info
->buf
, sizeof(info
->buf
));
5384 return syserror("Failed to parse network index");
5386 if (tmpidx
< 0 || tmpidx
>= INT_MAX
)
5387 return syserror_set(-ERANGE
, "Number of configured networks would overflow the counter");
5388 idx
= (unsigned int)tmpidx
;
5390 info
->netdev
= lxc_get_netdev_by_idx(lxc_conf
, idx
, allocate
);
5392 return ret_errno(EINVAL
);
5394 /* Make sure subkey points to the empty string. */
5395 info
->subkey
= info
->buf
;
5396 if (is_empty_string(info
->subkey
))
5397 return ret_errno(ENOENT
);
5399 if (info
->subkey
[0] != '.')
5400 return syserror_set(-EINVAL
, "Invalid subkey");
5403 /* lxc.net.<idx>.<subkey> */
5404 info
->ops
= lxc_get_config_net(info
->subkey
);
5405 if (info
->ops
== &unsupported_config_net_key
)
5406 return syserror_set(-ENOENT
, "Unknown network configuration key \"%s\"", key
);
5411 /* Config entry is something like "lxc.net.0.ipv4" the key 'lxc.net.' was
5412 * found. So we make sure next comes an integer, find the right callback (by
5413 * rewriting the key), and call it.
5415 static int set_config_jump_table_net(const char *key
, const char *value
,
5416 struct lxc_conf
*lxc_conf
, void *data
)
5418 struct config_net_info info
= {};
5420 const char *idxstring
;
5422 idxstring
= key
+ STRLITERALLEN("lxc.net.");
5423 if (!isdigit(*idxstring
))
5424 return ret_errno(EINVAL
);
5426 if (lxc_config_value_empty(value
))
5427 return clr_config_jump_table_net(key
, lxc_conf
, data
);
5429 ret
= get_network_config_ops(key
, lxc_conf
, &info
, true);
5433 return info
.ops
->set(info
.subkey
, value
, lxc_conf
, info
.netdev
);
5436 static int clr_config_jump_table_net(const char *key
, struct lxc_conf
*lxc_conf
,
5439 struct config_net_info info
= {};
5441 const char *idxstring
;
5443 idxstring
= key
+ 8;
5444 if (!isdigit(*idxstring
))
5445 return ret_errno(EINVAL
);
5447 /* The left conjunct is pretty self-explanatory. The right conjunct
5448 * checks whether the two pointers are equal. If they are we know that
5449 * this is not a key that is namespaced any further and so we are
5450 * supposed to clear the whole network.
5452 if (isdigit(*idxstring
) && (strrchr(key
, '.') == (idxstring
- 1))) {
5453 unsigned int rmnetdevidx
;
5455 ret
= lxc_safe_uint(idxstring
, &rmnetdevidx
);
5459 /* Remove network from network list. */
5460 lxc_remove_nic_by_idx(lxc_conf
, rmnetdevidx
);
5464 ret
= get_network_config_ops(key
, lxc_conf
, &info
, false);
5468 return info
.ops
->clr(info
.subkey
, lxc_conf
, info
.netdev
);
5471 static int clr_config_net_type(const char *key
, struct lxc_conf
*lxc_conf
,
5474 struct lxc_netdev
*netdev
= data
;
5477 return ret_errno(EINVAL
);
5479 lxc_clear_netdev(netdev
);
5484 static int clr_config_net_name(const char *key
, struct lxc_conf
*lxc_conf
,
5487 struct lxc_netdev
*netdev
= data
;
5490 return ret_errno(EINVAL
);
5492 netdev
->name
[0] = '\0';
5497 static int clr_config_net_flags(const char *key
, struct lxc_conf
*lxc_conf
,
5500 struct lxc_netdev
*netdev
= data
;
5503 return ret_errno(EINVAL
);
5510 static int clr_config_net_link(const char *key
, struct lxc_conf
*lxc_conf
,
5513 struct lxc_netdev
*netdev
= data
;
5516 return ret_errno(EINVAL
);
5518 netdev
->link
[0] = '\0';
5523 static int clr_config_net_l2proxy(const char *key
, struct lxc_conf
*lxc_conf
,
5526 struct lxc_netdev
*netdev
= data
;
5529 return ret_errno(EINVAL
);
5531 netdev
->l2proxy
= false;
5536 static int clr_config_net_macvlan_mode(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_MACVLAN
)
5547 netdev
->priv
.macvlan_attr
.mode
= -1;
5552 static int clr_config_net_ipvlan_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_IPVLAN
)
5563 netdev
->priv
.ipvlan_attr
.mode
= -1;
5568 static int clr_config_net_ipvlan_isolation(const char *key
,
5569 struct lxc_conf
*lxc_conf
, void *data
)
5571 struct lxc_netdev
*netdev
= data
;
5574 return ret_errno(EINVAL
);
5576 if (netdev
->type
!= LXC_NET_IPVLAN
)
5579 netdev
->priv
.ipvlan_attr
.isolation
= -1;
5584 static int clr_config_net_veth_mode(const char *key
,
5585 struct lxc_conf
*lxc_conf
, void *data
)
5587 struct lxc_netdev
*netdev
= data
;
5590 return ret_errno(EINVAL
);
5592 if (netdev
->type
!= LXC_NET_VETH
)
5595 netdev
->priv
.veth_attr
.mode
= -1;
5600 static int clr_config_net_veth_pair(const char *key
, struct lxc_conf
*lxc_conf
,
5603 struct lxc_netdev
*netdev
= data
;
5606 return ret_errno(EINVAL
);
5608 if (netdev
->type
!= LXC_NET_VETH
)
5611 netdev
->priv
.veth_attr
.pair
[0] = '\0';
5616 static int clr_config_net_veth_vlan_id(const char *key
, struct lxc_conf
*lxc_conf
,
5619 struct lxc_netdev
*netdev
= data
;
5622 return ret_errno(EINVAL
);
5624 if (netdev
->type
!= LXC_NET_VETH
)
5627 netdev
->priv
.veth_attr
.vlan_id
= 0;
5628 netdev
->priv
.veth_attr
.vlan_id_set
= false;
5633 static int clr_config_net_veth_vlan_tagged_id(const char *key
,
5634 struct lxc_conf
*lxc_conf
, void *data
)
5636 struct lxc_netdev
*netdev
= data
;
5637 struct lxc_list
*cur
, *next
;
5640 return ret_errno(EINVAL
);
5642 if (netdev
->type
!= LXC_NET_VETH
)
5645 lxc_list_for_each_safe(cur
, &netdev
->priv
.veth_attr
.vlan_tagged_ids
, next
) {
5654 static int clr_config_net_script_up(const char *key
, struct lxc_conf
*lxc_conf
,
5657 struct lxc_netdev
*netdev
= data
;
5660 return ret_errno(EINVAL
);
5662 free_disarm(netdev
->upscript
);
5667 static int clr_config_net_script_down(const char *key
,
5668 struct lxc_conf
*lxc_conf
, void *data
)
5670 struct lxc_netdev
*netdev
= data
;
5673 return ret_errno(EINVAL
);
5675 free_disarm(netdev
->downscript
);
5680 static int clr_config_net_hwaddr(const char *key
, struct lxc_conf
*lxc_conf
,
5683 struct lxc_netdev
*netdev
= data
;
5686 return ret_errno(EINVAL
);
5688 free_disarm(netdev
->hwaddr
);
5693 static int clr_config_net_mtu(const char *key
, struct lxc_conf
*lxc_conf
,
5696 struct lxc_netdev
*netdev
= data
;
5699 return ret_errno(EINVAL
);
5701 free_disarm(netdev
->mtu
);
5706 static int clr_config_net_vlan_id(const char *key
, struct lxc_conf
*lxc_conf
,
5709 struct lxc_netdev
*netdev
= data
;
5712 return ret_errno(EINVAL
);
5714 if (netdev
->type
!= LXC_NET_VLAN
)
5717 netdev
->priv
.vlan_attr
.vid
= 0;
5722 static int clr_config_net_ipv4_gateway(const char *key
,
5723 struct lxc_conf
*lxc_conf
, void *data
)
5725 struct lxc_netdev
*netdev
= data
;
5728 return ret_errno(EINVAL
);
5730 free_disarm(netdev
->ipv4_gateway
);
5735 static int clr_config_net_ipv4_address(const char *key
,
5736 struct lxc_conf
*lxc_conf
, void *data
)
5738 struct lxc_netdev
*netdev
= data
;
5739 struct lxc_list
*cur
, *next
;
5742 return ret_errno(EINVAL
);
5744 lxc_list_for_each_safe(cur
, &netdev
->ipv4
, next
) {
5753 static int clr_config_net_veth_ipv4_route(const char *key
,
5754 struct lxc_conf
*lxc_conf
, void *data
)
5756 struct lxc_netdev
*netdev
= data
;
5757 struct lxc_list
*cur
, *next
;
5760 return ret_errno(EINVAL
);
5762 if (netdev
->type
!= LXC_NET_VETH
)
5765 lxc_list_for_each_safe(cur
, &netdev
->priv
.veth_attr
.ipv4_routes
, next
) {
5774 static int clr_config_net_ipv6_gateway(const char *key
,
5775 struct lxc_conf
*lxc_conf
, void *data
)
5777 struct lxc_netdev
*netdev
= data
;
5780 return ret_errno(EINVAL
);
5782 free_disarm(netdev
->ipv6_gateway
);
5787 static int clr_config_net_ipv6_address(const char *key
,
5788 struct lxc_conf
*lxc_conf
, void *data
)
5790 struct lxc_netdev
*netdev
= data
;
5791 struct lxc_list
*cur
, *next
;
5794 return ret_errno(EINVAL
);
5796 lxc_list_for_each_safe(cur
, &netdev
->ipv6
, next
) {
5805 static int clr_config_net_veth_ipv6_route(const char *key
,
5806 struct lxc_conf
*lxc_conf
, void *data
)
5808 struct lxc_netdev
*netdev
= data
;
5809 struct lxc_list
*cur
, *next
;
5812 return ret_errno(EINVAL
);
5814 if (netdev
->type
!= LXC_NET_VETH
)
5817 lxc_list_for_each_safe(cur
, &netdev
->priv
.veth_attr
.ipv6_routes
, next
) {
5826 static int get_config_jump_table_net(const char *key
, char *retv
, int inlen
,
5827 struct lxc_conf
*c
, void *data
)
5829 struct config_net_info info
= {};
5831 const char *idxstring
;
5833 idxstring
= key
+ STRLITERALLEN("lxc.net.");
5834 if (!isdigit(*idxstring
))
5835 return ret_errno(EINVAL
);
5837 ret
= get_network_config_ops(key
, c
, &info
, false);
5841 return info
.ops
->get(info
.subkey
, retv
, inlen
, c
, info
.netdev
);
5844 static int get_config_net_type(const char *key
, char *retv
, int inlen
,
5845 struct lxc_conf
*c
, void *data
)
5849 struct lxc_netdev
*netdev
= data
;
5852 return ret_errno(EINVAL
);
5857 memset(retv
, 0, inlen
);
5859 strprint(retv
, inlen
, "%s", lxc_net_type_to_str(netdev
->type
));
5864 static int get_config_net_flags(const char *key
, char *retv
, int inlen
,
5865 struct lxc_conf
*c
, void *data
)
5869 struct lxc_netdev
*netdev
= data
;
5872 return ret_errno(EINVAL
);
5877 memset(retv
, 0, inlen
);
5879 if (netdev
->flags
& IFF_UP
)
5880 strprint(retv
, inlen
, "up");
5885 static int get_config_net_link(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
->link
[0] != '\0')
5901 strprint(retv
, inlen
, "%s", netdev
->link
);
5906 static int get_config_net_l2proxy(const char *key
, char *retv
, int inlen
,
5907 struct lxc_conf
*c
, void *data
)
5909 struct lxc_netdev
*netdev
= data
;
5912 return ret_errno(EINVAL
);
5914 return lxc_get_conf_bool(c
, retv
, inlen
, netdev
->l2proxy
);
5917 static int get_config_net_name(const char *key
, char *retv
, int inlen
,
5918 struct lxc_conf
*c
, void *data
)
5922 struct lxc_netdev
*netdev
= data
;
5925 return ret_errno(EINVAL
);
5930 memset(retv
, 0, inlen
);
5932 if (netdev
->name
[0] != '\0')
5933 strprint(retv
, inlen
, "%s", netdev
->name
);
5938 static int get_config_net_macvlan_mode(const char *key
, char *retv
, int inlen
,
5939 struct lxc_conf
*c
, void *data
)
5944 struct lxc_netdev
*netdev
= data
;
5947 return ret_errno(EINVAL
);
5949 if (netdev
->type
!= LXC_NET_MACVLAN
)
5950 return ret_errno(EINVAL
);
5955 memset(retv
, 0, inlen
);
5957 switch (netdev
->priv
.macvlan_attr
.mode
) {
5958 case MACVLAN_MODE_PRIVATE
:
5961 case MACVLAN_MODE_VEPA
:
5964 case MACVLAN_MODE_BRIDGE
:
5967 case MACVLAN_MODE_PASSTHRU
:
5975 strprint(retv
, inlen
, "%s", mode
);
5980 static int get_config_net_ipvlan_mode(const char *key
, char *retv
, int inlen
,
5981 struct lxc_conf
*c
, void *data
)
5984 struct lxc_netdev
*netdev
= data
;
5989 return ret_errno(EINVAL
);
5991 if (netdev
->type
!= LXC_NET_IPVLAN
)
5992 return ret_errno(EINVAL
);
5997 memset(retv
, 0, inlen
);
5999 switch (netdev
->priv
.ipvlan_attr
.mode
) {
6000 case IPVLAN_MODE_L3
:
6003 case IPVLAN_MODE_L3S
:
6006 case IPVLAN_MODE_L2
:
6014 strprint(retv
, inlen
, "%s", mode
);
6019 static int get_config_net_ipvlan_isolation(const char *key
, char *retv
, int inlen
,
6020 struct lxc_conf
*c
, void *data
)
6023 struct lxc_netdev
*netdev
= data
;
6028 return ret_errno(EINVAL
);
6030 if (netdev
->type
!= LXC_NET_IPVLAN
)
6031 return ret_errno(EINVAL
);
6036 memset(retv
, 0, inlen
);
6038 switch (netdev
->priv
.ipvlan_attr
.isolation
) {
6039 case IPVLAN_ISOLATION_BRIDGE
:
6042 case IPVLAN_ISOLATION_PRIVATE
:
6045 case IPVLAN_ISOLATION_VEPA
:
6053 strprint(retv
, inlen
, "%s", mode
);
6058 static int get_config_net_veth_mode(const char *key
, char *retv
, int inlen
,
6059 struct lxc_conf
*c
, void *data
)
6062 struct lxc_netdev
*netdev
= data
;
6067 return ret_errno(EINVAL
);
6069 if (netdev
->type
!= LXC_NET_VETH
)
6070 return ret_errno(EINVAL
);
6075 memset(retv
, 0, inlen
);
6077 switch (netdev
->priv
.veth_attr
.mode
) {
6078 case VETH_MODE_BRIDGE
:
6081 case VETH_MODE_ROUTER
:
6089 strprint(retv
, inlen
, "%s", mode
);
6094 static int get_config_net_veth_pair(const char *key
, char *retv
, int inlen
,
6095 struct lxc_conf
*c
, void *data
)
6099 struct lxc_netdev
*netdev
= data
;
6102 return ret_errno(EINVAL
);
6104 if (netdev
->type
!= LXC_NET_VETH
)
6105 return ret_errno(EINVAL
);
6110 memset(retv
, 0, inlen
);
6112 strprint(retv
, inlen
, "%s",
6113 netdev
->priv
.veth_attr
.pair
[0] != '\0'
6114 ? netdev
->priv
.veth_attr
.pair
6115 : netdev
->priv
.veth_attr
.veth1
);
6120 static int get_config_net_veth_vlan_id(const char *key
, char *retv
, int inlen
,
6121 struct lxc_conf
*c
, void *data
)
6125 struct lxc_netdev
*netdev
= data
;
6128 return ret_errno(EINVAL
);
6130 if (netdev
->type
!= LXC_NET_VETH
)
6131 return ret_errno(EINVAL
);
6136 memset(retv
, 0, inlen
);
6138 strprint(retv
, inlen
, "%d", netdev
->priv
.veth_attr
.vlan_id
);
6143 static int get_config_net_veth_vlan_tagged_id(const char *key
, char *retv
,
6144 int inlen
, struct lxc_conf
*c
,
6149 struct lxc_list
*it
;
6151 struct lxc_netdev
*netdev
= data
;
6154 return ret_errno(EINVAL
);
6156 if (netdev
->type
!= LXC_NET_VETH
)
6157 return ret_errno(EINVAL
);
6162 memset(retv
, 0, inlen
);
6164 listlen
= lxc_list_len(&netdev
->priv
.veth_attr
.vlan_tagged_ids
);
6166 lxc_list_for_each(it
, &netdev
->priv
.veth_attr
.vlan_tagged_ids
) {
6167 unsigned short i
= PTR_TO_USHORT(it
->elem
);
6168 strprint(retv
, inlen
, "%u%s", i
, (listlen
-- > 1) ? "\n" : "");
6174 static int get_config_net_script_up(const char *key
, char *retv
, int inlen
,
6175 struct lxc_conf
*c
, void *data
)
6179 struct lxc_netdev
*netdev
= data
;
6182 return ret_errno(EINVAL
);
6187 memset(retv
, 0, inlen
);
6189 if (netdev
->upscript
)
6190 strprint(retv
, inlen
, "%s", netdev
->upscript
);
6195 static int get_config_net_script_down(const char *key
, char *retv
, int inlen
,
6196 struct lxc_conf
*c
, void *data
)
6200 struct lxc_netdev
*netdev
= data
;
6203 return ret_errno(EINVAL
);
6208 memset(retv
, 0, inlen
);
6210 if (netdev
->downscript
)
6211 strprint(retv
, inlen
, "%s", netdev
->downscript
);
6216 static int get_config_net_hwaddr(const char *key
, char *retv
, int inlen
,
6217 struct lxc_conf
*c
, void *data
)
6221 struct lxc_netdev
*netdev
= data
;
6224 return ret_errno(EINVAL
);
6229 memset(retv
, 0, inlen
);
6232 strprint(retv
, inlen
, "%s", netdev
->hwaddr
);
6237 static int get_config_net_mtu(const char *key
, char *retv
, int inlen
,
6238 struct lxc_conf
*c
, void *data
)
6242 struct lxc_netdev
*netdev
= data
;
6245 return ret_errno(EINVAL
);
6250 memset(retv
, 0, inlen
);
6253 strprint(retv
, inlen
, "%s", netdev
->mtu
);
6258 static int get_config_net_vlan_id(const char *key
, char *retv
, int inlen
,
6259 struct lxc_conf
*c
, void *data
)
6263 struct lxc_netdev
*netdev
= data
;
6266 return ret_errno(EINVAL
);
6268 if (netdev
->type
!= LXC_NET_VLAN
)
6269 return ret_errno(EINVAL
);
6274 memset(retv
, 0, inlen
);
6276 strprint(retv
, inlen
, "%d", netdev
->priv
.vlan_attr
.vid
);
6281 static int get_config_net_ipv4_gateway(const char *key
, char *retv
, int inlen
,
6282 struct lxc_conf
*c
, void *data
)
6285 char buf
[INET_ADDRSTRLEN
];
6287 struct lxc_netdev
*netdev
= data
;
6290 return ret_errno(EINVAL
);
6295 memset(retv
, 0, inlen
);
6297 if (netdev
->ipv4_gateway_auto
) {
6298 strprint(retv
, inlen
, "auto");
6299 } else if (netdev
->ipv4_gateway_dev
) {
6300 strprint(retv
, inlen
, "dev");
6301 } else if (netdev
->ipv4_gateway
) {
6302 if (!inet_ntop(AF_INET
, netdev
->ipv4_gateway
, buf
, sizeof(buf
)))
6304 strprint(retv
, inlen
, "%s", buf
);
6310 static int get_config_net_ipv4_address(const char *key
, char *retv
, int inlen
,
6311 struct lxc_conf
*c
, void *data
)
6315 char buf
[INET_ADDRSTRLEN
];
6316 struct lxc_list
*it
;
6318 struct lxc_netdev
*netdev
= data
;
6321 return ret_errno(EINVAL
);
6326 memset(retv
, 0, inlen
);
6328 listlen
= lxc_list_len(&netdev
->ipv4
);
6330 lxc_list_for_each(it
, &netdev
->ipv4
) {
6331 struct lxc_inetdev
*i
= it
->elem
;
6332 if (!inet_ntop(AF_INET
, &i
->addr
, buf
, sizeof(buf
)))
6334 strprint(retv
, inlen
, "%s/%u%s", buf
, i
->prefix
,
6335 (listlen
-- > 1) ? "\n" : "");
6341 static int get_config_net_veth_ipv4_route(const char *key
, char *retv
, int inlen
,
6342 struct lxc_conf
*c
, void *data
)
6346 char buf
[INET_ADDRSTRLEN
];
6347 struct lxc_list
*it
;
6349 struct lxc_netdev
*netdev
= data
;
6352 return ret_errno(EINVAL
);
6354 if (netdev
->type
!= LXC_NET_VETH
)
6355 return ret_errno(EINVAL
);
6360 memset(retv
, 0, inlen
);
6362 listlen
= lxc_list_len(&netdev
->priv
.veth_attr
.ipv4_routes
);
6364 lxc_list_for_each(it
, &netdev
->priv
.veth_attr
.ipv4_routes
) {
6365 struct lxc_inetdev
*i
= it
->elem
;
6366 if (!inet_ntop(AF_INET
, &i
->addr
, buf
, sizeof(buf
)))
6368 strprint(retv
, inlen
, "%s/%u%s", buf
, i
->prefix
,
6369 (listlen
-- > 1) ? "\n" : "");
6375 static int get_config_net_ipv6_gateway(const char *key
, char *retv
, int inlen
,
6376 struct lxc_conf
*c
, void *data
)
6379 char buf
[INET6_ADDRSTRLEN
];
6381 struct lxc_netdev
*netdev
= data
;
6384 return ret_errno(EINVAL
);
6389 memset(retv
, 0, inlen
);
6391 if (netdev
->ipv6_gateway_auto
) {
6392 strprint(retv
, inlen
, "auto");
6393 } else if (netdev
->ipv6_gateway_dev
) {
6394 strprint(retv
, inlen
, "dev");
6395 } else if (netdev
->ipv6_gateway
) {
6396 if (!inet_ntop(AF_INET6
, netdev
->ipv6_gateway
, buf
, sizeof(buf
)))
6398 strprint(retv
, inlen
, "%s", buf
);
6404 static int get_config_net_ipv6_address(const char *key
, char *retv
, int inlen
,
6405 struct lxc_conf
*c
, void *data
)
6409 char buf
[INET6_ADDRSTRLEN
];
6410 struct lxc_list
*it
;
6412 struct lxc_netdev
*netdev
= data
;
6415 return ret_errno(EINVAL
);
6420 memset(retv
, 0, inlen
);
6422 listlen
= lxc_list_len(&netdev
->ipv6
);
6424 lxc_list_for_each(it
, &netdev
->ipv6
) {
6425 struct lxc_inet6dev
*i
= it
->elem
;
6426 if (!inet_ntop(AF_INET6
, &i
->addr
, buf
, sizeof(buf
)))
6428 strprint(retv
, inlen
, "%s/%u%s", buf
, i
->prefix
,
6429 (listlen
-- > 1) ? "\n" : "");
6435 static int get_config_net_veth_ipv6_route(const char *key
, char *retv
, int inlen
,
6436 struct lxc_conf
*c
, void *data
)
6440 char buf
[INET6_ADDRSTRLEN
];
6441 struct lxc_list
*it
;
6443 struct lxc_netdev
*netdev
= data
;
6446 return ret_errno(EINVAL
);
6448 if (netdev
->type
!= LXC_NET_VETH
)
6449 return ret_errno(EINVAL
);
6454 memset(retv
, 0, inlen
);
6456 listlen
= lxc_list_len(&netdev
->priv
.veth_attr
.ipv6_routes
);
6458 lxc_list_for_each(it
, &netdev
->priv
.veth_attr
.ipv6_routes
) {
6459 struct lxc_inet6dev
*i
= it
->elem
;
6460 if (!inet_ntop(AF_INET6
, &i
->addr
, buf
, sizeof(buf
)))
6462 strprint(retv
, inlen
, "%s/%u%s", buf
, i
->prefix
,
6463 (listlen
-- > 1) ? "\n" : "");
6469 int lxc_list_config_items(char *retv
, int inlen
)
6478 memset(retv
, 0, inlen
);
6480 for (i
= 0; i
< ARRAY_SIZE(config_jump_table
); i
++) {
6481 char *s
= config_jump_table
[i
].name
;
6483 if (s
[strlen(s
) - 1] == '.')
6486 strprint(retv
, inlen
, "%s\n", s
);
6492 int lxc_list_subkeys(struct lxc_conf
*conf
, const char *key
, char *retv
,
6501 memset(retv
, 0, inlen
);
6503 if (strequal(key
, "lxc.apparmor")) {
6504 strprint(retv
, inlen
, "allow_incomplete\n");
6505 strprint(retv
, inlen
, "allow_nesting\n");
6506 strprint(retv
, inlen
, "profile\n");
6507 strprint(retv
, inlen
, "raw\n");
6508 } else if (strequal(key
, "lxc.cgroup")) {
6509 strprint(retv
, inlen
, "dir\n");
6510 } else if (strequal(key
, "lxc.selinux")) {
6511 strprint(retv
, inlen
, "context\n");
6512 strprint(retv
, inlen
, "context.keyring\n");
6513 } else if (strequal(key
, "lxc.mount")) {
6514 strprint(retv
, inlen
, "auto\n");
6515 strprint(retv
, inlen
, "entry\n");
6516 strprint(retv
, inlen
, "fstab\n");
6517 } else if (strequal(key
, "lxc.rootfs")) {
6518 strprint(retv
, inlen
, "mount\n");
6519 strprint(retv
, inlen
, "options\n");
6520 strprint(retv
, inlen
, "path\n");
6521 } else if (strequal(key
, "lxc.uts")) {
6522 strprint(retv
, inlen
, "name\n");
6523 } else if (strequal(key
, "lxc.hook")) {
6524 strprint(retv
, inlen
, "autodev\n");
6525 strprint(retv
, inlen
, "autodevtmpfssize\n");
6526 strprint(retv
, inlen
, "clone\n");
6527 strprint(retv
, inlen
, "destroy\n");
6528 strprint(retv
, inlen
, "mount\n");
6529 strprint(retv
, inlen
, "post-stop\n");
6530 strprint(retv
, inlen
, "pre-mount\n");
6531 strprint(retv
, inlen
, "pre-start\n");
6532 strprint(retv
, inlen
, "start-host\n");
6533 strprint(retv
, inlen
, "start\n");
6534 strprint(retv
, inlen
, "stop\n");
6535 } else if (strequal(key
, "lxc.cap")) {
6536 strprint(retv
, inlen
, "drop\n");
6537 strprint(retv
, inlen
, "keep\n");
6538 } else if (strequal(key
, "lxc.console")) {
6539 strprint(retv
, inlen
, "logfile\n");
6540 strprint(retv
, inlen
, "path\n");
6541 } else if (strequal(key
, "lxc.seccomp")) {
6542 strprint(retv
, inlen
, "profile\n");
6543 } else if (strequal(key
, "lxc.signal")) {
6544 strprint(retv
, inlen
, "halt\n");
6545 strprint(retv
, inlen
, "reboot\n");
6546 strprint(retv
, inlen
, "stop\n");
6547 } else if (strequal(key
, "lxc.start")) {
6548 strprint(retv
, inlen
, "auto\n");
6549 strprint(retv
, inlen
, "delay\n");
6550 strprint(retv
, inlen
, "order\n");
6551 } else if (strequal(key
, "lxc.monitor")) {
6552 strprint(retv
, inlen
, "unshare\n");
6553 } else if (strequal(key
, "lxc.keyring")) {
6554 strprint(retv
, inlen
, "session\n");
6556 fulllen
= ret_errno(EINVAL
);
6562 int lxc_list_net(struct lxc_conf
*c
, const char *key
, char *retv
, int inlen
)
6564 struct config_net_info info
= {};
6565 struct lxc_netdev
*netdev
;
6567 const char *idxstring
;
6570 idxstring
= key
+ STRLITERALLEN("lxc.net.");
6571 if (!isdigit(*idxstring
))
6572 return ret_errno(EINVAL
);
6574 ret
= get_network_config_ops(key
, c
, &info
, false);
6577 return ret_errno(EINVAL
);
6579 netdev
= info
.netdev
;
6584 memset(retv
, 0, inlen
);
6586 strprint(retv
, inlen
, "type\n");
6587 strprint(retv
, inlen
, "script.up\n");
6588 strprint(retv
, inlen
, "script.down\n");
6590 if (netdev
->type
!= LXC_NET_EMPTY
) {
6591 strprint(retv
, inlen
, "flags\n");
6592 strprint(retv
, inlen
, "link\n");
6593 strprint(retv
, inlen
, "name\n");
6594 strprint(retv
, inlen
, "hwaddr\n");
6595 strprint(retv
, inlen
, "mtu\n");
6596 strprint(retv
, inlen
, "ipv6.address\n");
6597 strprint(retv
, inlen
, "ipv6.gateway\n");
6598 strprint(retv
, inlen
, "ipv4.address\n");
6599 strprint(retv
, inlen
, "ipv4.gateway\n");
6602 switch (netdev
->type
) {
6604 strprint(retv
, inlen
, "veth.pair\n");
6605 strprint(retv
, inlen
, "veth.ipv4.route\n");
6606 strprint(retv
, inlen
, "veth.ipv6.route\n");
6607 strprint(retv
, inlen
, "veth.vlan.id\n");
6609 case LXC_NET_MACVLAN
:
6610 strprint(retv
, inlen
, "macvlan.mode\n");
6612 case LXC_NET_IPVLAN
:
6613 strprint(retv
, inlen
, "ipvlan.mode\n");
6614 strprint(retv
, inlen
, "ipvlan.isolation\n");
6617 strprint(retv
, inlen
, "vlan.id\n");