summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--kike.c62
1 files changed, 60 insertions, 2 deletions
diff --git a/kike.c b/kike.c
index 5edf9e9..cfa535b 100644
--- a/kike.c
+++ b/kike.c
@@ -31,6 +31,16 @@
static struct config_item g_config_table[] =
{
+ // TODO: expand ~[blah] in resolve_config_filename()
+ // TODO: expand the path at least? Use XDG_RUNTIME_DIR if relative.
+ // The last fallback is: "$XDG_DATA_HOME defines the base directory
+ // relative to which user specific data files should be stored.
+ // If $XDG_DATA_HOME is either not set or empty, a default equal to
+ // $HOME/.local/share should be used."
+ //
+ // Note that when using XDG_RUNTIME_DIR, it either needs to have access
+ // time bumped every 6 hours, or have the sticky bit set.
+ { "pid_file", NULL, "Full path for the PID file" },
{ "server_name", NULL, "Server name" },
{ "server_info", "My server", "Brief server description" },
{ "motd", NULL, "MOTD filename" },
@@ -3661,6 +3671,51 @@ irc_initialize_server_name (struct server_context *ctx, struct error **e)
return true;
}
+static bool
+irc_lock_pid_file (struct server_context *ctx, struct error **e)
+{
+ const char *path = str_map_find (&ctx->config, "pid_file");
+ if (!path)
+ return true;
+
+ int fd = open (path, O_RDWR | O_CREAT,
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH /* 644 */);
+ if (fd < 0)
+ {
+ error_set (e, "can't open `%s': %s", path, strerror (errno));
+ return false;
+ }
+
+ struct flock lock =
+ {
+ .l_type = F_WRLCK,
+ .l_start = 0,
+ .l_whence = SEEK_SET,
+ .l_len = 0,
+ };
+ if (fcntl (fd, F_SETLK, &lock))
+ {
+ error_set (e, "can't lock `%s': %s", path, strerror (errno));
+ return false;
+ }
+
+ struct str pid;
+ str_init (&pid);
+ str_append_printf (&pid, "%ld", (long) getpid ());
+
+ if (ftruncate (fd, 0)
+ || write (fd, pid.str, pid.len) != (ssize_t) pid.len)
+ {
+ error_set (e, "can't write to `%s': %s", path, strerror (errno));
+ return false;
+ }
+ str_free (&pid);
+
+ // Intentionally not closing the file descriptor; it must stay alive
+ // for the entire life of the application
+ return true;
+}
+
static int
irc_listen (struct addrinfo *gai_iter)
{
@@ -3781,7 +3836,6 @@ on_signal_pipe_readable (const struct pollfd *fd, struct server_context *ctx)
static void
daemonize (void)
{
- // TODO: create and lock a PID file?
print_status ("daemonizing...");
if (chdir ("/"))
@@ -3804,7 +3858,10 @@ daemonize (void)
openlog (PROGRAM_NAME, LOG_NDELAY | LOG_NOWAIT | LOG_PID, 0);
g_log_message_real = log_message_syslog;
- // 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
+ // descriptors open. In theory we could try to enumerate the descriptors
+ // at the start of main().
for (int i = 0; i < 3; i++)
xclose (i);
@@ -3887,6 +3944,7 @@ 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);