summaryrefslogtreecommitdiffstats
path: root/src/btop_config.cpp
diff options
context:
space:
mode:
authorSteffen Winter <steffen.winter@proton.me>2023-10-23 15:18:28 +0200
committerSteffen Winter <steffen.winter@proton.me>2024-01-03 16:50:15 +0100
commitff8352fdcdc08d32494b5873bb85164f2054825a (patch)
tree0c44203561c4245f9f2f157e96121396c325744e /src/btop_config.cpp
parent32b6622cec38aa6caa02111d76186195dcfbe95f (diff)
Improved error handling when determining the config directory
More verbose error printing when a directory is e.g. not readable Also allow the use of read only configurations with disabled logging and persistent configuration
Diffstat (limited to 'src/btop_config.cpp')
-rw-r--r--src/btop_config.cpp67
1 files changed, 66 insertions, 1 deletions
diff --git a/src/btop_config.cpp b/src/btop_config.cpp
index 6ddfd43..535d8c8 100644
--- a/src/btop_config.cpp
+++ b/src/btop_config.cpp
@@ -24,6 +24,7 @@ tab-size = 4
#include <utility>
#include <fmt/core.h>
+#include <sys/statvfs.h>
#include "btop_config.hpp"
#include "btop_shared.hpp"
@@ -320,6 +321,65 @@ namespace Config {
};
std::unordered_map<std::string_view, int> intsTmp;
+ // Returns a valid config dir or an empty optional
+ // The config dir might be read only, a warning is printed, but a path is returned anyway
+ [[nodiscard]] std::optional<fs::path> get_config_dir() noexcept {
+ fs::path config_dir;
+ {
+ std::error_code error;
+ if (const auto xdg_config_home = std::getenv("XDG_CONFIG_HOME"); xdg_config_home != nullptr) {
+ if (fs::exists(xdg_config_home, error)) {
+ config_dir = fs::path(xdg_config_home) / "btop";
+ }
+ } else if (const auto home = std::getenv("HOME"); home != nullptr) {
+ error.clear();
+ if (fs::exists(home, error)) {
+ config_dir = fs::path(home) / ".config" / "btop";
+ }
+ if (error) {
+ fmt::print(stderr, "\033[0;31mWarning: \033[0m{} could not be accessed: {}\n", config_dir.string(), error.message());
+ config_dir = "";
+ }
+ }
+ }
+
+ // FIXME: This warnings can be noisy if the user deliberately has a non-writable config dir
+ // offer an alternative | disable messages by default | disable messages if config dir is not writable | disable messages with a flag
+ // FIXME: Make happy path not branch
+ if (not config_dir.empty()) {
+ std::error_code error;
+ if (fs::exists(config_dir, error)) {
+ if (fs::is_directory(config_dir, error)) {
+ struct statvfs stats {};
+ if ((fs::status(config_dir, error).permissions() & fs::perms::owner_write) == fs::perms::owner_write and
+ statvfs(config_dir.c_str(), &stats) == 0 and (stats.f_flag & ST_RDONLY) == 0) {
+ return config_dir;
+ } else {
+ fmt::print(stderr, "\033[0;31mWarning: \033[0m`{}` is not writable\n", fs::absolute(config_dir).string());
+ // If the config is readable we can still use the provided config, but changes will not be persistent
+ if ((fs::status(config_dir, error).permissions() & fs::perms::owner_read) == fs::perms::owner_read) {
+ fmt::print(stderr, "\033[0;31mWarning: \033[0mLogging is disabled, config changes are not persistent\n");
+ return config_dir;
+ }
+ }
+ } else {
+ fmt::print(stderr, "\033[0;31mWarning: \033[0m`{}` is not a directory\n", fs::absolute(config_dir).string());
+ }
+ } else {
+ // Doesn't exist
+ if (fs::create_directories(config_dir, error)) {
+ return config_dir;
+ } else {
+ fmt::print(stderr, "\033[0;31mWarning: \033[0m`{}` could not be created: {}\n", fs::absolute(config_dir).string(), error.message());
+ }
+ }
+ } else {
+ fmt::print(stderr, "\033[0;31mWarning: \033[0mCould not determine config path: Make sure `$XDG_CONFIG_HOME` or `$HOME` is set\n");
+ }
+ fmt::print(stderr, "\033[0;31mWarning: \033[0mLogging is disabled, config changes are not persistent\n");
+ return {};
+ }
+
bool _locked(const std::string_view name) {
atomic_wait(writelock, true);
if (not write_new and rng::find_if(descriptions, [&name](const auto& a) { return a.at(0) == name; }) != descriptions.end())
@@ -594,12 +654,17 @@ namespace Config {
}
void load(const fs::path& conf_file, vector<string>& load_warnings) {
+ std::error_code error;
if (conf_file.empty())
return;
- else if (not fs::exists(conf_file)) {
+ else if (not fs::exists(conf_file, error)) {
write_new = true;
return;
}
+ if (error) {
+ return;
+ }
+
std::ifstream cread(conf_file);
if (cread.good()) {
vector<string> valid_names;