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