From b4869652775416dde95cfc103d4b03b04828bf60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C5=99emysl=20Janouch?= Date: Thu, 2 Jul 2015 01:02:06 +0200 Subject: [PATCH] kike: resolve the path to PID files better --- common.c | 43 +++++++++++++++++++++++++++++++++++++++++++ kike.c | 35 ++++++++++++++++++++--------------- 2 files changed, 63 insertions(+), 15 deletions(-) diff --git a/common.c b/common.c index cc6221e..7b845d8 100644 --- a/common.c +++ b/common.c @@ -90,6 +90,49 @@ strncasecmp_ascii (const char *a, const char *b, size_t n) return 0; } +static char * +resolve_relative_runtime_filename (const char *filename) +{ + struct str path; + str_init (&path); + + const char *runtime_dir = getenv ("XDG_RUNTIME_DIR"); + if (runtime_dir && *runtime_dir == '/') + str_append (&path, runtime_dir); + else + get_xdg_home_dir (&path, "XDG_DATA_HOME", ".local/share"); + str_append_printf (&path, "/%s/%s", PROGRAM_NAME, filename); + + // Try to create the file's ancestors + const char *last_slash = strrchr (path.str, '/'); + if (last_slash && last_slash != path.str) + { + char *copy = xstrndup (path.str, last_slash - path.str); + (void) mkdir_with_parents (copy, NULL); + free (copy); + } + return str_steal (&path); +} + +static char * +resolve_filename (const char *filename, char *(*relative_cb) (const char *)) +{ + // Absolute path is absolute + if (*filename == '/') + return xstrdup (filename); + + // We don't want to use wordexp() for this as it may execute /bin/sh + if (*filename == '~') + { + // Paths to home directories ought to be absolute + char *expanded = try_expand_tilde (filename + 1); + if (expanded) + return expanded; + print_debug ("failed to expand the home directory in `%s'", filename); + } + return relative_cb (filename); +} + // --- Logging ----------------------------------------------------------------- static void diff --git a/kike.c b/kike.c index b5bda0a..c5c36da 100644 --- a/kike.c +++ b/kike.c @@ -31,15 +31,7 @@ static struct config_item g_config_table[] = { - // TODO: 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" }, + { "pid_file", NULL, "Path or name of the PID file" }, { "server_name", NULL, "Server name" }, { "server_info", "My server", "Brief server description" }, { "motd", NULL, "MOTD filename" }, @@ -3671,14 +3663,12 @@ irc_initialize_server_name (struct server_context *ctx, struct error **e) } static bool -irc_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"); - 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)); @@ -3695,6 +3685,7 @@ irc_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)); + xclose (fd); return false; } @@ -3706,6 +3697,7 @@ irc_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)); + xclose (fd); return false; } str_free (&pid); @@ -3715,6 +3707,19 @@ irc_lock_pid_file (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; + + char *resolved = resolve_filename (path, resolve_relative_runtime_filename); + bool result = lock_pid_file (resolved, e); + free (resolved); + return result; +} + static int irc_listen (struct addrinfo *gai_iter) {