Bitcoin Core 28.99.0
P2P Digital Currency
bitcoind.cpp
Go to the documentation of this file.
1// Copyright (c) 2009-2010 Satoshi Nakamoto
2// Copyright (c) 2009-2022 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/system.h>
13#include <compat/compat.h>
14#include <init.h>
15#include <interfaces/chain.h>
16#include <interfaces/init.h>
17#include <kernel/context.h>
18#include <node/context.h>
19#include <node/interface_ui.h>
20#include <node/warnings.h>
21#include <noui.h>
22#include <util/check.h>
23#include <util/exception.h>
25#include <util/strencodings.h>
26#include <util/syserror.h>
27#include <util/threadnames.h>
28#include <util/tokenpipe.h>
29#include <util/translation.h>
30
31#include <any>
32#include <functional>
33#include <optional>
34
36
37const std::function<std::string(const char*)> G_TRANSLATION_FUN = nullptr;
38
39#if HAVE_DECL_FORK
40
51int fork_daemon(bool nochdir, bool noclose, TokenPipeEnd& endpoint)
52{
53 // communication pipe with child process
54 std::optional<TokenPipe> umbilical = TokenPipe::Make();
55 if (!umbilical) {
56 return -1; // pipe or pipe2 failed.
57 }
58
59 int pid = fork();
60 if (pid < 0) {
61 return -1; // fork failed.
62 }
63 if (pid != 0) {
64 // Parent process gets read end, closes write end.
65 endpoint = umbilical->TakeReadEnd();
66 umbilical->TakeWriteEnd().Close();
67
68 int status = endpoint.TokenRead();
69 if (status != 0) { // Something went wrong while setting up child process.
70 endpoint.Close();
71 return -1;
72 }
73
74 return pid;
75 }
76 // Child process gets write end, closes read end.
77 endpoint = umbilical->TakeWriteEnd();
78 umbilical->TakeReadEnd().Close();
79
80#if HAVE_DECL_SETSID
81 if (setsid() < 0) {
82 exit(1); // setsid failed.
83 }
84#endif
85
86 if (!nochdir) {
87 if (chdir("/") != 0) {
88 exit(1); // chdir failed.
89 }
90 }
91 if (!noclose) {
92 // Open /dev/null, and clone it into STDIN, STDOUT and STDERR to detach
93 // from terminal.
94 int fd = open("/dev/null", O_RDWR);
95 if (fd >= 0) {
96 bool err = dup2(fd, STDIN_FILENO) < 0 || dup2(fd, STDOUT_FILENO) < 0 || dup2(fd, STDERR_FILENO) < 0;
97 // Don't close if fd<=2 to try to handle the case where the program was invoked without any file descriptors open.
98 if (fd > 2) close(fd);
99 if (err) {
100 exit(1); // dup2 failed.
101 }
102 } else {
103 exit(1); // open /dev/null failed.
104 }
105 }
106 endpoint.TokenWrite(0); // Success
107 return 0;
108}
109
110#endif
111
112static bool ParseArgs(NodeContext& node, int argc, char* argv[])
113{
114 ArgsManager& args{*Assert(node.args)};
115 // If Qt is used, parameters/bitcoin.conf are parsed in qt/bitcoin.cpp's main()
116 SetupServerArgs(args, node.init->canListenIpc());
117 std::string error;
118 if (!args.ParseParameters(argc, argv, error)) {
119 return InitError(Untranslated(strprintf("Error parsing command line arguments: %s", error)));
120 }
121
122 if (auto error = common::InitConfig(args)) {
123 return InitError(error->message, error->details);
124 }
125
126 // Error out when loose non-argument tokens are encountered on command line
127 for (int i = 1; i < argc; i++) {
128 if (!IsSwitchChar(argv[i][0])) {
129 return InitError(Untranslated(strprintf("Command line contains unexpected token '%s', see bitcoind -h for a list of options.", argv[i])));
130 }
131 }
132 return true;
133}
134
136{
137 // Process help and version before taking care about datadir
138 if (HelpRequested(args) || args.GetBoolArg("-version", false)) {
139 std::string strUsage = CLIENT_NAME " daemon version " + FormatFullVersion() + "\n";
140
141 if (args.GetBoolArg("-version", false)) {
142 strUsage += FormatParagraph(LicenseInfo());
143 } else {
144 strUsage += "\n"
145 "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"
146 "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"
147 "There is an optional wallet component which provides transaction services.\n\n"
148 "It can be used in a headless environment or as part of a server setup.\n"
149 "\n"
150 "Usage: bitcoind [options]\n"
151 "\n";
152 strUsage += args.GetHelpMessage();
153 }
154
155 tfm::format(std::cout, "%s", strUsage);
156 return true;
157 }
158
159 return false;
160}
161
163{
164 bool fRet = false;
165 ArgsManager& args = *Assert(node.args);
166
167#if HAVE_DECL_FORK
168 // Communication with parent after daemonizing. This is used for signalling in the following ways:
169 // - a boolean token is sent when the initialization process (all the Init* functions) have finished to indicate
170 // that the parent process can quit, and whether it was successful/unsuccessful.
171 // - an unexpected shutdown of the child process creates an unexpected end of stream at the parent
172 // end, which is interpreted as failure to start.
173 TokenPipeEnd daemon_ep;
174#endif
175 std::any context{&node};
176 try
177 {
178 // -server defaults to true for bitcoind but not for the GUI so do this here
179 args.SoftSetBoolArg("-server", true);
180 // Set this early so that parameter interactions go to console
183 if (!AppInitBasicSetup(args, node.exit_status)) {
184 // InitError will have been called with detailed error, which ends up on console
185 return false;
186 }
188 // InitError will have been called with detailed error, which ends up on console
189 return false;
190 }
191
192 node.warnings = std::make_unique<node::Warnings>();
193
194 node.kernel = std::make_unique<kernel::Context>();
195 node.ecc_context = std::make_unique<ECC_Context>();
196 if (!AppInitSanityChecks(*node.kernel))
197 {
198 // InitError will have been called with detailed error, which ends up on console
199 return false;
200 }
201
202 if (args.GetBoolArg("-daemon", DEFAULT_DAEMON) || args.GetBoolArg("-daemonwait", DEFAULT_DAEMONWAIT)) {
203#if HAVE_DECL_FORK
204 tfm::format(std::cout, CLIENT_NAME " starting\n");
205
206 // Daemonize
207 switch (fork_daemon(1, 0, daemon_ep)) { // don't chdir (1), do close FDs (0)
208 case 0: // Child: continue.
209 // If -daemonwait is not enabled, immediately send a success token the parent.
210 if (!args.GetBoolArg("-daemonwait", DEFAULT_DAEMONWAIT)) {
211 daemon_ep.TokenWrite(1);
212 daemon_ep.Close();
213 }
214 break;
215 case -1: // Error happened.
216 return InitError(Untranslated(strprintf("fork_daemon() failed: %s", SysErrorString(errno))));
217 default: { // Parent: wait and exit.
218 int token = daemon_ep.TokenRead();
219 if (token) { // Success
220 exit(EXIT_SUCCESS);
221 } else { // fRet = false or token read error (premature exit).
222 tfm::format(std::cerr, "Error during initialization - check debug.log for details\n");
223 exit(EXIT_FAILURE);
224 }
225 }
226 }
227#else
228 return InitError(Untranslated("-daemon is not supported on this operating system"));
229#endif // HAVE_DECL_FORK
230 }
231 // Lock data directory after daemonization
233 {
234 // If locking the data directory failed, exit immediately
235 return false;
236 }
238 }
239 catch (const std::exception& e) {
240 PrintExceptionContinue(&e, "AppInit()");
241 } catch (...) {
242 PrintExceptionContinue(nullptr, "AppInit()");
243 }
244
245#if HAVE_DECL_FORK
246 if (daemon_ep.IsOpen()) {
247 // Signal initialization status to parent, then close pipe.
248 daemon_ep.TokenWrite(fRet);
249 daemon_ep.Close();
250 }
251#endif
252 return fRet;
253}
254
256{
257#ifdef WIN32
258 common::WinCmdLineArgs winArgs;
259 std::tie(argc, argv) = winArgs.get();
260#endif
261
264 std::unique_ptr<interfaces::Init> init = interfaces::MakeNodeInit(node, argc, argv, exit_status);
265 if (!init) {
266 return exit_status;
267 }
268
270
271 // Connect bitcoind signal handlers
272 noui_connect();
273
275
276 // Interpret command line arguments
278 if (!ParseArgs(node, argc, argv)) return EXIT_FAILURE;
279 // Process early info return commands such as -help or -version
281
282 // Start application
283 if (!AppInit(node) || !Assert(node.shutdown_signal)->wait()) {
284 node.exit_status = EXIT_FAILURE;
285 }
288
289 return node.exit_status;
290}
bool HelpRequested(const ArgsManager &args)
Definition: args.cpp:684
bool IsSwitchChar(char c)
Definition: args.h:43
return EXIT_SUCCESS
int exit_status
Definition: bitcoind.cpp:263
noui_connect()
Definition: noui.cpp:60
ArgsManager & args
Definition: bitcoind.cpp:277
const std::function< std::string(const char *)> G_TRANSLATION_FUN
Translate string to current locale using Qt.
Definition: bitcoind.cpp:37
static bool ParseArgs(NodeContext &node, int argc, char *argv[])
Definition: bitcoind.cpp:112
SetupEnvironment()
Definition: system.cpp:59
static bool AppInit(NodeContext &node)
Definition: bitcoind.cpp:162
Interrupt(node)
Shutdown(node)
static bool ProcessInitCommands(ArgsManager &args)
Definition: bitcoind.cpp:135
MAIN_FUNCTION
Definition: bitcoind.cpp:256
#define Assert(val)
Identity function.
Definition: check.h:85
bool ParseParameters(int argc, const char *const argv[], std::string &error)
Definition: args.cpp:179
std::string GetHelpMessage() const
Get the help string.
Definition: args.cpp:609
bool SoftSetBoolArg(const std::string &strArg, bool fValue)
Set a boolean argument if it doesn't already have a value.
Definition: args.cpp:538
bool GetBoolArg(const std::string &strArg, bool fDefault) const
Return boolean argument or default value.
Definition: args.cpp:507
One end of a token pipe.
Definition: tokenpipe.h:15
bool IsOpen()
Return whether endpoint is open.
Definition: tokenpipe.h:53
int TokenWrite(uint8_t token)
Write token to endpoint.
Definition: tokenpipe.cpp:38
void Close()
Explicit close function.
Definition: tokenpipe.cpp:76
int TokenRead()
Read token from endpoint.
Definition: tokenpipe.cpp:56
static std::optional< TokenPipe > Make()
Create a new pipe.
Definition: tokenpipe.cpp:82
std::string FormatFullVersion()
std::string LicenseInfo()
Returns licensing information (for -version)
void PrintExceptionContinue(const std::exception *pex, std::string_view thread_name)
Definition: exception.cpp:36
void InitLogging(const ArgsManager &args)
Initialize global loggers.
Definition: init.cpp:801
bool AppInitLockDataDirectory()
Lock bitcoin core data directory.
Definition: init.cpp:1108
bool AppInitBasicSetup(const ArgsManager &args, std::atomic< int > &exit_status)
Initialize bitcoin core: Basic context setup.
Definition: init.cpp:830
bool AppInitParameterInteraction(const ArgsManager &args)
Initialization: parameter interaction.
Definition: init.cpp:867
bool AppInitInterfaces(NodeContext &node)
Initialize node and wallet interface pointers.
Definition: init.cpp:1120
void InitParameterInteraction(ArgsManager &args)
Parameter interaction: change current parameters depending on various rules.
Definition: init.cpp:713
bool AppInitMain(NodeContext &node, interfaces::BlockAndHeaderTipInfo *tip_info)
Bitcoin core main initialization.
Definition: init.cpp:1272
void SetupServerArgs(ArgsManager &argsman, bool can_listen_ipc)
Register all arguments with the ArgsManager.
Definition: init.cpp:443
bool AppInitSanityChecks(const kernel::Context &kernel)
Initialization sanity checks.
Definition: init.cpp:1089
static constexpr bool DEFAULT_DAEMON
Default value for -daemon option.
Definition: init.h:12
static constexpr bool DEFAULT_DAEMONWAIT
Default value for -daemonwait option.
Definition: init.h:14
bool InitError(const bilingual_str &str)
Show error message.
std::optional< ConfigError > InitConfig(ArgsManager &args, SettingsAbortFn settings_abort_fn)
Definition: init.cpp:18
std::unique_ptr< Init > MakeNodeInit(node::NodeContext &node, int argc, char *argv[], int &exit_status)
Return implementation of Init interface for the node process.
Definition: messages.h:20
void format(std::ostream &out, FormatStringCheck< sizeof...(Args)> fmt, const Args &... args)
Format list of arguments to the stream according to given format string.
Definition: tinyformat.h:1072
void ThreadSetInternalName(const std::string &)
Set the internal (in-memory) name of the current thread only.
Definition: threadnames.cpp:63
NodeContext struct containing references to chain state and connection state.
Definition: context.h:56
std::string SysErrorString(int err)
Return system error string from errno value.
Definition: syserror.cpp:19
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1165
bilingual_str Untranslated(std::string original)
Mark a bilingual_str as untranslated.
Definition: translation.h:51
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.