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