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