Files

469 lines
13 KiB
C++
Raw Permalink Normal View History

2017-11-09 19:34:51 +01:00
/*
* This file is part of the Flowee project
* Copyright (C) 2009-2010 Satoshi Nakamoto
* Copyright (C) 2009-2015 The Bitcoin Core developers
2024-08-31 23:11:09 +02:00
* Copyright (C) 2017-2018,2024 Tom Zander <tom@flowee.org>
2017-11-09 19:34:51 +01:00
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
2012-03-31 15:22:45 +02:00
#if defined(HAVE_CONFIG_H)
2018-01-16 10:47:52 +00:00
#include "config/flowee-config.h"
#endif
2013-04-13 00:13:08 -05:00
#include "util.h"
2018-02-12 14:15:24 +01:00
#include <SettingsDefaults.h>
2013-01-28 00:07:51 +01:00
#include "chainparamsbase.h"
#include "sync.h"
2014-08-21 16:11:09 +02:00
#include "utilstrencodings.h"
2013-04-13 00:13:08 -05:00
2015-03-27 13:19:49 +01:00
#if (defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__))
#include <pthread.h>
#include <pthread_np.h>
#endif
2013-04-13 00:13:08 -05:00
#ifndef WIN32
// for posix_fallocate
2014-08-12 12:05:03 +02:00
#ifdef __linux__
2013-04-13 00:13:08 -05:00
#ifdef _POSIX_C_SOURCE
#undef _POSIX_C_SOURCE
#endif
#define _POSIX_C_SOURCE 200112L
2014-08-12 12:05:03 +02:00
#endif // __linux__
2013-04-13 00:13:08 -05:00
#include <fcntl.h>
#include <sys/resource.h>
#include <sys/stat.h>
#else
#ifdef _MSC_VER
#pragma warning(disable:4786)
#pragma warning(disable:4804)
#pragma warning(disable:4805)
#pragma warning(disable:4717)
#endif
#ifdef _WIN32_WINNT
#undef _WIN32_WINNT
#endif
#define _WIN32_WINNT 0x0501
#ifdef _WIN32_IE
#undef _WIN32_IE
#endif
#define _WIN32_IE 0x0501
#define WIN32_LEAN_AND_MEAN 1
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include <io.h> /* for _commit */
#include <shlobj.h>
#endif
#ifdef HAVE_SYS_PRCTL_H
#include <sys/prctl.h>
#endif
2012-10-02 21:36:39 +02:00
#include <boost/algorithm/string/case_conv.hpp> // for to_lower()
2013-04-13 00:13:08 -05:00
#include <boost/algorithm/string/join.hpp>
2017-05-15 14:39:52 +02:00
#include <boost/algorithm/string/trim.hpp>
2012-10-02 21:36:39 +02:00
#include <boost/algorithm/string/predicate.hpp> // for startswith() and endswith()
2013-04-13 00:13:08 -05:00
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
#include <boost/foreach.hpp>
#include <boost/program_options/detail/config_file.hpp>
#include <boost/program_options/parsers.hpp>
2014-08-21 16:11:09 +02:00
#include <boost/thread.hpp>
2011-05-14 17:25:05 +02:00
2017-08-04 19:02:56 +05:30
std::map<std::string, std::string> mapArgs;
std::map<std::string, std::vector<std::string> > mapMultiArgs;
2011-05-14 17:25:05 +02:00
2015-06-15 17:17:23 +02:00
/** Turn -noX into -X=0 */
static void InterpretNegativeSetting(std::string& strKey, std::string& strValue)
{
if (strKey.length()>3 && strKey[0]=='-' && strKey[1]=='n' && strKey[2]=='o')
{
2015-06-15 17:17:23 +02:00
strKey = "-" + strKey.substr(3);
strValue = InterpretBool(strValue) ? "0" : "1";
}
}
2018-02-12 14:15:24 +01:00
void ParseParameters(int argc, const char* const argv[], const Settings::AllowedArgs& allowedArgs)
2011-05-14 17:25:05 +02:00
{
mapArgs.clear();
mapMultiArgs.clear();
2014-06-04 07:36:45 +03:00
2011-05-14 17:25:05 +02:00
for (int i = 1; i < argc; i++)
{
2012-10-02 21:36:39 +02:00
std::string str(argv[i]);
std::string strValue;
size_t is_index = str.find('=');
if (is_index != std::string::npos)
2011-05-14 17:25:05 +02:00
{
2012-10-02 21:36:39 +02:00
strValue = str.substr(is_index+1);
str = str.substr(0, is_index);
2011-05-14 17:25:05 +02:00
}
2012-10-02 21:36:39 +02:00
#ifdef WIN32
boost::to_lower(str);
if (boost::algorithm::starts_with(str, "/"))
str = "-" + str.substr(1);
#endif
2014-06-04 07:36:45 +03:00
2012-10-02 21:36:39 +02:00
if (str[0] != '-')
2011-05-14 17:25:05 +02:00
break;
2014-06-04 07:36:45 +03:00
// Interpret --foo as -foo.
// If both --foo and -foo are set, the last takes effect.
if (str.length() > 1 && str[1] == '-')
str = str.substr(1);
2015-06-15 17:17:23 +02:00
InterpretNegativeSetting(str, strValue);
allowedArgs.checkArg(str.substr(1), strValue);
2014-06-04 07:36:45 +03:00
2012-10-02 21:36:39 +02:00
mapArgs[str] = strValue;
mapMultiArgs[str].push_back(strValue);
2011-05-14 17:25:05 +02:00
}
}
2012-02-06 12:37:49 -05:00
std::string GetArg(const std::string& strArg, const std::string& strDefault)
{
if (mapArgs.count(strArg))
return mapArgs[strArg];
return strDefault;
}
2013-04-13 00:13:08 -05:00
int64_t GetArg(const std::string& strArg, int64_t nDefault)
2012-02-06 12:37:49 -05:00
{
if (mapArgs.count(strArg))
return atoi64(mapArgs[strArg]);
return nDefault;
}
bool GetBoolArg(const std::string& strArg, bool fDefault)
{
if (mapArgs.count(strArg))
2015-06-15 17:17:23 +02:00
return InterpretBool(mapArgs[strArg]);
2012-02-06 12:37:49 -05:00
return fDefault;
}
bool SoftSetArg(const std::string& strArg, const std::string& strValue)
{
if (mapArgs.count(strArg))
return false;
mapArgs[strArg] = strValue;
return true;
}
bool SoftSetBoolArg(const std::string& strArg, bool fValue)
{
if (fValue)
return SoftSetArg(strArg, std::string("1"));
else
return SoftSetArg(strArg, std::string("0"));
}
2014-12-07 13:29:06 +01:00
static std::string FormatException(const std::exception* pex, const char* pszThread)
2011-05-14 17:25:05 +02:00
{
2011-10-07 11:02:21 -04:00
#ifdef WIN32
char pszModule[MAX_PATH] = "";
2011-05-14 17:25:05 +02:00
GetModuleFileNameA(NULL, pszModule, sizeof(pszModule));
#else
const char* pszModule = "bitcoin";
#endif
if (pex)
return strprintf(
2011-05-14 17:25:05 +02:00
"EXCEPTION: %s \n%s \n%s in %s \n", typeid(*pex).name(), pex->what(), pszModule, pszThread);
else
return strprintf(
2011-05-14 17:25:05 +02:00
"UNKNOWN EXCEPTION \n%s in %s \n", pszModule, pszThread);
}
2014-12-07 13:29:06 +01:00
void PrintExceptionContinue(const std::exception* pex, const char* pszThread)
2011-05-14 17:25:05 +02:00
{
std::string message = FormatException(pex, pszThread);
2014-01-16 16:15:27 +01:00
LogPrintf("\n\n************************\n%s\n", message);
fprintf(stderr, "\n\n************************\n%s\n", message.c_str());
2011-05-14 17:25:05 +02:00
}
2018-01-16 20:15:22 +00:00
boost::filesystem::path GetDefaultDataDir()
2011-05-14 17:25:05 +02:00
{
namespace fs = boost::filesystem;
2018-03-07 22:13:10 +01:00
// Windows: C:\Users\Username\AppData\Roaming\flowee
// Mac: ~/Library/Application Support/flowee
// Unix: $XDG_DATA_HOME/flowee (typically $HOME/.local/share/flowee)
2017-07-31 23:12:53 +02:00
2018-03-07 22:13:10 +01:00
std::string dirName = "flowee";
2017-07-31 23:12:53 +02:00
2011-10-07 11:02:21 -04:00
#ifdef WIN32
2011-05-14 17:25:05 +02:00
// Windows
2017-07-31 23:12:53 +02:00
return GetSpecialFolderPath(CSIDL_APPDATA) / dirName;
2011-05-14 17:25:05 +02:00
#else
2017-01-12 18:00:09 -08:00
fs::path pathHome;
2011-05-14 17:25:05 +02:00
char* pszHome = getenv("HOME");
if (pszHome == NULL || strlen(pszHome) == 0)
2017-01-12 18:00:09 -08:00
pathHome = fs::path("/");
else
2017-01-12 18:00:09 -08:00
pathHome = fs::path(pszHome);
2011-10-07 11:02:21 -04:00
#ifdef MAC_OSX
2011-05-14 17:25:05 +02:00
// Mac
2017-08-07 09:50:22 +02:00
return pathHome / "Library/Application Support" / dirName;
2011-05-14 17:25:05 +02:00
#else
2017-01-12 18:00:09 -08:00
fs::path pathDataHome;
char* pszDataHome = getenv("XDG_DATA_HOME");
if (pszDataHome == NULL || strlen(pszDataHome) == 0)
pathDataHome = pathHome / ".local/share";
else
2017-01-12 18:00:09 -08:00
pathDataHome = fs::path(pszDataHome);
2017-07-31 23:12:53 +02:00
return pathDataHome / dirName;
2011-05-14 17:25:05 +02:00
#endif
#endif
}
static boost::filesystem::path pathCached;
static boost::filesystem::path pathCachedNetSpecific;
static CCriticalSection csPathCached;
const boost::filesystem::path &GetDataDir(bool fNetSpecific)
2011-05-14 17:25:05 +02:00
{
namespace fs = boost::filesystem;
LOCK(csPathCached);
fs::path &path = fNetSpecific ? pathCachedNetSpecific : pathCached;
2013-09-19 14:47:21 +02:00
// This can be called during exceptions by LogPrintf(), so we cache the
// value so we don't have to do memory allocations after that.
if (!path.empty())
return path;
if (mapArgs.count("-datadir")) {
2012-04-22 14:35:22 +02:00
path = fs::system_complete(mapArgs["-datadir"]);
if (!fs::is_directory(path)) {
path = "";
return path;
}
} else {
2018-01-16 20:15:22 +00:00
path = GetDefaultDataDir();
2011-05-14 17:25:05 +02:00
}
if (fNetSpecific)
path /= BaseParams().DataDir();
fs::create_directories(path);
return path;
2011-05-14 17:25:05 +02:00
}
void ClearDatadirCache()
{
pathCached = boost::filesystem::path();
pathCachedNetSpecific = boost::filesystem::path();
}
2018-03-07 22:13:10 +01:00
boost::filesystem::path GetConfigFile(const std::string &filename)
2011-05-14 17:25:05 +02:00
{
2017-01-12 18:00:09 -08:00
namespace fs = boost::filesystem;
2024-08-31 23:11:09 +02:00
const fs::path floweeConfigFile = GetArg("-conf", Settings::hubConfFilename());
2017-01-12 18:00:09 -08:00
2024-08-31 23:11:09 +02:00
auto testValid = [=](fs::path &path, const char *envVar = nullptr, const char *subdir = nullptr) -> bool {
auto filePart = filename;
if (filePart.empty())
filePart = Settings::hubConfFilename();
if (envVar) {
assert(subdir);
const char *p = getenv(envVar);
if (!p || strlen(p) == 0)
return false;
path = fs::path(p);
path /= fs::path(subdir) / filePart;
return fs::exists(path);
}
path /= filePart;
return fs::exists(path);
};
2017-01-12 18:00:09 -08:00
2024-08-31 23:11:09 +02:00
/*
* Asking with an empty filename means we need just the hub general config
* file.
* We try:
* 1. in case of user-set absolute filename, that is what we use.
* 2. check XDG dir
* 3. check $HOME/.config/flowee/ dir
*/
if (filename.empty()) {
assert(!floweeConfigFile.empty());
if (floweeConfigFile.is_absolute() || fs::exists(floweeConfigFile))
return floweeConfigFile;
fs::path path;
if (testValid(path, "XDG_CONFIG_HOME", "flowee"))
return path;
if (testValid(path, "HOME", ".config/flowee"))
return path;
return floweeConfigFile; // doesn't exist, though.
2018-03-07 22:13:10 +01:00
}
2024-08-31 23:11:09 +02:00
/*
* Any config file that is not the hubConfFilename will be tried in
* 1. the effective data directory. (testnet4 subdir, for instance)
* 2. the main datadir (which is the same as 1 in case of mainnet)
* 3. the same dir that the flowee.conf lives in.
* 4. The $XDG_CONFIG_HOME/ dir
* 5. In $HOME/.config/flowee/
*/
auto path = GetDataDir(true);
if (testValid(path))
return path;
path = GetDataDir(false);
if (testValid(path))
return path;
2017-01-12 18:00:09 -08:00
2024-08-31 23:11:09 +02:00
path = floweeConfigFile.parent_path();
if (testValid(path))
return path;
if (testValid(path, "XDG_CONFIG_HOME", "flowee"))
return path;
if (testValid(path, "HOME", ".config/flowee"))
return path;
return floweeConfigFile;
2011-05-14 17:25:05 +02:00
}
2017-08-04 19:02:56 +05:30
void ReadConfigFile(std::map<std::string, std::string>& mapSettingsRet,
std::map<std::string, std::vector<std::string> >& mapMultiSettingsRet)
2011-05-14 17:25:05 +02:00
{
boost::filesystem::ifstream streamConfig(GetConfigFile());
2011-05-14 17:25:05 +02:00
if (!streamConfig.good())
2018-03-07 22:13:10 +01:00
return; // No flowee.conf file is OK
2011-05-14 17:25:05 +02:00
2017-08-04 19:02:56 +05:30
std::set<std::string> setOptions;
2011-05-14 17:25:05 +02:00
setOptions.insert("*");
2018-02-12 14:15:24 +01:00
Settings::ConfigFile allowedArgs;
for (boost::program_options::detail::config_file_iterator it(streamConfig, setOptions), end; it != end; ++it)
2011-05-14 17:25:05 +02:00
{
2018-03-07 22:13:10 +01:00
// Don't overwrite existing settings so command line settings override flowee.conf
2017-08-04 19:02:56 +05:30
std::string strKey = std::string("-") + it->string_key;
std::string strValue = it->value[0];
2015-06-15 17:17:23 +02:00
InterpretNegativeSetting(strKey, strValue);
allowedArgs.checkArg(strKey.substr(1), strValue);
2011-05-14 17:25:05 +02:00
if (mapSettingsRet.count(strKey) == 0)
2015-06-15 17:17:23 +02:00
mapSettingsRet[strKey] = strValue;
mapMultiSettingsRet[strKey].push_back(strValue);
2011-05-14 17:25:05 +02:00
}
// If datadir is changed in .conf file:
ClearDatadirCache();
2011-05-14 17:25:05 +02:00
}
/**
* Ignores exceptions thrown by Boost's create_directory if the requested directory exists.
* Specifically handles case where path p exists, but it wasn't possible for the user to
* write to the parent directory.
*/
bool TryCreateDirectory(const boost::filesystem::path& p)
{
try
{
2017-08-03 12:25:07 +02:00
return boost::filesystem::create_directories(p);
2014-12-07 13:29:06 +01:00
} catch (const boost::filesystem::filesystem_error&) {
if (!boost::filesystem::exists(p) || !boost::filesystem::is_directory(p))
throw;
}
// create_directory didn't create the directory, it had to have existed already
return false;
}
2012-04-15 22:10:54 +02:00
#ifdef WIN32
boost::filesystem::path GetSpecialFolderPath(int nFolder, bool fCreate)
{
namespace fs = boost::filesystem;
char pszPath[MAX_PATH] = "";
if(SHGetSpecialFolderPathA(NULL, pszPath, nFolder, fCreate))
{
return fs::path(pszPath);
}
2013-09-18 20:38:08 +10:00
LogPrintf("SHGetSpecialFolderPathA() failed, could not obtain requested path.\n");
return fs::path("");
}
2012-04-15 22:10:54 +02:00
#endif
2012-05-23 23:10:59 -04:00
void RenameThread(const char* name)
{
#if defined(PR_SET_NAME)
// Only the first 15 characters are used (16 - NUL terminator)
::prctl(PR_SET_NAME, name, 0, 0, 0);
2015-04-29 20:04:34 +07:00
#elif (defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__))
pthread_set_name_np(pthread_self(), name);
#elif defined(MAC_OSX)
2013-03-06 22:16:05 -05:00
pthread_setname_np(name);
#else
// Prevent warnings for unused parameters...
(void)name;
#endif
}
void SetThreadPriority(int nPriority)
{
#ifdef WIN32
SetThreadPriority(GetCurrentThread(), nPriority);
#else // WIN32
#ifdef PRIO_THREAD
setpriority(PRIO_THREAD, 0, nPriority);
#else // PRIO_THREAD
setpriority(PRIO_PROCESS, 0, nPriority);
#endif // PRIO_THREAD
#endif // WIN32
}
2019-11-13 11:46:09 +01:00
std::string ChainNameFromCommandLine()
{
2020-09-26 14:30:05 -04:00
int num_selected = 0;
2019-11-13 11:46:09 +01:00
bool fRegTest = GetBoolArg("-regtest", false);
2020-09-26 14:30:05 -04:00
if (fRegTest) num_selected++;
2019-11-13 11:46:09 +01:00
bool fTestNet = GetBoolArg("-testnet", false);
2020-09-26 14:30:05 -04:00
if (fTestNet) num_selected++;
bool fTestNet4 = GetBoolArg("-testnet4", false);
if (fTestNet4) num_selected++;
2020-09-26 14:32:12 -04:00
bool fScaleNet = GetBoolArg("-scalenet", false);
if (fScaleNet) num_selected++;
bool fChipNet = GetBoolArg("-chipnet", false);
if (fChipNet) num_selected++;
2020-09-26 14:32:12 -04:00
2020-09-26 14:30:05 -04:00
if (num_selected > 1)
throw std::runtime_error("Invalid combination of -regtest, -testnet, -testnet4, -scalenet and -chipnet.");
2019-11-13 11:46:09 +01:00
if (fRegTest)
return CBaseChainParams::REGTEST;
if (fTestNet)
return CBaseChainParams::TESTNET;
2020-09-26 14:30:05 -04:00
if (fTestNet4)
return CBaseChainParams::TESTNET4;
2020-09-26 14:32:12 -04:00
if (fScaleNet)
return CBaseChainParams::SCALENET;
if (fChipNet)
return CBaseChainParams::CHIPNET;
2019-11-13 11:46:09 +01:00
return CBaseChainParams::MAIN;
}