From 18cb2941f340550c1425dfa1f1376fdf3e69d42e Mon Sep 17 00:00:00 2001
From: Přemysl Janouch
Date: Mon, 14 Jul 2014 22:12:04 +0200
Subject: Resolve paths relative to XDG config. paths
This should make the programs an awful lot less painful to set up.
---
src/common.c | 132 ++++++++++++++++++++++++++++++++++++++--------------------
src/kike.c | 66 +++++++++++++++--------------
src/zyklonb.c | 33 ++++-----------
3 files changed, 131 insertions(+), 100 deletions(-)
diff --git a/src/common.c b/src/common.c
index 2907159..8f7ffd1 100644
--- a/src/common.c
+++ b/src/common.c
@@ -1359,6 +1359,58 @@ get_xdg_home_dir (struct str *output, const char *var, const char *def)
}
}
+static void
+get_xdg_config_dirs (struct str_vector *out)
+{
+ struct str config_home;
+ str_init (&config_home);
+ get_xdg_home_dir (&config_home, "XDG_CONFIG_HOME", ".config");
+ str_vector_add (out, config_home.str);
+ str_free (&config_home);
+
+ const char *xdg_config_dirs;
+ if ((xdg_config_dirs = getenv ("XDG_CONFIG_DIRS")))
+ split_str_ignore_empty (xdg_config_dirs, ':', out);
+}
+
+static char *
+resolve_config_filename (const char *filename)
+{
+ // Absolute path is absolute
+ if (*filename == '/')
+ return xstrdup (filename);
+
+ struct str_vector paths;
+ str_vector_init (&paths);
+ get_xdg_config_dirs (&paths);
+
+ struct str file;
+ str_init (&file);
+
+ char *result = NULL;
+ for (unsigned i = 0; i < paths.len; i++)
+ {
+ // As per spec, relative paths are ignored
+ if (*paths.vector[i] != '/')
+ continue;
+
+ str_reset (&file);
+ str_append_printf (&file, "%s/" PROGRAM_NAME "/%s",
+ paths.vector[i], filename);
+
+ struct stat st;
+ if (!stat (file.str, &st))
+ {
+ result = str_steal (&file);
+ break;
+ }
+ }
+
+ str_vector_free (&paths);
+ str_free (&file);
+ return result;
+}
+
static size_t io_error_domain_tag;
#define IO_ERROR (error_resolve_domain (&io_error_domain_tag))
@@ -1729,45 +1781,6 @@ struct config_item
const char *description;
};
-static FILE *
-get_config_file (void)
-{
- struct str_vector paths;
- struct str config_home, file;
- const char *xdg_config_dirs;
- unsigned i;
- FILE *fp = NULL;
-
- str_vector_init (&paths);
-
- str_init (&config_home);
- get_xdg_home_dir (&config_home, "XDG_CONFIG_HOME", ".config");
- str_vector_add (&paths, config_home.str);
- str_free (&config_home);
-
- if ((xdg_config_dirs = getenv ("XDG_CONFIG_DIRS")))
- split_str_ignore_empty (xdg_config_dirs, ':', &paths);
-
- str_init (&file);
- for (i = 0; i < paths.len; i++)
- {
- // As per spec, relative paths are ignored
- if (*paths.vector[i] != '/')
- continue;
-
- str_reset (&file);
- str_append (&file, paths.vector[i]);
- str_append (&file, "/" PROGRAM_NAME "/" PROGRAM_NAME ".conf");
-
- if ((fp = fopen (file.str, "r")))
- break;
- }
-
- str_free (&file);
- str_vector_free (&paths);
- return fp;
-}
-
static void
load_config_defaults (struct str_map *config, const struct config_item *table)
{
@@ -1781,16 +1794,23 @@ load_config_defaults (struct str_map *config, const struct config_item *table)
static bool
read_config_file (struct str_map *config, struct error **e)
{
- struct str line;
- FILE *fp = get_config_file ();
- unsigned line_no = 0;
- bool errors = false;
+ char *filename = resolve_config_filename (PROGRAM_NAME ".conf");
+ if (!filename)
+ return true;
+ FILE *fp = fopen (filename, "r");
if (!fp)
- return true;
+ {
+ error_set (e, IO_ERROR, IO_ERROR_FAILED,
+ "could not open `%s' for reading: %s", filename, strerror (errno));
+ return false;
+ }
+ struct str line;
str_init (&line);
- for (line_no = 1; read_line (fp, &line); line_no++)
+
+ bool errors = false;
+ for (unsigned line_no = 1; read_line (fp, &line); line_no++)
{
char *start = line.str;
if (*start == '#')
@@ -1894,3 +1914,25 @@ error:
return NULL;
}
+
+static void
+call_write_default_config (const char *hint, const struct config_item *table)
+{
+ static const char *prolog =
+ "# " PROGRAM_NAME " " PROGRAM_VERSION " configuration file\n"
+ "#\n"
+ "# Relative paths are searched for in ${XDG_CONFIG_HOME:-~/.config}\n"
+ "# /" PROGRAM_NAME " as well as in $XDG_CONFIG_DIRS/" PROGRAM_NAME "\n"
+ "\n";
+
+ struct error *e = NULL;
+ char *filename = write_default_config (hint, prolog, table, &e);
+ if (!filename)
+ {
+ print_fatal ("%s", e->message);
+ error_free (e);
+ exit (EXIT_FAILURE);
+ }
+ print_status ("configuration written to `%s'", filename);
+ free (filename);
+}
diff --git a/src/kike.c b/src/kike.c
index de4ae36..04dd4fc 100644
--- a/src/kike.c
+++ b/src/kike.c
@@ -1073,15 +1073,20 @@ irc_initialize_ssl (struct server_context *ctx)
return true;
if (!ssl_cert)
- {
print_error ("no SSL certificate set");
- return false;
- }
if (!ssl_key)
- {
print_error ("no SSL private key set");
+ if (!ssl_cert || !ssl_key)
+ return false;
+
+ char *cert_path = resolve_config_filename (ssl_cert);
+ char *key_path = resolve_config_filename (ssl_key);
+ if (!cert_path)
+ print_error ("%s: %s", "cannot open file", ssl_cert);
+ if (!key_path)
+ print_error ("%s: %s", "cannot open file", ssl_key);
+ if (!cert_path || !key_path)
return false;
- }
ctx->ssl_ctx = SSL_CTX_new (SSLv23_server_method ());
if (!ctx->ssl_ctx)
@@ -1091,13 +1096,13 @@ irc_initialize_ssl (struct server_context *ctx)
// XXX: maybe we should call SSL_CTX_set_options() for some workarounds
// XXX: perhaps we should read the files ourselves for better messages
- if (!SSL_CTX_use_certificate_chain_file (ctx->ssl_ctx, ssl_cert))
+ if (!SSL_CTX_use_certificate_chain_file (ctx->ssl_ctx, cert_path))
{
print_error ("%s: %s", "setting the SSL client certificate failed",
ERR_error_string (ERR_get_error (), NULL));
goto error_ssl_2;
}
- if (!SSL_CTX_use_PrivateKey_file (ctx->ssl_ctx, ssl_key, SSL_FILETYPE_PEM))
+ if (!SSL_CTX_use_PrivateKey_file (ctx->ssl_ctx, key_path, SSL_FILETYPE_PEM))
{
print_error ("%s: %s", "setting the SSL private key failed",
ERR_error_string (ERR_get_error (), NULL));
@@ -1132,7 +1137,16 @@ irc_initialize_catalog (struct server_context *ctx, struct error **e)
if (!catalog)
return true;
- ctx->catalog = catopen (catalog, NL_CAT_LOCALE);
+ char *path = resolve_config_filename (catalog);
+ if (!path)
+ {
+ error_set (e, IO_ERROR, IO_ERROR_FAILED, "%s: %s",
+ "cannot open file", catalog);
+ return false;
+ }
+ ctx->catalog = catopen (path, NL_CAT_LOCALE);
+ free (path);
+
if (ctx->catalog == (nl_catd) -1)
{
error_set (e, IO_ERROR, IO_ERROR_FAILED, "%s: %s",
@@ -1150,11 +1164,20 @@ irc_initialize_motd (struct server_context *ctx, struct error **e)
if (!motd)
return true;
- FILE *fp = fopen (motd, "r");
+ char *path = resolve_config_filename (motd);
+ if (!path)
+ {
+ error_set (e, IO_ERROR, IO_ERROR_FAILED, "%s: %s",
+ "cannot open file", motd);
+ return false;
+ }
+ FILE *fp = fopen (path, "r");
+ free (path);
+
if (!fp)
{
- error_set (e, IO_ERROR, IO_ERROR_FAILED,
- "%s: %s", "failed reading the MOTD file", strerror (errno));
+ error_set (e, IO_ERROR, IO_ERROR_FAILED, "%s: %s",
+ "failed reading the MOTD file", strerror (errno));
return false;
}
@@ -1312,25 +1335,6 @@ print_usage (const char *program_name)
program_name);
}
-static void
-call_write_default_config (const char *hint)
-{
- static const char *prolog =
- "# " PROGRAM_NAME " " PROGRAM_VERSION " configuration file\n"
- "\n";
-
- struct error *e = NULL;
- char *filename = write_default_config (hint, prolog, g_config_table, &e);
- if (!filename)
- {
- print_fatal ("%s", e->message);
- error_free (e);
- exit (EXIT_FAILURE);
- }
- print_status ("configuration written to `%s'", filename);
- free (filename);
-}
-
int
main (int argc, char *argv[])
{
@@ -1365,7 +1369,7 @@ main (int argc, char *argv[])
printf (PROGRAM_NAME " " PROGRAM_VERSION "\n");
exit (EXIT_SUCCESS);
case 'w':
- call_write_default_config (optarg);
+ call_write_default_config (optarg, g_config_table);
exit (EXIT_SUCCESS);
default:
print_fatal ("error in options");
diff --git a/src/zyklonb.c b/src/zyklonb.c
index 1c7f6ae..de4e3ac 100644
--- a/src/zyklonb.c
+++ b/src/zyklonb.c
@@ -277,12 +277,16 @@ irc_initialize_ssl (struct bot_context *ctx, struct error **e)
goto error_ssl_2;
const char *ssl_cert = str_map_find (&ctx->config, "ssl_cert");
- if (ssl_cert
- && !SSL_use_certificate_file (ctx->ssl, ssl_cert, SSL_FILETYPE_PEM))
+ if (ssl_cert)
{
+ char *path = resolve_config_filename (ssl_cert);
+ if (!path)
+ print_error ("%s: %s", "cannot open file", ssl_cert);
// XXX: perhaps we should read the file ourselves for better messages
- print_error ("%s: %s", "setting the SSL client certificate failed",
- ERR_error_string (ERR_get_error (), NULL));
+ else if (!SSL_use_certificate_file (ctx->ssl, path, SSL_FILETYPE_PEM))
+ print_error ("%s: %s", "setting the SSL client certificate failed",
+ ERR_error_string (ERR_get_error (), NULL));
+ free (path);
}
SSL_set_connect_state (ctx->ssl);
@@ -1686,25 +1690,6 @@ print_usage (const char *program_name)
program_name);
}
-static void
-call_write_default_config (const char *hint)
-{
- static const char *prolog =
- "# " PROGRAM_NAME " " PROGRAM_VERSION " configuration file\n"
- "\n";
-
- struct error *e = NULL;
- char *filename = write_default_config (hint, prolog, g_config_table, &e);
- if (!filename)
- {
- print_fatal ("%s", e->message);
- error_free (e);
- exit (EXIT_FAILURE);
- }
- print_status ("configuration written to `%s'", filename);
- free (filename);
-}
-
int
main (int argc, char *argv[])
{
@@ -1741,7 +1726,7 @@ main (int argc, char *argv[])
printf (PROGRAM_NAME " " PROGRAM_VERSION "\n");
exit (EXIT_SUCCESS);
case 'w':
- call_write_default_config (optarg);
+ call_write_default_config (optarg, g_config_table);
exit (EXIT_SUCCESS);
default:
print_fatal ("error in options");
--
cgit v1.2.3-70-g09d2