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