1 /* SPDX-License-Identifier: LGPL-2.1+ */
12 #include <netinet/in.h>
17 #include <sys/param.h>
19 #include <sys/types.h>
20 #include <sys/utsname.h>
28 #include "confile_utils.h"
29 #include "netns_ifaddrs.h"
31 #include "lxcseccomp.h"
33 #include "memory_utils.h"
46 #if HAVE_SYS_RESOURCE_H
47 #include <sys/resource.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_n_rxqueues
);
129 lxc_config_define(net_veth_n_txqueues
);
130 lxc_config_define(net_veth_pair
);
131 lxc_config_define(net_veth_ipv4_route
);
132 lxc_config_define(net_veth_ipv6_route
);
133 lxc_config_define(net_veth_vlan_id
);
134 lxc_config_define(net_veth_vlan_tagged_id
);
135 lxc_config_define(net_vlan_id
);
136 lxc_config_define(no_new_privs
);
137 lxc_config_define(personality
);
138 lxc_config_define(prlimit
);
139 lxc_config_define(pty_max
);
140 lxc_config_define(rootfs_managed
);
141 lxc_config_define(rootfs_mount
);
142 lxc_config_define(rootfs_options
);
143 lxc_config_define(rootfs_path
);
144 lxc_config_define(seccomp_profile
);
145 lxc_config_define(seccomp_allow_nesting
);
146 lxc_config_define(seccomp_notify_cookie
);
147 lxc_config_define(seccomp_notify_proxy
);
148 lxc_config_define(selinux_context
);
149 lxc_config_define(selinux_context_keyring
);
150 lxc_config_define(signal_halt
);
151 lxc_config_define(signal_reboot
);
152 lxc_config_define(signal_stop
);
153 lxc_config_define(start
);
154 lxc_config_define(tty_max
);
155 lxc_config_define(tty_dir
);
156 lxc_config_define(uts_name
);
157 lxc_config_define(sysctl
);
158 lxc_config_define(proc
);
159 lxc_config_define(sched_core
);
161 static int set_config_unsupported_key(const char *key
, const char *value
,
162 struct lxc_conf
*lxc_conf
, void *data
)
164 return syserror_set(-EINVAL
, "Unsupported config key \"%s\"", key
);
167 static int get_config_unsupported_key(const char *key
, char *retv
, int inlen
,
168 struct lxc_conf
*c
, void *data
)
170 return syserror_set(-EINVAL
, "Unsupported config key \"%s\"", key
);
173 static int clr_config_unsupported_key(const char *key
,
174 struct lxc_conf
*lxc_conf
, void *data
)
176 return syserror_set(-EINVAL
, "Unsupported config key \"%s\"", key
);
181 * If a new config option is added to this table, be aware that
182 * the order in which the options are places into the table matters.
183 * That means that more specific options of a namespace have to be
184 * placed above more generic ones.
186 * For instance: If lxc.ab is placed before lxc.ab.c, the config option
187 * lxc.ab.c will always be matched to lxc.ab. That is, the lxc.ab.c option
188 * has to be placed above lxc.ab.
190 static struct lxc_config_t config_jump_table
[] = {
191 { "lxc.arch", true, set_config_personality
, get_config_personality
, clr_config_personality
, },
192 { "lxc.apparmor.profile", true, set_config_apparmor_profile
, get_config_apparmor_profile
, clr_config_apparmor_profile
, },
193 { "lxc.apparmor.allow_incomplete", true, set_config_apparmor_allow_incomplete
, get_config_apparmor_allow_incomplete
, clr_config_apparmor_allow_incomplete
, },
194 { "lxc.apparmor.allow_nesting", true, set_config_apparmor_allow_nesting
, get_config_apparmor_allow_nesting
, clr_config_apparmor_allow_nesting
, },
195 { "lxc.apparmor.raw", true, set_config_apparmor_raw
, get_config_apparmor_raw
, clr_config_apparmor_raw
, },
196 { "lxc.autodev.tmpfs.size", true, set_config_autodev_tmpfs_size
, get_config_autodev_tmpfs_size
, clr_config_autodev_tmpfs_size
, },
197 { "lxc.autodev", true, set_config_autodev
, get_config_autodev
, clr_config_autodev
, },
198 { "lxc.cap.drop", true, set_config_cap_drop
, get_config_cap_drop
, clr_config_cap_drop
, },
199 { "lxc.cap.keep", true, set_config_cap_keep
, get_config_cap_keep
, clr_config_cap_keep
, },
200 { "lxc.cgroup2", false, set_config_cgroup2_controller
, get_config_cgroup2_controller
, clr_config_cgroup2_controller
, },
201 { "lxc.cgroup.dir.monitor.pivot", true, set_config_cgroup_monitor_pivot_dir
, get_config_cgroup_monitor_pivot_dir
, clr_config_cgroup_monitor_pivot_dir
, },
202 { "lxc.cgroup.dir.monitor", true, set_config_cgroup_monitor_dir
, get_config_cgroup_monitor_dir
, clr_config_cgroup_monitor_dir
, },
203 { "lxc.cgroup.dir.container.inner", true, set_config_cgroup_container_inner_dir
, get_config_cgroup_container_inner_dir
, clr_config_cgroup_container_inner_dir
, },
204 { "lxc.cgroup.dir.container", true, set_config_cgroup_container_dir
, get_config_cgroup_container_dir
, clr_config_cgroup_container_dir
, },
205 { "lxc.cgroup.dir", true, set_config_cgroup_dir
, get_config_cgroup_dir
, clr_config_cgroup_dir
, },
206 { "lxc.cgroup.relative", true, set_config_cgroup_relative
, get_config_cgroup_relative
, clr_config_cgroup_relative
, },
207 { "lxc.cgroup", false, set_config_cgroup_controller
, get_config_cgroup_controller
, clr_config_cgroup_controller
, },
208 { "lxc.console.buffer.size", true, set_config_console_buffer_size
, get_config_console_buffer_size
, clr_config_console_buffer_size
, },
209 { "lxc.console.logfile", true, set_config_console_logfile
, get_config_console_logfile
, clr_config_console_logfile
, },
210 { "lxc.console.path", true, set_config_console_path
, get_config_console_path
, clr_config_console_path
, },
211 { "lxc.console.rotate", true, set_config_console_rotate
, get_config_console_rotate
, clr_config_console_rotate
, },
212 { "lxc.console.size", true, set_config_console_size
, get_config_console_size
, clr_config_console_size
, },
213 { "lxc.sched.core", true, set_config_sched_core
, get_config_sched_core
, clr_config_sched_core
, },
214 { "lxc.environment", true, set_config_environment
, get_config_environment
, clr_config_environment
, },
215 { "lxc.ephemeral", true, set_config_ephemeral
, get_config_ephemeral
, clr_config_ephemeral
, },
216 { "lxc.execute.cmd", true, set_config_execute_cmd
, get_config_execute_cmd
, clr_config_execute_cmd
, },
217 { "lxc.group", true, set_config_group
, get_config_group
, clr_config_group
, },
218 { "lxc.hook.autodev", true, set_config_hooks
, get_config_hooks
, clr_config_hooks
, },
219 { "lxc.hook.clone", true, set_config_hooks
, get_config_hooks
, clr_config_hooks
, },
220 { "lxc.hook.destroy", true, set_config_hooks
, get_config_hooks
, clr_config_hooks
, },
221 { "lxc.hook.mount", true, set_config_hooks
, get_config_hooks
, clr_config_hooks
, },
222 { "lxc.hook.post-stop", true, set_config_hooks
, get_config_hooks
, clr_config_hooks
, },
223 { "lxc.hook.pre-mount", true, set_config_hooks
, get_config_hooks
, clr_config_hooks
, },
224 { "lxc.hook.pre-start", true, set_config_hooks
, get_config_hooks
, clr_config_hooks
, },
225 { "lxc.hook.start", true, set_config_hooks
, get_config_hooks
, clr_config_hooks
, },
226 { "lxc.hook.start-host", true, set_config_hooks
, get_config_hooks
, clr_config_hooks
, },
227 { "lxc.hook.stop", true, set_config_hooks
, get_config_hooks
, clr_config_hooks
, },
228 { "lxc.hook.version", true, set_config_hooks_version
, get_config_hooks_version
, clr_config_hooks_version
, },
229 { "lxc.hook", true, set_config_hooks
, get_config_hooks
, clr_config_hooks
, },
230 { "lxc.idmap", true, set_config_idmaps
, get_config_idmaps
, clr_config_idmaps
, },
231 { "lxc.include", true, set_config_includefiles
, get_config_includefiles
, clr_config_includefiles
, },
232 { "lxc.init.cmd", true, set_config_init_cmd
, get_config_init_cmd
, clr_config_init_cmd
, },
233 { "lxc.init.gid", true, set_config_init_gid
, get_config_init_gid
, clr_config_init_gid
, },
234 { "lxc.init.groups", true, set_config_init_groups
, get_config_init_groups
, clr_config_init_groups
, },
235 { "lxc.init.uid", true, set_config_init_uid
, get_config_init_uid
, clr_config_init_uid
, },
236 { "lxc.init.cwd", true, set_config_init_cwd
, get_config_init_cwd
, clr_config_init_cwd
, },
237 { "lxc.keyring.session", true, set_config_keyring_session
, get_config_keyring_session
, clr_config_keyring_session
},
238 { "lxc.log.file", true, set_config_log_file
, get_config_log_file
, clr_config_log_file
, },
239 { "lxc.log.level", true, set_config_log_level
, get_config_log_level
, clr_config_log_level
, },
240 { "lxc.log.syslog", true, set_config_log_syslog
, get_config_log_syslog
, clr_config_log_syslog
, },
241 { "lxc.monitor.unshare", true, set_config_monitor
, get_config_monitor
, clr_config_monitor
, },
242 { "lxc.monitor.signal.pdeath", true, set_config_monitor_signal_pdeath
, get_config_monitor_signal_pdeath
, clr_config_monitor_signal_pdeath
, },
243 { "lxc.mount.auto", true, set_config_mount_auto
, get_config_mount_auto
, clr_config_mount_auto
, },
244 { "lxc.mount.entry", true, set_config_mount
, get_config_mount
, clr_config_mount
, },
245 { "lxc.mount.fstab", true, set_config_mount_fstab
, get_config_mount_fstab
, clr_config_mount_fstab
, },
246 { "lxc.namespace.clone", true, set_config_namespace_clone
, get_config_namespace_clone
, clr_config_namespace_clone
, },
247 { "lxc.namespace.keep", true, set_config_namespace_keep
, get_config_namespace_keep
, clr_config_namespace_keep
, },
248 { "lxc.namespace.share.", false, set_config_namespace_share
, get_config_namespace_share
, clr_config_namespace_share
, },
249 { "lxc.time.offset.boot", true, set_config_time_offset_boot
, get_config_time_offset_boot
, clr_config_time_offset_boot
, },
250 { "lxc.time.offset.monotonic", true, set_config_time_offset_monotonic
, get_config_time_offset_monotonic
, clr_config_time_offset_monotonic
, },
251 { "lxc.net.", false, set_config_jump_table_net
, get_config_jump_table_net
, clr_config_jump_table_net
, },
252 { "lxc.net", true, set_config_net
, get_config_net
, clr_config_net
, },
253 { "lxc.no_new_privs", true, set_config_no_new_privs
, get_config_no_new_privs
, clr_config_no_new_privs
, },
254 { "lxc.prlimit", false, set_config_prlimit
, get_config_prlimit
, clr_config_prlimit
, },
255 { "lxc.pty.max", true, set_config_pty_max
, get_config_pty_max
, clr_config_pty_max
, },
256 { "lxc.rootfs.managed", true, set_config_rootfs_managed
, get_config_rootfs_managed
, clr_config_rootfs_managed
, },
257 { "lxc.rootfs.mount", true, set_config_rootfs_mount
, get_config_rootfs_mount
, clr_config_rootfs_mount
, },
258 { "lxc.rootfs.options", true, set_config_rootfs_options
, get_config_rootfs_options
, clr_config_rootfs_options
, },
259 { "lxc.rootfs.path", true, set_config_rootfs_path
, get_config_rootfs_path
, clr_config_rootfs_path
, },
260 { "lxc.seccomp.allow_nesting", true, set_config_seccomp_allow_nesting
, get_config_seccomp_allow_nesting
, clr_config_seccomp_allow_nesting
, },
261 { "lxc.seccomp.notify.cookie", true, set_config_seccomp_notify_cookie
, get_config_seccomp_notify_cookie
, clr_config_seccomp_notify_cookie
, },
262 { "lxc.seccomp.notify.proxy", true, set_config_seccomp_notify_proxy
, get_config_seccomp_notify_proxy
, clr_config_seccomp_notify_proxy
, },
263 { "lxc.seccomp.profile", true, set_config_seccomp_profile
, get_config_seccomp_profile
, clr_config_seccomp_profile
, },
264 { "lxc.selinux.context.keyring", true, set_config_selinux_context_keyring
, get_config_selinux_context_keyring
, clr_config_selinux_context_keyring
},
265 { "lxc.selinux.context", true, set_config_selinux_context
, get_config_selinux_context
, clr_config_selinux_context
, },
266 { "lxc.signal.halt", true, set_config_signal_halt
, get_config_signal_halt
, clr_config_signal_halt
, },
267 { "lxc.signal.reboot", true, set_config_signal_reboot
, get_config_signal_reboot
, clr_config_signal_reboot
, },
268 { "lxc.signal.stop", true, set_config_signal_stop
, get_config_signal_stop
, clr_config_signal_stop
, },
269 { "lxc.start.auto", true, set_config_start
, get_config_start
, clr_config_start
, },
270 { "lxc.start.delay", true, set_config_start
, get_config_start
, clr_config_start
, },
271 { "lxc.start.order", true, set_config_start
, get_config_start
, clr_config_start
, },
272 { "lxc.tty.dir", true, set_config_tty_dir
, get_config_tty_dir
, clr_config_tty_dir
, },
273 { "lxc.tty.max", true, set_config_tty_max
, get_config_tty_max
, clr_config_tty_max
, },
274 { "lxc.uts.name", true, set_config_uts_name
, get_config_uts_name
, clr_config_uts_name
, },
275 { "lxc.sysctl", false, set_config_sysctl
, get_config_sysctl
, clr_config_sysctl
, },
276 { "lxc.proc", false, set_config_proc
, get_config_proc
, clr_config_proc
, },
279 static struct lxc_config_t unsupported_config_key
= {
282 set_config_unsupported_key
,
283 get_config_unsupported_key
,
284 clr_config_unsupported_key
,
287 struct lxc_config_net_t
{
291 static struct lxc_config_net_t config_jump_table_net
[] = {
292 /* If a longer key is added please update. */
293 #define NETWORK_SUBKEY_SIZE_MAX (STRLITERALLEN("veth.vlan.tagged.id") * 2)
294 { "flags", true, set_config_net_flags
, get_config_net_flags
, clr_config_net_flags
, },
295 { "hwaddr", true, set_config_net_hwaddr
, get_config_net_hwaddr
, clr_config_net_hwaddr
, },
296 { "ipv4.address", true, set_config_net_ipv4_address
, get_config_net_ipv4_address
, clr_config_net_ipv4_address
, },
297 { "ipv4.gateway", true, set_config_net_ipv4_gateway
, get_config_net_ipv4_gateway
, clr_config_net_ipv4_gateway
, },
298 { "ipv6.address", true, set_config_net_ipv6_address
, get_config_net_ipv6_address
, clr_config_net_ipv6_address
, },
299 { "ipv6.gateway", true, set_config_net_ipv6_gateway
, get_config_net_ipv6_gateway
, clr_config_net_ipv6_gateway
, },
300 { "link", true, set_config_net_link
, get_config_net_link
, clr_config_net_link
, },
301 { "l2proxy", true, set_config_net_l2proxy
, get_config_net_l2proxy
, clr_config_net_l2proxy
, },
302 { "macvlan.mode", true, set_config_net_macvlan_mode
, get_config_net_macvlan_mode
, clr_config_net_macvlan_mode
, },
303 { "ipvlan.mode", true, set_config_net_ipvlan_mode
, get_config_net_ipvlan_mode
, clr_config_net_ipvlan_mode
, },
304 { "ipvlan.isolation", true, set_config_net_ipvlan_isolation
, get_config_net_ipvlan_isolation
, clr_config_net_ipvlan_isolation
, },
305 { "mtu", true, set_config_net_mtu
, get_config_net_mtu
, clr_config_net_mtu
, },
306 { "name", true, set_config_net_name
, get_config_net_name
, clr_config_net_name
, },
307 { "script.down", true, set_config_net_script_down
, get_config_net_script_down
, clr_config_net_script_down
, },
308 { "script.up", true, set_config_net_script_up
, get_config_net_script_up
, clr_config_net_script_up
, },
309 { "type", true, set_config_net_type
, get_config_net_type
, clr_config_net_type
, },
310 { "vlan.id", true, set_config_net_vlan_id
, get_config_net_vlan_id
, clr_config_net_vlan_id
, },
311 { "veth.mode", true, set_config_net_veth_mode
, get_config_net_veth_mode
, clr_config_net_veth_mode
, },
312 { "veth.n_rxqueues", true, set_config_net_veth_n_rxqueues
, get_config_net_veth_n_rxqueues
, clr_config_net_veth_n_rxqueues
, },
313 { "veth.n_txqueues", true, set_config_net_veth_n_txqueues
, get_config_net_veth_n_txqueues
, clr_config_net_veth_n_txqueues
, },
314 { "veth.pair", true, set_config_net_veth_pair
, get_config_net_veth_pair
, clr_config_net_veth_pair
, },
315 { "veth.ipv4.route", true, set_config_net_veth_ipv4_route
, get_config_net_veth_ipv4_route
, clr_config_net_veth_ipv4_route
, },
316 { "veth.ipv6.route", true, set_config_net_veth_ipv6_route
, get_config_net_veth_ipv6_route
, clr_config_net_veth_ipv6_route
, },
317 { "veth.vlan.id", true, set_config_net_veth_vlan_id
, get_config_net_veth_vlan_id
, clr_config_net_veth_vlan_id
, },
318 { "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
, },
321 static struct lxc_config_net_t unsupported_config_net_key
= {
324 set_config_unsupported_key
,
325 get_config_unsupported_key
,
326 clr_config_unsupported_key
,
329 struct lxc_config_t
*lxc_get_config_exact(const char *key
)
333 for (i
= 0; i
< ARRAY_SIZE(config_jump_table
); i
++)
334 if (strequal(config_jump_table
[i
].name
, key
))
335 return &config_jump_table
[i
];
340 /* Assume a reasonable subkey size limit. */
341 #define LXC_SUBKEY_LEN_MAX 256
343 static inline int match_config_item(const struct lxc_config_t
*entry
, const char *key
)
348 return strequal(entry
->name
, key
);
350 /* There should be no subkey longer than this. */
351 len
= strnlen(entry
->name
, LXC_SUBKEY_LEN_MAX
);
352 if (len
== LXC_SUBKEY_LEN_MAX
)
353 return error_ret(-E2BIG
, "Excessive subkey length");
355 return strnequal(entry
->name
, key
, len
);
358 struct lxc_config_t
*lxc_get_config(const char *key
)
360 for (size_t i
= 0; i
< ARRAY_SIZE(config_jump_table
); i
++) {
361 struct lxc_config_t
*cur
= &config_jump_table
[i
];
363 switch (match_config_item(cur
, key
)) {
367 return &unsupported_config_key
;
373 return &unsupported_config_key
;
376 static inline bool match_config_net_item(const struct lxc_config_net_t
*entry
,
380 return strequal(entry
->name
, key
);
381 return strnequal(entry
->name
, key
, strlen(entry
->name
));
384 static struct lxc_config_net_t
*lxc_get_config_net(const char *key
)
386 for (size_t i
= 0; i
< ARRAY_SIZE(config_jump_table_net
); i
++) {
387 struct lxc_config_net_t
*cur
= &config_jump_table_net
[i
];
389 if (!match_config_net_item(cur
, key
))
395 return &unsupported_config_net_key
;
398 static int set_config_net(const char *key
, const char *value
,
399 struct lxc_conf
*lxc_conf
, void *data
)
401 if (!lxc_config_value_empty(value
))
402 return syserror_set(-EINVAL
, "lxc.net must not have a value");
404 return clr_config_net(key
, lxc_conf
, data
);
407 static int set_config_net_type(const char *key
, const char *value
,
408 struct lxc_conf
*lxc_conf
, void *data
)
410 struct lxc_netdev
*netdev
= data
;
413 return ret_errno(EINVAL
);
415 clr_config_net_type(key
, lxc_conf
, data
);
416 if (lxc_config_value_empty(value
))
419 if (strequal(value
, "veth")) {
420 netdev
->type
= LXC_NET_VETH
;
421 INIT_LIST_HEAD(&netdev
->priv
.veth_attr
.ipv4_routes
);
422 INIT_LIST_HEAD(&netdev
->priv
.veth_attr
.ipv6_routes
);
423 lxc_list_init(&netdev
->priv
.veth_attr
.vlan_tagged_ids
);
424 if (!lxc_veth_flag_to_mode(netdev
->priv
.veth_attr
.mode
))
425 lxc_veth_mode_to_flag(&netdev
->priv
.veth_attr
.mode
, "bridge");
426 } else if (strequal(value
, "macvlan")) {
427 netdev
->type
= LXC_NET_MACVLAN
;
428 if (!lxc_macvlan_flag_to_mode(netdev
->priv
.veth_attr
.mode
))
429 lxc_macvlan_mode_to_flag(&netdev
->priv
.macvlan_attr
.mode
, "private");
430 } else if (strequal(value
, "ipvlan")) {
431 netdev
->type
= LXC_NET_IPVLAN
;
432 if (!lxc_ipvlan_flag_to_mode(netdev
->priv
.ipvlan_attr
.mode
))
433 lxc_ipvlan_mode_to_flag(&netdev
->priv
.ipvlan_attr
.mode
, "l3");
434 if (!lxc_ipvlan_flag_to_isolation(netdev
->priv
.ipvlan_attr
.isolation
))
435 lxc_ipvlan_isolation_to_flag(&netdev
->priv
.ipvlan_attr
.isolation
, "bridge");
436 } else if (strequal(value
, "vlan")) {
437 netdev
->type
= LXC_NET_VLAN
;
438 } else if (strequal(value
, "phys")) {
439 netdev
->type
= LXC_NET_PHYS
;
440 } else if (strequal(value
, "empty")) {
441 netdev
->type
= LXC_NET_EMPTY
;
442 /* We don't support custom loopback device names. */
443 (void)strlcpy(netdev
->name
, "lo", IFNAMSIZ
);
444 } else if (strequal(value
, "none")) {
445 netdev
->type
= LXC_NET_NONE
;
447 return log_error(-1, "Invalid network type %s", value
);
453 static int set_config_net_flags(const char *key
, const char *value
,
454 struct lxc_conf
*lxc_conf
, void *data
)
456 struct lxc_netdev
*netdev
= data
;
459 return ret_errno(EINVAL
);
461 if (lxc_config_value_empty(value
))
462 return clr_config_net_flags(key
, lxc_conf
, data
);
464 netdev
->flags
|= IFF_UP
;
469 static int create_matched_ifnames(const char *value
, struct lxc_conf
*lxc_conf
,
470 struct lxc_netdev
*netdev
)
472 call_cleaner(netns_freeifaddrs
) struct netns_ifaddrs
*ifaddr
= NULL
;
473 struct netns_ifaddrs
*ifa
;
476 const char *type_key
= "lxc.net.type";
477 const char *link_key
= "lxc.net.link";
478 const char *tmpvalue
= "phys";
480 if (netns_getifaddrs(&ifaddr
, -1, &(bool){false}) < 0)
481 return log_error_errno(-1, errno
, "Failed to get network interfaces");
483 for (ifa
= ifaddr
, n
= 0; ifa
!= NULL
; ifa
= ifa
->ifa_next
, n
++) {
487 if (ifa
->ifa_addr
->sa_family
!= AF_PACKET
)
490 if (strnequal(value
, ifa
->ifa_name
, strlen(value
) - 1)) {
491 ret
= set_config_net_type(type_key
, tmpvalue
, lxc_conf
,
494 ret
= set_config_net_link(
495 link_key
, ifa
->ifa_name
, lxc_conf
, netdev
);
497 ERROR("Failed to create matched ifnames");
501 ERROR("Failed to create matched ifnames");
510 static int set_config_net_link(const char *key
, const char *value
,
511 struct lxc_conf
*lxc_conf
, void *data
)
513 struct lxc_netdev
*netdev
= data
;
517 return ret_errno(EINVAL
);
519 if (lxc_config_value_empty(value
))
520 return clr_config_net_link(key
, lxc_conf
, data
);
522 if (value
[strlen(value
) - 1] == '+' && netdev
->type
== LXC_NET_PHYS
)
523 ret
= create_matched_ifnames(value
, lxc_conf
, netdev
);
525 ret
= network_ifname(netdev
->link
, value
, sizeof(netdev
->link
));
530 static int set_config_net_l2proxy(const char *key
, const char *value
,
531 struct lxc_conf
*lxc_conf
, void *data
)
533 struct lxc_netdev
*netdev
= data
;
534 unsigned int val
= 0;
538 return ret_errno(EINVAL
);
540 if (lxc_config_value_empty(value
))
541 return clr_config_net_l2proxy(key
, lxc_conf
, data
);
543 ret
= lxc_safe_uint(value
, &val
);
545 return ret_errno(ret
);
549 netdev
->l2proxy
= false;
552 netdev
->l2proxy
= true;
556 return ret_errno(EINVAL
);
559 static int set_config_net_name(const char *key
, const char *value
,
560 struct lxc_conf
*lxc_conf
, void *data
)
562 struct lxc_netdev
*netdev
= data
;
565 return ret_errno(EINVAL
);
567 if (lxc_config_value_empty(value
))
568 return clr_config_net_name(key
, lxc_conf
, data
);
570 return network_ifname(netdev
->name
, value
, sizeof(netdev
->name
));
574 static int set_config_net_veth_mode(const char *key
, const char *value
,
575 struct lxc_conf
*lxc_conf
, void *data
)
577 struct lxc_netdev
*netdev
= data
;
580 return ret_errno(EINVAL
);
582 if (netdev
->type
!= LXC_NET_VETH
)
583 return ret_errno(EINVAL
);
585 if (lxc_config_value_empty(value
))
586 return clr_config_net_veth_mode(key
, lxc_conf
, data
);
589 return ret_errno(EINVAL
);
591 return lxc_veth_mode_to_flag(&netdev
->priv
.veth_attr
.mode
, value
);
594 static int set_config_net_veth_n_rxqueues(const char *key
, const char *value
,
595 struct lxc_conf
*lxc_conf
, void *data
)
598 struct lxc_netdev
*netdev
= data
;
601 return ret_errno(EINVAL
);
603 if (netdev
->type
!= LXC_NET_VETH
)
604 return ret_errno(EINVAL
);
606 if (lxc_config_value_empty(value
))
607 return clr_config_net_veth_n_rxqueues(key
, lxc_conf
, data
);
609 if (lxc_safe_int(value
, &n_rxqueues
))
610 return ret_errno(EINVAL
);
613 return ret_errno(EINVAL
);
615 netdev
->priv
.veth_attr
.n_rxqueues
= n_rxqueues
;
619 static int set_config_net_veth_n_txqueues(const char *key
, const char *value
,
620 struct lxc_conf
*lxc_conf
, void *data
)
623 struct lxc_netdev
*netdev
= data
;
626 return ret_errno(EINVAL
);
628 if (netdev
->type
!= LXC_NET_VETH
)
629 return ret_errno(EINVAL
);
631 if (lxc_config_value_empty(value
))
632 return clr_config_net_veth_n_txqueues(key
, lxc_conf
, data
);
634 if (lxc_safe_int(value
, &n_txqueues
))
635 return ret_errno(EINVAL
);
638 return ret_errno(EINVAL
);
640 netdev
->priv
.veth_attr
.n_txqueues
= n_txqueues
;
644 static int set_config_net_veth_pair(const char *key
, const char *value
,
645 struct lxc_conf
*lxc_conf
, void *data
)
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_pair(key
, lxc_conf
, data
);
658 return network_ifname(netdev
->priv
.veth_attr
.pair
, value
,
659 sizeof(netdev
->priv
.veth_attr
.pair
));
662 static int set_config_net_veth_vlan_id(const char *key
, const char *value
,
663 struct lxc_conf
*lxc_conf
, void *data
)
666 struct lxc_netdev
*netdev
= data
;
669 return ret_errno(EINVAL
);
671 if (netdev
->type
!= LXC_NET_VETH
)
672 return ret_errno(EINVAL
);
674 if (lxc_config_value_empty(value
))
675 return clr_config_net_veth_vlan_id(key
, lxc_conf
, data
);
677 if (strequal(value
, "none")) {
678 netdev
->priv
.veth_attr
.vlan_id
= BRIDGE_VLAN_NONE
;
680 unsigned short vlan_id
;
682 ret
= get_u16(&vlan_id
, value
, 0);
684 return ret_errno(EINVAL
);
686 if (vlan_id
> BRIDGE_VLAN_ID_MAX
)
687 return ret_errno(EINVAL
);
689 netdev
->priv
.veth_attr
.vlan_id
= vlan_id
;
692 netdev
->priv
.veth_attr
.vlan_id_set
= true;
696 static int set_config_net_veth_vlan_tagged_id(const char *key
, const char *value
,
697 struct lxc_conf
*lxc_conf
,
700 __do_free
struct lxc_list
*list
= NULL
;
702 unsigned short vlan_id
;
703 struct lxc_netdev
*netdev
= data
;
706 return ret_errno(EINVAL
);
708 if (netdev
->type
!= LXC_NET_VETH
)
709 return ret_errno(EINVAL
);
711 if (lxc_config_value_empty(value
))
712 return clr_config_net_veth_vlan_tagged_id(key
, lxc_conf
, data
);
714 ret
= get_u16(&vlan_id
, value
, 0);
716 return ret_errno(EINVAL
);
718 if (vlan_id
> BRIDGE_VLAN_ID_MAX
)
719 return ret_errno(EINVAL
);
721 list
= lxc_list_new();
723 return ret_errno(ENOMEM
);
725 list
->elem
= UINT_TO_PTR(vlan_id
);
727 lxc_list_add_tail(&netdev
->priv
.veth_attr
.vlan_tagged_ids
, move_ptr(list
));
732 static int set_config_net_macvlan_mode(const char *key
, const char *value
,
733 struct lxc_conf
*lxc_conf
, void *data
)
735 struct lxc_netdev
*netdev
= data
;
738 return ret_errno(EINVAL
);
740 if (netdev
->type
!= LXC_NET_MACVLAN
)
741 return ret_errno(EINVAL
);
743 if (lxc_config_value_empty(value
))
744 return clr_config_net_macvlan_mode(key
, lxc_conf
, data
);
746 return lxc_macvlan_mode_to_flag(&netdev
->priv
.macvlan_attr
.mode
, value
);
749 static int set_config_net_ipvlan_mode(const char *key
, const char *value
,
750 struct lxc_conf
*lxc_conf
, void *data
)
752 struct lxc_netdev
*netdev
= data
;
755 return ret_errno(EINVAL
);
757 if (netdev
->type
!= LXC_NET_IPVLAN
)
758 return syserror_set(-EINVAL
, "Invalid ipvlan mode \"%s\", can only be used with ipvlan network", value
);
760 if (lxc_config_value_empty(value
))
761 return clr_config_net_ipvlan_mode(key
, lxc_conf
, data
);
763 return lxc_ipvlan_mode_to_flag(&netdev
->priv
.ipvlan_attr
.mode
, value
);
766 static int set_config_net_ipvlan_isolation(const char *key
, const char *value
,
767 struct lxc_conf
*lxc_conf
, void *data
)
769 struct lxc_netdev
*netdev
= data
;
772 return ret_errno(EINVAL
);
774 if (netdev
->type
!= LXC_NET_IPVLAN
)
775 return syserror_set(-EINVAL
, "Invalid ipvlan isolation \"%s\", can only be used with ipvlan network", value
);
777 if (lxc_config_value_empty(value
))
778 return clr_config_net_ipvlan_isolation(key
, lxc_conf
, data
);
780 return lxc_ipvlan_isolation_to_flag(&netdev
->priv
.ipvlan_attr
.isolation
, value
);
783 static int set_config_net_hwaddr(const char *key
, const char *value
,
784 struct lxc_conf
*lxc_conf
, void *data
)
786 __do_free
char *new_value
= NULL
;
787 struct lxc_netdev
*netdev
= data
;
790 return ret_errno(EINVAL
);
792 clr_config_net_hwaddr(key
, lxc_conf
, data
);
793 if (lxc_config_value_empty(value
))
796 new_value
= strdup(value
);
798 return ret_errno(ENOMEM
);
800 rand_complete_hwaddr(new_value
);
801 if (!lxc_config_value_empty(new_value
))
802 netdev
->hwaddr
= move_ptr(new_value
);
807 static int set_config_net_vlan_id(const char *key
, const char *value
,
808 struct lxc_conf
*lxc_conf
, void *data
)
811 struct lxc_netdev
*netdev
= data
;
814 return ret_errno(EINVAL
);
816 if (netdev
->type
!= LXC_NET_VLAN
)
817 return ret_errno(EINVAL
);
819 if (lxc_config_value_empty(value
))
820 return clr_config_net_vlan_id(key
, lxc_conf
, data
);
822 ret
= get_u16(&netdev
->priv
.vlan_attr
.vid
, value
, 0);
829 static int set_config_net_mtu(const char *key
, const char *value
,
830 struct lxc_conf
*lxc_conf
, void *data
)
832 struct lxc_netdev
*netdev
= data
;
835 return ret_errno(EINVAL
);
837 clr_config_net_mtu(key
, lxc_conf
, data
);
838 if (lxc_config_value_empty(value
))
841 return set_config_string_item(&netdev
->mtu
, value
);
844 static int set_config_net_ipv4_address(const char *key
, const char *value
,
845 struct lxc_conf
*lxc_conf
, void *data
)
847 __do_free
char *addr
= NULL
;
848 __do_free
struct lxc_inetdev
*inetdev
= NULL
;
850 struct lxc_netdev
*netdev
= data
;
851 char *cursor
, *slash
;
852 char *bcast
= NULL
, *prefix
= NULL
;
855 return ret_errno(EINVAL
);
857 if (lxc_config_value_empty(value
))
858 return clr_config_net_ipv4_address(key
, lxc_conf
, data
);
860 inetdev
= zalloc(sizeof(*inetdev
));
862 return ret_errno(ENOMEM
);
864 addr
= strdup(value
);
866 return ret_errno(ENOMEM
);
868 cursor
= strstr(addr
, " ");
874 slash
= strstr(addr
, "/");
880 ret
= inet_pton(AF_INET
, addr
, &inetdev
->addr
);
882 return log_error_errno(-1, errno
, "Invalid ipv4 address \"%s\"", value
);
885 ret
= inet_pton(AF_INET
, bcast
, &inetdev
->bcast
);
887 return log_error_errno(-1, errno
, "Invalid ipv4 broadcast address \"%s\"", value
);
891 /* No prefix specified, determine it from the network class. */
894 ret
= lxc_safe_uint(prefix
, &inetdev
->prefix
);
896 inetdev
->prefix
= config_ip_prefix(&inetdev
->addr
);
897 if (ret
|| inetdev
->prefix
> 32)
898 return ret_errno(EINVAL
);
900 /* If no broadcast address, compute one from the prefix and address. */
902 unsigned int shift
= LAST_BIT_PER_TYPE(inetdev
->prefix
);
904 inetdev
->bcast
.s_addr
= inetdev
->addr
.s_addr
;
905 if (inetdev
->prefix
< shift
)
906 shift
= inetdev
->prefix
;
907 inetdev
->bcast
.s_addr
|= htonl(INADDR_BROADCAST
>> shift
);
910 list_add_tail(&inetdev
->head
, &netdev
->ipv4_addresses
);
916 static int set_config_net_ipv4_gateway(const char *key
, const char *value
,
917 struct lxc_conf
*lxc_conf
, void *data
)
919 struct lxc_netdev
*netdev
= data
;
922 return ret_errno(EINVAL
);
924 clr_config_net_ipv4_gateway(key
, lxc_conf
, data
);
925 if (lxc_config_value_empty(value
))
928 if (strequal(value
, "auto")) {
929 netdev
->ipv4_gateway
= NULL
;
930 netdev
->ipv4_gateway_auto
= true;
931 } else if (strequal(value
, "dev")) {
932 netdev
->ipv4_gateway
= NULL
;
933 netdev
->ipv4_gateway_auto
= false;
934 netdev
->ipv4_gateway_dev
= true;
936 __do_free
struct in_addr
*gw
= NULL
;
939 gw
= zalloc(sizeof(*gw
));
941 return ret_errno(ENOMEM
);
943 ret
= inet_pton(AF_INET
, value
, gw
);
945 return log_error_errno(-1, errno
, "Invalid ipv4 gateway address \"%s\"", value
);
947 netdev
->ipv4_gateway
= move_ptr(gw
);
948 netdev
->ipv4_gateway_auto
= false;
954 static int set_config_net_veth_ipv4_route(const char *key
, const char *value
,
955 struct lxc_conf
*lxc_conf
, void *data
)
957 __do_free
char *valdup
= NULL
;
958 __do_free
struct lxc_inetdev
*inetdev
= NULL
;
960 char *netmask
, *slash
;
961 struct lxc_netdev
*netdev
= data
;
964 return ret_errno(EINVAL
);
966 if (netdev
->type
!= LXC_NET_VETH
)
967 return syserror_set(-EINVAL
, "Invalid ipv4 route \"%s\", can only be used with veth network", value
);
969 if (lxc_config_value_empty(value
))
970 return clr_config_net_veth_ipv4_route(key
, lxc_conf
, data
);
972 inetdev
= zalloc(sizeof(*inetdev
));
974 return ret_errno(ENOMEM
);
976 valdup
= strdup(value
);
978 return ret_errno(ENOMEM
);
980 slash
= strchr(valdup
, '/');
982 return ret_errno(EINVAL
);
987 return ret_errno(EINVAL
);
991 ret
= lxc_safe_uint(netmask
, &inetdev
->prefix
);
992 if (ret
< 0 || inetdev
->prefix
> 32)
993 return ret_errno(EINVAL
);
995 ret
= inet_pton(AF_INET
, valdup
, &inetdev
->addr
);
997 return ret_errno(EINVAL
);
999 list_add_tail(&inetdev
->head
, &netdev
->priv
.veth_attr
.ipv4_routes
);
1005 static int set_config_net_ipv6_address(const char *key
, const char *value
,
1006 struct lxc_conf
*lxc_conf
, void *data
)
1008 __do_free
char *valdup
= NULL
;
1009 __do_free
struct lxc_inet6dev
*inet6dev
= NULL
;
1011 struct lxc_netdev
*netdev
= data
;
1012 char *slash
, *netmask
;
1015 return ret_errno(EINVAL
);
1017 if (lxc_config_value_empty(value
))
1018 return clr_config_net_ipv6_address(key
, lxc_conf
, data
);
1020 inet6dev
= zalloc(sizeof(*inet6dev
));
1022 return ret_errno(ENOMEM
);
1024 valdup
= strdup(value
);
1026 return ret_errno(ENOMEM
);
1028 inet6dev
->prefix
= 64;
1029 slash
= strstr(valdup
, "/");
1032 netmask
= slash
+ 1;
1034 ret
= lxc_safe_uint(netmask
, &inet6dev
->prefix
);
1039 ret
= inet_pton(AF_INET6
, valdup
, &inet6dev
->addr
);
1040 if (!ret
|| ret
< 0)
1041 return log_error_errno(-EINVAL
, EINVAL
, "Invalid ipv6 address \"%s\"", valdup
);
1043 list_add_tail(&inet6dev
->head
, &netdev
->ipv6_addresses
);
1049 static int set_config_net_ipv6_gateway(const char *key
, const char *value
,
1050 struct lxc_conf
*lxc_conf
, void *data
)
1052 struct lxc_netdev
*netdev
= data
;
1055 return ret_errno(EINVAL
);
1057 clr_config_net_ipv6_gateway(key
, lxc_conf
, data
);
1058 if (lxc_config_value_empty(value
))
1061 if (strequal(value
, "auto")) {
1062 netdev
->ipv6_gateway
= NULL
;
1063 netdev
->ipv6_gateway_auto
= true;
1064 } else if (strequal(value
, "dev")) {
1065 netdev
->ipv6_gateway
= NULL
;
1066 netdev
->ipv6_gateway_auto
= false;
1067 netdev
->ipv6_gateway_dev
= true;
1070 __do_free
struct in6_addr
*gw
= NULL
;
1072 gw
= zalloc(sizeof(*gw
));
1074 return ret_errno(ENOMEM
);
1076 ret
= inet_pton(AF_INET6
, value
, gw
);
1077 if (!ret
|| ret
< 0)
1078 return log_error_errno(-EINVAL
, EINVAL
,
1079 "Invalid ipv6 gateway address \"%s\"", value
);
1081 netdev
->ipv6_gateway
= move_ptr(gw
);
1082 netdev
->ipv6_gateway_auto
= false;
1088 static int set_config_net_veth_ipv6_route(const char *key
, const char *value
,
1089 struct lxc_conf
*lxc_conf
, void *data
)
1091 __do_free
char *valdup
= NULL
;
1092 __do_free
struct lxc_inet6dev
*inet6dev
= NULL
;
1094 char *netmask
, *slash
;
1095 struct lxc_netdev
*netdev
= data
;
1098 return ret_errno(EINVAL
);
1100 if (netdev
->type
!= LXC_NET_VETH
)
1101 return syserror_set(-EINVAL
, "Invalid ipv6 route \"%s\", can only be used with veth network", value
);
1103 if (lxc_config_value_empty(value
))
1104 return clr_config_net_veth_ipv6_route(key
, lxc_conf
, data
);
1106 inet6dev
= zalloc(sizeof(*inet6dev
));
1108 return ret_errno(ENOMEM
);
1110 valdup
= strdup(value
);
1112 return ret_errno(ENOMEM
);
1114 slash
= strchr(valdup
, '/');
1116 return ret_errno(EINVAL
);
1121 return ret_errno(EINVAL
);
1125 ret
= lxc_safe_uint(netmask
, &inet6dev
->prefix
);
1126 if (ret
< 0 || inet6dev
->prefix
> 128)
1127 return ret_errno(EINVAL
);
1129 ret
= inet_pton(AF_INET6
, valdup
, &inet6dev
->addr
);
1130 if (!ret
|| ret
< 0)
1131 return ret_errno(EINVAL
);
1133 list_add_tail(&inet6dev
->head
, &netdev
->priv
.veth_attr
.ipv6_routes
);
1139 static int set_config_net_script_up(const char *key
, const char *value
,
1140 struct lxc_conf
*lxc_conf
, void *data
)
1142 struct lxc_netdev
*netdev
= data
;
1145 return ret_errno(EINVAL
);
1147 clr_config_net_script_up(key
, lxc_conf
, data
);
1148 if (lxc_config_value_empty(value
))
1151 return set_config_string_item(&netdev
->upscript
, value
);
1154 static int set_config_net_script_down(const char *key
, const char *value
,
1155 struct lxc_conf
*lxc_conf
, void *data
)
1157 struct lxc_netdev
*netdev
= data
;
1160 return ret_errno(EINVAL
);
1162 clr_config_net_script_down(key
, lxc_conf
, data
);
1163 if (lxc_config_value_empty(value
))
1166 return set_config_string_item(&netdev
->downscript
, value
);
1169 static int add_hook(struct lxc_conf
*lxc_conf
, int which
, __owns
char *hook
)
1171 __do_free
char *val
= hook
;
1172 __do_free
struct string_entry
*entry
;
1174 entry
= zalloc(sizeof(struct string_entry
));
1176 return ret_errno(ENOMEM
);
1178 entry
->val
= move_ptr(val
);
1179 list_add_tail(&entry
->head
, &lxc_conf
->hooks
[which
]);
1185 static int set_config_seccomp_allow_nesting(const char *key
, const char *value
,
1186 struct lxc_conf
*lxc_conf
, void *data
)
1189 if (lxc_config_value_empty(value
))
1190 return clr_config_seccomp_allow_nesting(key
, lxc_conf
, NULL
);
1192 if (lxc_safe_uint(value
, &lxc_conf
->seccomp
.allow_nesting
) < 0)
1195 if (lxc_conf
->seccomp
.allow_nesting
> 1)
1196 return ret_errno(EINVAL
);
1200 return ret_errno(ENOSYS
);
1204 static int set_config_seccomp_notify_cookie(const char *key
, const char *value
,
1205 struct lxc_conf
*lxc_conf
, void *data
)
1207 #ifdef HAVE_SECCOMP_NOTIFY
1208 return set_config_string_item(&lxc_conf
->seccomp
.notifier
.cookie
, value
);
1210 return ret_errno(ENOSYS
);
1214 static int set_config_seccomp_notify_proxy(const char *key
, const char *value
,
1215 struct lxc_conf
*lxc_conf
, void *data
)
1217 #ifdef HAVE_SECCOMP_NOTIFY
1220 if (lxc_config_value_empty(value
))
1221 return clr_config_seccomp_notify_proxy(key
, lxc_conf
, NULL
);
1223 if (!strnequal(value
, "unix:", 5))
1224 return ret_errno(EINVAL
);
1227 if (lxc_unix_sockaddr(&lxc_conf
->seccomp
.notifier
.proxy_addr
, offset
) < 0)
1232 return ret_errno(ENOSYS
);
1236 static int set_config_seccomp_profile(const char *key
, const char *value
,
1237 struct lxc_conf
*lxc_conf
, void *data
)
1240 return set_config_path_item(&lxc_conf
->seccomp
.seccomp
, value
);
1242 return ret_errno(ENOSYS
);
1246 static int set_config_execute_cmd(const char *key
, const char *value
,
1247 struct lxc_conf
*lxc_conf
, void *data
)
1249 return set_config_path_item(&lxc_conf
->execute_cmd
, value
);
1252 static int set_config_init_cmd(const char *key
, const char *value
,
1253 struct lxc_conf
*lxc_conf
, void *data
)
1255 return set_config_path_item(&lxc_conf
->init_cmd
, value
);
1258 static int set_config_init_cwd(const char *key
, const char *value
,
1259 struct lxc_conf
*lxc_conf
, void *data
)
1261 return set_config_path_item(&lxc_conf
->init_cwd
, value
);
1264 static int set_config_init_uid(const char *key
, const char *value
,
1265 struct lxc_conf
*lxc_conf
, void *data
)
1267 unsigned int init_uid
;
1269 if (lxc_config_value_empty(value
)) {
1270 lxc_conf
->init_uid
= 0;
1274 if (lxc_safe_uint(value
, &init_uid
) < 0)
1277 lxc_conf
->init_uid
= init_uid
;
1282 static int set_config_init_gid(const char *key
, const char *value
,
1283 struct lxc_conf
*lxc_conf
, void *data
)
1285 unsigned int init_gid
;
1287 if (lxc_config_value_empty(value
)) {
1288 lxc_conf
->init_gid
= 0;
1292 if (lxc_safe_uint(value
, &init_gid
) < 0)
1295 lxc_conf
->init_gid
= init_gid
;
1300 static int set_config_init_groups(const char *key
, const char *value
,
1301 struct lxc_conf
*lxc_conf
, void *data
)
1303 __do_free
char *value_dup
= NULL
;
1304 gid_t
*init_groups
= NULL
;
1305 size_t num_groups
= 0;
1309 if (lxc_config_value_empty(value
))
1310 return clr_config_init_groups(key
, lxc_conf
, NULL
);
1312 value_dup
= strdup(value
);
1316 lxc_iterate_parts(token
, value_dup
, ",")
1319 if (num_groups
== INT_MAX
)
1320 return log_error_errno(-ERANGE
, ERANGE
, "Excessive number of supplementary groups specified");
1322 /* This means the string wasn't empty and all we found was garbage. */
1323 if (num_groups
== 0)
1324 return log_error_errno(-EINVAL
, EINVAL
, "No valid groups specified %s", value
);
1326 idx
= lxc_conf
->init_groups
.size
;
1327 init_groups
= realloc(lxc_conf
->init_groups
.list
, sizeof(gid_t
) * (idx
+ num_groups
));
1329 return ret_errno(ENOMEM
);
1332 * Once the realloc() succeeded we need to hand control of the memory
1333 * back to the config otherwise we risk a double-free when
1334 * lxc_conf_free() is called.
1336 lxc_conf
->init_groups
.list
= init_groups
;
1338 /* Restore duplicated value so we can call lxc_iterate_parts() again. */
1339 strcpy(value_dup
, value
);
1341 lxc_iterate_parts(token
, value_dup
, ",") {
1346 ret
= lxc_safe_uint(token
, &group
);
1348 return log_error_errno(ret
, -ret
, "Failed to parse group %s", token
);
1350 init_groups
[idx
++] = group
;
1353 lxc_conf
->init_groups
.size
+= num_groups
;
1358 static int set_config_hooks(const char *key
, const char *value
,
1359 struct lxc_conf
*lxc_conf
, void *data
)
1361 __do_free
char *copy
= NULL
;
1363 if (lxc_config_value_empty(value
))
1364 return lxc_clear_hooks(lxc_conf
, key
);
1366 if (strequal(key
+ 4, "hook"))
1367 return log_error_errno(-EINVAL
, EINVAL
, "lxc.hook must not have a value");
1369 copy
= strdup(value
);
1371 return ret_errno(ENOMEM
);
1373 if (strequal(key
+ 9, "pre-start"))
1374 return add_hook(lxc_conf
, LXCHOOK_PRESTART
, move_ptr(copy
));
1375 else if (strequal(key
+ 9, "start-host"))
1376 return add_hook(lxc_conf
, LXCHOOK_START_HOST
, move_ptr(copy
));
1377 else if (strequal(key
+ 9, "pre-mount"))
1378 return add_hook(lxc_conf
, LXCHOOK_PREMOUNT
, move_ptr(copy
));
1379 else if (strequal(key
+ 9, "autodev"))
1380 return add_hook(lxc_conf
, LXCHOOK_AUTODEV
, move_ptr(copy
));
1381 else if (strequal(key
+ 9, "mount"))
1382 return add_hook(lxc_conf
, LXCHOOK_MOUNT
, move_ptr(copy
));
1383 else if (strequal(key
+ 9, "start"))
1384 return add_hook(lxc_conf
, LXCHOOK_START
, move_ptr(copy
));
1385 else if (strequal(key
+ 9, "stop"))
1386 return add_hook(lxc_conf
, LXCHOOK_STOP
, move_ptr(copy
));
1387 else if (strequal(key
+ 9, "post-stop"))
1388 return add_hook(lxc_conf
, LXCHOOK_POSTSTOP
, move_ptr(copy
));
1389 else if (strequal(key
+ 9, "clone"))
1390 return add_hook(lxc_conf
, LXCHOOK_CLONE
, move_ptr(copy
));
1391 else if (strequal(key
+ 9, "destroy"))
1392 return add_hook(lxc_conf
, LXCHOOK_DESTROY
, move_ptr(copy
));
1394 return ret_errno(EINVAL
);
1397 static int set_config_hooks_version(const char *key
, const char *value
,
1398 struct lxc_conf
*lxc_conf
, void *data
)
1403 if (lxc_config_value_empty(value
))
1404 return clr_config_hooks_version(key
, lxc_conf
, NULL
);
1406 ret
= lxc_safe_uint(value
, &tmp
);
1411 return syserror_set(-EINVAL
, "Invalid hook version specified. Currently only 0 (legacy) and 1 are supported");
1413 lxc_conf
->hooks_version
= tmp
;
1418 static int set_config_personality(const char *key
, const char *value
,
1419 struct lxc_conf
*lxc_conf
, void *data
)
1422 personality_t personality
;
1424 ret
= lxc_config_parse_arch(value
, &personality
);
1426 return syserror("Unsupported personality \"%s\"", value
);
1428 lxc_conf
->personality
= personality
;
1432 static int set_config_pty_max(const char *key
, const char *value
,
1433 struct lxc_conf
*lxc_conf
, void *data
)
1436 unsigned int max
= 0;
1438 if (lxc_config_value_empty(value
)) {
1439 lxc_conf
->pty_max
= 0;
1443 ret
= lxc_safe_uint(value
, &max
);
1445 return ret_errno(EINVAL
);
1447 lxc_conf
->pty_max
= max
;
1452 /* We only need to check whether the first byte of the key after the lxc.start.
1453 * prefix matches our expectations since they fortunately all start with a
1454 * different letter. If anything was wrong with the key we would have already
1455 * noticed when the callback was called.
1457 static int set_config_start(const char *key
, const char *value
,
1458 struct lxc_conf
*lxc_conf
, void *data
)
1463 is_empty
= lxc_config_value_empty(value
);
1465 if (*(key
+ 10) == 'a') { /* lxc.start.auto */
1467 lxc_conf
->start_auto
= 0;
1471 ret
= lxc_safe_uint(value
, &lxc_conf
->start_auto
);
1475 if (lxc_conf
->start_auto
> 1)
1476 return ret_errno(EINVAL
);
1479 } else if (*(key
+ 10) == 'd') { /* lxc.start.delay */
1481 lxc_conf
->start_delay
= 0;
1485 return lxc_safe_uint(value
, &lxc_conf
->start_delay
);
1486 } else if (*(key
+ 10) == 'o') { /* lxc.start.order */
1488 lxc_conf
->start_order
= 0;
1492 return lxc_safe_int(value
, &lxc_conf
->start_order
);
1495 return ret_errno(EINVAL
);
1498 static int set_config_monitor(const char *key
, const char *value
,
1499 struct lxc_conf
*lxc_conf
, void *data
)
1501 if (lxc_config_value_empty(value
)) {
1502 lxc_conf
->monitor_unshare
= 0;
1506 if (strequal(key
+ 12, "unshare"))
1507 return lxc_safe_uint(value
, &lxc_conf
->monitor_unshare
);
1509 return ret_errno(EINVAL
);
1512 static int set_config_monitor_signal_pdeath(const char *key
, const char *value
,
1513 struct lxc_conf
*lxc_conf
, void *data
)
1515 if (lxc_config_value_empty(value
)) {
1516 lxc_conf
->monitor_signal_pdeath
= 0;
1520 if (strequal(key
+ 12, "signal.pdeath")) {
1523 sig_n
= sig_parse(value
);
1525 return ret_errno(EINVAL
);
1527 lxc_conf
->monitor_signal_pdeath
= sig_n
;
1531 return ret_errno(EINVAL
);
1534 static int set_config_group(const char *key
, const char *value
,
1535 struct lxc_conf
*lxc_conf
, void *data
)
1537 __do_free
char *groups
= NULL
;
1540 if (lxc_config_value_empty(value
))
1541 return lxc_clear_groups(lxc_conf
);
1543 groups
= strdup(value
);
1545 return ret_errno(ENOMEM
);
1548 * In case several groups are specified in a single line split these
1549 * groups in a single element for the list.
1551 lxc_iterate_parts(token
, groups
, " \t") {
1552 __do_free
char *val
= NULL
;
1553 __do_free
struct string_entry
*entry
= NULL
;
1555 entry
= zalloc(sizeof(struct string_entry
));
1557 return ret_errno(ENOMEM
);
1559 val
= strdup(token
);
1561 return ret_errno(ENOMEM
);
1563 entry
->val
= move_ptr(val
);
1564 list_add_tail(&entry
->head
, &lxc_conf
->groups
);
1571 static int set_config_environment(const char *key
, const char *value
,
1572 struct lxc_conf
*lxc_conf
, void *data
)
1574 __do_free
char *dup
= NULL
, *val
= NULL
;
1575 __do_free
struct environment_entry
*new_env
= NULL
;
1578 if (lxc_config_value_empty(value
))
1579 return lxc_clear_environment(lxc_conf
);
1581 new_env
= zalloc(sizeof(struct environment_entry
));
1583 return ret_errno(ENOMEM
);
1585 dup
= strdup(value
);
1587 return ret_errno(ENOMEM
);
1589 env_val
= strchr(dup
, '=');
1591 env_val
= getenv(dup
);
1597 return ret_errno(ENOENT
);
1599 val
= strdup(env_val
);
1601 return ret_errno(ENOMEM
);
1603 new_env
->key
= move_ptr(dup
);
1604 new_env
->val
= move_ptr(val
);
1606 list_add_tail(&new_env
->head
, &lxc_conf
->environment
);
1612 static int set_config_tty_max(const char *key
, const char *value
,
1613 struct lxc_conf
*lxc_conf
, void *data
)
1616 unsigned int nbtty
= 0;
1618 if (lxc_config_value_empty(value
)) {
1619 lxc_conf
->ttys
.max
= 0;
1623 ret
= lxc_safe_uint(value
, &nbtty
);
1627 lxc_conf
->ttys
.max
= nbtty
;
1632 static int set_config_tty_dir(const char *key
, const char *value
,
1633 struct lxc_conf
*lxc_conf
, void *data
)
1635 return set_config_string_item_max(&lxc_conf
->ttys
.dir
, value
,
1639 static int set_config_apparmor_profile(const char *key
, const char *value
,
1640 struct lxc_conf
*lxc_conf
, void *data
)
1643 return set_config_string_item(&lxc_conf
->lsm_aa_profile
, value
);
1645 return syserror_set(-EINVAL
, "Built without AppArmor support");
1649 static int set_config_apparmor_allow_incomplete(const char *key
,
1651 struct lxc_conf
*lxc_conf
,
1657 if (lxc_config_value_empty(value
)) {
1658 lxc_conf
->lsm_aa_allow_incomplete
= 0;
1662 ret
= lxc_safe_uint(value
, &lxc_conf
->lsm_aa_allow_incomplete
);
1666 if (lxc_conf
->lsm_aa_allow_incomplete
> 1)
1667 return ret_errno(EINVAL
);
1671 return syserror_set(-EINVAL
, "Built without AppArmor support");
1675 static int set_config_apparmor_allow_nesting(const char *key
,
1677 struct lxc_conf
*lxc_conf
,
1683 if (lxc_config_value_empty(value
))
1684 return clr_config_apparmor_allow_nesting(key
, lxc_conf
, NULL
);
1686 ret
= lxc_safe_uint(value
, &lxc_conf
->lsm_aa_allow_nesting
);
1690 if (lxc_conf
->lsm_aa_allow_nesting
> 1)
1691 return ret_errno(EINVAL
);
1695 return syserror_set(-EINVAL
, "Built without AppArmor support");
1699 static int set_config_apparmor_raw(const char *key
,
1701 struct lxc_conf
*lxc_conf
,
1705 __do_free
char *elem
= NULL
;
1706 __do_free
struct string_entry
*entry
= NULL
;
1708 if (lxc_config_value_empty(value
))
1709 return lxc_clear_apparmor_raw(lxc_conf
);
1711 entry
= zalloc(sizeof(struct string_entry
));
1713 return ret_errno(ENOMEM
);
1715 elem
= strdup(value
);
1717 return ret_errno(ENOMEM
);
1719 entry
->val
= move_ptr(elem
);
1720 list_add_tail(&entry
->head
, &lxc_conf
->lsm_aa_raw
);
1725 return syserror_set(-EINVAL
, "Built without AppArmor support");
1729 static int set_config_selinux_context(const char *key
, const char *value
,
1730 struct lxc_conf
*lxc_conf
, void *data
)
1733 return set_config_string_item(&lxc_conf
->lsm_se_context
, value
);
1735 return syserror_set(-EINVAL
, "Built without SELinux support");
1739 static int set_config_selinux_context_keyring(const char *key
, const char *value
,
1740 struct lxc_conf
*lxc_conf
, void *data
)
1743 return set_config_string_item(&lxc_conf
->lsm_se_keyring_context
, value
);
1745 return syserror_set(-EINVAL
, "Built without SELinux support");
1749 static int set_config_keyring_session(const char *key
, const char *value
,
1750 struct lxc_conf
*lxc_conf
, void *data
)
1752 return set_config_bool_item(&lxc_conf
->keyring_disable_session
, value
, false);
1755 static int set_config_log_file(const char *key
, const char *value
,
1756 struct lxc_conf
*c
, void *data
)
1760 if (lxc_config_value_empty(value
)) {
1761 free_disarm(c
->logfile
);
1766 * Store these values in the lxc_conf, and then try to set for actual
1769 ret
= set_config_path_item(&c
->logfile
, value
);
1771 ret
= lxc_log_set_file(&c
->logfd
, c
->logfile
);
1776 static int set_config_log_level(const char *key
, const char *value
,
1777 struct lxc_conf
*lxc_conf
, void *data
)
1781 if (lxc_config_value_empty(value
)) {
1782 lxc_conf
->loglevel
= LXC_LOG_LEVEL_NOTSET
;
1786 if (value
[0] >= '0' && value
[0] <= '9') {
1789 ret
= lxc_safe_int(value
, &newlevel
);
1791 return ret_errno(EINVAL
);
1793 newlevel
= lxc_log_priority_to_int(value
);
1797 * Store these values in the lxc_conf, and then try to set for actual
1800 lxc_conf
->loglevel
= newlevel
;
1802 return lxc_log_set_level(&lxc_conf
->loglevel
, newlevel
);
1805 static int set_config_autodev(const char *key
, const char *value
,
1806 struct lxc_conf
*lxc_conf
, void *data
)
1810 if (lxc_config_value_empty(value
)) {
1811 lxc_conf
->autodev
= 0;
1815 ret
= lxc_safe_uint(value
, &lxc_conf
->autodev
);
1817 return ret_errno(EINVAL
);
1819 if (lxc_conf
->autodev
> 1)
1820 return ret_errno(EINVAL
);
1825 static int set_config_autodev_tmpfs_size(const char *key
, const char *value
,
1826 struct lxc_conf
*lxc_conf
, void *data
)
1828 if (lxc_config_value_empty(value
)) {
1829 lxc_conf
->autodevtmpfssize
= 500000;
1833 if (lxc_safe_int(value
, &lxc_conf
->autodevtmpfssize
) < 0)
1834 lxc_conf
->autodevtmpfssize
= 500000;
1839 static int set_config_signal_halt(const char *key
, const char *value
,
1840 struct lxc_conf
*lxc_conf
, void *data
)
1844 if (lxc_config_value_empty(value
)) {
1845 lxc_conf
->haltsignal
= 0;
1849 sig_n
= sig_parse(value
);
1851 return ret_errno(EINVAL
);
1853 lxc_conf
->haltsignal
= sig_n
;
1858 static int set_config_signal_reboot(const char *key
, const char *value
,
1859 struct lxc_conf
*lxc_conf
, void *data
)
1863 if (lxc_config_value_empty(value
)) {
1864 lxc_conf
->rebootsignal
= 0;
1868 sig_n
= sig_parse(value
);
1870 return ret_errno(EINVAL
);
1872 lxc_conf
->rebootsignal
= sig_n
;
1877 static int set_config_signal_stop(const char *key
, const char *value
,
1878 struct lxc_conf
*lxc_conf
, void *data
)
1882 if (lxc_config_value_empty(value
)) {
1883 lxc_conf
->stopsignal
= 0;
1887 sig_n
= sig_parse(value
);
1889 return ret_errno(EINVAL
);
1891 lxc_conf
->stopsignal
= sig_n
;
1896 static int __set_config_cgroup_controller(const char *key
, const char *value
,
1897 struct lxc_conf
*lxc_conf
, int version
)
1899 call_cleaner(free_lxc_cgroup
) struct lxc_cgroup
*new_cgroup
= NULL
;
1900 const char *subkey
, *token
;
1903 if (lxc_config_value_empty(value
))
1904 return lxc_clear_cgroups(lxc_conf
, key
, version
);
1906 if (version
== CGROUP2_SUPER_MAGIC
) {
1907 token
= "lxc.cgroup2.";
1909 } else if (version
== CGROUP_SUPER_MAGIC
) {
1910 token
= "lxc.cgroup.";
1913 return ret_errno(EINVAL
);
1916 if (!strnequal(key
, token
, token_len
))
1917 return ret_errno(EINVAL
);
1919 subkey
= key
+ token_len
;
1920 if (*subkey
== '\0')
1921 return ret_errno(EINVAL
);
1923 new_cgroup
= zalloc(sizeof(*new_cgroup
));
1925 return ret_errno(ENOMEM
);
1927 new_cgroup
->subsystem
= strdup(subkey
);
1928 if (!new_cgroup
->subsystem
)
1929 return ret_errno(ENOMEM
);
1931 new_cgroup
->value
= strdup(value
);
1932 if (!new_cgroup
->value
)
1933 return ret_errno(ENOMEM
);
1935 new_cgroup
->version
= version
;
1937 if (version
== CGROUP2_SUPER_MAGIC
)
1938 list_add_tail(&new_cgroup
->head
, &lxc_conf
->cgroup2
);
1940 list_add_tail(&new_cgroup
->head
, &lxc_conf
->cgroup
);
1941 move_ptr(new_cgroup
);
1946 static int set_config_cgroup_controller(const char *key
, const char *value
,
1947 struct lxc_conf
*lxc_conf
, void *data
)
1949 return __set_config_cgroup_controller(key
, value
, lxc_conf
,
1950 CGROUP_SUPER_MAGIC
);
1953 static int set_config_cgroup2_controller(const char *key
, const char *value
,
1954 struct lxc_conf
*lxc_conf
, void *data
)
1956 return __set_config_cgroup_controller(key
, value
, lxc_conf
,
1957 CGROUP2_SUPER_MAGIC
);
1960 static int set_config_cgroup_dir(const char *key
, const char *value
,
1961 struct lxc_conf
*lxc_conf
, void *data
)
1963 if (!strequal(key
, "lxc.cgroup.dir"))
1964 return ret_errno(EINVAL
);
1966 if (lxc_config_value_empty(value
))
1967 return clr_config_cgroup_dir(key
, lxc_conf
, NULL
);
1970 return syserror_set(-EINVAL
, "%s paths may not be absolute", key
);
1973 return syserror_set(-EINVAL
, "%s paths may not walk upwards via \"../\"", key
);
1975 return set_config_path_item(&lxc_conf
->cgroup_meta
.dir
, value
);
1978 static int set_config_cgroup_monitor_dir(const char *key
, const char *value
,
1979 struct lxc_conf
*lxc_conf
, void *data
)
1981 if (lxc_config_value_empty(value
))
1982 return clr_config_cgroup_monitor_dir(key
, lxc_conf
, NULL
);
1985 return syserror_set(-EINVAL
, "%s paths may not be absolute", key
);
1988 return syserror_set(-EINVAL
, "%s paths may not walk upwards via \"../\"", key
);
1990 return set_config_path_item(&lxc_conf
->cgroup_meta
.monitor_dir
, value
);
1993 static int set_config_cgroup_monitor_pivot_dir(const char *key
, const char *value
,
1994 struct lxc_conf
*lxc_conf
, void *data
)
1996 if (lxc_config_value_empty(value
))
1997 return clr_config_cgroup_monitor_pivot_dir(key
, lxc_conf
, NULL
);
2000 return syserror_set(-EINVAL
, "%s paths may not be absolute", key
);
2003 return syserror_set(-EINVAL
, "%s paths may not walk upwards via \"../\"", key
);
2005 return set_config_path_item(&lxc_conf
->cgroup_meta
.monitor_pivot_dir
, value
);
2008 static int set_config_cgroup_container_dir(const char *key
, const char *value
,
2009 struct lxc_conf
*lxc_conf
,
2012 if (lxc_config_value_empty(value
))
2013 return clr_config_cgroup_container_dir(key
, lxc_conf
, NULL
);
2016 return syserror_set(-EINVAL
, "%s paths may not be absolute", key
);
2019 return syserror_set(-EINVAL
, "%s paths may not walk upwards via \"../\"", key
);
2021 return set_config_path_item(&lxc_conf
->cgroup_meta
.container_dir
, value
);
2024 static int set_config_cgroup_container_inner_dir(const char *key
,
2026 struct lxc_conf
*lxc_conf
,
2029 if (lxc_config_value_empty(value
))
2030 return clr_config_cgroup_container_inner_dir(key
, lxc_conf
, NULL
);
2033 return syserror_set(-EINVAL
, "%s paths may not be absolute", key
);
2035 if (strchr(value
, '/') || strequal(value
, ".") || strequal(value
, ".."))
2036 return log_error_errno(-EINVAL
, EINVAL
, "lxc.cgroup.dir.container.inner must be a single directory name");
2038 return set_config_string_item(&lxc_conf
->cgroup_meta
.namespace_dir
, value
);
2041 static int set_config_cgroup_relative(const char *key
, const char *value
,
2042 struct lxc_conf
*lxc_conf
, void *data
)
2044 unsigned int converted
;
2047 if (lxc_config_value_empty(value
))
2048 return clr_config_cgroup_relative(key
, lxc_conf
, NULL
);
2050 ret
= lxc_safe_uint(value
, &converted
);
2054 if (converted
== 1) {
2055 lxc_conf
->cgroup_meta
.relative
= true;
2059 if (converted
== 0) {
2060 lxc_conf
->cgroup_meta
.relative
= false;
2064 return ret_errno(EINVAL
);
2067 static bool parse_limit_value(const char **value
, rlim_t
*res
)
2069 char *endptr
= NULL
;
2071 if (strnequal(*value
, "unlimited", STRLITERALLEN("unlimited"))) {
2072 *res
= RLIM_INFINITY
;
2073 *value
+= STRLITERALLEN("unlimited");
2078 *res
= strtoull(*value
, &endptr
, 10);
2079 if (errno
|| !endptr
)
2087 static int set_config_prlimit(const char *key
, const char *value
,
2088 struct lxc_conf
*lxc_conf
, void *data
)
2090 call_cleaner(free_lxc_limit
) struct lxc_limit
*new_lim
= NULL
;
2091 struct rlimit limit
;
2093 struct lxc_limit
*lim
;
2095 if (lxc_config_value_empty(value
))
2096 return lxc_clear_limits(lxc_conf
, key
);
2098 if (!strnequal(key
, "lxc.prlimit.", STRLITERALLEN("lxc.prlimit.")))
2099 return ret_errno(EINVAL
);
2101 key
+= STRLITERALLEN("lxc.prlimit.");
2103 /* soft limit comes first in the value */
2104 if (!parse_limit_value(&value
, &limit_value
))
2105 return ret_errno(EINVAL
);
2107 limit
.rlim_cur
= limit_value
;
2109 /* skip spaces and a colon */
2110 while (isspace(*value
))
2115 else if (*value
) /* any other character is an error here */
2116 return ret_errno(EINVAL
);
2118 while (isspace(*value
))
2121 /* optional hard limit */
2123 if (!parse_limit_value(&value
, &limit_value
))
2124 return ret_errno(EINVAL
);
2126 limit
.rlim_max
= limit_value
;
2128 /* check for trailing garbage */
2129 while (isspace(*value
))
2133 return ret_errno(EINVAL
);
2135 /* a single value sets both hard and soft limit */
2136 limit
.rlim_max
= limit
.rlim_cur
;
2139 /* find existing list element */
2140 list_for_each_entry(lim
, &lxc_conf
->limits
, head
) {
2141 if (!strequal(key
, lim
->resource
))
2148 new_lim
= zalloc(sizeof(*new_lim
));
2150 return ret_errno(ENOMEM
);
2152 new_lim
->resource
= strdup(key
);
2153 if (!new_lim
->resource
)
2154 return ret_errno(ENOMEM
);
2156 new_lim
->limit
= limit
;
2157 list_add_tail(&new_lim
->head
, &lxc_conf
->limits
);
2163 static int set_config_sysctl(const char *key
, const char *value
,
2164 struct lxc_conf
*lxc_conf
, void *data
)
2166 call_cleaner(free_lxc_sysctl
) struct lxc_sysctl
*sysctl_elem
= NULL
;
2167 struct lxc_sysctl
*sysctl
, *nsysctl
;
2169 if (lxc_config_value_empty(value
))
2170 return clr_config_sysctl(key
, lxc_conf
, NULL
);
2172 if (!strnequal(key
, "lxc.sysctl.", STRLITERALLEN("lxc.sysctl.")))
2173 return ret_errno(EINVAL
);
2175 key
+= STRLITERALLEN("lxc.sysctl.");
2176 if (is_empty_string(key
))
2177 return ret_errno(EINVAL
);
2179 /* find existing list element */
2180 list_for_each_entry_safe(sysctl
, nsysctl
, &lxc_conf
->sysctls
, head
) {
2181 __do_free
char *replace_value
= NULL
;
2183 if (!strequal(key
, sysctl
->key
))
2186 replace_value
= strdup(value
);
2188 return ret_errno(EINVAL
);
2190 free(sysctl
->value
);
2191 sysctl
->value
= move_ptr(replace_value
);
2196 sysctl_elem
= zalloc(sizeof(*sysctl_elem
));
2198 return ret_errno(ENOMEM
);
2200 sysctl_elem
->key
= strdup(key
);
2201 if (!sysctl_elem
->key
)
2202 return ret_errno(ENOMEM
);
2204 sysctl_elem
->value
= strdup(value
);
2205 if (!sysctl_elem
->value
)
2206 return ret_errno(ENOMEM
);
2208 list_add_tail(&sysctl_elem
->head
, &lxc_conf
->sysctls
);
2209 move_ptr(sysctl_elem
);
2214 static int set_config_proc(const char *key
, const char *value
,
2215 struct lxc_conf
*lxc_conf
, void *data
)
2217 call_cleaner(free_lxc_proc
) struct lxc_proc
*new_proc
= NULL
;
2220 if (lxc_config_value_empty(value
))
2221 return clr_config_proc(key
, lxc_conf
, NULL
);
2223 if (!strnequal(key
, "lxc.proc.", STRLITERALLEN("lxc.proc.")))
2224 return ret_errno(EINVAL
);
2226 subkey
= key
+ STRLITERALLEN("lxc.proc.");
2227 if (*subkey
== '\0')
2228 return ret_errno(EINVAL
);
2230 new_proc
= zalloc(sizeof(*new_proc
));
2232 return ret_errno(ENOMEM
);
2234 new_proc
->filename
= strdup(subkey
);
2235 if (!new_proc
->filename
)
2236 return ret_errno(ENOMEM
);
2238 new_proc
->value
= strdup(value
);
2239 if (!new_proc
->value
)
2240 return ret_errno(ENOMEM
);
2242 list_add_tail(&new_proc
->head
, &lxc_conf
->procs
);
2248 static int set_config_idmaps(const char *key
, const char *value
,
2249 struct lxc_conf
*lxc_conf
, void *data
)
2251 __do_free
struct id_map
*idmap
= NULL
;
2252 unsigned long hostid
, nsid
, range
;
2256 if (lxc_config_value_empty(value
))
2257 return lxc_clear_idmaps(lxc_conf
);
2259 idmap
= zalloc(sizeof(*idmap
));
2261 return ret_errno(ENOMEM
);
2263 ret
= parse_idmaps(value
, &type
, &nsid
, &hostid
, &range
);
2265 return log_error_errno(-EINVAL
, EINVAL
, "Failed to parse id mappings");
2267 INFO("Read uid map: type %c nsid %lu hostid %lu range %lu", type
, nsid
, hostid
, range
);
2269 idmap
->idtype
= ID_TYPE_UID
;
2270 else if (type
== 'g')
2271 idmap
->idtype
= ID_TYPE_GID
;
2273 return ret_errno(EINVAL
);
2275 idmap
->hostid
= hostid
;
2277 idmap
->range
= range
;
2278 list_add_tail(&idmap
->head
, &lxc_conf
->id_map
);
2280 if (!lxc_conf
->root_nsuid_map
&& idmap
->idtype
== ID_TYPE_UID
)
2281 if (idmap
->nsid
== 0)
2282 lxc_conf
->root_nsuid_map
= idmap
;
2284 if (!lxc_conf
->root_nsgid_map
&& idmap
->idtype
== ID_TYPE_GID
)
2285 if (idmap
->nsid
== 0)
2286 lxc_conf
->root_nsgid_map
= idmap
;
2293 static int set_config_mount_fstab(const char *key
, const char *value
,
2294 struct lxc_conf
*lxc_conf
, void *data
)
2296 if (lxc_config_value_empty(value
)) {
2297 clr_config_mount_fstab(key
, lxc_conf
, NULL
);
2298 return ret_errno(EINVAL
);
2301 return set_config_path_item(&lxc_conf
->fstab
, value
);
2304 static int set_config_mount_auto(const char *key
, const char *value
,
2305 struct lxc_conf
*lxc_conf
, void *data
)
2307 __do_free
char *autos
= NULL
;
2314 } allowed_auto_mounts
[] = {
2315 { "proc", LXC_AUTO_PROC_MASK
, LXC_AUTO_PROC_MIXED
},
2316 { "proc:mixed", LXC_AUTO_PROC_MASK
, LXC_AUTO_PROC_MIXED
},
2317 { "proc:rw", LXC_AUTO_PROC_MASK
, LXC_AUTO_PROC_RW
},
2318 { "sys", LXC_AUTO_SYS_MASK
, LXC_AUTO_SYS_MIXED
},
2319 { "sys:ro", LXC_AUTO_SYS_MASK
, LXC_AUTO_SYS_RO
},
2320 { "sys:mixed", LXC_AUTO_SYS_MASK
, LXC_AUTO_SYS_MIXED
},
2321 { "sys:rw", LXC_AUTO_SYS_MASK
, LXC_AUTO_SYS_RW
},
2322 { "cgroup2", LXC_AUTO_CGROUP_MASK
, LXC_AUTO_CGROUP2_RW
| LXC_AUTO_CGROUP_FORCE
},
2323 { "cgroup2:ro", LXC_AUTO_CGROUP_MASK
, LXC_AUTO_CGROUP2_RO
| LXC_AUTO_CGROUP_FORCE
},
2324 { "cgroup2:force", LXC_AUTO_CGROUP_MASK
, LXC_AUTO_CGROUP2_RW
| LXC_AUTO_CGROUP_FORCE
},
2325 { "cgroup2:ro:force", LXC_AUTO_CGROUP_MASK
, LXC_AUTO_CGROUP2_RO
| LXC_AUTO_CGROUP_FORCE
},
2326 { "cgroup", LXC_AUTO_CGROUP_MASK
, LXC_AUTO_CGROUP_NOSPEC
},
2327 { "cgroup:mixed", LXC_AUTO_CGROUP_MASK
, LXC_AUTO_CGROUP_MIXED
},
2328 { "cgroup:ro", LXC_AUTO_CGROUP_MASK
, LXC_AUTO_CGROUP_RO
},
2329 { "cgroup:rw", LXC_AUTO_CGROUP_MASK
, LXC_AUTO_CGROUP_RW
},
2330 { "cgroup:force", LXC_AUTO_CGROUP_MASK
, LXC_AUTO_CGROUP_NOSPEC
| LXC_AUTO_CGROUP_FORCE
},
2331 { "cgroup:mixed:force", LXC_AUTO_CGROUP_MASK
, LXC_AUTO_CGROUP_MIXED
| LXC_AUTO_CGROUP_FORCE
},
2332 { "cgroup:ro:force", LXC_AUTO_CGROUP_MASK
, LXC_AUTO_CGROUP_RO
| LXC_AUTO_CGROUP_FORCE
},
2333 { "cgroup:rw:force", LXC_AUTO_CGROUP_MASK
, LXC_AUTO_CGROUP_RW
| LXC_AUTO_CGROUP_FORCE
},
2334 { "cgroup-full", LXC_AUTO_CGROUP_MASK
, LXC_AUTO_CGROUP_FULL_NOSPEC
},
2335 { "cgroup-full:mixed", LXC_AUTO_CGROUP_MASK
, LXC_AUTO_CGROUP_FULL_MIXED
},
2336 { "cgroup-full:ro", LXC_AUTO_CGROUP_MASK
, LXC_AUTO_CGROUP_FULL_RO
},
2337 { "cgroup-full:rw", LXC_AUTO_CGROUP_MASK
, LXC_AUTO_CGROUP_FULL_RW
},
2338 { "cgroup-full:force", LXC_AUTO_CGROUP_MASK
, LXC_AUTO_CGROUP_FULL_NOSPEC
| LXC_AUTO_CGROUP_FORCE
},
2339 { "cgroup-full:mixed:force", LXC_AUTO_CGROUP_MASK
, LXC_AUTO_CGROUP_FULL_MIXED
| LXC_AUTO_CGROUP_FORCE
},
2340 { "cgroup-full:ro:force", LXC_AUTO_CGROUP_MASK
, LXC_AUTO_CGROUP_FULL_RO
| LXC_AUTO_CGROUP_FORCE
},
2341 { "cgroup-full:rw:force", LXC_AUTO_CGROUP_MASK
, LXC_AUTO_CGROUP_FULL_RW
| LXC_AUTO_CGROUP_FORCE
},
2342 { "shmounts:", LXC_AUTO_SHMOUNTS_MASK
, LXC_AUTO_SHMOUNTS
},
2344 * For adding anything that is just a single on/off, but has no
2345 * options: keep mask and flag identical and just define the
2346 * enum value as an unused bit so far
2351 if (lxc_config_value_empty(value
)) {
2352 lxc_conf
->auto_mounts
= 0;
2356 autos
= strdup(value
);
2358 return ret_errno(ENOMEM
);
2360 lxc_iterate_parts(token
, autos
, " \t") {
2361 bool is_shmounts
= false;
2363 for (i
= 0; allowed_auto_mounts
[i
].token
; i
++) {
2364 if (strequal(allowed_auto_mounts
[i
].token
, token
))
2367 if (strequal("shmounts:", allowed_auto_mounts
[i
].token
) &&
2368 strnequal("shmounts:", token
, STRLITERALLEN("shmounts:"))) {
2374 if (!allowed_auto_mounts
[i
].token
)
2375 return log_error_errno(-EINVAL
, EINVAL
, "Invalid filesystem to automount \"%s\"", token
);
2377 lxc_conf
->auto_mounts
&= ~allowed_auto_mounts
[i
].mask
;
2378 lxc_conf
->auto_mounts
|= allowed_auto_mounts
[i
].flag
;
2381 __do_free
char *container_path
= NULL
, *host_path
= NULL
;
2384 val
= token
+ STRLITERALLEN("shmounts:");
2386 return log_error_errno(-EINVAL
, EINVAL
, "Failed to copy shmounts host path");
2388 host_path
= strdup(val
);
2390 return log_error_errno(-EINVAL
, EINVAL
, "Failed to copy shmounts host path");
2392 val
= strchr(host_path
, ':');
2393 if (!val
|| *(val
+ 1) == '\0')
2394 val
= "/dev/.lxc-mounts";
2398 container_path
= strdup(val
);
2400 return log_error_errno(-EINVAL
, EINVAL
, "Failed to copy shmounts container path");
2402 free_disarm(lxc_conf
->shmount
.path_host
);
2403 lxc_conf
->shmount
.path_host
= move_ptr(host_path
);
2405 free_disarm(lxc_conf
->shmount
.path_cont
);
2406 lxc_conf
->shmount
.path_cont
= move_ptr(container_path
);
2413 static int set_config_mount(const char *key
, const char *value
,
2414 struct lxc_conf
*lxc_conf
, void *data
)
2416 __do_free
char *mntelem
= NULL
;
2417 __do_free
struct string_entry
*entry
= NULL
;
2419 if (lxc_config_value_empty(value
))
2420 return lxc_clear_mount_entries(lxc_conf
);
2422 entry
= zalloc(sizeof(struct string_entry
));
2424 return ret_errno(ENOMEM
);
2426 mntelem
= strdup(value
);
2428 return ret_errno(ENOMEM
);
2430 entry
->val
= move_ptr(mntelem
);
2431 list_add_tail(&entry
->head
, &lxc_conf
->mount_entries
);
2437 int add_elem_to_mount_list(const char *value
, struct lxc_conf
*lxc_conf
) {
2438 return set_config_mount(NULL
, value
, lxc_conf
, NULL
);
2441 static int add_cap_entry(struct lxc_conf
*conf
, char *caps
, bool keep
)
2446 * In case several capability keep is specified in a single line split
2447 * these caps in a single element for the list.
2449 lxc_iterate_parts(token
, caps
, " \t") {
2450 __do_free
struct cap_entry
*new_cap
= NULL
;
2454 if (strequal(token
, "none")) {
2456 return syserror_set(-EINVAL
, "The \"none\" keyword is only valid when keeping caps");
2458 lxc_clear_config_caps(conf
);
2462 ret
= parse_cap(token
, &cap
);
2465 return syserror_set(-EINVAL
, "Invalid capability specified");
2467 INFO("Ignoring unknown capability \"%s\"", token
);
2471 new_cap
= zalloc(sizeof(struct cap_entry
));
2473 return ret_errno(ENOMEM
);
2475 new_cap
->cap_name
= strdup(token
);
2476 if (!new_cap
->cap_name
)
2477 return ret_errno(ENOMEM
);
2480 list_add_tail(&new_cap
->head
, &conf
->caps
.list
);
2487 static int set_config_cap_keep(const char *key
, const char *value
,
2488 struct lxc_conf
*lxc_conf
, void *data
)
2490 __do_free
char *caps
= NULL
;
2493 if (lxc_config_value_empty(value
))
2494 return lxc_clear_config_caps(lxc_conf
);
2496 caps
= strdup(value
);
2498 return ret_errno(ENOMEM
);
2500 if (!lxc_conf
->caps
.keep
&& !list_empty(&lxc_conf
->caps
.list
))
2501 return syserror_set(-EINVAL
, "Keeping and dropping capabilities are mutually exclusive");
2503 ret
= add_cap_entry(lxc_conf
, caps
, true);
2507 lxc_conf
->caps
.keep
= true;
2511 static int set_config_cap_drop(const char *key
, const char *value
,
2512 struct lxc_conf
*lxc_conf
, void *data
)
2514 __do_free
char *caps
= NULL
;
2517 if (lxc_config_value_empty(value
))
2518 return lxc_clear_config_caps(lxc_conf
);
2520 if (lxc_conf
->caps
.keep
)
2521 return syserror_set(-EINVAL
, "Keeping and dropping capabilities are mutually exclusive");
2523 caps
= strdup(value
);
2525 return ret_errno(ENOMEM
);
2527 ret
= add_cap_entry(lxc_conf
, caps
, false);
2531 lxc_conf
->caps
.keep
= false;
2535 static int set_config_console_path(const char *key
, const char *value
,
2536 struct lxc_conf
*lxc_conf
, void *data
)
2538 return set_config_path_item(&lxc_conf
->console
.path
, value
);
2541 static int set_config_console_rotate(const char *key
, const char *value
,
2542 struct lxc_conf
*lxc_conf
, void *data
)
2546 if (lxc_config_value_empty(value
)) {
2547 lxc_conf
->console
.log_rotate
= 0;
2551 ret
= lxc_safe_uint(value
, &lxc_conf
->console
.log_rotate
);
2553 return ret_errno(EINVAL
);
2555 if (lxc_conf
->console
.log_rotate
> 1)
2556 return log_error_errno(-EINVAL
, EINVAL
, "The \"lxc.console.rotate\" config key can only be set to 0 or 1");
2561 static int set_config_console_logfile(const char *key
, const char *value
,
2562 struct lxc_conf
*lxc_conf
, void *data
)
2564 return set_config_path_item(&lxc_conf
->console
.log_path
, value
);
2567 static int set_config_console_buffer_size(const char *key
, const char *value
,
2568 struct lxc_conf
*lxc_conf
, void *data
)
2572 uint64_t buffer_size
, pgsz
;
2574 if (lxc_config_value_empty(value
)) {
2575 lxc_conf
->console
.buffer_size
= 0;
2579 /* If the user specified "auto" the default log size is 2^17 = 128 Kib */
2580 if (strequal(value
, "auto")) {
2581 lxc_conf
->console
.buffer_size
= 1 << 17;
2585 ret
= parse_byte_size_string(value
, &size
);
2590 return ret_errno(EINVAL
);
2592 /* must be at least a page size */
2593 pgsz
= lxc_getpagesize();
2594 if ((uint64_t)size
< pgsz
) {
2595 NOTICE("Requested ringbuffer size for the console is %lld but must be at least %" PRId64
" bytes. Setting ringbuffer size to %" PRId64
" bytes",
2600 buffer_size
= lxc_find_next_power2((uint64_t)size
);
2601 if (buffer_size
== 0)
2602 return ret_errno(EINVAL
);
2604 if (buffer_size
!= (uint64_t)size
)
2605 NOTICE("Passed size was not a power of 2. Rounding log size to next power of two: %" PRIu64
" bytes", buffer_size
);
2607 lxc_conf
->console
.buffer_size
= buffer_size
;
2612 static int set_config_console_size(const char *key
, const char *value
,
2613 struct lxc_conf
*lxc_conf
, void *data
)
2617 uint64_t log_size
, pgsz
;
2619 if (lxc_config_value_empty(value
)) {
2620 lxc_conf
->console
.log_size
= 0;
2624 /* If the user specified "auto" the default log size is 2^17 = 128 Kib */
2625 if (strequal(value
, "auto")) {
2626 lxc_conf
->console
.log_size
= 1 << 17;
2630 ret
= parse_byte_size_string(value
, &size
);
2632 return ret_errno(EINVAL
);
2635 return ret_errno(EINVAL
);
2637 /* must be at least a page size */
2638 pgsz
= lxc_getpagesize();
2639 if ((uint64_t)size
< pgsz
) {
2640 NOTICE("Requested ringbuffer size for the console is %lld but must be at least %" PRId64
" bytes. Setting ringbuffer size to %" PRId64
" bytes",
2645 log_size
= lxc_find_next_power2((uint64_t)size
);
2647 return ret_errno(EINVAL
);
2649 if (log_size
!= (uint64_t)size
)
2650 NOTICE("Passed size was not a power of 2. Rounding log size to next power of two: %" PRIu64
" bytes", log_size
);
2652 lxc_conf
->console
.log_size
= log_size
;
2658 * If we find a lxc.net.[i].hwaddr or lxc.network.hwaddr in the original config
2659 * file, we expand it in the unexpanded_config, so that after a save_config we
2660 * store the hwaddr for re-use.
2661 * This is only called when reading the config file, not when executing a
2663 * 'x' and 'X' are substituted in-place.
2665 static void update_hwaddr(const char *line
)
2669 line
+= lxc_char_left_gc(line
, strlen(line
));
2673 if (!lxc_config_net_is_hwaddr(line
))
2676 /* Let config_net_hwaddr raise the error. */
2677 p
= strchr(line
, '=');
2688 rand_complete_hwaddr(p
);
2691 int append_unexp_config_line(const char *line
, struct lxc_conf
*conf
)
2694 size_t len
= conf
->unexpanded_len
;
2696 update_hwaddr(line
);
2698 linelen
= strlen(line
);
2699 while (conf
->unexpanded_alloced
<= len
+ linelen
+ 2) {
2702 tmp
= realloc(conf
->unexpanded_config
, conf
->unexpanded_alloced
+ 1024);
2704 return ret_errno(EINVAL
);
2706 if (!conf
->unexpanded_config
)
2709 conf
->unexpanded_config
= tmp
;
2710 conf
->unexpanded_alloced
+= 1024;
2713 memcpy(conf
->unexpanded_config
+ conf
->unexpanded_len
, line
, linelen
);
2714 conf
->unexpanded_len
+= linelen
;
2715 if (line
[linelen
- 1] != '\n')
2716 conf
->unexpanded_config
[conf
->unexpanded_len
++] = '\n';
2717 conf
->unexpanded_config
[conf
->unexpanded_len
] = '\0';
2722 static int do_includedir(const char *dirp
, struct lxc_conf
*lxc_conf
)
2724 __do_closedir
DIR *dir
= NULL
;
2725 struct dirent
*direntp
;
2728 dir
= opendir(dirp
);
2730 return errno
== ENOENT
? 0 : -errno
;
2732 while ((direntp
= readdir(dir
))) {
2734 char path
[PATH_MAX
];
2736 fnam
= direntp
->d_name
;
2737 if (strequal(fnam
, "."))
2740 if (strequal(fnam
, ".."))
2744 if (len
< 6 || !strnequal(fnam
+ len
- 5, ".conf", 5))
2747 len
= strnprintf(path
, sizeof(path
), "%s/%s", dirp
, fnam
);
2749 return ret_errno(EIO
);
2751 ret
= lxc_config_read(path
, lxc_conf
, true);
2759 static int set_config_includefiles(const char *key
, const char *value
,
2760 struct lxc_conf
*lxc_conf
, void *data
)
2762 if (lxc_config_value_empty(value
)) {
2763 clr_config_includefiles(key
, lxc_conf
, NULL
);
2767 if (value
[strlen(value
)-1] == '/' || is_dir(value
))
2768 return do_includedir(value
, lxc_conf
);
2770 return lxc_config_read(value
, lxc_conf
, true);
2773 static int set_config_rootfs_path(const char *key
, const char *value
,
2774 struct lxc_conf
*lxc_conf
, void *data
)
2776 __do_free
char *dup
= NULL
;
2779 const char *container_path
;
2781 if (lxc_config_value_empty(value
)) {
2782 free(lxc_conf
->rootfs
.path
);
2783 lxc_conf
->rootfs
.path
= NULL
;
2787 dup
= strdup(value
);
2789 return ret_errno(ENOMEM
);
2791 /* Split <storage type>:<container path> into <storage type> and
2792 * <container path>. Set "rootfs.bdev_type" to <storage type> and
2793 * "rootfs.path" to <container path>.
2795 tmp
= strchr(dup
, ':');
2799 ret
= set_config_path_item(&lxc_conf
->rootfs
.bdev_type
, dup
);
2801 return ret_errno(ENOMEM
);
2804 container_path
= tmp
;
2806 container_path
= value
;
2809 return set_config_path_item(&lxc_conf
->rootfs
.path
, container_path
);
2812 static int set_config_rootfs_managed(const char *key
, const char *value
,
2813 struct lxc_conf
*lxc_conf
, void *data
)
2815 return set_config_bool_item(&lxc_conf
->rootfs
.managed
, value
, true);
2818 static int set_config_rootfs_mount(const char *key
, const char *value
,
2819 struct lxc_conf
*lxc_conf
, void *data
)
2821 return set_config_path_item(&lxc_conf
->rootfs
.mount
, value
);
2824 static int set_config_rootfs_options(const char *key
, const char *value
,
2825 struct lxc_conf
*lxc_conf
, void *data
)
2827 __do_free
char *dup
= NULL
, *raw_options
= NULL
;
2828 struct lxc_rootfs
*rootfs
= &lxc_conf
->rootfs
;
2829 struct lxc_mount_options
*mnt_opts
= &rootfs
->mnt_opts
;
2832 clr_config_rootfs_options(key
, lxc_conf
, data
);
2833 if (lxc_config_value_empty(value
))
2836 ret
= set_config_string_item(&raw_options
, value
);
2838 return ret_errno(ENOMEM
);
2840 dup
= strdup(value
);
2844 ret
= parse_lxc_mount_attrs(mnt_opts
, dup
);
2848 /* Make sure we're only valid LXC specific mount options. */
2849 if (mnt_opts
->create_dir
|| mnt_opts
->create_file
||
2850 mnt_opts
->optional
|| mnt_opts
->relative
)
2851 return syserror_set(-EINVAL
, "Invalid LXC specific mount option for rootfs mount");
2853 ret
= parse_mount_attrs(mnt_opts
, dup
);
2855 return ret_errno(EINVAL
);
2857 rootfs
->mnt_opts
.raw_options
= move_ptr(raw_options
);
2861 static int set_config_uts_name(const char *key
, const char *value
,
2862 struct lxc_conf
*lxc_conf
, void *data
)
2864 __do_free
struct utsname
*utsname
= NULL
;
2866 if (lxc_config_value_empty(value
)) {
2867 clr_config_uts_name(key
, lxc_conf
, NULL
);
2871 utsname
= zalloc(sizeof(*utsname
));
2873 return ret_errno(ENOMEM
);
2875 if (strlen(value
) >= sizeof(utsname
->nodename
))
2876 return ret_errno(EINVAL
);
2878 (void)strlcpy(utsname
->nodename
, value
, sizeof(utsname
->nodename
));
2879 free(lxc_conf
->utsname
);
2880 lxc_conf
->utsname
= move_ptr(utsname
);
2885 static int set_config_namespace_clone(const char *key
, const char *value
,
2886 struct lxc_conf
*lxc_conf
, void *data
)
2888 __do_free
char *ns
= NULL
;
2892 if (lxc_config_value_empty(value
))
2893 return clr_config_namespace_clone(key
, lxc_conf
, data
);
2895 if (lxc_conf
->ns_keep
!= 0)
2896 return log_error_errno(-EINVAL
, EINVAL
, "Cannot set both \"lxc.namespace.clone\" and \"lxc.namespace.keep\"");
2900 return ret_errno(ENOMEM
);
2902 lxc_iterate_parts(token
, ns
, " \t") {
2903 token
+= lxc_char_left_gc(token
, strlen(token
));
2904 token
[lxc_char_right_gc(token
, strlen(token
))] = '\0';
2905 cloneflag
= lxc_namespace_2_cloneflag(token
);
2907 return ret_errno(EINVAL
);
2908 lxc_conf
->ns_clone
|= cloneflag
;
2914 static int set_config_namespace_keep(const char *key
, const char *value
,
2915 struct lxc_conf
*lxc_conf
, void *data
)
2917 __do_free
char *ns
= NULL
;
2921 if (lxc_config_value_empty(value
))
2922 return clr_config_namespace_keep(key
, lxc_conf
, data
);
2924 if (lxc_conf
->ns_clone
!= 0)
2925 return log_error_errno(-EINVAL
, EINVAL
, "Cannot set both \"lxc.namespace.clone\" and \"lxc.namespace.keep\"");
2929 return ret_errno(ENOMEM
);
2931 lxc_iterate_parts(token
, ns
, " \t") {
2932 token
+= lxc_char_left_gc(token
, strlen(token
));
2933 token
[lxc_char_right_gc(token
, strlen(token
))] = '\0';
2934 cloneflag
= lxc_namespace_2_cloneflag(token
);
2936 return ret_errno(EINVAL
);
2937 lxc_conf
->ns_keep
|= cloneflag
;
2943 static int set_config_time_offset_boot(const char *key
, const char *value
,
2944 struct lxc_conf
*lxc_conf
, void *data
)
2949 char buf
[STRLITERALLEN("ms") + 1];
2951 if (lxc_config_value_empty(value
))
2952 return clr_config_time_offset_boot(key
, lxc_conf
, data
);
2954 ret
= lxc_safe_int64_residual(value
, &offset
, 10, buf
, sizeof(buf
));
2958 unit
= lxc_trim_whitespace_in_place(buf
);
2959 if (strequal(unit
, "h")) {
2960 if (!multiply_overflow(offset
, 3600, &lxc_conf
->timens
.s_boot
))
2961 return ret_errno(EOVERFLOW
);
2962 } else if (strequal(unit
, "m")) {
2963 if (!multiply_overflow(offset
, 60, &lxc_conf
->timens
.s_boot
))
2964 return ret_errno(EOVERFLOW
);
2965 } else if (strequal(unit
, "s")) {
2966 lxc_conf
->timens
.s_boot
= offset
;
2967 } else if (strequal(unit
, "ms")) {
2968 if (!multiply_overflow(offset
, 1000000, &lxc_conf
->timens
.ns_boot
))
2969 return ret_errno(EOVERFLOW
);
2970 } else if (strequal(unit
, "us")) {
2971 if (!multiply_overflow(offset
, 1000, &lxc_conf
->timens
.ns_boot
))
2972 return ret_errno(EOVERFLOW
);
2973 } else if (strequal(unit
, "ns")) {
2974 lxc_conf
->timens
.ns_boot
= offset
;
2976 return ret_errno(EINVAL
);
2982 static int set_config_time_offset_monotonic(const char *key
, const char *value
,
2983 struct lxc_conf
*lxc_conf
, void *data
)
2988 char buf
[STRLITERALLEN("ms") + 1];
2990 if (lxc_config_value_empty(value
))
2991 return clr_config_time_offset_monotonic(key
, lxc_conf
, data
);
2993 ret
= lxc_safe_int64_residual(value
, &offset
, 10, buf
, sizeof(buf
));
2997 unit
= lxc_trim_whitespace_in_place(buf
);
2998 if (strequal(unit
, "h")) {
2999 if (!multiply_overflow(offset
, 3600, &lxc_conf
->timens
.s_monotonic
))
3000 return ret_errno(EOVERFLOW
);
3001 } else if (strequal(unit
, "m")) {
3002 if (!multiply_overflow(offset
, 60, &lxc_conf
->timens
.s_monotonic
))
3003 return ret_errno(EOVERFLOW
);
3004 } else if (strequal(unit
, "s")) {
3005 lxc_conf
->timens
.s_monotonic
= offset
;
3006 } else if (strequal(unit
, "ms")) {
3007 if (!multiply_overflow(offset
, 1000000, &lxc_conf
->timens
.ns_monotonic
))
3008 return ret_errno(EOVERFLOW
);
3009 } else if (strequal(unit
, "us")) {
3010 if (!multiply_overflow(offset
, 1000, &lxc_conf
->timens
.ns_monotonic
))
3011 return ret_errno(EOVERFLOW
);
3012 } else if (strequal(unit
, "ns")) {
3013 lxc_conf
->timens
.ns_monotonic
= offset
;
3015 return ret_errno(EINVAL
);
3021 static int set_config_namespace_share(const char *key
, const char *value
,
3022 struct lxc_conf
*lxc_conf
, void *data
)
3025 const char *namespace;
3027 if (lxc_config_value_empty(value
))
3028 return clr_config_namespace_share(key
, lxc_conf
, data
);
3030 namespace = key
+ STRLITERALLEN("lxc.namespace.share.");
3031 if (is_empty_string(namespace))
3032 return ret_errno(EINVAL
);
3034 ns_idx
= lxc_namespace_2_ns_idx(namespace);
3038 return set_config_string_item(&lxc_conf
->ns_share
[ns_idx
], value
);
3041 struct parse_line_conf
{
3042 struct lxc_conf
*conf
;
3046 static int parse_line(char *buffer
, void *data
)
3048 __do_free
char *linep
= NULL
;
3049 char *dot
, *key
, *line
, *value
;
3051 struct lxc_config_t
*config
;
3054 struct parse_line_conf
*plc
= data
;
3057 return syserror_set(-EINVAL
, "Missing config");
3059 /* If there are newlines in the config file we should keep them. */
3060 empty_line
= lxc_is_line_empty(dup
);
3064 /* We have to dup the buffer otherwise, at the re-exec for reboot we
3065 * modified the original string on the stack by replacing '=' by '\0'
3068 linep
= line
= strdup(dup
);
3070 return ret_errno(ENOMEM
);
3072 if (!plc
->from_include
) {
3073 ret
= append_unexp_config_line(line
, plc
->conf
);
3081 line
+= lxc_char_left_gc(line
, strlen(line
));
3083 /* ignore comments */
3087 /* martian option - don't add it to the config itself */
3088 if (!strnequal(line
, "lxc.", 4))
3091 dot
= strchr(line
, '=');
3093 return log_error_errno(-EINVAL
, EINVAL
, "Invalid configuration line: %s", line
);
3099 key
[lxc_char_right_gc(key
, strlen(key
))] = '\0';
3101 value
+= lxc_char_left_gc(value
, strlen(value
));
3102 value
[lxc_char_right_gc(value
, strlen(value
))] = '\0';
3104 if (*value
== '\'' || *value
== '\"') {
3107 len
= strlen(value
);
3108 if (len
> 1 && value
[len
- 1] == *value
) {
3109 value
[len
- 1] = '\0';
3114 config
= lxc_get_config(key
);
3115 return config
->set(key
, value
, plc
->conf
, NULL
);
3118 static struct new_config_item
*parse_new_conf_line(char *buffer
)
3120 __do_free
char *k
= NULL
, *linep
= NULL
, *v
= NULL
;
3121 __do_free
struct new_config_item
*new = NULL
;
3123 char *dot
, *key
, *line
, *value
;
3125 if (is_empty_string(buffer
))
3126 return log_error_errno(NULL
, EINVAL
, "Empty configuration line");
3128 linep
= line
= strdup(dup
);
3132 line
+= lxc_char_left_gc(line
, strlen(line
));
3134 /* martian option - don't add it to the config itself */
3135 if (!strnequal(line
, "lxc.", 4))
3138 dot
= strchr(line
, '=');
3140 return log_error_errno(NULL
, EINVAL
, "Invalid configuration line: %s", line
);
3146 key
[lxc_char_right_gc(key
, strlen(key
))] = '\0';
3148 value
+= lxc_char_left_gc(value
, strlen(value
));
3149 value
[lxc_char_right_gc(value
, strlen(value
))] = '\0';
3151 if (*value
== '\'' || *value
== '\"') {
3154 len
= strlen(value
);
3155 if (len
> 1 && value
[len
- 1] == *value
) {
3156 value
[len
- 1] = '\0';
3161 new = zalloc(sizeof(struct new_config_item
));
3173 new->key
= move_ptr(k
);
3174 new->val
= move_ptr(v
);
3175 return move_ptr(new);
3178 int lxc_config_read(const char *file
, struct lxc_conf
*conf
, bool from_include
)
3180 struct parse_line_conf plc
;
3183 return syserror_set(-EINVAL
, "Missing config");
3186 plc
.from_include
= from_include
;
3188 /* Catch only the top level config file name in the structure. */
3190 conf
->rcfile
= strdup(file
);
3192 return lxc_file_for_each_line_mmap(file
, parse_line
, &plc
);
3195 int lxc_config_define_add(struct lxc_list
*defines
, char *arg
)
3197 __do_free
struct lxc_list
*dent
= NULL
;
3199 dent
= lxc_list_new();
3201 return ret_errno(ENOMEM
);
3203 dent
->elem
= parse_new_conf_line(arg
);
3205 return ret_errno(ENOMEM
);
3207 lxc_list_add_tail(defines
, move_ptr(dent
));
3212 bool lxc_config_define_load(struct lxc_list
*defines
, struct lxc_container
*c
)
3214 struct lxc_list
*it
;
3217 lxc_list_for_each(it
, defines
) {
3218 struct new_config_item
*new_item
= it
->elem
;
3219 bret
= c
->set_config_item(c
, new_item
->key
, new_item
->val
);
3224 #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
3225 lxc_config_define_free(defines
);
3226 #endif /* !FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION */
3231 void lxc_config_define_free(struct lxc_list
*defines
)
3233 struct lxc_list
*it
, *next
;
3235 lxc_list_for_each_safe(it
, defines
, next
) {
3236 struct new_config_item
*new_item
= it
->elem
;
3237 free(new_item
->key
);
3238 free(new_item
->val
);
3245 int lxc_config_parse_arch(const char *arch
, signed long *persona
)
3247 static struct per_name
{
3251 { "arm", PER_LINUX32
},
3252 { "armel", PER_LINUX32
},
3253 { "armhf", PER_LINUX32
},
3254 { "armv7l", PER_LINUX32
},
3255 { "athlon", PER_LINUX32
},
3256 { "i386", PER_LINUX32
},
3257 { "i486", PER_LINUX32
},
3258 { "i586", PER_LINUX32
},
3259 { "i686", PER_LINUX32
},
3260 { "linux32", PER_LINUX32
},
3261 { "mips", PER_LINUX32
},
3262 { "mipsel", PER_LINUX32
},
3263 { "ppc", PER_LINUX32
},
3264 { "powerpc", PER_LINUX32
},
3265 { "x86", PER_LINUX32
},
3266 { "aarch64", PER_LINUX
},
3267 { "amd64", PER_LINUX
},
3268 { "arm64", PER_LINUX
},
3269 { "linux64", PER_LINUX
},
3270 { "mips64", PER_LINUX
},
3271 { "mips64el", PER_LINUX
},
3272 { "ppc64", PER_LINUX
},
3273 { "ppc64el", PER_LINUX
},
3274 { "ppc64le", PER_LINUX
},
3275 { "powerpc64", PER_LINUX
},
3276 { "riscv64", PER_LINUX
},
3277 { "s390x", PER_LINUX
},
3278 { "x86_64", PER_LINUX
},
3281 for (size_t i
= 0; i
< ARRAY_SIZE(pername
); i
++) {
3282 if (!strequal(pername
[i
].name
, arch
))
3285 *persona
= pername
[i
].per
;
3289 return ret_errno(EINVAL
);
3292 int lxc_fill_elevated_privileges(char *flaglist
, unsigned int *flags
)
3294 unsigned int flags_tmp
= 0;
3300 { "CGROUP", LXC_ATTACH_MOVE_TO_CGROUP
},
3301 { "CAP", LXC_ATTACH_DROP_CAPABILITIES
},
3302 { "LSM", LXC_ATTACH_LSM_EXEC
},
3308 * For the sake of backward compatibility, keep all privileges
3309 * if no specific privileges are specified.
3311 for (unsigned int i
= 0; all_privs
[i
].token
; i
++)
3312 flags_tmp
|= all_privs
[i
].flag
;
3318 lxc_iterate_parts(token
, flaglist
, "|") {
3319 bool valid_token
= false;
3321 for (unsigned int i
= 0; all_privs
[i
].token
; i
++) {
3322 if (!strequal(all_privs
[i
].token
, token
))
3326 flags_tmp
|= all_privs
[i
].flag
;
3330 return syserror_set(-EINVAL
, "Invalid elevated privilege \"%s\" requested", token
);
3337 /* Write out a configuration file. */
3338 int write_config(int fd
, const struct lxc_conf
*conf
)
3341 size_t len
= conf
->unexpanded_len
;
3346 ret
= lxc_write_nointr(fd
, conf
->unexpanded_config
, len
);
3348 return log_error_errno(-errno
, errno
, "Failed to write configuration file");
3353 bool do_append_unexp_config_line(struct lxc_conf
*conf
, const char *key
,
3356 __do_free
char *tmp
= NULL
;
3360 len
= strlen(key
) + strlen(v
) + 4;
3361 tmp
= must_realloc(NULL
, len
);
3363 if (lxc_config_value_empty(v
))
3364 ret
= strnprintf(tmp
, len
, "%s =", key
);
3366 ret
= strnprintf(tmp
, len
, "%s = %s", key
, v
);
3370 /* Save the line verbatim into unexpanded_conf */
3371 if (append_unexp_config_line(tmp
, conf
))
3377 void clear_unexp_config_line(struct lxc_conf
*conf
, const char *key
,
3381 char *lstart
= conf
->unexpanded_config
;
3383 if (!conf
->unexpanded_config
)
3387 lend
= strchr(lstart
, '\n');
3391 lend
= lstart
+ strlen(lstart
);
3395 if (!strnequal(lstart
, key
, strlen(key
))) {
3401 v
= lstart
[strlen(key
)];
3402 if (!isspace(v
) && v
!= '=') {
3408 conf
->unexpanded_len
-= (lend
- lstart
);
3410 if (*lend
== '\0') {
3415 memmove(lstart
, lend
, strlen(lend
) + 1);
3419 bool clone_update_unexp_ovl_paths(struct lxc_conf
*conf
, const char *oldpath
,
3420 const char *newpath
, const char *oldname
,
3421 const char *newname
, const char *ovldir
)
3423 __do_free
char *newdir
= NULL
, *olddir
= NULL
;
3424 char *lstart
= conf
->unexpanded_config
;
3425 const char *key
= "lxc.mount.entry";
3428 size_t newdirlen
, olddirlen
;
3430 olddirlen
= strlen(ovldir
) + strlen(oldpath
) + strlen(oldname
) + 2;
3431 olddir
= must_realloc(NULL
, olddirlen
+ 1);
3432 ret
= strnprintf(olddir
, olddirlen
+ 1, "%s=%s/%s", ovldir
, oldpath
, oldname
);
3436 newdirlen
= strlen(ovldir
) + strlen(newpath
) + strlen(newname
) + 2;
3437 newdir
= must_realloc(NULL
, newdirlen
+ 1);
3438 ret
= strnprintf(newdir
, newdirlen
+ 1, "%s=%s/%s", ovldir
, newpath
, newname
);
3442 if (!conf
->unexpanded_config
)
3446 lend
= strchr(lstart
, '\n');
3448 lend
= lstart
+ strlen(lstart
);
3452 if (!strnequal(lstart
, key
, strlen(key
)))
3455 p
= strchr(lstart
+ strlen(key
), '=');
3466 /* Whenever a lxc.mount.entry entry is found in a line we check
3467 * if the substring "overlay" is present before doing any
3468 * further work. We check for "overlay" because substrings need
3469 * to have at least one space before them in a valid overlay
3470 * lxc.mount.entry (/A B overlay). When the space before is
3471 * missing it is very likely that these substrings are part of a
3472 * path or something else. (Checking q >= lend ensures that we
3473 * only count matches in the current line.) */
3474 q
= strstr(p
, " overlay");
3475 if (!q
|| q
>= lend
)
3478 if (!(q
= strstr(p
, olddir
)) || (q
>= lend
))
3481 /* replace the olddir with newdir */
3482 if (olddirlen
>= newdirlen
) {
3483 size_t diff
= olddirlen
- newdirlen
;
3484 memcpy(q
, newdir
, newdirlen
);
3486 if (olddirlen
!= newdirlen
) {
3487 memmove(q
+ newdirlen
, q
+ newdirlen
+ diff
,
3488 strlen(q
) - newdirlen
- diff
+ 1);
3490 conf
->unexpanded_len
-= diff
;
3494 size_t diff
= newdirlen
- olddirlen
;
3495 size_t oldlen
= conf
->unexpanded_len
;
3496 size_t newlen
= oldlen
+ diff
;
3497 size_t poffset
= q
- conf
->unexpanded_config
;
3499 new = realloc(conf
->unexpanded_config
, newlen
+ 1);
3503 conf
->unexpanded_len
= newlen
;
3504 conf
->unexpanded_alloced
= newlen
+ 1;
3505 new[newlen
- 1] = '\0';
3506 lend
= new + (lend
- conf
->unexpanded_config
);
3508 /* Move over the remainder to make room for the newdir.
3510 memmove(new + poffset
+ newdirlen
,
3511 new + poffset
+ olddirlen
,
3512 oldlen
- poffset
- olddirlen
+ 1);
3513 conf
->unexpanded_config
= new;
3515 memcpy(new + poffset
, newdir
, newdirlen
);
3526 bool clone_update_unexp_hooks(struct lxc_conf
*conf
, const char *oldpath
,
3527 const char *newpath
, const char *oldname
,
3528 const char *newname
)
3530 __do_free
char *newdir
= NULL
, *olddir
= NULL
;
3531 char *lstart
= conf
->unexpanded_config
;
3532 const char *key
= "lxc.hook";
3535 size_t newdirlen
, olddirlen
;
3537 olddirlen
= strlen(oldpath
) + strlen(oldname
) + 1;
3538 olddir
= must_realloc(NULL
, olddirlen
+ 1);
3539 ret
= strnprintf(olddir
, olddirlen
+ 1, "%s/%s", oldpath
, oldname
);
3543 newdirlen
= strlen(newpath
) + strlen(newname
) + 1;
3544 newdir
= must_realloc(NULL
, newdirlen
+ 1);
3545 ret
= strnprintf(newdir
, newdirlen
+ 1, "%s/%s", newpath
, newname
);
3549 if (!conf
->unexpanded_config
)
3553 lend
= strchr(lstart
, '\n');
3555 lend
= lstart
+ strlen(lstart
);
3559 if (!strnequal(lstart
, key
, strlen(key
)))
3562 p
= strchr(lstart
+ strlen(key
), '=');
3573 if (!strnequal(p
, olddir
, strlen(olddir
)))
3576 /* replace the olddir with newdir */
3577 if (olddirlen
>= newdirlen
) {
3578 size_t diff
= olddirlen
- newdirlen
;
3579 memcpy(p
, newdir
, newdirlen
);
3581 if (olddirlen
!= newdirlen
) {
3582 memmove(p
+ newdirlen
, p
+ newdirlen
+ diff
,
3583 strlen(p
) - newdirlen
- diff
+ 1);
3585 conf
->unexpanded_len
-= diff
;
3589 size_t diff
= newdirlen
- olddirlen
;
3590 size_t oldlen
= conf
->unexpanded_len
;
3591 size_t newlen
= oldlen
+ diff
;
3592 size_t poffset
= p
- conf
->unexpanded_config
;
3594 new = realloc(conf
->unexpanded_config
, newlen
+ 1);
3598 conf
->unexpanded_len
= newlen
;
3599 conf
->unexpanded_alloced
= newlen
+ 1;
3600 new[newlen
- 1] = '\0';
3601 lend
= new + (lend
- conf
->unexpanded_config
);
3603 /* Move over the remainder to make room for the newdir.
3605 memmove(new + poffset
+ newdirlen
,
3606 new + poffset
+ olddirlen
,
3607 oldlen
- poffset
- olddirlen
+ 1);
3608 conf
->unexpanded_config
= new;
3610 memcpy(new + poffset
, newdir
, newdirlen
);
3624 ERROR("Error writing to new config"); \
3629 /* This is called only from clone. We wish to update all hwaddrs in the
3630 * unexpanded config file. We can't/don't want to update any which come from
3631 * lxc.includes (there shouldn't be any).
3632 * We can't just walk the c->lxc-conf->network list because that includes netifs
3633 * from the include files. So we update the ones which we find in the unexp
3634 * config file, then find the original macaddr in the conf->network, and update
3635 * that to the same value.
3637 bool network_new_hwaddrs(struct lxc_conf
*conf
)
3639 char *lend
, *p
, *p2
;
3640 char *lstart
= conf
->unexpanded_config
;
3642 if (!conf
->unexpanded_config
)
3646 char newhwaddr
[18], oldhwaddr
[17];
3647 struct lxc_netdev
*netdev
;
3649 lend
= strchr(lstart
, '\n');
3651 lend
= lstart
+ strlen(lstart
);
3655 if (!lxc_config_net_is_hwaddr(lstart
)) {
3660 p
= strchr(lstart
, '=');
3673 while (*p2
&& !isblank(*p2
) && *p2
!= '\n')
3676 if ((p2
- p
) != 17) {
3677 WARN("Bad hwaddr entry");
3682 memcpy(oldhwaddr
, p
, 17);
3684 if (!new_hwaddr(newhwaddr
))
3687 memcpy(p
, newhwaddr
, 17);
3688 list_for_each_entry(netdev
, &conf
->netdevs
, head
) {
3689 if (netdev
->hwaddr
&& memcmp(oldhwaddr
, netdev
->hwaddr
, 17) == 0)
3690 memcpy(netdev
->hwaddr
, newhwaddr
, 17);
3699 static int set_config_ephemeral(const char *key
, const char *value
,
3700 struct lxc_conf
*lxc_conf
, void *data
)
3704 if (lxc_config_value_empty(value
)) {
3705 lxc_conf
->ephemeral
= 0;
3709 ret
= lxc_safe_uint(value
, &lxc_conf
->ephemeral
);
3713 if (lxc_conf
->ephemeral
> 1)
3714 return ret_errno(EINVAL
);
3719 static int set_config_log_syslog(const char *key
, const char *value
,
3720 struct lxc_conf
*lxc_conf
, void *data
)
3724 if (lxc_conf
->syslog
)
3725 free_disarm(lxc_conf
->syslog
);
3727 if (lxc_config_value_empty(value
))
3730 facility
= lxc_syslog_priority_to_int(value
);
3731 if (facility
== -EINVAL
)
3732 return ret_errno(EINVAL
);
3734 lxc_log_syslog(facility
);
3736 return set_config_string_item(&lxc_conf
->syslog
, value
);
3739 static int set_config_no_new_privs(const char *key
, const char *value
,
3740 struct lxc_conf
*lxc_conf
, void *data
)
3745 if (lxc_config_value_empty(value
)) {
3746 lxc_conf
->no_new_privs
= false;
3750 ret
= lxc_safe_uint(value
, &v
);
3755 return ret_errno(EINVAL
);
3757 lxc_conf
->no_new_privs
= v
? true : false;
3762 /* Callbacks to get configuration items. */
3763 static int get_config_personality(const char *key
, char *retv
, int inlen
,
3764 struct lxc_conf
*c
, void *data
)
3771 memset(retv
, 0, inlen
);
3775 switch (c
->personality
) {
3777 strprint(retv
, inlen
, "i686");
3780 strprint(retv
, inlen
, "x86_64");
3789 static int get_config_pty_max(const char *key
, char *retv
, int inlen
,
3790 struct lxc_conf
*c
, void *data
)
3792 return lxc_get_conf_size_t(c
, retv
, inlen
, c
->pty_max
);
3795 static int get_config_tty_max(const char *key
, char *retv
, int inlen
,
3796 struct lxc_conf
*c
, void *data
)
3798 return lxc_get_conf_size_t(c
, retv
, inlen
, c
->ttys
.max
);
3801 static int get_config_tty_dir(const char *key
, char *retv
, int inlen
,
3802 struct lxc_conf
*c
, void *data
)
3804 return lxc_get_conf_str(retv
, inlen
, c
->ttys
.dir
);
3807 static int get_config_apparmor_profile(const char *key
, char *retv
, int inlen
,
3808 struct lxc_conf
*c
, void *data
)
3811 return lxc_get_conf_str(retv
, inlen
, c
->lsm_aa_profile
);
3813 return syserror_set(-EINVAL
, "Built without AppArmor support");
3817 static int get_config_apparmor_allow_incomplete(const char *key
, char *retv
,
3818 int inlen
, struct lxc_conf
*c
,
3822 return lxc_get_conf_int(c
, retv
, inlen
, c
->lsm_aa_allow_incomplete
);
3824 return syserror_set(-EINVAL
, "Built without AppArmor support");
3828 static int get_config_apparmor_allow_nesting(const char *key
, char *retv
,
3829 int inlen
, struct lxc_conf
*c
,
3833 return lxc_get_conf_int(c
, retv
, inlen
, c
->lsm_aa_allow_nesting
);
3835 return syserror_set(-EINVAL
, "Built without AppArmor support");
3839 static int get_config_apparmor_raw(const char *key
, char *retv
,
3840 int inlen
, struct lxc_conf
*c
,
3845 struct string_entry
*entry
;
3851 memset(retv
, 0, inlen
);
3853 list_for_each_entry(entry
, &c
->lsm_aa_raw
, head
) {
3854 strprint(retv
, inlen
, "%s\n", entry
->val
);
3859 return syserror_set(-EINVAL
, "Built without AppArmor support");
3863 static int get_config_selinux_context(const char *key
, char *retv
, int inlen
,
3864 struct lxc_conf
*c
, void *data
)
3867 return lxc_get_conf_str(retv
, inlen
, c
->lsm_se_context
);
3869 return syserror_set(-EINVAL
, "Built without SELinux support");
3873 static int get_config_selinux_context_keyring(const char *key
, char *retv
, int inlen
,
3874 struct lxc_conf
*c
, void *data
)
3877 return lxc_get_conf_str(retv
, inlen
, c
->lsm_se_keyring_context
);
3879 return syserror_set(-EINVAL
, "Built without SELinux support");
3883 static int get_config_keyring_session(const char *key
, char *retv
, int inlen
,
3884 struct lxc_conf
*c
, void *data
)
3886 return lxc_get_conf_bool(c
, retv
, inlen
, c
->keyring_disable_session
);
3890 /* If you ask for a specific cgroup value, i.e. lxc.cgroup.devices.list, then
3891 * just the value(s) will be printed. Since there still could be more than one,
3892 * it is newline-separated.
3893 * (Maybe that's ambiguous, since some values, i.e. devices.list, will already
3895 * If you ask for 'lxc.cgroup", then all cgroup entries will be printed, in
3896 * 'lxc.cgroup.subsystem.key = value' format.
3898 static int __get_config_cgroup_controller(const char *key
, char *retv
,
3899 int inlen
, struct lxc_conf
*c
,
3903 bool get_all
= false;
3905 size_t namespaced_token_len
;
3906 char *global_token
, *namespaced_token
;
3907 struct list_head
*list
;
3908 struct lxc_cgroup
*cgroup
;
3913 memset(retv
, 0, inlen
);
3915 if (version
== CGROUP2_SUPER_MAGIC
) {
3916 global_token
= "lxc.cgroup2";
3917 namespaced_token
= "lxc.cgroup2.";
3918 namespaced_token_len
= STRLITERALLEN("lxc.cgroup2.");
3920 } else if (version
== CGROUP_SUPER_MAGIC
) {
3921 global_token
= "lxc.cgroup";
3922 namespaced_token
= "lxc.cgroup.";
3923 namespaced_token_len
= STRLITERALLEN("lxc.cgroup.");
3926 return ret_errno(EINVAL
);
3929 if (strequal(key
, global_token
))
3931 else if (strnequal(key
, namespaced_token
, namespaced_token_len
))
3932 key
+= namespaced_token_len
;
3934 return ret_errno(EINVAL
);
3936 list_for_each_entry(cgroup
, list
, head
) {
3938 if (version
!= cgroup
->version
)
3941 strprint(retv
, inlen
, "%s.%s = %s\n", global_token
,
3942 cgroup
->subsystem
, cgroup
->value
);
3943 } else if (strequal(cgroup
->subsystem
, key
)) {
3944 strprint(retv
, inlen
, "%s\n", cgroup
->value
);
3951 static int get_config_cgroup_controller(const char *key
, char *retv
, int inlen
,
3952 struct lxc_conf
*c
, void *data
)
3954 return __get_config_cgroup_controller(key
, retv
, inlen
, c
,
3955 CGROUP_SUPER_MAGIC
);
3958 static int get_config_cgroup2_controller(const char *key
, char *retv
, int inlen
,
3959 struct lxc_conf
*c
, void *data
)
3961 return __get_config_cgroup_controller(key
, retv
, inlen
, c
,
3962 CGROUP2_SUPER_MAGIC
);
3965 static int get_config_cgroup_dir(const char *key
, char *retv
, int inlen
,
3966 struct lxc_conf
*lxc_conf
, void *data
)
3971 if (!strequal(key
, "lxc.cgroup.dir"))
3972 return ret_errno(EINVAL
);
3977 memset(retv
, 0, inlen
);
3979 strprint(retv
, inlen
, "%s", lxc_conf
->cgroup_meta
.dir
);
3984 static int get_config_cgroup_monitor_dir(const char *key
, char *retv
, int inlen
,
3985 struct lxc_conf
*lxc_conf
, void *data
)
3993 memset(retv
, 0, inlen
);
3995 strprint(retv
, inlen
, "%s", lxc_conf
->cgroup_meta
.monitor_dir
);
4000 static int get_config_cgroup_monitor_pivot_dir(const char *key
, char *retv
, int inlen
,
4001 struct lxc_conf
*lxc_conf
, void *data
)
4009 memset(retv
, 0, inlen
);
4011 strprint(retv
, inlen
, "%s", lxc_conf
->cgroup_meta
.monitor_pivot_dir
);
4016 static int get_config_cgroup_container_dir(const char *key
, char *retv
,
4018 struct lxc_conf
*lxc_conf
,
4027 memset(retv
, 0, inlen
);
4029 strprint(retv
, inlen
, "%s", lxc_conf
->cgroup_meta
.container_dir
);
4034 static int get_config_cgroup_container_inner_dir(const char *key
, char *retv
,
4036 struct lxc_conf
*lxc_conf
,
4045 memset(retv
, 0, inlen
);
4047 strprint(retv
, inlen
, "%s", lxc_conf
->cgroup_meta
.namespace_dir
);
4052 static inline int get_config_cgroup_relative(const char *key
, char *retv
,
4053 int inlen
, struct lxc_conf
*lxc_conf
,
4056 return lxc_get_conf_int(lxc_conf
, retv
, inlen
,
4057 lxc_conf
->cgroup_meta
.relative
);
4060 static int get_config_idmaps(const char *key
, char *retv
, int inlen
,
4061 struct lxc_conf
*c
, void *data
)
4064 int len
, listlen
, ret
;
4066 /* "u 1000 1000000 65536"
4068 * let's render this as
4086 #define __LXC_IDMAP_STR_BUF (3 * INTTYPE_TO_STRLEN(uint32_t) + 3 + 1 + 1)
4087 char buf
[__LXC_IDMAP_STR_BUF
];
4092 memset(retv
, 0, inlen
);
4094 listlen
= list_len(map
, &c
->id_map
, head
);
4095 list_for_each_entry(map
, &c
->id_map
, head
) {
4096 ret
= strnprintf(buf
, sizeof(buf
), "%c %lu %lu %lu",
4097 (map
->idtype
== ID_TYPE_UID
) ? 'u' : 'g',
4098 map
->nsid
, map
->hostid
, map
->range
);
4100 return ret_errno(EIO
);
4102 strprint(retv
, inlen
, "%s%s", buf
, (listlen
-- > 1) ? "\n" : "");
4108 static int get_config_log_level(const char *key
, char *retv
, int inlen
,
4109 struct lxc_conf
*c
, void *data
)
4112 v
= lxc_log_priority_to_string(c
->loglevel
);
4113 return lxc_get_conf_str(retv
, inlen
, v
);
4116 static int get_config_log_file(const char *key
, char *retv
, int inlen
,
4117 struct lxc_conf
*c
, void *data
)
4119 return lxc_get_conf_str(retv
, inlen
, c
->logfile
);
4122 static int get_config_mount_fstab(const char *key
, char *retv
, int inlen
,
4123 struct lxc_conf
*c
, void *data
)
4125 return lxc_get_conf_str(retv
, inlen
, c
->fstab
);
4128 static int get_config_mount_auto(const char *key
, char *retv
, int inlen
,
4129 struct lxc_conf
*c
, void *data
)
4131 int len
, fulllen
= 0;
4132 const char *sep
= "";
4137 memset(retv
, 0, inlen
);
4139 if (!(c
->auto_mounts
& LXC_AUTO_ALL_MASK
))
4142 switch (c
->auto_mounts
& LXC_AUTO_PROC_MASK
) {
4143 case LXC_AUTO_PROC_MIXED
:
4144 strprint(retv
, inlen
, "%sproc:mixed", sep
);
4147 case LXC_AUTO_PROC_RW
:
4148 strprint(retv
, inlen
, "%sproc:rw", sep
);
4155 switch (c
->auto_mounts
& LXC_AUTO_SYS_MASK
) {
4156 case LXC_AUTO_SYS_RO
:
4157 strprint(retv
, inlen
, "%ssys:ro", sep
);
4160 case LXC_AUTO_SYS_RW
:
4161 strprint(retv
, inlen
, "%ssys:rw", sep
);
4164 case LXC_AUTO_SYS_MIXED
:
4165 strprint(retv
, inlen
, "%ssys:mixed", sep
);
4172 switch (c
->auto_mounts
& LXC_AUTO_CGROUP_MASK
) {
4173 case LXC_AUTO_CGROUP_NOSPEC
:
4174 strprint(retv
, inlen
, "%scgroup", sep
);
4176 case LXC_AUTO_CGROUP_MIXED
:
4177 strprint(retv
, inlen
, "%scgroup:mixed", sep
);
4179 case LXC_AUTO_CGROUP_RO
:
4180 strprint(retv
, inlen
, "%scgroup:ro", sep
);
4182 case LXC_AUTO_CGROUP_RW
:
4183 strprint(retv
, inlen
, "%scgroup:rw", sep
);
4185 case LXC_AUTO_CGROUP_FULL_NOSPEC
:
4186 strprint(retv
, inlen
, "%scgroup-full", sep
);
4188 case LXC_AUTO_CGROUP_FULL_MIXED
:
4189 strprint(retv
, inlen
, "%scgroup-full:mixed", sep
);
4191 case LXC_AUTO_CGROUP_FULL_RO
:
4192 strprint(retv
, inlen
, "%scgroup-full:ro", sep
);
4194 case LXC_AUTO_CGROUP_FULL_RW
:
4195 strprint(retv
, inlen
, "%scgroup-full:rw", sep
);
4204 static int get_config_mount(const char *key
, char *retv
, int inlen
,
4205 struct lxc_conf
*c
, void *data
)
4207 int len
, fulllen
= 0;
4208 struct string_entry
*entry
;
4213 memset(retv
, 0, inlen
);
4215 list_for_each_entry(entry
, &c
->mount_entries
, head
) {
4216 strprint(retv
, inlen
, "%s\n", entry
->val
);
4222 static int get_config_rootfs_path(const char *key
, char *retv
, int inlen
,
4223 struct lxc_conf
*c
, void *data
)
4225 return lxc_get_conf_str(retv
, inlen
, c
->rootfs
.path
);
4228 static int get_config_rootfs_managed(const char *key
, char *retv
, int inlen
,
4229 struct lxc_conf
*c
, void *data
)
4231 return lxc_get_conf_bool(c
, retv
, inlen
, c
->rootfs
.managed
);
4234 static int get_config_rootfs_mount(const char *key
, char *retv
, int inlen
,
4235 struct lxc_conf
*c
, void *data
)
4237 return lxc_get_conf_str(retv
, inlen
, c
->rootfs
.mount
);
4240 static int get_config_rootfs_options(const char *key
, char *retv
, int inlen
,
4241 struct lxc_conf
*c
, void *data
)
4243 return lxc_get_conf_str(retv
, inlen
, c
->rootfs
.mnt_opts
.raw_options
);
4246 static int get_config_uts_name(const char *key
, char *retv
, int inlen
,
4247 struct lxc_conf
*c
, void *data
)
4249 return lxc_get_conf_str(
4251 c
->utsname
? c
->utsname
->nodename
: NULL
);
4254 static int get_config_hooks(const char *key
, char *retv
, int inlen
,
4255 struct lxc_conf
*c
, void *data
)
4258 int len
, fulllen
= 0, found
= -1;
4259 struct string_entry
*entry
;
4262 subkey
= strchr(key
, '.');
4264 return ret_errno(EINVAL
);
4266 subkey
= strchr(subkey
+ 1, '.');
4268 return ret_errno(EINVAL
);
4270 if (*subkey
== '\0')
4271 return ret_errno(EINVAL
);
4273 for (i
= 0; i
< NUM_LXC_HOOKS
; i
++) {
4274 if (strequal(lxchook_names
[i
], subkey
)) {
4281 return ret_errno(EINVAL
);
4286 memset(retv
, 0, inlen
);
4288 list_for_each_entry(entry
, &c
->hooks
[found
], head
) {
4289 strprint(retv
, inlen
, "%s\n", entry
->val
);
4295 static int get_config_hooks_version(const char *key
, char *retv
, int inlen
,
4296 struct lxc_conf
*c
, void *data
)
4298 return lxc_get_conf_int(c
, retv
, inlen
, c
->hooks_version
);
4301 static int get_config_net(const char *key
, char *retv
, int inlen
,
4302 struct lxc_conf
*c
, void *data
)
4304 int len
, fulllen
= 0;
4305 struct lxc_netdev
*netdev
;
4310 memset(retv
, 0, inlen
);
4312 list_for_each_entry(netdev
, &c
->netdevs
, head
) {
4313 const char *t
= lxc_net_type_to_str(netdev
->type
);
4314 strprint(retv
, inlen
, "%s\n", t
? t
: "(invalid)");
4320 static int get_config_cap_drop(const char *key
, char *retv
, int inlen
,
4321 struct lxc_conf
*c
, void *data
)
4323 int len
, fulllen
= 0;
4324 struct cap_entry
*cap
;
4329 memset(retv
, 0, inlen
);
4331 list_for_each_entry(cap
, &c
->caps
.list
, head
) {
4332 strprint(retv
, inlen
, "%s\n", cap
->cap_name
);
4338 static int get_config_cap_keep(const char *key
, char *retv
, int inlen
,
4339 struct lxc_conf
*c
, void *data
)
4341 int len
, fulllen
= 0;
4342 struct cap_entry
*cap
;
4347 memset(retv
, 0, inlen
);
4349 list_for_each_entry(cap
, &c
->caps
.list
, head
) {
4350 strprint(retv
, inlen
, "%s\n", cap
->cap_name
);
4356 static int get_config_console_path(const char *key
, char *retv
, int inlen
,
4357 struct lxc_conf
*c
, void *data
)
4359 return lxc_get_conf_str(retv
, inlen
, c
->console
.path
);
4362 static int get_config_console_logfile(const char *key
, char *retv
, int inlen
,
4363 struct lxc_conf
*c
, void *data
)
4365 return lxc_get_conf_str(retv
, inlen
, c
->console
.log_path
);
4368 static int get_config_console_rotate(const char *key
, char *retv
, int inlen
,
4369 struct lxc_conf
*c
, void *data
)
4371 return lxc_get_conf_int(c
, retv
, inlen
, c
->console
.log_rotate
);
4375 static int get_config_console_buffer_size(const char *key
, char *retv
,
4376 int inlen
, struct lxc_conf
*c
,
4379 return lxc_get_conf_uint64(c
, retv
, inlen
, c
->console
.buffer_size
);
4382 static int get_config_console_size(const char *key
, char *retv
, int inlen
,
4383 struct lxc_conf
*c
, void *data
)
4385 return lxc_get_conf_uint64(c
, retv
, inlen
, c
->console
.log_size
);
4388 static int get_config_seccomp_allow_nesting(const char *key
, char *retv
,
4389 int inlen
, struct lxc_conf
*c
,
4393 return lxc_get_conf_int(c
, retv
, inlen
, c
->seccomp
.allow_nesting
);
4395 return ret_errno(ENOSYS
);
4399 static int get_config_seccomp_notify_cookie(const char *key
, char *retv
, int inlen
,
4400 struct lxc_conf
*c
, void *data
)
4402 #ifdef HAVE_SECCOMP_NOTIFY
4403 return lxc_get_conf_str(retv
, inlen
, c
->seccomp
.notifier
.cookie
);
4405 return ret_errno(ENOSYS
);
4409 static int get_config_seccomp_notify_proxy(const char *key
, char *retv
, int inlen
,
4410 struct lxc_conf
*c
, void *data
)
4412 #ifdef HAVE_SECCOMP_NOTIFY
4413 return lxc_get_conf_str(retv
, inlen
,
4414 (c
->seccomp
.notifier
.proxy_addr
.sun_path
[0]) == '/'
4415 ? &c
->seccomp
.notifier
.proxy_addr
.sun_path
[0]
4416 : &c
->seccomp
.notifier
.proxy_addr
.sun_path
[1]);
4418 return ret_errno(ENOSYS
);
4422 static int get_config_seccomp_profile(const char *key
, char *retv
, int inlen
,
4423 struct lxc_conf
*c
, void *data
)
4426 return lxc_get_conf_str(retv
, inlen
, c
->seccomp
.seccomp
);
4428 return ret_errno(ENOSYS
);
4432 static int get_config_autodev(const char *key
, char *retv
, int inlen
,
4433 struct lxc_conf
*c
, void *data
)
4435 return lxc_get_conf_int(c
, retv
, inlen
, c
->autodev
);
4438 static int get_config_autodev_tmpfs_size(const char *key
, char *retv
, int inlen
,
4439 struct lxc_conf
*c
, void *data
)
4441 return lxc_get_conf_int(c
, retv
, inlen
, c
->autodevtmpfssize
);
4444 static int get_config_signal_halt(const char *key
, char *retv
, int inlen
,
4445 struct lxc_conf
*c
, void *data
)
4447 return lxc_get_conf_int(c
, retv
, inlen
, c
->haltsignal
);
4450 static int get_config_signal_reboot(const char *key
, char *retv
, int inlen
,
4451 struct lxc_conf
*c
, void *data
)
4453 return lxc_get_conf_int(c
, retv
, inlen
, c
->rebootsignal
);
4456 static int get_config_signal_stop(const char *key
, char *retv
, int inlen
,
4457 struct lxc_conf
*c
, void *data
)
4459 return lxc_get_conf_int(c
, retv
, inlen
, c
->stopsignal
);
4462 static int get_config_start(const char *key
, char *retv
, int inlen
,
4463 struct lxc_conf
*c
, void *data
)
4465 if (strequal(key
+ 10, "auto"))
4466 return lxc_get_conf_int(c
, retv
, inlen
, c
->start_auto
);
4467 else if (strequal(key
+ 10, "delay"))
4468 return lxc_get_conf_int(c
, retv
, inlen
, c
->start_delay
);
4469 else if (strequal(key
+ 10, "order"))
4470 return lxc_get_conf_int(c
, retv
, inlen
, c
->start_order
);
4472 return ret_errno(EINVAL
);
4475 static int get_config_log_syslog(const char *key
, char *retv
, int inlen
,
4476 struct lxc_conf
*c
, void *data
)
4478 return lxc_get_conf_str(retv
, inlen
, c
->syslog
);
4481 static int get_config_monitor(const char *key
, char *retv
, int inlen
,
4482 struct lxc_conf
*c
, void *data
)
4484 return lxc_get_conf_int(c
, retv
, inlen
, c
->monitor_unshare
);
4487 static int get_config_monitor_signal_pdeath(const char *key
, char *retv
,
4488 int inlen
, struct lxc_conf
*c
,
4491 return lxc_get_conf_int(c
, retv
, inlen
, c
->monitor_signal_pdeath
);
4494 static int get_config_group(const char *key
, char *retv
, int inlen
,
4495 struct lxc_conf
*c
, void *data
)
4497 int len
, fulllen
= 0;
4498 struct string_entry
*entry
;
4503 memset(retv
, 0, inlen
);
4505 list_for_each_entry(entry
, &c
->groups
, head
) {
4506 strprint(retv
, inlen
, "%s\n", entry
->val
);
4512 static int get_config_environment(const char *key
, char *retv
, int inlen
,
4513 struct lxc_conf
*c
, void *data
)
4515 int len
, fulllen
= 0;
4516 struct environment_entry
*env
;
4521 memset(retv
, 0, inlen
);
4523 list_for_each_entry(env
, &c
->environment
, head
) {
4524 strprint(retv
, inlen
, "%s=%s\n", env
->key
, env
->val
);
4530 static int get_config_execute_cmd(const char *key
, char *retv
, int inlen
,
4531 struct lxc_conf
*c
, void *data
)
4533 return lxc_get_conf_str(retv
, inlen
, c
->execute_cmd
);
4536 static int get_config_init_cmd(const char *key
, char *retv
, int inlen
,
4537 struct lxc_conf
*c
, void *data
)
4539 return lxc_get_conf_str(retv
, inlen
, c
->init_cmd
);
4542 static int get_config_init_cwd(const char *key
, char *retv
, int inlen
,
4543 struct lxc_conf
*c
, void *data
)
4545 return lxc_get_conf_str(retv
, inlen
, c
->init_cwd
);
4548 static int get_config_init_uid(const char *key
, char *retv
, int inlen
,
4549 struct lxc_conf
*c
, void *data
)
4551 return lxc_get_conf_int(c
, retv
, inlen
, c
->init_uid
);
4554 static int get_config_init_gid(const char *key
, char *retv
, int inlen
,
4555 struct lxc_conf
*c
, void *data
)
4557 return lxc_get_conf_int(c
, retv
, inlen
, c
->init_gid
);
4560 static int get_config_init_groups(const char *key
, char *retv
, int inlen
,
4561 struct lxc_conf
*c
, void *data
)
4563 int fulllen
= 0, len
;
4568 memset(retv
, 0, inlen
);
4570 if (c
->init_groups
.size
== 0)
4573 for (size_t i
= 0; i
< c
->init_groups
.size
; i
++)
4574 strprint(retv
, inlen
, "%s%d", (i
> 0) ? "," : "",
4575 c
->init_groups
.list
[i
]);
4580 static int get_config_ephemeral(const char *key
, char *retv
, int inlen
,
4581 struct lxc_conf
*c
, void *data
)
4583 return lxc_get_conf_int(c
, retv
, inlen
, c
->ephemeral
);
4586 static int get_config_no_new_privs(const char *key
, char *retv
, int inlen
,
4587 struct lxc_conf
*c
, void *data
)
4589 return lxc_get_conf_int(c
, retv
, inlen
, c
->no_new_privs
);
4592 /* If you ask for a specific value, i.e. lxc.prlimit.nofile, then just the value
4593 * will be printed. If you ask for 'lxc.prlimit', then all limit entries will be
4594 * printed, in 'lxc.prlimit.resource = value' format.
4596 static int get_config_prlimit(const char *key
, char *retv
, int inlen
,
4597 struct lxc_conf
*c
, void *data
)
4599 int fulllen
= 0, len
;
4600 bool get_all
= false;
4601 struct lxc_limit
*lim
;
4606 memset(retv
, 0, inlen
);
4608 if (strequal(key
, "lxc.prlimit"))
4610 else if (strnequal(key
, "lxc.prlimit.", 12))
4613 return ret_errno(EINVAL
);
4615 list_for_each_entry(lim
, &c
->limits
, head
) {
4616 /* 2 colon separated 64 bit integers or the word 'unlimited' */
4617 char buf
[INTTYPE_TO_STRLEN(uint64_t) * 2 + 2];
4620 if (lim
->limit
.rlim_cur
== RLIM_INFINITY
) {
4621 memcpy(buf
, "unlimited", STRLITERALLEN("unlimited") + 1);
4622 partlen
= STRLITERALLEN("unlimited");
4624 partlen
= sprintf(buf
, "%" PRIu64
,
4625 (uint64_t)lim
->limit
.rlim_cur
);
4628 if (lim
->limit
.rlim_cur
!= lim
->limit
.rlim_max
) {
4629 if (lim
->limit
.rlim_max
== RLIM_INFINITY
)
4630 memcpy(buf
+ partlen
, ":unlimited",
4631 STRLITERALLEN(":unlimited") + 1);
4633 sprintf(buf
+ partlen
, ":%" PRIu64
,
4634 (uint64_t)lim
->limit
.rlim_max
);
4638 strprint(retv
, inlen
, "lxc.prlimit.%s = %s\n",
4639 lim
->resource
, buf
);
4640 } else if (strequal(lim
->resource
, key
)) {
4641 strprint(retv
, inlen
, "%s", buf
);
4648 /* If you ask for a specific value, i.e. lxc.sysctl.net.ipv4.ip_forward, then
4649 * just the value will be printed. If you ask for 'lxc.sysctl', then all sysctl
4650 * entries will be printed, in 'lxc.sysctl.key = value' format.
4652 static int get_config_sysctl(const char *key
, char *retv
, int inlen
,
4653 struct lxc_conf
*c
, void *data
)
4656 bool get_all
= false;
4658 struct lxc_sysctl
*sysctl
;
4663 memset(retv
, 0, inlen
);
4665 if (strequal(key
, "lxc.sysctl"))
4667 else if (strnequal(key
, "lxc.sysctl.", STRLITERALLEN("lxc.sysctl.")))
4668 key
+= STRLITERALLEN("lxc.sysctl.");
4670 return ret_errno(EINVAL
);
4672 list_for_each_entry(sysctl
, &c
->sysctls
, head
) {
4674 strprint(retv
, inlen
, "lxc.sysctl.%s = %s\n", sysctl
->key
,
4676 } else if (strequal(sysctl
->key
, key
)) {
4677 strprint(retv
, inlen
, "%s", sysctl
->value
);
4684 static int get_config_proc(const char *key
, char *retv
, int inlen
,
4685 struct lxc_conf
*c
, void *data
)
4688 bool get_all
= false;
4690 struct lxc_proc
*proc
;
4695 memset(retv
, 0, inlen
);
4697 if (strequal(key
, "lxc.proc"))
4699 else if (strnequal(key
, "lxc.proc.", STRLITERALLEN("lxc.proc.")))
4700 key
+= STRLITERALLEN("lxc.proc.");
4702 return ret_errno(EINVAL
);
4704 list_for_each_entry(proc
, &c
->procs
, head
) {
4706 strprint(retv
, inlen
, "lxc.proc.%s = %s\n",
4707 proc
->filename
, proc
->value
);
4708 } else if (strequal(proc
->filename
, key
)) {
4709 strprint(retv
, inlen
, "%s", proc
->value
);
4716 static int get_config_namespace_clone(const char *key
, char *retv
, int inlen
,
4717 struct lxc_conf
*c
, void *data
)
4725 memset(retv
, 0, inlen
);
4727 for (i
= 0; i
< LXC_NS_MAX
; i
++) {
4728 if (c
->ns_clone
& ns_info
[i
].clone_flag
)
4729 strprint(retv
, inlen
, "%s\n", ns_info
[i
].proc_name
);
4735 static int get_config_namespace_keep(const char *key
, char *retv
, int inlen
,
4736 struct lxc_conf
*c
, void *data
)
4744 memset(retv
, 0, inlen
);
4746 for (i
= 0; i
< LXC_NS_MAX
; i
++) {
4747 if (c
->ns_keep
& ns_info
[i
].clone_flag
)
4748 strprint(retv
, inlen
, "%s\n", ns_info
[i
].proc_name
);
4754 static int get_config_time_offset_boot(const char *key
, char *retv
, int inlen
, struct lxc_conf
*c
,
4763 memset(retv
, 0, inlen
);
4765 if (c
->timens
.s_boot
) {
4766 strprint(retv
, inlen
, "%" PRId64
" s\n", c
->timens
.s_boot
);
4768 strprint(retv
, inlen
, "%" PRId64
" ns\n", c
->timens
.ns_boot
);
4774 static int get_config_time_offset_monotonic(const char *key
, char *retv
, int inlen
,
4775 struct lxc_conf
*c
, void *data
)
4783 memset(retv
, 0, inlen
);
4785 if (c
->timens
.s_monotonic
) {
4786 strprint(retv
, inlen
, "%" PRId64
"s\n", c
->timens
.s_monotonic
);
4788 strprint(retv
, inlen
, "%" PRId64
"ns\n", c
->timens
.ns_monotonic
);
4794 static int get_config_namespace_share(const char *key
, char *retv
, int inlen
,
4795 struct lxc_conf
*c
, void *data
)
4798 const char *namespace;
4804 memset(retv
, 0, inlen
);
4806 namespace = key
+ STRLITERALLEN("lxc.namespace.share.");
4807 if (is_empty_string(namespace))
4808 return ret_errno(EINVAL
);
4810 ns_idx
= lxc_namespace_2_ns_idx(namespace);
4814 strprint(retv
, inlen
, "%s", c
->ns_share
[ns_idx
]);
4819 /* Callbacks to clear config items. */
4820 static inline int clr_config_personality(const char *key
, struct lxc_conf
*c
,
4823 c
->personality
= -1;
4827 static inline int clr_config_pty_max(const char *key
, struct lxc_conf
*c
,
4834 static inline int clr_config_tty_max(const char *key
, struct lxc_conf
*c
,
4841 static inline int clr_config_tty_dir(const char *key
, struct lxc_conf
*c
,
4844 free_disarm(c
->ttys
.dir
);
4848 static inline int clr_config_apparmor_profile(const char *key
,
4849 struct lxc_conf
*c
, void *data
)
4852 free_disarm(c
->lsm_aa_profile
);
4855 return syserror_set(-EINVAL
, "Built without AppArmor support");
4859 static inline int clr_config_apparmor_allow_incomplete(const char *key
,
4864 c
->lsm_aa_allow_incomplete
= 0;
4867 return syserror_set(-EINVAL
, "Built without AppArmor support");
4871 static inline int clr_config_apparmor_allow_nesting(const char *key
,
4876 c
->lsm_aa_allow_nesting
= 0;
4879 return syserror_set(-EINVAL
, "Built without AppArmor support");
4883 static inline int clr_config_apparmor_raw(const char *key
,
4888 return lxc_clear_apparmor_raw(c
);
4890 return syserror_set(-EINVAL
, "Built without AppArmor support");
4894 static inline int clr_config_selinux_context(const char *key
,
4895 struct lxc_conf
*c
, void *data
)
4898 free_disarm(c
->lsm_se_context
);
4901 return syserror_set(-EINVAL
, "Built without SELinux support");
4905 static inline int clr_config_selinux_context_keyring(const char *key
,
4906 struct lxc_conf
*c
, void *data
)
4909 free_disarm(c
->lsm_se_keyring_context
);
4912 return syserror_set(-EINVAL
, "Built without SELinux support");
4916 static inline int clr_config_keyring_session(const char *key
,
4917 struct lxc_conf
*c
, void *data
)
4919 c
->keyring_disable_session
= false;
4923 static inline int clr_config_cgroup_controller(const char *key
,
4924 struct lxc_conf
*c
, void *data
)
4926 return lxc_clear_cgroups(c
, key
, CGROUP_SUPER_MAGIC
);
4929 static inline int clr_config_cgroup2_controller(const char *key
,
4930 struct lxc_conf
*c
, void *data
)
4932 return lxc_clear_cgroups(c
, key
, CGROUP2_SUPER_MAGIC
);
4935 static int clr_config_cgroup_dir(const char *key
, struct lxc_conf
*lxc_conf
,
4938 if (!strequal(key
, "lxc.cgroup.dir"))
4939 return ret_errno(EINVAL
);
4941 if (lxc_conf
->cgroup_meta
.dir
)
4942 free_disarm(lxc_conf
->cgroup_meta
.dir
);
4947 static int clr_config_cgroup_monitor_dir(const char *key
,
4948 struct lxc_conf
*lxc_conf
,
4951 free_disarm(lxc_conf
->cgroup_meta
.monitor_dir
);
4955 static int clr_config_cgroup_monitor_pivot_dir(const char *key
,
4956 struct lxc_conf
*lxc_conf
,
4959 free_disarm(lxc_conf
->cgroup_meta
.monitor_pivot_dir
);
4963 static int clr_config_cgroup_container_dir(const char *key
,
4964 struct lxc_conf
*lxc_conf
,
4967 free_disarm(lxc_conf
->cgroup_meta
.container_dir
);
4971 static int clr_config_cgroup_container_inner_dir(const char *key
,
4972 struct lxc_conf
*lxc_conf
,
4975 free_disarm(lxc_conf
->cgroup_meta
.namespace_dir
);
4979 static inline int clr_config_cgroup_relative(const char *key
,
4980 struct lxc_conf
*lxc_conf
,
4983 lxc_conf
->cgroup_meta
.relative
= false;
4987 static inline int clr_config_idmaps(const char *key
, struct lxc_conf
*c
,
4990 return lxc_clear_idmaps(c
);
4993 static inline int clr_config_log_level(const char *key
, struct lxc_conf
*c
,
4996 c
->loglevel
= LXC_LOG_LEVEL_NOTSET
;
5000 static inline int clr_config_log_file(const char *key
, struct lxc_conf
*c
,
5003 free_disarm(c
->logfile
);
5007 static inline int clr_config_mount(const char *key
, struct lxc_conf
*c
,
5010 return lxc_clear_mount_entries(c
);
5013 static inline int clr_config_mount_auto(const char *key
, struct lxc_conf
*c
,
5016 return lxc_clear_automounts(c
);
5019 static inline int clr_config_mount_fstab(const char *key
, struct lxc_conf
*c
,
5022 free_disarm(c
->fstab
);
5026 static inline int clr_config_rootfs_path(const char *key
, struct lxc_conf
*c
,
5029 free_disarm(c
->rootfs
.path
);
5033 static inline int clr_config_rootfs_managed(const char *key
, struct lxc_conf
*c
,
5036 c
->rootfs
.managed
= true;
5040 static inline int clr_config_rootfs_mount(const char *key
, struct lxc_conf
*c
,
5043 free_disarm(c
->rootfs
.mount
);
5047 static inline int clr_config_rootfs_options(const char *key
, struct lxc_conf
*c
,
5050 put_lxc_mount_options(&c
->rootfs
.mnt_opts
);
5055 static inline int clr_config_uts_name(const char *key
, struct lxc_conf
*c
,
5058 free_disarm(c
->utsname
);
5062 static inline int clr_config_hooks(const char *key
, struct lxc_conf
*c
,
5065 return lxc_clear_hooks(c
, key
);
5068 static inline int clr_config_hooks_version(const char *key
, struct lxc_conf
*c
,
5071 /* default to legacy hooks version */
5072 c
->hooks_version
= 0;
5076 static inline int clr_config_net(const char *key
, struct lxc_conf
*c
,
5079 lxc_free_networks(c
);
5084 static inline int clr_config_cap_drop(const char *key
, struct lxc_conf
*c
,
5087 return lxc_clear_config_caps(c
);
5090 static inline int clr_config_cap_keep(const char *key
, struct lxc_conf
*c
,
5093 return lxc_clear_config_caps(c
);
5096 static inline int clr_config_console_path(const char *key
, struct lxc_conf
*c
,
5099 free_disarm(c
->console
.path
);
5103 static inline int clr_config_console_logfile(const char *key
,
5104 struct lxc_conf
*c
, void *data
)
5106 free_disarm(c
->console
.log_path
);
5110 static inline int clr_config_console_rotate(const char *key
, struct lxc_conf
*c
,
5113 c
->console
.log_rotate
= 0;
5117 static inline int clr_config_console_buffer_size(const char *key
,
5118 struct lxc_conf
*c
, void *data
)
5120 c
->console
.buffer_size
= 0;
5124 static inline int clr_config_console_size(const char *key
, struct lxc_conf
*c
,
5127 c
->console
.log_size
= 0;
5131 static inline int clr_config_seccomp_allow_nesting(const char *key
,
5132 struct lxc_conf
*c
, void *data
)
5135 c
->seccomp
.allow_nesting
= 0;
5138 return ret_errno(ENOSYS
);
5142 static inline int clr_config_seccomp_notify_cookie(const char *key
,
5143 struct lxc_conf
*c
, void *data
)
5145 #ifdef HAVE_SECCOMP_NOTIFY
5146 free_disarm(c
->seccomp
.notifier
.cookie
);
5149 return ret_errno(ENOSYS
);
5153 static inline int clr_config_seccomp_notify_proxy(const char *key
,
5154 struct lxc_conf
*c
, void *data
)
5156 #ifdef HAVE_SECCOMP_NOTIFY
5157 memset(&c
->seccomp
.notifier
.proxy_addr
, 0,
5158 sizeof(c
->seccomp
.notifier
.proxy_addr
));
5161 return ret_errno(ENOSYS
);
5165 static inline int clr_config_seccomp_profile(const char *key
,
5166 struct lxc_conf
*c
, void *data
)
5168 free_disarm(c
->seccomp
.seccomp
);
5172 static inline int clr_config_autodev(const char *key
, struct lxc_conf
*c
,
5179 static inline int clr_config_autodev_tmpfs_size(const char *key
, struct lxc_conf
*c
,
5182 c
->autodevtmpfssize
= 500000;
5186 static inline int clr_config_signal_halt(const char *key
, struct lxc_conf
*c
,
5193 static inline int clr_config_signal_reboot(const char *key
, struct lxc_conf
*c
,
5196 c
->rebootsignal
= 0;
5200 static inline int clr_config_signal_stop(const char *key
, struct lxc_conf
*c
,
5207 static inline int clr_config_start(const char *key
, struct lxc_conf
*c
,
5210 if (strequal(key
+ 10, "auto"))
5212 else if (strequal(key
+ 10, "delay"))
5214 else if (strequal(key
+ 10, "order"))
5220 static inline int clr_config_log_syslog(const char *key
, struct lxc_conf
*c
,
5223 free_disarm(c
->syslog
);
5227 static inline int clr_config_monitor(const char *key
, struct lxc_conf
*c
,
5230 c
->monitor_unshare
= 0;
5234 static inline int clr_config_monitor_signal_pdeath(const char *key
,
5235 struct lxc_conf
*c
, void *data
)
5237 c
->monitor_signal_pdeath
= 0;
5241 static inline int clr_config_group(const char *key
, struct lxc_conf
*c
,
5244 return lxc_clear_groups(c
);
5247 static inline int clr_config_environment(const char *key
, struct lxc_conf
*c
,
5250 return lxc_clear_environment(c
);
5253 static inline int clr_config_execute_cmd(const char *key
, struct lxc_conf
*c
,
5256 free_disarm(c
->execute_cmd
);
5260 static inline int clr_config_init_cmd(const char *key
, struct lxc_conf
*c
,
5263 free_disarm(c
->init_cmd
);
5267 static inline int clr_config_init_cwd(const char *key
, struct lxc_conf
*c
,
5270 free_disarm(c
->init_cwd
);
5274 static inline int clr_config_init_uid(const char *key
, struct lxc_conf
*c
,
5281 static inline int clr_config_init_gid(const char *key
, struct lxc_conf
*c
,
5288 static inline int clr_config_init_groups(const char *key
, struct lxc_conf
*c
,
5291 c
->init_groups
.size
= 0;
5292 free_disarm(c
->init_groups
.list
);
5296 static inline int clr_config_ephemeral(const char *key
, struct lxc_conf
*c
,
5303 static inline int clr_config_no_new_privs(const char *key
, struct lxc_conf
*c
,
5306 c
->no_new_privs
= false;
5310 static inline int clr_config_prlimit(const char *key
, struct lxc_conf
*c
,
5313 return lxc_clear_limits(c
, key
);
5316 static inline int clr_config_sysctl(const char *key
, struct lxc_conf
*c
,
5319 return lxc_clear_sysctls(c
, key
);
5322 static inline int clr_config_proc(const char *key
, struct lxc_conf
*c
,
5325 return lxc_clear_procs(c
, key
);
5328 static inline int clr_config_includefiles(const char *key
, struct lxc_conf
*c
,
5334 static int clr_config_namespace_clone(const char *key
,
5335 struct lxc_conf
*lxc_conf
, void *data
)
5337 lxc_conf
->ns_clone
= 0;
5341 static int clr_config_namespace_keep(const char *key
, struct lxc_conf
*lxc_conf
,
5344 lxc_conf
->ns_keep
= 0;
5348 static int clr_config_time_offset_boot(const char *key
, struct lxc_conf
*lxc_conf
, void *data
)
5350 lxc_conf
->timens
.s_boot
= 0;
5351 lxc_conf
->timens
.ns_boot
= 0;
5355 static int clr_config_time_offset_monotonic(const char *key
, struct lxc_conf
*lxc_conf
, void *data
)
5357 lxc_conf
->timens
.s_monotonic
= 0;
5358 lxc_conf
->timens
.ns_monotonic
= 0;
5362 static int clr_config_namespace_share(const char *key
,
5363 struct lxc_conf
*lxc_conf
, void *data
)
5366 const char *namespace;
5368 namespace = key
+ STRLITERALLEN("lxc.namespace.share.");
5369 if (is_empty_string(namespace))
5370 return ret_errno(EINVAL
);
5372 ns_idx
= lxc_namespace_2_ns_idx(namespace);
5376 free(lxc_conf
->ns_share
[ns_idx
]);
5377 lxc_conf
->ns_share
[ns_idx
] = NULL
;
5382 static int get_config_includefiles(const char *key
, char *retv
, int inlen
,
5383 struct lxc_conf
*c
, void *data
)
5385 return ret_errno(ENOSYS
);
5388 struct config_net_info
{
5389 char buf
[NETWORK_SUBKEY_SIZE_MAX
];
5391 const struct lxc_config_net_t
*ops
;
5392 struct lxc_netdev
*netdev
;
5395 static int get_network_config_ops(const char *key
, struct lxc_conf
*lxc_conf
,
5396 struct config_net_info
*info
, bool allocate
)
5401 const char *idx_start
;
5403 if (is_empty_string(key
))
5404 return ret_errno(EINVAL
);
5406 /* check that this is a sensible network key */
5407 if (!strnequal("lxc.net.", key
, STRLITERALLEN("lxc.net.")))
5408 return syserror_set(-EINVAL
, "Invalid network configuration key \"%s\"", key
);
5411 /* beginning of index string */
5412 idx_start
= key
+ STRLITERALLEN("lxc.net.");
5413 if (!isdigit(*idx_start
))
5414 return syserror_set(-EINVAL
, "Failed to detect digit in string \"%s\"", key
+ 8);
5416 ret
= lxc_safe_int64_residual(idx_start
, &tmpidx
, 10, info
->buf
, sizeof(info
->buf
));
5418 return syserror("Failed to parse network index");
5420 if (tmpidx
< 0 || tmpidx
>= INT_MAX
)
5421 return syserror_set(-ERANGE
, "Number of configured networks would overflow the counter");
5422 idx
= (unsigned int)tmpidx
;
5424 info
->netdev
= lxc_get_netdev_by_idx(lxc_conf
, idx
, allocate
);
5426 return ret_errno(EINVAL
);
5428 /* Make sure subkey points to the empty string. */
5429 info
->subkey
= info
->buf
;
5430 if (is_empty_string(info
->subkey
))
5431 return ret_errno(ENOENT
);
5433 if (info
->subkey
[0] != '.')
5434 return syserror_set(-EINVAL
, "Invalid subkey");
5437 /* lxc.net.<idx>.<subkey> */
5438 info
->ops
= lxc_get_config_net(info
->subkey
);
5439 if (info
->ops
== &unsupported_config_net_key
)
5440 return syserror_set(-ENOENT
, "Unknown network configuration key \"%s\"", key
);
5445 /* Config entry is something like "lxc.net.0.ipv4" the key 'lxc.net.' was
5446 * found. So we make sure next comes an integer, find the right callback (by
5447 * rewriting the key), and call it.
5449 static int set_config_jump_table_net(const char *key
, const char *value
,
5450 struct lxc_conf
*lxc_conf
, void *data
)
5452 struct config_net_info info
= {};
5454 const char *idxstring
;
5456 idxstring
= key
+ STRLITERALLEN("lxc.net.");
5457 if (!isdigit(*idxstring
))
5458 return ret_errno(EINVAL
);
5460 if (lxc_config_value_empty(value
))
5461 return clr_config_jump_table_net(key
, lxc_conf
, data
);
5463 ret
= get_network_config_ops(key
, lxc_conf
, &info
, true);
5467 return info
.ops
->set(info
.subkey
, value
, lxc_conf
, info
.netdev
);
5470 static int clr_config_jump_table_net(const char *key
, struct lxc_conf
*lxc_conf
,
5473 struct config_net_info info
= {};
5475 const char *idxstring
;
5477 idxstring
= key
+ 8;
5478 if (!isdigit(*idxstring
))
5479 return ret_errno(EINVAL
);
5481 /* The left conjunct is pretty self-explanatory. The right conjunct
5482 * checks whether the two pointers are equal. If they are we know that
5483 * this is not a key that is namespaced any further and so we are
5484 * supposed to clear the whole network.
5486 if (isdigit(*idxstring
) && (strrchr(key
, '.') == (idxstring
- 1))) {
5487 unsigned int rmnetdevidx
;
5489 ret
= lxc_safe_uint(idxstring
, &rmnetdevidx
);
5493 /* Remove network from network list. */
5494 lxc_remove_nic_by_idx(lxc_conf
, rmnetdevidx
);
5498 ret
= get_network_config_ops(key
, lxc_conf
, &info
, false);
5502 return info
.ops
->clr(info
.subkey
, lxc_conf
, info
.netdev
);
5505 static int clr_config_net_type(const char *key
, struct lxc_conf
*lxc_conf
,
5508 struct lxc_netdev
*netdev
= data
;
5511 return ret_errno(EINVAL
);
5513 lxc_clear_netdev(netdev
);
5518 static int clr_config_net_name(const char *key
, struct lxc_conf
*lxc_conf
,
5521 struct lxc_netdev
*netdev
= data
;
5524 return ret_errno(EINVAL
);
5526 netdev
->name
[0] = '\0';
5531 static int clr_config_net_flags(const char *key
, struct lxc_conf
*lxc_conf
,
5534 struct lxc_netdev
*netdev
= data
;
5537 return ret_errno(EINVAL
);
5544 static int clr_config_net_link(const char *key
, struct lxc_conf
*lxc_conf
,
5547 struct lxc_netdev
*netdev
= data
;
5550 return ret_errno(EINVAL
);
5552 netdev
->link
[0] = '\0';
5557 static int clr_config_net_l2proxy(const char *key
, struct lxc_conf
*lxc_conf
,
5560 struct lxc_netdev
*netdev
= data
;
5563 return ret_errno(EINVAL
);
5565 netdev
->l2proxy
= false;
5570 static int clr_config_net_macvlan_mode(const char *key
,
5571 struct lxc_conf
*lxc_conf
, void *data
)
5573 struct lxc_netdev
*netdev
= data
;
5576 return ret_errno(EINVAL
);
5578 if (netdev
->type
!= LXC_NET_MACVLAN
)
5581 netdev
->priv
.macvlan_attr
.mode
= -1;
5586 static int clr_config_net_ipvlan_mode(const char *key
,
5587 struct lxc_conf
*lxc_conf
, void *data
)
5589 struct lxc_netdev
*netdev
= data
;
5592 return ret_errno(EINVAL
);
5594 if (netdev
->type
!= LXC_NET_IPVLAN
)
5597 netdev
->priv
.ipvlan_attr
.mode
= -1;
5602 static int clr_config_net_ipvlan_isolation(const char *key
,
5603 struct lxc_conf
*lxc_conf
, void *data
)
5605 struct lxc_netdev
*netdev
= data
;
5608 return ret_errno(EINVAL
);
5610 if (netdev
->type
!= LXC_NET_IPVLAN
)
5613 netdev
->priv
.ipvlan_attr
.isolation
= -1;
5618 static int clr_config_net_veth_mode(const char *key
,
5619 struct lxc_conf
*lxc_conf
, void *data
)
5621 struct lxc_netdev
*netdev
= data
;
5624 return ret_errno(EINVAL
);
5626 if (netdev
->type
!= LXC_NET_VETH
)
5629 netdev
->priv
.veth_attr
.mode
= -1;
5634 static int clr_config_net_veth_n_rxqueues(const char *key
, struct lxc_conf
*lxc_conf
,
5637 struct lxc_netdev
*netdev
= data
;
5640 return ret_errno(EINVAL
);
5642 if (netdev
->type
!= LXC_NET_VETH
)
5645 netdev
->priv
.veth_attr
.n_rxqueues
= -1;
5650 static int clr_config_net_veth_n_txqueues(const char *key
, struct lxc_conf
*lxc_conf
,
5653 struct lxc_netdev
*netdev
= data
;
5656 return ret_errno(EINVAL
);
5658 if (netdev
->type
!= LXC_NET_VETH
)
5661 netdev
->priv
.veth_attr
.n_txqueues
= -1;
5667 static int clr_config_net_veth_pair(const char *key
, struct lxc_conf
*lxc_conf
,
5670 struct lxc_netdev
*netdev
= data
;
5673 return ret_errno(EINVAL
);
5675 if (netdev
->type
!= LXC_NET_VETH
)
5678 netdev
->priv
.veth_attr
.pair
[0] = '\0';
5683 static int clr_config_net_veth_vlan_id(const char *key
, struct lxc_conf
*lxc_conf
,
5686 struct lxc_netdev
*netdev
= data
;
5689 return ret_errno(EINVAL
);
5691 if (netdev
->type
!= LXC_NET_VETH
)
5694 netdev
->priv
.veth_attr
.vlan_id
= 0;
5695 netdev
->priv
.veth_attr
.vlan_id_set
= false;
5700 static int clr_config_net_veth_vlan_tagged_id(const char *key
,
5701 struct lxc_conf
*lxc_conf
, void *data
)
5703 struct lxc_netdev
*netdev
= data
;
5704 struct lxc_list
*cur
, *next
;
5707 return ret_errno(EINVAL
);
5709 if (netdev
->type
!= LXC_NET_VETH
)
5712 lxc_list_for_each_safe(cur
, &netdev
->priv
.veth_attr
.vlan_tagged_ids
, next
) {
5721 static int clr_config_net_script_up(const char *key
, struct lxc_conf
*lxc_conf
,
5724 struct lxc_netdev
*netdev
= data
;
5727 return ret_errno(EINVAL
);
5729 free_disarm(netdev
->upscript
);
5734 static int clr_config_net_script_down(const char *key
,
5735 struct lxc_conf
*lxc_conf
, void *data
)
5737 struct lxc_netdev
*netdev
= data
;
5740 return ret_errno(EINVAL
);
5742 free_disarm(netdev
->downscript
);
5747 static int clr_config_net_hwaddr(const char *key
, struct lxc_conf
*lxc_conf
,
5750 struct lxc_netdev
*netdev
= data
;
5753 return ret_errno(EINVAL
);
5755 free_disarm(netdev
->hwaddr
);
5760 static int clr_config_net_mtu(const char *key
, struct lxc_conf
*lxc_conf
,
5763 struct lxc_netdev
*netdev
= data
;
5766 return ret_errno(EINVAL
);
5768 free_disarm(netdev
->mtu
);
5773 static int clr_config_net_vlan_id(const char *key
, struct lxc_conf
*lxc_conf
,
5776 struct lxc_netdev
*netdev
= data
;
5779 return ret_errno(EINVAL
);
5781 if (netdev
->type
!= LXC_NET_VLAN
)
5784 netdev
->priv
.vlan_attr
.vid
= 0;
5789 static int clr_config_net_ipv4_gateway(const char *key
,
5790 struct lxc_conf
*lxc_conf
, void *data
)
5792 struct lxc_netdev
*netdev
= data
;
5795 return ret_errno(EINVAL
);
5797 free_disarm(netdev
->ipv4_gateway
);
5802 static int clr_config_net_ipv4_address(const char *key
,
5803 struct lxc_conf
*lxc_conf
, void *data
)
5805 struct lxc_netdev
*netdev
= data
;
5806 struct lxc_inetdev
*inetdev
, *ninetdev
;
5809 return ret_errno(EINVAL
);
5811 list_for_each_entry_safe(inetdev
, ninetdev
, &netdev
->ipv4_addresses
, head
) {
5812 list_del(&inetdev
->head
);
5819 static int clr_config_net_veth_ipv4_route(const char *key
,
5820 struct lxc_conf
*lxc_conf
, void *data
)
5822 struct lxc_netdev
*netdev
= data
;
5823 struct lxc_inetdev
*inetdev
, *ninetdev
;
5826 return ret_errno(EINVAL
);
5828 if (netdev
->type
!= LXC_NET_VETH
)
5831 list_for_each_entry_safe(inetdev
, ninetdev
, &netdev
->priv
.veth_attr
.ipv4_routes
, head
) {
5832 list_del(&inetdev
->head
);
5839 static int clr_config_net_ipv6_gateway(const char *key
,
5840 struct lxc_conf
*lxc_conf
, void *data
)
5842 struct lxc_netdev
*netdev
= data
;
5845 return ret_errno(EINVAL
);
5847 free_disarm(netdev
->ipv6_gateway
);
5852 static int clr_config_net_ipv6_address(const char *key
,
5853 struct lxc_conf
*lxc_conf
, void *data
)
5855 struct lxc_netdev
*netdev
= data
;
5856 struct lxc_inet6dev
*inet6dev
, *ninet6dev
;
5859 return ret_errno(EINVAL
);
5861 list_for_each_entry_safe(inet6dev
, ninet6dev
, &netdev
->ipv6_addresses
, head
) {
5862 list_del(&inet6dev
->head
);
5869 static int clr_config_net_veth_ipv6_route(const char *key
,
5870 struct lxc_conf
*lxc_conf
, void *data
)
5872 struct lxc_netdev
*netdev
= data
;
5873 struct lxc_inet6dev
*inet6dev
, *ninet6dev
;
5876 return ret_errno(EINVAL
);
5878 if (netdev
->type
!= LXC_NET_VETH
)
5881 list_for_each_entry_safe(inet6dev
, ninet6dev
, &netdev
->priv
.veth_attr
.ipv6_routes
, head
) {
5882 list_del(&inet6dev
->head
);
5889 static int get_config_jump_table_net(const char *key
, char *retv
, int inlen
,
5890 struct lxc_conf
*c
, void *data
)
5892 struct config_net_info info
= {};
5894 const char *idxstring
;
5896 idxstring
= key
+ STRLITERALLEN("lxc.net.");
5897 if (!isdigit(*idxstring
))
5898 return ret_errno(EINVAL
);
5900 ret
= get_network_config_ops(key
, c
, &info
, false);
5904 return info
.ops
->get(info
.subkey
, retv
, inlen
, c
, info
.netdev
);
5907 static int get_config_net_type(const char *key
, char *retv
, int inlen
,
5908 struct lxc_conf
*c
, void *data
)
5912 struct lxc_netdev
*netdev
= data
;
5915 return ret_errno(EINVAL
);
5920 memset(retv
, 0, inlen
);
5922 strprint(retv
, inlen
, "%s", lxc_net_type_to_str(netdev
->type
));
5927 static int get_config_net_flags(const char *key
, char *retv
, int inlen
,
5928 struct lxc_conf
*c
, void *data
)
5932 struct lxc_netdev
*netdev
= data
;
5935 return ret_errno(EINVAL
);
5940 memset(retv
, 0, inlen
);
5942 if (netdev
->flags
& IFF_UP
)
5943 strprint(retv
, inlen
, "up");
5948 static int get_config_net_link(const char *key
, char *retv
, int inlen
,
5949 struct lxc_conf
*c
, void *data
)
5953 struct lxc_netdev
*netdev
= data
;
5956 return ret_errno(EINVAL
);
5961 memset(retv
, 0, inlen
);
5963 if (netdev
->link
[0] != '\0')
5964 strprint(retv
, inlen
, "%s", netdev
->link
);
5969 static int get_config_net_l2proxy(const char *key
, char *retv
, int inlen
,
5970 struct lxc_conf
*c
, void *data
)
5972 struct lxc_netdev
*netdev
= data
;
5975 return ret_errno(EINVAL
);
5977 return lxc_get_conf_bool(c
, retv
, inlen
, netdev
->l2proxy
);
5980 static int get_config_net_name(const char *key
, char *retv
, int inlen
,
5981 struct lxc_conf
*c
, void *data
)
5985 struct lxc_netdev
*netdev
= data
;
5988 return ret_errno(EINVAL
);
5993 memset(retv
, 0, inlen
);
5995 if (netdev
->name
[0] != '\0')
5996 strprint(retv
, inlen
, "%s", netdev
->name
);
6001 static int get_config_net_macvlan_mode(const char *key
, char *retv
, int inlen
,
6002 struct lxc_conf
*c
, void *data
)
6007 struct lxc_netdev
*netdev
= data
;
6010 return ret_errno(EINVAL
);
6012 if (netdev
->type
!= LXC_NET_MACVLAN
)
6013 return ret_errno(EINVAL
);
6018 memset(retv
, 0, inlen
);
6020 switch (netdev
->priv
.macvlan_attr
.mode
) {
6021 case MACVLAN_MODE_PRIVATE
:
6024 case MACVLAN_MODE_VEPA
:
6027 case MACVLAN_MODE_BRIDGE
:
6030 case MACVLAN_MODE_PASSTHRU
:
6038 strprint(retv
, inlen
, "%s", mode
);
6043 static int get_config_net_ipvlan_mode(const char *key
, char *retv
, int inlen
,
6044 struct lxc_conf
*c
, void *data
)
6047 struct lxc_netdev
*netdev
= data
;
6052 return ret_errno(EINVAL
);
6054 if (netdev
->type
!= LXC_NET_IPVLAN
)
6055 return ret_errno(EINVAL
);
6060 memset(retv
, 0, inlen
);
6062 switch (netdev
->priv
.ipvlan_attr
.mode
) {
6063 case IPVLAN_MODE_L3
:
6066 case IPVLAN_MODE_L3S
:
6069 case IPVLAN_MODE_L2
:
6077 strprint(retv
, inlen
, "%s", mode
);
6082 static int get_config_net_ipvlan_isolation(const char *key
, char *retv
, int inlen
,
6083 struct lxc_conf
*c
, void *data
)
6086 struct lxc_netdev
*netdev
= data
;
6091 return ret_errno(EINVAL
);
6093 if (netdev
->type
!= LXC_NET_IPVLAN
)
6094 return ret_errno(EINVAL
);
6099 memset(retv
, 0, inlen
);
6101 switch (netdev
->priv
.ipvlan_attr
.isolation
) {
6102 case IPVLAN_ISOLATION_BRIDGE
:
6105 case IPVLAN_ISOLATION_PRIVATE
:
6108 case IPVLAN_ISOLATION_VEPA
:
6116 strprint(retv
, inlen
, "%s", mode
);
6121 static int get_config_net_veth_mode(const char *key
, char *retv
, int inlen
,
6122 struct lxc_conf
*c
, void *data
)
6125 struct lxc_netdev
*netdev
= data
;
6130 return ret_errno(EINVAL
);
6132 if (netdev
->type
!= LXC_NET_VETH
)
6133 return ret_errno(EINVAL
);
6138 memset(retv
, 0, inlen
);
6140 switch (netdev
->priv
.veth_attr
.mode
) {
6141 case VETH_MODE_BRIDGE
:
6144 case VETH_MODE_ROUTER
:
6152 strprint(retv
, inlen
, "%s", mode
);
6157 static int get_config_net_veth_n_rxqueues(const char *key
, char *retv
, int inlen
,
6158 struct lxc_conf
*c
, void *data
)
6162 struct lxc_netdev
*netdev
= data
;
6165 return ret_errno(EINVAL
);
6167 if (netdev
->type
!= LXC_NET_VETH
)
6168 return ret_errno(EINVAL
);
6173 memset(retv
, 0, inlen
);
6175 if (netdev
->priv
.veth_attr
.n_rxqueues
> 0)
6176 strprint(retv
, inlen
, "%d", netdev
->priv
.veth_attr
.n_rxqueues
);
6181 static int get_config_net_veth_n_txqueues(const char *key
, char *retv
, int inlen
,
6182 struct lxc_conf
*c
, void *data
)
6186 struct lxc_netdev
*netdev
= data
;
6189 return ret_errno(EINVAL
);
6191 if (netdev
->type
!= LXC_NET_VETH
)
6192 return ret_errno(EINVAL
);
6197 memset(retv
, 0, inlen
);
6199 if (netdev
->priv
.veth_attr
.n_txqueues
> 0)
6200 strprint(retv
, inlen
, "%d", netdev
->priv
.veth_attr
.n_txqueues
);
6205 static int get_config_net_veth_pair(const char *key
, char *retv
, int inlen
,
6206 struct lxc_conf
*c
, void *data
)
6210 struct lxc_netdev
*netdev
= data
;
6213 return ret_errno(EINVAL
);
6215 if (netdev
->type
!= LXC_NET_VETH
)
6216 return ret_errno(EINVAL
);
6221 memset(retv
, 0, inlen
);
6223 strprint(retv
, inlen
, "%s",
6224 netdev
->priv
.veth_attr
.pair
[0] != '\0'
6225 ? netdev
->priv
.veth_attr
.pair
6226 : netdev
->priv
.veth_attr
.veth1
);
6231 static int get_config_net_veth_vlan_id(const char *key
, char *retv
, int inlen
,
6232 struct lxc_conf
*c
, void *data
)
6236 struct lxc_netdev
*netdev
= data
;
6239 return ret_errno(EINVAL
);
6241 if (netdev
->type
!= LXC_NET_VETH
)
6242 return ret_errno(EINVAL
);
6247 memset(retv
, 0, inlen
);
6249 strprint(retv
, inlen
, "%d", netdev
->priv
.veth_attr
.vlan_id
);
6254 static int get_config_net_veth_vlan_tagged_id(const char *key
, char *retv
,
6255 int inlen
, struct lxc_conf
*c
,
6260 struct lxc_list
*it
;
6262 struct lxc_netdev
*netdev
= data
;
6265 return ret_errno(EINVAL
);
6267 if (netdev
->type
!= LXC_NET_VETH
)
6268 return ret_errno(EINVAL
);
6273 memset(retv
, 0, inlen
);
6275 listlen
= lxc_list_len(&netdev
->priv
.veth_attr
.vlan_tagged_ids
);
6277 lxc_list_for_each(it
, &netdev
->priv
.veth_attr
.vlan_tagged_ids
) {
6278 unsigned short i
= PTR_TO_USHORT(it
->elem
);
6279 strprint(retv
, inlen
, "%u%s", i
, (listlen
-- > 1) ? "\n" : "");
6285 static int get_config_net_script_up(const char *key
, char *retv
, int inlen
,
6286 struct lxc_conf
*c
, void *data
)
6290 struct lxc_netdev
*netdev
= data
;
6293 return ret_errno(EINVAL
);
6298 memset(retv
, 0, inlen
);
6300 if (netdev
->upscript
)
6301 strprint(retv
, inlen
, "%s", netdev
->upscript
);
6306 static int get_config_net_script_down(const char *key
, char *retv
, int inlen
,
6307 struct lxc_conf
*c
, void *data
)
6311 struct lxc_netdev
*netdev
= data
;
6314 return ret_errno(EINVAL
);
6319 memset(retv
, 0, inlen
);
6321 if (netdev
->downscript
)
6322 strprint(retv
, inlen
, "%s", netdev
->downscript
);
6327 static int get_config_net_hwaddr(const char *key
, char *retv
, int inlen
,
6328 struct lxc_conf
*c
, void *data
)
6332 struct lxc_netdev
*netdev
= data
;
6335 return ret_errno(EINVAL
);
6340 memset(retv
, 0, inlen
);
6343 strprint(retv
, inlen
, "%s", netdev
->hwaddr
);
6348 static int get_config_net_mtu(const char *key
, char *retv
, int inlen
,
6349 struct lxc_conf
*c
, void *data
)
6353 struct lxc_netdev
*netdev
= data
;
6356 return ret_errno(EINVAL
);
6361 memset(retv
, 0, inlen
);
6364 strprint(retv
, inlen
, "%s", netdev
->mtu
);
6369 static int get_config_net_vlan_id(const char *key
, char *retv
, int inlen
,
6370 struct lxc_conf
*c
, void *data
)
6374 struct lxc_netdev
*netdev
= data
;
6377 return ret_errno(EINVAL
);
6379 if (netdev
->type
!= LXC_NET_VLAN
)
6380 return ret_errno(EINVAL
);
6385 memset(retv
, 0, inlen
);
6387 strprint(retv
, inlen
, "%d", netdev
->priv
.vlan_attr
.vid
);
6392 static int get_config_net_ipv4_gateway(const char *key
, char *retv
, int inlen
,
6393 struct lxc_conf
*c
, void *data
)
6396 char buf
[INET_ADDRSTRLEN
];
6398 struct lxc_netdev
*netdev
= data
;
6401 return ret_errno(EINVAL
);
6406 memset(retv
, 0, inlen
);
6408 if (netdev
->ipv4_gateway_auto
) {
6409 strprint(retv
, inlen
, "auto");
6410 } else if (netdev
->ipv4_gateway_dev
) {
6411 strprint(retv
, inlen
, "dev");
6412 } else if (netdev
->ipv4_gateway
) {
6413 if (!inet_ntop(AF_INET
, netdev
->ipv4_gateway
, buf
, sizeof(buf
)))
6415 strprint(retv
, inlen
, "%s", buf
);
6421 static int get_config_net_ipv4_address(const char *key
, char *retv
, int inlen
,
6422 struct lxc_conf
*c
, void *data
)
6425 struct lxc_netdev
*netdev
= data
;
6428 char buf
[INET_ADDRSTRLEN
];
6429 struct lxc_inetdev
*inetdev
;
6432 return ret_errno(EINVAL
);
6437 memset(retv
, 0, inlen
);
6439 listlen
= list_len(inetdev
, &netdev
->ipv4_addresses
, head
);
6441 list_for_each_entry(inetdev
, &netdev
->ipv4_addresses
, head
) {
6442 if (!inet_ntop(AF_INET
, &inetdev
->addr
, buf
, sizeof(buf
)))
6444 strprint(retv
, inlen
, "%s/%u%s", buf
, inetdev
->prefix
,
6445 (listlen
-- > 1) ? "\n" : "");
6451 static int get_config_net_veth_ipv4_route(const char *key
, char *retv
, int inlen
,
6452 struct lxc_conf
*c
, void *data
)
6456 char buf
[INET_ADDRSTRLEN
];
6457 struct lxc_inetdev
*inetdev
;
6459 struct lxc_netdev
*netdev
= data
;
6462 return ret_errno(EINVAL
);
6464 if (netdev
->type
!= LXC_NET_VETH
)
6465 return ret_errno(EINVAL
);
6470 memset(retv
, 0, inlen
);
6472 listlen
= list_len(inetdev
, &netdev
->priv
.veth_attr
.ipv4_routes
, head
);
6473 list_for_each_entry(inetdev
, &netdev
->priv
.veth_attr
.ipv4_routes
, head
) {
6474 if (!inet_ntop(AF_INET
, &inetdev
->addr
, buf
, sizeof(buf
)))
6476 strprint(retv
, inlen
, "%s/%u%s", buf
, inetdev
->prefix
,
6477 (listlen
-- > 1) ? "\n" : "");
6483 static int get_config_net_ipv6_gateway(const char *key
, char *retv
, int inlen
,
6484 struct lxc_conf
*c
, void *data
)
6487 char buf
[INET6_ADDRSTRLEN
];
6489 struct lxc_netdev
*netdev
= data
;
6492 return ret_errno(EINVAL
);
6497 memset(retv
, 0, inlen
);
6499 if (netdev
->ipv6_gateway_auto
) {
6500 strprint(retv
, inlen
, "auto");
6501 } else if (netdev
->ipv6_gateway_dev
) {
6502 strprint(retv
, inlen
, "dev");
6503 } else if (netdev
->ipv6_gateway
) {
6504 if (!inet_ntop(AF_INET6
, netdev
->ipv6_gateway
, buf
, sizeof(buf
)))
6506 strprint(retv
, inlen
, "%s", buf
);
6512 static int get_config_net_ipv6_address(const char *key
, char *retv
, int inlen
,
6513 struct lxc_conf
*c
, void *data
)
6517 char buf
[INET6_ADDRSTRLEN
];
6519 struct lxc_netdev
*netdev
= data
;
6520 struct lxc_inet6dev
*inet6dev
;
6523 return ret_errno(EINVAL
);
6528 memset(retv
, 0, inlen
);
6530 listlen
= list_len(inet6dev
, &netdev
->ipv6_addresses
, head
);
6531 list_for_each_entry(inet6dev
, &netdev
->ipv6_addresses
, head
) {
6532 if (!inet_ntop(AF_INET6
, &inet6dev
->addr
, buf
, sizeof(buf
)))
6534 strprint(retv
, inlen
, "%s/%u%s", buf
, inet6dev
->prefix
,
6535 (listlen
-- > 1) ? "\n" : "");
6541 static int get_config_net_veth_ipv6_route(const char *key
, char *retv
, int inlen
,
6542 struct lxc_conf
*c
, void *data
)
6546 char buf
[INET6_ADDRSTRLEN
];
6547 struct lxc_inet6dev
*inet6dev
;
6549 struct lxc_netdev
*netdev
= data
;
6552 return ret_errno(EINVAL
);
6554 if (netdev
->type
!= LXC_NET_VETH
)
6555 return ret_errno(EINVAL
);
6560 memset(retv
, 0, inlen
);
6562 listlen
= list_len(inet6dev
, &netdev
->priv
.veth_attr
.ipv6_routes
, head
);
6563 list_for_each_entry(inet6dev
, &netdev
->priv
.veth_attr
.ipv6_routes
, head
) {
6564 if (!inet_ntop(AF_INET6
, &inet6dev
->addr
, buf
, sizeof(buf
)))
6566 strprint(retv
, inlen
, "%s/%u%s", buf
, inet6dev
->prefix
,
6567 (listlen
-- > 1) ? "\n" : "");
6573 int lxc_list_config_items(char *retv
, int inlen
)
6582 memset(retv
, 0, inlen
);
6584 for (i
= 0; i
< ARRAY_SIZE(config_jump_table
); i
++) {
6585 char *s
= config_jump_table
[i
].name
;
6587 if (s
[strlen(s
) - 1] == '.')
6590 strprint(retv
, inlen
, "%s\n", s
);
6596 int lxc_list_subkeys(struct lxc_conf
*conf
, const char *key
, char *retv
,
6605 memset(retv
, 0, inlen
);
6607 if (strequal(key
, "lxc.apparmor")) {
6608 strprint(retv
, inlen
, "allow_incomplete\n");
6609 strprint(retv
, inlen
, "allow_nesting\n");
6610 strprint(retv
, inlen
, "profile\n");
6611 strprint(retv
, inlen
, "raw\n");
6612 } else if (strequal(key
, "lxc.cgroup")) {
6613 strprint(retv
, inlen
, "dir\n");
6614 } else if (strequal(key
, "lxc.selinux")) {
6615 strprint(retv
, inlen
, "context\n");
6616 strprint(retv
, inlen
, "context.keyring\n");
6617 } else if (strequal(key
, "lxc.mount")) {
6618 strprint(retv
, inlen
, "auto\n");
6619 strprint(retv
, inlen
, "entry\n");
6620 strprint(retv
, inlen
, "fstab\n");
6621 } else if (strequal(key
, "lxc.rootfs")) {
6622 strprint(retv
, inlen
, "mount\n");
6623 strprint(retv
, inlen
, "options\n");
6624 strprint(retv
, inlen
, "path\n");
6625 } else if (strequal(key
, "lxc.uts")) {
6626 strprint(retv
, inlen
, "name\n");
6627 } else if (strequal(key
, "lxc.hook")) {
6628 strprint(retv
, inlen
, "autodev\n");
6629 strprint(retv
, inlen
, "autodevtmpfssize\n");
6630 strprint(retv
, inlen
, "clone\n");
6631 strprint(retv
, inlen
, "destroy\n");
6632 strprint(retv
, inlen
, "mount\n");
6633 strprint(retv
, inlen
, "post-stop\n");
6634 strprint(retv
, inlen
, "pre-mount\n");
6635 strprint(retv
, inlen
, "pre-start\n");
6636 strprint(retv
, inlen
, "start-host\n");
6637 strprint(retv
, inlen
, "start\n");
6638 strprint(retv
, inlen
, "stop\n");
6639 } else if (strequal(key
, "lxc.cap")) {
6640 strprint(retv
, inlen
, "drop\n");
6641 strprint(retv
, inlen
, "keep\n");
6642 } else if (strequal(key
, "lxc.console")) {
6643 strprint(retv
, inlen
, "logfile\n");
6644 strprint(retv
, inlen
, "path\n");
6645 } else if (strequal(key
, "lxc.seccomp")) {
6646 strprint(retv
, inlen
, "profile\n");
6647 } else if (strequal(key
, "lxc.signal")) {
6648 strprint(retv
, inlen
, "halt\n");
6649 strprint(retv
, inlen
, "reboot\n");
6650 strprint(retv
, inlen
, "stop\n");
6651 } else if (strequal(key
, "lxc.start")) {
6652 strprint(retv
, inlen
, "auto\n");
6653 strprint(retv
, inlen
, "delay\n");
6654 strprint(retv
, inlen
, "order\n");
6655 } else if (strequal(key
, "lxc.monitor")) {
6656 strprint(retv
, inlen
, "unshare\n");
6657 } else if (strequal(key
, "lxc.keyring")) {
6658 strprint(retv
, inlen
, "session\n");
6660 fulllen
= ret_errno(EINVAL
);
6666 int lxc_list_net(struct lxc_conf
*c
, const char *key
, char *retv
, int inlen
)
6668 struct config_net_info info
= {};
6669 struct lxc_netdev
*netdev
;
6671 const char *idxstring
;
6674 idxstring
= key
+ STRLITERALLEN("lxc.net.");
6675 if (!isdigit(*idxstring
))
6676 return ret_errno(EINVAL
);
6678 ret
= get_network_config_ops(key
, c
, &info
, false);
6681 return ret_errno(EINVAL
);
6683 netdev
= info
.netdev
;
6688 memset(retv
, 0, inlen
);
6690 strprint(retv
, inlen
, "type\n");
6691 strprint(retv
, inlen
, "script.up\n");
6692 strprint(retv
, inlen
, "script.down\n");
6694 if (netdev
->type
!= LXC_NET_EMPTY
) {
6695 strprint(retv
, inlen
, "flags\n");
6696 strprint(retv
, inlen
, "link\n");
6697 strprint(retv
, inlen
, "name\n");
6698 strprint(retv
, inlen
, "hwaddr\n");
6699 strprint(retv
, inlen
, "mtu\n");
6700 strprint(retv
, inlen
, "ipv6.address\n");
6701 strprint(retv
, inlen
, "ipv6.gateway\n");
6702 strprint(retv
, inlen
, "ipv4.address\n");
6703 strprint(retv
, inlen
, "ipv4.gateway\n");
6706 switch (netdev
->type
) {
6708 strprint(retv
, inlen
, "veth.pair\n");
6709 strprint(retv
, inlen
, "veth.ipv4.route\n");
6710 strprint(retv
, inlen
, "veth.ipv6.route\n");
6711 strprint(retv
, inlen
, "veth.vlan.id\n");
6713 case LXC_NET_MACVLAN
:
6714 strprint(retv
, inlen
, "macvlan.mode\n");
6716 case LXC_NET_IPVLAN
:
6717 strprint(retv
, inlen
, "ipvlan.mode\n");
6718 strprint(retv
, inlen
, "ipvlan.isolation\n");
6721 strprint(retv
, inlen
, "vlan.id\n");
6730 static int set_config_sched_core(const char *key
, const char *value
,
6731 struct lxc_conf
*lxc_conf
, void *data
)
6736 if (lxc_config_value_empty(value
))
6737 return clr_config_sched_core(key
, lxc_conf
, data
);
6739 ret
= lxc_safe_uint(value
, &nr
);
6741 return ret_errno(EINVAL
);
6743 if (nr
!= 0 && nr
!= 1)
6744 return ret_errno(EINVAL
);
6746 lxc_conf
->sched_core
= (nr
== 1);
6750 static int get_config_sched_core(const char *key
, char *retv
, int inlen
,
6751 struct lxc_conf
*c
, void *data
)
6753 return lxc_get_conf_bool(c
, retv
, inlen
, c
->sched_core
);
6756 static int clr_config_sched_core(const char *key
, struct lxc_conf
*c
, void *data
)
6758 c
->sched_core
= false;