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