#include "copy.h"
#include "base-filesystem.h"
#include "barrier.h"
+#include "event-util.h"
#ifdef HAVE_SECCOMP
#include "seccomp-util.h"
* and char devices. */
if (S_ISDIR(source_st.st_mode)) {
r = mkdir_label(where, 0755);
- if (r < 0) {
+ if (r < 0 && errno != EEXIST) {
log_error("Failed to create mount point %s: %s", where, strerror(-r));
return r;
if (arg_share_system)
return 0;
- if (sethostname(arg_machine, strlen(arg_machine)) < 0)
+ if (sethostname_idempotent(arg_machine) < 0)
return -errno;
return 0;
* container argument.
* > 0 : The program executed in the container terminated with an
* error. The exit code of the program executed in the
- * container is returned. No change is made to the container
- * argument.
+ * container is returned. The container argument has been set
+ * to CONTAINER_TERMINATED.
* 0 : The container is being rebooted, has been shut down or exited
* successfully. The container argument has been set to either
* CONTAINER_TERMINATED or CONTAINER_REBOOTED.
* error is indicated by a non-zero value.
*/
static int wait_for_container(pid_t pid, ContainerStatus *container) {
- int r;
siginfo_t status;
+ int r;
r = wait_for_terminate(pid, &status);
if (r < 0) {
}
switch (status.si_code) {
+
case CLD_EXITED:
- r = status.si_status;
- if (r == 0) {
- if (!arg_quiet)
- log_debug("Container %s exited successfully.",
- arg_machine);
+ if (status.si_status == 0) {
+ log_full(arg_quiet ? LOG_DEBUG : LOG_INFO, "Container %s exited successfully.", arg_machine);
- *container = CONTAINER_TERMINATED;
- } else {
- log_error("Container %s failed with error code %i.",
- arg_machine, status.si_status);
- }
- break;
+ } else
+ log_full(arg_quiet ? LOG_DEBUG : LOG_INFO, "Container %s failed with error code %i.", arg_machine, status.si_status);
+
+ *container = CONTAINER_TERMINATED;
+ return status.si_status;
case CLD_KILLED:
if (status.si_status == SIGINT) {
- if (!arg_quiet)
- log_info("Container %s has been shut down.",
- arg_machine);
+ log_full(arg_quiet ? LOG_DEBUG : LOG_INFO, "Container %s has been shut down.", arg_machine);
*container = CONTAINER_TERMINATED;
- r = 0;
- break;
+ return 0;
+
} else if (status.si_status == SIGHUP) {
- if (!arg_quiet)
- log_info("Container %s is being rebooted.",
- arg_machine);
+ log_full(arg_quiet ? LOG_DEBUG : LOG_INFO, "Container %s is being rebooted.", arg_machine);
*container = CONTAINER_REBOOTED;
- r = 0;
- break;
+ return 0;
}
+
/* CLD_KILLED fallthrough */
case CLD_DUMPED:
- log_error("Container %s terminated by signal %s.",
- arg_machine, signal_to_string(status.si_status));
- r = -1;
- break;
+ log_error("Container %s terminated by signal %s.", arg_machine, signal_to_string(status.si_status));
+ return -EIO;
default:
- log_error("Container %s failed due to unknown reason.",
- arg_machine);
- r = -1;
- break;
+ log_error("Container %s failed due to unknown reason.", arg_machine);
+ return -EIO;
}
return r;
static void nop_handler(int sig) {}
+static int on_orderly_shutdown(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
+ pid_t pid;
+
+ pid = PTR_TO_UINT32(userdata);
+ if (pid > 0) {
+ if (kill(pid, SIGRTMIN+3) >= 0) {
+ log_info("Trying to halt container. Send SIGTERM again to trigger immediate termination.");
+ sd_event_source_set_userdata(s, NULL);
+ return 0;
+ }
+ }
+
+ sd_event_exit(sd_event_source_get_event(s), 0);
+ return 0;
+}
+
int main(int argc, char *argv[]) {
_cleanup_free_ char *kdbus_domain = NULL, *device_path = NULL, *root_device = NULL, *home_device = NULL, *srv_device = NULL;
"STATUS=Container running.");
assert_se(sigemptyset(&mask) == 0);
- assert_se(sigemptyset(&mask_chld) == 0);
- sigaddset(&mask_chld, SIGCHLD);
sigset_add_many(&mask, SIGCHLD, SIGWINCH, SIGTERM, SIGINT, -1);
assert_se(sigprocmask(SIG_BLOCK, &mask, NULL) == 0);
+ assert_se(sigemptyset(&mask_chld) == 0);
+ assert_se(sigaddset(&mask_chld, SIGCHLD) == 0);
+
for (;;) {
ContainerStatus container_status;
_cleanup_(barrier_destroy) Barrier barrier = BARRIER_NULL;
/* wait for child-setup to be done */
if (barrier_place_and_sync(&barrier)) {
+ _cleanup_event_unref_ sd_event *event = NULL;
+ _cleanup_(pty_forward_freep) PTYForward *forward = NULL;
int ifi = 0;
r = move_network_interfaces(pid);
* control to the code to run inside the container. */
barrier_place(&barrier);
- k = process_pty(master, &mask, arg_boot ? pid : 0, SIGRTMIN+3);
- if (k < 0) {
- r = EXIT_FAILURE;
- break;
+ r = sd_event_new(&event);
+ if (r < 0) {
+ log_error("Failed to get default event source: %s", strerror(-r));
+ goto finish;
}
+ if (arg_boot) {
+ /* Try to kill the init system on SIGINT or SIGTERM */
+ sd_event_add_signal(event, NULL, SIGINT, on_orderly_shutdown, UINT32_TO_PTR(pid));
+ sd_event_add_signal(event, NULL, SIGTERM, on_orderly_shutdown, UINT32_TO_PTR(pid));
+ } else {
+ /* Immediately exit */
+ sd_event_add_signal(event, NULL, SIGINT, NULL, NULL);
+ sd_event_add_signal(event, NULL, SIGTERM, NULL, NULL);
+ }
+
+ /* simply exit on sigchld */
+ sd_event_add_signal(event, NULL, SIGCHLD, NULL, NULL);
+
+ r = pty_forward_new(event, master, &forward);
+ if (r < 0) {
+ log_error("Failed to create PTY forwarder: %s", strerror(-r));
+ goto finish;
+ }
+
+ r = sd_event_loop(event);
+ if (r < 0) {
+ log_error("Failed to run event loop: %s", strerror(-r));
+ return r;
+ }
+
+ forward = pty_forward_free(forward);
+
if (!arg_quiet)
putc('\n', stdout);