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