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