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