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