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