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