+/*
+ * Return values:
+ * < 0 : wait_for_terminate() failed to get the state of the
+ * container, the container was terminated by a signal, or
+ * failed for an unknown reason. No change is made to the
+ * 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. 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.
+ *
+ * That is, success is indicated by a return value of zero, and an
+ * error is indicated by a non-zero value.
+ */
+static int wait_for_container(pid_t pid, ContainerStatus *container) {
+ siginfo_t status;
+ int r;
+
+ r = wait_for_terminate(pid, &status);
+ if (r < 0)
+ return log_warning_errno(r, "Failed to wait for container: %m");
+
+ switch (status.si_code) {
+
+ case CLD_EXITED:
+ if (status.si_status == 0) {
+ log_full(arg_quiet ? LOG_DEBUG : LOG_INFO, "Container %s exited successfully.", arg_machine);
+
+ } 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) {
+
+ log_full(arg_quiet ? LOG_DEBUG : LOG_INFO, "Container %s has been shut down.", arg_machine);
+ *container = CONTAINER_TERMINATED;
+ return 0;
+
+ } else if (status.si_status == SIGHUP) {
+
+ log_full(arg_quiet ? LOG_DEBUG : LOG_INFO, "Container %s is being rebooted.", arg_machine);
+ *container = CONTAINER_REBOOTED;
+ return 0;
+ }
+
+ /* CLD_KILLED fallthrough */
+
+ case CLD_DUMPED:
+ 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);
+ 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;
+}
+