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