From e1e3ef08ef3419f4aabcfb3f45ab49a78000cdb7 Mon Sep 17 00:00:00 2001 Message-Id: From: Mark Wooding Date: Thu, 4 Jun 2020 20:13:11 +0100 Subject: [PATCH] lib/home.c: Introduce functions for building pathmames in home directories. Organization: Straylight/Edgeware From: Mark Wooding Split the home-directory logic of `config_userconf' into its own file. Arrange to only calculate the home directory once. Most invasively, use this new functionality in place of looking up `$HOME' and building pathnames by hand. This change doesn't add much functionality, but it does add a little. Most notably, $ unset HOME; disobedience doesn't segfault any more. More subtly, the logic for finding one's home directory is now consistent. On Windows, we still use `%APPDATA%'; on Unix, we now /always/ use `$HOME' first, and then fall back to `getpwuid(getuid)->pw_dir' if that's unset. Previously, the configuration reader would ignore `$HOME' and use the password database, while Disobedience used `$HOME' exclusively and crashed if it was unset. This is all obviously silly. --- disobedience/disobedience.h | 1 + disobedience/rtp.c | 14 +++-- disobedience/settings.c | 13 +++-- lib/Makefile.am | 1 + lib/configuration.c | 21 +------- lib/home.c | 102 ++++++++++++++++++++++++++++++++++++ lib/home.h | 37 +++++++++++++ 7 files changed, 158 insertions(+), 31 deletions(-) create mode 100644 lib/home.c create mode 100644 lib/home.h diff --git a/disobedience/disobedience.h b/disobedience/disobedience.h index ab74592..94e3022 100644 --- a/disobedience/disobedience.h +++ b/disobedience/disobedience.h @@ -42,6 +42,7 @@ #include "defs.h" #include "configuration.h" #include "hash.h" +#include "home.h" #include "selection.h" #include "kvp.h" #include "eventdist.h" diff --git a/disobedience/rtp.c b/disobedience/rtp.c index 40e1ea2..3629b67 100644 --- a/disobedience/rtp.c +++ b/disobedience/rtp.c @@ -65,14 +65,13 @@ static char *substitute_instance_name(void) { /** @brief Initialize @ref rtp_socket and @ref rtp_log if necessary */ static void rtp_init(void) { if(!rtp_socket) { - const char *home = getenv("HOME"); - char *dir, *instance; - - byte_xasprintf(&dir, "%s/.disorder/", home); + const char *dir, *instance; + if(!(dir = profile_directory())) + disorder_fatal(0, "failed to find profile directory"); mkdir(dir, 02700); instance = substitute_instance_name(); - byte_xasprintf(&rtp_socket, "%s%s", dir, instance); - byte_xasprintf(&rtp_log, "%s%s.log", dir, instance); + byte_xasprintf(&rtp_socket, "%s/%s", dir, instance); + byte_xasprintf(&rtp_log, "%s/%s.log", dir, instance); } } @@ -202,9 +201,8 @@ void stop_rtp(void) { static char *rtp_config_file(void) { static char *rtp_config; - const char *home = getenv("HOME"); if(!rtp_config) - byte_xasprintf(&rtp_config, "%s/.disorder/api", home); + rtp_config = profile_filename("api"); return rtp_config; } diff --git a/disobedience/settings.c b/disobedience/settings.c index 2c4ffeb..18af6c1 100644 --- a/disobedience/settings.c +++ b/disobedience/settings.c @@ -150,11 +150,15 @@ void init_styles(void) { } void save_settings(void) { - char *dir, *path, *tmp; + const char *dir; + char *path, *tmp; FILE *fp = 0; size_t n, m, c; - byte_xasprintf(&dir, "%s/.disorder", getenv("HOME")); + if(!(dir = profile_directory())) { + fpopup_msg(GTK_MESSAGE_ERROR, "failed to find home directory"); + goto done; + } byte_xasprintf(&path, "%s/disobedience", dir); byte_xasprintf(&tmp, "%s.tmp", path); mkdir(dir, 02700); /* make sure directory exists */ @@ -206,8 +210,9 @@ void load_settings(void) { int nvec; size_t n, m, c; - byte_xasprintf(&path, "%s/.disorder/disobedience", getenv("HOME")); - if(!(fp = fopen(path, "r"))) { + if(!(path = profile_filename("disobedience"))) + fpopup_msg(GTK_MESSAGE_ERROR, "failed to find home directory"); + else if(!(fp = fopen(path, "r"))) { if(errno != ENOENT) fpopup_msg(GTK_MESSAGE_ERROR, "error opening %s: %s", path, strerror(errno)); diff --git a/lib/Makefile.am b/lib/Makefile.am index a6a362f..249bd98 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -52,6 +52,7 @@ libdisorder_a_SOURCES=charset.c charsetf.c charset.h \ hash.c hash.h \ heap.h \ hex.c hex.h \ + home.c home.h \ hostname.c hostname.h \ hreader.h \ ifreq.c ifreq.h \ diff --git a/lib/configuration.c b/lib/configuration.c index b5561dc..17f9ec7 100644 --- a/lib/configuration.c +++ b/lib/configuration.c @@ -37,9 +37,6 @@ # include #endif -#if HAVE_SHLOBJ_H -# include -#endif #include #include "rights.h" @@ -48,6 +45,7 @@ #include "log.h" #include "split.h" #include "syscalls.h" +#include "home.h" #include "table.h" #include "inputline.h" #include "charset.h" @@ -1673,22 +1671,7 @@ char *config_private(void) { /** @brief Return the path to user's personal configuration file */ char *config_userconf(void) { - char *s; -#if _WIN32 - wchar_t *wpath = 0; - char *appdata; - if(SHGetKnownFolderPath(&FOLDERID_RoamingAppData, 0, NULL, &wpath) != S_OK) - disorder_fatal(0, "error calling SHGetKnownFolderPath"); - appdata = win_wtomb(wpath); - CoTaskMemFree(wpath); - byte_xasprintf(&s, "%s\\DisOrder\\passwd", appdata); -#else - struct passwd *pw; - if(!(pw = getpwuid(getuid()))) - disorder_fatal(0, "cannot determine our username"); - byte_xasprintf(&s, "%s/.disorder/passwd", pw->pw_dir); -#endif - return s; + return profile_filename("passwd"); } #if !_WIN32 diff --git a/lib/home.c b/lib/home.c new file mode 100644 index 0000000..5426f76 --- /dev/null +++ b/lib/home.c @@ -0,0 +1,102 @@ +/* + * This file is part of DisOrder + * Copyright (C) 2020 Mark Wooding + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +/** @file lib/home.c + * @brief Find things in the user's home directory + */ + +#include "common.h" + +#include + +#if HAVE_UNISTD_H +# include +#endif +#if HAVE_PWD_H +# include +#endif +#if HAVE_SHLOBJ_H +# include +#endif + +#include "mem.h" +#include "home.h" +#include "log.h" +#include "printf.h" + +#if _WIN32 +# define DIRSEP "\\" +#else +# define DIRSEP "/" +#endif + +static char *profiledir; + + +/** @brief Return the user's profile directory + * @return profile directory + * On Unix, this defaults to `$HOME/.disorder/'; on Windows, it's + * `%APPDATA%\DisOrder\'. The trailing delimiter is included. + */ +const char *profile_directory(void) { + char *t; + + if(profiledir) return profiledir; +#if _WIN32 + wchar_t *wpath = 0; + char *appdata; + if(SHGetKnownFolderPath(&FOLDERID_RoamingAppData, 0, NULL, &wpath) != S_OK) { + disorder_error(0, "error calling SHGetKnownFolderPath"); + return 0; + } + t = win_wtomb(wpath); + CoTaskMemFree(wpath); + byte_xasprintf(&profiledir, "%s\\DisOrder", appdata); +#else + struct passwd *pw; + if(!(t = getenv("HOME"))) { + if(!(pw = getpwuid(getuid()))) + disorder_error(0, "user not found in password database"); + t = pw->pw_dir; + } + byte_xasprintf(&profiledir, "%s/.disorder", t); +#endif + return profiledir; +} + +/** @brief Return the name of a file within the user's profile directory + * @param file Basename of the file desired + * @return Full path name of selected file. + * This currently doesn't do anything very useful with directory separators + * within @a file. + */ +char *profile_filename(const char *file) { + const char *d; + char *t; + if(!(d = profile_directory())) return 0; + byte_xasprintf(&t, "%s" DIRSEP "%s", d, file); + return t; +} + +/* +Local Variables: +c-basic-offset:2 +comment-column:40 +fill-column:79 +indent-tabs-mode:nil +End: +*/ diff --git a/lib/home.h b/lib/home.h new file mode 100644 index 0000000..1956808 --- /dev/null +++ b/lib/home.h @@ -0,0 +1,37 @@ +/* + * This file is part of DisOrder + * Copyright (C) 2007 Richard Kettlewell + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +/** @file lib/home.h + * @brief Find things in the user's home directory + */ + +#ifndef HOME_H +#define HOME_H + +const char *profile_directory(void); +char *profile_filename(const char *file); + +#endif /* HOME_H */ + +/* +Local Variables: +c-basic-offset:2 +comment-column:40 +fill-column:79 +indent-tabs-mode:nil +End: +*/ -- [mdw]