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