File: | build-scan/../src/nspawn/nspawn.c |
Warning: | line 2621, column 17 Value stored to 'rtnl_socket' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* SPDX-License-Identifier: LGPL-2.1+ */ |
2 | |
3 | #if HAVE_BLKID1 |
4 | #include <blkid.h> |
5 | #endif |
6 | #include <errno(*__errno_location ()).h> |
7 | #include <getopt.h> |
8 | #include <grp.h> |
9 | #include <linux1/loop.h> |
10 | #include <pwd.h> |
11 | #include <sched.h> |
12 | #if HAVE_SELINUX1 |
13 | #include <selinux/selinux.h> |
14 | #endif |
15 | #include <signal.h> |
16 | #include <stdio.h> |
17 | #include <stdlib.h> |
18 | #include <string.h> |
19 | #include <sys/file.h> |
20 | #include <sys/mount.h> |
21 | #include <sys/personality.h> |
22 | #include <sys/prctl.h> |
23 | #include <sys/types.h> |
24 | #include <sys/wait.h> |
25 | #include <unistd.h> |
26 | |
27 | #include "sd-bus.h" |
28 | #include "sd-daemon.h" |
29 | #include "sd-id128.h" |
30 | |
31 | #include "alloc-util.h" |
32 | #include "barrier.h" |
33 | #include "base-filesystem.h" |
34 | #include "blkid-util.h" |
35 | #include "btrfs-util.h" |
36 | #include "bus-error.h" |
37 | #include "bus-util.h" |
38 | #include "cap-list.h" |
39 | #include "capability-util.h" |
40 | #include "cgroup-util.h" |
41 | #include "copy.h" |
42 | #include "cpu-set-util.h" |
43 | #include "dev-setup.h" |
44 | #include "dissect-image.h" |
45 | #include "env-util.h" |
46 | #include "fd-util.h" |
47 | #include "fdset.h" |
48 | #include "fileio.h" |
49 | #include "format-util.h" |
50 | #include "fs-util.h" |
51 | #include "gpt.h" |
52 | #include "hexdecoct.h" |
53 | #include "hostname-util.h" |
54 | #include "id128-util.h" |
55 | #include "log.h" |
56 | #include "loop-util.h" |
57 | #include "loopback-setup.h" |
58 | #include "machine-image.h" |
59 | #include "macro.h" |
60 | #include "missing.h" |
61 | #include "mkdir.h" |
62 | #include "mount-util.h" |
63 | #include "netlink-util.h" |
64 | #include "nspawn-cgroup.h" |
65 | #include "nspawn-def.h" |
66 | #include "nspawn-expose-ports.h" |
67 | #include "nspawn-mount.h" |
68 | #include "nspawn-network.h" |
69 | #include "nspawn-patch-uid.h" |
70 | #include "nspawn-register.h" |
71 | #include "nspawn-seccomp.h" |
72 | #include "nspawn-settings.h" |
73 | #include "nspawn-setuid.h" |
74 | #include "nspawn-stub-pid1.h" |
75 | #include "os-util.h" |
76 | #include "pager.h" |
77 | #include "parse-util.h" |
78 | #include "path-util.h" |
79 | #include "process-util.h" |
80 | #include "ptyfwd.h" |
81 | #include "random-util.h" |
82 | #include "raw-clone.h" |
83 | #include "rlimit-util.h" |
84 | #include "rm-rf.h" |
85 | #include "selinux-util.h" |
86 | #include "signal-util.h" |
87 | #include "socket-util.h" |
88 | #include "stat-util.h" |
89 | #include "stdio-util.h" |
90 | #include "string-table.h" |
91 | #include "string-util.h" |
92 | #include "strv.h" |
93 | #include "terminal-util.h" |
94 | #include "udev-util.h" |
95 | #include "umask-util.h" |
96 | #include "user-util.h" |
97 | #include "util.h" |
98 | |
99 | #if HAVE_SPLIT_USR0 |
100 | #define STATIC_RESOLV_CONF"/usr/lib/systemd/resolv.conf" "/lib/systemd/resolv.conf" |
101 | #else |
102 | #define STATIC_RESOLV_CONF"/usr/lib/systemd/resolv.conf" "/usr/lib/systemd/resolv.conf" |
103 | #endif |
104 | |
105 | /* nspawn is listening on the socket at the path in the constant nspawn_notify_socket_path |
106 | * nspawn_notify_socket_path is relative to the container |
107 | * the init process in the container pid can send messages to nspawn following the sd_notify(3) protocol */ |
108 | #define NSPAWN_NOTIFY_SOCKET_PATH"/run/systemd/nspawn/notify" "/run/systemd/nspawn/notify" |
109 | |
110 | #define EXIT_FORCE_RESTART133 133 |
111 | |
112 | typedef enum ContainerStatus { |
113 | CONTAINER_TERMINATED, |
114 | CONTAINER_REBOOTED |
115 | } ContainerStatus; |
116 | |
117 | static char *arg_directory = NULL((void*)0); |
118 | static char *arg_template = NULL((void*)0); |
119 | static char *arg_chdir = NULL((void*)0); |
120 | static char *arg_pivot_root_new = NULL((void*)0); |
121 | static char *arg_pivot_root_old = NULL((void*)0); |
122 | static char *arg_user = NULL((void*)0); |
123 | static sd_id128_t arg_uuid = {}; |
124 | static char *arg_machine = NULL((void*)0); /* The name used by the host to refer to this */ |
125 | static char *arg_hostname = NULL((void*)0); /* The name the payload sees by default */ |
126 | static const char *arg_selinux_context = NULL((void*)0); |
127 | static const char *arg_selinux_apifs_context = NULL((void*)0); |
128 | static const char *arg_slice = NULL((void*)0); |
129 | static bool_Bool arg_private_network = false0; |
130 | static bool_Bool arg_read_only = false0; |
131 | static StartMode arg_start_mode = START_PID1; |
132 | static bool_Bool arg_ephemeral = false0; |
133 | static LinkJournal arg_link_journal = LINK_AUTO; |
134 | static bool_Bool arg_link_journal_try = false0; |
135 | static uint64_t arg_caps_retain = |
136 | (1ULL << CAP_AUDIT_CONTROL30) | |
137 | (1ULL << CAP_AUDIT_WRITE29) | |
138 | (1ULL << CAP_CHOWN0) | |
139 | (1ULL << CAP_DAC_OVERRIDE1) | |
140 | (1ULL << CAP_DAC_READ_SEARCH2) | |
141 | (1ULL << CAP_FOWNER3) | |
142 | (1ULL << CAP_FSETID4) | |
143 | (1ULL << CAP_IPC_OWNER15) | |
144 | (1ULL << CAP_KILL5) | |
145 | (1ULL << CAP_LEASE28) | |
146 | (1ULL << CAP_LINUX_IMMUTABLE9) | |
147 | (1ULL << CAP_MKNOD27) | |
148 | (1ULL << CAP_NET_BIND_SERVICE10) | |
149 | (1ULL << CAP_NET_BROADCAST11) | |
150 | (1ULL << CAP_NET_RAW13) | |
151 | (1ULL << CAP_SETFCAP31) | |
152 | (1ULL << CAP_SETGID6) | |
153 | (1ULL << CAP_SETPCAP8) | |
154 | (1ULL << CAP_SETUID7) | |
155 | (1ULL << CAP_SYS_ADMIN21) | |
156 | (1ULL << CAP_SYS_BOOT22) | |
157 | (1ULL << CAP_SYS_CHROOT18) | |
158 | (1ULL << CAP_SYS_NICE23) | |
159 | (1ULL << CAP_SYS_PTRACE19) | |
160 | (1ULL << CAP_SYS_RESOURCE24) | |
161 | (1ULL << CAP_SYS_TTY_CONFIG26); |
162 | static CustomMount *arg_custom_mounts = NULL((void*)0); |
163 | static size_t arg_n_custom_mounts = 0; |
164 | static char **arg_setenv = NULL((void*)0); |
165 | static bool_Bool arg_quiet = false0; |
166 | static bool_Bool arg_register = true1; |
167 | static bool_Bool arg_keep_unit = false0; |
168 | static char **arg_network_interfaces = NULL((void*)0); |
169 | static char **arg_network_macvlan = NULL((void*)0); |
170 | static char **arg_network_ipvlan = NULL((void*)0); |
171 | static bool_Bool arg_network_veth = false0; |
172 | static char **arg_network_veth_extra = NULL((void*)0); |
173 | static char *arg_network_bridge = NULL((void*)0); |
174 | static char *arg_network_zone = NULL((void*)0); |
175 | static char *arg_network_namespace_path = NULL((void*)0); |
176 | static unsigned long arg_personality = PERSONALITY_INVALID0xffffffffLU; |
177 | static char *arg_image = NULL((void*)0); |
178 | static VolatileMode arg_volatile_mode = VOLATILE_NO; |
179 | static ExposePort *arg_expose_ports = NULL((void*)0); |
180 | static char **arg_property = NULL((void*)0); |
181 | static UserNamespaceMode arg_userns_mode = USER_NAMESPACE_NO; |
182 | static uid_t arg_uid_shift = UID_INVALID((uid_t) -1), arg_uid_range = 0x10000U; |
183 | static bool_Bool arg_userns_chown = false0; |
184 | static int arg_kill_signal = 0; |
185 | static CGroupUnified arg_unified_cgroup_hierarchy = CGROUP_UNIFIED_UNKNOWN; |
186 | static SettingsMask arg_settings_mask = 0; |
187 | static int arg_settings_trusted = -1; |
188 | static char **arg_parameters = NULL((void*)0); |
189 | static const char *arg_container_service_name = "systemd-nspawn"; |
190 | static bool_Bool arg_notify_ready = false0; |
191 | static bool_Bool arg_use_cgns = true1; |
192 | static unsigned long arg_clone_ns_flags = CLONE_NEWIPC0x08000000|CLONE_NEWPID0x20000000|CLONE_NEWUTS0x04000000; |
193 | static MountSettingsMask arg_mount_settings = MOUNT_APPLY_APIVFS_RO; |
194 | static void *arg_root_hash = NULL((void*)0); |
195 | static size_t arg_root_hash_size = 0; |
196 | static char **arg_syscall_whitelist = NULL((void*)0); |
197 | static char **arg_syscall_blacklist = NULL((void*)0); |
198 | static struct rlimit *arg_rlimit[_RLIMIT_MAX(__RLIMIT_RTTIME+1 > __RLIMIT_NLIMITS ? __RLIMIT_RTTIME+1 : __RLIMIT_NLIMITS)] = {}; |
199 | static bool_Bool arg_no_new_privileges = false0; |
200 | static int arg_oom_score_adjust = 0; |
201 | static bool_Bool arg_oom_score_adjust_set = false0; |
202 | static CPUSet arg_cpu_set = {}; |
203 | static ResolvConfMode arg_resolv_conf = RESOLV_CONF_AUTO; |
204 | static TimezoneMode arg_timezone = TIMEZONE_AUTO; |
205 | |
206 | static void help(void) { |
207 | (void) pager_open(false0, false0); |
208 | |
209 | printf("%s [OPTIONS...] [PATH] [ARGUMENTS...]\n\n" |
210 | "Spawn a minimal namespace container for debugging, testing and building.\n\n" |
211 | " -h --help Show this help\n" |
212 | " --version Print version string\n" |
213 | " -q --quiet Do not show status information\n" |
214 | " -D --directory=PATH Root directory for the container\n" |
215 | " --template=PATH Initialize root directory from template directory,\n" |
216 | " if missing\n" |
217 | " -x --ephemeral Run container with snapshot of root directory, and\n" |
218 | " remove it after exit\n" |
219 | " -i --image=PATH File system device or disk image for the container\n" |
220 | " --root-hash=HASH Specify verity root hash\n" |
221 | " -a --as-pid2 Maintain a stub init as PID1, invoke binary as PID2\n" |
222 | " -b --boot Boot up full system (i.e. invoke init)\n" |
223 | " --chdir=PATH Set working directory in the container\n" |
224 | " --pivot-root=PATH[:PATH]\n" |
225 | " Pivot root to given directory in the container\n" |
226 | " -u --user=USER Run the command under specified user or uid\n" |
227 | " -M --machine=NAME Set the machine name for the container\n" |
228 | " --hostname=NAME Override the hostname for the container\n" |
229 | " --uuid=UUID Set a specific machine UUID for the container\n" |
230 | " -S --slice=SLICE Place the container in the specified slice\n" |
231 | " --property=NAME=VALUE Set scope unit property\n" |
232 | " -U --private-users=pick Run within user namespace, autoselect UID/GID range\n" |
233 | " --private-users[=UIDBASE[:NUIDS]]\n" |
234 | " Similar, but with user configured UID/GID range\n" |
235 | " --private-users-chown Adjust OS tree ownership to private UID/GID range\n" |
236 | " --private-network Disable network in container\n" |
237 | " --network-interface=INTERFACE\n" |
238 | " Assign an existing network interface to the\n" |
239 | " container\n" |
240 | " --network-macvlan=INTERFACE\n" |
241 | " Create a macvlan network interface based on an\n" |
242 | " existing network interface to the container\n" |
243 | " --network-ipvlan=INTERFACE\n" |
244 | " Create a ipvlan network interface based on an\n" |
245 | " existing network interface to the container\n" |
246 | " -n --network-veth Add a virtual Ethernet connection between host\n" |
247 | " and container\n" |
248 | " --network-veth-extra=HOSTIF[:CONTAINERIF]\n" |
249 | " Add an additional virtual Ethernet link between\n" |
250 | " host and container\n" |
251 | " --network-bridge=INTERFACE\n" |
252 | " Add a virtual Ethernet connection to the container\n" |
253 | " and attach it to an existing bridge on the host\n" |
254 | " --network-zone=NAME Similar, but attach the new interface to an\n" |
255 | " an automatically managed bridge interface\n" |
256 | " --network-namespace-path=PATH\n" |
257 | " Set network namespace to the one represented by\n" |
258 | " the specified kernel namespace file node\n" |
259 | " -p --port=[PROTOCOL:]HOSTPORT[:CONTAINERPORT]\n" |
260 | " Expose a container IP port on the host\n" |
261 | " -Z --selinux-context=SECLABEL\n" |
262 | " Set the SELinux security context to be used by\n" |
263 | " processes in the container\n" |
264 | " -L --selinux-apifs-context=SECLABEL\n" |
265 | " Set the SELinux security context to be used by\n" |
266 | " API/tmpfs file systems in the container\n" |
267 | " --capability=CAP In addition to the default, retain specified\n" |
268 | " capability\n" |
269 | " --drop-capability=CAP Drop the specified capability from the default set\n" |
270 | " --system-call-filter=LIST|~LIST\n" |
271 | " Permit/prohibit specific system calls\n" |
272 | " --rlimit=NAME=LIMIT Set a resource limit for the payload\n" |
273 | " --oom-score-adjust=VALUE\n" |
274 | " Adjust the OOM score value for the payload\n" |
275 | " --cpu-affinity=CPUS Adjust the CPU affinity of the container\n" |
276 | " --kill-signal=SIGNAL Select signal to use for shutting down PID 1\n" |
277 | " --link-journal=MODE Link up guest journal, one of no, auto, guest, \n" |
278 | " host, try-guest, try-host\n" |
279 | " -j Equivalent to --link-journal=try-guest\n" |
280 | " --resolv-conf=MODE Select mode of /etc/resolv.conf initialization\n" |
281 | " --timezone=MODE Select mode of /etc/localtime initialization\n" |
282 | " --read-only Mount the root directory read-only\n" |
283 | " --bind=PATH[:PATH[:OPTIONS]]\n" |
284 | " Bind mount a file or directory from the host into\n" |
285 | " the container\n" |
286 | " --bind-ro=PATH[:PATH[:OPTIONS]\n" |
287 | " Similar, but creates a read-only bind mount\n" |
288 | " --tmpfs=PATH:[OPTIONS] Mount an empty tmpfs to the specified directory\n" |
289 | " --overlay=PATH[:PATH...]:PATH\n" |
290 | " Create an overlay mount from the host to \n" |
291 | " the container\n" |
292 | " --overlay-ro=PATH[:PATH...]:PATH\n" |
293 | " Similar, but creates a read-only overlay mount\n" |
294 | " -E --setenv=NAME=VALUE Pass an environment variable to PID 1\n" |
295 | " --register=BOOLEAN Register container as machine\n" |
296 | " --keep-unit Do not register a scope for the machine, reuse\n" |
297 | " the service unit nspawn is running in\n" |
298 | " --volatile[=MODE] Run the system in volatile mode\n" |
299 | " --settings=BOOLEAN Load additional settings from .nspawn file\n" |
300 | " --notify-ready=BOOLEAN Receive notifications from the child init process\n" |
301 | , program_invocation_short_name); |
302 | } |
303 | |
304 | static int custom_mount_check_all(void) { |
305 | size_t i; |
306 | |
307 | for (i = 0; i < arg_n_custom_mounts; i++) { |
308 | CustomMount *m = &arg_custom_mounts[i]; |
309 | |
310 | if (path_equal(m->destination, "/") && arg_userns_mode != USER_NAMESPACE_NO) { |
311 | |
312 | if (arg_userns_chown) { |
313 | log_error("--private-users-chown may not be combined with custom root mounts.")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 313, __func__, "--private-users-chown may not be combined with custom root mounts." ) : -abs(_e); }); |
314 | return -EINVAL22; |
315 | } else if (arg_uid_shift == UID_INVALID((uid_t) -1)) { |
316 | log_error("--private-users with automatic UID shift may not be combined with custom root mounts.")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 316, __func__, "--private-users with automatic UID shift may not be combined with custom root mounts." ) : -abs(_e); }); |
317 | return -EINVAL22; |
318 | } |
319 | } |
320 | } |
321 | |
322 | return 0; |
323 | } |
324 | |
325 | static int detect_unified_cgroup_hierarchy_from_environment(void) { |
326 | const char *e; |
327 | int r; |
328 | |
329 | /* Allow the user to control whether the unified hierarchy is used */ |
330 | e = getenv("UNIFIED_CGROUP_HIERARCHY"); |
331 | if (e) { |
332 | r = parse_boolean(e); |
333 | if (r < 0) |
334 | return log_error_errno(r, "Failed to parse $UNIFIED_CGROUP_HIERARCHY.")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 334, __func__, "Failed to parse $UNIFIED_CGROUP_HIERARCHY." ) : -abs(_e); }); |
335 | if (r > 0) |
336 | arg_unified_cgroup_hierarchy = CGROUP_UNIFIED_ALL; |
337 | else |
338 | arg_unified_cgroup_hierarchy = CGROUP_UNIFIED_NONE; |
339 | } |
340 | |
341 | return 0; |
342 | } |
343 | |
344 | static int detect_unified_cgroup_hierarchy_from_image(const char *directory) { |
345 | int r; |
346 | |
347 | /* Let's inherit the mode to use from the host system, but let's take into consideration what systemd in the |
348 | * image actually supports. */ |
349 | r = cg_all_unified(); |
350 | if (r < 0) |
351 | return log_error_errno(r, "Failed to determine whether we are in all unified mode.")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 351, __func__, "Failed to determine whether we are in all unified mode." ) : -abs(_e); }); |
352 | if (r > 0) { |
353 | /* Unified cgroup hierarchy support was added in 230. Unfortunately the detection |
354 | * routine only detects 231, so we'll have a false negative here for 230. */ |
355 | r = systemd_installation_has_version(directory, 230); |
356 | if (r < 0) |
357 | return log_error_errno(r, "Failed to determine systemd version in container: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 357, __func__, "Failed to determine systemd version in container: %m" ) : -abs(_e); }); |
358 | if (r > 0) |
359 | arg_unified_cgroup_hierarchy = CGROUP_UNIFIED_ALL; |
360 | else |
361 | arg_unified_cgroup_hierarchy = CGROUP_UNIFIED_NONE; |
362 | } else if (cg_unified_controller(SYSTEMD_CGROUP_CONTROLLER"_systemd") > 0) { |
363 | /* Mixed cgroup hierarchy support was added in 233 */ |
364 | r = systemd_installation_has_version(directory, 233); |
365 | if (r < 0) |
366 | return log_error_errno(r, "Failed to determine systemd version in container: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 366, __func__, "Failed to determine systemd version in container: %m" ) : -abs(_e); }); |
367 | if (r > 0) |
368 | arg_unified_cgroup_hierarchy = CGROUP_UNIFIED_SYSTEMD; |
369 | else |
370 | arg_unified_cgroup_hierarchy = CGROUP_UNIFIED_NONE; |
371 | } else |
372 | arg_unified_cgroup_hierarchy = CGROUP_UNIFIED_NONE; |
373 | |
374 | log_debug("Using %s hierarchy for container.",({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 376, __func__, "Using %s hierarchy for container." , arg_unified_cgroup_hierarchy == CGROUP_UNIFIED_NONE ? "legacy" : arg_unified_cgroup_hierarchy == CGROUP_UNIFIED_SYSTEMD ? "hybrid" : "unified") : -abs(_e); }) |
375 | arg_unified_cgroup_hierarchy == CGROUP_UNIFIED_NONE ? "legacy" :({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 376, __func__, "Using %s hierarchy for container." , arg_unified_cgroup_hierarchy == CGROUP_UNIFIED_NONE ? "legacy" : arg_unified_cgroup_hierarchy == CGROUP_UNIFIED_SYSTEMD ? "hybrid" : "unified") : -abs(_e); }) |
376 | arg_unified_cgroup_hierarchy == CGROUP_UNIFIED_SYSTEMD ? "hybrid" : "unified")({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 376, __func__, "Using %s hierarchy for container." , arg_unified_cgroup_hierarchy == CGROUP_UNIFIED_NONE ? "legacy" : arg_unified_cgroup_hierarchy == CGROUP_UNIFIED_SYSTEMD ? "hybrid" : "unified") : -abs(_e); }); |
377 | |
378 | return 0; |
379 | } |
380 | |
381 | static void parse_share_ns_env(const char *name, unsigned long ns_flag) { |
382 | int r; |
383 | |
384 | r = getenv_bool(name); |
385 | if (r == -ENXIO6) |
386 | return; |
387 | if (r < 0) |
388 | log_warning_errno(r, "Failed to parse %s from environment, defaulting to false.", name)({ int _level = ((4)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 388, __func__, "Failed to parse %s from environment, defaulting to false." , name) : -abs(_e); }); |
389 | arg_clone_ns_flags = (arg_clone_ns_flags & ~ns_flag) | (r > 0 ? 0 : ns_flag); |
390 | } |
391 | |
392 | static void parse_mount_settings_env(void) { |
393 | int r; |
394 | const char *e; |
395 | |
396 | e = getenv("SYSTEMD_NSPAWN_API_VFS_WRITABLE"); |
397 | if (!e) |
398 | return; |
399 | |
400 | if (streq(e, "network")(strcmp((e),("network")) == 0)) { |
401 | arg_mount_settings |= MOUNT_APPLY_APIVFS_RO|MOUNT_APPLY_APIVFS_NETNS; |
402 | return; |
403 | } |
404 | |
405 | r = parse_boolean(e); |
406 | if (r < 0) { |
407 | log_warning_errno(r, "Failed to parse SYSTEMD_NSPAWN_API_VFS_WRITABLE from environment, ignoring.")({ int _level = ((4)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 407, __func__, "Failed to parse SYSTEMD_NSPAWN_API_VFS_WRITABLE from environment, ignoring." ) : -abs(_e); }); |
408 | return; |
409 | } |
410 | |
411 | SET_FLAG(arg_mount_settings, MOUNT_APPLY_APIVFS_RO, r == 0)(arg_mount_settings) = (r == 0) ? ((arg_mount_settings) | (MOUNT_APPLY_APIVFS_RO )) : ((arg_mount_settings) & ~(MOUNT_APPLY_APIVFS_RO)); |
412 | SET_FLAG(arg_mount_settings, MOUNT_APPLY_APIVFS_NETNS, false)(arg_mount_settings) = (0) ? ((arg_mount_settings) | (MOUNT_APPLY_APIVFS_NETNS )) : ((arg_mount_settings) & ~(MOUNT_APPLY_APIVFS_NETNS)); |
413 | } |
414 | |
415 | static int parse_argv(int argc, char *argv[]) { |
416 | enum { |
417 | ARG_VERSION = 0x100, |
418 | ARG_PRIVATE_NETWORK, |
419 | ARG_UUID, |
420 | ARG_READ_ONLY, |
421 | ARG_CAPABILITY, |
422 | ARG_DROP_CAPABILITY, |
423 | ARG_LINK_JOURNAL, |
424 | ARG_BIND, |
425 | ARG_BIND_RO, |
426 | ARG_TMPFS, |
427 | ARG_OVERLAY, |
428 | ARG_OVERLAY_RO, |
429 | ARG_SHARE_SYSTEM, |
430 | ARG_REGISTER, |
431 | ARG_KEEP_UNIT, |
432 | ARG_NETWORK_INTERFACE, |
433 | ARG_NETWORK_MACVLAN, |
434 | ARG_NETWORK_IPVLAN, |
435 | ARG_NETWORK_BRIDGE, |
436 | ARG_NETWORK_ZONE, |
437 | ARG_NETWORK_VETH_EXTRA, |
438 | ARG_NETWORK_NAMESPACE_PATH, |
439 | ARG_PERSONALITY, |
440 | ARG_VOLATILE, |
441 | ARG_TEMPLATE, |
442 | ARG_PROPERTY, |
443 | ARG_PRIVATE_USERS, |
444 | ARG_KILL_SIGNAL, |
445 | ARG_SETTINGS, |
446 | ARG_CHDIR, |
447 | ARG_PIVOT_ROOT, |
448 | ARG_PRIVATE_USERS_CHOWN, |
449 | ARG_NOTIFY_READY, |
450 | ARG_ROOT_HASH, |
451 | ARG_SYSTEM_CALL_FILTER, |
452 | ARG_RLIMIT, |
453 | ARG_HOSTNAME, |
454 | ARG_NO_NEW_PRIVILEGES, |
455 | ARG_OOM_SCORE_ADJUST, |
456 | ARG_CPU_AFFINITY, |
457 | ARG_RESOLV_CONF, |
458 | ARG_TIMEZONE, |
459 | }; |
460 | |
461 | static const struct option options[] = { |
462 | { "help", no_argument0, NULL((void*)0), 'h' }, |
463 | { "version", no_argument0, NULL((void*)0), ARG_VERSION }, |
464 | { "directory", required_argument1, NULL((void*)0), 'D' }, |
465 | { "template", required_argument1, NULL((void*)0), ARG_TEMPLATE }, |
466 | { "ephemeral", no_argument0, NULL((void*)0), 'x' }, |
467 | { "user", required_argument1, NULL((void*)0), 'u' }, |
468 | { "private-network", no_argument0, NULL((void*)0), ARG_PRIVATE_NETWORK }, |
469 | { "as-pid2", no_argument0, NULL((void*)0), 'a' }, |
470 | { "boot", no_argument0, NULL((void*)0), 'b' }, |
471 | { "uuid", required_argument1, NULL((void*)0), ARG_UUID }, |
472 | { "read-only", no_argument0, NULL((void*)0), ARG_READ_ONLY }, |
473 | { "capability", required_argument1, NULL((void*)0), ARG_CAPABILITY }, |
474 | { "drop-capability", required_argument1, NULL((void*)0), ARG_DROP_CAPABILITY }, |
475 | { "no-new-privileges", required_argument1, NULL((void*)0), ARG_NO_NEW_PRIVILEGES }, |
476 | { "link-journal", required_argument1, NULL((void*)0), ARG_LINK_JOURNAL }, |
477 | { "bind", required_argument1, NULL((void*)0), ARG_BIND }, |
478 | { "bind-ro", required_argument1, NULL((void*)0), ARG_BIND_RO }, |
479 | { "tmpfs", required_argument1, NULL((void*)0), ARG_TMPFS }, |
480 | { "overlay", required_argument1, NULL((void*)0), ARG_OVERLAY }, |
481 | { "overlay-ro", required_argument1, NULL((void*)0), ARG_OVERLAY_RO }, |
482 | { "machine", required_argument1, NULL((void*)0), 'M' }, |
483 | { "hostname", required_argument1, NULL((void*)0), ARG_HOSTNAME }, |
484 | { "slice", required_argument1, NULL((void*)0), 'S' }, |
485 | { "setenv", required_argument1, NULL((void*)0), 'E' }, |
486 | { "selinux-context", required_argument1, NULL((void*)0), 'Z' }, |
487 | { "selinux-apifs-context", required_argument1, NULL((void*)0), 'L' }, |
488 | { "quiet", no_argument0, NULL((void*)0), 'q' }, |
489 | { "share-system", no_argument0, NULL((void*)0), ARG_SHARE_SYSTEM }, /* not documented */ |
490 | { "register", required_argument1, NULL((void*)0), ARG_REGISTER }, |
491 | { "keep-unit", no_argument0, NULL((void*)0), ARG_KEEP_UNIT }, |
492 | { "network-interface", required_argument1, NULL((void*)0), ARG_NETWORK_INTERFACE }, |
493 | { "network-macvlan", required_argument1, NULL((void*)0), ARG_NETWORK_MACVLAN }, |
494 | { "network-ipvlan", required_argument1, NULL((void*)0), ARG_NETWORK_IPVLAN }, |
495 | { "network-veth", no_argument0, NULL((void*)0), 'n' }, |
496 | { "network-veth-extra", required_argument1, NULL((void*)0), ARG_NETWORK_VETH_EXTRA }, |
497 | { "network-bridge", required_argument1, NULL((void*)0), ARG_NETWORK_BRIDGE }, |
498 | { "network-zone", required_argument1, NULL((void*)0), ARG_NETWORK_ZONE }, |
499 | { "network-namespace-path", required_argument1, NULL((void*)0), ARG_NETWORK_NAMESPACE_PATH }, |
500 | { "personality", required_argument1, NULL((void*)0), ARG_PERSONALITY }, |
501 | { "image", required_argument1, NULL((void*)0), 'i' }, |
502 | { "volatile", optional_argument2, NULL((void*)0), ARG_VOLATILE }, |
503 | { "port", required_argument1, NULL((void*)0), 'p' }, |
504 | { "property", required_argument1, NULL((void*)0), ARG_PROPERTY }, |
505 | { "private-users", optional_argument2, NULL((void*)0), ARG_PRIVATE_USERS }, |
506 | { "private-users-chown", optional_argument2, NULL((void*)0), ARG_PRIVATE_USERS_CHOWN }, |
507 | { "kill-signal", required_argument1, NULL((void*)0), ARG_KILL_SIGNAL }, |
508 | { "settings", required_argument1, NULL((void*)0), ARG_SETTINGS }, |
509 | { "chdir", required_argument1, NULL((void*)0), ARG_CHDIR }, |
510 | { "pivot-root", required_argument1, NULL((void*)0), ARG_PIVOT_ROOT }, |
511 | { "notify-ready", required_argument1, NULL((void*)0), ARG_NOTIFY_READY }, |
512 | { "root-hash", required_argument1, NULL((void*)0), ARG_ROOT_HASH }, |
513 | { "system-call-filter", required_argument1, NULL((void*)0), ARG_SYSTEM_CALL_FILTER }, |
514 | { "rlimit", required_argument1, NULL((void*)0), ARG_RLIMIT }, |
515 | { "oom-score-adjust", required_argument1, NULL((void*)0), ARG_OOM_SCORE_ADJUST }, |
516 | { "cpu-affinity", required_argument1, NULL((void*)0), ARG_CPU_AFFINITY }, |
517 | { "resolv-conf", required_argument1, NULL((void*)0), ARG_RESOLV_CONF }, |
518 | { "timezone", required_argument1, NULL((void*)0), ARG_TIMEZONE }, |
519 | {} |
520 | }; |
521 | |
522 | int c, r; |
523 | const char *p, *e; |
524 | uint64_t plus = 0, minus = 0; |
525 | bool_Bool mask_all_settings = false0, mask_no_settings = false0; |
526 | |
527 | assert(argc >= 0)do { if ((__builtin_expect(!!(!(argc >= 0)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("argc >= 0"), "../src/nspawn/nspawn.c" , 527, __PRETTY_FUNCTION__); } while (0); |
528 | assert(argv)do { if ((__builtin_expect(!!(!(argv)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("argv"), "../src/nspawn/nspawn.c", 528, __PRETTY_FUNCTION__ ); } while (0); |
529 | |
530 | while ((c = getopt_long(argc, argv, "+hD:u:abL:M:jS:Z:qi:xp:nUE:", options, NULL((void*)0))) >= 0) |
531 | switch (c) { |
532 | |
533 | case 'h': |
534 | help(); |
535 | return 0; |
536 | |
537 | case ARG_VERSION: |
538 | return version(); |
539 | |
540 | case 'D': |
541 | r = parse_path_argument_and_warn(optarg, false0, &arg_directory); |
542 | if (r < 0) |
543 | return r; |
544 | break; |
545 | |
546 | case ARG_TEMPLATE: |
547 | r = parse_path_argument_and_warn(optarg, false0, &arg_template); |
548 | if (r < 0) |
549 | return r; |
550 | break; |
551 | |
552 | case 'i': |
553 | r = parse_path_argument_and_warn(optarg, false0, &arg_image); |
554 | if (r < 0) |
555 | return r; |
556 | break; |
557 | |
558 | case 'x': |
559 | arg_ephemeral = true1; |
560 | break; |
561 | |
562 | case 'u': |
563 | r = free_and_strdup(&arg_user, optarg); |
564 | if (r < 0) |
565 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/nspawn/nspawn.c", 565, __func__); |
566 | |
567 | arg_settings_mask |= SETTING_USER; |
568 | break; |
569 | |
570 | case ARG_NETWORK_ZONE: { |
571 | char *j; |
572 | |
573 | j = strappend("vz-", optarg); |
574 | if (!j) |
575 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/nspawn/nspawn.c", 575, __func__); |
576 | |
577 | if (!ifname_valid(j)) { |
578 | log_error("Network zone name not valid: %s", j)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 578, __func__, "Network zone name not valid: %s" , j) : -abs(_e); }); |
579 | free(j); |
580 | return -EINVAL22; |
581 | } |
582 | |
583 | free_and_replace(arg_network_zone, j)({ free(arg_network_zone); (arg_network_zone) = (j); (j) = (( void*)0); 0; }); |
584 | |
585 | arg_network_veth = true1; |
586 | arg_private_network = true1; |
587 | arg_settings_mask |= SETTING_NETWORK; |
588 | break; |
589 | } |
590 | |
591 | case ARG_NETWORK_BRIDGE: |
592 | |
593 | if (!ifname_valid(optarg)) { |
594 | log_error("Bridge interface name not valid: %s", optarg)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 594, __func__, "Bridge interface name not valid: %s" , optarg) : -abs(_e); }); |
595 | return -EINVAL22; |
596 | } |
597 | |
598 | r = free_and_strdup(&arg_network_bridge, optarg); |
599 | if (r < 0) |
600 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/nspawn/nspawn.c", 600, __func__); |
601 | |
602 | _fallthrough_; |
603 | case 'n': |
604 | arg_network_veth = true1; |
605 | arg_private_network = true1; |
606 | arg_settings_mask |= SETTING_NETWORK; |
607 | break; |
608 | |
609 | case ARG_NETWORK_VETH_EXTRA: |
610 | r = veth_extra_parse(&arg_network_veth_extra, optarg); |
611 | if (r < 0) |
612 | return log_error_errno(r, "Failed to parse --network-veth-extra= parameter: %s", optarg)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 612, __func__, "Failed to parse --network-veth-extra= parameter: %s" , optarg) : -abs(_e); }); |
613 | |
614 | arg_private_network = true1; |
615 | arg_settings_mask |= SETTING_NETWORK; |
616 | break; |
617 | |
618 | case ARG_NETWORK_INTERFACE: |
619 | if (!ifname_valid(optarg)) { |
620 | log_error("Network interface name not valid: %s", optarg)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 620, __func__, "Network interface name not valid: %s" , optarg) : -abs(_e); }); |
621 | return -EINVAL22; |
622 | } |
623 | |
624 | if (strv_extend(&arg_network_interfaces, optarg) < 0) |
625 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/nspawn/nspawn.c", 625, __func__); |
626 | |
627 | arg_private_network = true1; |
628 | arg_settings_mask |= SETTING_NETWORK; |
629 | break; |
630 | |
631 | case ARG_NETWORK_MACVLAN: |
632 | |
633 | if (!ifname_valid(optarg)) { |
634 | log_error("MACVLAN network interface name not valid: %s", optarg)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 634, __func__, "MACVLAN network interface name not valid: %s" , optarg) : -abs(_e); }); |
635 | return -EINVAL22; |
636 | } |
637 | |
638 | if (strv_extend(&arg_network_macvlan, optarg) < 0) |
639 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/nspawn/nspawn.c", 639, __func__); |
640 | |
641 | arg_private_network = true1; |
642 | arg_settings_mask |= SETTING_NETWORK; |
643 | break; |
644 | |
645 | case ARG_NETWORK_IPVLAN: |
646 | |
647 | if (!ifname_valid(optarg)) { |
648 | log_error("IPVLAN network interface name not valid: %s", optarg)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 648, __func__, "IPVLAN network interface name not valid: %s" , optarg) : -abs(_e); }); |
649 | return -EINVAL22; |
650 | } |
651 | |
652 | if (strv_extend(&arg_network_ipvlan, optarg) < 0) |
653 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/nspawn/nspawn.c", 653, __func__); |
654 | |
655 | _fallthrough_; |
656 | case ARG_PRIVATE_NETWORK: |
657 | arg_private_network = true1; |
658 | arg_settings_mask |= SETTING_NETWORK; |
659 | break; |
660 | |
661 | case ARG_NETWORK_NAMESPACE_PATH: |
662 | r = parse_path_argument_and_warn(optarg, false0, &arg_network_namespace_path); |
663 | if (r < 0) |
664 | return r; |
665 | |
666 | break; |
667 | |
668 | case 'b': |
669 | if (arg_start_mode == START_PID2) { |
670 | log_error("--boot and --as-pid2 may not be combined.")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 670, __func__, "--boot and --as-pid2 may not be combined." ) : -abs(_e); }); |
671 | return -EINVAL22; |
672 | } |
673 | |
674 | arg_start_mode = START_BOOT; |
675 | arg_settings_mask |= SETTING_START_MODE; |
676 | break; |
677 | |
678 | case 'a': |
679 | if (arg_start_mode == START_BOOT) { |
680 | log_error("--boot and --as-pid2 may not be combined.")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 680, __func__, "--boot and --as-pid2 may not be combined." ) : -abs(_e); }); |
681 | return -EINVAL22; |
682 | } |
683 | |
684 | arg_start_mode = START_PID2; |
685 | arg_settings_mask |= SETTING_START_MODE; |
686 | break; |
687 | |
688 | case ARG_UUID: |
689 | r = sd_id128_from_string(optarg, &arg_uuid); |
690 | if (r < 0) |
691 | return log_error_errno(r, "Invalid UUID: %s", optarg)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 691, __func__, "Invalid UUID: %s" , optarg) : -abs(_e); }); |
692 | |
693 | if (sd_id128_is_null(arg_uuid)) { |
694 | log_error("Machine UUID may not be all zeroes.")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 694, __func__, "Machine UUID may not be all zeroes." ) : -abs(_e); }); |
695 | return -EINVAL22; |
696 | } |
697 | |
698 | arg_settings_mask |= SETTING_MACHINE_ID; |
699 | break; |
700 | |
701 | case 'S': |
702 | arg_slice = optarg; |
703 | break; |
704 | |
705 | case 'M': |
706 | if (isempty(optarg)) |
707 | arg_machine = mfree(arg_machine); |
708 | else { |
709 | if (!machine_name_is_valid(optarg)hostname_is_valid(optarg, 0)) { |
710 | log_error("Invalid machine name: %s", optarg)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 710, __func__, "Invalid machine name: %s" , optarg) : -abs(_e); }); |
711 | return -EINVAL22; |
712 | } |
713 | |
714 | r = free_and_strdup(&arg_machine, optarg); |
715 | if (r < 0) |
716 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/nspawn/nspawn.c", 716, __func__); |
717 | } |
718 | break; |
719 | |
720 | case ARG_HOSTNAME: |
721 | if (isempty(optarg)) |
722 | arg_hostname = mfree(arg_hostname); |
723 | else { |
724 | if (!hostname_is_valid(optarg, false0)) { |
725 | log_error("Invalid hostname: %s", optarg)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 725, __func__, "Invalid hostname: %s" , optarg) : -abs(_e); }); |
726 | return -EINVAL22; |
727 | } |
728 | |
729 | r = free_and_strdup(&arg_hostname, optarg); |
730 | if (r < 0) |
731 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/nspawn/nspawn.c", 731, __func__); |
732 | } |
733 | |
734 | arg_settings_mask |= SETTING_HOSTNAME; |
735 | break; |
736 | |
737 | case 'Z': |
738 | arg_selinux_context = optarg; |
739 | break; |
740 | |
741 | case 'L': |
742 | arg_selinux_apifs_context = optarg; |
743 | break; |
744 | |
745 | case ARG_READ_ONLY: |
746 | arg_read_only = true1; |
747 | arg_settings_mask |= SETTING_READ_ONLY; |
748 | break; |
749 | |
750 | case ARG_CAPABILITY: |
751 | case ARG_DROP_CAPABILITY: { |
752 | p = optarg; |
753 | for (;;) { |
754 | _cleanup_free___attribute__((cleanup(freep))) char *t = NULL((void*)0); |
755 | |
756 | r = extract_first_word(&p, &t, ",", 0); |
757 | if (r < 0) |
758 | return log_error_errno(r, "Failed to parse capability %s.", t)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 758, __func__, "Failed to parse capability %s." , t) : -abs(_e); }); |
759 | |
760 | if (r == 0) |
761 | break; |
762 | |
763 | if (streq(t, "all")(strcmp((t),("all")) == 0)) { |
764 | if (c == ARG_CAPABILITY) |
765 | plus = (uint64_t) -1; |
766 | else |
767 | minus = (uint64_t) -1; |
768 | } else { |
769 | int cap; |
770 | |
771 | cap = capability_from_name(t); |
772 | if (cap < 0) { |
773 | log_error("Failed to parse capability %s.", t)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 773, __func__, "Failed to parse capability %s." , t) : -abs(_e); }); |
774 | return -EINVAL22; |
775 | } |
776 | |
777 | if (c == ARG_CAPABILITY) |
778 | plus |= 1ULL << (uint64_t) cap; |
779 | else |
780 | minus |= 1ULL << (uint64_t) cap; |
781 | } |
782 | } |
783 | |
784 | arg_settings_mask |= SETTING_CAPABILITY; |
785 | break; |
786 | } |
787 | |
788 | case ARG_NO_NEW_PRIVILEGES: |
789 | r = parse_boolean(optarg); |
790 | if (r < 0) |
791 | return log_error_errno(r, "Failed to parse --no-new-privileges= argument: %s", optarg)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 791, __func__, "Failed to parse --no-new-privileges= argument: %s" , optarg) : -abs(_e); }); |
792 | |
793 | arg_no_new_privileges = r; |
794 | arg_settings_mask |= SETTING_NO_NEW_PRIVILEGES; |
795 | break; |
796 | |
797 | case 'j': |
798 | arg_link_journal = LINK_GUEST; |
799 | arg_link_journal_try = true1; |
800 | arg_settings_mask |= SETTING_LINK_JOURNAL; |
801 | break; |
802 | |
803 | case ARG_LINK_JOURNAL: |
804 | r = parse_link_journal(optarg, &arg_link_journal, &arg_link_journal_try); |
805 | if (r < 0) { |
806 | log_error_errno(r, "Failed to parse link journal mode %s", optarg)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 806, __func__, "Failed to parse link journal mode %s" , optarg) : -abs(_e); }); |
807 | return -EINVAL22; |
808 | } |
809 | |
810 | arg_settings_mask |= SETTING_LINK_JOURNAL; |
811 | break; |
812 | |
813 | case ARG_BIND: |
814 | case ARG_BIND_RO: |
815 | r = bind_mount_parse(&arg_custom_mounts, &arg_n_custom_mounts, optarg, c == ARG_BIND_RO); |
816 | if (r < 0) |
817 | return log_error_errno(r, "Failed to parse --bind(-ro)= argument %s: %m", optarg)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 817, __func__, "Failed to parse --bind(-ro)= argument %s: %m" , optarg) : -abs(_e); }); |
818 | |
819 | arg_settings_mask |= SETTING_CUSTOM_MOUNTS; |
820 | break; |
821 | |
822 | case ARG_TMPFS: |
823 | r = tmpfs_mount_parse(&arg_custom_mounts, &arg_n_custom_mounts, optarg); |
824 | if (r < 0) |
825 | return log_error_errno(r, "Failed to parse --tmpfs= argument %s: %m", optarg)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 825, __func__, "Failed to parse --tmpfs= argument %s: %m" , optarg) : -abs(_e); }); |
826 | |
827 | arg_settings_mask |= SETTING_CUSTOM_MOUNTS; |
828 | break; |
829 | |
830 | case ARG_OVERLAY: |
831 | case ARG_OVERLAY_RO: |
832 | r = overlay_mount_parse(&arg_custom_mounts, &arg_n_custom_mounts, optarg, c == ARG_OVERLAY_RO); |
833 | if (r == -EADDRNOTAVAIL99) |
834 | return log_error_errno(r, "--overlay(-ro)= needs at least two colon-separated directories specified.")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 834, __func__, "--overlay(-ro)= needs at least two colon-separated directories specified." ) : -abs(_e); }); |
835 | if (r < 0) |
836 | return log_error_errno(r, "Failed to parse --overlay(-ro)= argument %s: %m", optarg)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 836, __func__, "Failed to parse --overlay(-ro)= argument %s: %m" , optarg) : -abs(_e); }); |
837 | |
838 | arg_settings_mask |= SETTING_CUSTOM_MOUNTS; |
839 | break; |
840 | |
841 | case 'E': { |
842 | char **n; |
843 | |
844 | if (!env_assignment_is_valid(optarg)) { |
845 | log_error("Environment variable assignment '%s' is not valid.", optarg)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 845, __func__, "Environment variable assignment '%s' is not valid." , optarg) : -abs(_e); }); |
846 | return -EINVAL22; |
847 | } |
848 | |
849 | n = strv_env_set(arg_setenv, optarg); |
850 | if (!n) |
851 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/nspawn/nspawn.c", 851, __func__); |
852 | |
853 | strv_free_and_replace(arg_setenv, n)({ strv_free(arg_setenv); (arg_setenv) = (n); (n) = ((void*)0 ); 0; }); |
854 | arg_settings_mask |= SETTING_ENVIRONMENT; |
855 | break; |
856 | } |
857 | |
858 | case 'q': |
859 | arg_quiet = true1; |
860 | break; |
861 | |
862 | case ARG_SHARE_SYSTEM: |
863 | /* We don't officially support this anymore, except for compat reasons. People should use the |
864 | * $SYSTEMD_NSPAWN_SHARE_* environment variables instead. */ |
865 | log_warning("Please do not use --share-system anymore, use $SYSTEMD_NSPAWN_SHARE_* instead.")({ int _level = (((4))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 865, __func__, "Please do not use --share-system anymore, use $SYSTEMD_NSPAWN_SHARE_* instead." ) : -abs(_e); }); |
866 | arg_clone_ns_flags = 0; |
867 | break; |
868 | |
869 | case ARG_REGISTER: |
870 | r = parse_boolean(optarg); |
871 | if (r < 0) { |
872 | log_error("Failed to parse --register= argument: %s", optarg)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 872, __func__, "Failed to parse --register= argument: %s" , optarg) : -abs(_e); }); |
873 | return r; |
874 | } |
875 | |
876 | arg_register = r; |
877 | break; |
878 | |
879 | case ARG_KEEP_UNIT: |
880 | arg_keep_unit = true1; |
881 | break; |
882 | |
883 | case ARG_PERSONALITY: |
884 | |
885 | arg_personality = personality_from_string(optarg); |
886 | if (arg_personality == PERSONALITY_INVALID0xffffffffLU) { |
887 | log_error("Unknown or unsupported personality '%s'.", optarg)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 887, __func__, "Unknown or unsupported personality '%s'." , optarg) : -abs(_e); }); |
888 | return -EINVAL22; |
889 | } |
890 | |
891 | arg_settings_mask |= SETTING_PERSONALITY; |
892 | break; |
893 | |
894 | case ARG_VOLATILE: |
895 | |
896 | if (!optarg) |
897 | arg_volatile_mode = VOLATILE_YES; |
898 | else if (streq(optarg, "help")(strcmp((optarg),("help")) == 0)) { |
899 | DUMP_STRING_TABLE(volatile_mode, VolatileMode, _VOLATILE_MODE_MAX)do { VolatileMode _k; flockfile(stdout); for (_k = 0; _k < (_VOLATILE_MODE_MAX); _k++) { const char *_t; _t = volatile_mode_to_string (_k); if (!_t) continue; fputs_unlocked(_t, stdout); fputc_unlocked ('\n', stdout); } funlockfile(stdout); } while(0); |
900 | return 0; |
901 | } else { |
902 | VolatileMode m; |
903 | |
904 | m = volatile_mode_from_string(optarg); |
905 | if (m < 0) { |
906 | log_error("Failed to parse --volatile= argument: %s", optarg)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 906, __func__, "Failed to parse --volatile= argument: %s" , optarg) : -abs(_e); }); |
907 | return -EINVAL22; |
908 | } else |
909 | arg_volatile_mode = m; |
910 | } |
911 | |
912 | arg_settings_mask |= SETTING_VOLATILE_MODE; |
913 | break; |
914 | |
915 | case 'p': |
916 | r = expose_port_parse(&arg_expose_ports, optarg); |
917 | if (r == -EEXIST17) |
918 | return log_error_errno(r, "Duplicate port specification: %s", optarg)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 918, __func__, "Duplicate port specification: %s" , optarg) : -abs(_e); }); |
919 | if (r < 0) |
920 | return log_error_errno(r, "Failed to parse host port %s: %m", optarg)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 920, __func__, "Failed to parse host port %s: %m" , optarg) : -abs(_e); }); |
921 | |
922 | arg_settings_mask |= SETTING_EXPOSE_PORTS; |
923 | break; |
924 | |
925 | case ARG_PROPERTY: |
926 | if (strv_extend(&arg_property, optarg) < 0) |
927 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/nspawn/nspawn.c", 927, __func__); |
928 | |
929 | break; |
930 | |
931 | case ARG_PRIVATE_USERS: { |
932 | int boolean = -1; |
933 | |
934 | if (!optarg) |
935 | boolean = true1; |
936 | else if (!in_charset(optarg, DIGITS"0123456789")) |
937 | /* do *not* parse numbers as booleans */ |
938 | boolean = parse_boolean(optarg); |
939 | |
940 | if (boolean == false0) { |
941 | /* no: User namespacing off */ |
942 | arg_userns_mode = USER_NAMESPACE_NO; |
943 | arg_uid_shift = UID_INVALID((uid_t) -1); |
944 | arg_uid_range = UINT32_C(0x10000)0x10000U; |
945 | } else if (boolean == true1) { |
946 | /* yes: User namespacing on, UID range is read from root dir */ |
947 | arg_userns_mode = USER_NAMESPACE_FIXED; |
948 | arg_uid_shift = UID_INVALID((uid_t) -1); |
949 | arg_uid_range = UINT32_C(0x10000)0x10000U; |
950 | } else if (streq(optarg, "pick")(strcmp((optarg),("pick")) == 0)) { |
951 | /* pick: User namespacing on, UID range is picked randomly */ |
952 | arg_userns_mode = USER_NAMESPACE_PICK; |
953 | arg_uid_shift = UID_INVALID((uid_t) -1); |
954 | arg_uid_range = UINT32_C(0x10000)0x10000U; |
955 | } else { |
956 | _cleanup_free___attribute__((cleanup(freep))) char *buffer = NULL((void*)0); |
957 | const char *range, *shift; |
958 | |
959 | /* anything else: User namespacing on, UID range is explicitly configured */ |
960 | |
961 | range = strchr(optarg, ':'); |
962 | if (range) { |
963 | buffer = strndup(optarg, range - optarg); |
964 | if (!buffer) |
965 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/nspawn/nspawn.c", 965, __func__); |
966 | shift = buffer; |
967 | |
968 | range++; |
969 | r = safe_atou32(range, &arg_uid_range); |
970 | if (r < 0) |
971 | return log_error_errno(r, "Failed to parse UID range \"%s\": %m", range)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 971, __func__, "Failed to parse UID range \"%s\": %m" , range) : -abs(_e); }); |
972 | } else |
973 | shift = optarg; |
974 | |
975 | r = parse_uid(shift, &arg_uid_shift); |
976 | if (r < 0) |
977 | return log_error_errno(r, "Failed to parse UID \"%s\": %m", optarg)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 977, __func__, "Failed to parse UID \"%s\": %m" , optarg) : -abs(_e); }); |
978 | |
979 | arg_userns_mode = USER_NAMESPACE_FIXED; |
980 | } |
981 | |
982 | if (arg_uid_range <= 0) { |
983 | log_error("UID range cannot be 0.")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 983, __func__, "UID range cannot be 0." ) : -abs(_e); }); |
984 | return -EINVAL22; |
985 | } |
986 | |
987 | arg_settings_mask |= SETTING_USERNS; |
988 | break; |
989 | } |
990 | |
991 | case 'U': |
992 | if (userns_supported()) { |
993 | arg_userns_mode = USER_NAMESPACE_PICK; |
994 | arg_uid_shift = UID_INVALID((uid_t) -1); |
995 | arg_uid_range = UINT32_C(0x10000)0x10000U; |
996 | |
997 | arg_settings_mask |= SETTING_USERNS; |
998 | } |
999 | |
1000 | break; |
1001 | |
1002 | case ARG_PRIVATE_USERS_CHOWN: |
1003 | arg_userns_chown = true1; |
1004 | |
1005 | arg_settings_mask |= SETTING_USERNS; |
1006 | break; |
1007 | |
1008 | case ARG_KILL_SIGNAL: |
1009 | if (streq(optarg, "help")(strcmp((optarg),("help")) == 0)) { |
1010 | DUMP_STRING_TABLE(signal, int, _NSIG)do { int _k; flockfile(stdout); for (_k = 0; _k < ((64 + 1 )); _k++) { const char *_t; _t = signal_to_string(_k); if (!_t ) continue; fputs_unlocked(_t, stdout); fputc_unlocked('\n', stdout ); } funlockfile(stdout); } while(0); |
1011 | return 0; |
1012 | } |
1013 | |
1014 | arg_kill_signal = signal_from_string(optarg); |
1015 | if (arg_kill_signal < 0) { |
1016 | log_error("Cannot parse signal: %s", optarg)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 1016, __func__, "Cannot parse signal: %s" , optarg) : -abs(_e); }); |
1017 | return -EINVAL22; |
1018 | } |
1019 | |
1020 | arg_settings_mask |= SETTING_KILL_SIGNAL; |
1021 | break; |
1022 | |
1023 | case ARG_SETTINGS: |
1024 | |
1025 | /* no → do not read files |
1026 | * yes → read files, do not override cmdline, trust only subset |
1027 | * override → read files, override cmdline, trust only subset |
1028 | * trusted → read files, do not override cmdline, trust all |
1029 | */ |
1030 | |
1031 | r = parse_boolean(optarg); |
1032 | if (r < 0) { |
1033 | if (streq(optarg, "trusted")(strcmp((optarg),("trusted")) == 0)) { |
1034 | mask_all_settings = false0; |
1035 | mask_no_settings = false0; |
1036 | arg_settings_trusted = true1; |
1037 | |
1038 | } else if (streq(optarg, "override")(strcmp((optarg),("override")) == 0)) { |
1039 | mask_all_settings = false0; |
1040 | mask_no_settings = true1; |
1041 | arg_settings_trusted = -1; |
1042 | } else |
1043 | return log_error_errno(r, "Failed to parse --settings= argument: %s", optarg)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 1043, __func__, "Failed to parse --settings= argument: %s" , optarg) : -abs(_e); }); |
1044 | } else if (r > 0) { |
1045 | /* yes */ |
1046 | mask_all_settings = false0; |
1047 | mask_no_settings = false0; |
1048 | arg_settings_trusted = -1; |
1049 | } else { |
1050 | /* no */ |
1051 | mask_all_settings = true1; |
1052 | mask_no_settings = false0; |
1053 | arg_settings_trusted = false0; |
1054 | } |
1055 | |
1056 | break; |
1057 | |
1058 | case ARG_CHDIR: |
1059 | if (!path_is_absolute(optarg)) { |
1060 | log_error("Working directory %s is not an absolute path.", optarg)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 1060, __func__, "Working directory %s is not an absolute path." , optarg) : -abs(_e); }); |
1061 | return -EINVAL22; |
1062 | } |
1063 | |
1064 | r = free_and_strdup(&arg_chdir, optarg); |
1065 | if (r < 0) |
1066 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/nspawn/nspawn.c", 1066, __func__); |
1067 | |
1068 | arg_settings_mask |= SETTING_WORKING_DIRECTORY; |
1069 | break; |
1070 | |
1071 | case ARG_PIVOT_ROOT: |
1072 | r = pivot_root_parse(&arg_pivot_root_new, &arg_pivot_root_old, optarg); |
1073 | if (r < 0) |
1074 | return log_error_errno(r, "Failed to parse --pivot-root= argument %s: %m", optarg)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 1074, __func__, "Failed to parse --pivot-root= argument %s: %m" , optarg) : -abs(_e); }); |
1075 | |
1076 | arg_settings_mask |= SETTING_PIVOT_ROOT; |
1077 | break; |
1078 | |
1079 | case ARG_NOTIFY_READY: |
1080 | r = parse_boolean(optarg); |
1081 | if (r < 0) { |
1082 | log_error("%s is not a valid notify mode. Valid modes are: yes, no, and ready.", optarg)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 1082, __func__, "%s is not a valid notify mode. Valid modes are: yes, no, and ready." , optarg) : -abs(_e); }); |
1083 | return -EINVAL22; |
1084 | } |
1085 | arg_notify_ready = r; |
1086 | arg_settings_mask |= SETTING_NOTIFY_READY; |
1087 | break; |
1088 | |
1089 | case ARG_ROOT_HASH: { |
1090 | void *k; |
1091 | size_t l; |
1092 | |
1093 | r = unhexmem(optarg, strlen(optarg), &k, &l); |
1094 | if (r < 0) |
1095 | return log_error_errno(r, "Failed to parse root hash: %s", optarg)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 1095, __func__, "Failed to parse root hash: %s" , optarg) : -abs(_e); }); |
1096 | if (l < sizeof(sd_id128_t)) { |
1097 | log_error("Root hash must be at least 128bit long: %s", optarg)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 1097, __func__, "Root hash must be at least 128bit long: %s" , optarg) : -abs(_e); }); |
1098 | free(k); |
1099 | return -EINVAL22; |
1100 | } |
1101 | |
1102 | free(arg_root_hash); |
1103 | arg_root_hash = k; |
1104 | arg_root_hash_size = l; |
1105 | break; |
1106 | } |
1107 | |
1108 | case ARG_SYSTEM_CALL_FILTER: { |
1109 | bool_Bool negative; |
1110 | const char *items; |
1111 | |
1112 | negative = optarg[0] == '~'; |
1113 | items = negative ? optarg + 1 : optarg; |
1114 | |
1115 | for (;;) { |
1116 | _cleanup_free___attribute__((cleanup(freep))) char *word = NULL((void*)0); |
1117 | |
1118 | r = extract_first_word(&items, &word, NULL((void*)0), 0); |
1119 | if (r == 0) |
1120 | break; |
1121 | if (r == -ENOMEM12) |
1122 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/nspawn/nspawn.c", 1122, __func__); |
1123 | if (r < 0) |
1124 | return log_error_errno(r, "Failed to parse system call filter: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 1124, __func__, "Failed to parse system call filter: %m" ) : -abs(_e); }); |
1125 | |
1126 | if (negative) |
1127 | r = strv_extend(&arg_syscall_blacklist, word); |
1128 | else |
1129 | r = strv_extend(&arg_syscall_whitelist, word); |
1130 | if (r < 0) |
1131 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/nspawn/nspawn.c", 1131, __func__); |
1132 | } |
1133 | |
1134 | arg_settings_mask |= SETTING_SYSCALL_FILTER; |
1135 | break; |
1136 | } |
1137 | |
1138 | case ARG_RLIMIT: { |
1139 | const char *eq; |
1140 | char *name; |
1141 | int rl; |
1142 | |
1143 | if (streq(optarg, "help")(strcmp((optarg),("help")) == 0)) { |
1144 | DUMP_STRING_TABLE(rlimit, int, _RLIMIT_MAX)do { int _k; flockfile(stdout); for (_k = 0; _k < ((__RLIMIT_RTTIME +1 > __RLIMIT_NLIMITS ? __RLIMIT_RTTIME+1 : __RLIMIT_NLIMITS )); _k++) { const char *_t; _t = rlimit_to_string(_k); if (!_t ) continue; fputs_unlocked(_t, stdout); fputc_unlocked('\n', stdout ); } funlockfile(stdout); } while(0); |
1145 | return 0; |
1146 | } |
1147 | |
1148 | eq = strchr(optarg, '='); |
1149 | if (!eq) { |
1150 | log_error("--rlimit= expects an '=' assignment.")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 1150, __func__, "--rlimit= expects an '=' assignment." ) : -abs(_e); }); |
1151 | return -EINVAL22; |
1152 | } |
1153 | |
1154 | name = strndup(optarg, eq - optarg); |
1155 | if (!name) |
1156 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/nspawn/nspawn.c", 1156, __func__); |
1157 | |
1158 | rl = rlimit_from_string_harder(name); |
1159 | if (rl < 0) { |
1160 | log_error("Unknown resource limit: %s", name)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 1160, __func__, "Unknown resource limit: %s" , name) : -abs(_e); }); |
1161 | return -EINVAL22; |
1162 | } |
1163 | |
1164 | if (!arg_rlimit[rl]) { |
1165 | arg_rlimit[rl] = new0(struct rlimit, 1)((struct rlimit*) calloc((1), sizeof(struct rlimit))); |
1166 | if (!arg_rlimit[rl]) |
1167 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/nspawn/nspawn.c", 1167, __func__); |
1168 | } |
1169 | |
1170 | r = rlimit_parse(rl, eq + 1, arg_rlimit[rl]); |
1171 | if (r < 0) |
1172 | return log_error_errno(r, "Failed to parse resource limit: %s", eq + 1)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 1172, __func__, "Failed to parse resource limit: %s" , eq + 1) : -abs(_e); }); |
1173 | |
1174 | arg_settings_mask |= SETTING_RLIMIT_FIRST((uint64_t) SETTING_RLIMIT_FIRST) << rl; |
1175 | break; |
1176 | } |
1177 | |
1178 | case ARG_OOM_SCORE_ADJUST: |
1179 | r = parse_oom_score_adjust(optarg, &arg_oom_score_adjust); |
1180 | if (r < 0) |
1181 | return log_error_errno(r, "Failed to parse --oom-score-adjust= parameter: %s", optarg)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 1181, __func__, "Failed to parse --oom-score-adjust= parameter: %s" , optarg) : -abs(_e); }); |
1182 | |
1183 | arg_oom_score_adjust_set = true1; |
1184 | arg_settings_mask |= SETTING_OOM_SCORE_ADJUST; |
1185 | break; |
1186 | |
1187 | case ARG_CPU_AFFINITY: { |
1188 | CPUSet cpuset; |
1189 | |
1190 | r = parse_cpu_set(optarg, &cpuset); |
1191 | if (r < 0) |
1192 | return log_error_errno(r, "Failed to parse CPU affinity mask %s: %m", optarg)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 1192, __func__, "Failed to parse CPU affinity mask %s: %m" , optarg) : -abs(_e); }); |
1193 | |
1194 | cpu_set_reset(&arg_cpu_set); |
1195 | arg_cpu_set = cpuset; |
1196 | arg_settings_mask |= SETTING_CPU_AFFINITY; |
1197 | break; |
1198 | } |
1199 | |
1200 | case ARG_RESOLV_CONF: |
1201 | if (streq(optarg, "help")(strcmp((optarg),("help")) == 0)) { |
1202 | DUMP_STRING_TABLE(resolv_conf_mode, ResolvConfMode, _RESOLV_CONF_MODE_MAX)do { ResolvConfMode _k; flockfile(stdout); for (_k = 0; _k < (_RESOLV_CONF_MODE_MAX); _k++) { const char *_t; _t = resolv_conf_mode_to_string (_k); if (!_t) continue; fputs_unlocked(_t, stdout); fputc_unlocked ('\n', stdout); } funlockfile(stdout); } while(0); |
1203 | return 0; |
1204 | } |
1205 | |
1206 | arg_resolv_conf = resolv_conf_mode_from_string(optarg); |
1207 | if (arg_resolv_conf < 0) { |
1208 | log_error("Failed to parse /etc/resolv.conf mode: %s", optarg)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 1208, __func__, "Failed to parse /etc/resolv.conf mode: %s" , optarg) : -abs(_e); }); |
1209 | return -EINVAL22; |
1210 | } |
1211 | |
1212 | arg_settings_mask |= SETTING_RESOLV_CONF; |
1213 | break; |
1214 | |
1215 | case ARG_TIMEZONE: |
1216 | if (streq(optarg, "help")(strcmp((optarg),("help")) == 0)) { |
1217 | DUMP_STRING_TABLE(timezone_mode, TimezoneMode, _TIMEZONE_MODE_MAX)do { TimezoneMode _k; flockfile(stdout); for (_k = 0; _k < (_TIMEZONE_MODE_MAX); _k++) { const char *_t; _t = timezone_mode_to_string (_k); if (!_t) continue; fputs_unlocked(_t, stdout); fputc_unlocked ('\n', stdout); } funlockfile(stdout); } while(0); |
1218 | return 0; |
1219 | } |
1220 | |
1221 | arg_timezone = timezone_mode_from_string(optarg); |
1222 | if (arg_timezone < 0) { |
1223 | log_error("Failed to parse /etc/localtime mode: %s", optarg)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 1223, __func__, "Failed to parse /etc/localtime mode: %s" , optarg) : -abs(_e); }); |
1224 | return -EINVAL22; |
1225 | } |
1226 | |
1227 | arg_settings_mask |= SETTING_TIMEZONE; |
1228 | break; |
1229 | |
1230 | case '?': |
1231 | return -EINVAL22; |
1232 | |
1233 | default: |
1234 | assert_not_reached("Unhandled option")do { log_assert_failed_unreachable_realm(LOG_REALM_SYSTEMD, ( "Unhandled option"), "../src/nspawn/nspawn.c", 1234, __PRETTY_FUNCTION__ ); } while (0); |
1235 | } |
1236 | |
1237 | /* If --network-namespace-path is given with any other network-related option, |
1238 | * we need to error out, to avoid conflicts between different network options. */ |
1239 | if (arg_network_namespace_path && |
1240 | (arg_network_interfaces || arg_network_macvlan || |
1241 | arg_network_ipvlan || arg_network_veth_extra || |
1242 | arg_network_bridge || arg_network_zone || |
1243 | arg_network_veth || arg_private_network)) { |
1244 | log_error("--network-namespace-path cannot be combined with other network options.")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 1244, __func__, "--network-namespace-path cannot be combined with other network options." ) : -abs(_e); }); |
1245 | return -EINVAL22; |
1246 | } |
1247 | |
1248 | parse_share_ns_env("SYSTEMD_NSPAWN_SHARE_NS_IPC", CLONE_NEWIPC0x08000000); |
1249 | parse_share_ns_env("SYSTEMD_NSPAWN_SHARE_NS_PID", CLONE_NEWPID0x20000000); |
1250 | parse_share_ns_env("SYSTEMD_NSPAWN_SHARE_NS_UTS", CLONE_NEWUTS0x04000000); |
1251 | parse_share_ns_env("SYSTEMD_NSPAWN_SHARE_SYSTEM", CLONE_NEWIPC0x08000000|CLONE_NEWPID0x20000000|CLONE_NEWUTS0x04000000); |
1252 | |
1253 | if (arg_userns_mode != USER_NAMESPACE_NO) |
1254 | arg_mount_settings |= MOUNT_USE_USERNS; |
1255 | |
1256 | if (arg_private_network) |
1257 | arg_mount_settings |= MOUNT_APPLY_APIVFS_NETNS; |
1258 | |
1259 | parse_mount_settings_env(); |
1260 | |
1261 | if (!(arg_clone_ns_flags & CLONE_NEWPID0x20000000) || |
1262 | !(arg_clone_ns_flags & CLONE_NEWUTS0x04000000)) { |
1263 | arg_register = false0; |
1264 | if (arg_start_mode != START_PID1) { |
1265 | log_error("--boot cannot be used without namespacing.")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 1265, __func__, "--boot cannot be used without namespacing." ) : -abs(_e); }); |
1266 | return -EINVAL22; |
1267 | } |
1268 | } |
1269 | |
1270 | if (arg_userns_mode == USER_NAMESPACE_PICK) |
1271 | arg_userns_chown = true1; |
1272 | |
1273 | if (arg_keep_unit && arg_register && cg_pid_get_owner_uid(0, NULL((void*)0)) >= 0) { |
1274 | /* Save the user from accidentally registering either user-$SESSION.scope or user@.service. |
1275 | * The latter is not technically a user session, but we don't need to labour the point. */ |
1276 | log_error("--keep-unit --register=yes may not be used when invoked from a user session.")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 1276, __func__, "--keep-unit --register=yes may not be used when invoked from a user session." ) : -abs(_e); }); |
1277 | return -EINVAL22; |
1278 | } |
1279 | |
1280 | if (arg_directory && arg_image) { |
1281 | log_error("--directory= and --image= may not be combined.")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 1281, __func__, "--directory= and --image= may not be combined." ) : -abs(_e); }); |
1282 | return -EINVAL22; |
1283 | } |
1284 | |
1285 | if (arg_template && arg_image) { |
1286 | log_error("--template= and --image= may not be combined.")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 1286, __func__, "--template= and --image= may not be combined." ) : -abs(_e); }); |
1287 | return -EINVAL22; |
1288 | } |
1289 | |
1290 | if (arg_ephemeral && arg_template && !arg_directory) { |
1291 | /* User asked for ephemeral execution but specified --template= instead of --directory=. Semantically |
1292 | * such an invocation makes some sense, see https://github.com/systemd/systemd/issues/3667. Let's |
1293 | * accept this here, and silently make "--ephemeral --template=" equivalent to "--ephemeral |
1294 | * --directory=". */ |
1295 | |
1296 | arg_directory = TAKE_PTR(arg_template)({ typeof(arg_template) _ptr_ = (arg_template); (arg_template ) = ((void*)0); _ptr_; }); |
1297 | } |
1298 | |
1299 | if (arg_template && !(arg_directory || arg_machine)) { |
1300 | log_error("--template= needs --directory= or --machine=.")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 1300, __func__, "--template= needs --directory= or --machine=." ) : -abs(_e); }); |
1301 | return -EINVAL22; |
1302 | } |
1303 | |
1304 | if (arg_ephemeral && arg_template) { |
1305 | log_error("--ephemeral and --template= may not be combined.")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 1305, __func__, "--ephemeral and --template= may not be combined." ) : -abs(_e); }); |
1306 | return -EINVAL22; |
1307 | } |
1308 | |
1309 | if (arg_ephemeral && !IN_SET(arg_link_journal, LINK_NO, LINK_AUTO)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){LINK_NO, LINK_AUTO})/sizeof(int)]; switch (arg_link_journal) { case LINK_NO: case LINK_AUTO: _found = 1 ; break; default: break; } _found; })) { |
1310 | log_error("--ephemeral and --link-journal= may not be combined.")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 1310, __func__, "--ephemeral and --link-journal= may not be combined." ) : -abs(_e); }); |
1311 | return -EINVAL22; |
1312 | } |
1313 | |
1314 | if (arg_userns_mode != USER_NAMESPACE_NO && !userns_supported()) { |
1315 | log_error("--private-users= is not supported, kernel compiled without user namespace support.")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 1315, __func__, "--private-users= is not supported, kernel compiled without user namespace support." ) : -abs(_e); }); |
1316 | return -EOPNOTSUPP95; |
1317 | } |
1318 | |
1319 | if (arg_userns_chown && arg_read_only) { |
1320 | log_error("--read-only and --private-users-chown may not be combined.")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 1320, __func__, "--read-only and --private-users-chown may not be combined." ) : -abs(_e); }); |
1321 | return -EINVAL22; |
1322 | } |
1323 | |
1324 | if (arg_network_bridge && arg_network_zone) { |
1325 | log_error("--network-bridge= and --network-zone= may not be combined.")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 1325, __func__, "--network-bridge= and --network-zone= may not be combined." ) : -abs(_e); }); |
1326 | return -EINVAL22; |
1327 | } |
1328 | |
1329 | if (argc > optind) { |
1330 | arg_parameters = strv_copy(argv + optind); |
1331 | if (!arg_parameters) |
1332 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/nspawn/nspawn.c", 1332, __func__); |
1333 | |
1334 | arg_settings_mask |= SETTING_START_MODE; |
1335 | } |
1336 | |
1337 | /* Load all settings from .nspawn files */ |
1338 | if (mask_no_settings) |
1339 | arg_settings_mask = 0; |
1340 | |
1341 | /* Don't load any settings from .nspawn files */ |
1342 | if (mask_all_settings) |
1343 | arg_settings_mask = _SETTINGS_MASK_ALL; |
1344 | |
1345 | arg_caps_retain = (arg_caps_retain | plus | (arg_private_network ? 1ULL << CAP_NET_ADMIN12 : 0)) & ~minus; |
1346 | |
1347 | r = cg_unified_flush(); |
1348 | if (r < 0) |
1349 | return log_error_errno(r, "Failed to determine whether the unified cgroups hierarchy is used: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 1349, __func__, "Failed to determine whether the unified cgroups hierarchy is used: %m" ) : -abs(_e); }); |
1350 | |
1351 | e = getenv("SYSTEMD_NSPAWN_CONTAINER_SERVICE"); |
1352 | if (e) |
1353 | arg_container_service_name = e; |
1354 | |
1355 | r = getenv_bool("SYSTEMD_NSPAWN_USE_CGNS"); |
1356 | if (r < 0) |
1357 | arg_use_cgns = cg_ns_supported(); |
1358 | else |
1359 | arg_use_cgns = r; |
1360 | |
1361 | r = custom_mount_check_all(); |
1362 | if (r < 0) |
1363 | return r; |
1364 | |
1365 | return 1; |
1366 | } |
1367 | |
1368 | static int verify_arguments(void) { |
1369 | if (arg_userns_mode != USER_NAMESPACE_NO && (arg_mount_settings & MOUNT_APPLY_APIVFS_NETNS) && !arg_private_network) { |
1370 | log_error("Invalid namespacing settings. Mounting sysfs with --private-users requires --private-network.")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 1370, __func__, "Invalid namespacing settings. Mounting sysfs with --private-users requires --private-network." ) : -abs(_e); }); |
1371 | return -EINVAL22; |
1372 | } |
1373 | |
1374 | if (arg_userns_mode != USER_NAMESPACE_NO && !(arg_mount_settings & MOUNT_APPLY_APIVFS_RO)) { |
1375 | log_error("Cannot combine --private-users with read-write mounts.")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 1375, __func__, "Cannot combine --private-users with read-write mounts." ) : -abs(_e); }); |
1376 | return -EINVAL22; |
1377 | } |
1378 | |
1379 | if (arg_volatile_mode != VOLATILE_NO && arg_read_only) { |
1380 | log_error("Cannot combine --read-only with --volatile. Note that --volatile already implies a read-only base hierarchy.")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 1380, __func__, "Cannot combine --read-only with --volatile. Note that --volatile already implies a read-only base hierarchy." ) : -abs(_e); }); |
1381 | return -EINVAL22; |
1382 | } |
1383 | |
1384 | if (arg_expose_ports && !arg_private_network) { |
1385 | log_error("Cannot use --port= without private networking.")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 1385, __func__, "Cannot use --port= without private networking." ) : -abs(_e); }); |
1386 | return -EINVAL22; |
1387 | } |
1388 | |
1389 | #if ! HAVE_LIBIPTC1 |
1390 | if (arg_expose_ports) { |
1391 | log_error("--port= is not supported, compiled without libiptc support.")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 1391, __func__, "--port= is not supported, compiled without libiptc support." ) : -abs(_e); }); |
1392 | return -EOPNOTSUPP95; |
1393 | } |
1394 | #endif |
1395 | |
1396 | if (arg_start_mode == START_BOOT && arg_kill_signal <= 0) |
1397 | arg_kill_signal = SIGRTMIN(__libc_current_sigrtmin ())+3; |
1398 | |
1399 | return 0; |
1400 | } |
1401 | |
1402 | static int userns_lchown(const char *p, uid_t uid, gid_t gid) { |
1403 | assert(p)do { if ((__builtin_expect(!!(!(p)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("p"), "../src/nspawn/nspawn.c", 1403, __PRETTY_FUNCTION__ ); } while (0); |
1404 | |
1405 | if (arg_userns_mode == USER_NAMESPACE_NO) |
1406 | return 0; |
1407 | |
1408 | if (uid == UID_INVALID((uid_t) -1) && gid == GID_INVALID((gid_t) -1)) |
1409 | return 0; |
1410 | |
1411 | if (uid != UID_INVALID((uid_t) -1)) { |
1412 | uid += arg_uid_shift; |
1413 | |
1414 | if (uid < arg_uid_shift || uid >= arg_uid_shift + arg_uid_range) |
1415 | return -EOVERFLOW75; |
1416 | } |
1417 | |
1418 | if (gid != GID_INVALID((gid_t) -1)) { |
1419 | gid += (gid_t) arg_uid_shift; |
1420 | |
1421 | if (gid < (gid_t) arg_uid_shift || gid >= (gid_t) (arg_uid_shift + arg_uid_range)) |
1422 | return -EOVERFLOW75; |
1423 | } |
1424 | |
1425 | if (lchown(p, uid, gid) < 0) |
1426 | return -errno(*__errno_location ()); |
1427 | |
1428 | return 0; |
1429 | } |
1430 | |
1431 | static int userns_mkdir(const char *root, const char *path, mode_t mode, uid_t uid, gid_t gid) { |
1432 | const char *q; |
1433 | int r; |
1434 | |
1435 | q = prefix_roota(root, path)({ const char* _path = (path), *_root = (root), *_ret; char * _p, *_n; size_t _l; while (_path[0] == '/' && _path[1 ] == '/') _path ++; if (empty_or_root(_root)) _ret = _path; else { _l = strlen(_root) + 1 + strlen(_path) + 1; _n = __builtin_alloca (_l); _p = stpcpy(_n, _root); while (_p > _n && _p [-1] == '/') _p--; if (_path[0] != '/') *(_p++) = '/'; strcpy (_p, _path); _ret = _n; } _ret; }); |
1436 | r = mkdir_errno_wrapper(q, mode); |
1437 | if (r == -EEXIST17) |
1438 | return 0; |
1439 | if (r < 0) |
1440 | return r; |
1441 | |
1442 | return userns_lchown(q, uid, gid); |
1443 | } |
1444 | |
1445 | static const char *timezone_from_path(const char *path) { |
1446 | const char *z; |
1447 | |
1448 | z = path_startswith(path, "../usr/share/zoneinfo/"); |
1449 | if (z) |
1450 | return z; |
1451 | |
1452 | z = path_startswith(path, "/usr/share/zoneinfo/"); |
1453 | if (z) |
1454 | return z; |
1455 | |
1456 | return NULL((void*)0); |
1457 | } |
1458 | |
1459 | static int setup_timezone(const char *dest) { |
1460 | _cleanup_free___attribute__((cleanup(freep))) char *p = NULL((void*)0), *etc = NULL((void*)0); |
1461 | const char *where, *check; |
1462 | TimezoneMode m; |
1463 | int r; |
1464 | |
1465 | assert(dest)do { if ((__builtin_expect(!!(!(dest)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("dest"), "../src/nspawn/nspawn.c", 1465, __PRETTY_FUNCTION__); } while (0); |
1466 | |
1467 | if (IN_SET(arg_timezone, TIMEZONE_AUTO, TIMEZONE_SYMLINK)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){TIMEZONE_AUTO, TIMEZONE_SYMLINK})/sizeof (int)]; switch(arg_timezone) { case TIMEZONE_AUTO: case TIMEZONE_SYMLINK : _found = 1; break; default: break; } _found; })) { |
1468 | r = readlink_malloc("/etc/localtime", &p); |
1469 | if (r == -ENOENT2 && arg_timezone == TIMEZONE_AUTO) |
1470 | m = arg_read_only && arg_volatile_mode != VOLATILE_YES ? TIMEZONE_OFF : TIMEZONE_DELETE; |
1471 | else if (r == -EINVAL22 && arg_timezone == TIMEZONE_AUTO) /* regular file? */ |
1472 | m = arg_read_only && arg_volatile_mode != VOLATILE_YES ? TIMEZONE_BIND : TIMEZONE_COPY; |
1473 | else if (r < 0) { |
1474 | log_warning_errno(r, "Failed to read host's /etc/localtime symlink, not updating container timezone: %m")({ int _level = ((4)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 1474, __func__, "Failed to read host's /etc/localtime symlink, not updating container timezone: %m" ) : -abs(_e); }); |
1475 | /* To handle warning, delete /etc/localtime and replace it with a symbolic link to a time zone data |
1476 | * file. |
1477 | * |
1478 | * Example: |
1479 | * ln -s /usr/share/zoneinfo/UTC /etc/localtime |
1480 | */ |
1481 | return 0; |
1482 | } else if (arg_timezone == TIMEZONE_AUTO) |
1483 | m = arg_read_only && arg_volatile_mode != VOLATILE_YES ? TIMEZONE_BIND : TIMEZONE_SYMLINK; |
1484 | else |
1485 | m = arg_timezone; |
1486 | } else |
1487 | m = arg_timezone; |
1488 | |
1489 | if (m == TIMEZONE_OFF) |
1490 | return 0; |
1491 | |
1492 | r = chase_symlinks("/etc", dest, CHASE_PREFIX_ROOT, &etc); |
1493 | if (r < 0) { |
1494 | log_warning_errno(r, "Failed to resolve /etc path in container, ignoring: %m")({ int _level = ((4)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 1494, __func__, "Failed to resolve /etc path in container, ignoring: %m" ) : -abs(_e); }); |
1495 | return 0; |
1496 | } |
1497 | |
1498 | where = strjoina(etc, "/localtime")({ const char *_appendees_[] = { etc, "/localtime" }; char *_d_ , *_p_; size_t _len_ = 0; size_t _i_; for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p(typeof (_appendees_), typeof(&*(_appendees_))), sizeof(_appendees_ )/sizeof((_appendees_)[0]), ((void)0))) && _appendees_ [_i_]; _i_++) _len_ += strlen(_appendees_[_i_]); _p_ = _d_ = __builtin_alloca (_len_ + 1); for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr ( !__builtin_types_compatible_p(typeof(_appendees_), typeof(& *(_appendees_))), sizeof(_appendees_)/sizeof((_appendees_)[0] ), ((void)0))) && _appendees_[_i_]; _i_++) _p_ = stpcpy (_p_, _appendees_[_i_]); *_p_ = 0; _d_; }); |
1499 | |
1500 | switch (m) { |
1501 | |
1502 | case TIMEZONE_DELETE: |
1503 | if (unlink(where) < 0) |
1504 | log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_WARNING, errno, "Failed to remove '%s', ignoring: %m", where)({ int _level = (((*__errno_location ()) == 2 ? 7 : 4)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm (_realm) >= ((_level) & 0x07)) ? log_internal_realm((( _realm) << 10 | (_level)), _e, "../src/nspawn/nspawn.c" , 1504, __func__, "Failed to remove '%s', ignoring: %m", where ) : -abs(_e); }); |
1505 | |
1506 | return 0; |
1507 | |
1508 | case TIMEZONE_SYMLINK: { |
1509 | _cleanup_free___attribute__((cleanup(freep))) char *q = NULL((void*)0); |
1510 | const char *z, *what; |
1511 | |
1512 | z = timezone_from_path(p); |
1513 | if (!z) { |
1514 | log_warning("/etc/localtime does not point into /usr/share/zoneinfo/, not updating container timezone.")({ int _level = (((4))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 1514, __func__, "/etc/localtime does not point into /usr/share/zoneinfo/, not updating container timezone." ) : -abs(_e); }); |
1515 | return 0; |
1516 | } |
1517 | |
1518 | r = readlink_malloc(where, &q); |
1519 | if (r >= 0 && streq_ptr(timezone_from_path(q), z)) |
1520 | return 0; /* Already pointing to the right place? Then do nothing .. */ |
1521 | |
1522 | check = strjoina(dest, "/usr/share/zoneinfo/", z)({ const char *_appendees_[] = { dest, "/usr/share/zoneinfo/" , z }; char *_d_, *_p_; size_t _len_ = 0; size_t _i_; for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p (typeof(_appendees_), typeof(&*(_appendees_))), sizeof(_appendees_ )/sizeof((_appendees_)[0]), ((void)0))) && _appendees_ [_i_]; _i_++) _len_ += strlen(_appendees_[_i_]); _p_ = _d_ = __builtin_alloca (_len_ + 1); for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr ( !__builtin_types_compatible_p(typeof(_appendees_), typeof(& *(_appendees_))), sizeof(_appendees_)/sizeof((_appendees_)[0] ), ((void)0))) && _appendees_[_i_]; _i_++) _p_ = stpcpy (_p_, _appendees_[_i_]); *_p_ = 0; _d_; }); |
1523 | r = chase_symlinks(check, dest, 0, NULL((void*)0)); |
1524 | if (r < 0) |
1525 | log_debug_errno(r, "Timezone %s does not exist (or is not accessible) in container, not creating symlink: %m", z)({ int _level = ((7)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 1525, __func__, "Timezone %s does not exist (or is not accessible) in container, not creating symlink: %m" , z) : -abs(_e); }); |
1526 | else { |
1527 | if (unlink(where) < 0 && errno(*__errno_location ()) != ENOENT2) { |
1528 | log_full_errno(IN_SET(errno, EROFS, EACCES, EPERM) ? LOG_DEBUG : LOG_WARNING, /* Don't complain on read-only images */({ int _level = ((({ _Bool _found = 0; static __attribute__ ( (unused)) char _static_assert__macros_need_to_be_extended[20 - sizeof((int[]){30, 13, 1})/sizeof(int)]; switch((*__errno_location ())) { case 30: case 13: case 1: _found = 1; break; default: break; } _found; }) ? 7 : 4)), _e = (((*__errno_location ()) )), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm ) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/nspawn/nspawn.c", 1529, __func__, "Failed to remove existing timezone info %s in container, ignoring: %m" , where) : -abs(_e); }) |
1529 | errno, "Failed to remove existing timezone info %s in container, ignoring: %m", where)({ int _level = ((({ _Bool _found = 0; static __attribute__ ( (unused)) char _static_assert__macros_need_to_be_extended[20 - sizeof((int[]){30, 13, 1})/sizeof(int)]; switch((*__errno_location ())) { case 30: case 13: case 1: _found = 1; break; default: break; } _found; }) ? 7 : 4)), _e = (((*__errno_location ()) )), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm ) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/nspawn/nspawn.c", 1529, __func__, "Failed to remove existing timezone info %s in container, ignoring: %m" , where) : -abs(_e); }); |
1530 | return 0; |
1531 | } |
1532 | |
1533 | what = strjoina("../usr/share/zoneinfo/", z)({ const char *_appendees_[] = { "../usr/share/zoneinfo/", z } ; char *_d_, *_p_; size_t _len_ = 0; size_t _i_; for (_i_ = 0 ; _i_ < __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p (typeof(_appendees_), typeof(&*(_appendees_))), sizeof(_appendees_ )/sizeof((_appendees_)[0]), ((void)0))) && _appendees_ [_i_]; _i_++) _len_ += strlen(_appendees_[_i_]); _p_ = _d_ = __builtin_alloca (_len_ + 1); for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr ( !__builtin_types_compatible_p(typeof(_appendees_), typeof(& *(_appendees_))), sizeof(_appendees_)/sizeof((_appendees_)[0] ), ((void)0))) && _appendees_[_i_]; _i_++) _p_ = stpcpy (_p_, _appendees_[_i_]); *_p_ = 0; _d_; }); |
1534 | if (symlink(what, where) < 0) { |
1535 | log_full_errno(IN_SET(errno, EROFS, EACCES, EPERM) ? LOG_DEBUG : LOG_WARNING,({ int _level = ((({ _Bool _found = 0; static __attribute__ ( (unused)) char _static_assert__macros_need_to_be_extended[20 - sizeof((int[]){30, 13, 1})/sizeof(int)]; switch((*__errno_location ())) { case 30: case 13: case 1: _found = 1; break; default: break; } _found; }) ? 7 : 4)), _e = (((*__errno_location ()) )), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm ) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/nspawn/nspawn.c", 1536, __func__, "Failed to correct timezone of container, ignoring: %m" ) : -abs(_e); }) |
1536 | errno, "Failed to correct timezone of container, ignoring: %m")({ int _level = ((({ _Bool _found = 0; static __attribute__ ( (unused)) char _static_assert__macros_need_to_be_extended[20 - sizeof((int[]){30, 13, 1})/sizeof(int)]; switch((*__errno_location ())) { case 30: case 13: case 1: _found = 1; break; default: break; } _found; }) ? 7 : 4)), _e = (((*__errno_location ()) )), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm ) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/nspawn/nspawn.c", 1536, __func__, "Failed to correct timezone of container, ignoring: %m" ) : -abs(_e); }); |
1537 | return 0; |
1538 | } |
1539 | |
1540 | break; |
1541 | } |
1542 | |
1543 | _fallthrough_; |
1544 | } |
1545 | |
1546 | case TIMEZONE_BIND: { |
1547 | _cleanup_free___attribute__((cleanup(freep))) char *resolved = NULL((void*)0); |
1548 | int found; |
1549 | |
1550 | found = chase_symlinks(where, dest, CHASE_NONEXISTENT, &resolved); |
1551 | if (found < 0) { |
1552 | log_warning_errno(found, "Failed to resolve /etc/localtime path in container, ignoring: %m")({ int _level = ((4)), _e = ((found)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 1552, __func__, "Failed to resolve /etc/localtime path in container, ignoring: %m" ) : -abs(_e); }); |
1553 | return 0; |
1554 | } |
1555 | |
1556 | if (found == 0) /* missing? */ |
1557 | (void) touch(resolved); |
1558 | |
1559 | r = mount_verbose(LOG_WARNING4, "/etc/localtime", resolved, NULL((void*)0), MS_BINDMS_BIND, NULL((void*)0)); |
1560 | if (r >= 0) |
1561 | return mount_verbose(LOG_ERR3, NULL((void*)0), resolved, NULL((void*)0), MS_BINDMS_BIND|MS_REMOUNTMS_REMOUNT|MS_RDONLYMS_RDONLY|MS_NOSUIDMS_NOSUID|MS_NODEVMS_NODEV, NULL((void*)0)); |
1562 | |
1563 | _fallthrough_; |
1564 | } |
1565 | |
1566 | case TIMEZONE_COPY: |
1567 | /* If mounting failed, try to copy */ |
1568 | r = copy_file_atomic("/etc/localtime", where, 0644, 0, COPY_REFLINK|COPY_REPLACE); |
1569 | if (r < 0) { |
1570 | log_full_errno(IN_SET(r, -EROFS, -EACCES, -EPERM) ? LOG_DEBUG : LOG_WARNING, r,({ int _level = ((({ _Bool _found = 0; static __attribute__ ( (unused)) char _static_assert__macros_need_to_be_extended[20 - sizeof((int[]){-30, -13, -1})/sizeof(int)]; switch(r) { case -30: case -13: case -1: _found = 1; break; default: break; } _found; }) ? 7 : 4)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 1571, __func__, "Failed to copy /etc/localtime to %s, ignoring: %m" , where) : -abs(_e); }) |
1571 | "Failed to copy /etc/localtime to %s, ignoring: %m", where)({ int _level = ((({ _Bool _found = 0; static __attribute__ ( (unused)) char _static_assert__macros_need_to_be_extended[20 - sizeof((int[]){-30, -13, -1})/sizeof(int)]; switch(r) { case -30: case -13: case -1: _found = 1; break; default: break; } _found; }) ? 7 : 4)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 1571, __func__, "Failed to copy /etc/localtime to %s, ignoring: %m" , where) : -abs(_e); }); |
1572 | return 0; |
1573 | } |
1574 | |
1575 | break; |
1576 | |
1577 | default: |
1578 | assert_not_reached("unexpected mode")do { log_assert_failed_unreachable_realm(LOG_REALM_SYSTEMD, ( "unexpected mode"), "../src/nspawn/nspawn.c", 1578, __PRETTY_FUNCTION__ ); } while (0); |
1579 | } |
1580 | |
1581 | /* Fix permissions of the symlink or file copy we just created */ |
1582 | r = userns_lchown(where, 0, 0); |
1583 | if (r < 0) |
1584 | log_warning_errno(r, "Failed to chown /etc/localtime, ignoring: %m")({ int _level = ((4)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 1584, __func__, "Failed to chown /etc/localtime, ignoring: %m" ) : -abs(_e); }); |
1585 | |
1586 | return 0; |
1587 | } |
1588 | |
1589 | static int have_resolv_conf(const char *path) { |
1590 | assert(path)do { if ((__builtin_expect(!!(!(path)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("path"), "../src/nspawn/nspawn.c", 1590, __PRETTY_FUNCTION__); } while (0); |
1591 | |
1592 | if (access(path, F_OK0) < 0) { |
1593 | if (errno(*__errno_location ()) == ENOENT2) |
1594 | return 0; |
1595 | |
1596 | return log_debug_errno(errno, "Failed to determine whether '%s' is available: %m", path)({ int _level = ((7)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/nspawn/nspawn.c", 1596, __func__ , "Failed to determine whether '%s' is available: %m", path) : -abs(_e); }); |
1597 | } |
1598 | |
1599 | return 1; |
1600 | } |
1601 | |
1602 | static int resolved_listening(void) { |
1603 | _cleanup_(sd_bus_error_free)__attribute__((cleanup(sd_bus_error_free))) sd_bus_error error = SD_BUS_ERROR_NULL((const sd_bus_error) {(((void*)0)), (((void*)0)), 0}); |
1604 | _cleanup_(sd_bus_flush_close_unrefp)__attribute__((cleanup(sd_bus_flush_close_unrefp))) sd_bus *bus = NULL((void*)0); |
1605 | _cleanup_free___attribute__((cleanup(freep))) char *dns_stub_listener_mode = NULL((void*)0); |
1606 | int r; |
1607 | |
1608 | /* Check if resolved is listening */ |
1609 | |
1610 | r = sd_bus_open_system(&bus); |
1611 | if (r < 0) |
1612 | return log_debug_errno(r, "Failed to open system bus: %m")({ int _level = ((7)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 1612, __func__, "Failed to open system bus: %m" ) : -abs(_e); }); |
1613 | |
1614 | r = bus_name_has_owner(bus, "org.freedesktop.resolve1", NULL((void*)0)); |
1615 | if (r < 0) |
1616 | return log_debug_errno(r, "Failed to check whether the 'org.freedesktop.resolve1' bus name is taken: %m")({ int _level = ((7)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 1616, __func__, "Failed to check whether the 'org.freedesktop.resolve1' bus name is taken: %m" ) : -abs(_e); }); |
1617 | if (r == 0) |
1618 | return 0; |
1619 | |
1620 | r = sd_bus_get_property_string(bus, |
1621 | "org.freedesktop.resolve1", |
1622 | "/org/freedesktop/resolve1", |
1623 | "org.freedesktop.resolve1.Manager", |
1624 | "DNSStubListener", |
1625 | &error, |
1626 | &dns_stub_listener_mode); |
1627 | if (r < 0) |
1628 | return log_debug_errno(r, "Failed to query DNSStubListener property: %s", bus_error_message(&error, r))({ int _level = ((7)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 1628, __func__, "Failed to query DNSStubListener property: %s" , bus_error_message(&error, r)) : -abs(_e); }); |
1629 | |
1630 | return STR_IN_SET(dns_stub_listener_mode, "udp", "yes")(!!strv_find((((char**) ((const char*[]) { "udp", "yes", ((void *)0) }))), (dns_stub_listener_mode))); |
1631 | } |
1632 | |
1633 | static int setup_resolv_conf(const char *dest) { |
1634 | _cleanup_free___attribute__((cleanup(freep))) char *etc = NULL((void*)0); |
1635 | const char *where, *what; |
1636 | ResolvConfMode m; |
1637 | int r; |
1638 | |
1639 | assert(dest)do { if ((__builtin_expect(!!(!(dest)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("dest"), "../src/nspawn/nspawn.c", 1639, __PRETTY_FUNCTION__); } while (0); |
1640 | |
1641 | if (arg_resolv_conf == RESOLV_CONF_AUTO) { |
1642 | if (arg_private_network) |
1643 | m = RESOLV_CONF_OFF; |
1644 | else if (have_resolv_conf(STATIC_RESOLV_CONF"/usr/lib/systemd/resolv.conf") > 0 && resolved_listening() > 0) |
1645 | /* resolved is enabled on the host. In this, case bind mount its static resolv.conf file into the |
1646 | * container, so that the container can use the host's resolver. Given that network namespacing is |
1647 | * disabled it's only natural of the container also uses the host's resolver. It also has the big |
1648 | * advantage that the container will be able to follow the host's DNS server configuration changes |
1649 | * transparently. */ |
1650 | m = RESOLV_CONF_BIND_STATIC; |
1651 | else if (have_resolv_conf("/etc/resolv.conf") > 0) |
1652 | m = arg_read_only && arg_volatile_mode != VOLATILE_YES ? RESOLV_CONF_BIND_HOST : RESOLV_CONF_COPY_HOST; |
1653 | else |
1654 | m = arg_read_only && arg_volatile_mode != VOLATILE_YES ? RESOLV_CONF_OFF : RESOLV_CONF_DELETE; |
1655 | } else |
1656 | m = arg_resolv_conf; |
1657 | |
1658 | if (m == RESOLV_CONF_OFF) |
1659 | return 0; |
1660 | |
1661 | r = chase_symlinks("/etc", dest, CHASE_PREFIX_ROOT, &etc); |
1662 | if (r < 0) { |
1663 | log_warning_errno(r, "Failed to resolve /etc path in container, ignoring: %m")({ int _level = ((4)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 1663, __func__, "Failed to resolve /etc path in container, ignoring: %m" ) : -abs(_e); }); |
1664 | return 0; |
1665 | } |
1666 | |
1667 | where = strjoina(etc, "/resolv.conf")({ const char *_appendees_[] = { etc, "/resolv.conf" }; char * _d_, *_p_; size_t _len_ = 0; size_t _i_; for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p (typeof(_appendees_), typeof(&*(_appendees_))), sizeof(_appendees_ )/sizeof((_appendees_)[0]), ((void)0))) && _appendees_ [_i_]; _i_++) _len_ += strlen(_appendees_[_i_]); _p_ = _d_ = __builtin_alloca (_len_ + 1); for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr ( !__builtin_types_compatible_p(typeof(_appendees_), typeof(& *(_appendees_))), sizeof(_appendees_)/sizeof((_appendees_)[0] ), ((void)0))) && _appendees_[_i_]; _i_++) _p_ = stpcpy (_p_, _appendees_[_i_]); *_p_ = 0; _d_; }); |
1668 | |
1669 | if (m == RESOLV_CONF_DELETE) { |
1670 | if (unlink(where) < 0) |
1671 | log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_WARNING, errno, "Failed to remove '%s', ignoring: %m", where)({ int _level = (((*__errno_location ()) == 2 ? 7 : 4)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm (_realm) >= ((_level) & 0x07)) ? log_internal_realm((( _realm) << 10 | (_level)), _e, "../src/nspawn/nspawn.c" , 1671, __func__, "Failed to remove '%s', ignoring: %m", where ) : -abs(_e); }); |
1672 | |
1673 | return 0; |
1674 | } |
1675 | |
1676 | if (IN_SET(m, RESOLV_CONF_BIND_STATIC, RESOLV_CONF_COPY_STATIC)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){RESOLV_CONF_BIND_STATIC, RESOLV_CONF_COPY_STATIC })/sizeof(int)]; switch(m) { case RESOLV_CONF_BIND_STATIC: case RESOLV_CONF_COPY_STATIC: _found = 1; break; default: break; } _found; })) |
1677 | what = STATIC_RESOLV_CONF"/usr/lib/systemd/resolv.conf"; |
1678 | else |
1679 | what = "/etc/resolv.conf"; |
1680 | |
1681 | if (IN_SET(m, RESOLV_CONF_BIND_HOST, RESOLV_CONF_BIND_STATIC)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){RESOLV_CONF_BIND_HOST, RESOLV_CONF_BIND_STATIC })/sizeof(int)]; switch(m) { case RESOLV_CONF_BIND_HOST: case RESOLV_CONF_BIND_STATIC: _found = 1; break; default: break; } _found; })) { |
1682 | _cleanup_free___attribute__((cleanup(freep))) char *resolved = NULL((void*)0); |
1683 | int found; |
1684 | |
1685 | found = chase_symlinks(where, dest, CHASE_NONEXISTENT, &resolved); |
1686 | if (found < 0) { |
1687 | log_warning_errno(found, "Failed to resolve /etc/resolv.conf path in container, ignoring: %m")({ int _level = ((4)), _e = ((found)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 1687, __func__, "Failed to resolve /etc/resolv.conf path in container, ignoring: %m" ) : -abs(_e); }); |
1688 | return 0; |
1689 | } |
1690 | |
1691 | if (found == 0) /* missing? */ |
1692 | (void) touch(resolved); |
1693 | |
1694 | r = mount_verbose(LOG_WARNING4, what, resolved, NULL((void*)0), MS_BINDMS_BIND, NULL((void*)0)); |
1695 | if (r >= 0) |
1696 | return mount_verbose(LOG_ERR3, NULL((void*)0), resolved, NULL((void*)0), MS_BINDMS_BIND|MS_REMOUNTMS_REMOUNT|MS_RDONLYMS_RDONLY|MS_NOSUIDMS_NOSUID|MS_NODEVMS_NODEV, NULL((void*)0)); |
1697 | } |
1698 | |
1699 | /* If that didn't work, let's copy the file */ |
1700 | r = copy_file(what, where, O_TRUNC01000|O_NOFOLLOW0400000, 0644, 0, COPY_REFLINK); |
1701 | if (r < 0) { |
1702 | /* If the file already exists as symlink, let's suppress the warning, under the assumption that |
1703 | * resolved or something similar runs inside and the symlink points there. |
1704 | * |
1705 | * If the disk image is read-only, there's also no point in complaining. |
1706 | */ |
1707 | log_full_errno(!IN_SET(RESOLV_CONF_COPY_HOST, RESOLV_CONF_COPY_STATIC) && IN_SET(r, -ELOOP, -EROFS, -EACCES, -EPERM) ? LOG_DEBUG : LOG_WARNING, r,({ int _level = ((!({ _Bool _found = 0; static __attribute__ ( (unused)) char _static_assert__macros_need_to_be_extended[20 - sizeof((int[]){RESOLV_CONF_COPY_STATIC})/sizeof(int)]; switch (RESOLV_CONF_COPY_HOST) { case RESOLV_CONF_COPY_STATIC: _found = 1; break; default: break; } _found; }) && ({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){-40, -30, -13, -1})/sizeof(int)]; switch (r) { case -40: case -30: case -13: case -1: _found = 1; break ; default: break; } _found; }) ? 7 : 4)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ( (_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/nspawn/nspawn.c", 1708, __func__ , "Failed to copy /etc/resolv.conf to %s, ignoring: %m", where ) : -abs(_e); }) |
1708 | "Failed to copy /etc/resolv.conf to %s, ignoring: %m", where)({ int _level = ((!({ _Bool _found = 0; static __attribute__ ( (unused)) char _static_assert__macros_need_to_be_extended[20 - sizeof((int[]){RESOLV_CONF_COPY_STATIC})/sizeof(int)]; switch (RESOLV_CONF_COPY_HOST) { case RESOLV_CONF_COPY_STATIC: _found = 1; break; default: break; } _found; }) && ({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){-40, -30, -13, -1})/sizeof(int)]; switch (r) { case -40: case -30: case -13: case -1: _found = 1; break ; default: break; } _found; }) ? 7 : 4)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ( (_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/nspawn/nspawn.c", 1708, __func__ , "Failed to copy /etc/resolv.conf to %s, ignoring: %m", where ) : -abs(_e); }); |
1709 | return 0; |
1710 | } |
1711 | |
1712 | r = userns_lchown(where, 0, 0); |
1713 | if (r < 0) |
1714 | log_warning_errno(r, "Failed to chown /etc/resolv.conf, ignoring: %m")({ int _level = ((4)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 1714, __func__, "Failed to chown /etc/resolv.conf, ignoring: %m" ) : -abs(_e); }); |
1715 | |
1716 | return 0; |
1717 | } |
1718 | |
1719 | static int setup_boot_id(void) { |
1720 | _cleanup_(unlink_and_freep)__attribute__((cleanup(unlink_and_freep))) char *from = NULL((void*)0); |
1721 | _cleanup_free___attribute__((cleanup(freep))) char *path = NULL((void*)0); |
1722 | sd_id128_t rnd = SD_ID128_NULL((const sd_id128_t) { .qwords = { 0, 0 }}); |
1723 | const char *to; |
1724 | int r; |
1725 | |
1726 | /* Generate a new randomized boot ID, so that each boot-up of |
1727 | * the container gets a new one */ |
1728 | |
1729 | r = tempfn_random_child(NULL((void*)0), "proc-sys-kernel-random-boot-id", &path); |
1730 | if (r < 0) |
1731 | return log_error_errno(r, "Failed to generate random boot ID path: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 1731, __func__, "Failed to generate random boot ID path: %m" ) : -abs(_e); }); |
1732 | |
1733 | r = sd_id128_randomize(&rnd); |
1734 | if (r < 0) |
1735 | return log_error_errno(r, "Failed to generate random boot id: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 1735, __func__, "Failed to generate random boot id: %m" ) : -abs(_e); }); |
1736 | |
1737 | r = id128_write(path, ID128_UUID, rnd, false0); |
1738 | if (r < 0) |
1739 | return log_error_errno(r, "Failed to write boot id: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 1739, __func__, "Failed to write boot id: %m" ) : -abs(_e); }); |
1740 | |
1741 | from = TAKE_PTR(path)({ typeof(path) _ptr_ = (path); (path) = ((void*)0); _ptr_; } ); |
1742 | to = "/proc/sys/kernel/random/boot_id"; |
1743 | |
1744 | r = mount_verbose(LOG_ERR3, from, to, NULL((void*)0), MS_BINDMS_BIND, NULL((void*)0)); |
1745 | if (r < 0) |
1746 | return r; |
1747 | |
1748 | return mount_verbose(LOG_ERR3, NULL((void*)0), to, NULL((void*)0), MS_BINDMS_BIND|MS_REMOUNTMS_REMOUNT|MS_RDONLYMS_RDONLY|MS_NOSUIDMS_NOSUID|MS_NOEXECMS_NOEXEC|MS_NODEVMS_NODEV, NULL((void*)0)); |
1749 | } |
1750 | |
1751 | static int copy_devnodes(const char *dest) { |
1752 | static const char devnodes[] = |
1753 | "null\0" |
1754 | "zero\0" |
1755 | "full\0" |
1756 | "random\0" |
1757 | "urandom\0" |
1758 | "tty\0" |
1759 | "net/tun\0"; |
1760 | |
1761 | const char *d; |
1762 | int r = 0; |
1763 | _cleanup_umask___attribute__((cleanup(umaskp))) mode_t u; |
1764 | |
1765 | assert(dest)do { if ((__builtin_expect(!!(!(dest)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("dest"), "../src/nspawn/nspawn.c", 1765, __PRETTY_FUNCTION__); } while (0); |
1766 | |
1767 | u = umask(0000); |
1768 | |
1769 | /* Create /dev/net, so that we can create /dev/net/tun in it */ |
1770 | if (userns_mkdir(dest, "/dev/net", 0755, 0, 0) < 0) |
1771 | return log_error_errno(r, "Failed to create /dev/net directory: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 1771, __func__, "Failed to create /dev/net directory: %m" ) : -abs(_e); }); |
1772 | |
1773 | NULSTR_FOREACH(d, devnodes)for ((d) = (devnodes); (d) && *(d); (d) = strchr((d), 0)+1) { |
1774 | _cleanup_free___attribute__((cleanup(freep))) char *from = NULL((void*)0), *to = NULL((void*)0); |
1775 | struct stat st; |
1776 | |
1777 | from = strappend("/dev/", d); |
1778 | to = prefix_root(dest, from); |
1779 | |
1780 | if (stat(from, &st) < 0) { |
1781 | |
1782 | if (errno(*__errno_location ()) != ENOENT2) |
1783 | return log_error_errno(errno, "Failed to stat %s: %m", from)({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/nspawn/nspawn.c", 1783, __func__ , "Failed to stat %s: %m", from) : -abs(_e); }); |
1784 | |
1785 | } else if (!S_ISCHR(st.st_mode)((((st.st_mode)) & 0170000) == (0020000)) && !S_ISBLK(st.st_mode)((((st.st_mode)) & 0170000) == (0060000))) { |
1786 | |
1787 | log_error("%s is not a char or block device, cannot copy.", from)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 1787, __func__, "%s is not a char or block device, cannot copy." , from) : -abs(_e); }); |
1788 | return -EIO5; |
1789 | |
1790 | } else { |
1791 | if (mknod(to, st.st_mode, st.st_rdev) < 0) { |
1792 | /* Explicitly warn the user when /dev is already populated. */ |
1793 | if (errno(*__errno_location ()) == EEXIST17) |
1794 | log_notice("%s/dev is pre-mounted and pre-populated. If a pre-mounted /dev is provided it needs to be an unpopulated file system.", dest)({ int _level = (((5))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 1794, __func__, "%s/dev is pre-mounted and pre-populated. If a pre-mounted /dev is provided it needs to be an unpopulated file system." , dest) : -abs(_e); }); |
1795 | if (errno(*__errno_location ()) != EPERM1) |
1796 | return log_error_errno(errno, "mknod(%s) failed: %m", to)({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/nspawn/nspawn.c", 1796, __func__ , "mknod(%s) failed: %m", to) : -abs(_e); }); |
1797 | |
1798 | /* Some systems abusively restrict mknod but |
1799 | * allow bind mounts. */ |
1800 | r = touch(to); |
1801 | if (r < 0) |
1802 | return log_error_errno(r, "touch (%s) failed: %m", to)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 1802, __func__, "touch (%s) failed: %m" , to) : -abs(_e); }); |
1803 | r = mount_verbose(LOG_DEBUG7, from, to, NULL((void*)0), MS_BINDMS_BIND, NULL((void*)0)); |
1804 | if (r < 0) |
1805 | return log_error_errno(r, "Both mknod and bind mount (%s) failed: %m", to)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 1805, __func__, "Both mknod and bind mount (%s) failed: %m" , to) : -abs(_e); }); |
1806 | } |
1807 | |
1808 | r = userns_lchown(to, 0, 0); |
1809 | if (r < 0) |
1810 | return log_error_errno(r, "chown() of device node %s failed: %m", to)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 1810, __func__, "chown() of device node %s failed: %m" , to) : -abs(_e); }); |
1811 | } |
1812 | } |
1813 | |
1814 | return r; |
1815 | } |
1816 | |
1817 | static int setup_pts(const char *dest) { |
1818 | _cleanup_free___attribute__((cleanup(freep))) char *options = NULL((void*)0); |
1819 | const char *p; |
1820 | int r; |
1821 | |
1822 | #if HAVE_SELINUX1 |
1823 | if (arg_selinux_apifs_context) |
1824 | (void) asprintf(&options, |
1825 | "newinstance,ptmxmode=0666,mode=620,gid=" GID_FMT"%" "u" ",context=\"%s\"", |
1826 | arg_uid_shift + TTY_GID5, |
1827 | arg_selinux_apifs_context); |
1828 | else |
1829 | #endif |
1830 | (void) asprintf(&options, |
1831 | "newinstance,ptmxmode=0666,mode=620,gid=" GID_FMT"%" "u", |
1832 | arg_uid_shift + TTY_GID5); |
1833 | |
1834 | if (!options) |
1835 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/nspawn/nspawn.c", 1835, __func__); |
1836 | |
1837 | /* Mount /dev/pts itself */ |
1838 | p = prefix_roota(dest, "/dev/pts")({ const char* _path = ("/dev/pts"), *_root = (dest), *_ret; char *_p, *_n; size_t _l; while (_path[0] == '/' && _path [1] == '/') _path ++; if (empty_or_root(_root)) _ret = _path; else { _l = strlen(_root) + 1 + strlen(_path) + 1; _n = __builtin_alloca (_l); _p = stpcpy(_n, _root); while (_p > _n && _p [-1] == '/') _p--; if (_path[0] != '/') *(_p++) = '/'; strcpy (_p, _path); _ret = _n; } _ret; }); |
1839 | r = mkdir_errno_wrapper(p, 0755); |
1840 | if (r < 0) |
1841 | return log_error_errno(r, "Failed to create /dev/pts: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 1841, __func__, "Failed to create /dev/pts: %m" ) : -abs(_e); }); |
1842 | |
1843 | r = mount_verbose(LOG_ERR3, "devpts", p, "devpts", MS_NOSUIDMS_NOSUID|MS_NOEXECMS_NOEXEC, options); |
1844 | if (r < 0) |
1845 | return r; |
1846 | r = userns_lchown(p, 0, 0); |
1847 | if (r < 0) |
1848 | return log_error_errno(r, "Failed to chown /dev/pts: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 1848, __func__, "Failed to chown /dev/pts: %m" ) : -abs(_e); }); |
1849 | |
1850 | /* Create /dev/ptmx symlink */ |
1851 | p = prefix_roota(dest, "/dev/ptmx")({ const char* _path = ("/dev/ptmx"), *_root = (dest), *_ret; char *_p, *_n; size_t _l; while (_path[0] == '/' && _path [1] == '/') _path ++; if (empty_or_root(_root)) _ret = _path; else { _l = strlen(_root) + 1 + strlen(_path) + 1; _n = __builtin_alloca (_l); _p = stpcpy(_n, _root); while (_p > _n && _p [-1] == '/') _p--; if (_path[0] != '/') *(_p++) = '/'; strcpy (_p, _path); _ret = _n; } _ret; }); |
1852 | if (symlink("pts/ptmx", p) < 0) |
1853 | return log_error_errno(errno, "Failed to create /dev/ptmx symlink: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/nspawn/nspawn.c", 1853, __func__ , "Failed to create /dev/ptmx symlink: %m") : -abs(_e); }); |
1854 | r = userns_lchown(p, 0, 0); |
1855 | if (r < 0) |
1856 | return log_error_errno(r, "Failed to chown /dev/ptmx: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 1856, __func__, "Failed to chown /dev/ptmx: %m" ) : -abs(_e); }); |
1857 | |
1858 | /* And fix /dev/pts/ptmx ownership */ |
1859 | p = prefix_roota(dest, "/dev/pts/ptmx")({ const char* _path = ("/dev/pts/ptmx"), *_root = (dest), *_ret ; char *_p, *_n; size_t _l; while (_path[0] == '/' && _path[1] == '/') _path ++; if (empty_or_root(_root)) _ret = _path ; else { _l = strlen(_root) + 1 + strlen(_path) + 1; _n = __builtin_alloca (_l); _p = stpcpy(_n, _root); while (_p > _n && _p [-1] == '/') _p--; if (_path[0] != '/') *(_p++) = '/'; strcpy (_p, _path); _ret = _n; } _ret; }); |
1860 | r = userns_lchown(p, 0, 0); |
1861 | if (r < 0) |
1862 | return log_error_errno(r, "Failed to chown /dev/pts/ptmx: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 1862, __func__, "Failed to chown /dev/pts/ptmx: %m" ) : -abs(_e); }); |
1863 | |
1864 | return 0; |
1865 | } |
1866 | |
1867 | static int setup_dev_console(const char *dest, const char *console) { |
1868 | _cleanup_umask___attribute__((cleanup(umaskp))) mode_t u; |
1869 | const char *to; |
1870 | int r; |
1871 | |
1872 | assert(dest)do { if ((__builtin_expect(!!(!(dest)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("dest"), "../src/nspawn/nspawn.c", 1872, __PRETTY_FUNCTION__); } while (0); |
1873 | assert(console)do { if ((__builtin_expect(!!(!(console)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("console"), "../src/nspawn/nspawn.c", 1873 , __PRETTY_FUNCTION__); } while (0); |
1874 | |
1875 | u = umask(0000); |
1876 | |
1877 | r = chmod_and_chown(console, 0600, arg_uid_shift, arg_uid_shift); |
1878 | if (r < 0) |
1879 | return log_error_errno(r, "Failed to correct access mode for TTY: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 1879, __func__, "Failed to correct access mode for TTY: %m" ) : -abs(_e); }); |
1880 | |
1881 | /* We need to bind mount the right tty to /dev/console since |
1882 | * ptys can only exist on pts file systems. To have something |
1883 | * to bind mount things on we create a empty regular file. */ |
1884 | |
1885 | to = prefix_roota(dest, "/dev/console")({ const char* _path = ("/dev/console"), *_root = (dest), *_ret ; char *_p, *_n; size_t _l; while (_path[0] == '/' && _path[1] == '/') _path ++; if (empty_or_root(_root)) _ret = _path ; else { _l = strlen(_root) + 1 + strlen(_path) + 1; _n = __builtin_alloca (_l); _p = stpcpy(_n, _root); while (_p > _n && _p [-1] == '/') _p--; if (_path[0] != '/') *(_p++) = '/'; strcpy (_p, _path); _ret = _n; } _ret; }); |
1886 | r = touch(to); |
1887 | if (r < 0) |
1888 | return log_error_errno(r, "touch() for /dev/console failed: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 1888, __func__, "touch() for /dev/console failed: %m" ) : -abs(_e); }); |
1889 | |
1890 | return mount_verbose(LOG_ERR3, console, to, NULL((void*)0), MS_BINDMS_BIND, NULL((void*)0)); |
1891 | } |
1892 | |
1893 | static int setup_keyring(void) { |
1894 | key_serial_t keyring; |
1895 | |
1896 | /* Allocate a new session keyring for the container. This makes sure the keyring of the session systemd-nspawn |
1897 | * was invoked from doesn't leak into the container. Note that by default we block keyctl() and request_key() |
1898 | * anyway via seccomp so doing this operation isn't strictly necessary, but in case people explicitly whitelist |
1899 | * these system calls let's make sure we don't leak anything into the container. */ |
1900 | |
1901 | keyring = keyctlmissing_keyctl(KEYCTL_JOIN_SESSION_KEYRING1, 0, 0, 0, 0); |
1902 | if (keyring == -1) { |
1903 | if (errno(*__errno_location ()) == ENOSYS38) |
1904 | log_debug_errno(errno, "Kernel keyring not supported, ignoring.")({ int _level = ((7)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/nspawn/nspawn.c", 1904, __func__ , "Kernel keyring not supported, ignoring.") : -abs(_e); }); |
1905 | else if (IN_SET(errno, EACCES, EPERM)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){13, 1})/sizeof(int)]; switch((*__errno_location ())) { case 13: case 1: _found = 1; break; default: break; } _found; })) |
1906 | log_debug_errno(errno, "Kernel keyring access prohibited, ignoring.")({ int _level = ((7)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/nspawn/nspawn.c", 1906, __func__ , "Kernel keyring access prohibited, ignoring.") : -abs(_e); } ); |
1907 | else |
1908 | return log_error_errno(errno, "Setting up kernel keyring failed: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/nspawn/nspawn.c", 1908, __func__ , "Setting up kernel keyring failed: %m") : -abs(_e); }); |
1909 | } |
1910 | |
1911 | return 0; |
1912 | } |
1913 | |
1914 | static int setup_kmsg(int kmsg_socket) { |
1915 | _cleanup_(unlink_and_freep)__attribute__((cleanup(unlink_and_freep))) char *from = NULL((void*)0); |
1916 | _cleanup_free___attribute__((cleanup(freep))) char *fifo = NULL((void*)0); |
1917 | _cleanup_close___attribute__((cleanup(closep))) int fd = -1; |
1918 | _cleanup_umask___attribute__((cleanup(umaskp))) mode_t u; |
1919 | const char *to; |
1920 | int r; |
1921 | |
1922 | assert(kmsg_socket >= 0)do { if ((__builtin_expect(!!(!(kmsg_socket >= 0)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("kmsg_socket >= 0"), "../src/nspawn/nspawn.c" , 1922, __PRETTY_FUNCTION__); } while (0); |
1923 | |
1924 | u = umask(0000); |
1925 | |
1926 | /* We create the kmsg FIFO as as temporary file in /tmp, but immediately delete it after bind mounting it to |
1927 | * /proc/kmsg. While FIFOs on the reading side behave very similar to /proc/kmsg, their writing side behaves |
1928 | * differently from /dev/kmsg in that writing blocks when nothing is reading. In order to avoid any problems |
1929 | * with containers deadlocking due to this we simply make /dev/kmsg unavailable to the container. */ |
1930 | |
1931 | r = tempfn_random_child(NULL((void*)0), "proc-kmsg", &fifo); |
1932 | if (r < 0) |
1933 | return log_error_errno(r, "Failed to generate kmsg path: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 1933, __func__, "Failed to generate kmsg path: %m" ) : -abs(_e); }); |
1934 | |
1935 | if (mkfifo(fifo, 0600) < 0) |
1936 | return log_error_errno(errno, "mkfifo() for /run/kmsg failed: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/nspawn/nspawn.c", 1936, __func__ , "mkfifo() for /run/kmsg failed: %m") : -abs(_e); }); |
1937 | |
1938 | from = TAKE_PTR(fifo)({ typeof(fifo) _ptr_ = (fifo); (fifo) = ((void*)0); _ptr_; } ); |
1939 | to = "/proc/kmsg"; |
1940 | |
1941 | r = mount_verbose(LOG_ERR3, from, to, NULL((void*)0), MS_BINDMS_BIND, NULL((void*)0)); |
1942 | if (r < 0) |
1943 | return r; |
1944 | |
1945 | fd = open(from, O_RDWR02|O_NONBLOCK04000|O_CLOEXEC02000000); |
1946 | if (fd < 0) |
1947 | return log_error_errno(errno, "Failed to open fifo: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/nspawn/nspawn.c", 1947, __func__ , "Failed to open fifo: %m") : -abs(_e); }); |
1948 | |
1949 | /* Store away the fd in the socket, so that it stays open as long as we run the child */ |
1950 | r = send_one_fd(kmsg_socket, fd, 0)send_one_fd_iov_sa(kmsg_socket, fd, ((void*)0), 0, ((void*)0) , 0, 0); |
1951 | if (r < 0) |
1952 | return log_error_errno(r, "Failed to send FIFO fd: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 1952, __func__, "Failed to send FIFO fd: %m" ) : -abs(_e); }); |
1953 | |
1954 | return 0; |
1955 | } |
1956 | |
1957 | static int on_address_change(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) { |
1958 | union in_addr_union *exposed = userdata; |
1959 | |
1960 | assert(rtnl)do { if ((__builtin_expect(!!(!(rtnl)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("rtnl"), "../src/nspawn/nspawn.c", 1960, __PRETTY_FUNCTION__); } while (0); |
1961 | assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("m"), "../src/nspawn/nspawn.c", 1961, __PRETTY_FUNCTION__ ); } while (0); |
1962 | assert(exposed)do { if ((__builtin_expect(!!(!(exposed)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("exposed"), "../src/nspawn/nspawn.c", 1962 , __PRETTY_FUNCTION__); } while (0); |
1963 | |
1964 | expose_port_execute(rtnl, arg_expose_ports, exposed); |
1965 | return 0; |
1966 | } |
1967 | |
1968 | static int setup_hostname(void) { |
1969 | int r; |
1970 | |
1971 | if ((arg_clone_ns_flags & CLONE_NEWUTS0x04000000) == 0) |
1972 | return 0; |
1973 | |
1974 | r = sethostname_idempotent(arg_hostname ?: arg_machine); |
1975 | if (r < 0) |
1976 | return log_error_errno(r, "Failed to set hostname: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 1976, __func__, "Failed to set hostname: %m" ) : -abs(_e); }); |
1977 | |
1978 | return 0; |
1979 | } |
1980 | |
1981 | static int setup_journal(const char *directory) { |
1982 | sd_id128_t this_id; |
1983 | _cleanup_free___attribute__((cleanup(freep))) char *d = NULL((void*)0); |
1984 | const char *p, *q; |
1985 | bool_Bool try; |
1986 | char id[33]; |
1987 | int r; |
1988 | |
1989 | /* Don't link journals in ephemeral mode */ |
1990 | if (arg_ephemeral) |
1991 | return 0; |
1992 | |
1993 | if (arg_link_journal == LINK_NO) |
1994 | return 0; |
1995 | |
1996 | try = arg_link_journal_try || arg_link_journal == LINK_AUTO; |
1997 | |
1998 | r = sd_id128_get_machine(&this_id); |
1999 | if (r < 0) |
2000 | return log_error_errno(r, "Failed to retrieve machine ID: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 2000, __func__, "Failed to retrieve machine ID: %m" ) : -abs(_e); }); |
2001 | |
2002 | if (sd_id128_equal(arg_uuid, this_id)) { |
2003 | log_full(try ? LOG_WARNING : LOG_ERR,({ int _level = (((try ? 4 : 3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 2004, __func__, "Host and machine ids are equal (%s): refusing to link journals" , sd_id128_to_string(arg_uuid, id)) : -abs(_e); }) |
2004 | "Host and machine ids are equal (%s): refusing to link journals", sd_id128_to_string(arg_uuid, id))({ int _level = (((try ? 4 : 3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 2004, __func__, "Host and machine ids are equal (%s): refusing to link journals" , sd_id128_to_string(arg_uuid, id)) : -abs(_e); }); |
2005 | if (try) |
2006 | return 0; |
2007 | return -EEXIST17; |
2008 | } |
2009 | |
2010 | r = userns_mkdir(directory, "/var", 0755, 0, 0); |
2011 | if (r < 0) |
2012 | return log_error_errno(r, "Failed to create /var: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 2012, __func__, "Failed to create /var: %m" ) : -abs(_e); }); |
2013 | |
2014 | r = userns_mkdir(directory, "/var/log", 0755, 0, 0); |
2015 | if (r < 0) |
2016 | return log_error_errno(r, "Failed to create /var/log: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 2016, __func__, "Failed to create /var/log: %m" ) : -abs(_e); }); |
2017 | |
2018 | r = userns_mkdir(directory, "/var/log/journal", 0755, 0, 0); |
2019 | if (r < 0) |
2020 | return log_error_errno(r, "Failed to create /var/log/journal: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 2020, __func__, "Failed to create /var/log/journal: %m" ) : -abs(_e); }); |
2021 | |
2022 | (void) sd_id128_to_string(arg_uuid, id); |
2023 | |
2024 | p = strjoina("/var/log/journal/", id)({ const char *_appendees_[] = { "/var/log/journal/", id }; char *_d_, *_p_; size_t _len_ = 0; size_t _i_; for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p (typeof(_appendees_), typeof(&*(_appendees_))), sizeof(_appendees_ )/sizeof((_appendees_)[0]), ((void)0))) && _appendees_ [_i_]; _i_++) _len_ += strlen(_appendees_[_i_]); _p_ = _d_ = __builtin_alloca (_len_ + 1); for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr ( !__builtin_types_compatible_p(typeof(_appendees_), typeof(& *(_appendees_))), sizeof(_appendees_)/sizeof((_appendees_)[0] ), ((void)0))) && _appendees_[_i_]; _i_++) _p_ = stpcpy (_p_, _appendees_[_i_]); *_p_ = 0; _d_; }); |
2025 | q = prefix_roota(directory, p)({ const char* _path = (p), *_root = (directory), *_ret; char *_p, *_n; size_t _l; while (_path[0] == '/' && _path [1] == '/') _path ++; if (empty_or_root(_root)) _ret = _path; else { _l = strlen(_root) + 1 + strlen(_path) + 1; _n = __builtin_alloca (_l); _p = stpcpy(_n, _root); while (_p > _n && _p [-1] == '/') _p--; if (_path[0] != '/') *(_p++) = '/'; strcpy (_p, _path); _ret = _n; } _ret; }); |
2026 | |
2027 | if (path_is_mount_point(p, NULL((void*)0), 0) > 0) { |
2028 | if (try) |
2029 | return 0; |
2030 | |
2031 | log_error("%s: already a mount point, refusing to use for journal", p)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 2031, __func__, "%s: already a mount point, refusing to use for journal" , p) : -abs(_e); }); |
2032 | return -EEXIST17; |
2033 | } |
2034 | |
2035 | if (path_is_mount_point(q, NULL((void*)0), 0) > 0) { |
2036 | if (try) |
2037 | return 0; |
2038 | |
2039 | log_error("%s: already a mount point, refusing to use for journal", q)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 2039, __func__, "%s: already a mount point, refusing to use for journal" , q) : -abs(_e); }); |
2040 | return -EEXIST17; |
2041 | } |
2042 | |
2043 | r = readlink_and_make_absolute(p, &d); |
2044 | if (r >= 0) { |
2045 | if (IN_SET(arg_link_journal, LINK_GUEST, LINK_AUTO)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){LINK_GUEST, LINK_AUTO})/sizeof(int)]; switch (arg_link_journal) { case LINK_GUEST: case LINK_AUTO: _found = 1; break; default: break; } _found; }) && |
2046 | path_equal(d, q)) { |
2047 | |
2048 | r = userns_mkdir(directory, p, 0755, 0, 0); |
2049 | if (r < 0) |
2050 | log_warning_errno(r, "Failed to create directory %s: %m", q)({ int _level = ((4)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 2050, __func__, "Failed to create directory %s: %m" , q) : -abs(_e); }); |
2051 | return 0; |
2052 | } |
2053 | |
2054 | if (unlink(p) < 0) |
2055 | return log_error_errno(errno, "Failed to remove symlink %s: %m", p)({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/nspawn/nspawn.c", 2055, __func__ , "Failed to remove symlink %s: %m", p) : -abs(_e); }); |
2056 | } else if (r == -EINVAL22) { |
2057 | |
2058 | if (arg_link_journal == LINK_GUEST && |
2059 | rmdir(p) < 0) { |
2060 | |
2061 | if (errno(*__errno_location ()) == ENOTDIR20) { |
2062 | log_error("%s already exists and is neither a symlink nor a directory", p)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 2062, __func__, "%s already exists and is neither a symlink nor a directory" , p) : -abs(_e); }); |
2063 | return r; |
2064 | } else |
2065 | return log_error_errno(errno, "Failed to remove %s: %m", p)({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/nspawn/nspawn.c", 2065, __func__ , "Failed to remove %s: %m", p) : -abs(_e); }); |
2066 | } |
2067 | } else if (r != -ENOENT2) |
2068 | return log_error_errno(r, "readlink(%s) failed: %m", p)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 2068, __func__, "readlink(%s) failed: %m" , p) : -abs(_e); }); |
2069 | |
2070 | if (arg_link_journal == LINK_GUEST) { |
2071 | |
2072 | if (symlink(q, p) < 0) { |
2073 | if (try) { |
2074 | log_debug_errno(errno, "Failed to symlink %s to %s, skipping journal setup: %m", q, p)({ int _level = ((7)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/nspawn/nspawn.c", 2074, __func__ , "Failed to symlink %s to %s, skipping journal setup: %m", q , p) : -abs(_e); }); |
2075 | return 0; |
2076 | } else |
2077 | return log_error_errno(errno, "Failed to symlink %s to %s: %m", q, p)({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/nspawn/nspawn.c", 2077, __func__ , "Failed to symlink %s to %s: %m", q, p) : -abs(_e); }); |
2078 | } |
2079 | |
2080 | r = userns_mkdir(directory, p, 0755, 0, 0); |
2081 | if (r < 0) |
2082 | log_warning_errno(r, "Failed to create directory %s: %m", q)({ int _level = ((4)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 2082, __func__, "Failed to create directory %s: %m" , q) : -abs(_e); }); |
2083 | return 0; |
2084 | } |
2085 | |
2086 | if (arg_link_journal == LINK_HOST) { |
2087 | /* don't create parents here — if the host doesn't have |
2088 | * permanent journal set up, don't force it here */ |
2089 | |
2090 | r = mkdir_errno_wrapper(p, 0755); |
2091 | if (r < 0 && r != -EEXIST17) { |
2092 | if (try) { |
2093 | log_debug_errno(r, "Failed to create %s, skipping journal setup: %m", p)({ int _level = ((7)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 2093, __func__, "Failed to create %s, skipping journal setup: %m" , p) : -abs(_e); }); |
2094 | return 0; |
2095 | } else |
2096 | return log_error_errno(r, "Failed to create %s: %m", p)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 2096, __func__, "Failed to create %s: %m" , p) : -abs(_e); }); |
2097 | } |
2098 | |
2099 | } else if (access(p, F_OK0) < 0) |
2100 | return 0; |
2101 | |
2102 | if (dir_is_empty(q) == 0) |
2103 | log_warning("%s is not empty, proceeding anyway.", q)({ int _level = (((4))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 2103, __func__, "%s is not empty, proceeding anyway." , q) : -abs(_e); }); |
2104 | |
2105 | r = userns_mkdir(directory, p, 0755, 0, 0); |
2106 | if (r < 0) |
2107 | return log_error_errno(r, "Failed to create %s: %m", q)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 2107, __func__, "Failed to create %s: %m" , q) : -abs(_e); }); |
2108 | |
2109 | r = mount_verbose(LOG_DEBUG7, p, q, NULL((void*)0), MS_BINDMS_BIND, NULL((void*)0)); |
2110 | if (r < 0) |
2111 | return log_error_errno(errno, "Failed to bind mount journal from host into guest: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/nspawn/nspawn.c", 2111, __func__ , "Failed to bind mount journal from host into guest: %m") : - abs(_e); }); |
2112 | |
2113 | return 0; |
2114 | } |
2115 | |
2116 | static int drop_capabilities(void) { |
2117 | return capability_bounding_set_drop(arg_caps_retain, false0); |
2118 | } |
2119 | |
2120 | static int reset_audit_loginuid(void) { |
2121 | _cleanup_free___attribute__((cleanup(freep))) char *p = NULL((void*)0); |
2122 | int r; |
2123 | |
2124 | if ((arg_clone_ns_flags & CLONE_NEWPID0x20000000) == 0) |
2125 | return 0; |
2126 | |
2127 | r = read_one_line_file("/proc/self/loginuid", &p); |
2128 | if (r == -ENOENT2) |
2129 | return 0; |
2130 | if (r < 0) |
2131 | return log_error_errno(r, "Failed to read /proc/self/loginuid: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 2131, __func__, "Failed to read /proc/self/loginuid: %m" ) : -abs(_e); }); |
2132 | |
2133 | /* Already reset? */ |
2134 | if (streq(p, "4294967295")(strcmp((p),("4294967295")) == 0)) |
2135 | return 0; |
2136 | |
2137 | r = write_string_file("/proc/self/loginuid", "4294967295", 0); |
2138 | if (r < 0) { |
2139 | log_error_errno(r,({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 2144, __func__, "Failed to reset audit login UID. This probably means that your kernel is too\n" "old and you have audit enabled. Note that the auditing subsystem is known to\n" "be incompatible with containers on old kernels. Please make sure to upgrade\n" "your kernel or to off auditing with 'audit=0' on the kernel command line before\n" "using systemd-nspawn. Sleeping for 5s... (%m)") : -abs(_e); }) |
2140 | "Failed to reset audit login UID. This probably means that your kernel is too\n"({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 2144, __func__, "Failed to reset audit login UID. This probably means that your kernel is too\n" "old and you have audit enabled. Note that the auditing subsystem is known to\n" "be incompatible with containers on old kernels. Please make sure to upgrade\n" "your kernel or to off auditing with 'audit=0' on the kernel command line before\n" "using systemd-nspawn. Sleeping for 5s... (%m)") : -abs(_e); }) |
2141 | "old and you have audit enabled. Note that the auditing subsystem is known to\n"({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 2144, __func__, "Failed to reset audit login UID. This probably means that your kernel is too\n" "old and you have audit enabled. Note that the auditing subsystem is known to\n" "be incompatible with containers on old kernels. Please make sure to upgrade\n" "your kernel or to off auditing with 'audit=0' on the kernel command line before\n" "using systemd-nspawn. Sleeping for 5s... (%m)") : -abs(_e); }) |
2142 | "be incompatible with containers on old kernels. Please make sure to upgrade\n"({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 2144, __func__, "Failed to reset audit login UID. This probably means that your kernel is too\n" "old and you have audit enabled. Note that the auditing subsystem is known to\n" "be incompatible with containers on old kernels. Please make sure to upgrade\n" "your kernel or to off auditing with 'audit=0' on the kernel command line before\n" "using systemd-nspawn. Sleeping for 5s... (%m)") : -abs(_e); }) |
2143 | "your kernel or to off auditing with 'audit=0' on the kernel command line before\n"({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 2144, __func__, "Failed to reset audit login UID. This probably means that your kernel is too\n" "old and you have audit enabled. Note that the auditing subsystem is known to\n" "be incompatible with containers on old kernels. Please make sure to upgrade\n" "your kernel or to off auditing with 'audit=0' on the kernel command line before\n" "using systemd-nspawn. Sleeping for 5s... (%m)") : -abs(_e); }) |
2144 | "using systemd-nspawn. Sleeping for 5s... (%m)")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 2144, __func__, "Failed to reset audit login UID. This probably means that your kernel is too\n" "old and you have audit enabled. Note that the auditing subsystem is known to\n" "be incompatible with containers on old kernels. Please make sure to upgrade\n" "your kernel or to off auditing with 'audit=0' on the kernel command line before\n" "using systemd-nspawn. Sleeping for 5s... (%m)") : -abs(_e); }); |
2145 | |
2146 | sleep(5); |
2147 | } |
2148 | |
2149 | return 0; |
2150 | } |
2151 | |
2152 | static int setup_propagate(const char *root) { |
2153 | const char *p, *q; |
2154 | int r; |
2155 | |
2156 | (void) mkdir_p("/run/systemd/nspawn/", 0755); |
2157 | (void) mkdir_p("/run/systemd/nspawn/propagate", 0600); |
2158 | p = strjoina("/run/systemd/nspawn/propagate/", arg_machine)({ const char *_appendees_[] = { "/run/systemd/nspawn/propagate/" , arg_machine }; char *_d_, *_p_; size_t _len_ = 0; size_t _i_ ; for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr ( !__builtin_types_compatible_p(typeof(_appendees_), typeof(& *(_appendees_))), sizeof(_appendees_)/sizeof((_appendees_)[0] ), ((void)0))) && _appendees_[_i_]; _i_++) _len_ += strlen (_appendees_[_i_]); _p_ = _d_ = __builtin_alloca (_len_ + 1); for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p(typeof(_appendees_), typeof(& *(_appendees_))), sizeof(_appendees_)/sizeof((_appendees_)[0] ), ((void)0))) && _appendees_[_i_]; _i_++) _p_ = stpcpy (_p_, _appendees_[_i_]); *_p_ = 0; _d_; }); |
2159 | (void) mkdir_p(p, 0600); |
2160 | |
2161 | r = userns_mkdir(root, "/run/systemd", 0755, 0, 0); |
2162 | if (r < 0) |
2163 | return log_error_errno(r, "Failed to create /run/systemd: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 2163, __func__, "Failed to create /run/systemd: %m" ) : -abs(_e); }); |
2164 | |
2165 | r = userns_mkdir(root, "/run/systemd/nspawn", 0755, 0, 0); |
2166 | if (r < 0) |
2167 | return log_error_errno(r, "Failed to create /run/systemd/nspawn: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 2167, __func__, "Failed to create /run/systemd/nspawn: %m" ) : -abs(_e); }); |
2168 | |
2169 | r = userns_mkdir(root, "/run/systemd/nspawn/incoming", 0600, 0, 0); |
2170 | if (r < 0) |
2171 | return log_error_errno(r, "Failed to create /run/systemd/nspawn/incoming: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 2171, __func__, "Failed to create /run/systemd/nspawn/incoming: %m" ) : -abs(_e); }); |
2172 | |
2173 | q = prefix_roota(root, "/run/systemd/nspawn/incoming")({ const char* _path = ("/run/systemd/nspawn/incoming"), *_root = (root), *_ret; char *_p, *_n; size_t _l; while (_path[0] == '/' && _path[1] == '/') _path ++; if (empty_or_root( _root)) _ret = _path; else { _l = strlen(_root) + 1 + strlen( _path) + 1; _n = __builtin_alloca (_l); _p = stpcpy(_n, _root ); while (_p > _n && _p[-1] == '/') _p--; if (_path [0] != '/') *(_p++) = '/'; strcpy(_p, _path); _ret = _n; } _ret ; }); |
2174 | r = mount_verbose(LOG_ERR3, p, q, NULL((void*)0), MS_BINDMS_BIND, NULL((void*)0)); |
2175 | if (r < 0) |
2176 | return r; |
2177 | |
2178 | r = mount_verbose(LOG_ERR3, NULL((void*)0), q, NULL((void*)0), MS_BINDMS_BIND|MS_REMOUNTMS_REMOUNT|MS_RDONLYMS_RDONLY, NULL((void*)0)); |
2179 | if (r < 0) |
2180 | return r; |
2181 | |
2182 | /* machined will MS_MOVE into that directory, and that's only |
2183 | * supported for non-shared mounts. */ |
2184 | return mount_verbose(LOG_ERR3, NULL((void*)0), q, NULL((void*)0), MS_SLAVEMS_SLAVE, NULL((void*)0)); |
2185 | } |
2186 | |
2187 | static int setup_machine_id(const char *directory) { |
2188 | const char *etc_machine_id; |
2189 | sd_id128_t id; |
2190 | int r; |
2191 | |
2192 | /* If the UUID in the container is already set, then that's what counts, and we use. If it isn't set, and the |
2193 | * caller passed --uuid=, then we'll pass it in the $container_uuid env var to PID 1 of the container. The |
2194 | * assumption is that PID 1 will then write it to /etc/machine-id to make it persistent. If --uuid= is not |
2195 | * passed we generate a random UUID, and pass it via $container_uuid. In effect this means that /etc/machine-id |
2196 | * in the container and our idea of the container UUID will always be in sync (at least if PID 1 in the |
2197 | * container behaves nicely). */ |
2198 | |
2199 | etc_machine_id = prefix_roota(directory, "/etc/machine-id")({ const char* _path = ("/etc/machine-id"), *_root = (directory ), *_ret; char *_p, *_n; size_t _l; while (_path[0] == '/' && _path[1] == '/') _path ++; if (empty_or_root(_root)) _ret = _path ; else { _l = strlen(_root) + 1 + strlen(_path) + 1; _n = __builtin_alloca (_l); _p = stpcpy(_n, _root); while (_p > _n && _p [-1] == '/') _p--; if (_path[0] != '/') *(_p++) = '/'; strcpy (_p, _path); _ret = _n; } _ret; }); |
2200 | |
2201 | r = id128_read(etc_machine_id, ID128_PLAIN, &id); |
2202 | if (r < 0) { |
2203 | if (!IN_SET(r, -ENOENT, -ENOMEDIUM)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){-2, -123})/sizeof(int)]; switch(r) { case -2: case -123: _found = 1; break; default: break; } _found; } )) /* If the file is missing or empty, we don't mind */ |
2204 | return log_error_errno(r, "Failed to read machine ID from container image: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 2204, __func__, "Failed to read machine ID from container image: %m" ) : -abs(_e); }); |
2205 | |
2206 | if (sd_id128_is_null(arg_uuid)) { |
2207 | r = sd_id128_randomize(&arg_uuid); |
2208 | if (r < 0) |
2209 | return log_error_errno(r, "Failed to acquire randomized machine UUID: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 2209, __func__, "Failed to acquire randomized machine UUID: %m" ) : -abs(_e); }); |
2210 | } |
2211 | } else { |
2212 | if (sd_id128_is_null(id)) { |
2213 | log_error("Machine ID in container image is zero, refusing.")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 2213, __func__, "Machine ID in container image is zero, refusing." ) : -abs(_e); }); |
2214 | return -EINVAL22; |
2215 | } |
2216 | |
2217 | arg_uuid = id; |
2218 | } |
2219 | |
2220 | return 0; |
2221 | } |
2222 | |
2223 | static int recursive_chown(const char *directory, uid_t shift, uid_t range) { |
2224 | int r; |
2225 | |
2226 | assert(directory)do { if ((__builtin_expect(!!(!(directory)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("directory"), "../src/nspawn/nspawn.c", 2226 , __PRETTY_FUNCTION__); } while (0); |
2227 | |
2228 | if (arg_userns_mode == USER_NAMESPACE_NO || !arg_userns_chown) |
2229 | return 0; |
2230 | |
2231 | r = path_patch_uid(directory, arg_uid_shift, arg_uid_range); |
2232 | if (r == -EOPNOTSUPP95) |
2233 | return log_error_errno(r, "Automatic UID/GID adjusting is only supported for UID/GID ranges starting at multiples of 2^16 with a range of 2^16.")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 2233, __func__, "Automatic UID/GID adjusting is only supported for UID/GID ranges starting at multiples of 2^16 with a range of 2^16." ) : -abs(_e); }); |
2234 | if (r == -EBADE52) |
2235 | return log_error_errno(r, "Upper 16 bits of root directory UID and GID do not match.")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 2235, __func__, "Upper 16 bits of root directory UID and GID do not match." ) : -abs(_e); }); |
2236 | if (r < 0) |
2237 | return log_error_errno(r, "Failed to adjust UID/GID shift of OS tree: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 2237, __func__, "Failed to adjust UID/GID shift of OS tree: %m" ) : -abs(_e); }); |
2238 | if (r == 0) |
2239 | log_debug("Root directory of image is already owned by the right UID/GID range, skipping recursive chown operation.")({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 2239, __func__, "Root directory of image is already owned by the right UID/GID range, skipping recursive chown operation." ) : -abs(_e); }); |
2240 | else |
2241 | log_debug("Patched directory tree to match UID/GID range.")({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 2241, __func__, "Patched directory tree to match UID/GID range." ) : -abs(_e); }); |
2242 | |
2243 | return r; |
2244 | } |
2245 | |
2246 | /* |
2247 | * Return values: |
2248 | * < 0 : wait_for_terminate() failed to get the state of the |
2249 | * container, the container was terminated by a signal, or |
2250 | * failed for an unknown reason. No change is made to the |
2251 | * container argument. |
2252 | * > 0 : The program executed in the container terminated with an |
2253 | * error. The exit code of the program executed in the |
2254 | * container is returned. The container argument has been set |
2255 | * to CONTAINER_TERMINATED. |
2256 | * 0 : The container is being rebooted, has been shut down or exited |
2257 | * successfully. The container argument has been set to either |
2258 | * CONTAINER_TERMINATED or CONTAINER_REBOOTED. |
2259 | * |
2260 | * That is, success is indicated by a return value of zero, and an |
2261 | * error is indicated by a non-zero value. |
2262 | */ |
2263 | static int wait_for_container(pid_t pid, ContainerStatus *container) { |
2264 | siginfo_t status; |
2265 | int r; |
2266 | |
2267 | r = wait_for_terminate(pid, &status); |
2268 | if (r < 0) |
2269 | return log_warning_errno(r, "Failed to wait for container: %m")({ int _level = ((4)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 2269, __func__, "Failed to wait for container: %m" ) : -abs(_e); }); |
2270 | |
2271 | switch (status.si_code) { |
2272 | |
2273 | case CLD_EXITEDCLD_EXITED: |
2274 | if (status.si_status_sifields._sigchld.si_status == 0) |
2275 | log_full(arg_quiet ? LOG_DEBUG : LOG_INFO, "Container %s exited successfully.", arg_machine)({ int _level = (((arg_quiet ? 7 : 6))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ( (_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/nspawn/nspawn.c", 2275, __func__ , "Container %s exited successfully.", arg_machine) : -abs(_e ); }); |
2276 | else |
2277 | log_full(arg_quiet ? LOG_DEBUG : LOG_INFO, "Container %s failed with error code %i.", arg_machine, status.si_status)({ int _level = (((arg_quiet ? 7 : 6))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ( (_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/nspawn/nspawn.c", 2277, __func__ , "Container %s failed with error code %i.", arg_machine, status ._sifields._sigchld.si_status) : -abs(_e); }); |
2278 | |
2279 | *container = CONTAINER_TERMINATED; |
2280 | return status.si_status_sifields._sigchld.si_status; |
2281 | |
2282 | case CLD_KILLEDCLD_KILLED: |
2283 | if (status.si_status_sifields._sigchld.si_status == SIGINT2) { |
2284 | log_full(arg_quiet ? LOG_DEBUG : LOG_INFO, "Container %s has been shut down.", arg_machine)({ int _level = (((arg_quiet ? 7 : 6))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ( (_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/nspawn/nspawn.c", 2284, __func__ , "Container %s has been shut down.", arg_machine) : -abs(_e) ; }); |
2285 | *container = CONTAINER_TERMINATED; |
2286 | return 0; |
2287 | |
2288 | } else if (status.si_status_sifields._sigchld.si_status == SIGHUP1) { |
2289 | log_full(arg_quiet ? LOG_DEBUG : LOG_INFO, "Container %s is being rebooted.", arg_machine)({ int _level = (((arg_quiet ? 7 : 6))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ( (_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/nspawn/nspawn.c", 2289, __func__ , "Container %s is being rebooted.", arg_machine) : -abs(_e); }); |
2290 | *container = CONTAINER_REBOOTED; |
2291 | return 0; |
2292 | } |
2293 | |
2294 | _fallthrough_; |
2295 | case CLD_DUMPEDCLD_DUMPED: |
2296 | log_error("Container %s terminated by signal %s.", arg_machine, signal_to_string(status.si_status))({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 2296, __func__, "Container %s terminated by signal %s." , arg_machine, signal_to_string(status._sifields._sigchld.si_status )) : -abs(_e); }); |
2297 | return -EIO5; |
2298 | |
2299 | default: |
2300 | log_error("Container %s failed due to unknown reason.", arg_machine)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 2300, __func__, "Container %s failed due to unknown reason." , arg_machine) : -abs(_e); }); |
2301 | return -EIO5; |
2302 | } |
2303 | } |
2304 | |
2305 | static int on_orderly_shutdown(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) { |
2306 | pid_t pid; |
2307 | |
2308 | pid = PTR_TO_PID(userdata); |
2309 | if (pid > 0) { |
2310 | if (kill(pid, arg_kill_signal) >= 0) { |
2311 | log_info("Trying to halt container. Send SIGTERM again to trigger immediate termination.")({ int _level = (((6))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 2311, __func__, "Trying to halt container. Send SIGTERM again to trigger immediate termination." ) : -abs(_e); }); |
2312 | sd_event_source_set_userdata(s, NULL((void*)0)); |
2313 | return 0; |
2314 | } |
2315 | } |
2316 | |
2317 | sd_event_exit(sd_event_source_get_event(s), 0); |
2318 | return 0; |
2319 | } |
2320 | |
2321 | static int on_sigchld(sd_event_source *s, const struct signalfd_siginfo *ssi, void *userdata) { |
2322 | pid_t pid; |
2323 | |
2324 | assert(s)do { if ((__builtin_expect(!!(!(s)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("s"), "../src/nspawn/nspawn.c", 2324, __PRETTY_FUNCTION__ ); } while (0); |
2325 | assert(ssi)do { if ((__builtin_expect(!!(!(ssi)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("ssi"), "../src/nspawn/nspawn.c", 2325, __PRETTY_FUNCTION__ ); } while (0); |
2326 | |
2327 | pid = PTR_TO_PID(userdata); |
2328 | |
2329 | for (;;) { |
2330 | siginfo_t si = {}; |
2331 | |
2332 | if (waitid(P_ALL, 0, &si, WNOHANG1|WNOWAIT0x01000000|WEXITED4) < 0) |
2333 | return log_error_errno(errno, "Failed to waitid(): %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/nspawn/nspawn.c", 2333, __func__ , "Failed to waitid(): %m") : -abs(_e); }); |
2334 | if (si.si_pid_sifields._kill.si_pid == 0) /* No pending children. */ |
2335 | break; |
2336 | if (si.si_pid_sifields._kill.si_pid == pid) { |
2337 | /* The main process we care for has exited. Return from |
2338 | * signal handler but leave the zombie. */ |
2339 | sd_event_exit(sd_event_source_get_event(s), 0); |
2340 | break; |
2341 | } |
2342 | |
2343 | /* Reap all other children. */ |
2344 | (void) waitid(P_PID, si.si_pid_sifields._kill.si_pid, &si, WNOHANG1|WEXITED4); |
2345 | } |
2346 | |
2347 | return 0; |
2348 | } |
2349 | |
2350 | static int on_request_stop(sd_bus_message *m, void *userdata, sd_bus_error *error) { |
2351 | pid_t pid; |
2352 | |
2353 | assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("m"), "../src/nspawn/nspawn.c", 2353, __PRETTY_FUNCTION__ ); } while (0); |
2354 | |
2355 | pid = PTR_TO_PID(userdata); |
2356 | |
2357 | if (arg_kill_signal > 0) { |
2358 | log_info("Container termination requested. Attempting to halt container.")({ int _level = (((6))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 2358, __func__, "Container termination requested. Attempting to halt container." ) : -abs(_e); }); |
2359 | (void) kill(pid, arg_kill_signal); |
2360 | } else { |
2361 | log_info("Container termination requested. Exiting.")({ int _level = (((6))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 2361, __func__, "Container termination requested. Exiting." ) : -abs(_e); }); |
2362 | sd_event_exit(sd_bus_get_event(sd_bus_message_get_bus(m)), 0); |
2363 | } |
2364 | |
2365 | return 0; |
2366 | } |
2367 | |
2368 | static int determine_names(void) { |
2369 | int r; |
2370 | |
2371 | if (arg_template && !arg_directory && arg_machine) { |
2372 | |
2373 | /* If --template= was specified then we should not |
2374 | * search for a machine, but instead create a new one |
2375 | * in /var/lib/machine. */ |
2376 | |
2377 | arg_directory = strjoin("/var/lib/machines/", arg_machine)strjoin_real(("/var/lib/machines/"), arg_machine, ((void*)0)); |
2378 | if (!arg_directory) |
2379 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/nspawn/nspawn.c", 2379, __func__); |
2380 | } |
2381 | |
2382 | if (!arg_image && !arg_directory) { |
2383 | if (arg_machine) { |
2384 | _cleanup_(image_unrefp)__attribute__((cleanup(image_unrefp))) Image *i = NULL((void*)0); |
2385 | |
2386 | r = image_find(IMAGE_MACHINE, arg_machine, &i); |
2387 | if (r == -ENOENT2) |
2388 | return log_error_errno(r, "No image for machine '%s'.", arg_machine)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 2388, __func__, "No image for machine '%s'." , arg_machine) : -abs(_e); }); |
2389 | if (r < 0) |
2390 | return log_error_errno(r, "Failed to find image for machine '%s': %m", arg_machine)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 2390, __func__, "Failed to find image for machine '%s': %m" , arg_machine) : -abs(_e); }); |
2391 | |
2392 | if (IN_SET(i->type, IMAGE_RAW, IMAGE_BLOCK)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){IMAGE_RAW, IMAGE_BLOCK})/sizeof(int)]; switch (i->type) { case IMAGE_RAW: case IMAGE_BLOCK: _found = 1; break ; default: break; } _found; })) |
2393 | r = free_and_strdup(&arg_image, i->path); |
2394 | else |
2395 | r = free_and_strdup(&arg_directory, i->path); |
2396 | if (r < 0) |
2397 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/nspawn/nspawn.c", 2397, __func__); |
2398 | |
2399 | if (!arg_ephemeral) |
2400 | arg_read_only = arg_read_only || i->read_only; |
2401 | } else { |
2402 | r = safe_getcwd(&arg_directory); |
2403 | if (r < 0) |
2404 | return log_error_errno(r, "Failed to determine current directory: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 2404, __func__, "Failed to determine current directory: %m" ) : -abs(_e); }); |
2405 | } |
2406 | |
2407 | if (!arg_directory && !arg_image) { |
2408 | log_error("Failed to determine path, please use -D or -i.")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 2408, __func__, "Failed to determine path, please use -D or -i." ) : -abs(_e); }); |
2409 | return -EINVAL22; |
2410 | } |
2411 | } |
2412 | |
2413 | if (!arg_machine) { |
2414 | if (arg_directory && path_equal(arg_directory, "/")) |
2415 | arg_machine = gethostname_malloc(); |
2416 | else { |
2417 | if (arg_image) { |
2418 | char *e; |
2419 | |
2420 | arg_machine = strdup(basename(arg_image)); |
2421 | |
2422 | /* Truncate suffix if there is one */ |
2423 | e = endswith(arg_machine, ".raw"); |
2424 | if (e) |
2425 | *e = 0; |
2426 | } else |
2427 | arg_machine = strdup(basename(arg_directory)); |
2428 | } |
2429 | if (!arg_machine) |
2430 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/nspawn/nspawn.c", 2430, __func__); |
2431 | |
2432 | hostname_cleanup(arg_machine); |
2433 | if (!machine_name_is_valid(arg_machine)hostname_is_valid(arg_machine, 0)) { |
2434 | log_error("Failed to determine machine name automatically, please use -M.")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 2434, __func__, "Failed to determine machine name automatically, please use -M." ) : -abs(_e); }); |
2435 | return -EINVAL22; |
2436 | } |
2437 | |
2438 | if (arg_ephemeral) { |
2439 | char *b; |
2440 | |
2441 | /* Add a random suffix when this is an |
2442 | * ephemeral machine, so that we can run many |
2443 | * instances at once without manually having |
2444 | * to specify -M each time. */ |
2445 | |
2446 | if (asprintf(&b, "%s-%016" PRIx64"l" "x", arg_machine, random_u64()) < 0) |
2447 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/nspawn/nspawn.c", 2447, __func__); |
2448 | |
2449 | free(arg_machine); |
2450 | arg_machine = b; |
2451 | } |
2452 | } |
2453 | |
2454 | return 0; |
2455 | } |
2456 | |
2457 | static int chase_symlinks_and_update(char **p, unsigned flags) { |
2458 | char *chased; |
2459 | int r; |
2460 | |
2461 | assert(p)do { if ((__builtin_expect(!!(!(p)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("p"), "../src/nspawn/nspawn.c", 2461, __PRETTY_FUNCTION__ ); } while (0); |
2462 | |
2463 | if (!*p) |
2464 | return 0; |
2465 | |
2466 | r = chase_symlinks(*p, NULL((void*)0), flags, &chased); |
2467 | if (r < 0) |
2468 | return log_error_errno(r, "Failed to resolve path %s: %m", *p)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 2468, __func__, "Failed to resolve path %s: %m" , *p) : -abs(_e); }); |
2469 | |
2470 | free_and_replace(*p, chased)({ free(*p); (*p) = (chased); (chased) = ((void*)0); 0; }); |
2471 | return r; /* r might be an fd here in case we ever use CHASE_OPEN in flags */ |
2472 | } |
2473 | |
2474 | static int determine_uid_shift(const char *directory) { |
2475 | int r; |
2476 | |
2477 | if (arg_userns_mode == USER_NAMESPACE_NO) { |
2478 | arg_uid_shift = 0; |
2479 | return 0; |
2480 | } |
2481 | |
2482 | if (arg_uid_shift == UID_INVALID((uid_t) -1)) { |
2483 | struct stat st; |
2484 | |
2485 | r = stat(directory, &st); |
2486 | if (r < 0) |
2487 | return log_error_errno(errno, "Failed to determine UID base of %s: %m", directory)({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/nspawn/nspawn.c", 2487, __func__ , "Failed to determine UID base of %s: %m", directory) : -abs (_e); }); |
2488 | |
2489 | arg_uid_shift = st.st_uid & UINT32_C(0xffff0000)0xffff0000U; |
2490 | |
2491 | if (arg_uid_shift != (st.st_gid & UINT32_C(0xffff0000)0xffff0000U)) { |
2492 | log_error("UID and GID base of %s don't match.", directory)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 2492, __func__, "UID and GID base of %s don't match." , directory) : -abs(_e); }); |
2493 | return -EINVAL22; |
2494 | } |
2495 | |
2496 | arg_uid_range = UINT32_C(0x10000)0x10000U; |
2497 | } |
2498 | |
2499 | if (arg_uid_shift > (uid_t) -1 - arg_uid_range) { |
2500 | log_error("UID base too high for UID range.")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 2500, __func__, "UID base too high for UID range." ) : -abs(_e); }); |
2501 | return -EINVAL22; |
2502 | } |
2503 | |
2504 | return 0; |
2505 | } |
2506 | |
2507 | static int inner_child( |
2508 | Barrier *barrier, |
2509 | const char *directory, |
2510 | bool_Bool secondary, |
2511 | int kmsg_socket, |
2512 | int rtnl_socket, |
2513 | FDSet *fds) { |
2514 | |
2515 | _cleanup_free___attribute__((cleanup(freep))) char *home = NULL((void*)0); |
2516 | char as_uuid[37]; |
2517 | size_t n_env = 1; |
2518 | const char *envp[] = { |
2519 | "PATH=" DEFAULT_PATH_COMPAT"/usr/local/" "sbin:" "/usr/local/" "bin" ":" "/usr/" "sbin:" "/usr/" "bin" ":" "/" "sbin:" "/" "bin", |
2520 | NULL((void*)0), /* container */ |
2521 | NULL((void*)0), /* TERM */ |
2522 | NULL((void*)0), /* HOME */ |
2523 | NULL((void*)0), /* USER */ |
2524 | NULL((void*)0), /* LOGNAME */ |
2525 | NULL((void*)0), /* container_uuid */ |
2526 | NULL((void*)0), /* LISTEN_FDS */ |
2527 | NULL((void*)0), /* LISTEN_PID */ |
2528 | NULL((void*)0), /* NOTIFY_SOCKET */ |
2529 | NULL((void*)0) |
2530 | }; |
2531 | const char *exec_target; |
2532 | _cleanup_strv_free___attribute__((cleanup(strv_freep))) char **env_use = NULL((void*)0); |
2533 | int r; |
2534 | |
2535 | assert(barrier)do { if ((__builtin_expect(!!(!(barrier)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("barrier"), "../src/nspawn/nspawn.c", 2535 , __PRETTY_FUNCTION__); } while (0); |
2536 | assert(directory)do { if ((__builtin_expect(!!(!(directory)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("directory"), "../src/nspawn/nspawn.c", 2536 , __PRETTY_FUNCTION__); } while (0); |
2537 | assert(kmsg_socket >= 0)do { if ((__builtin_expect(!!(!(kmsg_socket >= 0)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("kmsg_socket >= 0"), "../src/nspawn/nspawn.c" , 2537, __PRETTY_FUNCTION__); } while (0); |
2538 | |
2539 | if (arg_userns_mode != USER_NAMESPACE_NO) { |
2540 | /* Tell the parent, that it now can write the UID map. */ |
2541 | (void) barrier_place(barrier); /* #1 */ |
2542 | |
2543 | /* Wait until the parent wrote the UID map */ |
2544 | if (!barrier_place_and_sync(barrier)) { /* #2 */ |
2545 | log_error("Parent died too early")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 2545, __func__, "Parent died too early" ) : -abs(_e); }); |
2546 | return -ESRCH3; |
2547 | } |
2548 | } |
2549 | |
2550 | r = reset_uid_gid(); |
2551 | if (r < 0) |
2552 | return log_error_errno(r, "Couldn't become new root: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 2552, __func__, "Couldn't become new root: %m" ) : -abs(_e); }); |
2553 | |
2554 | r = mount_all(NULL((void*)0), |
2555 | arg_mount_settings | MOUNT_IN_USERNS, |
2556 | arg_uid_shift, |
2557 | arg_uid_range, |
2558 | arg_selinux_apifs_context); |
2559 | if (r < 0) |
2560 | return r; |
2561 | |
2562 | if (!arg_network_namespace_path && arg_private_network) { |
2563 | r = unshare(CLONE_NEWNET0x40000000); |
2564 | if (r < 0) |
2565 | return log_error_errno(errno, "Failed to unshare network namespace: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/nspawn/nspawn.c", 2565, __func__ , "Failed to unshare network namespace: %m") : -abs(_e); }); |
2566 | |
2567 | /* Tell the parent that it can setup network interfaces. */ |
2568 | (void) barrier_place(barrier); /* #3 */ |
2569 | } |
2570 | |
2571 | r = mount_sysfs(NULL((void*)0), arg_mount_settings); |
2572 | if (r < 0) |
2573 | return r; |
2574 | |
2575 | /* Wait until we are cgroup-ified, so that we |
2576 | * can mount the right cgroup path writable */ |
2577 | if (!barrier_place_and_sync(barrier)) { /* #4 */ |
2578 | log_error("Parent died too early")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 2578, __func__, "Parent died too early" ) : -abs(_e); }); |
2579 | return -ESRCH3; |
2580 | } |
2581 | |
2582 | if (arg_use_cgns && cg_ns_supported()) { |
2583 | r = unshare(CLONE_NEWCGROUP0x02000000); |
2584 | if (r < 0) |
2585 | return log_error_errno(errno, "Failed to unshare cgroup namespace: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/nspawn/nspawn.c", 2585, __func__ , "Failed to unshare cgroup namespace: %m") : -abs(_e); }); |
2586 | r = mount_cgroups( |
2587 | "", |
2588 | arg_unified_cgroup_hierarchy, |
2589 | arg_userns_mode != USER_NAMESPACE_NO, |
2590 | arg_uid_shift, |
2591 | arg_uid_range, |
2592 | arg_selinux_apifs_context, |
2593 | true1); |
2594 | if (r < 0) |
2595 | return r; |
2596 | } else { |
2597 | r = mount_systemd_cgroup_writable("", arg_unified_cgroup_hierarchy); |
2598 | if (r < 0) |
2599 | return r; |
2600 | } |
2601 | |
2602 | r = setup_boot_id(); |
2603 | if (r < 0) |
2604 | return r; |
2605 | |
2606 | r = setup_kmsg(kmsg_socket); |
2607 | if (r < 0) |
2608 | return r; |
2609 | kmsg_socket = safe_close(kmsg_socket); |
2610 | |
2611 | if (setsid() < 0) |
2612 | return log_error_errno(errno, "setsid() failed: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/nspawn/nspawn.c", 2612, __func__ , "setsid() failed: %m") : -abs(_e); }); |
2613 | |
2614 | if (arg_private_network) |
2615 | loopback_setup(); |
2616 | |
2617 | if (arg_expose_ports) { |
2618 | r = expose_port_send_rtnl(rtnl_socket); |
2619 | if (r < 0) |
2620 | return r; |
2621 | rtnl_socket = safe_close(rtnl_socket); |
Value stored to 'rtnl_socket' is never read | |
2622 | } |
2623 | |
2624 | if (arg_oom_score_adjust_set) { |
2625 | r = set_oom_score_adjust(arg_oom_score_adjust); |
2626 | if (r < 0) |
2627 | return log_error_errno(r, "Failed to adjust OOM score: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 2627, __func__, "Failed to adjust OOM score: %m" ) : -abs(_e); }); |
2628 | } |
2629 | |
2630 | if (arg_cpu_set.set) |
2631 | if (sched_setaffinity(0, arg_cpu_set.allocated, arg_cpu_set.set) < 0) |
2632 | return log_error_errno(errno, "Failed to set CPU affinity: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/nspawn/nspawn.c", 2632, __func__ , "Failed to set CPU affinity: %m") : -abs(_e); }); |
2633 | |
2634 | r = drop_capabilities(); |
2635 | if (r < 0) |
2636 | return log_error_errno(r, "drop_capabilities() failed: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 2636, __func__, "drop_capabilities() failed: %m" ) : -abs(_e); }); |
2637 | |
2638 | (void) setup_hostname(); |
2639 | |
2640 | if (arg_personality != PERSONALITY_INVALID0xffffffffLU) { |
2641 | r = safe_personality(arg_personality); |
2642 | if (r < 0) |
2643 | return log_error_errno(r, "personality() failed: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 2643, __func__, "personality() failed: %m" ) : -abs(_e); }); |
2644 | } else if (secondary) { |
2645 | r = safe_personality(PER_LINUX32); |
2646 | if (r < 0) |
2647 | return log_error_errno(r, "personality() failed: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 2647, __func__, "personality() failed: %m" ) : -abs(_e); }); |
2648 | } |
2649 | |
2650 | #if HAVE_SELINUX1 |
2651 | if (arg_selinux_context) |
2652 | if (setexeccon(arg_selinux_context) < 0) |
2653 | return log_error_errno(errno, "setexeccon(\"%s\") failed: %m", arg_selinux_context)({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/nspawn/nspawn.c", 2653, __func__ , "setexeccon(\"%s\") failed: %m", arg_selinux_context) : -abs (_e); }); |
2654 | #endif |
2655 | |
2656 | r = change_uid_gid(arg_user, &home); |
2657 | if (r < 0) |
2658 | return r; |
2659 | |
2660 | if (arg_no_new_privileges) |
2661 | if (prctl(PR_SET_NO_NEW_PRIVS38, 1, 0, 0, 0) < 0) |
2662 | return log_error_errno(errno, "Failed to disable new privileges: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/nspawn/nspawn.c", 2662, __func__ , "Failed to disable new privileges: %m") : -abs(_e); }); |
2663 | |
2664 | /* LXC sets container=lxc, so follow the scheme here */ |
2665 | envp[n_env++] = strjoina("container=", arg_container_service_name)({ const char *_appendees_[] = { "container=", arg_container_service_name }; char *_d_, *_p_; size_t _len_ = 0; size_t _i_; for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p (typeof(_appendees_), typeof(&*(_appendees_))), sizeof(_appendees_ )/sizeof((_appendees_)[0]), ((void)0))) && _appendees_ [_i_]; _i_++) _len_ += strlen(_appendees_[_i_]); _p_ = _d_ = __builtin_alloca (_len_ + 1); for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr ( !__builtin_types_compatible_p(typeof(_appendees_), typeof(& *(_appendees_))), sizeof(_appendees_)/sizeof((_appendees_)[0] ), ((void)0))) && _appendees_[_i_]; _i_++) _p_ = stpcpy (_p_, _appendees_[_i_]); *_p_ = 0; _d_; }); |
2666 | |
2667 | envp[n_env] = strv_find_prefix(environ, "TERM="); |
2668 | if (envp[n_env]) |
2669 | n_env++; |
2670 | |
2671 | if ((asprintf((char**)(envp + n_env++), "HOME=%s", home ? home: "/root") < 0) || |
2672 | (asprintf((char**)(envp + n_env++), "USER=%s", arg_user ? arg_user : "root") < 0) || |
2673 | (asprintf((char**)(envp + n_env++), "LOGNAME=%s", arg_user ? arg_user : "root") < 0)) |
2674 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/nspawn/nspawn.c", 2674, __func__); |
2675 | |
2676 | assert(!sd_id128_is_null(arg_uuid))do { if ((__builtin_expect(!!(!(!sd_id128_is_null(arg_uuid))) ,0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("!sd_id128_is_null(arg_uuid)" ), "../src/nspawn/nspawn.c", 2676, __PRETTY_FUNCTION__); } while (0); |
2677 | |
2678 | if (asprintf((char**)(envp + n_env++), "container_uuid=%s", id128_to_uuid_string(arg_uuid, as_uuid)) < 0) |
2679 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/nspawn/nspawn.c", 2679, __func__); |
2680 | |
2681 | if (fdset_size(fds) > 0) { |
2682 | r = fdset_cloexec(fds, false0); |
2683 | if (r < 0) |
2684 | return log_error_errno(r, "Failed to unset O_CLOEXEC for file descriptors.")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 2684, __func__, "Failed to unset O_CLOEXEC for file descriptors." ) : -abs(_e); }); |
2685 | |
2686 | if ((asprintf((char **)(envp + n_env++), "LISTEN_FDS=%u", fdset_size(fds)) < 0) || |
2687 | (asprintf((char **)(envp + n_env++), "LISTEN_PID=1") < 0)) |
2688 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/nspawn/nspawn.c", 2688, __func__); |
2689 | } |
2690 | if (asprintf((char **)(envp + n_env++), "NOTIFY_SOCKET=%s", NSPAWN_NOTIFY_SOCKET_PATH"/run/systemd/nspawn/notify") < 0) |
2691 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/nspawn/nspawn.c", 2691, __func__); |
2692 | |
2693 | env_use = strv_env_merge(2, envp, arg_setenv); |
2694 | if (!env_use) |
2695 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/nspawn/nspawn.c", 2695, __func__); |
2696 | |
2697 | /* Let the parent know that we are ready and |
2698 | * wait until the parent is ready with the |
2699 | * setup, too... */ |
2700 | if (!barrier_place_and_sync(barrier)) { /* #5 */ |
2701 | log_error("Parent died too early")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 2701, __func__, "Parent died too early" ) : -abs(_e); }); |
2702 | return -ESRCH3; |
2703 | } |
2704 | |
2705 | if (arg_chdir) |
2706 | if (chdir(arg_chdir) < 0) |
2707 | return log_error_errno(errno, "Failed to change to specified working directory %s: %m", arg_chdir)({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/nspawn/nspawn.c", 2707, __func__ , "Failed to change to specified working directory %s: %m", arg_chdir ) : -abs(_e); }); |
2708 | |
2709 | if (arg_start_mode == START_PID2) { |
2710 | r = stub_pid1(arg_uuid); |
2711 | if (r < 0) |
2712 | return r; |
2713 | } |
2714 | |
2715 | /* Now, explicitly close the log, so that we then can close all remaining fds. Closing the log explicitly first |
2716 | * has the benefit that the logging subsystem knows about it, and is thus ready to be reopened should we need |
2717 | * it again. Note that the other fds closed here are at least the locking and barrier fds. */ |
2718 | log_close(); |
2719 | log_set_open_when_needed(true1); |
2720 | |
2721 | (void) fdset_close_others(fds); |
2722 | |
2723 | if (arg_start_mode == START_BOOT) { |
2724 | char **a; |
2725 | size_t m; |
2726 | |
2727 | /* Automatically search for the init system */ |
2728 | |
2729 | m = strv_length(arg_parameters); |
2730 | a = newa(char*, m + 2)({ do { if ((__builtin_expect(!!(!(!size_multiply_overflow(sizeof (char*), m + 2))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD , ("!size_multiply_overflow(sizeof(char*), m + 2)"), "../src/nspawn/nspawn.c" , 2730, __PRETTY_FUNCTION__); } while (0); (char**) __builtin_alloca (sizeof(char*)*(m + 2)); }); |
2731 | memcpy_safe(a + 1, arg_parameters, m * sizeof(char*)); |
2732 | a[1 + m] = NULL((void*)0); |
2733 | |
2734 | a[0] = (char*) "/usr/lib/systemd/systemd"; |
2735 | execve(a[0], a, env_use); |
2736 | |
2737 | a[0] = (char*) "/lib/systemd/systemd"; |
2738 | execve(a[0], a, env_use); |
2739 | |
2740 | a[0] = (char*) "/sbin/init"; |
2741 | execve(a[0], a, env_use); |
2742 | |
2743 | exec_target = "/usr/lib/systemd/systemd, /lib/systemd/systemd, /sbin/init"; |
2744 | } else if (!strv_isempty(arg_parameters)) { |
2745 | exec_target = arg_parameters[0]; |
2746 | execvpe(arg_parameters[0], arg_parameters, env_use); |
2747 | } else { |
2748 | if (!arg_chdir) |
2749 | /* If we cannot change the directory, we'll end up in /, that is expected. */ |
2750 | (void) chdir(home ?: "/root"); |
2751 | |
2752 | execle("/bin/bash", "-bash", NULL((void*)0), env_use); |
2753 | execle("/bin/sh", "-sh", NULL((void*)0), env_use); |
2754 | |
2755 | exec_target = "/bin/bash, /bin/sh"; |
2756 | } |
2757 | |
2758 | return log_error_errno(errno, "execv(%s) failed: %m", exec_target)({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/nspawn/nspawn.c", 2758, __func__ , "execv(%s) failed: %m", exec_target) : -abs(_e); }); |
2759 | } |
2760 | |
2761 | static int setup_sd_notify_child(void) { |
2762 | static const int one = 1; |
2763 | int fd = -1; |
2764 | union sockaddr_union sa = { |
2765 | .sa.sa_family = AF_UNIX1, |
2766 | }; |
2767 | int r; |
2768 | |
2769 | fd = socket(AF_UNIX1, SOCK_DGRAMSOCK_DGRAM|SOCK_CLOEXECSOCK_CLOEXEC|SOCK_NONBLOCKSOCK_NONBLOCK, 0); |
2770 | if (fd < 0) |
2771 | return log_error_errno(errno, "Failed to allocate notification socket: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/nspawn/nspawn.c", 2771, __func__ , "Failed to allocate notification socket: %m") : -abs(_e); } ); |
2772 | |
2773 | (void) mkdir_parents(NSPAWN_NOTIFY_SOCKET_PATH"/run/systemd/nspawn/notify", 0755); |
2774 | (void) unlink(NSPAWN_NOTIFY_SOCKET_PATH"/run/systemd/nspawn/notify"); |
2775 | |
2776 | strncpy(sa.un.sun_path, NSPAWN_NOTIFY_SOCKET_PATH"/run/systemd/nspawn/notify", sizeof(sa.un.sun_path)-1); |
2777 | r = bind(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)({ const struct sockaddr_un *_sa = &(sa.un); do { if ((__builtin_expect (!!(!(_sa->sun_family == 1)),0))) log_assert_failed_realm( LOG_REALM_SYSTEMD, ("_sa->sun_family == AF_UNIX"), "../src/nspawn/nspawn.c" , 2777, __PRETTY_FUNCTION__); } while (0); __builtin_offsetof (struct sockaddr_un, sun_path) + (_sa->sun_path[0] == 0 ? 1 + strnlen(_sa->sun_path+1, sizeof(_sa->sun_path)-1) : strnlen (_sa->sun_path, sizeof(_sa->sun_path))); })); |
2778 | if (r < 0) { |
2779 | safe_close(fd); |
2780 | return log_error_errno(errno, "bind(%s) failed: %m", sa.un.sun_path)({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/nspawn/nspawn.c", 2780, __func__ , "bind(%s) failed: %m", sa.un.sun_path) : -abs(_e); }); |
2781 | } |
2782 | |
2783 | r = userns_lchown(NSPAWN_NOTIFY_SOCKET_PATH"/run/systemd/nspawn/notify", 0, 0); |
2784 | if (r < 0) { |
2785 | safe_close(fd); |
2786 | return log_error_errno(r, "Failed to chown " NSPAWN_NOTIFY_SOCKET_PATH ": %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 2786, __func__, "Failed to chown " "/run/systemd/nspawn/notify" ": %m") : -abs(_e); }); |
2787 | } |
2788 | |
2789 | r = setsockopt(fd, SOL_SOCKET1, SO_PASSCRED16, &one, sizeof(one)); |
2790 | if (r < 0) { |
2791 | safe_close(fd); |
2792 | return log_error_errno(errno, "SO_PASSCRED failed: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/nspawn/nspawn.c", 2792, __func__ , "SO_PASSCRED failed: %m") : -abs(_e); }); |
2793 | } |
2794 | |
2795 | return fd; |
2796 | } |
2797 | |
2798 | static int outer_child( |
2799 | Barrier *barrier, |
2800 | const char *directory, |
2801 | const char *console, |
2802 | DissectedImage *dissected_image, |
2803 | bool_Bool interactive, |
2804 | bool_Bool secondary, |
2805 | int pid_socket, |
2806 | int uuid_socket, |
2807 | int notify_socket, |
2808 | int kmsg_socket, |
2809 | int rtnl_socket, |
2810 | int uid_shift_socket, |
2811 | int unified_cgroup_hierarchy_socket, |
2812 | FDSet *fds, |
2813 | int netns_fd) { |
2814 | |
2815 | _cleanup_close___attribute__((cleanup(closep))) int fd = -1; |
2816 | int r, which_failed; |
2817 | pid_t pid; |
2818 | ssize_t l; |
2819 | |
2820 | assert(barrier)do { if ((__builtin_expect(!!(!(barrier)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("barrier"), "../src/nspawn/nspawn.c", 2820 , __PRETTY_FUNCTION__); } while (0); |
2821 | assert(directory)do { if ((__builtin_expect(!!(!(directory)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("directory"), "../src/nspawn/nspawn.c", 2821 , __PRETTY_FUNCTION__); } while (0); |
2822 | assert(console)do { if ((__builtin_expect(!!(!(console)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("console"), "../src/nspawn/nspawn.c", 2822 , __PRETTY_FUNCTION__); } while (0); |
2823 | assert(pid_socket >= 0)do { if ((__builtin_expect(!!(!(pid_socket >= 0)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("pid_socket >= 0"), "../src/nspawn/nspawn.c" , 2823, __PRETTY_FUNCTION__); } while (0); |
2824 | assert(uuid_socket >= 0)do { if ((__builtin_expect(!!(!(uuid_socket >= 0)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("uuid_socket >= 0"), "../src/nspawn/nspawn.c" , 2824, __PRETTY_FUNCTION__); } while (0); |
2825 | assert(notify_socket >= 0)do { if ((__builtin_expect(!!(!(notify_socket >= 0)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("notify_socket >= 0"), "../src/nspawn/nspawn.c" , 2825, __PRETTY_FUNCTION__); } while (0); |
2826 | assert(kmsg_socket >= 0)do { if ((__builtin_expect(!!(!(kmsg_socket >= 0)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("kmsg_socket >= 0"), "../src/nspawn/nspawn.c" , 2826, __PRETTY_FUNCTION__); } while (0); |
2827 | |
2828 | if (prctl(PR_SET_PDEATHSIG1, SIGKILL9) < 0) |
2829 | return log_error_errno(errno, "PR_SET_PDEATHSIG failed: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/nspawn/nspawn.c", 2829, __func__ , "PR_SET_PDEATHSIG failed: %m") : -abs(_e); }); |
2830 | |
2831 | if (interactive) { |
2832 | int terminal; |
2833 | |
2834 | terminal = open_terminal(console, O_RDWR02); |
2835 | if (terminal < 0) |
2836 | return log_error_errno(terminal, "Failed to open console: %m")({ int _level = ((3)), _e = ((terminal)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 2836, __func__, "Failed to open console: %m" ) : -abs(_e); }); |
2837 | |
2838 | /* Make sure we can continue logging to the original stderr, even if stderr points elsewhere now */ |
2839 | r = log_dup_console(); |
2840 | if (r < 0) |
2841 | return log_error_errno(r, "Failed to duplicate stderr: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 2841, __func__, "Failed to duplicate stderr: %m" ) : -abs(_e); }); |
2842 | |
2843 | r = rearrange_stdio(terminal, terminal, terminal); /* invalidates 'terminal' on success and failure */ |
2844 | if (r < 0) |
2845 | return log_error_errno(r, "Failed to move console to stdin/stdout/stderr: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 2845, __func__, "Failed to move console to stdin/stdout/stderr: %m" ) : -abs(_e); }); |
2846 | } |
2847 | |
2848 | r = reset_audit_loginuid(); |
2849 | if (r < 0) |
2850 | return r; |
2851 | |
2852 | /* Mark everything as slave, so that we still |
2853 | * receive mounts from the real root, but don't |
2854 | * propagate mounts to the real root. */ |
2855 | r = mount_verbose(LOG_ERR3, NULL((void*)0), "/", NULL((void*)0), MS_SLAVEMS_SLAVE|MS_RECMS_REC, NULL((void*)0)); |
2856 | if (r < 0) |
2857 | return r; |
2858 | |
2859 | if (dissected_image) { |
2860 | /* If we are operating on a disk image, then mount its root directory now, but leave out the rest. We |
2861 | * can read the UID shift from it if we need to. Further down we'll mount the rest, but then with the |
2862 | * uid shift known. That way we can mount VFAT file systems shifted to the right place right away. This |
2863 | * makes sure ESP partitions and userns are compatible. */ |
2864 | |
2865 | r = dissected_image_mount(dissected_image, directory, arg_uid_shift, |
2866 | DISSECT_IMAGE_MOUNT_ROOT_ONLY|DISSECT_IMAGE_DISCARD_ON_LOOP| |
2867 | (arg_read_only ? DISSECT_IMAGE_READ_ONLY : 0)| |
2868 | (arg_start_mode == START_BOOT ? DISSECT_IMAGE_VALIDATE_OS : 0)); |
2869 | if (r < 0) |
2870 | return r; |
2871 | } |
2872 | |
2873 | r = determine_uid_shift(directory); |
2874 | if (r < 0) |
2875 | return r; |
2876 | |
2877 | if (arg_userns_mode != USER_NAMESPACE_NO) { |
2878 | /* Let the parent know which UID shift we read from the image */ |
2879 | l = send(uid_shift_socket, &arg_uid_shift, sizeof(arg_uid_shift), MSG_NOSIGNALMSG_NOSIGNAL); |
2880 | if (l < 0) |
2881 | return log_error_errno(errno, "Failed to send UID shift: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/nspawn/nspawn.c", 2881, __func__ , "Failed to send UID shift: %m") : -abs(_e); }); |
2882 | if (l != sizeof(arg_uid_shift)) { |
2883 | log_error("Short write while sending UID shift.")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 2883, __func__, "Short write while sending UID shift." ) : -abs(_e); }); |
2884 | return -EIO5; |
2885 | } |
2886 | |
2887 | if (arg_userns_mode == USER_NAMESPACE_PICK) { |
2888 | /* When we are supposed to pick the UID shift, the parent will check now whether the UID shift |
2889 | * we just read from the image is available. If yes, it will send the UID shift back to us, if |
2890 | * not it will pick a different one, and send it back to us. */ |
2891 | |
2892 | l = recv(uid_shift_socket, &arg_uid_shift, sizeof(arg_uid_shift), 0); |
2893 | if (l < 0) |
2894 | return log_error_errno(errno, "Failed to recv UID shift: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/nspawn/nspawn.c", 2894, __func__ , "Failed to recv UID shift: %m") : -abs(_e); }); |
2895 | if (l != sizeof(arg_uid_shift)) { |
2896 | log_error("Short read while receiving UID shift.")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 2896, __func__, "Short read while receiving UID shift." ) : -abs(_e); }); |
2897 | return -EIO5; |
2898 | } |
2899 | } |
2900 | |
2901 | log_info("Selected user namespace base " UID_FMT " and range " UID_FMT ".", arg_uid_shift, arg_uid_range)({ int _level = (((6))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 2901, __func__, "Selected user namespace base " "%" "u" " and range " "%" "u" ".", arg_uid_shift, arg_uid_range ) : -abs(_e); }); |
2902 | } |
2903 | |
2904 | if (dissected_image) { |
2905 | /* Now we know the uid shift, let's now mount everything else that might be in the image. */ |
2906 | r = dissected_image_mount(dissected_image, directory, arg_uid_shift, |
2907 | DISSECT_IMAGE_MOUNT_NON_ROOT_ONLY|DISSECT_IMAGE_DISCARD_ON_LOOP|(arg_read_only ? DISSECT_IMAGE_READ_ONLY : 0)); |
2908 | if (r < 0) |
2909 | return r; |
2910 | } |
2911 | |
2912 | if (arg_unified_cgroup_hierarchy == CGROUP_UNIFIED_UNKNOWN) { |
2913 | /* OK, we don't know yet which cgroup mode to use yet. Let's figure it out, and tell the parent. */ |
2914 | |
2915 | r = detect_unified_cgroup_hierarchy_from_image(directory); |
2916 | if (r < 0) |
2917 | return r; |
2918 | |
2919 | l = send(unified_cgroup_hierarchy_socket, &arg_unified_cgroup_hierarchy, sizeof(arg_unified_cgroup_hierarchy), MSG_NOSIGNALMSG_NOSIGNAL); |
2920 | if (l < 0) |
2921 | return log_error_errno(errno, "Failed to send cgroup mode: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/nspawn/nspawn.c", 2921, __func__ , "Failed to send cgroup mode: %m") : -abs(_e); }); |
2922 | if (l != sizeof(arg_unified_cgroup_hierarchy)) { |
2923 | log_error("Short write while sending cgroup mode.")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 2923, __func__, "Short write while sending cgroup mode." ) : -abs(_e); }); |
2924 | return -EIO5; |
2925 | } |
2926 | |
2927 | unified_cgroup_hierarchy_socket = safe_close(unified_cgroup_hierarchy_socket); |
2928 | } |
2929 | |
2930 | /* Turn directory into bind mount */ |
2931 | r = mount_verbose(LOG_ERR3, directory, directory, NULL((void*)0), MS_BINDMS_BIND|MS_RECMS_REC, NULL((void*)0)); |
2932 | if (r < 0) |
2933 | return r; |
2934 | |
2935 | r = setup_pivot_root( |
2936 | directory, |
2937 | arg_pivot_root_new, |
2938 | arg_pivot_root_old); |
2939 | if (r < 0) |
2940 | return r; |
2941 | |
2942 | r = setup_volatile( |
2943 | directory, |
2944 | arg_volatile_mode, |
2945 | arg_userns_mode != USER_NAMESPACE_NO, |
2946 | arg_uid_shift, |
2947 | arg_uid_range, |
2948 | arg_selinux_context); |
2949 | if (r < 0) |
2950 | return r; |
2951 | |
2952 | r = setup_volatile_state( |
2953 | directory, |
2954 | arg_volatile_mode, |
2955 | arg_userns_mode != USER_NAMESPACE_NO, |
2956 | arg_uid_shift, |
2957 | arg_uid_range, |
2958 | arg_selinux_context); |
2959 | if (r < 0) |
2960 | return r; |
2961 | |
2962 | /* Mark everything as shared so our mounts get propagated down. This is |
2963 | * required to make new bind mounts available in systemd services |
2964 | * inside the containter that create a new mount namespace. |
2965 | * See https://github.com/systemd/systemd/issues/3860 |
2966 | * Further submounts (such as /dev) done after this will inherit the |
2967 | * shared propagation mode. */ |
2968 | r = mount_verbose(LOG_ERR3, NULL((void*)0), directory, NULL((void*)0), MS_SHAREDMS_SHARED|MS_RECMS_REC, NULL((void*)0)); |
2969 | if (r < 0) |
2970 | return r; |
2971 | |
2972 | r = recursive_chown(directory, arg_uid_shift, arg_uid_range); |
2973 | if (r < 0) |
2974 | return r; |
2975 | |
2976 | r = base_filesystem_create(directory, arg_uid_shift, (gid_t) arg_uid_shift); |
2977 | if (r < 0) |
2978 | return r; |
2979 | |
2980 | if (arg_read_only) { |
2981 | r = bind_remount_recursive(directory, true1, NULL((void*)0)); |
2982 | if (r < 0) |
2983 | return log_error_errno(r, "Failed to make tree read-only: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 2983, __func__, "Failed to make tree read-only: %m" ) : -abs(_e); }); |
2984 | } |
2985 | |
2986 | r = mount_all(directory, |
2987 | arg_mount_settings, |
2988 | arg_uid_shift, |
2989 | arg_uid_range, |
2990 | arg_selinux_apifs_context); |
2991 | if (r < 0) |
2992 | return r; |
2993 | |
2994 | r = copy_devnodes(directory); |
2995 | if (r < 0) |
2996 | return r; |
2997 | |
2998 | dev_setup(directory, arg_uid_shift, arg_uid_shift); |
2999 | |
3000 | r = setup_pts(directory); |
3001 | if (r < 0) |
3002 | return r; |
3003 | |
3004 | r = setup_propagate(directory); |
3005 | if (r < 0) |
3006 | return r; |
3007 | |
3008 | r = setup_dev_console(directory, console); |
3009 | if (r < 0) |
3010 | return r; |
3011 | |
3012 | r = setup_keyring(); |
3013 | if (r < 0) |
3014 | return r; |
3015 | |
3016 | r = setup_seccomp(arg_caps_retain, arg_syscall_whitelist, arg_syscall_blacklist); |
3017 | if (r < 0) |
3018 | return r; |
3019 | |
3020 | r = setup_timezone(directory); |
3021 | if (r < 0) |
3022 | return r; |
3023 | |
3024 | r = setup_resolv_conf(directory); |
3025 | if (r < 0) |
3026 | return r; |
3027 | |
3028 | r = setup_machine_id(directory); |
3029 | if (r < 0) |
3030 | return r; |
3031 | |
3032 | r = setup_journal(directory); |
3033 | if (r < 0) |
3034 | return r; |
3035 | |
3036 | r = mount_custom( |
3037 | directory, |
3038 | arg_custom_mounts, |
3039 | arg_n_custom_mounts, |
3040 | arg_userns_mode != USER_NAMESPACE_NO, |
3041 | arg_uid_shift, |
3042 | arg_uid_range, |
3043 | arg_selinux_apifs_context); |
3044 | if (r < 0) |
3045 | return r; |
3046 | |
3047 | if (!arg_use_cgns || !cg_ns_supported()) { |
3048 | r = mount_cgroups( |
3049 | directory, |
3050 | arg_unified_cgroup_hierarchy, |
3051 | arg_userns_mode != USER_NAMESPACE_NO, |
3052 | arg_uid_shift, |
3053 | arg_uid_range, |
3054 | arg_selinux_apifs_context, |
3055 | false0); |
3056 | if (r < 0) |
3057 | return r; |
3058 | } |
3059 | |
3060 | r = mount_move_root(directory); |
3061 | if (r < 0) |
3062 | return log_error_errno(r, "Failed to move root directory: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 3062, __func__, "Failed to move root directory: %m" ) : -abs(_e); }); |
3063 | |
3064 | fd = setup_sd_notify_child(); |
3065 | if (fd < 0) |
3066 | return fd; |
3067 | |
3068 | r = setrlimit_closest_all((const struct rlimit *const*) arg_rlimit, &which_failed); |
3069 | if (r < 0) |
3070 | return log_error_errno(r, "Failed to apply resource limit RLIMIT_%s: %m", rlimit_to_string(which_failed))({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 3070, __func__, "Failed to apply resource limit RLIMIT_%s: %m" , rlimit_to_string(which_failed)) : -abs(_e); }); |
3071 | |
3072 | pid = raw_clone(SIGCHLD17|CLONE_NEWNS0x00020000| |
3073 | arg_clone_ns_flags | |
3074 | (arg_userns_mode != USER_NAMESPACE_NO ? CLONE_NEWUSER0x10000000 : 0)); |
3075 | if (pid < 0) |
3076 | return log_error_errno(errno, "Failed to fork inner child: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/nspawn/nspawn.c", 3076, __func__ , "Failed to fork inner child: %m") : -abs(_e); }); |
3077 | if (pid == 0) { |
3078 | pid_socket = safe_close(pid_socket); |
3079 | uuid_socket = safe_close(uuid_socket); |
3080 | notify_socket = safe_close(notify_socket); |
3081 | uid_shift_socket = safe_close(uid_shift_socket); |
3082 | |
3083 | /* The inner child has all namespaces that are |
3084 | * requested, so that we all are owned by the user if |
3085 | * user namespaces are turned on. */ |
3086 | |
3087 | if (arg_network_namespace_path) { |
3088 | r = namespace_enter(-1, -1, netns_fd, -1, -1); |
3089 | if (r < 0) |
3090 | return r; |
3091 | } |
3092 | |
3093 | r = inner_child(barrier, directory, secondary, kmsg_socket, rtnl_socket, fds); |
3094 | if (r < 0) |
3095 | _exit(EXIT_FAILURE1); |
3096 | |
3097 | _exit(EXIT_SUCCESS0); |
3098 | } |
3099 | |
3100 | l = send(pid_socket, &pid, sizeof(pid), MSG_NOSIGNALMSG_NOSIGNAL); |
3101 | if (l < 0) |
3102 | return log_error_errno(errno, "Failed to send PID: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/nspawn/nspawn.c", 3102, __func__ , "Failed to send PID: %m") : -abs(_e); }); |
3103 | if (l != sizeof(pid)) { |
3104 | log_error("Short write while sending PID.")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 3104, __func__, "Short write while sending PID." ) : -abs(_e); }); |
3105 | return -EIO5; |
3106 | } |
3107 | |
3108 | l = send(uuid_socket, &arg_uuid, sizeof(arg_uuid), MSG_NOSIGNALMSG_NOSIGNAL); |
3109 | if (l < 0) |
3110 | return log_error_errno(errno, "Failed to send machine ID: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/nspawn/nspawn.c", 3110, __func__ , "Failed to send machine ID: %m") : -abs(_e); }); |
3111 | if (l != sizeof(arg_uuid)) { |
3112 | log_error("Short write while sending machine ID.")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 3112, __func__, "Short write while sending machine ID." ) : -abs(_e); }); |
3113 | return -EIO5; |
3114 | } |
3115 | |
3116 | l = send_one_fd(notify_socket, fd, 0)send_one_fd_iov_sa(notify_socket, fd, ((void*)0), 0, ((void*) 0), 0, 0); |
3117 | if (l < 0) |
3118 | return log_error_errno(errno, "Failed to send notify fd: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/nspawn/nspawn.c", 3118, __func__ , "Failed to send notify fd: %m") : -abs(_e); }); |
3119 | |
3120 | pid_socket = safe_close(pid_socket); |
3121 | uuid_socket = safe_close(uuid_socket); |
3122 | notify_socket = safe_close(notify_socket); |
3123 | kmsg_socket = safe_close(kmsg_socket); |
3124 | rtnl_socket = safe_close(rtnl_socket); |
3125 | netns_fd = safe_close(netns_fd); |
3126 | |
3127 | return 0; |
3128 | } |
3129 | |
3130 | static int uid_shift_pick(uid_t *shift, LockFile *ret_lock_file) { |
3131 | bool_Bool tried_hashed = false0; |
3132 | unsigned n_tries = 100; |
3133 | uid_t candidate; |
3134 | int r; |
3135 | |
3136 | assert(shift)do { if ((__builtin_expect(!!(!(shift)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("shift"), "../src/nspawn/nspawn.c", 3136 , __PRETTY_FUNCTION__); } while (0); |
3137 | assert(ret_lock_file)do { if ((__builtin_expect(!!(!(ret_lock_file)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("ret_lock_file"), "../src/nspawn/nspawn.c" , 3137, __PRETTY_FUNCTION__); } while (0); |
3138 | assert(arg_userns_mode == USER_NAMESPACE_PICK)do { if ((__builtin_expect(!!(!(arg_userns_mode == USER_NAMESPACE_PICK )),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("arg_userns_mode == USER_NAMESPACE_PICK" ), "../src/nspawn/nspawn.c", 3138, __PRETTY_FUNCTION__); } while (0); |
3139 | assert(arg_uid_range == 0x10000U)do { if ((__builtin_expect(!!(!(arg_uid_range == 0x10000U)),0 ))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("arg_uid_range == 0x10000U" ), "../src/nspawn/nspawn.c", 3139, __PRETTY_FUNCTION__); } while (0); |
3140 | |
3141 | candidate = *shift; |
3142 | |
3143 | (void) mkdir("/run/systemd/nspawn-uid", 0755); |
3144 | |
3145 | for (;;) { |
3146 | char lock_path[STRLEN("/run/systemd/nspawn-uid/")(sizeof("""/run/systemd/nspawn-uid/""") - 1) + DECIMAL_STR_MAX(uid_t)(2+(sizeof(uid_t) <= 1 ? 3 : sizeof(uid_t) <= 2 ? 5 : sizeof (uid_t) <= 4 ? 10 : sizeof(uid_t) <= 8 ? 20 : sizeof(int [-2*(sizeof(uid_t) > 8)]))) + 1]; |
3147 | _cleanup_(release_lock_file)__attribute__((cleanup(release_lock_file))) LockFile lf = LOCK_FILE_INIT{ .fd = -1, .path = ((void*)0) }; |
3148 | |
3149 | if (--n_tries <= 0) |
3150 | return -EBUSY16; |
3151 | |
3152 | if (candidate < CONTAINER_UID_BASE_MIN524288 || candidate > CONTAINER_UID_BASE_MAX1878982656) |
3153 | goto next; |
3154 | if ((candidate & UINT32_C(0xFFFF)0xFFFFU) != 0) |
3155 | goto next; |
3156 | |
3157 | xsprintf(lock_path, "/run/systemd/nspawn-uid/" UID_FMT, candidate)do { if ((__builtin_expect(!!(!(((size_t) snprintf(lock_path, __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p (typeof(lock_path), typeof(&*(lock_path))), sizeof(lock_path )/sizeof((lock_path)[0]), ((void)0))), "/run/systemd/nspawn-uid/" "%" "u", candidate) < (__extension__ (__builtin_choose_expr ( !__builtin_types_compatible_p(typeof(lock_path), typeof(& *(lock_path))), sizeof(lock_path)/sizeof((lock_path)[0]), ((void )0))))))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("xsprintf: " "lock_path" "[] must be big enough"), "../src/nspawn/nspawn.c" , 3157, __PRETTY_FUNCTION__); } while (0); |
3158 | r = make_lock_file(lock_path, LOCK_EX2|LOCK_NB4, &lf); |
3159 | if (r == -EBUSY16) /* Range already taken by another nspawn instance */ |
3160 | goto next; |
3161 | if (r < 0) |
3162 | return r; |
3163 | |
3164 | /* Make some superficial checks whether the range is currently known in the user database */ |
3165 | if (getpwuid(candidate)) |
3166 | goto next; |
3167 | if (getpwuid(candidate + UINT32_C(0xFFFE)0xFFFEU)) |
3168 | goto next; |
3169 | if (getgrgid(candidate)) |
3170 | goto next; |
3171 | if (getgrgid(candidate + UINT32_C(0xFFFE)0xFFFEU)) |
3172 | goto next; |
3173 | |
3174 | *ret_lock_file = lf; |
3175 | lf = (struct LockFile) LOCK_FILE_INIT{ .fd = -1, .path = ((void*)0) }; |
3176 | *shift = candidate; |
3177 | return 0; |
3178 | |
3179 | next: |
3180 | if (arg_machine && !tried_hashed) { |
3181 | /* Try to hash the base from the container name */ |
3182 | |
3183 | static const uint8_t hash_key[] = { |
3184 | 0xe1, 0x56, 0xe0, 0xf0, 0x4a, 0xf0, 0x41, 0xaf, |
3185 | 0x96, 0x41, 0xcf, 0x41, 0x33, 0x94, 0xff, 0x72 |
3186 | }; |
3187 | |
3188 | candidate = (uid_t) siphash24(arg_machine, strlen(arg_machine), hash_key); |
3189 | |
3190 | tried_hashed = true1; |
3191 | } else |
3192 | random_bytes(&candidate, sizeof(candidate)); |
3193 | |
3194 | candidate = (candidate % (CONTAINER_UID_BASE_MAX1878982656 - CONTAINER_UID_BASE_MIN524288)) + CONTAINER_UID_BASE_MIN524288; |
3195 | candidate &= (uid_t) UINT32_C(0xFFFF0000)0xFFFF0000U; |
3196 | } |
3197 | } |
3198 | |
3199 | static int setup_uid_map(pid_t pid) { |
3200 | char uid_map[STRLEN("/proc//uid_map")(sizeof("""/proc//uid_map""") - 1) + DECIMAL_STR_MAX(uid_t)(2+(sizeof(uid_t) <= 1 ? 3 : sizeof(uid_t) <= 2 ? 5 : sizeof (uid_t) <= 4 ? 10 : sizeof(uid_t) <= 8 ? 20 : sizeof(int [-2*(sizeof(uid_t) > 8)]))) + 1], line[DECIMAL_STR_MAX(uid_t)(2+(sizeof(uid_t) <= 1 ? 3 : sizeof(uid_t) <= 2 ? 5 : sizeof (uid_t) <= 4 ? 10 : sizeof(uid_t) <= 8 ? 20 : sizeof(int [-2*(sizeof(uid_t) > 8)])))*3+3+1]; |
3201 | int r; |
3202 | |
3203 | assert(pid > 1)do { if ((__builtin_expect(!!(!(pid > 1)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("pid > 1"), "../src/nspawn/nspawn.c", 3203, __PRETTY_FUNCTION__); } while (0); |
3204 | |
3205 | xsprintf(uid_map, "/proc/" PID_FMT "/uid_map", pid)do { if ((__builtin_expect(!!(!(((size_t) snprintf(uid_map, __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p(typeof (uid_map), typeof(&*(uid_map))), sizeof(uid_map)/sizeof(( uid_map)[0]), ((void)0))), "/proc/" "%" "i" "/uid_map", pid) < (__extension__ (__builtin_choose_expr( !__builtin_types_compatible_p (typeof(uid_map), typeof(&*(uid_map))), sizeof(uid_map)/sizeof ((uid_map)[0]), ((void)0))))))),0))) log_assert_failed_realm( LOG_REALM_SYSTEMD, ("xsprintf: " "uid_map" "[] must be big enough" ), "../src/nspawn/nspawn.c", 3205, __PRETTY_FUNCTION__); } while (0); |
3206 | xsprintf(line, UID_FMT " " UID_FMT " " UID_FMT "\n", 0, arg_uid_shift, arg_uid_range)do { if ((__builtin_expect(!!(!(((size_t) snprintf(line, __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p(typeof (line), typeof(&*(line))), sizeof(line)/sizeof((line)[0]) , ((void)0))), "%" "u" " " "%" "u" " " "%" "u" "\n", 0, arg_uid_shift , arg_uid_range) < (__extension__ (__builtin_choose_expr( ! __builtin_types_compatible_p(typeof(line), typeof(&*(line ))), sizeof(line)/sizeof((line)[0]), ((void)0))))))),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("xsprintf: " "line" "[] must be big enough" ), "../src/nspawn/nspawn.c", 3206, __PRETTY_FUNCTION__); } while (0); |
3207 | r = write_string_file(uid_map, line, 0); |
3208 | if (r < 0) |
3209 | return log_error_errno(r, "Failed to write UID map: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 3209, __func__, "Failed to write UID map: %m" ) : -abs(_e); }); |
3210 | |
3211 | /* We always assign the same UID and GID ranges */ |
3212 | xsprintf(uid_map, "/proc/" PID_FMT "/gid_map", pid)do { if ((__builtin_expect(!!(!(((size_t) snprintf(uid_map, __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p(typeof (uid_map), typeof(&*(uid_map))), sizeof(uid_map)/sizeof(( uid_map)[0]), ((void)0))), "/proc/" "%" "i" "/gid_map", pid) < (__extension__ (__builtin_choose_expr( !__builtin_types_compatible_p (typeof(uid_map), typeof(&*(uid_map))), sizeof(uid_map)/sizeof ((uid_map)[0]), ((void)0))))))),0))) log_assert_failed_realm( LOG_REALM_SYSTEMD, ("xsprintf: " "uid_map" "[] must be big enough" ), "../src/nspawn/nspawn.c", 3212, __PRETTY_FUNCTION__); } while (0); |
3213 | r = write_string_file(uid_map, line, 0); |
3214 | if (r < 0) |
3215 | return log_error_errno(r, "Failed to write GID map: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 3215, __func__, "Failed to write GID map: %m" ) : -abs(_e); }); |
3216 | |
3217 | return 0; |
3218 | } |
3219 | |
3220 | static int nspawn_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata) { |
3221 | char buf[NOTIFY_BUFFER_MAX4096+1]; |
3222 | char *p = NULL((void*)0); |
3223 | struct iovec iovec = { |
3224 | .iov_base = buf, |
3225 | .iov_len = sizeof(buf)-1, |
3226 | }; |
3227 | union { |
3228 | struct cmsghdr cmsghdr; |
3229 | uint8_t buf[CMSG_SPACE(sizeof(struct ucred))((((sizeof(struct ucred)) + sizeof (size_t) - 1) & (size_t ) ~(sizeof (size_t) - 1)) + (((sizeof (struct cmsghdr)) + sizeof (size_t) - 1) & (size_t) ~(sizeof (size_t) - 1))) + |
3230 | CMSG_SPACE(sizeof(int) * NOTIFY_FD_MAX)((((sizeof(int) * 768) + sizeof (size_t) - 1) & (size_t) ~ (sizeof (size_t) - 1)) + (((sizeof (struct cmsghdr)) + sizeof (size_t) - 1) & (size_t) ~(sizeof (size_t) - 1)))]; |
3231 | } control = {}; |
3232 | struct msghdr msghdr = { |
3233 | .msg_iov = &iovec, |
3234 | .msg_iovlen = 1, |
3235 | .msg_control = &control, |
3236 | .msg_controllen = sizeof(control), |
3237 | }; |
3238 | struct cmsghdr *cmsg; |
3239 | struct ucred *ucred = NULL((void*)0); |
3240 | ssize_t n; |
3241 | pid_t inner_child_pid; |
3242 | _cleanup_strv_free___attribute__((cleanup(strv_freep))) char **tags = NULL((void*)0); |
3243 | |
3244 | assert(userdata)do { if ((__builtin_expect(!!(!(userdata)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("userdata"), "../src/nspawn/nspawn.c", 3244 , __PRETTY_FUNCTION__); } while (0); |
3245 | |
3246 | inner_child_pid = PTR_TO_PID(userdata); |
3247 | |
3248 | if (revents != EPOLLINEPOLLIN) { |
3249 | log_warning("Got unexpected poll event for notify fd.")({ int _level = (((4))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 3249, __func__, "Got unexpected poll event for notify fd." ) : -abs(_e); }); |
3250 | return 0; |
3251 | } |
3252 | |
3253 | n = recvmsg(fd, &msghdr, MSG_DONTWAITMSG_DONTWAIT|MSG_CMSG_CLOEXECMSG_CMSG_CLOEXEC); |
3254 | if (n < 0) { |
3255 | if (IN_SET(errno, EAGAIN, EINTR)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){11, 4})/sizeof(int)]; switch((*__errno_location ())) { case 11: case 4: _found = 1; break; default: break; } _found; })) |
3256 | return 0; |
3257 | |
3258 | return log_warning_errno(errno, "Couldn't read notification socket: %m")({ int _level = ((4)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/nspawn/nspawn.c", 3258, __func__ , "Couldn't read notification socket: %m") : -abs(_e); }); |
3259 | } |
3260 | cmsg_close_all(&msghdr); |
3261 | |
3262 | CMSG_FOREACH(cmsg, &msghdr)for ((cmsg) = ((size_t) (&msghdr)->msg_controllen >= sizeof (struct cmsghdr) ? (struct cmsghdr *) (&msghdr)-> msg_control : (struct cmsghdr *) 0); (cmsg); (cmsg) = __cmsg_nxthdr ((&msghdr), (cmsg))) { |
3263 | if (cmsg->cmsg_level == SOL_SOCKET1 && |
3264 | cmsg->cmsg_type == SCM_CREDENTIALSSCM_CREDENTIALS && |
3265 | cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))((((sizeof (struct cmsghdr)) + sizeof (size_t) - 1) & (size_t ) ~(sizeof (size_t) - 1)) + (sizeof(struct ucred)))) { |
3266 | |
3267 | ucred = (struct ucred*) CMSG_DATA(cmsg)((cmsg)->__cmsg_data); |
3268 | } |
3269 | } |
3270 | |
3271 | if (!ucred || ucred->pid != inner_child_pid) { |
3272 | log_debug("Received notify message without valid credentials. Ignoring.")({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 3272, __func__, "Received notify message without valid credentials. Ignoring." ) : -abs(_e); }); |
3273 | return 0; |
3274 | } |
3275 | |
3276 | if ((size_t) n >= sizeof(buf)) { |
3277 | log_warning("Received notify message exceeded maximum size. Ignoring.")({ int _level = (((4))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 3277, __func__, "Received notify message exceeded maximum size. Ignoring." ) : -abs(_e); }); |
3278 | return 0; |
3279 | } |
3280 | |
3281 | buf[n] = 0; |
3282 | tags = strv_split(buf, "\n\r"); |
3283 | if (!tags) |
3284 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/nspawn/nspawn.c", 3284, __func__); |
3285 | |
3286 | if (strv_find(tags, "READY=1")) |
3287 | sd_notifyf(false0, "READY=1\n"); |
3288 | |
3289 | p = strv_find_startswith(tags, "STATUS="); |
3290 | if (p) |
3291 | sd_notifyf(false0, "STATUS=Container running: %s", p); |
3292 | |
3293 | return 0; |
3294 | } |
3295 | |
3296 | static int setup_sd_notify_parent(sd_event *event, int fd, pid_t *inner_child_pid, sd_event_source **notify_event_source) { |
3297 | int r; |
3298 | |
3299 | r = sd_event_add_io(event, notify_event_source, fd, EPOLLINEPOLLIN, nspawn_dispatch_notify_fd, inner_child_pid); |
3300 | if (r < 0) |
3301 | return log_error_errno(r, "Failed to allocate notify event source: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 3301, __func__, "Failed to allocate notify event source: %m" ) : -abs(_e); }); |
3302 | |
3303 | (void) sd_event_source_set_description(*notify_event_source, "nspawn-notify"); |
3304 | |
3305 | return 0; |
3306 | } |
3307 | |
3308 | static int merge_settings(Settings *settings, const char *path) { |
3309 | int rl; |
3310 | |
3311 | assert(settings)do { if ((__builtin_expect(!!(!(settings)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("settings"), "../src/nspawn/nspawn.c", 3311 , __PRETTY_FUNCTION__); } while (0); |
3312 | assert(path)do { if ((__builtin_expect(!!(!(path)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("path"), "../src/nspawn/nspawn.c", 3312, __PRETTY_FUNCTION__); } while (0); |
3313 | |
3314 | /* Copy over bits from the settings, unless they have been explicitly masked by command line switches. Note |
3315 | * that this steals the fields of the Settings* structure, and hence modifies it. */ |
3316 | |
3317 | if ((arg_settings_mask & SETTING_START_MODE) == 0 && |
3318 | settings->start_mode >= 0) { |
3319 | arg_start_mode = settings->start_mode; |
3320 | strv_free_and_replace(arg_parameters, settings->parameters)({ strv_free(arg_parameters); (arg_parameters) = (settings-> parameters); (settings->parameters) = ((void*)0); 0; }); |
3321 | } |
3322 | |
3323 | if ((arg_settings_mask & SETTING_PIVOT_ROOT) == 0 && |
3324 | settings->pivot_root_new) { |
3325 | free_and_replace(arg_pivot_root_new, settings->pivot_root_new)({ free(arg_pivot_root_new); (arg_pivot_root_new) = (settings ->pivot_root_new); (settings->pivot_root_new) = ((void* )0); 0; }); |
3326 | free_and_replace(arg_pivot_root_old, settings->pivot_root_old)({ free(arg_pivot_root_old); (arg_pivot_root_old) = (settings ->pivot_root_old); (settings->pivot_root_old) = ((void* )0); 0; }); |
3327 | } |
3328 | |
3329 | if ((arg_settings_mask & SETTING_WORKING_DIRECTORY) == 0 && |
3330 | settings->working_directory) |
3331 | free_and_replace(arg_chdir, settings->working_directory)({ free(arg_chdir); (arg_chdir) = (settings->working_directory ); (settings->working_directory) = ((void*)0); 0; }); |
3332 | |
3333 | if ((arg_settings_mask & SETTING_ENVIRONMENT) == 0 && |
3334 | settings->environment) |
3335 | strv_free_and_replace(arg_setenv, settings->environment)({ strv_free(arg_setenv); (arg_setenv) = (settings->environment ); (settings->environment) = ((void*)0); 0; }); |
3336 | |
3337 | if ((arg_settings_mask & SETTING_USER) == 0 && |
3338 | settings->user) |
3339 | free_and_replace(arg_user, settings->user)({ free(arg_user); (arg_user) = (settings->user); (settings ->user) = ((void*)0); 0; }); |
3340 | |
3341 | if ((arg_settings_mask & SETTING_CAPABILITY) == 0) { |
3342 | uint64_t plus; |
3343 | |
3344 | plus = settings->capability; |
3345 | if (settings_private_network(settings)) |
3346 | plus |= (1ULL << CAP_NET_ADMIN12); |
3347 | |
3348 | if (!arg_settings_trusted && plus != 0) { |
3349 | if (settings->capability != 0) |
3350 | log_warning("Ignoring Capability= setting, file %s is not trusted.", path)({ int _level = (((4))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 3350, __func__, "Ignoring Capability= setting, file %s is not trusted." , path) : -abs(_e); }); |
3351 | } else |
3352 | arg_caps_retain |= plus; |
3353 | |
3354 | arg_caps_retain &= ~settings->drop_capability; |
3355 | } |
3356 | |
3357 | if ((arg_settings_mask & SETTING_KILL_SIGNAL) == 0 && |
3358 | settings->kill_signal > 0) |
3359 | arg_kill_signal = settings->kill_signal; |
3360 | |
3361 | if ((arg_settings_mask & SETTING_PERSONALITY) == 0 && |
3362 | settings->personality != PERSONALITY_INVALID0xffffffffLU) |
3363 | arg_personality = settings->personality; |
3364 | |
3365 | if ((arg_settings_mask & SETTING_MACHINE_ID) == 0 && |
3366 | !sd_id128_is_null(settings->machine_id)) { |
3367 | |
3368 | if (!arg_settings_trusted) |
3369 | log_warning("Ignoring MachineID= setting, file %s is not trusted.", path)({ int _level = (((4))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 3369, __func__, "Ignoring MachineID= setting, file %s is not trusted." , path) : -abs(_e); }); |
3370 | else |
3371 | arg_uuid = settings->machine_id; |
3372 | } |
3373 | |
3374 | if ((arg_settings_mask & SETTING_READ_ONLY) == 0 && |
3375 | settings->read_only >= 0) |
3376 | arg_read_only = settings->read_only; |
3377 | |
3378 | if ((arg_settings_mask & SETTING_VOLATILE_MODE) == 0 && |
3379 | settings->volatile_mode != _VOLATILE_MODE_INVALID) |
3380 | arg_volatile_mode = settings->volatile_mode; |
3381 | |
3382 | if ((arg_settings_mask & SETTING_CUSTOM_MOUNTS) == 0 && |
3383 | settings->n_custom_mounts > 0) { |
3384 | |
3385 | if (!arg_settings_trusted) |
3386 | log_warning("Ignoring TemporaryFileSystem=, Bind= and BindReadOnly= settings, file %s is not trusted.", path)({ int _level = (((4))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 3386, __func__, "Ignoring TemporaryFileSystem=, Bind= and BindReadOnly= settings, file %s is not trusted." , path) : -abs(_e); }); |
3387 | else { |
3388 | custom_mount_free_all(arg_custom_mounts, arg_n_custom_mounts); |
3389 | arg_custom_mounts = TAKE_PTR(settings->custom_mounts)({ typeof(settings->custom_mounts) _ptr_ = (settings->custom_mounts ); (settings->custom_mounts) = ((void*)0); _ptr_; }); |
3390 | arg_n_custom_mounts = settings->n_custom_mounts; |
3391 | settings->n_custom_mounts = 0; |
3392 | } |
3393 | } |
3394 | |
3395 | if ((arg_settings_mask & SETTING_NETWORK) == 0 && |
3396 | (settings->private_network >= 0 || |
3397 | settings->network_veth >= 0 || |
3398 | settings->network_bridge || |
3399 | settings->network_zone || |
3400 | settings->network_interfaces || |
3401 | settings->network_macvlan || |
3402 | settings->network_ipvlan || |
3403 | settings->network_veth_extra)) { |
3404 | |
3405 | if (!arg_settings_trusted) |
3406 | log_warning("Ignoring network settings, file %s is not trusted.", path)({ int _level = (((4))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 3406, __func__, "Ignoring network settings, file %s is not trusted." , path) : -abs(_e); }); |
3407 | else { |
3408 | arg_network_veth = settings_network_veth(settings); |
3409 | arg_private_network = settings_private_network(settings); |
3410 | |
3411 | strv_free_and_replace(arg_network_interfaces, settings->network_interfaces)({ strv_free(arg_network_interfaces); (arg_network_interfaces ) = (settings->network_interfaces); (settings->network_interfaces ) = ((void*)0); 0; }); |
3412 | strv_free_and_replace(arg_network_macvlan, settings->network_macvlan)({ strv_free(arg_network_macvlan); (arg_network_macvlan) = (settings ->network_macvlan); (settings->network_macvlan) = ((void *)0); 0; }); |
3413 | strv_free_and_replace(arg_network_ipvlan, settings->network_ipvlan)({ strv_free(arg_network_ipvlan); (arg_network_ipvlan) = (settings ->network_ipvlan); (settings->network_ipvlan) = ((void* )0); 0; }); |
3414 | strv_free_and_replace(arg_network_veth_extra, settings->network_veth_extra)({ strv_free(arg_network_veth_extra); (arg_network_veth_extra ) = (settings->network_veth_extra); (settings->network_veth_extra ) = ((void*)0); 0; }); |
3415 | |
3416 | free_and_replace(arg_network_bridge, settings->network_bridge)({ free(arg_network_bridge); (arg_network_bridge) = (settings ->network_bridge); (settings->network_bridge) = ((void* )0); 0; }); |
3417 | free_and_replace(arg_network_zone, settings->network_zone)({ free(arg_network_zone); (arg_network_zone) = (settings-> network_zone); (settings->network_zone) = ((void*)0); 0; } ); |
3418 | } |
3419 | } |
3420 | |
3421 | if ((arg_settings_mask & SETTING_EXPOSE_PORTS) == 0 && |
3422 | settings->expose_ports) { |
3423 | |
3424 | if (!arg_settings_trusted) |
3425 | log_warning("Ignoring Port= setting, file %s is not trusted.", path)({ int _level = (((4))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 3425, __func__, "Ignoring Port= setting, file %s is not trusted." , path) : -abs(_e); }); |
3426 | else { |
3427 | expose_port_free_all(arg_expose_ports); |
3428 | arg_expose_ports = TAKE_PTR(settings->expose_ports)({ typeof(settings->expose_ports) _ptr_ = (settings->expose_ports ); (settings->expose_ports) = ((void*)0); _ptr_; }); |
3429 | } |
3430 | } |
3431 | |
3432 | if ((arg_settings_mask & SETTING_USERNS) == 0 && |
3433 | settings->userns_mode != _USER_NAMESPACE_MODE_INVALID) { |
3434 | |
3435 | if (!arg_settings_trusted) |
3436 | log_warning("Ignoring PrivateUsers= and PrivateUsersChown= settings, file %s is not trusted.", path)({ int _level = (((4))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 3436, __func__, "Ignoring PrivateUsers= and PrivateUsersChown= settings, file %s is not trusted." , path) : -abs(_e); }); |
3437 | else { |
3438 | arg_userns_mode = settings->userns_mode; |
3439 | arg_uid_shift = settings->uid_shift; |
3440 | arg_uid_range = settings->uid_range; |
3441 | arg_userns_chown = settings->userns_chown; |
3442 | } |
3443 | } |
3444 | |
3445 | if ((arg_settings_mask & SETTING_NOTIFY_READY) == 0) |
3446 | arg_notify_ready = settings->notify_ready; |
3447 | |
3448 | if ((arg_settings_mask & SETTING_SYSCALL_FILTER) == 0) { |
3449 | |
3450 | if (!arg_settings_trusted && !strv_isempty(arg_syscall_whitelist)) |
3451 | log_warning("Ignoring SystemCallFilter= settings, file %s is not trusted.", path)({ int _level = (((4))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 3451, __func__, "Ignoring SystemCallFilter= settings, file %s is not trusted." , path) : -abs(_e); }); |
3452 | else { |
3453 | strv_free_and_replace(arg_syscall_whitelist, settings->syscall_whitelist)({ strv_free(arg_syscall_whitelist); (arg_syscall_whitelist) = (settings->syscall_whitelist); (settings->syscall_whitelist ) = ((void*)0); 0; }); |
3454 | strv_free_and_replace(arg_syscall_blacklist, settings->syscall_blacklist)({ strv_free(arg_syscall_blacklist); (arg_syscall_blacklist) = (settings->syscall_blacklist); (settings->syscall_blacklist ) = ((void*)0); 0; }); |
3455 | } |
3456 | } |
3457 | |
3458 | for (rl = 0; rl < _RLIMIT_MAX(__RLIMIT_RTTIME+1 > __RLIMIT_NLIMITS ? __RLIMIT_RTTIME+1 : __RLIMIT_NLIMITS); rl ++) { |
3459 | if ((arg_settings_mask & (SETTING_RLIMIT_FIRST((uint64_t) SETTING_RLIMIT_FIRST) << rl))) |
3460 | continue; |
3461 | |
3462 | if (!settings->rlimit[rl]) |
3463 | continue; |
3464 | |
3465 | if (!arg_settings_trusted) { |
3466 | log_warning("Ignoring Limit%s= setting, file '%s' is not trusted.", rlimit_to_string(rl), path)({ int _level = (((4))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 3466, __func__, "Ignoring Limit%s= setting, file '%s' is not trusted." , rlimit_to_string(rl), path) : -abs(_e); }); |
3467 | continue; |
3468 | } |
3469 | |
3470 | free_and_replace(arg_rlimit[rl], settings->rlimit[rl])({ free(arg_rlimit[rl]); (arg_rlimit[rl]) = (settings->rlimit [rl]); (settings->rlimit[rl]) = ((void*)0); 0; }); |
3471 | } |
3472 | |
3473 | if ((arg_settings_mask & SETTING_HOSTNAME) == 0 && |
3474 | settings->hostname) |
3475 | free_and_replace(arg_hostname, settings->hostname)({ free(arg_hostname); (arg_hostname) = (settings->hostname ); (settings->hostname) = ((void*)0); 0; }); |
3476 | |
3477 | if ((arg_settings_mask & SETTING_NO_NEW_PRIVILEGES) == 0 && |
3478 | settings->no_new_privileges >= 0) |
3479 | arg_no_new_privileges = settings->no_new_privileges; |
3480 | |
3481 | if ((arg_settings_mask & SETTING_OOM_SCORE_ADJUST) == 0 && |
3482 | settings->oom_score_adjust_set) { |
3483 | |
3484 | if (!arg_settings_trusted) |
3485 | log_warning("Ignoring OOMScoreAdjust= setting, file '%s' is not trusted.", path)({ int _level = (((4))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 3485, __func__, "Ignoring OOMScoreAdjust= setting, file '%s' is not trusted." , path) : -abs(_e); }); |
3486 | else { |
3487 | arg_oom_score_adjust = settings->oom_score_adjust; |
3488 | arg_oom_score_adjust_set = true1; |
3489 | } |
3490 | } |
3491 | |
3492 | if ((arg_settings_mask & SETTING_CPU_AFFINITY) == 0 && |
3493 | settings->cpu_set.set) { |
3494 | |
3495 | if (!arg_settings_trusted) |
3496 | log_warning("Ignoring CPUAffinity= setting, file '%s' is not trusted.", path)({ int _level = (((4))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 3496, __func__, "Ignoring CPUAffinity= setting, file '%s' is not trusted." , path) : -abs(_e); }); |
3497 | else { |
3498 | cpu_set_reset(&arg_cpu_set); |
3499 | arg_cpu_set = settings->cpu_set; |
3500 | settings->cpu_set = (CPUSet) {}; |
3501 | } |
3502 | } |
3503 | |
3504 | if ((arg_settings_mask & SETTING_RESOLV_CONF) == 0 && |
3505 | settings->resolv_conf != _RESOLV_CONF_MODE_INVALID) |
3506 | arg_resolv_conf = settings->resolv_conf; |
3507 | |
3508 | if ((arg_settings_mask & SETTING_LINK_JOURNAL) == 0 && |
3509 | settings->link_journal != _LINK_JOURNAL_INVALID) { |
3510 | |
3511 | if (!arg_settings_trusted) |
3512 | log_warning("Ignoring journal link setting, file '%s' is not trusted.", path)({ int _level = (((4))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 3512, __func__, "Ignoring journal link setting, file '%s' is not trusted." , path) : -abs(_e); }); |
3513 | else { |
3514 | arg_link_journal = settings->link_journal; |
3515 | arg_link_journal_try = settings->link_journal_try; |
3516 | } |
3517 | } |
3518 | |
3519 | if ((arg_settings_mask & SETTING_TIMEZONE) == 0 && |
3520 | settings->timezone != _TIMEZONE_MODE_INVALID) |
3521 | arg_timezone = settings->timezone; |
3522 | |
3523 | return 0; |
3524 | } |
3525 | |
3526 | static int load_settings(void) { |
3527 | _cleanup_(settings_freep)__attribute__((cleanup(settings_freep))) Settings *settings = NULL((void*)0); |
3528 | _cleanup_fclose___attribute__((cleanup(fclosep))) FILE *f = NULL((void*)0); |
3529 | _cleanup_free___attribute__((cleanup(freep))) char *p = NULL((void*)0); |
3530 | const char *fn, *i; |
3531 | int r; |
3532 | |
3533 | /* If all settings are masked, there's no point in looking for |
3534 | * the settings file */ |
3535 | if ((arg_settings_mask & _SETTINGS_MASK_ALL) == _SETTINGS_MASK_ALL) |
3536 | return 0; |
3537 | |
3538 | fn = strjoina(arg_machine, ".nspawn")({ const char *_appendees_[] = { arg_machine, ".nspawn" }; char *_d_, *_p_; size_t _len_ = 0; size_t _i_; for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p (typeof(_appendees_), typeof(&*(_appendees_))), sizeof(_appendees_ )/sizeof((_appendees_)[0]), ((void)0))) && _appendees_ [_i_]; _i_++) _len_ += strlen(_appendees_[_i_]); _p_ = _d_ = __builtin_alloca (_len_ + 1); for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr ( !__builtin_types_compatible_p(typeof(_appendees_), typeof(& *(_appendees_))), sizeof(_appendees_)/sizeof((_appendees_)[0] ), ((void)0))) && _appendees_[_i_]; _i_++) _p_ = stpcpy (_p_, _appendees_[_i_]); *_p_ = 0; _d_; }); |
3539 | |
3540 | /* We first look in the admin's directories in /etc and /run */ |
3541 | FOREACH_STRING(i, "/etc/systemd/nspawn", "/run/systemd/nspawn")for (char **_l = ({ char **_ll = ((char**) ((const char*[]) { "/etc/systemd/nspawn", "/run/systemd/nspawn", ((void*)0) })) ; i = _ll ? _ll[0] : ((void*)0); _ll; }); _l && *_l; i = ({ _l ++; _l[0]; })) { |
3542 | _cleanup_free___attribute__((cleanup(freep))) char *j = NULL((void*)0); |
3543 | |
3544 | j = strjoin(i, "/", fn)strjoin_real((i), "/", fn, ((void*)0)); |
3545 | if (!j) |
3546 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/nspawn/nspawn.c", 3546, __func__); |
3547 | |
3548 | f = fopen(j, "re"); |
3549 | if (f) { |
3550 | p = TAKE_PTR(j)({ typeof(j) _ptr_ = (j); (j) = ((void*)0); _ptr_; }); |
3551 | |
3552 | /* By default, we trust configuration from /etc and /run */ |
3553 | if (arg_settings_trusted < 0) |
3554 | arg_settings_trusted = true1; |
3555 | |
3556 | break; |
3557 | } |
3558 | |
3559 | if (errno(*__errno_location ()) != ENOENT2) |
3560 | return log_error_errno(errno, "Failed to open %s: %m", j)({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/nspawn/nspawn.c", 3560, __func__ , "Failed to open %s: %m", j) : -abs(_e); }); |
3561 | } |
3562 | |
3563 | if (!f) { |
3564 | /* After that, let's look for a file next to the |
3565 | * actual image we shall boot. */ |
3566 | |
3567 | if (arg_image) { |
3568 | p = file_in_same_dir(arg_image, fn); |
3569 | if (!p) |
3570 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/nspawn/nspawn.c", 3570, __func__); |
3571 | } else if (arg_directory) { |
3572 | p = file_in_same_dir(arg_directory, fn); |
3573 | if (!p) |
3574 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/nspawn/nspawn.c", 3574, __func__); |
3575 | } |
3576 | |
3577 | if (p) { |
3578 | f = fopen(p, "re"); |
3579 | if (!f && errno(*__errno_location ()) != ENOENT2) |
3580 | return log_error_errno(errno, "Failed to open %s: %m", p)({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/nspawn/nspawn.c", 3580, __func__ , "Failed to open %s: %m", p) : -abs(_e); }); |
3581 | |
3582 | /* By default, we do not trust configuration from /var/lib/machines */ |
3583 | if (arg_settings_trusted < 0) |
3584 | arg_settings_trusted = false0; |
3585 | } |
3586 | } |
3587 | |
3588 | if (!f) |
3589 | return 0; |
3590 | |
3591 | log_debug("Settings are trusted: %s", yes_no(arg_settings_trusted))({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 3591, __func__, "Settings are trusted: %s" , yes_no(arg_settings_trusted)) : -abs(_e); }); |
3592 | |
3593 | r = settings_load(f, p, &settings); |
3594 | if (r < 0) |
3595 | return r; |
3596 | |
3597 | return merge_settings(settings, p); |
3598 | } |
3599 | |
3600 | static int run(int master, |
3601 | const char* console, |
3602 | DissectedImage *dissected_image, |
3603 | bool_Bool interactive, |
3604 | bool_Bool secondary, |
3605 | FDSet *fds, |
3606 | char veth_name[IFNAMSIZ16], bool_Bool *veth_created, |
3607 | union in_addr_union *exposed, |
3608 | pid_t *pid, int *ret) { |
3609 | |
3610 | static const struct sigaction sa = { |
3611 | .sa_handler__sigaction_handler.sa_handler = nop_signal_handler, |
3612 | .sa_flags = SA_NOCLDSTOP1|SA_RESTART0x10000000, |
3613 | }; |
3614 | |
3615 | _cleanup_(release_lock_file)__attribute__((cleanup(release_lock_file))) LockFile uid_shift_lock = LOCK_FILE_INIT{ .fd = -1, .path = ((void*)0) }; |
3616 | _cleanup_close___attribute__((cleanup(closep))) int etc_passwd_lock = -1; |
3617 | _cleanup_close_pair___attribute__((cleanup(close_pairp))) int |
3618 | kmsg_socket_pair[2] = { -1, -1 }, |
3619 | rtnl_socket_pair[2] = { -1, -1 }, |
3620 | pid_socket_pair[2] = { -1, -1 }, |
3621 | uuid_socket_pair[2] = { -1, -1 }, |
3622 | notify_socket_pair[2] = { -1, -1 }, |
3623 | uid_shift_socket_pair[2] = { -1, -1 }, |
3624 | unified_cgroup_hierarchy_socket_pair[2] = { -1, -1}; |
3625 | |
3626 | _cleanup_close___attribute__((cleanup(closep))) int notify_socket= -1; |
3627 | _cleanup_(barrier_destroy)__attribute__((cleanup(barrier_destroy))) Barrier barrier = BARRIER_NULL{-1, -1, {-1, -1}, 0}; |
3628 | _cleanup_(sd_event_source_unrefp)__attribute__((cleanup(sd_event_source_unrefp))) sd_event_source *notify_event_source = NULL((void*)0); |
3629 | _cleanup_(sd_event_unrefp)__attribute__((cleanup(sd_event_unrefp))) sd_event *event = NULL((void*)0); |
3630 | _cleanup_(pty_forward_freep)__attribute__((cleanup(pty_forward_freep))) PTYForward *forward = NULL((void*)0); |
3631 | _cleanup_(sd_netlink_unrefp)__attribute__((cleanup(sd_netlink_unrefp))) sd_netlink *rtnl = NULL((void*)0); |
3632 | _cleanup_(sd_bus_flush_close_unrefp)__attribute__((cleanup(sd_bus_flush_close_unrefp))) sd_bus *bus = NULL((void*)0); |
3633 | ContainerStatus container_status = 0; |
3634 | char last_char = 0; |
3635 | int ifi = 0, r; |
3636 | ssize_t l; |
3637 | sigset_t mask_chld; |
3638 | _cleanup_close___attribute__((cleanup(closep))) int netns_fd = -1; |
3639 | |
3640 | assert_se(sigemptyset(&mask_chld) == 0)do { if ((__builtin_expect(!!(!(sigemptyset(&mask_chld) == 0)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("sigemptyset(&mask_chld) == 0" ), "../src/nspawn/nspawn.c", 3640, __PRETTY_FUNCTION__); } while (0); |
3641 | assert_se(sigaddset(&mask_chld, SIGCHLD) == 0)do { if ((__builtin_expect(!!(!(sigaddset(&mask_chld, 17) == 0)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("sigaddset(&mask_chld, SIGCHLD) == 0" ), "../src/nspawn/nspawn.c", 3641, __PRETTY_FUNCTION__); } while (0); |
3642 | |
3643 | if (arg_userns_mode == USER_NAMESPACE_PICK) { |
3644 | /* When we shall pick the UID/GID range, let's first lock /etc/passwd, so that we can safely |
3645 | * check with getpwuid() if the specific user already exists. Note that /etc might be |
3646 | * read-only, in which case this will fail with EROFS. But that's really OK, as in that case we |
3647 | * can be reasonably sure that no users are going to be added. Note that getpwuid() checks are |
3648 | * really just an extra safety net. We kinda assume that the UID range we allocate from is |
3649 | * really ours. */ |
3650 | |
3651 | etc_passwd_lock = take_etc_passwd_lock(NULL((void*)0)); |
3652 | if (etc_passwd_lock < 0 && etc_passwd_lock != -EROFS30) |
3653 | return log_error_errno(etc_passwd_lock, "Failed to take /etc/passwd lock: %m")({ int _level = ((3)), _e = ((etc_passwd_lock)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 3653, __func__, "Failed to take /etc/passwd lock: %m" ) : -abs(_e); }); |
3654 | } |
3655 | |
3656 | r = barrier_create(&barrier); |
3657 | if (r < 0) |
3658 | return log_error_errno(r, "Cannot initialize IPC barrier: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 3658, __func__, "Cannot initialize IPC barrier: %m" ) : -abs(_e); }); |
3659 | |
3660 | if (socketpair(AF_UNIX1, SOCK_SEQPACKETSOCK_SEQPACKET|SOCK_CLOEXECSOCK_CLOEXEC, 0, kmsg_socket_pair) < 0) |
3661 | return log_error_errno(errno, "Failed to create kmsg socket pair: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/nspawn/nspawn.c", 3661, __func__ , "Failed to create kmsg socket pair: %m") : -abs(_e); }); |
3662 | |
3663 | if (socketpair(AF_UNIX1, SOCK_SEQPACKETSOCK_SEQPACKET|SOCK_CLOEXECSOCK_CLOEXEC, 0, rtnl_socket_pair) < 0) |
3664 | return log_error_errno(errno, "Failed to create rtnl socket pair: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/nspawn/nspawn.c", 3664, __func__ , "Failed to create rtnl socket pair: %m") : -abs(_e); }); |
3665 | |
3666 | if (socketpair(AF_UNIX1, SOCK_SEQPACKETSOCK_SEQPACKET|SOCK_CLOEXECSOCK_CLOEXEC, 0, pid_socket_pair) < 0) |
3667 | return log_error_errno(errno, "Failed to create pid socket pair: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/nspawn/nspawn.c", 3667, __func__ , "Failed to create pid socket pair: %m") : -abs(_e); }); |
3668 | |
3669 | if (socketpair(AF_UNIX1, SOCK_SEQPACKETSOCK_SEQPACKET|SOCK_CLOEXECSOCK_CLOEXEC, 0, uuid_socket_pair) < 0) |
3670 | return log_error_errno(errno, "Failed to create id socket pair: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/nspawn/nspawn.c", 3670, __func__ , "Failed to create id socket pair: %m") : -abs(_e); }); |
3671 | |
3672 | if (socketpair(AF_UNIX1, SOCK_SEQPACKETSOCK_SEQPACKET|SOCK_CLOEXECSOCK_CLOEXEC, 0, notify_socket_pair) < 0) |
3673 | return log_error_errno(errno, "Failed to create notify socket pair: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/nspawn/nspawn.c", 3673, __func__ , "Failed to create notify socket pair: %m") : -abs(_e); }); |
3674 | |
3675 | if (arg_userns_mode != USER_NAMESPACE_NO) |
3676 | if (socketpair(AF_UNIX1, SOCK_SEQPACKETSOCK_SEQPACKET|SOCK_CLOEXECSOCK_CLOEXEC, 0, uid_shift_socket_pair) < 0) |
3677 | return log_error_errno(errno, "Failed to create uid shift socket pair: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/nspawn/nspawn.c", 3677, __func__ , "Failed to create uid shift socket pair: %m") : -abs(_e); } ); |
3678 | |
3679 | if (arg_unified_cgroup_hierarchy == CGROUP_UNIFIED_UNKNOWN) |
3680 | if (socketpair(AF_UNIX1, SOCK_SEQPACKETSOCK_SEQPACKET|SOCK_CLOEXECSOCK_CLOEXEC, 0, unified_cgroup_hierarchy_socket_pair) < 0) |
3681 | return log_error_errno(errno, "Failed to create unified cgroup socket pair: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/nspawn/nspawn.c", 3681, __func__ , "Failed to create unified cgroup socket pair: %m") : -abs(_e ); }); |
3682 | |
3683 | /* Child can be killed before execv(), so handle SIGCHLD in order to interrupt |
3684 | * parent's blocking calls and give it a chance to call wait() and terminate. */ |
3685 | r = sigprocmask(SIG_UNBLOCK1, &mask_chld, NULL((void*)0)); |
3686 | if (r < 0) |
3687 | return log_error_errno(errno, "Failed to change the signal mask: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/nspawn/nspawn.c", 3687, __func__ , "Failed to change the signal mask: %m") : -abs(_e); }); |
3688 | |
3689 | r = sigaction(SIGCHLD17, &sa, NULL((void*)0)); |
3690 | if (r < 0) |
3691 | return log_error_errno(errno, "Failed to install SIGCHLD handler: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/nspawn/nspawn.c", 3691, __func__ , "Failed to install SIGCHLD handler: %m") : -abs(_e); }); |
3692 | |
3693 | if (arg_network_namespace_path) { |
3694 | netns_fd = open(arg_network_namespace_path, O_RDONLY00|O_NOCTTY0400|O_CLOEXEC02000000); |
3695 | if (netns_fd < 0) |
3696 | return log_error_errno(errno, "Cannot open file %s: %m", arg_network_namespace_path)({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/nspawn/nspawn.c", 3696, __func__ , "Cannot open file %s: %m", arg_network_namespace_path) : -abs (_e); }); |
3697 | |
3698 | r = fd_is_network_ns(netns_fd); |
3699 | if (r == -EUCLEAN117) |
3700 | log_debug_errno(r, "Cannot determine if passed network namespace path '%s' really refers to a network namespace, assuming it does.", arg_network_namespace_path)({ int _level = ((7)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 3700, __func__, "Cannot determine if passed network namespace path '%s' really refers to a network namespace, assuming it does." , arg_network_namespace_path) : -abs(_e); }); |
3701 | else if (r < 0) |
3702 | return log_error_errno(r, "Failed to check %s fs type: %m", arg_network_namespace_path)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 3702, __func__, "Failed to check %s fs type: %m" , arg_network_namespace_path) : -abs(_e); }); |
3703 | else if (r == 0) { |
3704 | log_error("Path %s doesn't refer to a network namespace, refusing.", arg_network_namespace_path)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 3704, __func__, "Path %s doesn't refer to a network namespace, refusing." , arg_network_namespace_path) : -abs(_e); }); |
3705 | return -EINVAL22; |
3706 | } |
3707 | } |
3708 | |
3709 | *pid = raw_clone(SIGCHLD17|CLONE_NEWNS0x00020000); |
3710 | if (*pid < 0) |
3711 | return log_error_errno(errno, "clone() failed%s: %m",({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/nspawn/nspawn.c", 3713, __func__ , "clone() failed%s: %m", (*__errno_location ()) == 22 ? ", do you have namespace support enabled in your kernel? (You need UTS, IPC, PID and NET namespacing built in)" : "") : -abs(_e); }) |
3712 | errno == EINVAL ?({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/nspawn/nspawn.c", 3713, __func__ , "clone() failed%s: %m", (*__errno_location ()) == 22 ? ", do you have namespace support enabled in your kernel? (You need UTS, IPC, PID and NET namespacing built in)" : "") : -abs(_e); }) |
3713 | ", do you have namespace support enabled in your kernel? (You need UTS, IPC, PID and NET namespacing built in)" : "")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/nspawn/nspawn.c", 3713, __func__ , "clone() failed%s: %m", (*__errno_location ()) == 22 ? ", do you have namespace support enabled in your kernel? (You need UTS, IPC, PID and NET namespacing built in)" : "") : -abs(_e); }); |
3714 | |
3715 | if (*pid == 0) { |
3716 | /* The outer child only has a file system namespace. */ |
3717 | barrier_set_role(&barrier, BARRIER_CHILD); |
3718 | |
3719 | master = safe_close(master); |
3720 | |
3721 | kmsg_socket_pair[0] = safe_close(kmsg_socket_pair[0]); |
3722 | rtnl_socket_pair[0] = safe_close(rtnl_socket_pair[0]); |
3723 | pid_socket_pair[0] = safe_close(pid_socket_pair[0]); |
3724 | uuid_socket_pair[0] = safe_close(uuid_socket_pair[0]); |
3725 | notify_socket_pair[0] = safe_close(notify_socket_pair[0]); |
3726 | uid_shift_socket_pair[0] = safe_close(uid_shift_socket_pair[0]); |
3727 | unified_cgroup_hierarchy_socket_pair[0] = safe_close(unified_cgroup_hierarchy_socket_pair[0]); |
3728 | |
3729 | (void) reset_all_signal_handlers(); |
3730 | (void) reset_signal_mask(); |
3731 | |
3732 | r = outer_child(&barrier, |
3733 | arg_directory, |
3734 | console, |
3735 | dissected_image, |
3736 | interactive, |
3737 | secondary, |
3738 | pid_socket_pair[1], |
3739 | uuid_socket_pair[1], |
3740 | notify_socket_pair[1], |
3741 | kmsg_socket_pair[1], |
3742 | rtnl_socket_pair[1], |
3743 | uid_shift_socket_pair[1], |
3744 | unified_cgroup_hierarchy_socket_pair[1], |
3745 | fds, |
3746 | netns_fd); |
3747 | if (r < 0) |
3748 | _exit(EXIT_FAILURE1); |
3749 | |
3750 | _exit(EXIT_SUCCESS0); |
3751 | } |
3752 | |
3753 | barrier_set_role(&barrier, BARRIER_PARENT); |
3754 | |
3755 | fds = fdset_free(fds); |
3756 | |
3757 | kmsg_socket_pair[1] = safe_close(kmsg_socket_pair[1]); |
3758 | rtnl_socket_pair[1] = safe_close(rtnl_socket_pair[1]); |
3759 | pid_socket_pair[1] = safe_close(pid_socket_pair[1]); |
3760 | uuid_socket_pair[1] = safe_close(uuid_socket_pair[1]); |
3761 | notify_socket_pair[1] = safe_close(notify_socket_pair[1]); |
3762 | uid_shift_socket_pair[1] = safe_close(uid_shift_socket_pair[1]); |
3763 | unified_cgroup_hierarchy_socket_pair[1] = safe_close(unified_cgroup_hierarchy_socket_pair[1]); |
3764 | |
3765 | if (arg_userns_mode != USER_NAMESPACE_NO) { |
3766 | /* The child just let us know the UID shift it might have read from the image. */ |
3767 | l = recv(uid_shift_socket_pair[0], &arg_uid_shift, sizeof arg_uid_shift, 0); |
3768 | if (l < 0) |
3769 | return log_error_errno(errno, "Failed to read UID shift: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/nspawn/nspawn.c", 3769, __func__ , "Failed to read UID shift: %m") : -abs(_e); }); |
3770 | if (l != sizeof arg_uid_shift) { |
3771 | log_error("Short read while reading UID shift.")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 3771, __func__, "Short read while reading UID shift." ) : -abs(_e); }); |
3772 | return -EIO5; |
3773 | } |
3774 | |
3775 | if (arg_userns_mode == USER_NAMESPACE_PICK) { |
3776 | /* If we are supposed to pick the UID shift, let's try to use the shift read from the |
3777 | * image, but if that's already in use, pick a new one, and report back to the child, |
3778 | * which one we now picked. */ |
3779 | |
3780 | r = uid_shift_pick(&arg_uid_shift, &uid_shift_lock); |
3781 | if (r < 0) |
3782 | return log_error_errno(r, "Failed to pick suitable UID/GID range: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 3782, __func__, "Failed to pick suitable UID/GID range: %m" ) : -abs(_e); }); |
3783 | |
3784 | l = send(uid_shift_socket_pair[0], &arg_uid_shift, sizeof arg_uid_shift, MSG_NOSIGNALMSG_NOSIGNAL); |
3785 | if (l < 0) |
3786 | return log_error_errno(errno, "Failed to send UID shift: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/nspawn/nspawn.c", 3786, __func__ , "Failed to send UID shift: %m") : -abs(_e); }); |
3787 | if (l != sizeof arg_uid_shift) { |
3788 | log_error("Short write while writing UID shift.")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 3788, __func__, "Short write while writing UID shift." ) : -abs(_e); }); |
3789 | return -EIO5; |
3790 | } |
3791 | } |
3792 | } |
3793 | |
3794 | if (arg_unified_cgroup_hierarchy == CGROUP_UNIFIED_UNKNOWN) { |
3795 | /* The child let us know the support cgroup mode it might have read from the image. */ |
3796 | l = recv(unified_cgroup_hierarchy_socket_pair[0], &arg_unified_cgroup_hierarchy, sizeof(arg_unified_cgroup_hierarchy), 0); |
3797 | if (l < 0) |
3798 | return log_error_errno(errno, "Failed to read cgroup mode: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/nspawn/nspawn.c", 3798, __func__ , "Failed to read cgroup mode: %m") : -abs(_e); }); |
3799 | if (l != sizeof(arg_unified_cgroup_hierarchy)) { |
3800 | log_error("Short read while reading cgroup mode.")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 3800, __func__, "Short read while reading cgroup mode." ) : -abs(_e); }); |
3801 | return -EIO5; |
3802 | } |
3803 | } |
3804 | |
3805 | /* Wait for the outer child. */ |
3806 | r = wait_for_terminate_and_check("(sd-namespace)", *pid, WAIT_LOG_ABNORMAL); |
3807 | if (r < 0) |
3808 | return r; |
3809 | if (r != EXIT_SUCCESS0) |
3810 | return -EIO5; |
3811 | |
3812 | /* And now retrieve the PID of the inner child. */ |
3813 | l = recv(pid_socket_pair[0], pid, sizeof *pid, 0); |
3814 | if (l < 0) |
3815 | return log_error_errno(errno, "Failed to read inner child PID: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/nspawn/nspawn.c", 3815, __func__ , "Failed to read inner child PID: %m") : -abs(_e); }); |
3816 | if (l != sizeof *pid) { |
3817 | log_error("Short read while reading inner child PID.")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 3817, __func__, "Short read while reading inner child PID." ) : -abs(_e); }); |
3818 | return -EIO5; |
3819 | } |
3820 | |
3821 | /* We also retrieve container UUID in case it was generated by outer child */ |
3822 | l = recv(uuid_socket_pair[0], &arg_uuid, sizeof arg_uuid, 0); |
3823 | if (l < 0) |
3824 | return log_error_errno(errno, "Failed to read container machine ID: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/nspawn/nspawn.c", 3824, __func__ , "Failed to read container machine ID: %m") : -abs(_e); }); |
3825 | if (l != sizeof(arg_uuid)) { |
3826 | log_error("Short read while reading container machined ID.")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 3826, __func__, "Short read while reading container machined ID." ) : -abs(_e); }); |
3827 | return -EIO5; |
3828 | } |
3829 | |
3830 | /* We also retrieve the socket used for notifications generated by outer child */ |
3831 | notify_socket = receive_one_fd(notify_socket_pair[0], 0); |
3832 | if (notify_socket < 0) |
3833 | return log_error_errno(notify_socket,({ int _level = ((3)), _e = ((notify_socket)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 3834, __func__, "Failed to receive notification socket from the outer child: %m" ) : -abs(_e); }) |
3834 | "Failed to receive notification socket from the outer child: %m")({ int _level = ((3)), _e = ((notify_socket)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 3834, __func__, "Failed to receive notification socket from the outer child: %m" ) : -abs(_e); }); |
3835 | |
3836 | log_debug("Init process invoked as PID "PID_FMT, *pid)({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 3836, __func__, "Init process invoked as PID " "%" "i", *pid) : -abs(_e); }); |
3837 | |
3838 | if (arg_userns_mode != USER_NAMESPACE_NO) { |
3839 | if (!barrier_place_and_sync(&barrier)) { /* #1 */ |
3840 | log_error("Child died too early.")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 3840, __func__, "Child died too early." ) : -abs(_e); }); |
3841 | return -ESRCH3; |
3842 | } |
3843 | |
3844 | r = setup_uid_map(*pid); |
3845 | if (r < 0) |
3846 | return r; |
3847 | |
3848 | (void) barrier_place(&barrier); /* #2 */ |
3849 | } |
3850 | |
3851 | if (arg_private_network) { |
3852 | if (!arg_network_namespace_path) { |
3853 | /* Wait until the child has unshared its network namespace. */ |
3854 | if (!barrier_place_and_sync(&barrier)) { /* #3 */ |
3855 | log_error("Child died too early")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 3855, __func__, "Child died too early" ) : -abs(_e); }); |
3856 | return -ESRCH3; |
3857 | } |
3858 | } |
3859 | |
3860 | r = move_network_interfaces(*pid, arg_network_interfaces); |
3861 | if (r < 0) |
3862 | return r; |
3863 | |
3864 | if (arg_network_veth) { |
3865 | r = setup_veth(arg_machine, *pid, veth_name, |
3866 | arg_network_bridge || arg_network_zone); |
3867 | if (r < 0) |
3868 | return r; |
3869 | else if (r > 0) |
3870 | ifi = r; |
3871 | |
3872 | if (arg_network_bridge) { |
3873 | /* Add the interface to a bridge */ |
3874 | r = setup_bridge(veth_name, arg_network_bridge, false0); |
3875 | if (r < 0) |
3876 | return r; |
3877 | if (r > 0) |
3878 | ifi = r; |
3879 | } else if (arg_network_zone) { |
3880 | /* Add the interface to a bridge, possibly creating it */ |
3881 | r = setup_bridge(veth_name, arg_network_zone, true1); |
3882 | if (r < 0) |
3883 | return r; |
3884 | if (r > 0) |
3885 | ifi = r; |
3886 | } |
3887 | } |
3888 | |
3889 | r = setup_veth_extra(arg_machine, *pid, arg_network_veth_extra); |
3890 | if (r < 0) |
3891 | return r; |
3892 | |
3893 | /* We created the primary and extra veth links now; let's remember this, so that we know to |
3894 | remove them later on. Note that we don't bother with removing veth links that were created |
3895 | here when their setup failed half-way, because in that case the kernel should be able to |
3896 | remove them on its own, since they cannot be referenced by anything yet. */ |
3897 | *veth_created = true1; |
3898 | |
3899 | r = setup_macvlan(arg_machine, *pid, arg_network_macvlan); |
3900 | if (r < 0) |
3901 | return r; |
3902 | |
3903 | r = setup_ipvlan(arg_machine, *pid, arg_network_ipvlan); |
3904 | if (r < 0) |
3905 | return r; |
3906 | } |
3907 | |
3908 | if (arg_register || !arg_keep_unit) { |
3909 | r = sd_bus_default_system(&bus); |
3910 | if (r < 0) |
3911 | return log_error_errno(r, "Failed to open system bus: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 3911, __func__, "Failed to open system bus: %m" ) : -abs(_e); }); |
3912 | } |
3913 | |
3914 | if (!arg_keep_unit) { |
3915 | /* When a new scope is created for this container, then we'll be registered as its controller, in which |
3916 | * case PID 1 will send us a friendly RequestStop signal, when it is asked to terminate the |
3917 | * scope. Let's hook into that, and cleanly shut down the container, and print a friendly message. */ |
3918 | |
3919 | r = sd_bus_match_signal_async( |
3920 | bus, |
3921 | NULL((void*)0), |
3922 | "org.freedesktop.systemd1", |
3923 | NULL((void*)0), |
3924 | "org.freedesktop.systemd1.Scope", |
3925 | "RequestStop", |
3926 | on_request_stop, NULL((void*)0), PID_TO_PTR(*pid)); |
3927 | if (r < 0) |
3928 | return log_error_errno(r, "Failed to request RequestStop match: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 3928, __func__, "Failed to request RequestStop match: %m" ) : -abs(_e); }); |
3929 | } |
3930 | |
3931 | if (arg_register) { |
3932 | r = register_machine( |
3933 | bus, |
3934 | arg_machine, |
3935 | *pid, |
3936 | arg_directory, |
3937 | arg_uuid, |
3938 | ifi, |
3939 | arg_slice, |
3940 | arg_custom_mounts, arg_n_custom_mounts, |
3941 | arg_kill_signal, |
3942 | arg_property, |
3943 | arg_keep_unit, |
3944 | arg_container_service_name); |
3945 | if (r < 0) |
3946 | return r; |
3947 | |
3948 | } else if (!arg_keep_unit) { |
3949 | r = allocate_scope( |
3950 | bus, |
3951 | arg_machine, |
3952 | *pid, |
3953 | arg_slice, |
3954 | arg_custom_mounts, arg_n_custom_mounts, |
3955 | arg_kill_signal, |
3956 | arg_property); |
3957 | if (r < 0) |
3958 | return r; |
3959 | |
3960 | } else if (arg_slice || arg_property) |
3961 | log_notice("Machine and scope registration turned off, --slice= and --property= settings will have no effect.")({ int _level = (((5))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 3961, __func__, "Machine and scope registration turned off, --slice= and --property= settings will have no effect." ) : -abs(_e); }); |
3962 | |
3963 | r = create_subcgroup(*pid, arg_keep_unit, arg_unified_cgroup_hierarchy); |
3964 | if (r < 0) |
3965 | return r; |
3966 | |
3967 | r = sync_cgroup(*pid, arg_unified_cgroup_hierarchy, arg_uid_shift); |
3968 | if (r < 0) |
3969 | return r; |
3970 | |
3971 | r = chown_cgroup(*pid, arg_unified_cgroup_hierarchy, arg_uid_shift); |
3972 | if (r < 0) |
3973 | return r; |
3974 | |
3975 | /* Notify the child that the parent is ready with all |
3976 | * its setup (including cgroup-ification), and that |
3977 | * the child can now hand over control to the code to |
3978 | * run inside the container. */ |
3979 | (void) barrier_place(&barrier); /* #4 */ |
3980 | |
3981 | /* Block SIGCHLD here, before notifying child. |
3982 | * process_pty() will handle it with the other signals. */ |
3983 | assert_se(sigprocmask(SIG_BLOCK, &mask_chld, NULL) >= 0)do { if ((__builtin_expect(!!(!(sigprocmask(0, &mask_chld , ((void*)0)) >= 0)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD , ("sigprocmask(SIG_BLOCK, &mask_chld, NULL) >= 0"), "../src/nspawn/nspawn.c" , 3983, __PRETTY_FUNCTION__); } while (0); |
3984 | |
3985 | /* Reset signal to default */ |
3986 | r = default_signals(SIGCHLD17, -1); |
3987 | if (r < 0) |
3988 | return log_error_errno(r, "Failed to reset SIGCHLD: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 3988, __func__, "Failed to reset SIGCHLD: %m" ) : -abs(_e); }); |
3989 | |
3990 | r = sd_event_new(&event); |
3991 | if (r < 0) |
3992 | return log_error_errno(r, "Failed to get default event source: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 3992, __func__, "Failed to get default event source: %m" ) : -abs(_e); }); |
3993 | |
3994 | (void) sd_event_set_watchdog(event, true1); |
3995 | |
3996 | if (bus) { |
3997 | r = sd_bus_attach_event(bus, event, 0); |
3998 | if (r < 0) |
3999 | return log_error_errno(r, "Failed to attach bus to event loop: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 3999, __func__, "Failed to attach bus to event loop: %m" ) : -abs(_e); }); |
4000 | } |
4001 | |
4002 | r = setup_sd_notify_parent(event, notify_socket, PID_TO_PTR(*pid), ¬ify_event_source); |
4003 | if (r < 0) |
4004 | return r; |
4005 | |
4006 | /* Let the child know that we are ready and wait that the child is completely ready now. */ |
4007 | if (!barrier_place_and_sync(&barrier)) { /* #5 */ |
4008 | log_error("Child died too early.")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 4008, __func__, "Child died too early." ) : -abs(_e); }); |
4009 | return -ESRCH3; |
4010 | } |
4011 | |
4012 | /* At this point we have made use of the UID we picked, and thus nss-mymachines |
4013 | * will make them appear in getpwuid(), thus we can release the /etc/passwd lock. */ |
4014 | etc_passwd_lock = safe_close(etc_passwd_lock); |
4015 | |
4016 | sd_notifyf(false0, |
4017 | "STATUS=Container running.\n" |
4018 | "X_NSPAWN_LEADER_PID=" PID_FMT"%" "i", *pid); |
4019 | if (!arg_notify_ready) |
4020 | (void) sd_notify(false0, "READY=1\n"); |
4021 | |
4022 | if (arg_kill_signal > 0) { |
4023 | /* Try to kill the init system on SIGINT or SIGTERM */ |
4024 | (void) sd_event_add_signal(event, NULL((void*)0), SIGINT2, on_orderly_shutdown, PID_TO_PTR(*pid)); |
4025 | (void) sd_event_add_signal(event, NULL((void*)0), SIGTERM15, on_orderly_shutdown, PID_TO_PTR(*pid)); |
4026 | } else { |
4027 | /* Immediately exit */ |
4028 | (void) sd_event_add_signal(event, NULL((void*)0), SIGINT2, NULL((void*)0), NULL((void*)0)); |
4029 | (void) sd_event_add_signal(event, NULL((void*)0), SIGTERM15, NULL((void*)0), NULL((void*)0)); |
4030 | } |
4031 | |
4032 | /* Exit when the child exits */ |
4033 | (void) sd_event_add_signal(event, NULL((void*)0), SIGCHLD17, on_sigchld, PID_TO_PTR(*pid)); |
4034 | |
4035 | if (arg_expose_ports) { |
4036 | r = expose_port_watch_rtnl(event, rtnl_socket_pair[0], on_address_change, exposed, &rtnl); |
4037 | if (r < 0) |
4038 | return r; |
4039 | |
4040 | (void) expose_port_execute(rtnl, arg_expose_ports, exposed); |
4041 | } |
4042 | |
4043 | rtnl_socket_pair[0] = safe_close(rtnl_socket_pair[0]); |
4044 | |
4045 | r = pty_forward_new(event, master, |
4046 | PTY_FORWARD_IGNORE_VHANGUP | (interactive ? 0 : PTY_FORWARD_READ_ONLY), |
4047 | &forward); |
4048 | if (r < 0) |
4049 | return log_error_errno(r, "Failed to create PTY forwarder: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 4049, __func__, "Failed to create PTY forwarder: %m" ) : -abs(_e); }); |
4050 | |
4051 | r = sd_event_loop(event); |
4052 | if (r < 0) |
4053 | return log_error_errno(r, "Failed to run event loop: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 4053, __func__, "Failed to run event loop: %m" ) : -abs(_e); }); |
4054 | |
4055 | pty_forward_get_last_char(forward, &last_char); |
4056 | |
4057 | forward = pty_forward_free(forward); |
4058 | |
4059 | if (!arg_quiet && last_char != '\n') |
4060 | putc('\n', stdoutstdout); |
4061 | |
4062 | /* Kill if it is not dead yet anyway */ |
4063 | if (bus) { |
4064 | if (arg_register) |
4065 | terminate_machine(bus, arg_machine); |
4066 | else if (!arg_keep_unit) |
4067 | terminate_scope(bus, arg_machine); |
4068 | } |
4069 | |
4070 | /* Normally redundant, but better safe than sorry */ |
4071 | (void) kill(*pid, SIGKILL9); |
4072 | |
4073 | r = wait_for_container(*pid, &container_status); |
4074 | *pid = 0; |
4075 | |
4076 | if (r < 0) |
4077 | /* We failed to wait for the container, or the container exited abnormally. */ |
4078 | return r; |
4079 | if (r > 0 || container_status == CONTAINER_TERMINATED) { |
4080 | /* r > 0 → The container exited with a non-zero status. |
4081 | * As a special case, we need to replace 133 with a different value, |
4082 | * because 133 is special-cased in the service file to reboot the container. |
4083 | * otherwise → The container exited with zero status and a reboot was not requested. |
4084 | */ |
4085 | if (r == EXIT_FORCE_RESTART133) |
4086 | r = EXIT_FAILURE1; /* replace 133 with the general failure code */ |
4087 | *ret = r; |
4088 | return 0; /* finito */ |
4089 | } |
4090 | |
4091 | /* CONTAINER_REBOOTED, loop again */ |
4092 | |
4093 | if (arg_keep_unit) { |
4094 | /* Special handling if we are running as a service: instead of simply |
4095 | * restarting the machine we want to restart the entire service, so let's |
4096 | * inform systemd about this with the special exit code 133. The service |
4097 | * file uses RestartForceExitStatus=133 so that this results in a full |
4098 | * nspawn restart. This is necessary since we might have cgroup parameters |
4099 | * set we want to have flushed out. */ |
4100 | *ret = EXIT_FORCE_RESTART133; |
4101 | return 0; /* finito */ |
4102 | } |
4103 | |
4104 | expose_port_flush(arg_expose_ports, exposed); |
4105 | |
4106 | (void) remove_veth_links(veth_name, arg_network_veth_extra); |
4107 | *veth_created = false0; |
4108 | return 1; /* loop again */ |
4109 | } |
4110 | |
4111 | static int initialize_rlimits(void) { |
4112 | /* The default resource limits the kernel passes to PID 1, as per kernel 4.16. Let's pass our container payload |
4113 | * the same values as the kernel originally passed to PID 1, in order to minimize differences between host and |
4114 | * container execution environments. */ |
4115 | |
4116 | static const struct rlimit kernel_defaults[_RLIMIT_MAX(__RLIMIT_RTTIME+1 > __RLIMIT_NLIMITS ? __RLIMIT_RTTIME+1 : __RLIMIT_NLIMITS)] = { |
4117 | [RLIMIT_ASRLIMIT_AS] = { RLIM_INFINITY0xffffffffffffffffuLL, RLIM_INFINITY0xffffffffffffffffuLL }, |
4118 | [RLIMIT_CORERLIMIT_CORE] = { 0, RLIM_INFINITY0xffffffffffffffffuLL }, |
4119 | [RLIMIT_CPURLIMIT_CPU] = { RLIM_INFINITY0xffffffffffffffffuLL, RLIM_INFINITY0xffffffffffffffffuLL }, |
4120 | [RLIMIT_DATARLIMIT_DATA] = { RLIM_INFINITY0xffffffffffffffffuLL, RLIM_INFINITY0xffffffffffffffffuLL }, |
4121 | [RLIMIT_FSIZERLIMIT_FSIZE] = { RLIM_INFINITY0xffffffffffffffffuLL, RLIM_INFINITY0xffffffffffffffffuLL }, |
4122 | [RLIMIT_LOCKS__RLIMIT_LOCKS] = { RLIM_INFINITY0xffffffffffffffffuLL, RLIM_INFINITY0xffffffffffffffffuLL }, |
4123 | [RLIMIT_MEMLOCK__RLIMIT_MEMLOCK] = { 65536, 65536 }, |
4124 | [RLIMIT_MSGQUEUE__RLIMIT_MSGQUEUE] = { 819200, 819200 }, |
4125 | [RLIMIT_NICE__RLIMIT_NICE] = { 0, 0 }, |
4126 | [RLIMIT_NOFILERLIMIT_NOFILE] = { 1024, 4096 }, |
4127 | [RLIMIT_RSS__RLIMIT_RSS] = { RLIM_INFINITY0xffffffffffffffffuLL, RLIM_INFINITY0xffffffffffffffffuLL }, |
4128 | [RLIMIT_RTPRIO__RLIMIT_RTPRIO] = { 0, 0 }, |
4129 | [RLIMIT_RTTIME__RLIMIT_RTTIME] = { RLIM_INFINITY0xffffffffffffffffuLL, RLIM_INFINITY0xffffffffffffffffuLL }, |
4130 | [RLIMIT_STACKRLIMIT_STACK] = { 8388608, RLIM_INFINITY0xffffffffffffffffuLL }, |
4131 | |
4132 | /* The kernel scales the default for RLIMIT_NPROC and RLIMIT_SIGPENDING based on the system's amount of |
4133 | * RAM. To provide best compatibility we'll read these limits off PID 1 instead of hardcoding them |
4134 | * here. This is safe as we know that PID 1 doesn't change these two limits and thus the original |
4135 | * kernel's initialization should still be valid during runtime — at least if PID 1 is systemd. Note |
4136 | * that PID 1 changes a number of other resource limits during early initialization which is why we |
4137 | * don't read the other limits from PID 1 but prefer the static table above. */ |
4138 | }; |
4139 | |
4140 | int rl; |
4141 | |
4142 | for (rl = 0; rl < _RLIMIT_MAX(__RLIMIT_RTTIME+1 > __RLIMIT_NLIMITS ? __RLIMIT_RTTIME+1 : __RLIMIT_NLIMITS); rl++) { |
4143 | /* Let's only fill in what the user hasn't explicitly configured anyway */ |
4144 | if ((arg_settings_mask & (SETTING_RLIMIT_FIRST((uint64_t) SETTING_RLIMIT_FIRST) << rl)) == 0) { |
4145 | const struct rlimit *v; |
4146 | struct rlimit buffer; |
4147 | |
4148 | if (IN_SET(rl, RLIMIT_NPROC, RLIMIT_SIGPENDING)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){__RLIMIT_NPROC, __RLIMIT_SIGPENDING})/sizeof (int)]; switch(rl) { case __RLIMIT_NPROC: case __RLIMIT_SIGPENDING : _found = 1; break; default: break; } _found; })) { |
4149 | /* For these two let's read the limits off PID 1. See above for an explanation. */ |
4150 | |
4151 | if (prlimit(1, rl, NULL((void*)0), &buffer) < 0) |
4152 | return log_error_errno(errno, "Failed to read resource limit RLIMIT_%s of PID 1: %m", rlimit_to_string(rl))({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/nspawn/nspawn.c", 4152, __func__ , "Failed to read resource limit RLIMIT_%s of PID 1: %m", rlimit_to_string (rl)) : -abs(_e); }); |
4153 | |
4154 | v = &buffer; |
4155 | } else |
4156 | v = kernel_defaults + rl; |
4157 | |
4158 | arg_rlimit[rl] = newdup(struct rlimit, v, 1)((struct rlimit*) memdup_multiply(v, sizeof(struct rlimit), ( 1))); |
4159 | if (!arg_rlimit[rl]) |
4160 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/nspawn/nspawn.c", 4160, __func__); |
4161 | } |
4162 | |
4163 | if (DEBUG_LOGGING(__builtin_expect(!!(log_get_max_level_realm(LOG_REALM_SYSTEMD ) >= 7),0))) { |
4164 | _cleanup_free___attribute__((cleanup(freep))) char *k = NULL((void*)0); |
4165 | |
4166 | (void) rlimit_format(arg_rlimit[rl], &k); |
4167 | log_debug("Setting RLIMIT_%s to %s.", rlimit_to_string(rl), k)({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 4167, __func__, "Setting RLIMIT_%s to %s." , rlimit_to_string(rl), k) : -abs(_e); }); |
4168 | } |
4169 | } |
4170 | |
4171 | return 0; |
4172 | } |
4173 | |
4174 | int main(int argc, char *argv[]) { |
4175 | _cleanup_free___attribute__((cleanup(freep))) char *console = NULL((void*)0); |
4176 | _cleanup_close___attribute__((cleanup(closep))) int master = -1; |
4177 | _cleanup_fdset_free___attribute__((cleanup(fdset_freep))) FDSet *fds = NULL((void*)0); |
4178 | int r, n_fd_passed, ret = EXIT_SUCCESS0; |
4179 | char veth_name[IFNAMSIZ16] = ""; |
4180 | bool_Bool secondary = false0, remove_directory = false0, remove_image = false0; |
4181 | pid_t pid = 0; |
4182 | union in_addr_union exposed = {}; |
4183 | _cleanup_(release_lock_file)__attribute__((cleanup(release_lock_file))) LockFile tree_global_lock = LOCK_FILE_INIT{ .fd = -1, .path = ((void*)0) }, tree_local_lock = LOCK_FILE_INIT{ .fd = -1, .path = ((void*)0) }; |
4184 | bool_Bool interactive, veth_created = false0, remove_tmprootdir = false0; |
4185 | char tmprootdir[] = "/tmp/nspawn-root-XXXXXX"; |
4186 | _cleanup_(loop_device_unrefp)__attribute__((cleanup(loop_device_unrefp))) LoopDevice *loop = NULL((void*)0); |
4187 | _cleanup_(decrypted_image_unrefp)__attribute__((cleanup(decrypted_image_unrefp))) DecryptedImage *decrypted_image = NULL((void*)0); |
4188 | _cleanup_(dissected_image_unrefp)__attribute__((cleanup(dissected_image_unrefp))) DissectedImage *dissected_image = NULL((void*)0); |
4189 | |
4190 | log_parse_environment()log_parse_environment_realm(LOG_REALM_SYSTEMD); |
4191 | log_open(); |
4192 | |
4193 | /* Make sure rename_process() in the stub init process can work */ |
4194 | saved_argv = argv; |
4195 | saved_argc = argc; |
4196 | |
4197 | r = parse_argv(argc, argv); |
4198 | if (r <= 0) |
4199 | goto finish; |
4200 | |
4201 | r = must_be_root(); |
4202 | if (r < 0) |
4203 | goto finish; |
4204 | |
4205 | r = initialize_rlimits(); |
4206 | if (r < 0) |
4207 | goto finish; |
4208 | |
4209 | r = determine_names(); |
4210 | if (r < 0) |
4211 | goto finish; |
4212 | |
4213 | r = load_settings(); |
4214 | if (r < 0) |
4215 | goto finish; |
4216 | |
4217 | r = verify_arguments(); |
4218 | if (r < 0) |
4219 | goto finish; |
4220 | |
4221 | r = detect_unified_cgroup_hierarchy_from_environment(); |
4222 | if (r < 0) |
4223 | goto finish; |
4224 | |
4225 | n_fd_passed = sd_listen_fds(false0); |
4226 | if (n_fd_passed > 0) { |
4227 | r = fdset_new_listen_fds(&fds, false0); |
4228 | if (r < 0) { |
4229 | log_error_errno(r, "Failed to collect file descriptors: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 4229, __func__, "Failed to collect file descriptors: %m" ) : -abs(_e); }); |
4230 | goto finish; |
4231 | } |
4232 | } |
4233 | |
4234 | /* The "default" umask. This is appropriate for most file and directory |
4235 | * operations performed by nspawn, and is the umask that will be used for |
4236 | * the child. Functions like copy_devnodes() change the umask temporarily. */ |
4237 | umask(0022); |
4238 | |
4239 | if (arg_directory) { |
4240 | assert(!arg_image)do { if ((__builtin_expect(!!(!(!arg_image)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("!arg_image"), "../src/nspawn/nspawn.c", 4240, __PRETTY_FUNCTION__); } while (0); |
4241 | |
4242 | if (path_equal(arg_directory, "/") && !arg_ephemeral) { |
4243 | log_error("Spawning container on root directory is not supported. Consider using --ephemeral.")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 4243, __func__, "Spawning container on root directory is not supported. Consider using --ephemeral." ) : -abs(_e); }); |
4244 | r = -EINVAL22; |
4245 | goto finish; |
4246 | } |
4247 | |
4248 | if (arg_ephemeral) { |
4249 | _cleanup_free___attribute__((cleanup(freep))) char *np = NULL((void*)0); |
4250 | |
4251 | r = chase_symlinks_and_update(&arg_directory, 0); |
4252 | if (r < 0) |
4253 | goto finish; |
4254 | |
4255 | /* If the specified path is a mount point we |
4256 | * generate the new snapshot immediately |
4257 | * inside it under a random name. However if |
4258 | * the specified is not a mount point we |
4259 | * create the new snapshot in the parent |
4260 | * directory, just next to it. */ |
4261 | r = path_is_mount_point(arg_directory, NULL((void*)0), 0); |
4262 | if (r < 0) { |
4263 | log_error_errno(r, "Failed to determine whether directory %s is mount point: %m", arg_directory)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 4263, __func__, "Failed to determine whether directory %s is mount point: %m" , arg_directory) : -abs(_e); }); |
4264 | goto finish; |
4265 | } |
4266 | if (r > 0) |
4267 | r = tempfn_random_child(arg_directory, "machine.", &np); |
4268 | else |
4269 | r = tempfn_random(arg_directory, "machine.", &np); |
4270 | if (r < 0) { |
4271 | log_error_errno(r, "Failed to generate name for directory snapshot: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 4271, __func__, "Failed to generate name for directory snapshot: %m" ) : -abs(_e); }); |
4272 | goto finish; |
4273 | } |
4274 | |
4275 | r = image_path_lock(np, (arg_read_only ? LOCK_SH1 : LOCK_EX2) | LOCK_NB4, &tree_global_lock, &tree_local_lock); |
4276 | if (r < 0) { |
4277 | log_error_errno(r, "Failed to lock %s: %m", np)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 4277, __func__, "Failed to lock %s: %m" , np) : -abs(_e); }); |
4278 | goto finish; |
4279 | } |
4280 | |
4281 | r = btrfs_subvol_snapshot(arg_directory, np, |
4282 | (arg_read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) | |
4283 | BTRFS_SNAPSHOT_FALLBACK_COPY | |
4284 | BTRFS_SNAPSHOT_FALLBACK_DIRECTORY | |
4285 | BTRFS_SNAPSHOT_RECURSIVE | |
4286 | BTRFS_SNAPSHOT_QUOTA); |
4287 | if (r < 0) { |
4288 | log_error_errno(r, "Failed to create snapshot %s from %s: %m", np, arg_directory)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 4288, __func__, "Failed to create snapshot %s from %s: %m" , np, arg_directory) : -abs(_e); }); |
4289 | goto finish; |
4290 | } |
4291 | |
4292 | free_and_replace(arg_directory, np)({ free(arg_directory); (arg_directory) = (np); (np) = ((void *)0); 0; }); |
4293 | |
4294 | remove_directory = true1; |
4295 | |
4296 | } else { |
4297 | r = chase_symlinks_and_update(&arg_directory, arg_template ? CHASE_NONEXISTENT : 0); |
4298 | if (r < 0) |
4299 | goto finish; |
4300 | |
4301 | r = image_path_lock(arg_directory, (arg_read_only ? LOCK_SH1 : LOCK_EX2) | LOCK_NB4, &tree_global_lock, &tree_local_lock); |
4302 | if (r == -EBUSY16) { |
4303 | log_error_errno(r, "Directory tree %s is currently busy.", arg_directory)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 4303, __func__, "Directory tree %s is currently busy." , arg_directory) : -abs(_e); }); |
4304 | goto finish; |
4305 | } |
4306 | if (r < 0) { |
4307 | log_error_errno(r, "Failed to lock %s: %m", arg_directory)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 4307, __func__, "Failed to lock %s: %m" , arg_directory) : -abs(_e); }); |
4308 | goto finish; |
4309 | } |
4310 | |
4311 | if (arg_template) { |
4312 | r = chase_symlinks_and_update(&arg_template, 0); |
4313 | if (r < 0) |
4314 | goto finish; |
4315 | |
4316 | r = btrfs_subvol_snapshot(arg_template, arg_directory, |
4317 | (arg_read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) | |
4318 | BTRFS_SNAPSHOT_FALLBACK_COPY | |
4319 | BTRFS_SNAPSHOT_FALLBACK_DIRECTORY | |
4320 | BTRFS_SNAPSHOT_FALLBACK_IMMUTABLE | |
4321 | BTRFS_SNAPSHOT_RECURSIVE | |
4322 | BTRFS_SNAPSHOT_QUOTA); |
4323 | if (r == -EEXIST17) { |
4324 | if (!arg_quiet) |
4325 | log_info("Directory %s already exists, not populating from template %s.", arg_directory, arg_template)({ int _level = (((6))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 4325, __func__, "Directory %s already exists, not populating from template %s." , arg_directory, arg_template) : -abs(_e); }); |
4326 | } else if (r < 0) { |
4327 | log_error_errno(r, "Couldn't create snapshot %s from %s: %m", arg_directory, arg_template)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 4327, __func__, "Couldn't create snapshot %s from %s: %m" , arg_directory, arg_template) : -abs(_e); }); |
4328 | goto finish; |
4329 | } else { |
4330 | if (!arg_quiet) |
4331 | log_info("Populated %s from template %s.", arg_directory, arg_template)({ int _level = (((6))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 4331, __func__, "Populated %s from template %s." , arg_directory, arg_template) : -abs(_e); }); |
4332 | } |
4333 | } |
4334 | } |
4335 | |
4336 | if (arg_start_mode == START_BOOT) { |
4337 | const char *p; |
4338 | |
4339 | if (arg_pivot_root_new) |
4340 | p = prefix_roota(arg_directory, arg_pivot_root_new)({ const char* _path = (arg_pivot_root_new), *_root = (arg_directory ), *_ret; char *_p, *_n; size_t _l; while (_path[0] == '/' && _path[1] == '/') _path ++; if (empty_or_root(_root)) _ret = _path ; else { _l = strlen(_root) + 1 + strlen(_path) + 1; _n = __builtin_alloca (_l); _p = stpcpy(_n, _root); while (_p > _n && _p [-1] == '/') _p--; if (_path[0] != '/') *(_p++) = '/'; strcpy (_p, _path); _ret = _n; } _ret; }); |
4341 | else |
4342 | p = arg_directory; |
4343 | |
4344 | if (path_is_os_tree(p) <= 0) { |
4345 | log_error("Directory %s doesn't look like an OS root directory (os-release file is missing). Refusing.", p)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 4345, __func__, "Directory %s doesn't look like an OS root directory (os-release file is missing). Refusing." , p) : -abs(_e); }); |
4346 | r = -EINVAL22; |
4347 | goto finish; |
4348 | } |
4349 | } else { |
4350 | const char *p, *q; |
4351 | |
4352 | if (arg_pivot_root_new) |
4353 | p = prefix_roota(arg_directory, arg_pivot_root_new)({ const char* _path = (arg_pivot_root_new), *_root = (arg_directory ), *_ret; char *_p, *_n; size_t _l; while (_path[0] == '/' && _path[1] == '/') _path ++; if (empty_or_root(_root)) _ret = _path ; else { _l = strlen(_root) + 1 + strlen(_path) + 1; _n = __builtin_alloca (_l); _p = stpcpy(_n, _root); while (_p > _n && _p [-1] == '/') _p--; if (_path[0] != '/') *(_p++) = '/'; strcpy (_p, _path); _ret = _n; } _ret; }); |
4354 | else |
4355 | p = arg_directory; |
4356 | |
4357 | q = strjoina(p, "/usr/")({ const char *_appendees_[] = { p, "/usr/" }; char *_d_, *_p_ ; size_t _len_ = 0; size_t _i_; for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p(typeof (_appendees_), typeof(&*(_appendees_))), sizeof(_appendees_ )/sizeof((_appendees_)[0]), ((void)0))) && _appendees_ [_i_]; _i_++) _len_ += strlen(_appendees_[_i_]); _p_ = _d_ = __builtin_alloca (_len_ + 1); for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr ( !__builtin_types_compatible_p(typeof(_appendees_), typeof(& *(_appendees_))), sizeof(_appendees_)/sizeof((_appendees_)[0] ), ((void)0))) && _appendees_[_i_]; _i_++) _p_ = stpcpy (_p_, _appendees_[_i_]); *_p_ = 0; _d_; }); |
4358 | |
4359 | if (laccess(q, F_OK)faccessat(-100, (q), (0), 0x100) < 0) { |
4360 | log_error("Directory %s doesn't look like it has an OS tree. Refusing.", p)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 4360, __func__, "Directory %s doesn't look like it has an OS tree. Refusing." , p) : -abs(_e); }); |
4361 | r = -EINVAL22; |
4362 | goto finish; |
4363 | } |
4364 | } |
4365 | |
4366 | } else { |
4367 | assert(arg_image)do { if ((__builtin_expect(!!(!(arg_image)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("arg_image"), "../src/nspawn/nspawn.c", 4367 , __PRETTY_FUNCTION__); } while (0); |
4368 | assert(!arg_template)do { if ((__builtin_expect(!!(!(!arg_template)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("!arg_template"), "../src/nspawn/nspawn.c" , 4368, __PRETTY_FUNCTION__); } while (0); |
4369 | |
4370 | r = chase_symlinks_and_update(&arg_image, 0); |
4371 | if (r < 0) |
4372 | goto finish; |
4373 | |
4374 | if (arg_ephemeral) { |
4375 | _cleanup_free___attribute__((cleanup(freep))) char *np = NULL((void*)0); |
4376 | |
4377 | r = tempfn_random(arg_image, "machine.", &np); |
4378 | if (r < 0) { |
4379 | log_error_errno(r, "Failed to generate name for image snapshot: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 4379, __func__, "Failed to generate name for image snapshot: %m" ) : -abs(_e); }); |
4380 | goto finish; |
4381 | } |
4382 | |
4383 | r = image_path_lock(np, (arg_read_only ? LOCK_SH1 : LOCK_EX2) | LOCK_NB4, &tree_global_lock, &tree_local_lock); |
4384 | if (r < 0) { |
4385 | r = log_error_errno(r, "Failed to create image lock: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 4385, __func__, "Failed to create image lock: %m" ) : -abs(_e); }); |
4386 | goto finish; |
4387 | } |
4388 | |
4389 | r = copy_file(arg_image, np, O_EXCL0200, arg_read_only ? 0400 : 0600, FS_NOCOW_FL0x00800000, COPY_REFLINK); |
4390 | if (r < 0) { |
4391 | r = log_error_errno(r, "Failed to copy image file: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 4391, __func__, "Failed to copy image file: %m" ) : -abs(_e); }); |
4392 | goto finish; |
4393 | } |
4394 | |
4395 | free_and_replace(arg_image, np)({ free(arg_image); (arg_image) = (np); (np) = ((void*)0); 0; }); |
4396 | |
4397 | remove_image = true1; |
4398 | } else { |
4399 | r = image_path_lock(arg_image, (arg_read_only ? LOCK_SH1 : LOCK_EX2) | LOCK_NB4, &tree_global_lock, &tree_local_lock); |
4400 | if (r == -EBUSY16) { |
4401 | r = log_error_errno(r, "Disk image %s is currently busy.", arg_image)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 4401, __func__, "Disk image %s is currently busy." , arg_image) : -abs(_e); }); |
4402 | goto finish; |
4403 | } |
4404 | if (r < 0) { |
4405 | r = log_error_errno(r, "Failed to create image lock: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 4405, __func__, "Failed to create image lock: %m" ) : -abs(_e); }); |
4406 | goto finish; |
4407 | } |
4408 | |
4409 | if (!arg_root_hash) { |
4410 | r = root_hash_load(arg_image, &arg_root_hash, &arg_root_hash_size); |
4411 | if (r < 0) { |
4412 | log_error_errno(r, "Failed to load root hash file for %s: %m", arg_image)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 4412, __func__, "Failed to load root hash file for %s: %m" , arg_image) : -abs(_e); }); |
4413 | goto finish; |
4414 | } |
4415 | } |
4416 | } |
4417 | |
4418 | if (!mkdtemp(tmprootdir)) { |
4419 | r = log_error_errno(errno, "Failed to create temporary directory: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/nspawn/nspawn.c", 4419, __func__ , "Failed to create temporary directory: %m") : -abs(_e); }); |
4420 | goto finish; |
4421 | } |
4422 | |
4423 | remove_tmprootdir = true1; |
4424 | |
4425 | arg_directory = strdup(tmprootdir); |
4426 | if (!arg_directory) { |
4427 | r = log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/nspawn/nspawn.c", 4427, __func__); |
4428 | goto finish; |
4429 | } |
4430 | |
4431 | r = loop_device_make_by_path(arg_image, arg_read_only ? O_RDONLY00 : O_RDWR02, &loop); |
4432 | if (r < 0) { |
4433 | log_error_errno(r, "Failed to set up loopback block device: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 4433, __func__, "Failed to set up loopback block device: %m" ) : -abs(_e); }); |
4434 | goto finish; |
4435 | } |
4436 | |
4437 | r = dissect_image_and_warn( |
4438 | loop->fd, |
4439 | arg_image, |
4440 | arg_root_hash, arg_root_hash_size, |
4441 | DISSECT_IMAGE_REQUIRE_ROOT, |
4442 | &dissected_image); |
4443 | if (r == -ENOPKG65) { |
4444 | /* dissected_image_and_warn() already printed a brief error message. Extend on that with more details */ |
4445 | log_notice("Note that the disk image needs to\n"({ int _level = (((5))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 4450, __func__, "Note that the disk image needs to\n" " a) either contain only a single MBR partition of type 0x83 that is marked bootable\n" " b) or contain a single GPT partition of type 0FC63DAF-8483-4772-8E79-3D69D8477DE4\n" " c) or follow http://www.freedesktop.org/wiki/Specifications/DiscoverablePartitionsSpec/\n" " d) or contain a file system without a partition table\n" "in order to be bootable with systemd-nspawn.") : -abs(_e); } ) |
4446 | " a) either contain only a single MBR partition of type 0x83 that is marked bootable\n"({ int _level = (((5))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 4450, __func__, "Note that the disk image needs to\n" " a) either contain only a single MBR partition of type 0x83 that is marked bootable\n" " b) or contain a single GPT partition of type 0FC63DAF-8483-4772-8E79-3D69D8477DE4\n" " c) or follow http://www.freedesktop.org/wiki/Specifications/DiscoverablePartitionsSpec/\n" " d) or contain a file system without a partition table\n" "in order to be bootable with systemd-nspawn.") : -abs(_e); } ) |
4447 | " b) or contain a single GPT partition of type 0FC63DAF-8483-4772-8E79-3D69D8477DE4\n"({ int _level = (((5))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 4450, __func__, "Note that the disk image needs to\n" " a) either contain only a single MBR partition of type 0x83 that is marked bootable\n" " b) or contain a single GPT partition of type 0FC63DAF-8483-4772-8E79-3D69D8477DE4\n" " c) or follow http://www.freedesktop.org/wiki/Specifications/DiscoverablePartitionsSpec/\n" " d) or contain a file system without a partition table\n" "in order to be bootable with systemd-nspawn.") : -abs(_e); } ) |
4448 | " c) or follow http://www.freedesktop.org/wiki/Specifications/DiscoverablePartitionsSpec/\n"({ int _level = (((5))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 4450, __func__, "Note that the disk image needs to\n" " a) either contain only a single MBR partition of type 0x83 that is marked bootable\n" " b) or contain a single GPT partition of type 0FC63DAF-8483-4772-8E79-3D69D8477DE4\n" " c) or follow http://www.freedesktop.org/wiki/Specifications/DiscoverablePartitionsSpec/\n" " d) or contain a file system without a partition table\n" "in order to be bootable with systemd-nspawn.") : -abs(_e); } ) |
4449 | " d) or contain a file system without a partition table\n"({ int _level = (((5))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 4450, __func__, "Note that the disk image needs to\n" " a) either contain only a single MBR partition of type 0x83 that is marked bootable\n" " b) or contain a single GPT partition of type 0FC63DAF-8483-4772-8E79-3D69D8477DE4\n" " c) or follow http://www.freedesktop.org/wiki/Specifications/DiscoverablePartitionsSpec/\n" " d) or contain a file system without a partition table\n" "in order to be bootable with systemd-nspawn.") : -abs(_e); } ) |
4450 | "in order to be bootable with systemd-nspawn.")({ int _level = (((5))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 4450, __func__, "Note that the disk image needs to\n" " a) either contain only a single MBR partition of type 0x83 that is marked bootable\n" " b) or contain a single GPT partition of type 0FC63DAF-8483-4772-8E79-3D69D8477DE4\n" " c) or follow http://www.freedesktop.org/wiki/Specifications/DiscoverablePartitionsSpec/\n" " d) or contain a file system without a partition table\n" "in order to be bootable with systemd-nspawn.") : -abs(_e); } ); |
4451 | goto finish; |
4452 | } |
4453 | if (r < 0) |
4454 | goto finish; |
4455 | |
4456 | if (!arg_root_hash && dissected_image->can_verity) |
4457 | log_notice("Note: image %s contains verity information, but no root hash specified! Proceeding without integrity checking.", arg_image)({ int _level = (((5))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 4457, __func__, "Note: image %s contains verity information, but no root hash specified! Proceeding without integrity checking." , arg_image) : -abs(_e); }); |
4458 | |
4459 | r = dissected_image_decrypt_interactively(dissected_image, NULL((void*)0), arg_root_hash, arg_root_hash_size, 0, &decrypted_image); |
4460 | if (r < 0) |
4461 | goto finish; |
4462 | |
4463 | /* Now that we mounted the image, let's try to remove it again, if it is ephemeral */ |
4464 | if (remove_image && unlink(arg_image) >= 0) |
4465 | remove_image = false0; |
4466 | } |
4467 | |
4468 | r = custom_mount_prepare_all(arg_directory, arg_custom_mounts, arg_n_custom_mounts); |
4469 | if (r < 0) |
4470 | goto finish; |
4471 | |
4472 | interactive = |
4473 | isatty(STDIN_FILENO0) > 0 && |
4474 | isatty(STDOUT_FILENO1) > 0; |
4475 | |
4476 | master = posix_openpt(O_RDWR02|O_NOCTTY0400|O_CLOEXEC02000000|O_NONBLOCK04000); |
4477 | if (master < 0) { |
4478 | r = log_error_errno(errno, "Failed to acquire pseudo tty: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/nspawn/nspawn.c", 4478, __func__ , "Failed to acquire pseudo tty: %m") : -abs(_e); }); |
4479 | goto finish; |
4480 | } |
4481 | |
4482 | r = ptsname_malloc(master, &console); |
4483 | if (r < 0) { |
4484 | r = log_error_errno(r, "Failed to determine tty name: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 4484, __func__, "Failed to determine tty name: %m" ) : -abs(_e); }); |
4485 | goto finish; |
4486 | } |
4487 | |
4488 | if (arg_selinux_apifs_context) { |
4489 | r = mac_selinux_apply(console, arg_selinux_apifs_context); |
4490 | if (r < 0) |
4491 | goto finish; |
4492 | } |
4493 | |
4494 | if (unlockpt(master) < 0) { |
4495 | r = log_error_errno(errno, "Failed to unlock tty: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/nspawn/nspawn.c", 4495, __func__ , "Failed to unlock tty: %m") : -abs(_e); }); |
4496 | goto finish; |
4497 | } |
4498 | |
4499 | if (!arg_quiet) |
4500 | log_info("Spawning container %s on %s.\nPress ^] three times within 1s to kill container.",({ int _level = (((6))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 4501, __func__, "Spawning container %s on %s.\nPress ^] three times within 1s to kill container." , arg_machine, arg_image ?: arg_directory) : -abs(_e); }) |
4501 | arg_machine, arg_image ?: arg_directory)({ int _level = (((6))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 4501, __func__, "Spawning container %s on %s.\nPress ^] three times within 1s to kill container." , arg_machine, arg_image ?: arg_directory) : -abs(_e); }); |
4502 | |
4503 | assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD, SIGWINCH, SIGTERM, SIGINT, -1) >= 0)do { if ((__builtin_expect(!!(!(sigprocmask_many(0, ((void*)0 ), 17, 28, 15, 2, -1) >= 0)),0))) log_assert_failed_realm( LOG_REALM_SYSTEMD, ("sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD, SIGWINCH, SIGTERM, SIGINT, -1) >= 0" ), "../src/nspawn/nspawn.c", 4503, __PRETTY_FUNCTION__); } while (0); |
4504 | |
4505 | if (prctl(PR_SET_CHILD_SUBREAPER36, 1, 0, 0, 0) < 0) { |
4506 | r = log_error_errno(errno, "Failed to become subreaper: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/nspawn/nspawn.c", 4506, __func__ , "Failed to become subreaper: %m") : -abs(_e); }); |
4507 | goto finish; |
4508 | } |
4509 | |
4510 | for (;;) { |
4511 | r = run(master, |
4512 | console, |
4513 | dissected_image, |
4514 | interactive, secondary, |
4515 | fds, |
4516 | veth_name, &veth_created, |
4517 | &exposed, |
4518 | &pid, &ret); |
4519 | if (r <= 0) |
4520 | break; |
4521 | } |
4522 | |
4523 | finish: |
4524 | sd_notify(false0, |
4525 | r == 0 && ret == EXIT_FORCE_RESTART133 ? "STOPPING=1\nSTATUS=Restarting..." : |
4526 | "STOPPING=1\nSTATUS=Terminating..."); |
4527 | |
4528 | if (pid > 0) |
4529 | (void) kill(pid, SIGKILL9); |
4530 | |
4531 | /* Try to flush whatever is still queued in the pty */ |
4532 | if (master >= 0) { |
4533 | (void) copy_bytes(master, STDOUT_FILENO1, (uint64_t) -1, 0); |
4534 | master = safe_close(master); |
4535 | } |
4536 | |
4537 | if (pid > 0) |
4538 | (void) wait_for_terminate(pid, NULL((void*)0)); |
4539 | |
4540 | pager_close(); |
4541 | |
4542 | if (remove_directory && arg_directory) { |
4543 | int k; |
4544 | |
4545 | k = rm_rf(arg_directory, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME); |
4546 | if (k < 0) |
4547 | log_warning_errno(k, "Cannot remove '%s', ignoring: %m", arg_directory)({ int _level = ((4)), _e = ((k)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/nspawn/nspawn.c", 4547, __func__, "Cannot remove '%s', ignoring: %m" , arg_directory) : -abs(_e); }); |
4548 | } |
4549 | |
4550 | if (remove_image && arg_image) { |
4551 | if (unlink(arg_image) < 0) |
4552 | log_warning_errno(errno, "Can't remove image file '%s', ignoring: %m", arg_image)({ int _level = ((4)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/nspawn/nspawn.c", 4552, __func__ , "Can't remove image file '%s', ignoring: %m", arg_image) : - abs(_e); }); |
4553 | } |
4554 | |
4555 | if (remove_tmprootdir) { |
4556 | if (rmdir(tmprootdir) < 0) |
4557 | log_debug_errno(errno, "Can't remove temporary root directory '%s', ignoring: %m", tmprootdir)({ int _level = ((7)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/nspawn/nspawn.c", 4557, __func__ , "Can't remove temporary root directory '%s', ignoring: %m", tmprootdir) : -abs(_e); }); |
4558 | } |
4559 | |
4560 | if (arg_machine) { |
4561 | const char *p; |
4562 | |
4563 | p = strjoina("/run/systemd/nspawn/propagate/", arg_machine)({ const char *_appendees_[] = { "/run/systemd/nspawn/propagate/" , arg_machine }; char *_d_, *_p_; size_t _len_ = 0; size_t _i_ ; for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr ( !__builtin_types_compatible_p(typeof(_appendees_), typeof(& *(_appendees_))), sizeof(_appendees_)/sizeof((_appendees_)[0] ), ((void)0))) && _appendees_[_i_]; _i_++) _len_ += strlen (_appendees_[_i_]); _p_ = _d_ = __builtin_alloca (_len_ + 1); for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p(typeof(_appendees_), typeof(& *(_appendees_))), sizeof(_appendees_)/sizeof((_appendees_)[0] ), ((void)0))) && _appendees_[_i_]; _i_++) _p_ = stpcpy (_p_, _appendees_[_i_]); *_p_ = 0; _d_; }); |
4564 | (void) rm_rf(p, REMOVE_ROOT); |
4565 | } |
4566 | |
4567 | expose_port_flush(arg_expose_ports, &exposed); |
4568 | |
4569 | if (veth_created) |
4570 | (void) remove_veth_links(veth_name, arg_network_veth_extra); |
4571 | (void) remove_bridge(arg_network_zone); |
4572 | |
4573 | free(arg_directory); |
4574 | free(arg_template); |
4575 | free(arg_image); |
4576 | free(arg_machine); |
4577 | free(arg_hostname); |
4578 | free(arg_user); |
4579 | free(arg_pivot_root_new); |
4580 | free(arg_pivot_root_old); |
4581 | free(arg_chdir); |
4582 | strv_free(arg_setenv); |
4583 | free(arg_network_bridge); |
4584 | strv_free(arg_network_interfaces); |
4585 | strv_free(arg_network_macvlan); |
4586 | strv_free(arg_network_ipvlan); |
4587 | strv_free(arg_network_veth_extra); |
4588 | strv_free(arg_parameters); |
4589 | free(arg_network_zone); |
4590 | free(arg_network_namespace_path); |
4591 | strv_free(arg_property); |
4592 | custom_mount_free_all(arg_custom_mounts, arg_n_custom_mounts); |
4593 | expose_port_free_all(arg_expose_ports); |
4594 | free(arg_root_hash); |
4595 | rlimit_free_all(arg_rlimit); |
4596 | strv_free(arg_syscall_whitelist); |
4597 | strv_free(arg_syscall_blacklist); |
4598 | cpu_set_reset(&arg_cpu_set); |
4599 | |
4600 | return r < 0 ? EXIT_FAILURE1 : ret; |
4601 | } |