]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/confile.c
conf/ile: avoid atoi() in config_ephemeral()
[mirror_lxc.git] / src / lxc / confile.c
CommitLineData
c2cc9f0a 1/*
2 * lxc: linux Container library
3 *
4 * (C) Copyright IBM Corp. 2007, 2008
5 *
6 * Authors:
9afe19d6 7 * Daniel Lezcano <daniel.lezcano at free.fr>
c2cc9f0a 8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
250b1eec 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
c2cc9f0a 22 */
12a50cc6 23#define _GNU_SOURCE
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
AV
30#include <ctype.h>
31#include <signal.h>
63376d7d 32#include <sys/stat.h>
c2cc9f0a 33#include <sys/types.h>
34#include <sys/param.h>
35#include <sys/utsname.h>
36#include <arpa/inet.h>
37#include <netinet/in.h>
38#include <net/if.h>
67702c21 39#include <time.h>
e1daebd9 40#include <dirent.h>
64c57ea1 41#include <syslog.h>
c2cc9f0a 42
d8e48992 43#include "bdev.h"
b2718c72 44#include "parse.h"
6ff05e18 45#include "config.h"
525f0002 46#include "confile.h"
26c39028 47#include "utils.h"
f2363e38
ÇO
48#include "log.h"
49#include "conf.h"
72d0e1cb 50#include "network.h"
58e0f57d 51#include "lxcseccomp.h"
36eb9bde 52
6ff05e18
SG
53#if HAVE_SYS_PERSONALITY_H
54#include <sys/personality.h>
55#endif
56
36eb9bde 57lxc_log_define(lxc_confile, lxc);
576f946d 58
12a50cc6
DE
59static int config_personality(const char *, const char *, struct lxc_conf *);
60static int config_pts(const char *, const char *, struct lxc_conf *);
61static int config_tty(const char *, const char *, struct lxc_conf *);
62static int config_ttydir(const char *, const char *, struct lxc_conf *);
7e0e1d94 63static int config_kmsg(const char *, const char *, struct lxc_conf *);
fe4de9a6 64static int config_lsm_aa_profile(const char *, const char *, struct lxc_conf *);
7aff4f43 65static int config_lsm_aa_incomplete(const char *, const char *, struct lxc_conf *);
fe4de9a6 66static int config_lsm_se_context(const char *, const char *, struct lxc_conf *);
12a50cc6 67static int config_cgroup(const char *, const char *, struct lxc_conf *);
f6d3e3e4 68static int config_idmap(const char *, const char *, struct lxc_conf *);
4a85ce2a
SH
69static int config_loglevel(const char *, const char *, struct lxc_conf *);
70static int config_logfile(const char *, const char *, struct lxc_conf *);
12a50cc6 71static int config_mount(const char *, const char *, struct lxc_conf *);
70f55bfd
NC
72static int config_mount_auto(const char *, const char *, struct lxc_conf *);
73static int config_fstab(const char *, const char *, struct lxc_conf *);
12a50cc6
DE
74static int config_rootfs(const char *, const char *, struct lxc_conf *);
75static int config_rootfs_mount(const char *, const char *, struct lxc_conf *);
a17b1e65 76static int config_rootfs_options(const char *, const char *, struct lxc_conf *);
327a1e78 77static int config_rootfs_backend(const char *, const char *, struct lxc_conf *);
12a50cc6
DE
78static int config_pivotdir(const char *, const char *, struct lxc_conf *);
79static int config_utsname(const char *, const char *, struct lxc_conf *);
80static int config_hook(const char *, const char *, struct lxc_conf *lxc_conf);
6b0d5538 81static int config_network(const char *, const char *, struct lxc_conf *);
12a50cc6
DE
82static int config_network_type(const char *, const char *, struct lxc_conf *);
83static int config_network_flags(const char *, const char *, struct lxc_conf *);
84static int config_network_link(const char *, const char *, struct lxc_conf *);
85static int config_network_name(const char *, const char *, struct lxc_conf *);
86static int config_network_veth_pair(const char *, const char *, struct lxc_conf *);
87static int config_network_macvlan_mode(const char *, const char *, struct lxc_conf *);
88static int config_network_hwaddr(const char *, const char *, struct lxc_conf *);
89static int config_network_vlan_id(const char *, const char *, struct lxc_conf *);
90static int config_network_mtu(const char *, const char *, struct lxc_conf *);
91static int config_network_ipv4(const char *, const char *, struct lxc_conf *);
92static int config_network_ipv4_gateway(const char *, const char *, struct lxc_conf *);
8fc8295a
DE
93static int config_network_script_up(const char *, const char *, struct lxc_conf *);
94static int config_network_script_down(const char *, const char *, struct lxc_conf *);
12a50cc6
DE
95static int config_network_ipv6(const char *, const char *, struct lxc_conf *);
96static int config_network_ipv6_gateway(const char *, const char *, struct lxc_conf *);
97static int config_cap_drop(const char *, const char *, struct lxc_conf *);
1fb86a7c 98static int config_cap_keep(const char *, const char *, struct lxc_conf *);
12a50cc6 99static int config_console(const char *, const char *, struct lxc_conf *);
96f15ca1 100static int config_console_logfile(const char *, const char *, struct lxc_conf *);
12a50cc6
DE
101static int config_seccomp(const char *, const char *, struct lxc_conf *);
102static int config_includefile(const char *, const char *, struct lxc_conf *);
103static int config_network_nic(const char *, const char *, struct lxc_conf *);
104static int config_autodev(const char *, const char *, struct lxc_conf *);
f0f1d8c0 105static int config_haltsignal(const char *, const char *, struct lxc_conf *);
dd267776 106static int config_rebootsignal(const char *, const char *, struct lxc_conf *);
a84b9932 107static int config_stopsignal(const char *, const char *, struct lxc_conf *);
ee1e7aa0 108static int config_start(const char *, const char *, struct lxc_conf *);
64c57ea1 109static int config_syslog(const char *, const char *, struct lxc_conf *);
a8dfe4e0 110static int config_monitor(const char *, const char *, struct lxc_conf *);
ee1e7aa0 111static int config_group(const char *, const char *, struct lxc_conf *);
7c661726 112static int config_environment(const char *, const char *, struct lxc_conf *);
67c660d0 113static int config_init_cmd(const char *, const char *, struct lxc_conf *);
72bb04e4
PT
114static int config_init_uid(const char *, const char *, struct lxc_conf *);
115static int config_init_gid(const char *, const char *, struct lxc_conf *);
8796becf 116static int config_ephemeral(const char *, const char *, struct lxc_conf *);
5a46f283 117static int config_no_new_privs(const char *, const char *, struct lxc_conf *);
c2cc9f0a 118
72d0e1cb 119static struct lxc_config_t config[] = {
576f946d 120
cccc74b5 121 { "lxc.arch", config_personality },
e892973e
DL
122 { "lxc.pts", config_pts },
123 { "lxc.tty", config_tty },
7c6ef2a2 124 { "lxc.devttydir", config_ttydir },
7e0e1d94 125 { "lxc.kmsg", config_kmsg },
fe4de9a6 126 { "lxc.aa_profile", config_lsm_aa_profile },
7aff4f43 127 { "lxc.aa_allow_incomplete", config_lsm_aa_incomplete },
fe4de9a6 128 { "lxc.se_context", config_lsm_se_context },
e892973e 129 { "lxc.cgroup", config_cgroup },
f6d3e3e4 130 { "lxc.id_map", config_idmap },
4a85ce2a
SH
131 { "lxc.loglevel", config_loglevel },
132 { "lxc.logfile", config_logfile },
70f55bfd
NC
133 { "lxc.mount.entry", config_mount },
134 { "lxc.mount.auto", config_mount_auto },
135 { "lxc.mount", config_fstab },
23b7ea69 136 { "lxc.rootfs.mount", config_rootfs_mount },
a17b1e65 137 { "lxc.rootfs.options", config_rootfs_options },
327a1e78 138 { "lxc.rootfs.backend", config_rootfs_backend },
e892973e 139 { "lxc.rootfs", config_rootfs },
bf601689 140 { "lxc.pivotdir", config_pivotdir },
e892973e 141 { "lxc.utsname", config_utsname },
26ddeedd 142 { "lxc.hook.pre-start", config_hook },
12a50cc6 143 { "lxc.hook.pre-mount", config_hook },
26ddeedd 144 { "lxc.hook.mount", config_hook },
f7bee6c6 145 { "lxc.hook.autodev", config_hook },
26ddeedd 146 { "lxc.hook.start", config_hook },
52492063 147 { "lxc.hook.stop", config_hook },
26ddeedd 148 { "lxc.hook.post-stop", config_hook },
148e91f5 149 { "lxc.hook.clone", config_hook },
37cf711b 150 { "lxc.hook.destroy", config_hook },
6b0d5538 151 { "lxc.hook", config_hook },
e892973e
DL
152 { "lxc.network.type", config_network_type },
153 { "lxc.network.flags", config_network_flags },
154 { "lxc.network.link", config_network_link },
155 { "lxc.network.name", config_network_name },
156 { "lxc.network.macvlan.mode", config_network_macvlan_mode },
157 { "lxc.network.veth.pair", config_network_veth_pair },
8fc8295a
DE
158 { "lxc.network.script.up", config_network_script_up },
159 { "lxc.network.script.down", config_network_script_down },
e892973e
DL
160 { "lxc.network.hwaddr", config_network_hwaddr },
161 { "lxc.network.mtu", config_network_mtu },
162 { "lxc.network.vlan.id", config_network_vlan_id },
f8fee0e2 163 { "lxc.network.ipv4.gateway", config_network_ipv4_gateway },
e892973e 164 { "lxc.network.ipv4", config_network_ipv4 },
f8fee0e2 165 { "lxc.network.ipv6.gateway", config_network_ipv6_gateway },
e892973e 166 { "lxc.network.ipv6", config_network_ipv6 },
72d0e1cb
SG
167 /* config_network_nic must come after all other 'lxc.network.*' entries */
168 { "lxc.network.", config_network_nic },
6b0d5538 169 { "lxc.network", config_network },
81810dd1 170 { "lxc.cap.drop", config_cap_drop },
1fb86a7c 171 { "lxc.cap.keep", config_cap_keep },
96f15ca1 172 { "lxc.console.logfile", config_console_logfile },
63376d7d 173 { "lxc.console", config_console },
8f2c3a70 174 { "lxc.seccomp", config_seccomp },
09ad6246 175 { "lxc.include", config_includefile },
c6883f38 176 { "lxc.autodev", config_autodev },
f0f1d8c0 177 { "lxc.haltsignal", config_haltsignal },
dd267776 178 { "lxc.rebootsignal", config_rebootsignal },
a84b9932 179 { "lxc.stopsignal", config_stopsignal },
ee1e7aa0
SG
180 { "lxc.start.auto", config_start },
181 { "lxc.start.delay", config_start },
182 { "lxc.start.order", config_start },
a8dfe4e0 183 { "lxc.monitor.unshare", config_monitor },
ee1e7aa0 184 { "lxc.group", config_group },
7c661726 185 { "lxc.environment", config_environment },
67c660d0 186 { "lxc.init_cmd", config_init_cmd },
72bb04e4
PT
187 { "lxc.init_uid", config_init_uid },
188 { "lxc.init_gid", config_init_gid },
8796becf 189 { "lxc.ephemeral", config_ephemeral },
64c57ea1 190 { "lxc.syslog", config_syslog },
5a46f283 191 { "lxc.no_new_privs", config_no_new_privs },
a84b9932
AV
192};
193
194struct signame {
195 int num;
74a3920a 196 const char *name;
a84b9932
AV
197};
198
74a3920a 199static const struct signame signames[] = {
a84b9932
AV
200 { SIGHUP, "HUP" },
201 { SIGINT, "INT" },
202 { SIGQUIT, "QUIT" },
203 { SIGILL, "ILL" },
204 { SIGABRT, "ABRT" },
205 { SIGFPE, "FPE" },
206 { SIGKILL, "KILL" },
207 { SIGSEGV, "SEGV" },
208 { SIGPIPE, "PIPE" },
209 { SIGALRM, "ALRM" },
210 { SIGTERM, "TERM" },
211 { SIGUSR1, "USR1" },
212 { SIGUSR2, "USR2" },
213 { SIGCHLD, "CHLD" },
214 { SIGCONT, "CONT" },
215 { SIGSTOP, "STOP" },
216 { SIGTSTP, "TSTP" },
217 { SIGTTIN, "TTIN" },
218 { SIGTTOU, "TTOU" },
89dfc302
SY
219#ifdef SIGTRAP
220 { SIGTRAP, "TRAP" },
221#endif
222#ifdef SIGIOT
223 { SIGIOT, "IOT" },
224#endif
225#ifdef SIGEMT
226 { SIGEMT, "EMT" },
227#endif
228#ifdef SIGBUS
229 { SIGBUS, "BUS" },
230#endif
231#ifdef SIGSTKFLT
232 { SIGSTKFLT, "STKFLT" },
233#endif
234#ifdef SIGCLD
235 { SIGCLD, "CLD" },
236#endif
237#ifdef SIGURG
238 { SIGURG, "URG" },
239#endif
240#ifdef SIGXCPU
241 { SIGXCPU, "XCPU" },
242#endif
243#ifdef SIGXFSZ
244 { SIGXFSZ, "XFSZ" },
245#endif
246#ifdef SIGVTALRM
247 { SIGVTALRM, "VTALRM" },
248#endif
249#ifdef SIGPROF
250 { SIGPROF, "PROF" },
251#endif
252#ifdef SIGWINCH
253 { SIGWINCH, "WINCH" },
254#endif
255#ifdef SIGIO
256 { SIGIO, "IO" },
257#endif
258#ifdef SIGPOLL
259 { SIGPOLL, "POLL" },
260#endif
261#ifdef SIGINFO
262 { SIGINFO, "INFO" },
263#endif
264#ifdef SIGLOST
265 { SIGLOST, "LOST" },
266#endif
267#ifdef SIGPWR
268 { SIGPWR, "PWR" },
269#endif
270#ifdef SIGUNUSED
271 { SIGUNUSED, "UNUSED" },
272#endif
273#ifdef SIGSYS
274 { SIGSYS, "SYS" },
275#endif
c2cc9f0a 276};
277
72d0e1cb 278static const size_t config_size = sizeof(config)/sizeof(struct lxc_config_t);
c2cc9f0a 279
72d0e1cb 280extern struct lxc_config_t *lxc_getconfig(const char *key)
c2cc9f0a 281{
84760c11 282 size_t i;
c2cc9f0a 283
284 for (i = 0; i < config_size; i++)
a871ff6b 285 if (!strncmp(config[i].name, key,
c2cc9f0a 286 strlen(config[i].name)))
287 return &config[i];
288 return NULL;
289}
290
72d0e1cb
SG
291#define strprint(str, inlen, ...) \
292 do { \
293 len = snprintf(str, inlen, ##__VA_ARGS__); \
294 if (len < 0) { SYSERROR("snprintf"); return -1; }; \
295 fulllen += len; \
296 if (inlen > 0) { \
297 if (str) str += len; \
298 inlen -= len; \
299 if (inlen < 0) inlen = 0; \
300 } \
301 } while (0);
302
303int lxc_listconfigs(char *retv, int inlen)
304{
84760c11 305 size_t i;
306 int fulllen = 0, len;
72d0e1cb
SG
307
308 if (!retv)
309 inlen = 0;
310 else
311 memset(retv, 0, inlen);
312 for (i = 0; i < config_size; i++) {
313 char *s = config[i].name;
314 if (s[strlen(s)-1] == '.')
315 continue;
316 strprint(retv, inlen, "%s\n", s);
317 }
318 return fulllen;
319}
320
6d03d92a
DE
321static int config_string_item(char **conf_item, const char *value)
322{
323 char *new_value;
324
d6eca240 325 if (!value || strlen(value) == 0) {
f10fad2f 326 free(*conf_item);
d6eca240 327 *conf_item = NULL;
6d03d92a 328 return 0;
d6eca240 329 }
6d03d92a
DE
330
331 new_value = strdup(value);
332 if (!new_value) {
333 SYSERROR("failed to strdup '%s': %m", value);
334 return -1;
335 }
336
f10fad2f 337 free(*conf_item);
6d03d92a
DE
338 *conf_item = new_value;
339 return 0;
340}
341
342static int config_string_item_max(char **conf_item, const char *value,
343 size_t max)
344{
345 if (strlen(value) >= max) {
a5a82508 346 ERROR("%s is too long (>= %lu)", value, (unsigned long)max);
6d03d92a
DE
347 return -1;
348 }
349
350 return config_string_item(conf_item, value);
351}
352
353static int config_path_item(char **conf_item, const char *value)
354{
355 return config_string_item_max(conf_item, value, PATH_MAX);
356}
357
72d0e1cb
SG
358/*
359 * config entry is something like "lxc.network.0.ipv4"
360 * the key 'lxc.network.' was found. So we make sure next
361 * comes an integer, find the right callback (by rewriting
362 * the key), and call it.
363 */
12a50cc6 364static int config_network_nic(const char *key, const char *value,
72d0e1cb
SG
365 struct lxc_conf *lxc_conf)
366{
367 char *copy = strdup(key), *p;
368 int ret = -1;
369 struct lxc_config_t *config;
370
371 if (!copy) {
372 SYSERROR("failed to allocate memory");
373 return -1;
374 }
375 /*
376 * ok we know that to get here we've got "lxc.network."
377 * and it isn't any of the other network entries. So
378 * after the second . should come an integer (# of defined
379 * nic) followed by a valid entry.
380 */
381 if (*(key+12) < '0' || *(key+12) > '9')
382 goto out;
46cd2845 383 p = strchr(key+12, '.');
72d0e1cb
SG
384 if (!p)
385 goto out;
386 strcpy(copy+12, p+1);
387 config = lxc_getconfig(copy);
388 if (!config) {
389 ERROR("unknown key %s", key);
390 goto out;
391 }
392 ret = config->cb(key, value, lxc_conf);
393
394out:
395 free(copy);
396 return ret;
397}
398
6b0d5538
SH
399static int config_network(const char *key, const char *value,
400 struct lxc_conf *lxc_conf)
401{
402 if (value && strlen(value)) {
403 ERROR("lxc.network must not have a value");
404 return -1;
405 }
406
407 return lxc_clear_config_network(lxc_conf);
408}
409
261658e8
BP
410static int macvlan_mode(int *valuep, const char *value);
411
12a50cc6 412static int config_network_type(const char *key, const char *value,
e892973e 413 struct lxc_conf *lxc_conf)
c2cc9f0a 414{
5f4535a3 415 struct lxc_list *network = &lxc_conf->network;
c2cc9f0a 416 struct lxc_netdev *netdev;
417 struct lxc_list *list;
c2cc9f0a 418
7d0eb87e
SH
419 if (!value || strlen(value) == 0)
420 return lxc_clear_config_network(lxc_conf);
421
c2cc9f0a 422 netdev = malloc(sizeof(*netdev));
423 if (!netdev) {
36eb9bde 424 SYSERROR("failed to allocate memory");
c2cc9f0a 425 return -1;
426 }
427
82d5ae15 428 memset(netdev, 0, sizeof(*netdev));
c2cc9f0a 429 lxc_list_init(&netdev->ipv4);
430 lxc_list_init(&netdev->ipv6);
c2cc9f0a 431
432 list = malloc(sizeof(*list));
433 if (!list) {
36eb9bde 434 SYSERROR("failed to allocate memory");
022de5f3 435 free(netdev);
c2cc9f0a 436 return -1;
437 }
438
439 lxc_list_init(list);
5f4535a3 440 list->elem = netdev;
c2cc9f0a 441
bac89583 442 lxc_list_add_tail(network, list);
a871ff6b 443
c2cc9f0a 444 if (!strcmp(value, "veth"))
24654103 445 netdev->type = LXC_NET_VETH;
261658e8 446 else if (!strcmp(value, "macvlan")) {
24654103 447 netdev->type = LXC_NET_MACVLAN;
261658e8
BP
448 macvlan_mode(&netdev->priv.macvlan_attr.mode, "private");
449 }
26c39028 450 else if (!strcmp(value, "vlan"))
24654103 451 netdev->type = LXC_NET_VLAN;
c2cc9f0a 452 else if (!strcmp(value, "phys"))
24654103 453 netdev->type = LXC_NET_PHYS;
5f58350a 454 else if (!strcmp(value, "empty"))
24654103 455 netdev->type = LXC_NET_EMPTY;
26b797f3
SH
456 else if (!strcmp(value, "none"))
457 netdev->type = LXC_NET_NONE;
c2cc9f0a 458 else {
36eb9bde 459 ERROR("invalid network type %s", value);
c2cc9f0a 460 return -1;
461 }
462 return 0;
463}
464
a059591e
DL
465static int config_ip_prefix(struct in_addr *addr)
466{
467 if (IN_CLASSA(addr->s_addr))
468 return 32 - IN_CLASSA_NSHIFT;
469 if (IN_CLASSB(addr->s_addr))
470 return 32 - IN_CLASSB_NSHIFT;
471 if (IN_CLASSC(addr->s_addr))
472 return 32 - IN_CLASSC_NSHIFT;
473
474 return 0;
475}
476
72d0e1cb
SG
477/*
478 * if you have p="lxc.network.0.link", pass it p+12
479 * to get back '0' (the index of the nic)
480 */
481static int get_network_netdev_idx(const char *key)
482{
483 int ret, idx;
484
485 if (*key < '0' || *key > '9')
486 return -1;
487 ret = sscanf(key, "%d", &idx);
488 if (ret != 1)
489 return -1;
490 return idx;
491}
492
493/*
494 * if you have p="lxc.network.0", pass this p+12 and it will return
495 * the netdev of the first configured nic
496 */
497static struct lxc_netdev *get_netdev_from_key(const char *key,
498 struct lxc_list *network)
499{
500 int i = 0, idx = get_network_netdev_idx(key);
501 struct lxc_netdev *netdev = NULL;
502 struct lxc_list *it;
503 if (idx == -1)
504 return NULL;
505 lxc_list_for_each(it, network) {
506 if (idx == i++) {
507 netdev = it->elem;
508 break;
509 }
510 }
511 return netdev;
512}
513
12a50cc6
DE
514extern int lxc_list_nicconfigs(struct lxc_conf *c, const char *key,
515 char *retv, int inlen)
72d0e1cb
SG
516{
517 struct lxc_netdev *netdev;
518 int fulllen = 0, len;
519
520 netdev = get_netdev_from_key(key+12, &c->network);
521 if (!netdev)
522 return -1;
523
524 if (!retv)
525 inlen = 0;
526 else
527 memset(retv, 0, inlen);
528
74836992 529 strprint(retv, inlen, "type\n");
72d0e1cb 530 strprint(retv, inlen, "script.up\n");
8fc8295a 531 strprint(retv, inlen, "script.down\n");
72d0e1cb
SG
532 if (netdev->type != LXC_NET_EMPTY) {
533 strprint(retv, inlen, "flags\n");
534 strprint(retv, inlen, "link\n");
535 strprint(retv, inlen, "name\n");
536 strprint(retv, inlen, "hwaddr\n");
537 strprint(retv, inlen, "mtu\n");
538 strprint(retv, inlen, "ipv6\n");
9eaf8a59 539 strprint(retv, inlen, "ipv6.gateway\n");
72d0e1cb 540 strprint(retv, inlen, "ipv4\n");
9eaf8a59 541 strprint(retv, inlen, "ipv4.gateway\n");
72d0e1cb
SG
542 }
543 switch(netdev->type) {
544 case LXC_NET_VETH:
545 strprint(retv, inlen, "veth.pair\n");
546 break;
547 case LXC_NET_MACVLAN:
548 strprint(retv, inlen, "macvlan.mode\n");
549 break;
550 case LXC_NET_VLAN:
551 strprint(retv, inlen, "vlan.id\n");
552 break;
553 case LXC_NET_PHYS:
554 break;
555 }
556 return fulllen;
557}
558
16950ecb
DL
559static struct lxc_netdev *network_netdev(const char *key, const char *value,
560 struct lxc_list *network)
c2cc9f0a 561{
72d0e1cb 562 struct lxc_netdev *netdev = NULL;
c2cc9f0a 563
5f4535a3 564 if (lxc_list_empty(network)) {
16950ecb
DL
565 ERROR("network is not created for '%s' = '%s' option",
566 key, value);
33c945e0 567 return NULL;
c2cc9f0a 568 }
569
72d0e1cb
SG
570 if (get_network_netdev_idx(key+12) == -1)
571 netdev = lxc_list_last_elem(network);
572 else
573 netdev = get_netdev_from_key(key+12, network);
574
5f4535a3 575 if (!netdev) {
16950ecb
DL
576 ERROR("no network device defined for '%s' = '%s' option",
577 key, value);
33c945e0 578 return NULL;
c2cc9f0a 579 }
580
33c945e0 581 return netdev;
c2cc9f0a 582}
583
12a50cc6 584static int network_ifname(char **valuep, const char *value)
c2cc9f0a 585{
c9bb9a85 586 return config_string_item_max(valuep, value, IFNAMSIZ);
c2cc9f0a 587}
588
e892973e
DL
589#ifndef MACVLAN_MODE_PRIVATE
590# define MACVLAN_MODE_PRIVATE 1
591#endif
592
593#ifndef MACVLAN_MODE_VEPA
594# define MACVLAN_MODE_VEPA 2
595#endif
596
597#ifndef MACVLAN_MODE_BRIDGE
598# define MACVLAN_MODE_BRIDGE 4
599#endif
600
99854161
EL
601#ifndef MACVLAN_MODE_PASSTHRU
602# define MACVLAN_MODE_PASSTHRU 8
603#endif
604
12a50cc6 605static int macvlan_mode(int *valuep, const char *value)
e892973e
DL
606{
607 struct mc_mode {
608 char *name;
609 int mode;
610 } m[] = {
611 { "private", MACVLAN_MODE_PRIVATE },
612 { "vepa", MACVLAN_MODE_VEPA },
613 { "bridge", MACVLAN_MODE_BRIDGE },
99854161 614 { "passthru", MACVLAN_MODE_PASSTHRU },
e892973e
DL
615 };
616
84760c11 617 size_t i;
e892973e
DL
618
619 for (i = 0; i < sizeof(m)/sizeof(m[0]); i++) {
620 if (strcmp(m[i].name, value))
621 continue;
622
623 *valuep = m[i].mode;
624 return 0;
625 }
626
627 return -1;
628}
629
508c263e
SH
630static int rand_complete_hwaddr(char *hwaddr)
631{
632 const char hex[] = "0123456789abcdef";
633 char *curs = hwaddr;
634
635#ifndef HAVE_RAND_R
636 randseed(true);
637#else
638 unsigned int seed=randseed(false);
639#endif
e6744e9b 640 while (*curs != '\0' && *curs != '\n')
508c263e
SH
641 {
642 if ( *curs == 'x' || *curs == 'X' ) {
643 if (curs - hwaddr == 1) {
644 //ensure address is unicast
645#ifdef HAVE_RAND_R
646 *curs = hex[rand_r(&seed) & 0x0E];
647 } else {
648 *curs = hex[rand_r(&seed) & 0x0F];
649#else
650 *curs = hex[rand() & 0x0E];
651 } else {
652 *curs = hex[rand() & 0x0F];
653#endif
654 }
655 }
656 curs++;
657 }
658 return 0;
659}
660
12a50cc6 661static int config_network_flags(const char *key, const char *value,
33c945e0 662 struct lxc_conf *lxc_conf)
c2cc9f0a 663{
c2cc9f0a 664 struct lxc_netdev *netdev;
665
16950ecb 666 netdev = network_netdev(key, value, &lxc_conf->network);
33c945e0 667 if (!netdev)
c2cc9f0a 668 return -1;
c2cc9f0a 669
33c945e0 670 netdev->flags |= IFF_UP;
c2cc9f0a 671
33c945e0
MT
672 return 0;
673}
674
12a50cc6 675static int config_network_link(const char *key, const char *value,
33c945e0
MT
676 struct lxc_conf *lxc_conf)
677{
678 struct lxc_netdev *netdev;
679
16950ecb 680 netdev = network_netdev(key, value, &lxc_conf->network);
33c945e0 681 if (!netdev)
c2cc9f0a 682 return -1;
c2cc9f0a 683
33c945e0 684 return network_ifname(&netdev->link, value);
c2cc9f0a 685}
686
12a50cc6 687static int config_network_name(const char *key, const char *value,
33c945e0 688 struct lxc_conf *lxc_conf)
c2cc9f0a 689{
c2cc9f0a 690 struct lxc_netdev *netdev;
691
16950ecb 692 netdev = network_netdev(key, value, &lxc_conf->network);
33c945e0 693 if (!netdev)
c2cc9f0a 694 return -1;
c2cc9f0a 695
33c945e0
MT
696 return network_ifname(&netdev->name, value);
697}
698
12a50cc6 699static int config_network_veth_pair(const char *key, const char *value,
e892973e
DL
700 struct lxc_conf *lxc_conf)
701{
702 struct lxc_netdev *netdev;
703
704 netdev = network_netdev(key, value, &lxc_conf->network);
705 if (!netdev)
706 return -1;
707
c5316d60 708 if (netdev->type != LXC_NET_VETH) {
128d327a 709 ERROR("Invalid veth pair for a non-veth netdev");
c5316d60
SH
710 return -1;
711 }
e892973e
DL
712 return network_ifname(&netdev->priv.veth_attr.pair, value);
713}
714
12a50cc6 715static int config_network_macvlan_mode(const char *key, const char *value,
e892973e 716 struct lxc_conf *lxc_conf)
8634bc19
MT
717{
718 struct lxc_netdev *netdev;
719
720 netdev = network_netdev(key, value, &lxc_conf->network);
721 if (!netdev)
722 return -1;
723
c5316d60 724 if (netdev->type != LXC_NET_MACVLAN) {
128d327a 725 ERROR("Invalid macvlan.mode for a non-macvlan netdev");
c5316d60
SH
726 return -1;
727 }
e892973e 728 return macvlan_mode(&netdev->priv.macvlan_attr.mode, value);
8634bc19
MT
729}
730
12a50cc6 731static int config_network_hwaddr(const char *key, const char *value,
33c945e0
MT
732 struct lxc_conf *lxc_conf)
733{
734 struct lxc_netdev *netdev;
735
508c263e
SH
736 char *new_value = strdup(value);
737 if (!new_value) {
738 SYSERROR("failed to strdup '%s': %m", value);
c2cc9f0a 739 return -1;
508c263e
SH
740 }
741 rand_complete_hwaddr(new_value);
c2cc9f0a 742
508c263e
SH
743 netdev = network_netdev(key, new_value, &lxc_conf->network);
744 if (!netdev) {
745 free(new_value);
746 return -1;
747 };
748
749 if (!new_value || strlen(new_value) == 0) {
750 free(new_value);
751 netdev->hwaddr = NULL;
752 return 0;
753 }
754
755 netdev->hwaddr = new_value;
756 return 0;
c2cc9f0a 757}
758
12a50cc6 759static int config_network_vlan_id(const char *key, const char *value,
26c39028
JHS
760 struct lxc_conf *lxc_conf)
761{
762 struct lxc_netdev *netdev;
763
764 netdev = network_netdev(key, value, &lxc_conf->network);
765 if (!netdev)
766 return -1;
767
c5316d60 768 if (netdev->type != LXC_NET_VLAN) {
128d327a 769 ERROR("Invalid vlan.id for a non-macvlan netdev");
c5316d60
SH
770 return -1;
771 }
f6cc1de1 772 if (get_u16(&netdev->priv.vlan_attr.vid, value, 0))
26c39028
JHS
773 return -1;
774
775 return 0;
776}
777
12a50cc6 778static int config_network_mtu(const char *key, const char *value,
33c945e0 779 struct lxc_conf *lxc_conf)
442cbbe6 780{
442cbbe6
TR
781 struct lxc_netdev *netdev;
782
16950ecb 783 netdev = network_netdev(key, value, &lxc_conf->network);
33c945e0 784 if (!netdev)
442cbbe6 785 return -1;
442cbbe6 786
6d03d92a 787 return config_string_item(&netdev->mtu, value);
442cbbe6
TR
788}
789
12a50cc6 790static int config_network_ipv4(const char *key, const char *value,
33c945e0 791 struct lxc_conf *lxc_conf)
c2cc9f0a 792{
c2cc9f0a 793 struct lxc_netdev *netdev;
33c945e0 794 struct lxc_inetdev *inetdev;
c2cc9f0a 795 struct lxc_list *list;
796 char *cursor, *slash, *addr = NULL, *bcast = NULL, *prefix = NULL;
797
16950ecb 798 netdev = network_netdev(key, value, &lxc_conf->network);
33c945e0 799 if (!netdev)
c2cc9f0a 800 return -1;
c2cc9f0a 801
802 inetdev = malloc(sizeof(*inetdev));
803 if (!inetdev) {
36eb9bde 804 SYSERROR("failed to allocate ipv4 address");
c2cc9f0a 805 return -1;
806 }
807 memset(inetdev, 0, sizeof(*inetdev));
808
809 list = malloc(sizeof(*list));
810 if (!list) {
36eb9bde 811 SYSERROR("failed to allocate memory");
53719062 812 free(inetdev);
c2cc9f0a 813 return -1;
814 }
815
816 lxc_list_init(list);
817 list->elem = inetdev;
818
956edc54
SG
819 addr = strdup(value);
820 if (!addr) {
821 ERROR("no address specified");
53719062
SH
822 free(inetdev);
823 free(list);
956edc54
SG
824 return -1;
825 }
c2cc9f0a 826
827 cursor = strstr(addr, " ");
828 if (cursor) {
829 *cursor = '\0';
830 bcast = cursor + 1;
831 }
832
833 slash = strstr(addr, "/");
834 if (slash) {
835 *slash = '\0';
836 prefix = slash + 1;
837 }
838
c2cc9f0a 839 if (!inet_pton(AF_INET, addr, &inetdev->addr)) {
36eb9bde 840 SYSERROR("invalid ipv4 address: %s", value);
53719062 841 free(inetdev);
956edc54 842 free(addr);
53719062 843 free(list);
c2cc9f0a 844 return -1;
845 }
846
0093bb8c
DL
847 if (bcast && !inet_pton(AF_INET, bcast, &inetdev->bcast)) {
848 SYSERROR("invalid ipv4 broadcast address: %s", value);
53719062
SH
849 free(inetdev);
850 free(list);
956edc54 851 free(addr);
0093bb8c
DL
852 return -1;
853 }
c2cc9f0a 854
a059591e 855 /* no prefix specified, determine it from the network class */
1c633398
CB
856 if (prefix) {
857 if (lxc_safe_uint(prefix, &inetdev->prefix) < 0)
858 return -1;
859 } else {
860 inetdev->prefix = config_ip_prefix(&inetdev->addr);
861 }
a059591e 862
b3df193c 863 /* if no broadcast address, let compute one from the
0093bb8c
DL
864 * prefix and address
865 */
866 if (!bcast) {
1b7d4743
DL
867 inetdev->bcast.s_addr = inetdev->addr.s_addr;
868 inetdev->bcast.s_addr |=
869 htonl(INADDR_BROADCAST >> inetdev->prefix);
0093bb8c 870 }
c2cc9f0a 871
8538f388 872 lxc_list_add_tail(&netdev->ipv4, list);
c2cc9f0a 873
956edc54 874 free(addr);
c2cc9f0a 875 return 0;
876}
877
12a50cc6 878static int config_network_ipv4_gateway(const char *key, const char *value,
f8fee0e2
MK
879 struct lxc_conf *lxc_conf)
880{
881 struct lxc_netdev *netdev;
f8fee0e2
MK
882
883 netdev = network_netdev(key, value, &lxc_conf->network);
884 if (!netdev)
885 return -1;
886
e088e926 887 free(netdev->ipv4_gateway);
f8fee0e2 888
e088e926
SG
889 if (!value || strlen(value) == 0) {
890 netdev->ipv4_gateway = NULL;
891 } else if (!strcmp(value, "auto")) {
19a26f82
MK
892 netdev->ipv4_gateway = NULL;
893 netdev->ipv4_gateway_auto = true;
894 } else {
e088e926
SG
895 struct in_addr *gw;
896
897 gw = malloc(sizeof(*gw));
898 if (!gw) {
899 SYSERROR("failed to allocate ipv4 gateway address");
900 return -1;
901 }
902
19a26f82
MK
903 if (!inet_pton(AF_INET, value, gw)) {
904 SYSERROR("invalid ipv4 gateway address: %s", value);
53719062 905 free(gw);
19a26f82
MK
906 return -1;
907 }
908
909 netdev->ipv4_gateway = gw;
910 netdev->ipv4_gateway_auto = false;
f8fee0e2
MK
911 }
912
f8fee0e2
MK
913 return 0;
914}
915
12a50cc6 916static int config_network_ipv6(const char *key, const char *value,
e892973e 917 struct lxc_conf *lxc_conf)
c2cc9f0a 918{
c2cc9f0a 919 struct lxc_netdev *netdev;
920 struct lxc_inet6dev *inet6dev;
921 struct lxc_list *list;
12a50cc6 922 char *slash,*valdup;
c2cc9f0a 923 char *netmask;
924
16950ecb 925 netdev = network_netdev(key, value, &lxc_conf->network);
33c945e0 926 if (!netdev)
c2cc9f0a 927 return -1;
c2cc9f0a 928
929 inet6dev = malloc(sizeof(*inet6dev));
930 if (!inet6dev) {
36eb9bde 931 SYSERROR("failed to allocate ipv6 address");
c2cc9f0a 932 return -1;
933 }
934 memset(inet6dev, 0, sizeof(*inet6dev));
935
936 list = malloc(sizeof(*list));
937 if (!list) {
36eb9bde 938 SYSERROR("failed to allocate memory");
28027320 939 free(inet6dev);
c2cc9f0a 940 return -1;
941 }
942
943 lxc_list_init(list);
944 list->elem = inet6dev;
945
956edc54
SG
946 valdup = strdup(value);
947 if (!valdup) {
948 ERROR("no address specified");
28027320
SH
949 free(list);
950 free(inet6dev);
956edc54
SG
951 return -1;
952 }
953
a059591e 954 inet6dev->prefix = 64;
12a50cc6 955 slash = strstr(valdup, "/");
c2cc9f0a 956 if (slash) {
957 *slash = '\0';
958 netmask = slash + 1;
1c633398
CB
959 if (lxc_safe_uint(netmask, &inet6dev->prefix) < 0)
960 return -1;
c2cc9f0a 961 }
962
5acccf95
SH
963 if (!inet_pton(AF_INET6, valdup, &inet6dev->addr)) {
964 SYSERROR("invalid ipv6 address: %s", valdup);
28027320
SH
965 free(list);
966 free(inet6dev);
956edc54 967 free(valdup);
c2cc9f0a 968 return -1;
969 }
970
8538f388 971 lxc_list_add_tail(&netdev->ipv6, list);
c2cc9f0a 972
956edc54 973 free(valdup);
c2cc9f0a 974 return 0;
975}
976
12a50cc6 977static int config_network_ipv6_gateway(const char *key, const char *value,
f8fee0e2
MK
978 struct lxc_conf *lxc_conf)
979{
980 struct lxc_netdev *netdev;
f8fee0e2
MK
981
982 netdev = network_netdev(key, value, &lxc_conf->network);
983 if (!netdev)
984 return -1;
985
e088e926 986 free(netdev->ipv6_gateway);
f8fee0e2 987
e088e926 988 if (!value || strlen(value) == 0) {
ffe34437 989 netdev->ipv6_gateway = NULL;
e088e926 990 } else if (!strcmp(value, "auto")) {
19a26f82
MK
991 netdev->ipv6_gateway = NULL;
992 netdev->ipv6_gateway_auto = true;
993 } else {
8fb86a37
SH
994 struct in6_addr *gw;
995
bec695f3
DE
996 gw = malloc(sizeof(*gw));
997 if (!gw) {
998 SYSERROR("failed to allocate ipv6 gateway address");
999 return -1;
1000 }
1001
19a26f82
MK
1002 if (!inet_pton(AF_INET6, value, gw)) {
1003 SYSERROR("invalid ipv6 gateway address: %s", value);
28027320 1004 free(gw);
19a26f82
MK
1005 return -1;
1006 }
1007
1008 netdev->ipv6_gateway = gw;
1009 netdev->ipv6_gateway_auto = false;
f8fee0e2
MK
1010 }
1011
f8fee0e2
MK
1012 return 0;
1013}
1014
8fc8295a
DE
1015static int config_network_script_up(const char *key, const char *value,
1016 struct lxc_conf *lxc_conf)
e3b4c4c4
ST
1017{
1018 struct lxc_netdev *netdev;
1019
1020 netdev = network_netdev(key, value, &lxc_conf->network);
1021 if (!netdev)
8fc8295a 1022 return -1;
e3b4c4c4 1023
8fc8295a
DE
1024 return config_string_item(&netdev->upscript, value);
1025}
1026
1027static int config_network_script_down(const char *key, const char *value,
1028 struct lxc_conf *lxc_conf)
1029{
1030 struct lxc_netdev *netdev;
1031
1032 netdev = network_netdev(key, value, &lxc_conf->network);
1033 if (!netdev)
1034 return -1;
1035
1036 return config_string_item(&netdev->downscript, value);
e3b4c4c4
ST
1037}
1038
26ddeedd
SH
1039static int add_hook(struct lxc_conf *lxc_conf, int which, char *hook)
1040{
1041 struct lxc_list *hooklist;
1042
1043 hooklist = malloc(sizeof(*hooklist));
1044 if (!hooklist) {
1045 free(hook);
1046 return -1;
1047 }
1048 hooklist->elem = hook;
1049 lxc_list_add_tail(&lxc_conf->hooks[which], hooklist);
1050 return 0;
1051}
1052
12a50cc6 1053static int config_seccomp(const char *key, const char *value,
8f2c3a70
SH
1054 struct lxc_conf *lxc_conf)
1055{
6d03d92a 1056 return config_path_item(&lxc_conf->seccomp, value);
8f2c3a70
SH
1057}
1058
67c660d0
SG
1059static int config_init_cmd(const char *key, const char *value,
1060 struct lxc_conf *lxc_conf)
1061{
1062 return config_path_item(&lxc_conf->init_cmd, value);
1063}
1064
72bb04e4
PT
1065static int config_init_uid(const char *key, const char *value,
1066 struct lxc_conf *lxc_conf)
1067{
d1e5d636
CB
1068 unsigned int init_uid;
1069
1070 if (lxc_safe_uint(value, &init_uid) < 0)
1071 return -1;
1072 lxc_conf->init_uid = init_uid;
1073
72bb04e4
PT
1074 return 0;
1075}
1076
1077static int config_init_gid(const char *key, const char *value,
1078 struct lxc_conf *lxc_conf)
1079{
d1e5d636
CB
1080 unsigned int init_gid;
1081
1082 if (lxc_safe_uint(value, &init_gid) < 0)
1083 return -1;
1084 lxc_conf->init_gid = init_gid;
1085
72bb04e4
PT
1086 return 0;
1087}
1088
12a50cc6 1089static int config_hook(const char *key, const char *value,
26ddeedd
SH
1090 struct lxc_conf *lxc_conf)
1091{
7d0eb87e 1092 char *copy;
72bb04e4 1093
7d0eb87e
SH
1094 if (!value || strlen(value) == 0)
1095 return lxc_clear_hooks(lxc_conf, key);
1096
6b0d5538
SH
1097 if (strcmp(key, "lxc.hook") == 0) {
1098 ERROR("lxc.hook cannot take a value");
1099 return -1;
1100 }
7d0eb87e 1101 copy = strdup(value);
26ddeedd
SH
1102 if (!copy) {
1103 SYSERROR("failed to dup string '%s'", value);
1104 return -1;
1105 }
1106 if (strcmp(key, "lxc.hook.pre-start") == 0)
1107 return add_hook(lxc_conf, LXCHOOK_PRESTART, copy);
5ea6163a
SH
1108 else if (strcmp(key, "lxc.hook.pre-mount") == 0)
1109 return add_hook(lxc_conf, LXCHOOK_PREMOUNT, copy);
f7bee6c6
MW
1110 else if (strcmp(key, "lxc.hook.autodev") == 0)
1111 return add_hook(lxc_conf, LXCHOOK_AUTODEV, copy);
26ddeedd
SH
1112 else if (strcmp(key, "lxc.hook.mount") == 0)
1113 return add_hook(lxc_conf, LXCHOOK_MOUNT, copy);
1114 else if (strcmp(key, "lxc.hook.start") == 0)
1115 return add_hook(lxc_conf, LXCHOOK_START, copy);
52492063
WB
1116 else if (strcmp(key, "lxc.hook.stop") == 0)
1117 return add_hook(lxc_conf, LXCHOOK_STOP, copy);
26ddeedd
SH
1118 else if (strcmp(key, "lxc.hook.post-stop") == 0)
1119 return add_hook(lxc_conf, LXCHOOK_POSTSTOP, copy);
148e91f5
SH
1120 else if (strcmp(key, "lxc.hook.clone") == 0)
1121 return add_hook(lxc_conf, LXCHOOK_CLONE, copy);
37cf711b
SY
1122 else if (strcmp(key, "lxc.hook.destroy") == 0)
1123 return add_hook(lxc_conf, LXCHOOK_DESTROY, copy);
26ddeedd
SH
1124 SYSERROR("Unknown key: %s", key);
1125 free(copy);
1126 return -1;
1127}
1128
8f47bc3f 1129static int config_personality(const char *key, const char *value,
cccc74b5
DL
1130 struct lxc_conf *lxc_conf)
1131{
525f0002 1132 signed long personality = lxc_config_parse_arch(value);
cccc74b5 1133
525f0002
CS
1134 if (personality >= 0)
1135 lxc_conf->personality = personality;
1136 else
1137 WARN("unsupported personality '%s'", value);
970ab589
DL
1138
1139 return 0;
cccc74b5
DL
1140}
1141
12a50cc6
DE
1142static int config_pts(const char *key, const char *value,
1143 struct lxc_conf *lxc_conf)
10db618d 1144{
17919969
CB
1145 if (lxc_safe_uint(value, &lxc_conf->pts) < 0)
1146 return -1;
10db618d 1147
1148 return 0;
1149}
1150
ee1e7aa0
SG
1151static int config_start(const char *key, const char *value,
1152 struct lxc_conf *lxc_conf)
1153{
1154 if(strcmp(key, "lxc.start.auto") == 0) {
3590152f
CB
1155 if (lxc_safe_uint(value, &lxc_conf->start_auto) < 0)
1156 return -1;
1157 if (lxc_conf->start_auto > 1)
1158 return -1;
ee1e7aa0
SG
1159 return 0;
1160 }
1161 else if (strcmp(key, "lxc.start.delay") == 0) {
3590152f
CB
1162 if (lxc_safe_uint(value, &lxc_conf->start_delay) < 0)
1163 return -1;
ee1e7aa0
SG
1164 return 0;
1165 }
1166 else if (strcmp(key, "lxc.start.order") == 0) {
3590152f
CB
1167 if (lxc_safe_int(value, &lxc_conf->start_order) < 0)
1168 return -1;
ee1e7aa0
SG
1169 return 0;
1170 }
1171 SYSERROR("Unknown key: %s", key);
1172 return -1;
1173}
1174
a8dfe4e0
WB
1175static int config_monitor(const char *key, const char *value,
1176 struct lxc_conf *lxc_conf)
1177{
1178 if(strcmp(key, "lxc.monitor.unshare") == 0) {
226dc30e
CB
1179 if (lxc_safe_uint(value, &lxc_conf->monitor_unshare) < 0)
1180 return -1;
a8dfe4e0
WB
1181 return 0;
1182 }
1183 SYSERROR("Unknown key: %s", key);
1184 return -1;
1185}
1186
ee1e7aa0
SG
1187static int config_group(const char *key, const char *value,
1188 struct lxc_conf *lxc_conf)
1189{
1190 char *groups, *groupptr, *sptr, *token;
1191 struct lxc_list *grouplist;
1192 int ret = -1;
1193
1194 if (!strlen(value))
1195 return lxc_clear_groups(lxc_conf);
1196
1197 groups = strdup(value);
1198 if (!groups) {
1199 SYSERROR("failed to dup '%s'", value);
1200 return -1;
1201 }
1202
1203 /* in case several groups are specified in a single line
1204 * split these groups in a single element for the list */
1205 for (groupptr = groups;;groupptr = NULL) {
d028235d
SG
1206 token = strtok_r(groupptr, " \t", &sptr);
1207 if (!token) {
ee1e7aa0 1208 ret = 0;
d028235d 1209 break;
ee1e7aa0
SG
1210 }
1211
1212 grouplist = malloc(sizeof(*grouplist));
1213 if (!grouplist) {
1214 SYSERROR("failed to allocate groups list");
1215 break;
1216 }
1217
1218 grouplist->elem = strdup(token);
1219 if (!grouplist->elem) {
1220 SYSERROR("failed to dup '%s'", token);
1221 free(grouplist);
1222 break;
1223 }
1224
1225 lxc_list_add_tail(&lxc_conf->groups, grouplist);
d028235d 1226 }
ee1e7aa0
SG
1227
1228 free(groups);
1229
1230 return ret;
1231}
1232
7c661726
MP
1233static int config_environment(const char *key, const char *value,
1234 struct lxc_conf *lxc_conf)
1235{
1236 struct lxc_list *list_item = NULL;
1237
ab799c0b
SG
1238 if (!strlen(value))
1239 return lxc_clear_environment(lxc_conf);
1240
7c661726
MP
1241 list_item = malloc(sizeof(*list_item));
1242 if (!list_item)
1243 goto freak_out;
1244
1245 list_item->elem = strdup(value);
1246
1247 if (!list_item->elem)
1248 goto freak_out;
1249
1250 lxc_list_add_tail(&lxc_conf->environment, list_item);
1251
1252 return 0;
1253
1254freak_out:
f10fad2f 1255 free(list_item);
7c661726
MP
1256
1257 return -1;
1258}
1259
12a50cc6
DE
1260static int config_tty(const char *key, const char *value,
1261 struct lxc_conf *lxc_conf)
b0a33c1e 1262{
1c30b4ad
CB
1263 if (lxc_safe_uint(value, &lxc_conf->tty) < 0)
1264 return -1;
b0a33c1e 1265
1266 return 0;
1267}
1268
12a50cc6 1269static int config_ttydir(const char *key, const char *value,
7c6ef2a2
SH
1270 struct lxc_conf *lxc_conf)
1271{
6d03d92a 1272 return config_string_item_max(&lxc_conf->ttydir, value, NAME_MAX+1);
7c6ef2a2
SH
1273}
1274
7e0e1d94
AV
1275static int config_kmsg(const char *key, const char *value,
1276 struct lxc_conf *lxc_conf)
1277{
91863d36
CB
1278 if (lxc_safe_uint(value, &lxc_conf->kmsg) < 0)
1279 return -1;
7e0e1d94 1280
91863d36
CB
1281 if (lxc_conf->kmsg > 1)
1282 return -1;
7e0e1d94
AV
1283
1284 return 0;
1285}
1286
fe4de9a6
DE
1287static int config_lsm_aa_profile(const char *key, const char *value,
1288 struct lxc_conf *lxc_conf)
e075f5d9 1289{
6d03d92a 1290 return config_string_item(&lxc_conf->lsm_aa_profile, value);
fe4de9a6
DE
1291}
1292
7aff4f43
SH
1293static int config_lsm_aa_incomplete(const char *key, const char *value,
1294 struct lxc_conf *lxc_conf)
1295{
a56e2df9
CB
1296 if (lxc_safe_uint(value, &lxc_conf->lsm_aa_allow_incomplete) < 0)
1297 return -1;
7aff4f43 1298
a56e2df9
CB
1299 if (lxc_conf->lsm_aa_allow_incomplete > 1) {
1300 ERROR("Wrong value for lxc.lsm_aa_allow_incomplete. Can only be set to 0 or 1");
1301 return -1;
1302 }
7aff4f43
SH
1303
1304 return 0;
1305}
1306
fe4de9a6
DE
1307static int config_lsm_se_context(const char *key, const char *value,
1308 struct lxc_conf *lxc_conf)
1309{
6d03d92a 1310 return config_string_item(&lxc_conf->lsm_se_context, value);
e075f5d9 1311}
e075f5d9 1312
4a85ce2a 1313static int config_logfile(const char *key, const char *value,
858377e4 1314 struct lxc_conf *c)
4a85ce2a 1315{
6d03d92a
DE
1316 int ret;
1317
b40a606e
SH
1318 // store these values in the lxc_conf, and then try to set for
1319 // actual current logging.
858377e4 1320 ret = config_path_item(&c->logfile, value);
6d03d92a 1321 if (ret == 0)
858377e4 1322 ret = lxc_log_set_file(&c->logfd, c->logfile);
6d03d92a 1323 return ret;
4a85ce2a
SH
1324}
1325
1326static int config_loglevel(const char *key, const char *value,
1327 struct lxc_conf *lxc_conf)
1328{
9ea87d5d
SH
1329 int newlevel;
1330
4a85ce2a
SH
1331 if (!value || strlen(value) == 0)
1332 return 0;
1333
a56e2df9
CB
1334 if (value[0] >= '0' && value[0] <= '9') {
1335 if (lxc_safe_int(value, &newlevel) < 0)
1336 return -1;
1337 } else {
9ea87d5d 1338 newlevel = lxc_log_priority_to_int(value);
a56e2df9 1339 }
b40a606e
SH
1340 // store these values in the lxc_conf, and then try to set for
1341 // actual current logging.
1342 lxc_conf->loglevel = newlevel;
858377e4 1343 return lxc_log_set_level(&lxc_conf->loglevel, newlevel);
4a85ce2a
SH
1344}
1345
12a50cc6 1346static int config_autodev(const char *key, const char *value,
c6883f38
SH
1347 struct lxc_conf *lxc_conf)
1348{
ff6cb4ed
CB
1349 if (lxc_safe_uint(value, &lxc_conf->autodev) < 0)
1350 return -1;
c6883f38 1351
ff6cb4ed
CB
1352 if (lxc_conf->autodev > 1) {
1353 ERROR("Wrong value for lxc.autodev. Can only be set to 0 or 1");
1354 return -1;
1355 }
c6883f38
SH
1356
1357 return 0;
1358}
1359
a84b9932
AV
1360static int sig_num(const char *sig)
1361{
1362 int n;
1363 char *endp = NULL;
1364
1365 errno = 0;
1366 n = strtol(sig, &endp, 10);
1367 if (sig == endp || n < 0 || errno != 0)
1368 return -1;
1369 return n;
1370}
1371
1372static int rt_sig_num(const char *signame)
1373{
1374 int sig_n = 0;
1375 int rtmax = 0;
1376
1377 if (strncasecmp(signame, "max-", 4) == 0) {
1378 rtmax = 1;
1379 }
1380 signame += 4;
1381 if (!isdigit(*signame))
1382 return -1;
1383 sig_n = sig_num(signame);
1384 sig_n = rtmax ? SIGRTMAX - sig_n : SIGRTMIN + sig_n;
1385 if (sig_n > SIGRTMAX || sig_n < SIGRTMIN)
1386 return -1;
1387 return sig_n;
1388}
1389
1390static int sig_parse(const char *signame) {
84760c11 1391 size_t n;
a84b9932
AV
1392
1393 if (isdigit(*signame)) {
1394 return sig_num(signame);
1395 } else if (strncasecmp(signame, "sig", 3) == 0) {
1396 signame += 3;
1397 if (strncasecmp(signame, "rt", 2) == 0)
1398 return rt_sig_num(signame + 2);
1399 for (n = 0; n < sizeof(signames) / sizeof((signames)[0]); n++) {
1400 if (strcasecmp (signames[n].name, signame) == 0)
1401 return signames[n].num;
1402 }
1403 }
1404 return -1;
1405}
1406
f0f1d8c0
DE
1407static int config_haltsignal(const char *key, const char *value,
1408 struct lxc_conf *lxc_conf)
1409{
1410 int sig_n = sig_parse(value);
1411
1412 if (sig_n < 0)
1413 return -1;
1414 lxc_conf->haltsignal = sig_n;
1415
1416 return 0;
1417}
1418
dd267776
BP
1419static int config_rebootsignal(const char *key, const char *value,
1420 struct lxc_conf *lxc_conf)
1421{
1422 int sig_n = sig_parse(value);
1423
1424 if (sig_n < 0)
1425 return -1;
1426 lxc_conf->rebootsignal = sig_n;
1427
1428 return 0;
1429}
1430
a84b9932
AV
1431static int config_stopsignal(const char *key, const char *value,
1432 struct lxc_conf *lxc_conf)
1433{
1434 int sig_n = sig_parse(value);
1435
1436 if (sig_n < 0)
1437 return -1;
1438 lxc_conf->stopsignal = sig_n;
1439
1440 return 0;
1441}
1442
12a50cc6
DE
1443static int config_cgroup(const char *key, const char *value,
1444 struct lxc_conf *lxc_conf)
576f946d 1445{
1446 char *token = "lxc.cgroup.";
1447 char *subkey;
bf83c5b9
MS
1448 struct lxc_list *cglist = NULL;
1449 struct lxc_cgroup *cgelem = NULL;
576f946d 1450
7d0eb87e
SH
1451 if (!value || strlen(value) == 0)
1452 return lxc_clear_cgroups(lxc_conf, key);
1453
576f946d 1454 subkey = strstr(key, token);
1455
1456 if (!subkey)
1457 return -1;
1458
1459 if (!strlen(subkey))
1460 return -1;
1461
1462 if (strlen(subkey) == strlen(token))
1463 return -1;
a871ff6b 1464
576f946d 1465 subkey += strlen(token);
1466
1467 cglist = malloc(sizeof(*cglist));
1468 if (!cglist)
bf83c5b9 1469 goto out;
576f946d 1470
1471 cgelem = malloc(sizeof(*cgelem));
bf83c5b9
MS
1472 if (!cgelem)
1473 goto out;
1474 memset(cgelem, 0, sizeof(*cgelem));
576f946d 1475
1476 cgelem->subsystem = strdup(subkey);
1477 cgelem->value = strdup(value);
bf83c5b9
MS
1478
1479 if (!cgelem->subsystem || !cgelem->value)
1480 goto out;
1481
576f946d 1482 cglist->elem = cgelem;
1483
94d12f0a 1484 lxc_list_add_tail(&lxc_conf->cgroup, cglist);
576f946d 1485
1486 return 0;
bf83c5b9
MS
1487
1488out:
f10fad2f 1489 free(cglist);
bf83c5b9
MS
1490
1491 if (cgelem) {
f10fad2f 1492 free(cgelem->subsystem);
bf83c5b9 1493
f10fad2f 1494 free(cgelem->value);
bf83c5b9
MS
1495
1496 free(cgelem);
1497 }
1498
1499 return -1;
576f946d 1500}
1501
f6d3e3e4
SH
1502static int config_idmap(const char *key, const char *value, struct lxc_conf *lxc_conf)
1503{
1504 char *token = "lxc.id_map";
1505 char *subkey;
1506 struct lxc_list *idmaplist = NULL;
1507 struct id_map *idmap = NULL;
251d0d2a 1508 unsigned long hostid, nsid, range;
f6d3e3e4
SH
1509 char type;
1510 int ret;
1511
7d0eb87e
SH
1512 if (!value || strlen(value) == 0)
1513 return lxc_clear_idmaps(lxc_conf);
1514
f6d3e3e4
SH
1515 subkey = strstr(key, token);
1516
1517 if (!subkey)
1518 return -1;
1519
1520 if (!strlen(subkey))
1521 return -1;
1522
1523 idmaplist = malloc(sizeof(*idmaplist));
1524 if (!idmaplist)
1525 goto out;
1526
1527 idmap = malloc(sizeof(*idmap));
1528 if (!idmap)
1529 goto out;
1530 memset(idmap, 0, sizeof(*idmap));
1531
251d0d2a 1532 ret = sscanf(value, "%c %lu %lu %lu", &type, &nsid, &hostid, &range);
f6d3e3e4
SH
1533 if (ret != 4)
1534 goto out;
7e60c3f0 1535
251d0d2a 1536 INFO("read uid map: type %c nsid %lu hostid %lu range %lu", type, nsid, hostid, range);
ac7725e7 1537 if (type == 'u')
f6d3e3e4 1538 idmap->idtype = ID_TYPE_UID;
ac7725e7 1539 else if (type == 'g')
f6d3e3e4
SH
1540 idmap->idtype = ID_TYPE_GID;
1541 else
1542 goto out;
7e60c3f0 1543
f6d3e3e4
SH
1544 idmap->hostid = hostid;
1545 idmap->nsid = nsid;
1546 idmap->range = range;
1547
7e60c3f0
SG
1548 idmaplist->elem = idmap;
1549 lxc_list_add_tail(&lxc_conf->id_map, idmaplist);
1550
f6d3e3e4
SH
1551 return 0;
1552
1553out:
f10fad2f 1554 free(idmaplist);
f6d3e3e4
SH
1555
1556 if (idmap) {
1557 free(idmap);
1558 }
1559
1560 return -1;
1561}
1562
d95db067
DE
1563static int config_fstab(const char *key, const char *value,
1564 struct lxc_conf *lxc_conf)
1565{
d9192f5d
SH
1566 if (!value || strlen(value) == 0)
1567 return -1;
6d03d92a 1568 return config_path_item(&lxc_conf->fstab, value);
d95db067
DE
1569}
1570
368bbc02
CS
1571static int config_mount_auto(const char *key, const char *value,
1572 struct lxc_conf *lxc_conf)
1573{
1574 char *autos, *autoptr, *sptr, *token;
b06b8511 1575 static struct { const char *token; int mask; int flag; } allowed_auto_mounts[] = {
0769b82a
CS
1576 { "proc", LXC_AUTO_PROC_MASK, LXC_AUTO_PROC_MIXED },
1577 { "proc:mixed", LXC_AUTO_PROC_MASK, LXC_AUTO_PROC_MIXED },
1578 { "proc:rw", LXC_AUTO_PROC_MASK, LXC_AUTO_PROC_RW },
f24a52d5 1579 { "sys", LXC_AUTO_SYS_MASK, LXC_AUTO_SYS_MIXED },
0769b82a 1580 { "sys:ro", LXC_AUTO_SYS_MASK, LXC_AUTO_SYS_RO },
f24a52d5 1581 { "sys:mixed", LXC_AUTO_SYS_MASK, LXC_AUTO_SYS_MIXED },
0769b82a
CS
1582 { "sys:rw", LXC_AUTO_SYS_MASK, LXC_AUTO_SYS_RW },
1583 { "cgroup", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_NOSPEC },
1584 { "cgroup:mixed", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_MIXED },
1585 { "cgroup:ro", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_RO },
1586 { "cgroup:rw", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_RW },
1587 { "cgroup-full", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_FULL_NOSPEC },
1588 { "cgroup-full:mixed", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_FULL_MIXED },
1589 { "cgroup-full:ro", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_FULL_RO },
1590 { "cgroup-full:rw", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_FULL_RW },
70f55bfd 1591 /* NB: For adding anything that is just a single on/off, but has
b06b8511
CS
1592 * no options: keep mask and flag identical and just define the
1593 * enum value as an unused bit so far
1594 */
368bbc02
CS
1595 { NULL, 0 }
1596 };
1597 int i;
1598 int ret = -1;
1599
d9192f5d
SH
1600 if (!value || strlen(value) == 0) {
1601 lxc_conf->auto_mounts = 0;
1602 return 0;
1603 }
368bbc02
CS
1604
1605 autos = strdup(value);
1606 if (!autos) {
1607 SYSERROR("failed to dup '%s'", value);
1608 return -1;
1609 }
1610
1611 for (autoptr = autos; ; autoptr = NULL) {
d028235d
SG
1612 token = strtok_r(autoptr, " \t", &sptr);
1613 if (!token) {
368bbc02 1614 ret = 0;
d028235d 1615 break;
368bbc02
CS
1616 }
1617
1618 for (i = 0; allowed_auto_mounts[i].token; i++) {
1619 if (!strcmp(allowed_auto_mounts[i].token, token))
1620 break;
1621 }
1622
1623 if (!allowed_auto_mounts[i].token) {
1624 ERROR("Invalid filesystem to automount: %s", token);
1625 break;
1626 }
1627
b06b8511 1628 lxc_conf->auto_mounts &= ~allowed_auto_mounts[i].mask;
368bbc02 1629 lxc_conf->auto_mounts |= allowed_auto_mounts[i].flag;
d028235d 1630 }
368bbc02
CS
1631
1632 free(autos);
1633
1634 return ret;
1635}
1636
12a50cc6
DE
1637static int config_mount(const char *key, const char *value,
1638 struct lxc_conf *lxc_conf)
e7938e9e 1639{
e7938e9e
MN
1640 char *mntelem;
1641 struct lxc_list *mntlist;
1642
d9192f5d
SH
1643 if (!value || strlen(value) == 0)
1644 return lxc_clear_mount_entries(lxc_conf);
e7938e9e
MN
1645
1646 mntlist = malloc(sizeof(*mntlist));
1647 if (!mntlist)
1648 return -1;
1649
1650 mntelem = strdup(value);
00b6be44
SH
1651 if (!mntelem) {
1652 free(mntlist);
bf83c5b9 1653 return -1;
00b6be44 1654 }
e7938e9e
MN
1655 mntlist->elem = mntelem;
1656
1657 lxc_list_add_tail(&lxc_conf->mount_list, mntlist);
1658
1659 return 0;
1660}
1661
1fb86a7c
SH
1662static int config_cap_keep(const char *key, const char *value,
1663 struct lxc_conf *lxc_conf)
1664{
1665 char *keepcaps, *keepptr, *sptr, *token;
1666 struct lxc_list *keeplist;
1667 int ret = -1;
1668
1669 if (!strlen(value))
7d0eb87e 1670 return lxc_clear_config_keepcaps(lxc_conf);
1fb86a7c
SH
1671
1672 keepcaps = strdup(value);
1673 if (!keepcaps) {
1674 SYSERROR("failed to dup '%s'", value);
1675 return -1;
1676 }
1677
1678 /* in case several capability keep is specified in a single line
1679 * split these caps in a single element for the list */
1680 for (keepptr = keepcaps;;keepptr = NULL) {
d028235d
SG
1681 token = strtok_r(keepptr, " \t", &sptr);
1682 if (!token) {
1fb86a7c 1683 ret = 0;
d028235d 1684 break;
1fb86a7c
SH
1685 }
1686
7035407c
DE
1687 if (!strcmp(token, "none"))
1688 lxc_clear_config_keepcaps(lxc_conf);
1689
1fb86a7c
SH
1690 keeplist = malloc(sizeof(*keeplist));
1691 if (!keeplist) {
1692 SYSERROR("failed to allocate keepcap list");
1693 break;
1694 }
1695
1696 keeplist->elem = strdup(token);
1697 if (!keeplist->elem) {
1698 SYSERROR("failed to dup '%s'", token);
1699 free(keeplist);
1700 break;
1701 }
1702
1703 lxc_list_add_tail(&lxc_conf->keepcaps, keeplist);
d028235d 1704 }
1fb86a7c
SH
1705
1706 free(keepcaps);
1707
1708 return ret;
1709}
1710
12a50cc6 1711static int config_cap_drop(const char *key, const char *value,
81810dd1
DL
1712 struct lxc_conf *lxc_conf)
1713{
d95db067 1714 char *dropcaps, *dropptr, *sptr, *token;
81810dd1
DL
1715 struct lxc_list *droplist;
1716 int ret = -1;
1717
1718 if (!strlen(value))
7d0eb87e 1719 return lxc_clear_config_caps(lxc_conf);
81810dd1
DL
1720
1721 dropcaps = strdup(value);
1722 if (!dropcaps) {
1723 SYSERROR("failed to dup '%s'", value);
1724 return -1;
1725 }
1726
1727 /* in case several capability drop is specified in a single line
1728 * split these caps in a single element for the list */
d95db067 1729 for (dropptr = dropcaps;;dropptr = NULL) {
d028235d
SG
1730 token = strtok_r(dropptr, " \t", &sptr);
1731 if (!token) {
81810dd1 1732 ret = 0;
d028235d 1733 break;
81810dd1 1734 }
81810dd1
DL
1735
1736 droplist = malloc(sizeof(*droplist));
1737 if (!droplist) {
1738 SYSERROR("failed to allocate drop list");
1739 break;
1740 }
1741
1742 droplist->elem = strdup(token);
1743 if (!droplist->elem) {
1744 SYSERROR("failed to dup '%s'", token);
1745 free(droplist);
1746 break;
1747 }
1748
1749 lxc_list_add_tail(&lxc_conf->caps, droplist);
d028235d 1750 }
81810dd1
DL
1751
1752 free(dropcaps);
1753
1754 return ret;
1755}
1756
12a50cc6 1757static int config_console(const char *key, const char *value,
28a4b0e5
DL
1758 struct lxc_conf *lxc_conf)
1759{
6d03d92a 1760 return config_path_item(&lxc_conf->console.path, value);
28a4b0e5
DL
1761}
1762
96f15ca1
SH
1763static int config_console_logfile(const char *key, const char *value,
1764 struct lxc_conf *lxc_conf)
1765{
1766 return config_path_item(&lxc_conf->console.log_path, value);
1767}
1768
e6744e9b
SH
1769/*
1770 * If we find a lxc.network.hwaddr in the original config file,
1771 * we expand it in the unexpanded_config, so that after a save_config
1772 * we store the hwaddr for re-use.
1773 * This is only called when reading the config file, not when executing
1774 * a lxc.include.
1775 * 'x' and 'X' are substituted in-place.
1776 */
1777static void update_hwaddr(const char *line)
1778{
1779 char *p;
1780
1781 line += lxc_char_left_gc(line, strlen(line));
1782 if (line[0] == '#')
1783 return;
1784 if (strncmp(line, "lxc.network.hwaddr", 18) != 0)
1785 return;
1786 p = strchr(line, '=');
1787 if (!p)
1788 return; // let config_network_hwaddr raise the error
1789 p++;
1790 while (isblank(*p))
1791 p++;
1792 if (!*p)
1793 return;
1794
1795 rand_complete_hwaddr(p);
1796}
1797
6b0d5538 1798int append_unexp_config_line(const char *line, struct lxc_conf *conf)
f979ac15 1799{
6b0d5538 1800 size_t len = conf->unexpanded_len, linelen = strlen(line);
f979ac15 1801
e6744e9b
SH
1802 update_hwaddr(line);
1803
6b0d5538
SH
1804 while (conf->unexpanded_alloced <= len + linelen + 2) {
1805 char *tmp = realloc(conf->unexpanded_config, conf->unexpanded_alloced + 1024);
1806 if (!tmp)
1807 return -1;
1808 if (!conf->unexpanded_config)
1809 *tmp = '\0';
1810 conf->unexpanded_config = tmp;
1811 conf->unexpanded_alloced += 1024;
1812 }
1813 strcat(conf->unexpanded_config, line);
1814 conf->unexpanded_len += linelen;
1815 if (line[linelen-1] != '\n') {
1816 strcat(conf->unexpanded_config, "\n");
1817 conf->unexpanded_len++;
f979ac15 1818 }
f979ac15
SH
1819 return 0;
1820}
1821
e1daebd9
SH
1822static int do_includedir(const char *dirp, struct lxc_conf *lxc_conf)
1823{
74f96976 1824 struct dirent *direntp;
e1daebd9
SH
1825 DIR *dir;
1826 char path[MAXPATHLEN];
1827 int ret = -1, len;
1828
1829 dir = opendir(dirp);
1830 if (!dir) {
1831 SYSERROR("failed to open '%s'", dirp);
1832 return -1;
1833 }
1834
74f96976 1835 while ((direntp = readdir(dir))) {
e1daebd9
SH
1836 const char *fnam;
1837 if (!direntp)
1838 break;
1839
1840 fnam = direntp->d_name;
1841 if (!strcmp(fnam, "."))
1842 continue;
1843
1844 if (!strcmp(fnam, ".."))
1845 continue;
1846
1847 len = strlen(fnam);
1848 if (len < 6 || strncmp(fnam+len-5, ".conf", 5) != 0)
1849 continue;
1850 len = snprintf(path, MAXPATHLEN, "%s/%s", dirp, fnam);
1851 if (len < 0 || len >= MAXPATHLEN) {
1852 ERROR("lxc.include filename too long under '%s'", dirp);
1853 ret = -1;
1854 goto out;
1855 }
1856
1857 ret = lxc_config_read(path, lxc_conf, true);
1858 if (ret < 0)
1859 goto out;
1860 }
1861 ret = 0;
1862
1863out:
1864 if (closedir(dir))
1865 WARN("lxc.include dir: failed to close directory");
1866
1867 return ret;
1868}
1869
12a50cc6 1870static int config_includefile(const char *key, const char *value,
09ad6246
SH
1871 struct lxc_conf *lxc_conf)
1872{
e1daebd9
SH
1873 if (is_dir(value))
1874 return do_includedir(value, lxc_conf);
1875
6b0d5538 1876 return lxc_config_read(value, lxc_conf, true);
09ad6246
SH
1877}
1878
12a50cc6
DE
1879static int config_rootfs(const char *key, const char *value,
1880 struct lxc_conf *lxc_conf)
c2cc9f0a 1881{
6d03d92a 1882 return config_path_item(&lxc_conf->rootfs.path, value);
c2cc9f0a 1883}
1884
12a50cc6
DE
1885static int config_rootfs_mount(const char *key, const char *value,
1886 struct lxc_conf *lxc_conf)
23b7ea69 1887{
6d03d92a 1888 return config_path_item(&lxc_conf->rootfs.mount, value);
23b7ea69
DL
1889}
1890
a17b1e65
SG
1891static int config_rootfs_options(const char *key, const char *value,
1892 struct lxc_conf *lxc_conf)
1893{
1894 return config_string_item(&lxc_conf->rootfs.options, value);
1895}
1896
327a1e78 1897static int config_rootfs_backend(const char *key, const char *value,
bfd77214
SH
1898 struct lxc_conf *lxc_conf)
1899{
6a21d4ae
SH
1900 if (strlen(value) == 0) {
1901 free(lxc_conf->rootfs.bdev_type);
1902 lxc_conf->rootfs.bdev_type = NULL;
1903 }
bfd77214 1904 if (!is_valid_bdev_type(value)) {
327a1e78 1905 ERROR("Bad rootfs.backend: '%s'", value);
bfd77214
SH
1906 return -1;
1907 }
1908
b3b8c97f 1909 return config_string_item(&lxc_conf->rootfs.bdev_type, value);
bfd77214
SH
1910}
1911
12a50cc6
DE
1912static int config_pivotdir(const char *key, const char *value,
1913 struct lxc_conf *lxc_conf)
bf601689 1914{
2d489f9e 1915 WARN("lxc.pivotdir is ignored. It will soon become an error.");
59bb8698 1916 return 0;
bf601689
MH
1917}
1918
12a50cc6
DE
1919static int config_utsname(const char *key, const char *value,
1920 struct lxc_conf *lxc_conf)
c2cc9f0a 1921{
1922 struct utsname *utsname;
1923
1924 utsname = malloc(sizeof(*utsname));
1925 if (!utsname) {
36eb9bde 1926 SYSERROR("failed to allocate memory");
c2cc9f0a 1927 return -1;
1928 }
1929
1930 if (strlen(value) >= sizeof(utsname->nodename)) {
36eb9bde 1931 ERROR("node name '%s' is too long",
16e29c91 1932 value);
b6f24d54 1933 free(utsname);
c2cc9f0a 1934 return -1;
1935 }
1936
1937 strcpy(utsname->nodename, value);
f10fad2f 1938 free(lxc_conf->utsname);
c2cc9f0a 1939 lxc_conf->utsname = utsname;
1940
1941 return 0;
1942}
1943
6b0d5538
SH
1944struct parse_line_conf {
1945 struct lxc_conf *conf;
1946 bool from_include;
1947};
4184c3e1 1948
7a7ff0c6 1949static int parse_line(char *buffer, void *data)
c2cc9f0a 1950{
72d0e1cb 1951 struct lxc_config_t *config;
81192358 1952 char *line, *linep;
c2cc9f0a 1953 char *dot;
1954 char *key;
1955 char *value;
476d4cf1 1956 int ret = 0;
6b0d5538 1957 struct parse_line_conf *plc = data;
c2cc9f0a 1958
91480a0f 1959 if (lxc_is_line_empty(buffer))
c2cc9f0a 1960 return 0;
1961
81192358
DL
1962 /* we have to dup the buffer otherwise, at the re-exec for
1963 * reboot we modified the original string on the stack by
1964 * replacing '=' by '\0' below
91480a0f 1965 */
81192358 1966 linep = line = strdup(buffer);
91480a0f
DL
1967 if (!line) {
1968 SYSERROR("failed to allocate memory for '%s'", buffer);
81192358 1969 return -1;
91480a0f
DL
1970 }
1971
6b0d5538
SH
1972 if (!plc->from_include)
1973 if ((ret = append_unexp_config_line(line, plc->conf)))
1974 goto out;
1975
b2718c72 1976 line += lxc_char_left_gc(line, strlen(line));
476d4cf1 1977
4184c3e1
SH
1978 /* ignore comments */
1979 if (line[0] == '#')
91480a0f 1980 goto out;
476d4cf1 1981
6b0d5538
SH
1982 /* martian option - don't add it to the config itself */
1983 if (strncmp(line, "lxc.", 4))
4184c3e1 1984 goto out;
4184c3e1 1985
476d4cf1 1986 ret = -1;
c2cc9f0a 1987
b2718c72 1988 dot = strstr(line, "=");
c2cc9f0a 1989 if (!dot) {
36eb9bde 1990 ERROR("invalid configuration line: %s", line);
91480a0f 1991 goto out;
c2cc9f0a 1992 }
a871ff6b 1993
c2cc9f0a 1994 *dot = '\0';
1995 value = dot + 1;
1996
b2718c72 1997 key = line;
1998 key[lxc_char_right_gc(key, strlen(key))] = '\0';
c2cc9f0a 1999
b2718c72 2000 value += lxc_char_left_gc(value, strlen(value));
2001 value[lxc_char_right_gc(value, strlen(value))] = '\0';
c2cc9f0a 2002
bd878dee
SB
2003 if (*value == '\'' || *value == '\"') {
2004 size_t len = strlen(value);
2005 if (len > 1 && value[len-1] == *value) {
2006 value[len-1] = '\0';
2007 value++;
2008 }
2009 }
2010
72d0e1cb 2011 config = lxc_getconfig(key);
c2cc9f0a 2012 if (!config) {
6e1d9b94 2013 ERROR("unknown key %s", key);
91480a0f 2014 goto out;
c2cc9f0a 2015 }
2016
6b0d5538 2017 ret = config->cb(key, value, plc->conf);
91480a0f
DL
2018
2019out:
81192358 2020 free(linep);
91480a0f 2021 return ret;
c2cc9f0a 2022}
2023
74a3920a 2024static int lxc_config_readline(char *buffer, struct lxc_conf *conf)
af5b0155 2025{
6b0d5538
SH
2026 struct parse_line_conf c;
2027
2028 c.conf = conf;
2029 c.from_include = false;
2030
2031 return parse_line(buffer, &c);
af5b0155
CLG
2032}
2033
6b0d5538 2034int lxc_config_read(const char *file, struct lxc_conf *conf, bool from_include)
c2cc9f0a 2035{
6b0d5538
SH
2036 struct parse_line_conf c;
2037
2038 c.conf = conf;
2039 c.from_include = from_include;
f979ac15 2040
f3ca99fd
SH
2041 if( access(file, R_OK) == -1 ) {
2042 return -1;
2043 }
6b0d5538 2044
f7bee6c6 2045 /* Catch only the top level config file name in the structure */
76d0127f
CB
2046 if(!conf->rcfile)
2047 conf->rcfile = strdup(file);
f979ac15 2048
6b0d5538 2049 return lxc_file_for_each_line(file, parse_line, &c);
c2cc9f0a 2050}
62e46035
CLG
2051
2052int lxc_config_define_add(struct lxc_list *defines, char* arg)
2053{
2054 struct lxc_list *dent;
2055
2056 dent = malloc(sizeof(struct lxc_list));
2057 if (!dent)
2058 return -1;
2059
2060 dent->elem = arg;
2061 lxc_list_add_tail(defines, dent);
2062 return 0;
2063}
2064
226a18d6 2065int lxc_config_define_load(struct lxc_list *defines, struct lxc_conf *conf)
62e46035 2066{
9ebb03ad 2067 struct lxc_list *it,*next;
62e46035
CLG
2068 int ret = 0;
2069
2070 lxc_list_for_each(it, defines) {
2071 ret = lxc_config_readline(it->elem, conf);
2072 if (ret)
2073 break;
2074 }
2075
9ebb03ad 2076 lxc_list_for_each_safe(it, defines, next) {
62e46035
CLG
2077 lxc_list_del(it);
2078 free(it);
2079 }
2080
2081 return ret;
2082}
525f0002
CS
2083
2084signed long lxc_config_parse_arch(const char *arch)
2085{
6ff05e18 2086 #if HAVE_SYS_PERSONALITY_H
525f0002
CS
2087 struct per_name {
2088 char *name;
2089 unsigned long per;
bb8d8207 2090 } pername[] = {
525f0002 2091 { "x86", PER_LINUX32 },
bb8d8207
DE
2092 { "linux32", PER_LINUX32 },
2093 { "i386", PER_LINUX32 },
2094 { "i486", PER_LINUX32 },
2095 { "i586", PER_LINUX32 },
525f0002 2096 { "i686", PER_LINUX32 },
bb8d8207 2097 { "athlon", PER_LINUX32 },
e319eb34
JC
2098 { "mips", PER_LINUX32 },
2099 { "mipsel", PER_LINUX32 },
08245e8c
CB
2100 { "ppc", PER_LINUX32 },
2101 { "arm", PER_LINUX32 },
2102 { "armv7l", PER_LINUX32 },
2103 { "armhf", PER_LINUX32 },
2104 { "armel", PER_LINUX32 },
2105 { "powerpc", PER_LINUX32 },
bb8d8207 2106 { "linux64", PER_LINUX },
525f0002
CS
2107 { "x86_64", PER_LINUX },
2108 { "amd64", PER_LINUX },
e319eb34
JC
2109 { "mips64", PER_LINUX },
2110 { "mips64el", PER_LINUX },
08245e8c
CB
2111 { "ppc64", PER_LINUX },
2112 { "ppc64le", PER_LINUX },
2113 { "ppc64el", PER_LINUX },
2114 { "powerpc64", PER_LINUX },
2115 { "s390x", PER_LINUX },
2116 { "aarch64", PER_LINUX },
2117 { "arm64", PER_LINUX },
525f0002
CS
2118 };
2119 size_t len = sizeof(pername) / sizeof(pername[0]);
2120
84760c11 2121 size_t i;
525f0002
CS
2122
2123 for (i = 0; i < len; i++) {
2124 if (!strcmp(pername[i].name, arch))
2125 return pername[i].per;
2126 }
6ff05e18 2127 #endif
525f0002
CS
2128
2129 return -1;
2130}
72d0e1cb 2131
4d69b293
NK
2132int lxc_fill_elevated_privileges(char *flaglist, int *flags)
2133{
2134 char *token, *saveptr = NULL;
2135 int i, aflag;
2136 struct { const char *token; int flag; } all_privs[] = {
2137 { "CGROUP", LXC_ATTACH_MOVE_TO_CGROUP },
2138 { "CAP", LXC_ATTACH_DROP_CAPABILITIES },
2139 { "LSM", LXC_ATTACH_LSM_EXEC },
2140 { NULL, 0 }
2141 };
2142
2143 if (!flaglist) {
2144 /* for the sake of backward compatibility, drop all privileges
2145 if none is specified */
2146 for (i = 0; all_privs[i].token; i++) {
d028235d 2147 *flags |= all_privs[i].flag;
4d69b293
NK
2148 }
2149 return 0;
2150 }
2151
2152 token = strtok_r(flaglist, "|", &saveptr);
2153 while (token) {
2154 aflag = -1;
2155 for (i = 0; all_privs[i].token; i++) {
2156 if (!strcmp(all_privs[i].token, token))
2157 aflag = all_privs[i].flag;
2158 }
2159 if (aflag < 0)
2160 return -1;
2161
2162 *flags |= aflag;
2163
2164 token = strtok_r(NULL, "|", &saveptr);
2165 }
2166 return 0;
2167}
2168
72d0e1cb
SG
2169static int lxc_get_conf_int(struct lxc_conf *c, char *retv, int inlen, int v)
2170{
2171 if (!retv)
2172 inlen = 0;
2173 else
2174 memset(retv, 0, inlen);
2175 return snprintf(retv, inlen, "%d", v);
2176}
2177
2178static int lxc_get_arch_entry(struct lxc_conf *c, char *retv, int inlen)
2179{
6ff05e18 2180 int fulllen = 0;
72d0e1cb
SG
2181
2182 if (!retv)
2183 inlen = 0;
2184 else
2185 memset(retv, 0, inlen);
2186
6ff05e18
SG
2187 #if HAVE_SYS_PERSONALITY_H
2188 int len = 0;
2189
72d0e1cb 2190 switch(c->personality) {
14622799 2191 case PER_LINUX32: strprint(retv, inlen, "i686"); break;
72d0e1cb
SG
2192 case PER_LINUX: strprint(retv, inlen, "x86_64"); break;
2193 default: break;
2194 }
6ff05e18 2195 #endif
72d0e1cb
SG
2196
2197 return fulllen;
2198}
2199
2200/*
2201 * If you ask for a specific cgroup value, i.e. lxc.cgroup.devices.list,
2202 * then just the value(s) will be printed. Since there still could be
2203 * more than one, it is newline-separated.
2204 * (Maybe that's ambigous, since some values, i.e. devices.list, will
2205 * already have newlines?)
2206 * If you ask for 'lxc.cgroup", then all cgroup entries will be printed,
2207 * in 'lxc.cgroup.subsystem.key = value' format.
2208 */
12a50cc6
DE
2209static int lxc_get_cgroup_entry(struct lxc_conf *c, char *retv, int inlen,
2210 const char *key)
72d0e1cb
SG
2211{
2212 int fulllen = 0, len;
2213 int all = 0;
2214 struct lxc_list *it;
2215
2216 if (!retv)
2217 inlen = 0;
2218 else
2219 memset(retv, 0, inlen);
2220
2221 if (strcmp(key, "all") == 0)
2222 all = 1;
2223
2224 lxc_list_for_each(it, &c->cgroup) {
2225 struct lxc_cgroup *cg = it->elem;
2226 if (all) {
2227 strprint(retv, inlen, "lxc.cgroup.%s = %s\n", cg->subsystem, cg->value);
2228 } else if (strcmp(cg->subsystem, key) == 0) {
2229 strprint(retv, inlen, "%s\n", cg->value);
2230 }
2231 }
2232 return fulllen;
2233}
2234
12a50cc6
DE
2235static int lxc_get_item_hooks(struct lxc_conf *c, char *retv, int inlen,
2236 const char *key)
72d0e1cb
SG
2237{
2238 char *subkey;
2239 int len, fulllen = 0, found = -1;
2240 struct lxc_list *it;
2241 int i;
2242
2243 /* "lxc.hook.mount" */
46cd2845
PL
2244 subkey = strchr(key, '.');
2245 if (subkey) subkey = strchr(subkey+1, '.');
72d0e1cb
SG
2246 if (!subkey)
2247 return -1;
2248 subkey++;
2249 if (!*subkey)
2250 return -1;
2251 for (i=0; i<NUM_LXC_HOOKS; i++) {
2252 if (strcmp(lxchook_names[i], subkey) == 0) {
2253 found=i;
2254 break;
2255 }
2256 }
2257 if (found == -1)
2258 return -1;
2259
2260 if (!retv)
2261 inlen = 0;
2262 else
2263 memset(retv, 0, inlen);
2264
2265 lxc_list_for_each(it, &c->hooks[found]) {
2266 strprint(retv, inlen, "%s\n", (char *)it->elem);
2267 }
2268 return fulllen;
2269}
2270
ee1e7aa0
SG
2271static int lxc_get_item_groups(struct lxc_conf *c, char *retv, int inlen)
2272{
2273 int len, fulllen = 0;
2274 struct lxc_list *it;
2275
2276 if (!retv)
2277 inlen = 0;
2278 else
2279 memset(retv, 0, inlen);
2280
2281 lxc_list_for_each(it, &c->groups) {
2282 strprint(retv, inlen, "%s\n", (char *)it->elem);
2283 }
2284 return fulllen;
2285}
2286
ab799c0b
SG
2287static int lxc_get_item_environment(struct lxc_conf *c, char *retv, int inlen)
2288{
2289 int len, fulllen = 0;
2290 struct lxc_list *it;
2291
2292 if (!retv)
2293 inlen = 0;
2294 else
2295 memset(retv, 0, inlen);
2296
2297 lxc_list_for_each(it, &c->environment) {
2298 strprint(retv, inlen, "%s\n", (char *)it->elem);
2299 }
2300 return fulllen;
2301}
2302
72d0e1cb
SG
2303static int lxc_get_item_cap_drop(struct lxc_conf *c, char *retv, int inlen)
2304{
2305 int len, fulllen = 0;
2306 struct lxc_list *it;
2307
2308 if (!retv)
2309 inlen = 0;
2310 else
2311 memset(retv, 0, inlen);
2312
2313 lxc_list_for_each(it, &c->caps) {
2314 strprint(retv, inlen, "%s\n", (char *)it->elem);
2315 }
2316 return fulllen;
2317}
2318
1fb86a7c
SH
2319static int lxc_get_item_cap_keep(struct lxc_conf *c, char *retv, int inlen)
2320{
2321 int len, fulllen = 0;
2322 struct lxc_list *it;
2323
2324 if (!retv)
2325 inlen = 0;
2326 else
2327 memset(retv, 0, inlen);
2328
2329 lxc_list_for_each(it, &c->keepcaps) {
2330 strprint(retv, inlen, "%s\n", (char *)it->elem);
2331 }
2332 return fulllen;
2333}
2334
72d0e1cb
SG
2335static int lxc_get_mount_entries(struct lxc_conf *c, char *retv, int inlen)
2336{
2337 int len, fulllen = 0;
2338 struct lxc_list *it;
2339
2340 if (!retv)
2341 inlen = 0;
2342 else
2343 memset(retv, 0, inlen);
2344
2345 lxc_list_for_each(it, &c->mount_list) {
2346 strprint(retv, inlen, "%s\n", (char *)it->elem);
2347 }
2348 return fulllen;
2349}
2350
b099e9e9
SH
2351static int lxc_get_auto_mounts(struct lxc_conf *c, char *retv, int inlen)
2352{
2353 int len, fulllen = 0;
0769b82a 2354 const char *sep = "";
b099e9e9
SH
2355
2356 if (!retv)
2357 inlen = 0;
2358 else
2359 memset(retv, 0, inlen);
2360
2361 if (!(c->auto_mounts & LXC_AUTO_ALL_MASK))
2362 return 0;
2363
2364 switch (c->auto_mounts & LXC_AUTO_PROC_MASK) {
0769b82a
CS
2365 case LXC_AUTO_PROC_MIXED: strprint(retv, inlen, "%sproc:mixed", sep); sep = " "; break;
2366 case LXC_AUTO_PROC_RW: strprint(retv, inlen, "%sproc:rw", sep); sep = " "; break;
b099e9e9
SH
2367 default: break;
2368 }
2369 switch (c->auto_mounts & LXC_AUTO_SYS_MASK) {
0769b82a
CS
2370 case LXC_AUTO_SYS_RO: strprint(retv, inlen, "%ssys:ro", sep); sep = " "; break;
2371 case LXC_AUTO_SYS_RW: strprint(retv, inlen, "%ssys:rw", sep); sep = " "; break;
10f27710 2372 case LXC_AUTO_SYS_MIXED: strprint(retv, inlen, "%ssys:mixed", sep); sep = " "; break;
b099e9e9
SH
2373 default: break;
2374 }
2375 switch (c->auto_mounts & LXC_AUTO_CGROUP_MASK) {
0769b82a
CS
2376 case LXC_AUTO_CGROUP_NOSPEC: strprint(retv, inlen, "%scgroup", sep); sep = " "; break;
2377 case LXC_AUTO_CGROUP_MIXED: strprint(retv, inlen, "%scgroup:mixed", sep); sep = " "; break;
2378 case LXC_AUTO_CGROUP_RO: strprint(retv, inlen, "%scgroup:ro", sep); sep = " "; break;
2379 case LXC_AUTO_CGROUP_RW: strprint(retv, inlen, "%scgroup:rw", sep); sep = " "; break;
2380 case LXC_AUTO_CGROUP_FULL_NOSPEC: strprint(retv, inlen, "%scgroup-full", sep); sep = " "; break;
2381 case LXC_AUTO_CGROUP_FULL_MIXED: strprint(retv, inlen, "%scgroup-full:mixed", sep); sep = " "; break;
2382 case LXC_AUTO_CGROUP_FULL_RO: strprint(retv, inlen, "%scgroup-full:ro", sep); sep = " "; break;
2383 case LXC_AUTO_CGROUP_FULL_RW: strprint(retv, inlen, "%scgroup-full:rw", sep); sep = " "; break;
b099e9e9
SH
2384 default: break;
2385 }
0769b82a 2386
b099e9e9
SH
2387 return fulllen;
2388}
2389
72d0e1cb
SG
2390/*
2391 * lxc.network.0.XXX, where XXX can be: name, type, link, flags, type,
8fc8295a 2392 * macvlan.mode, veth.pair, vlan, ipv4, ipv6, script.up, hwaddr, mtu,
9eaf8a59 2393 * ipv4.gateway, ipv6.gateway. ipvX.gateway can return 'auto' instead
72d0e1cb
SG
2394 * of an address. ipv4 and ipv6 return lists (newline-separated).
2395 * things like veth.pair return '' if invalid (i.e. if called for vlan
2396 * type).
2397 */
12a50cc6
DE
2398static int lxc_get_item_nic(struct lxc_conf *c, char *retv, int inlen,
2399 const char *key)
72d0e1cb
SG
2400{
2401 char *p1;
fe88b9d2 2402 int len, fulllen = 0;
72d0e1cb
SG
2403 struct lxc_netdev *netdev;
2404
2405 if (!retv)
2406 inlen = 0;
2407 else
2408 memset(retv, 0, inlen);
2409
46cd2845 2410 p1 = strchr(key, '.');
72d0e1cb
SG
2411 if (!p1 || *(p1+1) == '\0') return -1;
2412 p1++;
2413
2414 netdev = get_netdev_from_key(key, &c->network);
2415 if (!netdev)
2416 return -1;
2417 if (strcmp(p1, "name") == 0) {
2418 if (netdev->name)
2419 strprint(retv, inlen, "%s", netdev->name);
2420 } else if (strcmp(p1, "type") == 0) {
2421 strprint(retv, inlen, "%s", lxc_net_type_to_str(netdev->type));
2422 } else if (strcmp(p1, "link") == 0) {
2423 if (netdev->link)
2424 strprint(retv, inlen, "%s", netdev->link);
2425 } else if (strcmp(p1, "flags") == 0) {
2426 if (netdev->flags & IFF_UP)
2427 strprint(retv, inlen, "up");
8fc8295a 2428 } else if (strcmp(p1, "script.up") == 0) {
72d0e1cb
SG
2429 if (netdev->upscript)
2430 strprint(retv, inlen, "%s", netdev->upscript);
8fc8295a
DE
2431 } else if (strcmp(p1, "script.down") == 0) {
2432 if (netdev->downscript)
2433 strprint(retv, inlen, "%s", netdev->downscript);
72d0e1cb
SG
2434 } else if (strcmp(p1, "hwaddr") == 0) {
2435 if (netdev->hwaddr)
2436 strprint(retv, inlen, "%s", netdev->hwaddr);
2437 } else if (strcmp(p1, "mtu") == 0) {
2438 if (netdev->mtu)
2439 strprint(retv, inlen, "%s", netdev->mtu);
2440 } else if (strcmp(p1, "macvlan.mode") == 0) {
2441 if (netdev->type == LXC_NET_MACVLAN) {
2442 const char *mode;
2443 switch (netdev->priv.macvlan_attr.mode) {
2444 case MACVLAN_MODE_PRIVATE: mode = "private"; break;
2445 case MACVLAN_MODE_VEPA: mode = "vepa"; break;
2446 case MACVLAN_MODE_BRIDGE: mode = "bridge"; break;
99854161 2447 case MACVLAN_MODE_PASSTHRU: mode = "passthru"; break;
72d0e1cb
SG
2448 default: mode = "(invalid)"; break;
2449 }
2450 strprint(retv, inlen, "%s", mode);
2451 }
2452 } else if (strcmp(p1, "veth.pair") == 0) {
11029c02
DE
2453 if (netdev->type == LXC_NET_VETH) {
2454 strprint(retv, inlen, "%s",
2455 netdev->priv.veth_attr.pair ?
2456 netdev->priv.veth_attr.pair :
2457 netdev->priv.veth_attr.veth1);
2458 }
72d0e1cb
SG
2459 } else if (strcmp(p1, "vlan") == 0) {
2460 if (netdev->type == LXC_NET_VLAN) {
2461 strprint(retv, inlen, "%d", netdev->priv.vlan_attr.vid);
2462 }
9eaf8a59 2463 } else if (strcmp(p1, "ipv4.gateway") == 0) {
72d0e1cb
SG
2464 if (netdev->ipv4_gateway_auto) {
2465 strprint(retv, inlen, "auto");
2466 } else if (netdev->ipv4_gateway) {
2467 char buf[INET_ADDRSTRLEN];
2468 inet_ntop(AF_INET, netdev->ipv4_gateway, buf, sizeof(buf));
2469 strprint(retv, inlen, "%s", buf);
2470 }
2471 } else if (strcmp(p1, "ipv4") == 0) {
2472 struct lxc_list *it2;
2473 lxc_list_for_each(it2, &netdev->ipv4) {
2474 struct lxc_inetdev *i = it2->elem;
2475 char buf[INET_ADDRSTRLEN];
2476 inet_ntop(AF_INET, &i->addr, buf, sizeof(buf));
28417b5a 2477 strprint(retv, inlen, "%s/%d\n", buf, i->prefix);
72d0e1cb 2478 }
9eaf8a59 2479 } else if (strcmp(p1, "ipv6.gateway") == 0) {
72d0e1cb
SG
2480 if (netdev->ipv6_gateway_auto) {
2481 strprint(retv, inlen, "auto");
2482 } else if (netdev->ipv6_gateway) {
6afb165d
AN
2483 char buf[INET6_ADDRSTRLEN];
2484 inet_ntop(AF_INET6, netdev->ipv6_gateway, buf, sizeof(buf));
72d0e1cb
SG
2485 strprint(retv, inlen, "%s", buf);
2486 }
2487 } else if (strcmp(p1, "ipv6") == 0) {
2488 struct lxc_list *it2;
2489 lxc_list_for_each(it2, &netdev->ipv6) {
6afb165d
AN
2490 struct lxc_inet6dev *i = it2->elem;
2491 char buf[INET6_ADDRSTRLEN];
72d0e1cb 2492 inet_ntop(AF_INET6, &i->addr, buf, sizeof(buf));
28417b5a 2493 strprint(retv, inlen, "%s/%d\n", buf, i->prefix);
72d0e1cb
SG
2494 }
2495 }
2496 return fulllen;
2497}
2498
2499static int lxc_get_item_network(struct lxc_conf *c, char *retv, int inlen)
2500{
2501 int len, fulllen = 0;
2502 struct lxc_list *it;
2503
2504 if (!retv)
2505 inlen = 0;
2506 else
2507 memset(retv, 0, inlen);
2508
2509 lxc_list_for_each(it, &c->network) {
2510 struct lxc_netdev *n = it->elem;
2511 const char *t = lxc_net_type_to_str(n->type);
2512 strprint(retv, inlen, "%s\n", t ? t : "(invalid)");
2513 }
2514 return fulllen;
2515}
2516
12a50cc6
DE
2517int lxc_get_config_item(struct lxc_conf *c, const char *key, char *retv,
2518 int inlen)
72d0e1cb 2519{
4a85ce2a 2520 const char *v = NULL;
72d0e1cb
SG
2521
2522 if (strcmp(key, "lxc.mount.entry") == 0)
2523 return lxc_get_mount_entries(c, retv, inlen);
b099e9e9
SH
2524 else if (strcmp(key, "lxc.mount.auto") == 0)
2525 return lxc_get_auto_mounts(c, retv, inlen);
72d0e1cb
SG
2526 else if (strcmp(key, "lxc.mount") == 0)
2527 v = c->fstab;
2528 else if (strcmp(key, "lxc.tty") == 0)
2529 return lxc_get_conf_int(c, retv, inlen, c->tty);
2530 else if (strcmp(key, "lxc.pts") == 0)
2531 return lxc_get_conf_int(c, retv, inlen, c->pts);
2532 else if (strcmp(key, "lxc.devttydir") == 0)
2533 v = c->ttydir;
2534 else if (strcmp(key, "lxc.arch") == 0)
2535 return lxc_get_arch_entry(c, retv, inlen);
2536 else if (strcmp(key, "lxc.aa_profile") == 0)
fe4de9a6 2537 v = c->lsm_aa_profile;
7aff4f43
SH
2538 else if (strcmp(key, "lxc.aa_allow_incomplete") == 0)
2539 return lxc_get_conf_int(c, retv, inlen, c->lsm_aa_allow_incomplete);
fe4de9a6
DE
2540 else if (strcmp(key, "lxc.se_context") == 0)
2541 v = c->lsm_se_context;
4a85ce2a 2542 else if (strcmp(key, "lxc.logfile") == 0)
858377e4 2543 v = c->logfile;
4a85ce2a 2544 else if (strcmp(key, "lxc.loglevel") == 0)
858377e4 2545 v = lxc_log_priority_to_string(c->loglevel);
72d0e1cb
SG
2546 else if (strcmp(key, "lxc.cgroup") == 0) // all cgroup info
2547 return lxc_get_cgroup_entry(c, retv, inlen, "all");
2548 else if (strncmp(key, "lxc.cgroup.", 11) == 0) // specific cgroup info
2549 return lxc_get_cgroup_entry(c, retv, inlen, key + 11);
2550 else if (strcmp(key, "lxc.utsname") == 0)
64fca455 2551 v = c->utsname ? c->utsname->nodename : NULL;
96f15ca1
SH
2552 else if (strcmp(key, "lxc.console.logfile") == 0)
2553 v = c->console.log_path;
72d0e1cb
SG
2554 else if (strcmp(key, "lxc.console") == 0)
2555 v = c->console.path;
2556 else if (strcmp(key, "lxc.rootfs.mount") == 0)
2557 v = c->rootfs.mount;
327a1e78 2558 else if (strcmp(key, "lxc.rootfs.backend") == 0)
6a21d4ae 2559 v = c->rootfs.bdev_type;
a17b1e65
SG
2560 else if (strcmp(key, "lxc.rootfs.options") == 0)
2561 v = c->rootfs.options;
72d0e1cb
SG
2562 else if (strcmp(key, "lxc.rootfs") == 0)
2563 v = c->rootfs.path;
72d0e1cb
SG
2564 else if (strcmp(key, "lxc.cap.drop") == 0)
2565 return lxc_get_item_cap_drop(c, retv, inlen);
1fb86a7c
SH
2566 else if (strcmp(key, "lxc.cap.keep") == 0)
2567 return lxc_get_item_cap_keep(c, retv, inlen);
72d0e1cb
SG
2568 else if (strncmp(key, "lxc.hook", 8) == 0)
2569 return lxc_get_item_hooks(c, retv, inlen, key);
2570 else if (strcmp(key, "lxc.network") == 0)
2571 return lxc_get_item_network(c, retv, inlen);
2572 else if (strncmp(key, "lxc.network.", 12) == 0)
2573 return lxc_get_item_nic(c, retv, inlen, key + 12);
ee1e7aa0
SG
2574 else if (strcmp(key, "lxc.start.auto") == 0)
2575 return lxc_get_conf_int(c, retv, inlen, c->start_auto);
2576 else if (strcmp(key, "lxc.start.delay") == 0)
2577 return lxc_get_conf_int(c, retv, inlen, c->start_delay);
2578 else if (strcmp(key, "lxc.start.order") == 0)
2579 return lxc_get_conf_int(c, retv, inlen, c->start_order);
a8dfe4e0
WB
2580 else if (strcmp(key, "lxc.monitor.unshare") == 0)
2581 return lxc_get_conf_int(c, retv, inlen, c->monitor_unshare);
ee1e7aa0
SG
2582 else if (strcmp(key, "lxc.group") == 0)
2583 return lxc_get_item_groups(c, retv, inlen);
58e0f57d
SH
2584 else if (strcmp(key, "lxc.seccomp") == 0)
2585 v = c->seccomp;
ab799c0b
SG
2586 else if (strcmp(key, "lxc.environment") == 0)
2587 return lxc_get_item_environment(c, retv, inlen);
67c660d0
SG
2588 else if (strcmp(key, "lxc.init_cmd") == 0)
2589 v = c->init_cmd;
68d18db8
PT
2590 else if (strcmp(key, "lxc.init_uid") == 0)
2591 return lxc_get_conf_int(c, retv, inlen, c->init_uid);
2592 else if (strcmp(key, "lxc.init_gid") == 0)
2593 return lxc_get_conf_int(c, retv, inlen, c->init_gid);
8796becf
CB
2594 else if (strcmp(key, "lxc.ephemeral") == 0)
2595 return lxc_get_conf_int(c, retv, inlen, c->ephemeral);
76d0127f
CB
2596 else if (strcmp(key, "lxc.syslog") == 0)
2597 v = c->syslog;
5a46f283
CB
2598 else if (strcmp(key, "lxc.no_new_privs") == 0)
2599 return lxc_get_conf_int(c, retv, inlen, c->no_new_privs);
72d0e1cb
SG
2600 else return -1;
2601
2602 if (!v)
2603 return 0;
2604 if (retv && inlen >= strlen(v) + 1)
2605 strncpy(retv, v, strlen(v)+1);
2606 return strlen(v);
2607}
2608
12a50cc6 2609int lxc_clear_config_item(struct lxc_conf *c, const char *key)
72d0e1cb
SG
2610{
2611 if (strcmp(key, "lxc.network") == 0)
2612 return lxc_clear_config_network(c);
2613 else if (strncmp(key, "lxc.network.", 12) == 0)
2614 return lxc_clear_nic(c, key + 12);
2615 else if (strcmp(key, "lxc.cap.drop") == 0)
2616 return lxc_clear_config_caps(c);
1fb86a7c
SH
2617 else if (strcmp(key, "lxc.cap.keep") == 0)
2618 return lxc_clear_config_keepcaps(c);
72d0e1cb
SG
2619 else if (strncmp(key, "lxc.cgroup", 10) == 0)
2620 return lxc_clear_cgroups(c, key);
a7c6b8c7 2621 else if (strcmp(key, "lxc.mount.entry") == 0)
72d0e1cb 2622 return lxc_clear_mount_entries(c);
b099e9e9
SH
2623 else if (strcmp(key, "lxc.mount.auto") == 0)
2624 return lxc_clear_automounts(c);
17ed13a3
SH
2625 else if (strncmp(key, "lxc.hook", 8) == 0)
2626 return lxc_clear_hooks(c, key);
ee1e7aa0
SG
2627 else if (strncmp(key, "lxc.group", 9) == 0)
2628 return lxc_clear_groups(c);
fcdc3e50 2629 else if (strncmp(key, "lxc.environment", 15) == 0)
ab799c0b 2630 return lxc_clear_environment(c);
fcdc3e50 2631 else if (strncmp(key, "lxc.id_map", 10) == 0)
26f1b390 2632 return lxc_clear_idmaps(c);
72d0e1cb
SG
2633 return -1;
2634}
2635
2636/*
2637 * writing out a confile.
2638 */
2639void write_config(FILE *fout, struct lxc_conf *c)
2640{
6b0d5538
SH
2641 size_t len = c->unexpanded_len;
2642 int ret;
72d0e1cb 2643
6b0d5538
SH
2644 if (!len)
2645 return;
2646 ret = fwrite(c->unexpanded_config, 1, len, fout);
2647 if (ret != len)
2648 SYSERROR("Error writing configuration file");
2649}
f979ac15 2650
6b0d5538
SH
2651bool do_append_unexp_config_line(struct lxc_conf *conf, const char *key, const char *v)
2652{
2653 int ret;
2654 size_t len = strlen(key) + strlen(v) + 4;
2655 char *tmp = alloca(len);
4184c3e1 2656
6b0d5538
SH
2657 ret = snprintf(tmp, len, "%s = %s", key, v);
2658 if (ret < 0 || ret >= len)
2659 return false;
2660
2661 /* Save the line verbatim into unexpanded_conf */
2662 if (append_unexp_config_line(tmp, conf))
2663 return false;
2664
2665 return true;
2666}
2667
2668void clear_unexp_config_line(struct lxc_conf *conf, const char *key, bool rm_subkeys)
2669{
2670 char *lstart = conf->unexpanded_config, *lend;
2671
2672 if (!conf->unexpanded_config)
2673 return;
2674 while (*lstart) {
2675 lend = strchr(lstart, '\n');
2676 char v;
2677 if (!lend)
2678 lend = lstart + strlen(lstart);
2679 else
2680 lend++;
2681 if (strncmp(lstart, key, strlen(key)) != 0) {
2682 lstart = lend;
2683 continue;
5f62730e 2684 }
6b0d5538
SH
2685 if (!rm_subkeys) {
2686 v = lstart[strlen(key)];
2687 if (!isspace(v) && v != '=') {
2688 lstart = lend;
2689 continue;
2690 }
5f62730e 2691 }
6b0d5538
SH
2692 conf->unexpanded_len -= (lend - lstart);
2693 if (*lend == '\0') {
2694 *lstart = '\0';
2695 return;
fd986e08 2696 }
6b0d5538 2697 memmove(lstart, lend, strlen(lend)+1);
fd986e08 2698 }
6b0d5538
SH
2699}
2700
329b3625
CB
2701bool clone_update_unexp_ovl_paths(struct lxc_conf *conf, const char *oldpath,
2702 const char *newpath, const char *oldname,
2703 const char *newname, const char *ovldir)
2704{
2705 const char *key = "lxc.mount.entry";
2706 int ret;
2707 char *lstart = conf->unexpanded_config;
2708 char *lend;
2709 char *p;
2710 char *q;
2711 size_t newdirlen = strlen(ovldir) + strlen(newpath) + strlen(newname) + 2;
2712 size_t olddirlen = strlen(ovldir) + strlen(oldpath) + strlen(oldname) + 2;
2713 char *olddir = alloca(olddirlen + 1);
2714 char *newdir = alloca(newdirlen + 1);
2715
2716 ret = snprintf(olddir, olddirlen + 1, "%s=%s/%s", ovldir, oldpath, oldname);
2717 if (ret < 0 || ret >= olddirlen + 1) {
2718 ERROR("Bug in %s", __func__);
2719 return false;
2720 }
2721 ret = snprintf(newdir, newdirlen + 1, "%s=%s/%s", ovldir, newpath, newname);
2722 if (ret < 0 || ret >= newdirlen + 1) {
2723 ERROR("Bug in %s", __func__);
2724 return false;
2725 }
2726 if (!conf->unexpanded_config)
2727 return true;
2728 while (*lstart) {
2729 lend = strchr(lstart, '\n');
2730 if (!lend)
2731 lend = lstart + strlen(lstart);
2732 else
2733 lend++;
2734 if (strncmp(lstart, key, strlen(key)) != 0)
2735 goto next;
2736 p = strchr(lstart + strlen(key), '=');
2737 if (!p)
2738 goto next;
2739 p++;
2740 while (isblank(*p))
2741 p++;
2742 if (p >= lend)
2743 goto next;
2744 /* Whenever an lxc.mount.entry entry is found in a line we check
2745 * if the substring " overlay" or the substring " aufs" is
2746 * present before doing any further work. We check for "
2747 * overlay" and " aufs" since both substrings need to have at
2748 * least one space before them in a valid overlay
2749 * lxc.mount.entry (/A B overlay). When the space before is
2750 * missing it is very likely that these substrings are part of a
2751 * path or something else. (Checking q >= lend ensures that we
2752 * only count matches in the current line.) */
2753 if ((!(q = strstr(p, " overlay")) || q >= lend) && (!(q = strstr(p, " aufs")) || q >= lend))
2754 goto next;
2755 if (!(q = strstr(p, olddir)) || (q >= lend))
2756 goto next;
2757
2758 /* replace the olddir with newdir */
2759 if (olddirlen >= newdirlen) {
2760 size_t diff = olddirlen - newdirlen;
2761 memcpy(q, newdir, newdirlen);
2762 if (olddirlen != newdirlen) {
2763 memmove(q + newdirlen, q + newdirlen + diff,
2764 strlen(q) - newdirlen - diff + 1);
2765 lend -= diff;
2766 conf->unexpanded_len -= diff;
2767 }
2768 } else {
2769 char *new;
2770 size_t diff = newdirlen - olddirlen;
2771 size_t oldlen = conf->unexpanded_len;
2772 size_t newlen = oldlen + diff;
2773 size_t poffset = q - conf->unexpanded_config;
2774 new = realloc(conf->unexpanded_config, newlen + 1);
2775 if (!new) {
2776 ERROR("Out of memory");
2777 return false;
2778 }
2779 conf->unexpanded_len = newlen;
2780 conf->unexpanded_alloced = newlen + 1;
2781 new[newlen - 1] = '\0';
2782 lend = new + (lend - conf->unexpanded_config);
2783 /* move over the remainder to make room for the newdir */
2784 memmove(new + poffset + newdirlen,
2785 new + poffset + olddirlen,
2786 oldlen - poffset - olddirlen + 1);
2787 conf->unexpanded_config = new;
2788 memcpy(new + poffset, newdir, newdirlen);
2789 lend += diff;
2790 }
2791next:
2792 lstart = lend;
2793 }
2794 return true;
2795}
2796
67702c21 2797bool clone_update_unexp_hooks(struct lxc_conf *conf, const char *oldpath,
d546aa0e
CB
2798 const char *newpath, const char *oldname,
2799 const char *newname)
6b0d5538 2800{
67702c21
SH
2801 const char *key = "lxc.hook";
2802 int ret;
2803 char *lstart = conf->unexpanded_config, *lend, *p;
2804 size_t newdirlen = strlen(newpath) + strlen(newname) + 1;
2805 size_t olddirlen = strlen(oldpath) + strlen(oldname) + 1;
2806 char *olddir = alloca(olddirlen + 1);
2807 char *newdir = alloca(newdirlen + 1);
2808
d546aa0e
CB
2809 ret = snprintf(olddir, olddirlen + 1, "%s/%s", oldpath, oldname);
2810 if (ret < 0 || ret >= olddirlen + 1) {
67702c21
SH
2811 ERROR("Bug in %s", __func__);
2812 return false;
2813 }
d546aa0e
CB
2814 ret = snprintf(newdir, newdirlen + 1, "%s/%s", newpath, newname);
2815 if (ret < 0 || ret >= newdirlen + 1) {
67702c21
SH
2816 ERROR("Bug in %s", __func__);
2817 return false;
2818 }
2819 if (!conf->unexpanded_config)
2820 return true;
2821 while (*lstart) {
2822 lend = strchr(lstart, '\n');
2823 if (!lend)
2824 lend = lstart + strlen(lstart);
2825 else
2826 lend++;
d546aa0e
CB
2827 if (strncmp(lstart, key, strlen(key)) != 0)
2828 goto next;
2829 p = strchr(lstart + strlen(key), '=');
2830 if (!p)
2831 goto next;
67702c21
SH
2832 p++;
2833 while (isblank(*p))
2834 p++;
d546aa0e
CB
2835 if (p >= lend)
2836 goto next;
2837 if (strncmp(p, olddir, strlen(olddir)) != 0)
2838 goto next;
67702c21
SH
2839 /* replace the olddir with newdir */
2840 if (olddirlen >= newdirlen) {
2841 size_t diff = olddirlen - newdirlen;
2842 memcpy(p, newdir, newdirlen);
2843 if (olddirlen != newdirlen) {
d546aa0e
CB
2844 memmove(p + newdirlen, p + newdirlen + diff,
2845 strlen(p) - newdirlen - diff + 1);
67702c21
SH
2846 lend -= diff;
2847 conf->unexpanded_len -= diff;
2848 }
67702c21
SH
2849 } else {
2850 char *new;
2851 size_t diff = newdirlen - olddirlen;
2852 size_t oldlen = conf->unexpanded_len;
2853 size_t newlen = oldlen + diff;
2854 size_t poffset = p - conf->unexpanded_config;
d546aa0e 2855 new = realloc(conf->unexpanded_config, newlen + 1);
67702c21
SH
2856 if (!new) {
2857 ERROR("Out of memory");
6b0d5538 2858 return false;
67702c21
SH
2859 }
2860 conf->unexpanded_len = newlen;
d546aa0e
CB
2861 conf->unexpanded_alloced = newlen + 1;
2862 new[newlen - 1] = '\0';
67702c21 2863 lend = new + (lend - conf->unexpanded_config);
d546aa0e
CB
2864 /* move over the remainder to make room for the newdir */
2865 memmove(new + poffset + newdirlen,
2866 new + poffset + olddirlen,
2867 oldlen - poffset - olddirlen + 1);
67702c21 2868 conf->unexpanded_config = new;
d546aa0e
CB
2869 memcpy(new + poffset, newdir, newdirlen);
2870 lend += diff;
fd986e08 2871 }
d546aa0e
CB
2872next:
2873 lstart = lend;
fd986e08 2874 }
6b0d5538
SH
2875 return true;
2876}
2877
2878#define DO(cmd) { \
2879 if (!(cmd)) { \
2880 ERROR("Error writing to new config"); \
2881 return false; \
2882 } \
2883}
2884
67702c21
SH
2885static void new_hwaddr(char *hwaddr)
2886{
2887 FILE *f;
2888 f = fopen("/dev/urandom", "r");
2889 if (f) {
2890 unsigned int seed;
2891 int ret = fread(&seed, sizeof(seed), 1, f);
2892 if (ret != 1)
2893 seed = time(NULL);
2894 fclose(f);
2895 srand(seed);
2896 } else
2897 srand(time(NULL));
2898 snprintf(hwaddr, 18, "00:16:3e:%02x:%02x:%02x",
2899 rand() % 255, rand() % 255, rand() % 255);
2900}
2901
2902/*
2903 * This is called only from clone.
2904 * We wish to update all hwaddrs in the unexpanded config file. We
2905 * can't/don't want to update any which come from lxc.includes (there
2906 * shouldn't be any).
2907 * We can't just walk the c->lxc-conf->network list because that includes
2908 * netifs from the include files. So we update the ones which we find in
2909 * the unexp config file, then find the original macaddr in the
2910 * conf->network, and update that to the same value.
2911 */
2912bool network_new_hwaddrs(struct lxc_conf *conf)
6b0d5538
SH
2913{
2914 struct lxc_list *it;
2915
67702c21
SH
2916 const char *key = "lxc.network.hwaddr";
2917 char *lstart = conf->unexpanded_config, *lend, *p, *p2;
6b0d5538 2918
67702c21
SH
2919 if (!conf->unexpanded_config)
2920 return true;
2921 while (*lstart) {
2922 char newhwaddr[18], oldhwaddr[17];
2923 lend = strchr(lstart, '\n');
2924 if (!lend)
2925 lend = lstart + strlen(lstart);
2926 else
2927 lend++;
2928 if (strncmp(lstart, key, strlen(key)) != 0) {
2929 lstart = lend;
2930 continue;
72d0e1cb 2931 }
67702c21
SH
2932 p = strchr(lstart+strlen(key), '=');
2933 if (!p) {
2934 lstart = lend;
2935 continue;
72d0e1cb 2936 }
67702c21
SH
2937 p++;
2938 while (isblank(*p))
2939 p++;
2940 if (!*p)
2941 return true;
2942 p2 = p;
2943 while (*p2 && !isblank(*p2) && *p2 != '\n')
2944 p2++;
2945 if (p2-p != 17) {
2946 WARN("Bad hwaddr entry");
2947 lstart = lend;
2948 continue;
72d0e1cb 2949 }
67702c21
SH
2950 memcpy(oldhwaddr, p, 17);
2951 new_hwaddr(newhwaddr);
2952 memcpy(p, newhwaddr, 17);
2953 lxc_list_for_each(it, &conf->network) {
2954 struct lxc_netdev *n = it->elem;
2955 if (n->hwaddr && memcmp(oldhwaddr, n->hwaddr, 17) == 0)
2956 memcpy(n->hwaddr, newhwaddr, 17);
72d0e1cb 2957 }
67702c21
SH
2958
2959 lstart = lend;
72d0e1cb 2960 }
6b0d5538 2961 return true;
72d0e1cb 2962}
8796becf
CB
2963
2964static int config_ephemeral(const char *key, const char *value,
2965 struct lxc_conf *lxc_conf)
2966{
66ffdb1a
CB
2967 if (lxc_safe_uint(value, &lxc_conf->ephemeral) < 0)
2968 return -1;
8796becf 2969
66ffdb1a 2970 if (lxc_conf->ephemeral > 1) {
8796becf
CB
2971 ERROR("Wrong value for lxc.ephemeral. Can only be set to 0 or 1");
2972 return -1;
8796becf
CB
2973 }
2974
2975 return 0;
2976}
2977
64c57ea1 2978static int config_syslog(const char *key, const char *value,
76d0127f 2979 struct lxc_conf *lxc_conf)
64c57ea1 2980{
76d0127f
CB
2981 int facility;
2982 facility = lxc_syslog_priority_to_int(value);
2983 if (facility == -EINVAL) {
2984 ERROR("Wrong value for lxc.syslog");
2985 return -1;
64c57ea1
BD
2986 }
2987
76d0127f
CB
2988 lxc_log_syslog(facility);
2989 return config_string_item(&lxc_conf->syslog, value);
64c57ea1 2990}
5a46f283
CB
2991
2992static int config_no_new_privs(const char *key, const char *value,
2993 struct lxc_conf *lxc_conf)
2994{
2995 int v = atoi(value);
2996
2997 if (v != 0 && v != 1) {
2998 ERROR("Wrong value for lxc.no_new_privs. Can only be set to 0 or 1");
2999 return -1;
3000 }
3001 lxc_conf->no_new_privs = v ? true : false;
3002
3003 return 0;
3004}