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