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