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