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