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