diff --git a/doc/release-notes.md b/doc/release-notes.md --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -21,3 +21,9 @@ - The `getmininginfo` RPC now omits `currentblocksize` and `currentblocktx` when a block was never assembled via RPC on this node. +Seeder +------ + - Added the `seederdir` option to the seeder allowing a directory to be + specified for the files the seeder writes to and reads from (default is the + `~/.bitcoin` directory). See help for more details. + diff --git a/src/Makefile.am b/src/Makefile.am --- a/src/Makefile.am +++ b/src/Makefile.am @@ -553,6 +553,8 @@ seeder/db.h \ seeder/dns.cpp \ seeder/dns.h \ + seeder/filesystem.cpp \ + seeder/filesystem.h \ seeder/util.h nodist_libbitcoin_util_a_SOURCES = $(srcdir)/obj/build.h diff --git a/src/seeder/CMakeLists.txt b/src/seeder/CMakeLists.txt --- a/src/seeder/CMakeLists.txt +++ b/src/seeder/CMakeLists.txt @@ -4,7 +4,7 @@ project(bitcoin-seeder) -add_library(seeder bitcoin.cpp db.cpp dns.cpp) +add_library(seeder bitcoin.cpp db.cpp dns.cpp filesystem.cpp) target_link_libraries(seeder common bitcoinconsensus) add_executable(bitcoin-seeder main.cpp) diff --git a/src/seeder/filesystem.h b/src/seeder/filesystem.h new file mode 100644 --- /dev/null +++ b/src/seeder/filesystem.h @@ -0,0 +1,14 @@ +// Copyright (c) 2020 The Bitcoin developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_SEEDER_FILESYSTEM_H +#define BITCOIN_SEEDER_FILESYSTEM_H + +#include + +// The seeder directory is always net specific. +const fs::path &GetSeederDir(); +bool CheckSeederDirOption(); + +#endif // BITCOIN_SEEDER_FILESYSTEM_H diff --git a/src/seeder/filesystem.cpp b/src/seeder/filesystem.cpp new file mode 100644 --- /dev/null +++ b/src/seeder/filesystem.cpp @@ -0,0 +1,40 @@ +// Copyright (c) 2020 The Bitcoin developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include +#include + +static fs::path seederPathCachedNetSpecific; +static RecursiveMutex csSeederPathCached; + +const fs::path &GetSeederDir() { + LOCK(csSeederPathCached); + fs::path &path = seederPathCachedNetSpecific; + + // Cache the path to avoid calling fs::create_directories on every call of + // this function + if (!path.empty()) { + return path; + } + if (gArgs.IsArgSet("-seederdir")) { + path = fs::system_complete(gArgs.GetArg("-seederdir", "")); + if (!fs::is_directory(path)) { + path = ""; + return path; + } + } else { + path = GetDataDir(false); + } + + path /= BaseParams().DataDir(); + path /= "seeder"; + fs::create_directories(path); + return path; +} + +bool CheckSeederDirOption() { + std::string seederdir = gArgs.GetArg("-seederdir", ""); + return seederdir.empty() || + fs::is_directory(fs::system_complete(seederdir)); +} diff --git a/src/seeder/main.cpp b/src/seeder/main.cpp --- a/src/seeder/main.cpp +++ b/src/seeder/main.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -94,6 +95,26 @@ ipv6_proxy = gArgs.GetArg("-proxyipv6", DEFAULT_IPV6_PROXY); SelectParams(gArgs.GetChainName()); + if (!CheckSeederDirOption()) { + tfm::format(std::cout, + "Specified data directory \"%s\" does not exist.\n", + gArgs.GetArg("-seederdir", "")); + return EXIT_FAILURE; + } + + // Warn about relative -seederdir path + if (gArgs.IsArgSet("-seederdir") && + !fs::path(gArgs.GetArg("-seederdir", "")).is_absolute()) { + tfm::format( + std::cout, + "Warning: relative seederdir option '%s' specified, which will " + "be interpreted relative to the current working directory " + "'%s'. This is fragile, because if the seeder is started in " + "the future from a different location, it will be unable to " + "locate the current data files.\n", + gArgs.GetArg("-seederdir", ""), fs::current_path().string()); + } + if (gArgs.IsArgSet("-filter")) { // Parse whitelist additions std::string flagString = gArgs.GetArg("-filter", ""); @@ -154,6 +175,10 @@ gArgs.AddArg("-help-debug", "Show all debugging options (usage: --help -help-debug)", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST); + gArgs.AddArg("-seederdir=", + "Specify directory to hold the subdirectory for files the " + "seeder writes to and reads from (default: ~/.bitcoin/)", + ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); SetupChainParamsBaseOptions(); gArgs.AddArg("-help", "", ArgsManager::ALLOW_ANY, @@ -382,15 +407,16 @@ { std::vector v = db.GetAll(); sort(v.begin(), v.end(), StatCompare); - FILE *f = fsbridge::fopen("dnsseed.dat.new", "w+"); + FILE *f = fsbridge::fopen(GetSeederDir() / "dnsseed.dat.new", "w+"); if (f) { { CAutoFile cf(f, SER_DISK, CLIENT_VERSION); cf << db; } - rename("dnsseed.dat.new", "dnsseed.dat"); + rename(GetSeederDir() / "dnsseed.dat.new", + GetSeederDir() / "dnsseed.dat"); } - fsbridge::ofstream d{"dnsseed.dump"}; + fsbridge::ofstream d{GetSeederDir() / "dnsseed.dump"}; tfm::format( d, "# address good " "lastSuccess %%(2h) %%(8h) %%(1d) %%(7d) " @@ -413,7 +439,8 @@ stat[3] += rep.uptime[3]; stat[4] += rep.uptime[4]; } - fsbridge::ofstream ff{"dnsstats.log", std::ios_base::app}; + fsbridge::ofstream ff{GetSeederDir() / "dnsstats.log", + std::ios_base::app}; tfm::format(ff, "%llu %g %g %g %g %g\n", (unsigned long long)(time(nullptr)), stat[0], stat[1], stat[2], stat[3], stat[4]); @@ -534,7 +561,8 @@ tfm::format(std::cerr, "No e-mail address set. Please use -m.\n"); return EXIT_FAILURE; } - FILE *f = fsbridge::fopen("dnsseed.dat", "r"); + + FILE *f = fsbridge::fopen(GetSeederDir() / "dnsseed.dat", "r"); if (f) { tfm::format(std::cout, "Loading dnsseed.dat..."); CAutoFile cf(f, SER_DISK, CLIENT_VERSION);