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