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