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