aboutsummaryrefslogtreecommitdiff
path: root/liberty.c
diff options
context:
space:
mode:
Diffstat (limited to 'liberty.c')
-rw-r--r--liberty.c42
1 files changed, 42 insertions, 0 deletions
diff --git a/liberty.c b/liberty.c
index 1ae9df4..a9f30aa 100644
--- a/liberty.c
+++ b/liberty.c
@@ -46,6 +46,7 @@
#include <syslog.h>
#include <fnmatch.h>
#include <iconv.h>
+#include <pwd.h>
#include <sys/socket.h>
#include <sys/types.h>
@@ -2194,12 +2195,53 @@ get_xdg_config_dirs (struct str_vector *out)
}
static char *
+try_expand_tilde (const char *filename)
+{
+ size_t until_slash = strcspn (filename, "/");
+ if (!until_slash)
+ {
+ struct str expanded;
+ str_init (&expanded);
+ str_append_env_path (&expanded, "HOME", false);
+ str_append (&expanded, filename);
+ return str_steal (&expanded);
+ }
+
+ int buf_len = sysconf (_SC_GETPW_R_SIZE_MAX);
+ if (buf_len < 0)
+ buf_len = 1024;
+ struct passwd pwd, *success = NULL;
+
+ char *user = xstrndup (filename, until_slash);
+ char *buf = xmalloc (buf_len);
+ while (getpwnam_r (user, &pwd, buf, buf_len, &success) == ERANGE)
+ buf = xrealloc (buf, buf_len <<= 1);
+ free (user);
+
+ char *result = NULL;
+ if (success)
+ result = xstrdup_printf ("%s%s", pwd.pw_dir, filename + until_slash);
+ free (buf);
+ return result;
+}
+
+static char *
resolve_config_filename (const char *filename)
{
// 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);
+ }
+
struct str_vector paths;
str_vector_init (&paths);
get_xdg_config_dirs (&paths);