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