Resolve paths relative to XDG config. paths
This should make the programs an awful lot less painful to set up.
This commit is contained in:
parent
b0cf09fb4c
commit
18cb2941f3
134
src/common.c
134
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;
|
static size_t io_error_domain_tag;
|
||||||
#define IO_ERROR (error_resolve_domain (&io_error_domain_tag))
|
#define IO_ERROR (error_resolve_domain (&io_error_domain_tag))
|
||||||
|
|
||||||
@ -1729,45 +1781,6 @@ struct config_item
|
|||||||
const char *description;
|
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
|
static void
|
||||||
load_config_defaults (struct str_map *config, const struct config_item *table)
|
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
|
static bool
|
||||||
read_config_file (struct str_map *config, struct error **e)
|
read_config_file (struct str_map *config, struct error **e)
|
||||||
{
|
{
|
||||||
struct str line;
|
char *filename = resolve_config_filename (PROGRAM_NAME ".conf");
|
||||||
FILE *fp = get_config_file ();
|
if (!filename)
|
||||||
unsigned line_no = 0;
|
|
||||||
bool errors = false;
|
|
||||||
|
|
||||||
if (!fp)
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
FILE *fp = fopen (filename, "r");
|
||||||
|
if (!fp)
|
||||||
|
{
|
||||||
|
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);
|
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;
|
char *start = line.str;
|
||||||
if (*start == '#')
|
if (*start == '#')
|
||||||
@ -1894,3 +1914,25 @@ error:
|
|||||||
return NULL;
|
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);
|
||||||
|
}
|
||||||
|
66
src/kike.c
66
src/kike.c
@ -1073,15 +1073,20 @@ irc_initialize_ssl (struct server_context *ctx)
|
|||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (!ssl_cert)
|
if (!ssl_cert)
|
||||||
{
|
|
||||||
print_error ("no SSL certificate set");
|
print_error ("no SSL certificate set");
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!ssl_key)
|
if (!ssl_key)
|
||||||
{
|
|
||||||
print_error ("no SSL private key set");
|
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;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
ctx->ssl_ctx = SSL_CTX_new (SSLv23_server_method ());
|
ctx->ssl_ctx = SSL_CTX_new (SSLv23_server_method ());
|
||||||
if (!ctx->ssl_ctx)
|
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: maybe we should call SSL_CTX_set_options() for some workarounds
|
||||||
|
|
||||||
// XXX: perhaps we should read the files ourselves for better messages
|
// 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",
|
print_error ("%s: %s", "setting the SSL client certificate failed",
|
||||||
ERR_error_string (ERR_get_error (), NULL));
|
ERR_error_string (ERR_get_error (), NULL));
|
||||||
goto error_ssl_2;
|
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",
|
print_error ("%s: %s", "setting the SSL private key failed",
|
||||||
ERR_error_string (ERR_get_error (), NULL));
|
ERR_error_string (ERR_get_error (), NULL));
|
||||||
@ -1132,7 +1137,16 @@ irc_initialize_catalog (struct server_context *ctx, struct error **e)
|
|||||||
if (!catalog)
|
if (!catalog)
|
||||||
return true;
|
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)
|
if (ctx->catalog == (nl_catd) -1)
|
||||||
{
|
{
|
||||||
error_set (e, IO_ERROR, IO_ERROR_FAILED, "%s: %s",
|
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)
|
if (!motd)
|
||||||
return true;
|
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)
|
if (!fp)
|
||||||
{
|
{
|
||||||
error_set (e, IO_ERROR, IO_ERROR_FAILED,
|
error_set (e, IO_ERROR, IO_ERROR_FAILED, "%s: %s",
|
||||||
"%s: %s", "failed reading the MOTD file", strerror (errno));
|
"failed reading the MOTD file", strerror (errno));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1312,25 +1335,6 @@ print_usage (const char *program_name)
|
|||||||
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
|
int
|
||||||
main (int argc, char *argv[])
|
main (int argc, char *argv[])
|
||||||
{
|
{
|
||||||
@ -1365,7 +1369,7 @@ main (int argc, char *argv[])
|
|||||||
printf (PROGRAM_NAME " " PROGRAM_VERSION "\n");
|
printf (PROGRAM_NAME " " PROGRAM_VERSION "\n");
|
||||||
exit (EXIT_SUCCESS);
|
exit (EXIT_SUCCESS);
|
||||||
case 'w':
|
case 'w':
|
||||||
call_write_default_config (optarg);
|
call_write_default_config (optarg, g_config_table);
|
||||||
exit (EXIT_SUCCESS);
|
exit (EXIT_SUCCESS);
|
||||||
default:
|
default:
|
||||||
print_fatal ("error in options");
|
print_fatal ("error in options");
|
||||||
|
@ -277,12 +277,16 @@ irc_initialize_ssl (struct bot_context *ctx, struct error **e)
|
|||||||
goto error_ssl_2;
|
goto error_ssl_2;
|
||||||
|
|
||||||
const char *ssl_cert = str_map_find (&ctx->config, "ssl_cert");
|
const char *ssl_cert = str_map_find (&ctx->config, "ssl_cert");
|
||||||
if (ssl_cert
|
if (ssl_cert)
|
||||||
&& !SSL_use_certificate_file (ctx->ssl, ssl_cert, SSL_FILETYPE_PEM))
|
|
||||||
{
|
{
|
||||||
|
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
|
// XXX: perhaps we should read the file ourselves for better messages
|
||||||
print_error ("%s: %s", "setting the SSL client certificate failed",
|
else if (!SSL_use_certificate_file (ctx->ssl, path, SSL_FILETYPE_PEM))
|
||||||
ERR_error_string (ERR_get_error (), NULL));
|
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);
|
SSL_set_connect_state (ctx->ssl);
|
||||||
@ -1686,25 +1690,6 @@ print_usage (const char *program_name)
|
|||||||
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
|
int
|
||||||
main (int argc, char *argv[])
|
main (int argc, char *argv[])
|
||||||
{
|
{
|
||||||
@ -1741,7 +1726,7 @@ main (int argc, char *argv[])
|
|||||||
printf (PROGRAM_NAME " " PROGRAM_VERSION "\n");
|
printf (PROGRAM_NAME " " PROGRAM_VERSION "\n");
|
||||||
exit (EXIT_SUCCESS);
|
exit (EXIT_SUCCESS);
|
||||||
case 'w':
|
case 'w':
|
||||||
call_write_default_config (optarg);
|
call_write_default_config (optarg, g_config_table);
|
||||||
exit (EXIT_SUCCESS);
|
exit (EXIT_SUCCESS);
|
||||||
default:
|
default:
|
||||||
print_fatal ("error in options");
|
print_fatal ("error in options");
|
||||||
|
Loading…
x
Reference in New Issue
Block a user