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