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