From 1b36e7e118207a242aa90361eb1edc8db4fe0bc7 Mon Sep 17 00:00:00 2001 From: robxnano <89391914+robxnano@users.noreply.github.com> Date: Fri, 30 Sep 2022 18:28:42 +0100 Subject: [PATCH] Unix: Added support for old prefs paths, refactored code Improved the XDG_CONFIG_HOME implementation by adding fallback paths. If a prefs file in the old location exists, this will be loaded ahead of the new one. But if no existing file is found, a new one will be created in the new config directory. Additionally new log messages were added to show where the prefs file was loaded from. --- BasiliskII/src/Unix/prefs_unix.cpp | 217 ++++++++++++++++++--------- BasiliskII/src/Unix/xpram_unix.cpp | 33 +++-- SheepShaver/src/Unix/prefs_unix.cpp | 219 +++++++++++++++++++--------- 3 files changed, 321 insertions(+), 148 deletions(-) diff --git a/BasiliskII/src/Unix/prefs_unix.cpp b/BasiliskII/src/Unix/prefs_unix.cpp index 59dec302..75ac72d2 100644 --- a/BasiliskII/src/Unix/prefs_unix.cpp +++ b/BasiliskII/src/Unix/prefs_unix.cpp @@ -19,9 +19,7 @@ */ #include "sysdeps.h" - #include - #include using std::string; @@ -39,87 +37,158 @@ prefs_desc platform_prefs_items[] = { {NULL, TYPE_END, false, NULL} // End of list }; +// Standard file names and paths +static const char PREFS_FILE_NAME[] = "/.basilisk_ii_prefs"; +static const char XDG_PREFS_FILE_NAME[] = "/prefs"; +static const char XPRAM_FILE_NAME[] = "/.basilisk_ii_xpram"; +static const char XDG_XPRAM_FILE_NAME[] = "/xpram"; +static const char XDG_CONFIG_SUBDIR[] = "/BasiliskII"; + // Prefs file name and path -static const char PREFS_FILE_NAME[] = "/prefs"; string UserPrefsPath; -static string prefs_path; +static string home_dir; +static string xdg_config_dir; static string prefs_name; extern string xpram_name; -/* - * Load preferences from settings file - */ +static string get_xdg_config_dir(void) +{ + char *env; + if (env = getenv("XDG_CONFIG_HOME")) + return string(env) + XDG_CONFIG_SUBDIR; + if (env = getenv("HOME")) + return string(env) + "/.config" + XDG_CONFIG_SUBDIR; + return ""; +} -// Comply with XDG Base Directory Specification -// https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html -static void get_prefs_path_from_env(void){ - char* env; - if(env=getenv("XDG_CONFIG_HOME")){ - prefs_path = string(env); +static string get_home_dir(void) +{ + char *env; + if(env = getenv("HOME")) + return string(env); + return "."; // last resort, use the current directory +} + +static string get_dir(string *path) +{ + int pos = path->find_last_of('/'); + if (pos == 0) + return ""; // file is in root folder + if (pos == std::string::npos) + return "."; // file is in current folder + return path->substr(0, pos); +} + +static void exit_if_dir(const string& path) +{ + struct stat info; + if (stat(path.c_str(), &info) != 0){ return; } - if(env=getenv("HOME")){ - prefs_path = string(env) + "/.config"; + if ((info.st_mode & S_IFDIR) != 0) + { + fprintf(stderr, "ERROR: Cannot open %s (Is a directory)\n", prefs_name.c_str()); + exit(1); } } -void LoadPrefs(const char* vmdir){ - if(vmdir){ - prefs_path = string(vmdir); - prefs_name = prefs_path + PREFS_FILE_NAME; - FILE *prefs = fopen(prefs_name.c_str(), "r"); - if (!prefs) { - printf("No file at %s found.\n", prefs_name.c_str()); - exit(1); - } +static bool load_prefs_file(const string& path, bool exit_on_failure) +{ + exit_if_dir(path); + FILE *prefs = fopen(path.c_str(), "r"); + if (prefs != NULL) + { LoadPrefsFromStream(prefs); fclose(prefs); - return; + printf("Using prefs file at %s\n", prefs_name.c_str()); + return true; } - - // Construct prefs path - get_prefs_path_from_env(); - if(!prefs_path.empty()){ - prefs_path += "/BasiliskII"; - prefs_name = prefs_path + PREFS_FILE_NAME; - } - xpram_name = prefs_path + "/xpram"; - - // --config was specified - if(!UserPrefsPath.empty()){ - prefs_name = UserPrefsPath; - } - - // Read preferences from settings file - FILE *f = fopen(prefs_name.c_str(), "r"); - if (f != NULL) { - - // Prefs file found, load settings - LoadPrefsFromStream(f); - fclose(f); - - } else { -#ifdef __linux__ - PrefsAddString("cdrom", "/dev/cdrom"); -#endif - // No prefs file, save defaults - SavePrefs(); + else if (exit_on_failure) + { + fprintf(stderr, "ERROR: Could not load prefs file from %s (%s)\n", + path.c_str(), strerror(errno)); + exit(1); } + return false; } -static bool is_dir(const std::string& path){ +/* + * Look for prefs file in the following locations (in order of priority): + * 1. From vmdir/.basilisk_ii_prefs if a vmdir has been specified + * 2. From path specified with --config command line + * 3. From $HOME/.basilisk_ii_prefs if it exists + * 4. From $XDG_CONFIG_HOME/BasiliskII/prefs if it exists + * 5. Create a new prefs file at $XDG_CONFIG_HOME/BasiliskII/prefs + * If $XDG_CONFIG_HOME doesn't exist, $HOME/.config is used instead, + * in accordance with XDG Base Directory Specification: + * https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html + */ + +void LoadPrefs(const char* vmdir) +{ + home_dir = get_home_dir(); + xdg_config_dir = get_xdg_config_dir(); + + // vmdir was specified on the command line + if (vmdir) + { + prefs_name = string(vmdir) + XDG_PREFS_FILE_NAME; + xpram_name = string(vmdir) + XDG_XPRAM_FILE_NAME; + if (load_prefs_file(prefs_name, true)) + return; + } + + // --config was specified + if (!UserPrefsPath.empty()) + { + prefs_name = UserPrefsPath; + xpram_name = get_dir(&prefs_name) + XPRAM_FILE_NAME; + if (load_prefs_file(prefs_name, true)) + return; + } + + // Load .basilisk_ii_prefs from $HOME if it exists + if (!home_dir.empty()) + { + prefs_name = home_dir + PREFS_FILE_NAME; + xpram_name = home_dir + XPRAM_FILE_NAME; + if (load_prefs_file(prefs_name, false)) + return; + } + + // If no other prefs file exists, try the $XDG_CONFIG_HOME directory + if (!xdg_config_dir.empty()) + { + prefs_name = xdg_config_dir + XDG_PREFS_FILE_NAME; + xpram_name = xdg_config_dir + XDG_XPRAM_FILE_NAME; + if (load_prefs_file(prefs_name, false)) + return; + } + + // No prefs file, save defaults in $XDG_CONFIG_HOME directory +#ifdef __linux__ + PrefsAddString("cdrom", "/dev/cdrom"); +#endif + printf("No prefs file found, creating new one at %s\n", prefs_name.c_str()); + SavePrefs(); +} + +static bool is_dir(const string& path) +{ struct stat info; - if(stat(path.c_str(), &info) != 0){ + if (stat(path.c_str(), &info) != 0){ return false; } return (info.st_mode & S_IFDIR) != 0; } -static bool create_directories(const std::string& path,mode_t mode){ - if(mkdir(path.c_str(),mode)==0) +static bool create_directories(const string& path, mode_t mode) +{ + if (mkdir(path.c_str(), mode) == 0) return true; - switch (errno){ + switch (errno) + { case ENOENT: { int pos = path.find_last_of('/'); @@ -141,15 +210,25 @@ static bool create_directories(const std::string& path,mode_t mode){ * Save preferences to settings file */ -void SavePrefs(void){ + +void SavePrefs(void) +{ FILE *f; - if(!prefs_path.empty()&&!is_dir(prefs_path)){ - create_directories(prefs_path,0700); + string prefs_dir = get_dir(&prefs_name); + if (!prefs_dir.empty() && !is_dir(prefs_dir)) + { + create_directories(prefs_dir, 0700); } - if ((f = fopen(prefs_name.c_str(), "w")) != NULL) { + if ((f = fopen(prefs_name.c_str(), "w")) != NULL) + { SavePrefsToStream(f); fclose(f); } + else + { + fprintf(stderr, "WARNING: Unable to save %s (%s)\n", + prefs_name.c_str(), strerror(errno)); + } } /* @@ -164,14 +243,20 @@ void AddPlatformPrefsDefaults(void) PrefsReplaceInt32("mousewheelmode", 1); PrefsReplaceInt32("mousewheellines", 3); #ifdef __linux__ - if (access("/dev/sound/dsp", F_OK) == 0) { + if (access("/dev/sound/dsp", F_OK) == 0) + { PrefsReplaceString("dsp", "/dev/sound/dsp"); - } else { + } + else + { PrefsReplaceString("dsp", "/dev/dsp"); } - if (access("/dev/sound/mixer", F_OK) == 0) { + if (access("/dev/sound/mixer", F_OK) == 0) + { PrefsReplaceString("mixer", "/dev/sound/mixer"); - } else { + } + else + { PrefsReplaceString("mixer", "/dev/mixer"); } #else diff --git a/BasiliskII/src/Unix/xpram_unix.cpp b/BasiliskII/src/Unix/xpram_unix.cpp index e0bca701..dcf9c0bf 100644 --- a/BasiliskII/src/Unix/xpram_unix.cpp +++ b/BasiliskII/src/Unix/xpram_unix.cpp @@ -32,41 +32,48 @@ string xpram_name; * Load XPRAM from settings file */ -void LoadXPRAM(const char* vmdir){ - if(vmdir){ -#if POWERPC_ROM - xpram_name = string(vmdir) + "/nvram"; -#else - xpram_name = string(vmdir) + "/xpram"; -#endif - } - +void LoadXPRAM(const char* vmdir) +{ assert(!xpram_name.empty()); int fd; - if ((fd = open(xpram_name.c_str(), O_RDONLY)) >= 0) { + if ((fd = open(xpram_name.c_str(), O_RDONLY)) >= 0) + { read(fd, XPRAM, XPRAM_SIZE); close(fd); } + else + { + fprintf(stderr, "WARNING: Unable to load %s (%s)\n", + xpram_name.c_str(), strerror(errno)); + } } /* * Save XPRAM to settings file */ -void SaveXPRAM(void){ +void SaveXPRAM(void) +{ assert(!xpram_name.empty()); int fd; - if ((fd = open(xpram_name.c_str(), O_WRONLY | O_CREAT, 0666)) >= 0) { + if ((fd = open(xpram_name.c_str(), O_WRONLY | O_CREAT, 0666)) >= 0) + { write(fd, XPRAM, XPRAM_SIZE); close(fd); } + else + { + fprintf(stderr, "WARNING: Unable to save %s (%s)\n", + xpram_name.c_str(), strerror(errno)); + } } /* * Delete PRAM file */ -void ZapPRAM(void){ +void ZapPRAM(void) +{ // Delete file assert(!xpram_name.empty()); unlink(xpram_name.c_str()); diff --git a/SheepShaver/src/Unix/prefs_unix.cpp b/SheepShaver/src/Unix/prefs_unix.cpp index df496512..f8784b09 100644 --- a/SheepShaver/src/Unix/prefs_unix.cpp +++ b/SheepShaver/src/Unix/prefs_unix.cpp @@ -1,5 +1,5 @@ /* - * prefs_unix.cpp - Preferences handling, Unix specific things + * prefs_unix.cpp - Preferences handling, Unix specific stuff * * SheepShaver (C) 1997-2008 Christian Bauer and Marc Hellwig * @@ -19,10 +19,7 @@ */ #include "sysdeps.h" - -#include #include - #include using std::string; @@ -45,89 +42,158 @@ prefs_desc platform_prefs_items[] = { {NULL, TYPE_END, false, NULL} // End of list }; +// Standard file names and paths +static const char PREFS_FILE_NAME[] = "/.sheepshaver_prefs"; +static const char XDG_PREFS_FILE_NAME[] = "/prefs"; +static const char XPRAM_FILE_NAME[] = "/.sheepshaver_nvram"; +static const char XDG_XPRAM_FILE_NAME[] = "/nvram"; +static const char XDG_CONFIG_SUBDIR[] = "/SheepShaver"; // Prefs file name and path -static const char PREFS_FILE_NAME[] = "/prefs"; -static string prefs_path; +string UserPrefsPath; +static string home_dir; +static string xdg_config_dir; static string prefs_name; extern string xpram_name; -std::string UserPrefsPath; +static string get_xdg_config_dir(void) +{ + char *env; + if (env = getenv("XDG_CONFIG_HOME")) + return string(env) + XDG_CONFIG_SUBDIR; + if (env = getenv("HOME")) + return string(env) + "/.config" + XDG_CONFIG_SUBDIR; + return ""; +} -/* - * Load preferences from settings file - */ +static string get_home_dir(void) +{ + char *env; + if(env = getenv("HOME")) + return string(env); + return "."; // last resort, use the current directory +} -// Comply with XDG Base Directory Specification -// https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html -static void get_prefs_path_from_env(void){ - char* env; - if(env=getenv("XDG_CONFIG_HOME")){ - prefs_path = string(env); +static string get_dir(string *path) +{ + int pos = path->find_last_of('/'); + if (pos == 0) + return ""; // file is in root folder + if (pos == std::string::npos) + return "."; // file is in current folder + return path->substr(0, pos); +} + +static void exit_if_dir(const string& path) +{ + struct stat info; + if (stat(path.c_str(), &info) != 0){ return; } - if(env=getenv("HOME")){ - prefs_path = string(env) + "/.config"; + if ((info.st_mode & S_IFDIR) != 0) + { + fprintf(stderr, "ERROR: Cannot open %s (Is a directory)\n", prefs_name.c_str()); + exit(1); } } -void LoadPrefs(const char* vmdir){ - if(vmdir){ - prefs_path = string(vmdir); - prefs_name = prefs_path + PREFS_FILE_NAME; - FILE *prefs = fopen(prefs_name.c_str(), "r"); - if (!prefs) { - printf("No file at %s found.\n", prefs_name.c_str()); - exit(1); - } +static bool load_prefs_file(const string& path, bool exit_on_failure) +{ + exit_if_dir(path); + FILE *prefs = fopen(path.c_str(), "r"); + if (prefs != NULL) + { LoadPrefsFromStream(prefs); fclose(prefs); - return; + printf("Using prefs file at %s\n", prefs_name.c_str()); + return true; } - - // Construct prefs path - get_prefs_path_from_env(); - if(!prefs_path.empty()){ - prefs_path += "/SheepShaver"; - prefs_name = prefs_path + PREFS_FILE_NAME; - } - xpram_name = prefs_path + "/nvram"; - - // --config was specified - if(!UserPrefsPath.empty()){ - prefs_name = UserPrefsPath; - } - - // Read preferences from settings file - FILE *f = fopen(prefs_name.c_str(), "r"); - if (f != NULL) { - - // Prefs file found, load settings - LoadPrefsFromStream(f); - fclose(f); - - } else { -#ifdef __linux__ - PrefsAddString("cdrom", "/dev/cdrom"); -#endif - // No prefs file, save defaults - SavePrefs(); + else if (exit_on_failure) + { + fprintf(stderr, "ERROR: Could not load prefs file from %s (%s)\n", + path.c_str(), strerror(errno)); + exit(1); } + return false; } -static bool is_dir(const std::string& path){ +/* + * Look for prefs file in the following locations (in order of priority): + * 1. From vmdir/.sheepshaver_prefs if a vmdir has been specified + * 2. From path specified with --config command line + * 3. From $HOME/.sheepshaver_prefs if it exists + * 4. From $XDG_CONFIG_HOME/SheepShaver/prefs if it exists + * 5. Create a new prefs file at $XDG_CONFIG_HOME/SheepShaver/prefs + * If $XDG_CONFIG_HOME doesn't exist, $HOME/.config is used instead, + * in accordance with XDG Base Directory Specification: + * https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html + */ + +void LoadPrefs(const char* vmdir) +{ + home_dir = get_home_dir(); + xdg_config_dir = get_xdg_config_dir(); + + // vmdir was specified on the command line + if (vmdir) + { + prefs_name = string(vmdir) + XDG_PREFS_FILE_NAME; + xpram_name = string(vmdir) + XDG_XPRAM_FILE_NAME; + if (load_prefs_file(prefs_name, true)) + return; + } + + // --config was specified + if (!UserPrefsPath.empty()) + { + prefs_name = UserPrefsPath; + xpram_name = get_dir(&prefs_name) + XPRAM_FILE_NAME; + if (load_prefs_file(prefs_name, true)) + return; + } + + // Load .basilisk_ii_prefs from $HOME if it exists + if (!home_dir.empty()) + { + prefs_name = home_dir + PREFS_FILE_NAME; + xpram_name = home_dir + XPRAM_FILE_NAME; + if (load_prefs_file(prefs_name, false)) + return; + } + + // If no other prefs file exists, try the $XDG_CONFIG_HOME directory + if (!xdg_config_dir.empty()) + { + prefs_name = xdg_config_dir + XDG_PREFS_FILE_NAME; + xpram_name = xdg_config_dir + XDG_XPRAM_FILE_NAME; + if (load_prefs_file(prefs_name, false)) + return; + } + + // No prefs file, save defaults in $XDG_CONFIG_HOME directory +#ifdef __linux__ + PrefsAddString("cdrom", "/dev/cdrom"); +#endif + printf("No prefs file found, creating new one at %s\n", prefs_name.c_str()); + SavePrefs(); +} + +static bool is_dir(const string& path) +{ struct stat info; - if(stat(path.c_str(), &info) != 0){ + if (stat(path.c_str(), &info) != 0){ return false; } return (info.st_mode & S_IFDIR) != 0; } -static bool create_directories(const std::string& path,mode_t mode){ - if(mkdir(path.c_str(),mode)==0) +static bool create_directories(const string& path, mode_t mode) +{ + if (mkdir(path.c_str(), mode) == 0) return true; - switch (errno){ + switch (errno) + { case ENOENT: { int pos = path.find_last_of('/'); @@ -149,15 +215,24 @@ static bool create_directories(const std::string& path,mode_t mode){ * Save preferences to settings file */ -void SavePrefs(void){ +void SavePrefs(void) +{ FILE *f; - if(!prefs_path.empty()&&!is_dir(prefs_path)){ - create_directories(prefs_path,0700); + string prefs_dir = get_dir(&prefs_name); + if (!prefs_dir.empty() && !is_dir(prefs_dir)) + { + create_directories(prefs_dir, 0700); } - if ((f = fopen(prefs_name.c_str(), "w")) != NULL) { + if ((f = fopen(prefs_name.c_str(), "w")) != NULL) + { SavePrefsToStream(f); fclose(f); } + else + { + fprintf(stderr, "WARNING: Unable to save %s (%s)\n", + prefs_name.c_str(), strerror(errno)); + } } /* @@ -172,14 +247,20 @@ void AddPlatformPrefsDefaults(void) PrefsReplaceInt32("mousewheelmode", 1); PrefsReplaceInt32("mousewheellines", 3); #ifdef __linux__ - if (access("/dev/sound/dsp", F_OK) == 0) { + if (access("/dev/sound/dsp", F_OK) == 0) + { PrefsReplaceString("dsp", "/dev/sound/dsp"); - } else { + } + else + { PrefsReplaceString("dsp", "/dev/dsp"); } - if (access("/dev/sound/mixer", F_OK) == 0) { + if (access("/dev/sound/mixer", F_OK) == 0) + { PrefsReplaceString("mixer", "/dev/sound/mixer"); - } else { + } + else + { PrefsReplaceString("mixer", "/dev/mixer"); } #else