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