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