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