@@ -24,6 +24,7 @@ tab-size = 4
24
24
#include < utility>
25
25
26
26
#include < fmt/core.h>
27
+ #include < sys/statvfs.h>
27
28
28
29
#include " btop_config.hpp"
29
30
#include " btop_shared.hpp"
@@ -320,6 +321,65 @@ namespace Config {
320
321
};
321
322
std::unordered_map<std::string_view, int > intsTmp;
322
323
324
+ // Returns a valid config dir or an empty optional
325
+ // The config dir might be read only, a warning is printed, but a path is returned anyway
326
+ [[nodiscard]] std::optional<fs::path> get_config_dir () noexcept {
327
+ fs::path config_dir;
328
+ {
329
+ std::error_code error;
330
+ if (const auto xdg_config_home = std::getenv (" XDG_CONFIG_HOME" ); xdg_config_home != nullptr ) {
331
+ if (fs::exists (xdg_config_home, error)) {
332
+ config_dir = fs::path (xdg_config_home) / " btop" ;
333
+ }
334
+ } else if (const auto home = std::getenv (" HOME" ); home != nullptr ) {
335
+ error.clear ();
336
+ if (fs::exists (home, error)) {
337
+ config_dir = fs::path (home) / " .config" / " btop" ;
338
+ }
339
+ if (error) {
340
+ fmt::print (stderr, " \033 [0;31mWarning: \033 [0m{} could not be accessed: {}\n " , config_dir.string (), error.message ());
341
+ config_dir = " " ;
342
+ }
343
+ }
344
+ }
345
+
346
+ // FIXME: This warnings can be noisy if the user deliberately has a non-writable config dir
347
+ // offer an alternative | disable messages by default | disable messages if config dir is not writable | disable messages with a flag
348
+ // FIXME: Make happy path not branch
349
+ if (not config_dir.empty ()) {
350
+ std::error_code error;
351
+ if (fs::exists (config_dir, error)) {
352
+ if (fs::is_directory (config_dir, error)) {
353
+ struct statvfs stats {};
354
+ if ((fs::status (config_dir, error).permissions () & fs::perms::owner_write) == fs::perms::owner_write and
355
+ statvfs (config_dir.c_str (), &stats) == 0 and (stats.f_flag & ST_RDONLY) == 0 ) {
356
+ return config_dir;
357
+ } else {
358
+ fmt::print (stderr, " \033 [0;31mWarning: \033 [0m`{}` is not writable\n " , fs::absolute (config_dir).string ());
359
+ // If the config is readable we can still use the provided config, but changes will not be persistent
360
+ if ((fs::status (config_dir, error).permissions () & fs::perms::owner_read) == fs::perms::owner_read) {
361
+ fmt::print (stderr, " \033 [0;31mWarning: \033 [0mLogging is disabled, config changes are not persistent\n " );
362
+ return config_dir;
363
+ }
364
+ }
365
+ } else {
366
+ fmt::print (stderr, " \033 [0;31mWarning: \033 [0m`{}` is not a directory\n " , fs::absolute (config_dir).string ());
367
+ }
368
+ } else {
369
+ // Doesn't exist
370
+ if (fs::create_directories (config_dir, error)) {
371
+ return config_dir;
372
+ } else {
373
+ fmt::print (stderr, " \033 [0;31mWarning: \033 [0m`{}` could not be created: {}\n " , fs::absolute (config_dir).string (), error.message ());
374
+ }
375
+ }
376
+ } else {
377
+ fmt::print (stderr, " \033 [0;31mWarning: \033 [0mCould not determine config path: Make sure `$XDG_CONFIG_HOME` or `$HOME` is set\n " );
378
+ }
379
+ fmt::print (stderr, " \033 [0;31mWarning: \033 [0mLogging is disabled, config changes are not persistent\n " );
380
+ return {};
381
+ }
382
+
323
383
bool _locked (const std::string_view name) {
324
384
atomic_wait (writelock, true );
325
385
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 {
594
654
}
595
655
596
656
void load (const fs::path& conf_file, vector<string>& load_warnings) {
657
+ std::error_code error;
597
658
if (conf_file.empty ())
598
659
return ;
599
- else if (not fs::exists (conf_file)) {
660
+ else if (not fs::exists (conf_file, error )) {
600
661
write_new = true ;
601
662
return ;
602
663
}
664
+ if (error) {
665
+ return ;
666
+ }
667
+
603
668
std::ifstream cread (conf_file);
604
669
if (cread.good ()) {
605
670
vector<string> valid_names;
0 commit comments