diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp --- a/src/bitcoind.cpp +++ b/src/bitcoind.cpp @@ -19,13 +19,12 @@ #include #include #include +#include #include #include #include #include -#include - const std::function G_TRANSLATION_FUN = nullptr; /* Introduction text for doxygen: */ @@ -83,9 +82,8 @@ SetupServerArgs(); std::string error; if (!gArgs.ParseParameters(argc, argv, error)) { - tfm::format(std::cerr, "Error parsing command line arguments: %s\n", - error.c_str()); - return false; + return InitError( + strprintf("Error parsing command line arguments: %s\n", error)); } // Process help and version before taking care about datadir @@ -108,24 +106,20 @@ try { if (!fs::is_directory(GetDataDir(false))) { - tfm::format( - std::cerr, - "Error: Specified data directory \"%s\" does not exist.\n", - gArgs.GetArg("-datadir", "").c_str()); - return false; + return InitError( + strprintf("Specified data directory \"%s\" does not exist.\n", + gArgs.GetArg("-datadir", ""))); } if (!gArgs.ReadConfigFiles(error, true)) { - tfm::format(std::cerr, "Error reading configuration file: %s\n", - error.c_str()); - return false; + return InitError( + strprintf("Error reading configuration file: %s\n", error)); } // Check for -testnet or -regtest parameter (Params() calls are only // valid after this clause) try { SelectParams(gArgs.GetChainName()); } catch (const std::exception &e) { - tfm::format(std::cerr, "Error: %s\n", e.what()); - return false; + return InitError(strprintf("%s\n", e.what())); } // Make sure we create the net-specific data directory early on: if it @@ -142,12 +136,10 @@ // line for (int i = 1; i < argc; i++) { if (!IsSwitchChar(argv[i][0])) { - tfm::format( - std::cerr, - "Error: Command line contains unexpected token '%s', " - "see bitcoind -h for a list of options.\n", - argv[i]); - return false; + return InitError( + strprintf("Command line contains unexpected token '%s', " + "see bitcoind -h for a list of options.\n", + argv[i])); } } @@ -178,23 +170,20 @@ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated-declarations" #endif - tfm::format(std::cout, "Bitcoin server starting\n"); + tfm::format(std::cout, PACKAGE_NAME "daemon starting\n"); // Daemonize if (daemon(1, 0)) { // don't chdir (1), do close FDs (0) - tfm::format(std::cerr, "Error: daemon() failed: %s\n", - strerror(errno)); - return false; + return InitError( + strprintf("daemon() failed: %s\n", strerror(errno))); } #if defined(MAC_OSX) #pragma GCC diagnostic pop #endif #else - tfm::format( - std::cerr, - "Error: -daemon is not supported on this operating system\n"); - return false; + return InitError( + "-daemon is not supported on this operating system\n"); #endif // HAVE_DECL_DAEMON } diff --git a/src/interfaces/node.h b/src/interfaces/node.h --- a/src/interfaces/node.h +++ b/src/interfaces/node.h @@ -40,6 +40,9 @@ public: virtual ~Node() {} + //! Send init error. + virtual void initError(const std::string &message) = 0; + //! Set command line arguments. virtual bool parseParameters(int argc, const char *const argv[], std::string &error) = 0; diff --git a/src/interfaces/node.cpp b/src/interfaces/node.cpp --- a/src/interfaces/node.cpp +++ b/src/interfaces/node.cpp @@ -54,6 +54,9 @@ class NodeImpl : public Node { public: NodeImpl() { m_interfaces.chain = MakeChain(); } + void initError(const std::string &message) override { + InitError(message); + } bool parseParameters(int argc, const char *const argv[], std::string &error) override { return gArgs.ParseParameters(argc, argv, error); diff --git a/src/qt/bitcoin.h b/src/qt/bitcoin.h --- a/src/qt/bitcoin.h +++ b/src/qt/bitcoin.h @@ -12,7 +12,6 @@ #include #include -#include class BitcoinGUI; class ClientModel; diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -61,7 +61,6 @@ #endif #endif -#include #include // Declare meta types used for QMetaObject::invokeMethod @@ -572,9 +571,15 @@ SetupUIArgs(); std::string error; if (!node->parseParameters(argc, argv, error)) { + node->initError( + strprintf("Error parsing command line arguments: %s\n", error)); + // Create a message box, because the gui has neither been created nor + // has subscribed to core signals QMessageBox::critical( nullptr, PACKAGE_NAME, - QObject::tr("Error parsing command line arguments: %1.") + // message can not be translated because translations have not been + // initialized + QString::fromStdString("Error parsing command line arguments: %1.") .arg(QString::fromStdString(error))); return EXIT_FAILURE; } @@ -622,6 +627,9 @@ /// bitcoin.conf /// - Do not call GetDataDir(true) before this step finishes. if (!fs::is_directory(GetDataDir(false))) { + node->initError( + strprintf("Specified data directory \"%s\" does not exist.\n", + gArgs.GetArg("-datadir", ""))); QMessageBox::critical( nullptr, PACKAGE_NAME, QObject::tr( @@ -630,6 +638,8 @@ return EXIT_FAILURE; } if (!node->readConfigFiles(error)) { + node->initError( + strprintf("Error reading configuration file: %s\n", error)); QMessageBox::critical( nullptr, PACKAGE_NAME, QObject::tr("Error: Cannot parse configuration file: %1.") @@ -650,6 +660,7 @@ try { node->selectParams(gArgs.GetChainName()); } catch (std::exception &e) { + node->initError(strprintf("%s\n", e.what())); QMessageBox::critical(nullptr, PACKAGE_NAME, QObject::tr("Error: %1").arg(e.what())); return EXIT_FAILURE; diff --git a/test/functional/feature_config_args.py b/test/functional/feature_config_args.py --- a/test/functional/feature_config_args.py +++ b/test/functional/feature_config_args.py @@ -25,7 +25,7 @@ conf.write('includeconf={}\n'.format(inc_conf_file_path)) self.nodes[0].assert_start_raises_init_error( - expected_msg='Error parsing command line arguments: Invalid parameter -dash_cli', + expected_msg='Error: Error parsing command line arguments: Invalid parameter -dash_cli', extra_args=['-dash_cli=1'], ) with open(inc_conf_file_path, 'w', encoding='utf-8') as conf: @@ -37,7 +37,7 @@ with open(inc_conf_file_path, 'w', encoding='utf-8') as conf: conf.write('-dash=1\n') self.nodes[0].assert_start_raises_init_error( - expected_msg='Error reading configuration file: parse error on line 1: -dash=1, options in configuration file must be specified without leading -') + expected_msg='Error: Error reading configuration file: parse error on line 1: -dash=1, options in configuration file must be specified without leading -') if self.is_wallet_compiled(): with open(inc_conf_file_path, 'w', encoding='utf8') as conf: @@ -54,23 +54,23 @@ with open(inc_conf_file_path, 'w', encoding='utf-8') as conf: conf.write('nono\n') self.nodes[0].assert_start_raises_init_error( - expected_msg='Error reading configuration file: parse error on line 1: nono, if you intended to specify a negated option, use nono=1 instead') + expected_msg='Error: Error reading configuration file: parse error on line 1: nono, if you intended to specify a negated option, use nono=1 instead') with open(inc_conf_file_path, 'w', encoding='utf-8') as conf: conf.write('server=1\nrpcuser=someuser\nrpcpassword=some#pass') self.nodes[0].assert_start_raises_init_error( - expected_msg='Error reading configuration file: parse error on line 3, using # in rpcpassword can be ambiguous and should be avoided') + expected_msg='Error: Error reading configuration file: parse error on line 3, using # in rpcpassword can be ambiguous and should be avoided') with open(inc_conf_file_path, 'w', encoding='utf-8') as conf: conf.write('server=1\nrpcuser=someuser\nmain.rpcpassword=some#pass') self.nodes[0].assert_start_raises_init_error( - expected_msg='Error reading configuration file: parse error on line 3, using # in rpcpassword can be ambiguous and should be avoided') + expected_msg='Error: Error reading configuration file: parse error on line 3, using # in rpcpassword can be ambiguous and should be avoided') with open(inc_conf_file_path, 'w', encoding='utf-8') as conf: conf.write( 'server=1\nrpcuser=someuser\n[main]\nrpcpassword=some#pass') self.nodes[0].assert_start_raises_init_error( - expected_msg='Error reading configuration file: parse error on line 4, using # in rpcpassword can be ambiguous and should be avoided') + expected_msg='Error: Error reading configuration file: parse error on line 4, using # in rpcpassword can be ambiguous and should be avoided') inc_conf_file2_path = os.path.join( self.nodes[0].datadir, 'include2.conf') @@ -130,14 +130,16 @@ f.write(conf_file_contents) self.nodes[0].assert_start_raises_init_error( - ['-conf=' + conf_file], 'Error reading configuration file: specified data directory "' + new_data_dir + '" does not exist.') + ['-conf=' + conf_file], 'Error: Error reading configuration file: specified data directory "' + new_data_dir + '" does not exist.') # Create the directory and ensure the config file now works os.mkdir(new_data_dir) self.start_node(0, ['-conf=' + conf_file, '-wallet=w1']) self.stop_node(0) - assert os.path.exists(os.path.join( - new_data_dir, 'regtest', 'wallets', 'w1')) + assert os.path.exists(os.path.join(new_data_dir, 'regtest', 'blocks')) + if self.is_wallet_compiled(): + assert os.path.exists(os.path.join( + new_data_dir, 'regtest', 'wallets', 'w1')) # Ensure command line argument overrides datadir in conf os.mkdir(new_data_dir_2) diff --git a/test/functional/feature_includeconf.py b/test/functional/feature_includeconf.py --- a/test/functional/feature_includeconf.py +++ b/test/functional/feature_includeconf.py @@ -46,7 +46,7 @@ self.log.info("-includeconf cannot be used as command-line arg") self.stop_node(0) self.nodes[0].assert_start_raises_init_error(extra_args=["-includeconf=relative2.conf"], - expected_msg="Error parsing command line arguments: -includeconf cannot be used from commandline; -includeconf=relative2.conf") + expected_msg="Error: Error parsing command line arguments: -includeconf cannot be used from commandline; -includeconf=relative2.conf") self.log.info( "-includeconf cannot be used recursively. subversion should end with 'main; relative)/'") @@ -65,13 +65,13 @@ # with open(os.path.join(self.options.tmpdir, "node0", "relative.conf"), "w", encoding="utf8") as f: # f.write("foo=bar\n") # self.nodes[0].assert_start_raises_init_error( - # expected_msg="Error reading configuration file: Invalid configuration value foo") + # expected_msg="Error: Error reading configuration file: Invalid configuration value foo") # See https://github.com/bitcoin/bitcoin/pull/13799 self.log.info("-includeconf cannot be invalid path") os.remove(os.path.join(self.options.tmpdir, "node0", "relative.conf")) self.nodes[0].assert_start_raises_init_error( - expected_msg="Error reading configuration file: Failed to include configuration file relative.conf") + expected_msg="Error: Error reading configuration file: Failed to include configuration file relative.conf") self.log.info( "multiple -includeconf args can be used from the base config file. subversion should end with 'main; relative; relative2)/'")