diff --git a/kike.c b/kike.c index 768126b..b4f4434 100644 --- a/kike.c +++ b/kike.c @@ -25,6 +25,8 @@ #include "kike-replies.c" #include +enum { PIPE_READ, PIPE_WRITE }; + // FIXME: don't use time_t to compute time deltas // --- Configuration (application-specific) ------------------------------------ @@ -3838,18 +3840,34 @@ on_signal_pipe_readable (const struct pollfd *fd, struct server_context *ctx) } static void -daemonize (void) +daemonize (struct server_context *ctx) { print_status ("daemonizing..."); if (chdir ("/")) exit_fatal ("%s: %s", "chdir", strerror (errno)); + // Because of systemd, we need to exit the parent process _after_ writing + // a PID file, otherwise our grandchild would receive a SIGTERM + int sync_pipe[2]; + if (pipe (sync_pipe)) + exit_fatal ("%s: %s", "pipe", strerror (errno)); + pid_t pid; if ((pid = fork ()) < 0) exit_fatal ("%s: %s", "fork", strerror (errno)); else if (pid) + { + // Wait until all write ends of the pipe are closed, which can mean + // either success or failure, we don't need to care + xclose (sync_pipe[PIPE_WRITE]); + + char dummy; + if (read (sync_pipe[PIPE_READ], &dummy, 1) < 0) + exit_fatal ("%s: %s", "read", strerror (errno)); + exit (EXIT_SUCCESS); + } setsid (); signal (SIGHUP, SIG_IGN); @@ -3862,6 +3880,15 @@ daemonize (void) openlog (PROGRAM_NAME, LOG_NDELAY | LOG_NOWAIT | LOG_PID, 0); g_log_message_real = log_message_syslog; + // Write the PID file (if so configured) and get rid of the pipe, so that + // the read() in our grandparent finally returns zero (no write ends) + struct error *e = NULL; + if (!irc_lock_pid_file (ctx, &e)) + exit_fatal ("%s", e->message); + + xclose (sync_pipe[PIPE_READ]); + xclose (sync_pipe[PIPE_WRITE]); + // XXX: we may close our own descriptors this way, crippling ourselves; // there is no real guarantee that we will start with all three // descriptors open. In theory we could try to enumerate the descriptors @@ -3948,16 +3975,13 @@ main (int argc, char *argv[]) || !irc_initialize_motd (&ctx, &e) || !irc_initialize_catalog (&ctx, &e) || !irc_parse_config (&ctx, &e) - || !irc_lock_pid_file (&ctx, &e) || !irc_setup_listen_fds (&ctx, &e)) - { - print_error ("%s", e->message); - error_free (e); - exit (EXIT_FAILURE); - } + exit_fatal ("%s", e->message); if (!g_debug_mode) - daemonize (); + daemonize (&ctx); + else if (!irc_lock_pid_file (&ctx, &e)) + exit_fatal ("%s", e->message); ctx.polling = true; while (ctx.polling)