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