aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPřemysl Janouch <p.janouch@gmail.com>2016-01-16 22:16:25 +0100
committerPřemysl Janouch <p.janouch@gmail.com>2016-01-16 22:33:57 +0100
commita95867dbeec78ccd3e377f3cc96a72741d4c12e8 (patch)
tree25aae883a7c2312d373298e13123e3545151f5ec
parent5298d802bb728185855f76afd3d19fde0dd0cf53 (diff)
downloadjson-rpc-shell-a95867dbeec78ccd3e377f3cc96a72741d4c12e8.tar.gz
json-rpc-shell-a95867dbeec78ccd3e377f3cc96a72741d4c12e8.tar.xz
json-rpc-shell-a95867dbeec78ccd3e377f3cc96a72741d4c12e8.zip
Fix daemonization
-rw-r--r--demo-json-rpc-server.c73
1 files changed, 56 insertions, 17 deletions
diff --git a/demo-json-rpc-server.c b/demo-json-rpc-server.c
index 2e0b104..483f701 100644
--- a/demo-json-rpc-server.c
+++ b/demo-json-rpc-server.c
@@ -44,9 +44,7 @@
#include "http-parser/http_parser.h"
-// --- Extensions to liberty ---------------------------------------------------
-
-// Currently in sync, nothing to be moved.
+enum { PIPE_READ, PIPE_WRITE };
// --- libev helpers -----------------------------------------------------------
@@ -2430,21 +2428,21 @@ setup_listen_fds (struct server_context *ctx, struct error **e)
return true;
}
-static bool
-lock_pid_file (struct server_context *ctx, struct error **e)
+static int
+lock_pid_file (const char *path, struct error **e)
{
- const char *path = str_map_find (&ctx->config, "pid_file");
- if (!path)
- return true;
-
+ // When using XDG_RUNTIME_DIR, the file needs to either have its
+ // access time bumped every 6 hours, or have the sticky bit set
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)
{
error_set (e, "can't open `%s': %s", path, strerror (errno));
- return false;
+ return -1;
}
+ set_cloexec (fd);
+
struct flock lock =
{
.l_type = F_WRLCK,
@@ -2455,7 +2453,8 @@ lock_pid_file (struct server_context *ctx, struct error **e)
if (fcntl (fd, F_SETLK, &lock))
{
error_set (e, "can't lock `%s': %s", path, strerror (errno));
- return false;
+ xclose (fd);
+ return -1;
}
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)
{
error_set (e, "can't write to `%s': %s", path, strerror (errno));
- return false;
+ xclose (fd);
+ return -1;
}
str_free (&pid);
// Intentionally not closing the file descriptor; it must stay alive
// for the entire life of the application
- return true;
+ 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;
+
+ char *resolved = resolve_filename (path, resolve_relative_runtime_filename);
+ bool result = lock_pid_file (resolved, e) != -1;
+ free (resolved);
+ return result;
}
// --- Tests -------------------------------------------------------------------
@@ -2517,18 +2530,34 @@ on_termination_signal (EV_P_ ev_signal *handle, int revents)
}
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);
@@ -2541,6 +2570,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 (!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;
// there is no real guarantee that we will start with all three
// 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);
if (!parse_config (&ctx, &e)
- || !lock_pid_file (&ctx, &e)
|| !setup_listen_fds (&ctx, &e))
{
print_error ("%s", e->message);
@@ -2652,7 +2689,9 @@ main (int argc, char *argv[])
}
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_loop_destroy (loop);