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