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