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