]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/confile.c
Merge pull request #1639 from brauner/2017-06-23/lxc_2_1_preparations
[mirror_lxc.git] / src / lxc / confile.c
CommitLineData
c2cc9f0a 1/*
2 * lxc: linux Container library
c2cc9f0a 3 * (C) Copyright IBM Corp. 2007, 2008
4 *
5 * Authors:
9afe19d6 6 * Daniel Lezcano <daniel.lezcano at free.fr>
c2cc9f0a 7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
250b1eec 20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
c2cc9f0a 21 */
12a50cc6 22#define _GNU_SOURCE
2e6e3feb 23#define __STDC_FORMAT_MACROS /* Required for PRIu64 to work. */
c2cc9f0a 24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27#include <unistd.h>
28#include <errno.h>
63376d7d 29#include <fcntl.h>
a84b9932 30#include <ctype.h>
2e6e3feb 31#include <inttypes.h> /* Required for PRIu64 to work. */
a84b9932 32#include <signal.h>
63376d7d 33#include <sys/stat.h>
c2cc9f0a 34#include <sys/types.h>
35#include <sys/param.h>
36#include <sys/utsname.h>
37#include <arpa/inet.h>
38#include <netinet/in.h>
39#include <net/if.h>
67702c21 40#include <time.h>
e1daebd9 41#include <dirent.h>
64c57ea1 42#include <syslog.h>
c2cc9f0a 43
d8e48992 44#include "bdev.h"
b2718c72 45#include "parse.h"
6ff05e18 46#include "config.h"
525f0002 47#include "confile.h"
953fe44f 48#include "confile_legacy.h"
0b843d35 49#include "confile_utils.h"
26c39028 50#include "utils.h"
f2363e38
ÇO
51#include "log.h"
52#include "conf.h"
72d0e1cb 53#include "network.h"
58e0f57d 54#include "lxcseccomp.h"
36eb9bde 55
576400e5 56#if HAVE_IFADDRS_H
57#include <ifaddrs.h>
58#else
59#include <../include/ifaddrs.h>
60#endif
61
6ff05e18
SG
62#if HAVE_SYS_PERSONALITY_H
63#include <sys/personality.h>
64#endif
65
36eb9bde 66lxc_log_define(lxc_confile, lxc);
576f946d 67
c7e27aaf
CB
68static int set_config_personality(const char *, const char *, struct lxc_conf *,
69 void *);
cccd2219
CB
70static int get_config_personality(const char *, char *, int, struct lxc_conf *,
71 void *);
26471403 72static int clr_config_personality(const char *, struct lxc_conf *, void *);
bdf91ab4 73
c7e27aaf
CB
74static int set_config_pts(const char *, const char *, struct lxc_conf *,
75 void *);
cccd2219 76static int get_config_pts(const char *, char *, int, struct lxc_conf *, void *);
26471403 77static int clr_config_pts(const char *, struct lxc_conf *, void *);
bdf91ab4 78
c7e27aaf
CB
79static int set_config_tty(const char *, const char *, struct lxc_conf *,
80 void *);
cccd2219 81static int get_config_tty(const char *, char *, int, struct lxc_conf *, void *);
26471403 82static int clr_config_tty(const char *, struct lxc_conf *, void *);
5485782f 83
c7e27aaf
CB
84static int set_config_ttydir(const char *, const char *, struct lxc_conf *,
85 void *);
cccd2219
CB
86static int get_config_ttydir(const char *, char *, int, struct lxc_conf *,
87 void *);
26471403 88static int clr_config_ttydir(const char *, struct lxc_conf *, void *);
8015e018 89
953fe44f
CB
90static int set_config_apparmor_profile(const char *, const char *,
91 struct lxc_conf *, void *);
92static int get_config_apparmor_profile(const char *, char *, int,
93 struct lxc_conf *, void *);
94static int clr_config_apparmor_profile(const char *, struct lxc_conf *, void *);
104c8e6c 95
953fe44f
CB
96static int set_config_apparmor_allow_incomplete(const char *, const char *,
97 struct lxc_conf *, void *);
98static int get_config_apparmor_allow_incomplete(const char *, char *, int,
99 struct lxc_conf *, void *);
100static int clr_config_apparmor_allow_incomplete(const char *, struct lxc_conf *,
101 void *);
d60d18c6 102
953fe44f
CB
103static int set_config_selinux_context(const char *, const char *,
104 struct lxc_conf *, void *);
105static int get_config_selinux_context(const char *, char *, int,
106 struct lxc_conf *, void *);
107static int clr_config_selinux_context(const char *, struct lxc_conf *, void *);
4203a0b5 108
c7e27aaf
CB
109static int set_config_cgroup(const char *, const char *, struct lxc_conf *,
110 void *);
cccd2219
CB
111static int get_config_cgroup(const char *, char *, int, struct lxc_conf *,
112 void *);
26471403 113static int clr_config_cgroup(const char *, struct lxc_conf *, void *);
b863bf92 114
c7e27aaf
CB
115static int set_config_idmaps(const char *, const char *, struct lxc_conf *,
116 void *);
cccd2219
CB
117static int get_config_idmaps(const char *, char *, int, struct lxc_conf *,
118 void *);
26471403 119static int clr_config_idmaps(const char *, struct lxc_conf *, void *);
5014ff2e 120
c7e27aaf
CB
121static int set_config_loglevel(const char *, const char *, struct lxc_conf *,
122 void *);
cccd2219
CB
123static int get_config_loglevel(const char *, char *, int, struct lxc_conf *,
124 void *);
26471403 125static int clr_config_loglevel(const char *, struct lxc_conf *, void *);
b29b29be 126
c7e27aaf
CB
127static int set_config_logfile(const char *, const char *, struct lxc_conf *,
128 void *);
cccd2219
CB
129static int get_config_logfile(const char *, char *, int, struct lxc_conf *,
130 void *);
26471403 131static int clr_config_logfile(const char *, struct lxc_conf *, void *);
3d4630ab 132
c7e27aaf
CB
133static int set_config_mount(const char *, const char *, struct lxc_conf *,
134 void *);
cccd2219
CB
135static int get_config_mount(const char *, char *, int, struct lxc_conf *,
136 void *);
26471403 137static int clr_config_mount(const char *, struct lxc_conf *, void *);
0d601acb 138
c7e27aaf
CB
139static int set_config_mount_auto(const char *, const char *, struct lxc_conf *,
140 void *);
cccd2219
CB
141static int get_config_mount_auto(const char *, char *, int, struct lxc_conf *,
142 void *);
26471403 143static int clr_config_mount_auto(const char *, struct lxc_conf *, void *);
0d601acb 144
c7e27aaf
CB
145static int set_config_fstab(const char *, const char *, struct lxc_conf *,
146 void *);
cccd2219
CB
147static int get_config_fstab(const char *, char *, int, struct lxc_conf *,
148 void *);
26471403 149static int clr_config_fstab(const char *, struct lxc_conf *, void *);
0d601acb 150
c7e27aaf
CB
151static int set_config_rootfs_mount(const char *, const char *,
152 struct lxc_conf *, void *);
cccd2219
CB
153static int get_config_rootfs_mount(const char *, char *, int, struct lxc_conf *,
154 void *);
26471403 155static int clr_config_rootfs_mount(const char *, struct lxc_conf *, void *);
3af60359 156
c7e27aaf
CB
157static int set_config_rootfs_options(const char *, const char *,
158 struct lxc_conf *, void *);
159static int get_config_rootfs_options(const char *, char *, int,
cccd2219 160 struct lxc_conf *, void *);
26471403 161static int clr_config_rootfs_options(const char *, struct lxc_conf *, void *);
0e9db631 162
c7e27aaf
CB
163static int set_config_rootfs_backend(const char *, const char *,
164 struct lxc_conf *, void *);
165static int get_config_rootfs_backend(const char *, char *, int,
cccd2219 166 struct lxc_conf *, void *);
26471403 167static int clr_config_rootfs_backend(const char *, struct lxc_conf *, void *);
8f183f38 168
c7e27aaf
CB
169static int set_config_rootfs(const char *, const char *, struct lxc_conf *,
170 void *);
cccd2219
CB
171static int get_config_rootfs(const char *, char *, int, struct lxc_conf *,
172 void *);
26471403 173static int clr_config_rootfs(const char *, struct lxc_conf *, void *);
faca124d 174
c7e27aaf
CB
175static int set_config_utsname(const char *, const char *, struct lxc_conf *,
176 void *);
cccd2219
CB
177static int get_config_utsname(const char *, char *, int, struct lxc_conf *,
178 void *);
26471403 179static int clr_config_utsname(const char *, struct lxc_conf *, void *);
e274f8b0 180
c7e27aaf
CB
181static int set_config_hooks(const char *, const char *, struct lxc_conf *,
182 void *);
cccd2219
CB
183static int get_config_hooks(const char *, char *, int, struct lxc_conf *,
184 void *);
26471403 185static int clr_config_hooks(const char *, struct lxc_conf *, void *);
466c2e93 186
f9373e40
CB
187static int set_config_net_type(const char *, const char *, struct lxc_conf *,
188 void *);
189static int get_config_net_type(const char *, char *, int, struct lxc_conf *,
190 void *);
191static int clr_config_net_type(const char *, struct lxc_conf *, void *);
ff6da295 192
f9373e40
CB
193static int set_config_net_flags(const char *, const char *, struct lxc_conf *,
194 void *);
195static int get_config_net_flags(const char *, char *, int, struct lxc_conf *,
196 void *);
197static int clr_config_net_flags(const char *, struct lxc_conf *, void *);
ff6da295 198
f9373e40
CB
199static int set_config_net_link(const char *, const char *, struct lxc_conf *,
200 void *);
201static int get_config_net_link(const char *, char *, int, struct lxc_conf *,
202 void *);
203static int clr_config_net_link(const char *, struct lxc_conf *, void *);
ff6da295 204
f9373e40
CB
205static int set_config_net_name(const char *, const char *, struct lxc_conf *,
206 void *);
207static int get_config_net_name(const char *, char *, int, struct lxc_conf *,
208 void *);
209static int clr_config_net_name(const char *, struct lxc_conf *, void *);
ff6da295 210
f9373e40
CB
211static int set_config_net_veth_pair(const char *, const char *,
212 struct lxc_conf *, void *);
213static int get_config_net_veth_pair(const char *, char *, int,
214 struct lxc_conf *, void *);
215static int clr_config_net_veth_pair(const char *, struct lxc_conf *, void *);
ff6da295 216
f9373e40
CB
217static int set_config_net_macvlan_mode(const char *, const char *,
218 struct lxc_conf *, void *);
219static int get_config_net_macvlan_mode(const char *, char *, int,
220 struct lxc_conf *, void *);
221static int clr_config_net_macvlan_mode(const char *, struct lxc_conf *, void *);
ff6da295 222
f9373e40
CB
223static int set_config_net_hwaddr(const char *, const char *, struct lxc_conf *,
224 void *);
225static int get_config_net_hwaddr(const char *, char *, int, struct lxc_conf *,
226 void *);
227static int clr_config_net_hwaddr(const char *, struct lxc_conf *, void *);
ff6da295 228
f9373e40 229static int set_config_net_vlan_id(const char *, const char *, struct lxc_conf *,
c7e27aaf 230 void *);
f9373e40 231static int get_config_net_vlan_id(const char *, char *, int, struct lxc_conf *,
9d4bf22d 232 void *);
f9373e40 233static int clr_config_net_vlan_id(const char *, struct lxc_conf *, void *);
ff6da295 234
f9373e40
CB
235static int set_config_net_mtu(const char *, const char *, struct lxc_conf *,
236 void *);
237static int get_config_net_mtu(const char *, char *, int, struct lxc_conf *,
238 void *);
239static int clr_config_net_mtu(const char *, struct lxc_conf *, void *);
ff6da295 240
f9373e40
CB
241static int set_config_net_ipv4(const char *, const char *, struct lxc_conf *,
242 void *);
243static int get_config_net_ipv4(const char *, char *, int, struct lxc_conf *,
244 void *);
245static int clr_config_net_ipv4(const char *, struct lxc_conf *, void *);
ff6da295 246
f9373e40
CB
247static int set_config_net_ipv4_gateway(const char *, const char *,
248 struct lxc_conf *, void *);
249static int get_config_net_ipv4_gateway(const char *, char *, int,
250 struct lxc_conf *, void *);
251static int clr_config_net_ipv4_gateway(const char *, struct lxc_conf *, void *);
ff6da295 252
f9373e40
CB
253static int set_config_net_script_up(const char *, const char *,
254 struct lxc_conf *, void *);
255static int get_config_net_script_up(const char *, char *, int,
256 struct lxc_conf *, void *);
257static int clr_config_net_script_up(const char *, struct lxc_conf *, void *);
ff6da295 258
f9373e40
CB
259static int set_config_net_script_down(const char *, const char *,
260 struct lxc_conf *, void *);
261static int get_config_net_script_down(const char *, char *, int,
262 struct lxc_conf *, void *);
263static int clr_config_net_script_down(const char *, struct lxc_conf *, void *);
ff6da295 264
f9373e40
CB
265static int set_config_net_ipv6(const char *, const char *, struct lxc_conf *,
266 void *);
267static int get_config_net_ipv6(const char *, char *, int, struct lxc_conf *,
268 void *);
269static int clr_config_net_ipv6(const char *, struct lxc_conf *, void *);
ff6da295 270
f9373e40
CB
271static int set_config_net_ipv6_gateway(const char *, const char *,
272 struct lxc_conf *, void *);
273static int get_config_net_ipv6_gateway(const char *, char *, int,
274 struct lxc_conf *, void *);
275static int clr_config_net_ipv6_gateway(const char *, struct lxc_conf *, void *);
e2410c4e 276
f9373e40 277static int set_config_net_nic(const char *, const char *, struct lxc_conf *,
c7e27aaf 278 void *);
f9373e40 279static int get_config_net_nic(const char *, char *, int, struct lxc_conf *,
cccd2219 280 void *);
f9373e40
CB
281static int clr_config_net_nic(const char *, struct lxc_conf *, void *);
282
283static int set_config_net(const char *, const char *, struct lxc_conf *,
284 void *);
285static int get_config_net(const char *, char *, int, struct lxc_conf *, void *);
286static int clr_config_net(const char *, struct lxc_conf *, void *);
bdccff60 287
c7e27aaf
CB
288static int set_config_cap_drop(const char *, const char *, struct lxc_conf *,
289 void *);
cccd2219
CB
290static int get_config_cap_drop(const char *, char *, int, struct lxc_conf *,
291 void *);
26471403 292static int clr_config_cap_drop(const char *, struct lxc_conf *, void *);
1c96d6d8 293
c7e27aaf
CB
294static int set_config_cap_keep(const char *, const char *, struct lxc_conf *,
295 void *);
cccd2219
CB
296static int get_config_cap_keep(const char *, char *, int, struct lxc_conf *,
297 void *);
26471403 298static int clr_config_cap_keep(const char *, struct lxc_conf *, void *);
b80927f2 299
c7e27aaf
CB
300static int set_config_console_logfile(const char *, const char *,
301 struct lxc_conf *, void *);
302static int get_config_console_logfile(const char *, char *, int,
cccd2219 303 struct lxc_conf *, void *);
26471403 304static int clr_config_console_logfile(const char *, struct lxc_conf *, void *);
794d1c06 305
c7e27aaf
CB
306static int set_config_console(const char *, const char *, struct lxc_conf *,
307 void *);
cccd2219
CB
308static int get_config_console(const char *, char *, int, struct lxc_conf *,
309 void *);
26471403 310static int clr_config_console(const char *, struct lxc_conf *, void *);
4e5b633f 311
c7e27aaf
CB
312static int set_config_seccomp(const char *, const char *, struct lxc_conf *,
313 void *);
cccd2219
CB
314static int get_config_seccomp(const char *, char *, int, struct lxc_conf *,
315 void *);
26471403 316static int clr_config_seccomp(const char *, struct lxc_conf *, void *);
75f55b1f 317
c7e27aaf
CB
318static int set_config_includefiles(const char *, const char *,
319 struct lxc_conf *, void *);
320static int get_config_includefiles(const char *, char *, int,
cccd2219 321 struct lxc_conf *, void *);
26471403 322static int clr_config_includefiles(const char *, struct lxc_conf *, void *);
97f6dad0 323
c7e27aaf
CB
324static int set_config_autodev(const char *, const char *, struct lxc_conf *,
325 void *);
cccd2219
CB
326static int get_config_autodev(const char *, char *, int, struct lxc_conf *,
327 void *);
26471403 328static int clr_config_autodev(const char *, struct lxc_conf *, void *);
97f6dad0 329
c7e27aaf
CB
330static int set_config_haltsignal(const char *, const char *, struct lxc_conf *,
331 void *);
cccd2219
CB
332static int get_config_haltsignal(const char *, char *, int, struct lxc_conf *,
333 void *);
26471403 334static int clr_config_haltsignal(const char *, struct lxc_conf *, void *);
afee4324 335
c7e27aaf
CB
336static int set_config_rebootsignal(const char *, const char *,
337 struct lxc_conf *, void *);
338static int get_config_rebootsignal(const char *, char *, int,
cccd2219 339 struct lxc_conf *, void *);
26471403 340static int clr_config_rebootsignal(const char *, struct lxc_conf *, void *);
3aa8f359 341
c7e27aaf
CB
342static int set_config_stopsignal(const char *, const char *, struct lxc_conf *,
343 void *);
cccd2219
CB
344static int get_config_stopsignal(const char *, char *, int, struct lxc_conf *,
345 void *);
26471403 346static int clr_config_stopsignal(const char *, struct lxc_conf *, void *);
2e16269f 347
c7e27aaf
CB
348static int set_config_start(const char *, const char *, struct lxc_conf *,
349 void *);
cccd2219
CB
350static int get_config_start(const char *, char *, int, struct lxc_conf *,
351 void *);
26471403 352static int clr_config_start(const char *, struct lxc_conf *, void *);
54345299 353
c7e27aaf
CB
354static int set_config_monitor(const char *, const char *, struct lxc_conf *,
355 void *);
cccd2219
CB
356static int get_config_monitor(const char *, char *, int, struct lxc_conf *,
357 void *);
26471403 358static int clr_config_monitor(const char *, struct lxc_conf *, void *);
ac0f949c 359
c7e27aaf
CB
360static int set_config_group(const char *, const char *, struct lxc_conf *,
361 void *);
cccd2219
CB
362static int get_config_group(const char *, char *, int, struct lxc_conf *,
363 void *);
26471403 364static int clr_config_group(const char *, struct lxc_conf *, void *);
90ec7b6e 365
c7e27aaf
CB
366static int set_config_environment(const char *, const char *, struct lxc_conf *,
367 void *);
cccd2219
CB
368static int get_config_environment(const char *, char *, int, struct lxc_conf *,
369 void *);
26471403 370static int clr_config_environment(const char *, struct lxc_conf *, void *);
aa0db7d3 371
c7e27aaf
CB
372static int set_config_init_cmd(const char *, const char *, struct lxc_conf *,
373 void *);
cccd2219
CB
374static int get_config_init_cmd(const char *, char *, int, struct lxc_conf *,
375 void *);
26471403 376static int clr_config_init_cmd(const char *, struct lxc_conf *, void *);
96dfcb7d 377
c7e27aaf
CB
378static int set_config_init_uid(const char *, const char *, struct lxc_conf *,
379 void *);
cccd2219
CB
380static int get_config_init_uid(const char *, char *, int, struct lxc_conf *,
381 void *);
26471403 382static int clr_config_init_uid(const char *, struct lxc_conf *, void *);
1398e9b1 383
c7e27aaf
CB
384static int set_config_init_gid(const char *, const char *, struct lxc_conf *,
385 void *);
cccd2219
CB
386static int get_config_init_gid(const char *, char *, int, struct lxc_conf *,
387 void *);
26471403 388static int clr_config_init_gid(const char *, struct lxc_conf *, void *);
dfeb7e42 389
c7e27aaf
CB
390static int set_config_ephemeral(const char *, const char *, struct lxc_conf *,
391 void *);
cccd2219
CB
392static int get_config_ephemeral(const char *, char *, int, struct lxc_conf *,
393 void *);
26471403 394static int clr_config_ephemeral(const char *, struct lxc_conf *, void *);
62048afe 395
c7e27aaf
CB
396static int set_config_syslog(const char *, const char *, struct lxc_conf *,
397 void *);
cccd2219
CB
398static int get_config_syslog(const char *, char *, int, struct lxc_conf *,
399 void *);
26471403 400static int clr_config_syslog(const char *, struct lxc_conf *, void *);
998ca94f 401
c7e27aaf
CB
402static int set_config_no_new_privs(const char *, const char *,
403 struct lxc_conf *, void *);
404static int get_config_no_new_privs(const char *, char *, int,
cccd2219 405 struct lxc_conf *, void *);
26471403 406static int clr_config_no_new_privs(const char *, struct lxc_conf *, void *);
b09521ac 407
c7e27aaf
CB
408static int set_config_limit(const char *, const char *, struct lxc_conf *,
409 void *);
cccd2219
CB
410static int get_config_limit(const char *, char *, int, struct lxc_conf *,
411 void *);
26471403 412static int clr_config_limit(const char *, struct lxc_conf *, void *);
c2cc9f0a 413
72d0e1cb 414static struct lxc_config_t config[] = {
953fe44f
CB
415 { "lxc.arch", set_config_personality, get_config_personality, clr_config_personality, },
416 { "lxc.pts", set_config_pts, get_config_pts, clr_config_pts, },
417 { "lxc.tty", set_config_tty, get_config_tty, clr_config_tty, },
418 { "lxc.devttydir", set_config_ttydir, get_config_ttydir, clr_config_ttydir, },
953fe44f
CB
419 { "lxc.apparmor.profile", set_config_apparmor_profile, get_config_apparmor_profile, clr_config_apparmor_profile, },
420 { "lxc.apparmor.allow_incomplete", set_config_apparmor_allow_incomplete, get_config_apparmor_allow_incomplete, clr_config_apparmor_allow_incomplete, },
421 { "lxc.selinux.context", set_config_selinux_context, get_config_selinux_context, clr_config_selinux_context, },
422
423 /* REMOVE IN LXC 3.0
424 legacy security keys
425 */
426 { "lxc.aa_profile", set_config_lsm_aa_profile, get_config_lsm_aa_profile, clr_config_lsm_aa_profile, },
427 { "lxc.aa_allow_incomplete", set_config_lsm_aa_incomplete, get_config_lsm_aa_incomplete, clr_config_lsm_aa_incomplete, },
428 { "lxc.se_context", set_config_lsm_se_context, get_config_lsm_se_context, clr_config_lsm_se_context, },
429
430 { "lxc.cgroup", set_config_cgroup, get_config_cgroup, clr_config_cgroup, },
431 { "lxc.id_map", set_config_idmaps, get_config_idmaps, clr_config_idmaps, },
432 { "lxc.loglevel", set_config_loglevel, get_config_loglevel, clr_config_loglevel, },
433 { "lxc.logfile", set_config_logfile, get_config_logfile, clr_config_logfile, },
434 { "lxc.mount.entry", set_config_mount, get_config_mount, clr_config_mount, },
435 { "lxc.mount.auto", set_config_mount_auto, get_config_mount_auto, clr_config_mount_auto, },
436 { "lxc.mount", set_config_fstab, get_config_fstab, clr_config_fstab, },
437 { "lxc.rootfs.mount", set_config_rootfs_mount, get_config_rootfs_mount, clr_config_rootfs_mount, },
438 { "lxc.rootfs.options", set_config_rootfs_options, get_config_rootfs_options, clr_config_rootfs_options, },
439 { "lxc.rootfs.backend", set_config_rootfs_backend, get_config_rootfs_backend, clr_config_rootfs_backend, },
440 { "lxc.rootfs", set_config_rootfs, get_config_rootfs, clr_config_rootfs, },
953fe44f
CB
441 { "lxc.utsname", set_config_utsname, get_config_utsname, clr_config_utsname, },
442 { "lxc.hook.pre-start", set_config_hooks, get_config_hooks, clr_config_hooks, },
443 { "lxc.hook.pre-mount", set_config_hooks, get_config_hooks, clr_config_hooks, },
444 { "lxc.hook.mount", set_config_hooks, get_config_hooks, clr_config_hooks, },
445 { "lxc.hook.autodev", set_config_hooks, get_config_hooks, clr_config_hooks, },
446 { "lxc.hook.start", set_config_hooks, get_config_hooks, clr_config_hooks, },
447 { "lxc.hook.stop", set_config_hooks, get_config_hooks, clr_config_hooks, },
448 { "lxc.hook.post-stop", set_config_hooks, get_config_hooks, clr_config_hooks, },
449 { "lxc.hook.clone", set_config_hooks, get_config_hooks, clr_config_hooks, },
450 { "lxc.hook.destroy", set_config_hooks, get_config_hooks, clr_config_hooks, },
451 { "lxc.hook", set_config_hooks, get_config_hooks, clr_config_hooks, },
452
453 /* REMOVE IN LXC 3.0
454 legacy security keys
455 */
456 { "lxc.network.type", set_config_network_legacy_type, get_config_network_legacy_item, clr_config_network_legacy_item, },
457 { "lxc.network.flags", set_config_network_legacy_flags, get_config_network_legacy_item, clr_config_network_legacy_item, },
458 { "lxc.network.link", set_config_network_legacy_link, get_config_network_legacy_item, clr_config_network_legacy_item, },
459 { "lxc.network.name", set_config_network_legacy_name, get_config_network_legacy_item, clr_config_network_legacy_item, },
460 { "lxc.network.macvlan.mode", set_config_network_legacy_macvlan_mode, get_config_network_legacy_item, clr_config_network_legacy_item, },
461 { "lxc.network.veth.pair", set_config_network_legacy_veth_pair, get_config_network_legacy_item, clr_config_network_legacy_item, },
462 { "lxc.network.script.up", set_config_network_legacy_script_up, get_config_network_legacy_item, clr_config_network_legacy_item, },
463 { "lxc.network.script.down", set_config_network_legacy_script_down, get_config_network_legacy_item, clr_config_network_legacy_item, },
464 { "lxc.network.hwaddr", set_config_network_legacy_hwaddr, get_config_network_legacy_item, clr_config_network_legacy_item, },
465 { "lxc.network.mtu", set_config_network_legacy_mtu, get_config_network_legacy_item, clr_config_network_legacy_item, },
466 { "lxc.network.vlan.id", set_config_network_legacy_vlan_id, get_config_network_legacy_item, clr_config_network_legacy_item, },
467 { "lxc.network.ipv4.gateway", set_config_network_legacy_ipv4_gateway, get_config_network_legacy_item, clr_config_network_legacy_item, },
468 { "lxc.network.ipv4", set_config_network_legacy_ipv4, get_config_network_legacy_item, clr_config_network_legacy_item, },
469 { "lxc.network.ipv6.gateway", set_config_network_legacy_ipv6_gateway, get_config_network_legacy_item, clr_config_network_legacy_item, },
470 { "lxc.network.ipv6", set_config_network_legacy_ipv6, get_config_network_legacy_item, clr_config_network_legacy_item, },
471 { "lxc.network.", set_config_network_legacy_nic, get_config_network_legacy_item, clr_config_network_legacy_item, },
472 { "lxc.network", set_config_network_legacy, get_config_network_legacy, clr_config_network_legacy, },
473
474 { "lxc.net.type", set_config_net_type, get_config_net_type, clr_config_net_type, },
475 { "lxc.net.flags", set_config_net_flags, get_config_net_flags, clr_config_net_flags, },
476 { "lxc.net.link", set_config_net_link, get_config_net_link, clr_config_net_link, },
477 { "lxc.net.name", set_config_net_name, get_config_net_name, clr_config_net_name, },
478 { "lxc.net.macvlan.mode", set_config_net_macvlan_mode, get_config_net_macvlan_mode, clr_config_net_macvlan_mode, },
479 { "lxc.net.veth.pair", set_config_net_veth_pair, get_config_net_veth_pair, clr_config_net_veth_pair, },
480 { "lxc.net.script.up", set_config_net_script_up, get_config_net_script_up, clr_config_net_script_up, },
481 { "lxc.net.script.down", set_config_net_script_down, get_config_net_script_down, clr_config_net_script_down, },
482 { "lxc.net.hwaddr", set_config_net_hwaddr, get_config_net_hwaddr, clr_config_net_hwaddr, },
483 { "lxc.net.mtu", set_config_net_mtu, get_config_net_mtu, clr_config_net_mtu, },
484 { "lxc.net.vlan.id", set_config_net_vlan_id, get_config_net_vlan_id, clr_config_net_vlan_id, },
485 { "lxc.net.ipv4.gateway", set_config_net_ipv4_gateway, get_config_net_ipv4_gateway, clr_config_net_ipv4_gateway, },
486 { "lxc.net.ipv4", set_config_net_ipv4, get_config_net_ipv4, clr_config_net_ipv4, },
487 { "lxc.net.ipv6.gateway", set_config_net_ipv6_gateway, get_config_net_ipv6_gateway, clr_config_net_ipv6_gateway, },
488 { "lxc.net.ipv6", set_config_net_ipv6, get_config_net_ipv6, clr_config_net_ipv6, },
489 { "lxc.net.", set_config_net_nic, get_config_net_nic, clr_config_net_nic, },
490 { "lxc.net", set_config_net, get_config_net, clr_config_net, },
491 { "lxc.cap.drop", set_config_cap_drop, get_config_cap_drop, clr_config_cap_drop, },
492 { "lxc.cap.keep", set_config_cap_keep, get_config_cap_keep, clr_config_cap_keep, },
493 { "lxc.console.logfile", set_config_console_logfile, get_config_console_logfile, clr_config_console_logfile, },
494 { "lxc.console", set_config_console, get_config_console, clr_config_console, },
495 { "lxc.seccomp", set_config_seccomp, get_config_seccomp, clr_config_seccomp, },
496 { "lxc.include", set_config_includefiles, get_config_includefiles, clr_config_includefiles, },
497 { "lxc.autodev", set_config_autodev, get_config_autodev, clr_config_autodev, },
498 { "lxc.haltsignal", set_config_haltsignal, get_config_haltsignal, clr_config_haltsignal, },
499 { "lxc.rebootsignal", set_config_rebootsignal, get_config_rebootsignal, clr_config_rebootsignal, },
500 { "lxc.stopsignal", set_config_stopsignal, get_config_stopsignal, clr_config_stopsignal, },
501 { "lxc.start.auto", set_config_start, get_config_start, clr_config_start, },
502 { "lxc.start.delay", set_config_start, get_config_start, clr_config_start, },
503 { "lxc.start.order", set_config_start, get_config_start, clr_config_start, },
504 { "lxc.monitor.unshare", set_config_monitor, get_config_monitor, clr_config_monitor, },
505 { "lxc.group", set_config_group, get_config_group, clr_config_group, },
506 { "lxc.environment", set_config_environment, get_config_environment, clr_config_environment, },
507 { "lxc.init_cmd", set_config_init_cmd, get_config_init_cmd, clr_config_init_cmd, },
508 { "lxc.init_uid", set_config_init_uid, get_config_init_uid, clr_config_init_uid, },
509 { "lxc.init_gid", set_config_init_gid, get_config_init_gid, clr_config_init_gid, },
510 { "lxc.ephemeral", set_config_ephemeral, get_config_ephemeral, clr_config_ephemeral, },
511 { "lxc.syslog", set_config_syslog, get_config_syslog, clr_config_syslog, },
512 { "lxc.no_new_privs", set_config_no_new_privs, get_config_no_new_privs, clr_config_no_new_privs, },
513 { "lxc.limit", set_config_limit, get_config_limit, clr_config_limit, },
a84b9932
AV
514};
515
516struct signame {
517 int num;
74a3920a 518 const char *name;
a84b9932
AV
519};
520
74a3920a 521static const struct signame signames[] = {
504a2217
CB
522 { SIGHUP, "HUP" },
523 { SIGINT, "INT" },
524 { SIGQUIT, "QUIT" },
525 { SIGILL, "ILL" },
526 { SIGABRT, "ABRT" },
527 { SIGFPE, "FPE" },
528 { SIGKILL, "KILL" },
529 { SIGSEGV, "SEGV" },
530 { SIGPIPE, "PIPE" },
531 { SIGALRM, "ALRM" },
532 { SIGTERM, "TERM" },
533 { SIGUSR1, "USR1" },
534 { SIGUSR2, "USR2" },
535 { SIGCHLD, "CHLD" },
536 { SIGCONT, "CONT" },
537 { SIGSTOP, "STOP" },
538 { SIGTSTP, "TSTP" },
539 { SIGTTIN, "TTIN" },
540 { SIGTTOU, "TTOU" },
89dfc302 541#ifdef SIGTRAP
504a2217 542 { SIGTRAP, "TRAP" },
89dfc302
SY
543#endif
544#ifdef SIGIOT
504a2217 545 { SIGIOT, "IOT" },
89dfc302
SY
546#endif
547#ifdef SIGEMT
504a2217 548 { SIGEMT, "EMT" },
89dfc302
SY
549#endif
550#ifdef SIGBUS
504a2217 551 { SIGBUS, "BUS" },
89dfc302
SY
552#endif
553#ifdef SIGSTKFLT
554 { SIGSTKFLT, "STKFLT" },
555#endif
556#ifdef SIGCLD
504a2217 557 { SIGCLD, "CLD" },
89dfc302
SY
558#endif
559#ifdef SIGURG
504a2217 560 { SIGURG, "URG" },
89dfc302
SY
561#endif
562#ifdef SIGXCPU
504a2217 563 { SIGXCPU, "XCPU" },
89dfc302
SY
564#endif
565#ifdef SIGXFSZ
504a2217 566 { SIGXFSZ, "XFSZ" },
89dfc302
SY
567#endif
568#ifdef SIGVTALRM
569 { SIGVTALRM, "VTALRM" },
570#endif
571#ifdef SIGPROF
504a2217 572 { SIGPROF, "PROF" },
89dfc302
SY
573#endif
574#ifdef SIGWINCH
504a2217 575 { SIGWINCH, "WINCH" },
89dfc302
SY
576#endif
577#ifdef SIGIO
504a2217 578 { SIGIO, "IO" },
89dfc302
SY
579#endif
580#ifdef SIGPOLL
504a2217 581 { SIGPOLL, "POLL" },
89dfc302
SY
582#endif
583#ifdef SIGINFO
504a2217 584 { SIGINFO, "INFO" },
89dfc302
SY
585#endif
586#ifdef SIGLOST
504a2217 587 { SIGLOST, "LOST" },
89dfc302
SY
588#endif
589#ifdef SIGPWR
504a2217 590 { SIGPWR, "PWR" },
89dfc302
SY
591#endif
592#ifdef SIGUNUSED
593 { SIGUNUSED, "UNUSED" },
594#endif
595#ifdef SIGSYS
504a2217 596 { SIGSYS, "SYS" },
89dfc302 597#endif
c2cc9f0a 598};
599
504a2217 600static const size_t config_size = sizeof(config) / sizeof(struct lxc_config_t);
c2cc9f0a 601
72d0e1cb 602extern struct lxc_config_t *lxc_getconfig(const char *key)
c2cc9f0a 603{
84760c11 604 size_t i;
c2cc9f0a 605
606 for (i = 0; i < config_size; i++)
504a2217 607 if (!strncmp(config[i].name, key, strlen(config[i].name)))
c2cc9f0a 608 return &config[i];
609 return NULL;
610}
611
72d0e1cb
SG
612int lxc_listconfigs(char *retv, int inlen)
613{
84760c11 614 size_t i;
504a2217
CB
615 int len;
616 int fulllen = 0;
72d0e1cb
SG
617
618 if (!retv)
619 inlen = 0;
620 else
621 memset(retv, 0, inlen);
504a2217 622
72d0e1cb
SG
623 for (i = 0; i < config_size; i++) {
624 char *s = config[i].name;
504a2217 625 if (s[strlen(s) - 1] == '.')
72d0e1cb
SG
626 continue;
627 strprint(retv, inlen, "%s\n", s);
628 }
504a2217 629
72d0e1cb
SG
630 return fulllen;
631}
632
f9373e40
CB
633static int set_config_net(const char *key, const char *value,
634 struct lxc_conf *lxc_conf, void *data)
6b0d5538 635{
663e9916 636 if (!lxc_config_value_empty(value)) {
f9373e40 637 ERROR("lxc.net must not have a value");
6b0d5538
SH
638 return -1;
639 }
640
f9373e40 641 return clr_config_net(key, lxc_conf, data);
6b0d5538
SH
642}
643
f9373e40
CB
644static int set_config_net_type(const char *key, const char *value,
645 struct lxc_conf *lxc_conf, void *data)
c2cc9f0a 646{
c2cc9f0a 647 struct lxc_netdev *netdev;
c2cc9f0a 648
663e9916 649 if (lxc_config_value_empty(value))
f9373e40 650 return clr_config_net_type(key, lxc_conf, data);
c302b476 651
f9373e40
CB
652 if (!data)
653 return -1;
654 else
bbc079cf
CB
655 netdev = data;
656 if (!netdev)
c2cc9f0a 657 return -1;
c2cc9f0a 658
bbc079cf 659 if (!strcmp(value, "veth")) {
24654103 660 netdev->type = LXC_NET_VETH;
bbc079cf 661 } else if (!strcmp(value, "macvlan")) {
24654103 662 netdev->type = LXC_NET_MACVLAN;
9b0df30f
CB
663 lxc_macvlan_mode_to_flag(&netdev->priv.macvlan_attr.mode,
664 "private");
bbc079cf 665 } else if (!strcmp(value, "vlan")) {
24654103 666 netdev->type = LXC_NET_VLAN;
bbc079cf 667 } else if (!strcmp(value, "phys")) {
24654103 668 netdev->type = LXC_NET_PHYS;
bbc079cf 669 } else if (!strcmp(value, "empty")) {
24654103 670 netdev->type = LXC_NET_EMPTY;
bbc079cf 671 } else if (!strcmp(value, "none")) {
26b797f3 672 netdev->type = LXC_NET_NONE;
bbc079cf 673 } else {
36eb9bde 674 ERROR("invalid network type %s", value);
c2cc9f0a 675 return -1;
676 }
bbc079cf 677
c2cc9f0a 678 return 0;
679}
680
72d0e1cb 681/*
f9373e40 682 * If you have p="lxc.net.0.link", pass it p+12
504a2217 683 * to get back '0' (the index of the nic).
72d0e1cb
SG
684 */
685static int get_network_netdev_idx(const char *key)
686{
687 int ret, idx;
688
689 if (*key < '0' || *key > '9')
690 return -1;
504a2217 691
72d0e1cb
SG
692 ret = sscanf(key, "%d", &idx);
693 if (ret != 1)
694 return -1;
504a2217 695
72d0e1cb
SG
696 return idx;
697}
698
699/*
f9373e40 700 * If you have p="lxc.net.0", pass this p+12 and it will return
504a2217 701 * the netdev of the first configured nic.
72d0e1cb
SG
702 */
703static struct lxc_netdev *get_netdev_from_key(const char *key,
704 struct lxc_list *network)
705{
504a2217 706 int idx;
72d0e1cb 707 struct lxc_list *it;
504a2217
CB
708 int i = 0;
709 struct lxc_netdev *netdev = NULL;
710
711 idx = get_network_netdev_idx(key);
72d0e1cb
SG
712 if (idx == -1)
713 return NULL;
504a2217 714
72d0e1cb
SG
715 lxc_list_for_each(it, network) {
716 if (idx == i++) {
717 netdev = it->elem;
718 break;
719 }
720 }
504a2217 721
72d0e1cb
SG
722 return netdev;
723}
724
504a2217
CB
725extern int lxc_list_nicconfigs(struct lxc_conf *c, const char *key, char *retv,
726 int inlen)
72d0e1cb
SG
727{
728 struct lxc_netdev *netdev;
504a2217
CB
729 int len;
730 int fulllen = 0;
72d0e1cb 731
f9373e40 732 netdev = get_netdev_from_key(key + 8, &c->network);
72d0e1cb
SG
733 if (!netdev)
734 return -1;
735
736 if (!retv)
737 inlen = 0;
738 else
739 memset(retv, 0, inlen);
740
74836992 741 strprint(retv, inlen, "type\n");
72d0e1cb 742 strprint(retv, inlen, "script.up\n");
8fc8295a 743 strprint(retv, inlen, "script.down\n");
72d0e1cb
SG
744 if (netdev->type != LXC_NET_EMPTY) {
745 strprint(retv, inlen, "flags\n");
746 strprint(retv, inlen, "link\n");
747 strprint(retv, inlen, "name\n");
748 strprint(retv, inlen, "hwaddr\n");
749 strprint(retv, inlen, "mtu\n");
750 strprint(retv, inlen, "ipv6\n");
9eaf8a59 751 strprint(retv, inlen, "ipv6.gateway\n");
72d0e1cb 752 strprint(retv, inlen, "ipv4\n");
9eaf8a59 753 strprint(retv, inlen, "ipv4.gateway\n");
72d0e1cb 754 }
504a2217
CB
755
756 switch (netdev->type) {
72d0e1cb
SG
757 case LXC_NET_VETH:
758 strprint(retv, inlen, "veth.pair\n");
759 break;
760 case LXC_NET_MACVLAN:
761 strprint(retv, inlen, "macvlan.mode\n");
762 break;
763 case LXC_NET_VLAN:
764 strprint(retv, inlen, "vlan.id\n");
765 break;
766 case LXC_NET_PHYS:
767 break;
768 }
504a2217 769
72d0e1cb
SG
770 return fulllen;
771}
772
f9373e40
CB
773static int set_config_net_flags(const char *key, const char *value,
774 struct lxc_conf *lxc_conf, void *data)
c2cc9f0a 775{
c2cc9f0a 776 struct lxc_netdev *netdev;
777
9d4bf22d 778 if (lxc_config_value_empty(value))
f9373e40 779 return clr_config_net_flags(key, lxc_conf, data);
9d4bf22d 780
f9373e40
CB
781 if (!data)
782 return -1;
783 else
bbc079cf 784 netdev = data;
33c945e0 785 if (!netdev)
c2cc9f0a 786 return -1;
c2cc9f0a 787
33c945e0 788 netdev->flags |= IFF_UP;
c2cc9f0a 789
33c945e0
MT
790 return 0;
791}
792
b45e32f9 793static int create_matched_ifnames(const char *value, struct lxc_conf *lxc_conf,
f9373e40 794 struct lxc_netdev *netdev)
576400e5 795{
796 struct ifaddrs *ifaddr, *ifa;
504a2217
CB
797 int n;
798 int ret = 0;
f9373e40
CB
799 const char *type_key = "lxc.net.type";
800 const char *link_key = "lxc.net.link";
576400e5 801 const char *tmpvalue = "phys";
576400e5 802
803 if (getifaddrs(&ifaddr) == -1) {
804 SYSERROR("Get network interfaces failed");
805 return -1;
806 }
807
808 for (ifa = ifaddr, n = 0; ifa != NULL; ifa = ifa->ifa_next, n++) {
809 if (!ifa->ifa_addr)
810 continue;
811 if (ifa->ifa_addr->sa_family != AF_PACKET)
812 continue;
813
504a2217 814 if (!strncmp(value, ifa->ifa_name, strlen(value) - 1)) {
f9373e40
CB
815 ret = set_config_net_type(type_key, tmpvalue, lxc_conf,
816 netdev);
576400e5 817 if (!ret) {
f9373e40 818 ret = set_config_net_link(
c302b476 819 link_key, ifa->ifa_name, lxc_conf, netdev);
576400e5 820 if (ret) {
821 ERROR("failed to create matched ifnames");
822 break;
823 }
824 } else {
825 ERROR("failed to create matched ifnames");
826 break;
827 }
828 }
829 }
830
504a2217
CB
831 freeifaddrs(ifaddr);
832 ifaddr = NULL;
091045f8 833
576400e5 834 return ret;
835}
836
f9373e40
CB
837static int set_config_net_link(const char *key, const char *value,
838 struct lxc_conf *lxc_conf, void *data)
33c945e0
MT
839{
840 struct lxc_netdev *netdev;
576400e5 841 int ret = 0;
33c945e0 842
6bed0fb6 843 if (lxc_config_value_empty(value))
f9373e40 844 return clr_config_net_link(key, lxc_conf, data);
6bed0fb6 845
f9373e40
CB
846 if (!data)
847 return -1;
848 else
bbc079cf 849 netdev = data;
33c945e0 850 if (!netdev)
c2cc9f0a 851 return -1;
c2cc9f0a 852
b45e32f9
CB
853 if (value[strlen(value) - 1] == '+' && netdev->type == LXC_NET_PHYS)
854 ret = create_matched_ifnames(value, lxc_conf, netdev);
855 else
576400e5 856 ret = network_ifname(&netdev->link, value);
576400e5 857
858 return ret;
c2cc9f0a 859}
860
f9373e40
CB
861static int set_config_net_name(const char *key, const char *value,
862 struct lxc_conf *lxc_conf, void *data)
c2cc9f0a 863{
c2cc9f0a 864 struct lxc_netdev *netdev;
865
6bed0fb6 866 if (lxc_config_value_empty(value))
f9373e40 867 return clr_config_net_name(key, lxc_conf, data);
6bed0fb6 868
f9373e40
CB
869 if (!data)
870 return -1;
871 else
bbc079cf 872 netdev = data;
33c945e0 873 if (!netdev)
c2cc9f0a 874 return -1;
c2cc9f0a 875
33c945e0
MT
876 return network_ifname(&netdev->name, value);
877}
878
f9373e40
CB
879static int set_config_net_veth_pair(const char *key, const char *value,
880 struct lxc_conf *lxc_conf, void *data)
e892973e
DL
881{
882 struct lxc_netdev *netdev;
883
6bed0fb6 884 if (lxc_config_value_empty(value))
f9373e40 885 return clr_config_net_veth_pair(key, lxc_conf, data);
6bed0fb6 886
f9373e40
CB
887 if (!data)
888 return -1;
889 else
bbc079cf 890 netdev = data;
e892973e
DL
891 if (!netdev)
892 return -1;
893
894 return network_ifname(&netdev->priv.veth_attr.pair, value);
895}
896
f9373e40
CB
897static int set_config_net_macvlan_mode(const char *key, const char *value,
898 struct lxc_conf *lxc_conf, void *data)
8634bc19
MT
899{
900 struct lxc_netdev *netdev;
901
6bed0fb6 902 if (lxc_config_value_empty(value))
f9373e40 903 return clr_config_net_macvlan_mode(key, lxc_conf, data);
6bed0fb6 904
f9373e40
CB
905 if (!data)
906 return -1;
907 else
bbc079cf 908 netdev = data;
8634bc19
MT
909 if (!netdev)
910 return -1;
911
9b0df30f 912 return lxc_macvlan_mode_to_flag(&netdev->priv.macvlan_attr.mode, value);
8634bc19
MT
913}
914
f9373e40
CB
915static int set_config_net_hwaddr(const char *key, const char *value,
916 struct lxc_conf *lxc_conf, void *data)
33c945e0
MT
917{
918 struct lxc_netdev *netdev;
504a2217 919 char *new_value;
33c945e0 920
6bed0fb6 921 if (lxc_config_value_empty(value))
f9373e40 922 return clr_config_net_hwaddr(key, lxc_conf, data);
6bed0fb6 923
f9373e40
CB
924 if (!data)
925 return -1;
926 else
ecbb3790 927 netdev = data;
ecbb3790
CB
928 if (!netdev)
929 return -1;
930
504a2217 931 new_value = strdup(value);
508c263e 932 if (!new_value) {
504a2217 933 SYSERROR("failed to strdup \"%s\"", value);
c2cc9f0a 934 return -1;
508c263e
SH
935 }
936 rand_complete_hwaddr(new_value);
c2cc9f0a 937
663e9916 938 if (lxc_config_value_empty(new_value)) {
508c263e
SH
939 free(new_value);
940 netdev->hwaddr = NULL;
941 return 0;
942 }
943
944 netdev->hwaddr = new_value;
945 return 0;
c2cc9f0a 946}
947
f9373e40
CB
948static int set_config_net_vlan_id(const char *key, const char *value,
949 struct lxc_conf *lxc_conf, void *data)
26c39028
JHS
950{
951 struct lxc_netdev *netdev;
952
6bed0fb6 953 if (lxc_config_value_empty(value))
f9373e40 954 return clr_config_net_vlan_id(key, lxc_conf, data);
6bed0fb6 955
f9373e40
CB
956 if (!data)
957 return -1;
958 else
bbc079cf 959 netdev = data;
26c39028
JHS
960 if (!netdev)
961 return -1;
962
f6cc1de1 963 if (get_u16(&netdev->priv.vlan_attr.vid, value, 0))
26c39028
JHS
964 return -1;
965
966 return 0;
967}
968
f9373e40
CB
969static int set_config_net_mtu(const char *key, const char *value,
970 struct lxc_conf *lxc_conf, void *data)
442cbbe6 971{
442cbbe6
TR
972 struct lxc_netdev *netdev;
973
6bed0fb6 974 if (lxc_config_value_empty(value))
f9373e40 975 return clr_config_net_mtu(key, lxc_conf, data);
6bed0fb6 976
f9373e40
CB
977 if (!data)
978 return -1;
979 else
bbc079cf 980 netdev = data;
33c945e0 981 if (!netdev)
442cbbe6 982 return -1;
442cbbe6 983
713046e3 984 return set_config_string_item(&netdev->mtu, value);
442cbbe6
TR
985}
986
f9373e40
CB
987static int set_config_net_ipv4(const char *key, const char *value,
988 struct lxc_conf *lxc_conf, void *data)
c2cc9f0a 989{
c2cc9f0a 990 struct lxc_netdev *netdev;
33c945e0 991 struct lxc_inetdev *inetdev;
c2cc9f0a 992 struct lxc_list *list;
504a2217
CB
993 char *cursor, *slash;
994 char *addr = NULL, *bcast = NULL, *prefix = NULL;
c2cc9f0a 995
663e9916 996 if (lxc_config_value_empty(value))
f9373e40 997 return clr_config_net_ipv4(key, lxc_conf, data);
0797e123 998
f9373e40
CB
999 if (!data)
1000 return -1;
1001 else
bbc079cf 1002 netdev = data;
33c945e0 1003 if (!netdev)
c2cc9f0a 1004 return -1;
c2cc9f0a 1005
1006 inetdev = malloc(sizeof(*inetdev));
1007 if (!inetdev) {
36eb9bde 1008 SYSERROR("failed to allocate ipv4 address");
c2cc9f0a 1009 return -1;
1010 }
1011 memset(inetdev, 0, sizeof(*inetdev));
1012
1013 list = malloc(sizeof(*list));
1014 if (!list) {
36eb9bde 1015 SYSERROR("failed to allocate memory");
53719062 1016 free(inetdev);
c2cc9f0a 1017 return -1;
1018 }
1019
1020 lxc_list_init(list);
1021 list->elem = inetdev;
1022
956edc54
SG
1023 addr = strdup(value);
1024 if (!addr) {
1025 ERROR("no address specified");
53719062
SH
1026 free(inetdev);
1027 free(list);
956edc54
SG
1028 return -1;
1029 }
c2cc9f0a 1030
1031 cursor = strstr(addr, " ");
1032 if (cursor) {
1033 *cursor = '\0';
1034 bcast = cursor + 1;
1035 }
1036
1037 slash = strstr(addr, "/");
1038 if (slash) {
1039 *slash = '\0';
1040 prefix = slash + 1;
1041 }
1042
c2cc9f0a 1043 if (!inet_pton(AF_INET, addr, &inetdev->addr)) {
36eb9bde 1044 SYSERROR("invalid ipv4 address: %s", value);
53719062 1045 free(inetdev);
956edc54 1046 free(addr);
53719062 1047 free(list);
c2cc9f0a 1048 return -1;
1049 }
1050
0093bb8c
DL
1051 if (bcast && !inet_pton(AF_INET, bcast, &inetdev->bcast)) {
1052 SYSERROR("invalid ipv4 broadcast address: %s", value);
53719062
SH
1053 free(inetdev);
1054 free(list);
956edc54 1055 free(addr);
0093bb8c
DL
1056 return -1;
1057 }
c2cc9f0a 1058
504a2217 1059 /* No prefix specified, determine it from the network class. */
1c633398
CB
1060 if (prefix) {
1061 if (lxc_safe_uint(prefix, &inetdev->prefix) < 0)
1062 return -1;
1063 } else {
1064 inetdev->prefix = config_ip_prefix(&inetdev->addr);
1065 }
a059591e 1066
504a2217
CB
1067 /* If no broadcast address, let compute one from the
1068 * prefix and address.
0093bb8c
DL
1069 */
1070 if (!bcast) {
1b7d4743
DL
1071 inetdev->bcast.s_addr = inetdev->addr.s_addr;
1072 inetdev->bcast.s_addr |=
504a2217 1073 htonl(INADDR_BROADCAST >> inetdev->prefix);
0093bb8c 1074 }
c2cc9f0a 1075
8538f388 1076 lxc_list_add_tail(&netdev->ipv4, list);
c2cc9f0a 1077
956edc54 1078 free(addr);
c2cc9f0a 1079 return 0;
1080}
1081
f9373e40
CB
1082static int set_config_net_ipv4_gateway(const char *key, const char *value,
1083 struct lxc_conf *lxc_conf, void *data)
f8fee0e2
MK
1084{
1085 struct lxc_netdev *netdev;
f8fee0e2 1086
6bed0fb6 1087 if (lxc_config_value_empty(value))
f9373e40 1088 return clr_config_net_ipv4_gateway(key, lxc_conf, data);
6bed0fb6 1089
f9373e40
CB
1090 if (!data)
1091 return -1;
1092 else
bbc079cf 1093 netdev = data;
f8fee0e2
MK
1094 if (!netdev)
1095 return -1;
1096
e088e926 1097 free(netdev->ipv4_gateway);
f8fee0e2 1098
ab6faf2e 1099 if (!strcmp(value, "auto")) {
19a26f82
MK
1100 netdev->ipv4_gateway = NULL;
1101 netdev->ipv4_gateway_auto = true;
1102 } else {
e088e926
SG
1103 struct in_addr *gw;
1104
1105 gw = malloc(sizeof(*gw));
1106 if (!gw) {
1107 SYSERROR("failed to allocate ipv4 gateway address");
1108 return -1;
1109 }
1110
19a26f82
MK
1111 if (!inet_pton(AF_INET, value, gw)) {
1112 SYSERROR("invalid ipv4 gateway address: %s", value);
53719062 1113 free(gw);
19a26f82
MK
1114 return -1;
1115 }
1116
1117 netdev->ipv4_gateway = gw;
1118 netdev->ipv4_gateway_auto = false;
f8fee0e2
MK
1119 }
1120
f8fee0e2
MK
1121 return 0;
1122}
1123
f9373e40
CB
1124static int set_config_net_ipv6(const char *key, const char *value,
1125 struct lxc_conf *lxc_conf, void *data)
c2cc9f0a 1126{
c2cc9f0a 1127 struct lxc_netdev *netdev;
1128 struct lxc_inet6dev *inet6dev;
1129 struct lxc_list *list;
504a2217 1130 char *slash, *valdup, *netmask;
c2cc9f0a 1131
6bed0fb6 1132 if (lxc_config_value_empty(value))
f9373e40 1133 return clr_config_net_ipv6(key, lxc_conf, data);
6bed0fb6 1134
f9373e40
CB
1135 if (!data)
1136 return -1;
1137 else
bbc079cf 1138 netdev = data;
33c945e0 1139 if (!netdev)
c2cc9f0a 1140 return -1;
c2cc9f0a 1141
1142 inet6dev = malloc(sizeof(*inet6dev));
1143 if (!inet6dev) {
36eb9bde 1144 SYSERROR("failed to allocate ipv6 address");
c2cc9f0a 1145 return -1;
1146 }
1147 memset(inet6dev, 0, sizeof(*inet6dev));
1148
1149 list = malloc(sizeof(*list));
1150 if (!list) {
36eb9bde 1151 SYSERROR("failed to allocate memory");
28027320 1152 free(inet6dev);
c2cc9f0a 1153 return -1;
1154 }
1155
1156 lxc_list_init(list);
1157 list->elem = inet6dev;
1158
956edc54
SG
1159 valdup = strdup(value);
1160 if (!valdup) {
1161 ERROR("no address specified");
28027320
SH
1162 free(list);
1163 free(inet6dev);
956edc54
SG
1164 return -1;
1165 }
1166
a059591e 1167 inet6dev->prefix = 64;
12a50cc6 1168 slash = strstr(valdup, "/");
c2cc9f0a 1169 if (slash) {
1170 *slash = '\0';
1171 netmask = slash + 1;
1c633398
CB
1172 if (lxc_safe_uint(netmask, &inet6dev->prefix) < 0)
1173 return -1;
c2cc9f0a 1174 }
1175
5acccf95
SH
1176 if (!inet_pton(AF_INET6, valdup, &inet6dev->addr)) {
1177 SYSERROR("invalid ipv6 address: %s", valdup);
28027320
SH
1178 free(list);
1179 free(inet6dev);
956edc54 1180 free(valdup);
c2cc9f0a 1181 return -1;
1182 }
1183
8538f388 1184 lxc_list_add_tail(&netdev->ipv6, list);
c2cc9f0a 1185
956edc54 1186 free(valdup);
c2cc9f0a 1187 return 0;
1188}
1189
f9373e40
CB
1190static int set_config_net_ipv6_gateway(const char *key, const char *value,
1191 struct lxc_conf *lxc_conf, void *data)
f8fee0e2
MK
1192{
1193 struct lxc_netdev *netdev;
f8fee0e2 1194
6bed0fb6 1195 if (lxc_config_value_empty(value))
f9373e40 1196 return clr_config_net_ipv6_gateway(key, lxc_conf, data);
6bed0fb6 1197
f9373e40
CB
1198 if (!data)
1199 return -1;
1200 else
bbc079cf 1201 netdev = data;
f8fee0e2
MK
1202 if (!netdev)
1203 return -1;
1204
e088e926 1205 free(netdev->ipv6_gateway);
f8fee0e2 1206
ab6faf2e 1207 if (!strcmp(value, "auto")) {
19a26f82
MK
1208 netdev->ipv6_gateway = NULL;
1209 netdev->ipv6_gateway_auto = true;
1210 } else {
8fb86a37
SH
1211 struct in6_addr *gw;
1212
bec695f3
DE
1213 gw = malloc(sizeof(*gw));
1214 if (!gw) {
1215 SYSERROR("failed to allocate ipv6 gateway address");
1216 return -1;
1217 }
1218
19a26f82
MK
1219 if (!inet_pton(AF_INET6, value, gw)) {
1220 SYSERROR("invalid ipv6 gateway address: %s", value);
28027320 1221 free(gw);
19a26f82
MK
1222 return -1;
1223 }
1224
1225 netdev->ipv6_gateway = gw;
1226 netdev->ipv6_gateway_auto = false;
f8fee0e2
MK
1227 }
1228
f8fee0e2
MK
1229 return 0;
1230}
1231
f9373e40
CB
1232static int set_config_net_script_up(const char *key, const char *value,
1233 struct lxc_conf *lxc_conf, void *data)
e3b4c4c4
ST
1234{
1235 struct lxc_netdev *netdev;
1236
6bed0fb6 1237 if (lxc_config_value_empty(value))
f9373e40 1238 return clr_config_net_script_up(key, lxc_conf, data);
6bed0fb6 1239
f9373e40
CB
1240 if (!data)
1241 return -1;
1242 else
bbc079cf 1243 netdev = data;
e3b4c4c4 1244 if (!netdev)
504a2217 1245 return -1;
e3b4c4c4 1246
713046e3 1247 return set_config_string_item(&netdev->upscript, value);
8fc8295a
DE
1248}
1249
f9373e40
CB
1250static int set_config_net_script_down(const char *key, const char *value,
1251 struct lxc_conf *lxc_conf, void *data)
8fc8295a
DE
1252{
1253 struct lxc_netdev *netdev;
1254
6bed0fb6 1255 if (lxc_config_value_empty(value))
f9373e40 1256 return clr_config_net_script_down(key, lxc_conf, data);
6bed0fb6 1257
f9373e40
CB
1258 if (!data)
1259 return -1;
1260 else
bbc079cf 1261 netdev = data;
8fc8295a 1262 if (!netdev)
504a2217 1263 return -1;
8fc8295a 1264
713046e3 1265 return set_config_string_item(&netdev->downscript, value);
e3b4c4c4
ST
1266}
1267
26ddeedd
SH
1268static int add_hook(struct lxc_conf *lxc_conf, int which, char *hook)
1269{
1270 struct lxc_list *hooklist;
1271
1272 hooklist = malloc(sizeof(*hooklist));
1273 if (!hooklist) {
1274 free(hook);
1275 return -1;
1276 }
504a2217 1277
26ddeedd
SH
1278 hooklist->elem = hook;
1279 lxc_list_add_tail(&lxc_conf->hooks[which], hooklist);
1280 return 0;
1281}
1282
713046e3 1283static int set_config_seccomp(const char *key, const char *value,
c7e27aaf 1284 struct lxc_conf *lxc_conf, void *data)
8f2c3a70 1285{
713046e3 1286 return set_config_path_item(&lxc_conf->seccomp, value);
8f2c3a70
SH
1287}
1288
713046e3 1289static int set_config_init_cmd(const char *key, const char *value,
c7e27aaf 1290 struct lxc_conf *lxc_conf, void *data)
67c660d0 1291{
713046e3 1292 return set_config_path_item(&lxc_conf->init_cmd, value);
67c660d0
SG
1293}
1294
713046e3 1295static int set_config_init_uid(const char *key, const char *value,
c7e27aaf 1296 struct lxc_conf *lxc_conf, void *data)
72bb04e4 1297{
d1e5d636
CB
1298 unsigned int init_uid;
1299
2e7cde40 1300 /* Set config value to default. */
663e9916 1301 if (lxc_config_value_empty(value)) {
2e7cde40 1302 lxc_conf->init_uid = 0;
fee80911 1303 return 0;
2e7cde40 1304 }
fee80911 1305
2e7cde40 1306 /* Parse new config value. */
d1e5d636
CB
1307 if (lxc_safe_uint(value, &init_uid) < 0)
1308 return -1;
1309 lxc_conf->init_uid = init_uid;
1310
72bb04e4
PT
1311 return 0;
1312}
1313
713046e3 1314static int set_config_init_gid(const char *key, const char *value,
c7e27aaf 1315 struct lxc_conf *lxc_conf, void *data)
72bb04e4 1316{
d1e5d636
CB
1317 unsigned int init_gid;
1318
2debb6e6 1319 /* Set config value to default. */
663e9916 1320 if (lxc_config_value_empty(value)) {
2debb6e6 1321 lxc_conf->init_gid = 0;
a757cc7d 1322 return 0;
2debb6e6 1323 }
a757cc7d 1324
2debb6e6 1325 /* Parse new config value. */
d1e5d636
CB
1326 if (lxc_safe_uint(value, &init_gid) < 0)
1327 return -1;
1328 lxc_conf->init_gid = init_gid;
1329
72bb04e4
PT
1330 return 0;
1331}
1332
466c2e93 1333static int set_config_hooks(const char *key, const char *value,
c7e27aaf 1334 struct lxc_conf *lxc_conf, void *data)
26ddeedd 1335{
7d0eb87e 1336 char *copy;
72bb04e4 1337
663e9916 1338 if (lxc_config_value_empty(value))
7d0eb87e
SH
1339 return lxc_clear_hooks(lxc_conf, key);
1340
a182feae 1341 if (strcmp(key + 4, "hook") == 0) {
6b0d5538
SH
1342 ERROR("lxc.hook cannot take a value");
1343 return -1;
1344 }
7d0eb87e 1345 copy = strdup(value);
26ddeedd
SH
1346 if (!copy) {
1347 SYSERROR("failed to dup string '%s'", value);
1348 return -1;
1349 }
504a2217 1350
a182feae 1351 if (strcmp(key + 9, "pre-start") == 0)
26ddeedd 1352 return add_hook(lxc_conf, LXCHOOK_PRESTART, copy);
a182feae 1353 else if (strcmp(key + 9, "pre-mount") == 0)
5ea6163a 1354 return add_hook(lxc_conf, LXCHOOK_PREMOUNT, copy);
a182feae 1355 else if (strcmp(key + 9, "autodev") == 0)
f7bee6c6 1356 return add_hook(lxc_conf, LXCHOOK_AUTODEV, copy);
a182feae 1357 else if (strcmp(key + 9, "mount") == 0)
26ddeedd 1358 return add_hook(lxc_conf, LXCHOOK_MOUNT, copy);
a182feae 1359 else if (strcmp(key + 9, "start") == 0)
26ddeedd 1360 return add_hook(lxc_conf, LXCHOOK_START, copy);
a182feae 1361 else if (strcmp(key + 9, "stop") == 0)
52492063 1362 return add_hook(lxc_conf, LXCHOOK_STOP, copy);
a182feae 1363 else if (strcmp(key + 9, "post-stop") == 0)
26ddeedd 1364 return add_hook(lxc_conf, LXCHOOK_POSTSTOP, copy);
a182feae 1365 else if (strcmp(key + 9, "clone") == 0)
148e91f5 1366 return add_hook(lxc_conf, LXCHOOK_CLONE, copy);
a182feae 1367 else if (strcmp(key + 9, "destroy") == 0)
37cf711b 1368 return add_hook(lxc_conf, LXCHOOK_DESTROY, copy);
504a2217 1369
26ddeedd
SH
1370 SYSERROR("Unknown key: %s", key);
1371 free(copy);
1372 return -1;
1373}
1374
713046e3 1375static int set_config_personality(const char *key, const char *value,
c7e27aaf 1376 struct lxc_conf *lxc_conf, void *data)
cccc74b5 1377{
525f0002 1378 signed long personality = lxc_config_parse_arch(value);
cccc74b5 1379
525f0002
CS
1380 if (personality >= 0)
1381 lxc_conf->personality = personality;
1382 else
1383 WARN("unsupported personality '%s'", value);
970ab589
DL
1384
1385 return 0;
cccc74b5
DL
1386}
1387
713046e3 1388static int set_config_pts(const char *key, const char *value,
c7e27aaf 1389 struct lxc_conf *lxc_conf, void *data)
10db618d 1390{
ec200ce9 1391 /* Set config value to default. */
663e9916 1392 if (lxc_config_value_empty(value)) {
ec200ce9 1393 lxc_conf->pts = 0;
884a4580 1394 return 0;
ec200ce9 1395 }
884a4580 1396
ec200ce9 1397 /* Parse new config value. */
17919969
CB
1398 if (lxc_safe_uint(value, &lxc_conf->pts) < 0)
1399 return -1;
10db618d 1400
1401 return 0;
1402}
1403
a182feae
CB
1404/* We only need to check whether the first byte of the key after the lxc.start.
1405 * prefix matches our expectations since they fortunately all start with a
1406 * different letter. If anything was wrong with the key we would have already
1407 * noticed when the callback was called.
1408 */
713046e3 1409static int set_config_start(const char *key, const char *value,
c7e27aaf 1410 struct lxc_conf *lxc_conf, void *data)
ee1e7aa0 1411{
ebb80f95
CB
1412 bool is_empty;
1413
663e9916 1414 is_empty = lxc_config_value_empty(value);
ebb80f95 1415
a182feae 1416 if (*(key + 10) == 'a') { /* lxc.start.auto */
ebb80f95
CB
1417 /* Set config value to default. */
1418 if (is_empty) {
1419 lxc_conf->start_auto = 0;
1420 return 0;
1421 }
61ff8fc8 1422
ebb80f95 1423 /* Parse new config value. */
3590152f
CB
1424 if (lxc_safe_uint(value, &lxc_conf->start_auto) < 0)
1425 return -1;
ebb80f95 1426
3590152f
CB
1427 if (lxc_conf->start_auto > 1)
1428 return -1;
ebb80f95 1429
ee1e7aa0 1430 return 0;
a182feae 1431 } else if (*(key + 10) == 'd') { /* lxc.start.delay */
ebb80f95
CB
1432 /* Set config value to default. */
1433 if (is_empty) {
1434 lxc_conf->start_delay = 0;
1435 return 0;
1436 }
1437
1438 /* Parse new config value. */
1439 return lxc_safe_uint(value, &lxc_conf->start_delay);
a182feae 1440 } else if (*(key + 10) == 'o') { /* lxc.start.order */
ebb80f95
CB
1441 /* Set config value to default. */
1442 if (is_empty) {
1443 lxc_conf->start_order = 0;
1444 return 0;
1445 }
1446
1447 /* Parse new config value. */
1448 return lxc_safe_int(value, &lxc_conf->start_order);
ee1e7aa0 1449 }
ebb80f95 1450
ee1e7aa0
SG
1451 SYSERROR("Unknown key: %s", key);
1452 return -1;
1453}
1454
713046e3 1455static int set_config_monitor(const char *key, const char *value,
c7e27aaf 1456 struct lxc_conf *lxc_conf, void *data)
a8dfe4e0 1457{
4ad9cd26 1458 /* Set config value to default. */
663e9916 1459 if (lxc_config_value_empty(value)) {
4ad9cd26 1460 lxc_conf->monitor_unshare = 0;
a8dfe4e0
WB
1461 return 0;
1462 }
4ad9cd26
CB
1463
1464 /* Parse new config value. */
a182feae 1465 if (strcmp(key + 12, "unshare") == 0)
4ad9cd26
CB
1466 return lxc_safe_uint(value, &lxc_conf->monitor_unshare);
1467
a8dfe4e0
WB
1468 SYSERROR("Unknown key: %s", key);
1469 return -1;
1470}
1471
713046e3 1472static int set_config_group(const char *key, const char *value,
c7e27aaf 1473 struct lxc_conf *lxc_conf, void *data)
ee1e7aa0
SG
1474{
1475 char *groups, *groupptr, *sptr, *token;
1476 struct lxc_list *grouplist;
1477 int ret = -1;
1478
663e9916 1479 if (lxc_config_value_empty(value))
ee1e7aa0
SG
1480 return lxc_clear_groups(lxc_conf);
1481
1482 groups = strdup(value);
1483 if (!groups) {
1484 SYSERROR("failed to dup '%s'", value);
1485 return -1;
1486 }
1487
504a2217
CB
1488 /* In case several groups are specified in a single line
1489 * split these groups in a single element for the list.
1490 */
1491 for (groupptr = groups;; groupptr = NULL) {
d028235d
SG
1492 token = strtok_r(groupptr, " \t", &sptr);
1493 if (!token) {
ee1e7aa0 1494 ret = 0;
d028235d 1495 break;
ee1e7aa0
SG
1496 }
1497
1498 grouplist = malloc(sizeof(*grouplist));
1499 if (!grouplist) {
1500 SYSERROR("failed to allocate groups list");
1501 break;
1502 }
1503
1504 grouplist->elem = strdup(token);
1505 if (!grouplist->elem) {
1506 SYSERROR("failed to dup '%s'", token);
1507 free(grouplist);
1508 break;
1509 }
1510
1511 lxc_list_add_tail(&lxc_conf->groups, grouplist);
d028235d 1512 }
ee1e7aa0
SG
1513
1514 free(groups);
ee1e7aa0
SG
1515 return ret;
1516}
1517
713046e3 1518static int set_config_environment(const char *key, const char *value,
c7e27aaf 1519 struct lxc_conf *lxc_conf, void *data)
7c661726
MP
1520{
1521 struct lxc_list *list_item = NULL;
1522
663e9916 1523 if (lxc_config_value_empty(value))
ab799c0b
SG
1524 return lxc_clear_environment(lxc_conf);
1525
7c661726
MP
1526 list_item = malloc(sizeof(*list_item));
1527 if (!list_item)
504a2217 1528 goto on_error;
7c661726
MP
1529
1530 list_item->elem = strdup(value);
1531
1532 if (!list_item->elem)
504a2217 1533 goto on_error;
7c661726
MP
1534
1535 lxc_list_add_tail(&lxc_conf->environment, list_item);
1536
1537 return 0;
1538
504a2217 1539on_error:
f10fad2f 1540 free(list_item);
7c661726
MP
1541 return -1;
1542}
1543
713046e3 1544static int set_config_tty(const char *key, const char *value,
c7e27aaf 1545 struct lxc_conf *lxc_conf, void *data)
b0a33c1e 1546{
cb508ee8 1547 /* Set config value to default. */
663e9916 1548 if (lxc_config_value_empty(value)) {
cb508ee8 1549 lxc_conf->tty = 0;
fb12b12a 1550 return 0;
cb508ee8 1551 }
fb12b12a 1552
cb508ee8
CB
1553 /* Parse new config value. */
1554 return lxc_safe_uint(value, &lxc_conf->tty);
b0a33c1e 1555}
1556
713046e3 1557static int set_config_ttydir(const char *key, const char *value,
c7e27aaf 1558 struct lxc_conf *lxc_conf, void *data)
7c6ef2a2 1559{
504a2217
CB
1560 return set_config_string_item_max(&lxc_conf->ttydir, value,
1561 NAME_MAX + 1);
7c6ef2a2
SH
1562}
1563
953fe44f
CB
1564static int set_config_apparmor_profile(const char *key, const char *value,
1565 struct lxc_conf *lxc_conf, void *data)
e075f5d9 1566{
713046e3 1567 return set_config_string_item(&lxc_conf->lsm_aa_profile, value);
fe4de9a6
DE
1568}
1569
953fe44f
CB
1570static int set_config_apparmor_allow_incomplete(const char *key,
1571 const char *value,
1572 struct lxc_conf *lxc_conf,
1573 void *data)
7aff4f43 1574{
cccfa758 1575 /* Set config value to default. */
663e9916 1576 if (lxc_config_value_empty(value)) {
cccfa758 1577 lxc_conf->lsm_aa_allow_incomplete = 0;
a678e9fa 1578 return 0;
cccfa758 1579 }
a678e9fa 1580
cccfa758 1581 /* Parse new config value. */
a56e2df9
CB
1582 if (lxc_safe_uint(value, &lxc_conf->lsm_aa_allow_incomplete) < 0)
1583 return -1;
7aff4f43 1584
a56e2df9 1585 if (lxc_conf->lsm_aa_allow_incomplete > 1) {
cccfa758
CB
1586 ERROR("Wrong value for lxc.lsm_aa_allow_incomplete. Can only "
1587 "be set to 0 or 1");
a56e2df9
CB
1588 return -1;
1589 }
7aff4f43
SH
1590
1591 return 0;
1592}
1593
953fe44f
CB
1594static int set_config_selinux_context(const char *key, const char *value,
1595 struct lxc_conf *lxc_conf, void *data)
fe4de9a6 1596{
713046e3 1597 return set_config_string_item(&lxc_conf->lsm_se_context, value);
e075f5d9 1598}
e075f5d9 1599
713046e3 1600static int set_config_logfile(const char *key, const char *value,
c7e27aaf 1601 struct lxc_conf *c, void *data)
4a85ce2a 1602{
6d03d92a
DE
1603 int ret;
1604
663e9916 1605 if (lxc_config_value_empty(value)) {
0d601acb
CB
1606 free(c->logfile);
1607 c->logfile = NULL;
1608 return 0;
1609 }
1610
1611 /* Store these values in the lxc_conf, and then try to set for actual
504a2217
CB
1612 * current logging.
1613 */
713046e3 1614 ret = set_config_path_item(&c->logfile, value);
6d03d92a 1615 if (ret == 0)
858377e4 1616 ret = lxc_log_set_file(&c->logfd, c->logfile);
6d03d92a 1617 return ret;
4a85ce2a
SH
1618}
1619
713046e3 1620static int set_config_loglevel(const char *key, const char *value,
c7e27aaf 1621 struct lxc_conf *lxc_conf, void *data)
4a85ce2a 1622{
9ea87d5d
SH
1623 int newlevel;
1624
575b9745 1625 /* Set config value to default. */
663e9916 1626 if (lxc_config_value_empty(value)) {
4b73005c 1627 lxc_conf->loglevel = LXC_LOG_LEVEL_NOTSET;
4a85ce2a 1628 return 0;
575b9745 1629 }
4a85ce2a 1630
575b9745 1631 /* Parse new config value. */
a56e2df9
CB
1632 if (value[0] >= '0' && value[0] <= '9') {
1633 if (lxc_safe_int(value, &newlevel) < 0)
1634 return -1;
1635 } else {
9ea87d5d 1636 newlevel = lxc_log_priority_to_int(value);
a56e2df9 1637 }
575b9745 1638
504a2217 1639 /* Store these values in the lxc_conf, and then try to set for actual
575b9745
CB
1640 * current logging.
1641 */
b40a606e 1642 lxc_conf->loglevel = newlevel;
858377e4 1643 return lxc_log_set_level(&lxc_conf->loglevel, newlevel);
4a85ce2a
SH
1644}
1645
713046e3 1646static int set_config_autodev(const char *key, const char *value,
c7e27aaf 1647 struct lxc_conf *lxc_conf, void *data)
c6883f38 1648{
1045031e 1649 /* Set config value to default. */
663e9916 1650 if (lxc_config_value_empty(value)) {
1045031e 1651 lxc_conf->autodev = 0;
180abbc0 1652 return 0;
1045031e 1653 }
180abbc0 1654
1045031e 1655 /* Parse new config value. */
ff6cb4ed
CB
1656 if (lxc_safe_uint(value, &lxc_conf->autodev) < 0)
1657 return -1;
c6883f38 1658
ff6cb4ed
CB
1659 if (lxc_conf->autodev > 1) {
1660 ERROR("Wrong value for lxc.autodev. Can only be set to 0 or 1");
1661 return -1;
1662 }
c6883f38
SH
1663
1664 return 0;
1665}
1666
a84b9932
AV
1667static int sig_num(const char *sig)
1668{
f2e539b3 1669 unsigned int signum;
a84b9932 1670
f2e539b3 1671 if (lxc_safe_uint(sig, &signum) < 0)
a84b9932 1672 return -1;
f2e539b3
CB
1673
1674 return signum;
a84b9932
AV
1675}
1676
1677static int rt_sig_num(const char *signame)
1678{
504a2217 1679 int rtmax = 0, sig_n = 0;
a84b9932
AV
1680
1681 if (strncasecmp(signame, "max-", 4) == 0) {
1682 rtmax = 1;
1683 }
504a2217 1684
a84b9932
AV
1685 signame += 4;
1686 if (!isdigit(*signame))
1687 return -1;
504a2217 1688
a84b9932
AV
1689 sig_n = sig_num(signame);
1690 sig_n = rtmax ? SIGRTMAX - sig_n : SIGRTMIN + sig_n;
1691 if (sig_n > SIGRTMAX || sig_n < SIGRTMIN)
1692 return -1;
504a2217 1693
a84b9932
AV
1694 return sig_n;
1695}
1696
504a2217
CB
1697static int sig_parse(const char *signame)
1698{
84760c11 1699 size_t n;
a84b9932
AV
1700
1701 if (isdigit(*signame)) {
1702 return sig_num(signame);
1703 } else if (strncasecmp(signame, "sig", 3) == 0) {
1704 signame += 3;
1705 if (strncasecmp(signame, "rt", 2) == 0)
1706 return rt_sig_num(signame + 2);
1707 for (n = 0; n < sizeof(signames) / sizeof((signames)[0]); n++) {
504a2217 1708 if (strcasecmp(signames[n].name, signame) == 0)
a84b9932
AV
1709 return signames[n].num;
1710 }
1711 }
504a2217 1712
a84b9932
AV
1713 return -1;
1714}
1715
713046e3 1716static int set_config_haltsignal(const char *key, const char *value,
c7e27aaf 1717 struct lxc_conf *lxc_conf, void *data)
f0f1d8c0 1718{
62a085fb 1719 int sig_n;
f0f1d8c0 1720
c1a64603 1721 /* Set config value to default. */
663e9916 1722 if (lxc_config_value_empty(value)) {
c1a64603 1723 lxc_conf->haltsignal = 0;
955912f0 1724 return 0;
c1a64603 1725 }
955912f0 1726
c1a64603 1727 /* Parse new config value. */
62a085fb
CB
1728 sig_n = sig_parse(value);
1729
f0f1d8c0
DE
1730 if (sig_n < 0)
1731 return -1;
1732 lxc_conf->haltsignal = sig_n;
1733
1734 return 0;
1735}
1736
713046e3 1737static int set_config_rebootsignal(const char *key, const char *value,
c7e27aaf 1738 struct lxc_conf *lxc_conf, void *data)
dd267776 1739{
9d7e7587 1740 int sig_n;
dd267776 1741
18fcee44 1742 /* Set config value to default. */
663e9916 1743 if (lxc_config_value_empty(value)) {
18fcee44 1744 lxc_conf->rebootsignal = 0;
9d7e7587 1745 return 0;
18fcee44 1746 }
9d7e7587 1747
18fcee44 1748 /* Parse new config value. */
9d7e7587 1749 sig_n = sig_parse(value);
dd267776
BP
1750 if (sig_n < 0)
1751 return -1;
1752 lxc_conf->rebootsignal = sig_n;
1753
1754 return 0;
1755}
1756
713046e3 1757static int set_config_stopsignal(const char *key, const char *value,
c7e27aaf 1758 struct lxc_conf *lxc_conf, void *data)
a84b9932 1759{
6ca6aedd 1760 int sig_n;
a84b9932 1761
4100d1a7 1762 /* Set config value to default. */
663e9916 1763 if (lxc_config_value_empty(value)) {
4100d1a7 1764 lxc_conf->stopsignal = 0;
6ca6aedd 1765 return 0;
4100d1a7 1766 }
6ca6aedd 1767
4100d1a7 1768 /* Parse new config value. */
6ca6aedd 1769 sig_n = sig_parse(value);
a84b9932
AV
1770 if (sig_n < 0)
1771 return -1;
1772 lxc_conf->stopsignal = sig_n;
1773
1774 return 0;
1775}
1776
713046e3 1777static int set_config_cgroup(const char *key, const char *value,
c7e27aaf 1778 struct lxc_conf *lxc_conf, void *data)
576f946d 1779{
576f946d 1780 char *subkey;
504a2217 1781 char *token = "lxc.cgroup.";
bf83c5b9
MS
1782 struct lxc_list *cglist = NULL;
1783 struct lxc_cgroup *cgelem = NULL;
576f946d 1784
663e9916 1785 if (lxc_config_value_empty(value))
7d0eb87e
SH
1786 return lxc_clear_cgroups(lxc_conf, key);
1787
576f946d 1788 subkey = strstr(key, token);
576f946d 1789 if (!subkey)
1790 return -1;
1791
1792 if (!strlen(subkey))
1793 return -1;
1794
1795 if (strlen(subkey) == strlen(token))
1796 return -1;
a871ff6b 1797
576f946d 1798 subkey += strlen(token);
1799
1800 cglist = malloc(sizeof(*cglist));
1801 if (!cglist)
bf83c5b9 1802 goto out;
576f946d 1803
1804 cgelem = malloc(sizeof(*cgelem));
bf83c5b9
MS
1805 if (!cgelem)
1806 goto out;
1807 memset(cgelem, 0, sizeof(*cgelem));
576f946d 1808
1809 cgelem->subsystem = strdup(subkey);
1810 cgelem->value = strdup(value);
bf83c5b9
MS
1811
1812 if (!cgelem->subsystem || !cgelem->value)
1813 goto out;
1814
576f946d 1815 cglist->elem = cgelem;
1816
94d12f0a 1817 lxc_list_add_tail(&lxc_conf->cgroup, cglist);
576f946d 1818
1819 return 0;
bf83c5b9
MS
1820
1821out:
f10fad2f 1822 free(cglist);
bf83c5b9
MS
1823
1824 if (cgelem) {
f10fad2f 1825 free(cgelem->subsystem);
bf83c5b9 1826
f10fad2f 1827 free(cgelem->value);
bf83c5b9
MS
1828
1829 free(cgelem);
1830 }
1831
1832 return -1;
576f946d 1833}
1834
504a2217
CB
1835static bool parse_limit_value(const char **value, unsigned long *res)
1836{
c6d09e15
WB
1837 char *endptr = NULL;
1838
504a2217 1839 if (strncmp(*value, "unlimited", sizeof("unlimited") - 1) == 0) {
c6d09e15 1840 *res = RLIM_INFINITY;
504a2217 1841 *value += sizeof("unlimited") - 1;
c6d09e15
WB
1842 return true;
1843 }
1844
1845 errno = 0;
1846 *res = strtoul(*value, &endptr, 10);
1847 if (errno || !endptr)
1848 return false;
1849 *value = endptr;
1850
1851 return true;
1852}
1853
713046e3 1854static int set_config_limit(const char *key, const char *value,
c7e27aaf 1855 struct lxc_conf *lxc_conf, void *data)
c6d09e15 1856{
c6d09e15
WB
1857 struct lxc_list *iter;
1858 struct rlimit limit;
1859 unsigned long limit_value;
504a2217
CB
1860 struct lxc_list *limlist = NULL;
1861 struct lxc_limit *limelem = NULL;
c6d09e15 1862
663e9916 1863 if (lxc_config_value_empty(value))
c6d09e15
WB
1864 return lxc_clear_limits(lxc_conf, key);
1865
504a2217 1866 if (strncmp(key, "lxc.limit.", sizeof("lxc.limit.") - 1) != 0)
c6d09e15
WB
1867 return -1;
1868
504a2217 1869 key += sizeof("lxc.limit.") - 1;
c6d09e15
WB
1870
1871 /* soft limit comes first in the value */
1872 if (!parse_limit_value(&value, &limit_value))
1873 return -1;
1874 limit.rlim_cur = limit_value;
1875
1876 /* skip spaces and a colon */
1877 while (isspace(*value))
1878 ++value;
504a2217 1879
c6d09e15
WB
1880 if (*value == ':')
1881 ++value;
1882 else if (*value) /* any other character is an error here */
1883 return -1;
504a2217 1884
c6d09e15
WB
1885 while (isspace(*value))
1886 ++value;
1887
1888 /* optional hard limit */
1889 if (*value) {
1890 if (!parse_limit_value(&value, &limit_value))
1891 return -1;
1892 limit.rlim_max = limit_value;
504a2217 1893
c6d09e15
WB
1894 /* check for trailing garbage */
1895 while (isspace(*value))
1896 ++value;
504a2217 1897
c6d09e15
WB
1898 if (*value)
1899 return -1;
1900 } else {
1901 /* a single value sets both hard and soft limit */
1902 limit.rlim_max = limit.rlim_cur;
1903 }
1904
1905 /* find existing list element */
504a2217
CB
1906 lxc_list_for_each(iter, &lxc_conf->limits)
1907 {
c6d09e15
WB
1908 limelem = iter->elem;
1909 if (!strcmp(key, limelem->resource)) {
1910 limelem->limit = limit;
1911 return 0;
1912 }
1913 }
1914
1915 /* allocate list element */
1916 limlist = malloc(sizeof(*limlist));
1917 if (!limlist)
1918 goto out;
2e6e3feb 1919
c6d09e15
WB
1920 limelem = malloc(sizeof(*limelem));
1921 if (!limelem)
1922 goto out;
1923 memset(limelem, 0, sizeof(*limelem));
1924
1925 limelem->resource = strdup(key);
1926 if (!limelem->resource)
1927 goto out;
1928 limelem->limit = limit;
1929
1930 limlist->elem = limelem;
1931
1932 lxc_list_add_tail(&lxc_conf->limits, limlist);
1933
1934 return 0;
1935
1936out:
1937 free(limlist);
1938 if (limelem) {
1939 free(limelem->resource);
1940 free(limelem);
1941 }
1942 return -1;
1943}
1944
5014ff2e 1945static int set_config_idmaps(const char *key, const char *value,
c7e27aaf 1946 struct lxc_conf *lxc_conf, void *data)
f6d3e3e4 1947{
251d0d2a 1948 unsigned long hostid, nsid, range;
f6d3e3e4 1949 char type;
0b843d35 1950 int ret;
34a7a4c6
CB
1951 struct lxc_list *idmaplist = NULL;
1952 struct id_map *idmap = NULL;
f6d3e3e4 1953
663e9916 1954 if (lxc_config_value_empty(value))
7d0eb87e
SH
1955 return lxc_clear_idmaps(lxc_conf);
1956
f6d3e3e4
SH
1957 idmaplist = malloc(sizeof(*idmaplist));
1958 if (!idmaplist)
34a7a4c6 1959 goto on_error;
f6d3e3e4
SH
1960
1961 idmap = malloc(sizeof(*idmap));
1962 if (!idmap)
34a7a4c6 1963 goto on_error;
f6d3e3e4
SH
1964 memset(idmap, 0, sizeof(*idmap));
1965
0b843d35
CB
1966 ret = parse_idmaps(value, &type, &nsid, &hostid, &range);
1967 if (ret < 0)
34a7a4c6
CB
1968 goto on_error;
1969
251d0d2a 1970 INFO("read uid map: type %c nsid %lu hostid %lu range %lu", type, nsid, hostid, range);
ac7725e7 1971 if (type == 'u')
f6d3e3e4 1972 idmap->idtype = ID_TYPE_UID;
ac7725e7 1973 else if (type == 'g')
f6d3e3e4
SH
1974 idmap->idtype = ID_TYPE_GID;
1975 else
34a7a4c6 1976 goto on_error;
7e60c3f0 1977
f6d3e3e4
SH
1978 idmap->hostid = hostid;
1979 idmap->nsid = nsid;
1980 idmap->range = range;
7e60c3f0
SG
1981 idmaplist->elem = idmap;
1982 lxc_list_add_tail(&lxc_conf->id_map, idmaplist);
34a7a4c6 1983 idmap = NULL;
7e60c3f0 1984
f6d3e3e4
SH
1985 return 0;
1986
34a7a4c6 1987on_error:
f10fad2f 1988 free(idmaplist);
34a7a4c6 1989 free(idmap);
f6d3e3e4
SH
1990
1991 return -1;
1992}
1993
713046e3 1994static int set_config_fstab(const char *key, const char *value,
c7e27aaf 1995 struct lxc_conf *lxc_conf, void *data)
d95db067 1996{
663e9916 1997 if (lxc_config_value_empty(value)) {
26471403 1998 clr_config_fstab(key, lxc_conf, NULL);
d9192f5d 1999 return -1;
46f3de30 2000 }
6f5685f0 2001
713046e3 2002 return set_config_path_item(&lxc_conf->fstab, value);
d95db067
DE
2003}
2004
713046e3 2005static int set_config_mount_auto(const char *key, const char *value,
c7e27aaf 2006 struct lxc_conf *lxc_conf, void *data)
368bbc02
CS
2007{
2008 char *autos, *autoptr, *sptr, *token;
368bbc02
CS
2009 int i;
2010 int ret = -1;
504a2217
CB
2011 static struct {
2012 const char *token;
2013 int mask;
2014 int flag;
2015 } allowed_auto_mounts[] = {
2016 { "proc", LXC_AUTO_PROC_MASK, LXC_AUTO_PROC_MIXED },
2017 { "proc:mixed", LXC_AUTO_PROC_MASK, LXC_AUTO_PROC_MIXED },
2018 { "proc:rw", LXC_AUTO_PROC_MASK, LXC_AUTO_PROC_RW },
2019 { "sys", LXC_AUTO_SYS_MASK, LXC_AUTO_SYS_MIXED },
2020 { "sys:ro", LXC_AUTO_SYS_MASK, LXC_AUTO_SYS_RO },
2021 { "sys:mixed", LXC_AUTO_SYS_MASK, LXC_AUTO_SYS_MIXED },
2022 { "sys:rw", LXC_AUTO_SYS_MASK, LXC_AUTO_SYS_RW },
2023 { "cgroup", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_NOSPEC },
2024 { "cgroup:mixed", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_MIXED },
2025 { "cgroup:ro", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_RO },
2026 { "cgroup:rw", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_RW },
2027 { "cgroup-full", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_FULL_NOSPEC },
2028 { "cgroup-full:mixed", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_FULL_MIXED },
2029 { "cgroup-full:ro", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_FULL_RO },
2030 { "cgroup-full:rw", LXC_AUTO_CGROUP_MASK, LXC_AUTO_CGROUP_FULL_RW },
2031 /* NB: For adding anything that is just a single on/off, but has
2032 * no options: keep mask and flag identical and just define the
2033 * enum value as an unused bit so far
2034 */
2035 { NULL, 0, 0 }
2036 };
368bbc02 2037
663e9916 2038 if (lxc_config_value_empty(value)) {
d9192f5d
SH
2039 lxc_conf->auto_mounts = 0;
2040 return 0;
2041 }
368bbc02
CS
2042
2043 autos = strdup(value);
2044 if (!autos) {
2045 SYSERROR("failed to dup '%s'", value);
2046 return -1;
2047 }
2048
504a2217 2049 for (autoptr = autos;; autoptr = NULL) {
d028235d
SG
2050 token = strtok_r(autoptr, " \t", &sptr);
2051 if (!token) {
368bbc02 2052 ret = 0;
d028235d 2053 break;
368bbc02
CS
2054 }
2055
2056 for (i = 0; allowed_auto_mounts[i].token; i++) {
2057 if (!strcmp(allowed_auto_mounts[i].token, token))
2058 break;
2059 }
2060
2061 if (!allowed_auto_mounts[i].token) {
2062 ERROR("Invalid filesystem to automount: %s", token);
2063 break;
2064 }
2065
b06b8511 2066 lxc_conf->auto_mounts &= ~allowed_auto_mounts[i].mask;
368bbc02 2067 lxc_conf->auto_mounts |= allowed_auto_mounts[i].flag;
d028235d 2068 }
368bbc02
CS
2069
2070 free(autos);
368bbc02
CS
2071 return ret;
2072}
2073
713046e3 2074static int set_config_mount(const char *key, const char *value,
c7e27aaf 2075 struct lxc_conf *lxc_conf, void *data)
e7938e9e 2076{
e7938e9e
MN
2077 char *mntelem;
2078 struct lxc_list *mntlist;
2079
663e9916 2080 if (lxc_config_value_empty(value))
d9192f5d 2081 return lxc_clear_mount_entries(lxc_conf);
e7938e9e
MN
2082
2083 mntlist = malloc(sizeof(*mntlist));
2084 if (!mntlist)
2085 return -1;
2086
2087 mntelem = strdup(value);
00b6be44
SH
2088 if (!mntelem) {
2089 free(mntlist);
bf83c5b9 2090 return -1;
00b6be44 2091 }
e7938e9e
MN
2092 mntlist->elem = mntelem;
2093
2094 lxc_list_add_tail(&lxc_conf->mount_list, mntlist);
2095
2096 return 0;
2097}
2098
713046e3 2099static int set_config_cap_keep(const char *key, const char *value,
c7e27aaf 2100 struct lxc_conf *lxc_conf, void *data)
1fb86a7c
SH
2101{
2102 char *keepcaps, *keepptr, *sptr, *token;
2103 struct lxc_list *keeplist;
2104 int ret = -1;
2105
663e9916 2106 if (lxc_config_value_empty(value))
7d0eb87e 2107 return lxc_clear_config_keepcaps(lxc_conf);
1fb86a7c
SH
2108
2109 keepcaps = strdup(value);
2110 if (!keepcaps) {
2111 SYSERROR("failed to dup '%s'", value);
2112 return -1;
2113 }
2114
504a2217
CB
2115 /* In case several capability keep is specified in a single line
2116 * split these caps in a single element for the list.
2117 */
2118 for (keepptr = keepcaps;; keepptr = NULL) {
d028235d
SG
2119 token = strtok_r(keepptr, " \t", &sptr);
2120 if (!token) {
1fb86a7c 2121 ret = 0;
d028235d 2122 break;
1fb86a7c
SH
2123 }
2124
7035407c
DE
2125 if (!strcmp(token, "none"))
2126 lxc_clear_config_keepcaps(lxc_conf);
2127
1fb86a7c
SH
2128 keeplist = malloc(sizeof(*keeplist));
2129 if (!keeplist) {
2130 SYSERROR("failed to allocate keepcap list");
2131 break;
2132 }
2133
2134 keeplist->elem = strdup(token);
2135 if (!keeplist->elem) {
2136 SYSERROR("failed to dup '%s'", token);
2137 free(keeplist);
2138 break;
2139 }
2140
2141 lxc_list_add_tail(&lxc_conf->keepcaps, keeplist);
d028235d 2142 }
1fb86a7c
SH
2143
2144 free(keepcaps);
2145
2146 return ret;
2147}
2148
713046e3 2149static int set_config_cap_drop(const char *key, const char *value,
c7e27aaf 2150 struct lxc_conf *lxc_conf, void *data)
81810dd1 2151{
d95db067 2152 char *dropcaps, *dropptr, *sptr, *token;
81810dd1
DL
2153 struct lxc_list *droplist;
2154 int ret = -1;
2155
663e9916 2156 if (lxc_config_value_empty(value))
7d0eb87e 2157 return lxc_clear_config_caps(lxc_conf);
81810dd1
DL
2158
2159 dropcaps = strdup(value);
2160 if (!dropcaps) {
2161 SYSERROR("failed to dup '%s'", value);
2162 return -1;
2163 }
2164
504a2217
CB
2165 /* In case several capability drop is specified in a single line
2166 * split these caps in a single element for the list.
2167 */
2168 for (dropptr = dropcaps;; dropptr = NULL) {
d028235d
SG
2169 token = strtok_r(dropptr, " \t", &sptr);
2170 if (!token) {
81810dd1 2171 ret = 0;
d028235d 2172 break;
81810dd1 2173 }
81810dd1
DL
2174
2175 droplist = malloc(sizeof(*droplist));
2176 if (!droplist) {
2177 SYSERROR("failed to allocate drop list");
2178 break;
2179 }
2180
2181 droplist->elem = strdup(token);
2182 if (!droplist->elem) {
2183 SYSERROR("failed to dup '%s'", token);
2184 free(droplist);
2185 break;
2186 }
2187
2188 lxc_list_add_tail(&lxc_conf->caps, droplist);
d028235d 2189 }
81810dd1
DL
2190
2191 free(dropcaps);
2192
2193 return ret;
2194}
2195
713046e3 2196static int set_config_console(const char *key, const char *value,
c7e27aaf 2197 struct lxc_conf *lxc_conf, void *data)
28a4b0e5 2198{
713046e3 2199 return set_config_path_item(&lxc_conf->console.path, value);
28a4b0e5
DL
2200}
2201
713046e3 2202static int set_config_console_logfile(const char *key, const char *value,
c7e27aaf 2203 struct lxc_conf *lxc_conf, void *data)
96f15ca1 2204{
713046e3 2205 return set_config_path_item(&lxc_conf->console.log_path, value);
96f15ca1
SH
2206}
2207
6b0d5538 2208int append_unexp_config_line(const char *line, struct lxc_conf *conf)
f979ac15 2209{
6b0d5538 2210 size_t len = conf->unexpanded_len, linelen = strlen(line);
f979ac15 2211
e6744e9b
SH
2212 update_hwaddr(line);
2213
6b0d5538 2214 while (conf->unexpanded_alloced <= len + linelen + 2) {
504a2217
CB
2215 char *tmp = realloc(conf->unexpanded_config,
2216 conf->unexpanded_alloced + 1024);
6b0d5538
SH
2217 if (!tmp)
2218 return -1;
504a2217 2219
6b0d5538
SH
2220 if (!conf->unexpanded_config)
2221 *tmp = '\0';
2222 conf->unexpanded_config = tmp;
2223 conf->unexpanded_alloced += 1024;
2224 }
2225 strcat(conf->unexpanded_config, line);
2226 conf->unexpanded_len += linelen;
504a2217 2227 if (line[linelen - 1] != '\n') {
6b0d5538
SH
2228 strcat(conf->unexpanded_config, "\n");
2229 conf->unexpanded_len++;
f979ac15 2230 }
f979ac15
SH
2231 return 0;
2232}
2233
e1daebd9
SH
2234static int do_includedir(const char *dirp, struct lxc_conf *lxc_conf)
2235{
74f96976 2236 struct dirent *direntp;
e1daebd9
SH
2237 DIR *dir;
2238 char path[MAXPATHLEN];
504a2217
CB
2239 int len;
2240 int ret = -1;
e1daebd9
SH
2241
2242 dir = opendir(dirp);
2243 if (!dir) {
2244 SYSERROR("failed to open '%s'", dirp);
2245 return -1;
2246 }
2247
74f96976 2248 while ((direntp = readdir(dir))) {
e1daebd9
SH
2249 const char *fnam;
2250 if (!direntp)
2251 break;
2252
2253 fnam = direntp->d_name;
2254 if (!strcmp(fnam, "."))
2255 continue;
2256
2257 if (!strcmp(fnam, ".."))
2258 continue;
2259
2260 len = strlen(fnam);
504a2217 2261 if (len < 6 || strncmp(fnam + len - 5, ".conf", 5) != 0)
e1daebd9
SH
2262 continue;
2263 len = snprintf(path, MAXPATHLEN, "%s/%s", dirp, fnam);
2264 if (len < 0 || len >= MAXPATHLEN) {
2265 ERROR("lxc.include filename too long under '%s'", dirp);
2266 ret = -1;
2267 goto out;
2268 }
2269
2270 ret = lxc_config_read(path, lxc_conf, true);
2271 if (ret < 0)
2272 goto out;
2273 }
2274 ret = 0;
2275
2276out:
2277 if (closedir(dir))
2278 WARN("lxc.include dir: failed to close directory");
2279
2280 return ret;
2281}
2282
973082f5 2283static int set_config_includefiles(const char *key, const char *value,
c7e27aaf 2284 struct lxc_conf *lxc_conf, void *data)
09ad6246 2285{
355c5701 2286 /* Set config value to default. */
663e9916 2287 if (lxc_config_value_empty(value)) {
26471403 2288 clr_config_includefiles(key, lxc_conf, NULL);
616422f1 2289 return 0;
355c5701 2290 }
616422f1 2291
355c5701 2292 /* Parse new config value. */
e1daebd9
SH
2293 if (is_dir(value))
2294 return do_includedir(value, lxc_conf);
2295
6b0d5538 2296 return lxc_config_read(value, lxc_conf, true);
09ad6246
SH
2297}
2298
713046e3 2299static int set_config_rootfs(const char *key, const char *value,
c7e27aaf 2300 struct lxc_conf *lxc_conf, void *data)
c2cc9f0a 2301{
713046e3 2302 return set_config_path_item(&lxc_conf->rootfs.path, value);
c2cc9f0a 2303}
2304
713046e3 2305static int set_config_rootfs_mount(const char *key, const char *value,
c7e27aaf 2306 struct lxc_conf *lxc_conf, void *data)
23b7ea69 2307{
713046e3 2308 return set_config_path_item(&lxc_conf->rootfs.mount, value);
23b7ea69
DL
2309}
2310
713046e3 2311static int set_config_rootfs_options(const char *key, const char *value,
c7e27aaf 2312 struct lxc_conf *lxc_conf, void *data)
a17b1e65 2313{
713046e3 2314 return set_config_string_item(&lxc_conf->rootfs.options, value);
a17b1e65
SG
2315}
2316
713046e3 2317static int set_config_rootfs_backend(const char *key, const char *value,
c7e27aaf 2318 struct lxc_conf *lxc_conf, void *data)
bfd77214 2319{
663e9916 2320 if (lxc_config_value_empty(value)) {
6a21d4ae
SH
2321 free(lxc_conf->rootfs.bdev_type);
2322 lxc_conf->rootfs.bdev_type = NULL;
b8223439 2323 return 0;
6a21d4ae 2324 }
b8223439 2325
bfd77214 2326 if (!is_valid_bdev_type(value)) {
327a1e78 2327 ERROR("Bad rootfs.backend: '%s'", value);
bfd77214
SH
2328 return -1;
2329 }
2330
713046e3 2331 return set_config_string_item(&lxc_conf->rootfs.bdev_type, value);
bfd77214
SH
2332}
2333
713046e3 2334static int set_config_utsname(const char *key, const char *value,
c7e27aaf 2335 struct lxc_conf *lxc_conf, void *data)
c2cc9f0a 2336{
2337 struct utsname *utsname;
2338
663e9916 2339 if (lxc_config_value_empty(value)) {
26471403 2340 clr_config_utsname(key, lxc_conf, NULL);
1939e73d 2341 return 0;
00cd8039 2342 }
1939e73d 2343
c2cc9f0a 2344 utsname = malloc(sizeof(*utsname));
2345 if (!utsname) {
36eb9bde 2346 SYSERROR("failed to allocate memory");
c2cc9f0a 2347 return -1;
2348 }
2349
2350 if (strlen(value) >= sizeof(utsname->nodename)) {
00cd8039 2351 ERROR("node name '%s' is too long", value);
b6f24d54 2352 free(utsname);
c2cc9f0a 2353 return -1;
2354 }
2355
2356 strcpy(utsname->nodename, value);
f10fad2f 2357 free(lxc_conf->utsname);
c2cc9f0a 2358 lxc_conf->utsname = utsname;
2359
2360 return 0;
2361}
2362
6b0d5538
SH
2363struct parse_line_conf {
2364 struct lxc_conf *conf;
2365 bool from_include;
2366};
4184c3e1 2367
7a7ff0c6 2368static int parse_line(char *buffer, void *data)
c2cc9f0a 2369{
72d0e1cb 2370 struct lxc_config_t *config;
504a2217 2371 char *dot, *key, *line, *linep, *value;
6b0d5538 2372 struct parse_line_conf *plc = data;
504a2217 2373 int ret = 0;
c2cc9f0a 2374
91480a0f 2375 if (lxc_is_line_empty(buffer))
c2cc9f0a 2376 return 0;
2377
81192358
DL
2378 /* we have to dup the buffer otherwise, at the re-exec for
2379 * reboot we modified the original string on the stack by
2380 * replacing '=' by '\0' below
91480a0f 2381 */
81192358 2382 linep = line = strdup(buffer);
91480a0f
DL
2383 if (!line) {
2384 SYSERROR("failed to allocate memory for '%s'", buffer);
81192358 2385 return -1;
91480a0f
DL
2386 }
2387
6b0d5538
SH
2388 if (!plc->from_include)
2389 if ((ret = append_unexp_config_line(line, plc->conf)))
2390 goto out;
2391
b2718c72 2392 line += lxc_char_left_gc(line, strlen(line));
476d4cf1 2393
4184c3e1
SH
2394 /* ignore comments */
2395 if (line[0] == '#')
91480a0f 2396 goto out;
476d4cf1 2397
6b0d5538
SH
2398 /* martian option - don't add it to the config itself */
2399 if (strncmp(line, "lxc.", 4))
4184c3e1 2400 goto out;
4184c3e1 2401
476d4cf1 2402 ret = -1;
c2cc9f0a 2403
b2718c72 2404 dot = strstr(line, "=");
c2cc9f0a 2405 if (!dot) {
36eb9bde 2406 ERROR("invalid configuration line: %s", line);
91480a0f 2407 goto out;
c2cc9f0a 2408 }
a871ff6b 2409
c2cc9f0a 2410 *dot = '\0';
2411 value = dot + 1;
2412
b2718c72 2413 key = line;
2414 key[lxc_char_right_gc(key, strlen(key))] = '\0';
c2cc9f0a 2415
b2718c72 2416 value += lxc_char_left_gc(value, strlen(value));
2417 value[lxc_char_right_gc(value, strlen(value))] = '\0';
c2cc9f0a 2418
bd878dee
SB
2419 if (*value == '\'' || *value == '\"') {
2420 size_t len = strlen(value);
504a2217
CB
2421 if (len > 1 && value[len - 1] == *value) {
2422 value[len - 1] = '\0';
bd878dee
SB
2423 value++;
2424 }
2425 }
2426
72d0e1cb 2427 config = lxc_getconfig(key);
c2cc9f0a 2428 if (!config) {
6e1d9b94 2429 ERROR("unknown key %s", key);
91480a0f 2430 goto out;
c2cc9f0a 2431 }
2432
bbc079cf 2433 ret = config->set(key, value, plc->conf, NULL);
91480a0f
DL
2434
2435out:
81192358 2436 free(linep);
91480a0f 2437 return ret;
c2cc9f0a 2438}
2439
74a3920a 2440static int lxc_config_readline(char *buffer, struct lxc_conf *conf)
af5b0155 2441{
6b0d5538
SH
2442 struct parse_line_conf c;
2443
2444 c.conf = conf;
2445 c.from_include = false;
2446
2447 return parse_line(buffer, &c);
af5b0155
CLG
2448}
2449
6b0d5538 2450int lxc_config_read(const char *file, struct lxc_conf *conf, bool from_include)
c2cc9f0a 2451{
6b0d5538
SH
2452 struct parse_line_conf c;
2453
2454 c.conf = conf;
2455 c.from_include = from_include;
f979ac15 2456
504a2217 2457 if (access(file, R_OK) == -1) {
f3ca99fd
SH
2458 return -1;
2459 }
6b0d5538 2460
f7bee6c6 2461 /* Catch only the top level config file name in the structure */
504a2217 2462 if (!conf->rcfile)
76d0127f 2463 conf->rcfile = strdup(file);
f979ac15 2464
6b0d5538 2465 return lxc_file_for_each_line(file, parse_line, &c);
c2cc9f0a 2466}
62e46035 2467
504a2217 2468int lxc_config_define_add(struct lxc_list *defines, char *arg)
62e46035
CLG
2469{
2470 struct lxc_list *dent;
2471
2472 dent = malloc(sizeof(struct lxc_list));
2473 if (!dent)
2474 return -1;
2475
2476 dent->elem = arg;
2477 lxc_list_add_tail(defines, dent);
2478 return 0;
2479}
2480
226a18d6 2481int lxc_config_define_load(struct lxc_list *defines, struct lxc_conf *conf)
62e46035 2482{
504a2217 2483 struct lxc_list *it, *next;
62e46035
CLG
2484 int ret = 0;
2485
2486 lxc_list_for_each(it, defines) {
2487 ret = lxc_config_readline(it->elem, conf);
2488 if (ret)
2489 break;
2490 }
2491
9ebb03ad 2492 lxc_list_for_each_safe(it, defines, next) {
62e46035
CLG
2493 lxc_list_del(it);
2494 free(it);
2495 }
2496
2497 return ret;
2498}
525f0002
CS
2499
2500signed long lxc_config_parse_arch(const char *arch)
2501{
504a2217
CB
2502#if HAVE_SYS_PERSONALITY_H
2503 size_t i;
525f0002
CS
2504 struct per_name {
2505 char *name;
2506 unsigned long per;
bb8d8207 2507 } pername[] = {
504a2217
CB
2508 { "x86", PER_LINUX32 },
2509 { "linux32", PER_LINUX32 },
2510 { "i386", PER_LINUX32 },
2511 { "i486", PER_LINUX32 },
2512 { "i586", PER_LINUX32 },
2513 { "i686", PER_LINUX32 },
2514 { "athlon", PER_LINUX32 },
2515 { "mips", PER_LINUX32 },
2516 { "mipsel", PER_LINUX32 },
2517 { "ppc", PER_LINUX32 },
2518 { "arm", PER_LINUX32 },
2519 { "armv7l", PER_LINUX32 },
2520 { "armhf", PER_LINUX32 },
2521 { "armel", PER_LINUX32 },
2522 { "powerpc", PER_LINUX32 },
2523 { "linux64", PER_LINUX },
2524 { "x86_64", PER_LINUX },
2525 { "amd64", PER_LINUX },
2526 { "mips64", PER_LINUX },
2527 { "mips64el", PER_LINUX },
2528 { "ppc64", PER_LINUX },
2529 { "ppc64le", PER_LINUX },
2530 { "ppc64el", PER_LINUX },
2531 { "powerpc64", PER_LINUX },
2532 { "s390x", PER_LINUX },
2533 { "aarch64", PER_LINUX },
2534 { "arm64", PER_LINUX },
525f0002
CS
2535 };
2536 size_t len = sizeof(pername) / sizeof(pername[0]);
2537
525f0002
CS
2538 for (i = 0; i < len; i++) {
2539 if (!strcmp(pername[i].name, arch))
504a2217 2540 return pername[i].per;
525f0002 2541 }
504a2217 2542#endif
525f0002
CS
2543
2544 return -1;
2545}
72d0e1cb 2546
4d69b293
NK
2547int lxc_fill_elevated_privileges(char *flaglist, int *flags)
2548{
2549 char *token, *saveptr = NULL;
2550 int i, aflag;
504a2217
CB
2551 struct {
2552 const char *token;
2553 int flag;
2554 } all_privs[] = {
2555 { "CGROUP", LXC_ATTACH_MOVE_TO_CGROUP },
2556 { "CAP", LXC_ATTACH_DROP_CAPABILITIES },
2557 { "LSM", LXC_ATTACH_LSM_EXEC },
2558 { NULL, 0 }
4d69b293
NK
2559 };
2560
2561 if (!flaglist) {
504a2217
CB
2562 /* For the sake of backward compatibility, drop all privileges
2563 * if none is specified.
2564 */
4d69b293 2565 for (i = 0; all_privs[i].token; i++) {
d028235d 2566 *flags |= all_privs[i].flag;
4d69b293
NK
2567 }
2568 return 0;
2569 }
2570
2571 token = strtok_r(flaglist, "|", &saveptr);
2572 while (token) {
2573 aflag = -1;
2574 for (i = 0; all_privs[i].token; i++) {
2575 if (!strcmp(all_privs[i].token, token))
2576 aflag = all_privs[i].flag;
2577 }
2578 if (aflag < 0)
2579 return -1;
2580
2581 *flags |= aflag;
2582
2583 token = strtok_r(NULL, "|", &saveptr);
2584 }
504a2217 2585
4d69b293
NK
2586 return 0;
2587}
2588
504a2217 2589/* Write out a configuration file. */
72d0e1cb
SG
2590void write_config(FILE *fout, struct lxc_conf *c)
2591{
6b0d5538 2592 int ret;
504a2217 2593 size_t len = c->unexpanded_len;
72d0e1cb 2594
6b0d5538
SH
2595 if (!len)
2596 return;
504a2217 2597
6b0d5538
SH
2598 ret = fwrite(c->unexpanded_config, 1, len, fout);
2599 if (ret != len)
2600 SYSERROR("Error writing configuration file");
2601}
f979ac15 2602
504a2217
CB
2603bool do_append_unexp_config_line(struct lxc_conf *conf, const char *key,
2604 const char *v)
6b0d5538
SH
2605{
2606 int ret;
151d2da2
CB
2607 size_t len;
2608 char *tmp;
4184c3e1 2609
151d2da2
CB
2610 len = strlen(key) + strlen(v) + 4;
2611 tmp = alloca(len);
2612
663e9916 2613 if (lxc_config_value_empty(v))
151d2da2
CB
2614 ret = snprintf(tmp, len, "%s =", key);
2615 else
2616 ret = snprintf(tmp, len, "%s = %s", key, v);
6b0d5538
SH
2617 if (ret < 0 || ret >= len)
2618 return false;
2619
2620 /* Save the line verbatim into unexpanded_conf */
2621 if (append_unexp_config_line(tmp, conf))
2622 return false;
2623
2624 return true;
2625}
2626
504a2217
CB
2627void clear_unexp_config_line(struct lxc_conf *conf, const char *key,
2628 bool rm_subkeys)
6b0d5538 2629{
504a2217
CB
2630 char *lend;
2631 char *lstart = conf->unexpanded_config;
6b0d5538
SH
2632
2633 if (!conf->unexpanded_config)
2634 return;
504a2217 2635
6b0d5538
SH
2636 while (*lstart) {
2637 lend = strchr(lstart, '\n');
2638 char v;
2639 if (!lend)
2640 lend = lstart + strlen(lstart);
2641 else
2642 lend++;
2643 if (strncmp(lstart, key, strlen(key)) != 0) {
2644 lstart = lend;
2645 continue;
5f62730e 2646 }
6b0d5538
SH
2647 if (!rm_subkeys) {
2648 v = lstart[strlen(key)];
2649 if (!isspace(v) && v != '=') {
2650 lstart = lend;
2651 continue;
2652 }
5f62730e 2653 }
6b0d5538
SH
2654 conf->unexpanded_len -= (lend - lstart);
2655 if (*lend == '\0') {
2656 *lstart = '\0';
2657 return;
fd986e08 2658 }
504a2217 2659 memmove(lstart, lend, strlen(lend) + 1);
fd986e08 2660 }
6b0d5538
SH
2661}
2662
329b3625
CB
2663bool clone_update_unexp_ovl_paths(struct lxc_conf *conf, const char *oldpath,
2664 const char *newpath, const char *oldname,
2665 const char *newname, const char *ovldir)
2666{
329b3625 2667 int ret;
504a2217
CB
2668 char *lend, *newdir, *olddir, *p, *q;
2669 size_t newdirlen, olddirlen;
329b3625 2670 char *lstart = conf->unexpanded_config;
504a2217 2671 const char *key = "lxc.mount.entry";
329b3625 2672
504a2217
CB
2673 olddirlen = strlen(ovldir) + strlen(oldpath) + strlen(oldname) + 2;
2674 olddir = alloca(olddirlen + 1);
2675 ret = snprintf(olddir, olddirlen + 1, "%s=%s/%s", ovldir, oldpath,
2676 oldname);
329b3625 2677 if (ret < 0 || ret >= olddirlen + 1) {
504a2217 2678 ERROR("failed to create string");
329b3625
CB
2679 return false;
2680 }
504a2217
CB
2681
2682 newdirlen = strlen(ovldir) + strlen(newpath) + strlen(newname) + 2;
2683 newdir = alloca(newdirlen + 1);
2684 ret = snprintf(newdir, newdirlen + 1, "%s=%s/%s", ovldir, newpath,
2685 newname);
329b3625 2686 if (ret < 0 || ret >= newdirlen + 1) {
504a2217 2687 ERROR("failed to create string");
329b3625
CB
2688 return false;
2689 }
504a2217 2690
329b3625
CB
2691 if (!conf->unexpanded_config)
2692 return true;
504a2217 2693
329b3625
CB
2694 while (*lstart) {
2695 lend = strchr(lstart, '\n');
2696 if (!lend)
2697 lend = lstart + strlen(lstart);
2698 else
2699 lend++;
504a2217 2700
329b3625 2701 if (strncmp(lstart, key, strlen(key)) != 0)
504a2217
CB
2702 goto next;
2703
329b3625
CB
2704 p = strchr(lstart + strlen(key), '=');
2705 if (!p)
504a2217 2706 goto next;
329b3625 2707 p++;
504a2217 2708
329b3625
CB
2709 while (isblank(*p))
2710 p++;
504a2217 2711
329b3625 2712 if (p >= lend)
504a2217
CB
2713 goto next;
2714
2715 /* Whenever an lxc.mount.entry entry is found in a line we check
2716 * if the substring " overlay" or the substring " aufs" is
2717 * present before doing any further work. We check for "
2718 * overlay" and " aufs" since both substrings need to have at
2719 * least one space before them in a valid overlay
2720 * lxc.mount.entry (/A B overlay). When the space before is
2721 * missing it is very likely that these substrings are part of a
2722 * path or something else. (Checking q >= lend ensures that we
2723 * only count matches in the current line.) */
2724 if ((!(q = strstr(p, " overlay")) || q >= lend) &&
2725 (!(q = strstr(p, " aufs")) || q >= lend))
2726 goto next;
2727
329b3625 2728 if (!(q = strstr(p, olddir)) || (q >= lend))
504a2217 2729 goto next;
329b3625
CB
2730
2731 /* replace the olddir with newdir */
2732 if (olddirlen >= newdirlen) {
2733 size_t diff = olddirlen - newdirlen;
2734 memcpy(q, newdir, newdirlen);
2735 if (olddirlen != newdirlen) {
2736 memmove(q + newdirlen, q + newdirlen + diff,
2737 strlen(q) - newdirlen - diff + 1);
2738 lend -= diff;
2739 conf->unexpanded_len -= diff;
2740 }
2741 } else {
2742 char *new;
2743 size_t diff = newdirlen - olddirlen;
2744 size_t oldlen = conf->unexpanded_len;
2745 size_t newlen = oldlen + diff;
2746 size_t poffset = q - conf->unexpanded_config;
504a2217 2747
329b3625
CB
2748 new = realloc(conf->unexpanded_config, newlen + 1);
2749 if (!new) {
2750 ERROR("Out of memory");
2751 return false;
2752 }
2753 conf->unexpanded_len = newlen;
2754 conf->unexpanded_alloced = newlen + 1;
2755 new[newlen - 1] = '\0';
2756 lend = new + (lend - conf->unexpanded_config);
504a2217
CB
2757 /* move over the remainder to make room for the newdir
2758 */
329b3625
CB
2759 memmove(new + poffset + newdirlen,
2760 new + poffset + olddirlen,
2761 oldlen - poffset - olddirlen + 1);
2762 conf->unexpanded_config = new;
2763 memcpy(new + poffset, newdir, newdirlen);
2764 lend += diff;
2765 }
504a2217
CB
2766 next:
2767 lstart = lend;
329b3625 2768 }
504a2217 2769
329b3625
CB
2770 return true;
2771}
2772
67702c21 2773bool clone_update_unexp_hooks(struct lxc_conf *conf, const char *oldpath,
d546aa0e
CB
2774 const char *newpath, const char *oldname,
2775 const char *newname)
6b0d5538 2776{
67702c21 2777 int ret;
504a2217
CB
2778 char *lend, *newdir, *olddir, *p;
2779 char *lstart = conf->unexpanded_config;
2780 size_t newdirlen, olddirlen;
2781 const char *key = "lxc.hook";
67702c21 2782
504a2217
CB
2783 olddirlen = strlen(oldpath) + strlen(oldname) + 1;
2784 olddir = alloca(olddirlen + 1);
d546aa0e
CB
2785 ret = snprintf(olddir, olddirlen + 1, "%s/%s", oldpath, oldname);
2786 if (ret < 0 || ret >= olddirlen + 1) {
504a2217 2787 ERROR("failed to create string");
67702c21
SH
2788 return false;
2789 }
504a2217
CB
2790
2791 newdirlen = strlen(newpath) + strlen(newname) + 1;
2792 newdir = alloca(newdirlen + 1);
d546aa0e
CB
2793 ret = snprintf(newdir, newdirlen + 1, "%s/%s", newpath, newname);
2794 if (ret < 0 || ret >= newdirlen + 1) {
504a2217 2795 ERROR("failed to create string");
67702c21
SH
2796 return false;
2797 }
2798 if (!conf->unexpanded_config)
2799 return true;
2800 while (*lstart) {
2801 lend = strchr(lstart, '\n');
2802 if (!lend)
2803 lend = lstart + strlen(lstart);
2804 else
2805 lend++;
504a2217 2806
d546aa0e 2807 if (strncmp(lstart, key, strlen(key)) != 0)
504a2217
CB
2808 goto next;
2809
d546aa0e
CB
2810 p = strchr(lstart + strlen(key), '=');
2811 if (!p)
504a2217 2812 goto next;
67702c21 2813 p++;
504a2217 2814
67702c21
SH
2815 while (isblank(*p))
2816 p++;
504a2217
CB
2817
2818 if (p >= lend)
2819 goto next;
2820
d546aa0e 2821 if (strncmp(p, olddir, strlen(olddir)) != 0)
504a2217
CB
2822 goto next;
2823
67702c21
SH
2824 /* replace the olddir with newdir */
2825 if (olddirlen >= newdirlen) {
2826 size_t diff = olddirlen - newdirlen;
2827 memcpy(p, newdir, newdirlen);
2828 if (olddirlen != newdirlen) {
d546aa0e
CB
2829 memmove(p + newdirlen, p + newdirlen + diff,
2830 strlen(p) - newdirlen - diff + 1);
67702c21
SH
2831 lend -= diff;
2832 conf->unexpanded_len -= diff;
2833 }
67702c21
SH
2834 } else {
2835 char *new;
2836 size_t diff = newdirlen - olddirlen;
2837 size_t oldlen = conf->unexpanded_len;
2838 size_t newlen = oldlen + diff;
2839 size_t poffset = p - conf->unexpanded_config;
504a2217 2840
d546aa0e 2841 new = realloc(conf->unexpanded_config, newlen + 1);
67702c21 2842 if (!new) {
504a2217 2843 ERROR("failed to allocate memory");
6b0d5538 2844 return false;
67702c21
SH
2845 }
2846 conf->unexpanded_len = newlen;
d546aa0e
CB
2847 conf->unexpanded_alloced = newlen + 1;
2848 new[newlen - 1] = '\0';
67702c21 2849 lend = new + (lend - conf->unexpanded_config);
504a2217
CB
2850 /* move over the remainder to make room for the newdir
2851 */
d546aa0e
CB
2852 memmove(new + poffset + newdirlen,
2853 new + poffset + olddirlen,
2854 oldlen - poffset - olddirlen + 1);
67702c21 2855 conf->unexpanded_config = new;
d546aa0e
CB
2856 memcpy(new + poffset, newdir, newdirlen);
2857 lend += diff;
fd986e08 2858 }
504a2217
CB
2859 next:
2860 lstart = lend;
fd986e08 2861 }
504a2217 2862
6b0d5538
SH
2863 return true;
2864}
2865
504a2217
CB
2866#define DO(cmd) \
2867 { \
2868 if (!(cmd)) { \
2869 ERROR("Error writing to new config"); \
2870 return false; \
2871 } \
2872 }
6b0d5538 2873
67702c21 2874/*
504a2217
CB
2875 * This is called only from clone. We wish to update all hwaddrs in the
2876 * unexpanded config file. We can't/don't want to update any which come from
2877 * lxc.includes (there shouldn't be any).
2878 * We can't just walk the c->lxc-conf->network list because that includes netifs
2879 * from the include files. So we update the ones which we find in the unexp
2880 * config file, then find the original macaddr in the conf->network, and update
2881 * that to the same value.
67702c21
SH
2882 */
2883bool network_new_hwaddrs(struct lxc_conf *conf)
6b0d5538 2884{
504a2217 2885 char *lend, *p, *p2;
6b0d5538 2886 struct lxc_list *it;
67702c21 2887 const char *key = "lxc.network.hwaddr";
504a2217 2888 char *lstart = conf->unexpanded_config;
6b0d5538 2889
67702c21
SH
2890 if (!conf->unexpanded_config)
2891 return true;
091045f8 2892
67702c21
SH
2893 while (*lstart) {
2894 char newhwaddr[18], oldhwaddr[17];
091045f8 2895
67702c21
SH
2896 lend = strchr(lstart, '\n');
2897 if (!lend)
2898 lend = lstart + strlen(lstart);
2899 else
2900 lend++;
091045f8 2901
67702c21
SH
2902 if (strncmp(lstart, key, strlen(key)) != 0) {
2903 lstart = lend;
2904 continue;
72d0e1cb 2905 }
091045f8 2906
504a2217 2907 p = strchr(lstart + strlen(key), '=');
67702c21
SH
2908 if (!p) {
2909 lstart = lend;
2910 continue;
72d0e1cb 2911 }
091045f8 2912
67702c21
SH
2913 p++;
2914 while (isblank(*p))
2915 p++;
2916 if (!*p)
2917 return true;
091045f8 2918
67702c21
SH
2919 p2 = p;
2920 while (*p2 && !isblank(*p2) && *p2 != '\n')
2921 p2++;
504a2217
CB
2922
2923 if ((p2 - p) != 17) {
67702c21
SH
2924 WARN("Bad hwaddr entry");
2925 lstart = lend;
2926 continue;
72d0e1cb 2927 }
091045f8 2928
67702c21 2929 memcpy(oldhwaddr, p, 17);
091045f8
CB
2930
2931 if (!new_hwaddr(newhwaddr))
2932 return false;
2933
67702c21 2934 memcpy(p, newhwaddr, 17);
504a2217
CB
2935 lxc_list_for_each(it, &conf->network)
2936 {
67702c21
SH
2937 struct lxc_netdev *n = it->elem;
2938 if (n->hwaddr && memcmp(oldhwaddr, n->hwaddr, 17) == 0)
2939 memcpy(n->hwaddr, newhwaddr, 17);
72d0e1cb 2940 }
67702c21
SH
2941
2942 lstart = lend;
72d0e1cb 2943 }
091045f8 2944
6b0d5538 2945 return true;
72d0e1cb 2946}
8796becf 2947
713046e3 2948static int set_config_ephemeral(const char *key, const char *value,
c7e27aaf 2949 struct lxc_conf *lxc_conf, void *data)
8796becf 2950{
3c6cf53a 2951 /* Set config value to default. */
663e9916 2952 if (lxc_config_value_empty(value)) {
3c6cf53a 2953 lxc_conf->ephemeral = 0;
78304622 2954 return 0;
3c6cf53a 2955 }
78304622 2956
3c6cf53a 2957 /* Parse new config value. */
66ffdb1a
CB
2958 if (lxc_safe_uint(value, &lxc_conf->ephemeral) < 0)
2959 return -1;
8796becf 2960
66ffdb1a 2961 if (lxc_conf->ephemeral > 1) {
504a2217
CB
2962 ERROR(
2963 "Wrong value for lxc.ephemeral. Can only be set to 0 or 1");
8796becf 2964 return -1;
8796becf
CB
2965 }
2966
2967 return 0;
2968}
2969
713046e3 2970static int set_config_syslog(const char *key, const char *value,
c7e27aaf 2971 struct lxc_conf *lxc_conf, void *data)
64c57ea1 2972{
76d0127f 2973 int facility;
7ca56b84 2974
ee10a69c
CB
2975 /* Clear any previously set value. */
2976 if (lxc_conf->syslog) {
2977 free(lxc_conf->syslog);
2978 lxc_conf->syslog = NULL;
2979 }
2980
2981 /* Check if value is empty. */
663e9916 2982 if (lxc_config_value_empty(value))
7ca56b84
CB
2983 return 0;
2984
ee10a69c 2985 /* Parse value. */
76d0127f
CB
2986 facility = lxc_syslog_priority_to_int(value);
2987 if (facility == -EINVAL) {
d47f1b43 2988 ERROR("Wrong value for lxc.syslog.");
76d0127f 2989 return -1;
64c57ea1
BD
2990 }
2991
76d0127f 2992 lxc_log_syslog(facility);
713046e3 2993 return set_config_string_item(&lxc_conf->syslog, value);
64c57ea1 2994}
5a46f283 2995
713046e3 2996static int set_config_no_new_privs(const char *key, const char *value,
c7e27aaf 2997 struct lxc_conf *lxc_conf, void *data)
5a46f283 2998{
e8ec7c9e 2999 unsigned int v;
5a46f283 3000
cf3f8bf6 3001 /* Set config value to default. */
663e9916 3002 if (lxc_config_value_empty(value)) {
cf3f8bf6 3003 lxc_conf->no_new_privs = false;
80926845 3004 return 0;
cf3f8bf6 3005 }
80926845 3006
cf3f8bf6 3007 /* Parse new config value. */
e8ec7c9e
CB
3008 if (lxc_safe_uint(value, &v) < 0)
3009 return -1;
3010
3011 if (v > 1) {
504a2217
CB
3012 ERROR("Wrong value for lxc.no_new_privs. Can only be set to 0 "
3013 "or 1");
5a46f283
CB
3014 return -1;
3015 }
e8ec7c9e 3016
5a46f283
CB
3017 lxc_conf->no_new_privs = v ? true : false;
3018
3019 return 0;
3020}
7b992a3e
CB
3021
3022/* Callbacks to get configuration items. */
6bede808 3023static int get_config_personality(const char *key, char *retv, int inlen,
cccd2219 3024 struct lxc_conf *c, void *data)
7b992a3e
CB
3025{
3026 int fulllen = 0;
3027
3028 if (!retv)
3029 inlen = 0;
3030 else
3031 memset(retv, 0, inlen);
3032
3033#if HAVE_SYS_PERSONALITY_H
3034 int len = 0;
3035
6bede808 3036 switch (c->personality) {
7b992a3e
CB
3037 case PER_LINUX32:
3038 strprint(retv, inlen, "i686");
3039 break;
3040 case PER_LINUX:
3041 strprint(retv, inlen, "x86_64");
3042 break;
3043 default:
3044 break;
3045 }
3046#endif
3047
3048 return fulllen;
3049}
bdf91ab4 3050
6bede808 3051static int get_config_pts(const char *key, char *retv, int inlen,
cccd2219 3052 struct lxc_conf *c, void *data)
bdf91ab4 3053{
6bede808 3054 return lxc_get_conf_int(c, retv, inlen, c->pts);
bdf91ab4 3055}
5485782f 3056
6bede808 3057static int get_config_tty(const char *key, char *retv, int inlen,
cccd2219 3058 struct lxc_conf *c, void *data)
5485782f 3059{
6bede808 3060 return lxc_get_conf_int(c, retv, inlen, c->tty);
5485782f 3061}
8015e018 3062
6bede808 3063static int get_config_ttydir(const char *key, char *retv, int inlen,
cccd2219 3064 struct lxc_conf *c, void *data)
8015e018 3065{
6bede808 3066 return lxc_get_conf_str(retv, inlen, c->ttydir);
8015e018 3067}
de1ede69 3068
953fe44f
CB
3069static int get_config_apparmor_profile(const char *key, char *retv, int inlen,
3070 struct lxc_conf *c, void *data)
104c8e6c 3071{
6bede808 3072 return lxc_get_conf_str(retv, inlen, c->lsm_aa_profile);
104c8e6c 3073}
d60d18c6 3074
953fe44f
CB
3075static int get_config_apparmor_allow_incomplete(const char *key, char *retv,
3076 int inlen, struct lxc_conf *c,
3077 void *data)
d60d18c6 3078{
6bede808
CB
3079 return lxc_get_conf_int(c, retv, inlen,
3080 c->lsm_aa_allow_incomplete);
d60d18c6 3081}
4203a0b5 3082
953fe44f
CB
3083static int get_config_selinux_context(const char *key, char *retv, int inlen,
3084 struct lxc_conf *c, void *data)
4203a0b5 3085{
6bede808 3086 return lxc_get_conf_str(retv, inlen, c->lsm_se_context);
4203a0b5 3087}
b863bf92
CB
3088
3089/*
3090 * If you ask for a specific cgroup value, i.e. lxc.cgroup.devices.list,
3091 * then just the value(s) will be printed. Since there still could be
3092 * more than one, it is newline-separated.
3093 * (Maybe that's ambigous, since some values, i.e. devices.list, will
3094 * already have newlines?)
3095 * If you ask for 'lxc.cgroup", then all cgroup entries will be printed,
3096 * in 'lxc.cgroup.subsystem.key = value' format.
3097 */
6bede808 3098static int get_config_cgroup(const char *key, char *retv, int inlen,
cccd2219 3099 struct lxc_conf *c, void *data)
b863bf92
CB
3100{
3101 struct lxc_list *it;
3102 int len;
3103 int fulllen = 0;
3104 bool get_all = false;
3105
3106 if (!retv)
3107 inlen = 0;
3108 else
3109 memset(retv, 0, inlen);
3110
3111 if (!strcmp(key, "lxc.cgroup"))
3112 get_all = true;
3113 else if (!strncmp(key, "lxc.cgroup.", 11))
3114 key += 11;
3115 else
3116 return -1;
3117
6bede808 3118 lxc_list_for_each(it, &c->cgroup) {
b863bf92
CB
3119 struct lxc_cgroup *cg = it->elem;
3120 if (get_all) {
3121 strprint(retv, inlen, "lxc.cgroup.%s = %s\n", cg->subsystem, cg->value);
3122 } else if (!strcmp(cg->subsystem, key)) {
3123 strprint(retv, inlen, "%s\n", cg->value);
3124 }
3125 }
3126
3127 return fulllen;
3128}
5014ff2e 3129
6bede808 3130static int get_config_idmaps(const char *key, char *retv, int inlen,
cccd2219 3131 struct lxc_conf *c, void *data)
5014ff2e
CB
3132{
3133 struct lxc_list *it;
3134 int len, listlen, ret;
3135 int fulllen = 0;
3136/* "u 1000 1000000 65536"
3137 *
3138 * let's render this as
3139 *
3140 * sizeof(char)
3141 * +
3142 * sizeof(" ")
3143 * +
3144 * sizeof(uint64_t)
3145 * +
3146 * sizeof(" ")
3147 * +
3148 * sizeof(uint64_t)
3149 * +
3150 * sizeof(" ")
3151 * +
3152 * sizeof(uint64_t)
3153 * +
3154 * \0
3155 */
3156#define __LXC_IDMAP_STR_BUF (3 * LXC_NUMSTRLEN64 + 3 + 1 + 1)
3157 char buf[__LXC_IDMAP_STR_BUF];
3158
3159 if (!retv)
3160 inlen = 0;
3161 else
3162 memset(retv, 0, inlen);
3163
6bede808
CB
3164 listlen = lxc_list_len(&c->id_map);
3165 lxc_list_for_each(it, &c->id_map)
5014ff2e
CB
3166 {
3167 struct id_map *map = it->elem;
3168 ret = snprintf(buf, __LXC_IDMAP_STR_BUF, "%c %lu %lu %lu",
3169 (map->idtype == ID_TYPE_UID) ? 'u' : 'g',
3170 map->nsid, map->hostid, map->range);
3171 if (ret < 0 || ret >= __LXC_IDMAP_STR_BUF)
3172 return -1;
3173
3174 strprint(retv, inlen, "%s%s", buf, (listlen-- > 1) ? "\n" : "");
3175 }
3176 return fulllen;
3177}
b29b29be 3178
6bede808 3179static int get_config_loglevel(const char *key, char *retv, int inlen,
cccd2219 3180 struct lxc_conf *c, void *data)
b29b29be
CB
3181{
3182 const char *v;
6bede808 3183 v = lxc_log_priority_to_string(c->loglevel);
b29b29be
CB
3184 return lxc_get_conf_str(retv, inlen, v);
3185}
3d4630ab 3186
6bede808 3187static int get_config_logfile(const char *key, char *retv, int inlen,
cccd2219 3188 struct lxc_conf *c, void *data)
3d4630ab 3189{
6bede808 3190 return lxc_get_conf_str(retv, inlen, c->logfile);
3d4630ab 3191}
0d601acb 3192
6bede808 3193static int get_config_fstab(const char *key, char *retv, int inlen,
cccd2219 3194 struct lxc_conf *c, void *data)
0d601acb 3195{
6bede808 3196 return lxc_get_conf_str(retv, inlen, c->fstab);
0d601acb 3197}
43fbf8d9 3198
6bede808 3199static int get_config_mount_auto(const char *key, char *retv, int inlen,
cccd2219 3200 struct lxc_conf *c, void *data)
43fbf8d9
CB
3201{
3202 int len, fulllen = 0;
3203 const char *sep = "";
3204
3205 if (!retv)
3206 inlen = 0;
3207 else
3208 memset(retv, 0, inlen);
3209
6bede808 3210 if (!(c->auto_mounts & LXC_AUTO_ALL_MASK))
43fbf8d9
CB
3211 return 0;
3212
6bede808 3213 switch (c->auto_mounts & LXC_AUTO_PROC_MASK) {
43fbf8d9
CB
3214 case LXC_AUTO_PROC_MIXED:
3215 strprint(retv, inlen, "%sproc:mixed", sep);
3216 sep = " ";
3217 break;
3218 case LXC_AUTO_PROC_RW:
3219 strprint(retv, inlen, "%sproc:rw", sep);
3220 sep = " ";
3221 break;
3222 default:
3223 break;
3224 }
3225
6bede808 3226 switch (c->auto_mounts & LXC_AUTO_SYS_MASK) {
43fbf8d9
CB
3227 case LXC_AUTO_SYS_RO:
3228 strprint(retv, inlen, "%ssys:ro", sep);
3229 sep = " ";
3230 break;
3231 case LXC_AUTO_SYS_RW:
3232 strprint(retv, inlen, "%ssys:rw", sep);
3233 sep = " ";
3234 break;
3235 case LXC_AUTO_SYS_MIXED:
3236 strprint(retv, inlen, "%ssys:mixed", sep);
3237 sep = " ";
3238 break;
3239 default:
3240 break;
3241 }
3242
6bede808 3243 switch (c->auto_mounts & LXC_AUTO_CGROUP_MASK) {
43fbf8d9
CB
3244 case LXC_AUTO_CGROUP_NOSPEC:
3245 strprint(retv, inlen, "%scgroup", sep);
3246 sep = " ";
3247 break;
3248 case LXC_AUTO_CGROUP_MIXED:
3249 strprint(retv, inlen, "%scgroup:mixed", sep);
3250 sep = " ";
3251 break;
3252 case LXC_AUTO_CGROUP_RO:
3253 strprint(retv, inlen, "%scgroup:ro", sep);
3254 sep = " ";
3255 break;
3256 case LXC_AUTO_CGROUP_RW:
3257 strprint(retv, inlen, "%scgroup:rw", sep);
3258 sep = " ";
3259 break;
3260 case LXC_AUTO_CGROUP_FULL_NOSPEC:
3261 strprint(retv, inlen, "%scgroup-full", sep);
3262 sep = " ";
3263 break;
3264 case LXC_AUTO_CGROUP_FULL_MIXED:
3265 strprint(retv, inlen, "%scgroup-full:mixed", sep);
3266 sep = " ";
3267 break;
3268 case LXC_AUTO_CGROUP_FULL_RO:
3269 strprint(retv, inlen, "%scgroup-full:ro", sep);
3270 sep = " ";
3271 break;
3272 case LXC_AUTO_CGROUP_FULL_RW:
3273 strprint(retv, inlen, "%scgroup-full:rw", sep);
3274 sep = " ";
3275 break;
3276 default:
3277 break;
3278 }
3279
3280 return fulllen;
3281}
cc921848 3282
6bede808 3283static int get_config_mount(const char *key, char *retv, int inlen,
cccd2219 3284 struct lxc_conf *c, void *data)
cc921848
CB
3285{
3286 int len, fulllen = 0;
3287 struct lxc_list *it;
3288
3289 if (!retv)
3290 inlen = 0;
3291 else
3292 memset(retv, 0, inlen);
3293
6bede808 3294 lxc_list_for_each(it, &c->mount_list)
cc921848
CB
3295 {
3296 strprint(retv, inlen, "%s\n", (char *)it->elem);
3297 }
3298
3299 return fulllen;
3300}
819114b6 3301
6bede808 3302static int get_config_rootfs(const char *key, char *retv, int inlen,
cccd2219 3303 struct lxc_conf *c, void *data)
819114b6 3304{
6bede808 3305 return lxc_get_conf_str(retv, inlen, c->rootfs.path);
819114b6 3306}
3af60359 3307
6bede808 3308static int get_config_rootfs_mount(const char *key, char *retv, int inlen,
cccd2219 3309 struct lxc_conf *c, void *data)
3af60359 3310{
6bede808 3311 return lxc_get_conf_str(retv, inlen, c->rootfs.mount);
3af60359 3312}
0e9db631 3313
6bede808 3314static int get_config_rootfs_options(const char *key, char *retv, int inlen,
cccd2219 3315 struct lxc_conf *c, void *data)
0e9db631 3316{
6bede808 3317 return lxc_get_conf_str(retv, inlen, c->rootfs.options);
0e9db631 3318}
8f183f38 3319
6bede808 3320static int get_config_rootfs_backend(const char *key, char *retv, int inlen,
cccd2219 3321 struct lxc_conf *c, void *data)
8f183f38 3322{
6bede808 3323 return lxc_get_conf_str(retv, inlen, c->rootfs.bdev_type);
8f183f38 3324}
b87574e7 3325
6bede808 3326static int get_config_utsname(const char *key, char *retv, int inlen,
cccd2219 3327 struct lxc_conf *c, void *data)
e274f8b0
CB
3328{
3329 return lxc_get_conf_str(
3330 retv, inlen,
6bede808 3331 c->utsname ? c->utsname->nodename : NULL);
e274f8b0 3332}
466c2e93 3333
6bede808 3334static int get_config_hooks(const char *key, char *retv, int inlen,
cccd2219 3335 struct lxc_conf *c, void *data)
466c2e93
CB
3336{
3337 char *subkey;
3338 int len, fulllen = 0, found = -1;
3339 struct lxc_list *it;
3340 int i;
3341
3342 /* "lxc.hook.mount" */
3343 subkey = strchr(key, '.');
3344 if (subkey)
3345 subkey = strchr(subkey + 1, '.');
3346 if (!subkey)
3347 return -1;
3348 subkey++;
3349 if (!*subkey)
3350 return -1;
3351 for (i = 0; i < NUM_LXC_HOOKS; i++) {
3352 if (strcmp(lxchook_names[i], subkey) == 0) {
3353 found = i;
3354 break;
3355 }
3356 }
3357 if (found == -1)
3358 return -1;
3359
3360 if (!retv)
3361 inlen = 0;
3362 else
3363 memset(retv, 0, inlen);
3364
6bede808 3365 lxc_list_for_each(it, &c->hooks[found]) {
466c2e93
CB
3366 strprint(retv, inlen, "%s\n", (char *)it->elem);
3367 }
3368 return fulllen;
3369}
d2ceff53 3370
f9373e40
CB
3371static int get_config_net(const char *key, char *retv, int inlen,
3372 struct lxc_conf *c, void *data)
d2ceff53
CB
3373{
3374 int len, fulllen = 0;
3375 struct lxc_list *it;
3376
3377 if (!retv)
3378 inlen = 0;
3379 else
3380 memset(retv, 0, inlen);
3381
6bede808 3382 lxc_list_for_each(it, &c->network) {
d2ceff53
CB
3383 struct lxc_netdev *n = it->elem;
3384 const char *t = lxc_net_type_to_str(n->type);
3385 strprint(retv, inlen, "%s\n", t ? t : "(invalid)");
3386 }
3387
3388 return fulllen;
3389}
bdccff60 3390
6bede808 3391static int get_config_cap_drop(const char *key, char *retv, int inlen,
cccd2219 3392 struct lxc_conf *c, void *data)
1c96d6d8
CB
3393{
3394 int len, fulllen = 0;
3395 struct lxc_list *it;
3396
3397 if (!retv)
3398 inlen = 0;
3399 else
3400 memset(retv, 0, inlen);
3401
6bede808 3402 lxc_list_for_each(it, &c->caps) {
b80927f2
CB
3403 strprint(retv, inlen, "%s\n", (char *)it->elem);
3404 }
3405 return fulllen;
3406}
3407
6bede808 3408static int get_config_cap_keep(const char *key, char *retv, int inlen,
cccd2219 3409 struct lxc_conf *c, void *data)
b80927f2
CB
3410{
3411 int len, fulllen = 0;
3412 struct lxc_list *it;
3413
3414 if (!retv)
3415 inlen = 0;
3416 else
3417 memset(retv, 0, inlen);
3418
6bede808 3419 lxc_list_for_each(it, &c->keepcaps) {
1c96d6d8
CB
3420 strprint(retv, inlen, "%s\n", (char *)it->elem);
3421 }
3422 return fulllen;
3423}
0692663a 3424
6bede808 3425static int get_config_console(const char *key, char *retv, int inlen,
cccd2219 3426 struct lxc_conf *c, void *data)
0692663a 3427{
6bede808 3428 return lxc_get_conf_str(retv, inlen, c->console.path);
0692663a 3429}
794d1c06 3430
6bede808 3431static int get_config_console_logfile(const char *key, char *retv, int inlen,
cccd2219 3432 struct lxc_conf *c, void *data)
794d1c06 3433{
6bede808 3434 return lxc_get_conf_str(retv, inlen, c->console.log_path);
794d1c06 3435}
75f55b1f 3436
6bede808 3437static int get_config_seccomp(const char *key, char *retv, int inlen,
cccd2219 3438 struct lxc_conf *c, void *data)
75f55b1f 3439{
6bede808 3440 return lxc_get_conf_str(retv, inlen, c->seccomp);
75f55b1f 3441}
97f6dad0 3442
6bede808 3443static int get_config_autodev(const char *key, char *retv, int inlen,
cccd2219 3444 struct lxc_conf *c, void *data)
97f6dad0 3445{
6bede808 3446 return lxc_get_conf_int(c, retv, inlen, c->autodev);
97f6dad0 3447}
afee4324 3448
6bede808 3449static int get_config_haltsignal(const char *key, char *retv, int inlen,
cccd2219 3450 struct lxc_conf *c, void *data)
afee4324 3451{
6bede808 3452 return lxc_get_conf_int(c, retv, inlen, c->haltsignal);
afee4324 3453}
3aa8f359 3454
6bede808 3455static int get_config_rebootsignal(const char *key, char *retv, int inlen,
cccd2219 3456 struct lxc_conf *c, void *data)
3aa8f359 3457{
6bede808 3458 return lxc_get_conf_int(c, retv, inlen, c->rebootsignal);
3aa8f359 3459}
2e16269f 3460
6bede808 3461static int get_config_stopsignal(const char *key, char *retv, int inlen,
cccd2219 3462 struct lxc_conf *c, void *data)
2e16269f 3463{
6bede808 3464 return lxc_get_conf_int(c, retv, inlen, c->stopsignal);
2e16269f 3465}
54345299 3466
6bede808 3467static int get_config_start(const char *key, char *retv, int inlen,
cccd2219 3468 struct lxc_conf *c, void *data)
54345299 3469{
c6182222 3470 if (strcmp(key + 10, "auto") == 0)
6bede808 3471 return lxc_get_conf_int(c, retv, inlen, c->start_auto);
c6182222 3472 else if (strcmp(key + 10, "delay") == 0)
6bede808 3473 return lxc_get_conf_int(c, retv, inlen, c->start_delay);
c6182222 3474 else if (strcmp(key + 10, "order") == 0)
6bede808 3475 return lxc_get_conf_int(c, retv, inlen, c->start_order);
54345299
CB
3476
3477 return -1;
3478}
de9df15e 3479
6bede808 3480static int get_config_syslog(const char *key, char *retv, int inlen,
cccd2219 3481 struct lxc_conf *c, void *data)
de9df15e 3482{
6bede808 3483 return lxc_get_conf_str(retv, inlen, c->syslog);
de9df15e 3484}
ac0f949c 3485
6bede808 3486static int get_config_monitor(const char *key, char *retv, int inlen,
cccd2219 3487 struct lxc_conf *c, void *data)
ac0f949c 3488{
6bede808 3489 return lxc_get_conf_int(c, retv, inlen, c->monitor_unshare);
ac0f949c 3490}
90ec7b6e 3491
6bede808 3492static int get_config_group(const char *key, char *retv, int inlen,
cccd2219 3493 struct lxc_conf *c, void *data)
90ec7b6e
CB
3494{
3495 int len, fulllen = 0;
3496 struct lxc_list *it;
3497
3498 if (!retv)
3499 inlen = 0;
3500 else
3501 memset(retv, 0, inlen);
3502
6bede808 3503 lxc_list_for_each(it, &c->groups) {
90ec7b6e
CB
3504 strprint(retv, inlen, "%s\n", (char *)it->elem);
3505 }
3506 return fulllen;
3507}
aa0db7d3 3508
6bede808 3509static int get_config_environment(const char *key, char *retv, int inlen,
cccd2219 3510 struct lxc_conf *c, void *data)
aa0db7d3
CB
3511{
3512 int len, fulllen = 0;
3513 struct lxc_list *it;
3514
3515 if (!retv)
3516 inlen = 0;
3517 else
3518 memset(retv, 0, inlen);
3519
6bede808 3520 lxc_list_for_each(it, &c->environment) {
aa0db7d3
CB
3521 strprint(retv, inlen, "%s\n", (char *)it->elem);
3522 }
3523 return fulllen;
3524}
96dfcb7d 3525
6bede808 3526static int get_config_init_cmd(const char *key, char *retv, int inlen,
cccd2219 3527 struct lxc_conf *c, void *data)
96dfcb7d 3528{
6bede808 3529 return lxc_get_conf_str(retv, inlen, c->init_cmd);
96dfcb7d 3530}
1398e9b1 3531
6bede808 3532static int get_config_init_uid(const char *key, char *retv, int inlen,
cccd2219 3533 struct lxc_conf *c, void *data)
1398e9b1 3534{
6bede808 3535 return lxc_get_conf_int(c, retv, inlen, c->init_uid);
1398e9b1 3536}
dfeb7e42 3537
6bede808 3538static int get_config_init_gid(const char *key, char *retv, int inlen,
cccd2219 3539 struct lxc_conf *c, void *data)
dfeb7e42 3540{
6bede808 3541 return lxc_get_conf_int(c, retv, inlen, c->init_gid);
dfeb7e42 3542}
62048afe 3543
6bede808 3544static int get_config_ephemeral(const char *key, char *retv, int inlen,
cccd2219 3545 struct lxc_conf *c, void *data)
62048afe 3546{
6bede808 3547 return lxc_get_conf_int(c, retv, inlen, c->ephemeral);
62048afe 3548}
b09521ac 3549
6bede808 3550static int get_config_no_new_privs(const char *key, char *retv, int inlen,
cccd2219 3551 struct lxc_conf *c, void *data)
b09521ac 3552{
6bede808 3553 return lxc_get_conf_int(c, retv, inlen, c->no_new_privs);
b09521ac 3554}
389f6466
CB
3555
3556/*
3557 * If you ask for a specific value, i.e. lxc.limit.nofile, then just the value
3558 * will be printed. If you ask for 'lxc.limit', then all limit entries will be
3559 * printed, in 'lxc.limit.resource = value' format.
3560 */
6bede808 3561static int get_config_limit(const char *key, char *retv, int inlen,
cccd2219 3562 struct lxc_conf *c, void *data)
389f6466
CB
3563{
3564 int fulllen = 0, len;
3565 bool get_all = false;
3566 struct lxc_list *it;
3567
3568 if (!retv)
3569 inlen = 0;
3570 else
3571 memset(retv, 0, inlen);
3572
3573 if (!strcmp(key, "lxc.limit"))
3574 get_all = true;
3575 else if (strncmp(key, "lxc.limit.", 10) == 0)
3576 key += 10;
3577 else
3578 return -1;
3579
6bede808 3580 lxc_list_for_each(it, &c->limits) {
389f6466
CB
3581 char buf[LXC_NUMSTRLEN64 * 2 + 2]; /* 2 colon separated 64 bit
3582 integers or the word
3583 'unlimited' */
3584 int partlen;
3585 struct lxc_limit *lim = it->elem;
3586
3587 if (lim->limit.rlim_cur == RLIM_INFINITY) {
3588 memcpy(buf, "unlimited", sizeof("unlimited"));
3589 partlen = sizeof("unlimited") - 1;
3590 } else {
3591 partlen = sprintf(buf, "%" PRIu64,
3592 (uint64_t)lim->limit.rlim_cur);
3593 }
3594 if (lim->limit.rlim_cur != lim->limit.rlim_max) {
3595 if (lim->limit.rlim_max == RLIM_INFINITY) {
3596 memcpy(buf + partlen, ":unlimited",
3597 sizeof(":unlimited"));
3598 } else {
3599 sprintf(buf + partlen, ":%" PRIu64,
3600 (uint64_t)lim->limit.rlim_max);
3601 }
3602 }
3603
3604 if (get_all) {
3605 strprint(retv, inlen, "lxc.limit.%s = %s\n",
3606 lim->resource, buf);
3607 } else if (strcmp(lim->resource, key) == 0) {
3608 strprint(retv, inlen, "%s", buf);
3609 }
3610 }
3611
3612 return fulllen;
3613}
e08cb901
CB
3614
3615/* Callbacks to clear config items. */
26471403
CB
3616static inline int clr_config_personality(const char *key, struct lxc_conf *c,
3617 void *data)
e08cb901
CB
3618{
3619 c->personality = -1;
3620 return 0;
3621}
03818ae3 3622
26471403
CB
3623static inline int clr_config_pts(const char *key, struct lxc_conf *c,
3624 void *data)
03818ae3
CB
3625{
3626 c->pts = 0;
3627 return 0;
3628}
e7a4b096 3629
26471403
CB
3630static inline int clr_config_tty(const char *key, struct lxc_conf *c,
3631 void *data)
e7a4b096
CB
3632{
3633 c->tty = 0;
3634 return 0;
3635}
eaf8c0c7 3636
26471403
CB
3637static inline int clr_config_ttydir(const char *key, struct lxc_conf *c,
3638 void *data)
eaf8c0c7
CB
3639{
3640 free(c->ttydir);
3641 c->ttydir = NULL;
3642 return 0;
3643}
6bd86308 3644
953fe44f
CB
3645static inline int clr_config_apparmor_profile(const char *key,
3646 struct lxc_conf *c, void *data)
025718fb
CB
3647{
3648 free(c->lsm_aa_profile);
3649 c->lsm_aa_profile = NULL;
3650 return 0;
3651}
3061e04e 3652
953fe44f
CB
3653static inline int clr_config_apparmor_allow_incomplete(const char *key,
3654 struct lxc_conf *c,
3655 void *data)
3061e04e
CB
3656{
3657 c->lsm_aa_allow_incomplete = 0;
3658 return 0;
3659}
31fc3494 3660
953fe44f
CB
3661static inline int clr_config_selinux_context(const char *key,
3662 struct lxc_conf *c, void *data)
31fc3494
CB
3663{
3664 free(c->lsm_se_context);
3665 c->lsm_se_context = NULL;
3666 return 0;
3667}
754d01ce 3668
26471403
CB
3669static inline int clr_config_cgroup(const char *key, struct lxc_conf *c,
3670 void *data)
754d01ce
CB
3671{
3672 return lxc_clear_cgroups(c, key);
3673}
d3a178de 3674
26471403
CB
3675static inline int clr_config_idmaps(const char *key, struct lxc_conf *c,
3676 void *data)
d3a178de
CB
3677{
3678 return lxc_clear_idmaps(c);
3679}
97d3338d 3680
26471403
CB
3681static inline int clr_config_loglevel(const char *key, struct lxc_conf *c,
3682 void *data)
97d3338d 3683{
4b73005c 3684 c->loglevel = LXC_LOG_LEVEL_NOTSET;
97d3338d
CB
3685 return 0;
3686}
de46099c 3687
26471403
CB
3688static inline int clr_config_logfile(const char *key, struct lxc_conf *c,
3689 void *data)
de46099c
CB
3690{
3691 free(c->logfile);
3692 c->logfile = NULL;
3693 return 0;
3694}
b4fa13cd 3695
26471403
CB
3696static inline int clr_config_mount(const char *key, struct lxc_conf *c,
3697 void *data)
b4fa13cd
CB
3698{
3699 return lxc_clear_mount_entries(c);
3700}
4be81021 3701
26471403
CB
3702static inline int clr_config_mount_auto(const char *key, struct lxc_conf *c,
3703 void *data)
4be81021
CB
3704{
3705 return lxc_clear_automounts(c);
3706}
350d4b15 3707
26471403
CB
3708static inline int clr_config_fstab(const char *key, struct lxc_conf *c,
3709 void *data)
350d4b15
CB
3710{
3711 free(c->fstab);
3712 c->fstab = NULL;
3713 return 0;
3714}
faca124d 3715
26471403
CB
3716static inline int clr_config_rootfs(const char *key, struct lxc_conf *c,
3717 void *data)
faca124d
CB
3718{
3719 free(c->rootfs.path);
3720 c->rootfs.path = NULL;
3721 return 0;
3722}
3723
26471403
CB
3724static inline int clr_config_rootfs_mount(const char *key, struct lxc_conf *c,
3725 void *data)
fddefc2d
CB
3726{
3727 free(c->rootfs.mount);
3728 c->rootfs.mount = NULL;
3729 return 0;
3730}
7b1eb67d 3731
26471403
CB
3732static inline int clr_config_rootfs_options(const char *key, struct lxc_conf *c,
3733 void *data)
7b1eb67d
CB
3734{
3735 free(c->rootfs.options);
3736 c->rootfs.options = NULL;
3737 return 0;
3738}
02becb8d 3739
26471403
CB
3740static inline int clr_config_rootfs_backend(const char *key, struct lxc_conf *c,
3741 void *data)
02becb8d
CB
3742{
3743 free(c->rootfs.bdev_type);
3744 c->rootfs.bdev_type = NULL;
3745 return 0;
3746}
3747
26471403
CB
3748static inline int clr_config_utsname(const char *key, struct lxc_conf *c,
3749 void *data)
d31d0103
CB
3750{
3751 free(c->utsname);
3752 c->utsname = NULL;
3753 return 0;
3754}
c9eeb90c 3755
26471403
CB
3756static inline int clr_config_hooks(const char *key, struct lxc_conf *c,
3757 void *data)
c9eeb90c
CB
3758{
3759 return lxc_clear_hooks(c, key);
3760}
3761
f9373e40
CB
3762static inline int clr_config_net(const char *key, struct lxc_conf *c,
3763 void *data)
f4488271 3764{
c302b476
CB
3765 lxc_free_networks(&c->network);
3766
e5d2fd7c 3767 return 0;
f4488271
CB
3768}
3769
26471403
CB
3770static inline int clr_config_cap_drop(const char *key, struct lxc_conf *c,
3771 void *data)
244cb55b
CB
3772{
3773 return lxc_clear_config_caps(c);
3774}
c74cc490 3775
26471403
CB
3776static inline int clr_config_cap_keep(const char *key, struct lxc_conf *c,
3777 void *data)
c74cc490
CB
3778{
3779 return lxc_clear_config_keepcaps(c);
3780}
4e5b633f 3781
26471403
CB
3782static inline int clr_config_console(const char *key, struct lxc_conf *c,
3783 void *data)
4e5b633f
CB
3784{
3785 free(c->console.path);
3786 c->console.path = NULL;
3787 return 0;
3788}
3789
7c2ec23a 3790static inline int clr_config_console_logfile(const char *key,
26471403 3791 struct lxc_conf *c, void *data)
7c2ec23a
CB
3792{
3793 free(c->console.log_path);
3794 c->console.log_path = NULL;
3795 return 0;
3796}
bbca37d8 3797
26471403
CB
3798static inline int clr_config_seccomp(const char *key, struct lxc_conf *c,
3799 void *data)
bbca37d8
CB
3800{
3801 free(c->seccomp);
3802 c->seccomp = NULL;
3803 return 0;
3804}
c721e86c 3805
26471403
CB
3806static inline int clr_config_autodev(const char *key, struct lxc_conf *c,
3807 void *data)
c721e86c
CB
3808{
3809 c->autodev = 1;
3810 return 0;
3811}
87b288d1 3812
26471403
CB
3813static inline int clr_config_haltsignal(const char *key, struct lxc_conf *c,
3814 void *data)
87b288d1
CB
3815{
3816 c->haltsignal = 0;
3817 return 0;
3818}
cae63cfa 3819
26471403
CB
3820static inline int clr_config_rebootsignal(const char *key, struct lxc_conf *c,
3821 void *data)
cae63cfa
CB
3822{
3823 c->rebootsignal = 0;
3824 return 0;
3825}
de45f3a8 3826
26471403
CB
3827static inline int clr_config_stopsignal(const char *key, struct lxc_conf *c,
3828 void *data)
de45f3a8
CB
3829{
3830 c->stopsignal = 0;
3831 return 0;
3832}
c6182222 3833
26471403
CB
3834static inline int clr_config_start(const char *key, struct lxc_conf *c,
3835 void *data)
c6182222
CB
3836{
3837 if (strcmp(key + 10, "auto") == 0)
3838 c->start_auto = 0;
3839 else if (strcmp(key + 10, "delay") == 0)
3840 c->start_delay = 0;
3841 else if (strcmp(key + 10, "order") == 0)
3842 c->start_order = 0;
3843
3844 return 0;
3845}
998ca94f 3846
26471403
CB
3847static inline int clr_config_syslog(const char *key, struct lxc_conf *c,
3848 void *data)
998ca94f
CB
3849{
3850 free(c->syslog);
3851 c->syslog = NULL;
3852 return 0;
3853}
adad12ca 3854
26471403
CB
3855static inline int clr_config_monitor(const char *key, struct lxc_conf *c,
3856 void *data)
adad12ca
CB
3857{
3858 c->monitor_unshare = 0;
3859 return 0;
3860}
4850d223 3861
26471403
CB
3862static inline int clr_config_group(const char *key, struct lxc_conf *c,
3863 void *data)
4850d223
CB
3864{
3865 return lxc_clear_groups(c);
3866}
832fb63a 3867
26471403
CB
3868static inline int clr_config_environment(const char *key, struct lxc_conf *c,
3869 void *data)
832fb63a
CB
3870{
3871 return lxc_clear_environment(c);
4850d223 3872}
8e90af3e 3873
26471403
CB
3874static inline int clr_config_init_cmd(const char *key, struct lxc_conf *c,
3875 void *data)
8e90af3e
CB
3876{
3877 free(c->init_cmd);
3878 c->init_cmd = NULL;
3879 return 0;
3880}
ec76dcfb 3881
26471403
CB
3882static inline int clr_config_init_uid(const char *key, struct lxc_conf *c,
3883 void *data)
ec76dcfb
CB
3884{
3885 c->init_uid = 0;
3886 return 0;
3887}
1044b247 3888
26471403
CB
3889static inline int clr_config_init_gid(const char *key, struct lxc_conf *c,
3890 void *data)
1044b247
CB
3891{
3892 c->init_gid = 0;
3893 return 0;
3894}
59e370db 3895
26471403
CB
3896static inline int clr_config_ephemeral(const char *key, struct lxc_conf *c,
3897 void *data)
59e370db
CB
3898{
3899 c->ephemeral = 0;
3900 return 0;
3901}
b98c5ab0 3902
26471403
CB
3903static inline int clr_config_no_new_privs(const char *key, struct lxc_conf *c,
3904 void *data)
b98c5ab0
CB
3905{
3906 c->no_new_privs = false;
3907 return 0;
3908}
715ccc96 3909
26471403
CB
3910static inline int clr_config_limit(const char *key, struct lxc_conf *c,
3911 void *data)
715ccc96
CB
3912{
3913 return lxc_clear_limits(c, key);
3914}
fdf3c589 3915
26471403
CB
3916static inline int clr_config_includefiles(const char *key, struct lxc_conf *c,
3917 void *data)
fdf3c589
CB
3918{
3919 lxc_clear_includes(c);
3920 return 0;
3921}
a3c8e600
CB
3922
3923static int get_config_includefiles(const char *key, char *retv, int inlen,
cccd2219 3924 struct lxc_conf *c, void *data)
a3c8e600
CB
3925{
3926 return -ENOSYS;
3927}
40db5d2f
CB
3928
3929static struct lxc_config_t *
3930get_network_config_ops(const char *key, struct lxc_conf *lxc_conf, ssize_t *idx)
3931{
3932 char *copy, *idx_start, *idx_end;
3933 struct lxc_config_t *config = NULL;
3934
3935 /* check that this is a sensible network key */
f9373e40 3936 if (strncmp("lxc.net.", key, 8))
40db5d2f
CB
3937 return NULL;
3938
3939 copy = strdup(key);
3940 if (!copy)
3941 return NULL;
3942
f9373e40
CB
3943 /* lxc.net.<n> */
3944 if (isdigit(*(key + 8))) {
40db5d2f
CB
3945 int ret;
3946 unsigned int tmpidx;
3947 size_t numstrlen;
3948
3949 /* beginning of index string */
f9373e40 3950 idx_start = (copy + 7);
40db5d2f
CB
3951 *idx_start = '\0';
3952
3953 /* end of index string */
f9373e40 3954 idx_end = strchr((copy + 8), '.');
40db5d2f
CB
3955 if (!idx_end)
3956 goto on_error;
3957 *idx_end = '\0';
3958
3959 /* parse current index */
3960 ret = lxc_safe_uint((idx_start + 1), &tmpidx);
3961 if (ret < 0) {
3962 *idx = ret;
3963 goto on_error;
3964 }
3965
3966 /* This, of course is utterly nonsensical on so many levels, but
519df1c1 3967 * better safe than sorry.
c302b476 3968 * (Checking for INT_MAX here is intentional.)
40db5d2f 3969 */
c302b476 3970 if (tmpidx == INT_MAX) {
40db5d2f
CB
3971 SYSERROR(
3972 "number of configured networks would overflow the "
3973 "counter... what are you doing?");
3974 goto on_error;
3975 }
3976 *idx = tmpidx;
3977
3978 numstrlen = strlen((idx_start + 1));
3979
3980 /* repair configuration key */
3981 *idx_start = '.';
3982 *idx_end = '.';
3983
f9373e40 3984 memmove(copy + 8, idx_end + 1, strlen(idx_end + 1));
40db5d2f
CB
3985 copy[strlen(key) - numstrlen + 1] = '\0';
3986 }
3987
3988 config = lxc_getconfig(copy);
3989 if (!config)
3990 ERROR("unknown network configuration key %s", key);
3991
3992on_error:
3993 free(copy);
3994 return config;
3995}
3996
3997/*
f9373e40 3998 * Config entry is something like "lxc.net.0.ipv4" the key 'lxc.net.'
40db5d2f
CB
3999 * was found. So we make sure next comes an integer, find the right callback
4000 * (by rewriting the key), and call it.
4001 */
f9373e40
CB
4002static int set_config_net_nic(const char *key, const char *value,
4003 struct lxc_conf *lxc_conf, void *data)
40db5d2f
CB
4004{
4005 struct lxc_config_t *config;
4006 struct lxc_netdev *netdev;
4007 ssize_t idx = -1;
4008
6bed0fb6 4009 if (lxc_config_value_empty(value))
f9373e40 4010 return clr_config_net_nic(key, lxc_conf, data);
6bed0fb6 4011
40db5d2f
CB
4012 config = get_network_config_ops(key, lxc_conf, &idx);
4013 if (!config || idx < 0)
4014 return -1;
4015
0070b1c4 4016 netdev = lxc_get_netdev_by_idx(lxc_conf, (unsigned int)idx, true);
40db5d2f
CB
4017 if (!netdev)
4018 return -1;
4019
4020 return config->set(key, value, lxc_conf, netdev);
4021}
ff6da295
CB
4022
4023/*
f9373e40 4024 * Config entry is something like "lxc.net.0.ipv4" the key 'lxc.net.'
ff6da295
CB
4025 * was found. So we make sure next comes an integer, find the right callback
4026 * (by rewriting the key), and call it.
4027 */
f9373e40
CB
4028static int clr_config_net_nic(const char *key, struct lxc_conf *lxc_conf,
4029 void *data)
ff6da295 4030{
519df1c1 4031 const char *idxstring;
ff6da295
CB
4032 struct lxc_config_t *config;
4033 struct lxc_netdev *netdev;
519df1c1
CB
4034 ssize_t idx;
4035
f9373e40
CB
4036 /* If we get passed "lxc.net.<n>" we clear the whole network. */
4037 if (strncmp("lxc.net.", key, 8))
519df1c1
CB
4038 return -1;
4039
f9373e40 4040 idxstring = key + 8;
519df1c1
CB
4041 /* The left conjunct is pretty self-explanatory. The right conjunct
4042 * checks whether the two pointers are equal. If they are we now that
4043 * this is not a key that is namespaced any further and so we are
4044 * supposed to clear the whole network.
4045 */
4046 if (isdigit(*idxstring) && (strrchr(key, '.') == (idxstring - 1))) {
4047 unsigned int rmnetdevidx;
4048
4049 if (lxc_safe_uint(idxstring, &rmnetdevidx) < 0)
4050 return -1;
4051
4052 /* Remove network from network list. */
4053 lxc_remove_nic_by_idx(lxc_conf, rmnetdevidx);
4054 return 0;
4055 }
ff6da295
CB
4056
4057 config = get_network_config_ops(key, lxc_conf, &idx);
4058 if (!config || idx < 0)
4059 return -1;
4060
0070b1c4 4061 netdev = lxc_get_netdev_by_idx(lxc_conf, (unsigned int)idx, false);
ff6da295
CB
4062 if (!netdev)
4063 return -1;
4064
4065 return config->clr(key, lxc_conf, netdev);
4066}
4067
f9373e40
CB
4068static int clr_config_net_type(const char *key, struct lxc_conf *lxc_conf,
4069 void *data)
ff6da295
CB
4070{
4071 struct lxc_netdev *netdev;
4072
f9373e40
CB
4073 if (!data)
4074 return -1;
4075 else
ff6da295
CB
4076 netdev = data;
4077 if (!netdev)
4078 return -1;
4079
4080 netdev->type = -1;
4081
4082 return 0;
4083}
4084
f9373e40
CB
4085static int clr_config_net_name(const char *key, struct lxc_conf *lxc_conf,
4086 void *data)
ff6da295
CB
4087{
4088 struct lxc_netdev *netdev;
4089
f9373e40
CB
4090 if (!data)
4091 return -1;
4092 else
ff6da295
CB
4093 netdev = data;
4094 if (!netdev)
4095 return -1;
4096
4097 free(netdev->name);
4098 netdev->name = NULL;
4099
4100 return 0;
4101}
4102
f9373e40
CB
4103static int clr_config_net_flags(const char *key, struct lxc_conf *lxc_conf,
4104 void *data)
ff6da295
CB
4105{
4106 struct lxc_netdev *netdev;
4107
f9373e40
CB
4108 if (!data)
4109 return -1;
4110 else
ff6da295
CB
4111 netdev = data;
4112 if (!netdev)
4113 return -1;
4114
4115 netdev->flags = 0;
4116
4117 return 0;
4118}
4119
f9373e40
CB
4120static int clr_config_net_link(const char *key, struct lxc_conf *lxc_conf,
4121 void *data)
ff6da295
CB
4122{
4123 struct lxc_netdev *netdev;
4124
f9373e40
CB
4125 if (!data)
4126 return -1;
4127 else
ff6da295
CB
4128 netdev = data;
4129 if (!netdev)
4130 return -1;
4131
4132 free(netdev->link);
4133 netdev->link = NULL;
4134
4135 return 0;
4136}
4137
f9373e40
CB
4138static int clr_config_net_macvlan_mode(const char *key,
4139 struct lxc_conf *lxc_conf, void *data)
ff6da295
CB
4140{
4141 struct lxc_netdev *netdev;
4142
f9373e40
CB
4143 if (!data)
4144 return -1;
4145 else
ff6da295
CB
4146 netdev = data;
4147 if (!netdev)
4148 return -1;
4149
6bed0fb6
CB
4150 if (netdev->type != LXC_NET_MACVLAN)
4151 return 0;
4152
ff6da295
CB
4153 netdev->priv.macvlan_attr.mode = -1;
4154
4155 return 0;
4156}
4157
f9373e40
CB
4158static int clr_config_net_veth_pair(const char *key, struct lxc_conf *lxc_conf,
4159 void *data)
ff6da295
CB
4160{
4161 struct lxc_netdev *netdev;
4162
f9373e40
CB
4163 if (!data)
4164 return -1;
4165 else
ff6da295
CB
4166 netdev = data;
4167 if (!netdev)
4168 return -1;
4169
4170 free(netdev->priv.veth_attr.pair);
4171 netdev->priv.veth_attr.pair = NULL;
4172
4173 return 0;
4174}
4175
f9373e40
CB
4176static int clr_config_net_script_up(const char *key, struct lxc_conf *lxc_conf,
4177 void *data)
ff6da295
CB
4178{
4179 struct lxc_netdev *netdev;
4180
f9373e40
CB
4181 if (!data)
4182 return -1;
4183 else
ff6da295
CB
4184 netdev = data;
4185 if (!netdev)
4186 return -1;
4187
4188 free(netdev->upscript);
4189 netdev->upscript = NULL;
4190
4191 return 0;
4192}
4193
f9373e40
CB
4194static int clr_config_net_script_down(const char *key,
4195 struct lxc_conf *lxc_conf, void *data)
ff6da295
CB
4196{
4197 struct lxc_netdev *netdev;
4198
f9373e40
CB
4199 if (!data)
4200 return -1;
4201 else
ff6da295
CB
4202 netdev = data;
4203 if (!netdev)
4204 return -1;
4205
4206 free(netdev->downscript);
4207 netdev->downscript = NULL;
4208
4209 return 0;
4210}
4211
f9373e40
CB
4212static int clr_config_net_hwaddr(const char *key, struct lxc_conf *lxc_conf,
4213 void *data)
ff6da295
CB
4214{
4215 struct lxc_netdev *netdev;
4216
f9373e40
CB
4217 if (!data)
4218 return -1;
4219 else
ff6da295
CB
4220 netdev = data;
4221 if (!netdev)
4222 return -1;
4223
4224 free(netdev->hwaddr);
4225 netdev->hwaddr = NULL;
4226
4227 return 0;
4228}
4229
f9373e40
CB
4230static int clr_config_net_mtu(const char *key, struct lxc_conf *lxc_conf,
4231 void *data)
ff6da295
CB
4232{
4233 struct lxc_netdev *netdev;
4234
f9373e40
CB
4235 if (!data)
4236 return -1;
4237 else
ff6da295
CB
4238 netdev = data;
4239 if (!netdev)
4240 return -1;
4241
4242 free(netdev->mtu);
4243 netdev->mtu = NULL;
4244
4245 return 0;
4246}
4247
f9373e40
CB
4248static int clr_config_net_vlan_id(const char *key, struct lxc_conf *lxc_conf,
4249 void *data)
ff6da295
CB
4250{
4251 struct lxc_netdev *netdev;
4252
f9373e40
CB
4253 if (!data)
4254 return -1;
4255 else
ff6da295
CB
4256 netdev = data;
4257 if (!netdev)
4258 return -1;
4259
4260 netdev->priv.vlan_attr.vid = 0;
4261
4262 return 0;
4263}
4264
f9373e40
CB
4265static int clr_config_net_ipv4_gateway(const char *key,
4266 struct lxc_conf *lxc_conf, void *data)
ff6da295
CB
4267{
4268 struct lxc_netdev *netdev;
4269
f9373e40
CB
4270 if (!data)
4271 return -1;
4272 else
ff6da295
CB
4273 netdev = data;
4274 if (!netdev)
4275 return -1;
4276
4277 free(netdev->ipv4_gateway);
4278 netdev->ipv4_gateway = NULL;
4279
4280 return 0;
4281}
4282
f9373e40
CB
4283static int clr_config_net_ipv4(const char *key, struct lxc_conf *lxc_conf,
4284 void *data)
ff6da295
CB
4285{
4286 struct lxc_netdev *netdev;
4287 struct lxc_list *cur, *next;
4288
f9373e40
CB
4289 if (!data)
4290 return -1;
4291 else
ff6da295 4292 netdev = data;
ecbb3790
CB
4293 if (!netdev)
4294 return -1;
ff6da295
CB
4295
4296 lxc_list_for_each_safe(cur, &netdev->ipv4, next) {
4297 lxc_list_del(cur);
4298 free(cur->elem);
4299 free(cur);
4300 }
4301
4302 return 0;
4303}
4304
f9373e40
CB
4305static int clr_config_net_ipv6_gateway(const char *key,
4306 struct lxc_conf *lxc_conf, void *data)
ff6da295
CB
4307{
4308 struct lxc_netdev *netdev;
4309
f9373e40
CB
4310 if (!data)
4311 return -1;
4312 else
ff6da295
CB
4313 netdev = data;
4314 if (!netdev)
4315 return -1;
4316
4317 free(netdev->ipv6_gateway);
4318 netdev->ipv6_gateway = NULL;
4319
4320 return 0;
4321}
4322
f9373e40
CB
4323static int clr_config_net_ipv6(const char *key, struct lxc_conf *lxc_conf,
4324 void *data)
ff6da295
CB
4325{
4326 struct lxc_netdev *netdev;
4327 struct lxc_list *cur, *next;
4328
f9373e40
CB
4329 if (!data)
4330 return -1;
4331 else
ff6da295 4332 netdev = data;
ecbb3790
CB
4333 if (!netdev)
4334 return -1;
ff6da295
CB
4335
4336 lxc_list_for_each_safe(cur, &netdev->ipv6, next) {
4337 lxc_list_del(cur);
4338 free(cur->elem);
4339 free(cur);
4340 }
4341
4342 return 0;
4343}
9d4bf22d 4344
f9373e40
CB
4345static int get_config_net_nic(const char *key, char *retv, int inlen,
4346 struct lxc_conf *c, void *data)
9d4bf22d
CB
4347{
4348 struct lxc_config_t *config;
4349 struct lxc_netdev *netdev;
4350 ssize_t idx = -1;
4351
4352 config = get_network_config_ops(key, c, &idx);
4353 if (!config || idx < 0)
4354 return -1;
4355
0070b1c4 4356 netdev = lxc_get_netdev_by_idx(c, (unsigned int)idx, false);
9d4bf22d
CB
4357 if (!netdev)
4358 return -1;
4359
4360 return config->get(key, retv, inlen, c, netdev);
4361}
4362
f9373e40
CB
4363static int get_config_net_type(const char *key, char *retv, int inlen,
4364 struct lxc_conf *c, void *data)
9d4bf22d
CB
4365{
4366 int len, fulllen = 0;
4367 struct lxc_netdev *netdev;
4368
4369 if (!retv)
4370 inlen = 0;
4371 else
4372 memset(retv, 0, inlen);
4373
f9373e40
CB
4374 if (!data)
4375 return -1;
4376 else
9d4bf22d
CB
4377 netdev = data;
4378 if (!netdev)
4379 return -1;
4380
4381 strprint(retv, inlen, "%s", lxc_net_type_to_str(netdev->type));
4382
4383 return fulllen;
4384}
4385
f9373e40
CB
4386static int get_config_net_flags(const char *key, char *retv, int inlen,
4387 struct lxc_conf *c, void *data)
9d4bf22d
CB
4388{
4389 int len, fulllen = 0;
4390 struct lxc_netdev *netdev;
4391
4392 if (!retv)
4393 inlen = 0;
4394 else
4395 memset(retv, 0, inlen);
4396
f9373e40
CB
4397 if (!data)
4398 return -1;
4399 else
9d4bf22d
CB
4400 netdev = data;
4401 if (!netdev)
4402 return -1;
4403
4404 if (netdev->flags & IFF_UP)
4405 strprint(retv, inlen, "up");
4406
4407 return fulllen;
4408}
4409
f9373e40
CB
4410static int get_config_net_link(const char *key, char *retv, int inlen,
4411 struct lxc_conf *c, void *data)
9d4bf22d
CB
4412{
4413 int len, fulllen = 0;
4414 struct lxc_netdev *netdev;
4415
4416 if (!retv)
4417 inlen = 0;
4418 else
4419 memset(retv, 0, inlen);
4420
f9373e40
CB
4421 if (!data)
4422 return -1;
4423 else
9d4bf22d
CB
4424 netdev = data;
4425 if (!netdev)
4426 return -1;
4427
4428 if (netdev->link)
4429 strprint(retv, inlen, "%s", netdev->link);
4430
4431 return fulllen;
4432}
4433
f9373e40
CB
4434static int get_config_net_name(const char *key, char *retv, int inlen,
4435 struct lxc_conf *c, void *data)
9d4bf22d
CB
4436{
4437 int len, fulllen = 0;
4438 struct lxc_netdev *netdev;
4439
4440 if (!retv)
4441 inlen = 0;
4442 else
4443 memset(retv, 0, inlen);
4444
f9373e40
CB
4445 if (!data)
4446 return -1;
4447 else
9d4bf22d
CB
4448 netdev = data;
4449 if (!netdev)
4450 return -1;
4451
4452 if (netdev->name)
4453 strprint(retv, inlen, "%s", netdev->name);
4454
4455 return fulllen;
4456}
4457
f9373e40
CB
4458static int get_config_net_macvlan_mode(const char *key, char *retv, int inlen,
4459 struct lxc_conf *c, void *data)
9d4bf22d
CB
4460{
4461 const char *mode;
4462 int len, fulllen = 0;
4463 struct lxc_netdev *netdev;
4464
4465 if (!retv)
4466 inlen = 0;
4467 else
4468 memset(retv, 0, inlen);
4469
f9373e40
CB
4470 if (!data)
4471 return -1;
4472 else
9d4bf22d
CB
4473 netdev = data;
4474 if (!netdev)
4475 return -1;
4476
4477 if (netdev->type != LXC_NET_MACVLAN)
4478 return 0;
4479
4480 switch (netdev->priv.macvlan_attr.mode) {
4481 case MACVLAN_MODE_PRIVATE:
4482 mode = "private";
4483 break;
4484 case MACVLAN_MODE_VEPA:
4485 mode = "vepa";
4486 break;
4487 case MACVLAN_MODE_BRIDGE:
4488 mode = "bridge";
4489 break;
4490 case MACVLAN_MODE_PASSTHRU:
4491 mode = "passthru";
4492 break;
4493 default:
4494 mode = "(invalid)";
4495 break;
4496 }
4497
4498 strprint(retv, inlen, "%s", mode);
4499
4500 return fulllen;
4501}
4502
f9373e40
CB
4503static int get_config_net_veth_pair(const char *key, char *retv, int inlen,
4504 struct lxc_conf *c, void *data)
9d4bf22d
CB
4505{
4506 int len, fulllen = 0;
4507 struct lxc_netdev *netdev;
4508
4509 if (!retv)
4510 inlen = 0;
4511 else
4512 memset(retv, 0, inlen);
4513
f9373e40
CB
4514 if (!data)
4515 return -1;
4516 else
9d4bf22d
CB
4517 netdev = data;
4518 if (!netdev)
4519 return -1;
4520
4521 if (netdev->type != LXC_NET_VETH)
4522 return 0;
4523
4524 strprint(retv, inlen, "%s",
4525 netdev->priv.veth_attr.pair ? netdev->priv.veth_attr.pair
4526 : netdev->priv.veth_attr.veth1);
4527
4528 return fulllen;
4529}
4530
f9373e40
CB
4531static int get_config_net_script_up(const char *key, char *retv, int inlen,
4532 struct lxc_conf *c, void *data)
9d4bf22d
CB
4533{
4534 int len, fulllen = 0;
4535 struct lxc_netdev *netdev;
4536
4537 if (!retv)
4538 inlen = 0;
4539 else
4540 memset(retv, 0, inlen);
4541
f9373e40
CB
4542 if (!data)
4543 return -1;
4544 else
9d4bf22d
CB
4545 netdev = data;
4546 if (!netdev)
4547 return -1;
4548
4549 if (netdev->upscript)
4550 strprint(retv, inlen, "%s", netdev->upscript);
4551
4552 return fulllen;
4553}
4554
f9373e40
CB
4555static int get_config_net_script_down(const char *key, char *retv, int inlen,
4556 struct lxc_conf *c, void *data)
9d4bf22d
CB
4557{
4558 int len, fulllen = 0;
4559 struct lxc_netdev *netdev;
4560
4561 if (!retv)
4562 inlen = 0;
4563 else
4564 memset(retv, 0, inlen);
4565
f9373e40
CB
4566 if (!data)
4567 return -1;
4568 else
9d4bf22d
CB
4569 netdev = data;
4570 if (!netdev)
4571 return -1;
4572
4573 if (netdev->downscript)
4574 strprint(retv, inlen, "%s", netdev->downscript);
4575
4576 return fulllen;
4577}
4578
f9373e40
CB
4579static int get_config_net_hwaddr(const char *key, char *retv, int inlen,
4580 struct lxc_conf *c, void *data)
9d4bf22d
CB
4581{
4582 int len, fulllen = 0;
4583 struct lxc_netdev *netdev;
4584
4585 if (!retv)
4586 inlen = 0;
4587 else
4588 memset(retv, 0, inlen);
4589
f9373e40
CB
4590 if (!data)
4591 return -1;
4592 else
9d4bf22d
CB
4593 netdev = data;
4594 if (!netdev)
4595 return -1;
4596
4597 if (netdev->hwaddr)
4598 strprint(retv, inlen, "%s", netdev->hwaddr);
4599
4600 return fulllen;
4601}
4602
f9373e40
CB
4603static int get_config_net_mtu(const char *key, char *retv, int inlen,
4604 struct lxc_conf *c, void *data)
9d4bf22d
CB
4605{
4606 int len, fulllen = 0;
4607 struct lxc_netdev *netdev;
4608
4609 if (!retv)
4610 inlen = 0;
4611 else
4612 memset(retv, 0, inlen);
4613
f9373e40
CB
4614 if (!data)
4615 return -1;
4616 else
9d4bf22d
CB
4617 netdev = data;
4618 if (!netdev)
4619 return -1;
4620
4621 if (netdev->mtu)
4622 strprint(retv, inlen, "%s", netdev->mtu);
4623
4624 return fulllen;
4625}
4626
f9373e40
CB
4627static int get_config_net_vlan_id(const char *key, char *retv, int inlen,
4628 struct lxc_conf *c, void *data)
9d4bf22d
CB
4629{
4630 int len, fulllen = 0;
4631 struct lxc_netdev *netdev;
4632
4633 if (!retv)
4634 inlen = 0;
4635 else
4636 memset(retv, 0, inlen);
4637
f9373e40
CB
4638 if (!data)
4639 return -1;
4640 else
9d4bf22d
CB
4641 netdev = data;
4642 if (!netdev)
4643 return -1;
4644
4645 if (netdev->type != LXC_NET_VLAN)
4646 return 0;
4647
4648 strprint(retv, inlen, "%d", netdev->priv.vlan_attr.vid);
4649
4650 return fulllen;
4651}
4652
f9373e40
CB
4653static int get_config_net_ipv4_gateway(const char *key, char *retv, int inlen,
4654 struct lxc_conf *c, void *data)
9d4bf22d
CB
4655{
4656 int len, fulllen = 0;
4657 char buf[INET_ADDRSTRLEN];
4658 struct lxc_netdev *netdev;
4659
4660 if (!retv)
4661 inlen = 0;
4662 else
4663 memset(retv, 0, inlen);
4664
f9373e40
CB
4665 if (!data)
4666 return -1;
4667 else
9d4bf22d
CB
4668 netdev = data;
4669 if (!netdev)
4670 return -1;
4671
4672 if (netdev->ipv4_gateway_auto) {
4673 strprint(retv, inlen, "auto");
4674 } else if (netdev->ipv4_gateway) {
4675 inet_ntop(AF_INET, netdev->ipv4_gateway, buf, sizeof(buf));
4676 strprint(retv, inlen, "%s", buf);
4677 }
4678
4679 return fulllen;
4680}
4681
f9373e40
CB
4682static int get_config_net_ipv4(const char *key, char *retv, int inlen,
4683 struct lxc_conf *c, void *data)
9d4bf22d
CB
4684{
4685 int len, fulllen = 0;
4686 size_t listlen;
4687 char buf[INET_ADDRSTRLEN];
4688 struct lxc_netdev *netdev;
4689 struct lxc_list *it;
4690
4691 if (!retv)
4692 inlen = 0;
4693 else
4694 memset(retv, 0, inlen);
4695
f9373e40
CB
4696 if (!data)
4697 return -1;
4698 else
9d4bf22d
CB
4699 netdev = data;
4700 if (!netdev)
4701 return -1;
4702
4703 listlen = lxc_list_len(&netdev->ipv4);
4704 lxc_list_for_each(it, &netdev->ipv4) {
4705 struct lxc_inetdev *i = it->elem;
4706 inet_ntop(AF_INET, &i->addr, buf, sizeof(buf));
4707 strprint(retv, inlen, "%s/%d%s", buf, i->prefix,
4708 (listlen-- > 1) ? "\n" : "");
4709 }
4710
4711 return fulllen;
4712}
4713
f9373e40
CB
4714static int get_config_net_ipv6_gateway(const char *key, char *retv, int inlen,
4715 struct lxc_conf *c, void *data)
9d4bf22d
CB
4716{
4717 int len, fulllen = 0;
4718 char buf[INET6_ADDRSTRLEN];
4719 struct lxc_netdev *netdev;
4720
4721 if (!retv)
4722 inlen = 0;
4723 else
4724 memset(retv, 0, inlen);
4725
f9373e40
CB
4726 if (!data)
4727 return -1;
4728 else
9d4bf22d
CB
4729 netdev = data;
4730 if (!netdev)
4731 return -1;
4732
4733 if (netdev->ipv6_gateway_auto) {
4734 strprint(retv, inlen, "auto");
4735 } else if (netdev->ipv6_gateway) {
4736 inet_ntop(AF_INET6, netdev->ipv6_gateway, buf, sizeof(buf));
4737 strprint(retv, inlen, "%s", buf);
4738 }
4739
4740 return fulllen;
4741}
4742
f9373e40
CB
4743static int get_config_net_ipv6(const char *key, char *retv, int inlen,
4744 struct lxc_conf *c, void *data)
9d4bf22d
CB
4745{
4746 int len, fulllen = 0;
4747 size_t listlen;
4748 char buf[INET6_ADDRSTRLEN];
4749 struct lxc_netdev *netdev;
4750 struct lxc_list *it;
4751
4752 if (!retv)
4753 inlen = 0;
4754 else
4755 memset(retv, 0, inlen);
4756
f9373e40
CB
4757 if (!data)
4758 return -1;
4759 else
9d4bf22d
CB
4760 netdev = data;
4761 if (!netdev)
4762 return -1;
4763
4764 listlen = lxc_list_len(&netdev->ipv6);
4765 lxc_list_for_each(it, &netdev->ipv6) {
4766 struct lxc_inet6dev *i = it->elem;
4767 inet_ntop(AF_INET6, &i->addr, buf, sizeof(buf));
4768 strprint(retv, inlen, "%s/%d%s", buf, i->prefix,
4769 (listlen-- > 1) ? "\n" : "");
4770 }
4771
4772 return fulllen;
4773}