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