Line data Source code
1 : // Copyright (c) 2009-2010 Satoshi Nakamoto 2 : // Copyright (c) 2009-2020 The Bitcoin Core developers 3 : // Distributed under the MIT software license, see the accompanying 4 : // file COPYING or http://www.opensource.org/licenses/mit-license.php. 5 : 6 : #if defined(HAVE_CONFIG_H) 7 : #include <config/bitcoin-config.h> 8 : #endif 9 : 10 : #include <chainparams.h> 11 : #include <clientversion.h> 12 : #include <compat.h> 13 : #include <init.h> 14 : #include <interfaces/chain.h> 15 : #include <node/context.h> 16 : #include <node/ui_interface.h> 17 : #include <noui.h> 18 : #include <shutdown.h> 19 : #include <util/ref.h> 20 : #include <util/strencodings.h> 21 : #include <util/system.h> 22 : #include <util/threadnames.h> 23 : #include <util/translation.h> 24 : #include <util/url.h> 25 : 26 : #include <functional> 27 : 28 549 : const std::function<std::string(const char*)> G_TRANSLATION_FUN = nullptr; 29 : UrlDecodeFn* const URL_DECODE = urlDecode; 30 : 31 492 : static void WaitForShutdown(NodeContext& node) 32 : { 33 64421 : while (!ShutdownRequested()) 34 : { 35 63929 : UninterruptibleSleep(std::chrono::milliseconds{200}); 36 : } 37 492 : Interrupt(node); 38 492 : } 39 : 40 : ////////////////////////////////////////////////////////////////////////////// 41 : // 42 : // Start 43 : // 44 549 : static bool AppInit(int argc, char* argv[]) 45 : { 46 549 : NodeContext node; 47 : 48 : bool fRet = false; 49 : 50 549 : util::ThreadSetInternalName("init"); 51 : 52 : // If Qt is used, parameters/bitcoin.conf are parsed in qt/bitcoin.cpp's main() 53 549 : SetupServerArgs(node); 54 1098 : ArgsManager& args = *Assert(node.args); 55 549 : std::string error; 56 549 : if (!args.ParseParameters(argc, argv, error)) { 57 3 : return InitError(Untranslated(strprintf("Error parsing command line arguments: %s\n", error))); 58 : } 59 : 60 : // Process help and version before taking care about datadir 61 546 : if (HelpRequested(args) || args.IsArgSet("-version")) { 62 2 : std::string strUsage = PACKAGE_NAME " version " + FormatFullVersion() + "\n"; 63 : 64 2 : if (args.IsArgSet("-version")) { 65 1 : strUsage += FormatParagraph(LicenseInfo()) + "\n"; 66 1 : } else { 67 1 : strUsage += "\nUsage: bitcoind [options] Start " PACKAGE_NAME "\n"; 68 1 : strUsage += "\n" + args.GetHelpMessage(); 69 : } 70 : 71 2 : tfm::format(std::cout, "%s", strUsage); 72 : return true; 73 2 : } 74 : 75 544 : util::Ref context{node}; 76 : try 77 : { 78 544 : if (!CheckDataDirOption()) { 79 1 : return InitError(Untranslated(strprintf("Specified data directory \"%s\" does not exist.\n", args.GetArg("-datadir", "")))); 80 : } 81 543 : if (!args.ReadConfigFiles(error, true)) { 82 7 : return InitError(Untranslated(strprintf("Error reading configuration file: %s\n", error))); 83 : } 84 : // Check for -chain, -testnet or -regtest parameter (Params() calls are only valid after this clause) 85 : try { 86 536 : SelectParams(args.GetChainName()); 87 0 : } catch (const std::exception& e) { 88 0 : return InitError(Untranslated(strprintf("%s\n", e.what()))); 89 0 : } 90 : 91 : // Error out when loose non-argument tokens are encountered on command line 92 5077 : for (int i = 1; i < argc; i++) { 93 4541 : if (!IsSwitchChar(argv[i][0])) { 94 0 : return InitError(Untranslated(strprintf("Command line contains unexpected token '%s', see bitcoind -h for a list of options.\n", argv[i]))); 95 : } 96 : } 97 : 98 536 : if (!args.InitSettings(error)) { 99 3 : InitError(Untranslated(error)); 100 3 : return false; 101 : } 102 : 103 : // -server defaults to true for bitcoind but not for the GUI so do this here 104 533 : args.SoftSetBoolArg("-server", true); 105 : // Set this early so that parameter interactions go to console 106 533 : InitLogging(args); 107 533 : InitParameterInteraction(args); 108 533 : if (!AppInitBasicSetup(args)) { 109 : // InitError will have been called with detailed error, which ends up on console 110 0 : return false; 111 : } 112 533 : if (!AppInitParameterInteraction(args)) { 113 : // InitError will have been called with detailed error, which ends up on console 114 3 : return false; 115 : } 116 530 : if (!AppInitSanityChecks()) 117 : { 118 : // InitError will have been called with detailed error, which ends up on console 119 1 : return false; 120 : } 121 529 : if (args.GetBoolArg("-daemon", false)) { 122 : #if HAVE_DECL_DAEMON 123 : #if defined(MAC_OSX) 124 : #pragma GCC diagnostic push 125 : #pragma GCC diagnostic ignored "-Wdeprecated-declarations" 126 : #endif 127 0 : tfm::format(std::cout, PACKAGE_NAME " starting\n"); 128 : 129 : // Daemonize 130 0 : if (daemon(1, 0)) { // don't chdir (1), do close FDs (0) 131 0 : return InitError(Untranslated(strprintf("daemon() failed: %s\n", strerror(errno)))); 132 : } 133 : #if defined(MAC_OSX) 134 : #pragma GCC diagnostic pop 135 : #endif 136 : #else 137 : return InitError(Untranslated("-daemon is not supported on this operating system\n")); 138 : #endif // HAVE_DECL_DAEMON 139 : } 140 : // Lock data directory after daemonization 141 529 : if (!AppInitLockDataDirectory()) 142 : { 143 : // If locking the data directory failed, exit immediately 144 0 : return false; 145 : } 146 529 : fRet = AppInitInterfaces(node) && AppInitMain(context, node); 147 529 : } 148 : catch (const std::exception& e) { 149 2 : PrintExceptionContinue(&e, "AppInit()"); 150 2 : } catch (...) { 151 0 : PrintExceptionContinue(nullptr, "AppInit()"); 152 2 : } 153 : 154 529 : if (!fRet) 155 : { 156 37 : Interrupt(node); 157 : } else { 158 492 : WaitForShutdown(node); 159 : } 160 529 : Shutdown(node); 161 : 162 529 : return fRet; 163 551 : } 164 : 165 549 : int main(int argc, char* argv[]) 166 : { 167 : #ifdef WIN32 168 : util::WinCmdLineArgs winArgs; 169 : std::tie(argc, argv) = winArgs.get(); 170 : #endif 171 549 : SetupEnvironment(); 172 : 173 : // Connect bitcoind signal handlers 174 549 : noui_connect(); 175 : 176 549 : return (AppInit(argc, argv) ? EXIT_SUCCESS : EXIT_FAILURE); 177 : }