Bitcoin Core 32.99.0
P2P Digital Currency
Loading...
Searching...
No Matches
bitcoind.cpp
Go to the documentation of this file.
1// Copyright (c) 2009-2010 Satoshi Nakamoto
2// Copyright (c) 2009-present 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#include <bitcoin-build-config.h> // IWYU pragma: keep
7
8#include <chainparams.h>
9#include <clientversion.h>
10#include <common/args.h>
11#include <common/init.h>
12#include <common/license_info.h>
13#include <common/system.h>
14#include <compat/compat.h>
15#include <init.h>
16#include <interfaces/chain.h>
17#include <interfaces/init.h>
18#include <kernel/context.h>
19#include <logging.h>
20#include <node/context.h>
21#include <node/interface_ui.h>
22#include <node/warnings.h>
23#include <noui.h>
24#include <util/check.h>
25#include <util/exception.h>
27#include <util/strencodings.h>
28#include <util/syserror.h>
29#include <util/threadnames.h>
30#include <util/tokenpipe.h>
31#include <util/translation.h>
32
33#include <any>
34#include <functional>
35#include <optional>
36
38
40
41#if HAVE_DECL_FORK
42
54{
55 // communication pipe with child process
56 std::optional<TokenPipe> umbilical = TokenPipe::Make();
57 if (!umbilical) {
58 return -1; // pipe or pipe2 failed.
59 }
60
61 int pid = fork();
62 if (pid < 0) {
63 return -1; // fork failed.
64 }
65 if (pid != 0) {
66 // Parent process gets read end, closes write end.
67 endpoint = umbilical->TakeReadEnd();
68 umbilical->TakeWriteEnd().Close();
69
70 int status = endpoint.TokenRead();
71 if (status != 0) { // Something went wrong while setting up child process.
72 endpoint.Close();
73 return -1;
74 }
75
76 return pid;
77 }
78 // Child process gets write end, closes read end.
79 endpoint = umbilical->TakeWriteEnd();
80 umbilical->TakeReadEnd().Close();
81
82#if HAVE_DECL_SETSID
83 if (setsid() < 0) {
84 exit(1); // setsid failed.
85 }
86#endif
87
88 if (!nochdir) {
89 if (chdir("/") != 0) {
90 exit(1); // chdir failed.
91 }
92 }
93 if (!noclose) {
94 // Open /dev/null, and clone it into STDIN, STDOUT and STDERR to detach
95 // from terminal.
96 int fd = open("/dev/null", O_RDWR);
97 if (fd >= 0) {
98 bool err = dup2(fd, STDIN_FILENO) < 0 || dup2(fd, STDOUT_FILENO) < 0 || dup2(fd, STDERR_FILENO) < 0;
99 // Don't close if fd<=2 to try to handle the case where the program was invoked without any file descriptors open.
100 if (fd > 2) close(fd);
101 if (err) {
102 exit(1); // dup2 failed.
103 }
104 } else {
105 exit(1); // open /dev/null failed.
106 }
107 }
108 endpoint.TokenWrite(0); // Success
109 return 0;
110}
111
112#endif
113
114static bool ParseArgs(NodeContext& node, int argc, char* argv[])
115{
116 ArgsManager& args{*Assert(node.args)};
117 // If Qt is used, parameters/bitcoin.conf are parsed in qt/bitcoin.cpp's main()
118 SetupServerArgs(args, node.init->canListenIpc());
119 std::string error;
120 if (!args.ParseParameters(argc, argv, error)) {
121 return InitError(Untranslated(strprintf("Error parsing command line arguments: %s", error)));
122 }
123
124 if (auto error = common::InitConfig(args)) {
125 return InitError(error->message, error->details);
126 }
127
128 // Error out when loose non-argument tokens are encountered on command line
129 for (int i = 1; i < argc; i++) {
130 if (!IsSwitchChar(argv[i][0])) {
131 return InitError(Untranslated(strprintf("Command line contains unexpected token '%s', see bitcoind -h for a list of options.", argv[i])));
132 }
133 }
134 return true;
135}
136
138{
139 // Process help and version before taking care about datadir
140 if (HelpRequested(args) || args.GetBoolArg("-version", false)) {
141 std::string strUsage = CLIENT_NAME " daemon version " + FormatFullVersion();
142 if (const char* exe_name{init.exeName()}) {
143 strUsage += ' ';
145 }
146 strUsage += '\n';
147
148 if (args.GetBoolArg("-version", false)) {
150 } else {
151 strUsage += "\n"
152 "The " CLIENT_NAME " daemon (bitcoind) is a headless program that connects to the Bitcoin network to validate and relay transactions and blocks, as well as relaying addresses.\n\n"
153 "It provides the backbone of the Bitcoin network and its RPC, REST and ZMQ services can provide various transaction, block and address-related services.\n\n"
154 "There is an optional wallet component which provides transaction services.\n\n"
155 "It can be used in a headless environment or as part of a server setup.\n"
156 "\n"
157 "Usage: bitcoind [options]\n"
158 "\n";
160 }
161
162 tfm::format(std::cout, "%s", strUsage);
163 return true;
164 }
165
166 return false;
167}
168
170{
171 bool fRet = false;
172 ArgsManager& args = *Assert(node.args);
173
174#if HAVE_DECL_FORK
175 // Communication with parent after daemonizing. This is used for signalling in the following ways:
176 // - a boolean token is sent when the initialization process (all the Init* functions) have finished to indicate
177 // that the parent process can quit, and whether it was successful/unsuccessful.
178 // - an unexpected shutdown of the child process creates an unexpected end of stream at the parent
179 // end, which is interpreted as failure to start.
181#endif
182 std::any context{&node};
183 try
184 {
185 // -server defaults to true for bitcoind but not for the GUI so do this here
186 args.SoftSetBoolArg("-server", true);
187 // Set this early so that parameter interactions go to console
190 if (!AppInitBasicSetup(args, node.exit_status)) {
191 // InitError will have been called with detailed error, which ends up on console
192 return false;
193 }
195 // InitError will have been called with detailed error, which ends up on console
196 return false;
197 }
198
199 node.warnings = std::make_unique<node::Warnings>();
200
201 node.kernel = std::make_unique<kernel::Context>();
202 node.ecc_context = std::make_unique<ECC_Context>();
203 if (!AppInitSanityChecks(*node.kernel))
204 {
205 // InitError will have been called with detailed error, which ends up on console
206 return false;
207 }
208
209 if (args.GetBoolArg("-daemon", DEFAULT_DAEMON) || args.GetBoolArg("-daemonwait", DEFAULT_DAEMONWAIT)) {
210#if HAVE_DECL_FORK
211 tfm::format(std::cout, CLIENT_NAME " starting\n");
212
213 // Daemonize
214 switch (fork_daemon(1, 0, daemon_ep)) { // don't chdir (1), do close FDs (0)
215 case 0: // Child: continue.
216 // If -daemonwait is not enabled, immediately send a success token the parent.
217 if (!args.GetBoolArg("-daemonwait", DEFAULT_DAEMONWAIT)) {
218 daemon_ep.TokenWrite(1);
219 daemon_ep.Close();
220 }
221 break;
222 case -1: // Error happened.
223 return InitError(Untranslated(strprintf("fork_daemon() failed: %s", SysErrorString(errno))));
224 default: { // Parent: wait and exit.
225 int token = daemon_ep.TokenRead();
226 if (token) { // Success
228 } else { // fRet = false or token read error (premature exit).
229 tfm::format(std::cerr, "Error during initialization - check %s for details\n", fs::PathToString(LogInstance().m_file_path.filename()));
231 }
232 }
233 }
234#else
235 return InitError(Untranslated("-daemon is not supported on this operating system"));
236#endif // HAVE_DECL_FORK
237 }
238 // Lock critical directories after daemonization
240 {
241 // If locking a directory failed, exit immediately
242 return false;
243 }
245 }
246 catch (const std::exception& e) {
247 PrintExceptionContinue(&e, "AppInit()");
248 } catch (...) {
249 PrintExceptionContinue(nullptr, "AppInit()");
250 }
251
252#if HAVE_DECL_FORK
253 if (daemon_ep.IsOpen()) {
254 // Signal initialization status to parent, then close pipe.
255 daemon_ep.TokenWrite(fRet);
256 daemon_ep.Close();
257 }
258#endif
259 return fRet;
260}
261
264{
267 std::unique_ptr<interfaces::Init> init = interfaces::MakeNodeInit(node, argc, argv, exit_status);
268 if (!init) {
269 return exit_status;
270 }
271
273
274 // Connect bitcoind signal handlers
275 noui_connect();
276
278
279 // Interpret command line arguments
282 // Process early info return commands such as -help or -version
284
285 // Start application
286 if (!AppInit(node) || !Assert(node.shutdown_signal)->wait()) {
287 node.exit_status = EXIT_FAILURE;
288 }
291
292 return node.exit_status;
293}
bool HelpRequested(const ArgsManager &args)
Definition args.cpp:795
bool IsSwitchChar(char c)
Definition args.h:44
return EXIT_SUCCESS
int exit_status
Definition bitcoind.cpp:266
noui_connect()
Definition noui.cpp:57
ArgsManager & args
Definition bitcoind.cpp:280
static bool ParseArgs(NodeContext &node, int argc, char *argv[])
Definition bitcoind.cpp:114
SetupEnvironment()
Definition system.cpp:56
const TranslateFn G_TRANSLATION_FUN
Translate string to current locale using Qt.
Definition bitcoind.cpp:39
static bool AppInit(NodeContext &node)
Definition bitcoind.cpp:169
Interrupt(node)
Shutdown(node)
static bool ProcessInitCommands(interfaces::Init &init, ArgsManager &args)
Definition bitcoind.cpp:137
MAIN_FUNCTION
Definition bitcoind.cpp:264
#define Assert(val)
Identity function.
Definition check.h:119
bool ParseParameters(int argc, const char *const argv[], std::string &error) EXCLUSIVE_LOCKS_REQUIRED(!cs_args)
Definition args.cpp:175
bool SoftSetBoolArg(const std::string &strArg, bool fValue) EXCLUSIVE_LOCKS_REQUIRED(!cs_args)
Set a boolean argument if it doesn't already have a value.
Definition args.cpp:602
bool GetBoolArg(const std::string &strArg, bool fDefault) const EXCLUSIVE_LOCKS_REQUIRED(!cs_args)
Return boolean argument or default value.
Definition args.cpp:560
std::string GetHelpMessage() const EXCLUSIVE_LOCKS_REQUIRED(!cs_args)
Get the help string.
Definition args.cpp:703
One end of a token pipe.
Definition tokenpipe.h:15
static std::optional< TokenPipe > Make()
Create a new pipe.
Definition tokenpipe.cpp:85
Initial interface created when a process is first started, and used to give and get access to other i...
Definition init.h:39
std::string FormatFullVersion()
void PrintExceptionContinue(const std::exception *pex, std::string_view thread_name)
Definition exception.cpp:36
static std::string PathToString(const path &path)
Convert path object to a byte string.
Definition fs.h:160
void InitLogging(const ArgsManager &args)
Initialize global loggers.
Definition init.cpp:880
bool AppInitBasicSetup(const ArgsManager &args, std::atomic< int > &exit_status)
Initialize bitcoin core: Basic context setup.
Definition init.cpp:909
bool AppInitParameterInteraction(const ArgsManager &args)
Initialization: parameter interaction.
Definition init.cpp:946
bool AppInitInterfaces(NodeContext &node)
Initialize node and wallet interface pointers.
Definition init.cpp:1307
void InitParameterInteraction(ArgsManager &args)
Parameter interaction: change current parameters depending on various rules.
Definition init.cpp:791
bool AppInitMain(NodeContext &node, interfaces::BlockAndHeaderTipInfo *tip_info)
Bitcoin core main initialization.
Definition init.cpp:1523
bool AppInitLockDirectories()
Lock bitcoin core critical directories.
Definition init.cpp:1295
void SetupServerArgs(ArgsManager &argsman, bool can_listen_ipc)
Register all arguments with the ArgsManager.
Definition init.cpp:479
bool AppInitSanityChecks(const kernel::Context &kernel)
Initialization sanity checks.
Definition init.cpp:1276
constexpr bool DEFAULT_DAEMON
Default value for -daemon option.
Definition init.h:12
constexpr bool DEFAULT_DAEMONWAIT
Default value for -daemonwait option.
Definition init.h:14
bool InitError(const bilingual_str &str)
Show error message.
std::string LicenseInfo()
Returns licensing information (for -version)
BCLog::Logger & LogInstance()
Definition logging.cpp:27
std::optional< ConfigError > InitConfig(ArgsManager &args, SettingsAbortFn settings_abort_fn)
Definition init.cpp:18
Definition basic.cpp:11
std::unique_ptr< Init > MakeNodeInit(node::NodeContext &node, int argc, char *argv[], int &exit_status)
Return implementation of Init interface for the node process.
void format(std::ostream &out, FormatStringCheck< sizeof...(Args)> fmt, const Args &... args)
Format list of arguments to the stream according to given format string.
void ThreadSetInternalName(const std::string &)
Set the internal (in-memory) name of the current thread only.
NodeContext struct containing references to chain state and connection state.
Definition context.h:57
std::string SysErrorString(int err)
Return system error string from errno value.
Definition syserror.cpp:18
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
std::function< std::string(const char *)> TranslateFn
Translate a message to the native language of the user.
Definition translation.h:16
bilingual_str Untranslated(std::string original)
Mark a bilingual_str as untranslated.
Definition translation.h:82
std::string FormatParagraph(std::string_view in, size_t width, size_t indent)
Format a paragraph of text to a fixed width, adding spaces for indentation to any added line.
constexpr auto Ticks(Dur2 d)
Helper to count the seconds of a duration/time_point.
Definition time.h:82
WalletContext context