diff --git a/src/blockchain_db/lmdb/db_lmdb.cpp b/src/blockchain_db/lmdb/db_lmdb.cpp index 7e54041d7..d854cbeaf 100644 --- a/src/blockchain_db/lmdb/db_lmdb.cpp +++ b/src/blockchain_db/lmdb/db_lmdb.cpp @@ -1196,8 +1196,12 @@ void BlockchainLMDB::open(const std::string& filename, const int db_flags) throw DB_ERROR("Database could not be opened"); } - if (tools::is_hdd(filename.c_str())) - MCLOG_RED(el::Level::Warning, "global", "The blockchain is on a rotating drive: this will be very slow, use a SSD if possible"); + boost::optional is_hdd_result = tools::is_hdd(filename.c_str()); + if (is_hdd_result) + { + if (is_hdd_result.value()) + MCLOG_RED(el::Level::Warning, "global", "The blockchain is on a rotating drive: this will be very slow, use a SSD if possible"); + } m_folder = filename; diff --git a/src/common/util.cpp b/src/common/util.cpp index 25312bdda..c56c77505 100644 --- a/src/common/util.cpp +++ b/src/common/util.cpp @@ -45,6 +45,13 @@ #include #endif +//tools::is_hdd +#ifdef __GLIBC__ + #include + #include + #include +#endif + #include "unbound.h" #include "include_base_utils.h" @@ -732,62 +739,41 @@ std::string get_nix_version_display_string() #endif } - bool is_hdd(const char *path) + boost::optional is_hdd(const char *file_path) { #ifdef __GLIBC__ - std::string device = ""; - struct stat st, dst; - if (stat(path, &st) < 0) - return 0; - - DIR *dir = opendir("/dev/block"); - if (!dir) - return 0; - struct dirent *de; - while ((de = readdir(dir))) - { - if (strcmp(de->d_name, ".") && strcmp(de->d_name, "..")) + struct stat st; + std::string prefix; + if(stat(file_path, &st) == 0) + { + std::ostringstream s; + s << "/sys/dev/block/" << major(st.st_dev) << ":" << minor(st.st_dev); + prefix = s.str(); + } + else + { + return boost::none; + } + std::string attr_path = prefix + "/queue/rotational"; + std::ifstream f(attr_path, std::ios_base::in); + if(not f.is_open()) + { + attr_path = prefix + "/../queue/rotational"; + f.open(attr_path, std::ios_base::in); + if(not f.is_open()) { - std::string dev_path = std::string("/dev/block/") + de->d_name; - char resolved[PATH_MAX]; - if (realpath(dev_path.c_str(), resolved) && !strncmp(resolved, "/dev/", 5)) - { - if (stat(resolved, &dst) == 0) - { - if (dst.st_rdev == st.st_dev) - { - // take out trailing digits (eg, sda1 -> sda) - char *ptr = resolved; - while (*ptr) - ++ptr; - while (ptr > resolved && isdigit(*--ptr)) - *ptr = 0; - device = resolved + 5; - break; - } - } - } + return boost::none; } } - closedir(dir); - - if (device.empty()) - return 0; - - std::string sys_path = "/sys/block/" + device + "/queue/rotational"; - FILE *f = fopen(sys_path.c_str(), "r"); - if (!f) - return false; - char s[8]; - char *ptr = fgets(s, sizeof(s), f); - fclose(f); - if (!ptr) - return 0; - s[sizeof(s) - 1] = 0; - int n = atoi(s); // returns 0 on parse error - return n == 1; + unsigned short val = 0xdead; + f >> val; + if(not f.fail()) + { + return (val == 1); + } + return boost::none; #else - return 0; + return boost::none; #endif } diff --git a/src/common/util.h b/src/common/util.h index 8815232e2..0e0b50520 100644 --- a/src/common/util.h +++ b/src/common/util.h @@ -230,7 +230,7 @@ namespace tools bool sha256sum(const uint8_t *data, size_t len, crypto::hash &hash); bool sha256sum(const std::string &filename, crypto::hash &hash); - bool is_hdd(const char *path); + boost::optional is_hdd(const char *path); boost::optional> parse_subaddress_lookahead(const std::string& str); diff --git a/tests/unit_tests/CMakeLists.txt b/tests/unit_tests/CMakeLists.txt index 076a4a873..7366990ad 100644 --- a/tests/unit_tests/CMakeLists.txt +++ b/tests/unit_tests/CMakeLists.txt @@ -77,7 +77,8 @@ set(unit_tests_sources output_selection.cpp vercmp.cpp ringdb.cpp - wipeable_string.cpp) + wipeable_string.cpp + is_hdd.cpp) set(unit_tests_headers unit_tests_utils.h) diff --git a/tests/unit_tests/is_hdd.cpp b/tests/unit_tests/is_hdd.cpp new file mode 100644 index 000000000..1be670e5e --- /dev/null +++ b/tests/unit_tests/is_hdd.cpp @@ -0,0 +1,17 @@ +#include "common/util.h" +#include +#include + +#if defined(__GLIBC__) +TEST(is_hdd, linux_os_root) +{ + std::string path = "/"; + EXPECT_TRUE(tools::is_hdd(path.c_str())); +} +#else +TEST(is_hdd, unknown_os) +{ + std::string path = ""; + EXPECT_FALSE(tools::is_hdd(path.c_str())); +} +#endif