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