]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/confile.c
confile: add clearer for lxc.devttydir
[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>
c2cc9f0a 7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
250b1eec 20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
c2cc9f0a 21 */
12a50cc6 22#define _GNU_SOURCE
2e6e3feb 23#define __STDC_FORMAT_MACROS /* Required for PRIu64 to work. */
c2cc9f0a 24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27#include <unistd.h>
28#include <errno.h>
63376d7d 29#include <fcntl.h>
a84b9932 30#include <ctype.h>
2e6e3feb 31#include <inttypes.h> /* Required for PRIu64 to work. */
a84b9932 32#include <signal.h>
63376d7d 33#include <sys/stat.h>
c2cc9f0a 34#include <sys/types.h>
35#include <sys/param.h>
36#include <sys/utsname.h>
37#include <arpa/inet.h>
38#include <netinet/in.h>
39#include <net/if.h>
67702c21 40#include <time.h>
e1daebd9 41#include <dirent.h>
64c57ea1 42#include <syslog.h>
c2cc9f0a 43
d8e48992 44#include "bdev.h"
b2718c72 45#include "parse.h"
6ff05e18 46#include "config.h"
525f0002 47#include "confile.h"
26c39028 48#include "utils.h"
f2363e38
ÇO
49#include "log.h"
50#include "conf.h"
72d0e1cb 51#include "network.h"
58e0f57d 52#include "lxcseccomp.h"
36eb9bde 53
576400e5 54#if HAVE_IFADDRS_H
55#include <ifaddrs.h>
56#else
57#include <../include/ifaddrs.h>
58#endif
59
6ff05e18
SG
60#if HAVE_SYS_PERSONALITY_H
61#include <sys/personality.h>
62#endif
63
36eb9bde 64lxc_log_define(lxc_confile, lxc);
576f946d 65
713046e3 66static int set_config_personality(const char *, const char *, struct lxc_conf *);
6bede808 67static int get_config_personality(const char *, char *, int, struct lxc_conf *);
e08cb901 68static int clr_config_personality(const char *, struct lxc_conf *);
bdf91ab4 69
713046e3 70static int set_config_pts(const char *, const char *, struct lxc_conf *);
6bede808 71static int get_config_pts(const char *, char *, int, struct lxc_conf *);
03818ae3 72static int clr_config_pts(const char *, struct lxc_conf *);
bdf91ab4 73
713046e3 74static int set_config_tty(const char *, const char *, struct lxc_conf *);
6bede808 75static int get_config_tty(const char *, char *, int, struct lxc_conf *);
e7a4b096 76static int clr_config_tty(const char *, struct lxc_conf *);
5485782f 77
713046e3 78static int set_config_ttydir(const char *, const char *, struct lxc_conf *);
6bede808 79static int get_config_ttydir(const char *, char *, int, struct lxc_conf *);
eaf8c0c7 80static int clr_config_ttydir(const char *, struct lxc_conf *);
8015e018 81
713046e3 82static int set_config_kmsg(const char *, const char *, struct lxc_conf *);
6bede808 83static int get_config_kmsg(const char *, char *, int, struct lxc_conf *);
de1ede69 84
713046e3 85static int set_config_lsm_aa_profile(const char *, const char *, struct lxc_conf *);
6bede808 86static int get_config_lsm_aa_profile(const char *, char *, int, struct lxc_conf *);
104c8e6c 87
713046e3 88static int set_config_lsm_aa_incomplete(const char *, const char *, struct lxc_conf *);
6bede808 89static int get_config_lsm_aa_incomplete(const char *, char *, int, struct lxc_conf *);
d60d18c6 90
713046e3 91static int set_config_lsm_se_context(const char *, const char *, struct lxc_conf *);
6bede808 92static int get_config_lsm_se_context(const char *, char *, int, struct lxc_conf *);
4203a0b5 93
713046e3 94static int set_config_cgroup(const char *, const char *, struct lxc_conf *);
6bede808 95static int get_config_cgroup(const char *, char *, int, struct lxc_conf *);
b863bf92 96
5014ff2e 97static int set_config_idmaps(const char *, const char *, struct lxc_conf *);
6bede808 98static int get_config_idmaps(const char *, char *, int, struct lxc_conf *);
5014ff2e 99
713046e3 100static int set_config_loglevel(const char *, const char *, struct lxc_conf *);
6bede808 101static int get_config_loglevel(const char *, char *, int, struct lxc_conf *);
b29b29be 102
713046e3 103static int set_config_logfile(const char *, const char *, struct lxc_conf *);
6bede808 104static int get_config_logfile(const char *, char *, int, struct lxc_conf *);
3d4630ab 105
713046e3 106static int set_config_mount(const char *, const char *, struct lxc_conf *);
6bede808 107static int get_config_mount(const char *, char *, int, struct lxc_conf *);
0d601acb 108
713046e3 109static int set_config_mount_auto(const char *, const char *, struct lxc_conf *);
6bede808 110static int get_config_mount_auto(const char *, char *, int, struct lxc_conf *);
0d601acb 111
713046e3 112static int set_config_fstab(const char *, const char *, struct lxc_conf *);
6bede808 113static int get_config_fstab(const char *, char *, int, struct lxc_conf *);
0d601acb 114
713046e3 115static int set_config_rootfs(const char *, const char *, struct lxc_conf *);
6bede808 116static int get_config_rootfs(const char *, char *, int, struct lxc_conf *);
819114b6 117
713046e3 118static int set_config_rootfs_mount(const char *, const char *, struct lxc_conf *);
6bede808 119static int get_config_rootfs_mount(const char *, char *, int, struct lxc_conf *);
3af60359 120
713046e3 121static int set_config_rootfs_options(const char *, const char *, struct lxc_conf *);
6bede808 122static int get_config_rootfs_options(const char *, char *, int, struct lxc_conf *);
0e9db631 123
713046e3 124static int set_config_rootfs_backend(const char *, const char *, struct lxc_conf *);
6bede808 125static int get_config_rootfs_backend(const char *, char *, int, struct lxc_conf *);
8f183f38 126
713046e3 127static int set_config_pivotdir(const char *, const char *, struct lxc_conf *);
6bede808 128static int get_config_pivotdir(const char *, char *, int, struct lxc_conf *);
b87574e7 129
713046e3 130static int set_config_utsname(const char *, const char *, struct lxc_conf *);
6bede808 131static int get_config_utsname(const char *, char *, int, struct lxc_conf *);
e274f8b0 132
466c2e93 133static int set_config_hooks(const char *, const char *, struct lxc_conf *lxc_conf);
6bede808 134static int get_config_hooks(const char *, char *, int, struct lxc_conf *);
466c2e93 135
713046e3 136static int set_config_network(const char *, const char *, struct lxc_conf *);
6bede808 137static int get_config_network(const char *, char *, int, struct lxc_conf *);
d2ceff53 138
713046e3
CB
139static int set_config_network_type(const char *, const char *, struct lxc_conf *);
140static int set_config_network_flags(const char *, const char *, struct lxc_conf *);
141static int set_config_network_link(const char *, const char *, struct lxc_conf *);
142static int set_config_network_name(const char *, const char *, struct lxc_conf *);
143static int set_config_network_veth_pair(const char *, const char *, struct lxc_conf *);
144static int set_config_network_macvlan_mode(const char *, const char *, struct lxc_conf *);
145static int set_config_network_hwaddr(const char *, const char *, struct lxc_conf *);
146static int set_config_network_vlan_id(const char *, const char *, struct lxc_conf *);
147static int set_config_network_mtu(const char *, const char *, struct lxc_conf *);
148static int set_config_network_ipv4(const char *, const char *, struct lxc_conf *);
149static int set_config_network_ipv4_gateway(const char *, const char *, struct lxc_conf *);
150static int set_config_network_script_up(const char *, const char *, struct lxc_conf *);
151static int set_config_network_script_down(const char *, const char *, struct lxc_conf *);
152static int set_config_network_ipv6(const char *, const char *, struct lxc_conf *);
153static int set_config_network_ipv6_gateway(const char *, const char *, struct lxc_conf *);
6bede808 154static int get_config_network_item(const char *, char *, int, struct lxc_conf *);
bdccff60 155
713046e3 156static int set_config_cap_drop(const char *, const char *, struct lxc_conf *);
6bede808 157static int get_config_cap_drop(const char *, char *, int, struct lxc_conf *);
1c96d6d8 158
713046e3 159static int set_config_cap_keep(const char *, const char *, struct lxc_conf *);
6bede808 160static int get_config_cap_keep(const char *, char *, int, struct lxc_conf *);
b80927f2 161
713046e3 162static int set_config_console(const char *, const char *, struct lxc_conf *);
6bede808 163static int get_config_console(const char *, char *, int, struct lxc_conf *);
0692663a 164
713046e3 165static int set_config_console_logfile(const char *, const char *, struct lxc_conf *);
6bede808 166static int get_config_console_logfile(const char *, char *, int, struct lxc_conf *);
794d1c06 167
713046e3 168static int set_config_seccomp(const char *, const char *, struct lxc_conf *);
6bede808 169static int get_config_seccomp(const char *, char *, int, struct lxc_conf *);
75f55b1f 170
713046e3
CB
171static int set_config_includefile(const char *, const char *, struct lxc_conf *);
172static int set_config_network_nic(const char *, const char *, struct lxc_conf *);
97f6dad0 173
713046e3 174static int set_config_autodev(const char *, const char *, struct lxc_conf *);
6bede808 175static int get_config_autodev(const char *, char *, int, struct lxc_conf *);
97f6dad0 176
713046e3 177static int set_config_haltsignal(const char *, const char *, struct lxc_conf *);
6bede808 178static int get_config_haltsignal(const char *, char *, int, struct lxc_conf *);
afee4324 179
713046e3 180static int set_config_rebootsignal(const char *, const char *, struct lxc_conf *);
6bede808 181static int get_config_rebootsignal(const char *, char *, int, struct lxc_conf *);
3aa8f359 182
713046e3 183static int set_config_stopsignal(const char *, const char *, struct lxc_conf *);
6bede808 184static int get_config_stopsignal(const char *, char *, int, struct lxc_conf *);
2e16269f 185
713046e3 186static int set_config_start(const char *, const char *, struct lxc_conf *);
6bede808 187static int get_config_start(const char *, char *, int, struct lxc_conf *);
54345299 188
713046e3 189static int set_config_syslog(const char *, const char *, struct lxc_conf *);
6bede808 190static int get_config_syslog(const char *, char *, int, struct lxc_conf *);
de9df15e 191
713046e3 192static int set_config_monitor(const char *, const char *, struct lxc_conf *);
6bede808 193static int get_config_monitor(const char *, char *, int, struct lxc_conf *);
ac0f949c 194
713046e3 195static int set_config_group(const char *, const char *, struct lxc_conf *);
6bede808 196static int get_config_group(const char *, char *, int, struct lxc_conf *);
90ec7b6e 197
713046e3 198static int set_config_environment(const char *, const char *, struct lxc_conf *);
6bede808 199static int get_config_environment(const char *, char *, int, struct lxc_conf *);
aa0db7d3 200
713046e3 201static int set_config_init_cmd(const char *, const char *, struct lxc_conf *);
6bede808 202static int get_config_init_cmd(const char *, char *, int, struct lxc_conf *);
96dfcb7d 203
713046e3 204static int set_config_init_uid(const char *, const char *, struct lxc_conf *);
6bede808 205static int get_config_init_uid(const char *, char *, int, struct lxc_conf *);
1398e9b1 206
713046e3 207static int set_config_init_gid(const char *, const char *, struct lxc_conf *);
6bede808 208static int get_config_init_gid(const char *, char *, int, struct lxc_conf *);
dfeb7e42 209
713046e3 210static int set_config_ephemeral(const char *, const char *, struct lxc_conf *);
6bede808 211static int get_config_ephemeral(const char *, char *, int, struct lxc_conf *);
62048afe 212
713046e3 213static int set_config_no_new_privs(const char *, const char *, struct lxc_conf *);
6bede808 214static int get_config_no_new_privs(const char *, char *, int, struct lxc_conf *);
b09521ac 215
713046e3 216static int set_config_limit(const char *, const char *, struct lxc_conf *);
6bede808 217static int get_config_limit(const char *, char *, int, struct lxc_conf *);
c2cc9f0a 218
72d0e1cb 219static struct lxc_config_t config[] = {
e08cb901 220 { "lxc.arch", set_config_personality, get_config_personality, clr_config_personality, },
03818ae3 221 { "lxc.pts", set_config_pts, get_config_pts, clr_config_pts, },
e7a4b096 222 { "lxc.tty", set_config_tty, get_config_tty, clr_config_tty, },
eaf8c0c7 223 { "lxc.devttydir", set_config_ttydir, get_config_ttydir, clr_config_ttydir, },
504a2217
CB
224 { "lxc.kmsg", set_config_kmsg, get_config_kmsg, NULL },
225 { "lxc.aa_profile", set_config_lsm_aa_profile, get_config_lsm_aa_profile, NULL },
226 { "lxc.aa_allow_incomplete", set_config_lsm_aa_incomplete, get_config_lsm_aa_incomplete, NULL },
227 { "lxc.se_context", set_config_lsm_se_context, get_config_lsm_se_context, NULL },
228 { "lxc.cgroup", set_config_cgroup, get_config_cgroup, NULL },
229 { "lxc.id_map", set_config_idmaps, get_config_idmaps, NULL },
230 { "lxc.loglevel", set_config_loglevel, get_config_loglevel, NULL },
231 { "lxc.logfile", set_config_logfile, get_config_logfile, NULL },
232 { "lxc.mount.entry", set_config_mount, get_config_mount, NULL },
233 { "lxc.mount.auto", set_config_mount_auto, get_config_mount_auto, NULL },
234 { "lxc.mount", set_config_fstab, get_config_fstab, NULL },
235 { "lxc.rootfs.mount", set_config_rootfs_mount, get_config_rootfs_mount, NULL },
236 { "lxc.rootfs.options", set_config_rootfs_options, get_config_rootfs_options, NULL },
237 { "lxc.rootfs.backend", set_config_rootfs_backend, get_config_rootfs_backend, NULL },
238 { "lxc.rootfs", set_config_rootfs, get_config_rootfs, NULL },
239 { "lxc.pivotdir", set_config_pivotdir, get_config_pivotdir, NULL },
240 { "lxc.utsname", set_config_utsname, get_config_utsname, NULL },
241 { "lxc.hook.pre-start", set_config_hooks, get_config_hooks, NULL },
242 { "lxc.hook.pre-mount", set_config_hooks, get_config_hooks, NULL },
243 { "lxc.hook.mount", set_config_hooks, get_config_hooks, NULL },
244 { "lxc.hook.autodev", set_config_hooks, get_config_hooks, NULL },
245 { "lxc.hook.start", set_config_hooks, get_config_hooks, NULL },
246 { "lxc.hook.stop", set_config_hooks, get_config_hooks, NULL },
247 { "lxc.hook.post-stop", set_config_hooks, get_config_hooks, NULL },
248 { "lxc.hook.clone", set_config_hooks, get_config_hooks, NULL },
249 { "lxc.hook.destroy", set_config_hooks, get_config_hooks, NULL },
250 { "lxc.hook", set_config_hooks, get_config_hooks, NULL },
251 { "lxc.network.type", set_config_network_type, get_config_network_item, NULL },
252 { "lxc.network.flags", set_config_network_flags, get_config_network_item, NULL },
253 { "lxc.network.link", set_config_network_link, get_config_network_item, NULL },
254 { "lxc.network.name", set_config_network_name, get_config_network_item, NULL },
255 { "lxc.network.macvlan.mode", set_config_network_macvlan_mode, get_config_network_item, NULL },
256 { "lxc.network.veth.pair", set_config_network_veth_pair, get_config_network_item, NULL },
257 { "lxc.network.script.up", set_config_network_script_up, get_config_network_item, NULL },
258 { "lxc.network.script.down", set_config_network_script_down, get_config_network_item, NULL },
259 { "lxc.network.hwaddr", set_config_network_hwaddr, get_config_network_item, NULL },
260 { "lxc.network.mtu", set_config_network_mtu, get_config_network_item, NULL },
261 { "lxc.network.vlan.id", set_config_network_vlan_id, get_config_network_item, NULL },
262 { "lxc.network.ipv4.gateway", set_config_network_ipv4_gateway, get_config_network_item, NULL },
263 { "lxc.network.ipv4", set_config_network_ipv4, get_config_network_item, NULL },
264 { "lxc.network.ipv6.gateway", set_config_network_ipv6_gateway, get_config_network_item, NULL },
265 { "lxc.network.ipv6", set_config_network_ipv6, get_config_network_item, NULL },
266 { "lxc.network.", set_config_network_nic, get_config_network_item, NULL },
267 { "lxc.network", set_config_network, get_config_network, NULL },
268 { "lxc.cap.drop", set_config_cap_drop, get_config_cap_drop, NULL },
269 { "lxc.cap.keep", set_config_cap_keep, get_config_cap_keep, NULL },
270 { "lxc.console.logfile", set_config_console_logfile, get_config_console_logfile, NULL },
271 { "lxc.console", set_config_console, get_config_console, NULL },
272 { "lxc.seccomp", set_config_seccomp, get_config_seccomp, NULL },
273 { "lxc.include", set_config_includefile, NULL, NULL },
274 { "lxc.autodev", set_config_autodev, get_config_autodev, NULL },
275 { "lxc.haltsignal", set_config_haltsignal, get_config_haltsignal, NULL },
276 { "lxc.rebootsignal", set_config_rebootsignal, get_config_rebootsignal, NULL },
277 { "lxc.stopsignal", set_config_stopsignal, get_config_stopsignal, NULL },
278 { "lxc.start.auto", set_config_start, get_config_start, NULL },
279 { "lxc.start.delay", set_config_start, get_config_start, NULL },
280 { "lxc.start.order", set_config_start, get_config_start, NULL },
281 { "lxc.monitor.unshare", set_config_monitor, get_config_monitor, NULL },
282 { "lxc.group", set_config_group, get_config_group, NULL },
283 { "lxc.environment", set_config_environment, get_config_environment, NULL },
284 { "lxc.init_cmd", set_config_init_cmd, get_config_init_cmd, NULL },
285 { "lxc.init_uid", set_config_init_uid, get_config_init_uid, NULL },
286 { "lxc.init_gid", set_config_init_gid, get_config_init_gid, NULL },
287 { "lxc.ephemeral", set_config_ephemeral, get_config_ephemeral, NULL },
288 { "lxc.syslog", set_config_syslog, get_config_syslog, NULL },
289 { "lxc.no_new_privs", set_config_no_new_privs, get_config_no_new_privs, NULL },
290 { "lxc.limit", set_config_limit, get_config_limit, NULL },
a84b9932
AV
291};
292
293struct signame {
294 int num;
74a3920a 295 const char *name;
a84b9932
AV
296};
297
74a3920a 298static const struct signame signames[] = {
504a2217
CB
299 { SIGHUP, "HUP" },
300 { SIGINT, "INT" },
301 { SIGQUIT, "QUIT" },
302 { SIGILL, "ILL" },
303 { SIGABRT, "ABRT" },
304 { SIGFPE, "FPE" },
305 { SIGKILL, "KILL" },
306 { SIGSEGV, "SEGV" },
307 { SIGPIPE, "PIPE" },
308 { SIGALRM, "ALRM" },
309 { SIGTERM, "TERM" },
310 { SIGUSR1, "USR1" },
311 { SIGUSR2, "USR2" },
312 { SIGCHLD, "CHLD" },
313 { SIGCONT, "CONT" },
314 { SIGSTOP, "STOP" },
315 { SIGTSTP, "TSTP" },
316 { SIGTTIN, "TTIN" },
317 { SIGTTOU, "TTOU" },
89dfc302 318#ifdef SIGTRAP
504a2217 319 { SIGTRAP, "TRAP" },
89dfc302
SY
320#endif
321#ifdef SIGIOT
504a2217 322 { SIGIOT, "IOT" },
89dfc302
SY
323#endif
324#ifdef SIGEMT
504a2217 325 { SIGEMT, "EMT" },
89dfc302
SY
326#endif
327#ifdef SIGBUS
504a2217 328 { SIGBUS, "BUS" },
89dfc302
SY
329#endif
330#ifdef SIGSTKFLT
331 { SIGSTKFLT, "STKFLT" },
332#endif
333#ifdef SIGCLD
504a2217 334 { SIGCLD, "CLD" },
89dfc302
SY
335#endif
336#ifdef SIGURG
504a2217 337 { SIGURG, "URG" },
89dfc302
SY
338#endif
339#ifdef SIGXCPU
504a2217 340 { SIGXCPU, "XCPU" },
89dfc302
SY
341#endif
342#ifdef SIGXFSZ
504a2217 343 { SIGXFSZ, "XFSZ" },
89dfc302
SY
344#endif
345#ifdef SIGVTALRM
346 { SIGVTALRM, "VTALRM" },
347#endif
348#ifdef SIGPROF
504a2217 349 { SIGPROF, "PROF" },
89dfc302
SY
350#endif
351#ifdef SIGWINCH
504a2217 352 { SIGWINCH, "WINCH" },
89dfc302
SY
353#endif
354#ifdef SIGIO
504a2217 355 { SIGIO, "IO" },
89dfc302
SY
356#endif
357#ifdef SIGPOLL
504a2217 358 { SIGPOLL, "POLL" },
89dfc302
SY
359#endif
360#ifdef SIGINFO
504a2217 361 { SIGINFO, "INFO" },
89dfc302
SY
362#endif
363#ifdef SIGLOST
504a2217 364 { SIGLOST, "LOST" },
89dfc302
SY
365#endif
366#ifdef SIGPWR
504a2217 367 { SIGPWR, "PWR" },
89dfc302
SY
368#endif
369#ifdef SIGUNUSED
370 { SIGUNUSED, "UNUSED" },
371#endif
372#ifdef SIGSYS
504a2217 373 { SIGSYS, "SYS" },
89dfc302 374#endif
c2cc9f0a 375};
376
504a2217 377static const size_t config_size = sizeof(config) / sizeof(struct lxc_config_t);
c2cc9f0a 378
72d0e1cb 379extern struct lxc_config_t *lxc_getconfig(const char *key)
c2cc9f0a 380{
84760c11 381 size_t i;
c2cc9f0a 382
383 for (i = 0; i < config_size; i++)
504a2217 384 if (!strncmp(config[i].name, key, strlen(config[i].name)))
c2cc9f0a 385 return &config[i];
386 return NULL;
387}
388
504a2217
CB
389#define strprint(str, inlen, ...) \
390 do { \
391 len = snprintf(str, inlen, ##__VA_ARGS__); \
392 if (len < 0) { \
393 SYSERROR("failed to create string"); \
394 return -1; \
395 }; \
396 fulllen += len; \
397 if (inlen > 0) { \
398 if (str) \
399 str += len; \
400 inlen -= len; \
401 if (inlen < 0) \
402 inlen = 0; \
403 } \
72d0e1cb
SG
404 } while (0);
405
406int lxc_listconfigs(char *retv, int inlen)
407{
84760c11 408 size_t i;
504a2217
CB
409 int len;
410 int fulllen = 0;
72d0e1cb
SG
411
412 if (!retv)
413 inlen = 0;
414 else
415 memset(retv, 0, inlen);
504a2217 416
72d0e1cb
SG
417 for (i = 0; i < config_size; i++) {
418 char *s = config[i].name;
504a2217 419 if (s[strlen(s) - 1] == '.')
72d0e1cb
SG
420 continue;
421 strprint(retv, inlen, "%s\n", s);
422 }
504a2217 423
72d0e1cb
SG
424 return fulllen;
425}
426
fe8d7be7
CB
427static inline bool config_value_empty(const char *value)
428{
429 if (value && strlen(value) > 0)
430 return false;
431
432 return true;
433}
434
713046e3 435static int set_config_string_item(char **conf_item, const char *value)
6d03d92a
DE
436{
437 char *new_value;
438
e70b9db5 439 if (config_value_empty(value)) {
f10fad2f 440 free(*conf_item);
d6eca240 441 *conf_item = NULL;
6d03d92a 442 return 0;
d6eca240 443 }
6d03d92a
DE
444
445 new_value = strdup(value);
446 if (!new_value) {
e70b9db5 447 SYSERROR("failed to duplicate string \"%s\"", value);
6d03d92a
DE
448 return -1;
449 }
450
f10fad2f 451 free(*conf_item);
6d03d92a
DE
452 *conf_item = new_value;
453 return 0;
454}
455
713046e3 456static int set_config_string_item_max(char **conf_item, const char *value,
504a2217 457 size_t max)
6d03d92a
DE
458{
459 if (strlen(value) >= max) {
a5a82508 460 ERROR("%s is too long (>= %lu)", value, (unsigned long)max);
6d03d92a
DE
461 return -1;
462 }
463
713046e3 464 return set_config_string_item(conf_item, value);
6d03d92a
DE
465}
466
713046e3 467static int set_config_path_item(char **conf_item, const char *value)
6d03d92a 468{
713046e3 469 return set_config_string_item_max(conf_item, value, PATH_MAX);
6d03d92a
DE
470}
471
72d0e1cb 472/*
504a2217
CB
473 * Config entry is something like "lxc.network.0.ipv4" the key 'lxc.network.'
474 * was found. So we make sure next comes an integer, find the right callback
475 * (by rewriting the key), and call it.
72d0e1cb 476 */
713046e3 477static int set_config_network_nic(const char *key, const char *value,
504a2217 478 struct lxc_conf *lxc_conf)
72d0e1cb
SG
479{
480 char *copy = strdup(key), *p;
481 int ret = -1;
482 struct lxc_config_t *config;
483
484 if (!copy) {
485 SYSERROR("failed to allocate memory");
486 return -1;
487 }
488 /*
504a2217 489 * Ok we know that to get here we've got "lxc.network."
72d0e1cb 490 * and it isn't any of the other network entries. So
504a2217 491 * after the second . Should come an integer (# of defined
72d0e1cb
SG
492 * nic) followed by a valid entry.
493 */
504a2217 494 if (*(key + 12) < '0' || *(key + 12) > '9')
72d0e1cb 495 goto out;
504a2217
CB
496
497 p = strchr(key + 12, '.');
72d0e1cb
SG
498 if (!p)
499 goto out;
504a2217
CB
500
501 strcpy(copy + 12, p + 1);
72d0e1cb
SG
502 config = lxc_getconfig(copy);
503 if (!config) {
504 ERROR("unknown key %s", key);
505 goto out;
506 }
d37f7cd7 507 ret = config->set(key, value, lxc_conf);
72d0e1cb
SG
508
509out:
510 free(copy);
511 return ret;
512}
513
713046e3 514static int set_config_network(const char *key, const char *value,
504a2217 515 struct lxc_conf *lxc_conf)
6b0d5538 516{
61924323 517 if (!config_value_empty(value)) {
6b0d5538
SH
518 ERROR("lxc.network must not have a value");
519 return -1;
520 }
521
522 return lxc_clear_config_network(lxc_conf);
523}
524
261658e8
BP
525static int macvlan_mode(int *valuep, const char *value);
526
713046e3 527static int set_config_network_type(const char *key, const char *value,
504a2217 528 struct lxc_conf *lxc_conf)
c2cc9f0a 529{
5f4535a3 530 struct lxc_list *network = &lxc_conf->network;
c2cc9f0a 531 struct lxc_netdev *netdev;
532 struct lxc_list *list;
c2cc9f0a 533
d4ba45b3 534 if (config_value_empty(value))
7d0eb87e
SH
535 return lxc_clear_config_network(lxc_conf);
536
c2cc9f0a 537 netdev = malloc(sizeof(*netdev));
538 if (!netdev) {
36eb9bde 539 SYSERROR("failed to allocate memory");
c2cc9f0a 540 return -1;
541 }
542
82d5ae15 543 memset(netdev, 0, sizeof(*netdev));
c2cc9f0a 544 lxc_list_init(&netdev->ipv4);
545 lxc_list_init(&netdev->ipv6);
c2cc9f0a 546
547 list = malloc(sizeof(*list));
548 if (!list) {
36eb9bde 549 SYSERROR("failed to allocate memory");
022de5f3 550 free(netdev);
c2cc9f0a 551 return -1;
552 }
553
554 lxc_list_init(list);
5f4535a3 555 list->elem = netdev;
c2cc9f0a 556
bac89583 557 lxc_list_add_tail(network, list);
a871ff6b 558
c2cc9f0a 559 if (!strcmp(value, "veth"))
24654103 560 netdev->type = LXC_NET_VETH;
261658e8 561 else if (!strcmp(value, "macvlan")) {
24654103 562 netdev->type = LXC_NET_MACVLAN;
261658e8 563 macvlan_mode(&netdev->priv.macvlan_attr.mode, "private");
504a2217 564 } else if (!strcmp(value, "vlan"))
24654103 565 netdev->type = LXC_NET_VLAN;
c2cc9f0a 566 else if (!strcmp(value, "phys"))
24654103 567 netdev->type = LXC_NET_PHYS;
5f58350a 568 else if (!strcmp(value, "empty"))
24654103 569 netdev->type = LXC_NET_EMPTY;
26b797f3
SH
570 else if (!strcmp(value, "none"))
571 netdev->type = LXC_NET_NONE;
c2cc9f0a 572 else {
36eb9bde 573 ERROR("invalid network type %s", value);
c2cc9f0a 574 return -1;
575 }
576 return 0;
577}
578
a059591e
DL
579static int config_ip_prefix(struct in_addr *addr)
580{
581 if (IN_CLASSA(addr->s_addr))
582 return 32 - IN_CLASSA_NSHIFT;
583 if (IN_CLASSB(addr->s_addr))
584 return 32 - IN_CLASSB_NSHIFT;
585 if (IN_CLASSC(addr->s_addr))
586 return 32 - IN_CLASSC_NSHIFT;
587
588 return 0;
589}
590
72d0e1cb 591/*
504a2217
CB
592 * If you have p="lxc.network.0.link", pass it p+12
593 * to get back '0' (the index of the nic).
72d0e1cb
SG
594 */
595static int get_network_netdev_idx(const char *key)
596{
597 int ret, idx;
598
599 if (*key < '0' || *key > '9')
600 return -1;
504a2217 601
72d0e1cb
SG
602 ret = sscanf(key, "%d", &idx);
603 if (ret != 1)
604 return -1;
504a2217 605
72d0e1cb
SG
606 return idx;
607}
608
609/*
504a2217
CB
610 * If you have p="lxc.network.0", pass this p+12 and it will return
611 * the netdev of the first configured nic.
72d0e1cb
SG
612 */
613static struct lxc_netdev *get_netdev_from_key(const char *key,
614 struct lxc_list *network)
615{
504a2217 616 int idx;
72d0e1cb 617 struct lxc_list *it;
504a2217
CB
618 int i = 0;
619 struct lxc_netdev *netdev = NULL;
620
621 idx = get_network_netdev_idx(key);
72d0e1cb
SG
622 if (idx == -1)
623 return NULL;
504a2217 624
72d0e1cb
SG
625 lxc_list_for_each(it, network) {
626 if (idx == i++) {
627 netdev = it->elem;
628 break;
629 }
630 }
504a2217 631
72d0e1cb
SG
632 return netdev;
633}
634
504a2217
CB
635extern int lxc_list_nicconfigs(struct lxc_conf *c, const char *key, char *retv,
636 int inlen)
72d0e1cb
SG
637{
638 struct lxc_netdev *netdev;
504a2217
CB
639 int len;
640 int fulllen = 0;
72d0e1cb 641
504a2217 642 netdev = get_netdev_from_key(key + 12, &c->network);
72d0e1cb
SG
643 if (!netdev)
644 return -1;
645
646 if (!retv)
647 inlen = 0;
648 else
649 memset(retv, 0, inlen);
650
74836992 651 strprint(retv, inlen, "type\n");
72d0e1cb 652 strprint(retv, inlen, "script.up\n");
8fc8295a 653 strprint(retv, inlen, "script.down\n");
72d0e1cb
SG
654 if (netdev->type != LXC_NET_EMPTY) {
655 strprint(retv, inlen, "flags\n");
656 strprint(retv, inlen, "link\n");
657 strprint(retv, inlen, "name\n");
658 strprint(retv, inlen, "hwaddr\n");
659 strprint(retv, inlen, "mtu\n");
660 strprint(retv, inlen, "ipv6\n");
9eaf8a59 661 strprint(retv, inlen, "ipv6.gateway\n");
72d0e1cb 662 strprint(retv, inlen, "ipv4\n");
9eaf8a59 663 strprint(retv, inlen, "ipv4.gateway\n");
72d0e1cb 664 }
504a2217
CB
665
666 switch (netdev->type) {
72d0e1cb
SG
667 case LXC_NET_VETH:
668 strprint(retv, inlen, "veth.pair\n");
669 break;
670 case LXC_NET_MACVLAN:
671 strprint(retv, inlen, "macvlan.mode\n");
672 break;
673 case LXC_NET_VLAN:
674 strprint(retv, inlen, "vlan.id\n");
675 break;
676 case LXC_NET_PHYS:
677 break;
678 }
504a2217 679
72d0e1cb
SG
680 return fulllen;
681}
682
16950ecb
DL
683static struct lxc_netdev *network_netdev(const char *key, const char *value,
684 struct lxc_list *network)
c2cc9f0a 685{
72d0e1cb 686 struct lxc_netdev *netdev = NULL;
c2cc9f0a 687
5f4535a3 688 if (lxc_list_empty(network)) {
504a2217
CB
689 ERROR("network is not created for '%s' = '%s' option", key,
690 value);
33c945e0 691 return NULL;
c2cc9f0a 692 }
693
504a2217 694 if (get_network_netdev_idx(key + 12) == -1)
72d0e1cb
SG
695 netdev = lxc_list_last_elem(network);
696 else
504a2217 697 netdev = get_netdev_from_key(key + 12, network);
72d0e1cb 698
5f4535a3 699 if (!netdev) {
504a2217
CB
700 ERROR("no network device defined for '%s' = '%s' option", key,
701 value);
33c945e0 702 return NULL;
c2cc9f0a 703 }
704
33c945e0 705 return netdev;
c2cc9f0a 706}
707
12a50cc6 708static int network_ifname(char **valuep, const char *value)
c2cc9f0a 709{
713046e3 710 return set_config_string_item_max(valuep, value, IFNAMSIZ);
c2cc9f0a 711}
712
e892973e 713#ifndef MACVLAN_MODE_PRIVATE
504a2217 714#define MACVLAN_MODE_PRIVATE 1
e892973e
DL
715#endif
716
717#ifndef MACVLAN_MODE_VEPA
504a2217 718#define MACVLAN_MODE_VEPA 2
e892973e
DL
719#endif
720
721#ifndef MACVLAN_MODE_BRIDGE
504a2217 722#define MACVLAN_MODE_BRIDGE 4
e892973e
DL
723#endif
724
99854161 725#ifndef MACVLAN_MODE_PASSTHRU
504a2217 726#define MACVLAN_MODE_PASSTHRU 8
99854161
EL
727#endif
728
12a50cc6 729static int macvlan_mode(int *valuep, const char *value)
e892973e
DL
730{
731 struct mc_mode {
732 char *name;
733 int mode;
734 } m[] = {
504a2217
CB
735 { "private", MACVLAN_MODE_PRIVATE },
736 { "vepa", MACVLAN_MODE_VEPA },
737 { "bridge", MACVLAN_MODE_BRIDGE },
738 { "passthru", MACVLAN_MODE_PASSTHRU },
e892973e
DL
739 };
740
84760c11 741 size_t i;
e892973e 742
504a2217 743 for (i = 0; i < sizeof(m) / sizeof(m[0]); i++) {
e892973e
DL
744 if (strcmp(m[i].name, value))
745 continue;
746
747 *valuep = m[i].mode;
748 return 0;
749 }
750
751 return -1;
752}
753
508c263e
SH
754static int rand_complete_hwaddr(char *hwaddr)
755{
756 const char hex[] = "0123456789abcdef";
757 char *curs = hwaddr;
758
759#ifndef HAVE_RAND_R
760 randseed(true);
761#else
504a2217
CB
762 unsigned int seed;
763
764 seed = randseed(false);
508c263e 765#endif
504a2217
CB
766 while (*curs != '\0' && *curs != '\n') {
767 if (*curs == 'x' || *curs == 'X') {
508c263e 768 if (curs - hwaddr == 1) {
504a2217 769 /* ensure address is unicast */
508c263e
SH
770#ifdef HAVE_RAND_R
771 *curs = hex[rand_r(&seed) & 0x0E];
772 } else {
773 *curs = hex[rand_r(&seed) & 0x0F];
774#else
775 *curs = hex[rand() & 0x0E];
776 } else {
777 *curs = hex[rand() & 0x0F];
778#endif
779 }
780 }
781 curs++;
782 }
783 return 0;
784}
785
713046e3 786static int set_config_network_flags(const char *key, const char *value,
504a2217 787 struct lxc_conf *lxc_conf)
c2cc9f0a 788{
c2cc9f0a 789 struct lxc_netdev *netdev;
790
16950ecb 791 netdev = network_netdev(key, value, &lxc_conf->network);
33c945e0 792 if (!netdev)
c2cc9f0a 793 return -1;
c2cc9f0a 794
33c945e0 795 netdev->flags |= IFF_UP;
c2cc9f0a 796
33c945e0
MT
797 return 0;
798}
799
504a2217
CB
800static int set_network_link(const char *key, const char *value,
801 struct lxc_conf *lxc_conf)
576400e5 802{
504a2217 803 struct lxc_netdev *netdev;
576400e5 804
504a2217
CB
805 netdev = network_netdev(key, value, &lxc_conf->network);
806 if (!netdev)
807 return -1;
576400e5 808
504a2217 809 return network_ifname(&netdev->link, value);
576400e5 810}
811
812static int create_matched_ifnames(const char *value, struct lxc_conf *lxc_conf)
813{
814 struct ifaddrs *ifaddr, *ifa;
504a2217
CB
815 int n;
816 int ret = 0;
576400e5 817 const char *type_key = "lxc.network.type";
818 const char *link_key = "lxc.network.link";
819 const char *tmpvalue = "phys";
576400e5 820
821 if (getifaddrs(&ifaddr) == -1) {
822 SYSERROR("Get network interfaces failed");
823 return -1;
824 }
825
826 for (ifa = ifaddr, n = 0; ifa != NULL; ifa = ifa->ifa_next, n++) {
827 if (!ifa->ifa_addr)
828 continue;
829 if (ifa->ifa_addr->sa_family != AF_PACKET)
830 continue;
831
504a2217
CB
832 if (!strncmp(value, ifa->ifa_name, strlen(value) - 1)) {
833 ret = set_config_network_type(type_key, tmpvalue,
834 lxc_conf);
576400e5 835 if (!ret) {
504a2217
CB
836 ret = set_network_link(link_key, ifa->ifa_name,
837 lxc_conf);
576400e5 838 if (ret) {
839 ERROR("failed to create matched ifnames");
840 break;
841 }
842 } else {
843 ERROR("failed to create matched ifnames");
844 break;
845 }
846 }
847 }
848
504a2217
CB
849 freeifaddrs(ifaddr);
850 ifaddr = NULL;
091045f8 851
576400e5 852 return ret;
853}
854
713046e3 855static int set_config_network_link(const char *key, const char *value,
504a2217 856 struct lxc_conf *lxc_conf)
33c945e0
MT
857{
858 struct lxc_netdev *netdev;
504a2217 859 struct lxc_list *it;
576400e5 860 int ret = 0;
33c945e0 861
16950ecb 862 netdev = network_netdev(key, value, &lxc_conf->network);
33c945e0 863 if (!netdev)
c2cc9f0a 864 return -1;
c2cc9f0a 865
576400e5 866 if (value[strlen(value) - 1] == '+' && netdev->type == LXC_NET_PHYS) {
504a2217 867 /* Get the last network list and remove it. */
576400e5 868 it = lxc_conf->network.prev;
869 if (((struct lxc_netdev *)(it->elem))->type != LXC_NET_PHYS) {
504a2217
CB
870 ERROR("lxc config cannot support string pattern "
871 "matching for this link type");
576400e5 872 return -1;
873 }
874
875 lxc_list_del(it);
876 free(it);
877 ret = create_matched_ifnames(value, lxc_conf);
576400e5 878 } else {
879 ret = network_ifname(&netdev->link, value);
880 }
881
882 return ret;
c2cc9f0a 883}
884
713046e3 885static int set_config_network_name(const char *key, const char *value,
504a2217 886 struct lxc_conf *lxc_conf)
c2cc9f0a 887{
c2cc9f0a 888 struct lxc_netdev *netdev;
889
16950ecb 890 netdev = network_netdev(key, value, &lxc_conf->network);
33c945e0 891 if (!netdev)
c2cc9f0a 892 return -1;
c2cc9f0a 893
33c945e0
MT
894 return network_ifname(&netdev->name, value);
895}
896
713046e3 897static int set_config_network_veth_pair(const char *key, const char *value,
504a2217 898 struct lxc_conf *lxc_conf)
e892973e
DL
899{
900 struct lxc_netdev *netdev;
901
902 netdev = network_netdev(key, value, &lxc_conf->network);
903 if (!netdev)
904 return -1;
905
c5316d60 906 if (netdev->type != LXC_NET_VETH) {
128d327a 907 ERROR("Invalid veth pair for a non-veth netdev");
c5316d60
SH
908 return -1;
909 }
504a2217 910
e892973e
DL
911 return network_ifname(&netdev->priv.veth_attr.pair, value);
912}
913
713046e3 914static int set_config_network_macvlan_mode(const char *key, const char *value,
504a2217 915 struct lxc_conf *lxc_conf)
8634bc19
MT
916{
917 struct lxc_netdev *netdev;
918
919 netdev = network_netdev(key, value, &lxc_conf->network);
920 if (!netdev)
921 return -1;
922
c5316d60 923 if (netdev->type != LXC_NET_MACVLAN) {
128d327a 924 ERROR("Invalid macvlan.mode for a non-macvlan netdev");
c5316d60
SH
925 return -1;
926 }
504a2217 927
e892973e 928 return macvlan_mode(&netdev->priv.macvlan_attr.mode, value);
8634bc19
MT
929}
930
713046e3 931static int set_config_network_hwaddr(const char *key, const char *value,
504a2217 932 struct lxc_conf *lxc_conf)
33c945e0
MT
933{
934 struct lxc_netdev *netdev;
504a2217 935 char *new_value;
33c945e0 936
504a2217 937 new_value = strdup(value);
508c263e 938 if (!new_value) {
504a2217 939 SYSERROR("failed to strdup \"%s\"", value);
c2cc9f0a 940 return -1;
508c263e
SH
941 }
942 rand_complete_hwaddr(new_value);
c2cc9f0a 943
508c263e
SH
944 netdev = network_netdev(key, new_value, &lxc_conf->network);
945 if (!netdev) {
946 free(new_value);
947 return -1;
948 };
949
9763f881 950 if (config_value_empty(new_value)) {
508c263e
SH
951 free(new_value);
952 netdev->hwaddr = NULL;
953 return 0;
954 }
955
956 netdev->hwaddr = new_value;
957 return 0;
c2cc9f0a 958}
959
713046e3 960static int set_config_network_vlan_id(const char *key, const char *value,
504a2217 961 struct lxc_conf *lxc_conf)
26c39028
JHS
962{
963 struct lxc_netdev *netdev;
964
965 netdev = network_netdev(key, value, &lxc_conf->network);
966 if (!netdev)
967 return -1;
968
c5316d60 969 if (netdev->type != LXC_NET_VLAN) {
128d327a 970 ERROR("Invalid vlan.id for a non-macvlan netdev");
c5316d60
SH
971 return -1;
972 }
504a2217 973
f6cc1de1 974 if (get_u16(&netdev->priv.vlan_attr.vid, value, 0))
26c39028
JHS
975 return -1;
976
977 return 0;
978}
979
713046e3 980static int set_config_network_mtu(const char *key, const char *value,
504a2217 981 struct lxc_conf *lxc_conf)
442cbbe6 982{
442cbbe6
TR
983 struct lxc_netdev *netdev;
984
16950ecb 985 netdev = network_netdev(key, value, &lxc_conf->network);
33c945e0 986 if (!netdev)
442cbbe6 987 return -1;
442cbbe6 988
713046e3 989 return set_config_string_item(&netdev->mtu, value);
442cbbe6
TR
990}
991
713046e3 992static int set_config_network_ipv4(const char *key, const char *value,
504a2217 993 struct lxc_conf *lxc_conf)
c2cc9f0a 994{
c2cc9f0a 995 struct lxc_netdev *netdev;
33c945e0 996 struct lxc_inetdev *inetdev;
c2cc9f0a 997 struct lxc_list *list;
504a2217
CB
998 char *cursor, *slash;
999 char *addr = NULL, *bcast = NULL, *prefix = NULL;
c2cc9f0a 1000
c3760156 1001 if (config_value_empty(value))
0797e123
CB
1002 return lxc_clear_config_item(lxc_conf, key);
1003
16950ecb 1004 netdev = network_netdev(key, value, &lxc_conf->network);
33c945e0 1005 if (!netdev)
c2cc9f0a 1006 return -1;
c2cc9f0a 1007
1008 inetdev = malloc(sizeof(*inetdev));
1009 if (!inetdev) {
36eb9bde 1010 SYSERROR("failed to allocate ipv4 address");
c2cc9f0a 1011 return -1;
1012 }
1013 memset(inetdev, 0, sizeof(*inetdev));
1014
1015 list = malloc(sizeof(*list));
1016 if (!list) {
36eb9bde 1017 SYSERROR("failed to allocate memory");
53719062 1018 free(inetdev);
c2cc9f0a 1019 return -1;
1020 }
1021
1022 lxc_list_init(list);
1023 list->elem = inetdev;
1024
956edc54
SG
1025 addr = strdup(value);
1026 if (!addr) {
1027 ERROR("no address specified");
53719062
SH
1028 free(inetdev);
1029 free(list);
956edc54
SG
1030 return -1;
1031 }
c2cc9f0a 1032
1033 cursor = strstr(addr, " ");
1034 if (cursor) {
1035 *cursor = '\0';
1036 bcast = cursor + 1;
1037 }
1038
1039 slash = strstr(addr, "/");
1040 if (slash) {
1041 *slash = '\0';
1042 prefix = slash + 1;
1043 }
1044
c2cc9f0a 1045 if (!inet_pton(AF_INET, addr, &inetdev->addr)) {
36eb9bde 1046 SYSERROR("invalid ipv4 address: %s", value);
53719062 1047 free(inetdev);
956edc54 1048 free(addr);
53719062 1049 free(list);
c2cc9f0a 1050 return -1;
1051 }
1052
0093bb8c
DL
1053 if (bcast && !inet_pton(AF_INET, bcast, &inetdev->bcast)) {
1054 SYSERROR("invalid ipv4 broadcast address: %s", value);
53719062
SH
1055 free(inetdev);
1056 free(list);
956edc54 1057 free(addr);
0093bb8c
DL
1058 return -1;
1059 }
c2cc9f0a 1060
504a2217 1061 /* No prefix specified, determine it from the network class. */
1c633398
CB
1062 if (prefix) {
1063 if (lxc_safe_uint(prefix, &inetdev->prefix) < 0)
1064 return -1;
1065 } else {
1066 inetdev->prefix = config_ip_prefix(&inetdev->addr);
1067 }
a059591e 1068
504a2217
CB
1069 /* If no broadcast address, let compute one from the
1070 * prefix and address.
0093bb8c
DL
1071 */
1072 if (!bcast) {
1b7d4743
DL
1073 inetdev->bcast.s_addr = inetdev->addr.s_addr;
1074 inetdev->bcast.s_addr |=
504a2217 1075 htonl(INADDR_BROADCAST >> inetdev->prefix);
0093bb8c 1076 }
c2cc9f0a 1077
8538f388 1078 lxc_list_add_tail(&netdev->ipv4, list);
c2cc9f0a 1079
956edc54 1080 free(addr);
c2cc9f0a 1081 return 0;
1082}
1083
713046e3 1084static int set_config_network_ipv4_gateway(const char *key, const char *value,
504a2217 1085 struct lxc_conf *lxc_conf)
f8fee0e2
MK
1086{
1087 struct lxc_netdev *netdev;
f8fee0e2
MK
1088
1089 netdev = network_netdev(key, value, &lxc_conf->network);
1090 if (!netdev)
1091 return -1;
1092
e088e926 1093 free(netdev->ipv4_gateway);
f8fee0e2 1094
10da55e4 1095 if (config_value_empty(value)) {
e088e926
SG
1096 netdev->ipv4_gateway = NULL;
1097 } else if (!strcmp(value, "auto")) {
19a26f82
MK
1098 netdev->ipv4_gateway = NULL;
1099 netdev->ipv4_gateway_auto = true;
1100 } else {
e088e926
SG
1101 struct in_addr *gw;
1102
1103 gw = malloc(sizeof(*gw));
1104 if (!gw) {
1105 SYSERROR("failed to allocate ipv4 gateway address");
1106 return -1;
1107 }
1108
19a26f82
MK
1109 if (!inet_pton(AF_INET, value, gw)) {
1110 SYSERROR("invalid ipv4 gateway address: %s", value);
53719062 1111 free(gw);
19a26f82
MK
1112 return -1;
1113 }
1114
1115 netdev->ipv4_gateway = gw;
1116 netdev->ipv4_gateway_auto = false;
f8fee0e2
MK
1117 }
1118
f8fee0e2
MK
1119 return 0;
1120}
1121
713046e3 1122static int set_config_network_ipv6(const char *key, const char *value,
504a2217 1123 struct lxc_conf *lxc_conf)
c2cc9f0a 1124{
c2cc9f0a 1125 struct lxc_netdev *netdev;
1126 struct lxc_inet6dev *inet6dev;
1127 struct lxc_list *list;
504a2217 1128 char *slash, *valdup, *netmask;
c2cc9f0a 1129
cae8a0f0 1130 if (config_value_empty(value))
0797e123
CB
1131 return lxc_clear_config_item(lxc_conf, key);
1132
16950ecb 1133 netdev = network_netdev(key, value, &lxc_conf->network);
33c945e0 1134 if (!netdev)
c2cc9f0a 1135 return -1;
c2cc9f0a 1136
1137 inet6dev = malloc(sizeof(*inet6dev));
1138 if (!inet6dev) {
36eb9bde 1139 SYSERROR("failed to allocate ipv6 address");
c2cc9f0a 1140 return -1;
1141 }
1142 memset(inet6dev, 0, sizeof(*inet6dev));
1143
1144 list = malloc(sizeof(*list));
1145 if (!list) {
36eb9bde 1146 SYSERROR("failed to allocate memory");
28027320 1147 free(inet6dev);
c2cc9f0a 1148 return -1;
1149 }
1150
1151 lxc_list_init(list);
1152 list->elem = inet6dev;
1153
956edc54
SG
1154 valdup = strdup(value);
1155 if (!valdup) {
1156 ERROR("no address specified");
28027320
SH
1157 free(list);
1158 free(inet6dev);
956edc54
SG
1159 return -1;
1160 }
1161
a059591e 1162 inet6dev->prefix = 64;
12a50cc6 1163 slash = strstr(valdup, "/");
c2cc9f0a 1164 if (slash) {
1165 *slash = '\0';
1166 netmask = slash + 1;
1c633398
CB
1167 if (lxc_safe_uint(netmask, &inet6dev->prefix) < 0)
1168 return -1;
c2cc9f0a 1169 }
1170
5acccf95
SH
1171 if (!inet_pton(AF_INET6, valdup, &inet6dev->addr)) {
1172 SYSERROR("invalid ipv6 address: %s", valdup);
28027320
SH
1173 free(list);
1174 free(inet6dev);
956edc54 1175 free(valdup);
c2cc9f0a 1176 return -1;
1177 }
1178
8538f388 1179 lxc_list_add_tail(&netdev->ipv6, list);
c2cc9f0a 1180
956edc54 1181 free(valdup);
c2cc9f0a 1182 return 0;
1183}
1184
713046e3 1185static int set_config_network_ipv6_gateway(const char *key, const char *value,
504a2217 1186 struct lxc_conf *lxc_conf)
f8fee0e2
MK
1187{
1188 struct lxc_netdev *netdev;
f8fee0e2
MK
1189
1190 netdev = network_netdev(key, value, &lxc_conf->network);
1191 if (!netdev)
1192 return -1;
1193
e088e926 1194 free(netdev->ipv6_gateway);
f8fee0e2 1195
114df19e 1196 if (config_value_empty(value)) {
ffe34437 1197 netdev->ipv6_gateway = NULL;
e088e926 1198 } else if (!strcmp(value, "auto")) {
19a26f82
MK
1199 netdev->ipv6_gateway = NULL;
1200 netdev->ipv6_gateway_auto = true;
1201 } else {
8fb86a37
SH
1202 struct in6_addr *gw;
1203
bec695f3
DE
1204 gw = malloc(sizeof(*gw));
1205 if (!gw) {
1206 SYSERROR("failed to allocate ipv6 gateway address");
1207 return -1;
1208 }
1209
19a26f82
MK
1210 if (!inet_pton(AF_INET6, value, gw)) {
1211 SYSERROR("invalid ipv6 gateway address: %s", value);
28027320 1212 free(gw);
19a26f82
MK
1213 return -1;
1214 }
1215
1216 netdev->ipv6_gateway = gw;
1217 netdev->ipv6_gateway_auto = false;
f8fee0e2
MK
1218 }
1219
f8fee0e2
MK
1220 return 0;
1221}
1222
713046e3 1223static int set_config_network_script_up(const char *key, const char *value,
504a2217 1224 struct lxc_conf *lxc_conf)
e3b4c4c4
ST
1225{
1226 struct lxc_netdev *netdev;
1227
1228 netdev = network_netdev(key, value, &lxc_conf->network);
1229 if (!netdev)
504a2217 1230 return -1;
e3b4c4c4 1231
713046e3 1232 return set_config_string_item(&netdev->upscript, value);
8fc8295a
DE
1233}
1234
713046e3 1235static int set_config_network_script_down(const char *key, const char *value,
504a2217 1236 struct lxc_conf *lxc_conf)
8fc8295a
DE
1237{
1238 struct lxc_netdev *netdev;
1239
1240 netdev = network_netdev(key, value, &lxc_conf->network);
1241 if (!netdev)
504a2217 1242 return -1;
8fc8295a 1243
713046e3 1244 return set_config_string_item(&netdev->downscript, value);
e3b4c4c4
ST
1245}
1246
26ddeedd
SH
1247static int add_hook(struct lxc_conf *lxc_conf, int which, char *hook)
1248{
1249 struct lxc_list *hooklist;
1250
1251 hooklist = malloc(sizeof(*hooklist));
1252 if (!hooklist) {
1253 free(hook);
1254 return -1;
1255 }
504a2217 1256
26ddeedd
SH
1257 hooklist->elem = hook;
1258 lxc_list_add_tail(&lxc_conf->hooks[which], hooklist);
1259 return 0;
1260}
1261
713046e3 1262static int set_config_seccomp(const char *key, const char *value,
504a2217 1263 struct lxc_conf *lxc_conf)
8f2c3a70 1264{
713046e3 1265 return set_config_path_item(&lxc_conf->seccomp, value);
8f2c3a70
SH
1266}
1267
713046e3 1268static int set_config_init_cmd(const char *key, const char *value,
504a2217 1269 struct lxc_conf *lxc_conf)
67c660d0 1270{
713046e3 1271 return set_config_path_item(&lxc_conf->init_cmd, value);
67c660d0
SG
1272}
1273
713046e3 1274static int set_config_init_uid(const char *key, const char *value,
504a2217 1275 struct lxc_conf *lxc_conf)
72bb04e4 1276{
d1e5d636
CB
1277 unsigned int init_uid;
1278
2e7cde40
CB
1279 /* Set config value to default. */
1280 if (config_value_empty(value)) {
1281 lxc_conf->init_uid = 0;
fee80911 1282 return 0;
2e7cde40 1283 }
fee80911 1284
2e7cde40 1285 /* Parse new config value. */
d1e5d636
CB
1286 if (lxc_safe_uint(value, &init_uid) < 0)
1287 return -1;
1288 lxc_conf->init_uid = init_uid;
1289
72bb04e4
PT
1290 return 0;
1291}
1292
713046e3 1293static int set_config_init_gid(const char *key, const char *value,
504a2217 1294 struct lxc_conf *lxc_conf)
72bb04e4 1295{
d1e5d636
CB
1296 unsigned int init_gid;
1297
2debb6e6
CB
1298 /* Set config value to default. */
1299 if (config_value_empty(value)) {
1300 lxc_conf->init_gid = 0;
a757cc7d 1301 return 0;
2debb6e6 1302 }
a757cc7d 1303
2debb6e6 1304 /* Parse new config value. */
d1e5d636
CB
1305 if (lxc_safe_uint(value, &init_gid) < 0)
1306 return -1;
1307 lxc_conf->init_gid = init_gid;
1308
72bb04e4
PT
1309 return 0;
1310}
1311
466c2e93
CB
1312static int set_config_hooks(const char *key, const char *value,
1313 struct lxc_conf *lxc_conf)
26ddeedd 1314{
7d0eb87e 1315 char *copy;
72bb04e4 1316
03d88f7c 1317 if (config_value_empty(value))
7d0eb87e
SH
1318 return lxc_clear_hooks(lxc_conf, key);
1319
6b0d5538
SH
1320 if (strcmp(key, "lxc.hook") == 0) {
1321 ERROR("lxc.hook cannot take a value");
1322 return -1;
1323 }
7d0eb87e 1324 copy = strdup(value);
26ddeedd
SH
1325 if (!copy) {
1326 SYSERROR("failed to dup string '%s'", value);
1327 return -1;
1328 }
504a2217 1329
26ddeedd
SH
1330 if (strcmp(key, "lxc.hook.pre-start") == 0)
1331 return add_hook(lxc_conf, LXCHOOK_PRESTART, copy);
5ea6163a
SH
1332 else if (strcmp(key, "lxc.hook.pre-mount") == 0)
1333 return add_hook(lxc_conf, LXCHOOK_PREMOUNT, copy);
f7bee6c6
MW
1334 else if (strcmp(key, "lxc.hook.autodev") == 0)
1335 return add_hook(lxc_conf, LXCHOOK_AUTODEV, copy);
26ddeedd
SH
1336 else if (strcmp(key, "lxc.hook.mount") == 0)
1337 return add_hook(lxc_conf, LXCHOOK_MOUNT, copy);
1338 else if (strcmp(key, "lxc.hook.start") == 0)
1339 return add_hook(lxc_conf, LXCHOOK_START, copy);
52492063
WB
1340 else if (strcmp(key, "lxc.hook.stop") == 0)
1341 return add_hook(lxc_conf, LXCHOOK_STOP, copy);
26ddeedd
SH
1342 else if (strcmp(key, "lxc.hook.post-stop") == 0)
1343 return add_hook(lxc_conf, LXCHOOK_POSTSTOP, copy);
148e91f5
SH
1344 else if (strcmp(key, "lxc.hook.clone") == 0)
1345 return add_hook(lxc_conf, LXCHOOK_CLONE, copy);
37cf711b
SY
1346 else if (strcmp(key, "lxc.hook.destroy") == 0)
1347 return add_hook(lxc_conf, LXCHOOK_DESTROY, copy);
504a2217 1348
26ddeedd
SH
1349 SYSERROR("Unknown key: %s", key);
1350 free(copy);
1351 return -1;
1352}
1353
713046e3 1354static int set_config_personality(const char *key, const char *value,
504a2217 1355 struct lxc_conf *lxc_conf)
cccc74b5 1356{
525f0002 1357 signed long personality = lxc_config_parse_arch(value);
cccc74b5 1358
525f0002
CS
1359 if (personality >= 0)
1360 lxc_conf->personality = personality;
1361 else
1362 WARN("unsupported personality '%s'", value);
970ab589
DL
1363
1364 return 0;
cccc74b5
DL
1365}
1366
713046e3 1367static int set_config_pts(const char *key, const char *value,
504a2217 1368 struct lxc_conf *lxc_conf)
10db618d 1369{
ec200ce9
CB
1370 /* Set config value to default. */
1371 if (config_value_empty(value)) {
1372 lxc_conf->pts = 0;
884a4580 1373 return 0;
ec200ce9 1374 }
884a4580 1375
ec200ce9 1376 /* Parse new config value. */
17919969
CB
1377 if (lxc_safe_uint(value, &lxc_conf->pts) < 0)
1378 return -1;
10db618d 1379
1380 return 0;
1381}
1382
713046e3 1383static int set_config_start(const char *key, const char *value,
504a2217 1384 struct lxc_conf *lxc_conf)
ee1e7aa0 1385{
ebb80f95
CB
1386 bool is_empty;
1387
1388 is_empty = config_value_empty(value);
1389
1390 if (strcmp(key, "lxc.start.auto") == 0) {
1391 /* Set config value to default. */
1392 if (is_empty) {
1393 lxc_conf->start_auto = 0;
1394 return 0;
1395 }
61ff8fc8 1396
ebb80f95 1397 /* Parse new config value. */
3590152f
CB
1398 if (lxc_safe_uint(value, &lxc_conf->start_auto) < 0)
1399 return -1;
ebb80f95 1400
3590152f
CB
1401 if (lxc_conf->start_auto > 1)
1402 return -1;
ebb80f95 1403
ee1e7aa0 1404 return 0;
ebb80f95
CB
1405 } else if (strcmp(key, "lxc.start.delay") == 0) {
1406 /* Set config value to default. */
1407 if (is_empty) {
1408 lxc_conf->start_delay = 0;
1409 return 0;
1410 }
1411
1412 /* Parse new config value. */
1413 return lxc_safe_uint(value, &lxc_conf->start_delay);
1414 } else if (strcmp(key, "lxc.start.order") == 0) {
1415 /* Set config value to default. */
1416 if (is_empty) {
1417 lxc_conf->start_order = 0;
1418 return 0;
1419 }
1420
1421 /* Parse new config value. */
1422 return lxc_safe_int(value, &lxc_conf->start_order);
ee1e7aa0 1423 }
ebb80f95 1424
ee1e7aa0
SG
1425 SYSERROR("Unknown key: %s", key);
1426 return -1;
1427}
1428
713046e3 1429static int set_config_monitor(const char *key, const char *value,
504a2217 1430 struct lxc_conf *lxc_conf)
a8dfe4e0 1431{
4ad9cd26
CB
1432 /* Set config value to default. */
1433 if (config_value_empty(value)) {
1434 lxc_conf->monitor_unshare = 0;
a8dfe4e0
WB
1435 return 0;
1436 }
4ad9cd26
CB
1437
1438 /* Parse new config value. */
1439 if (strcmp(key, "lxc.monitor.unshare") == 0)
1440 return lxc_safe_uint(value, &lxc_conf->monitor_unshare);
1441
a8dfe4e0
WB
1442 SYSERROR("Unknown key: %s", key);
1443 return -1;
1444}
1445
713046e3 1446static int set_config_group(const char *key, const char *value,
504a2217 1447 struct lxc_conf *lxc_conf)
ee1e7aa0
SG
1448{
1449 char *groups, *groupptr, *sptr, *token;
1450 struct lxc_list *grouplist;
1451 int ret = -1;
1452
7584546d 1453 if (config_value_empty(value))
ee1e7aa0
SG
1454 return lxc_clear_groups(lxc_conf);
1455
1456 groups = strdup(value);
1457 if (!groups) {
1458 SYSERROR("failed to dup '%s'", value);
1459 return -1;
1460 }
1461
504a2217
CB
1462 /* In case several groups are specified in a single line
1463 * split these groups in a single element for the list.
1464 */
1465 for (groupptr = groups;; groupptr = NULL) {
d028235d
SG
1466 token = strtok_r(groupptr, " \t", &sptr);
1467 if (!token) {
ee1e7aa0 1468 ret = 0;
d028235d 1469 break;
ee1e7aa0
SG
1470 }
1471
1472 grouplist = malloc(sizeof(*grouplist));
1473 if (!grouplist) {
1474 SYSERROR("failed to allocate groups list");
1475 break;
1476 }
1477
1478 grouplist->elem = strdup(token);
1479 if (!grouplist->elem) {
1480 SYSERROR("failed to dup '%s'", token);
1481 free(grouplist);
1482 break;
1483 }
1484
1485 lxc_list_add_tail(&lxc_conf->groups, grouplist);
d028235d 1486 }
ee1e7aa0
SG
1487
1488 free(groups);
ee1e7aa0
SG
1489 return ret;
1490}
1491
713046e3 1492static int set_config_environment(const char *key, const char *value,
504a2217 1493 struct lxc_conf *lxc_conf)
7c661726
MP
1494{
1495 struct lxc_list *list_item = NULL;
1496
cdee76e3 1497 if (config_value_empty(value))
ab799c0b
SG
1498 return lxc_clear_environment(lxc_conf);
1499
7c661726
MP
1500 list_item = malloc(sizeof(*list_item));
1501 if (!list_item)
504a2217 1502 goto on_error;
7c661726
MP
1503
1504 list_item->elem = strdup(value);
1505
1506 if (!list_item->elem)
504a2217 1507 goto on_error;
7c661726
MP
1508
1509 lxc_list_add_tail(&lxc_conf->environment, list_item);
1510
1511 return 0;
1512
504a2217 1513on_error:
f10fad2f 1514 free(list_item);
7c661726
MP
1515 return -1;
1516}
1517
713046e3 1518static int set_config_tty(const char *key, const char *value,
504a2217 1519 struct lxc_conf *lxc_conf)
b0a33c1e 1520{
cb508ee8
CB
1521 /* Set config value to default. */
1522 if (config_value_empty(value)) {
1523 lxc_conf->tty = 0;
fb12b12a 1524 return 0;
cb508ee8 1525 }
fb12b12a 1526
cb508ee8
CB
1527 /* Parse new config value. */
1528 return lxc_safe_uint(value, &lxc_conf->tty);
b0a33c1e 1529}
1530
713046e3 1531static int set_config_ttydir(const char *key, const char *value,
504a2217 1532 struct lxc_conf *lxc_conf)
7c6ef2a2 1533{
504a2217
CB
1534 return set_config_string_item_max(&lxc_conf->ttydir, value,
1535 NAME_MAX + 1);
7c6ef2a2
SH
1536}
1537
713046e3 1538static int set_config_kmsg(const char *key, const char *value,
504a2217 1539 struct lxc_conf *lxc_conf)
7e0e1d94 1540{
3d6b7fdc
CB
1541 /* Set config value to default. */
1542 if (config_value_empty(value)) {
1543 lxc_conf->kmsg = 0;
5767e9ba 1544 return 0;
3d6b7fdc 1545 }
5767e9ba 1546
3d6b7fdc 1547 /* Parse new config value. */
91863d36
CB
1548 if (lxc_safe_uint(value, &lxc_conf->kmsg) < 0)
1549 return -1;
7e0e1d94 1550
91863d36
CB
1551 if (lxc_conf->kmsg > 1)
1552 return -1;
7e0e1d94
AV
1553
1554 return 0;
1555}
1556
713046e3 1557static int set_config_lsm_aa_profile(const char *key, const char *value,
504a2217 1558 struct lxc_conf *lxc_conf)
e075f5d9 1559{
713046e3 1560 return set_config_string_item(&lxc_conf->lsm_aa_profile, value);
fe4de9a6
DE
1561}
1562
713046e3 1563static int set_config_lsm_aa_incomplete(const char *key, const char *value,
504a2217 1564 struct lxc_conf *lxc_conf)
7aff4f43 1565{
cccfa758
CB
1566 /* Set config value to default. */
1567 if (config_value_empty(value)) {
1568 lxc_conf->lsm_aa_allow_incomplete = 0;
a678e9fa 1569 return 0;
cccfa758 1570 }
a678e9fa 1571
cccfa758 1572 /* Parse new config value. */
a56e2df9
CB
1573 if (lxc_safe_uint(value, &lxc_conf->lsm_aa_allow_incomplete) < 0)
1574 return -1;
7aff4f43 1575
a56e2df9 1576 if (lxc_conf->lsm_aa_allow_incomplete > 1) {
cccfa758
CB
1577 ERROR("Wrong value for lxc.lsm_aa_allow_incomplete. Can only "
1578 "be set to 0 or 1");
a56e2df9
CB
1579 return -1;
1580 }
7aff4f43
SH
1581
1582 return 0;
1583}
1584
713046e3 1585static int set_config_lsm_se_context(const char *key, const char *value,
504a2217 1586 struct lxc_conf *lxc_conf)
fe4de9a6 1587{
713046e3 1588 return set_config_string_item(&lxc_conf->lsm_se_context, value);
e075f5d9 1589}
e075f5d9 1590
713046e3 1591static int set_config_logfile(const char *key, const char *value,
0d601acb 1592 struct lxc_conf *c)
4a85ce2a 1593{
6d03d92a
DE
1594 int ret;
1595
0d601acb
CB
1596 if (config_value_empty(value)) {
1597 free(c->logfile);
1598 c->logfile = NULL;
1599 return 0;
1600 }
1601
1602 /* Store these values in the lxc_conf, and then try to set for actual
504a2217
CB
1603 * current logging.
1604 */
713046e3 1605 ret = set_config_path_item(&c->logfile, value);
6d03d92a 1606 if (ret == 0)
858377e4 1607 ret = lxc_log_set_file(&c->logfd, c->logfile);
6d03d92a 1608 return ret;
4a85ce2a
SH
1609}
1610
713046e3 1611static int set_config_loglevel(const char *key, const char *value,
504a2217 1612 struct lxc_conf *lxc_conf)
4a85ce2a 1613{
9ea87d5d
SH
1614 int newlevel;
1615
575b9745
CB
1616 /* Set config value to default. */
1617 if (config_value_empty(value)) {
1618 lxc_conf->loglevel = LXC_LOG_PRIORITY_NOTSET;
4a85ce2a 1619 return 0;
575b9745 1620 }
4a85ce2a 1621
575b9745 1622 /* Parse new config value. */
a56e2df9
CB
1623 if (value[0] >= '0' && value[0] <= '9') {
1624 if (lxc_safe_int(value, &newlevel) < 0)
1625 return -1;
1626 } else {
9ea87d5d 1627 newlevel = lxc_log_priority_to_int(value);
a56e2df9 1628 }
575b9745 1629
504a2217 1630 /* Store these values in the lxc_conf, and then try to set for actual
575b9745
CB
1631 * current logging.
1632 */
b40a606e 1633 lxc_conf->loglevel = newlevel;
858377e4 1634 return lxc_log_set_level(&lxc_conf->loglevel, newlevel);
4a85ce2a
SH
1635}
1636
713046e3 1637static int set_config_autodev(const char *key, const char *value,
504a2217 1638 struct lxc_conf *lxc_conf)
c6883f38 1639{
1045031e
CB
1640 /* Set config value to default. */
1641 if (config_value_empty(value)) {
1642 lxc_conf->autodev = 0;
180abbc0 1643 return 0;
1045031e 1644 }
180abbc0 1645
1045031e 1646 /* Parse new config value. */
ff6cb4ed
CB
1647 if (lxc_safe_uint(value, &lxc_conf->autodev) < 0)
1648 return -1;
c6883f38 1649
ff6cb4ed
CB
1650 if (lxc_conf->autodev > 1) {
1651 ERROR("Wrong value for lxc.autodev. Can only be set to 0 or 1");
1652 return -1;
1653 }
c6883f38
SH
1654
1655 return 0;
1656}
1657
a84b9932
AV
1658static int sig_num(const char *sig)
1659{
f2e539b3 1660 unsigned int signum;
a84b9932 1661
f2e539b3 1662 if (lxc_safe_uint(sig, &signum) < 0)
a84b9932 1663 return -1;
f2e539b3
CB
1664
1665 return signum;
a84b9932
AV
1666}
1667
1668static int rt_sig_num(const char *signame)
1669{
504a2217 1670 int rtmax = 0, sig_n = 0;
a84b9932
AV
1671
1672 if (strncasecmp(signame, "max-", 4) == 0) {
1673 rtmax = 1;
1674 }
504a2217 1675
a84b9932
AV
1676 signame += 4;
1677 if (!isdigit(*signame))
1678 return -1;
504a2217 1679
a84b9932
AV
1680 sig_n = sig_num(signame);
1681 sig_n = rtmax ? SIGRTMAX - sig_n : SIGRTMIN + sig_n;
1682 if (sig_n > SIGRTMAX || sig_n < SIGRTMIN)
1683 return -1;
504a2217 1684
a84b9932
AV
1685 return sig_n;
1686}
1687
504a2217
CB
1688static int sig_parse(const char *signame)
1689{
84760c11 1690 size_t n;
a84b9932
AV
1691
1692 if (isdigit(*signame)) {
1693 return sig_num(signame);
1694 } else if (strncasecmp(signame, "sig", 3) == 0) {
1695 signame += 3;
1696 if (strncasecmp(signame, "rt", 2) == 0)
1697 return rt_sig_num(signame + 2);
1698 for (n = 0; n < sizeof(signames) / sizeof((signames)[0]); n++) {
504a2217 1699 if (strcasecmp(signames[n].name, signame) == 0)
a84b9932
AV
1700 return signames[n].num;
1701 }
1702 }
504a2217 1703
a84b9932
AV
1704 return -1;
1705}
1706
713046e3 1707static int set_config_haltsignal(const char *key, const char *value,
504a2217 1708 struct lxc_conf *lxc_conf)
f0f1d8c0 1709{
62a085fb 1710 int sig_n;
f0f1d8c0 1711
c1a64603
CB
1712 /* Set config value to default. */
1713 if (config_value_empty(value)) {
1714 lxc_conf->haltsignal = 0;
955912f0 1715 return 0;
c1a64603 1716 }
955912f0 1717
c1a64603 1718 /* Parse new config value. */
62a085fb
CB
1719 sig_n = sig_parse(value);
1720
f0f1d8c0
DE
1721 if (sig_n < 0)
1722 return -1;
1723 lxc_conf->haltsignal = sig_n;
1724
1725 return 0;
1726}
1727
713046e3 1728static int set_config_rebootsignal(const char *key, const char *value,
504a2217 1729 struct lxc_conf *lxc_conf)
dd267776 1730{
9d7e7587 1731 int sig_n;
dd267776 1732
18fcee44
CB
1733 /* Set config value to default. */
1734 if (config_value_empty(value)) {
1735 lxc_conf->rebootsignal = 0;
9d7e7587 1736 return 0;
18fcee44 1737 }
9d7e7587 1738
18fcee44 1739 /* Parse new config value. */
9d7e7587 1740 sig_n = sig_parse(value);
dd267776
BP
1741 if (sig_n < 0)
1742 return -1;
1743 lxc_conf->rebootsignal = sig_n;
1744
1745 return 0;
1746}
1747
713046e3 1748static int set_config_stopsignal(const char *key, const char *value,
504a2217 1749 struct lxc_conf *lxc_conf)
a84b9932 1750{
6ca6aedd 1751 int sig_n;
a84b9932 1752
4100d1a7
CB
1753 /* Set config value to default. */
1754 if (config_value_empty(value)) {
1755 lxc_conf->stopsignal = 0;
6ca6aedd 1756 return 0;
4100d1a7 1757 }
6ca6aedd 1758
4100d1a7 1759 /* Parse new config value. */
6ca6aedd 1760 sig_n = sig_parse(value);
a84b9932
AV
1761 if (sig_n < 0)
1762 return -1;
1763 lxc_conf->stopsignal = sig_n;
1764
1765 return 0;
1766}
1767
713046e3 1768static int set_config_cgroup(const char *key, const char *value,
504a2217 1769 struct lxc_conf *lxc_conf)
576f946d 1770{
576f946d 1771 char *subkey;
504a2217 1772 char *token = "lxc.cgroup.";
bf83c5b9
MS
1773 struct lxc_list *cglist = NULL;
1774 struct lxc_cgroup *cgelem = NULL;
576f946d 1775
fb0752be 1776 if (config_value_empty(value))
7d0eb87e
SH
1777 return lxc_clear_cgroups(lxc_conf, key);
1778
576f946d 1779 subkey = strstr(key, token);
576f946d 1780 if (!subkey)
1781 return -1;
1782
1783 if (!strlen(subkey))
1784 return -1;
1785
1786 if (strlen(subkey) == strlen(token))
1787 return -1;
a871ff6b 1788
576f946d 1789 subkey += strlen(token);
1790
1791 cglist = malloc(sizeof(*cglist));
1792 if (!cglist)
bf83c5b9 1793 goto out;
576f946d 1794
1795 cgelem = malloc(sizeof(*cgelem));
bf83c5b9
MS
1796 if (!cgelem)
1797 goto out;
1798 memset(cgelem, 0, sizeof(*cgelem));
576f946d 1799
1800 cgelem->subsystem = strdup(subkey);
1801 cgelem->value = strdup(value);
bf83c5b9
MS
1802
1803 if (!cgelem->subsystem || !cgelem->value)
1804 goto out;
1805
576f946d 1806 cglist->elem = cgelem;
1807
94d12f0a 1808 lxc_list_add_tail(&lxc_conf->cgroup, cglist);
576f946d 1809
1810 return 0;
bf83c5b9
MS
1811
1812out:
f10fad2f 1813 free(cglist);
bf83c5b9
MS
1814
1815 if (cgelem) {
f10fad2f 1816 free(cgelem->subsystem);
bf83c5b9 1817
f10fad2f 1818 free(cgelem->value);
bf83c5b9
MS
1819
1820 free(cgelem);
1821 }
1822
1823 return -1;
576f946d 1824}
1825
504a2217
CB
1826static bool parse_limit_value(const char **value, unsigned long *res)
1827{
c6d09e15
WB
1828 char *endptr = NULL;
1829
504a2217 1830 if (strncmp(*value, "unlimited", sizeof("unlimited") - 1) == 0) {
c6d09e15 1831 *res = RLIM_INFINITY;
504a2217 1832 *value += sizeof("unlimited") - 1;
c6d09e15
WB
1833 return true;
1834 }
1835
1836 errno = 0;
1837 *res = strtoul(*value, &endptr, 10);
1838 if (errno || !endptr)
1839 return false;
1840 *value = endptr;
1841
1842 return true;
1843}
1844
713046e3 1845static int set_config_limit(const char *key, const char *value,
504a2217 1846 struct lxc_conf *lxc_conf)
c6d09e15 1847{
c6d09e15
WB
1848 struct lxc_list *iter;
1849 struct rlimit limit;
1850 unsigned long limit_value;
504a2217
CB
1851 struct lxc_list *limlist = NULL;
1852 struct lxc_limit *limelem = NULL;
c6d09e15 1853
7a18f483 1854 if (config_value_empty(value))
c6d09e15
WB
1855 return lxc_clear_limits(lxc_conf, key);
1856
504a2217 1857 if (strncmp(key, "lxc.limit.", sizeof("lxc.limit.") - 1) != 0)
c6d09e15
WB
1858 return -1;
1859
504a2217 1860 key += sizeof("lxc.limit.") - 1;
c6d09e15
WB
1861
1862 /* soft limit comes first in the value */
1863 if (!parse_limit_value(&value, &limit_value))
1864 return -1;
1865 limit.rlim_cur = limit_value;
1866
1867 /* skip spaces and a colon */
1868 while (isspace(*value))
1869 ++value;
504a2217 1870
c6d09e15
WB
1871 if (*value == ':')
1872 ++value;
1873 else if (*value) /* any other character is an error here */
1874 return -1;
504a2217 1875
c6d09e15
WB
1876 while (isspace(*value))
1877 ++value;
1878
1879 /* optional hard limit */
1880 if (*value) {
1881 if (!parse_limit_value(&value, &limit_value))
1882 return -1;
1883 limit.rlim_max = limit_value;
504a2217 1884
c6d09e15
WB
1885 /* check for trailing garbage */
1886 while (isspace(*value))
1887 ++value;
504a2217 1888
c6d09e15
WB
1889 if (*value)
1890 return -1;
1891 } else {
1892 /* a single value sets both hard and soft limit */
1893 limit.rlim_max = limit.rlim_cur;
1894 }
1895
1896 /* find existing list element */
504a2217
CB
1897 lxc_list_for_each(iter, &lxc_conf->limits)
1898 {
c6d09e15
WB
1899 limelem = iter->elem;
1900 if (!strcmp(key, limelem->resource)) {
1901 limelem->limit = limit;
1902 return 0;
1903 }
1904 }
1905
1906 /* allocate list element */
1907 limlist = malloc(sizeof(*limlist));
1908 if (!limlist)
1909 goto out;
2e6e3feb 1910
c6d09e15
WB
1911 limelem = malloc(sizeof(*limelem));
1912 if (!limelem)
1913 goto out;
1914 memset(limelem, 0, sizeof(*limelem));
1915
1916 limelem->resource = strdup(key);
1917 if (!limelem->resource)
1918 goto out;
1919 limelem->limit = limit;
1920
1921 limlist->elem = limelem;
1922
1923 lxc_list_add_tail(&lxc_conf->limits, limlist);
1924
1925 return 0;
1926
1927out:
1928 free(limlist);
1929 if (limelem) {
1930 free(limelem->resource);
1931 free(limelem);
1932 }
1933 return -1;
1934}
1935
5014ff2e
CB
1936static int set_config_idmaps(const char *key, const char *value,
1937 struct lxc_conf *lxc_conf)
f6d3e3e4 1938{
251d0d2a 1939 unsigned long hostid, nsid, range;
f6d3e3e4 1940 char type;
34a7a4c6
CB
1941 char *window, *slide;
1942 char *dup = NULL;
1943 struct lxc_list *idmaplist = NULL;
1944 struct id_map *idmap = NULL;
f6d3e3e4 1945
ab8d8307 1946 if (config_value_empty(value))
7d0eb87e
SH
1947 return lxc_clear_idmaps(lxc_conf);
1948
f6d3e3e4
SH
1949 idmaplist = malloc(sizeof(*idmaplist));
1950 if (!idmaplist)
34a7a4c6 1951 goto on_error;
f6d3e3e4
SH
1952
1953 idmap = malloc(sizeof(*idmap));
1954 if (!idmap)
34a7a4c6 1955 goto on_error;
f6d3e3e4
SH
1956 memset(idmap, 0, sizeof(*idmap));
1957
34a7a4c6
CB
1958 /* Duplicate string. */
1959 dup = strdup(value);
1960 if (!dup)
1961 goto on_error;
1962
504a2217 1963 /* A prototypical idmap entry would be: "u 1000 1000000 65536" */
34a7a4c6
CB
1964
1965 /* align */
1966 slide = window = dup;
1967 /* skip whitespace */
1968 slide += strspn(slide, " \t\r");
1969 if (slide != window && *slide == '\0')
1970 goto on_error;
1971
1972 /* Validate type. */
1973 if (*slide != 'u' && *slide != 'g')
1974 goto on_error;
1975 /* Assign type. */
1976 type = *slide;
1977
1978 /* move beyond type */
1979 slide++;
1980 /* align */
1981 window = slide;
1982 /* Validate that only whitespace follows. */
1983 slide += strspn(slide, " \t\r");
1984 /* There must be whitespace. */
1985 if (slide == window)
1986 goto on_error;
1987
1988 /* Mark beginning of nsuid. */
1989 window = slide;
1990 /* Validate that non-whitespace follows. */
1991 slide += strcspn(slide, " \t\r");
1992 /* There must be non-whitespace. */
1993 if (slide == window || *slide == '\0')
1994 goto on_error;
1995 /* Mark end of nsuid. */
1996 *slide = '\0';
1997
1998 /* Parse nsuid. */
1999 if (lxc_safe_ulong(window, &nsid) < 0)
2000 goto on_error;
2001
2002 /* Move beyond \0. */
2003 slide++;
2004 /* align */
2005 window = slide;
2006 /* Validate that only whitespace follows. */
2007 slide += strspn(slide, " \t\r");
2008 /* If there was only one whitespace then we whiped it with our \0 above.
2009 * So only ensure that we're not at the end of the string.
2010 */
2011 if (*slide == '\0')
2012 goto on_error;
2013
2014 /* Mark beginning of hostid. */
2015 window = slide;
2016 /* Validate that non-whitespace follows. */
2017 slide += strcspn(slide, " \t\r");
2018 /* There must be non-whitespace. */
2019 if (slide == window || *slide == '\0')
2020 goto on_error;
2021 /* Mark end of nsuid. */
2022 *slide = '\0';
2023
2024 /* Parse hostid. */
2025 if (lxc_safe_ulong(window, &hostid) < 0)
2026 goto on_error;
2027
2028 /* Move beyond \0. */
2029 slide++;
2030 /* align */
2031 window = slide;
2032 /* Validate that only whitespace follows. */
2033 slide += strspn(slide, " \t\r");
2034 /* If there was only one whitespace then we whiped it with our \0 above.
2035 * So only ensure that we're not at the end of the string.
2036 */
2037 if (*slide == '\0')
2038 goto on_error;
2039
2040 /* Mark beginning of range. */
2041 window = slide;
2042 /* Validate that non-whitespace follows. */
2043 slide += strcspn(slide, " \t\r");
2044 /* There must be non-whitespace. */
2045 if (slide == window)
2046 goto on_error;
2047
2048 /* The range is the last valid entry we expect. So make sure that there
2049 * is not trailing garbage and if there is, error out.
2050 */
2051 if (*(slide + strspn(slide, " \t\r\n")) != '\0')
2052 goto on_error;
2053 /* Mark end of range. */
2054 *slide = '\0';
7e60c3f0 2055
34a7a4c6
CB
2056 /* Parse range. */
2057 if (lxc_safe_ulong(window, &range) < 0)
2058 goto on_error;
2059
2060 /* Yay, we survived. */
251d0d2a 2061 INFO("read uid map: type %c nsid %lu hostid %lu range %lu", type, nsid, hostid, range);
ac7725e7 2062 if (type == 'u')
f6d3e3e4 2063 idmap->idtype = ID_TYPE_UID;
ac7725e7 2064 else if (type == 'g')
f6d3e3e4
SH
2065 idmap->idtype = ID_TYPE_GID;
2066 else
34a7a4c6 2067 goto on_error;
7e60c3f0 2068
f6d3e3e4
SH
2069 idmap->hostid = hostid;
2070 idmap->nsid = nsid;
2071 idmap->range = range;
7e60c3f0
SG
2072 idmaplist->elem = idmap;
2073 lxc_list_add_tail(&lxc_conf->id_map, idmaplist);
34a7a4c6 2074 idmap = NULL;
7e60c3f0 2075
f6d3e3e4
SH
2076 return 0;
2077
34a7a4c6 2078on_error:
f10fad2f 2079 free(idmaplist);
34a7a4c6
CB
2080 free(idmap);
2081 free(dup);
f6d3e3e4
SH
2082
2083 return -1;
2084}
2085
713046e3 2086static int set_config_fstab(const char *key, const char *value,
504a2217 2087 struct lxc_conf *lxc_conf)
d95db067 2088{
46f3de30
CB
2089 if (config_value_empty(value)) {
2090 lxc_clear_config_item(lxc_conf, key);
d9192f5d 2091 return -1;
46f3de30 2092 }
6f5685f0 2093
713046e3 2094 return set_config_path_item(&lxc_conf->fstab, value);
d95db067
DE
2095}
2096
713046e3 2097static int set_config_mount_auto(const char *key, const char *value,
504a2217 2098 struct lxc_conf *lxc_conf)
368bbc02
CS
2099{
2100 char *autos, *autoptr, *sptr, *token;
368bbc02
CS
2101 int i;
2102 int ret = -1;
504a2217
CB
2103 static struct {
2104 const char *token;
2105 int mask;
2106 int flag;
2107 } allowed_auto_mounts[] = {
2108 { "proc", LXC_AUTO_PROC_MASK, LXC_AUTO_PROC_MIXED },
2109 { "proc:mixed", LXC_AUTO_PROC_MASK, LXC_AUTO_PROC_MIXED },
2110 { "proc:rw", LXC_AUTO_PROC_MASK, LXC_AUTO_PROC_RW },
2111 { "sys", LXC_AUTO_SYS_MASK, LXC_AUTO_SYS_MIXED },
2112 { "sys:ro", LXC_AUTO_SYS_MASK, LXC_AUTO_SYS_RO },
2113 { "sys:mixed", LXC_AUTO_SYS_MASK, LXC_AUTO_SYS_MIXED },
2114 { "sys:rw", LXC_AUTO_SYS_MASK, LXC_AUTO_SYS_RW },
2115 { "cgroup", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_NOSPEC },
2116 { "cgroup:mixed", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_MIXED },
2117 { "cgroup:ro", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_RO },
2118 { "cgroup:rw", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_RW },
2119 { "cgroup-full", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_FULL_NOSPEC },
2120 { "cgroup-full:mixed", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_FULL_MIXED },
2121 { "cgroup-full:ro", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_FULL_RO },
2122 { "cgroup-full:rw", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_FULL_RW },
2123 /* NB: For adding anything that is just a single on/off, but has
2124 * no options: keep mask and flag identical and just define the
2125 * enum value as an unused bit so far
2126 */
2127 { NULL, 0, 0 }
2128 };
368bbc02 2129
ede57f73 2130 if (config_value_empty(value)) {
d9192f5d
SH
2131 lxc_conf->auto_mounts = 0;
2132 return 0;
2133 }
368bbc02
CS
2134
2135 autos = strdup(value);
2136 if (!autos) {
2137 SYSERROR("failed to dup '%s'", value);
2138 return -1;
2139 }
2140
504a2217 2141 for (autoptr = autos;; autoptr = NULL) {
d028235d
SG
2142 token = strtok_r(autoptr, " \t", &sptr);
2143 if (!token) {
368bbc02 2144 ret = 0;
d028235d 2145 break;
368bbc02
CS
2146 }
2147
2148 for (i = 0; allowed_auto_mounts[i].token; i++) {
2149 if (!strcmp(allowed_auto_mounts[i].token, token))
2150 break;
2151 }
2152
2153 if (!allowed_auto_mounts[i].token) {
2154 ERROR("Invalid filesystem to automount: %s", token);
2155 break;
2156 }
2157
b06b8511 2158 lxc_conf->auto_mounts &= ~allowed_auto_mounts[i].mask;
368bbc02 2159 lxc_conf->auto_mounts |= allowed_auto_mounts[i].flag;
d028235d 2160 }
368bbc02
CS
2161
2162 free(autos);
368bbc02
CS
2163 return ret;
2164}
2165
713046e3 2166static int set_config_mount(const char *key, const char *value,
504a2217 2167 struct lxc_conf *lxc_conf)
e7938e9e 2168{
e7938e9e
MN
2169 char *mntelem;
2170 struct lxc_list *mntlist;
2171
67cbe21a 2172 if (config_value_empty(value))
d9192f5d 2173 return lxc_clear_mount_entries(lxc_conf);
e7938e9e
MN
2174
2175 mntlist = malloc(sizeof(*mntlist));
2176 if (!mntlist)
2177 return -1;
2178
2179 mntelem = strdup(value);
00b6be44
SH
2180 if (!mntelem) {
2181 free(mntlist);
bf83c5b9 2182 return -1;
00b6be44 2183 }
e7938e9e
MN
2184 mntlist->elem = mntelem;
2185
2186 lxc_list_add_tail(&lxc_conf->mount_list, mntlist);
2187
2188 return 0;
2189}
2190
713046e3 2191static int set_config_cap_keep(const char *key, const char *value,
504a2217 2192 struct lxc_conf *lxc_conf)
1fb86a7c
SH
2193{
2194 char *keepcaps, *keepptr, *sptr, *token;
2195 struct lxc_list *keeplist;
2196 int ret = -1;
2197
99feb7f1 2198 if (config_value_empty(value))
7d0eb87e 2199 return lxc_clear_config_keepcaps(lxc_conf);
1fb86a7c
SH
2200
2201 keepcaps = strdup(value);
2202 if (!keepcaps) {
2203 SYSERROR("failed to dup '%s'", value);
2204 return -1;
2205 }
2206
504a2217
CB
2207 /* In case several capability keep is specified in a single line
2208 * split these caps in a single element for the list.
2209 */
2210 for (keepptr = keepcaps;; keepptr = NULL) {
d028235d
SG
2211 token = strtok_r(keepptr, " \t", &sptr);
2212 if (!token) {
1fb86a7c 2213 ret = 0;
d028235d 2214 break;
1fb86a7c
SH
2215 }
2216
7035407c
DE
2217 if (!strcmp(token, "none"))
2218 lxc_clear_config_keepcaps(lxc_conf);
2219
1fb86a7c
SH
2220 keeplist = malloc(sizeof(*keeplist));
2221 if (!keeplist) {
2222 SYSERROR("failed to allocate keepcap list");
2223 break;
2224 }
2225
2226 keeplist->elem = strdup(token);
2227 if (!keeplist->elem) {
2228 SYSERROR("failed to dup '%s'", token);
2229 free(keeplist);
2230 break;
2231 }
2232
2233 lxc_list_add_tail(&lxc_conf->keepcaps, keeplist);
d028235d 2234 }
1fb86a7c
SH
2235
2236 free(keepcaps);
2237
2238 return ret;
2239}
2240
713046e3 2241static int set_config_cap_drop(const char *key, const char *value,
504a2217 2242 struct lxc_conf *lxc_conf)
81810dd1 2243{
d95db067 2244 char *dropcaps, *dropptr, *sptr, *token;
81810dd1
DL
2245 struct lxc_list *droplist;
2246 int ret = -1;
2247
b2fae748 2248 if (config_value_empty(value))
7d0eb87e 2249 return lxc_clear_config_caps(lxc_conf);
81810dd1
DL
2250
2251 dropcaps = strdup(value);
2252 if (!dropcaps) {
2253 SYSERROR("failed to dup '%s'", value);
2254 return -1;
2255 }
2256
504a2217
CB
2257 /* In case several capability drop is specified in a single line
2258 * split these caps in a single element for the list.
2259 */
2260 for (dropptr = dropcaps;; dropptr = NULL) {
d028235d
SG
2261 token = strtok_r(dropptr, " \t", &sptr);
2262 if (!token) {
81810dd1 2263 ret = 0;
d028235d 2264 break;
81810dd1 2265 }
81810dd1
DL
2266
2267 droplist = malloc(sizeof(*droplist));
2268 if (!droplist) {
2269 SYSERROR("failed to allocate drop list");
2270 break;
2271 }
2272
2273 droplist->elem = strdup(token);
2274 if (!droplist->elem) {
2275 SYSERROR("failed to dup '%s'", token);
2276 free(droplist);
2277 break;
2278 }
2279
2280 lxc_list_add_tail(&lxc_conf->caps, droplist);
d028235d 2281 }
81810dd1
DL
2282
2283 free(dropcaps);
2284
2285 return ret;
2286}
2287
713046e3 2288static int set_config_console(const char *key, const char *value,
504a2217 2289 struct lxc_conf *lxc_conf)
28a4b0e5 2290{
713046e3 2291 return set_config_path_item(&lxc_conf->console.path, value);
28a4b0e5
DL
2292}
2293
713046e3 2294static int set_config_console_logfile(const char *key, const char *value,
504a2217 2295 struct lxc_conf *lxc_conf)
96f15ca1 2296{
713046e3 2297 return set_config_path_item(&lxc_conf->console.log_path, value);
96f15ca1
SH
2298}
2299
e6744e9b 2300/*
504a2217
CB
2301 * If we find a lxc.network.hwaddr in the original config file, we expand it in
2302 * the unexpanded_config, so that after a save_config we store the hwaddr for
2303 * re-use.
2304 * This is only called when reading the config file, not when executing a
2305 * lxc.include.
e6744e9b
SH
2306 * 'x' and 'X' are substituted in-place.
2307 */
2308static void update_hwaddr(const char *line)
2309{
2310 char *p;
2311
2312 line += lxc_char_left_gc(line, strlen(line));
2313 if (line[0] == '#')
2314 return;
504a2217 2315
e6744e9b
SH
2316 if (strncmp(line, "lxc.network.hwaddr", 18) != 0)
2317 return;
504a2217
CB
2318
2319 /* Let config_network_hwaddr raise the error. */
e6744e9b
SH
2320 p = strchr(line, '=');
2321 if (!p)
504a2217 2322 return;
e6744e9b 2323 p++;
504a2217 2324
e6744e9b
SH
2325 while (isblank(*p))
2326 p++;
504a2217 2327
e6744e9b
SH
2328 if (!*p)
2329 return;
2330
2331 rand_complete_hwaddr(p);
2332}
2333
6b0d5538 2334int append_unexp_config_line(const char *line, struct lxc_conf *conf)
f979ac15 2335{
6b0d5538 2336 size_t len = conf->unexpanded_len, linelen = strlen(line);
f979ac15 2337
e6744e9b
SH
2338 update_hwaddr(line);
2339
6b0d5538 2340 while (conf->unexpanded_alloced <= len + linelen + 2) {
504a2217
CB
2341 char *tmp = realloc(conf->unexpanded_config,
2342 conf->unexpanded_alloced + 1024);
6b0d5538
SH
2343 if (!tmp)
2344 return -1;
504a2217 2345
6b0d5538
SH
2346 if (!conf->unexpanded_config)
2347 *tmp = '\0';
2348 conf->unexpanded_config = tmp;
2349 conf->unexpanded_alloced += 1024;
2350 }
2351 strcat(conf->unexpanded_config, line);
2352 conf->unexpanded_len += linelen;
504a2217 2353 if (line[linelen - 1] != '\n') {
6b0d5538
SH
2354 strcat(conf->unexpanded_config, "\n");
2355 conf->unexpanded_len++;
f979ac15 2356 }
f979ac15
SH
2357 return 0;
2358}
2359
e1daebd9
SH
2360static int do_includedir(const char *dirp, struct lxc_conf *lxc_conf)
2361{
74f96976 2362 struct dirent *direntp;
e1daebd9
SH
2363 DIR *dir;
2364 char path[MAXPATHLEN];
504a2217
CB
2365 int len;
2366 int ret = -1;
e1daebd9
SH
2367
2368 dir = opendir(dirp);
2369 if (!dir) {
2370 SYSERROR("failed to open '%s'", dirp);
2371 return -1;
2372 }
2373
74f96976 2374 while ((direntp = readdir(dir))) {
e1daebd9
SH
2375 const char *fnam;
2376 if (!direntp)
2377 break;
2378
2379 fnam = direntp->d_name;
2380 if (!strcmp(fnam, "."))
2381 continue;
2382
2383 if (!strcmp(fnam, ".."))
2384 continue;
2385
2386 len = strlen(fnam);
504a2217 2387 if (len < 6 || strncmp(fnam + len - 5, ".conf", 5) != 0)
e1daebd9
SH
2388 continue;
2389 len = snprintf(path, MAXPATHLEN, "%s/%s", dirp, fnam);
2390 if (len < 0 || len >= MAXPATHLEN) {
2391 ERROR("lxc.include filename too long under '%s'", dirp);
2392 ret = -1;
2393 goto out;
2394 }
2395
2396 ret = lxc_config_read(path, lxc_conf, true);
2397 if (ret < 0)
2398 goto out;
2399 }
2400 ret = 0;
2401
2402out:
2403 if (closedir(dir))
2404 WARN("lxc.include dir: failed to close directory");
2405
2406 return ret;
2407}
2408
713046e3 2409static int set_config_includefile(const char *key, const char *value,
504a2217 2410 struct lxc_conf *lxc_conf)
09ad6246 2411{
355c5701
CB
2412 /* Set config value to default. */
2413 if (config_value_empty(value)) {
2414 lxc_clear_config_item(lxc_conf, key);
616422f1 2415 return 0;
355c5701 2416 }
616422f1 2417
355c5701 2418 /* Parse new config value. */
e1daebd9
SH
2419 if (is_dir(value))
2420 return do_includedir(value, lxc_conf);
2421
6b0d5538 2422 return lxc_config_read(value, lxc_conf, true);
09ad6246
SH
2423}
2424
713046e3 2425static int set_config_rootfs(const char *key, const char *value,
504a2217 2426 struct lxc_conf *lxc_conf)
c2cc9f0a 2427{
713046e3 2428 return set_config_path_item(&lxc_conf->rootfs.path, value);
c2cc9f0a 2429}
2430
713046e3 2431static int set_config_rootfs_mount(const char *key, const char *value,
504a2217 2432 struct lxc_conf *lxc_conf)
23b7ea69 2433{
713046e3 2434 return set_config_path_item(&lxc_conf->rootfs.mount, value);
23b7ea69
DL
2435}
2436
713046e3 2437static int set_config_rootfs_options(const char *key, const char *value,
504a2217 2438 struct lxc_conf *lxc_conf)
a17b1e65 2439{
713046e3 2440 return set_config_string_item(&lxc_conf->rootfs.options, value);
a17b1e65
SG
2441}
2442
713046e3 2443static int set_config_rootfs_backend(const char *key, const char *value,
504a2217 2444 struct lxc_conf *lxc_conf)
bfd77214 2445{
b8223439 2446 if (config_value_empty(value)) {
6a21d4ae
SH
2447 free(lxc_conf->rootfs.bdev_type);
2448 lxc_conf->rootfs.bdev_type = NULL;
b8223439 2449 return 0;
6a21d4ae 2450 }
b8223439 2451
bfd77214 2452 if (!is_valid_bdev_type(value)) {
327a1e78 2453 ERROR("Bad rootfs.backend: '%s'", value);
bfd77214
SH
2454 return -1;
2455 }
2456
713046e3 2457 return set_config_string_item(&lxc_conf->rootfs.bdev_type, value);
bfd77214
SH
2458}
2459
713046e3 2460static int set_config_pivotdir(const char *key, const char *value,
504a2217 2461 struct lxc_conf *lxc_conf)
bf601689 2462{
2d489f9e 2463 WARN("lxc.pivotdir is ignored. It will soon become an error.");
59bb8698 2464 return 0;
bf601689
MH
2465}
2466
713046e3 2467static int set_config_utsname(const char *key, const char *value,
504a2217 2468 struct lxc_conf *lxc_conf)
c2cc9f0a 2469{
2470 struct utsname *utsname;
2471
00cd8039
CB
2472 if (config_value_empty(value)) {
2473 lxc_clear_config_item(lxc_conf, key);
1939e73d 2474 return 0;
00cd8039 2475 }
1939e73d 2476
c2cc9f0a 2477 utsname = malloc(sizeof(*utsname));
2478 if (!utsname) {
36eb9bde 2479 SYSERROR("failed to allocate memory");
c2cc9f0a 2480 return -1;
2481 }
2482
2483 if (strlen(value) >= sizeof(utsname->nodename)) {
00cd8039 2484 ERROR("node name '%s' is too long", value);
b6f24d54 2485 free(utsname);
c2cc9f0a 2486 return -1;
2487 }
2488
2489 strcpy(utsname->nodename, value);
f10fad2f 2490 free(lxc_conf->utsname);
c2cc9f0a 2491 lxc_conf->utsname = utsname;
2492
2493 return 0;
2494}
2495
6b0d5538
SH
2496struct parse_line_conf {
2497 struct lxc_conf *conf;
2498 bool from_include;
2499};
4184c3e1 2500
7a7ff0c6 2501static int parse_line(char *buffer, void *data)
c2cc9f0a 2502{
72d0e1cb 2503 struct lxc_config_t *config;
504a2217 2504 char *dot, *key, *line, *linep, *value;
6b0d5538 2505 struct parse_line_conf *plc = data;
504a2217 2506 int ret = 0;
c2cc9f0a 2507
91480a0f 2508 if (lxc_is_line_empty(buffer))
c2cc9f0a 2509 return 0;
2510
81192358
DL
2511 /* we have to dup the buffer otherwise, at the re-exec for
2512 * reboot we modified the original string on the stack by
2513 * replacing '=' by '\0' below
91480a0f 2514 */
81192358 2515 linep = line = strdup(buffer);
91480a0f
DL
2516 if (!line) {
2517 SYSERROR("failed to allocate memory for '%s'", buffer);
81192358 2518 return -1;
91480a0f
DL
2519 }
2520
6b0d5538
SH
2521 if (!plc->from_include)
2522 if ((ret = append_unexp_config_line(line, plc->conf)))
2523 goto out;
2524
b2718c72 2525 line += lxc_char_left_gc(line, strlen(line));
476d4cf1 2526
4184c3e1
SH
2527 /* ignore comments */
2528 if (line[0] == '#')
91480a0f 2529 goto out;
476d4cf1 2530
6b0d5538
SH
2531 /* martian option - don't add it to the config itself */
2532 if (strncmp(line, "lxc.", 4))
4184c3e1 2533 goto out;
4184c3e1 2534
476d4cf1 2535 ret = -1;
c2cc9f0a 2536
b2718c72 2537 dot = strstr(line, "=");
c2cc9f0a 2538 if (!dot) {
36eb9bde 2539 ERROR("invalid configuration line: %s", line);
91480a0f 2540 goto out;
c2cc9f0a 2541 }
a871ff6b 2542
c2cc9f0a 2543 *dot = '\0';
2544 value = dot + 1;
2545
b2718c72 2546 key = line;
2547 key[lxc_char_right_gc(key, strlen(key))] = '\0';
c2cc9f0a 2548
b2718c72 2549 value += lxc_char_left_gc(value, strlen(value));
2550 value[lxc_char_right_gc(value, strlen(value))] = '\0';
c2cc9f0a 2551
bd878dee
SB
2552 if (*value == '\'' || *value == '\"') {
2553 size_t len = strlen(value);
504a2217
CB
2554 if (len > 1 && value[len - 1] == *value) {
2555 value[len - 1] = '\0';
bd878dee
SB
2556 value++;
2557 }
2558 }
2559
72d0e1cb 2560 config = lxc_getconfig(key);
c2cc9f0a 2561 if (!config) {
6e1d9b94 2562 ERROR("unknown key %s", key);
91480a0f 2563 goto out;
c2cc9f0a 2564 }
2565
d37f7cd7 2566 ret = config->set(key, value, plc->conf);
91480a0f
DL
2567
2568out:
81192358 2569 free(linep);
91480a0f 2570 return ret;
c2cc9f0a 2571}
2572
74a3920a 2573static int lxc_config_readline(char *buffer, struct lxc_conf *conf)
af5b0155 2574{
6b0d5538
SH
2575 struct parse_line_conf c;
2576
2577 c.conf = conf;
2578 c.from_include = false;
2579
2580 return parse_line(buffer, &c);
af5b0155
CLG
2581}
2582
6b0d5538 2583int lxc_config_read(const char *file, struct lxc_conf *conf, bool from_include)
c2cc9f0a 2584{
6b0d5538
SH
2585 struct parse_line_conf c;
2586
2587 c.conf = conf;
2588 c.from_include = from_include;
f979ac15 2589
504a2217 2590 if (access(file, R_OK) == -1) {
f3ca99fd
SH
2591 return -1;
2592 }
6b0d5538 2593
f7bee6c6 2594 /* Catch only the top level config file name in the structure */
504a2217 2595 if (!conf->rcfile)
76d0127f 2596 conf->rcfile = strdup(file);
f979ac15 2597
6b0d5538 2598 return lxc_file_for_each_line(file, parse_line, &c);
c2cc9f0a 2599}
62e46035 2600
504a2217 2601int lxc_config_define_add(struct lxc_list *defines, char *arg)
62e46035
CLG
2602{
2603 struct lxc_list *dent;
2604
2605 dent = malloc(sizeof(struct lxc_list));
2606 if (!dent)
2607 return -1;
2608
2609 dent->elem = arg;
2610 lxc_list_add_tail(defines, dent);
2611 return 0;
2612}
2613
226a18d6 2614int lxc_config_define_load(struct lxc_list *defines, struct lxc_conf *conf)
62e46035 2615{
504a2217 2616 struct lxc_list *it, *next;
62e46035
CLG
2617 int ret = 0;
2618
2619 lxc_list_for_each(it, defines) {
2620 ret = lxc_config_readline(it->elem, conf);
2621 if (ret)
2622 break;
2623 }
2624
9ebb03ad 2625 lxc_list_for_each_safe(it, defines, next) {
62e46035
CLG
2626 lxc_list_del(it);
2627 free(it);
2628 }
2629
2630 return ret;
2631}
525f0002
CS
2632
2633signed long lxc_config_parse_arch(const char *arch)
2634{
504a2217
CB
2635#if HAVE_SYS_PERSONALITY_H
2636 size_t i;
525f0002
CS
2637 struct per_name {
2638 char *name;
2639 unsigned long per;
bb8d8207 2640 } pername[] = {
504a2217
CB
2641 { "x86", PER_LINUX32 },
2642 { "linux32", PER_LINUX32 },
2643 { "i386", PER_LINUX32 },
2644 { "i486", PER_LINUX32 },
2645 { "i586", PER_LINUX32 },
2646 { "i686", PER_LINUX32 },
2647 { "athlon", PER_LINUX32 },
2648 { "mips", PER_LINUX32 },
2649 { "mipsel", PER_LINUX32 },
2650 { "ppc", PER_LINUX32 },
2651 { "arm", PER_LINUX32 },
2652 { "armv7l", PER_LINUX32 },
2653 { "armhf", PER_LINUX32 },
2654 { "armel", PER_LINUX32 },
2655 { "powerpc", PER_LINUX32 },
2656 { "linux64", PER_LINUX },
2657 { "x86_64", PER_LINUX },
2658 { "amd64", PER_LINUX },
2659 { "mips64", PER_LINUX },
2660 { "mips64el", PER_LINUX },
2661 { "ppc64", PER_LINUX },
2662 { "ppc64le", PER_LINUX },
2663 { "ppc64el", PER_LINUX },
2664 { "powerpc64", PER_LINUX },
2665 { "s390x", PER_LINUX },
2666 { "aarch64", PER_LINUX },
2667 { "arm64", PER_LINUX },
525f0002
CS
2668 };
2669 size_t len = sizeof(pername) / sizeof(pername[0]);
2670
525f0002
CS
2671 for (i = 0; i < len; i++) {
2672 if (!strcmp(pername[i].name, arch))
504a2217 2673 return pername[i].per;
525f0002 2674 }
504a2217 2675#endif
525f0002
CS
2676
2677 return -1;
2678}
72d0e1cb 2679
4d69b293
NK
2680int lxc_fill_elevated_privileges(char *flaglist, int *flags)
2681{
2682 char *token, *saveptr = NULL;
2683 int i, aflag;
504a2217
CB
2684 struct {
2685 const char *token;
2686 int flag;
2687 } all_privs[] = {
2688 { "CGROUP", LXC_ATTACH_MOVE_TO_CGROUP },
2689 { "CAP", LXC_ATTACH_DROP_CAPABILITIES },
2690 { "LSM", LXC_ATTACH_LSM_EXEC },
2691 { NULL, 0 }
4d69b293
NK
2692 };
2693
2694 if (!flaglist) {
504a2217
CB
2695 /* For the sake of backward compatibility, drop all privileges
2696 * if none is specified.
2697 */
4d69b293 2698 for (i = 0; all_privs[i].token; i++) {
d028235d 2699 *flags |= all_privs[i].flag;
4d69b293
NK
2700 }
2701 return 0;
2702 }
2703
2704 token = strtok_r(flaglist, "|", &saveptr);
2705 while (token) {
2706 aflag = -1;
2707 for (i = 0; all_privs[i].token; i++) {
2708 if (!strcmp(all_privs[i].token, token))
2709 aflag = all_privs[i].flag;
2710 }
2711 if (aflag < 0)
2712 return -1;
2713
2714 *flags |= aflag;
2715
2716 token = strtok_r(NULL, "|", &saveptr);
2717 }
504a2217 2718
4d69b293
NK
2719 return 0;
2720}
2721
bdf91ab4
CB
2722static inline int lxc_get_conf_int(struct lxc_conf *c, char *retv, int inlen,
2723 int v)
72d0e1cb
SG
2724{
2725 if (!retv)
2726 inlen = 0;
2727 else
2728 memset(retv, 0, inlen);
bdf91ab4 2729
72d0e1cb
SG
2730 return snprintf(retv, inlen, "%d", v);
2731}
2732
12a50cc6 2733int lxc_clear_config_item(struct lxc_conf *c, const char *key)
72d0e1cb 2734{
c7b15d1e
CB
2735 int ret = 0;
2736
2737 if (strcmp(key, "lxc.network") == 0) {
2738 ret = lxc_clear_config_network(c);
2739
2740 } else if (strncmp(key, "lxc.network.", 12) == 0) {
2741 ret = lxc_clear_nic(c, key + 12);
2742
504a2217 2743 } else if (strcmp(key, "lxc.cap.drop") == 0) {
c7b15d1e
CB
2744 ret = lxc_clear_config_caps(c);
2745
504a2217 2746 } else if (strcmp(key, "lxc.cap.keep") == 0) {
c7b15d1e
CB
2747 ret = lxc_clear_config_keepcaps(c);
2748
2749 } else if (strncmp(key, "lxc.cgroup", 10) == 0) {
2750 ret = lxc_clear_cgroups(c, key);
2751
504a2217 2752 } else if (strcmp(key, "lxc.mount.entry") == 0) {
c7b15d1e
CB
2753 ret = lxc_clear_mount_entries(c);
2754
504a2217 2755 } else if (strcmp(key, "lxc.mount.auto") == 0) {
c7b15d1e
CB
2756 ret = lxc_clear_automounts(c);
2757
2758 } else if (strncmp(key, "lxc.hook", 8) == 0) {
2759 ret = lxc_clear_hooks(c, key);
2760
2761 } else if (strncmp(key, "lxc.group", 9) == 0) {
2762 ret = lxc_clear_groups(c);
2763
2764 } else if (strncmp(key, "lxc.environment", 15) == 0) {
2765 ret = lxc_clear_environment(c);
2766
2767 } else if (strncmp(key, "lxc.id_map", 10) == 0) {
2768 ret = lxc_clear_idmaps(c);
2769
2770 } else if (strncmp(key, "lxc.limit", 9) == 0) {
2771 ret = lxc_clear_limits(c, key);
2772
2773 } else if (strcmp(key, "lxc.utsname") == 0) {
2774 free(c->utsname);
2775 c->utsname = NULL;
2776
c7b15d1e
CB
2777 } else if (strcmp(key, "lxc.haltsignal") == 0) {
2778 c->haltsignal = 0;
2779
2780 } else if (strcmp(key, "lxc.rebootsignal") == 0) {
2781 c->rebootsignal = 0;
2782
2783 } else if (strcmp(key, "lxc.stopsignal") == 0) {
2784 c->stopsignal = 0;
2785
2786 } else if (strcmp(key, "lxc.init_cmd") == 0) {
2787 free(c->init_cmd);
2788 c->init_cmd = NULL;
2789
2790 } else if (strcmp(key, "lxc.init_uid") == 0) {
2791 c->init_uid = 0;
2792
2793 } else if (strcmp(key, "lxc.init_gid") == 0) {
2794 c->init_gid = 0;
2795
2796 } else if (strcmp(key, "lxc.ephemeral") == 0) {
2797 c->ephemeral = 0;
2798
2799 } else if (strcmp(key, "lxc.console.logfile") == 0) {
2800 free(c->console.log_path);
2801 c->console.log_path = NULL;
2802
2803 } else if (strcmp(key, "lxc.console") == 0) {
2804 free(c->console.path);
2805 c->console.path = NULL;
2806
c7b15d1e
CB
2807 } else if (strcmp(key, "lxc.autodev") == 0) {
2808 c->autodev = 1;
2809
2810 } else if (strcmp(key, "lxc.kmsg") == 0) {
2811 c->kmsg = 0;
2812
2813 } else if (strcmp(key, "lxc.mount") == 0) {
2814 free(c->fstab);
2815 c->fstab = NULL;
2816
2817 } else if (strcmp(key, "lxc.rootfs") == 0) {
2818 free(c->rootfs.path);
2819 c->rootfs.path = NULL;
2820
2821 } else if (strcmp(key, "lxc.rootfs.mount") == 0) {
2822 free(c->rootfs.mount);
2823 c->rootfs.mount = NULL;
2824
2825 } else if (strcmp(key, "lxc.rootfs.options") == 0) {
2826 free(c->rootfs.options);
2827 c->rootfs.options = NULL;
2828
2829 } else if (strcmp(key, "lxc.rootfs.backend") == 0) {
2830 free(c->rootfs.bdev_type);
2831 c->rootfs.bdev_type = NULL;
2832
2833 } else if (strcmp(key, "lxc.aa_profile") == 0) {
2834 free(c->lsm_aa_profile);
2835 c->lsm_aa_profile = NULL;
2836
2837 } else if (strcmp(key, "lxc.aa_allow_incomplete") == 0) {
2838 c->lsm_aa_allow_incomplete = 0;
2839
2840 } else if (strcmp(key, "lxc.se_context") == 0) {
2841 free(c->lsm_se_context);
2842 c->lsm_se_context = NULL;
2843
2844 } else if (strcmp(key, "lxc.seccomp") == 0) {
2845 free(c->seccomp);
2846 c->seccomp = NULL;
2847
2848 } else if (strcmp(key, "lxc.loglevel") == 0) {
2849 c->loglevel = LXC_LOG_PRIORITY_NOTSET;
2850
2851 } else if (strcmp(key, "lxc.logfile") == 0) {
2852 free(c->logfile);
2853 c->logfile = NULL;
2854
2855 } else if (strcmp(key, "lxc.monitor.unshare") == 0) {
2856 c->monitor_unshare = 0;
2857
c7b15d1e
CB
2858 } else if (strcmp(key, "lxc.include") == 0) {
2859 lxc_clear_includes(c);
2860
2861 } else if (strcmp(key, "lxc.syslog") == 0) {
2862 free(c->syslog);
2863 c->syslog = NULL;
54345299
CB
2864
2865 } else if (strcmp(key, "lxc.start.auto") == 0) {
2866 c->start_auto = 0;
2867
2868 } else if (strcmp(key, "lxc.start.delay") == 0) {
2869 c->start_delay = 0;
2870
2871 } else if (strcmp(key, "lxc.start.order") == 0) {
2872 c->start_order = 0;
2873
b09521ac
CB
2874 } else if (strcmp(key, "lxc.no_new_privs") == 0) {
2875 c->no_new_privs = false;
2876
c7b15d1e
CB
2877 } else {
2878 ret = -1;
2879 }
2880
2881 return ret;
72d0e1cb
SG
2882}
2883
504a2217 2884/* Write out a configuration file. */
72d0e1cb
SG
2885void write_config(FILE *fout, struct lxc_conf *c)
2886{
6b0d5538 2887 int ret;
504a2217 2888 size_t len = c->unexpanded_len;
72d0e1cb 2889
6b0d5538
SH
2890 if (!len)
2891 return;
504a2217 2892
6b0d5538
SH
2893 ret = fwrite(c->unexpanded_config, 1, len, fout);
2894 if (ret != len)
2895 SYSERROR("Error writing configuration file");
2896}
f979ac15 2897
504a2217
CB
2898bool do_append_unexp_config_line(struct lxc_conf *conf, const char *key,
2899 const char *v)
6b0d5538
SH
2900{
2901 int ret;
151d2da2
CB
2902 size_t len;
2903 char *tmp;
4184c3e1 2904
151d2da2
CB
2905 len = strlen(key) + strlen(v) + 4;
2906 tmp = alloca(len);
2907
2908 if (config_value_empty(v))
2909 ret = snprintf(tmp, len, "%s =", key);
2910 else
2911 ret = snprintf(tmp, len, "%s = %s", key, v);
6b0d5538
SH
2912 if (ret < 0 || ret >= len)
2913 return false;
2914
2915 /* Save the line verbatim into unexpanded_conf */
2916 if (append_unexp_config_line(tmp, conf))
2917 return false;
2918
2919 return true;
2920}
2921
504a2217
CB
2922void clear_unexp_config_line(struct lxc_conf *conf, const char *key,
2923 bool rm_subkeys)
6b0d5538 2924{
504a2217
CB
2925 char *lend;
2926 char *lstart = conf->unexpanded_config;
6b0d5538
SH
2927
2928 if (!conf->unexpanded_config)
2929 return;
504a2217 2930
6b0d5538
SH
2931 while (*lstart) {
2932 lend = strchr(lstart, '\n');
2933 char v;
2934 if (!lend)
2935 lend = lstart + strlen(lstart);
2936 else
2937 lend++;
2938 if (strncmp(lstart, key, strlen(key)) != 0) {
2939 lstart = lend;
2940 continue;
5f62730e 2941 }
6b0d5538
SH
2942 if (!rm_subkeys) {
2943 v = lstart[strlen(key)];
2944 if (!isspace(v) && v != '=') {
2945 lstart = lend;
2946 continue;
2947 }
5f62730e 2948 }
6b0d5538
SH
2949 conf->unexpanded_len -= (lend - lstart);
2950 if (*lend == '\0') {
2951 *lstart = '\0';
2952 return;
fd986e08 2953 }
504a2217 2954 memmove(lstart, lend, strlen(lend) + 1);
fd986e08 2955 }
6b0d5538
SH
2956}
2957
329b3625
CB
2958bool clone_update_unexp_ovl_paths(struct lxc_conf *conf, const char *oldpath,
2959 const char *newpath, const char *oldname,
2960 const char *newname, const char *ovldir)
2961{
329b3625 2962 int ret;
504a2217
CB
2963 char *lend, *newdir, *olddir, *p, *q;
2964 size_t newdirlen, olddirlen;
329b3625 2965 char *lstart = conf->unexpanded_config;
504a2217 2966 const char *key = "lxc.mount.entry";
329b3625 2967
504a2217
CB
2968 olddirlen = strlen(ovldir) + strlen(oldpath) + strlen(oldname) + 2;
2969 olddir = alloca(olddirlen + 1);
2970 ret = snprintf(olddir, olddirlen + 1, "%s=%s/%s", ovldir, oldpath,
2971 oldname);
329b3625 2972 if (ret < 0 || ret >= olddirlen + 1) {
504a2217 2973 ERROR("failed to create string");
329b3625
CB
2974 return false;
2975 }
504a2217
CB
2976
2977 newdirlen = strlen(ovldir) + strlen(newpath) + strlen(newname) + 2;
2978 newdir = alloca(newdirlen + 1);
2979 ret = snprintf(newdir, newdirlen + 1, "%s=%s/%s", ovldir, newpath,
2980 newname);
329b3625 2981 if (ret < 0 || ret >= newdirlen + 1) {
504a2217 2982 ERROR("failed to create string");
329b3625
CB
2983 return false;
2984 }
504a2217 2985
329b3625
CB
2986 if (!conf->unexpanded_config)
2987 return true;
504a2217 2988
329b3625
CB
2989 while (*lstart) {
2990 lend = strchr(lstart, '\n');
2991 if (!lend)
2992 lend = lstart + strlen(lstart);
2993 else
2994 lend++;
504a2217 2995
329b3625 2996 if (strncmp(lstart, key, strlen(key)) != 0)
504a2217
CB
2997 goto next;
2998
329b3625
CB
2999 p = strchr(lstart + strlen(key), '=');
3000 if (!p)
504a2217 3001 goto next;
329b3625 3002 p++;
504a2217 3003
329b3625
CB
3004 while (isblank(*p))
3005 p++;
504a2217 3006
329b3625 3007 if (p >= lend)
504a2217
CB
3008 goto next;
3009
3010 /* Whenever an lxc.mount.entry entry is found in a line we check
3011 * if the substring " overlay" or the substring " aufs" is
3012 * present before doing any further work. We check for "
3013 * overlay" and " aufs" since both substrings need to have at
3014 * least one space before them in a valid overlay
3015 * lxc.mount.entry (/A B overlay). When the space before is
3016 * missing it is very likely that these substrings are part of a
3017 * path or something else. (Checking q >= lend ensures that we
3018 * only count matches in the current line.) */
3019 if ((!(q = strstr(p, " overlay")) || q >= lend) &&
3020 (!(q = strstr(p, " aufs")) || q >= lend))
3021 goto next;
3022
329b3625 3023 if (!(q = strstr(p, olddir)) || (q >= lend))
504a2217 3024 goto next;
329b3625
CB
3025
3026 /* replace the olddir with newdir */
3027 if (olddirlen >= newdirlen) {
3028 size_t diff = olddirlen - newdirlen;
3029 memcpy(q, newdir, newdirlen);
3030 if (olddirlen != newdirlen) {
3031 memmove(q + newdirlen, q + newdirlen + diff,
3032 strlen(q) - newdirlen - diff + 1);
3033 lend -= diff;
3034 conf->unexpanded_len -= diff;
3035 }
3036 } else {
3037 char *new;
3038 size_t diff = newdirlen - olddirlen;
3039 size_t oldlen = conf->unexpanded_len;
3040 size_t newlen = oldlen + diff;
3041 size_t poffset = q - conf->unexpanded_config;
504a2217 3042
329b3625
CB
3043 new = realloc(conf->unexpanded_config, newlen + 1);
3044 if (!new) {
3045 ERROR("Out of memory");
3046 return false;
3047 }
3048 conf->unexpanded_len = newlen;
3049 conf->unexpanded_alloced = newlen + 1;
3050 new[newlen - 1] = '\0';
3051 lend = new + (lend - conf->unexpanded_config);
504a2217
CB
3052 /* move over the remainder to make room for the newdir
3053 */
329b3625
CB
3054 memmove(new + poffset + newdirlen,
3055 new + poffset + olddirlen,
3056 oldlen - poffset - olddirlen + 1);
3057 conf->unexpanded_config = new;
3058 memcpy(new + poffset, newdir, newdirlen);
3059 lend += diff;
3060 }
504a2217
CB
3061 next:
3062 lstart = lend;
329b3625 3063 }
504a2217 3064
329b3625
CB
3065 return true;
3066}
3067
67702c21 3068bool clone_update_unexp_hooks(struct lxc_conf *conf, const char *oldpath,
d546aa0e
CB
3069 const char *newpath, const char *oldname,
3070 const char *newname)
6b0d5538 3071{
67702c21 3072 int ret;
504a2217
CB
3073 char *lend, *newdir, *olddir, *p;
3074 char *lstart = conf->unexpanded_config;
3075 size_t newdirlen, olddirlen;
3076 const char *key = "lxc.hook";
67702c21 3077
504a2217
CB
3078 olddirlen = strlen(oldpath) + strlen(oldname) + 1;
3079 olddir = alloca(olddirlen + 1);
d546aa0e
CB
3080 ret = snprintf(olddir, olddirlen + 1, "%s/%s", oldpath, oldname);
3081 if (ret < 0 || ret >= olddirlen + 1) {
504a2217 3082 ERROR("failed to create string");
67702c21
SH
3083 return false;
3084 }
504a2217
CB
3085
3086 newdirlen = strlen(newpath) + strlen(newname) + 1;
3087 newdir = alloca(newdirlen + 1);
d546aa0e
CB
3088 ret = snprintf(newdir, newdirlen + 1, "%s/%s", newpath, newname);
3089 if (ret < 0 || ret >= newdirlen + 1) {
504a2217 3090 ERROR("failed to create string");
67702c21
SH
3091 return false;
3092 }
3093 if (!conf->unexpanded_config)
3094 return true;
3095 while (*lstart) {
3096 lend = strchr(lstart, '\n');
3097 if (!lend)
3098 lend = lstart + strlen(lstart);
3099 else
3100 lend++;
504a2217 3101
d546aa0e 3102 if (strncmp(lstart, key, strlen(key)) != 0)
504a2217
CB
3103 goto next;
3104
d546aa0e
CB
3105 p = strchr(lstart + strlen(key), '=');
3106 if (!p)
504a2217 3107 goto next;
67702c21 3108 p++;
504a2217 3109
67702c21
SH
3110 while (isblank(*p))
3111 p++;
504a2217
CB
3112
3113 if (p >= lend)
3114 goto next;
3115
d546aa0e 3116 if (strncmp(p, olddir, strlen(olddir)) != 0)
504a2217
CB
3117 goto next;
3118
67702c21
SH
3119 /* replace the olddir with newdir */
3120 if (olddirlen >= newdirlen) {
3121 size_t diff = olddirlen - newdirlen;
3122 memcpy(p, newdir, newdirlen);
3123 if (olddirlen != newdirlen) {
d546aa0e
CB
3124 memmove(p + newdirlen, p + newdirlen + diff,
3125 strlen(p) - newdirlen - diff + 1);
67702c21
SH
3126 lend -= diff;
3127 conf->unexpanded_len -= diff;
3128 }
67702c21
SH
3129 } else {
3130 char *new;
3131 size_t diff = newdirlen - olddirlen;
3132 size_t oldlen = conf->unexpanded_len;
3133 size_t newlen = oldlen + diff;
3134 size_t poffset = p - conf->unexpanded_config;
504a2217 3135
d546aa0e 3136 new = realloc(conf->unexpanded_config, newlen + 1);
67702c21 3137 if (!new) {
504a2217 3138 ERROR("failed to allocate memory");
6b0d5538 3139 return false;
67702c21
SH
3140 }
3141 conf->unexpanded_len = newlen;
d546aa0e
CB
3142 conf->unexpanded_alloced = newlen + 1;
3143 new[newlen - 1] = '\0';
67702c21 3144 lend = new + (lend - conf->unexpanded_config);
504a2217
CB
3145 /* move over the remainder to make room for the newdir
3146 */
d546aa0e
CB
3147 memmove(new + poffset + newdirlen,
3148 new + poffset + olddirlen,
3149 oldlen - poffset - olddirlen + 1);
67702c21 3150 conf->unexpanded_config = new;
d546aa0e
CB
3151 memcpy(new + poffset, newdir, newdirlen);
3152 lend += diff;
fd986e08 3153 }
504a2217
CB
3154 next:
3155 lstart = lend;
fd986e08 3156 }
504a2217 3157
6b0d5538
SH
3158 return true;
3159}
3160
504a2217
CB
3161#define DO(cmd) \
3162 { \
3163 if (!(cmd)) { \
3164 ERROR("Error writing to new config"); \
3165 return false; \
3166 } \
3167 }
6b0d5538 3168
091045f8 3169static bool new_hwaddr(char *hwaddr)
67702c21 3170{
091045f8
CB
3171 int ret;
3172
091045f8
CB
3173 (void)randseed(true);
3174
3175 ret = snprintf(hwaddr, 18, "00:16:3e:%02x:%02x:%02x", rand() % 255,
3176 rand() % 255, rand() % 255);
3177 if (ret < 0 || ret >= 18) {
3178 SYSERROR("Failed to call snprintf().");
3179 return false;
3180 }
3181
3182 return true;
67702c21
SH
3183}
3184
3185/*
504a2217
CB
3186 * This is called only from clone. We wish to update all hwaddrs in the
3187 * unexpanded config file. We can't/don't want to update any which come from
3188 * lxc.includes (there shouldn't be any).
3189 * We can't just walk the c->lxc-conf->network list because that includes netifs
3190 * from the include files. So we update the ones which we find in the unexp
3191 * config file, then find the original macaddr in the conf->network, and update
3192 * that to the same value.
67702c21
SH
3193 */
3194bool network_new_hwaddrs(struct lxc_conf *conf)
6b0d5538 3195{
504a2217 3196 char *lend, *p, *p2;
6b0d5538 3197 struct lxc_list *it;
67702c21 3198 const char *key = "lxc.network.hwaddr";
504a2217 3199 char *lstart = conf->unexpanded_config;
6b0d5538 3200
67702c21
SH
3201 if (!conf->unexpanded_config)
3202 return true;
091045f8 3203
67702c21
SH
3204 while (*lstart) {
3205 char newhwaddr[18], oldhwaddr[17];
091045f8 3206
67702c21
SH
3207 lend = strchr(lstart, '\n');
3208 if (!lend)
3209 lend = lstart + strlen(lstart);
3210 else
3211 lend++;
091045f8 3212
67702c21
SH
3213 if (strncmp(lstart, key, strlen(key)) != 0) {
3214 lstart = lend;
3215 continue;
72d0e1cb 3216 }
091045f8 3217
504a2217 3218 p = strchr(lstart + strlen(key), '=');
67702c21
SH
3219 if (!p) {
3220 lstart = lend;
3221 continue;
72d0e1cb 3222 }
091045f8 3223
67702c21
SH
3224 p++;
3225 while (isblank(*p))
3226 p++;
3227 if (!*p)
3228 return true;
091045f8 3229
67702c21
SH
3230 p2 = p;
3231 while (*p2 && !isblank(*p2) && *p2 != '\n')
3232 p2++;
504a2217
CB
3233
3234 if ((p2 - p) != 17) {
67702c21
SH
3235 WARN("Bad hwaddr entry");
3236 lstart = lend;
3237 continue;
72d0e1cb 3238 }
091045f8 3239
67702c21 3240 memcpy(oldhwaddr, p, 17);
091045f8
CB
3241
3242 if (!new_hwaddr(newhwaddr))
3243 return false;
3244
67702c21 3245 memcpy(p, newhwaddr, 17);
504a2217
CB
3246 lxc_list_for_each(it, &conf->network)
3247 {
67702c21
SH
3248 struct lxc_netdev *n = it->elem;
3249 if (n->hwaddr && memcmp(oldhwaddr, n->hwaddr, 17) == 0)
3250 memcpy(n->hwaddr, newhwaddr, 17);
72d0e1cb 3251 }
67702c21
SH
3252
3253 lstart = lend;
72d0e1cb 3254 }
091045f8 3255
6b0d5538 3256 return true;
72d0e1cb 3257}
8796becf 3258
713046e3 3259static int set_config_ephemeral(const char *key, const char *value,
504a2217 3260 struct lxc_conf *lxc_conf)
8796becf 3261{
3c6cf53a
CB
3262 /* Set config value to default. */
3263 if (config_value_empty(value)) {
3264 lxc_conf->ephemeral = 0;
78304622 3265 return 0;
3c6cf53a 3266 }
78304622 3267
3c6cf53a 3268 /* Parse new config value. */
66ffdb1a
CB
3269 if (lxc_safe_uint(value, &lxc_conf->ephemeral) < 0)
3270 return -1;
8796becf 3271
66ffdb1a 3272 if (lxc_conf->ephemeral > 1) {
504a2217
CB
3273 ERROR(
3274 "Wrong value for lxc.ephemeral. Can only be set to 0 or 1");
8796becf 3275 return -1;
8796becf
CB
3276 }
3277
3278 return 0;
3279}
3280
713046e3 3281static int set_config_syslog(const char *key, const char *value,
504a2217 3282 struct lxc_conf *lxc_conf)
64c57ea1 3283{
76d0127f 3284 int facility;
7ca56b84 3285
ee10a69c
CB
3286 /* Clear any previously set value. */
3287 if (lxc_conf->syslog) {
3288 free(lxc_conf->syslog);
3289 lxc_conf->syslog = NULL;
3290 }
3291
3292 /* Check if value is empty. */
7ca56b84
CB
3293 if (config_value_empty(value))
3294 return 0;
3295
ee10a69c 3296 /* Parse value. */
76d0127f
CB
3297 facility = lxc_syslog_priority_to_int(value);
3298 if (facility == -EINVAL) {
d47f1b43 3299 ERROR("Wrong value for lxc.syslog.");
76d0127f 3300 return -1;
64c57ea1
BD
3301 }
3302
76d0127f 3303 lxc_log_syslog(facility);
713046e3 3304 return set_config_string_item(&lxc_conf->syslog, value);
64c57ea1 3305}
5a46f283 3306
713046e3 3307static int set_config_no_new_privs(const char *key, const char *value,
504a2217 3308 struct lxc_conf *lxc_conf)
5a46f283 3309{
e8ec7c9e 3310 unsigned int v;
5a46f283 3311
cf3f8bf6
CB
3312 /* Set config value to default. */
3313 if (config_value_empty(value)) {
3314 lxc_conf->no_new_privs = false;
80926845 3315 return 0;
cf3f8bf6 3316 }
80926845 3317
cf3f8bf6 3318 /* Parse new config value. */
e8ec7c9e
CB
3319 if (lxc_safe_uint(value, &v) < 0)
3320 return -1;
3321
3322 if (v > 1) {
504a2217
CB
3323 ERROR("Wrong value for lxc.no_new_privs. Can only be set to 0 "
3324 "or 1");
5a46f283
CB
3325 return -1;
3326 }
e8ec7c9e 3327
5a46f283
CB
3328 lxc_conf->no_new_privs = v ? true : false;
3329
3330 return 0;
3331}
7b992a3e
CB
3332
3333/* Callbacks to get configuration items. */
6bede808
CB
3334static int get_config_personality(const char *key, char *retv, int inlen,
3335 struct lxc_conf *c)
7b992a3e
CB
3336{
3337 int fulllen = 0;
3338
3339 if (!retv)
3340 inlen = 0;
3341 else
3342 memset(retv, 0, inlen);
3343
3344#if HAVE_SYS_PERSONALITY_H
3345 int len = 0;
3346
6bede808 3347 switch (c->personality) {
7b992a3e
CB
3348 case PER_LINUX32:
3349 strprint(retv, inlen, "i686");
3350 break;
3351 case PER_LINUX:
3352 strprint(retv, inlen, "x86_64");
3353 break;
3354 default:
3355 break;
3356 }
3357#endif
3358
3359 return fulllen;
3360}
bdf91ab4 3361
6bede808
CB
3362static int get_config_pts(const char *key, char *retv, int inlen,
3363 struct lxc_conf *c)
bdf91ab4 3364{
6bede808 3365 return lxc_get_conf_int(c, retv, inlen, c->pts);
bdf91ab4 3366}
5485782f 3367
6bede808
CB
3368static int get_config_tty(const char *key, char *retv, int inlen,
3369 struct lxc_conf *c)
5485782f 3370{
6bede808 3371 return lxc_get_conf_int(c, retv, inlen, c->tty);
5485782f 3372}
8015e018 3373
b29b29be 3374static inline int lxc_get_conf_str(char *retv, int inlen, const char *value)
8015e018
CB
3375{
3376 if (!value)
3377 return 0;
3378 if (retv && inlen >= strlen(value) + 1)
3379 strncpy(retv, value, strlen(value) + 1);
3380
3381 return strlen(value);
3382}
3383
6bede808
CB
3384static int get_config_ttydir(const char *key, char *retv, int inlen,
3385 struct lxc_conf *c)
8015e018 3386{
6bede808 3387 return lxc_get_conf_str(retv, inlen, c->ttydir);
8015e018 3388}
de1ede69 3389
6bede808
CB
3390static int get_config_kmsg(const char *key, char *retv, int inlen,
3391 struct lxc_conf *c)
de1ede69 3392{
6bede808 3393 return lxc_get_conf_int(c, retv, inlen, c->kmsg);
de1ede69 3394}
104c8e6c 3395
6bede808
CB
3396static int get_config_lsm_aa_profile(const char *key, char *retv, int inlen,
3397 struct lxc_conf *c)
104c8e6c 3398{
6bede808 3399 return lxc_get_conf_str(retv, inlen, c->lsm_aa_profile);
104c8e6c 3400}
d60d18c6 3401
6bede808
CB
3402static int get_config_lsm_aa_incomplete(const char *key, char *retv, int inlen,
3403 struct lxc_conf *c)
d60d18c6 3404{
6bede808
CB
3405 return lxc_get_conf_int(c, retv, inlen,
3406 c->lsm_aa_allow_incomplete);
d60d18c6 3407}
4203a0b5 3408
6bede808
CB
3409static int get_config_lsm_se_context(const char *key, char *retv, int inlen,
3410 struct lxc_conf *c)
4203a0b5 3411{
6bede808 3412 return lxc_get_conf_str(retv, inlen, c->lsm_se_context);
4203a0b5 3413}
b863bf92
CB
3414
3415/*
3416 * If you ask for a specific cgroup value, i.e. lxc.cgroup.devices.list,
3417 * then just the value(s) will be printed. Since there still could be
3418 * more than one, it is newline-separated.
3419 * (Maybe that's ambigous, since some values, i.e. devices.list, will
3420 * already have newlines?)
3421 * If you ask for 'lxc.cgroup", then all cgroup entries will be printed,
3422 * in 'lxc.cgroup.subsystem.key = value' format.
3423 */
6bede808
CB
3424static int get_config_cgroup(const char *key, char *retv, int inlen,
3425 struct lxc_conf *c)
b863bf92
CB
3426{
3427 struct lxc_list *it;
3428 int len;
3429 int fulllen = 0;
3430 bool get_all = false;
3431
3432 if (!retv)
3433 inlen = 0;
3434 else
3435 memset(retv, 0, inlen);
3436
3437 if (!strcmp(key, "lxc.cgroup"))
3438 get_all = true;
3439 else if (!strncmp(key, "lxc.cgroup.", 11))
3440 key += 11;
3441 else
3442 return -1;
3443
6bede808 3444 lxc_list_for_each(it, &c->cgroup) {
b863bf92
CB
3445 struct lxc_cgroup *cg = it->elem;
3446 if (get_all) {
3447 strprint(retv, inlen, "lxc.cgroup.%s = %s\n", cg->subsystem, cg->value);
3448 } else if (!strcmp(cg->subsystem, key)) {
3449 strprint(retv, inlen, "%s\n", cg->value);
3450 }
3451 }
3452
3453 return fulllen;
3454}
5014ff2e 3455
6bede808
CB
3456static int get_config_idmaps(const char *key, char *retv, int inlen,
3457 struct lxc_conf *c)
5014ff2e
CB
3458{
3459 struct lxc_list *it;
3460 int len, listlen, ret;
3461 int fulllen = 0;
3462/* "u 1000 1000000 65536"
3463 *
3464 * let's render this as
3465 *
3466 * sizeof(char)
3467 * +
3468 * sizeof(" ")
3469 * +
3470 * sizeof(uint64_t)
3471 * +
3472 * sizeof(" ")
3473 * +
3474 * sizeof(uint64_t)
3475 * +
3476 * sizeof(" ")
3477 * +
3478 * sizeof(uint64_t)
3479 * +
3480 * \0
3481 */
3482#define __LXC_IDMAP_STR_BUF (3 * LXC_NUMSTRLEN64 + 3 + 1 + 1)
3483 char buf[__LXC_IDMAP_STR_BUF];
3484
3485 if (!retv)
3486 inlen = 0;
3487 else
3488 memset(retv, 0, inlen);
3489
6bede808
CB
3490 listlen = lxc_list_len(&c->id_map);
3491 lxc_list_for_each(it, &c->id_map)
5014ff2e
CB
3492 {
3493 struct id_map *map = it->elem;
3494 ret = snprintf(buf, __LXC_IDMAP_STR_BUF, "%c %lu %lu %lu",
3495 (map->idtype == ID_TYPE_UID) ? 'u' : 'g',
3496 map->nsid, map->hostid, map->range);
3497 if (ret < 0 || ret >= __LXC_IDMAP_STR_BUF)
3498 return -1;
3499
3500 strprint(retv, inlen, "%s%s", buf, (listlen-- > 1) ? "\n" : "");
3501 }
3502 return fulllen;
3503}
b29b29be 3504
6bede808
CB
3505static int get_config_loglevel(const char *key, char *retv, int inlen,
3506 struct lxc_conf *c)
b29b29be
CB
3507{
3508 const char *v;
6bede808 3509 v = lxc_log_priority_to_string(c->loglevel);
b29b29be
CB
3510 return lxc_get_conf_str(retv, inlen, v);
3511}
3d4630ab 3512
6bede808
CB
3513static int get_config_logfile(const char *key, char *retv, int inlen,
3514 struct lxc_conf *c)
3d4630ab 3515{
6bede808 3516 return lxc_get_conf_str(retv, inlen, c->logfile);
3d4630ab 3517}
0d601acb 3518
6bede808
CB
3519static int get_config_fstab(const char *key, char *retv, int inlen,
3520 struct lxc_conf *c)
0d601acb 3521{
6bede808 3522 return lxc_get_conf_str(retv, inlen, c->fstab);
0d601acb 3523}
43fbf8d9 3524
6bede808
CB
3525static int get_config_mount_auto(const char *key, char *retv, int inlen,
3526 struct lxc_conf *c)
43fbf8d9
CB
3527{
3528 int len, fulllen = 0;
3529 const char *sep = "";
3530
3531 if (!retv)
3532 inlen = 0;
3533 else
3534 memset(retv, 0, inlen);
3535
6bede808 3536 if (!(c->auto_mounts & LXC_AUTO_ALL_MASK))
43fbf8d9
CB
3537 return 0;
3538
6bede808 3539 switch (c->auto_mounts & LXC_AUTO_PROC_MASK) {
43fbf8d9
CB
3540 case LXC_AUTO_PROC_MIXED:
3541 strprint(retv, inlen, "%sproc:mixed", sep);
3542 sep = " ";
3543 break;
3544 case LXC_AUTO_PROC_RW:
3545 strprint(retv, inlen, "%sproc:rw", sep);
3546 sep = " ";
3547 break;
3548 default:
3549 break;
3550 }
3551
6bede808 3552 switch (c->auto_mounts & LXC_AUTO_SYS_MASK) {
43fbf8d9
CB
3553 case LXC_AUTO_SYS_RO:
3554 strprint(retv, inlen, "%ssys:ro", sep);
3555 sep = " ";
3556 break;
3557 case LXC_AUTO_SYS_RW:
3558 strprint(retv, inlen, "%ssys:rw", sep);
3559 sep = " ";
3560 break;
3561 case LXC_AUTO_SYS_MIXED:
3562 strprint(retv, inlen, "%ssys:mixed", sep);
3563 sep = " ";
3564 break;
3565 default:
3566 break;
3567 }
3568
6bede808 3569 switch (c->auto_mounts & LXC_AUTO_CGROUP_MASK) {
43fbf8d9
CB
3570 case LXC_AUTO_CGROUP_NOSPEC:
3571 strprint(retv, inlen, "%scgroup", sep);
3572 sep = " ";
3573 break;
3574 case LXC_AUTO_CGROUP_MIXED:
3575 strprint(retv, inlen, "%scgroup:mixed", sep);
3576 sep = " ";
3577 break;
3578 case LXC_AUTO_CGROUP_RO:
3579 strprint(retv, inlen, "%scgroup:ro", sep);
3580 sep = " ";
3581 break;
3582 case LXC_AUTO_CGROUP_RW:
3583 strprint(retv, inlen, "%scgroup:rw", sep);
3584 sep = " ";
3585 break;
3586 case LXC_AUTO_CGROUP_FULL_NOSPEC:
3587 strprint(retv, inlen, "%scgroup-full", sep);
3588 sep = " ";
3589 break;
3590 case LXC_AUTO_CGROUP_FULL_MIXED:
3591 strprint(retv, inlen, "%scgroup-full:mixed", sep);
3592 sep = " ";
3593 break;
3594 case LXC_AUTO_CGROUP_FULL_RO:
3595 strprint(retv, inlen, "%scgroup-full:ro", sep);
3596 sep = " ";
3597 break;
3598 case LXC_AUTO_CGROUP_FULL_RW:
3599 strprint(retv, inlen, "%scgroup-full:rw", sep);
3600 sep = " ";
3601 break;
3602 default:
3603 break;
3604 }
3605
3606 return fulllen;
3607}
cc921848 3608
6bede808
CB
3609static int get_config_mount(const char *key, char *retv, int inlen,
3610 struct lxc_conf *c)
cc921848
CB
3611{
3612 int len, fulllen = 0;
3613 struct lxc_list *it;
3614
3615 if (!retv)
3616 inlen = 0;
3617 else
3618 memset(retv, 0, inlen);
3619
6bede808 3620 lxc_list_for_each(it, &c->mount_list)
cc921848
CB
3621 {
3622 strprint(retv, inlen, "%s\n", (char *)it->elem);
3623 }
3624
3625 return fulllen;
3626}
819114b6 3627
6bede808
CB
3628static int get_config_rootfs(const char *key, char *retv, int inlen,
3629 struct lxc_conf *c)
819114b6 3630{
6bede808 3631 return lxc_get_conf_str(retv, inlen, c->rootfs.path);
819114b6 3632}
3af60359 3633
6bede808
CB
3634static int get_config_rootfs_mount(const char *key, char *retv, int inlen,
3635 struct lxc_conf *c)
3af60359 3636{
6bede808 3637 return lxc_get_conf_str(retv, inlen, c->rootfs.mount);
3af60359 3638}
0e9db631 3639
6bede808
CB
3640static int get_config_rootfs_options(const char *key, char *retv, int inlen,
3641 struct lxc_conf *c)
0e9db631 3642{
6bede808 3643 return lxc_get_conf_str(retv, inlen, c->rootfs.options);
0e9db631 3644}
8f183f38 3645
6bede808
CB
3646static int get_config_rootfs_backend(const char *key, char *retv, int inlen,
3647 struct lxc_conf *c)
8f183f38 3648{
6bede808 3649 return lxc_get_conf_str(retv, inlen, c->rootfs.bdev_type);
8f183f38 3650}
b87574e7 3651
6bede808
CB
3652static int get_config_pivotdir(const char *key, char *retv, int inlen,
3653 struct lxc_conf *c)
b87574e7
CB
3654{
3655 return 0;
3656}
e274f8b0 3657
6bede808
CB
3658static int get_config_utsname(const char *key, char *retv, int inlen,
3659 struct lxc_conf *c)
e274f8b0
CB
3660{
3661 return lxc_get_conf_str(
3662 retv, inlen,
6bede808 3663 c->utsname ? c->utsname->nodename : NULL);
e274f8b0 3664}
466c2e93 3665
6bede808
CB
3666static int get_config_hooks(const char *key, char *retv, int inlen,
3667 struct lxc_conf *c)
466c2e93
CB
3668{
3669 char *subkey;
3670 int len, fulllen = 0, found = -1;
3671 struct lxc_list *it;
3672 int i;
3673
3674 /* "lxc.hook.mount" */
3675 subkey = strchr(key, '.');
3676 if (subkey)
3677 subkey = strchr(subkey + 1, '.');
3678 if (!subkey)
3679 return -1;
3680 subkey++;
3681 if (!*subkey)
3682 return -1;
3683 for (i = 0; i < NUM_LXC_HOOKS; i++) {
3684 if (strcmp(lxchook_names[i], subkey) == 0) {
3685 found = i;
3686 break;
3687 }
3688 }
3689 if (found == -1)
3690 return -1;
3691
3692 if (!retv)
3693 inlen = 0;
3694 else
3695 memset(retv, 0, inlen);
3696
6bede808 3697 lxc_list_for_each(it, &c->hooks[found]) {
466c2e93
CB
3698 strprint(retv, inlen, "%s\n", (char *)it->elem);
3699 }
3700 return fulllen;
3701}
d2ceff53 3702
6bede808
CB
3703static int get_config_network(const char *key, char *retv, int inlen,
3704 struct lxc_conf *c)
d2ceff53
CB
3705{
3706 int len, fulllen = 0;
3707 struct lxc_list *it;
3708
3709 if (!retv)
3710 inlen = 0;
3711 else
3712 memset(retv, 0, inlen);
3713
6bede808 3714 lxc_list_for_each(it, &c->network) {
d2ceff53
CB
3715 struct lxc_netdev *n = it->elem;
3716 const char *t = lxc_net_type_to_str(n->type);
3717 strprint(retv, inlen, "%s\n", t ? t : "(invalid)");
3718 }
3719
3720 return fulllen;
3721}
bdccff60
CB
3722
3723/*
3724 * lxc.network.0.XXX, where XXX can be: name, type, link, flags, type,
3725 * macvlan.mode, veth.pair, vlan, ipv4, ipv6, script.up, hwaddr, mtu,
3726 * ipv4.gateway, ipv6.gateway. ipvX.gateway can return 'auto' instead
3727 * of an address. ipv4 and ipv6 return lists (newline-separated).
3728 * things like veth.pair return '' if invalid (i.e. if called for vlan
3729 * type).
3730 */
6bede808
CB
3731static int get_config_network_item(const char *key, char *retv, int inlen,
3732 struct lxc_conf *c)
bdccff60
CB
3733{
3734 char *p1;
3735 int len, fulllen = 0;
3736 struct lxc_netdev *netdev;
3737
3738 if (!retv)
3739 inlen = 0;
3740 else
3741 memset(retv, 0, inlen);
3742
3743 if (!strncmp(key, "lxc.network.", 12))
3744 key += 12;
3745 else
3746 return -1;
3747
3748 p1 = strchr(key, '.');
3749 if (!p1 || *(p1 + 1) == '\0')
3750 return -1;
3751 p1++;
3752
6bede808 3753 netdev = get_netdev_from_key(key, &c->network);
bdccff60
CB
3754 if (!netdev)
3755 return -1;
3756 if (strcmp(p1, "name") == 0) {
3757 if (netdev->name)
3758 strprint(retv, inlen, "%s", netdev->name);
3759 } else if (strcmp(p1, "type") == 0) {
3760 strprint(retv, inlen, "%s", lxc_net_type_to_str(netdev->type));
3761 } else if (strcmp(p1, "link") == 0) {
3762 if (netdev->link)
3763 strprint(retv, inlen, "%s", netdev->link);
3764 } else if (strcmp(p1, "flags") == 0) {
3765 if (netdev->flags & IFF_UP)
3766 strprint(retv, inlen, "up");
3767 } else if (strcmp(p1, "script.up") == 0) {
3768 if (netdev->upscript)
3769 strprint(retv, inlen, "%s", netdev->upscript);
3770 } else if (strcmp(p1, "script.down") == 0) {
3771 if (netdev->downscript)
3772 strprint(retv, inlen, "%s", netdev->downscript);
3773 } else if (strcmp(p1, "hwaddr") == 0) {
3774 if (netdev->hwaddr)
3775 strprint(retv, inlen, "%s", netdev->hwaddr);
3776 } else if (strcmp(p1, "mtu") == 0) {
3777 if (netdev->mtu)
3778 strprint(retv, inlen, "%s", netdev->mtu);
3779 } else if (strcmp(p1, "macvlan.mode") == 0) {
3780 if (netdev->type == LXC_NET_MACVLAN) {
3781 const char *mode;
3782 switch (netdev->priv.macvlan_attr.mode) {
3783 case MACVLAN_MODE_PRIVATE:
3784 mode = "private";
3785 break;
3786 case MACVLAN_MODE_VEPA:
3787 mode = "vepa";
3788 break;
3789 case MACVLAN_MODE_BRIDGE:
3790 mode = "bridge";
3791 break;
3792 case MACVLAN_MODE_PASSTHRU:
3793 mode = "passthru";
3794 break;
3795 default:
3796 mode = "(invalid)";
3797 break;
3798 }
3799 strprint(retv, inlen, "%s", mode);
3800 }
3801 } else if (strcmp(p1, "veth.pair") == 0) {
3802 if (netdev->type == LXC_NET_VETH) {
3803 strprint(retv, inlen, "%s",
3804 netdev->priv.veth_attr.pair
3805 ? netdev->priv.veth_attr.pair
3806 : netdev->priv.veth_attr.veth1);
3807 }
3808 } else if (strcmp(p1, "vlan") == 0) {
3809 if (netdev->type == LXC_NET_VLAN) {
3810 strprint(retv, inlen, "%d", netdev->priv.vlan_attr.vid);
3811 }
3812 } else if (strcmp(p1, "ipv4.gateway") == 0) {
3813 if (netdev->ipv4_gateway_auto) {
3814 strprint(retv, inlen, "auto");
3815 } else if (netdev->ipv4_gateway) {
3816 char buf[INET_ADDRSTRLEN];
3817 inet_ntop(AF_INET, netdev->ipv4_gateway, buf,
3818 sizeof(buf));
3819 strprint(retv, inlen, "%s", buf);
3820 }
3821 } else if (strcmp(p1, "ipv4") == 0) {
3822 struct lxc_list *it2;
3823 lxc_list_for_each(it2, &netdev->ipv4) {
3824 struct lxc_inetdev *i = it2->elem;
3825 char buf[INET_ADDRSTRLEN];
3826 inet_ntop(AF_INET, &i->addr, buf, sizeof(buf));
3827 strprint(retv, inlen, "%s/%d\n", buf, i->prefix);
3828 }
3829 } else if (strcmp(p1, "ipv6.gateway") == 0) {
3830 if (netdev->ipv6_gateway_auto) {
3831 strprint(retv, inlen, "auto");
3832 } else if (netdev->ipv6_gateway) {
3833 char buf[INET6_ADDRSTRLEN];
3834 inet_ntop(AF_INET6, netdev->ipv6_gateway, buf,
3835 sizeof(buf));
3836 strprint(retv, inlen, "%s", buf);
3837 }
3838 } else if (strcmp(p1, "ipv6") == 0) {
3839 struct lxc_list *it2;
3840 lxc_list_for_each(it2, &netdev->ipv6) {
3841 struct lxc_inet6dev *i = it2->elem;
3842 char buf[INET6_ADDRSTRLEN];
3843 inet_ntop(AF_INET6, &i->addr, buf, sizeof(buf));
3844 strprint(retv, inlen, "%s/%d\n", buf, i->prefix);
3845 }
3846 }
3847 return fulllen;
3848}
1c96d6d8 3849
6bede808
CB
3850static int get_config_cap_drop(const char *key, char *retv, int inlen,
3851 struct lxc_conf *c)
1c96d6d8
CB
3852{
3853 int len, fulllen = 0;
3854 struct lxc_list *it;
3855
3856 if (!retv)
3857 inlen = 0;
3858 else
3859 memset(retv, 0, inlen);
3860
6bede808 3861 lxc_list_for_each(it, &c->caps) {
b80927f2
CB
3862 strprint(retv, inlen, "%s\n", (char *)it->elem);
3863 }
3864 return fulllen;
3865}
3866
6bede808
CB
3867static int get_config_cap_keep(const char *key, char *retv, int inlen,
3868 struct lxc_conf *c)
b80927f2
CB
3869{
3870 int len, fulllen = 0;
3871 struct lxc_list *it;
3872
3873 if (!retv)
3874 inlen = 0;
3875 else
3876 memset(retv, 0, inlen);
3877
6bede808 3878 lxc_list_for_each(it, &c->keepcaps) {
1c96d6d8
CB
3879 strprint(retv, inlen, "%s\n", (char *)it->elem);
3880 }
3881 return fulllen;
3882}
0692663a 3883
6bede808
CB
3884static int get_config_console(const char *key, char *retv, int inlen,
3885 struct lxc_conf *c)
0692663a 3886{
6bede808 3887 return lxc_get_conf_str(retv, inlen, c->console.path);
0692663a 3888}
794d1c06 3889
6bede808
CB
3890static int get_config_console_logfile(const char *key, char *retv, int inlen,
3891 struct lxc_conf *c)
794d1c06 3892{
6bede808 3893 return lxc_get_conf_str(retv, inlen, c->console.log_path);
794d1c06 3894}
75f55b1f 3895
6bede808
CB
3896static int get_config_seccomp(const char *key, char *retv, int inlen,
3897 struct lxc_conf *c)
75f55b1f 3898{
6bede808 3899 return lxc_get_conf_str(retv, inlen, c->seccomp);
75f55b1f 3900}
97f6dad0 3901
6bede808
CB
3902static int get_config_autodev(const char *key, char *retv, int inlen,
3903 struct lxc_conf *c)
97f6dad0 3904{
6bede808 3905 return lxc_get_conf_int(c, retv, inlen, c->autodev);
97f6dad0 3906}
afee4324 3907
6bede808
CB
3908static int get_config_haltsignal(const char *key, char *retv, int inlen,
3909 struct lxc_conf *c)
afee4324 3910{
6bede808 3911 return lxc_get_conf_int(c, retv, inlen, c->haltsignal);
afee4324 3912}
3aa8f359 3913
6bede808
CB
3914static int get_config_rebootsignal(const char *key, char *retv, int inlen,
3915 struct lxc_conf *c)
3aa8f359 3916{
6bede808 3917 return lxc_get_conf_int(c, retv, inlen, c->rebootsignal);
3aa8f359 3918}
2e16269f 3919
6bede808
CB
3920static int get_config_stopsignal(const char *key, char *retv, int inlen,
3921 struct lxc_conf *c)
2e16269f 3922{
6bede808 3923 return lxc_get_conf_int(c, retv, inlen, c->stopsignal);
2e16269f 3924}
54345299 3925
6bede808
CB
3926static int get_config_start(const char *key, char *retv, int inlen,
3927 struct lxc_conf *c)
54345299
CB
3928{
3929 if (strcmp(key, "lxc.start.auto") == 0)
6bede808 3930 return lxc_get_conf_int(c, retv, inlen, c->start_auto);
54345299 3931 else if (strcmp(key, "lxc.start.delay") == 0)
6bede808 3932 return lxc_get_conf_int(c, retv, inlen, c->start_delay);
54345299 3933 else if (strcmp(key, "lxc.start.order") == 0)
6bede808 3934 return lxc_get_conf_int(c, retv, inlen, c->start_order);
54345299
CB
3935
3936 return -1;
3937}
de9df15e 3938
6bede808
CB
3939static int get_config_syslog(const char *key, char *retv, int inlen,
3940 struct lxc_conf *c)
de9df15e 3941{
6bede808 3942 return lxc_get_conf_str(retv, inlen, c->syslog);
de9df15e 3943}
ac0f949c 3944
6bede808
CB
3945static int get_config_monitor(const char *key, char *retv, int inlen,
3946 struct lxc_conf *c)
ac0f949c 3947{
6bede808 3948 return lxc_get_conf_int(c, retv, inlen, c->monitor_unshare);
ac0f949c 3949}
90ec7b6e 3950
6bede808
CB
3951static int get_config_group(const char *key, char *retv, int inlen,
3952 struct lxc_conf *c)
90ec7b6e
CB
3953{
3954 int len, fulllen = 0;
3955 struct lxc_list *it;
3956
3957 if (!retv)
3958 inlen = 0;
3959 else
3960 memset(retv, 0, inlen);
3961
6bede808 3962 lxc_list_for_each(it, &c->groups) {
90ec7b6e
CB
3963 strprint(retv, inlen, "%s\n", (char *)it->elem);
3964 }
3965 return fulllen;
3966}
aa0db7d3 3967
6bede808
CB
3968static int get_config_environment(const char *key, char *retv, int inlen,
3969 struct lxc_conf *c)
aa0db7d3
CB
3970{
3971 int len, fulllen = 0;
3972 struct lxc_list *it;
3973
3974 if (!retv)
3975 inlen = 0;
3976 else
3977 memset(retv, 0, inlen);
3978
6bede808 3979 lxc_list_for_each(it, &c->environment) {
aa0db7d3
CB
3980 strprint(retv, inlen, "%s\n", (char *)it->elem);
3981 }
3982 return fulllen;
3983}
96dfcb7d 3984
6bede808
CB
3985static int get_config_init_cmd(const char *key, char *retv, int inlen,
3986 struct lxc_conf *c)
96dfcb7d 3987{
6bede808 3988 return lxc_get_conf_str(retv, inlen, c->init_cmd);
96dfcb7d 3989}
1398e9b1 3990
6bede808
CB
3991static int get_config_init_uid(const char *key, char *retv, int inlen,
3992 struct lxc_conf *c)
1398e9b1 3993{
6bede808 3994 return lxc_get_conf_int(c, retv, inlen, c->init_uid);
1398e9b1 3995}
dfeb7e42 3996
6bede808
CB
3997static int get_config_init_gid(const char *key, char *retv, int inlen,
3998 struct lxc_conf *c)
dfeb7e42 3999{
6bede808 4000 return lxc_get_conf_int(c, retv, inlen, c->init_gid);
dfeb7e42 4001}
62048afe 4002
6bede808
CB
4003static int get_config_ephemeral(const char *key, char *retv, int inlen,
4004 struct lxc_conf *c)
62048afe 4005{
6bede808 4006 return lxc_get_conf_int(c, retv, inlen, c->ephemeral);
62048afe 4007}
b09521ac 4008
6bede808
CB
4009static int get_config_no_new_privs(const char *key, char *retv, int inlen,
4010 struct lxc_conf *c)
b09521ac 4011{
6bede808 4012 return lxc_get_conf_int(c, retv, inlen, c->no_new_privs);
b09521ac 4013}
389f6466
CB
4014
4015/*
4016 * If you ask for a specific value, i.e. lxc.limit.nofile, then just the value
4017 * will be printed. If you ask for 'lxc.limit', then all limit entries will be
4018 * printed, in 'lxc.limit.resource = value' format.
4019 */
6bede808
CB
4020static int get_config_limit(const char *key, char *retv, int inlen,
4021 struct lxc_conf *c)
389f6466
CB
4022{
4023 int fulllen = 0, len;
4024 bool get_all = false;
4025 struct lxc_list *it;
4026
4027 if (!retv)
4028 inlen = 0;
4029 else
4030 memset(retv, 0, inlen);
4031
4032 if (!strcmp(key, "lxc.limit"))
4033 get_all = true;
4034 else if (strncmp(key, "lxc.limit.", 10) == 0)
4035 key += 10;
4036 else
4037 return -1;
4038
6bede808 4039 lxc_list_for_each(it, &c->limits) {
389f6466
CB
4040 char buf[LXC_NUMSTRLEN64 * 2 + 2]; /* 2 colon separated 64 bit
4041 integers or the word
4042 'unlimited' */
4043 int partlen;
4044 struct lxc_limit *lim = it->elem;
4045
4046 if (lim->limit.rlim_cur == RLIM_INFINITY) {
4047 memcpy(buf, "unlimited", sizeof("unlimited"));
4048 partlen = sizeof("unlimited") - 1;
4049 } else {
4050 partlen = sprintf(buf, "%" PRIu64,
4051 (uint64_t)lim->limit.rlim_cur);
4052 }
4053 if (lim->limit.rlim_cur != lim->limit.rlim_max) {
4054 if (lim->limit.rlim_max == RLIM_INFINITY) {
4055 memcpy(buf + partlen, ":unlimited",
4056 sizeof(":unlimited"));
4057 } else {
4058 sprintf(buf + partlen, ":%" PRIu64,
4059 (uint64_t)lim->limit.rlim_max);
4060 }
4061 }
4062
4063 if (get_all) {
4064 strprint(retv, inlen, "lxc.limit.%s = %s\n",
4065 lim->resource, buf);
4066 } else if (strcmp(lim->resource, key) == 0) {
4067 strprint(retv, inlen, "%s", buf);
4068 }
4069 }
4070
4071 return fulllen;
4072}
e08cb901
CB
4073
4074/* Callbacks to clear config items. */
4075static inline int clr_config_personality(const char *key, struct lxc_conf *c)
4076{
4077 c->personality = -1;
4078 return 0;
4079}
03818ae3
CB
4080
4081static inline int clr_config_pts(const char *key, struct lxc_conf *c)
4082{
4083 c->pts = 0;
4084 return 0;
4085}
e7a4b096
CB
4086
4087static inline int clr_config_tty(const char *key, struct lxc_conf *c)
4088{
4089 c->tty = 0;
4090 return 0;
4091}
eaf8c0c7
CB
4092
4093static inline int clr_config_ttydir(const char *key, struct lxc_conf *c)
4094{
4095 free(c->ttydir);
4096 c->ttydir = NULL;
4097 return 0;
4098}