#include "mount-setup.h"
#include "parse-util.h"
#include "process-util.h"
+#include "signal-util.h"
#include "socket-util.h"
#include "stdio-util.h"
#include "string-util.h"
# define ELOGIND_PID_FILE "/run/elogind.pid"
#endif // ELOGIND_PID_FILE
+
+static int elogind_signal_handler(sd_event_source *s,
+ const struct signalfd_siginfo *si,
+ void *userdata) {
+ Manager *m = userdata;
+ int r;
+
+ log_warning("Received signal %u [%s]", si->ssi_signo,
+ signal_to_string(si->ssi_signo));
+
+ r = sd_event_get_state(m->event);
+
+ if (r != SD_EVENT_FINISHED)
+ sd_event_exit(m->event, si->ssi_signo);
+
+ return 0;
+}
+
+
static void remove_pid_file(void) {
if (access(ELOGIND_PID_FILE, F_OK) == 0)
unlink_noerrno(ELOGIND_PID_FILE);
pid_t SID;
int r;
- child = fork();
+#if ENABLE_DEBUG_ELOGIND
+ log_notice("Double forking elogind");
+ log_notice("Parent PID : %5d", getpid_cached());
+ log_notice("Parent SID : %5d", getsid(getpid_cached()));
+#endif // ENABLE_DEBUG_ELOGIND
- if (child < 0)
- return log_error_errno(errno, "Failed to fork: %m");
+ r = safe_fork_full("elogind-forker", NULL, 0, FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_CLOSE_ALL_FDS|FORK_NULL_STDIO|FORK_WAIT, &child);
- if (child) {
- /* Wait for the child to terminate, so the decoupling
- * is guaranteed to succeed.
- */
- r = wait_for_terminate_and_warn("elogind control child", child, true);
- if (r < 0)
- return r;
+ if (r < 0)
+ return log_error_errno(errno, "Failed to fork daemon leader: %m");
+
+ /* safe_fork_full() Has waited for the child to terminate, so we
+ * are safe to return here. The child already has forked off the
+ * daemon itself.
+ */
+ if (r)
return child;
- }
- /* The first child has to become a new session leader. */
- close_all_fds(NULL, 0);
+#if ENABLE_DEBUG_ELOGIND
+ log_notice("Child PID : %5d", getpid_cached());
+ log_notice("Child SID : %5d", getsid(getpid_cached()));
+#endif // ENABLE_DEBUG_ELOGIND
+
SID = setsid();
if ((pid_t)-1 == SID)
return log_error_errno(errno, "Failed to create new SID: %m");
+
+#if ENABLE_DEBUG_ELOGIND
+ log_notice("Child new SID : %5d", getsid(getpid_cached()));
+#endif // ENABLE_DEBUG_ELOGIND
+
umask(0022);
/* Now the grandchild, the true daemon, can be created. */
- grandchild = fork();
+ r = safe_fork_full("elogind-daemon", NULL, 0, FORK_REOPEN_LOG, &grandchild);
- if (grandchild < 0)
- return log_error_errno(errno, "Failed to double fork: %m");
+ if (r < 0)
+ return log_error_errno(errno, "Failed to fork daemon: %m");
- if (grandchild)
+ if (r)
/* Exit immediately! */
return grandchild;
- close_all_fds(NULL, 0);
umask(0022);
+#if ENABLE_DEBUG_ELOGIND
+ log_notice("Grand child PID: %5d", getpid_cached());
+ log_notice("Grand child SID: %5d", getsid(getpid_cached()));
+#endif // ENABLE_DEBUG_ELOGIND
+
/* Take care of our PID-file now */
write_pid_file();
/// Simple tool to see, if elogind is already running
-static pid_t elogind_is_already_running(void) {
+static pid_t elogind_is_already_running(bool need_pid_file) {
_cleanup_free_ char *s = NULL;
pid_t pid;
int r;
/* Take care of our PID-file now.
If the user is going to fork elogind, the PID file
will be overwritten. */
- write_pid_file();
+ if (need_pid_file)
+ write_pid_file();
return 0;
}
* to it. The system instance hence listens on this special socket, but the user instances listen on the system
* bus for these messages. */
- if (m->test_run)
+ if (m->test_run_flags)
return 0;
if (!MANAGER_IS_SYSTEM(m))
} else if (argc > 2)
wrong_arg = true;
+ /* Note: At this point, the logging is not initialized, so we can not
+ use log_debug_elogind(). */
+#if ENABLE_DEBUG_ELOGIND
+ log_notice("elogind startup: Daemonize: %s, Show Help: %s, Wrong arg: %s",
+ daemonize ? "True" : "False",
+ show_help ? "True" : "False",
+ wrong_arg ? "True" : "False");
+#endif // ENABLE_DEBUG_ELOGIND
+
/* try to get some meaningful output in case of an error */
if (wrong_arg) {
- fprintf(stderr, "ERROR: Unknown arguments\n");
+ log_error("Unknown arguments");
show_help = true;
r = -EINVAL;
}
if (show_help) {
- fprintf(stderr, "%s [<-D|--daemon>|<-h|--help>]\n", argv[0]);
+ log_info("%s [<-D|--daemon>|<-h|--help>]", basename(argv[0]));
return r;
}
/* Do not continue if elogind is already running */
- pid = elogind_is_already_running();
+ pid = elogind_is_already_running(!daemonize);
if (pid) {
- fprintf(stderr, "elogind is already running:" PID_FMT "\n", pid);
+ log_error("elogind is already running as PID " PID_FMT, pid);
return pid;
}
m->cgroups_agent_fd = -1;
m->pin_cgroupfs_fd = -1;
- m->test_run = false;
+ m->test_run_flags = 0;
/* Init sleep modes and states */
- m->suspend_mode = NULL;
- m->suspend_state = NULL;
- m->hibernate_mode = NULL;
- m->hibernate_state = NULL;
- m->hybrid_sleep_mode = NULL;
- m->hybrid_sleep_state = NULL;
+ m->suspend_mode = NULL;
+ m->suspend_state = NULL;
+ m->hibernate_mode = NULL;
+ m->hibernate_state = NULL;
+ m->hybrid_sleep_mode = NULL;
+ m->hybrid_sleep_state = NULL;
+ m->hibernate_delay_sec = 0;
/* If elogind should be its own controller, mount its cgroup */
if (streq(SYSTEMD_CGROUP_CONTROLLER, "_elogind")) {
/// Add-On for manager_reset_config()
void elogind_manager_reset_config(Manager* m) {
-#ifdef ENABLE_DEBUG_ELOGIND
+#if ENABLE_DEBUG_ELOGIND
int dbg_cnt;
#endif // ENABLE_DEBUG_ELOGIND
m->hybrid_sleep_mode = strv_new("suspend", "platform", "shutdown", NULL);
if (!m->hybrid_sleep_state)
m->hybrid_sleep_state = strv_new("disk", NULL);
+ if (!m->hibernate_delay_sec)
+ m->hibernate_delay_sec = 180 * USEC_PER_MINUTE;
-#ifdef ENABLE_DEBUG_ELOGIND
+#if ENABLE_DEBUG_ELOGIND
dbg_cnt = -1;
while (m->suspend_mode && m->suspend_mode[++dbg_cnt])
log_debug_elogind("suspend_mode[%d] = %s",
while (m->hybrid_sleep_state[++dbg_cnt])
log_debug_elogind("hybrid_sleep_state[%d] = %s",
dbg_cnt, m->hybrid_sleep_state[dbg_cnt]);
+ log_debug_elogind("hibernate_delay_sec: %ul seconds (%ul minutes)",
+ m->hibernate_delay_sec / USEC_PER_SEC,
+ m->hibernate_delay_sec / USEC_PER_MINUTE);
#endif // ENABLE_DEBUG_ELOGIND
}
+
+
+/// Add-On for manager_startup()
+int elogind_manager_startup(Manager *m) {
+ int r;
+
+ assert(m);
+
+ assert_se(sigprocmask_many(SIG_SETMASK, NULL, SIGINT, -1) >= 0);
+ r = sd_event_add_signal(m->event, NULL, SIGINT, elogind_signal_handler, m);
+ if (r < 0)
+ return log_error_errno(r, "Failed to register SIGINT handler: %m");
+
+ assert_se(sigprocmask_many(SIG_SETMASK, NULL, SIGQUIT, -1) >= 0);
+ r = sd_event_add_signal(m->event, NULL, SIGQUIT, elogind_signal_handler, m);
+ if (r < 0)
+ return log_error_errno(r, "Failed to register SIGQUIT handler: %m");
+
+ assert_se(sigprocmask_many(SIG_SETMASK, NULL, SIGTERM, -1) >= 0);
+ r = sd_event_add_signal(m->event, NULL, SIGTERM, elogind_signal_handler, m);
+ if (r < 0)
+ return log_error_errno(r, "Failed to register SIGTERM handler: %m");
+
+ return 0;
+}