* the init process in the container pid can send messages to nspawn following the sd_notify(3) protocol */
#define NSPAWN_NOTIFY_SOCKET_PATH "/run/systemd/nspawn/notify"
+#define EXIT_FORCE_RESTART 133
+
typedef enum ContainerStatus {
CONTAINER_TERMINATED,
CONTAINER_REBOOTED
static bool arg_notify_ready = false;
static bool arg_use_cgns = true;
static unsigned long arg_clone_ns_flags = CLONE_NEWIPC|CLONE_NEWPID|CLONE_NEWUTS;
+ static MountSettingsMask arg_mount_settings = MOUNT_APPLY_APIVFS_RO;
static void help(void) {
printf("%s [OPTIONS...] [PATH] [ARGUMENTS...]\n\n"
arg_clone_ns_flags = (arg_clone_ns_flags & ~ns_flag) | (r > 0 ? 0 : ns_flag);
}
+ static void parse_mount_settings_env(void) {
+ int r;
+ const char *e;
+
+ e = getenv("SYSTEMD_NSPAWN_API_VFS_WRITABLE");
+ if (!e)
+ return;
+
+ if (streq(e, "network")) {
+ arg_mount_settings |= MOUNT_APPLY_APIVFS_RO|MOUNT_APPLY_APIVFS_NETNS;
+ return;
+ }
+
+ r = parse_boolean(e);
+ if (r < 0) {
+ log_warning_errno(r, "Failed to parse SYSTEMD_NSPAWN_API_VFS_WRITABLE from environment, ignoring.");
+ return;
+ } else if (r > 0)
+ arg_mount_settings &= ~MOUNT_APPLY_APIVFS_RO;
+ else
+ arg_mount_settings |= MOUNT_APPLY_APIVFS_RO;
+
+ arg_mount_settings &= ~MOUNT_APPLY_APIVFS_NETNS;
+ }
+
static int parse_argv(int argc, char *argv[]) {
enum {
parse_share_ns_env("SYSTEMD_NSPAWN_SHARE_NS_UTS", CLONE_NEWUTS);
parse_share_ns_env("SYSTEMD_NSPAWN_SHARE_SYSTEM", CLONE_NEWIPC|CLONE_NEWPID|CLONE_NEWUTS);
+ if (arg_userns_mode != USER_NAMESPACE_NO)
+ arg_mount_settings |= MOUNT_USE_USERNS;
+
+ if (arg_private_network)
+ arg_mount_settings |= MOUNT_APPLY_APIVFS_NETNS;
+
+ parse_mount_settings_env();
+
if (!(arg_clone_ns_flags & CLONE_NEWPID) ||
!(arg_clone_ns_flags & CLONE_NEWUTS)) {
arg_register = false;
}
static int verify_arguments(void) {
+ if (arg_userns_mode != USER_NAMESPACE_NO && (arg_mount_settings & MOUNT_APPLY_APIVFS_NETNS) && !arg_private_network) {
+ log_error("Invalid namespacing settings. Mounting sysfs with --private-users requires --private-network.");
+ return -EINVAL;
+ }
+
+ if (arg_userns_mode != USER_NAMESPACE_NO && !(arg_mount_settings & MOUNT_APPLY_APIVFS_RO)) {
+ log_error("Cannot combine --private-users with read-write mounts.");
+ return -EINVAL;
+ }
if (arg_volatile_mode != VOLATILE_NO && arg_read_only) {
log_error("Cannot combine --read-only with --volatile. Note that --volatile already implies a read-only base hierarchy.");
return log_error_errno(r, "Couldn't become new root: %m");
r = mount_all(NULL,
- arg_userns_mode != USER_NAMESPACE_NO,
- true,
- arg_private_network,
+ arg_mount_settings | MOUNT_IN_USERNS,
arg_uid_shift,
arg_uid_range,
arg_selinux_apifs_context);
if (r < 0)
return r;
- r = mount_sysfs(NULL);
+ r = mount_sysfs(NULL, arg_mount_settings);
if (r < 0)
return r;
}
r = mount_all(directory,
- arg_userns_mode != USER_NAMESPACE_NO,
- false,
- arg_private_network,
+ arg_mount_settings,
arg_uid_shift,
arg_uid_range,
arg_selinux_apifs_context);
* because 133 is special-cased in the service file to reboot the container.
* otherwise → The container exited with zero status and a reboot was not requested.
*/
- if (r == 133)
+ if (r == EXIT_FORCE_RESTART)
r = EXIT_FAILURE; /* replace 133 with the general failure code */
*ret = r;
return 0; /* finito */
* file uses RestartForceExitStatus=133 so that this results in a full
* nspawn restart. This is necessary since we might have cgroup parameters
* set we want to have flushed out. */
- *ret = 0;
- return 133;
+ *ret = EXIT_FORCE_RESTART;
+ return 0; /* finito */
}
expose_port_flush(arg_expose_ports, exposed);
finish:
sd_notify(false,
- "STOPPING=1\n"
- "STATUS=Terminating...");
+ r == 0 && ret == EXIT_FORCE_RESTART ? "STOPPING=1\nSTATUS=Restarting..." :
+ "STOPPING=1\nSTATUS=Terminating...");
if (pid > 0)
kill(pid, SIGKILL);