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