Fix daemonization
This commit is contained in:
parent
5298d802bb
commit
a95867dbee
|
@ -44,9 +44,7 @@
|
||||||
|
|
||||||
#include "http-parser/http_parser.h"
|
#include "http-parser/http_parser.h"
|
||||||
|
|
||||||
// --- Extensions to liberty ---------------------------------------------------
|
enum { PIPE_READ, PIPE_WRITE };
|
||||||
|
|
||||||
// Currently in sync, nothing to be moved.
|
|
||||||
|
|
||||||
// --- libev helpers -----------------------------------------------------------
|
// --- libev helpers -----------------------------------------------------------
|
||||||
|
|
||||||
|
@ -2430,21 +2428,21 @@ setup_listen_fds (struct server_context *ctx, struct error **e)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static int
|
||||||
lock_pid_file (struct server_context *ctx, struct error **e)
|
lock_pid_file (const char *path, struct error **e)
|
||||||
{
|
{
|
||||||
const char *path = str_map_find (&ctx->config, "pid_file");
|
// When using XDG_RUNTIME_DIR, the file needs to either have its
|
||||||
if (!path)
|
// access time bumped every 6 hours, or have the sticky bit set
|
||||||
return true;
|
|
||||||
|
|
||||||
int fd = open (path, O_RDWR | O_CREAT,
|
int fd = open (path, O_RDWR | O_CREAT,
|
||||||
S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH /* 644 */);
|
S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH /* 644 */ | S_ISVTX /* sticky */);
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
{
|
{
|
||||||
error_set (e, "can't open `%s': %s", path, strerror (errno));
|
error_set (e, "can't open `%s': %s", path, strerror (errno));
|
||||||
return false;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
set_cloexec (fd);
|
||||||
|
|
||||||
struct flock lock =
|
struct flock lock =
|
||||||
{
|
{
|
||||||
.l_type = F_WRLCK,
|
.l_type = F_WRLCK,
|
||||||
|
@ -2455,7 +2453,8 @@ lock_pid_file (struct server_context *ctx, struct error **e)
|
||||||
if (fcntl (fd, F_SETLK, &lock))
|
if (fcntl (fd, F_SETLK, &lock))
|
||||||
{
|
{
|
||||||
error_set (e, "can't lock `%s': %s", path, strerror (errno));
|
error_set (e, "can't lock `%s': %s", path, strerror (errno));
|
||||||
return false;
|
xclose (fd);
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct str pid;
|
struct str pid;
|
||||||
|
@ -2466,13 +2465,27 @@ lock_pid_file (struct server_context *ctx, struct error **e)
|
||||||
|| write (fd, pid.str, pid.len) != (ssize_t) pid.len)
|
|| write (fd, pid.str, pid.len) != (ssize_t) pid.len)
|
||||||
{
|
{
|
||||||
error_set (e, "can't write to `%s': %s", path, strerror (errno));
|
error_set (e, "can't write to `%s': %s", path, strerror (errno));
|
||||||
return false;
|
xclose (fd);
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
str_free (&pid);
|
str_free (&pid);
|
||||||
|
|
||||||
// Intentionally not closing the file descriptor; it must stay alive
|
// Intentionally not closing the file descriptor; it must stay alive
|
||||||
// for the entire life of the application
|
// for the entire life of the application
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
app_lock_pid_file (struct server_context *ctx, struct error **e)
|
||||||
|
{
|
||||||
|
const char *path = str_map_find (&ctx->config, "pid_file");
|
||||||
|
if (!path)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
char *resolved = resolve_filename (path, resolve_relative_runtime_filename);
|
||||||
|
bool result = lock_pid_file (resolved, e) != -1;
|
||||||
|
free (resolved);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Tests -------------------------------------------------------------------
|
// --- Tests -------------------------------------------------------------------
|
||||||
|
@ -2517,18 +2530,34 @@ on_termination_signal (EV_P_ ev_signal *handle, int revents)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
daemonize (void)
|
daemonize (struct server_context *ctx)
|
||||||
{
|
{
|
||||||
print_status ("daemonizing...");
|
print_status ("daemonizing...");
|
||||||
|
|
||||||
if (chdir ("/"))
|
if (chdir ("/"))
|
||||||
exit_fatal ("%s: %s", "chdir", strerror (errno));
|
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;
|
pid_t pid;
|
||||||
if ((pid = fork ()) < 0)
|
if ((pid = fork ()) < 0)
|
||||||
exit_fatal ("%s: %s", "fork", strerror (errno));
|
exit_fatal ("%s: %s", "fork", strerror (errno));
|
||||||
else if (pid)
|
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);
|
exit (EXIT_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
setsid ();
|
setsid ();
|
||||||
signal (SIGHUP, SIG_IGN);
|
signal (SIGHUP, SIG_IGN);
|
||||||
|
@ -2541,6 +2570,15 @@ daemonize (void)
|
||||||
openlog (PROGRAM_NAME, LOG_NDELAY | LOG_NOWAIT | LOG_PID, 0);
|
openlog (PROGRAM_NAME, LOG_NDELAY | LOG_NOWAIT | LOG_PID, 0);
|
||||||
g_log_message_real = log_message_syslog;
|
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 (!app_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;
|
// XXX: we may close our own descriptors this way, crippling ourselves;
|
||||||
// there is no real guarantee that we will start with all three
|
// there is no real guarantee that we will start with all three
|
||||||
// descriptors open. In theory we could try to enumerate the descriptors
|
// descriptors open. In theory we could try to enumerate the descriptors
|
||||||
|
@ -2643,7 +2681,6 @@ main (int argc, char *argv[])
|
||||||
LIST_PREPEND (ctx.handlers, &g_request_handler_json_rpc);
|
LIST_PREPEND (ctx.handlers, &g_request_handler_json_rpc);
|
||||||
|
|
||||||
if (!parse_config (&ctx, &e)
|
if (!parse_config (&ctx, &e)
|
||||||
|| !lock_pid_file (&ctx, &e)
|
|
||||||
|| !setup_listen_fds (&ctx, &e))
|
|| !setup_listen_fds (&ctx, &e))
|
||||||
{
|
{
|
||||||
print_error ("%s", e->message);
|
print_error ("%s", e->message);
|
||||||
|
@ -2652,7 +2689,9 @@ main (int argc, char *argv[])
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!g_debug_mode)
|
if (!g_debug_mode)
|
||||||
daemonize ();
|
daemonize (&ctx);
|
||||||
|
else if (!app_lock_pid_file (&ctx, &e))
|
||||||
|
exit_fatal ("%s", e->message);
|
||||||
|
|
||||||
ev_run (loop, 0);
|
ev_run (loop, 0);
|
||||||
ev_loop_destroy (loop);
|
ev_loop_destroy (loop);
|
||||||
|
|
Loading…
Reference in New Issue